diff --git a/.gitattributes b/.gitattributes index 2b4f3d472632a..b223c8ac5fb84 100644 --- a/.gitattributes +++ b/.gitattributes @@ -4,7 +4,8 @@ *.cpp rust *.h rust *.rs rust +*.fixed linguist-language=Rust src/etc/installer/gfx/* binary *.woff binary src/vendor/** -text -Cargo.lock -merge +Cargo.lock -merge linguist-generated=false diff --git a/.gitignore b/.gitignore index efbbf22ffe57b..9ffaa82e1c8b5 100644 --- a/.gitignore +++ b/.gitignore @@ -74,27 +74,30 @@ __pycache__/ /obj/ /rt/ /rustllvm/ -/src/libstd_unicode/DerivedCoreProperties.txt -/src/libstd_unicode/DerivedNormalizationProps.txt -/src/libstd_unicode/PropList.txt -/src/libstd_unicode/ReadMe.txt -/src/libstd_unicode/Scripts.txt -/src/libstd_unicode/SpecialCasing.txt -/src/libstd_unicode/UnicodeData.txt +/src/libcore/unicode/DerivedCoreProperties.txt +/src/libcore/unicode/DerivedNormalizationProps.txt +/src/libcore/unicode/PropList.txt +/src/libcore/unicode/ReadMe.txt +/src/libcore/unicode/Scripts.txt +/src/libcore/unicode/SpecialCasing.txt +/src/libcore/unicode/UnicodeData.txt /stage[0-9]+/ /target target/ /test/ /tmp/ +tags +tags.* TAGS -TAGS.emacs -TAGS.vi +TAGS.* \#* \#*\# config.mk config.stamp keywords.md lexer.ml +mir_dump +Session.vim src/etc/dl tmp.*.rs version.md diff --git a/.gitmodules b/.gitmodules index 55f586389b117..f3eb902709ca7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -53,3 +53,6 @@ [submodule "src/tools/lld"] path = src/tools/lld url = https://github.com/rust-lang/lld.git +[submodule "src/libbacktrace"] + path = src/libbacktrace + url = https://github.com/rust-lang-nursery/libbacktrace diff --git a/.mailmap b/.mailmap index 3ff9e94ee5410..8f4287a438580 100644 --- a/.mailmap +++ b/.mailmap @@ -51,6 +51,7 @@ Carol Willing Chris C Cerami Chris C Cerami Chris Pressey Chris Thorn Chris Thorn +Chris Vittal Christopher Vittal Clark Gaebel Clinton Ryan Corey Richardson Elaine "See More" Nemo diff --git a/.travis.yml b/.travis.yml index 63831cd596122..0228fdc994dd7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,6 +3,10 @@ sudo: required dist: trusty services: - docker +addons: + apt: + packages: + - gdb git: depth: 2 @@ -12,7 +16,7 @@ matrix: fast_finish: true include: # Images used in testing PR and try-build should be run first. - - env: IMAGE=x86_64-gnu-llvm-3.9 RUST_BACKTRACE=1 + - env: IMAGE=x86_64-gnu-llvm-5.0 RUST_BACKTRACE=1 if: type = pull_request OR branch = auto - env: IMAGE=dist-x86_64-linux DEPLOY=1 @@ -169,7 +173,7 @@ matrix: - env: IMAGE=x86_64-gnu-aux if: branch = auto - env: IMAGE=x86_64-gnu-tools - if: branch = auto + if: branch = auto OR (type = pull_request AND commit_message =~ /(?i:^update.*\b(rls|rustfmt|clippy|miri)\b)/) - env: IMAGE=x86_64-gnu-debug if: branch = auto - env: IMAGE=x86_64-gnu-nopt @@ -197,7 +201,7 @@ env: # AWS_SECRET_ACCESS_KEY=... - secure: "j96XxTVOSUf4s4r4htIxn/fvIa5DWbMgLqWl7r8z2QfgUwscmkMXAwXuFNc7s7bGTpV/+CgDiMFFM6BAFLGKutytIF6oA02s9b+usQYnM0th7YQ2AIgm9GtMTJCJp4AoyfFmh8F2faUICBZlfVLUJ34udHEe35vOklix+0k4WDo=" # TOOLSTATE_REPO_ACCESS_TOKEN=... - - secure: "cFh8thThqEJLC98XKI5pfqflUzOlxsYPRW20AWRaYOOgYHPTiGWypTXiPbGSKaeAXTZoOA+DpQtEmefc0U6lt9dHc7a/MIaK6isFurjlnKYiLOeTruzyu1z7PWCeZ/jKXsU2RK/88DBtlNwfMdaMIeuKj14IVfpepPPL71ETbuk=" + - secure: "ESfcXqv4N2VMhqi2iIyw6da9VrsA78I4iR1asouCaq4hzTTrkB4WNRrfURy6xg72gQ4nMhtRJbB0/2jmc9Cu1+g2CzXtyiL223aJ5CKrXdcvbitopQSDfp07dMWm+UED+hNFEanpErKAeU/6FM3A+J+60PMk8MCF1h9tqNRISJw=" before_install: # We'll use the AWS cli to download/upload cached docker layers, so install @@ -230,7 +234,11 @@ install: travis_retry curl -fo /usr/local/bin/sccache https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-apple-darwin && chmod +x /usr/local/bin/sccache && travis_retry curl -fo /usr/local/bin/stamp https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2017-03-17-stamp-x86_64-apple-darwin && - chmod +x /usr/local/bin/stamp + chmod +x /usr/local/bin/stamp && + travis_retry curl -f http://releases.llvm.org/6.0.0/clang+llvm-6.0.0-x86_64-apple-darwin.tar.xz | tar xJf - && + export CC=`pwd`/clang+llvm-6.0.0-x86_64-apple-darwin/bin/clang && + export CXX=`pwd`/clang+llvm-6.0.0-x86_64-apple-darwin/bin/clang++ && + export AR=ar ;; esac @@ -245,6 +253,8 @@ before_script: export RUN_SCRIPT="$RUN_SCRIPT && src/ci/run.sh"; else export RUN_SCRIPT="$RUN_SCRIPT && src/ci/docker/run.sh $IMAGE"; + # Enable core dump on Linux. + sudo sh -c 'echo "/checkout/obj/cores/core.%p.%E" > /proc/sys/kernel/core_pattern'; fi # Log time information from this machine and an external machine for insight into possible @@ -270,6 +280,8 @@ after_failure: # Random attempt at debugging currently. Just poking around in here to see if # anything shows up. + + # Dump backtrace for macOS - ls -lat $HOME/Library/Logs/DiagnosticReports/ - find $HOME/Library/Logs/DiagnosticReports -type f @@ -280,6 +292,25 @@ after_failure: -exec head -750 {} \; -exec echo travis_fold":"end:crashlog \; || true + # Dump backtrace for Linux + - ln -s . checkout && + for CORE in obj/cores/core.*; do + EXE=$(echo $CORE | sed 's|obj/cores/core\.[0-9]*\.!checkout!\(.*\)|\1|;y|!|/|'); + if [ -f "$EXE" ]; then + printf travis_fold":start:crashlog\n\033[31;1m%s\033[0m\n" "$CORE"; + gdb -q -c "$CORE" "$EXE" + -iex 'set auto-load off' + -iex 'dir src/' + -iex 'set sysroot .' + -ex bt + -ex q; + echo travis_fold":"end:crashlog; + fi; + done || true + + # see #50887 + - cat ./obj/build/x86_64-unknown-linux-gnu/native/asan/build/lib/asan/clang_rt.asan-dynamic-i386.vers || true + # attempt to debug anything killed by the oom killer on linux, just to see if # it happened - dmesg | grep -i kill @@ -297,7 +328,6 @@ before_deploy: rm -rf obj/build/dist/doc && cp -r obj/build/dist/* deploy/$TRAVIS_COMMIT; fi - - travis_retry gem update --system - ls -la deploy/$TRAVIS_COMMIT deploy: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e7041dcddc42c..ea9f2c1943005 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,7 +48,7 @@ always work, and sometimes it's hard to know what to search for, so consider thi extra credit. We won't mind if you accidentally file a duplicate report. Similarly, to help others who encountered the bug find your issue, -consider filing an issue with with a descriptive title, which contains information that might be unique to it. +consider filing an issue with a descriptive title, which contains information that might be unique to it. This can be the language or compiler feature used, the conditions that trigger the bug, or part of the error message if there is any. An example could be: **"impossible case reached" on lifetime inference for impl Trait in return position**. @@ -142,7 +142,7 @@ file. If you still have a `config.mk` file in your directory - from ### Building [building]: #building -A default configuration shall use around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB. +A default configuration requires around 3.5 GB of disk space, whereas building a debug configuration may require more than 30 GB. Dependencies - [build dependencies](README.md#building-from-source) diff --git a/README.md b/README.md index 19ef96fae015c..a2acfe8b478e2 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ Read ["Installation"] from [The Book]. 3. Build and install: ```sh + $ git submodule update --init --recursive --progress $ ./x.py build && sudo ./x.py install ``` @@ -119,7 +120,7 @@ shell with: > python x.py build ``` -Currently building Rust only works with some known versions of Visual Studio. If +Currently, building Rust only works with some known versions of Visual Studio. If you have a more recent version installed the build system doesn't understand then you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. @@ -133,7 +134,7 @@ python x.py build [specifying-an-abi]: #specifying-an-abi Each specific ABI can also be used from either environment (for example, using -the GNU ABI in powershell) by using an explicit build triple. The available +the GNU ABI in PowerShell) by using an explicit build triple. The available Windows build triples are: - GNU ABI (using GCC) - `i686-pc-windows-gnu` @@ -179,7 +180,7 @@ the ABI used. I.e., if the ABI was `x86_64-pc-windows-msvc`, the directory will [notes]: #notes Since the Rust compiler is written in Rust, it must be built by a -precompiled "snapshot" version of itself (made in an earlier state of +precompiled "snapshot" version of itself (made in an earlier stage of development). As such, source builds require a connection to the Internet, to fetch snapshots, and an OS that can execute the available snapshot binaries. @@ -224,13 +225,16 @@ variety of channels on Mozilla's IRC network, irc.mozilla.org. The most popular channel is [#rust], a venue for general discussion about Rust. And a good place to ask for help would be [#rust-beginners]. -Also, the [rustc guide] might be a good place to start if you want to -find out how various parts of the compiler work. +The [rustc guide] might be a good place to start if you want to find out how +various parts of the compiler work. + +Also, you may find the [rustdocs for the compiler itself][rustdocs] useful. [IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat [#rust]: irc://irc.mozilla.org/rust [#rust-beginners]: irc://irc.mozilla.org/rust-beginners [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html +[rustdocs]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc/ ## License [license]: #license diff --git a/RELEASES.md b/RELEASES.md index 39cef1e2a5770..b983851f88198 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,9 +1,581 @@ +Version 1.28.0 (2018-08-02) +=========================== + +Language +-------- +- [The `#[repr(transparent)]` attribute is now stable.][51562] This attribute + allows a Rust newtype wrapper (`struct NewType(T);`) to be represented as + the inner type across Foreign Function Interface (FFI) boundaries. +- [The keywords `pure`, `sizeof`, `alignof`, and `offsetof` have been unreserved + and can now be used as identifiers.][51196] +- [The `GlobalAlloc` trait and `#[global_allocator]` attribute are now + stable.][51241] This will allow users to specify a global allocator for + their program. +- [Unit test functions marked with the `#[test]` attribute can now return + `Result<(), E: Debug>` in addition to `()`.][51298] +- [The `lifetime` specifier for `macro_rules!` is now stable.][50385] This + allows macros to easily target lifetimes. + +Compiler +-------- +- [The `s` and `z` optimisation levels are now stable.][50265] These optimisations + prioritise making smaller binary sizes. `z` is the same as `s` with the + exception that it does not vectorise loops, which typically results in an even + smaller binary. +- [The short error format is now stable.][49546] Specified with + `--error-format=short` this option will provide a more compressed output of + rust error messages. +- [Added a lint warning when you have duplicated `macro_export`s.][50143] +- [Reduced the number of allocations in the macro parser.][50855] This can + improve compile times of macro heavy crates on average by 5%. + +Libraries +--------- +- [Implemented `Default` for `&mut str`.][51306] +- [Implemented `From` for all integer and unsigned number types.][50554] +- [Implemented `Extend` for `()`.][50234] +- [The `Debug` implementation of `time::Duration` should now be more easily + human readable.][50364] Previously a `Duration` of one second would printed as + `Duration { secs: 1, nanos: 0 }` and will now be printed as `1s`. +- [Implemented `From<&String>` for `Cow`, `From<&Vec>` for `Cow<[T]>`, + `From>` for `CString`, `From, From, From<&CString>` + for `Cow`, `From, From, From<&OsString>` for + `Cow`, `From<&PathBuf>` for `Cow`, and `From>` + for `PathBuf`.][50170] +- [Implemented `Shl` and `Shr` for `Wrapping` + and `Wrapping`.][50465] +- [`DirEntry::metadata` now uses `fstatat` instead of `lstat` when + possible.][51050] This can provide up to a 40% speed increase. +- [Improved error messages when using `format!`.][50610] + +Stabilized APIs +--------------- +- [`Iterator::step_by`] +- [`Path::ancestors`] +- [`SystemTime::UNIX_EPOCH`] +- [`alloc::GlobalAlloc`] +- [`alloc::Layout`] +- [`alloc::LayoutErr`] +- [`alloc::System`] +- [`alloc::alloc`] +- [`alloc::alloc_zeroed`] +- [`alloc::dealloc`] +- [`alloc::realloc`] +- [`alloc::handle_alloc_error`] +- [`btree_map::Entry::or_default`] +- [`fmt::Alignment`] +- [`hash_map::Entry::or_default`] +- [`iter::repeat_with`] +- [`num::NonZeroUsize`] +- [`num::NonZeroU128`] +- [`num::NonZeroU16`] +- [`num::NonZeroU32`] +- [`num::NonZeroU64`] +- [`num::NonZeroU8`] +- [`ops::RangeBounds`] +- [`slice::SliceIndex`] +- [`slice::from_mut`] +- [`slice::from_ref`] +- [`{Any + Send + Sync}::downcast_mut`] +- [`{Any + Send + Sync}::downcast_ref`] +- [`{Any + Send + Sync}::is`] + +Cargo +----- +- [Cargo will now no longer allow you to publish crates with build scripts that + modify the `src` directory.][cargo/5584] The `src` directory in a crate should be + considered to be immutable. + +Misc +---- +- [The `suggestion_applicability` field in `rustc`'s json output is now + stable.][50486] This will allow dev tools to check whether a code suggestion + would apply to them. + +Compatibility Notes +------------------- +- [Rust will no longer consider trait objects with duplicated constraints to + have implementations.][51276] For example the below code will now fail + to compile. + ```rust + trait Trait {} + + impl Trait + Send { + fn test(&self) { println!("one"); } //~ ERROR duplicate definitions with name `test` + } + + impl Trait + Send + Send { + fn test(&self) { println!("two"); } + } + ``` + +[49546]: https://github.com/rust-lang/rust/pull/49546/ +[50143]: https://github.com/rust-lang/rust/pull/50143/ +[50170]: https://github.com/rust-lang/rust/pull/50170/ +[50234]: https://github.com/rust-lang/rust/pull/50234/ +[50265]: https://github.com/rust-lang/rust/pull/50265/ +[50364]: https://github.com/rust-lang/rust/pull/50364/ +[50385]: https://github.com/rust-lang/rust/pull/50385/ +[50465]: https://github.com/rust-lang/rust/pull/50465/ +[50486]: https://github.com/rust-lang/rust/pull/50486/ +[50554]: https://github.com/rust-lang/rust/pull/50554/ +[50610]: https://github.com/rust-lang/rust/pull/50610/ +[50855]: https://github.com/rust-lang/rust/pull/50855/ +[51050]: https://github.com/rust-lang/rust/pull/51050/ +[51196]: https://github.com/rust-lang/rust/pull/51196/ +[51200]: https://github.com/rust-lang/rust/pull/51200/ +[51241]: https://github.com/rust-lang/rust/pull/51241/ +[51276]: https://github.com/rust-lang/rust/pull/51276/ +[51298]: https://github.com/rust-lang/rust/pull/51298/ +[51306]: https://github.com/rust-lang/rust/pull/51306/ +[51562]: https://github.com/rust-lang/rust/pull/51562/ +[cargo/5584]: https://github.com/rust-lang/cargo/pull/5584/ +[`Iterator::step_by`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.step_by +[`Path::ancestors`]: https://doc.rust-lang.org/std/path/struct.Path.html#method.ancestors +[`SystemTime::UNIX_EPOCH`]: https://doc.rust-lang.org/std/time/struct.SystemTime.html#associatedconstant.UNIX_EPOCH +[`alloc::GlobalAlloc`]: https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html +[`alloc::Layout`]: https://doc.rust-lang.org/std/alloc/struct.Layout.html +[`alloc::LayoutErr`]: https://doc.rust-lang.org/std/alloc/struct.LayoutErr.html +[`alloc::System`]: https://doc.rust-lang.org/std/alloc/struct.System.html +[`alloc::alloc`]: https://doc.rust-lang.org/std/alloc/fn.alloc.html +[`alloc::alloc_zeroed`]: https://doc.rust-lang.org/std/alloc/fn.alloc_zeroed.html +[`alloc::dealloc`]: https://doc.rust-lang.org/std/alloc/fn.dealloc.html +[`alloc::realloc`]: https://doc.rust-lang.org/std/alloc/fn.realloc.html +[`alloc::handle_alloc_error`]: https://doc.rust-lang.org/std/alloc/fn.handle_alloc_error.html +[`btree_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.or_default +[`fmt::Alignment`]: https://doc.rust-lang.org/std/fmt/enum.Alignment.html +[`hash_map::Entry::or_default`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.or_default +[`iter::repeat_with`]: https://doc.rust-lang.org/std/iter/fn.repeat_with.html +[`num::NonZeroUsize`]: https://doc.rust-lang.org/std/num/struct.NonZeroUsize.html +[`num::NonZeroU128`]: https://doc.rust-lang.org/std/num/struct.NonZeroU128.html +[`num::NonZeroU16`]: https://doc.rust-lang.org/std/num/struct.NonZeroU16.html +[`num::NonZeroU32`]: https://doc.rust-lang.org/std/num/struct.NonZeroU32.html +[`num::NonZeroU64`]: https://doc.rust-lang.org/std/num/struct.NonZeroU64.html +[`num::NonZeroU8`]: https://doc.rust-lang.org/std/num/struct.NonZeroU8.html +[`ops::RangeBounds`]: https://doc.rust-lang.org/std/ops/trait.RangeBounds.html +[`slice::SliceIndex`]: https://doc.rust-lang.org/std/slice/trait.SliceIndex.html +[`slice::from_mut`]: https://doc.rust-lang.org/std/slice/fn.from_mut.html +[`slice::from_ref`]: https://doc.rust-lang.org/std/slice/fn.from_ref.html +[`{Any + Send + Sync}::downcast_mut`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_mut-2 +[`{Any + Send + Sync}::downcast_ref`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.downcast_ref-2 +[`{Any + Send + Sync}::is`]: https://doc.rust-lang.org/std/any/trait.Any.html#method.is-2 + +Version 1.27.1 (2018-07-10) +=========================== + +Security Notes +-------------- + +- rustdoc would execute plugins in the /tmp/rustdoc/plugins directory + when running, which enabled executing code as some other user on a + given machine. This release fixes that vulnerability; you can read + more about this on the [blog][rustdoc-sec]. The associated CVE is [CVE-2018-1000622]. + + Thank you to Red Hat for responsibily disclosing this vulnerability to us. + +Compatibility Notes +------------------- + +- The borrow checker was fixed to avoid an additional potential unsoundness when using + match ergonomics: [#51415][51415], [#49534][49534]. + +[51415]: https://github.com/rust-lang/rust/issues/51415 +[49534]: https://github.com/rust-lang/rust/issues/49534 +[rustdoc-sec]: https://blog.rust-lang.org/2018/07/06/security-advisory-for-rustdoc.html +[CVE-2018-1000622]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=%20CVE-2018-1000622 + +Version 1.27.0 (2018-06-21) +========================== + +Language +-------- +- [Removed 'proc' from the reserved keywords list.][49699] This allows `proc` to + be used as an identifer. +- [The dyn syntax is now available.][49968] This syntax is equivalent to the + bare `Trait` syntax, and should make it clearer when being used in tandem with + `impl Trait`. Since it is equivalent to the following syntax: + `&Trait == &dyn Trait`, `&mut Trait == &mut dyn Trait`, and + `Box == Box`. +- [Attributes on generic parameters such as types and lifetimes are + now stable.][48851] e.g. + `fn foo<#[lifetime_attr] 'a, #[type_attr] T: 'a>() {}` +- [The `#[must_use]` attribute can now also be used on functions as well as + types.][48925] It provides a lint that by default warns users when the + value returned by a function has not been used. + +Compiler +-------- +- [Added the `armv5te-unknown-linux-musl` target.][50423] + +Libraries +--------- +- [SIMD (Single Instruction Multiple Data) on x86/x86_64 is now stable.][49664] + This includes [`arch::x86`] & [`arch::x86_64`] modules which contain + SIMD intrinsics, a new macro called `is_x86_feature_detected!`, the + `#[target_feature(enable="")]` attribute, and adding `target_feature = ""` to + the `cfg` attribute. +- [A lot of methods for `[u8]`, `f32`, and `f64` previously only available in + std are now available in core.][49896] +- [The generic `Rhs` type parameter on `ops::{Shl, ShlAssign, Shr}` now defaults + to `Self`.][49630] +- [`std::str::replace` now has the `#[must_use]` attribute][50177] to clarify + that the operation isn't done in place. +- [`Clone::clone`, `Iterator::collect`, and `ToOwned::to_owned` now have + the `#[must_use]` attribute][49533] to warn about unused potentially + expensive allocations. + +Stabilized APIs +--------------- +- [`DoubleEndedIterator::rfind`] +- [`DoubleEndedIterator::rfold`] +- [`DoubleEndedIterator::try_rfold`] +- [`Duration::from_micros`] +- [`Duration::from_nanos`] +- [`Duration::subsec_micros`] +- [`Duration::subsec_millis`] +- [`HashMap::remove_entry`] +- [`Iterator::try_fold`] +- [`Iterator::try_for_each`] +- [`NonNull::cast`] +- [`Option::filter`] +- [`String::replace_range`] +- [`Take::set_limit`] +- [`hint::unreachable_unchecked`] +- [`os::unix::process::parent_id`] +- [`ptr::swap_nonoverlapping`] +- [`slice::rsplit_mut`] +- [`slice::rsplit`] +- [`slice::swap_with_slice`] + +Cargo +----- +- [`cargo-metadata` now includes `authors`, `categories`, `keywords`, + `readme`, and `repository` fields.][cargo/5386] +- [`cargo-metadata` now includes a package's `metadata` table.][cargo/5360] +- [Added the `--target-dir` optional argument.][cargo/5393] This allows you to specify + a different directory than `target` for placing compilation artifacts. +- [Cargo will be adding automatic target inference for binaries, benchmarks, + examples, and tests in the Rust 2018 edition.][cargo/5335] If your project specifies + specific targets e.g. using `[[bin]]` and have other binaries in locations + where cargo would infer a binary, Cargo will produce a warning. You can + disable this feature ahead of time by setting any of the following `autobins`, + `autobenches`, `autoexamples`, `autotests` to false. +- [Cargo will now cache compiler information.][cargo/5359] This can be disabled by + setting `CARGO_CACHE_RUSTC_INFO=0` in your environment. + +Misc +---- +- [Added “The Rustc book” into the official documentation.][49707] + [“The Rustc book”] documents and teaches how to use the rustc compiler. +- [All books available on `doc.rust-lang.org` are now searchable.][49623] + +Compatibility Notes +------------------- +- [Calling a `CharExt` or `StrExt` method directly on core will no longer + work.][49896] e.g. `::core::prelude::v1::StrExt::is_empty("")` will not + compile, `"".is_empty()` will still compile. +- [`Debug` output on `atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize}` + will only print the inner type.][48553] e.g. + `print!("{:?}", AtomicBool::new(true))` will print `true` + not `AtomicBool(true)`. +- [The maximum number for `repr(align(N))` is now 2²⁹.][50378] Previously you + could enter higher numbers but they were not supported by LLVM. Up to 512MB + alignment should cover all use cases. + +[48553]: https://github.com/rust-lang/rust/pull/48553/ +[48851]: https://github.com/rust-lang/rust/pull/48851/ +[48925]: https://github.com/rust-lang/rust/pull/48925/ +[49533]: https://github.com/rust-lang/rust/pull/49533/ +[49623]: https://github.com/rust-lang/rust/pull/49623/ +[49630]: https://github.com/rust-lang/rust/pull/49630/ +[49664]: https://github.com/rust-lang/rust/pull/49664/ +[49699]: https://github.com/rust-lang/rust/pull/49699/ +[49707]: https://github.com/rust-lang/rust/pull/49707/ +[49719]: https://github.com/rust-lang/rust/pull/49719/ +[49896]: https://github.com/rust-lang/rust/pull/49896/ +[49968]: https://github.com/rust-lang/rust/pull/49968/ +[50177]: https://github.com/rust-lang/rust/pull/50177/ +[50378]: https://github.com/rust-lang/rust/pull/50378/ +[50398]: https://github.com/rust-lang/rust/pull/50398/ +[50423]: https://github.com/rust-lang/rust/pull/50423/ +[cargo/5203]: https://github.com/rust-lang/cargo/pull/5203/ +[cargo/5335]: https://github.com/rust-lang/cargo/pull/5335/ +[cargo/5359]: https://github.com/rust-lang/cargo/pull/5359/ +[cargo/5360]: https://github.com/rust-lang/cargo/pull/5360/ +[cargo/5386]: https://github.com/rust-lang/cargo/pull/5386/ +[cargo/5393]: https://github.com/rust-lang/cargo/pull/5393/ +[`DoubleEndedIterator::rfind`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfind +[`DoubleEndedIterator::rfold`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.rfold +[`DoubleEndedIterator::try_rfold`]: https://doc.rust-lang.org/std/iter/trait.DoubleEndedIterator.html#method.try_rfold +[`Duration::from_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_micros +[`Duration::from_nanos`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.from_nanos +[`Duration::subsec_micros`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.subsec_micros +[`Duration::subsec_millis`]: https://doc.rust-lang.org/std/time/struct.Duration.html#method.subsec_millis +[`HashMap::remove_entry`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html#method.remove_entry +[`Iterator::try_fold`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_fold +[`Iterator::try_for_each`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_for_each +[`NonNull::cast`]: https://doc.rust-lang.org/std/ptr/struct.NonNull.html#method.cast +[`Option::filter`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.filter +[`String::replace_range`]: https://doc.rust-lang.org/std/string/struct.String.html#method.replace_range +[`Take::set_limit`]: https://doc.rust-lang.org/std/io/struct.Take.html#method.set_limit +[`hint::unreachable_unchecked`]: https://doc.rust-lang.org/std/hint/fn.unreachable_unchecked.html +[`os::unix::process::parent_id`]: https://doc.rust-lang.org/std/os/unix/process/fn.parent_id.html +[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html +[`ptr::swap_nonoverlapping`]: https://doc.rust-lang.org/std/ptr/fn.swap_nonoverlapping.html +[`slice::rsplit_mut`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit_mut +[`slice::rsplit`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rsplit +[`slice::swap_with_slice`]: https://doc.rust-lang.org/std/primitive.slice.html#method.swap_with_slice +[`arch::x86_64`]: https://doc.rust-lang.org/std/arch/x86_64/index.html +[`arch::x86`]: https://doc.rust-lang.org/std/arch/x86/index.html +[“The Rustc book”]: https://doc.rust-lang.org/rustc + + +Version 1.26.2 (2018-06-05) +========================== + +Compatibility Notes +------------------- + +- [The borrow checker was fixed to avoid unsoundness when using match ergonomics][51117] + +[51117]: https://github.com/rust-lang/rust/issues/51117 + + +Version 1.26.1 (2018-05-29) +========================== + +Tools +----- + +- [RLS now works on Windows][50646] +- [Rustfmt stopped badly formatting text in some cases][rustfmt/2695] + + +Compatibility Notes +-------- + +- [`fn main() -> impl Trait` no longer works for non-Termination + trait][50656] + This reverts an accidental stabilization. +- [`NaN > NaN` no longer returns true in const-fn contexts][50812] +- [Prohibit using turbofish for `impl Trait` in method arguments][50950] + +[50646]: https://github.com/rust-lang/rust/issues/50646 +[50656]: https://github.com/rust-lang/rust/pull/50656 +[50812]: https://github.com/rust-lang/rust/pull/50812 +[50950]: https://github.com/rust-lang/rust/issues/50950 +[rustfmt/2695]: https://github.com/rust-lang-nursery/rustfmt/issues/2695 + +Version 1.26.0 (2018-05-10) +========================== + +Language +-------- +- [Closures now implement `Copy` and/or `Clone` if all captured variables + implement either or both traits.][49299] +- [The inclusive range syntax e.g. `for x in 0..=10` is now stable.][47813] +- [The `'_` lifetime is now stable. The underscore lifetime can be used anywhere where a + lifetime can be elided.][49458] +- [`impl Trait` is now stable allowing you to have abstract types in returns + or in function parameters.][49255] e.g. `fn foo() -> impl Iterator` or + `fn open(path: impl AsRef)`. +- [Pattern matching will now automatically apply dereferences.][49394] +- [128-bit integers in the form of `u128` and `i128` are now stable.][49101] +- [`main` can now return `Result<(), E: Debug>`][49162] in addition to `()`. +- [A lot of operations are now available in a const context.][46882] E.g. You + can now index into constant arrays, reference and dereference into constants, + and use Tuple struct constructors. +- [Fixed entry slice patterns are now stable.][48516] e.g. + ```rust + let points = [1, 2, 3, 4]; + match points { + [1, 2, 3, 4] => println!("All points were sequential."), + _ => println!("Not all points were sequential."), + } + ``` + + +Compiler +-------- +- [LLD is now used as the default linker for `wasm32-unknown-unknown`.][48125] +- [Fixed exponential projection complexity on nested types.][48296] + This can provide up to a ~12% reduction in compile times for certain crates. +- [Added the `--remap-path-prefix` option to rustc.][48359] Allowing you + to remap path prefixes outputted by the compiler. +- [Added `powerpc-unknown-netbsd` target.][48281] + +Libraries +--------- +- [Implemented `From for usize` & `From<{u8, i16}> for isize`.][49305] +- [Added hexadecimal formatting for integers with fmt::Debug][48978] + e.g. `assert!(format!("{:02x?}", b"Foo\0") == "[46, 6f, 6f, 00]")` +- [Implemented `Default, Hash` for `cmp::Reverse`.][48628] +- [Optimized `str::repeat` being 8x faster in large cases.][48657] +- [`ascii::escape_default` is now available in libcore.][48735] +- [Trailing commas are now supported in std and core macros.][48056] +- [Implemented `Copy, Clone` for `cmp::Reverse`][47379] +- [Implemented `Clone` for `char::{ToLowercase, ToUppercase}`.][48629] + +Stabilized APIs +--------------- +- [`*const T::add`] +- [`*const T::copy_to_nonoverlapping`] +- [`*const T::copy_to`] +- [`*const T::read_unaligned`] +- [`*const T::read_volatile`] +- [`*const T::read`] +- [`*const T::sub`] +- [`*const T::wrapping_add`] +- [`*const T::wrapping_sub`] +- [`*mut T::add`] +- [`*mut T::copy_to_nonoverlapping`] +- [`*mut T::copy_to`] +- [`*mut T::read_unaligned`] +- [`*mut T::read_volatile`] +- [`*mut T::read`] +- [`*mut T::replace`] +- [`*mut T::sub`] +- [`*mut T::swap`] +- [`*mut T::wrapping_add`] +- [`*mut T::wrapping_sub`] +- [`*mut T::write_bytes`] +- [`*mut T::write_unaligned`] +- [`*mut T::write_volatile`] +- [`*mut T::write`] +- [`Box::leak`] +- [`FromUtf8Error::as_bytes`] +- [`LocalKey::try_with`] +- [`Option::cloned`] +- [`btree_map::Entry::and_modify`] +- [`fs::read_to_string`] +- [`fs::read`] +- [`fs::write`] +- [`hash_map::Entry::and_modify`] +- [`iter::FusedIterator`] +- [`ops::RangeInclusive`] +- [`ops::RangeToInclusive`] +- [`process::id`] +- [`slice::rotate_left`] +- [`slice::rotate_right`] +- [`String::retain`] + + +Cargo +----- +- [Cargo will now output path to custom commands when `-v` is + passed with `--list`][cargo/5041] +- [The Cargo binary version is now the same as the Rust version][cargo/5083] + +Misc +---- +- [The second edition of "The Rust Programming Language" book is now recommended + over the first.][48404] + +Compatibility Notes +------------------- + +- [aliasing a `Fn` trait as `dyn` no longer works.][48481] E.g. the following + syntax is now invalid. + ``` + use std::ops::Fn as dyn; + fn g(_: Box) {} + ``` +- [The result of dereferences are no longer promoted to `'static`.][47408] + e.g. + ```rust + fn main() { + const PAIR: &(i32, i32) = &(0, 1); + let _reversed_pair: &'static _ = &(PAIR.1, PAIR.0); // Doesn't work + } + ``` +- [Deprecate `AsciiExt` trait in favor of inherent methods.][49109] +- [`".e0"` will now no longer parse as `0.0` and will instead cause + an error.][48235] +- [Removed hoedown from rustdoc.][48274] +- [Bounds on higher-kinded lifetimes a hard error.][48326] + +[46882]: https://github.com/rust-lang/rust/pull/46882 +[47379]: https://github.com/rust-lang/rust/pull/47379 +[47408]: https://github.com/rust-lang/rust/pull/47408 +[47813]: https://github.com/rust-lang/rust/pull/47813 +[48056]: https://github.com/rust-lang/rust/pull/48056 +[48125]: https://github.com/rust-lang/rust/pull/48125 +[48166]: https://github.com/rust-lang/rust/pull/48166 +[48235]: https://github.com/rust-lang/rust/pull/48235 +[48274]: https://github.com/rust-lang/rust/pull/48274 +[48281]: https://github.com/rust-lang/rust/pull/48281 +[48296]: https://github.com/rust-lang/rust/pull/48296 +[48326]: https://github.com/rust-lang/rust/pull/48326 +[48359]: https://github.com/rust-lang/rust/pull/48359 +[48404]: https://github.com/rust-lang/rust/pull/48404 +[48481]: https://github.com/rust-lang/rust/pull/48481 +[48516]: https://github.com/rust-lang/rust/pull/48516 +[48628]: https://github.com/rust-lang/rust/pull/48628 +[48629]: https://github.com/rust-lang/rust/pull/48629 +[48657]: https://github.com/rust-lang/rust/pull/48657 +[48735]: https://github.com/rust-lang/rust/pull/48735 +[48978]: https://github.com/rust-lang/rust/pull/48978 +[49101]: https://github.com/rust-lang/rust/pull/49101 +[49109]: https://github.com/rust-lang/rust/pull/49109 +[49121]: https://github.com/rust-lang/rust/pull/49121 +[49162]: https://github.com/rust-lang/rust/pull/49162 +[49184]: https://github.com/rust-lang/rust/pull/49184 +[49234]: https://github.com/rust-lang/rust/pull/49234 +[49255]: https://github.com/rust-lang/rust/pull/49255 +[49299]: https://github.com/rust-lang/rust/pull/49299 +[49305]: https://github.com/rust-lang/rust/pull/49305 +[49394]: https://github.com/rust-lang/rust/pull/49394 +[49458]: https://github.com/rust-lang/rust/pull/49458 +[`*const T::add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.add +[`*const T::copy_to_nonoverlapping`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.copy_to_nonoverlapping +[`*const T::copy_to`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.copy_to +[`*const T::read_unaligned`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read_unaligned +[`*const T::read_volatile`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read_volatile +[`*const T::read`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read +[`*const T::sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.sub +[`*const T::wrapping_add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add +[`*const T::wrapping_sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub +[`*mut T::add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.add-1 +[`*mut T::copy_to_nonoverlapping`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.copy_to_nonoverlapping-1 +[`*mut T::copy_to`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.copy_to-1 +[`*mut T::read_unaligned`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read_unaligned-1 +[`*mut T::read_volatile`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read_volatile-1 +[`*mut T::read`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.read-1 +[`*mut T::replace`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.replace +[`*mut T::sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.sub-1 +[`*mut T::swap`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.swap +[`*mut T::wrapping_add`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_add-1 +[`*mut T::wrapping_sub`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.wrapping_sub-1 +[`*mut T::write_bytes`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.write_bytes +[`*mut T::write_unaligned`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.write_unaligned +[`*mut T::write_volatile`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.write_volatile +[`*mut T::write`]: https://doc.rust-lang.org/std/primitive.pointer.html#method.write +[`Box::leak`]: https://doc.rust-lang.org/std/boxed/struct.Box.html#method.leak +[`FromUtf8Error::as_bytes`]: https://doc.rust-lang.org/std/string/struct.FromUtf8Error.html#method.as_bytes +[`LocalKey::try_with`]: https://doc.rust-lang.org/std/thread/struct.LocalKey.html#method.try_with +[`Option::cloned`]: https://doc.rust-lang.org/std/option/enum.Option.html#method.cloned +[`btree_map::Entry::and_modify`]: https://doc.rust-lang.org/std/collections/btree_map/enum.Entry.html#method.and_modify +[`fs::read_to_string`]: https://doc.rust-lang.org/std/fs/fn.read_to_string.html +[`fs::read`]: https://doc.rust-lang.org/std/fs/fn.read.html +[`fs::write`]: https://doc.rust-lang.org/std/fs/fn.write.html +[`hash_map::Entry::and_modify`]: https://doc.rust-lang.org/std/collections/hash_map/enum.Entry.html#method.and_modify +[`iter::FusedIterator`]: https://doc.rust-lang.org/std/iter/trait.FusedIterator.html +[`ops::RangeInclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeInclusive.html +[`ops::RangeToInclusive`]: https://doc.rust-lang.org/std/ops/struct.RangeToInclusive.html +[`process::id`]: https://doc.rust-lang.org/std/process/fn.id.html +[`slice::rotate_left`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rotate_left +[`slice::rotate_right`]: https://doc.rust-lang.org/std/primitive.slice.html#method.rotate_right +[`String::retain`]: https://doc.rust-lang.org/std/string/struct.String.html#method.retain +[cargo/5041]: https://github.com/rust-lang/cargo/pull/5041 +[cargo/5083]: https://github.com/rust-lang/cargo/pull/5083 + + Version 1.25.0 (2018-03-29) ========================== Language -------- -- [Stabilised `#[repr(align(x))]`.][47006] [RFC 1358] +- [The `#[repr(align(x))]` attribute is now stable.][47006] [RFC 1358] - [You can now use nested groups of imports.][47948] e.g. `use std::{fs::File, io::Read, path::{Path, PathBuf}};` - [You can now have `|` at the start of a match arm.][47947] e.g. @@ -2535,7 +3107,7 @@ Language [RFC 1513](https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md). * [Add a new crate type, 'cdylib'](https://github.com/rust-lang/rust/pull/33553). cdylibs are dynamic libraries suitable for loading by non-Rust hosts. - [RFC 1510](https://github.com/rust-lang/rfcs/blob/master/text/1510-rdylib.md). + [RFC 1510](https://github.com/rust-lang/rfcs/blob/master/text/1510-cdylib.md). Note that Cargo does not yet directly support cdylibs. Stabilized APIs @@ -2610,7 +3182,7 @@ Stabilized APIs * [`UnixDatagram::shutdown`](http://doc.rust-lang.org/std/os/unix/net/struct.UnixDatagram.html#method.shutdown) * RawFd impls for `UnixDatagram` * `{BTree,Hash}Map::values_mut` -* [`<[_]>::binary_search_by_key`](http://doc.rust-lang.org/beta/std/primitive.slice.html#method.binary_search_by_key) +* [`<[_]>::binary_search_by_key`](http://doc.rust-lang.org/std/primitive.slice.html#method.binary_search_by_key) Libraries --------- @@ -3528,7 +4100,7 @@ Compatibility Notes [1.6bh]: https://github.com/rust-lang/rust/pull/29811 [1.6c]: https://github.com/rust-lang/cargo/pull/2192 [1.6cc]: https://github.com/rust-lang/cargo/pull/2131 -[1.6co]: http://doc.rust-lang.org/beta/core/index.html +[1.6co]: http://doc.rust-lang.org/core/index.html [1.6dv]: https://github.com/rust-lang/rust/pull/30000 [1.6f]: https://github.com/rust-lang/rust/pull/29129 [1.6m]: https://github.com/rust-lang/rust/pull/29828 diff --git a/appveyor.yml b/appveyor.yml index a15f3dd8d5cac..b1e2e1545cf85 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,7 +6,7 @@ environment: secure: 7Y+JiquYedOAgnUU26uL0DPzrxmTtR+qIwG6rNKSuWDffqU3vVZxbGXim9QpTO80 SCCACHE_DIGEST: f808afabb4a4eb1d7112bcb3fa6be03b61e93412890c88e177c667eb37f46353d7ec294e559b16f9f4b5e894f2185fe7670a0df15fd064889ecbd80f0c34166c TOOLSTATE_REPO_ACCESS_TOKEN: - secure: PTZiSxJMVUZ0VnMR5i13E4OagbXfglj7pcskDQiKufVrDm13mLoI0vDJAEM35+bY + secure: gKGlVktr7iuqCoYSxHxDE9ltLOKU0nYDEuQxvWbNxUIW7ri5ppn8L06jQzN0GGzN # By default schannel checks revocation of certificates unlike some other SSL # backends, but we've historically had problems on CI where a revocation @@ -138,6 +138,20 @@ install: - if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul - if defined MINGW_URL set PATH=%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH% + # If we're compiling for MSVC then we, like most other distribution builders, + # switch to clang as the compiler. This'll allow us eventually to enable LTO + # amongst LLVM and rustc. Note that we only do this on MSVC as I don't think + # clang has an output mode compatible with MinGW that we need. If it does we + # should switch to clang for MinGW as well! + # + # Note that the LLVM installer is an NSIS installer + # + # Original downloaded here came from + # http://releases.llvm.org/6.0.0/LLVM-6.0.0-win64.exe + - if NOT defined MINGW_URL appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/LLVM-6.0.0-win64.exe + - if NOT defined MINGW_URL .\LLVM-6.0.0-win64.exe /S /NCRC /D=C:\clang-rust + - if NOT defined MINGW_URL set RUST_CONFIGURE_ARGS=%RUST_CONFIGURE_ARGS% --set llvm.clang-cl=C:\clang-rust\bin\clang-cl.exe + # Here we do a pretty heinous thing which is to mangle the MinGW installation # we just had above. Currently, as of this writing, we're using MinGW-w64 # builds of gcc, and that's currently at 6.3.0. We use 6.3.0 as it appears to @@ -166,8 +180,8 @@ install: - set PATH=C:\Python27;%PATH% # Download and install sccache - - appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-02-sccache-x86_64-pc-windows-msvc - - mv 2018-04-02-sccache-x86_64-pc-windows-msvc sccache.exe + - appveyor-retry appveyor DownloadFile https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/2018-04-26-sccache-x86_64-pc-windows-msvc + - mv 2018-04-26-sccache-x86_64-pc-windows-msvc sccache.exe - set PATH=%PATH%;%CD% # Download and install ninja @@ -197,6 +211,11 @@ test_script: - set NO_CCACHE=1 - sh src/ci/run.sh +on_failure: + # Dump crash log + - set PATH=%PATH%;"C:\Program Files (x86)\Windows Kits\10\Debuggers\X64" + - if exist %LOCALAPPDATA%\CrashDumps for %%f in (%LOCALAPPDATA%\CrashDumps\*) do cdb -c "k;q" -G -z "%%f" + branches: only: - auto diff --git a/config.toml.example b/config.toml.example index 34fcc755b3a49..99073416334f5 100644 --- a/config.toml.example +++ b/config.toml.example @@ -76,6 +76,10 @@ # passed to prefer linking to shared libraries. #link-shared = false +# On MSVC you can compile LLVM with clang-cl, but the test suite doesn't pass +# with clang-cl, so this is special in that it only compiles LLVM with clang-cl +#clang-cl = '/path/to/clang-cl.exe' + # ============================================================================= # General build configuration options # ============================================================================= @@ -275,6 +279,9 @@ # Whether or not `panic!`s generate backtraces (RUST_BACKTRACE) #backtrace = true +# Whether to always use incremental compilation when building rustc +#incremental = false + # Build rustc with experimental parallelization #experimental-parallel-queries = false @@ -294,9 +301,9 @@ # desired in distributions, for example. #rpath = true -# Suppresses extraneous output from tests to ensure the output of the test -# harness is relatively clean. -#quiet-tests = false +# Emits extraneous output from tests to ensure that failures of the test +# harness are debuggable just from logfiles. +#verbose-tests = false # Flag indicating whether tests are compiled with optimizations (the -O flag) or # with debuginfo (the -g flag) @@ -343,12 +350,19 @@ # rustc to execute. #lld = false +# Indicates whether some LLVM tools, like llvm-objdump, will be made available in the +# sysroot. +#llvm-tools = false + # Whether to deny warnings in crates #deny-warnings = true # Print backtrace on internal compiler errors during bootstrap #backtrace-on-ice = false +# Whether to verify generated LLVM IR +#verify-llvm-ir = false + # ============================================================================= # Options for specific targets # diff --git a/src/Cargo.lock b/src/Cargo.lock index a2767bd290d5e..89daa8e09c7d1 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1,6 +1,6 @@ [[package]] name = "aho-corasick" -version = "0.6.4" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -20,7 +20,7 @@ name = "alloc_jemalloc" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", @@ -41,12 +41,12 @@ name = "ammonia" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "html5ever 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -54,14 +54,9 @@ name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "ar" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "arena" version = "0.0.0" @@ -79,57 +74,48 @@ dependencies = [ [[package]] name = "assert_cli" -version = "0.5.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "atty" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace" -version = "0.3.6" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.16" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bin_lib" -version = "0.1.0" - -[[package]] -name = "bitflags" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "0.9.1" @@ -137,7 +123,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -145,26 +131,22 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "borrow_error" -version = "0.1.0" - [[package]] name = "bufstream" version = "0.1.3" @@ -174,8 +156,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "build-manifest" version = "0.1.0" dependencies = [ - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -183,85 +165,129 @@ dependencies = [ name = "build_helper" version = "0.1.0" -[[package]] -name = "bytecount" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.16.0", + "crates-io 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "git2-curl 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "home 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ignore 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cargo" +version = "0.30.0" +dependencies = [ + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crates-io 0.18.0", + "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "git2-curl 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "home 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ignore 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cargo_metadata" -version = "0.3.3" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cargo_metadata" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -270,53 +296,75 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.10" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.2" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "chalk-engine" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "chalk-macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "chrono" -version = "0.4.1" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clap" -version = "2.31.2" +version = "2.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "clippy" -version = "0.0.195" +version = "0.0.212" dependencies = [ - "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "clippy-mini-macro-test 0.2.0", - "clippy_lints 0.0.195", - "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.212", + "compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -325,29 +373,38 @@ version = "0.2.0" [[package]] name = "clippy_lints" -version = "0.0.195" +version = "0.0.212" dependencies = [ - "if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "quine-mc_cluskey 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cmake" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -371,14 +428,14 @@ name = "commoncrypto-sys" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -387,43 +444,39 @@ name = "compiletest" version = "0.0.0" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiletest_rs" -version = "0.3.9" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "completion" -version = "0.1.0" - [[package]] name = "core" version = "0.0.0" @@ -437,7 +490,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "core-foundation" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -445,19 +507,37 @@ name = "core-foundation-sys" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "core-foundation-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crates-io" version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crates-io" +version = "0.18.0" +dependencies = [ + "curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -465,6 +545,18 @@ name = "crossbeam" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crossbeam-channel" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.2.0" @@ -480,92 +572,108 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-epoch" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-utils" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-utils" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crypto-hash" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "curl" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "curl-sys" -version = "0.4.2" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "debug_unreachable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "deglob" +name = "datafrog" version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "derive-new" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "diff" -version = "0.1.11" +name = "derive_more" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "difference" -version = "1.0.0" +name = "diff" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -583,7 +691,7 @@ dependencies = [ [[package]] name = "dtoa" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -593,48 +701,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "elasticlunr-rs" -version = "2.2.0" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strum_macros 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ena" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "endian-type" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "enum_primitive" -version = "0.1.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "env_logger" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -648,7 +743,15 @@ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "error-chain" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -663,7 +766,7 @@ name = "failure" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -677,38 +780,16 @@ dependencies = [ "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "features" -version = "0.1.0" - [[package]] name = "filetime" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "filetime" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "find_all_refs_no_cfg_test" -version = "0.1.0" - -[[package]] -name = "find_impls" -version = "0.1.0" - [[package]] name = "fixedbitset" version = "0.1.9" @@ -719,7 +800,7 @@ name = "flate2" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -750,8 +831,17 @@ name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fst" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -759,7 +849,7 @@ name = "fuchsia-zircon" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -770,16 +860,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futf" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "futures" -version = "0.1.20" +version = "0.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -789,16 +879,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "git2" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -806,10 +896,10 @@ name = "git2-curl" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", - "git2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", + "git2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -819,14 +909,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "globset" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -835,22 +925,22 @@ version = "0.0.0" [[package]] name = "handlebars" -version = "0.32.0" +version = "0.32.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hex" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -860,19 +950,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "html5ever" -version = "0.22.0" +version = "0.22.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -880,66 +971,54 @@ name = "humantime" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "idna" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "if_chain" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ignore" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "infer_bin" -version = "0.1.0" - -[[package]] -name = "infer_custom_bin" -version = "0.1.0" - -[[package]] -name = "infer_lib" -version = "0.1.0" - [[package]] name = "installer" version = "0.0.0" dependencies = [ - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)", + "tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -947,6 +1026,16 @@ name = "is-match" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "isatty" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.7.8" @@ -957,7 +1046,7 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -965,26 +1054,21 @@ name = "jobserver" version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "json" -version = "0.11.13" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "jsonrpc-core" version = "8.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -998,15 +1082,16 @@ dependencies = [ [[package]] name = "languageserver-types" -version = "0.39.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1017,7 +1102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lazy_static" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1025,6 +1110,11 @@ name = "lazycell" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lazycell" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "libc" version = "0.0.0" @@ -1035,34 +1125,35 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.40" +version = "0.2.42" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libgit2-sys" -version = "0.7.1" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "curl-sys 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "libssh2-sys 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libssh2-sys" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1070,10 +1161,10 @@ name = "libz-sys" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1085,34 +1176,34 @@ name = "log" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log_settings" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lzma-sys" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1130,19 +1221,19 @@ name = "markup5ever" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "matches" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1151,24 +1242,24 @@ version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "handlebars 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1178,7 +1269,16 @@ name = "memchr" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memmap" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1186,13 +1286,21 @@ name = "memoffset" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "minifier" +version = "0.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1200,31 +1308,31 @@ name = "miow" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "miri" version = "0.1.0" dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "multiple_bins" -version = "0.1.0" - -[[package]] -name = "nibble_vec" -version = "0.0.4" +name = "new_debug_unreachable" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "nodrop" @@ -1232,24 +1340,27 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "num-integer" -version = "0.1.36" +name = "num-derive" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "num-traits" -version = "0.1.43" +name = "num-integer" +version = "0.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.2" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1257,7 +1368,7 @@ name = "num_cpus" version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1267,14 +1378,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl" -version = "0.10.6" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1284,13 +1396,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "openssl-sys" -version = "0.9.28" +version = "0.9.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1298,12 +1410,17 @@ name = "ordermap" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "ordslice" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "owning_ref" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1340,10 +1457,10 @@ name = "parking_lot_core" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1377,33 +1494,33 @@ dependencies = [ [[package]] name = "phf" -version = "0.7.21" +version = "0.7.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_codegen" -version = "0.7.21" +version = "0.7.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_generator" -version = "0.7.21" +version = "0.7.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "phf_shared" -version = "0.7.21" +version = "0.7.22" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1411,9 +1528,19 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "polonius-engine" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "datafrog 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "precomputed-hash" version = "0.1.1" @@ -1430,7 +1557,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.2.3" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1438,7 +1565,7 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "0.3.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1458,7 +1585,7 @@ dependencies = [ name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1474,7 +1601,7 @@ dependencies = [ [[package]] name = "quick-error" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1489,62 +1616,63 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "0.4.2" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" -version = "0.5.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "racer" -version = "2.0.13" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", - "toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive_more 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "radix_trie" -version = "0.1.3" +name = "rand" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "nibble_vec 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.3.22" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand" -version = "0.4.2" +name = "rand_core" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "rayon" @@ -1561,15 +1689,15 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "redox_syscall" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1577,32 +1705,44 @@ name = "redox_termios" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "reformat" -version = "0.1.0" - -[[package]] -name = "reformat_with_range" -version = "0.1.0" +name = "regex" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "regex" -version = "0.2.10" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.5.5" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1621,48 +1761,53 @@ name = "remove_dir_all" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls" -version = "0.127.0" +version = "0.129.0" dependencies = [ - "cargo 0.28.0", - "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy_lints 0.0.195", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo 0.30.0", + "cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy_lints 0.0.212", + "crossbeam-channel 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "languageserver-types 0.45.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-analysis 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-analysis 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-rustc 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfmt-nightly 0.6.1", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-vfs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfmt-nightly 0.9.0", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-analysis" -version = "0.12.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "fst 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1674,18 +1819,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rls-data" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-rustc" -version = "0.2.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1694,16 +1839,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rls-vfs" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)", + "racer 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1711,7 +1856,7 @@ dependencies = [ name = "rustbook" version = "0.1.0" dependencies = [ - "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1720,115 +1865,136 @@ name = "rustc" version = "0.0.0" dependencies = [ "arena 0.0.0", - "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "fmt_macros 0.0.0", "graphviz 0.0.0", "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", + "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_apfloat 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-ap-arena" +version = "209.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_cratesio_shim" -version = "113.0.0" +version = "209.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_data_structures" -version = "113.0.0" +version = "209.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_errors" -version = "113.0.0" +version = "209.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-rustc_target" -version = "113.0.0" +version = "209.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_cratesio_shim 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-serialize" -version = "113.0.0" +version = "209.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rustc-ap-syntax" -version = "113.0.0" +version = "209.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_errors 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_errors 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_target 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-ap-syntax_pos" -version = "113.0.0" +version = "209.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-arena 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc-demangle" -version = "0.1.7" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-hash" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "rustc-main" @@ -1838,6 +2004,27 @@ dependencies = [ "rustc_target 0.0.0", ] +[[package]] +name = "rustc-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-rayon-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc-serialize" version = "0.3.24" @@ -1847,6 +2034,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "rustc_allocator" version = "0.0.0" dependencies = [ + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", @@ -1858,7 +2046,7 @@ dependencies = [ name = "rustc_apfloat" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -1869,7 +2057,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -1879,11 +2067,56 @@ name = "rustc_borrowck" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_errors 0.0.0", + "rustc_mir 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", +] + +[[package]] +name = "rustc_codegen_llvm" +version = "0.0.0" +dependencies = [ + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc-demangle 0.1.8 (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", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", + "rustc_incremental 0.0.0", + "rustc_llvm 0.0.0", + "rustc_mir 0.0.0", + "rustc_platform_intrinsics 0.0.0", + "rustc_target 0.0.0", + "serialize 0.0.0", + "syntax 0.0.0", + "syntax_pos 0.0.0", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_codegen_utils" +version = "0.0.0" +dependencies = [ + "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc 0.0.0", + "rustc_data_structures 0.0.0", + "rustc_incremental 0.0.0", "rustc_mir 0.0.0", + "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -1892,36 +2125,40 @@ dependencies = [ name = "rustc_cratesio_shim" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc_data_structures" version = "0.0.0" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", - "stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustc_driver" version = "0.0.0" dependencies = [ - "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "arena 0.0.0", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", + "rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_allocator 0.0.0", "rustc_borrowck 0.0.0", + "rustc_codegen_utils 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_incremental 0.0.0", @@ -1935,8 +2172,8 @@ dependencies = [ "rustc_save_analysis 0.0.0", "rustc_target 0.0.0", "rustc_traits 0.0.0", - "rustc_trans_utils 0.0.0", "rustc_typeck 0.0.0", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax 0.0.0", "syntax_ext 0.0.0", @@ -1947,12 +2184,12 @@ dependencies = [ name = "rustc_errors" version = "0.0.0" dependencies = [ - "atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "serialize 0.0.0", "syntax_pos 0.0.0", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1960,7 +2197,7 @@ name = "rustc_incremental" version = "0.0.0" dependencies = [ "graphviz 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", @@ -1973,7 +2210,7 @@ dependencies = [ name = "rustc_lint" version = "0.0.0" dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_mir 0.0.0", "rustc_target 0.0.0", @@ -1985,10 +2222,10 @@ dependencies = [ name = "rustc_llvm" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "build_helper 0.1.0", - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -1999,7 +2236,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -2009,7 +2246,7 @@ name = "rustc_metadata" version = "0.0.0" dependencies = [ "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "proc_macro 0.0.0", "rustc 0.0.0", "rustc_data_structures 0.0.0", @@ -2026,11 +2263,13 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "arena 0.0.0", - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_apfloat 0.0.0", "rustc_data_structures 0.0.0", @@ -2048,7 +2287,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -2057,7 +2296,7 @@ dependencies = [ name = "rustc_passes" version = "0.0.0" dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -2097,7 +2336,7 @@ name = "rustc_resolve" version = "0.0.0" dependencies = [ "arena 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -2109,8 +2348,8 @@ dependencies = [ name = "rustc_save_analysis" version = "0.0.0" dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)", "rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2125,8 +2364,8 @@ dependencies = [ name = "rustc_target" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", "serialize 0.0.0", ] @@ -2135,56 +2374,12 @@ dependencies = [ name = "rustc_traits" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "graphviz 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc_data_structures 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", -] - -[[package]] -name = "rustc_trans" -version = "0.0.0" -dependencies = [ - "cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc 0.0.0", - "rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_allocator 0.0.0", - "rustc_apfloat 0.0.0", - "rustc_data_structures 0.0.0", - "rustc_errors 0.0.0", - "rustc_incremental 0.0.0", - "rustc_llvm 0.0.0", - "rustc_mir 0.0.0", - "rustc_platform_intrinsics 0.0.0", - "rustc_target 0.0.0", - "rustc_trans_utils 0.0.0", - "serialize 0.0.0", - "syntax 0.0.0", - "syntax_pos 0.0.0", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_trans_utils" -version = "0.0.0" -dependencies = [ - "ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", - "rustc_incremental 0.0.0", - "rustc_mir 0.0.0", - "rustc_target 0.0.0", "syntax 0.0.0", "syntax_pos 0.0.0", ] @@ -2196,7 +2391,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", + "cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", ] @@ -2206,8 +2401,7 @@ name = "rustc_typeck" version = "0.0.0" dependencies = [ "arena 0.0.0", - "fmt_macros 0.0.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc 0.0.0", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", @@ -2217,12 +2411,21 @@ dependencies = [ "syntax_pos 0.0.0", ] +[[package]] +name = "rustc_version" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustdoc" version = "0.0.0" dependencies = [ + "minifier 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)", "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2238,49 +2441,41 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rustfmt-nightly" -version = "0.6.1" +version = "0.9.0" dependencies = [ - "assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", - "derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)", + "isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-rustc_target 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-ap-syntax_pos 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "same-file" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2288,21 +2483,21 @@ name = "same-file" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "schannel" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "scoped-tls" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2310,22 +2505,13 @@ name = "scopeguard" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "semver" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2335,27 +2521,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.40" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde_derive" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "serde_derive_internals" -version = "0.23.1" +version = "1.0.70" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2363,18 +2539,17 @@ name = "serde_ignored" version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.15" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2397,38 +2572,27 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "skeptic" -version = "0.13.2" +name = "smallvec" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "smallvec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "socket2" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "stable_deref_trait" -version = "1.0.0" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2439,6 +2603,7 @@ dependencies = [ "alloc_jemalloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", + "cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", "compiler_builtins 0.0.0", "core 0.0.0", "libc 0.0.0", @@ -2464,26 +2629,27 @@ dependencies = [ [[package]] name = "string_cache" -version = "0.7.1" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "string_cache_codegen" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2504,11 +2670,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "strum_macros" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2523,21 +2690,21 @@ dependencies = [ [[package]] name = "syn" -version = "0.12.15" +version = "0.13.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "0.13.1" +version = "0.14.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2562,12 +2729,12 @@ dependencies = [ name = "syntax" version = "0.0.0" dependencies = [ - "bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", "rustc_errors 0.0.0", "rustc_target 0.0.0", - "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", "syntax_pos 0.0.0", ] @@ -2589,78 +2756,35 @@ dependencies = [ name = "syntax_pos" version = "0.0.0" dependencies = [ + "arena 0.0.0", + "cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_data_structures 0.0.0", - "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "serialize 0.0.0", - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_errors" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_pos" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syntex_syntax" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tar" -version = "0.4.15" +version = "0.4.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "xattr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tempdir" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tempfile" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2668,7 +2792,7 @@ name = "tendril" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2679,28 +2803,27 @@ version = "0.0.0" [[package]] name = "term" -version = "0.4.6" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "term" -version = "0.5.1" +name = "termcolor" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "termcolor" -version = "0.3.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "wincolor 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2708,8 +2831,8 @@ name = "termion" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2723,10 +2846,10 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2734,7 +2857,7 @@ name = "thread_local" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2742,27 +2865,19 @@ dependencies = [ name = "tidy" version = "0.1.0" dependencies = [ - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "time" -version = "0.1.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "toml" -version = "0.2.1" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2770,7 +2885,7 @@ name = "toml" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2780,8 +2895,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2795,27 +2910,22 @@ name = "unicode-bidi" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-normalization" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-segmentation" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "unicode-width" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "unicode-xid" -version = "0.0.3" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2828,14 +2938,6 @@ name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unreachable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unreachable" version = "1.0.0" @@ -2848,7 +2950,7 @@ dependencies = [ name = "unstable-book-gen" version = "0.1.0" dependencies = [ - "num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "tidy 0.1.0", ] @@ -2863,11 +2965,11 @@ dependencies = [ [[package]] name = "url" -version = "1.7.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2876,8 +2978,8 @@ name = "url_serde" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2901,12 +3003,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vcpkg" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vec_map" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -2914,23 +3016,13 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "walkdir" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "walkdir" version = "2.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2940,7 +3032,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2967,27 +3059,31 @@ name = "wincolor" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "workspace_symbol" -version = "0.1.0" +name = "wincolor" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "xattr" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "xz2" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lzma-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lzma-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2996,121 +3092,131 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4" +"checksum aho-corasick 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c1c6d463cbe7ed28720b5b489e7c083eeb8f90d08be2a0d6bb9e1ffea9ce1afa" "checksum ammonia 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd4c682378117e4186a492b2252b9537990e1617f44aed9788b9a1149de45477" "checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" -"checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" -"checksum assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "72342c21057a3cb5f7c2d849bf7999a83795434dd36d74fa8c24680581bd1930" -"checksum atty 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "af80143d6f7608d746df1520709e5d141c96f240b0e62b0aa41bdfb53374d9d4" -"checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e" -"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" +"checksum assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98589b0e465a6c510d95fceebd365bb79bedece7f6e18a480897f2015f85ec51" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" +"checksum backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "89a47830402e9981c5c41223151efcced65a0510c13097c769cede7efb34782a" +"checksum backtrace-sys 0.1.23 (registry+https://github.com/rust-lang/crates.io-index)" = "bff67d0c06556c0b8e6b5f090f0eac52d950d9dfd1d35ba04e4ca3543eaf6a7e" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" -"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf" +"checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" -"checksum bytecount 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "af27422163679dea46a1a7239dffff64d3dcdc3ba5fe9c49c789fbfe0eb949de" -"checksum byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "73b5bdfe7ee3ad0b99c9801d58807a9dbc9e09196365b0203853b99889ab3c87" -"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537" -"checksum cargo_metadata 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6ebd6272a2ca4fd39dbabbd6611eb03df45c2259b3b80b39a9ff8fbdcf42a4b3" -"checksum cc 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8b9d2900f78631a5876dc5d6c9033ede027253efcd33dd36b1309fc6cab97ee0" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"checksum chrono 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ba5f60682a4c264e7f8d77b82e7788938a76befdf949d4a98026d19099c9d873" -"checksum clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0f16b89cbb9ee36d87483dc939fe9f1e13c05898d56d7b230a0d4dff033a536" -"checksum cmake 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)" = "5cf678ceebedde428000cb3a34465cf3606d1a48da17014948a916deac39da7c" +"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9" +"checksum cargo 0.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "21dd0ac7737313b8c5c6fbfaf351aa93d4e90f66d4a33a11d1f3fb29584ac631" +"checksum cargo_metadata 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1efca0b863ca03ed4c109fb1c55e0bc4bbeb221d3e103d86251046b06a526bd0" +"checksum cargo_metadata 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6809b327f87369e6f3651efd2c5a96c49847a3ed2559477ecba79014751ee1" +"checksum cc 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "2119ea4867bd2b8ed3aecab467709720b2d55b1bcfe09f772fd68066eaf15275" +"checksum cfg-if 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "efe5c877e17a9c717a0bf3613b2709f723202c4e4675cc8f12926ded29bcb17e" +"checksum chalk-engine 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a146c19172c7eea48ea55a7123ac95da786639bc665097f1e14034ee5f1d8699" +"checksum chalk-macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "295635afd6853aa9f20baeb7f0204862440c0fe994c5a253d5f479dac41d047e" +"checksum chrono 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6962c635d530328acc53ac6a955e83093fedc91c5809dfac1fa60fa470830a37" +"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum cmake 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "95470235c31c726d72bf2e1f421adc1e65b9d561bf5529612cbe1a72da1467b3" "checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc" "checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" -"checksum compiletest_rs 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "608d9d3ccc45b63bf337d2ff5e65def5a5a52c187122232509f6b72707f61b1b" +"checksum compiletest_rs 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "d3064bc712922596dd5ab449fca9261d411893356581fe5297b96aa8f53bb1b8" "checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" +"checksum core-foundation 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc3532ec724375c7cb7ff0a097b714fde180bb1f6ed2ab27cfcd99ffca873cd2" "checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" +"checksum core-foundation-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a3fb15cdbdd9cf8b82d97d0296bb5cd3631bba58d6e31650a002a8e7fb5721f9" +"checksum crates-io 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f78703ef5348db1e3244fb6b496e840965fb4754a5319270f2bd77ddb856e1c" "checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19" +"checksum crossbeam-channel 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efff2d411e0ac3731b9f6de882b2790fdd2de651577500a806ce78b95b2b9f31" "checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3" "checksum crossbeam-epoch 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "927121f5407de9956180ff5e936fe3cf4324279280001cd56b669d28ee7e9150" +"checksum crossbeam-epoch 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "285987a59c4d91388e749850e3cb7b3a92299668528caaacd08005b8f238c0ea" "checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" +"checksum crossbeam-utils 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ea52fab26a99d96cdff39d0ca75c9716125937f5dba2ab83923aaaf5928f684a" "checksum crypto-hash 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "09de9ee0fc255ace04c7fa0763c9395a945c37c8292bb554f8d48361d1dcf1b4" -"checksum curl 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "aaf20bbe084f285f215eef2165feed70d6b75ba29cad24469badb853a4a287d0" -"checksum curl-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f3f7738d877ec81040305d5bb91976ac594f564f5e455dc02a29a23c1d00fe6f" -"checksum debug_unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9a032eac705ca39214d169f83e3d3da290af06d8d1d344d1baad2fd002dca4b3" -"checksum derive-new 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6fcb923bab47a948f1b01cec2f758fdebba95c9ebc255458654b2b88efe59d71" +"checksum curl 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "893713db705eab9847e050268507b0e2a2aad64e90a831874bd4e8e0d67f9523" +"checksum curl-sys 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "de9cf174efdf90b5887c4e2e900769373c89c5e18152e8f3ed75b501a6f1c0fb" +"checksum datafrog 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "16d724bf4ffe77cdceeecd461009b5f8d9e23c5d645d68bedb4586bf43e7e142" +"checksum derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ceed73957c449214f8440eec8ad7fa282b67dc9eacbb24a3085b15d60397a17a" +"checksum derive_more 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46c7f14685a20f5dd08e7f754f2ea8cc064d8f4214ae21116c106a2768ba7b9b" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" -"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" -"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" +"checksum dtoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6d301140eb411af13d3115f9a562c85cc6b541ade9dfa314132244aaee7489dd" "checksum either 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3be565ca5c557d7f59e7cfcf1844f9e3033650c929c6566f511e8005f205c1d0" -"checksum elasticlunr-rs 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4511b63d69dd5d31e8e29aed2c132c413f87acea8035d0584801feaab9dd1f0f" -"checksum ena 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8b449f3b18c89d2dbe40548d2ee4fa58ea0a08b761992da6ecb9788e4688834" -"checksum endian-type 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" -"checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180" -"checksum env_logger 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "be27f8ea102a7182093a80d98f0b78623b580eda8791cbe8e2345fe6e57567a6" +"checksum elasticlunr-rs 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4837d77a1e157489a3933b743fd774ae75074e0e390b2b7f071530048a0d87ee" +"checksum ena 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dc8393b3c7352f94092497f6b52019643e493b6b890eb417cdb7c46117e621" +"checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" "checksum environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4b14e20978669064c33b4c1e0fb4083412e40fe56cbea2eae80fd7591503ee" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07e791d3be96241c77c43846b665ef1384606da2cd2a48730abe606a12906e02" "checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" "checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" -"checksum filetime 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "714653f3e34871534de23771ac7b26e999651a0a228f47beb324dfdf1dd4b10f" -"checksum filetime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08530a39af0bd442c40aabb9e854f442a83bd2403feb1ed58fbe982dec2385f3" +"checksum filetime 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "da4b9849e77b13195302c174324b5ba73eec9b236b24c221a61000daefb95c5f" "checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" "checksum flate2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fac2277e84e5e858483756647a9d0aa8d9a2b7cba517fd84325a0aaa69a0909" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +"checksum fst 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d94485a00b1827b861dd9d1a2cc9764f9044d4c535514c0760a5a2012ef3399f" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futf 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "51f93f3de6ba1794dcd5810b3546d004600a59a98266487c8407bc4b24e398f3" -"checksum futures 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5a3176836efa0b37f0e321b86672dfada1564aeb516fbed67b7c24050a0263" +"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" +"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" "checksum getopts 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "b900c08c1939860ce8b54dc6a89e26e00c04c380fd0e09796799bd7f12861e05" -"checksum git2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f41c0035c37ec11ed3f1e1946a76070b0c740393687e9a9c7612f6a709036b3" +"checksum git2 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b87cffac882c99f9654ca5eb4c6c61527b47bc1e113304f8c57333567cd31f2" "checksum git2-curl 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b502f6b1b467957403d168f0039e0c46fa6a1220efa2adaef25d5b267b5fe024" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" -"checksum globset 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1e96ab92362c06811385ae9a34d2698e8a1160745e0c78fbb434a44c8de3fabc" -"checksum handlebars 0.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07af2ff31f66f39a5c8b8b8a5dc02734a453110146763e3a2323f4931a915a76" -"checksum hex 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "459d3cf58137bb02ad4adeef5036377ff59f066dbb82517b7192e3a5462a2abc" +"checksum globset 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142754da2c9b3722affd909f9e27f2a6700a7a303f362971e0a74c652005a43d" +"checksum handlebars 0.32.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d89ec99d1594f285d4590fc32bac5f75cdab383f1123d504d27862c644a807dd" +"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum home 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8f94f6fbdc000a6eba0c8cf08632b2091bb59141d36ac321a2a96d6365e5e4dc" -"checksum html5ever 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e579ac8647178ab915d400d7d22938bda5cd351c6c62e1c294d56884ccfc75fe" +"checksum html5ever 0.22.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b04478cf718862650a0bf66acaf8f2f8c906fbc703f35c916c1f4211b069a364" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" -"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" -"checksum if_chain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "61bb90bdd39e3af69b0172dfc6130f6cd6332bf040fbb9bdd4401d37adbd48b8" -"checksum ignore 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "245bea0ba52531a3739cb8ba99f8689eda13d7faf8c36b6a73ce4421aab42588" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum if_chain 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4bac95d9aa0624e7b78187d6fb8ab012b41d9f6f54b1bcb61e61c4845f8357ec" +"checksum ignore 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "787a5940ab88e0f2f3b2cad3687060bddcf67520f3b761abc31065c9c495d088" "checksum is-match 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7e5b386aef33a1c677be65237cb9d32c3f3ef56bd035949710c4bb13083eb053" +"checksum isatty 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6c324313540cd4d7ba008d43dc6606a32a5579f13cc17b2804c13096f0a5c522" "checksum itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "f58856976b776fedd95533137617a02fb25719f40e7d9b01c7043cd65474f450" -"checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" +"checksum itoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5adb58558dcd1d786b5f0bd15f3226ee23486e24b7b58304b60f64dc68e62606" "checksum jobserver 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "60af5f849e1981434e4a31d3d782c4774ae9b434ce55b101a96ecfd09147e8be" -"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be" "checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum languageserver-types 0.39.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad4cdd5e52d71aca47050e5b25f03082609c63a1e76b7362ebdd010895b3f854" +"checksum languageserver-types 0.45.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d91d91d1c23db74187096d191967cb49f49bb175ad6d855fa9229d16ef2c982" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" -"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" +"checksum lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fb497c35d362b6a331cfd94956a07fc2c78a4604cdbee844a81170386b996dd3" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" -"checksum libc 0.2.40 (registry+https://github.com/rust-lang/crates.io-index)" = "6fd41f331ac7c5b8ac259b8bf82c75c0fb2e469bbf37d2becbba9a6a2221965b" -"checksum libgit2-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1ecbd6428006c321c29b6c8a895f0d90152f1cf4fd8faab69fc436a3d9594f63" -"checksum libssh2-sys 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0db4ec23611747ef772db1c4d650f8bd762f07b461727ec998f953c614024b75" +"checksum lazycell 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d33a48d0365c96081958cc663eef834975cb1e8d8bea3378513fc72bdbf11e50" +"checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" +"checksum libgit2-sys 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c9051a4b288ba6f8728e9e52bb2510816946b8bcb2e20259e4d4cdc93b9ecafd" +"checksum libssh2-sys 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c628b499e8d1a4f4bd09a95d6cb1f8aeb231b46a9d40959bbd0408f14dd63adf" "checksum libz-sys 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "87f737ad6cc6fd6eefe3d9dc5412f1573865bded441300904d2f42269e140f16" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" -"checksum log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3d382732ea0fbc09790c4899db3255bdea0fc78b54bf234bd18a63bb603915b6" -"checksum lzma-sys 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c1b93b78f89e8737dac81837fc8f5521ac162abcba902e1a3db949d55346d1da" +"checksum log 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "61bd98ae7f7b754bc53dca7d44b604f733c6bba044ea6f41bc8d89272d8161d2" +"checksum log_settings 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19af41f0565d7c19b2058153ad0b42d4d5ce89ec4dbf06ed6741114a8b63e7cd" +"checksum lzma-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d1eaa027402541975218bb0eec67d6b0412f6233af96e0d096d31dbdfd22e614" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" "checksum maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08cbb6b4fef96b6d77bfc40ec491b1690c779e77b05cd9f07f787ed376fd4c43" "checksum markup5ever 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfedc97d5a503e96816d10fedcd5b42f760b2e525ce2f7ec71f6a41780548475" -"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" +"checksum matches 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "835511bab37c34c47da5cb44844bea2cfde0236db0b506f90ea4224482c9774a" "checksum mdbook 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "90b5a8d7e341ceee5db3882a06078d42661ddcfa2b3687319cc5da76ec4e782f" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" +"checksum minifier 0.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "78cb57f9a385530d60f2d67f6e108050b478b7a0ffd0bb9c350803e1356535dd" "checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4" "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" -"checksum nibble_vec 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c8d77f3db4bce033f4d04db08079b2ef1c3d02b44e86f25d08886fafa7756ffa" +"checksum new_debug_unreachable 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0cdc457076c78ab54d5e0d6fa7c47981757f1e34dc39ff92787f217dede586c4" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" -"checksum num-integer 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f8d26da319fb45674985c78f1d1caf99aa4941f785d384a2ae36d0740bc3e2fe" -"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" +"checksum num-derive 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d2c31b75c36a993d30c7a13d70513cb93f02acafdd5b7ba250f9b0e18615de7" +"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" +"checksum num-traits 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "630de1ef5cc79d0cdd78b7e33b81f083cbfe90de0f4b2b2f07f905867c70e9fe" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" "checksum open 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c281318d992e4432cfa799969467003d05921582a7489a8325e37f8a450d5113" -"checksum openssl 0.10.6 (registry+https://github.com/rust-lang/crates.io-index)" = "63246f69962e8d5ef865f82a65241d6483c8a2905a1801e2f7feb5d187d51320" +"checksum openssl 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ed18a0f40ec4e9a8a81f8865033d823b7195d16a0a5721e10963ee1b0c2980ca" "checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" -"checksum openssl-sys 0.9.28 (registry+https://github.com/rust-lang/crates.io-index)" = "0bbd90640b148b46305c1691eed6039b5c8509bed16991e3562a01eeb76902a3" +"checksum openssl-sys 0.9.33 (registry+https://github.com/rust-lang/crates.io-index)" = "d8abc04833dcedef24221a91852931df2f63e3369ae003134e70aff3645775cc" "checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" +"checksum ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parking_lot 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4d05f1349491390b1730afba60bb20d55761bef489a954546b58b4b34e1e2ac" "checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" @@ -3118,122 +3224,119 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum pest 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0fce5d8b5cc33983fc74f78ad552b5522ab41442c4ca91606e4236eb4b5ceefc" "checksum pest_derive 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ab94faafeb93f4c5e3ce81ca0e5a779529a602ad5d09ae6d21996bfb8b6a52bf" "checksum petgraph 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "8b30dc85588cd02b9b76f5e386535db546d21dc68506cff2abebee0b6445e8e4" -"checksum phf 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "cb325642290f28ee14d8c6201159949a872f220c62af6e110a56ea914fbe42fc" -"checksum phf_codegen 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "d62594c0bb54c464f633175d502038177e90309daf2e0158be42ed5f023ce88f" -"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03" -"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2" -"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903" +"checksum phf 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "7d37a244c75a9748e049225155f56dbcb98fe71b192fd25fd23cb914b5ad62f2" +"checksum phf_codegen 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "4e4048fe7dd7a06b8127ecd6d3803149126e9b33c7558879846da3a63f734f2b" +"checksum phf_generator 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "05a079dd052e7b674d21cb31cbb6c05efd56a2cd2827db7692e2f1a507ebd998" +"checksum phf_shared 0.7.22 (registry+https://github.com/rust-lang/crates.io-index)" = "c2261d544c2bb6aa3b10022b0be371b9c7c64f762ef28c6f5d4f1ef6d97b5930" +"checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" +"checksum polonius-engine 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a5b6b0a7f5f4278b991ffd14abce1d01b013121ad297460237ef0a2f08d43201" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" "checksum pretty_assertions 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a029430f0d744bc3d15dd474d591bed2402b645d024583082b9f63bb936dac6" -"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" -"checksum proc-macro2 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "49b6a521dc81b643e9a51e0d1cf05df46d5a2f3c0280ea72bcb68276ba64a118" +"checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" +"checksum proc-macro2 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c65b1ea15bb859d922cade2d1765b4b88beac339cbfad545ef2d2ef8c8215ee6" "checksum pulldown-cmark 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d6fdf85cda6cadfae5428a54661d431330b312bc767ddbc57adbedc24da66e32" -"checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" +"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 quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" -"checksum quote 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7b0ff51282f28dc1b53fd154298feaa2e77c5ea0dba68e1fd8b03b72fbe13d2a" -"checksum racer 2.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40d44bc30fc8d403b665286b2c9a83466ddbf69297668fb02b785c3e58eb8e0d" -"checksum radix_trie 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "03d0d770481e8af620ca61d3d304bf014f965d7f78e923dc58545e6a545070a9" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" +"checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" +"checksum quote 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e44651a0dc4cdd99f71c83b561e221f714912d11af1a4dff0631f923d53af035" +"checksum racer 2.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c20890fccfc19a28835ee4ffab6af13d300a60a33be29162cfdf8db981811f25" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" +"checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea" +"checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" "checksum rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "80e811e76f1dbf68abf87a759083d34600017fc4e10b6bd5ad84a700f9dba4b1" "checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8" -"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "aec3f58d903a7d2a9dc2bf0e41a746f4530e0cab6b615494e058f67a3ef947fb" -"checksum regex-syntax 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "bd90079345f4a4c3409214734ae220fd773c6f2e8a543d07370c6c1c369cfbfb" +"checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" +"checksum regex 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "13c93d55961981ba9226a213b385216f83ab43bd6ac53ab16b2eeb47e337cf4e" +"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" +"checksum regex-syntax 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05b06a75f5217880fc5e905952a42750bf44787e56a6c6d6852ed0992f5e1d54" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" -"checksum rls-analysis 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b339561571efd8d2d4ae1b16eb27f760cad46907d49e9726242844dbbde14e79" +"checksum rls-analysis 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96f84d303dcbe1c1bdd41b10867d3399c38fbdac32c4e3645cdb6dbd7f82db1d" "checksum rls-blacklist 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a9cc2545ccb7e05b355bfe047b8039a6ec12270d5f3c996b766b340a50f7d2" -"checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510" -"checksum rls-rustc 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "885f66b92757420572cbb02e033d4a9558c7413ca9b7ac206f28fd58ffdb44ea" +"checksum rls-data 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dd20763e1c60ae8945384c8a8fa4ac44f8afa7b0a817511f5e8927e5d24f988" +"checksum rls-rustc 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c8c09117ae2887baaa4b17fe1cb572f9b22e4d2c6a5cda04093d8b366b0be99" "checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a" -"checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb" -"checksum rustc-ap-rustc_cratesio_shim 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a01334797c5c4cf56cc40bb9636d7b4c4a076665b9b9b7f100fd666cf0a02ffc" -"checksum rustc-ap-rustc_data_structures 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "03d6f8f7da0de905f6ef80dc14dce3bbc372430622b6aeb421cf13190bc70e8a" -"checksum rustc-ap-rustc_errors 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfd6183804a685c48601651d8c8c7b0daa8f83b0b5e24edfbcb6a0337085127" -"checksum rustc-ap-rustc_target 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f223157f51bf0e0621bef099de862468892ee4c4b83056f48f63e1bc00ccb72" -"checksum rustc-ap-serialize 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2104a55a87d65cba8a845656f1f19a35da52af403863cd2a4bd5876ba522d879" -"checksum rustc-ap-syntax 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b50671adb9b0a7c57a4690ac6a40cb614879f543b64aada42f55b66212492323" -"checksum rustc-ap-syntax_pos 113.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "55793c2a775230c42661194c48d44b35d4c8439d79ad8528e56651e854c48c63" -"checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" +"checksum rls-vfs 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ecbc8541b4c341d6271eae10f869dd9d36db871afe184f5b6f9bffbd6ed0373f" +"checksum rustc-ap-arena 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b098827864368459cbc7a79fbc54eafb92df7e00a46c0cda352b5a21583ee436" +"checksum rustc-ap-rustc_cratesio_shim 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4d923dea14fb085bca743fb982f6a3bc11c0d5d30b822bcf6fa16e9464a56c" +"checksum rustc-ap-rustc_data_structures 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18c6a5c9edc6b4ae035cdc03af7d8662d39fad7879c5501d103e7087dfaebc80" +"checksum rustc-ap-rustc_errors 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9a1e9bdc597abd95cebce0c14c1da58943a9e5b8255530a0fec30659d144eb0b" +"checksum rustc-ap-rustc_target 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "142ddef3dc12dda2bcd3412f0d96d3745413a8fbc2f224f0cc97afa04c071d89" +"checksum rustc-ap-serialize 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8b08f8f175b038a82caa7e51fc52b72ff96cfe8c1429755da30380dbd4199c7f" +"checksum rustc-ap-syntax 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4c802e0e1fbc64eddc21e0798527eb1f5fdbd5781d119bd2c44b6130afdc81cc" +"checksum rustc-ap-syntax_pos 209.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "008d47cc54ed12a2784217b9e6630a7fa1c8dc3591a283f65ad4b7fa307d49d5" +"checksum rustc-demangle 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "76d7ba1feafada44f2d38eed812bd2489a03c0f5abb975799251518b68848649" +"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" +"checksum rustc-rayon 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c6d5a683c6ba4ed37959097e88d71c9e8e26659a3cb5be8b389078e7ad45306" +"checksum rustc-rayon-core 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40f06724db71e18d68b3b946fdf890ca8c921d9edccc1404fdfdb537b0d12649" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" -"checksum rustfix 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "165a212dd11124d7070892da20f71d82970ef1d1dd41cd804b70f39740a21c85" -"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7" +"checksum rustc_version 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a54aa04a10c68c1c4eacb4337fd883b435997ede17a9385784b990777686b09a" +"checksum rustfix 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f77b09d42bae4adfbcd105a8914e2d9fb46b63612c1a765b824a2b4a4bb814" "checksum same-file 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cfb6eded0b06a0b512c8ddbcf04089138c9b4362c2f696f3c3d76039d68f3637" -"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade" -"checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4" +"checksum schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1fabf2a7b6483a141426e1afd09ad543520a77ac49bd03c286e7696ccfd77f" +"checksum scoped-tls 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "332ffa32bf586782a3efaeb58f127980944bbc8c4d6913a86107ac2a5ab24b28" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "29465552c9b767d0cb44be3ddf4c3214be15d34975a7750f6cf4f409835f0248" -"checksum serde_derive 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "fb88f3c93214390ed9ef3ad15ce303c36684a915a97a30883ac6ca261bf67dc7" -"checksum serde_derive_internals 0.23.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9d30c4596450fd7bbda79ef15559683f9a79ac0193ea819db90000d7e1cae794" +"checksum serde 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "0c3adf19c07af6d186d91dae8927b83b0553d07ca56cbf7f2f32560455c91920" +"checksum serde_derive 1.0.70 (registry+https://github.com/rust-lang/crates.io-index)" = "3525a779832b08693031b8ecfb0de81cd71cfd3812088fafe9a7496789572124" "checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142" -"checksum serde_json 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7bf1cbb1387028a13739cb018ee0d9b3db534f22ca3c84a5904f7eadfde14e75" +"checksum serde_json 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c6908c7b925cd6c590358a4034de93dbddb20c45e1d021931459fd419bf0e2" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537" -"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a" -"checksum smallvec 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44db0ecb22921ef790d17ae13a3f6d15784183ff5f2a01aa32098c7498d2b4b9" -"checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d" -"checksum stable_deref_trait 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "15132e0e364248108c5e2c02e3ab539be8d6f5d52a01ca9bbf27ed657316f02b" -"checksum string_cache 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39cb4173bcbd1319da31faa5468a7e3870683d7a237150b0b0aaafd546f6ad12" -"checksum string_cache_codegen 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "479cde50c3539481f33906a387f2bd17c8e87cb848c35b6021d41fb81ff9b4d7" +"checksum smallvec 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "26df3bb03ca5eac2e64192b723d51f56c1b1e0860e7c766281f4598f181acdc8" +"checksum socket2 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "962a516af4d3a7c272cb3a1d50a8cc4e5b41802e4ad54cfb7bee8ba61d37d703" +"checksum stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa" +"checksum string_cache 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25d70109977172b127fe834e5449e5ab1740b9ba49fa18a2020f509174f25423" +"checksum string_cache_codegen 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35293b05cf1494e8ddd042a7df6756bf18d07f42d234f32e71dce8a7aabb0191" "checksum string_cache_shared 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b1884d1bc09741d466d9b14e6d37ac89d6909cbcac41dd9ae982d4d063bbedfc" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum strum 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099e21b5dd6dd07b5adcf8c4b723a7c0b7efd7a9359bf963d58c0caae8532545" -"checksum strum_macros 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0dd9bd569e88028750e3ae5c25616b8278ac16a8e61aba4339195c72396d49e1" +"checksum strum_macros 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1292d85e688e4696ecb69b2db2648994fb8af266974e89be53cefdf003861a5d" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -"checksum syn 0.12.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97c05b8ebc34ddd6b967994d5c6e9852fa92f8b82b3858c39451f97346dcce5" -"checksum syn 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "91b52877572087400e83d24b9178488541e3d535259e04ff17a63df1e5ceff59" +"checksum syn 0.13.11 (registry+https://github.com/rust-lang/crates.io-index)" = "14f9bf6292f3a61d2c716723fdb789a41bbe104168e6f496dc6497e531ea1b9b" +"checksum syn 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)" = "2beff8ebc3658f07512a413866875adddd20f4fd47b2a4e6c9da65cd281baaea" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" -"checksum syntex_errors 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9e52bffe6202cfb67587784cf23e0ec5bf26d331eef4922a16d5c42e12aa1e9b" -"checksum syntex_pos 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "955ef4b16af4c468e4680d1497f873ff288f557d338180649e18f915af5e15ac" -"checksum syntex_syntax 0.52.0 (registry+https://github.com/rust-lang/crates.io-index)" = "76a302e717e348aa372ff577791c3832395650073b8d8432f8b3cb170b34afde" -"checksum tar 0.4.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6af6b94659f9a571bf769a5b71f54079393585ee0bfdd71b691be22d7d6b1d18" -"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" -"checksum tempfile 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8cddbd26c5686ece823b507f304c8f188daef548b4cb753512d929ce478a093c" +"checksum tar 0.4.16 (registry+https://github.com/rust-lang/crates.io-index)" = "e8f41ca4a5689f06998f0247fcb60da6c760f1950cc9df2a10d71575ad0b062a" +"checksum tempfile 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "47776f63b85777d984a50ce49d6b9e58826b6a3766a449fc95bc66cd5663c15b" "checksum tendril 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9de21546595a0873061940d994bbbc5c35f024ae4fd61ec5c5b159115684f508" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum term 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5e6b677dd1e8214ea1ef4297f85dbcbed8e8cdddb561040cc998ca2551c37561" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" +"checksum termcolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "722426c4a0539da2c4ffd9b419d90ad540b4cff4a053be9069c908d4d07e2836" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693" +"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" -"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" -"checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" +"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" "checksum toml-query 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6854664bfc6df0360c695480836ee90e2d0c965f06db291d10be9344792d43e8" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" -"checksum unicode-segmentation 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8083c594e02b8ae1654ae26f0ade5158b119bd88ad0e8227a5d8fcd72407946" -"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" +"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" +"checksum unicode-segmentation 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aa6024fc12ddfd1c6dbc14a80fa2324d4568849869b779f6bd37e5e4c03344d1" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" -"checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" -"checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" +"checksum url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2a321979c09843d272956e73700d12c4e7d3d92b2ee112b31548aef0d4efc5a6" "checksum url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e7d099f1ee52f823d4bdd60c93c3602043c728f5db3b97bdb548467f7bddea" "checksum userenv-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71d28ea36bbd9192d75bd9fa9b39f96ddb986eaee824adae5d53b6e51919b2f3" "checksum utf-8 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1262dfab4c30d5cb7c07026be00ee343a6cf5027fdc0104a9160f354e5db75c" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" -"checksum vcpkg 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7ed0f6789c8a85ca41bbc1c9d175422116a9869bd1cf31bb08e1493ecce60380" -"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c" +"checksum vcpkg 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cbe533e138811704c0e3cbde65a818b35d3240409b4346256c5ede403e082474" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -"checksum walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bb08f9e670fab86099470b97cd2b252d6527f0b3cc1401acdb595ffc9dd288ff" "checksum walkdir 2.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "63636bd0eb3d00ccb8b9036381b526efac53caf112b7783b730ab3f8e44da369" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" -"checksum xattr 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "abb373b92de38a4301d66bec009929b4fb83120ea1c4a401be89dbe0b9777443" -"checksum xz2 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "98df591c3504d014dd791d998123ed00a476c7e26dc6b2e873cb55c6ac9e59fa" +"checksum wincolor 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b9dc3aa9dcda98b5a16150c54619c1ead22e3d3a5d458778ae914be760aa981a" +"checksum xattr 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +"checksum xz2 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "df8bf41d3030c3577c9458fd6640a05afbf43b150d0b531b16bd77d3f794f27a" "checksum yaml-rust 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e66366e18dc58b46801afbf2ca7661a9f59cc8c5962c29892b6039b4f86fa992" diff --git a/src/Cargo.toml b/src/Cargo.toml index 35858ee286838..62403700f3a40 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -4,7 +4,7 @@ members = [ "rustc", "libstd", "libtest", - "librustc_trans", + "librustc_codegen_llvm", "tools/cargotest", "tools/clippy", "tools/compiletest", @@ -23,22 +23,17 @@ members = [ "tools/rustfmt", "tools/miri", "tools/rustdoc-themes", - # FIXME(https://github.com/rust-lang/cargo/issues/4089): move these to exclude - "tools/rls/test_data/bin_lib", - "tools/rls/test_data/borrow_error", - "tools/rls/test_data/common", - "tools/rls/test_data/deglob", - "tools/rls/test_data/features", - "tools/rls/test_data/find_all_refs_no_cfg_test", - "tools/rls/test_data/find_impls", - "tools/rls/test_data/infer_bin", - "tools/rls/test_data/infer_custom_bin", - "tools/rls/test_data/infer_lib", - "tools/rls/test_data/multiple_bins", - "tools/rls/test_data/reformat", - "tools/rls/test_data/reformat_with_range", - "tools/rls/test_data/workspace_symbol", ] +exclude = [ + "tools/rls/test_data", +] + +# Curiously, LLVM 7.0 will segfault if compiled with opt-level=3 +# See issue https://github.com/rust-lang/rust/issues/52378 +[profile.release] +opt-level = 2 +[profile.bench] +opt-level = 2 # These options are controlled from our rustc wrapper script, so turn them off # here and have them controlled elsewhere. @@ -57,11 +52,11 @@ debug-assertions = false [patch."https://github.com/rust-lang/cargo"] cargo = { path = "tools/cargo" } -[patch.crates-io] +[patch."https://github.com/rust-lang-nursery/rustfmt"] # Similar to Cargo above we want the RLS to use a vendored version of `rustfmt` # that we're shipping as well (to ensure that the rustfmt in RLS and the -# `rustfmt` executable are the same exact vesion). Unlike Cargo, however, the -# RLS depends on `rustfmt` from crates.io, so we put this in a `[patch]` section -# for crates.io +# `rustfmt` executable are the same exact version). rustfmt-nightly = { path = "tools/rustfmt" } + +[patch."https://github.com/rust-lang-nursery/rust-clippy"] clippy_lints = { path = "tools/clippy/clippy_lints" } diff --git a/src/README.md b/src/README.md index 690ab674c64eb..6da4944c392db 100644 --- a/src/README.md +++ b/src/README.md @@ -6,7 +6,7 @@ This directory contains the source code of the rust project, including: For more information on how various parts of the compiler work, see the [rustc guide]. Their is also useful content in the following READMEs, which are gradually being moved over to the guide: -- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/maps +- https://github.com/rust-lang/rust/tree/master/src/librustc/ty/query - https://github.com/rust-lang/rust/tree/master/src/librustc/dep_graph - https://github.com/rust-lang/rust/blob/master/src/librustc/infer/region_constraints - https://github.com/rust-lang/rust/tree/master/src/librustc/infer/higher_ranked diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 2f9c4e148a6ba..57a526038041e 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -28,10 +28,15 @@ name = "sccache-plus-cl" path = "bin/sccache-plus-cl.rs" test = false +[[bin]] +name = "llvm-config-wrapper" +path = "bin/llvm-config-wrapper.rs" +test = false + [dependencies] build_helper = { path = "../build_helper" } cmake = "0.1.23" -filetime = "0.1" +filetime = "0.2" num_cpus = "1.0" getopts = "0.2" cc = "1.0.1" diff --git a/src/bootstrap/bin/llvm-config-wrapper.rs b/src/bootstrap/bin/llvm-config-wrapper.rs new file mode 100644 index 0000000000000..b1703f8c728e2 --- /dev/null +++ b/src/bootstrap/bin/llvm-config-wrapper.rs @@ -0,0 +1,27 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// The sheer existence of this file is an awful hack. See the comments in +// `src/bootstrap/native.rs` for why this is needed when compiling LLD. + +use std::env; +use std::process::{self, Stdio, Command}; +use std::io::{self, Write}; + +fn main() { + let real_llvm_config = env::var_os("LLVM_CONFIG_REAL").unwrap(); + let mut cmd = Command::new(real_llvm_config); + cmd.args(env::args().skip(1)).stderr(Stdio::piped()); + let output = cmd.output().expect("failed to spawn llvm-config"); + let stdout = String::from_utf8_lossy(&output.stdout); + print!("{}", stdout.replace("\\", "/")); + io::stdout().flush().unwrap(); + process::exit(output.status.code().unwrap_or(1)); +} diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 3f97accaa4d84..7192cae8956e4 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -268,12 +268,25 @@ fn main() { if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { cmd.arg(format!("-Clinker={}", host_linker)); } + + if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") { + if s == "true" { + cmd.arg("-C").arg("target-feature=+crt-static"); + } + if s == "false" { + cmd.arg("-C").arg("target-feature=-crt-static"); + } + } } if env::var_os("RUSTC_PARALLEL_QUERIES").is_some() { cmd.arg("--cfg").arg("parallel_queries"); } + if env::var_os("RUSTC_VERIFY_LLVM_IR").is_some() { + cmd.arg("-Z").arg("verify-llvm-ir"); + } + let color = match env::var("RUSTC_COLOR") { Ok(s) => usize::from_str(&s).expect("RUSTC_COLOR should be an integer"), Err(_) => 0, @@ -283,12 +296,19 @@ fn main() { cmd.arg("--color=always"); } - if env::var_os("RUSTC_DENY_WARNINGS").is_some() { + if env::var_os("RUSTC_DENY_WARNINGS").is_some() && env::var_os("RUSTC_EXTERNAL_TOOL").is_none() + { cmd.arg("-Dwarnings"); + cmd.arg("-Dbare_trait_objects"); } if verbose > 1 { - eprintln!("rustc command: {:?}", cmd); + eprintln!( + "rustc command: {:?}={:?} {:?}", + bootstrap::util::dylib_path_var(), + env::join_paths(&dylib_path).unwrap(), + cmd, + ); eprintln!("sysroot: {:?}", sysroot); eprintln!("libdir: {:?}", libdir); } @@ -308,7 +328,7 @@ fn main() { let start = Instant::now(); let status = cmd .status() - .expect(&format!("\n\n failed to run {:?}", cmd)); + .unwrap_or_else(|_| panic!("\n\n failed to run {:?}", cmd)); let dur = start.elapsed(); let is_test = args.iter().any(|a| a == "--test"); @@ -328,7 +348,7 @@ fn main() { } } - let code = exec_cmd(&mut cmd).expect(&format!("\n\n failed to run {:?}", cmd)); + let code = exec_cmd(&mut cmd).unwrap_or_else(|_| panic!("\n\n failed to run {:?}", cmd)); std::process::exit(code); } diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index 798d5c3eb6736..a54e58665cceb 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -35,7 +35,7 @@ fn main() { }; let mut dylib_path = bootstrap::util::dylib_path(); - dylib_path.insert(0, PathBuf::from(libdir)); + dylib_path.insert(0, PathBuf::from(libdir.clone())); let mut cmd = Command::new(rustdoc); cmd.args(&args) @@ -69,6 +69,7 @@ fn main() { if verbose > 1 { eprintln!("rustdoc command: {:?}", cmd); + eprintln!("libdir: {:?}", libdir); } std::process::exit(match cmd.status() { diff --git a/src/bootstrap/bin/sccache-plus-cl.rs b/src/bootstrap/bin/sccache-plus-cl.rs index 8584014d48d5f..0a20ac7e492dc 100644 --- a/src/bootstrap/bin/sccache-plus-cl.rs +++ b/src/bootstrap/bin/sccache-plus-cl.rs @@ -16,8 +16,8 @@ use std::process::{self, Command}; fn main() { let target = env::var("SCCACHE_TARGET").unwrap(); // Locate the actual compiler that we're invoking - env::remove_var("CC"); - env::remove_var("CXX"); + env::set_var("CC", env::var_os("SCCACHE_CC").unwrap()); + env::set_var("CXX", env::var_os("SCCACHE_CXX").unwrap()); let mut cfg = cc::Build::new(); cfg.cargo_metadata(false) .out_dir("/") @@ -39,6 +39,12 @@ fn main() { cmd.arg(arg); } + if let Ok(s) = env::var("SCCACHE_EXTRA_ARGS") { + for s in s.split_whitespace() { + cmd.arg(s); + } + } + let status = cmd.status().expect("failed to spawn"); process::exit(status.code().unwrap_or(2)) } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 487440becf630..71c1c61e3d97e 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -303,6 +303,19 @@ def default_build_triple(): return "{}-{}".format(cputype, ostype) +@contextlib.contextmanager +def output(filepath): + tmp = filepath + '.tmp' + with open(tmp, 'w') as f: + yield f + try: + os.remove(filepath) # PermissionError/OSError on Win32 if in use + os.rename(tmp, filepath) + except OSError: + shutil.copy2(tmp, filepath) + os.remove(tmp) + + class RustBuild(object): """Provide all the methods required to build Rust""" def __init__(self): @@ -346,7 +359,7 @@ def download_stage0(self): self._download_stage0_helper(filename, "rustc") self.fix_executable("{}/bin/rustc".format(self.bin_root())) self.fix_executable("{}/bin/rustdoc".format(self.bin_root())) - with open(self.rustc_stamp(), 'w') as rust_stamp: + with output(self.rustc_stamp()) as rust_stamp: rust_stamp.write(self.date) # This is required so that we don't mix incompatible MinGW @@ -363,7 +376,7 @@ def download_stage0(self): filename = "cargo-{}-{}.tar.gz".format(cargo_channel, self.build) self._download_stage0_helper(filename, "cargo") self.fix_executable("{}/bin/cargo".format(self.bin_root())) - with open(self.cargo_stamp(), 'w') as cargo_stamp: + with output(self.cargo_stamp()) as cargo_stamp: cargo_stamp.write(self.date) def _download_stage0_helper(self, filename, pattern): @@ -489,7 +502,7 @@ def bin_root(self): """ return os.path.join(self.build_dir, self.build, "stage0") - def get_toml(self, key): + def get_toml(self, key, section=None): """Returns the value of the given key in config.toml, otherwise returns None >>> rb = RustBuild() @@ -501,12 +514,29 @@ def get_toml(self, key): >>> rb.get_toml("key3") is None True + + Optionally also matches the section the key appears in + + >>> rb.config_toml = '[a]\\nkey = "value1"\\n[b]\\nkey = "value2"' + >>> rb.get_toml('key', 'a') + 'value1' + >>> rb.get_toml('key', 'b') + 'value2' + >>> rb.get_toml('key', 'c') is None + True """ + + cur_section = None for line in self.config_toml.splitlines(): + section_match = re.match(r'^\s*\[(.*)\]\s*$', line) + if section_match is not None: + cur_section = section_match.group(1) + match = re.match(r'^{}\s*=(.*)$'.format(key), line) if match is not None: value = match.group(1) - return self.get_string(value) or value.strip() + if section is None or section == cur_section: + return self.get_string(value) or value.strip() return None def cargo(self): @@ -589,7 +619,17 @@ def build_bootstrap(self): env["LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ (os.pathsep + env["LIBRARY_PATH"]) \ if "LIBRARY_PATH" in env else "" - env["RUSTFLAGS"] = "-Cdebuginfo=2" + env["RUSTFLAGS"] = "-Cdebuginfo=2 " + + build_section = "target.{}".format(self.build_triple()) + target_features = [] + if self.get_toml("crt-static", build_section) == "true": + target_features += ["+crt-static"] + elif self.get_toml("crt-static", build_section) == "false": + target_features += ["-crt-static"] + if target_features: + env["RUSTFLAGS"] += "-C target-feature=" + (",".join(target_features)) + " " + env["PATH"] = os.path.join(self.bin_root(), "bin") + \ os.pathsep + env["PATH"] if not os.path.isfile(self.cargo()): @@ -749,7 +789,7 @@ def bootstrap(help_triggered): if build.use_vendored_sources: if not os.path.exists('.cargo'): os.makedirs('.cargo') - with open('.cargo/config', 'w') as cargo_config: + with output('.cargo/config') as cargo_config: cargo_config.write(""" [source.crates-io] replace-with = 'vendored-sources' @@ -788,6 +828,9 @@ def bootstrap(help_triggered): env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable env["BUILD_DIR"] = build.build_dir + env["RUSTC_BOOTSTRAP"] = '1' + env["CARGO"] = build.cargo() + env["RUSTC"] = build.rustc() run(args, env=env, verbose=build.verbose) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 9c35cb7f506f9..724d3b741903f 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -11,6 +11,7 @@ use std::any::Any; use std::cell::{Cell, RefCell}; use std::collections::BTreeSet; +use std::collections::HashMap; use std::env; use std::fmt::Debug; use std::fs; @@ -18,33 +19,32 @@ use std::hash::Hash; use std::ops::Deref; use std::path::{Path, PathBuf}; use std::process::Command; -use std::time::{Instant, Duration}; -use std::collections::HashMap; +use std::time::{Duration, Instant}; +use cache::{Cache, Interned, INTERNER}; +use check; use compile; -use install; use dist; -use util::{exe, libdir, add_lib_path}; -use {Build, Mode, DocTests}; -use cache::{INTERNER, Interned, Cache}; -use check; -use test; -use flags::Subcommand; use doc; -use tool; +use flags::Subcommand; +use install; use native; +use test; +use tool; +use util::{add_lib_path, exe, libdir}; +use {Build, DocTests, Mode}; pub use Compiler; -use petgraph::Graph; use petgraph::graph::NodeIndex; +use petgraph::Graph; pub struct Builder<'a> { pub build: &'a Build, pub top_stage: u32, pub kind: Kind, cache: Cache, - stack: RefCell>>, + stack: RefCell>>, time_spent_on_dependencies: Cell, pub paths: Vec, graph_nodes: RefCell>, @@ -111,27 +111,38 @@ struct StepDescription { } #[derive(Debug, Clone, PartialOrd, Ord, PartialEq, Eq)] -struct PathSet { - set: BTreeSet, +pub enum PathSet { + Set(BTreeSet), + Suite(PathBuf), } impl PathSet { fn empty() -> PathSet { - PathSet { set: BTreeSet::new() } + PathSet::Set(BTreeSet::new()) } fn one>(path: P) -> PathSet { let mut set = BTreeSet::new(); set.insert(path.into()); - PathSet { set } + PathSet::Set(set) } fn has(&self, needle: &Path) -> bool { - self.set.iter().any(|p| p.ends_with(needle)) + match self { + PathSet::Set(set) => set.iter().any(|p| p.ends_with(needle)), + PathSet::Suite(_) => false, + } } fn path(&self, builder: &Builder) -> PathBuf { - self.set.iter().next().unwrap_or(&builder.build.src).to_path_buf() + match self { + PathSet::Set(set) => set + .iter() + .next() + .unwrap_or(&builder.build.src) + .to_path_buf(), + PathSet::Suite(path) => PathBuf::from(path), + } } } @@ -151,8 +162,10 @@ impl StepDescription { eprintln!("Skipping {:?} because it is excluded", pathset); return; } else if !builder.config.exclude.is_empty() { - eprintln!("{:?} not skipped for {:?} -- not in {:?}", pathset, - self.name, builder.config.exclude); + eprintln!( + "{:?} not skipped for {:?} -- not in {:?}", + pathset, self.name, builder.config.exclude + ); } let hosts = &builder.hosts; @@ -181,14 +194,18 @@ impl StepDescription { } fn run(v: &[StepDescription], builder: &Builder, paths: &[PathBuf]) { - let should_runs = v.iter().map(|desc| { - (desc.should_run)(ShouldRun::new(builder)) - }).collect::>(); + let should_runs = v + .iter() + .map(|desc| (desc.should_run)(ShouldRun::new(builder))) + .collect::>(); // sanity checks on rules for (desc, should_run) in v.iter().zip(&should_runs) { - assert!(!should_run.paths.is_empty(), - "{:?} should have at least one pathset", desc.name); + assert!( + !should_run.paths.is_empty(), + "{:?} should have at least one pathset", + desc.name + ); } if paths.is_empty() { @@ -201,9 +218,18 @@ impl StepDescription { } } else { for path in paths { + // strip CurDir prefix if present + let path = match path.strip_prefix(".") { + Ok(p) => p, + Err(_) => path, + }; + let mut attempted_run = false; for (desc, should_run) in v.iter().zip(&should_runs) { - if let Some(pathset) = should_run.pathset_for_path(path) { + if let Some(suite) = should_run.is_suite_path(path) { + attempted_run = true; + desc.maybe_run(builder, suite); + } else if let Some(pathset) = should_run.pathset_for_path(path) { attempted_run = true; desc.maybe_run(builder, pathset); } @@ -250,7 +276,7 @@ impl<'a> ShouldRun<'a> { for krate in self.builder.in_tree_crates(name) { set.insert(PathBuf::from(&krate.path)); } - self.paths.insert(PathSet { set }); + self.paths.insert(PathSet::Set(set)); self } @@ -268,9 +294,20 @@ impl<'a> ShouldRun<'a> { // multiple aliases for the same job pub fn paths(mut self, paths: &[&str]) -> Self { - self.paths.insert(PathSet { - set: paths.iter().map(PathBuf::from).collect(), - }); + self.paths + .insert(PathSet::Set(paths.iter().map(PathBuf::from).collect())); + self + } + + pub fn is_suite_path(&self, path: &Path) -> Option<&PathSet> { + self.paths.iter().find(|pathset| match pathset { + PathSet::Suite(p) => path.starts_with(p), + PathSet::Set(_) => false, + }) + } + + pub fn suite_path(mut self, suite: &str) -> Self { + self.paths.insert(PathSet::Suite(PathBuf::from(suite))); self } @@ -304,40 +341,140 @@ impl<'a> Builder<'a> { }}; } match kind { - Kind::Build => describe!(compile::Std, compile::Test, compile::Rustc, - compile::StartupObjects, tool::BuildManifest, tool::Rustbook, tool::ErrorIndex, - tool::UnstableBookGen, tool::Tidy, tool::Linkchecker, tool::CargoTest, - tool::Compiletest, tool::RemoteTestServer, tool::RemoteTestClient, - tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy, - native::Llvm, tool::Rustfmt, tool::Miri, native::Lld), - Kind::Check => describe!(check::Std, check::Test, check::Rustc, check::CodegenBackend, - check::Rustdoc), - Kind::Test => describe!(test::Tidy, test::Bootstrap, test::Ui, test::RunPass, - test::CompileFail, test::ParseFail, test::RunFail, test::RunPassValgrind, - test::MirOpt, test::Codegen, test::CodegenUnits, test::Incremental, test::Debuginfo, - test::UiFullDeps, test::RunPassFullDeps, test::RunFailFullDeps, - test::CompileFailFullDeps, test::IncrementalFullDeps, test::Rustdoc, test::Pretty, - test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty, - test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, - test::Crate, test::CrateLibrustc, test::CrateRustdoc, test::Linkcheck, - test::Cargotest, test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck, + Kind::Build => describe!( + compile::Std, + compile::Test, + compile::Rustc, + compile::CodegenBackend, + compile::StartupObjects, + tool::BuildManifest, + tool::Rustbook, + tool::ErrorIndex, + tool::UnstableBookGen, + tool::Tidy, + tool::Linkchecker, + tool::CargoTest, + tool::Compiletest, + tool::RemoteTestServer, + tool::RemoteTestClient, + tool::RustInstaller, + tool::Cargo, + tool::Rls, + tool::Rustdoc, + tool::Clippy, + native::Llvm, + tool::Rustfmt, + tool::Miri, + native::Lld + ), + Kind::Check => describe!( + check::Std, + check::Test, + check::Rustc, + check::CodegenBackend, + check::Rustdoc + ), + Kind::Test => describe!( + test::Tidy, + test::Ui, + test::RunPass, + test::CompileFail, + test::ParseFail, + test::RunFail, + test::RunPassValgrind, + test::MirOpt, + test::Codegen, + test::CodegenUnits, + test::Incremental, + test::Debuginfo, + test::UiFullDeps, + test::RunPassFullDeps, + test::RunFailFullDeps, + test::CompileFailFullDeps, + test::IncrementalFullDeps, + test::Rustdoc, + test::Pretty, + test::RunPassPretty, + test::RunFailPretty, + test::RunPassValgrindPretty, + test::RunPassFullDepsPretty, + test::RunFailFullDepsPretty, + test::Crate, + test::CrateLibrustc, + test::CrateRustdoc, + test::Linkcheck, + test::Cargotest, + test::Cargo, + test::Rls, + test::ErrorIndex, + test::Distcheck, test::RunMakeFullDeps, - test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample, - test::TheBook, test::UnstableBook, test::RustcBook, - test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme, + test::Nomicon, + test::Reference, + test::RustdocBook, + test::RustByExample, + test::TheBook, + test::UnstableBook, + test::RustcBook, + test::Rustfmt, + test::Miri, + test::Clippy, + test::RustdocJS, + test::RustdocTheme, + // Run bootstrap close to the end as it's unlikely to fail + test::Bootstrap, // Run run-make last, since these won't pass without make on Windows - test::RunMake, test::RustdocUi), + test::RunMake, + test::RustdocUi + ), Kind::Bench => describe!(test::Crate, test::CrateLibrustc), - Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook, - doc::Standalone, doc::Std, doc::Test, doc::WhitelistedRustc, doc::Rustc, - doc::ErrorIndex, doc::Nomicon, doc::Reference, doc::Rustdoc, doc::RustByExample, - doc::RustcBook, doc::CargoBook), - Kind::Dist => describe!(dist::Docs, dist::RustcDocs, dist::Mingw, dist::Rustc, - dist::DebuggerScripts, dist::Std, dist::Analysis, dist::Src, - dist::PlainSourceTarball, dist::Cargo, dist::Rls, dist::Rustfmt, dist::Extended, - dist::HashSign), - Kind::Install => describe!(install::Docs, install::Std, install::Cargo, install::Rls, - install::Rustfmt, install::Analysis, install::Src, install::Rustc), + Kind::Doc => describe!( + doc::UnstableBook, + doc::UnstableBookGen, + doc::TheBook, + doc::Standalone, + doc::Std, + doc::Test, + doc::WhitelistedRustc, + doc::Rustc, + doc::Rustdoc, + doc::ErrorIndex, + doc::Nomicon, + doc::Reference, + doc::RustdocBook, + doc::RustByExample, + doc::RustcBook, + doc::CargoBook + ), + Kind::Dist => describe!( + dist::Docs, + dist::RustcDocs, + dist::Mingw, + dist::Rustc, + dist::DebuggerScripts, + dist::Std, + dist::Analysis, + dist::Src, + dist::PlainSourceTarball, + dist::Cargo, + dist::Rls, + dist::Rustfmt, + dist::Clippy, + dist::LlvmTools, + dist::Extended, + dist::HashSign + ), + Kind::Install => describe!( + install::Docs, + install::Std, + install::Cargo, + install::Rls, + install::Rustfmt, + install::Clippy, + install::Analysis, + install::Src, + install::Rustc + ), } } @@ -372,8 +509,12 @@ impl<'a> Builder<'a> { } let mut help = String::from("Available paths:\n"); for pathset in should_run.paths { - for path in pathset.set { - help.push_str(format!(" ./x.py {} {}\n", subcommand, path.display()).as_str()); + if let PathSet::Set(set) = pathset { + set.iter().for_each(|path| { + help.push_str( + format!(" ./x.py {} {}\n", subcommand, path.display()).as_str(), + ) + }) } } Some(help) @@ -405,9 +546,12 @@ impl<'a> Builder<'a> { }; if kind == Kind::Dist { - assert!(!builder.config.test_miri, "Do not distribute with miri enabled.\n\ + assert!( + !builder.config.test_miri, + "Do not distribute with miri enabled.\n\ The distributed libraries would include all MIR (increasing binary size). - The distributed MIR would include validation statements."); + The distributed MIR would include validation statements." + ); } builder @@ -432,7 +576,9 @@ impl<'a> Builder<'a> { /// obtained through this function, since it ensures that they are valid /// (i.e., built and assembled). pub fn compiler(&self, stage: u32, host: Interned) -> Compiler { - self.ensure(compile::Assemble { target_compiler: Compiler { stage, host } }) + self.ensure(compile::Assemble { + target_compiler: Compiler { stage, host }, + }) } pub fn sysroot(&self, compiler: Compiler) -> Interned { @@ -442,7 +588,9 @@ impl<'a> Builder<'a> { /// Returns the libdir where the standard library and other artifacts are /// found for a compiler's sysroot. pub fn sysroot_libdir( - &self, compiler: Compiler, target: Interned + &self, + compiler: Compiler, + target: Interned, ) -> Interned { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] struct Libdir { @@ -464,8 +612,12 @@ impl<'a> Builder<'a> { } else { Path::new("lib") }; - let sysroot = builder.sysroot(self.compiler).join(lib) - .join("rustlib").join(self.target).join("lib"); + let sysroot = builder + .sysroot(self.compiler) + .join(lib) + .join("rustlib") + .join(self.target) + .join("lib"); let _ = fs::remove_dir_all(&sysroot); t!(fs::create_dir_all(&sysroot)); INTERNER.intern_path(sysroot) @@ -499,7 +651,7 @@ impl<'a> Builder<'a> { // compiler live next to the compiler and the system will find them // automatically. if cfg!(windows) { - return + return; } add_lib_path(vec![self.rustc_libdir(compiler)], cmd); @@ -510,7 +662,9 @@ impl<'a> Builder<'a> { if compiler.is_snapshot(self) { self.initial_rustc.clone() } else { - self.sysroot(compiler).join("bin").join(exe("rustc", &compiler.host)) + self.sysroot(compiler) + .join("bin") + .join(exe("rustc", &compiler.host)) } } @@ -522,12 +676,15 @@ impl<'a> Builder<'a> { let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); let compiler = self.compiler(self.top_stage, host); cmd.env("RUSTC_STAGE", compiler.stage.to_string()) - .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build)) - .env("CFG_RELEASE_CHANNEL", &self.config.channel) - .env("RUSTDOC_REAL", self.rustdoc(host)) - .env("RUSTDOC_CRATE_VERSION", self.rust_version()) - .env("RUSTC_BOOTSTRAP", "1"); + .env("RUSTC_SYSROOT", self.sysroot(compiler)) + .env( + "RUSTDOC_LIBDIR", + self.sysroot_libdir(compiler, self.config.build), + ) + .env("CFG_RELEASE_CHANNEL", &self.config.channel) + .env("RUSTDOC_REAL", self.rustdoc(host)) + .env("RUSTDOC_CRATE_VERSION", self.rust_version()) + .env("RUSTC_BOOTSTRAP", "1"); if let Some(linker) = self.linker(host) { cmd.env("RUSTC_TARGET_LINKER", linker); } @@ -541,17 +698,25 @@ impl<'a> Builder<'a> { /// rustc compiler, its output will be scoped by `mode`'s output directory, /// it will pass the `--target` flag for the specified `target`, and will be /// executing the Cargo command `cmd`. - pub fn cargo(&self, - compiler: Compiler, - mode: Mode, - target: Interned, - cmd: &str) -> Command { + pub fn cargo( + &self, + compiler: Compiler, + mode: Mode, + target: Interned, + cmd: &str, + ) -> Command { let mut cargo = Command::new(&self.initial_cargo); let out_dir = self.stage_out(compiler, mode); - cargo.env("CARGO_TARGET_DIR", out_dir) - .arg(cmd) - .arg("--target") - .arg(target); + cargo + .env("CARGO_TARGET_DIR", out_dir) + .arg(cmd); + + if cmd != "install" { + cargo.arg("--target") + .arg(target); + } else { + assert_eq!(target, compiler.host); + } // Set a flag for `check` so that certain build scripts can do less work // (e.g. not building/requiring LLVM). @@ -559,15 +724,22 @@ impl<'a> Builder<'a> { cargo.env("RUST_CHECK", "1"); } - // If we were invoked from `make` then that's already got a jobserver - // set up for us so no need to tell Cargo about jobs all over again. - if env::var_os("MAKEFLAGS").is_none() && env::var_os("MFLAGS").is_none() { - cargo.arg("-j").arg(self.jobs().to_string()); - } + cargo.arg("-j").arg(self.jobs().to_string()); + // Remove make-related flags to ensure Cargo can correctly set things up + cargo.env_remove("MAKEFLAGS"); + cargo.env_remove("MFLAGS"); // FIXME: Temporary fix for https://github.com/rust-lang/cargo/issues/3005 // Force cargo to output binaries with disambiguating hashes in the name - cargo.env("__CARGO_DEFAULT_LIB_METADATA", &self.config.channel); + let metadata = if compiler.stage == 0 { + // Treat stage0 like special channel, whether it's a normal prior- + // release rustc or a local rebuild with the same version, so we + // never mix these libraries by accident. + "bootstrap" + } else { + &self.config.channel + }; + cargo.env("__CARGO_DEFAULT_LIB_METADATA", &metadata); let stage; if compiler.stage == 0 && self.local_rebuild { @@ -587,35 +759,63 @@ impl<'a> Builder<'a> { } if !extra_args.is_empty() { - cargo.env("RUSTFLAGS", - format!("{} {}", env::var("RUSTFLAGS").unwrap_or_default(), extra_args)); + cargo.env( + "RUSTFLAGS", + format!( + "{} {}", + env::var("RUSTFLAGS").unwrap_or_default(), + extra_args + ), + ); } let want_rustdoc = self.doc_tests != DocTests::No; + // We synthetically interpret a stage0 compiler used to build tools as a + // "raw" compiler in that it's the exact snapshot we download. Normally + // the stage0 build means it uses libraries build by the stage0 + // compiler, but for tools we just use the precompiled libraries that + // we've downloaded + let use_snapshot = mode == Mode::ToolBootstrap; + assert!(!use_snapshot || stage == 0); + + let maybe_sysroot = self.sysroot(compiler); + let sysroot = if use_snapshot { + self.rustc_snapshot_sysroot() + } else { + &maybe_sysroot + }; + let libdir = sysroot.join(libdir(&compiler.host)); + // Customize the compiler we're running. Specify the compiler to cargo // as our shim and then pass it some various options used to configure // how the actual compiler itself is called. // // These variables are primarily all read by // src/bootstrap/bin/{rustc.rs,rustdoc.rs} - cargo.env("RUSTBUILD_NATIVE_DIR", self.native_dir(target)) - .env("RUSTC", self.out.join("bootstrap/debug/rustc")) - .env("RUSTC_REAL", self.rustc(compiler)) - .env("RUSTC_STAGE", stage.to_string()) - .env("RUSTC_DEBUG_ASSERTIONS", - self.config.rust_debug_assertions.to_string()) - .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTC_LIBDIR", self.rustc_libdir(compiler)) - .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) - .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) - .env("RUSTDOC_REAL", if cmd == "doc" || (cmd == "test" && want_rustdoc) { - self.rustdoc(compiler.host) - } else { - PathBuf::from("/path/to/nowhere/rustdoc/not/required") - }) - .env("TEST_MIRI", self.config.test_miri.to_string()) - .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); + cargo + .env("RUSTBUILD_NATIVE_DIR", self.native_dir(target)) + .env("RUSTC", self.out.join("bootstrap/debug/rustc")) + .env("RUSTC_REAL", self.rustc(compiler)) + .env("RUSTC_STAGE", stage.to_string()) + .env( + "RUSTC_DEBUG_ASSERTIONS", + self.config.rust_debug_assertions.to_string(), + ) + .env("RUSTC_SYSROOT", &sysroot) + .env("RUSTC_LIBDIR", &libdir) + .env("RUSTC_RPATH", self.config.rust_rpath.to_string()) + .env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc")) + .env( + "RUSTDOC_REAL", + if cmd == "doc" || (cmd == "test" && want_rustdoc) { + self.rustdoc(compiler.host) + } else { + PathBuf::from("/path/to/nowhere/rustdoc/not/required") + }, + ) + .env("TEST_MIRI", self.config.test_miri.to_string()) + .env("RUSTC_ERROR_METADATA_DST", self.extended_error_dir()); if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); @@ -627,19 +827,25 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_ERROR_FORMAT", error_format); } if cmd != "build" && cmd != "check" && want_rustdoc { - cargo.env("RUSTDOC_LIBDIR", self.rustc_libdir(self.compiler(2, self.config.build))); + cargo.env("RUSTDOC_LIBDIR", self.sysroot_libdir(compiler, self.config.build)); } - if mode == Mode::Tool { + if mode.is_tool() { // Tools like cargo and rls don't get debuginfo by default right now, but this can be // enabled in the config. Adding debuginfo makes them several times larger. if self.config.rust_debuginfo_tools { cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()); - cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()); + cargo.env( + "RUSTC_DEBUGINFO_LINES", + self.config.rust_debuginfo_lines.to_string(), + ); } } else { cargo.env("RUSTC_DEBUGINFO", self.config.rust_debuginfo.to_string()); - cargo.env("RUSTC_DEBUGINFO_LINES", self.config.rust_debuginfo_lines.to_string()); + cargo.env( + "RUSTC_DEBUGINFO_LINES", + self.config.rust_debuginfo_lines.to_string(), + ); cargo.env("RUSTC_FORCE_UNSTABLE", "1"); // Currently the compiler depends on crates from crates.io, and @@ -665,6 +871,10 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_CRT_STATIC", x.to_string()); } + if let Some(x) = self.crt_static(compiler.host) { + cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string()); + } + // Enable usage of unstable features cargo.env("RUSTC_BOOTSTRAP", "1"); self.add_rust_test_threads(&mut cargo); @@ -685,18 +895,17 @@ impl<'a> Builder<'a> { // // If LLVM support is disabled we need to use the snapshot compiler to compile // build scripts, as the new compiler doesn't support executables. - if mode == Mode::Libstd || !self.config.llvm_enabled { - cargo.env("RUSTC_SNAPSHOT", &self.initial_rustc) - .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); + if mode == Mode::Std || !self.config.llvm_enabled { + cargo + .env("RUSTC_SNAPSHOT", &self.initial_rustc) + .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_snapshot_libdir()); } else { - cargo.env("RUSTC_SNAPSHOT", self.rustc(compiler)) - .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler)); + cargo + .env("RUSTC_SNAPSHOT", self.rustc(compiler)) + .env("RUSTC_SNAPSHOT_LIBDIR", self.rustc_libdir(compiler)); } - // Ignore incremental modes except for stage0, since we're - // not guaranteeing correctness across builds if the compiler - // is changing under your feet.` - if self.config.incremental && compiler.stage == 0 { + if self.config.incremental { cargo.env("CARGO_INCREMENTAL", "1"); } @@ -712,10 +921,14 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_BACKTRACE_ON_ICE", "1"); } - cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); + if self.config.rust_verify_llvm_ir { + cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); + } + + cargo.env("RUSTC_VERBOSE", self.verbosity.to_string()); // in std, we want to avoid denying warnings for stage 0 as that makes cfg's painful. - if self.config.deny_warnings && !(mode == Mode::Libstd && stage == 0) { + if self.config.deny_warnings && !(mode == Mode::Std && stage == 0) { cargo.env("RUSTC_DENY_WARNINGS", "1"); } @@ -726,7 +939,11 @@ impl<'a> Builder<'a> { // the options through environment variables that are fetched and understood by both. // // FIXME: the guard against msvc shouldn't need to be here - if !target.contains("msvc") { + if target.contains("msvc") { + if let Some(ref cl) = self.config.llvm_clang_cl { + cargo.env("CC", cl).env("CXX", cl); + } + } else { let ccache = self.config.ccache.as_ref(); let ccacheify = |s: &Path| { let ccache = match ccache { @@ -744,32 +961,36 @@ impl<'a> Builder<'a> { } }; let cc = ccacheify(&self.cc(target)); - cargo.env(format!("CC_{}", target), &cc) - .env("CC", &cc); + cargo.env(format!("CC_{}", target), &cc).env("CC", &cc); let cflags = self.cflags(target).join(" "); - cargo.env(format!("CFLAGS_{}", target), cflags.clone()) - .env("CFLAGS", cflags.clone()); + cargo + .env(format!("CFLAGS_{}", target), cflags.clone()) + .env("CFLAGS", cflags.clone()); if let Some(ar) = self.ar(target) { let ranlib = format!("{} s", ar.display()); - cargo.env(format!("AR_{}", target), ar) - .env("AR", ar) - .env(format!("RANLIB_{}", target), ranlib.clone()) - .env("RANLIB", ranlib); + cargo + .env(format!("AR_{}", target), ar) + .env("AR", ar) + .env(format!("RANLIB_{}", target), ranlib.clone()) + .env("RANLIB", ranlib); } if let Ok(cxx) = self.cxx(target) { let cxx = ccacheify(&cxx); - cargo.env(format!("CXX_{}", target), &cxx) - .env("CXX", &cxx) - .env(format!("CXXFLAGS_{}", target), cflags.clone()) - .env("CXXFLAGS", cflags); + cargo + .env(format!("CXX_{}", target), &cxx) + .env("CXX", &cxx) + .env(format!("CXXFLAGS_{}", target), cflags.clone()) + .env("CXXFLAGS", cflags); } } - if cmd == "build" && mode == Mode::Libstd - && self.config.extended && compiler.is_final_stage(self) + if cmd == "build" + && mode == Mode::Std + && self.config.extended + && compiler.is_final_stage(self) { cargo.env("RUSTC_SAVE_ANALYSIS", "api".to_string()); } @@ -803,7 +1024,7 @@ impl<'a> Builder<'a> { // default via `-ldylib=winapi_foo`. That is, they're linked with the // `dylib` type with a `winapi_` prefix (so the winapi ones don't // conflict with the system MinGW ones). This consequently means that - // the binaries we ship of things like rustc_trans (aka the rustc_trans + // the binaries we ship of things like rustc_codegen_llvm (aka the rustc_codegen_llvm // DLL) when linked against *again*, for example with procedural macros // or plugins, will trigger the propagation logic of `-ldylib`, passing // `-lwinapi_foo` to the linker again. This isn't actually available in @@ -816,7 +1037,7 @@ impl<'a> Builder<'a> { // be resolved because MinGW has the import library. The downside is we // don't get newer functions from Windows, but we don't use any of them // anyway. - if mode != Mode::Tool { + if !mode.is_tool() { cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); } @@ -831,8 +1052,8 @@ impl<'a> Builder<'a> { } if self.config.rust_optimize { - // FIXME: cargo bench does not accept `--release` - if cmd != "bench" { + // FIXME: cargo bench/install do not accept `--release` + if cmd != "bench" && cmd != "install" { cargo.arg("--release"); } } @@ -857,7 +1078,10 @@ impl<'a> Builder<'a> { let mut stack = self.stack.borrow_mut(); for stack_step in stack.iter() { // should skip - if stack_step.downcast_ref::().map_or(true, |stack_step| *stack_step != step) { + if stack_step + .downcast_ref::() + .map_or(true, |stack_step| *stack_step != step) + { continue; } let mut out = String::new(); @@ -873,7 +1097,9 @@ impl<'a> Builder<'a> { { let mut graph = self.graph.borrow_mut(); let parent = self.parent.get(); - let us = *self.graph_nodes.borrow_mut() + let us = *self + .graph_nodes + .borrow_mut() .entry(format!("{:?}", step)) .or_insert_with(|| graph.add_node(format!("{:?}", step))); if let Some(parent) = parent { @@ -892,7 +1118,9 @@ impl<'a> Builder<'a> { { let mut graph = self.graph.borrow_mut(); let parent = self.parent.get(); - let us = *self.graph_nodes.borrow_mut() + let us = *self + .graph_nodes + .borrow_mut() .entry(format!("{:?}", step)) .or_insert_with(|| graph.add_node(format!("{:?}", step))); self.parent.set(Some(us)); @@ -914,10 +1142,12 @@ impl<'a> Builder<'a> { self.parent.set(prev_parent); if self.config.print_step_timings && dur > Duration::from_millis(100) { - println!("[TIMING] {:?} -- {}.{:03}", - step, - dur.as_secs(), - dur.subsec_nanos() / 1_000_000); + println!( + "[TIMING] {:?} -- {}.{:03}", + step, + dur.as_secs(), + dur.subsec_nanos() / 1_000_000 + ); } { @@ -925,7 +1155,11 @@ impl<'a> Builder<'a> { let cur_step = stack.pop().expect("step stack empty"); assert_eq!(cur_step.downcast_ref(), Some(&step)); } - self.verbose(&format!("{}< {:?}", " ".repeat(self.stack.borrow().len()), step)); + self.verbose(&format!( + "{}< {:?}", + " ".repeat(self.stack.borrow().len()), + step + )); self.cache.put(step, out.clone()); out } @@ -933,9 +1167,9 @@ impl<'a> Builder<'a> { #[cfg(test)] mod __test { + use super::*; use config::Config; use std::thread; - use super::*; fn configure(host: &[&str], target: &[&str]) -> Config { let mut config = Config::default_opts(); @@ -944,15 +1178,26 @@ mod __test { config.run_host_only = true; config.dry_run = true; // try to avoid spurious failures in dist where we create/delete each others file - let dir = config.out.join("tmp-rustbuild-tests") - .join(&thread::current().name().unwrap_or("unknown").replace(":", "-")); + let dir = config.out.join("tmp-rustbuild-tests").join( + &thread::current() + .name() + .unwrap_or("unknown") + .replace(":", "-"), + ); t!(fs::create_dir_all(&dir)); config.out = dir; config.build = INTERNER.intern_str("A"); - config.hosts = vec![config.build].clone().into_iter() - .chain(host.iter().map(|s| INTERNER.intern_str(s))).collect::>(); - config.targets = config.hosts.clone().into_iter() - .chain(target.iter().map(|s| INTERNER.intern_str(s))).collect::>(); + config.hosts = vec![config.build] + .clone() + .into_iter() + .chain(host.iter().map(|s| INTERNER.intern_str(s))) + .collect::>(); + config.targets = config + .hosts + .clone() + .into_iter() + .chain(target.iter().map(|s| INTERNER.intern_str(s))) + .collect::>(); config } @@ -968,21 +1213,27 @@ mod __test { let a = INTERNER.intern_str("A"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { + assert_eq!( + first(builder.cache.all::()), + &[dist::Docs { stage: 2, host: a },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: a, - }, - ]); + },] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -995,27 +1246,36 @@ mod __test { let a = INTERNER.intern_str("A"); let b = INTERNER.intern_str("B"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -1028,28 +1288,41 @@ mod __test { let a = INTERNER.intern_str("A"); let b = INTERNER.intern_str("B"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -1063,34 +1336,50 @@ mod __test { let b = INTERNER.intern_str("B"); let c = INTERNER.intern_str("C"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - dist::Docs { stage: 2, host: c }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - dist::Mingw { host: c }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + dist::Docs { stage: 2, host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -1106,31 +1395,40 @@ mod __test { let b = INTERNER.intern_str("B"); let c = INTERNER.intern_str("C"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - dist::Docs { stage: 2, host: c }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - dist::Mingw { host: c }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + dist::Docs { stage: 2, host: c }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Mingw { host: a }, + dist::Mingw { host: b }, + dist::Mingw { host: c }, + ] + ); assert_eq!(first(builder.cache.all::()), &[]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[]); } @@ -1143,87 +1441,109 @@ mod __test { let a = INTERNER.intern_str("A"); let b = INTERNER.intern_str("B"); - assert_eq!(first(builder.cache.all::()), &[ - dist::Docs { stage: 2, host: a }, - dist::Docs { stage: 2, host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Mingw { host: a }, - dist::Mingw { host: b }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Rustc { compiler: Compiler { host: a, stage: 2 } }, - dist::Rustc { compiler: Compiler { host: b, stage: 2 } }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - dist::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Docs { stage: 2, host: a }, + dist::Docs { stage: 2, host: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[dist::Mingw { host: a }, dist::Mingw { host: b },] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Rustc { + compiler: Compiler { host: a, stage: 2 } + }, + dist::Rustc { + compiler: Compiler { host: b, stage: 2 } + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + dist::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); - assert_eq!(first(builder.cache.all::()), &[ - compile::Std { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Std { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Std { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - compile::Assemble { - target_compiler: Compiler { host: a, stage: 0 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 2 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 2 }, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Std { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Std { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { + target_compiler: Compiler { host: a, stage: 0 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 2 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 2 }, + }, + ] + ); } #[test] @@ -1238,83 +1558,89 @@ mod __test { assert!(!builder.cache.all::().is_empty()); assert!(!builder.cache.all::().is_empty()); - assert_eq!(first(builder.cache.all::()), &[ - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - ]); - - assert_eq!(first(builder.cache.all::()), &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: c, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + ] + ); + + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ] + ); } #[test] @@ -1330,84 +1656,93 @@ mod __test { let c = INTERNER.intern_str("C"); assert!(!builder.cache.all::().is_empty()); - assert_eq!(first(builder.cache.all::()), &[ - compile::Assemble { - target_compiler: Compiler { host: a, stage: 0 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 1 }, - }, - compile::Assemble { - target_compiler: Compiler { host: a, stage: 2 }, - }, - compile::Assemble { - target_compiler: Compiler { host: b, stage: 2 }, - }, - ]); - assert_eq!(first(builder.cache.all::()), &[ - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Rustc { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - ]); - - assert_eq!(first(builder.cache.all::()), &[ - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: a, - }, - compile::Test { - compiler: Compiler { host: a, stage: 0 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 1 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: b, - }, - compile::Test { - compiler: Compiler { host: a, stage: 2 }, - target: c, - }, - compile::Test { - compiler: Compiler { host: b, stage: 2 }, - target: c, - }, - ]); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { + target_compiler: Compiler { host: a, stage: 0 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 1 }, + }, + compile::Assemble { + target_compiler: Compiler { host: a, stage: 2 }, + }, + compile::Assemble { + target_compiler: Compiler { host: b, stage: 2 }, + }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Rustc { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + ] + ); + + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: a, + }, + compile::Test { + compiler: Compiler { host: a, stage: 0 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 1 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: b, + }, + compile::Test { + compiler: Compiler { host: a, stage: 2 }, + target: c, + }, + compile::Test { + compiler: Compiler { host: b, stage: 2 }, + target: c, + }, + ] + ); } #[test] @@ -1420,6 +1755,8 @@ mod __test { rustc_args: vec![], fail_fast: true, doc_tests: DocTests::No, + bless: false, + compare_mode: None, }; let build = Build::new(config); @@ -1434,14 +1771,15 @@ mod __test { // Ensure we don't build any compiler artifacts. assert!(builder.cache.all::().is_empty()); - assert_eq!(first(builder.cache.all::()), &[ - test::Crate { + assert_eq!( + first(builder.cache.all::()), + &[test::Crate { compiler: Compiler { host, stage: 0 }, target: host, - mode: Mode::Libstd, + mode: Mode::Std, test_kind: test::TestKind::Test, krate: INTERNER.intern_str("std"), - }, - ]); + },] + ); } } diff --git a/src/bootstrap/cache.rs b/src/bootstrap/cache.rs index d81c6bc28e527..bca5ff85ba23e 100644 --- a/src/bootstrap/cache.rs +++ b/src/bootstrap/cache.rs @@ -249,7 +249,7 @@ lazy_static! { pub struct Cache( RefCell, // actually a HashMap> + Box, // actually a HashMap> >> ); diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 3453933a9652c..04d576df95546 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -24,7 +24,7 @@ use Build; use config::Config; // The version number -pub const CFG_RELEASE_NUM: &str = "1.27.0"; +pub const CFG_RELEASE_NUM: &str = "1.29.0"; pub struct GitInfo { inner: Option, diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 64354ae29aa24..8838cdeed8687 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -12,7 +12,7 @@ use compile::{run_cargo, std_cargo, test_cargo, rustc_cargo, rustc_cargo_env, add_to_sysroot}; use builder::{RunConfig, Builder, ShouldRun, Step}; -use tool::{self, prepare_tool_cargo}; +use tool::{self, prepare_tool_cargo, SourceType}; use {Compiler, Mode}; use cache::{INTERNER, Interned}; use std::path::PathBuf; @@ -40,10 +40,10 @@ impl Step for Std { let target = self.target; let compiler = builder.compiler(0, builder.config.build); - let out_dir = builder.stage_out(compiler, Mode::Libstd); + let out_dir = builder.stage_out(compiler, Mode::Std); builder.clear_if_dirty(&out_dir, &builder.rustc(compiler)); - let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Std, target, "check"); std_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); @@ -87,11 +87,11 @@ impl Step for Rustc { let compiler = builder.compiler(0, builder.config.build); let target = self.target; - let stage_out = builder.stage_out(compiler, Mode::Librustc); + let stage_out = builder.stage_out(compiler, Mode::Rustc); builder.clear_if_dirty(&stage_out, &libstd_stamp(builder, compiler, target)); builder.clear_if_dirty(&stage_out, &libtest_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "check"); rustc_cargo(builder, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage)); @@ -118,7 +118,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.all_krates("rustc_trans") + run.all_krates("rustc_codegen_llvm") } fn make_run(run: RunConfig) { @@ -137,14 +137,14 @@ impl Step for CodegenBackend { let target = self.target; let backend = self.backend; - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "check"); let features = builder.rustc_features().to_string(); - cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_trans/Cargo.toml")); + cargo.arg("--manifest-path").arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); rustc_cargo_env(builder, &mut cargo); // We won't build LLVM if it's not available, as it shouldn't affect `check`. - let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); run_cargo(builder, cargo.arg("--features").arg(features), &codegen_backend_stamp(builder, compiler, target, backend), @@ -175,10 +175,10 @@ impl Step for Test { let compiler = builder.compiler(0, builder.config.build); let target = self.target; - let out_dir = builder.stage_out(compiler, Mode::Libtest); + let out_dir = builder.stage_out(compiler, Mode::Test); builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "check"); + let mut cargo = builder.cargo(compiler, Mode::Test, target, "check"); test_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); @@ -219,9 +219,11 @@ impl Step for Rustdoc { let mut cargo = prepare_tool_cargo(builder, compiler, + Mode::ToolRustc, target, "check", - "src/tools/rustdoc"); + "src/tools/rustdoc", + SourceType::InTree); let _folder = builder.fold_output(|| format!("stage{}-rustdoc", compiler.stage)); println!("Checking rustdoc artifacts ({} -> {})", &compiler.host, target); @@ -236,7 +238,7 @@ impl Step for Rustdoc { builder.ensure(tool::CleanTools { compiler, target, - mode: Mode::Tool, + cause: Mode::Rustc, }); } } @@ -244,33 +246,34 @@ impl Step for Rustdoc { /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd-check.stamp") + builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest-check.stamp") + builder.cargo_out(compiler, Mode::Test, target).join(".libtest-check.stamp") } /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc-check.stamp") + builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc-check.stamp") } -/// Cargo's output path for librustc_trans in a given stage, compiled by a particular +/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular /// compiler for the specified target and backend. fn codegen_backend_stamp(builder: &Builder, compiler: Compiler, target: Interned, backend: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Librustc, target) - .join(format!(".librustc_trans-{}-check.stamp", backend)) + builder.cargo_out(compiler, Mode::Codegen, target) + .join(format!(".librustc_codegen_llvm-{}-check.stamp", backend)) } /// Cargo's output path for rustdoc in a given stage, compiled by a particular /// compiler for the specified target. pub fn rustdoc_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Tool, target).join(".rustdoc-check.stamp") + builder.cargo_out(compiler, Mode::ToolRustc, target) + .join(".rustdoc-check.stamp") } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 1248c2b50be5e..04e8e133b03a1 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -24,7 +24,6 @@ use std::io::prelude::*; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::str; -use std::cmp::min; use build_helper::{output, mtime, up_to_date}; use filetime::FileTime; @@ -68,6 +67,16 @@ impl Step for Std { let target = self.target; let compiler = self.compiler; + if builder.config.keep_stage.contains(&compiler.stage) { + builder.info("Warning: Using a potentially old libstd. This may not behave well."); + builder.ensure(StdLink { + compiler: compiler, + target_compiler: compiler, + target, + }); + return; + } + builder.ensure(StartupObjects { compiler, target }); if builder.force_use_stage1(compiler, target) { @@ -98,9 +107,9 @@ impl Step for Std { copy_musl_third_party_objects(builder, target, &libdir); } - let out_dir = builder.cargo_out(compiler, Mode::Libstd, target); + let out_dir = builder.cargo_out(compiler, Mode::Std, target); builder.clear_if_dirty(&out_dir, &builder.rustc(compiler)); - let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Std, target, "build"); std_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-std", compiler.stage)); @@ -240,7 +249,7 @@ impl Step for StdLink { builder.ensure(tool::CleanTools { compiler: target_compiler, target, - mode: Mode::Libstd, + cause: Mode::Std, }); } } @@ -353,6 +362,16 @@ impl Step for Test { builder.ensure(Std { compiler, target }); + if builder.config.keep_stage.contains(&compiler.stage) { + builder.info("Warning: Using a potentially old libtest. This may not behave well."); + builder.ensure(TestLink { + compiler: compiler, + target_compiler: compiler, + target, + }); + return; + } + if builder.force_use_stage1(compiler, target) { builder.ensure(Test { compiler: builder.compiler(1, builder.config.build), @@ -368,9 +387,9 @@ impl Step for Test { return; } - let out_dir = builder.cargo_out(compiler, Mode::Libtest, target); + let out_dir = builder.cargo_out(compiler, Mode::Test, target); builder.clear_if_dirty(&out_dir, &libstd_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Test, target, "build"); test_cargo(builder, &compiler, target, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-test", compiler.stage)); @@ -431,7 +450,7 @@ impl Step for TestLink { builder.ensure(tool::CleanTools { compiler: target_compiler, target, - mode: Mode::Libtest, + cause: Mode::Test, }); } } @@ -469,6 +488,16 @@ impl Step for Rustc { builder.ensure(Test { compiler, target }); + if builder.config.keep_stage.contains(&compiler.stage) { + builder.info("Warning: Using a potentially old librustc. This may not behave well."); + builder.ensure(RustcLink { + compiler: compiler, + target_compiler: compiler, + target, + }); + return; + } + if builder.force_use_stage1(compiler, target) { builder.ensure(Rustc { compiler: builder.compiler(1, builder.config.build), @@ -489,11 +518,11 @@ impl Step for Rustc { compiler: builder.compiler(self.compiler.stage, builder.config.build), target: builder.config.build, }); - let cargo_out = builder.cargo_out(compiler, Mode::Librustc, target); + let cargo_out = builder.cargo_out(compiler, Mode::Rustc, target); builder.clear_if_dirty(&cargo_out, &libstd_stamp(builder, compiler, target)); builder.clear_if_dirty(&cargo_out, &libtest_stamp(builder, compiler, target)); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "build"); rustc_cargo(builder, &mut cargo); let _folder = builder.fold_output(|| format!("stage{}-rustc", compiler.stage)); @@ -585,7 +614,7 @@ impl Step for RustcLink { builder.ensure(tool::CleanTools { compiler: target_compiler, target, - mode: Mode::Librustc, + cause: Mode::Rustc, }); } } @@ -603,7 +632,7 @@ impl Step for CodegenBackend { const DEFAULT: bool = true; fn should_run(run: ShouldRun) -> ShouldRun { - run.all_krates("rustc_trans") + run.all_krates("rustc_codegen_llvm") } fn make_run(run: RunConfig) { @@ -625,6 +654,14 @@ impl Step for CodegenBackend { builder.ensure(Rustc { compiler, target }); + if builder.config.keep_stage.contains(&compiler.stage) { + builder.info("Warning: Using a potentially old codegen backend. \ + This may not behave well."); + // Codegen backends are linked separately from this step today, so we don't do + // anything here. + return; + } + if builder.force_use_stage1(compiler, target) { builder.ensure(CodegenBackend { compiler: builder.compiler(1, builder.config.build), @@ -634,18 +671,18 @@ impl Step for CodegenBackend { return; } - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "build"); + let mut cargo = builder.cargo(compiler, Mode::Codegen, target, "build"); let mut features = builder.rustc_features().to_string(); cargo.arg("--manifest-path") - .arg(builder.src.join("src/librustc_trans/Cargo.toml")); + .arg(builder.src.join("src/librustc_codegen_llvm/Cargo.toml")); rustc_cargo_env(builder, &mut cargo); features += &build_codegen_backend(&builder, &mut cargo, &compiler, target, backend); - let tmp_stamp = builder.cargo_out(compiler, Mode::Librustc, target) + let tmp_stamp = builder.cargo_out(compiler, Mode::Codegen, target) .join(".tmp.stamp"); - let _folder = builder.fold_output(|| format!("stage{}-rustc_trans", compiler.stage)); + let _folder = builder.fold_output(|| format!("stage{}-rustc_codegen_llvm", compiler.stage)); let files = run_cargo(builder, cargo.arg("--features").arg(features), &tmp_stamp, @@ -656,7 +693,7 @@ impl Step for CodegenBackend { let mut files = files.into_iter() .filter(|f| { let filename = f.file_name().unwrap().to_str().unwrap(); - is_dylib(filename) && filename.contains("rustc_trans-") + is_dylib(filename) && filename.contains("rustc_codegen_llvm-") }); let codegen_backend = match files.next() { Some(f) => f, @@ -697,7 +734,7 @@ pub fn build_codegen_backend(builder: &Builder, compiler.stage, &compiler.host, target, backend)); // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_trans. + // librustc_llvm and librustc_codegen_llvm. if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } @@ -762,7 +799,7 @@ fn copy_codegen_backends_to_sysroot(builder: &Builder, t!(t!(File::open(&stamp)).read_to_string(&mut dylib)); let file = Path::new(&dylib); let filename = file.file_name().unwrap().to_str().unwrap(); - // change `librustc_trans-xxxxxx.so` to `librustc_trans-llvm.so` + // change `librustc_codegen_llvm-xxxxxx.so` to `librustc_codegen_llvm-llvm.so` let target_filename = { let dash = filename.find("-").unwrap(); let dot = filename.find(".").unwrap(); @@ -786,36 +823,39 @@ fn copy_lld_to_sysroot(builder: &Builder, .join("bin"); t!(fs::create_dir_all(&dst)); - let exe = exe("lld", &target); - builder.copy(&lld_install_root.join("bin").join(&exe), &dst.join(&exe)); + let src_exe = exe("lld", &target); + let dst_exe = exe("rust-lld", &target); + // we prepend this bin directory to the user PATH when linking Rust binaries. To + // avoid shadowing the system LLD we rename the LLD we provide to `rust-lld`. + builder.copy(&lld_install_root.join("bin").join(&src_exe), &dst.join(&dst_exe)); } /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. pub fn libstd_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Libstd, target).join(".libstd.stamp") + builder.cargo_out(compiler, Mode::Std, target).join(".libstd.stamp") } /// Cargo's output path for libtest in a given stage, compiled by a particular /// compiler for the specified target. pub fn libtest_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Libtest, target).join(".libtest.stamp") + builder.cargo_out(compiler, Mode::Test, target).join(".libtest.stamp") } /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. pub fn librustc_stamp(builder: &Builder, compiler: Compiler, target: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Librustc, target).join(".librustc.stamp") + builder.cargo_out(compiler, Mode::Rustc, target).join(".librustc.stamp") } -/// Cargo's output path for librustc_trans in a given stage, compiled by a particular +/// Cargo's output path for librustc_codegen_llvm in a given stage, compiled by a particular /// compiler for the specified target and backend. fn codegen_backend_stamp(builder: &Builder, compiler: Compiler, target: Interned, backend: Interned) -> PathBuf { - builder.cargo_out(compiler, Mode::Librustc, target) - .join(format!(".librustc_trans-{}.stamp", backend)) + builder.cargo_out(compiler, Mode::Codegen, target) + .join(format!(".librustc_codegen_llvm-{}.stamp", backend)) } pub fn compiler_file(builder: &Builder, @@ -873,7 +913,7 @@ impl Step for Assemble { type Output = Compiler; fn should_run(run: ShouldRun) -> ShouldRun { - run.all_krates("rustc-main") + run.never() } /// Prepare a new compiler from the artifacts in `stage` @@ -915,28 +955,16 @@ impl Step for Assemble { // link to these. (FIXME: Is that correct? It seems to be correct most // of the time but I think we do link to these for stage2/bin compilers // when not performing a full bootstrap). - if builder.config.keep_stage.map_or(false, |s| target_compiler.stage <= s) { - builder.verbose("skipping compilation of compiler due to --keep-stage"); - let compiler = build_compiler; - for stage in 0..min(target_compiler.stage, builder.config.keep_stage.unwrap()) { - let target_compiler = builder.compiler(stage, target_compiler.host); - let target = target_compiler.host; - builder.ensure(StdLink { compiler, target_compiler, target }); - builder.ensure(TestLink { compiler, target_compiler, target }); - builder.ensure(RustcLink { compiler, target_compiler, target }); - } - } else { - builder.ensure(Rustc { + builder.ensure(Rustc { + compiler: build_compiler, + target: target_compiler.host, + }); + for &backend in builder.config.rust_codegen_backends.iter() { + builder.ensure(CodegenBackend { compiler: build_compiler, target: target_compiler.host, + backend, }); - for &backend in builder.config.rust_codegen_backends.iter() { - builder.ensure(CodegenBackend { - compiler: build_compiler, - target: target_compiler.host, - backend, - }); - } } let lld_install = if builder.config.lld_enabled { @@ -971,8 +999,8 @@ impl Step for Assemble { } // Link the compiler binary itself into place - let out_dir = builder.cargo_out(build_compiler, Mode::Librustc, host); - let rustc = out_dir.join(exe("rustc", &*host)); + let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); + let rustc = out_dir.join(exe("rustc_binary", &*host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); let compiler = builder.rustc(target_compiler); @@ -1049,7 +1077,7 @@ pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: !filename.ends_with(".lib") && !is_dylib(&filename) && !(is_check && filename.ends_with(".rmeta")) { - return; + continue; } let filename = Path::new(&*filename); @@ -1057,14 +1085,14 @@ pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: // If this was an output file in the "host dir" we don't actually // worry about it, it's not relevant for us. if filename.starts_with(&host_root_dir) { - return; + continue; } // If this was output in the `deps` dir then this is a precise file // name (hash included) so we start tracking it. if filename.starts_with(&target_deps_dir) { deps.push(filename.to_path_buf()); - return; + continue; } // Otherwise this was a "top level artifact" which right now doesn't @@ -1163,7 +1191,7 @@ pub fn run_cargo(builder: &Builder, cargo: &mut Command, stamp: &Path, is_check: pub fn stream_cargo( builder: &Builder, cargo: &mut Command, - cb: &mut FnMut(CargoMessage), + cb: &mut dyn FnMut(CargoMessage), ) -> bool { if builder.config.dry_run { return true; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 6dd6291be2397..0a8a5c87d0da1 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -23,7 +23,6 @@ use std::cmp; use num_cpus; use toml; -use util::exe; use cache::{INTERNER, Interned}; use flags::Flags; pub use flags::Subcommand; @@ -64,7 +63,7 @@ pub struct Config { pub on_fail: Option, pub stage: Option, - pub keep_stage: Option, + pub keep_stage: Vec, pub src: PathBuf, pub jobs: Option, pub cmd: Subcommand, @@ -82,11 +81,13 @@ pub struct Config { pub llvm_version_check: bool, pub llvm_static_stdcpp: bool, pub llvm_link_shared: bool, + pub llvm_clang_cl: Option, pub llvm_targets: Option, pub llvm_experimental_targets: String, pub llvm_link_jobs: Option, pub lld_enabled: bool, + pub llvm_tools_enabled: bool, // rust codegen options pub rust_optimize: bool, @@ -104,6 +105,7 @@ pub struct Config { pub rust_dist_src: bool, pub rust_codegen_backends: Vec>, pub rust_codegen_backends_dir: String, + pub rust_verify_llvm_ir: bool, pub build: Interned, pub hosts: Vec>, @@ -124,7 +126,7 @@ pub struct Config { // misc pub low_priority: bool, pub channel: String, - pub quiet_tests: bool, + pub verbose_tests: bool, pub test_miri: bool, pub save_toolstates: Option, pub print_step_timings: bool, @@ -250,6 +252,7 @@ struct Llvm { experimental_targets: Option, link_jobs: Option, link_shared: Option, + clang_cl: Option } #[derive(Deserialize, Default, Clone)] @@ -299,15 +302,18 @@ struct Rust { ignore_git: Option, debug: Option, dist_src: Option, - quiet_tests: Option, + verbose_tests: Option, test_miri: Option, + incremental: Option, save_toolstates: Option, codegen_backends: Option>, codegen_backends_dir: Option, wasm_syscall: Option, lld: Option, + llvm_tools: Option, deny_warnings: Option, backtrace_on_ice: Option, + verify_llvm_ir: Option, } /// TOML representation of how each build target is configured. @@ -362,9 +368,8 @@ impl Config { config.src = Config::path_from_python("SRC"); config.out = Config::path_from_python("BUILD_DIR"); - let stage0_root = config.out.join(&config.build).join("stage0/bin"); - config.initial_rustc = stage0_root.join(exe("rustc", &config.build)); - config.initial_cargo = stage0_root.join(exe("cargo", &config.build)); + config.initial_rustc = Config::path_from_python("RUSTC"); + config.initial_cargo = Config::path_from_python("CARGO"); config } @@ -504,6 +509,7 @@ impl Config { config.llvm_experimental_targets = llvm.experimental_targets.clone() .unwrap_or("WebAssembly".to_string()); config.llvm_link_jobs = llvm.link_jobs; + config.llvm_clang_cl = llvm.clang_cl.clone(); } if let Some(ref rust) = toml.rust { @@ -524,16 +530,22 @@ impl Config { set(&mut config.backtrace, rust.backtrace); set(&mut config.channel, rust.channel.clone()); set(&mut config.rust_dist_src, rust.dist_src); - set(&mut config.quiet_tests, rust.quiet_tests); + set(&mut config.verbose_tests, rust.verbose_tests); set(&mut config.test_miri, rust.test_miri); + // in the case "false" is set explicitly, do not overwrite the command line args + if let Some(true) = rust.incremental { + config.incremental = true; + } set(&mut config.wasm_syscall, rust.wasm_syscall); set(&mut config.lld_enabled, rust.lld); + set(&mut config.llvm_tools_enabled, rust.llvm_tools); config.rustc_parallel_queries = rust.experimental_parallel_queries.unwrap_or(false); config.rustc_default_linker = rust.default_linker.clone(); config.musl_root = rust.musl_root.clone().map(PathBuf::from); config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings)); set(&mut config.backtrace_on_ice, rust.backtrace_on_ice); + set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir); if let Some(ref backends) = rust.codegen_backends { config.rust_codegen_backends = backends.iter() diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index 3574b7d210a2d..9fdba044f4be3 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -47,7 +47,7 @@ def v(*args): o("experimental-parallel-queries", "rust.experimental-parallel-queries", "build rustc with experimental parallelization") o("test-miri", "rust.test-miri", "run miri's test suite") o("debuginfo-tests", "rust.debuginfo-tests", "build tests with debugger metadata") -o("quiet-tests", "rust.quiet-tests", "enable quieter output when running tests") +o("verbose-tests", "rust.verbose-tests", "enable verbose output when running tests") o("ccache", "llvm.ccache", "invoke gcc/clang via ccache to reuse object files between builds") o("sccache", None, "invoke gcc/clang via sccache to reuse object files between builds") o("local-rust", None, "use an installed rustc rather than downloading a snapshot") @@ -335,6 +335,7 @@ def set(key, value): elif option.name == 'full-tools': set('rust.codegen-backends', ['llvm', 'emscripten']) set('rust.lld', True) + set('rust.llvm-tools', True) set('build.extended', True) elif option.name == 'option-checking': # this was handled above @@ -431,7 +432,7 @@ def configure_section(lines, config): # order that we read it in. p("") p("writing `config.toml` in current directory") -with open('config.toml', 'w') as f: +with bootstrap.output('config.toml') as f: for section in section_order: if section == 'target': for target in targets: @@ -441,7 +442,7 @@ def configure_section(lines, config): for line in sections[section]: f.write(line + "\n") -with open('Makefile', 'w') as f: +with bootstrap.output('Makefile') as f: contents = os.path.join(rust_dir, 'src', 'bootstrap', 'mk', 'Makefile.in') contents = open(contents).read() contents = contents.replace("$(CFG_SRC_DIR)", rust_dir + '/') diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index e21a59390b7b6..7b4808ef018f7 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -26,7 +26,7 @@ use std::process::{Command, Stdio}; use build_helper::output; -use {Compiler, Mode}; +use {Compiler, Mode, LLVM_TOOLS}; use channel; use util::{libdir, is_dylib, exe}; use builder::{Builder, RunConfig, ShouldRun, Step}; @@ -41,8 +41,12 @@ pub fn pkgname(builder: &Builder, component: &str) -> String { format!("{}-{}", component, builder.cargo_package_vers()) } else if component == "rls" { format!("{}-{}", component, builder.rls_package_vers()) + } else if component == "clippy" { + format!("{}-{}", component, builder.clippy_package_vers()) } else if component == "rustfmt" { format!("{}-{}", component, builder.rustfmt_package_vers()) + } else if component == "llvm-tools" { + format!("{}-{}", component, builder.llvm_tools_package_vers()) } else { assert!(component.starts_with("rust")); format!("{}-{}", component, builder.rust_package_vers()) @@ -304,6 +308,14 @@ fn make_win_dist( builder.copy_to_folder(&src, &target_bin_dir); } + // Warn windows-gnu users that the bundled GCC cannot compile C files + builder.create( + &target_bin_dir.join("GCC-WARNING.txt"), + "gcc.exe contained in this folder cannot be used for compiling C files - it is only\ + used as a linker. In order to be able to compile projects containing C code use\ + the GCC provided by MinGW or Cygwin." + ); + //Copy platform libs to platform-specific lib directory let target_lib_dir = plat_root.join("lib").join("rustlib").join(target_triple).join("lib"); fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed"); @@ -394,7 +406,7 @@ impl Step for Rustc { let compiler = self.compiler; let host = self.compiler.host; - builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, compiler.host)); + builder.info(&format!("Dist rustc stage{} ({})", compiler.stage, host)); let name = pkgname(builder, "rustc"); let image = tmpdir(builder).join(format!("{}-{}-image", name, host)); let _ = fs::remove_dir_all(&image); @@ -489,12 +501,13 @@ impl Step for Rustc { // Copy over lld if it's there if builder.config.lld_enabled { - let exe = exe("lld", &compiler.host); + let exe = exe("rust-lld", &compiler.host); let src = builder.sysroot_libdir(compiler, host) .parent() .unwrap() .join("bin") .join(&exe); + // for the rationale about this rename check `compile::copy_lld_to_sysroot` let dst = image.join("lib/rustlib") .join(&*host) .join("bin") @@ -722,7 +735,7 @@ impl Step for Analysis { let image = tmpdir(builder).join(format!("{}-{}-image", name, target)); - let src = builder.stage_out(compiler, Mode::Libstd) + let src = builder.stage_out(compiler, Mode::Std) .join(target).join(builder.cargo_dir()).join("deps"); let image_src = src.join("save-analysis"); @@ -951,13 +964,16 @@ impl Step for PlainSourceTarball { has_cargo_vendor |= line.starts_with("cargo-vendor "); } if !has_cargo_vendor { - let mut cmd = Command::new(&builder.initial_cargo); - cmd.arg("install") - .arg("--force") + let mut cmd = builder.cargo( + builder.compiler(0, builder.config.build), + Mode::ToolBootstrap, + builder.config.build, + "install" + ); + cmd.arg("--force") .arg("--debug") .arg("--vers").arg(CARGO_VENDOR_VERSION) - .arg("cargo-vendor") - .env("RUSTC", &builder.initial_rustc); + .arg("cargo-vendor"); if let Some(dir) = builder.openssl_install_dir(builder.config.build) { builder.ensure(native::Openssl { target: builder.config.build, @@ -1178,6 +1194,87 @@ impl Step for Rls { } } +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Clippy { + pub stage: u32, + pub target: Interned, +} + +impl Step for Clippy { + type Output = Option; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("clippy") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Clippy { + stage: run.builder.top_stage, + target: run.target, + }); + } + + fn run(self, builder: &Builder) -> Option { + let stage = self.stage; + let target = self.target; + assert!(builder.config.extended); + + builder.info(&format!("Dist clippy stage{} ({})", stage, target)); + let src = builder.src.join("src/tools/clippy"); + let release_num = builder.release_num("clippy"); + let name = pkgname(builder, "clippy"); + let version = builder.clippy_info.version(builder, &release_num); + + let tmp = tmpdir(builder); + let image = tmp.join("clippy-image"); + drop(fs::remove_dir_all(&image)); + builder.create_dir(&image); + + // Prepare the image directory + // We expect clippy to build, because we've exited this step above if tool + // state for clippy isn't testing. + let clippy = builder.ensure(tool::Clippy { + compiler: builder.compiler(stage, builder.config.build), + target, extra_features: Vec::new() + }).or_else(|| { println!("Unable to build clippy, skipping dist"); None })?; + let cargoclippy = builder.ensure(tool::CargoClippy { + compiler: builder.compiler(stage, builder.config.build), + target, extra_features: Vec::new() + }).or_else(|| { println!("Unable to build cargo clippy, skipping dist"); None })?; + + builder.install(&clippy, &image.join("bin"), 0o755); + builder.install(&cargoclippy, &image.join("bin"), 0o755); + let doc = image.join("share/doc/clippy"); + builder.install(&src.join("README.md"), &doc, 0o644); + builder.install(&src.join("LICENSE"), &doc, 0o644); + + // Prepare the overlay + let overlay = tmp.join("clippy-overlay"); + drop(fs::remove_dir_all(&overlay)); + t!(fs::create_dir_all(&overlay)); + builder.install(&src.join("README.md"), &overlay, 0o644); + builder.install(&src.join("LICENSE"), &doc, 0o644); + builder.create(&overlay.join("version"), &version); + + // Generate the installer tarball + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=clippy-ready-to-serve.") + .arg("--image-dir").arg(&image) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) + .arg("--non-installed-overlay").arg(&overlay) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=clippy-preview"); + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) + } +} #[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] pub struct Rustfmt { @@ -1298,6 +1395,8 @@ impl Step for Extended { let cargo_installer = builder.ensure(Cargo { stage, target }); let rustfmt_installer = builder.ensure(Rustfmt { stage, target }); let rls_installer = builder.ensure(Rls { stage, target }); + let llvm_tools_installer = builder.ensure(LlvmTools { stage, target }); + let clippy_installer = builder.ensure(Clippy { stage, target }); let mingw_installer = builder.ensure(Mingw { host: target }); let analysis_installer = builder.ensure(Analysis { compiler: builder.compiler(stage, self.host), @@ -1334,7 +1433,9 @@ impl Step for Extended { tarballs.push(rustc_installer); tarballs.push(cargo_installer); tarballs.extend(rls_installer.clone()); + tarballs.extend(clippy_installer.clone()); tarballs.extend(rustfmt_installer.clone()); + tarballs.extend(llvm_tools_installer.clone()); tarballs.push(analysis_installer); tarballs.push(std_installer); if builder.config.docs { @@ -1402,6 +1503,9 @@ impl Step for Extended { if rls_installer.is_none() { contents = filter(&contents, "rls"); } + if clippy_installer.is_none() { + contents = filter(&contents, "clippy"); + } if rustfmt_installer.is_none() { contents = filter(&contents, "rustfmt"); } @@ -1439,6 +1543,9 @@ impl Step for Extended { if rls_installer.is_some() { prepare("rls"); } + if clippy_installer.is_some() { + prepare("clippy"); + } // create an 'uninstall' package builder.install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755); @@ -1467,6 +1574,8 @@ impl Step for Extended { format!("{}-{}", name, target) } else if name == "rls" { "rls-preview".to_string() + } else if name == "clippy" { + "clippy-preview".to_string() } else { name.to_string() }; @@ -1483,6 +1592,9 @@ impl Step for Extended { if rls_installer.is_some() { prepare("rls"); } + if clippy_installer.is_some() { + prepare("clippy"); + } if target.contains("windows-gnu") { prepare("rust-mingw"); } @@ -1563,6 +1675,18 @@ impl Step for Extended { .arg("-out").arg(exe.join("RlsGroup.wxs")) .arg("-t").arg(etc.join("msi/remove-duplicates.xsl"))); } + if clippy_installer.is_some() { + builder.run(Command::new(&heat) + .current_dir(&exe) + .arg("dir") + .arg("clippy") + .args(&heat_flags) + .arg("-cg").arg("ClippyGroup") + .arg("-dr").arg("Clippy") + .arg("-var").arg("var.ClippyDir") + .arg("-out").arg(exe.join("ClippyGroup.wxs")) + .arg("-t").arg(etc.join("msi/remove-duplicates.xsl"))); + } builder.run(Command::new(&heat) .current_dir(&exe) .arg("dir") @@ -1605,6 +1729,9 @@ impl Step for Extended { if rls_installer.is_some() { cmd.arg("-dRlsDir=rls"); } + if clippy_installer.is_some() { + cmd.arg("-dClippyDir=clippy"); + } if target.contains("windows-gnu") { cmd.arg("-dGccDir=rust-mingw"); } @@ -1620,6 +1747,9 @@ impl Step for Extended { if rls_installer.is_some() { candle("RlsGroup.wxs".as_ref()); } + if clippy_installer.is_some() { + candle("ClippyGroup.wxs".as_ref()); + } candle("AnalysisGroup.wxs".as_ref()); if target.contains("windows-gnu") { @@ -1649,6 +1779,9 @@ impl Step for Extended { if rls_installer.is_some() { cmd.arg("RlsGroup.wixobj"); } + if clippy_installer.is_some() { + cmd.arg("ClippyGroup.wixobj"); + } if target.contains("windows-gnu") { cmd.arg("GccGroup.wixobj"); @@ -1734,7 +1867,9 @@ impl Step for HashSign { cmd.arg(builder.rust_package_vers()); cmd.arg(builder.package_vers(&builder.release_num("cargo"))); cmd.arg(builder.package_vers(&builder.release_num("rls"))); + cmd.arg(builder.package_vers(&builder.release_num("clippy"))); cmd.arg(builder.package_vers(&builder.release_num("rustfmt"))); + cmd.arg(builder.llvm_tools_package_vers()); cmd.arg(addr); builder.create_dir(&distdir(builder)); @@ -1745,3 +1880,87 @@ impl Step for HashSign { assert!(status.success()); } } + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct LlvmTools { + pub stage: u32, + pub target: Interned, +} + +impl Step for LlvmTools { + type Output = Option; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.path("llvm-tools") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(LlvmTools { + stage: run.builder.top_stage, + target: run.target, + }); + } + + fn run(self, builder: &Builder) -> Option { + let stage = self.stage; + let target = self.target; + assert!(builder.config.extended); + + /* run only if llvm-config isn't used */ + if let Some(config) = builder.config.target_config.get(&target) { + if let Some(ref _s) = config.llvm_config { + builder.info(&format!("Skipping LlvmTools stage{} ({}): external LLVM", + stage, target)); + return None; + } + } + + builder.info(&format!("Dist LlvmTools stage{} ({})", stage, target)); + let src = builder.src.join("src/llvm"); + let name = pkgname(builder, "llvm-tools"); + + let tmp = tmpdir(builder); + let image = tmp.join("llvm-tools-image"); + drop(fs::remove_dir_all(&image)); + + // Prepare the image directory + let bindir = builder + .llvm_out(target) + .join("bin"); + let dst = image.join("lib/rustlib") + .join(target) + .join("bin"); + t!(fs::create_dir_all(&dst)); + for tool in LLVM_TOOLS { + let exe = bindir.join(exe(tool, &target)); + builder.install(&exe, &dst, 0o755); + } + + // Prepare the overlay + let overlay = tmp.join("llvm-tools-overlay"); + drop(fs::remove_dir_all(&overlay)); + builder.create_dir(&overlay); + builder.install(&src.join("README.txt"), &overlay, 0o644); + builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644); + builder.create(&overlay.join("version"), &builder.llvm_tools_vers()); + + // Generate the installer tarball + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=llvm-tools-installed.") + .arg("--image-dir").arg(&image) + .arg("--work-dir").arg(&tmpdir(builder)) + .arg("--output-dir").arg(&distdir(builder)) + .arg("--non-installed-overlay").arg(&overlay) + .arg(format!("--package-name={}-{}", name, target)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=llvm-tools-preview"); + + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target))) + } +} diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 16f4b29dcceef..fd3730ffc78de 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -28,7 +28,7 @@ use build_helper::up_to_date; use util::symlink_dir; use builder::{Builder, Compiler, RunConfig, ShouldRun, Step}; -use tool::Tool; +use tool::{self, prepare_tool_cargo, Tool, SourceType}; use compile; use cache::{INTERNER, Interned}; use config::Config; @@ -70,7 +70,7 @@ macro_rules! book { book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; - Rustdoc, "src/doc/rustdoc", "rustdoc"; + RustdocBook, "src/doc/rustdoc", "rustdoc"; RustcBook, "src/doc/rustc", "rustc"; RustByExample, "src/doc/rust-by-example", "rust-by-example"; ); @@ -272,6 +272,12 @@ impl Step for TheBook { name: INTERNER.intern_string(format!("{}/second-edition", name)), }); + // build book 2018 edition + builder.ensure(Rustbook { + target, + name: INTERNER.intern_string(format!("{}/2018-edition", name)), + }); + // build the version info page and CSS builder.ensure(Standalone { compiler, @@ -457,7 +463,7 @@ impl Step for Std { }; builder.ensure(compile::Std { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Libstd) + let out_dir = builder.stage_out(compiler, Mode::Std) .join(target).join("doc"); // Here what we're doing is creating a *symlink* (directory junction on @@ -477,7 +483,7 @@ impl Step for Std { builder.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - let mut cargo = builder.cargo(compiler, Mode::Libstd, target, "doc"); + let mut cargo = builder.cargo(compiler, Mode::Std, target, "doc"); compile::std_cargo(builder, &compiler, target, &mut cargo); // Keep a whitelist so we do not build internal stdlib crates, these will be @@ -540,7 +546,7 @@ impl Step for Test { builder.ensure(Std { stage, target }); builder.ensure(compile::Test { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Libtest) + let out_dir = builder.stage_out(compiler, Mode::Test) .join(target).join("doc"); // See docs in std above for why we symlink @@ -548,7 +554,7 @@ impl Step for Test { builder.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - let mut cargo = builder.cargo(compiler, Mode::Libtest, target, "doc"); + let mut cargo = builder.cargo(compiler, Mode::Test, target, "doc"); compile::test_cargo(builder, &compiler, target, &mut cargo); cargo.arg("--no-deps").arg("-p").arg("test"); @@ -608,7 +614,7 @@ impl Step for WhitelistedRustc { builder.ensure(Std { stage, target }); builder.ensure(compile::Rustc { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Librustc) + let out_dir = builder.stage_out(compiler, Mode::Rustc) .join(target).join("doc"); // See docs in std above for why we symlink @@ -616,7 +622,7 @@ impl Step for WhitelistedRustc { builder.clear_if_dirty(&my_out, &rustdoc); t!(symlink_dir_force(&builder.config, &my_out, &out_dir)); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); compile::rustc_cargo(builder, &mut cargo); // We don't want to build docs for internal compiler dependencies in this @@ -665,8 +671,12 @@ impl Step for Rustc { let stage = self.stage; let target = self.target; builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); + + // This is the intended out directory for compiler documentation. let out = builder.compiler_doc_out(target); t!(fs::create_dir_all(&out)); + + // Get the correct compiler for this stage. let compiler = builder.compiler(stage, builder.config.build); let rustdoc = builder.rustdoc(compiler.host); let compiler = if builder.force_use_stage1(compiler, target) { @@ -676,22 +686,24 @@ impl Step for Rustc { }; if !builder.config.compiler_docs { - builder.info(&format!("\tskipping - compiler docs disabled")); + builder.info(&format!("\tskipping - compiler/librustdoc docs disabled")); return; } - // Build libstd docs so that we generate relative links + // Build libstd docs so that we generate relative links. builder.ensure(Std { stage, target }); + // Build rustc. builder.ensure(compile::Rustc { compiler, target }); - let out_dir = builder.stage_out(compiler, Mode::Librustc) - .join(target).join("doc"); + // We do not symlink to the same shared folder that already contains std library // documentation from previous steps as we do not want to include that. + let out_dir = builder.stage_out(compiler, Mode::Rustc).join(target).join("doc"); builder.clear_if_dirty(&out, &rustdoc); t!(symlink_dir_force(&builder.config, &out, &out_dir)); - let mut cargo = builder.cargo(compiler, Mode::Librustc, target, "doc"); + // Build cargo command. + let mut cargo = builder.cargo(compiler, Mode::Rustc, target, "doc"); cargo.env("RUSTDOCFLAGS", "--document-private-items"); compile::rustc_cargo(builder, &mut cargo); @@ -729,6 +741,87 @@ fn find_compiler_crates( } } +#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct Rustdoc { + stage: u32, + target: Interned, +} + +impl Step for Rustdoc { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun) -> ShouldRun { + run.krate("rustdoc-tool") + } + + fn make_run(run: RunConfig) { + run.builder.ensure(Rustdoc { + stage: run.builder.top_stage, + target: run.target, + }); + } + + /// Generate compiler documentation. + /// + /// This will generate all documentation for compiler and dependencies. + /// Compiler documentation is distributed separately, so we make sure + /// we do not merge it with the other documentation from std, test and + /// proc_macros. This is largely just a wrapper around `cargo doc`. + fn run(self, builder: &Builder) { + let stage = self.stage; + let target = self.target; + builder.info(&format!("Documenting stage{} rustdoc ({})", stage, target)); + + // This is the intended out directory for compiler documentation. + let out = builder.compiler_doc_out(target); + t!(fs::create_dir_all(&out)); + + // Get the correct compiler for this stage. + let compiler = builder.compiler(stage, builder.config.build); + let rustdoc = builder.rustdoc(compiler.host); + let compiler = if builder.force_use_stage1(compiler, target) { + builder.compiler(1, compiler.host) + } else { + compiler + }; + + if !builder.config.compiler_docs { + builder.info(&format!("\tskipping - compiler/librustdoc docs disabled")); + return; + } + + // Build libstd docs so that we generate relative links. + builder.ensure(Std { stage, target }); + + // Build rustdoc. + builder.ensure(tool::Rustdoc { host: compiler.host }); + + // Symlink compiler docs to the output directory of rustdoc documentation. + let out_dir = builder.stage_out(compiler, Mode::ToolRustc) + .join(target) + .join("doc"); + t!(fs::create_dir_all(&out_dir)); + builder.clear_if_dirty(&out, &rustdoc); + t!(symlink_dir_force(&builder.config, &out, &out_dir)); + + // Build cargo command. + let mut cargo = prepare_tool_cargo( + builder, + compiler, + Mode::ToolRustc, + target, + "doc", + "src/tools/rustdoc", + SourceType::InTree, + ); + + cargo.env("RUSTDOCFLAGS", "--document-private-items"); + builder.run(&mut cargo); + } +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct ErrorIndex { target: Interned, diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 5315a3028ffa9..6a013053e580c 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -19,10 +19,10 @@ use std::process; use getopts::Options; -use {Build, DocTests}; +use builder::Builder; use config::Config; use metadata; -use builder::Builder; +use {Build, DocTests}; use cache::{Interned, INTERNER}; @@ -31,7 +31,7 @@ pub struct Flags { pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo pub on_fail: Option, pub stage: Option, - pub keep_stage: Option, + pub keep_stage: Vec, pub host: Vec>, pub target: Vec>, @@ -59,6 +59,9 @@ pub enum Subcommand { }, Test { paths: Vec, + /// Whether to automatically update stderr/stdout files + bless: bool, + compare_mode: Option, test_args: Vec, rustc_args: Vec, fail_fast: bool, @@ -90,7 +93,8 @@ impl Default for Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { let mut extra_help = String::new(); - let mut subcommand_help = format!("\ + let mut subcommand_help = format!( + "\ Usage: x.py [options] [...] Subcommands: @@ -103,7 +107,8 @@ Subcommands: dist Build distribution artifacts install Install distribution artifacts -To learn more about a subcommand, run `./x.py -h`"); +To learn more about a subcommand, run `./x.py -h`" + ); let mut opts = Options::new(); // Options common to all subcommands @@ -117,37 +122,43 @@ To learn more about a subcommand, run `./x.py -h`"); opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optflag("", "dry-run", "dry run; don't build anything"); opts.optopt("", "stage", "stage to build", "N"); - opts.optopt("", "keep-stage", "stage to keep without recompiling", "N"); + opts.optmulti("", "keep-stage", "stage(s) to keep without recompiling", "N"); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); opts.optopt("j", "jobs", "number of jobs to run in parallel", "JOBS"); opts.optflag("h", "help", "print this help message"); - opts.optopt("", "warnings", "if value is deny, will deny warnings, otherwise use default", - "VALUE"); + opts.optopt( + "", + "warnings", + "if value is deny, will deny warnings, otherwise use default", + "VALUE", + ); opts.optopt("", "error-format", "rustc error format", "FORMAT"); // fn usage() - let usage = |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { - println!("{}", opts.usage(subcommand_help)); - if !extra_help.is_empty() { - println!("{}", extra_help); - } - process::exit(exit_code); - }; + let usage = + |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; // We can't use getopt to parse the options until we have completed specifying which // options are valid, but under the current implementation, some options are conditional on // the subcommand. Therefore we must manually identify the subcommand first, so that we can // complete the definition of the options. Then we can use the getopt::Matches object from // there on out. - let subcommand = args.iter().find(|&s| + let subcommand = args.iter().find(|&s| { (s == "build") - || (s == "check") - || (s == "test") - || (s == "bench") - || (s == "doc") - || (s == "clean") - || (s == "dist") - || (s == "install")); + || (s == "check") + || (s == "test") + || (s == "bench") + || (s == "doc") + || (s == "clean") + || (s == "dist") + || (s == "install") + }); let subcommand = match subcommand { Some(s) => s, None => { @@ -162,7 +173,7 @@ To learn more about a subcommand, run `./x.py -h`"); // Some subcommands get extra options match subcommand.as_str() { - "test" => { + "test" => { opts.optflag("", "no-fail-fast", "Run all tests regardless of failure"); opts.optmulti("", "test-args", "extra arguments", "ARGS"); opts.optmulti( @@ -173,10 +184,25 @@ To learn more about a subcommand, run `./x.py -h`"); ); opts.optflag("", "no-doc", "do not run doc tests"); opts.optflag("", "doc", "only run doc tests"); - }, - "bench" => { opts.optmulti("", "test-args", "extra arguments", "ARGS"); }, - "clean" => { opts.optflag("", "all", "clean all build artifacts"); }, - _ => { }, + opts.optflag( + "", + "bless", + "update all stderr/stdout files of failing ui tests", + ); + opts.optopt( + "", + "compare-mode", + "mode describing what file the actual ui output will be compared to", + "COMPARE MODE", + ); + } + "bench" => { + opts.optmulti("", "test-args", "extra arguments", "ARGS"); + } + "clean" => { + opts.optflag("", "all", "clean all build artifacts"); + } + _ => {} }; // Done specifying what options are possible, so do the getopts parsing @@ -196,21 +222,24 @@ To learn more about a subcommand, run `./x.py -h`"); if check_subcommand != subcommand { pass_sanity_check = false; } - }, + } None => { pass_sanity_check = false; } } if !pass_sanity_check { println!("{}\n", subcommand_help); - println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ - You may need to move some options to after the subcommand.\n"); + println!( + "Sorry, I couldn't figure out which subcommand you were trying to specify.\n\ + You may need to move some options to after the subcommand.\n" + ); process::exit(1); } // Extra help text for some commands match subcommand.as_str() { "build" => { - subcommand_help.push_str("\n + subcommand_help.push_str( + "\n Arguments: This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: @@ -232,10 +261,12 @@ Arguments: This will first build everything once (like --stage 0 without further arguments would), and then use the compiler built in stage 0 to build src/libtest and its dependencies. - Once this is done, build/$ARCH/stage1 contains a usable compiler."); + Once this is done, build/$ARCH/stage1 contains a usable compiler.", + ); } "check" => { - subcommand_help.push_str("\n + subcommand_help.push_str( + "\n Arguments: This subcommand accepts a number of paths to directories to the crates and/or artifacts to compile. For example: @@ -247,10 +278,12 @@ Arguments: also that since we use `cargo check`, by default this will automatically enable incremental compilation, so there's no need to pass it separately, though it won't hurt. We also completely ignore the stage passed, as there's no way to compile in non-stage 0 without actually building - the compiler."); + the compiler.", + ); } "test" => { - subcommand_help.push_str("\n + subcommand_help.push_str( + "\n Arguments: This subcommand accepts a number of paths to directories to tests that should be compiled and run. For example: @@ -258,15 +291,19 @@ Arguments: ./x.py test src/test/run-pass ./x.py test src/libstd --test-args hash_map ./x.py test src/libstd --stage 0 + ./x.py test src/test/ui --bless + ./x.py test src/test/ui --compare-mode nll If no arguments are passed then the complete artifacts for that stage are compiled and tested. ./x.py test - ./x.py test --stage 1"); + ./x.py test --stage 1", + ); } "doc" => { - subcommand_help.push_str("\n + subcommand_help.push_str( + "\n Arguments: This subcommand accepts a number of paths to directories of documentation to build. For example: @@ -278,12 +315,16 @@ Arguments: If no arguments are passed then everything is documented: ./x.py doc - ./x.py doc --stage 1"); + ./x.py doc --stage 1", + ); } - _ => { } + _ => {} }; // Get any optional paths which occur after the subcommand - let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); + let paths = matches.free[1..] + .iter() + .map(|p| p.into()) + .collect::>(); let cfg_file = matches.opt_str("config").map(PathBuf::from).or_else(|| { if fs::metadata("config.toml").is_ok() { @@ -302,9 +343,12 @@ Arguments: let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); } else if subcommand.as_str() != "clean" { - extra_help.push_str(format!( - "Run `./x.py {} -h -v` to see a list of available paths.", - subcommand).as_str()); + extra_help.push_str( + format!( + "Run `./x.py {} -h -v` to see a list of available paths.", + subcommand + ).as_str(), + ); } // User passed in -h/--help? @@ -313,36 +357,28 @@ Arguments: } let cmd = match subcommand.as_str() { - "build" => { - Subcommand::Build { paths: paths } - } - "check" => { - Subcommand::Check { paths: paths } - } - "test" => { - Subcommand::Test { - paths, - test_args: matches.opt_strs("test-args"), - rustc_args: matches.opt_strs("rustc-args"), - fail_fast: !matches.opt_present("no-fail-fast"), - doc_tests: if matches.opt_present("doc") { - DocTests::Only - } else if matches.opt_present("no-doc") { - DocTests::No - } else { - DocTests::Yes - } - } - } - "bench" => { - Subcommand::Bench { - paths, - test_args: matches.opt_strs("test-args"), - } - } - "doc" => { - Subcommand::Doc { paths: paths } - } + "build" => Subcommand::Build { paths: paths }, + "check" => Subcommand::Check { paths: paths }, + "test" => Subcommand::Test { + paths, + bless: matches.opt_present("bless"), + compare_mode: matches.opt_str("compare-mode"), + test_args: matches.opt_strs("test-args"), + rustc_args: matches.opt_strs("rustc-args"), + fail_fast: !matches.opt_present("no-fail-fast"), + doc_tests: if matches.opt_present("doc") { + DocTests::Only + } else if matches.opt_present("no-doc") { + DocTests::No + } else { + DocTests::Yes + }, + }, + "bench" => Subcommand::Bench { + paths, + test_args: matches.opt_strs("test-args"), + }, + "doc" => Subcommand::Doc { paths: paths }, "clean" => { if paths.len() > 0 { println!("\nclean does not take a path argument\n"); @@ -353,39 +389,38 @@ Arguments: all: matches.opt_present("all"), } } - "dist" => { - Subcommand::Dist { - paths, - } - } - "install" => { - Subcommand::Install { - paths, - } - } + "dist" => Subcommand::Dist { paths }, + "install" => Subcommand::Install { paths }, _ => { usage(1, &opts, &subcommand_help, &extra_help); } }; - Flags { verbose: matches.opt_count("verbose"), stage: matches.opt_str("stage").map(|j| j.parse().unwrap()), dry_run: matches.opt_present("dry-run"), on_fail: matches.opt_str("on-fail"), rustc_error_format: matches.opt_str("error-format"), - keep_stage: matches.opt_str("keep-stage").map(|j| j.parse().unwrap()), + keep_stage: matches.opt_strs("keep-stage") + .into_iter().map(|j| j.parse().unwrap()) + .collect(), host: split(matches.opt_strs("host")) - .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), + .into_iter() + .map(|x| INTERNER.intern_string(x)) + .collect::>(), target: split(matches.opt_strs("target")) - .into_iter().map(|x| INTERNER.intern_string(x)).collect::>(), + .into_iter() + .map(|x| INTERNER.intern_string(x)) + .collect::>(), config: cfg_file, jobs: matches.opt_str("jobs").map(|j| j.parse().unwrap()), cmd, incremental: matches.opt_present("incremental"), exclude: split(matches.opt_strs("exclude")) - .into_iter().map(|p| p.into()).collect::>(), + .into_iter() + .map(|p| p.into()) + .collect::>(), warnings: matches.opt_str("warnings").map(|v| v == "deny"), } } @@ -394,9 +429,11 @@ Arguments: impl Subcommand { pub fn test_args(&self) -> Vec<&str> { match *self { - Subcommand::Test { ref test_args, .. } | - Subcommand::Bench { ref test_args, .. } => { - test_args.iter().flat_map(|s| s.split_whitespace()).collect() + Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => { + test_args + .iter() + .flat_map(|s| s.split_whitespace()) + .collect() } _ => Vec::new(), } @@ -404,9 +441,10 @@ impl Subcommand { pub fn rustc_args(&self) -> Vec<&str> { match *self { - Subcommand::Test { ref rustc_args, .. } => { - rustc_args.iter().flat_map(|s| s.split_whitespace()).collect() - } + Subcommand::Test { ref rustc_args, .. } => rustc_args + .iter() + .flat_map(|s| s.split_whitespace()) + .collect(), _ => Vec::new(), } } @@ -424,8 +462,27 @@ impl Subcommand { _ => DocTests::Yes, } } + + pub fn bless(&self) -> bool { + match *self { + Subcommand::Test { bless, .. } => bless, + _ => false, + } + } + + pub fn compare_mode(&self) -> Option<&str> { + match *self { + Subcommand::Test { + ref compare_mode, .. + } => compare_mode.as_ref().map(|s| &s[..]), + _ => None, + } + } } fn split(s: Vec) -> Vec { - s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect() + s.iter() + .flat_map(|s| s.split(',')) + .map(|s| s.to_string()) + .collect() } diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index b37a007e86390..cb28698aa3d6d 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -39,6 +39,9 @@ pub fn install_cargo(builder: &Builder, stage: u32, host: Interned) { pub fn install_rls(builder: &Builder, stage: u32, host: Interned) { install_sh(builder, "rls", "rls", stage, Some(host)); } +pub fn install_clippy(builder: &Builder, stage: u32, host: Interned) { + install_sh(builder, "clippy", "clippy", stage, Some(host)); +} pub fn install_rustfmt(builder: &Builder, stage: u32, host: Interned) { install_sh(builder, "rustfmt", "rustfmt", stage, Some(host)); @@ -72,7 +75,7 @@ fn install_sh( let libdir_default = PathBuf::from("lib"); let mandir_default = datadir_default.join("man"); let prefix = builder.config.prefix.as_ref().map_or(prefix_default, |p| { - fs::canonicalize(p).expect(&format!("could not canonicalize {}", p.display())) + fs::canonicalize(p).unwrap_or_else(|_| panic!("could not canonicalize {}", p.display())) }); let sysconfdir = builder.config.sysconfdir.as_ref().unwrap_or(&sysconfdir_default); let datadir = builder.config.datadir.as_ref().unwrap_or(&datadir_default); @@ -216,6 +219,14 @@ install!((self, builder, _config), builder.info(&format!("skipping Install RLS stage{} ({})", self.stage, self.target)); } }; + Clippy, "clippy", Self::should_build(_config), only_hosts: true, { + if builder.ensure(dist::Clippy { stage: self.stage, target: self.target }).is_some() || + Self::should_install(builder) { + install_clippy(builder, self.stage, self.target); + } else { + builder.info(&format!("skipping Install clippy stage{} ({})", self.stage, self.target)); + } + }; Rustfmt, "rustfmt", Self::should_build(_config), only_hosts: true, { if builder.ensure(dist::Rustfmt { stage: self.stage, target: self.target }).is_some() || Self::should_install(builder) { diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index e53fef0678613..1efff19dfb993 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -113,8 +113,10 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. +#![deny(bare_trait_objects)] #![deny(warnings)] #![feature(core_intrinsics)] +#![feature(drain_filter)] #[macro_use] extern crate build_helper; @@ -177,7 +179,7 @@ mod toolstate; #[cfg(windows)] mod job; -#[cfg(unix)] +#[cfg(all(unix, not(target_os = "haiku")))] mod job { use libc; @@ -188,7 +190,7 @@ mod job { } } -#[cfg(not(any(unix, windows)))] +#[cfg(any(target_os = "haiku", not(any(unix, windows))))] mod job { pub unsafe fn setup(_build: &mut ::Build) { } @@ -199,6 +201,15 @@ use flags::Subcommand; use cache::{Interned, INTERNER}; use toolstate::ToolState; +const LLVM_TOOLS: &[&str] = &[ + "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility + "llvm-objcopy", // used to transform ELFs into binary format which flashing tools consume + "llvm-objdump", // used to disassemble programs + "llvm-profdata", // used to inspect and merge files generated by profiles + "llvm-size", // used to prints the size of the linker sections of a program + "llvm-strip", // used to discard symbols from binary files to reduce their size +]; + /// A structure representing a Rust compiler. /// /// Each compiler has a `stage` that it is associated with and a `host` that @@ -240,6 +251,7 @@ pub struct Build { rust_info: channel::GitInfo, cargo_info: channel::GitInfo, rls_info: channel::GitInfo, + clippy_info: channel::GitInfo, rustfmt_info: channel::GitInfo, local_rebuild: bool, fail_fast: bool, @@ -280,7 +292,8 @@ pub struct Build { struct Crate { name: Interned, version: String, - deps: Vec>, + deps: HashSet>, + id: String, path: PathBuf, doc_step: String, build_step: String, @@ -307,16 +320,37 @@ impl Crate { #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum Mode { /// Build the standard library, placing output in the "stageN-std" directory. - Libstd, + Std, /// Build libtest, placing output in the "stageN-test" directory. - Libtest, + Test, + + /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory. + Rustc, + + /// Build codegen libraries, placing output in the "stageN-codegen" directory + Codegen, + + /// Build some tools, placing output in the "stageN-tools" directory. The + /// "other" here is for miscellaneous sets of tools that are built using the + /// bootstrap compiler in its entirety (target libraries and all). + /// Typically these tools compile with stable Rust. + ToolBootstrap, - /// Build librustc and compiler libraries, placing output in the "stageN-rustc" directory. - Librustc, + /// Compile a tool which uses all libraries we compile (up to rustc). + /// Doesn't use the stage0 compiler libraries like "other", and includes + /// tools like rustdoc, cargo, rls, etc. + ToolStd, + ToolRustc, +} - /// Build some tool, placing output in the "stageN-tools" directory. - Tool, +impl Mode { + pub fn is_tool(&self) -> bool { + match self { + Mode::ToolBootstrap | Mode::ToolRustc | Mode::ToolStd => true, + _ => false + } + } } impl Build { @@ -340,6 +374,7 @@ impl Build { let rust_info = channel::GitInfo::new(&config, &src); let cargo_info = channel::GitInfo::new(&config, &src.join("src/tools/cargo")); let rls_info = channel::GitInfo::new(&config, &src.join("src/tools/rls")); + let clippy_info = channel::GitInfo::new(&config, &src.join("src/tools/clippy")); let rustfmt_info = channel::GitInfo::new(&config, &src.join("src/tools/rustfmt")); let mut build = Build { @@ -361,6 +396,7 @@ impl Build { rust_info, cargo_info, rls_info, + clippy_info, rustfmt_info, cc: HashMap::new(), cxx: HashMap::new(), @@ -517,10 +553,13 @@ impl Build { /// The mode indicates what the root directory is for. fn stage_out(&self, compiler: Compiler, mode: Mode) -> PathBuf { let suffix = match mode { - Mode::Libstd => "-std", - Mode::Libtest => "-test", - Mode::Tool => "-tools", - Mode::Librustc => "-rustc", + Mode::Std => "-std", + Mode::Test => "-test", + Mode::Codegen => "-rustc", + Mode::Rustc => "-rustc", + Mode::ToolBootstrap => "-bootstrap-tools", + Mode::ToolStd => "-tools", + Mode::ToolRustc => "-tools", }; self.out.join(&*compiler.host) .join(format!("stage{}{}", compiler.stage, suffix)) @@ -592,12 +631,20 @@ impl Build { Path::new(llvm_bindir.trim()).join(exe("FileCheck", &*target)) } else { let base = self.llvm_out(self.config.build).join("build"); - let exe = exe("FileCheck", &*target); - if !self.config.ninja && self.config.build.contains("msvc") { - base.join("Release/bin").join(exe) + let base = if !self.config.ninja && self.config.build.contains("msvc") { + if self.config.llvm_optimize { + if self.config.llvm_release_debuginfo { + base.join("RelWithDebInfo") + } else { + base.join("Release") + } + } else { + base.join("Debug") + } } else { - base.join("bin").join(exe) - } + base + }; + base.join("bin").join(exe("FileCheck", &*target)) } } @@ -621,8 +668,12 @@ impl Build { /// Returns the libdir of the snapshot compiler. fn rustc_snapshot_libdir(&self) -> PathBuf { + self.rustc_snapshot_sysroot().join(libdir(&self.config.build)) + } + + /// Returns the sysroot of the snapshot compiler. + fn rustc_snapshot_sysroot(&self) -> &Path { self.initial_rustc.parent().unwrap().parent().unwrap() - .join(libdir(&self.config.build)) } /// Runs a command, printing out nice contextual information if it fails. @@ -936,11 +987,24 @@ impl Build { self.package_vers(&self.release_num("rls")) } + /// Returns the value of `package_vers` above for clippy + fn clippy_package_vers(&self) -> String { + self.package_vers(&self.release_num("clippy")) + } + /// Returns the value of `package_vers` above for rustfmt fn rustfmt_package_vers(&self) -> String { self.package_vers(&self.release_num("rustfmt")) } + fn llvm_tools_package_vers(&self) -> String { + self.package_vers(&self.rust_version()) + } + + fn llvm_tools_vers(&self) -> String { + self.rust_version() + } + /// Returns the `version` string associated with this compiler for Rust /// itself. /// @@ -1112,13 +1176,13 @@ impl Build { /// Copies the `src` directory recursively to `dst`. Both are assumed to exist /// when this function is called. Unwanted files or directories can be skipped /// by returning `false` from the filter function. - pub fn cp_filtered(&self, src: &Path, dst: &Path, filter: &Fn(&Path) -> bool) { + pub fn cp_filtered(&self, src: &Path, dst: &Path, filter: &dyn Fn(&Path) -> bool) { // Immediately recurse with an empty relative path self.recurse_(src, dst, Path::new(""), filter) } // Inner function does the actual work - fn recurse_(&self, src: &Path, dst: &Path, relative: &Path, filter: &Fn(&Path) -> bool) { + fn recurse_(&self, src: &Path, dst: &Path, relative: &Path, filter: &dyn Fn(&Path) -> bool) { for f in self.read_dir(src) { let path = f.path(); let name = path.file_name().unwrap(); diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 5f1df1d26e273..fa0b1983510b9 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -11,6 +11,7 @@ use std::collections::HashMap; use std::process::Command; use std::path::PathBuf; +use std::collections::HashSet; use build_helper::output; use serde_json; @@ -45,12 +46,34 @@ struct ResolveNode { } pub fn build(build: &mut Build) { - build_krate(build, "src/libstd"); - build_krate(build, "src/libtest"); - build_krate(build, "src/rustc"); + let mut resolves = Vec::new(); + build_krate(&build.std_features(), build, &mut resolves, "src/libstd"); + build_krate("", build, &mut resolves, "src/libtest"); + build_krate(&build.rustc_features(), build, &mut resolves, "src/rustc"); + + let mut id2name = HashMap::with_capacity(build.crates.len()); + for (name, krate) in build.crates.iter() { + id2name.insert(krate.id.clone(), name.clone()); + } + + for node in resolves { + let name = match id2name.get(&node.id) { + Some(name) => name, + None => continue, + }; + + let krate = build.crates.get_mut(name).unwrap(); + for dep in node.dependencies.iter() { + let dep = match id2name.get(dep) { + Some(dep) => dep, + None => continue, + }; + krate.deps.insert(*dep); + } + } } -fn build_krate(build: &mut Build, krate: &str) { +fn build_krate(features: &str, build: &mut Build, resolves: &mut Vec, krate: &str) { // Run `cargo metadata` to figure out what crates we're testing. // // Down below we're going to call `cargo test`, but to test the right set @@ -60,14 +83,13 @@ fn build_krate(build: &mut Build, krate: &str) { let mut cargo = Command::new(&build.initial_cargo); cargo.arg("metadata") .arg("--format-version").arg("1") + .arg("--features").arg(features) .arg("--manifest-path").arg(build.src.join(krate).join("Cargo.toml")); let output = output(&mut cargo); let output: Output = serde_json::from_str(&output).unwrap(); - let mut id2name = HashMap::new(); for package in output.packages { if package.source.is_none() { let name = INTERNER.intern_string(package.name); - id2name.insert(package.id, name); let mut path = PathBuf::from(package.manifest_path); path.pop(); build.crates.insert(name, Crate { @@ -77,25 +99,11 @@ fn build_krate(build: &mut Build, krate: &str) { bench_step: format!("bench-crate-{}", name), name, version: package.version, - deps: Vec::new(), + id: package.id, + deps: HashSet::new(), path, }); } } - - for node in output.resolve.nodes { - let name = match id2name.get(&node.id) { - Some(name) => name, - None => continue, - }; - - let krate = build.crates.get_mut(name).unwrap(); - for dep in node.dependencies.iter() { - let dep = match id2name.get(dep) { - Some(dep) => dep, - None => continue, - }; - krate.deps.push(*dep); - } - } + resolves.extend(output.resolve.nodes); } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index d952cb5bfc4bc..264acfacee6b0 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -167,8 +167,22 @@ impl Step for Llvm { // which saves both memory during parallel links and overall disk space // for the tools. We don't distribute any of those tools, so this is // just a local concern. However, it doesn't work well everywhere. - if target.contains("linux-gnu") || target.contains("apple-darwin") { - cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); + // + // If we are shipping llvm tools then we statically link them LLVM + if (target.contains("linux-gnu") || target.contains("apple-darwin")) && + !builder.config.llvm_tools_enabled { + cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); + } + + // For distribution we want the LLVM tools to be *statically* linked to libstdc++ + if builder.config.llvm_tools_enabled { + if !target.contains("windows") { + if target.contains("apple") { + cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++"); + } else { + cfg.define("CMAKE_EXE_LINKER_FLAGS", "-Wl,-Bsymbolic -static-libstdc++"); + } + } } if target.contains("msvc") { @@ -242,12 +256,12 @@ fn check_llvm_version(builder: &Builder, llvm_config: &Path) { let version = output(cmd.arg("--version")); let mut parts = version.split('.').take(2) .filter_map(|s| s.parse::().ok()); - if let (Some(major), Some(minor)) = (parts.next(), parts.next()) { - if major > 3 || (major == 3 && minor >= 9) { + if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) { + if major >= 5 { return } } - panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version) + panic!("\n\nbad LLVM version: {}, need >=5.0\n\n", version) } fn configure_cmake(builder: &Builder, @@ -275,21 +289,53 @@ fn configure_cmake(builder: &Builder, return } - let cc = builder.cc(target); - let cxx = builder.cxx(target).unwrap(); + let (cc, cxx) = match builder.config.llvm_clang_cl { + Some(ref cl) => (cl.as_ref(), cl.as_ref()), + None => (builder.cc(target), builder.cxx(target).unwrap()), + }; // Handle msvc + ninja + ccache specially (this is what the bots use) if target.contains("msvc") && builder.config.ninja && - builder.config.ccache.is_some() { - let mut cc = env::current_exe().expect("failed to get cwd"); - cc.set_file_name("sccache-plus-cl.exe"); + builder.config.ccache.is_some() + { + let mut wrap_cc = env::current_exe().expect("failed to get cwd"); + wrap_cc.set_file_name("sccache-plus-cl.exe"); - cfg.define("CMAKE_C_COMPILER", sanitize_cc(&cc)) - .define("CMAKE_CXX_COMPILER", sanitize_cc(&cc)); + cfg.define("CMAKE_C_COMPILER", sanitize_cc(&wrap_cc)) + .define("CMAKE_CXX_COMPILER", sanitize_cc(&wrap_cc)); cfg.env("SCCACHE_PATH", builder.config.ccache.as_ref().unwrap()) - .env("SCCACHE_TARGET", target); + .env("SCCACHE_TARGET", target) + .env("SCCACHE_CC", &cc) + .env("SCCACHE_CXX", &cxx); + + // Building LLVM on MSVC can be a little ludicrous at times. We're so far + // off the beaten path here that I'm not really sure this is even half + // supported any more. Here we're trying to: + // + // * Build LLVM on MSVC + // * Build LLVM with `clang-cl` instead of `cl.exe` + // * Build a project with `sccache` + // * Build for 32-bit as well + // * Build with Ninja + // + // For `cl.exe` there are different binaries to compile 32/64 bit which + // we use but for `clang-cl` there's only one which internally + // multiplexes via flags. As a result it appears that CMake's detection + // of a compiler's architecture and such on MSVC **doesn't** pass any + // custom flags we pass in CMAKE_CXX_FLAGS below. This means that if we + // use `clang-cl.exe` it's always diagnosed as a 64-bit compiler which + // definitely causes problems since all the env vars are pointing to + // 32-bit libraries. + // + // To hack aroudn this... again... we pass an argument that's + // unconditionally passed in the sccache shim. This'll get CMake to + // correctly diagnose it's doing a 32-bit compilation and LLVM will + // internally configure itself appropriately. + if builder.config.llvm_clang_cl.is_some() && target.contains("i686") { + cfg.env("SCCACHE_EXTRA_ARGS", "-m32"); + } // If ccache is configured we inform the build a little differently hwo // to invoke ccache while also invoking our compilers. @@ -368,9 +414,27 @@ impl Step for Lld { let mut cfg = cmake::Config::new(builder.src.join("src/tools/lld")); configure_cmake(builder, target, &mut cfg, true); + // This is an awful, awful hack. Discovered when we migrated to using + // clang-cl to compile LLVM/LLD it turns out that LLD, when built out of + // tree, will execute `llvm-config --cmakedir` and then tell CMake about + // that directory for later processing. Unfortunately if this path has + // forward slashes in it (which it basically always does on Windows) + // then CMake will hit a syntax error later on as... something isn't + // escaped it seems? + // + // Instead of attempting to fix this problem in upstream CMake and/or + // LLVM/LLD we just hack around it here. This thin wrapper will take the + // output from llvm-config and replace all instances of `\` with `/` to + // ensure we don't hit the same bugs with escaping. It means that you + // can't build on a system where your paths require `\` on Windows, but + // there's probably a lot of reasons you can't do that other than this. + let llvm_config_shim = env::current_exe() + .unwrap() + .with_file_name("llvm-config-wrapper"); cfg.out_dir(&out_dir) .profile("Release") - .define("LLVM_CONFIG_PATH", llvm_config) + .env("LLVM_CONFIG_REAL", llvm_config) + .define("LLVM_CONFIG_PATH", llvm_config_shim) .define("LLVM_INCLUDE_TESTS", "OFF"); cfg.build(); @@ -546,8 +610,10 @@ impl Step for Openssl { "arm-linux-androideabi" => "android", "arm-unknown-linux-gnueabi" => "linux-armv4", "arm-unknown-linux-gnueabihf" => "linux-armv4", + "armv6-unknown-netbsd-eabihf" => "BSD-generic32", "armv7-linux-androideabi" => "android-armv7", "armv7-unknown-linux-gnueabihf" => "linux-armv4", + "armv7-unknown-netbsd-eabihf" => "BSD-generic32", "i586-unknown-linux-gnu" => "linux-elf", "i586-unknown-linux-musl" => "linux-elf", "i686-apple-darwin" => "darwin-i386-cc", @@ -565,6 +631,7 @@ impl Step for Openssl { "powerpc-unknown-netbsd" => "BSD-generic32", "powerpc64-unknown-linux-gnu" => "linux-ppc64", "powerpc64le-unknown-linux-gnu" => "linux-ppc64le", + "powerpc64le-unknown-linux-musl" => "linux-ppc64le", "s390x-unknown-linux-gnu" => "linux64-s390x", "sparc-unknown-linux-gnu" => "linux-sparcv9", "sparc64-unknown-linux-gnu" => "linux64-sparcv9", diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index cbb952bab61b2..24a1dbbde6639 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -15,25 +15,26 @@ use std::env; use std::ffi::OsString; -use std::iter; use std::fmt; use std::fs::{self, File}; -use std::path::{PathBuf, Path}; -use std::process::Command; use std::io::Read; +use std::iter; +use std::path::{Path, PathBuf}; +use std::process::Command; use build_helper::{self, output}; -use builder::{Kind, RunConfig, ShouldRun, Builder, Compiler, Step}; -use Crate as CargoCrate; -use cache::{INTERNER, Interned}; +use builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; +use cache::{Interned, INTERNER}; use compile; use dist; +use flags::Subcommand; use native; -use tool::{self, Tool}; -use util::{self, dylib_path, dylib_path_var}; -use {Mode, DocTests}; +use tool::{self, Tool, SourceType}; use toolstate::ToolState; +use util::{self, dylib_path, dylib_path_var}; +use Crate as CargoCrate; +use {DocTests, Mode}; const ADB_TEST_DIR: &str = "/data/tmp/work"; @@ -46,6 +47,16 @@ pub enum TestKind { Bench, } +impl From for TestKind { + fn from(kind: Kind) -> Self { + match kind { + Kind::Test => TestKind::Test, + Kind::Bench => TestKind::Bench, + _ => panic!("unexpected kind in crate: {:?}", kind), + } + } +} + impl TestKind { // Return the cargo subcommand for this test kind fn subcommand(self) -> &'static str { @@ -113,13 +124,18 @@ impl Step for Linkcheck { builder.default_doc(None); let _time = util::timeit(&builder); - try_run(builder, builder.tool_cmd(Tool::Linkchecker) - .arg(builder.out.join(host).join("doc"))); + try_run( + builder, + builder + .tool_cmd(Tool::Linkchecker) + .arg(builder.out.join(host).join("doc")), + ); } fn should_run(run: ShouldRun) -> ShouldRun { let builder = run.builder; - run.path("src/tools/linkchecker").default_condition(builder.config.docs) + run.path("src/tools/linkchecker") + .default_condition(builder.config.docs) } fn make_run(run: RunConfig) { @@ -154,7 +170,10 @@ impl Step for Cargotest { /// test` to ensure that we don't regress the test suites there. fn run(self, builder: &Builder) { let compiler = builder.compiler(self.stage, self.host); - builder.ensure(compile::Rustc { compiler, target: compiler.host }); + builder.ensure(compile::Rustc { + compiler, + target: compiler.host, + }); // Note that this is a short, cryptic, and not scoped directory name. This // is currently to minimize the length of path on Windows where we otherwise @@ -164,10 +183,13 @@ impl Step for Cargotest { let _time = util::timeit(&builder); let mut cmd = builder.tool_cmd(Tool::CargoTest); - try_run(builder, cmd.arg(&builder.initial_cargo) - .arg(&out_dir) - .env("RUSTC", builder.rustc(compiler)) - .env("RUSTDOC", builder.rustdoc(compiler.host))); + try_run( + builder, + cmd.arg(&builder.initial_cargo) + .arg(&out_dir) + .env("RUSTC", builder.rustc(compiler)) + .env("RUSTDOC", builder.rustdoc(compiler.host)), + ); } } @@ -196,21 +218,30 @@ impl Step for Cargo { fn run(self, builder: &Builder) { let compiler = builder.compiler(self.stage, self.host); - builder.ensure(tool::Cargo { compiler, target: self.host }); - let mut cargo = builder.cargo(compiler, Mode::Tool, self.host, "test"); - cargo.arg("--manifest-path").arg(builder.src.join("src/tools/cargo/Cargo.toml")); + builder.ensure(tool::Cargo { + compiler, + target: self.host, + }); + let mut cargo = tool::prepare_tool_cargo(builder, + compiler, + Mode::ToolRustc, + self.host, + "test", + "src/tools/cargo", + SourceType::Submodule); + if !builder.fail_fast { cargo.arg("--no-fail-fast"); } - // Don't build tests dynamically, just a pain to work with - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - // Don't run cross-compile tests, we may not have cross-compiled libstd libs // available. cargo.env("CFG_DISABLE_CROSS_TESTS", "1"); - try_run(builder, cargo.env("PATH", &path_for_cargo(builder, compiler))); + try_run( + builder, + cargo.env("PATH", &path_for_cargo(builder, compiler)), + ); } } @@ -253,12 +284,18 @@ impl Step for Rls { let mut cargo = tool::prepare_tool_cargo(builder, compiler, + Mode::ToolRustc, host, "test", - "src/tools/rls"); + "src/tools/rls", + SourceType::Submodule); - // Don't build tests dynamically, just a pain to work with - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + // Copy `src/tools/rls/test_data` to a writable drive. + let test_workspace_path = builder.out.join("rls-test-data"); + let test_data_path = test_workspace_path.join("test_data"); + builder.create_dir(&test_data_path); + builder.cp_r(&builder.src.join("src/tools/rls/test_data"), &test_data_path); + cargo.env("RLS_TEST_WORKSPACE_DIR", test_workspace_path); builder.add_rustc_lib_path(compiler, &mut cargo); @@ -307,12 +344,15 @@ impl Step for Rustfmt { let mut cargo = tool::prepare_tool_cargo(builder, compiler, + Mode::ToolRustc, host, "test", - "src/tools/rustfmt"); + "src/tools/rustfmt", + SourceType::Submodule); - // Don't build tests dynamically, just a pain to work with - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + let dir = testdir(builder, compiler.host); + t!(fs::create_dir_all(&dir)); + cargo.env("RUSTFMT_TEST_DIR", dir); builder.add_rustc_lib_path(compiler, &mut cargo); @@ -357,11 +397,14 @@ impl Step for Miri { extra_features: Vec::new(), }); if let Some(miri) = miri { - let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(builder.src.join("src/tools/miri/Cargo.toml")); + let mut cargo = tool::prepare_tool_cargo(builder, + compiler, + Mode::ToolRustc, + host, + "test", + "src/tools/miri", + SourceType::Submodule); - // Don't build tests dynamically, just a pain to work with - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", builder.sysroot(compiler)); cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); @@ -413,16 +456,21 @@ impl Step for Clippy { extra_features: Vec::new(), }); if let Some(clippy) = clippy { - let mut cargo = builder.cargo(compiler, Mode::Tool, host, "test"); - cargo.arg("--manifest-path").arg(builder.src.join("src/tools/clippy/Cargo.toml")); + let mut cargo = tool::prepare_tool_cargo(builder, + compiler, + Mode::ToolRustc, + host, + "test", + "src/tools/clippy", + SourceType::Submodule); - // Don't build tests dynamically, just a pain to work with - cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); // clippy tests need to know about the stage sysroot cargo.env("SYSROOT", builder.sysroot(compiler)); cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler)); cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler)); - let host_libs = builder.stage_out(compiler, Mode::Tool).join(builder.cargo_dir()); + let host_libs = builder + .stage_out(compiler, Mode::ToolRustc) + .join(builder.cargo_dir()); cargo.env("HOST_LIBS", host_libs); // clippy tests need to find the driver cargo.env("CLIPPY_DRIVER_PATH", clippy); @@ -464,23 +512,30 @@ impl Step for RustdocTheme { fn make_run(run: RunConfig) { let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocTheme { - compiler: compiler, - }); + run.builder.ensure(RustdocTheme { compiler: compiler }); } fn run(self, builder: &Builder) { let rustdoc = builder.out.join("bootstrap/debug/rustdoc"); let mut cmd = builder.tool_cmd(Tool::RustdocTheme); cmd.arg(rustdoc.to_str().unwrap()) - .arg(builder.src.join("src/librustdoc/html/static/themes").to_str().unwrap()) - .env("RUSTC_STAGE", self.compiler.stage.to_string()) - .env("RUSTC_SYSROOT", builder.sysroot(self.compiler)) - .env("RUSTDOC_LIBDIR", builder.sysroot_libdir(self.compiler, self.compiler.host)) - .env("CFG_RELEASE_CHANNEL", &builder.config.channel) - .env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host)) - .env("RUSTDOC_CRATE_VERSION", builder.rust_version()) - .env("RUSTC_BOOTSTRAP", "1"); + .arg( + builder + .src + .join("src/librustdoc/html/static/themes") + .to_str() + .unwrap(), + ) + .env("RUSTC_STAGE", self.compiler.stage.to_string()) + .env("RUSTC_SYSROOT", builder.sysroot(self.compiler)) + .env( + "RUSTDOC_LIBDIR", + builder.sysroot_libdir(self.compiler, self.compiler.host), + ) + .env("CFG_RELEASE_CHANNEL", &builder.config.channel) + .env("RUSTDOC_REAL", builder.rustdoc(self.compiler.host)) + .env("RUSTDOC_CRATE_VERSION", builder.rust_version()) + .env("RUSTC_BOOTSTRAP", "1"); if let Some(linker) = builder.linker(self.compiler.host) { cmd.env("RUSTC_TARGET_LINKER", linker); } @@ -520,7 +575,9 @@ impl Step for RustdocJS { }); builder.run(&mut command); } else { - builder.info(&format!("No nodejs found, skipping \"src/test/rustdoc-js\" tests")); + builder.info(&format!( + "No nodejs found, skipping \"src/test/rustdoc-js\" tests" + )); } } } @@ -556,6 +613,7 @@ impl Step for RustdocUi { target: self.target, mode: "ui", suite: "rustdoc-ui", + path: None, compare_mode: None, }) } @@ -581,7 +639,7 @@ impl Step for Tidy { if !builder.config.vendor { cmd.arg("--no-vendor"); } - if builder.config.quiet_tests { + if !builder.config.verbose_tests { cmd.arg("--quiet"); } @@ -660,7 +718,7 @@ macro_rules! test_definitions { const ONLY_HOSTS: bool = $host; fn should_run(run: ShouldRun) -> ShouldRun { - run.path($path) + run.suite_path($path) } fn make_run(run: RunConfig) { @@ -678,6 +736,7 @@ macro_rules! test_definitions { target: self.target, mode: $mode, suite: $suite, + path: Some($path), compare_mode: $compare_mode, }) } @@ -850,6 +909,7 @@ struct Compiletest { target: Interned, mode: &'static str, suite: &'static str, + path: Option<&'static str>, compare_mode: Option<&'static str>, } @@ -870,7 +930,9 @@ impl Step for Compiletest { let target = self.target; let mode = self.mode; let suite = self.suite; - let compare_mode = self.compare_mode; + + // Path for test suite + let suite_path = self.path.unwrap_or(""); // Skip codegen tests if they aren't enabled in configuration. if !builder.config.codegen_tests && suite == "codegen" { @@ -899,19 +961,21 @@ impl Step for Compiletest { builder.ensure(dist::DebuggerScripts { sysroot: builder.sysroot(compiler), - host: target + host: target, }); } if suite.ends_with("fulldeps") || // FIXME: Does pretty need librustc compiled? Note that there are // fulldeps test suites with mode = pretty as well. - mode == "pretty" || - mode == "rustdoc" { + mode == "pretty" + { builder.ensure(compile::Rustc { compiler, target }); } - builder.ensure(compile::Test { compiler, target }); + if builder.no_std(target) != Some(true) { + builder.ensure(compile::Test { compiler, target }); + } builder.ensure(native::TestHelpers { target }); builder.ensure(RemoteCopyLibs { compiler, target }); @@ -920,26 +984,40 @@ impl Step for Compiletest { // compiletest currently has... a lot of arguments, so let's just pass all // of them! - cmd.arg("--compile-lib-path").arg(builder.rustc_libdir(compiler)); - cmd.arg("--run-lib-path").arg(builder.sysroot_libdir(compiler, target)); + cmd.arg("--compile-lib-path") + .arg(builder.rustc_libdir(compiler)); + cmd.arg("--run-lib-path") + .arg(builder.sysroot_libdir(compiler, target)); cmd.arg("--rustc-path").arg(builder.rustc(compiler)); let is_rustdoc_ui = suite.ends_with("rustdoc-ui"); // Avoid depending on rustdoc when we don't need it. - if mode == "rustdoc" || - (mode == "run-make" && suite.ends_with("fulldeps")) || - (mode == "ui" && is_rustdoc_ui) { - cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); + if mode == "rustdoc" + || (mode == "run-make" && suite.ends_with("fulldeps")) + || (mode == "ui" && is_rustdoc_ui) + { + cmd.arg("--rustdoc-path") + .arg(builder.rustdoc(compiler.host)); } - cmd.arg("--src-base").arg(builder.src.join("src/test").join(suite)); - cmd.arg("--build-base").arg(testdir(builder, compiler.host).join(suite)); - cmd.arg("--stage-id").arg(format!("stage{}-{}", compiler.stage, target)); + cmd.arg("--src-base") + .arg(builder.src.join("src/test").join(suite)); + cmd.arg("--build-base") + .arg(testdir(builder, compiler.host).join(suite)); + cmd.arg("--stage-id") + .arg(format!("stage{}-{}", compiler.stage, target)); cmd.arg("--mode").arg(mode); cmd.arg("--target").arg(target); cmd.arg("--host").arg(&*compiler.host); - cmd.arg("--llvm-filecheck").arg(builder.llvm_filecheck(builder.config.build)); + cmd.arg("--llvm-filecheck") + .arg(builder.llvm_filecheck(builder.config.build)); + + if builder.config.cmd.bless() { + cmd.arg("--bless"); + } + + let compare_mode = builder.config.cmd.compare_mode().or(self.compare_mode); if let Some(ref nodejs) = builder.config.nodejs { cmd.arg("--nodejs").arg(nodejs); @@ -969,8 +1047,10 @@ impl Step for Compiletest { cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); let mut targetflags = flags.clone(); - targetflags.push(format!("-Lnative={}", - builder.test_helpers_out(target).display())); + targetflags.push(format!( + "-Lnative={}", + builder.test_helpers_out(target).display() + )); cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); cmd.arg("--docck-python").arg(builder.python()); @@ -994,13 +1074,34 @@ impl Step for Compiletest { cmd.arg("--lldb-python-dir").arg(dir); } - cmd.args(&builder.config.cmd.test_args()); + // Get paths from cmd args + let paths = match &builder.config.cmd { + Subcommand::Test { ref paths, .. } => &paths[..], + _ => &[], + }; + + // Get test-args by striping suite path + let mut test_args: Vec<&str> = paths + .iter() + .map(|p| { + match p.strip_prefix(".") { + Ok(path) => path, + Err(_) => p, + } + }) + .filter(|p| p.starts_with(suite_path) && p.is_file()) + .map(|p| p.strip_prefix(suite_path).unwrap().to_str().unwrap()) + .collect(); + + test_args.append(&mut builder.config.cmd.test_args()); + + cmd.args(&test_args); if builder.is_verbose() { cmd.arg("--verbose"); } - if builder.config.quiet_tests { + if !builder.config.verbose_tests { cmd.arg("--quiet"); } @@ -1022,32 +1123,44 @@ impl Step for Compiletest { if !builder.config.dry_run && suite == "run-make-fulldeps" { let llvm_components = output(Command::new(&llvm_config).arg("--components")); let llvm_cxxflags = output(Command::new(&llvm_config).arg("--cxxflags")); - cmd.arg("--cc").arg(builder.cc(target)) - .arg("--cxx").arg(builder.cxx(target).unwrap()) - .arg("--cflags").arg(builder.cflags(target).join(" ")) - .arg("--llvm-components").arg(llvm_components.trim()) - .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); + cmd.arg("--cc") + .arg(builder.cc(target)) + .arg("--cxx") + .arg(builder.cxx(target).unwrap()) + .arg("--cflags") + .arg(builder.cflags(target).join(" ")) + .arg("--llvm-components") + .arg(llvm_components.trim()) + .arg("--llvm-cxxflags") + .arg(llvm_cxxflags.trim()); if let Some(ar) = builder.ar(target) { cmd.arg("--ar").arg(ar); } } } if suite == "run-make-fulldeps" && !builder.config.llvm_enabled { - builder.info( - &format!("Ignoring run-make test suite as they generally don't work without LLVM")); + builder.info(&format!( + "Ignoring run-make test suite as they generally don't work without LLVM" + )); return; } if suite != "run-make-fulldeps" { - cmd.arg("--cc").arg("") - .arg("--cxx").arg("") - .arg("--cflags").arg("") - .arg("--llvm-components").arg("") - .arg("--llvm-cxxflags").arg(""); + cmd.arg("--cc") + .arg("") + .arg("--cxx") + .arg("") + .arg("--cflags") + .arg("") + .arg("--llvm-components") + .arg("") + .arg("--llvm-cxxflags") + .arg(""); } if builder.remote_tested(target) { - cmd.arg("--remote-test-client").arg(builder.tool_exe(Tool::RemoteTestClient)); + cmd.arg("--remote-test-client") + .arg(builder.tool_exe(Tool::RemoteTestClient)); } // Running a C compiler on MSVC requires a few env vars to be set, to be @@ -1080,7 +1193,7 @@ impl Step for Compiletest { if target.contains("android") { // Assume that cc for this target comes from the android sysroot cmd.arg("--android-cross-path") - .arg(builder.cc(target).parent().unwrap().parent().unwrap()); + .arg(builder.cc(target).parent().unwrap().parent().unwrap()); } else { cmd.arg("--android-cross-path").arg(""); } @@ -1088,16 +1201,20 @@ impl Step for Compiletest { builder.ci_env.force_coloring_in_ci(&mut cmd); let _folder = builder.fold_output(|| format!("test_{}", suite)); - builder.info(&format!("Check compiletest suite={} mode={} ({} -> {})", - suite, mode, &compiler.host, target)); + builder.info(&format!( + "Check compiletest suite={} mode={} ({} -> {})", + suite, mode, &compiler.host, target + )); let _time = util::timeit(&builder); try_run(builder, &mut cmd); if let Some(compare_mode) = compare_mode { cmd.arg("--compare-mode").arg(compare_mode); let _folder = builder.fold_output(|| format!("test_{}_{}", suite, compare_mode)); - builder.info(&format!("Check compiletest suite={} mode={} compare_mode={} ({} -> {})", - suite, mode, compare_mode, &compiler.host, target)); + builder.info(&format!( + "Check compiletest suite={} mode={} compare_mode={} ({} -> {})", + suite, mode, compare_mode, &compiler.host, target + )); let _time = util::timeit(&builder); try_run(builder, &mut cmd); } @@ -1128,7 +1245,10 @@ impl Step for DocTest { fn run(self, builder: &Builder) { let compiler = self.compiler; - builder.ensure(compile::Test { compiler, target: compiler.host }); + builder.ensure(compile::Test { + compiler, + target: compiler.host, + }); // Do a breadth-first traversal of the `src/doc` directory and just run // tests for all files that end in `*.md` @@ -1140,7 +1260,7 @@ impl Step for DocTest { while let Some(p) = stack.pop() { if p.is_dir() { stack.extend(t!(p.read_dir()).map(|p| t!(p).path())); - continue + continue; } if p.extension().and_then(|s| s.to_str()) != Some("md") { @@ -1158,17 +1278,15 @@ impl Step for DocTest { files.sort(); + let mut toolstate = ToolState::TestPass; for file in files { - let test_result = markdown_test(builder, compiler, &file); - if self.is_ext_doc { - let toolstate = if test_result { - ToolState::TestPass - } else { - ToolState::TestFail - }; - builder.save_toolstate(self.name, toolstate); + if !markdown_test(builder, compiler, &file) { + toolstate = ToolState::TestFail; } } + if self.is_ext_doc { + builder.save_toolstate(self.name, toolstate); + } } } @@ -1247,7 +1365,10 @@ impl Step for ErrorIndex { fn run(self, builder: &Builder) { let compiler = self.compiler; - builder.ensure(compile::Std { compiler, target: compiler.host }); + builder.ensure(compile::Std { + compiler, + target: compiler.host, + }); let dir = testdir(builder, compiler.host); t!(fs::create_dir_all(&dir)); @@ -1259,7 +1380,6 @@ impl Step for ErrorIndex { .env("CFG_BUILD", &builder.config.build) .env("RUSTC_ERROR_METADATA_DST", builder.extended_error_dir()); - let _folder = builder.fold_output(|| "test_error_index"); builder.info(&format!("Testing error-index stage{}", compiler.stage)); let _time = util::timeit(&builder); @@ -1277,7 +1397,7 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool return true; } } - Err(_) => {}, + Err(_) => {} } builder.info(&format!("doc tests for: {}", markdown.display())); @@ -1290,10 +1410,10 @@ fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool let test_args = builder.config.cmd.test_args().join(" "); cmd.arg("--test-args").arg(test_args); - if builder.config.quiet_tests { - try_run_quiet(builder, &mut cmd) - } else { + if builder.config.verbose_tests { try_run(builder, &mut cmd) + } else { + try_run_quiet(builder, &mut cmd) } } @@ -1320,13 +1440,7 @@ impl Step for CrateLibrustc { for krate in builder.in_tree_crates("rustc-main") { if run.path.ends_with(&krate.path) { - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + let test_kind = builder.kind.into(); builder.ensure(CrateLibrustc { compiler, @@ -1342,7 +1456,7 @@ impl Step for CrateLibrustc { builder.ensure(Crate { compiler: self.compiler, target: self.target, - mode: Mode::Librustc, + mode: Mode::Rustc, test_kind: self.test_kind, krate: self.krate, }); @@ -1372,13 +1486,7 @@ impl Step for CrateNotDefault { let builder = run.builder; let compiler = builder.compiler(builder.top_stage, run.host); - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + let test_kind = builder.kind.into(); builder.ensure(CrateNotDefault { compiler, @@ -1399,14 +1507,13 @@ impl Step for CrateNotDefault { builder.ensure(Crate { compiler: self.compiler, target: self.target, - mode: Mode::Libstd, + mode: Mode::Std, test_kind: self.test_kind, krate: INTERNER.intern_str(self.krate), }); } } - #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Crate { pub compiler: Compiler, @@ -1424,10 +1531,11 @@ impl Step for Crate { let builder = run.builder; run = run.krate("test"); for krate in run.builder.in_tree_crates("std") { - if krate.is_local(&run.builder) && - !krate.name.contains("jemalloc") && - !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) && - krate.name != "dlmalloc" { + if krate.is_local(&run.builder) + && !krate.name.contains("jemalloc") + && !(krate.name.starts_with("rustc_") && krate.name.ends_with("san")) + && krate.name != "dlmalloc" + { run = run.path(krate.local_path(&builder).to_str().unwrap()); } } @@ -1439,13 +1547,7 @@ impl Step for Crate { let compiler = builder.compiler(builder.top_stage, run.host); let make = |mode: Mode, krate: &CargoCrate| { - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + let test_kind = builder.kind.into(); builder.ensure(Crate { compiler, @@ -1458,12 +1560,12 @@ impl Step for Crate { for krate in builder.in_tree_crates("std") { if run.path.ends_with(&krate.local_path(&builder)) { - make(Mode::Libstd, krate); + make(Mode::Std, krate); } } for krate in builder.in_tree_crates("test") { if run.path.ends_with(&krate.local_path(&builder)) { - make(Mode::Libtest, krate); + make(Mode::Test, krate); } } } @@ -1498,13 +1600,13 @@ impl Step for Crate { let mut cargo = builder.cargo(compiler, mode, target, test_kind.subcommand()); match mode { - Mode::Libstd => { + Mode::Std => { compile::std_cargo(builder, &compiler, target, &mut cargo); } - Mode::Libtest => { + Mode::Test => { compile::test_cargo(builder, &compiler, target, &mut cargo); } - Mode::Librustc => { + Mode::Rustc => { builder.ensure(compile::Rustc { compiler, target }); compile::rustc_cargo(builder, &mut cargo); } @@ -1543,43 +1645,64 @@ impl Step for Crate { cargo.arg("--"); cargo.args(&builder.config.cmd.test_args()); - if builder.config.quiet_tests { + if !builder.config.verbose_tests { cargo.arg("--quiet"); } if target.contains("emscripten") { - cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), - builder.config.nodejs.as_ref().expect("nodejs not configured")); + cargo.env( + format!("CARGO_TARGET_{}_RUNNER", envify(&target)), + builder + .config + .nodejs + .as_ref() + .expect("nodejs not configured"), + ); } else if target.starts_with("wasm32") { // Warn about running tests without the `wasm_syscall` feature enabled. // The javascript shim implements the syscall interface so that test // output can be correctly reported. if !builder.config.wasm_syscall { - builder.info(&format!("Libstd was built without `wasm_syscall` feature enabled: \ - test output may not be visible.")); + builder.info(&format!( + "Libstd was built without `wasm_syscall` feature enabled: \ + test output may not be visible." + )); } // On the wasm32-unknown-unknown target we're using LTO which is // incompatible with `-C prefer-dynamic`, so disable that here cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); - let node = builder.config.nodejs.as_ref() + let node = builder + .config + .nodejs + .as_ref() .expect("nodejs not configured"); - let runner = format!("{} {}/src/etc/wasm32-shim.js", - node.display(), - builder.src.display()); + let runner = format!( + "{} {}/src/etc/wasm32-shim.js", + node.display(), + builder.src.display() + ); cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), &runner); } else if builder.remote_tested(target) { - cargo.env(format!("CARGO_TARGET_{}_RUNNER", envify(&target)), - format!("{} run", - builder.tool_exe(Tool::RemoteTestClient).display())); + cargo.env( + format!("CARGO_TARGET_{}_RUNNER", envify(&target)), + format!("{} run", builder.tool_exe(Tool::RemoteTestClient).display()), + ); } let _folder = builder.fold_output(|| { - format!("{}_stage{}-{}", test_kind.subcommand(), compiler.stage, krate) + format!( + "{}_stage{}-{}", + test_kind.subcommand(), + compiler.stage, + krate + ) }); - builder.info(&format!("{} {} stage{} ({} -> {})", test_kind, krate, compiler.stage, - &compiler.host, target)); + builder.info(&format!( + "{} {} stage{} ({} -> {})", + test_kind, krate, compiler.stage, &compiler.host, target + )); let _time = util::timeit(&builder); try_run(builder, &mut cargo); } @@ -1603,13 +1726,7 @@ impl Step for CrateRustdoc { fn make_run(run: RunConfig) { let builder = run.builder; - let test_kind = if builder.kind == Kind::Test { - TestKind::Test - } else if builder.kind == Kind::Bench { - TestKind::Bench - } else { - panic!("unexpected builder.kind in crate: {:?}", builder.kind); - }; + let test_kind = builder.kind.into(); builder.ensure(CrateRustdoc { host: run.host, @@ -1622,12 +1739,15 @@ impl Step for CrateRustdoc { let compiler = builder.compiler(builder.top_stage, self.host); let target = compiler.host; + builder.ensure(compile::Rustc { compiler, target }); let mut cargo = tool::prepare_tool_cargo(builder, compiler, + Mode::ToolRustc, target, test_kind.subcommand(), - "src/tools/rustdoc"); + "src/tools/rustdoc", + SourceType::InTree); if test_kind.subcommand() == "test" && !builder.fail_fast { cargo.arg("--no-fail-fast"); } @@ -1637,15 +1757,16 @@ impl Step for CrateRustdoc { cargo.arg("--"); cargo.args(&builder.config.cmd.test_args()); - if builder.config.quiet_tests { + if !builder.config.verbose_tests { cargo.arg("--quiet"); } - let _folder = builder.fold_output(|| { - format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage) - }); - builder.info(&format!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage, - &compiler.host, target)); + let _folder = builder + .fold_output(|| format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)); + builder.info(&format!( + "{} rustdoc stage{} ({} -> {})", + test_kind, compiler.stage, &compiler.host, target + )); let _time = util::timeit(&builder); try_run(builder, &mut cargo); @@ -1653,12 +1774,13 @@ impl Step for CrateRustdoc { } fn envify(s: &str) -> String { - s.chars().map(|c| { - match c { + s.chars() + .map(|c| match c { '-' => '_', c => c, - } - }).flat_map(|c| c.to_uppercase()).collect() + }) + .flat_map(|c| c.to_uppercase()) + .collect() } /// Some test suites are run inside emulators or on remote devices, and most @@ -1687,7 +1809,7 @@ impl Step for RemoteCopyLibs { let compiler = self.compiler; let target = self.target; if !builder.remote_tested(target) { - return + return; } builder.ensure(compile::Test { compiler, target }); @@ -1695,15 +1817,18 @@ impl Step for RemoteCopyLibs { builder.info(&format!("REMOTE copy libs to emulator ({})", target)); t!(fs::create_dir_all(builder.out.join("tmp"))); - let server = builder.ensure(tool::RemoteTestServer { compiler, target }); + let server = builder.ensure(tool::RemoteTestServer { + compiler: compiler.with_stage(0), + target, + }); // Spawn the emulator and wait for it to come online let tool = builder.tool_exe(Tool::RemoteTestClient); let mut cmd = Command::new(&tool); cmd.arg("spawn-emulator") - .arg(target) - .arg(&server) - .arg(builder.out.join("tmp")); + .arg(target) + .arg(&server) + .arg(builder.out.join("tmp")); if let Some(rootfs) = builder.qemu_rootfs(target) { cmd.arg(rootfs); } @@ -1714,9 +1839,7 @@ impl Step for RemoteCopyLibs { let f = t!(f); let name = f.file_name().into_string().unwrap(); if util::is_dylib(&name) { - builder.run(Command::new(&tool) - .arg("push") - .arg(f.path())); + builder.run(Command::new(&tool).arg("push").arg(f.path())); } } } @@ -1749,17 +1872,21 @@ impl Step for Distcheck { let mut cmd = Command::new("tar"); cmd.arg("-xzf") - .arg(builder.ensure(dist::PlainSourceTarball)) - .arg("--strip-components=1") - .current_dir(&dir); + .arg(builder.ensure(dist::PlainSourceTarball)) + .arg("--strip-components=1") + .current_dir(&dir); builder.run(&mut cmd); - builder.run(Command::new("./configure") - .args(&builder.config.configure_args) - .arg("--enable-vendor") - .current_dir(&dir)); - builder.run(Command::new(build_helper::make(&builder.config.build)) - .arg("check") - .current_dir(&dir)); + builder.run( + Command::new("./configure") + .args(&builder.config.configure_args) + .arg("--enable-vendor") + .current_dir(&dir), + ); + builder.run( + Command::new(build_helper::make(&builder.config.build)) + .arg("check") + .current_dir(&dir), + ); // Now make sure that rust-src has all of libstd's dependencies builder.info(&format!("Distcheck rust-src")); @@ -1769,17 +1896,19 @@ impl Step for Distcheck { let mut cmd = Command::new("tar"); cmd.arg("-xzf") - .arg(builder.ensure(dist::Src)) - .arg("--strip-components=1") - .current_dir(&dir); + .arg(builder.ensure(dist::Src)) + .arg("--strip-components=1") + .current_dir(&dir); builder.run(&mut cmd); let toml = dir.join("rust-src/lib/rustlib/src/rust/src/libstd/Cargo.toml"); - builder.run(Command::new(&builder.initial_cargo) - .arg("generate-lockfile") - .arg("--manifest-path") - .arg(&toml) - .current_dir(&dir)); + builder.run( + Command::new(&builder.initial_cargo) + .arg("generate-lockfile") + .arg("--manifest-path") + .arg(&toml) + .current_dir(&dir), + ); } } @@ -1795,11 +1924,11 @@ impl Step for Bootstrap { fn run(self, builder: &Builder) { let mut cmd = Command::new(&builder.initial_cargo); cmd.arg("test") - .current_dir(builder.src.join("src/bootstrap")) - .env("RUSTFLAGS", "-Cdebuginfo=2") - .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) - .env("RUSTC_BOOTSTRAP", "1") - .env("RUSTC", &builder.initial_rustc); + .current_dir(builder.src.join("src/bootstrap")) + .env("RUSTFLAGS", "-Cdebuginfo=2") + .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) + .env("RUSTC_BOOTSTRAP", "1") + .env("RUSTC", &builder.initial_rustc); if let Some(flags) = option_env!("RUSTFLAGS") { // Use the same rustc flags for testing as for "normal" compilation, // so that Cargo doesn’t recompile the entire dependency graph every time: @@ -1810,6 +1939,9 @@ impl Step for Bootstrap { cmd.arg("--no-fail-fast"); } cmd.arg("--").args(&builder.config.cmd.test_args()); + // rustbuild tests are racy on directory creation so just run them one at a time. + // Since there's not many this shouldn't be a problem. + cmd.arg("--test-threads=1"); try_run(builder, &mut cmd); } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 6c29bd84fe467..5e68b797b3d54 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -10,8 +10,10 @@ use std::fs; use std::env; +use std::iter; use std::path::PathBuf; use std::process::{Command, exit}; +use std::collections::HashSet; use Mode; use Compiler; @@ -27,7 +29,7 @@ use toolstate::ToolState; pub struct CleanTools { pub compiler: Compiler, pub target: Interned, - pub mode: Mode, + pub cause: Mode, } impl Step for CleanTools { @@ -40,23 +42,23 @@ impl Step for CleanTools { fn run(self, builder: &Builder) { let compiler = self.compiler; let target = self.target; - let mode = self.mode; + let cause = self.cause; // This is for the original compiler, but if we're forced to use stage 1, then // std/test/rustc stamps won't exist in stage 2, so we need to get those from stage 1, since // we copy the libs forward. - let tools_dir = builder.stage_out(compiler, Mode::Tool); + let tools_dir = builder.stage_out(compiler, Mode::ToolRustc); let compiler = if builder.force_use_stage1(compiler, target) { builder.compiler(1, compiler.host) } else { compiler }; - for &cur_mode in &[Mode::Libstd, Mode::Libtest, Mode::Librustc] { + for &cur_mode in &[Mode::Std, Mode::Test, Mode::Rustc] { let stamp = match cur_mode { - Mode::Libstd => libstd_stamp(builder, compiler, target), - Mode::Libtest => libtest_stamp(builder, compiler, target), - Mode::Librustc => librustc_stamp(builder, compiler, target), + Mode::Std => libstd_stamp(builder, compiler, target), + Mode::Test => libtest_stamp(builder, compiler, target), + Mode::Rustc => librustc_stamp(builder, compiler, target), _ => panic!(), }; @@ -66,13 +68,19 @@ impl Step for CleanTools { // If we are a rustc tool, and std changed, we also need to clear ourselves out -- our // dependencies depend on std. Therefore, we iterate up until our own mode. - if mode == cur_mode { + if cause == cur_mode { break; } } } } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub enum SourceType { + InTree, + Submodule, +} + #[derive(Debug, Clone, Hash, PartialEq, Eq)] struct ToolBuild { compiler: Compiler, @@ -80,7 +88,8 @@ struct ToolBuild { tool: &'static str, path: &'static str, mode: Mode, - is_ext_tool: bool, + is_optional_tool: bool, + source_type: SourceType, extra_features: Vec, } @@ -100,16 +109,28 @@ impl Step for ToolBuild { let target = self.target; let tool = self.tool; let path = self.path; - let is_ext_tool = self.is_ext_tool; + let is_optional_tool = self.is_optional_tool; match self.mode { - Mode::Libstd => builder.ensure(compile::Std { compiler, target }), - Mode::Libtest => builder.ensure(compile::Test { compiler, target }), - Mode::Librustc => builder.ensure(compile::Rustc { compiler, target }), - Mode::Tool => panic!("unexpected Mode::Tool for tool build") + Mode::ToolRustc => { + builder.ensure(compile::Rustc { compiler, target }) + } + Mode::ToolStd => { + builder.ensure(compile::Std { compiler, target }) + } + Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs + _ => panic!("unexpected Mode for tool build") } - let mut cargo = prepare_tool_cargo(builder, compiler, target, "build", path); + let mut cargo = prepare_tool_cargo( + builder, + compiler, + self.mode, + target, + "build", + path, + self.source_type, + ); cargo.arg("--features").arg(self.extra_features.join(" ")); let _folder = builder.fold_output(|| format!("stage{}-{}", compiler.stage, tool)); @@ -117,8 +138,13 @@ impl Step for ToolBuild { let mut duplicates = Vec::new(); let is_expected = compile::stream_cargo(builder, &mut cargo, &mut |msg| { // Only care about big things like the RLS/Cargo for now - if tool != "rls" && tool != "cargo" { - return + match tool { + | "rls" + | "cargo" + | "clippy-driver" + => {} + + _ => return, } let (id, features, filenames) = match msg { compile::CargoMessage::CompilerArtifact { @@ -177,12 +203,22 @@ impl Step for ToolBuild { typically means that something was recompiled because \ a transitive dependency has different features activated \ than in a previous build:\n"); + println!("the following dependencies are duplicated although they \ + have the same features enabled:"); + for (id, cur, prev) in duplicates.drain_filter(|(_, cur, prev)| cur.2 == prev.2) { + println!(" {}", id); + // same features + println!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1); + } + println!("the following dependencies have different features:"); for (id, cur, prev) in duplicates { println!(" {}", id); - println!(" `{}` enabled features {:?} at {:?}", - cur.0, cur.2, cur.1); - println!(" `{}` enabled features {:?} at {:?}", - prev.0, prev.2, prev.1); + let cur_features: HashSet<_> = cur.2.into_iter().collect(); + let prev_features: HashSet<_> = prev.2.into_iter().collect(); + println!(" `{}` additionally enabled features {:?} at {:?}", + cur.0, &cur_features - &prev_features, cur.1); + println!(" `{}` additionally enabled features {:?} at {:?}", + prev.0, &prev_features - &cur_features, prev.1); } println!(""); panic!("tools should not compile multiple copies of the same crate"); @@ -195,13 +231,13 @@ impl Step for ToolBuild { }); if !is_expected { - if !is_ext_tool { + if !is_optional_tool { exit(1); } else { return None; } } else { - let cargo_out = builder.cargo_out(compiler, Mode::Tool, target) + let cargo_out = builder.cargo_out(compiler, self.mode, target) .join(exe(tool, &compiler.host)); let bin = builder.tools_dir(compiler).join(exe(tool, &compiler.host)); builder.copy(&cargo_out, &bin); @@ -213,11 +249,13 @@ impl Step for ToolBuild { pub fn prepare_tool_cargo( builder: &Builder, compiler: Compiler, + mode: Mode, target: Interned, command: &'static str, path: &'static str, + source_type: SourceType, ) -> Command { - let mut cargo = builder.cargo(compiler, Mode::Tool, target, command); + let mut cargo = builder.cargo(compiler, mode, target, command); let dir = builder.src.join(path); cargo.arg("--manifest-path").arg(dir.join("Cargo.toml")); @@ -225,6 +263,10 @@ pub fn prepare_tool_cargo( // stages and such and it's just easier if they're not dynamically linked. cargo.env("RUSTC_NO_PREFER_DYNAMIC", "1"); + if source_type == SourceType::Submodule { + cargo.env("RUSTC_EXTERNAL_TOOL", "1"); + } + if let Some(dir) = builder.openssl_install_dir(target) { cargo.env("OPENSSL_STATIC", "1"); cargo.env("OPENSSL_DIR", dir); @@ -252,14 +294,31 @@ pub fn prepare_tool_cargo( } macro_rules! tool { - ($($name:ident, $path:expr, $tool_name:expr, $mode:expr;)+) => { - #[derive(Copy, Clone)] + ($($name:ident, $path:expr, $tool_name:expr, $mode:expr + $(,llvm_tools = $llvm:expr)* $(,is_external_tool = $external:expr)*;)+) => { + #[derive(Copy, PartialEq, Eq, Clone)] pub enum Tool { $( $name, )+ } + impl Tool { + pub fn get_mode(&self) -> Mode { + let mode = match self { + $(Tool::$name => $mode,)+ + }; + mode + } + + /// Whether this tool requires LLVM to run + pub fn uses_llvm_tools(&self) -> bool { + match self { + $(Tool::$name => false $(|| $llvm)*,)+ + } + } + } + impl<'a> Builder<'a> { pub fn tool_exe(&self, tool: Tool) -> PathBuf { let stage = self.tool_default_stage(tool); @@ -313,7 +372,12 @@ macro_rules! tool { tool: $tool_name, mode: $mode, path: $path, - is_ext_tool: false, + is_optional_tool: false, + source_type: if false $(|| $external)* { + SourceType::Submodule + } else { + SourceType::InTree + }, extra_features: Vec::new(), }).expect("expected to build -- essential tool") } @@ -323,17 +387,18 @@ macro_rules! tool { } tool!( - Rustbook, "src/tools/rustbook", "rustbook", Mode::Librustc; - ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::Librustc; - UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::Libstd; - Tidy, "src/tools/tidy", "tidy", Mode::Libstd; - Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::Libstd; - CargoTest, "src/tools/cargotest", "cargotest", Mode::Libstd; - Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest; - BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Libstd; - RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd; - RustInstaller, "src/tools/rust-installer", "fabricate", Mode::Libstd; - RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::Libstd; + Rustbook, "src/tools/rustbook", "rustbook", Mode::ToolBootstrap; + ErrorIndex, "src/tools/error_index_generator", "error_index_generator", Mode::ToolRustc; + UnstableBookGen, "src/tools/unstable-book-gen", "unstable-book-gen", Mode::ToolBootstrap; + Tidy, "src/tools/tidy", "tidy", Mode::ToolBootstrap; + Linkchecker, "src/tools/linkchecker", "linkchecker", Mode::ToolBootstrap; + CargoTest, "src/tools/cargotest", "cargotest", Mode::ToolBootstrap; + Compiletest, "src/tools/compiletest", "compiletest", Mode::ToolBootstrap, llvm_tools = true; + BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::ToolBootstrap; + RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::ToolBootstrap; + RustInstaller, "src/tools/rust-installer", "fabricate", Mode::ToolBootstrap, + is_external_tool = true; + RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes", Mode::ToolBootstrap; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] @@ -361,9 +426,10 @@ impl Step for RemoteTestServer { compiler: self.compiler, target: self.target, tool: "remote-test-server", - mode: Mode::Libstd, + mode: Mode::ToolStd, path: "src/tools/remote-test-server", - is_ext_tool: false, + is_optional_tool: false, + source_type: SourceType::InTree, extra_features: Vec::new(), }).expect("expected to build -- essential tool") } @@ -411,11 +477,15 @@ impl Step for Rustdoc { target: builder.config.build, }); - let mut cargo = prepare_tool_cargo(builder, - build_compiler, - target, - "build", - "src/tools/rustdoc"); + let mut cargo = prepare_tool_cargo( + builder, + build_compiler, + Mode::ToolRustc, + target, + "build", + "src/tools/rustdoc", + SourceType::InTree, + ); // Most tools don't get debuginfo, but rustdoc should. cargo.env("RUSTC_DEBUGINFO", builder.config.rust_debuginfo.to_string()) @@ -429,8 +499,8 @@ impl Step for Rustdoc { // Cargo adds a number of paths to the dylib search path on windows, which results in // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool" // rustdoc a different name. - let tool_rustdoc = builder.cargo_out(build_compiler, Mode::Tool, target) - .join(exe("rustdoc-tool-binary", &target_compiler.host)); + let tool_rustdoc = builder.cargo_out(build_compiler, Mode::ToolRustc, target) + .join(exe("rustdoc_tool_binary", &target_compiler.host)); // don't create a stage0-sysroot/bin directory. if target_compiler.stage > 0 { @@ -484,9 +554,10 @@ impl Step for Cargo { compiler: self.compiler, target: self.target, tool: "cargo", - mode: Mode::Librustc, + mode: Mode::ToolRustc, path: "src/tools/cargo", - is_ext_tool: false, + is_optional_tool: false, + source_type: SourceType::Submodule, extra_features: Vec::new(), }).expect("expected to build -- essential tool") } @@ -532,10 +603,11 @@ macro_rules! tool_extended { compiler: $sel.compiler, target: $sel.target, tool: $tool_name, - mode: Mode::Librustc, + mode: Mode::ToolRustc, path: $path, extra_features: $sel.extra_features, - is_ext_tool: true, + is_optional_tool: true, + source_type: SourceType::Submodule, }) } } @@ -545,6 +617,14 @@ macro_rules! tool_extended { tool_extended!((self, builder), Cargofmt, rustfmt, "src/tools/rustfmt", "cargo-fmt", {}; + CargoClippy, clippy, "src/tools/clippy", "cargo-clippy", { + // Clippy depends on procedural macros (serde), which requires a full host + // compiler to be available, so we need to depend on that. + builder.ensure(compile::Rustc { + compiler: self.compiler, + target: builder.config.build, + }); + }; Clippy, clippy, "src/tools/clippy", "clippy-driver", { // Clippy depends on procedural macros (serde), which requires a full host // compiler to be available, so we need to depend on that. @@ -560,8 +640,7 @@ tool_extended!((self, builder), target: self.target, extra_features: Vec::new(), }); - let channel = &builder.config.channel; - if clippy.is_some() && channel != "stable" && channel != "beta" { + if clippy.is_some() { self.extra_features.push("clippy".to_owned()); } builder.ensure(native::Openssl { @@ -583,7 +662,7 @@ impl<'a> Builder<'a> { pub fn tool_cmd(&self, tool: Tool) -> Command { let mut cmd = Command::new(self.tool_exe(tool)); let compiler = self.compiler(self.tool_default_stage(tool), self.config.build); - self.prepare_tool_cmd(compiler, &mut cmd); + self.prepare_tool_cmd(compiler, tool, &mut cmd); cmd } @@ -591,11 +670,15 @@ impl<'a> Builder<'a> { /// /// Notably this munges the dynamic library lookup path to point to the /// right location to run `compiler`. - fn prepare_tool_cmd(&self, compiler: Compiler, cmd: &mut Command) { + fn prepare_tool_cmd(&self, compiler: Compiler, tool: Tool, cmd: &mut Command) { let host = &compiler.host; - let mut paths: Vec = vec![ - PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)), - self.cargo_out(compiler, Mode::Tool, *host).join("deps"), + let mut lib_paths: Vec = vec![ + if compiler.stage == 0 && tool != Tool::ErrorIndex { + self.build.rustc_snapshot_libdir() + } else { + PathBuf::from(&self.sysroot_libdir(compiler, compiler.host)) + }, + self.cargo_out(compiler, tool.get_mode(), *host).join("deps"), ]; // On MSVC a tool may invoke a C compiler (e.g. compiletest in run-make @@ -610,11 +693,48 @@ impl<'a> Builder<'a> { } for path in env::split_paths(v) { if !curpaths.contains(&path) { - paths.push(path); + lib_paths.push(path); } } } } - add_lib_path(paths, cmd); + + // Add the llvm/bin directory to PATH since it contains lots of + // useful, platform-independent tools + if tool.uses_llvm_tools() { + if let Some(llvm_bin_path) = self.llvm_bin_path() { + if host.contains("windows") { + // On Windows, PATH and the dynamic library path are the same, + // so we just add the LLVM bin path to lib_path + lib_paths.push(llvm_bin_path); + } else { + let old_path = env::var_os("PATH").unwrap_or_default(); + let new_path = env::join_paths(iter::once(llvm_bin_path) + .chain(env::split_paths(&old_path))) + .expect("Could not add LLVM bin path to PATH"); + cmd.env("PATH", new_path); + } + } + } + + add_lib_path(lib_paths, cmd); + } + + fn llvm_bin_path(&self) -> Option { + if self.config.llvm_enabled && !self.config.dry_run { + let llvm_config = self.ensure(native::Llvm { + target: self.config.build, + emscripten: false, + }); + + // Add the llvm/bin directory to PATH since it contains lots of + // useful, platform-independent tools + let llvm_bin_path = llvm_config.parent() + .expect("Expected llvm-config to be contained in directory"); + assert!(llvm_bin_path.is_dir()); + Some(llvm_bin_path.to_path_buf()) + } else { + None + } } } diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index 9a2b9e90440e5..be03796921af8 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -92,10 +92,7 @@ pub fn push_exe_path(mut buf: PathBuf, components: &[&str]) -> PathBuf { file.push_str(".exe"); } - for c in components { - buf.push(c); - } - + buf.extend(components); buf.push(file); buf diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index 2f9953330f42c..1cbb8e49bfa15 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -13,6 +13,7 @@ use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; use std::time::{SystemTime, UNIX_EPOCH}; use std::{env, fs}; +use std::thread; /// A helper macro to `unwrap` a result except also print out details like: /// @@ -179,7 +180,9 @@ pub struct NativeLibBoilerplate { impl Drop for NativeLibBoilerplate { fn drop(&mut self) { - t!(File::create(self.out_dir.join("rustbuild.timestamp"))); + if !thread::panicking() { + t!(File::create(self.out_dir.join("rustbuild.timestamp"))); + } } } @@ -223,24 +226,34 @@ pub fn native_lib_boilerplate( } } -pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) -> Result { - let (link_name, search_path) = match &*env::var("TARGET").unwrap() { +pub fn sanitizer_lib_boilerplate(sanitizer_name: &str) + -> Result<(NativeLibBoilerplate, String), ()> +{ + let (link_name, search_path, dynamic) = match &*env::var("TARGET").unwrap() { "x86_64-unknown-linux-gnu" => ( format!("clang_rt.{}-x86_64", sanitizer_name), "build/lib/linux", + false, ), "x86_64-apple-darwin" => ( - format!("dylib=clang_rt.{}_osx_dynamic", sanitizer_name), + format!("clang_rt.{}_osx_dynamic", sanitizer_name), "build/lib/darwin", + true, ), _ => return Err(()), }; - native_lib_boilerplate( + let to_link = if dynamic { + format!("dylib={}", link_name) + } else { + format!("static={}", link_name) + }; + let lib = native_lib_boilerplate( "libcompiler_builtins/compiler-rt", sanitizer_name, - &link_name, + &to_link, search_path, - ) + )?; + Ok((lib, link_name)) } fn dir_up_to_date(src: &Path, threshold: SystemTime) -> bool { diff --git a/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile b/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile new file mode 100644 index 0000000000000..34c6e640abb7c --- /dev/null +++ b/src/ci/docker/disabled/dist-armebv7r-none-eabihf/Dockerfile @@ -0,0 +1,36 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + xz-utils \ + bzip2 \ + libssl-dev \ + pkg-config + + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV BASE_URL=https://releases.linaro.org/components/toolchain/binaries/latest/armeb-eabi/ +ENV GCC_LINARO=gcc-linaro-7.2.1-2017.11-x86_64_armeb-eabi + +RUN curl -sL $BASE_URL/$GCC_LINARO.tar.xz | tar -xJ + +ENV PATH=$PATH:/$GCC_LINARO/bin + +ENV TARGET=armebv7r-none-eabihf + +ENV CC_armebv7r_none_eabihf=armeb-eabi-gcc \ + CFLAGS_armebv7r_none_eabihf="-march=armv7-r" + +ENV RUST_CONFIGURE_ARGS --disable-docs + +ENV SCRIPT python2.7 ../x.py dist --target $TARGET diff --git a/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile b/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile new file mode 100644 index 0000000000000..952c265a1390b --- /dev/null +++ b/src/ci/docker/disabled/dist-sparc64-linux/Dockerfile @@ -0,0 +1,26 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + xz-utils \ + g++-sparc64-linux-gnu \ + libssl-dev \ + pkg-config + + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +ENV HOSTS=sparc64-unknown-linux-gnu + +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile index e12bed3abc5ad..ba2d32a9296b4 100644 --- a/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile +++ b/src/ci/docker/dist-i586-gnu-i586-i686-musl/Dockerfile @@ -42,9 +42,7 @@ ENV RUST_CONFIGURE_ARGS \ # See: https://github.com/rust-lang/rust/issues/34978 ENV CFLAGS_i686_unknown_linux_musl=-Wa,-mrelax-relocations=no ENV CFLAGS_i586_unknown_linux_gnu=-Wa,-mrelax-relocations=no -# FIXME remove -Wl,-melf_i386 after cc is updated to include -# https://github.com/alexcrichton/cc-rs/pull/281 -ENV CFLAGS_i586_unknown_linux_musl="-Wa,-mrelax-relocations=no -Wl,-melf_i386" +ENV CFLAGS_i586_unknown_linux_musl=-Wa,-mrelax-relocations=no ENV TARGETS=i586-unknown-linux-gnu,i686-unknown-linux-musl diff --git a/src/ci/docker/dist-i686-linux/Dockerfile b/src/ci/docker/dist-i686-linux/Dockerfile index 0ec57ee088687..d591fb28f36ed 100644 --- a/src/ci/docker/dist-i686-linux/Dockerfile +++ b/src/ci/docker/dist-i686-linux/Dockerfile @@ -29,13 +29,13 @@ ENV PATH=/rustroot/bin:$PATH ENV LD_LIBRARY_PATH=/rustroot/lib64:/rustroot/lib ENV PKG_CONFIG_PATH=/rustroot/lib/pkgconfig WORKDIR /tmp -COPY dist-i686-linux/shared.sh dist-i686-linux/build-binutils.sh /tmp/ +COPY dist-x86_64-linux/shared.sh /tmp/ # We need a build of openssl which supports SNI to download artifacts from # static.rust-lang.org. This'll be used to link into libcurl below (and used # later as well), so build a copy of OpenSSL with dynamic libraries into our # generic root. -COPY dist-i686-linux/build-openssl.sh /tmp/ +COPY dist-x86_64-linux/build-openssl.sh /tmp/ RUN ./build-openssl.sh # The `curl` binary on CentOS doesn't support SNI which is needed for fetching @@ -44,36 +44,43 @@ RUN ./build-openssl.sh # # Note that we also disable a bunch of optional features of curl that we don't # really need. -COPY dist-i686-linux/build-curl.sh /tmp/ +COPY dist-x86_64-linux/build-curl.sh /tmp/ RUN ./build-curl.sh # binutils < 2.22 has a bug where the 32-bit executables it generates # immediately segfault in Rust, so we need to install our own binutils. # # See https://github.com/rust-lang/rust/issues/20440 for more info +COPY dist-x86_64-linux/build-binutils.sh /tmp/ RUN ./build-binutils.sh +# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS +# only has 2.6.4, so build our own +COPY dist-x86_64-linux/build-cmake.sh /tmp/ +RUN ./build-cmake.sh + # Need a newer version of gcc than centos has to compile LLVM nowadays -COPY dist-i686-linux/build-gcc.sh /tmp/ +COPY dist-x86_64-linux/build-gcc.sh /tmp/ RUN ./build-gcc.sh # CentOS 5.5 has Python 2.4 by default, but LLVM needs 2.7+ -COPY dist-i686-linux/build-python.sh /tmp/ +COPY dist-x86_64-linux/build-python.sh /tmp/ RUN ./build-python.sh +# Now build LLVM+Clang 6, afterwards configuring further compilations to use the +# clang/clang++ compilers. +COPY dist-x86_64-linux/build-clang.sh /tmp/ +RUN ./build-clang.sh +ENV CC=clang CXX=clang++ + # Apparently CentOS 5.5 desn't have `git` in yum, but we're gonna need it for # cloning, so download and build it here. -COPY dist-i686-linux/build-git.sh /tmp/ +COPY dist-x86_64-linux/build-git.sh /tmp/ RUN ./build-git.sh -# libssh2 (a dependency of Cargo) requires cmake 2.8.11 or higher but CentOS -# only has 2.6.4, so build our own -COPY dist-i686-linux/build-cmake.sh /tmp/ -RUN ./build-cmake.sh - # for sanitizers, we need kernel headers files newer than the ones CentOS ships # with so we install newer ones here -COPY dist-i686-linux/build-headers.sh /tmp/ +COPY dist-x86_64-linux/build-headers.sh /tmp/ RUN ./build-headers.sh COPY scripts/sccache.sh /scripts/ @@ -84,11 +91,21 @@ ENV HOSTS=i686-unknown-linux-gnu ENV RUST_CONFIGURE_ARGS \ --enable-full-tools \ --enable-sanitizers \ - --enable-profiler + --enable-profiler \ + --set target.i686-unknown-linux-gnu.linker=clang \ + --build=i686-unknown-linux-gnu ENV SCRIPT python2.7 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS - -# This is the only builder which will create source tarballs -ENV DIST_SRC 1 +ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=clang + +# This was added when we switched from gcc to clang. It's not clear why this is +# needed unfortunately, but without this the stage1 bootstrap segfaults +# somewhere inside of a build script. The build ends up just hanging instead of +# actually killing the process that segfaulted, but if the process is run +# manually in a debugger the segfault is immediately seen as well as the +# misaligned stack access. +# +# Added in #50200 there's some more logs there +ENV CFLAGS -mstackrealign # When we build cargo in this container, we don't want it to use the system # libcurl, instead it should compile its own. diff --git a/src/ci/docker/dist-i686-linux/build-binutils.sh b/src/ci/docker/dist-i686-linux/build-binutils.sh deleted file mode 100755 index f4bdbd80d0edb..0000000000000 --- a/src/ci/docker/dist-i686-linux/build-binutils.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex - -source shared.sh - -curl https://ftp.gnu.org/gnu/binutils/binutils-2.25.1.tar.bz2 | tar xfj - - -mkdir binutils-build -cd binutils-build -hide_output ../binutils-2.25.1/configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf binutils-build -rm -rf binutils-2.25.1 diff --git a/src/ci/docker/dist-i686-linux/build-cmake.sh b/src/ci/docker/dist-i686-linux/build-cmake.sh deleted file mode 100755 index 9a3763d421ad2..0000000000000 --- a/src/ci/docker/dist-i686-linux/build-cmake.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -curl https://cmake.org/files/v3.6/cmake-3.6.3.tar.gz | tar xzf - - -mkdir cmake-build -cd cmake-build -hide_output ../cmake-3.6.3/configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf cmake-build -rm -rf cmake-3.6.3 diff --git a/src/ci/docker/dist-i686-linux/build-curl.sh b/src/ci/docker/dist-i686-linux/build-curl.sh deleted file mode 100755 index edf3175b81c43..0000000000000 --- a/src/ci/docker/dist-i686-linux/build-curl.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -VERSION=7.51.0 - -curl http://cool.haxx.se/download/curl-$VERSION.tar.bz2 | tar xjf - - -mkdir curl-build -cd curl-build -hide_output ../curl-$VERSION/configure \ - --prefix=/rustroot \ - --with-ssl=/rustroot \ - --disable-sspi \ - --disable-gopher \ - --disable-smtp \ - --disable-smb \ - --disable-imap \ - --disable-pop3 \ - --disable-tftp \ - --disable-telnet \ - --disable-manual \ - --disable-dict \ - --disable-rtsp \ - --disable-ldaps \ - --disable-ldap -hide_output make -j10 -hide_output make install - -cd .. -rm -rf curl-build -rm -rf curl-$VERSION -yum erase -y curl diff --git a/src/ci/docker/dist-i686-linux/build-gcc.sh b/src/ci/docker/dist-i686-linux/build-gcc.sh deleted file mode 100755 index 08020e533ff19..0000000000000 --- a/src/ci/docker/dist-i686-linux/build-gcc.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex - -source shared.sh - -GCC=4.8.5 - -curl https://ftp.gnu.org/gnu/gcc/gcc-$GCC/gcc-$GCC.tar.bz2 | tar xjf - -cd gcc-$GCC - -# FIXME(#49246): Remove the `sed` below. -# -# On 2018 March 21st, two Travis builders' cache for Docker are suddenly invalidated. Normally this -# is fine, because we just need to rebuild the Docker image. However, it reveals a network issue: -# downloading from `ftp://gcc.gnu.org/` from Travis (using passive mode) often leads to "Connection -# timed out" error, and even when the download completed, the file is usually corrupted. This causes -# nothing to be landed that day. -# -# We observed that the `gcc-4.8.5.tar.bz2` above can be downloaded successfully, so as a stability -# improvement we try to download from the HTTPS mirror instead. Turns out this uncovered the third -# bug: the host `gcc.gnu.org` and `cygwin.com` share the same IP, and the TLS certificate of the -# latter host is presented to `wget`! Therefore, we choose to download from the insecure HTTP server -# instead here. -# -sed -i'' 's|ftp://gcc\.gnu\.org/|http://gcc.gnu.org/|g' ./contrib/download_prerequisites - -./contrib/download_prerequisites -mkdir ../gcc-build -cd ../gcc-build -hide_output ../gcc-$GCC/configure \ - --prefix=/rustroot \ - --enable-languages=c,c++ -hide_output make -j10 -hide_output make install -ln -nsf gcc /rustroot/bin/cc - -cd .. -rm -rf gcc-build -rm -rf gcc-$GCC -yum erase -y gcc gcc-c++ binutils diff --git a/src/ci/docker/dist-i686-linux/build-git.sh b/src/ci/docker/dist-i686-linux/build-git.sh deleted file mode 100755 index aa31f50ba0343..0000000000000 --- a/src/ci/docker/dist-i686-linux/build-git.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - - -cd git-2.10.0 -make configure -hide_output ./configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf git-2.10.0 diff --git a/src/ci/docker/dist-i686-linux/build-headers.sh b/src/ci/docker/dist-i686-linux/build-headers.sh deleted file mode 100755 index 2f15114d6f980..0000000000000 --- a/src/ci/docker/dist-i686-linux/build-headers.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x - -cd linux-3.2.84 -hide_output make mrproper -hide_output make INSTALL_HDR_PATH=dest headers_install - -find dest/include \( -name .install -o -name ..install.cmd \) -delete -yes | cp -fr dest/include/* /usr/include - -cd .. -rm -rf linux-3.2.84 diff --git a/src/ci/docker/dist-i686-linux/build-openssl.sh b/src/ci/docker/dist-i686-linux/build-openssl.sh deleted file mode 100755 index e7226ace020bd..0000000000000 --- a/src/ci/docker/dist-i686-linux/build-openssl.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -VERSION=1.0.2k -URL=https://s3-us-west-1.amazonaws.com/rust-lang-ci2/rust-ci-mirror/openssl-$VERSION.tar.gz - -curl $URL | tar xzf - - -cd openssl-$VERSION -hide_output ./config --prefix=/rustroot shared -fPIC -hide_output make -j10 -hide_output make install -cd .. -rm -rf openssl-$VERSION - -# Make the system cert collection available to the new install. -ln -nsf /etc/pki/tls/cert.pem /rustroot/ssl/ diff --git a/src/ci/docker/dist-i686-linux/build-python.sh b/src/ci/docker/dist-i686-linux/build-python.sh deleted file mode 100755 index c6b8cdde4b9af..0000000000000 --- a/src/ci/docker/dist-i686-linux/build-python.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -set -ex -source shared.sh - -curl https://www.python.org/ftp/python/2.7.12/Python-2.7.12.tgz | \ - tar xzf - - -mkdir python-build -cd python-build - -# Gotta do some hackery to tell python about our custom OpenSSL build, but other -# than that fairly normal. -CFLAGS='-I /rustroot/include' LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ - hide_output ../Python-2.7.12/configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf python-build -rm -rf Python-2.7.12 diff --git a/src/ci/docker/dist-i686-linux/shared.sh b/src/ci/docker/dist-i686-linux/shared.sh deleted file mode 100644 index 97e6d2908cf8a..0000000000000 --- a/src/ci/docker/dist-i686-linux/shared.sh +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2017 The Rust Project Developers. See the COPYRIGHT -# file at the top-level directory of this distribution and at -# http://rust-lang.org/COPYRIGHT. -# -# Licensed under the Apache License, Version 2.0 or the MIT license -# , at your -# option. This file may not be copied, modified, or distributed -# except according to those terms. - -hide_output() { - set +x - on_err=" -echo ERROR: An error was encountered with the build. -cat /tmp/build.log -exit 1 -" - trap "$on_err" ERR - bash -c "while true; do sleep 30; echo \$(date) - building ...; done" & - PING_LOOP_PID=$! - $@ &> /tmp/build.log - trap - ERR - kill $PING_LOOP_PID - set -x -} diff --git a/src/ci/docker/dist-various-1/Dockerfile b/src/ci/docker/dist-various-1/Dockerfile index b195decfcf574..6302f550091ad 100644 --- a/src/ci/docker/dist-various-1/Dockerfile +++ b/src/ci/docker/dist-various-1/Dockerfile @@ -80,6 +80,11 @@ RUN \ echo "# a" >> /usr/local/mips-linux-musl/bin/mips-openwrt-linux-musl-wrapper.sh && \ echo "# b" >> /usr/local/mipsel-linux-musl/bin/mipsel-openwrt-linux-musl-wrapper.sh +ENV RUN_MAKE_TARGETS=thumbv6m-none-eabi +ENV RUN_MAKE_TARGETS=$RUN_MAKE_TARGETS,thumbv7m-none-eabi +ENV RUN_MAKE_TARGETS=$RUN_MAKE_TARGETS,thumbv7em-none-eabi +ENV RUN_MAKE_TARGETS=$RUN_MAKE_TARGETS,thumbv7em-none-eabihf + ENV TARGETS=asmjs-unknown-emscripten ENV TARGETS=$TARGETS,wasm32-unknown-emscripten ENV TARGETS=$TARGETS,x86_64-rumprun-netbsd @@ -98,16 +103,10 @@ ENV TARGETS=$TARGETS,thumbv7m-none-eabi ENV TARGETS=$TARGETS,thumbv7em-none-eabi ENV TARGETS=$TARGETS,thumbv7em-none-eabihf -# FIXME: remove armv5te vars after https://github.com/alexcrichton/cc-rs/issues/271 -# get fixed and cc update ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \ CC_sparc64_unknown_linux_gnu=sparc64-linux-gnu-gcc \ - CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc \ - CC_armv5te_unknown_linux_gnueabi=arm-linux-gnueabi-gcc \ - CFLAGS_armv5te_unknown_linux_gnueabi="-march=armv5te -marm -mfloat-abi=soft" \ - CC_armv5te_unknown_linux_musleabi=arm-linux-gnueabi-gcc \ - CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" + CC_x86_64_unknown_redox=x86_64-unknown-redox-gcc ENV RUST_CONFIGURE_ARGS \ --musl-root-armv5te=/musl-armv5te \ @@ -120,7 +119,9 @@ ENV RUST_CONFIGURE_ARGS \ --enable-emscripten \ --disable-docs -ENV SCRIPT python2.7 ../x.py dist --target $TARGETS +ENV SCRIPT \ + python2.7 ../x.py test --target $RUN_MAKE_TARGETS src/test/run-make && \ + python2.7 ../x.py dist --target $TARGETS # sccache COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/dist-various-2/Dockerfile b/src/ci/docker/dist-various-2/Dockerfile index e8d6c12de4474..7adb32efa1d41 100644 --- a/src/ci/docker/dist-various-2/Dockerfile +++ b/src/ci/docker/dist-various-2/Dockerfile @@ -34,12 +34,12 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV \ - AR_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-ar \ - CC_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang \ - CXX_x86_64_unknown_fuchsia=x86_64-unknown-fuchsia-clang++ \ - AR_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-ar \ - CC_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang \ - CXX_aarch64_unknown_fuchsia=aarch64-unknown-fuchsia-clang++ \ + AR_x86_64_fuchsia=x86_64-fuchsia-ar \ + CC_x86_64_fuchsia=x86_64-fuchsia-clang \ + CXX_x86_64_fuchsia=x86_64-fuchsia-clang++ \ + AR_aarch64_fuchsia=aarch64-fuchsia-ar \ + CC_aarch64_fuchsia=aarch64-fuchsia-clang \ + CXX_aarch64_fuchsia=aarch64-fuchsia-clang++ \ AR_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-ar \ CC_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-gcc \ CXX_sparcv9_sun_solaris=sparcv9-sun-solaris2.10-g++ \ @@ -47,8 +47,8 @@ ENV \ CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \ CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ -ENV TARGETS=x86_64-unknown-fuchsia -ENV TARGETS=$TARGETS,aarch64-unknown-fuchsia +ENV TARGETS=x86_64-fuchsia +ENV TARGETS=$TARGETS,aarch64-fuchsia ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,wasm32-unknown-unknown ENV TARGETS=$TARGETS,x86_64-sun-solaris diff --git a/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh b/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh index ef8f0c37f8c37..ec19f7c4f45d9 100755 --- a/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh +++ b/src/ci/docker/dist-various-2/build-fuchsia-toolchain.sh @@ -39,7 +39,7 @@ build() { esac hide_output make -j$(getconf _NPROCESSORS_ONLN) $tgt - dst=/usr/local/${arch}-unknown-fuchsia + dst=/usr/local/${arch}-fuchsia mkdir -p $dst cp -a build-${tgt}/sysroot/include $dst/ cp -a build-${tgt}/sysroot/lib $dst/ @@ -55,11 +55,11 @@ rm -rf zircon for arch in x86_64 aarch64; do for tool in clang clang++; do - cat >/usr/local/bin/${arch}-unknown-fuchsia-${tool} </usr/local/bin/${arch}-fuchsia-${tool} < or the MIT license +# , at your +# option. This file may not be copied, modified, or distributed +# except according to those terms. + +set -ex + +source shared.sh + +LLVM=6.0.0 + +mkdir clang +cd clang + +curl https://releases.llvm.org/$LLVM/llvm-$LLVM.src.tar.xz | \ + xz -d | \ + tar xf - + +cd llvm-$LLVM.src + +mkdir -p tools/clang + +curl https://releases.llvm.org/$LLVM/cfe-$LLVM.src.tar.xz | \ + xz -d | \ + tar xf - -C tools/clang --strip-components=1 + +mkdir ../clang-build +cd ../clang-build + +# For whatever reason the default set of include paths for clang is different +# than that of gcc. As a result we need to manually include our sysroot's +# include path, /rustroot/include, to clang's default include path. +# +# Alsow there's this weird oddity with gcc where there's an 'include-fixed' +# directory that it generates. It turns out [1] that Centos 5's headers are so +# old that they're incompatible with modern C semantics. While gcc automatically +# fixes that clang doesn't account for this. Tell clang to manually include the +# fixed headers so we can successfully compile code later on. +# +# [1]: https://sourceware.org/ml/crossgcc/2008-11/msg00028.html +INC="/rustroot/include" +INC="$INC:/rustroot/lib/gcc/x86_64-unknown-linux-gnu/4.8.5/include-fixed" +INC="$INC:/usr/include" + +hide_output \ + cmake ../llvm-$LLVM.src \ + -DCMAKE_C_COMPILER=/rustroot/bin/gcc \ + -DCMAKE_CXX_COMPILER=/rustroot/bin/g++ \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/rustroot \ + -DLLVM_TARGETS_TO_BUILD=X86 \ + -DC_INCLUDE_DIRS="$INC" + +hide_output make -j10 +hide_output make install + +cd ../.. +rm -rf clang diff --git a/src/ci/docker/dist-x86_64-linux/build-gcc.sh b/src/ci/docker/dist-x86_64-linux/build-gcc.sh index 08020e533ff19..62ea2506f4ef8 100755 --- a/src/ci/docker/dist-x86_64-linux/build-gcc.sh +++ b/src/ci/docker/dist-x86_64-linux/build-gcc.sh @@ -42,7 +42,6 @@ hide_output ../gcc-$GCC/configure \ --enable-languages=c,c++ hide_output make -j10 hide_output make install -ln -nsf gcc /rustroot/bin/cc cd .. rm -rf gcc-build diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh index c470ae7eb3030..b1ee636644ec7 100755 --- a/src/ci/docker/run.sh +++ b/src/ci/docker/run.sh @@ -36,8 +36,10 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then s3url="s3://$SCCACHE_BUCKET/docker/$cksum" url="https://s3-us-west-1.amazonaws.com/$SCCACHE_BUCKET/docker/$cksum" echo "Attempting to download $s3url" + rm -f /tmp/rustci_docker_cache set +e - loaded_images=$(curl $url | docker load | sed 's/.* sha/sha/') + retry curl -f -L -C - -o /tmp/rustci_docker_cache "$url" + loaded_images=$(docker load -i /tmp/rustci_docker_cache | sed 's/.* sha/sha/') set -e echo "Downloaded containers:\n$loaded_images" fi @@ -97,6 +99,7 @@ objdir=$root_dir/obj mkdir -p $HOME/.cargo mkdir -p $objdir/tmp +mkdir -p $objdir/cores args= if [ "$SCCACHE_BUCKET" != "" ]; then @@ -116,6 +119,10 @@ fi # goes ahead and sets it for all builders. args="$args --privileged" +if [ "$CI" != "" ]; then + args="$args --dns 8.8.8.8 --dns 8.8.4.4 --dns 1.1.1.1 --dns 1.0.0.1" +fi + exec docker \ run \ --volume "$root_dir:/checkout:ro" \ diff --git a/src/ci/docker/scripts/musl.sh b/src/ci/docker/scripts/musl.sh index f87ba8fe4e60e..4ca7389d6d1a5 100644 --- a/src/ci/docker/scripts/musl.sh +++ b/src/ci/docker/scripts/musl.sh @@ -32,11 +32,17 @@ shift export CFLAGS="-fPIC $CFLAGS" -MUSL=musl-1.1.18 +# FIXME: remove the patch when upate to 1.1.20 +MUSL=musl-1.1.19 # may have been downloaded in a previous run if [ ! -d $MUSL ]; then curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf - + # Patch to fix https://github.com/rust-lang/rust/issues/48967 + cd $MUSL && \ + curl "https://git.musl-libc.org/cgit/musl/patch/?id=610c5a8524c3d6cd3ac5a5f1231422e7648a3791" |\ + patch -p1 && \ + cd - fi cd $MUSL diff --git a/src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile deleted file mode 100644 index 6b8186048988d..0000000000000 --- a/src/ci/docker/x86_64-gnu-llvm-3.9/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -FROM ubuntu:16.04 - -RUN apt-get update && apt-get install -y --no-install-recommends \ - g++ \ - make \ - file \ - curl \ - ca-certificates \ - python2.7 \ - git \ - cmake \ - sudo \ - gdb \ - llvm-3.9-tools \ - libedit-dev \ - zlib1g-dev \ - xz-utils - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -# using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-3.9 \ - --enable-llvm-link-shared -ENV RUST_CHECK_TARGET check diff --git a/src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile b/src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile new file mode 100644 index 0000000000000..4f90c5097260c --- /dev/null +++ b/src/ci/docker/x86_64-gnu-llvm-5.0/Dockerfile @@ -0,0 +1,27 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y --no-install-recommends \ + g++ \ + make \ + file \ + curl \ + ca-certificates \ + python2.7 \ + git \ + cmake \ + sudo \ + gdb \ + llvm-5.0-tools \ + libedit-dev \ + zlib1g-dev \ + xz-utils + +COPY scripts/sccache.sh /scripts/ +RUN sh /scripts/sccache.sh + +# using llvm-link-shared due to libffi issues -- see #34486 +ENV RUST_CONFIGURE_ARGS \ + --build=x86_64-unknown-linux-gnu \ + --llvm-root=/usr/lib/llvm-5.0 \ + --enable-llvm-link-shared +ENV RUST_CHECK_TARGET check diff --git a/src/ci/docker/x86_64-gnu-tools/checkregression.py b/src/ci/docker/x86_64-gnu-tools/checkregression.py index df791d12645fd..208aab434ce1f 100755 --- a/src/ci/docker/x86_64-gnu-tools/checkregression.py +++ b/src/ci/docker/x86_64-gnu-tools/checkregression.py @@ -18,6 +18,7 @@ os_name = sys.argv[1] toolstate_file = sys.argv[2] current_state = sys.argv[3] + verb = sys.argv[4] # 'regressed' or 'changed' with open(toolstate_file, 'r') as f: toolstate = json.load(f) @@ -29,10 +30,17 @@ tool = cur['tool'] state = cur[os_name] new_state = toolstate.get(tool, '') - if new_state < state: + if verb == 'regressed': + updated = new_state < state + elif verb == 'changed': + updated = new_state != state + else: + print('Unknown verb {}'.format(updated)) + sys.exit(2) + if updated: print( - 'Error: The state of "{}" has regressed from "{}" to "{}"' - .format(tool, state, new_state) + 'The state of "{}" has {} from "{}" to "{}"' + .format(tool, verb, state, new_state) ) regressed = True diff --git a/src/ci/docker/x86_64-gnu-tools/checktools.sh b/src/ci/docker/x86_64-gnu-tools/checktools.sh index 3fed0175371a7..16055078ad5eb 100755 --- a/src/ci/docker/x86_64-gnu-tools/checktools.sh +++ b/src/ci/docker/x86_64-gnu-tools/checktools.sh @@ -23,21 +23,25 @@ SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))" touch "$TOOLSTATE_FILE" +# Try to test all the tools and store the build/test success in the TOOLSTATE_FILE + set +e python2.7 "$X_PY" test --no-fail-fast \ src/doc/book \ src/doc/nomicon \ src/doc/reference \ src/doc/rust-by-example \ + src/tools/clippy \ src/tools/rls \ src/tools/rustfmt \ src/tools/miri \ - src/tools/clippy + set -e cat "$TOOLSTATE_FILE" echo +# This function checks that if a tool's submodule changed, the tool's state must improve verify_status() { echo "Verifying status of $1..." if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then @@ -57,35 +61,63 @@ verify_status() { fi } +# deduplicates the submodule check and the assertion that on beta some tools MUST be passing +check_dispatch() { + if [ "$1" = submodule_changed ]; then + # ignore $2 (branch id) + verify_status $3 $4 + elif [ "$2" = beta ]; then + echo "Requiring test passing for $3..." + if grep -q '"'"$3"'":"\(test\|build\)-fail"' "$TOOLSTATE_FILE"; then + exit 4 + fi + fi +} + +# list all tools here +status_check() { + check_dispatch $1 beta book src/doc/book + check_dispatch $1 beta nomicon src/doc/nomicon + check_dispatch $1 beta reference src/doc/reference + check_dispatch $1 beta rust-by-example src/doc/rust-by-example + check_dispatch $1 beta rls src/tools/rls + check_dispatch $1 beta rustfmt src/tools/rustfmt + check_dispatch $1 beta clippy-driver src/tools/clippy + # these tools are not required for beta to successfully branch + check_dispatch $1 nightly miri src/tools/miri +} + # If this PR is intended to update one of these tools, do not let the build pass # when they do not test-pass. -verify_status book src/doc/book -verify_status nomicon src/doc/nomicon -verify_status reference src/doc/reference -verify_status rust-by-example src/doc/rust-by-example -verify_status rls src/tool/rls -verify_status rustfmt src/tool/rustfmt -verify_status clippy-driver src/tool/clippy -verify_status miri src/tool/miri - -if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then - . "$(dirname $0)/repo.sh" - MESSAGE_FILE=$(mktemp -t msg.XXXXXX) - echo "($OS CI update)" > "$MESSAGE_FILE" - commit_toolstate_change "$MESSAGE_FILE" \ +status_check "submodule_changed" + +CHECK_NOT="$(readlink -f "$(dirname $0)/checkregression.py")" +change_toolstate() { + # only update the history + if python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" changed; then + echo 'Toolstate is not changed. Not updating.' + else + if [ $SIX_WEEK_CYCLE -eq 5 ]; then + python2.7 "$CHECK_NOT" "$OS" "$TOOLSTATE_FILE" "_data/latest.json" regressed + fi sed -i "1 a\\ $COMMIT\t$(cat "$TOOLSTATE_FILE") " "history/$OS.tsv" - # if we are at the last week in the 6-week release cycle, reject any kind of regression. - if [ $SIX_WEEK_CYCLE -eq 5 ]; then - python2.7 "$(dirname $0)/checkregression.py" \ - "$OS" "$TOOLSTATE_FILE" "rust-toolstate/_data/latest.json" fi - rm -f "$MESSAGE_FILE" +} + +if [ "$RUST_RELEASE_CHANNEL" = nightly ]; then + if [ -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then + . "$(dirname $0)/repo.sh" + MESSAGE_FILE=$(mktemp -t msg.XXXXXX) + echo "($OS CI update)" > "$MESSAGE_FILE" + commit_toolstate_change "$MESSAGE_FILE" change_toolstate + rm -f "$MESSAGE_FILE" + fi exit 0 fi -if grep -q fail "$TOOLSTATE_FILE"; then - exit 4 -fi +# abort compilation if an important tool doesn't build +# (this code is reachable if not on the nightly channel) +status_check "beta_required" diff --git a/src/ci/docker/x86_64-gnu-tools/repo.sh b/src/ci/docker/x86_64-gnu-tools/repo.sh index c10afef753e81..807e6fb7b642e 100644 --- a/src/ci/docker/x86_64-gnu-tools/repo.sh +++ b/src/ci/docker/x86_64-gnu-tools/repo.sh @@ -60,7 +60,7 @@ commit_toolstate_change() { OLDFLAGS="$-" set -eu - git config --global user.email '34210020+rust-toolstate-update@users.noreply.github.com' + git config --global user.email '7378925+rust-toolstate-update@users.noreply.github.com' git config --global user.name 'Rust Toolstate Update' git config --global credential.helper store printf 'https://%s:x-oauth-basic@github.com\n' "$TOOLSTATE_REPO_ACCESS_TOKEN" \ diff --git a/src/ci/run.sh b/src/ci/run.sh index 456f8cc7317e7..09a0cf3541d8d 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -24,13 +24,16 @@ if [ "$NO_CHANGE_USER" = "" ]; then fi fi +# only enable core dump on Linux +if [ -f /proc/sys/kernel/core_pattern ]; then + ulimit -c unlimited +fi + ci_dir=`cd $(dirname $0) && pwd` source "$ci_dir/shared.sh" -if [ "$TRAVIS" == "true" ] && [ "$TRAVIS_BRANCH" != "auto" ]; then - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests" -else - RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings" +if [ "$TRAVIS" != "true" ] || [ "$TRAVIS_BRANCH" == "auto" ]; then + RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set build.print-step-timings --enable-verbose-tests" fi RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache" diff --git a/src/ci/shared.sh b/src/ci/shared.sh index 4a08683e3ee86..bb6945f0fd6bb 100644 --- a/src/ci/shared.sh +++ b/src/ci/shared.sh @@ -21,11 +21,12 @@ function retry { while true; do "$@" && break || { if [[ $n -lt $max ]]; then + sleep $n # don't retry immediately ((n++)) echo "Command failed. Attempt $n/$max:" else echo "The command has failed after $n attempts." - exit 1 + return 1 fi } done diff --git a/src/doc/book b/src/doc/book index f51127530d46b..f475da63a18d5 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit f51127530d46b9acbf4747c859da185e771cfcf3 +Subproject commit f475da63a18d50217459a601cbef69a4bcac5e71 diff --git a/src/doc/grammar.md b/src/doc/grammar.md index 78432b6a96593..ee9135b6578f6 100644 --- a/src/doc/grammar.md +++ b/src/doc/grammar.md @@ -101,29 +101,24 @@ properties: `ident`, `non_null`, `non_eol`, `non_single_quote` and ### Identifiers -The `ident` production is any nonempty Unicode[^non_ascii_idents] string of +The `ident` production is any nonempty Unicode string of the following form: -[^non_ascii_idents]: Non-ASCII characters in identifiers are currently feature - gated. This is expected to improve soon. +- The first character is in one of the following ranges `U+0041` to `U+005A` +("A" to "Z"), `U+0061` to `U+007A` ("a" to "z"), or `U+005F` ("\_"). +- The remaining characters are in the range `U+0030` to `U+0039` ("0" to "9"), +or any of the prior valid initial characters. -- The first character has property `XID_start` -- The remaining characters have property `XID_continue` - -that does _not_ occur in the set of [keywords](#keywords). - -> **Note**: `XID_start` and `XID_continue` as character properties cover the -> character ranges used to form the more familiar C and Java language-family -> identifiers. +as long as the identifier does _not_ occur in the set of [keywords](#keywords). ### Delimiter-restricted productions Some productions are defined by exclusion of particular Unicode characters: - `non_null` is any single Unicode character aside from `U+0000` (null) -- `non_eol` is `non_null` restricted to exclude `U+000A` (`'\n'`) -- `non_single_quote` is `non_null` restricted to exclude `U+0027` (`'`) -- `non_double_quote` is `non_null` restricted to exclude `U+0022` (`"`) +- `non_eol` is any single Unicode character aside from `U+000A` (`'\n'`) +- `non_single_quote` is any single Unicode character aside from `U+0027` (`'`) +- `non_double_quote` is any single Unicode character aside from `U+0022` (`"`) ## Comments diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1 index 39d1053995945..8f611063dbe5d 100644 --- a/src/doc/man/rustc.1 +++ b/src/doc/man/rustc.1 @@ -55,7 +55,7 @@ Configure the output that \fBrustc\fR will produce. Each emission may also have an optional explicit output \fIPATH\fR specified for that particular emission kind. This path takes precedence over the \fB-o\fR option. .TP -\fB\-\-print\fR [crate\-name|file\-names|sysroot] +\fB\-\-print\fR [crate\-name|\:file\-names|\:sysroot|\:cfg|\:target\-list|\:target\-cpus|\:target\-features|\:relocation\-models|\:code\-models|\:tls\-models|\:target\-spec\-json|\:native\-static\-libs] Comma separated list of compiler information to print on stdout. .TP \fB\-g\fR diff --git a/src/doc/nomicon b/src/doc/nomicon index 748a5e6742db4..66ef7373409d1 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit 748a5e6742db4a21c4c630a58087f818828e8a0a +Subproject commit 66ef7373409d1979c2839db8886ac2ec9b6a58cd diff --git a/src/doc/reference b/src/doc/reference index 134f419ee6271..219e261ddb833 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 134f419ee62714590b04712fe6072253bc2a7822 +Subproject commit 219e261ddb833a5683627b0a9be87a0f4486abb9 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index eebda16e4b45f..d2a64395a5210 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit eebda16e4b45f2eed4310cf7b9872cc752278163 +Subproject commit d2a64395a5210a61d3512a3a5c615f5c47699443 diff --git a/src/doc/rustc-ux-guidelines.md b/src/doc/rustc-ux-guidelines.md index b62762ef69e01..93e94e5586302 100644 --- a/src/doc/rustc-ux-guidelines.md +++ b/src/doc/rustc-ux-guidelines.md @@ -69,7 +69,7 @@ for details on how to format and write long error codes. [librustc_passes](https://github.com/rust-lang/rust/blob/master/src/librustc_passes/diagnostics.rs), [librustc_privacy](https://github.com/rust-lang/rust/blob/master/src/librustc_privacy/diagnostics.rs), [librustc_resolve](https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/diagnostics.rs), - [librustc_trans](https://github.com/rust-lang/rust/blob/master/src/librustc_trans/diagnostics.rs), + [librustc_codegen_llvm](https://github.com/rust-lang/rust/blob/master/src/librustc_codegen_llvm/diagnostics.rs), [librustc_plugin](https://github.com/rust-lang/rust/blob/master/src/librustc_plugin/diagnostics.rs), [librustc_typeck](https://github.com/rust-lang/rust/blob/master/src/librustc_typeck/diagnostics.rs). * Explanations have full markdown support. Use it, especially to highlight diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index e1a3f96a6fe6e..7768b41f85ee4 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -64,7 +64,7 @@ To fix it, do as the help message suggests: ```rust #![feature(dyn_trait)] -#![deny(bare_trait_object)] +#![deny(bare_trait_objects)] trait Trait { } diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md index e7ec6af8be1e3..3a85a40fd1fdb 100644 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -91,43 +91,6 @@ The legacy_directory_ownership warning is issued when The warning can be fixed by renaming the parent module to "mod.rs" and moving it into its own directory if appropriate. -## legacy-imports - -This lint detects names that resolve to ambiguous glob imports. Some example -code that triggers this lint: - -```rust,ignore -pub struct Foo; - -mod bar { - struct Foo; - - mod baz { - use *; - use bar::*; - fn f(_: Foo) {} - } -} -``` - -This will produce: - -```text -error: `Foo` is ambiguous - --> src/main.rs:9:17 - | -7 | use *; - | - `Foo` could refer to the name imported here -8 | use bar::*; - | ------ `Foo` could also refer to the name imported here -9 | fn f(_: Foo) {} - | ^^^ - | - = note: #[deny(legacy_imports)] on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #38260 -``` - ## missing-fragment-specifier @@ -239,3 +202,44 @@ error: invalid `crate_type` value | ^^^^^^^^^^^^^^^^^^^^ | ``` + +## incoherent-fundamental-impls + +This lint detects potentially-conflicting impls that were erroneously allowed. Some +example code that triggers this lint: + +```rust,ignore +pub trait Trait1 { + type Output; +} + +pub trait Trait2 {} + +pub struct A; + +impl Trait1 for T where T: Trait2 { + type Output = (); +} + +impl Trait1> for A { + type Output = i32; +} +``` + +This will produce: + +```text +error: conflicting implementations of trait `Trait1>` for type `A`: (E0119) + --> src/main.rs:13:1 + | +9 | impl Trait1 for T where T: Trait2 { + | --------------------------------------------- first implementation here +... +13 | impl Trait1> for A { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` + | + = note: #[deny(incoherent_fundamental_impls)] on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46205 + = note: downstream crates may implement trait `Trait2>` for type `A` +``` diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index 1171f75caa1fd..b49708ff6adcd 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -117,47 +117,6 @@ warning: found struct without foreign-function-safe representation annotation in | ``` -## incoherent-fundamental-impls - -This lint detects potentially-conflicting impls that were erroneously allowed. Some -example code that triggers this lint: - -```rust -pub trait Trait1 { - type Output; -} - -pub trait Trait2 {} - -pub struct A; - -impl Trait1 for T where T: Trait2 { - type Output = (); -} - -impl Trait1> for A { - type Output = i32; -} -``` - -This will produce: - -```text -warning: conflicting implementations of trait `Trait1>` for type `A`: (E0119) - --> src/main.rs:13:1 - | -9 | impl Trait1 for T where T: Trait2 { - | --------------------------------------------- first implementation here -... -13 | impl Trait1> for A { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `A` - | - = note: #[warn(incoherent_fundamental_impls)] on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46205 - = note: downstream crates may implement trait `Trait2>` for type `A` -``` - ## late-bound-lifetime-arguments This lint detects detects generic lifetime arguments in path segments with diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index 3098587a8a4cc..e4af122d0cb98 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -79,8 +79,9 @@ from your example, but are important to make the tests work. Consider an example block that looks like this: ```text -/// Some documentation. -# fn foo() {} +/// /// Some documentation. +/// # fn foo() {} // this function will be hidden +/// println!("Hello, World!"); ``` It will render like this: @@ -88,6 +89,7 @@ It will render like this: ```rust /// Some documentation. # fn foo() {} +println!("Hello, World!"); ``` Yes, that's right: you can add lines that start with `# `, and they will @@ -168,37 +170,73 @@ By repeating all parts of the example, you can ensure that your example still compiles, while only showing the parts that are relevant to that part of your explanation. -Another case where the use of `#` is handy is when you want to ignore -error handling. Lets say you want the following, +The `#`-hiding of lines can be prevented by using two consecutive hashes +`##`. This only needs to be done with with the first `#` which would've +otherwise caused hiding. If we have a string literal like the following, +which has a line that starts with a `#`: + +```rust +let s = "foo +## bar # baz"; +``` + +We can document it by escaping the initial `#`: + +```text +/// let s = "foo +/// ## bar # baz"; +``` + + +## Using `?` in doc tests + +When writing an example, it is rarely useful to include a complete error +handling, as it would add significant amounts of boilerplate code. Instead, you +may want the following: ```ignore +/// ``` /// use std::io; /// let mut input = String::new(); /// io::stdin().read_line(&mut input)?; +/// ``` ``` -The problem is that `?` returns a `Result` and test functions -don't return anything so this will give a mismatched types error. +The problem is that `?` returns a `Result` and test functions don't +return anything, so this will give a mismatched types error. + +You can get around this limitation by manually adding a `main` that returns +`Result`, because `Result` implements the `Termination` trait: ```ignore /// A doc test using ? /// /// ``` /// use std::io; -/// # fn foo() -> io::Result<()> { +/// +/// fn main() -> io::Result<()> { +/// let mut input = String::new(); +/// io::stdin().read_line(&mut input)?; +/// Ok(()) +/// } +/// ``` +``` + +Together with the `# ` from the section above, you arrive at a solution that +appears to the reader as the initial idea but works with doc tests: + +```ignore +/// ``` +/// use std::io; +/// # fn main() -> io::Result<()> { /// let mut input = String::new(); /// io::stdin().read_line(&mut input)?; /// # Ok(()) /// # } /// ``` -# fn foo() {} ``` -You can get around this by wrapping the code in a function. This catches -and swallows the `Result` when running tests on the docs. This -pattern appears regularly in the standard library. - -### Documenting macros +## Documenting macros Here’s an example of documenting a macro: @@ -268,10 +306,10 @@ not actually pass as a test. # fn foo() {} ``` -`compile_fail` tells `rustdoc` that the compilation should fail. If it -compiles, then the test will fail. However please note that code failing -with the current Rust release may work in a future release, as new features -are added. +The `no_run` attribute will compile your code, but not run it. This is +important for examples such as "Here's how to retrieve a web page," +which you would want to ensure compiles, but might be run in a test +environment that has no network access. ```text /// ```compile_fail @@ -280,7 +318,31 @@ are added. /// ``` ``` -The `no_run` attribute will compile your code, but not run it. This is -important for examples such as "Here's how to retrieve a web page," -which you would want to ensure compiles, but might be run in a test -environment that has no network access. +`compile_fail` tells `rustdoc` that the compilation should fail. If it +compiles, then the test will fail. However please note that code failing +with the current Rust release may work in a future release, as new features +are added. + +## Syntax reference + +The *exact* syntax for code blocks, including the edge cases, can be found +in the [Fenced Code Blocks](https://spec.commonmark.org/0.28/#fenced-code-blocks) +section of the CommonMark specification. + +Rustdoc also accepts *indented* code blocks as an alternative to fenced +code blocks: instead of surrounding your code with three backticks, you +can indent each line by four or more spaces. + +``````markdown + let foo = "foo"; + assert_eq!(foo, "foo"); +`````` + +These, too, are documented in the CommonMark specification, in the +[Indented Code Blocks](https://spec.commonmark.org/0.28/#indented-code-blocks) +section. + +However, it's preferable to use fenced code blocks over indented code blocks. +Not only are fenced code blocks considered more idiomatic for Rust code, +but there is no way to use directives such as `ignore` or `should_panic` with +indented code blocks. diff --git a/src/doc/rustdoc/src/passes.md b/src/doc/rustdoc/src/passes.md index de7c10292680c..615b3dca199f1 100644 --- a/src/doc/rustdoc/src/passes.md +++ b/src/doc/rustdoc/src/passes.md @@ -5,8 +5,8 @@ Rustdoc has a concept called "passes". These are transformations that In addition to the passes below, check out the docs for these flags: -* [`--passes`](command-line-arguments.html#--passes-add-more-rustdoc-passes) -* [`--no-defaults`](command-line-arguments.html#--no-defaults-dont-run-default-passes) +* [`--passes`](command-line-arguments.html#a--passes-add-more-rustdoc-passes) +* [`--no-defaults`](command-line-arguments.html#a--no-defaults-dont-run-default-passes) ## Default passes diff --git a/src/doc/tutorial.md b/src/doc/tutorial.md index 87f3a0c765c5e..320283f31b51f 100644 --- a/src/doc/tutorial.md +++ b/src/doc/tutorial.md @@ -1,3 +1,3 @@ % The Rust Tutorial -This tutorial has been deprecated in favor of [the Book](book/index.html). Go check that out instead! +This tutorial has been deprecated in favor of [the Book](book/index.html), which is available free online and in dead tree form. Go check that out instead! diff --git a/src/doc/unstable-book/src/language-features/box-syntax.md b/src/doc/unstable-book/src/language-features/box-syntax.md index 50e59231a4df2..414dc48e557d3 100644 --- a/src/doc/unstable-book/src/language-features/box-syntax.md +++ b/src/doc/unstable-book/src/language-features/box-syntax.md @@ -1,8 +1,8 @@ # `box_syntax` -The tracking issue for this feature is: [#27779] +The tracking issue for this feature is: [#49733] -[#27779]: https://github.com/rust-lang/rust/issues/27779 +[#49733]: https://github.com/rust-lang/rust/issues/49733 See also [`box_patterns`](language-features/box-patterns.html) diff --git a/src/doc/unstable-book/src/language-features/global-allocator.md b/src/doc/unstable-book/src/language-features/global-allocator.md deleted file mode 100644 index 8f1ba22de8cb1..0000000000000 --- a/src/doc/unstable-book/src/language-features/global-allocator.md +++ /dev/null @@ -1,72 +0,0 @@ -# `global_allocator` - -The tracking issue for this feature is: [#27389] - -[#27389]: https://github.com/rust-lang/rust/issues/27389 - ------------------------- - -Rust programs may need to change the allocator that they're running with from -time to time. This use case is distinct from an allocator-per-collection (e.g. a -`Vec` with a custom allocator) and instead is more related to changing the -global default allocator, e.g. what `Vec` uses by default. - -Currently Rust programs don't have a specified global allocator. The compiler -may link to a version of [jemalloc] on some platforms, but this is not -guaranteed. Libraries, however, like cdylibs and staticlibs are guaranteed -to use the "system allocator" which means something like `malloc` on Unixes and -`HeapAlloc` on Windows. - -[jemalloc]: https://github.com/jemalloc/jemalloc - -The `#[global_allocator]` attribute, however, allows configuring this choice. -You can use this to implement a completely custom global allocator to route all -default allocation requests to a custom object. Defined in [RFC 1974] usage -looks like: - -[RFC 1974]: https://github.com/rust-lang/rfcs/pull/1974 - -```rust -#![feature(global_allocator, allocator_api, heap_api)] - -use std::alloc::{GlobalAlloc, System, Layout, Opaque}; -use std::ptr::NonNull; - -struct MyAllocator; - -unsafe impl GlobalAlloc for MyAllocator { - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - System.alloc(layout) - } - - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { - System.dealloc(ptr, layout) - } -} - -#[global_allocator] -static GLOBAL: MyAllocator = MyAllocator; - -fn main() { - // This `Vec` will allocate memory through `GLOBAL` above - let mut v = Vec::new(); - v.push(1); -} -``` - -And that's it! The `#[global_allocator]` attribute is applied to a `static` -which implements the `Alloc` trait in the `std::alloc` module. Note, though, -that the implementation is defined for `&MyAllocator`, not just `MyAllocator`. -You may wish, however, to also provide `Alloc for MyAllocator` for other use -cases. - -A crate can only have one instance of `#[global_allocator]` and this instance -may be loaded through a dependency. For example `#[global_allocator]` above -could have been placed in one of the dependencies loaded through `extern crate`. - -Note that `Alloc` itself is an `unsafe` trait, with much documentation on the -trait itself about usage and for implementors. Extra care should be taken when -implementing a global allocator as well as the allocator may be called from many -portions of the standard library, such as the panicking routine. As a result it -is highly recommended to not panic during allocation and work in as many -situations with as few dependencies as possible as well. diff --git a/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md b/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md new file mode 100644 index 0000000000000..73c7eafdb98d5 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/infer-outlives-requirements.md @@ -0,0 +1,67 @@ +# `infer_outlives_requirements` + +The tracking issue for this feature is: [#44493] + +[#44493]: https://github.com/rust-lang/rust/issues/44493 + +------------------------ +The `infer_outlives_requirements` feature indicates that certain +outlives requirements can be infered by the compiler rather than +stating them explicitly. + +For example, currently generic struct definitions that contain +references, require where-clauses of the form T: 'a. By using +this feature the outlives predicates will be infered, although +they may still be written explicitly. + +```rust,ignore (pseudo-Rust) +struct Foo<'a, T> + where T: 'a // <-- currently required + { + bar: &'a T, + } +``` + + +## Examples: + + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] + +// Implicitly infer T: 'a +struct Foo<'a, T> { + bar: &'a T, +} +``` + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] + +// Implicitly infer `U: 'b` +struct Foo<'b, U> { + bar: Bar<'b, U> +} + +struct Bar<'a, T> where T: 'a { + x: &'a (), + y: T, +} +``` + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] + +// Implicitly infer `b': 'a` +struct Foo<'a, 'b, T> { + x: &'a &'b T +} +``` + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] + +// Implicitly infer `::Item : 'a` +struct Foo<'a, T: Iterator> { + bar: &'a T::Item +``` diff --git a/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md b/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md new file mode 100644 index 0000000000000..f50472fb41e31 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md @@ -0,0 +1,45 @@ +# `infer_static_outlives_requirements` + +The tracking issue for this feature is: [#44493] + +[#44493]: https://github.com/rust-lang/rust/issues/44493 + +------------------------ +The `infer_static_outlives_requirements` feature indicates that certain +`'static` outlives requirements can be infered by the compiler rather than +stating them explicitly. + +Note: It is an accompanying feature to `infer_outlives_requirements`, +which must be enabled to infer outlives requirements. + +For example, currently generic struct definitions that contain +references, require where-clauses of the form T: 'static. By using +this feature the outlives predicates will be infered, although +they may still be written explicitly. + +```rust,ignore (pseudo-Rust) +struct Foo where U: 'static { // <-- currently required + bar: Bar +} +struct Bar { + x: T, +} +``` + + +## Examples: + +```rust,ignore (pseudo-Rust) +#![feature(infer_outlives_requirements)] +#![feature(infer_static_outlives_requirements)] + +#[rustc_outlives] +// Implicitly infer U: 'static +struct Foo { + bar: Bar +} +struct Bar { + x: T, +} +``` + diff --git a/src/doc/unstable-book/src/language-features/irrefutable-let-patterns.md b/src/doc/unstable-book/src/language-features/irrefutable-let-patterns.md new file mode 100644 index 0000000000000..46b843778e810 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/irrefutable-let-patterns.md @@ -0,0 +1,28 @@ +# `irrefutable_let_patterns` + +The tracking issue for this feature is: [#44495] + +[#44495]: https://github.com/rust-lang/rust/issues/44495 + +------------------------ + +This feature changes the way that "irrefutable patterns" are handled +in the `if let` and `while let` forms. An *irrefutable pattern* is one +that cannot fail to match -- for example, the `_` pattern matches any +value, and hence it is "irrefutable". Without this feature, using an +irrefutable pattern in an `if let` gives a hard error (since often +this indicates programmer error). But when the feature is enabled, the +error becomes a lint (since in some cases irrefutable patterns are +expected). This means you can use `#[allow]` to silence the lint: + +```rust +#![feature(irrefutable_let_patterns)] + +#[allow(irrefutable_let_patterns)] +fn main() { + // These two examples used to be errors, but now they + // trigger a lint (that is allowed): + if let _ = 5 {} + while let _ = 5 { break; } +} +``` diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 6a7aea7f1c27e..bac619fd4a30d 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -19,6 +19,7 @@ sugar for dynamic allocations via `malloc` and `free`: #![feature(lang_items, box_syntax, start, libc, core_intrinsics)] #![no_std] use core::intrinsics; +use core::panic::PanicInfo; extern crate libc; @@ -50,7 +51,7 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize { } #[lang = "eh_personality"] extern fn rust_eh_personality() {} -#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } } +#[lang = "panic_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {} #[no_mangle] pub extern fn rust_eh_register_frames () {} #[no_mangle] pub extern fn rust_eh_unregister_frames () {} @@ -110,6 +111,7 @@ in the same format as C: #![feature(start)] #![no_std] use core::intrinsics; +use core::panic::PanicInfo; // Pull in the system libc library for what crt0.o likely requires. extern crate libc; @@ -134,12 +136,9 @@ pub extern fn rust_eh_personality() { pub extern fn rust_eh_unwind_resume() { } -#[lang = "panic_fmt"] +#[lang = "panic_impl"] #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, - _file: &'static str, - _line: u32, - _column: u32) -> ! { +pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } ``` @@ -155,6 +154,7 @@ compiler's name mangling too: #![no_std] #![no_main] use core::intrinsics; +use core::panic::PanicInfo; // Pull in the system libc library for what crt0.o likely requires. extern crate libc; @@ -179,12 +179,9 @@ pub extern fn rust_eh_personality() { pub extern fn rust_eh_unwind_resume() { } -#[lang = "panic_fmt"] +#[lang = "panic_impl"] #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, - _file: &'static str, - _line: u32, - _column: u32) -> ! { +pub extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } } ``` @@ -215,7 +212,7 @@ called. The language item's name is `eh_personality`. The second function, `rust_begin_panic`, is also used by the failure mechanisms of the compiler. When a panic happens, this controls the message that's displayed on -the screen. While the language item's name is `panic_fmt`, the symbol name is +the screen. While the language item's name is `panic_impl`, the symbol name is `rust_begin_panic`. A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume` @@ -259,8 +256,8 @@ the source code. - `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH) - `panic`: `libcore/panicking.rs` - `panic_bounds_check`: `libcore/panicking.rs` - - `panic_fmt`: `libcore/panicking.rs` - - `panic_fmt`: `libstd/panicking.rs` + - `panic_impl`: `libcore/panicking.rs` + - `panic_impl`: `libstd/panicking.rs` - Allocations - `owned_box`: `liballoc/boxed.rs` - `exchange_malloc`: `liballoc/heap.rs` diff --git a/src/doc/unstable-book/src/language-features/macro-at-most-once-rep.md b/src/doc/unstable-book/src/language-features/macro-at-most-once-rep.md index ec9d85db107d4..251fc7209122c 100644 --- a/src/doc/unstable-book/src/language-features/macro-at-most-once-rep.md +++ b/src/doc/unstable-book/src/language-features/macro-at-most-once-rep.md @@ -1,13 +1,15 @@ # `macro_at_most_once_rep` -The tracking issue for this feature is: TODO(mark-i-m) +NOTE: This feature is only available in the 2018 Edition. + +The tracking issue for this feature is: #48075 With this feature gate enabled, one can use `?` as a Kleene operator meaning "0 or 1 repetitions" in a macro definition. Previously only `+` and `*` were allowed. For example: -```rust +```rust,ignore #![feature(macro_at_most_once_rep)] macro_rules! foo { diff --git a/src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md b/src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md deleted file mode 100644 index 5b585d7f041d2..0000000000000 --- a/src/doc/unstable-book/src/language-features/macro-lifetime-matcher.md +++ /dev/null @@ -1,14 +0,0 @@ -# `macro_lifetime_matcher` - -The tracking issue for this feature is: [#46895] - -With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry: - -* `lifetime`: a lifetime. Examples: 'static, 'a. - -A `lifetime` variable may be followed by anything. - -[#46895]: https://github.com/rust-lang/rust/issues/46895 -[frags]: ../book/first-edition/macros.html#syntactic-requirements - ------------------------- diff --git a/src/doc/unstable-book/src/language-features/macro-literal-matcher.md b/src/doc/unstable-book/src/language-features/macro-literal-matcher.md new file mode 100644 index 0000000000000..7e3638fd1cf4c --- /dev/null +++ b/src/doc/unstable-book/src/language-features/macro-literal-matcher.md @@ -0,0 +1,17 @@ +# `macro_literal_matcher` + +The tracking issue for this feature is: [#35625] + +The RFC is: [rfc#1576]. + +With this feature gate enabled, the [list of fragment specifiers][frags] gains one more entry: + +* `literal`: a literal. Examples: 2, "string", 'c' + +A `literal` may be followed by anything, similarly to the `ident` specifier. + +[rfc#1576]: http://rust-lang.github.io/rfcs/1576-macros-literal-matcher.html +[#35625]: https://github.com/rust-lang/rust/issues/35625 +[frags]: ../book/first-edition/macros.html#syntactic-requirements + +------------------------ diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index 1cece930eeaa5..19ece09509078 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -183,6 +183,8 @@ that warns about any item named `lintme`. ```rust,ignore #![feature(plugin_registrar)] #![feature(box_syntax, rustc_private)] +#![feature(macro_vis_matcher)] +#![feature(macro_at_most_once_rep)] extern crate syntax; @@ -208,7 +210,7 @@ impl LintPass for Pass { impl EarlyLintPass for Pass { fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) { - if it.ident.name.as_str() == "lintme" { + if it.ident.as_str() == "lintme" { cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'"); } } diff --git a/src/doc/unstable-book/src/language-features/proc-macro.md b/src/doc/unstable-book/src/language-features/proc-macro.md deleted file mode 100644 index 1bd8c41629eea..0000000000000 --- a/src/doc/unstable-book/src/language-features/proc-macro.md +++ /dev/null @@ -1,241 +0,0 @@ -# `proc_macro` - -The tracking issue for this feature is: [#38356] - -[#38356]: https://github.com/rust-lang/rust/issues/38356 - ------------------------- - -This feature flag guards the new procedural macro features as laid out by [RFC 1566], which alongside the now-stable -[custom derives], provide stabilizable alternatives to the compiler plugin API (which requires the use of -perma-unstable internal APIs) for programmatically modifying Rust code at compile-time. - -The two new procedural macro kinds are: - -* Function-like procedural macros which are invoked like regular declarative macros, and: - -* Attribute-like procedural macros which can be applied to any item which built-in attributes can -be applied to, and which can take arguments in their invocation as well. - -Additionally, this feature flag implicitly enables the [`use_extern_macros`](language-features/use-extern-macros.html) feature, -which allows macros to be imported like any other item with `use` statements, as compared to -applying `#[macro_use]` to an `extern crate` declaration. It is important to note that procedural macros may -**only** be imported in this manner, and will throw an error otherwise. - -You **must** declare the `proc_macro` feature in both the crate declaring these new procedural macro kinds as well as -in any crates that use them. - -### Common Concepts - -As with custom derives, procedural macros may only be declared in crates of the `proc-macro` type, and must be public -functions. No other public items may be declared in `proc-macro` crates, but private items are fine. - -To declare your crate as a `proc-macro` crate, simply add: - -```toml -[lib] -proc-macro = true -``` - -to your `Cargo.toml`. - -Unlike custom derives, however, the name of the function implementing the procedural macro is used directly as the -procedural macro's name, so choose carefully. - -Additionally, both new kinds of procedural macros return a `TokenStream` which *wholly* replaces the original -invocation and its input. - -#### Importing - -As referenced above, the new procedural macros are not meant to be imported via `#[macro_use]` and will throw an -error if they are. Instead, they are meant to be imported like any other item in Rust, with `use` statements: - -```rust,ignore -#![feature(proc_macro)] - -// Where `my_proc_macros` is some crate of type `proc_macro` -extern crate my_proc_macros; - -// And declares a `#[proc_macro] pub fn my_bang_macro()` at its root. -use my_proc_macros::my_bang_macro; - -fn main() { - println!("{}", my_bang_macro!()); -} -``` - -#### Error Reporting - -Any panics in a procedural macro implementation will be caught by the compiler and turned into an error message pointing -to the problematic invocation. Thus, it is important to make your panic messages as informative as possible: use -`Option::expect` instead of `Option::unwrap` and `Result::expect` instead of `Result::unwrap`, and inform the user of -the error condition as unambiguously as you can. - -#### `TokenStream` - -The `proc_macro::TokenStream` type is hardcoded into the signatures of procedural macro functions for both input and -output. It is a wrapper around the compiler's internal representation for a given chunk of Rust code. - -### Function-like Procedural Macros - -These are procedural macros that are invoked like regular declarative macros. They are declared as public functions in -crates of the `proc_macro` type and using the `#[proc_macro]` attribute. The name of the declared function becomes the -name of the macro as it is to be imported and used. The function must be of the kind `fn(TokenStream) -> TokenStream` -where the sole argument is the input to the macro and the return type is the macro's output. - -This kind of macro can expand to anything that is valid for the context it is invoked in, including expressions and -statements, as well as items. - -**Note**: invocations of this kind of macro require a wrapping `[]`, `{}` or `()` like regular macros, but these do not -appear in the input, only the tokens between them. The tokens between the braces do not need to be valid Rust syntax. - -my_macro_crate/src/lib.rs - -```rust,ignore -#![feature(proc_macro)] - -// This is always necessary to get the `TokenStream` typedef. -extern crate proc_macro; - -use proc_macro::TokenStream; - -#[proc_macro] -pub fn say_hello(_input: TokenStream) -> TokenStream { - // This macro will accept any input because it ignores it. - // To enforce correctness in macros which don't take input, - // you may want to add `assert!(_input.to_string().is_empty());`. - "println!(\"Hello, world!\")".parse().unwrap() -} -``` - -my_macro_user/Cargo.toml - -```toml -[dependencies] -my_macro_crate = { path = "" } -``` - -my_macro_user/src/lib.rs - -```rust,ignore -#![feature(proc_macro)] - -extern crate my_macro_crate; - -use my_macro_crate::say_hello; - -fn main() { - say_hello!(); -} -``` - -As expected, this prints `Hello, world!`. - -### Attribute-like Procedural Macros - -These are arguably the most powerful flavor of procedural macro as they can be applied anywhere attributes are allowed. - -They are declared as public functions in crates of the `proc-macro` type, using the `#[proc_macro_attribute]` attribute. -The name of the function becomes the name of the attribute as it is to be imported and used. The function must be of the -kind `fn(TokenStream, TokenStream) -> TokenStream` where: - -The first argument represents any metadata for the attribute (see [the reference chapter on attributes][refr-attr]). -Only the metadata itself will appear in this argument, for example: - - * `#[my_macro]` will get an empty string. - * `#[my_macro = "string"]` will get `= "string"`. - * `#[my_macro(ident)]` will get `(ident)`. - * etc. - -The second argument is the item that the attribute is applied to. It can be a function, a type definition, -an impl block, an `extern` block, or a module—attribute invocations can take the inner form (`#![my_attr]`) -or outer form (`#[my_attr]`). - -The return type is the output of the macro which *wholly* replaces the item it was applied to. Thus, if your intention -is to merely modify an item, it *must* be copied to the output. The output must be an item; expressions, statements -and bare blocks are not allowed. - -There is no restriction on how many items an attribute-like procedural macro can emit as long as they are valid in -the given context. - -my_macro_crate/src/lib.rs - -```rust,ignore -#![feature(proc_macro)] - -extern crate proc_macro; - -use proc_macro::TokenStream; - -/// Adds a `/// ### Panics` docstring to the end of the input's documentation -/// -/// Does not assert that its receiver is a function or method. -#[proc_macro_attribute] -pub fn panics_note(args: TokenStream, input: TokenStream) -> TokenStream { - let args = args.to_string(); - let mut input = input.to_string(); - - assert!(args.starts_with("= \""), "`#[panics_note]` requires an argument of the form \ - `#[panics_note = \"panic note here\"]`"); - - // Get just the bare note string - let panics_note = args.trim_matches(&['=', ' ', '"'][..]); - - // The input will include all docstrings regardless of where the attribute is placed, - // so we need to find the last index before the start of the item - let insert_idx = idx_after_last_docstring(&input); - - // And insert our `### Panics` note there so it always appears at the end of an item's docs - input.insert_str(insert_idx, &format!("/// # Panics \n/// {}\n", panics_note)); - - input.parse().unwrap() -} - -// `proc-macro` crates can contain any kind of private item still -fn idx_after_last_docstring(input: &str) -> usize { - // Skip docstring lines to find the start of the item proper - input.lines().skip_while(|line| line.trim_left().starts_with("///")).next() - // Find the index of the first non-docstring line in the input - // Note: assumes this exact line is unique in the input - .and_then(|line_after| input.find(line_after)) - // No docstrings in the input - .unwrap_or(0) -} -``` - -my_macro_user/Cargo.toml - -```toml -[dependencies] -my_macro_crate = { path = "" } -``` - -my_macro_user/src/lib.rs - -```rust,ignore -#![feature(proc_macro)] - -extern crate my_macro_crate; - -use my_macro_crate::panics_note; - -/// Do the `foo` thing. -#[panics_note = "Always."] -pub fn foo() { - panic!() -} -``` - -Then the rendered documentation for `pub fn foo` will look like this: - -> `pub fn foo()` -> -> ---- -> Do the `foo` thing. -> # Panics -> Always. - -[RFC 1566]: https://github.com/rust-lang/rfcs/blob/master/text/1566-proc-macros.md -[custom derives]: https://doc.rust-lang.org/book/procedural-macros.html -[rust-lang/rust#41430]: https://github.com/rust-lang/rust/issues/41430 -[refr-attr]: https://doc.rust-lang.org/reference/attributes.html diff --git a/src/doc/unstable-book/src/language-features/repr-transparent.md b/src/doc/unstable-book/src/language-features/repr-transparent.md deleted file mode 100644 index 62202dc96fd46..0000000000000 --- a/src/doc/unstable-book/src/language-features/repr-transparent.md +++ /dev/null @@ -1,176 +0,0 @@ -# `repr_transparent` - -The tracking issue for this feature is: [#43036] - -[#43036]: https://github.com/rust-lang/rust/issues/43036 - ------------------------- - -This feature enables the `repr(transparent)` attribute on structs, which enables -the use of newtypes without the usual ABI implications of wrapping the value in -a struct. - -## Background - -It's sometimes useful to add additional type safety by introducing *newtypes*. -For example, code that handles numeric quantities in different units such as -millimeters, centimeters, grams, kilograms, etc. may want to use the type system -to rule out mistakes such as adding millimeters to grams: - -```rust -use std::ops::Add; - -struct Millimeters(f64); -struct Grams(f64); - -impl Add for Millimeters { - type Output = Millimeters; - - fn add(self, other: Millimeters) -> Millimeters { - Millimeters(self.0 + other.0) - } -} - -// Likewise: impl Add for Grams {} -``` - -Other uses of newtypes include using `PhantomData` to add lifetimes to raw -pointers or to implement the "phantom types" pattern. See the [PhantomData] -documentation and [the Nomicon][nomicon-phantom] for more details. - -The added type safety is especially useful when interacting with C or other -languages. However, in those cases we need to ensure the newtypes we add do not -introduce incompatibilities with the C ABI. - -## Newtypes in FFI - -Luckily, `repr(C)` newtypes are laid out just like the type they wrap on all -platforms which Rust currently supports, and likely on many more. For example, -consider this C declaration: - -```C -struct Object { - double weight; //< in grams - double height; //< in millimeters - // ... -} - -void frobnicate(struct Object *); -``` - -While using this C code from Rust, we could add `repr(C)` to the `Grams` and -`Millimeters` newtypes introduced above and use them to add some type safety -while staying compatible with the memory layout of `Object`: - -```rust,no_run -#[repr(C)] -struct Grams(f64); - -#[repr(C)] -struct Millimeters(f64); - -#[repr(C)] -struct Object { - weight: Grams, - height: Millimeters, - // ... -} - -extern { - fn frobnicate(_: *mut Object); -} -``` - -This works even when adding some `PhantomData` fields, because they are -zero-sized and therefore don't have to affect the memory layout. - -However, there's more to the ABI than just memory layout: there's also the -question of how function call arguments and return values are passed. Many -common ABI treat a struct containing a single field differently from that field -itself, at least when the field is a scalar (e.g., integer or float or pointer). - -To continue the above example, suppose the C library also exposes a function -like this: - -```C -double calculate_weight(double height); -``` - -Using our newtypes on the Rust side like this will cause an ABI mismatch on many -platforms: - -```rust,ignore -extern { - fn calculate_weight(height: Millimeters) -> Grams; -} -``` - -For example, on x86_64 Linux, Rust will pass the argument in an integer -register, while the C function expects the argument to be in a floating-point -register. Likewise, the C function will return the result in a floating-point -register while Rust will expect it in an integer register. - -Note that this problem is not specific to floats: To give another example, -32-bit x86 linux will pass and return `struct Foo(i32);` on the stack while -`i32` is placed in registers. - -## Enter `repr(transparent)` - -So while `repr(C)` happens to do the right thing with respect to memory layout, -it's not quite the right tool for newtypes in FFI. Instead of declaring a C -struct, we need to communicate to the Rust compiler that our newtype is just for -type safety on the Rust side. This is what `repr(transparent)` does. - -The attribute can be applied to a newtype-like structs that contains a single -field. It indicates that the newtype should be represented exactly like that -field's type, i.e., the newtype should be ignored for ABI purpopses: not only is -it laid out the same in memory, it is also passed identically in function calls. - -In the above example, the ABI mismatches can be prevented by making the newtypes -`Grams` and `Millimeters` transparent like this: - -```rust -#![feature(repr_transparent)] - -#[repr(transparent)] -struct Grams(f64); - -#[repr(transparent)] -struct Millimeters(f64); -``` - -In addition to that single field, any number of zero-sized fields are permitted, -including but not limited to `PhantomData`: - -```rust -#![feature(repr_transparent)] - -use std::marker::PhantomData; - -struct Foo { /* ... */ } - -#[repr(transparent)] -struct FooPtrWithLifetime<'a>(*const Foo, PhantomData<&'a Foo>); - -#[repr(transparent)] -struct NumberWithUnit(T, PhantomData); - -struct CustomZst; - -#[repr(transparent)] -struct PtrWithCustomZst<'a> { - ptr: FooPtrWithLifetime<'a>, - some_marker: CustomZst, -} -``` - -Transparent structs can be nested: `PtrWithCustomZst` is also represented -exactly like `*const Foo`. - -Because `repr(transparent)` delegates all representation concerns to another -type, it is incompatible with all other `repr(..)` attributes. It also cannot be -applied to enums, unions, empty structs, structs whose fields are all -zero-sized, or structs with *multiple* non-zero-sized fields. - -[PhantomData]: https://doc.rust-lang.org/std/marker/struct.PhantomData.html -[nomicon-phantom]: https://doc.rust-lang.org/nomicon/phantom-data.html diff --git a/src/doc/unstable-book/src/language-features/tool-lints.md b/src/doc/unstable-book/src/language-features/tool-lints.md new file mode 100644 index 0000000000000..5c0d33b5ab0c4 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/tool-lints.md @@ -0,0 +1,35 @@ +# `tool_lints` + +The tracking issue for this feature is: [#44690] + +[#44690]: https://github.com/rust-lang/rust/issues/44690 + +------------------------ + +Tool lints let you use scoped lints, to `allow`, `warn`, `deny` or `forbid` lints of +certain tools. + +Currently `clippy` is the only available lint tool. + +It is recommended for lint tools to implement the scoped lints like this: + +- `#[_(TOOL_NAME::lintname)]`: for lint names +- `#[_(TOOL_NAME::lintgroup)]`: for groups of lints +- `#[_(TOOL_NAME::all)]`: for (almost[^1]) all lints + +## An example + +```rust +#![feature(tool_lints)] + +#![warn(clippy::pedantic)] + +#[allow(clippy::filter_map)] +fn main() { + let v = vec![0; 10]; + let _ = v.into_iter().filter(|&x| x < 1).map(|x| x + 1).collect::>(); + println!("No filter_map()!"); +} +``` + +[^1]: Some defined lint groups can be excluded here. diff --git a/src/doc/unstable-book/src/language-features/used.md b/src/doc/unstable-book/src/language-features/used.md index 75a8b2774f422..c3b7f2e41e15b 100644 --- a/src/doc/unstable-book/src/language-features/used.md +++ b/src/doc/unstable-book/src/language-features/used.md @@ -87,11 +87,13 @@ This condition can be met using `#[used]` and `#[link_section]` plus a linker script. ``` rust,ignore -#![feature(lang_items)] +#![feature(panic_implementation)] #![feature(used)] #![no_main] #![no_std] +use core::panic::PanicInfo; + extern "C" fn reset_handler() -> ! { loop {} } @@ -100,8 +102,10 @@ extern "C" fn reset_handler() -> ! { #[used] static RESET_HANDLER: extern "C" fn() -> ! = reset_handler; -#[lang = "panic_fmt"] -fn panic_fmt() {} +#[panic_implementation] +fn panic_impl(info: &PanicInfo) -> ! { + loop {} +} ``` ``` text diff --git a/src/doc/unstable-book/src/library-features/alloc-jemalloc.md b/src/doc/unstable-book/src/library-features/alloc-jemalloc.md deleted file mode 100644 index 425d4cb79b2df..0000000000000 --- a/src/doc/unstable-book/src/library-features/alloc-jemalloc.md +++ /dev/null @@ -1,13 +0,0 @@ -# `alloc_jemalloc` - -The tracking issue for this feature is: [#33082] - -[#33082]: https://github.com/rust-lang/rust/issues/33082 - -See also [`alloc_system`](library-features/alloc-system.html). - ------------------------- - -This feature has been replaced by [the `jemallocator` crate on crates.io.][jemallocator]. - -[jemallocator]: https://crates.io/crates/jemallocator diff --git a/src/doc/unstable-book/src/library-features/alloc-system.md b/src/doc/unstable-book/src/library-features/alloc-system.md deleted file mode 100644 index 9effab202cabd..0000000000000 --- a/src/doc/unstable-book/src/library-features/alloc-system.md +++ /dev/null @@ -1,77 +0,0 @@ -# `alloc_system` - -The tracking issue for this feature is: [#32838] - -[#32838]: https://github.com/rust-lang/rust/issues/32838 - -See also [`global_allocator`](language-features/global-allocator.html). - ------------------------- - -The compiler currently ships two default allocators: `alloc_system` and -`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators -are normal Rust crates and contain an implementation of the routines to -allocate and deallocate memory. The standard library is not compiled assuming -either one, and the compiler will decide which allocator is in use at -compile-time depending on the type of output artifact being produced. - -Binaries generated by the compiler will use `alloc_jemalloc` by default (where -available). In this situation the compiler "controls the world" in the sense of -it has power over the final link. Primarily this means that the allocator -decision can be left up the compiler. - -Dynamic and static libraries, however, will use `alloc_system` by default. Here -Rust is typically a 'guest' in another application or another world where it -cannot authoritatively decide what allocator is in use. As a result it resorts -back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing -memory. - -# Switching Allocators - -Although the compiler's default choices may work most of the time, it's often -necessary to tweak certain aspects. Overriding the compiler's decision about -which allocator is in use is done through the `#[global_allocator]` attribute: - -```rust,no_run -#![feature(alloc_system, global_allocator, allocator_api)] - -extern crate alloc_system; - -use alloc_system::System; - -#[global_allocator] -static A: System = System; - -fn main() { - let a = Box::new(4); // Allocates from the system allocator. - println!("{}", a); -} -``` - -In this example the binary generated will not link to jemalloc by default but -instead use the system allocator. Conversely to generate a dynamic library which -uses jemalloc by default one would write: - -(The `alloc_jemalloc` crate cannot be used to control the global allocator, -crate.io’s `jemallocator` crate provides equivalent functionality.) - -```toml -# Cargo.toml -[dependencies] -jemallocator = "0.1" -``` -```rust,ignore -#![feature(global_allocator)] -#![crate_type = "dylib"] - -extern crate jemallocator; - -#[global_allocator] -static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; - -pub fn foo() { - let a = Box::new(4); // Allocates from jemalloc. - println!("{}", a); -} -# fn main() {} -``` diff --git a/src/doc/unstable-book/src/library-features/entry-or-default.md b/src/doc/unstable-book/src/library-features/entry-or-default.md deleted file mode 100644 index f8c8a2a7a718b..0000000000000 --- a/src/doc/unstable-book/src/library-features/entry-or-default.md +++ /dev/null @@ -1,13 +0,0 @@ -# `entry_or_default` - -The tracking issue for this feature is: [#44324] - -[#44324]: https://github.com/rust-lang/rust/issues/44324 - ------------------------- - -The `entry_or_default` feature adds a new method to `hash_map::Entry` -and `btree_map::Entry`, `or_default`, when `V: Default`. This method is -semantically identical to `or_insert_with(Default::default)`, and will -insert the default value for the type if no entry exists for the current -key. diff --git a/src/etc/generate-deriving-span-tests.py b/src/etc/generate-deriving-span-tests.py index edb9389c00c58..2e9169ce5b942 100755 --- a/src/etc/generate-deriving-span-tests.py +++ b/src/etc/generate-deriving-span-tests.py @@ -122,7 +122,7 @@ def write_file(name, string): for (trait, supers, errs) in [('Clone', [], 1), ('PartialEq', [], 2), - ('PartialOrd', ['PartialEq'], 5), + ('PartialOrd', ['PartialEq'], 1), ('Eq', ['PartialEq'], 1), ('Ord', ['Eq', 'PartialOrd', 'PartialEq'], 1), ('Debug', [], 1), diff --git a/src/etc/htmldocck.py b/src/etc/htmldocck.py index 8a11c6f7cfc4c..569788fe9c08a 100644 --- a/src/etc/htmldocck.py +++ b/src/etc/htmldocck.py @@ -346,15 +346,19 @@ def check_tree_attr(tree, path, attr, pat, regexp): def check_tree_text(tree, path, pat, regexp): path = normalize_xpath(path) ret = False - for e in tree.findall(path): - try: - value = flatten(e) - except KeyError: - continue - else: - ret = check_string(value, pat, regexp) - if ret: - break + try: + for e in tree.findall(path): + try: + value = flatten(e) + except KeyError: + continue + else: + ret = check_string(value, pat, regexp) + if ret: + break + except Exception as e: + print('Failed to get path "{}"'.format(path)) + raise e return ret diff --git a/src/etc/platform-intrinsics/generator.py b/src/etc/platform-intrinsics/generator.py index d9f78978a251e..046ea48638baf 100644 --- a/src/etc/platform-intrinsics/generator.py +++ b/src/etc/platform-intrinsics/generator.py @@ -806,9 +806,6 @@ def open(platform): use {{Intrinsic, Type}}; use IntrinsicDef::Named; -// The default inlining settings trigger a pathological behaviour in -// LLVM, which causes makes compilation very slow. See #28273. -#[inline(never)] pub fn find(name: &str) -> Option {{ if !name.starts_with("{0}") {{ return None }} Some(match &name["{0}".len()..] {{'''.format(platform.platform_prefix()) diff --git a/src/etc/rust-gdb b/src/etc/rust-gdb index 52601cd96f80d..6835d6aa90874 100755 --- a/src/etc/rust-gdb +++ b/src/etc/rust-gdb @@ -21,6 +21,6 @@ GDB_PYTHON_MODULE_DIRECTORY="$RUSTC_SYSROOT/lib/rustlib/etc" # different/specific command (defaults to `gdb`). RUST_GDB="${RUST_GDB:-gdb}" PYTHONPATH="$PYTHONPATH:$GDB_PYTHON_MODULE_DIRECTORY" ${RUST_GDB} \ - -d "$GDB_PYTHON_MODULE_DIRECTORY" \ + --directory="$GDB_PYTHON_MODULE_DIRECTORY" \ -iex "add-auto-load-safe-path $GDB_PYTHON_MODULE_DIRECTORY" \ "$@" diff --git a/src/etc/wasm32-shim.js b/src/etc/wasm32-shim.js index 98d6202a63fbf..378aae5973316 100644 --- a/src/etc/wasm32-shim.js +++ b/src/etc/wasm32-shim.js @@ -107,6 +107,10 @@ imports.env = { exp2f: function(x) { return Math.pow(2, x); }, ldexp: function(x, y) { return x * Math.pow(2, y); }, ldexpf: function(x, y) { return x * Math.pow(2, y); }, + sin: Math.sin, + sinf: Math.sin, + cos: Math.cos, + cosf: Math.cos, log: Math.log, log2: Math.log2, log10: Math.log10, diff --git a/src/liballoc/Cargo.toml b/src/liballoc/Cargo.toml index 6383bd1e941ed..ada21e04b306c 100644 --- a/src/liballoc/Cargo.toml +++ b/src/liballoc/Cargo.toml @@ -2,6 +2,8 @@ authors = ["The Rust Project Developers"] name = "alloc" version = "0.0.0" +autotests = false +autobenches = false [lib] name = "alloc" diff --git a/src/liballoc/alloc.rs b/src/liballoc/alloc.rs index f59c9f7fd61cb..84bd275df347c 100644 --- a/src/liballoc/alloc.rs +++ b/src/liballoc/alloc.rs @@ -8,42 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] +//! Memory allocation APIs + +#![stable(feature = "alloc_module", since = "1.28.0")] use core::intrinsics::{min_align_of_val, size_of_val}; use core::ptr::{NonNull, Unique}; use core::usize; +#[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use core::alloc::*; -#[cfg(stage0)] -extern "Rust" { - #[allocator] - #[rustc_allocator_nounwind] - fn __rust_alloc(size: usize, align: usize, err: *mut u8) -> *mut u8; - #[cold] - #[rustc_allocator_nounwind] - fn __rust_oom(err: *const u8) -> !; - #[rustc_allocator_nounwind] - fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); - #[rustc_allocator_nounwind] - fn __rust_realloc(ptr: *mut u8, - old_size: usize, - old_align: usize, - new_size: usize, - new_align: usize, - err: *mut u8) -> *mut u8; - #[rustc_allocator_nounwind] - fn __rust_alloc_zeroed(size: usize, align: usize, err: *mut u8) -> *mut u8; -} - -#[cfg(not(stage0))] extern "Rust" { #[allocator] #[rustc_allocator_nounwind] @@ -59,82 +35,117 @@ extern "Rust" { fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8; } +/// The global memory allocator. +/// +/// This type implements the [`Alloc`] trait by forwarding calls +/// to the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, Default, Debug)] pub struct Global; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] -pub type Heap = Global; - -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "type renamed to `Global`")] -#[allow(non_upper_case_globals)] -pub const Heap: Global = Global; - -unsafe impl GlobalAlloc for Global { - #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - #[cfg(not(stage0))] - let ptr = __rust_alloc(layout.size(), layout.align()); - #[cfg(stage0)] - let ptr = __rust_alloc(layout.size(), layout.align(), &mut 0); - ptr as *mut Opaque - } +/// Allocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::alloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `alloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::alloc`]. +#[stable(feature = "global_alloc", since = "1.28.0")] +#[inline] +pub unsafe fn alloc(layout: Layout) -> *mut u8 { + __rust_alloc(layout.size(), layout.align()) +} - #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { - __rust_dealloc(ptr as *mut u8, layout.size(), layout.align()) - } +/// Deallocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::dealloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `dealloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::dealloc`]. +#[stable(feature = "global_alloc", since = "1.28.0")] +#[inline] +pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) { + __rust_dealloc(ptr, layout.size(), layout.align()) +} - #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { - #[cfg(not(stage0))] - let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), new_size); - #[cfg(stage0)] - let ptr = __rust_realloc(ptr as *mut u8, layout.size(), layout.align(), - new_size, layout.align(), &mut 0); - ptr as *mut Opaque - } +/// Reallocate memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::realloc`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `realloc` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::realloc`]. +#[stable(feature = "global_alloc", since = "1.28.0")] +#[inline] +pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + __rust_realloc(ptr, layout.size(), layout.align(), new_size) +} - #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - #[cfg(not(stage0))] - let ptr = __rust_alloc_zeroed(layout.size(), layout.align()); - #[cfg(stage0)] - let ptr = __rust_alloc_zeroed(layout.size(), layout.align(), &mut 0); - ptr as *mut Opaque - } +/// Allocate zero-initialized memory with the global allocator. +/// +/// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method +/// of the allocator registered with the `#[global_allocator]` attribute +/// if there is one, or the `std` crate’s default. +/// +/// This function is expected to be deprecated in favor of the `alloc_zeroed` method +/// of the [`Global`] type when it and the [`Alloc`] trait become stable. +/// +/// # Safety +/// +/// See [`GlobalAlloc::alloc_zeroed`]. +#[stable(feature = "global_alloc", since = "1.28.0")] +#[inline] +pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { + __rust_alloc_zeroed(layout.size(), layout.align()) } +#[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for Global { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + NonNull::new(alloc(layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + dealloc(ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) - -> Result, AllocErr> + -> Result, AllocErr> { - NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) + NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr) } } /// The allocator for unique pointers. -// This function must not unwind. If it does, MIR trans will fail. +// This function must not unwind. If it does, MIR codegen will fail. #[cfg(not(test))] #[lang = "exchange_malloc"] #[inline] @@ -143,23 +154,16 @@ unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { align as *mut u8 } else { let layout = Layout::from_size_align_unchecked(size, align); - let ptr = Global.alloc(layout); + let ptr = alloc(layout); if !ptr.is_null() { - ptr as *mut u8 + ptr } else { - oom() + handle_alloc_error(layout) } } } -#[cfg(stage0)] -#[lang = "box_free"] -#[inline] -unsafe fn old_box_free(ptr: *mut T) { - box_free(Unique::new_unchecked(ptr)) -} - -#[cfg_attr(not(any(test, stage0)), lang = "box_free")] +#[cfg_attr(not(test), lang = "box_free")] #[inline] pub(crate) unsafe fn box_free(ptr: Unique) { let ptr = ptr.as_ptr(); @@ -168,22 +172,31 @@ pub(crate) unsafe fn box_free(ptr: Unique) { // We do not allocate for Box when T is ZST, so deallocation is also not necessary. if size != 0 { let layout = Layout::from_size_align_unchecked(size, align); - Global.dealloc(ptr as *mut Opaque, layout); + dealloc(ptr as *mut u8, layout); } } -#[cfg(stage0)] -pub fn oom() -> ! { - unsafe { ::core::intrinsics::abort() } -} - -#[cfg(not(stage0))] -pub fn oom() -> ! { - extern { +/// Abort on memory allocation error or failure. +/// +/// Callers of memory allocation APIs wishing to abort computation +/// in response to an allocation error are encouraged to call this function, +/// rather than directly invoking `panic!` or similar. +/// +/// The default behavior of this function is to print a message to standard error +/// and abort the process. +/// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`]. +/// +/// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html +/// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html +#[stable(feature = "global_alloc", since = "1.28.0")] +#[rustc_allocator_nounwind] +pub fn handle_alloc_error(layout: Layout) -> ! { + #[allow(improper_ctypes)] + extern "Rust" { #[lang = "oom"] - fn oom_impl() -> !; + fn oom_impl(layout: Layout) -> !; } - unsafe { oom_impl() } + unsafe { oom_impl(layout) } } #[cfg(test)] @@ -191,14 +204,14 @@ mod tests { extern crate test; use self::test::Bencher; use boxed::Box; - use alloc::{Global, Alloc, Layout, oom}; + use alloc::{Global, Alloc, Layout, handle_alloc_error}; #[test] fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); let ptr = Global.alloc_zeroed(layout.clone()) - .unwrap_or_else(|_| oom()); + .unwrap_or_else(|_| handle_alloc_error(layout)); let mut i = ptr.cast::().as_ptr(); let end = i.offset(layout.size() as isize); diff --git a/src/liballoc/arc.rs b/src/liballoc/arc.rs deleted file mode 100644 index d0950bff9ce80..0000000000000 --- a/src/liballoc/arc.rs +++ /dev/null @@ -1,1861 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![stable(feature = "rust1", since = "1.0.0")] - -//! Thread-safe reference-counting pointers. -//! -//! See the [`Arc`][arc] documentation for more details. -//! -//! [arc]: struct.Arc.html - -use core::sync::atomic; -use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use core::borrow; -use core::fmt; -use core::cmp::Ordering; -use core::intrinsics::abort; -use core::mem::{self, align_of_val, size_of_val, uninitialized}; -use core::ops::Deref; -use core::ops::CoerceUnsized; -use core::ptr::{self, NonNull}; -use core::marker::{Unsize, PhantomData}; -use core::hash::{Hash, Hasher}; -use core::{isize, usize}; -use core::convert::From; - -use alloc::{Global, Alloc, Layout, box_free, oom}; -use boxed::Box; -use string::String; -use vec::Vec; - -/// A soft limit on the amount of references that may be made to an `Arc`. -/// -/// Going above this limit will abort your program (although not -/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. -const MAX_REFCOUNT: usize = (isize::MAX) as usize; - -/// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically -/// Reference Counted'. -/// -/// The type `Arc` provides shared ownership of a value of type `T`, -/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces -/// a new pointer to the same value in the heap. When the last `Arc` -/// pointer to a given value is destroyed, the pointed-to value is -/// also destroyed. -/// -/// Shared references in Rust disallow mutation by default, and `Arc` is no -/// exception: you cannot generally obtain a mutable reference to something -/// inside an `Arc`. If you need to mutate through an `Arc`, use -/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic] -/// types. -/// -/// ## Thread Safety -/// -/// Unlike [`Rc`], `Arc` uses atomic operations for its reference -/// counting. This means that it is thread-safe. The disadvantage is that -/// atomic operations are more expensive than ordinary memory accesses. If you -/// are not sharing reference-counted values between threads, consider using -/// [`Rc`] for lower overhead. [`Rc`] is a safe default, because the -/// compiler will catch any attempt to send an [`Rc`] between threads. -/// However, a library might choose `Arc` in order to give library consumers -/// more flexibility. -/// -/// `Arc` will implement [`Send`] and [`Sync`] as long as the `T` implements -/// [`Send`] and [`Sync`]. Why can't you put a non-thread-safe type `T` in an -/// `Arc` to make it thread-safe? This may be a bit counter-intuitive at -/// first: after all, isn't the point of `Arc` thread safety? The key is -/// this: `Arc` makes it thread safe to have multiple ownership of the same -/// data, but it doesn't add thread safety to its data. Consider -/// `Arc<`[`RefCell`]`>`. [`RefCell`] isn't [`Sync`], and if `Arc` was always -/// [`Send`], `Arc<`[`RefCell`]`>` would be as well. But then we'd have a problem: -/// [`RefCell`] is not thread safe; it keeps track of the borrowing count using -/// non-atomic operations. -/// -/// In the end, this means that you may need to pair `Arc` with some sort of -/// [`std::sync`] type, usually [`Mutex`][mutex]. -/// -/// ## Breaking cycles with `Weak` -/// -/// The [`downgrade`][downgrade] method can be used to create a non-owning -/// [`Weak`][weak] pointer. A [`Weak`][weak] pointer can be [`upgrade`][upgrade]d -/// to an `Arc`, but this will return [`None`] if the value has already been -/// dropped. -/// -/// A cycle between `Arc` pointers will never be deallocated. For this reason, -/// [`Weak`][weak] is used to break cycles. For example, a tree could have -/// strong `Arc` pointers from parent nodes to children, and [`Weak`][weak] -/// pointers from children back to their parents. -/// -/// # Cloning references -/// -/// Creating a new reference from an existing reference counted pointer is done using the -/// `Clone` trait implemented for [`Arc`][arc] and [`Weak`][weak]. -/// -/// ``` -/// use std::sync::Arc; -/// let foo = Arc::new(vec![1.0, 2.0, 3.0]); -/// // The two syntaxes below are equivalent. -/// let a = foo.clone(); -/// let b = Arc::clone(&foo); -/// // a and b both point to the same memory location as foo. -/// ``` -/// -/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly -/// the meaning of the code. In the example above, this syntax makes it easier to see that -/// this code is creating a new reference rather than copying the whole content of foo. -/// -/// ## `Deref` behavior -/// -/// `Arc` automatically dereferences to `T` (via the [`Deref`][deref] trait), -/// so you can call `T`'s methods on a value of type `Arc`. To avoid name -/// clashes with `T`'s methods, the methods of `Arc` itself are [associated -/// functions][assoc], called using function-like syntax: -/// -/// ``` -/// use std::sync::Arc; -/// let my_arc = Arc::new(()); -/// -/// Arc::downgrade(&my_arc); -/// ``` -/// -/// [`Weak`][weak] does not auto-dereference to `T`, because the value may have -/// already been destroyed. -/// -/// [arc]: struct.Arc.html -/// [weak]: struct.Weak.html -/// [`Rc`]: ../../std/rc/struct.Rc.html -/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone -/// [mutex]: ../../std/sync/struct.Mutex.html -/// [rwlock]: ../../std/sync/struct.RwLock.html -/// [atomic]: ../../std/sync/atomic/index.html -/// [`Send`]: ../../std/marker/trait.Send.html -/// [`Sync`]: ../../std/marker/trait.Sync.html -/// [deref]: ../../std/ops/trait.Deref.html -/// [downgrade]: struct.Arc.html#method.downgrade -/// [upgrade]: struct.Weak.html#method.upgrade -/// [`None`]: ../../std/option/enum.Option.html#variant.None -/// [assoc]: ../../book/first-edition/method-syntax.html#associated-functions -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`std::sync`]: ../../std/sync/index.html -/// [`Arc::clone(&from)`]: #method.clone -/// -/// # Examples -/// -/// Sharing some immutable data between threads: -/// -// Note that we **do not** run these tests here. The windows builders get super -// unhappy if a thread outlives the main thread and then exits at the same time -// (something deadlocks) so we just avoid this entirely by not running these -// tests. -/// ```no_run -/// use std::sync::Arc; -/// use std::thread; -/// -/// let five = Arc::new(5); -/// -/// for _ in 0..10 { -/// let five = Arc::clone(&five); -/// -/// thread::spawn(move || { -/// println!("{:?}", five); -/// }); -/// } -/// ``` -/// -/// Sharing a mutable [`AtomicUsize`]: -/// -/// [`AtomicUsize`]: ../../std/sync/atomic/struct.AtomicUsize.html -/// -/// ```no_run -/// use std::sync::Arc; -/// use std::sync::atomic::{AtomicUsize, Ordering}; -/// use std::thread; -/// -/// let val = Arc::new(AtomicUsize::new(5)); -/// -/// for _ in 0..10 { -/// let val = Arc::clone(&val); -/// -/// thread::spawn(move || { -/// let v = val.fetch_add(1, Ordering::SeqCst); -/// println!("{:?}", v); -/// }); -/// } -/// ``` -/// -/// See the [`rc` documentation][rc_examples] for more examples of reference -/// counting in general. -/// -/// [rc_examples]: ../../std/rc/index.html#examples -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Arc { - ptr: NonNull>, - phantom: PhantomData, -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Arc {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for Arc {} - -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized> CoerceUnsized> for Arc {} - -/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the -/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` -/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. -/// -/// Since a `Weak` reference does not count towards ownership, it will not -/// prevent the inner value from being dropped, and `Weak` itself makes no -/// guarantees about the value still being present and may return [`None`] -/// when [`upgrade`]d. -/// -/// A `Weak` pointer is useful for keeping a temporary reference to the value -/// within [`Arc`] without extending its lifetime. It is also used to prevent -/// circular references between [`Arc`] pointers, since mutual owning references -/// would never allow either [`Arc`] to be dropped. For example, a tree could -/// have strong [`Arc`] pointers from parent nodes to children, and `Weak` -/// pointers from children back to their parents. -/// -/// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. -/// -/// [`Arc`]: struct.Arc.html -/// [`Arc::downgrade`]: struct.Arc.html#method.downgrade -/// [`upgrade`]: struct.Weak.html#method.upgrade -/// [`Option`]: ../../std/option/enum.Option.html -/// [`None`]: ../../std/option/enum.Option.html#variant.None -#[stable(feature = "arc_weak", since = "1.4.0")] -pub struct Weak { - ptr: NonNull>, -} - -#[stable(feature = "arc_weak", since = "1.4.0")] -unsafe impl Send for Weak {} -#[stable(feature = "arc_weak", since = "1.4.0")] -unsafe impl Sync for Weak {} - -#[unstable(feature = "coerce_unsized", issue = "27732")] -impl, U: ?Sized> CoerceUnsized> for Weak {} - -#[stable(feature = "arc_weak", since = "1.4.0")] -impl fmt::Debug for Weak { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "(Weak)") - } -} - -struct ArcInner { - strong: atomic::AtomicUsize, - - // the value usize::MAX acts as a sentinel for temporarily "locking" the - // ability to upgrade weak pointers or downgrade strong ones; this is used - // to avoid races in `make_mut` and `get_mut`. - weak: atomic::AtomicUsize, - - data: T, -} - -unsafe impl Send for ArcInner {} -unsafe impl Sync for ArcInner {} - -impl Arc { - /// Constructs a new `Arc`. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// ``` - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - pub fn new(data: T) -> Arc { - // Start the weak pointer count as 1 which is the weak pointer that's - // held by all the strong pointers (kinda), see std/rc.rs for more info - let x: Box<_> = box ArcInner { - strong: atomic::AtomicUsize::new(1), - weak: atomic::AtomicUsize::new(1), - data, - }; - Arc { ptr: Box::into_raw_non_null(x), phantom: PhantomData } - } - - /// Returns the contained value, if the `Arc` has exactly one strong reference. - /// - /// Otherwise, an [`Err`][result] is returned with the same `Arc` that was - /// passed in. - /// - /// This will succeed even if there are outstanding weak references. - /// - /// [result]: ../../std/result/enum.Result.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x = Arc::new(3); - /// assert_eq!(Arc::try_unwrap(x), Ok(3)); - /// - /// let x = Arc::new(4); - /// let _y = Arc::clone(&x); - /// assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4); - /// ``` - #[inline] - #[stable(feature = "arc_unique", since = "1.4.0")] - pub fn try_unwrap(this: Self) -> Result { - // See `drop` for why all these atomics are like this - if this.inner().strong.compare_exchange(1, 0, Release, Relaxed).is_err() { - return Err(this); - } - - atomic::fence(Acquire); - - unsafe { - let elem = ptr::read(&this.ptr.as_ref().data); - - // Make a weak pointer to clean up the implicit strong-weak reference - let _weak = Weak { ptr: this.ptr }; - mem::forget(this); - - Ok(elem) - } - } -} - -impl Arc { - /// Consumes the `Arc`, returning the wrapped pointer. - /// - /// To avoid a memory leak the pointer must be converted back to an `Arc` using - /// [`Arc::from_raw`][from_raw]. - /// - /// [from_raw]: struct.Arc.html#method.from_raw - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x = Arc::new(10); - /// let x_ptr = Arc::into_raw(x); - /// assert_eq!(unsafe { *x_ptr }, 10); - /// ``` - #[stable(feature = "rc_raw", since = "1.17.0")] - pub fn into_raw(this: Self) -> *const T { - let ptr: *const T = &*this; - mem::forget(this); - ptr - } - - /// Constructs an `Arc` from a raw pointer. - /// - /// The raw pointer must have been previously returned by a call to a - /// [`Arc::into_raw`][into_raw]. - /// - /// This function is unsafe because improper use may lead to memory problems. For example, a - /// double-free may occur if the function is called twice on the same raw pointer. - /// - /// [into_raw]: struct.Arc.html#method.into_raw - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x = Arc::new(10); - /// let x_ptr = Arc::into_raw(x); - /// - /// unsafe { - /// // Convert back to an `Arc` to prevent leak. - /// let x = Arc::from_raw(x_ptr); - /// assert_eq!(*x, 10); - /// - /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. - /// } - /// - /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! - /// ``` - #[stable(feature = "rc_raw", since = "1.17.0")] - pub unsafe fn from_raw(ptr: *const T) -> Self { - // Align the unsized value to the end of the ArcInner. - // Because it is ?Sized, it will always be the last field in memory. - let align = align_of_val(&*ptr); - let layout = Layout::new::>(); - let offset = (layout.size() + layout.padding_needed_for(align)) as isize; - - // Reverse the offset to find the original ArcInner. - let fake_ptr = ptr as *mut ArcInner; - let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); - - Arc { - ptr: NonNull::new_unchecked(arc_ptr), - phantom: PhantomData, - } - } - - /// Creates a new [`Weak`][weak] pointer to this value. - /// - /// [weak]: struct.Weak.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// let weak_five = Arc::downgrade(&five); - /// ``` - #[stable(feature = "arc_weak", since = "1.4.0")] - pub fn downgrade(this: &Self) -> Weak { - // This Relaxed is OK because we're checking the value in the CAS - // below. - let mut cur = this.inner().weak.load(Relaxed); - - loop { - // check if the weak counter is currently "locked"; if so, spin. - if cur == usize::MAX { - cur = this.inner().weak.load(Relaxed); - continue; - } - - // NOTE: this code currently ignores the possibility of overflow - // into usize::MAX; in general both Rc and Arc need to be adjusted - // to deal with overflow. - - // Unlike with Clone(), we need this to be an Acquire read to - // synchronize with the write coming from `is_unique`, so that the - // events prior to that write happen before this read. - match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) { - Ok(_) => return Weak { ptr: this.ptr }, - Err(old) => cur = old, - } - } - } - - /// Gets the number of [`Weak`][weak] pointers to this value. - /// - /// [weak]: struct.Weak.html - /// - /// # Safety - /// - /// This method by itself is safe, but using it correctly requires extra care. - /// Another thread can change the weak count at any time, - /// including potentially between calling this method and acting on the result. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// let _weak_five = Arc::downgrade(&five); - /// - /// // This assertion is deterministic because we haven't shared - /// // the `Arc` or `Weak` between threads. - /// assert_eq!(1, Arc::weak_count(&five)); - /// ``` - #[inline] - #[stable(feature = "arc_counts", since = "1.15.0")] - pub fn weak_count(this: &Self) -> usize { - let cnt = this.inner().weak.load(SeqCst); - // If the weak count is currently locked, the value of the - // count was 0 just before taking the lock. - if cnt == usize::MAX { 0 } else { cnt - 1 } - } - - /// Gets the number of strong (`Arc`) pointers to this value. - /// - /// # Safety - /// - /// This method by itself is safe, but using it correctly requires extra care. - /// Another thread can change the strong count at any time, - /// including potentially between calling this method and acting on the result. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// let _also_five = Arc::clone(&five); - /// - /// // This assertion is deterministic because we haven't shared - /// // the `Arc` between threads. - /// assert_eq!(2, Arc::strong_count(&five)); - /// ``` - #[inline] - #[stable(feature = "arc_counts", since = "1.15.0")] - pub fn strong_count(this: &Self) -> usize { - this.inner().strong.load(SeqCst) - } - - #[inline] - fn inner(&self) -> &ArcInner { - // This unsafety is ok because while this arc is alive we're guaranteed - // that the inner pointer is valid. Furthermore, we know that the - // `ArcInner` structure itself is `Sync` because the inner data is - // `Sync` as well, so we're ok loaning out an immutable pointer to these - // contents. - unsafe { self.ptr.as_ref() } - } - - // Non-inlined part of `drop`. - #[inline(never)] - unsafe fn drop_slow(&mut self) { - // Destroy the data at this time, even though we may not free the box - // allocation itself (there may still be weak pointers lying around). - ptr::drop_in_place(&mut self.ptr.as_mut().data); - - if self.inner().weak.fetch_sub(1, Release) == 1 { - atomic::fence(Acquire); - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) - } - } - - #[inline] - #[stable(feature = "ptr_eq", since = "1.17.0")] - /// Returns true if the two `Arc`s point to the same value (not - /// just values that compare as equal). - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// let same_five = Arc::clone(&five); - /// let other_five = Arc::new(5); - /// - /// assert!(Arc::ptr_eq(&five, &same_five)); - /// assert!(!Arc::ptr_eq(&five, &other_five)); - /// ``` - pub fn ptr_eq(this: &Self, other: &Self) -> bool { - this.ptr.as_ptr() == other.ptr.as_ptr() - } -} - -impl Arc { - // Allocates an `ArcInner` with sufficient space for an unsized value - unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner { - // Create a fake ArcInner to find allocation size and alignment - let fake_ptr = ptr as *mut ArcInner; - - let layout = Layout::for_value(&*fake_ptr); - - let mem = Global.alloc(layout) - .unwrap_or_else(|_| oom()); - - // Initialize the real ArcInner - let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; - - ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); - ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); - - inner - } - - fn from_box(v: Box) -> Arc { - unsafe { - let box_unique = Box::into_unique(v); - let bptr = box_unique.as_ptr(); - - let value_size = size_of_val(&*bptr); - let ptr = Self::allocate_for_ptr(bptr); - - // Copy value as bytes - ptr::copy_nonoverlapping( - bptr as *const T as *const u8, - &mut (*ptr).data as *mut _ as *mut u8, - value_size); - - // Free the allocation without dropping its contents - box_free(box_unique); - - Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } - } - } -} - -// Sets the data pointer of a `?Sized` raw pointer. -// -// For a slice/trait object, this sets the `data` field and leaves the rest -// unchanged. For a sized raw pointer, this simply sets the pointer. -unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { - ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); - ptr -} - -impl Arc<[T]> { - // Copy elements from slice into newly allocated Arc<[T]> - // - // Unsafe because the caller must either take ownership or bind `T: Copy` - unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { - let v_ptr = v as *const [T]; - let ptr = Self::allocate_for_ptr(v_ptr); - - ptr::copy_nonoverlapping( - v.as_ptr(), - &mut (*ptr).data as *mut [T] as *mut T, - v.len()); - - Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } - } -} - -// Specialization trait used for From<&[T]> -trait ArcFromSlice { - fn from_slice(slice: &[T]) -> Self; -} - -impl ArcFromSlice for Arc<[T]> { - #[inline] - default fn from_slice(v: &[T]) -> Self { - // Panic guard while cloning T elements. - // In the event of a panic, elements that have been written - // into the new ArcInner will be dropped, then the memory freed. - struct Guard { - mem: NonNull, - elems: *mut T, - layout: Layout, - n_elems: usize, - } - - impl Drop for Guard { - fn drop(&mut self) { - use core::slice::from_raw_parts_mut; - - unsafe { - let slice = from_raw_parts_mut(self.elems, self.n_elems); - ptr::drop_in_place(slice); - - Global.dealloc(self.mem.as_opaque(), self.layout.clone()); - } - } - } - - unsafe { - let v_ptr = v as *const [T]; - let ptr = Self::allocate_for_ptr(v_ptr); - - let mem = ptr as *mut _ as *mut u8; - let layout = Layout::for_value(&*ptr); - - // Pointer to first element - let elems = &mut (*ptr).data as *mut [T] as *mut T; - - let mut guard = Guard{ - mem: NonNull::new_unchecked(mem), - elems: elems, - layout: layout, - n_elems: 0, - }; - - for (i, item) in v.iter().enumerate() { - ptr::write(elems.offset(i as isize), item.clone()); - guard.n_elems += 1; - } - - // All clear. Forget the guard so it doesn't free the new ArcInner. - mem::forget(guard); - - Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } - } - } -} - -impl ArcFromSlice for Arc<[T]> { - #[inline] - fn from_slice(v: &[T]) -> Self { - unsafe { Arc::copy_from_slice(v) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Arc { - /// Makes a clone of the `Arc` pointer. - /// - /// This creates another pointer to the same inner value, increasing the - /// strong reference count. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// Arc::clone(&five); - /// ``` - #[inline] - fn clone(&self) -> Arc { - // Using a relaxed ordering is alright here, as knowledge of the - // original reference prevents other threads from erroneously deleting - // the object. - // - // As explained in the [Boost documentation][1], Increasing the - // reference counter can always be done with memory_order_relaxed: New - // references to an object can only be formed from an existing - // reference, and passing an existing reference from one thread to - // another must already provide any required synchronization. - // - // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) - let old_size = self.inner().strong.fetch_add(1, Relaxed); - - // However we need to guard against massive refcounts in case someone - // is `mem::forget`ing Arcs. If we don't do this the count can overflow - // and users will use-after free. We racily saturate to `isize::MAX` on - // the assumption that there aren't ~2 billion threads incrementing - // the reference count at once. This branch will never be taken in - // any realistic program. - // - // We abort because such a program is incredibly degenerate, and we - // don't care to support it. - if old_size > MAX_REFCOUNT { - unsafe { - abort(); - } - } - - Arc { ptr: self.ptr, phantom: PhantomData } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Deref for Arc { - type Target = T; - - #[inline] - fn deref(&self) -> &T { - &self.inner().data - } -} - -impl Arc { - /// Makes a mutable reference into the given `Arc`. - /// - /// If there are other `Arc` or [`Weak`][weak] pointers to the same value, - /// then `make_mut` will invoke [`clone`][clone] on the inner value to - /// ensure unique ownership. This is also referred to as clone-on-write. - /// - /// See also [`get_mut`][get_mut], which will fail rather than cloning. - /// - /// [weak]: struct.Weak.html - /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone - /// [get_mut]: struct.Arc.html#method.get_mut - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let mut data = Arc::new(5); - /// - /// *Arc::make_mut(&mut data) += 1; // Won't clone anything - /// let mut other_data = Arc::clone(&data); // Won't clone inner data - /// *Arc::make_mut(&mut data) += 1; // Clones inner data - /// *Arc::make_mut(&mut data) += 1; // Won't clone anything - /// *Arc::make_mut(&mut other_data) *= 2; // Won't clone anything - /// - /// // Now `data` and `other_data` point to different values. - /// assert_eq!(*data, 8); - /// assert_eq!(*other_data, 12); - /// ``` - #[inline] - #[stable(feature = "arc_unique", since = "1.4.0")] - pub fn make_mut(this: &mut Self) -> &mut T { - // Note that we hold both a strong reference and a weak reference. - // Thus, releasing our strong reference only will not, by itself, cause - // the memory to be deallocated. - // - // Use Acquire to ensure that we see any writes to `weak` that happen - // before release writes (i.e., decrements) to `strong`. Since we hold a - // weak count, there's no chance the ArcInner itself could be - // deallocated. - if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() { - // Another strong pointer exists; clone - *this = Arc::new((**this).clone()); - } else if this.inner().weak.load(Relaxed) != 1 { - // Relaxed suffices in the above because this is fundamentally an - // optimization: we are always racing with weak pointers being - // dropped. Worst case, we end up allocated a new Arc unnecessarily. - - // We removed the last strong ref, but there are additional weak - // refs remaining. We'll move the contents to a new Arc, and - // invalidate the other weak refs. - - // Note that it is not possible for the read of `weak` to yield - // usize::MAX (i.e., locked), since the weak count can only be - // locked by a thread with a strong reference. - - // Materialize our own implicit weak pointer, so that it can clean - // up the ArcInner as needed. - let weak = Weak { ptr: this.ptr }; - - // mark the data itself as already deallocated - unsafe { - // there is no data race in the implicit write caused by `read` - // here (due to zeroing) because data is no longer accessed by - // other threads (due to there being no more strong refs at this - // point). - let mut swap = Arc::new(ptr::read(&weak.ptr.as_ref().data)); - mem::swap(this, &mut swap); - mem::forget(swap); - } - } else { - // We were the sole reference of either kind; bump back up the - // strong ref count. - this.inner().strong.store(1, Release); - } - - // As with `get_mut()`, the unsafety is ok because our reference was - // either unique to begin with, or became one upon cloning the contents. - unsafe { - &mut this.ptr.as_mut().data - } - } -} - -impl Arc { - /// Returns a mutable reference to the inner value, if there are - /// no other `Arc` or [`Weak`][weak] pointers to the same value. - /// - /// Returns [`None`][option] otherwise, because it is not safe to - /// mutate a shared value. - /// - /// See also [`make_mut`][make_mut], which will [`clone`][clone] - /// the inner value when it's shared. - /// - /// [weak]: struct.Weak.html - /// [option]: ../../std/option/enum.Option.html - /// [make_mut]: struct.Arc.html#method.make_mut - /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let mut x = Arc::new(3); - /// *Arc::get_mut(&mut x).unwrap() = 4; - /// assert_eq!(*x, 4); - /// - /// let _y = Arc::clone(&x); - /// assert!(Arc::get_mut(&mut x).is_none()); - /// ``` - #[inline] - #[stable(feature = "arc_unique", since = "1.4.0")] - pub fn get_mut(this: &mut Self) -> Option<&mut T> { - if this.is_unique() { - // This unsafety is ok because we're guaranteed that the pointer - // returned is the *only* pointer that will ever be returned to T. Our - // reference count is guaranteed to be 1 at this point, and we required - // the Arc itself to be `mut`, so we're returning the only possible - // reference to the inner data. - unsafe { - Some(&mut this.ptr.as_mut().data) - } - } else { - None - } - } - - /// Determine whether this is the unique reference (including weak refs) to - /// the underlying data. - /// - /// Note that this requires locking the weak ref count. - fn is_unique(&mut self) -> bool { - // lock the weak pointer count if we appear to be the sole weak pointer - // holder. - // - // The acquire label here ensures a happens-before relationship with any - // writes to `strong` prior to decrements of the `weak` count (via drop, - // which uses Release). - if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() { - // Due to the previous acquire read, this will observe any writes to - // `strong` that were due to upgrading weak pointers; only strong - // clones remain, which require that the strong count is > 1 anyway. - let unique = self.inner().strong.load(Relaxed) == 1; - - // The release write here synchronizes with a read in `downgrade`, - // effectively preventing the above read of `strong` from happening - // after the write. - self.inner().weak.store(1, Release); // release the lock - unique - } else { - false - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { - /// Drops the `Arc`. - /// - /// This will decrement the strong reference count. If the strong reference - /// count reaches zero then the only other references (if any) are - /// [`Weak`][weak], so we `drop` the inner value. - /// - /// [weak]: struct.Weak.html - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// struct Foo; - /// - /// impl Drop for Foo { - /// fn drop(&mut self) { - /// println!("dropped!"); - /// } - /// } - /// - /// let foo = Arc::new(Foo); - /// let foo2 = Arc::clone(&foo); - /// - /// drop(foo); // Doesn't print anything - /// drop(foo2); // Prints "dropped!" - /// ``` - #[inline] - fn drop(&mut self) { - // Because `fetch_sub` is already atomic, we do not need to synchronize - // with other threads unless we are going to delete the object. This - // same logic applies to the below `fetch_sub` to the `weak` count. - if self.inner().strong.fetch_sub(1, Release) != 1 { - return; - } - - // This fence is needed to prevent reordering of use of the data and - // deletion of the data. Because it is marked `Release`, the decreasing - // of the reference count synchronizes with this `Acquire` fence. This - // means that use of the data happens before decreasing the reference - // count, which happens before this fence, which happens before the - // deletion of the data. - // - // As explained in the [Boost documentation][1], - // - // > It is important to enforce any possible access to the object in one - // > thread (through an existing reference) to *happen before* deleting - // > the object in a different thread. This is achieved by a "release" - // > operation after dropping a reference (any access to the object - // > through this reference must obviously happened before), and an - // > "acquire" operation before deleting the object. - // - // In particular, while the contents of an Arc are usually immutable, it's - // possible to have interior writes to something like a Mutex. Since a - // Mutex is not acquired when it is deleted, we can't rely on its - // synchronization logic to make writes in thread A visible to a destructor - // running in thread B. - // - // Also note that the Acquire fence here could probably be replaced with an - // Acquire load, which could improve performance in highly-contended - // situations. See [2]. - // - // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) - // [2]: (https://github.com/rust-lang/rust/pull/41714) - atomic::fence(Acquire); - - unsafe { - self.drop_slow(); - } - } -} - -impl Weak { - /// Constructs a new `Weak`, allocating memory for `T` without initializing - /// it. Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: struct.Weak.html#method.upgrade - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::sync::Weak; - /// - /// let empty: Weak = Weak::new(); - /// assert!(empty.upgrade().is_none()); - /// ``` - #[stable(feature = "downgraded_weak", since = "1.10.0")] - pub fn new() -> Weak { - unsafe { - Weak { - ptr: Box::into_raw_non_null(box ArcInner { - strong: atomic::AtomicUsize::new(0), - weak: atomic::AtomicUsize::new(1), - data: uninitialized(), - }), - } - } - } -} - -impl Weak { - /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending - /// the lifetime of the value if successful. - /// - /// Returns [`None`] if the value has since been dropped. - /// - /// [`Arc`]: struct.Arc.html - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// let weak_five = Arc::downgrade(&five); - /// - /// let strong_five: Option> = weak_five.upgrade(); - /// assert!(strong_five.is_some()); - /// - /// // Destroy all strong pointers. - /// drop(strong_five); - /// drop(five); - /// - /// assert!(weak_five.upgrade().is_none()); - /// ``` - #[stable(feature = "arc_weak", since = "1.4.0")] - pub fn upgrade(&self) -> Option> { - // We use a CAS loop to increment the strong count instead of a - // fetch_add because once the count hits 0 it must never be above 0. - let inner = self.inner(); - - // Relaxed load because any write of 0 that we can observe - // leaves the field in a permanently zero state (so a - // "stale" read of 0 is fine), and any other value is - // confirmed via the CAS below. - let mut n = inner.strong.load(Relaxed); - - loop { - if n == 0 { - return None; - } - - // See comments in `Arc::clone` for why we do this (for `mem::forget`). - if n > MAX_REFCOUNT { - unsafe { - abort(); - } - } - - // Relaxed is valid for the same reason it is on Arc's Clone impl - match inner.strong.compare_exchange_weak(n, n + 1, Relaxed, Relaxed) { - Ok(_) => return Some(Arc { ptr: self.ptr, phantom: PhantomData }), - Err(old) => n = old, - } - } - } - - #[inline] - fn inner(&self) -> &ArcInner { - // See comments above for why this is "safe" - unsafe { self.ptr.as_ref() } - } -} - -#[stable(feature = "arc_weak", since = "1.4.0")] -impl Clone for Weak { - /// Makes a clone of the `Weak` pointer that points to the same value. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Weak}; - /// - /// let weak_five = Arc::downgrade(&Arc::new(5)); - /// - /// Weak::clone(&weak_five); - /// ``` - #[inline] - fn clone(&self) -> Weak { - // See comments in Arc::clone() for why this is relaxed. This can use a - // fetch_add (ignoring the lock) because the weak count is only locked - // where are *no other* weak pointers in existence. (So we can't be - // running this code in that case). - let old_size = self.inner().weak.fetch_add(1, Relaxed); - - // See comments in Arc::clone() for why we do this (for mem::forget). - if old_size > MAX_REFCOUNT { - unsafe { - abort(); - } - } - - return Weak { ptr: self.ptr }; - } -} - -#[stable(feature = "downgraded_weak", since = "1.10.0")] -impl Default for Weak { - /// Constructs a new `Weak`, allocating memory for `T` without initializing - /// it. Calling [`upgrade`] on the return value always gives [`None`]. - /// - /// [`upgrade`]: struct.Weak.html#method.upgrade - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// - /// # Examples - /// - /// ``` - /// use std::sync::Weak; - /// - /// let empty: Weak = Default::default(); - /// assert!(empty.upgrade().is_none()); - /// ``` - fn default() -> Weak { - Weak::new() - } -} - -#[stable(feature = "arc_weak", since = "1.4.0")] -impl Drop for Weak { - /// Drops the `Weak` pointer. - /// - /// # Examples - /// - /// ``` - /// use std::sync::{Arc, Weak}; - /// - /// struct Foo; - /// - /// impl Drop for Foo { - /// fn drop(&mut self) { - /// println!("dropped!"); - /// } - /// } - /// - /// let foo = Arc::new(Foo); - /// let weak_foo = Arc::downgrade(&foo); - /// let other_weak_foo = Weak::clone(&weak_foo); - /// - /// drop(weak_foo); // Doesn't print anything - /// drop(foo); // Prints "dropped!" - /// - /// assert!(other_weak_foo.upgrade().is_none()); - /// ``` - fn drop(&mut self) { - // If we find out that we were the last weak pointer, then its time to - // deallocate the data entirely. See the discussion in Arc::drop() about - // the memory orderings - // - // It's not necessary to check for the locked state here, because the - // weak count can only be locked if there was precisely one weak ref, - // meaning that drop could only subsequently run ON that remaining weak - // ref, which can only happen after the lock is released. - if self.inner().weak.fetch_sub(1, Release) == 1 { - atomic::fence(Acquire); - unsafe { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())) - } - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq for Arc { - /// Equality for two `Arc`s. - /// - /// Two `Arc`s are equal if their inner values are equal. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five == Arc::new(5)); - /// ``` - fn eq(&self, other: &Arc) -> bool { - *(*self) == *(*other) - } - - /// Inequality for two `Arc`s. - /// - /// Two `Arc`s are unequal if their inner values are unequal. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five != Arc::new(6)); - /// ``` - fn ne(&self, other: &Arc) -> bool { - *(*self) != *(*other) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for Arc { - /// Partial comparison for two `Arc`s. - /// - /// The two are compared by calling `partial_cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// use std::cmp::Ordering; - /// - /// let five = Arc::new(5); - /// - /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Arc::new(6))); - /// ``` - fn partial_cmp(&self, other: &Arc) -> Option { - (**self).partial_cmp(&**other) - } - - /// Less-than comparison for two `Arc`s. - /// - /// The two are compared by calling `<` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five < Arc::new(6)); - /// ``` - fn lt(&self, other: &Arc) -> bool { - *(*self) < *(*other) - } - - /// 'Less than or equal to' comparison for two `Arc`s. - /// - /// The two are compared by calling `<=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five <= Arc::new(5)); - /// ``` - fn le(&self, other: &Arc) -> bool { - *(*self) <= *(*other) - } - - /// Greater-than comparison for two `Arc`s. - /// - /// The two are compared by calling `>` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five > Arc::new(4)); - /// ``` - fn gt(&self, other: &Arc) -> bool { - *(*self) > *(*other) - } - - /// 'Greater than or equal to' comparison for two `Arc`s. - /// - /// The two are compared by calling `>=` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let five = Arc::new(5); - /// - /// assert!(five >= Arc::new(5)); - /// ``` - fn ge(&self, other: &Arc) -> bool { - *(*self) >= *(*other) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for Arc { - /// Comparison for two `Arc`s. - /// - /// The two are compared by calling `cmp()` on their inner values. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// use std::cmp::Ordering; - /// - /// let five = Arc::new(5); - /// - /// assert_eq!(Ordering::Less, five.cmp(&Arc::new(6))); - /// ``` - fn cmp(&self, other: &Arc) -> Ordering { - (**self).cmp(&**other) - } -} -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for Arc {} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Arc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&**self, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Arc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&**self, f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Pointer for Arc { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Pointer::fmt(&(&**self as *const T), f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Default for Arc { - /// Creates a new `Arc`, with the `Default` value for `T`. - /// - /// # Examples - /// - /// ``` - /// use std::sync::Arc; - /// - /// let x: Arc = Default::default(); - /// assert_eq!(*x, 0); - /// ``` - fn default() -> Arc { - Arc::new(Default::default()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Hash for Arc { - fn hash(&self, state: &mut H) { - (**self).hash(state) - } -} - -#[stable(feature = "from_for_ptrs", since = "1.6.0")] -impl From for Arc { - fn from(t: T) -> Self { - Arc::new(t) - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl<'a, T: Clone> From<&'a [T]> for Arc<[T]> { - #[inline] - fn from(v: &[T]) -> Arc<[T]> { - >::from_slice(v) - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl<'a> From<&'a str> for Arc { - #[inline] - fn from(v: &str) -> Arc { - let arc = Arc::<[u8]>::from(v.as_bytes()); - unsafe { Arc::from_raw(Arc::into_raw(arc) as *const str) } - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From for Arc { - #[inline] - fn from(v: String) -> Arc { - Arc::from(&v[..]) - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Arc { - #[inline] - fn from(v: Box) -> Arc { - Arc::from_box(v) - } -} - -#[stable(feature = "shared_from_slice", since = "1.21.0")] -impl From> for Arc<[T]> { - #[inline] - fn from(mut v: Vec) -> Arc<[T]> { - unsafe { - let arc = Arc::copy_from_slice(&v); - - // Allow the Vec to free its memory, but not destroy its contents - v.set_len(0); - - arc - } - } -} - -#[cfg(test)] -mod tests { - use std::boxed::Box; - use std::clone::Clone; - use std::sync::mpsc::channel; - use std::mem::drop; - use std::ops::Drop; - use std::option::Option; - use std::option::Option::{None, Some}; - use std::sync::atomic; - use std::sync::atomic::Ordering::{Acquire, SeqCst}; - use std::thread; - use std::sync::Mutex; - use std::convert::From; - - use super::{Arc, Weak}; - use vec::Vec; - - struct Canary(*mut atomic::AtomicUsize); - - impl Drop for Canary { - fn drop(&mut self) { - unsafe { - match *self { - Canary(c) => { - (*c).fetch_add(1, SeqCst); - } - } - } - } - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn manually_share_arc() { - let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let arc_v = Arc::new(v); - - let (tx, rx) = channel(); - - let _t = thread::spawn(move || { - let arc_v: Arc> = rx.recv().unwrap(); - assert_eq!((*arc_v)[3], 4); - }); - - tx.send(arc_v.clone()).unwrap(); - - assert_eq!((*arc_v)[2], 3); - assert_eq!((*arc_v)[4], 5); - } - - #[test] - fn test_arc_get_mut() { - let mut x = Arc::new(3); - *Arc::get_mut(&mut x).unwrap() = 4; - assert_eq!(*x, 4); - let y = x.clone(); - assert!(Arc::get_mut(&mut x).is_none()); - drop(y); - assert!(Arc::get_mut(&mut x).is_some()); - let _w = Arc::downgrade(&x); - assert!(Arc::get_mut(&mut x).is_none()); - } - - #[test] - fn try_unwrap() { - let x = Arc::new(3); - assert_eq!(Arc::try_unwrap(x), Ok(3)); - let x = Arc::new(4); - let _y = x.clone(); - assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); - let x = Arc::new(5); - let _w = Arc::downgrade(&x); - assert_eq!(Arc::try_unwrap(x), Ok(5)); - } - - #[test] - fn into_from_raw() { - let x = Arc::new(box "hello"); - let y = x.clone(); - - let x_ptr = Arc::into_raw(x); - drop(y); - unsafe { - assert_eq!(**x_ptr, "hello"); - - let x = Arc::from_raw(x_ptr); - assert_eq!(**x, "hello"); - - assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); - } - } - - #[test] - fn test_into_from_raw_unsized() { - use std::fmt::Display; - use std::string::ToString; - - let arc: Arc = Arc::from("foo"); - - let ptr = Arc::into_raw(arc.clone()); - let arc2 = unsafe { Arc::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }, "foo"); - assert_eq!(arc, arc2); - - let arc: Arc = Arc::new(123); - - let ptr = Arc::into_raw(arc.clone()); - let arc2 = unsafe { Arc::from_raw(ptr) }; - - assert_eq!(unsafe { &*ptr }.to_string(), "123"); - assert_eq!(arc2.to_string(), "123"); - } - - #[test] - fn test_cowarc_clone_make_mut() { - let mut cow0 = Arc::new(75); - let mut cow1 = cow0.clone(); - let mut cow2 = cow1.clone(); - - assert!(75 == *Arc::make_mut(&mut cow0)); - assert!(75 == *Arc::make_mut(&mut cow1)); - assert!(75 == *Arc::make_mut(&mut cow2)); - - *Arc::make_mut(&mut cow0) += 1; - *Arc::make_mut(&mut cow1) += 2; - *Arc::make_mut(&mut cow2) += 3; - - assert!(76 == *cow0); - assert!(77 == *cow1); - assert!(78 == *cow2); - - // none should point to the same backing memory - assert!(*cow0 != *cow1); - assert!(*cow0 != *cow2); - assert!(*cow1 != *cow2); - } - - #[test] - fn test_cowarc_clone_unique2() { - let mut cow0 = Arc::new(75); - let cow1 = cow0.clone(); - let cow2 = cow1.clone(); - - assert!(75 == *cow0); - assert!(75 == *cow1); - assert!(75 == *cow2); - - *Arc::make_mut(&mut cow0) += 1; - assert!(76 == *cow0); - assert!(75 == *cow1); - assert!(75 == *cow2); - - // cow1 and cow2 should share the same contents - // cow0 should have a unique reference - assert!(*cow0 != *cow1); - assert!(*cow0 != *cow2); - assert!(*cow1 == *cow2); - } - - #[test] - fn test_cowarc_clone_weak() { - let mut cow0 = Arc::new(75); - let cow1_weak = Arc::downgrade(&cow0); - - assert!(75 == *cow0); - assert!(75 == *cow1_weak.upgrade().unwrap()); - - *Arc::make_mut(&mut cow0) += 1; - - assert!(76 == *cow0); - assert!(cow1_weak.upgrade().is_none()); - } - - #[test] - fn test_live() { - let x = Arc::new(5); - let y = Arc::downgrade(&x); - assert!(y.upgrade().is_some()); - } - - #[test] - fn test_dead() { - let x = Arc::new(5); - let y = Arc::downgrade(&x); - drop(x); - assert!(y.upgrade().is_none()); - } - - #[test] - fn weak_self_cyclic() { - struct Cycle { - x: Mutex>>, - } - - let a = Arc::new(Cycle { x: Mutex::new(None) }); - let b = Arc::downgrade(&a.clone()); - *a.x.lock().unwrap() = Some(b); - - // hopefully we don't double-free (or leak)... - } - - #[test] - fn drop_arc() { - let mut canary = atomic::AtomicUsize::new(0); - let x = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); - drop(x); - assert!(canary.load(Acquire) == 1); - } - - #[test] - fn drop_arc_weak() { - let mut canary = atomic::AtomicUsize::new(0); - let arc = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); - let arc_weak = Arc::downgrade(&arc); - assert!(canary.load(Acquire) == 0); - drop(arc); - assert!(canary.load(Acquire) == 1); - drop(arc_weak); - } - - #[test] - fn test_strong_count() { - let a = Arc::new(0); - assert!(Arc::strong_count(&a) == 1); - let w = Arc::downgrade(&a); - assert!(Arc::strong_count(&a) == 1); - let b = w.upgrade().expect(""); - assert!(Arc::strong_count(&b) == 2); - assert!(Arc::strong_count(&a) == 2); - drop(w); - drop(a); - assert!(Arc::strong_count(&b) == 1); - let c = b.clone(); - assert!(Arc::strong_count(&b) == 2); - assert!(Arc::strong_count(&c) == 2); - } - - #[test] - fn test_weak_count() { - let a = Arc::new(0); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 0); - let w = Arc::downgrade(&a); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 1); - let x = w.clone(); - assert!(Arc::weak_count(&a) == 2); - drop(w); - drop(x); - assert!(Arc::strong_count(&a) == 1); - assert!(Arc::weak_count(&a) == 0); - let c = a.clone(); - assert!(Arc::strong_count(&a) == 2); - assert!(Arc::weak_count(&a) == 0); - let d = Arc::downgrade(&c); - assert!(Arc::weak_count(&c) == 1); - assert!(Arc::strong_count(&c) == 2); - - drop(a); - drop(c); - drop(d); - } - - #[test] - fn show_arc() { - let a = Arc::new(5); - assert_eq!(format!("{:?}", a), "5"); - } - - // Make sure deriving works with Arc - #[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)] - struct Foo { - inner: Arc, - } - - #[test] - fn test_unsized() { - let x: Arc<[i32]> = Arc::new([1, 2, 3]); - assert_eq!(format!("{:?}", x), "[1, 2, 3]"); - let y = Arc::downgrade(&x.clone()); - drop(x); - assert!(y.upgrade().is_none()); - } - - #[test] - fn test_from_owned() { - let foo = 123; - let foo_arc = Arc::from(foo); - assert!(123 == *foo_arc); - } - - #[test] - fn test_new_weak() { - let foo: Weak = Weak::new(); - assert!(foo.upgrade().is_none()); - } - - #[test] - fn test_ptr_eq() { - let five = Arc::new(5); - let same_five = five.clone(); - let other_five = Arc::new(5); - - assert!(Arc::ptr_eq(&five, &same_five)); - assert!(!Arc::ptr_eq(&five, &other_five)); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_weak_count_locked() { - let mut a = Arc::new(atomic::AtomicBool::new(false)); - let a2 = a.clone(); - let t = thread::spawn(move || { - for _i in 0..1000000 { - Arc::get_mut(&mut a); - } - a.store(true, SeqCst); - }); - - while !a2.load(SeqCst) { - let n = Arc::weak_count(&a2); - assert!(n < 2, "bad weak count: {}", n); - } - t.join().unwrap(); - } - - #[test] - fn test_from_str() { - let r: Arc = Arc::from("foo"); - - assert_eq!(&r[..], "foo"); - } - - #[test] - fn test_copy_from_slice() { - let s: &[u32] = &[1, 2, 3]; - let r: Arc<[u32]> = Arc::from(s); - - assert_eq!(&r[..], [1, 2, 3]); - } - - #[test] - fn test_clone_from_slice() { - #[derive(Clone, Debug, Eq, PartialEq)] - struct X(u32); - - let s: &[X] = &[X(1), X(2), X(3)]; - let r: Arc<[X]> = Arc::from(s); - - assert_eq!(&r[..], s); - } - - #[test] - #[should_panic] - fn test_clone_from_slice_panic() { - use std::string::{String, ToString}; - - struct Fail(u32, String); - - impl Clone for Fail { - fn clone(&self) -> Fail { - if self.0 == 2 { - panic!(); - } - Fail(self.0, self.1.clone()) - } - } - - let s: &[Fail] = &[ - Fail(0, "foo".to_string()), - Fail(1, "bar".to_string()), - Fail(2, "baz".to_string()), - ]; - - // Should panic, but not cause memory corruption - let _r: Arc<[Fail]> = Arc::from(s); - } - - #[test] - fn test_from_box() { - let b: Box = box 123; - let r: Arc = Arc::from(b); - - assert_eq!(*r, 123); - } - - #[test] - fn test_from_box_str() { - use std::string::String; - - let s = String::from("foo").into_boxed_str(); - let r: Arc = Arc::from(s); - - assert_eq!(&r[..], "foo"); - } - - #[test] - fn test_from_box_slice() { - let s = vec![1, 2, 3].into_boxed_slice(); - let r: Arc<[u32]> = Arc::from(s); - - assert_eq!(&r[..], [1, 2, 3]); - } - - #[test] - fn test_from_box_trait() { - use std::fmt::Display; - use std::string::ToString; - - let b: Box = box 123; - let r: Arc = Arc::from(b); - - assert_eq!(r.to_string(), "123"); - } - - #[test] - fn test_from_box_trait_zero_sized() { - use std::fmt::Debug; - - let b: Box = box (); - let r: Arc = Arc::from(b); - - assert_eq!(format!("{:?}", r), "()"); - } - - #[test] - fn test_from_vec() { - let v = vec![1, 2, 3]; - let r: Arc<[u32]> = Arc::from(v); - - assert_eq!(&r[..], [1, 2, 3]); - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl borrow::Borrow for Arc { - fn borrow(&self) -> &T { - &**self - } -} - -#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] -impl AsRef for Arc { - fn as_ref(&self) -> &T { - &**self - } -} diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index 1b4f86dcfac1c..2cf9b13a67a27 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -58,14 +58,16 @@ use core::any::Any; use core::borrow; use core::cmp::Ordering; +use core::convert::From; use core::fmt; +use core::future::{Future, FutureObj, LocalFutureObj, UnsafeFutureObj}; use core::hash::{Hash, Hasher}; use core::iter::FusedIterator; use core::marker::{Unpin, Unsize}; -use core::mem::{self, Pin}; +use core::mem::{self, PinMut}; use core::ops::{CoerceUnsized, Deref, DerefMut, Generator, GeneratorState}; use core::ptr::{self, NonNull, Unique}; -use core::convert::From; +use core::task::{Context, Poll, Executor, SpawnErrorKind, SpawnObjError}; use raw_vec::RawVec; use str::from_boxed_utf8_unchecked; @@ -192,7 +194,9 @@ impl Box { } /// Consumes and leaks the `Box`, returning a mutable reference, - /// `&'a mut T`. Here, the lifetime `'a` may be chosen to be `'static`. + /// `&'a mut T`. Note that the type `T` must outlive the chosen lifetime + /// `'a`. If the type has only static references, or none at all, then this + /// may be chosen to be `'static`. /// /// This function is mainly useful for data that lives for the remainder of /// the program's life. Dropping the returned reference will cause a memory @@ -444,7 +448,7 @@ impl From> for Box<[u8]> { } } -impl Box { +impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. @@ -466,10 +470,10 @@ impl Box { /// print_if_string(Box::new(0i8)); /// } /// ``` - pub fn downcast(self) -> Result, Box> { + pub fn downcast(self) -> Result, Box> { if self.is::() { unsafe { - let raw: *mut Any = Box::into_raw(self); + let raw: *mut dyn Any = Box::into_raw(self); Ok(Box::from_raw(raw as *mut T)) } } else { @@ -478,7 +482,7 @@ impl Box { } } -impl Box { +impl Box { #[inline] #[stable(feature = "rust1", since = "1.0.0")] /// Attempt to downcast the box to a concrete type. @@ -500,10 +504,10 @@ impl Box { /// print_if_string(Box::new(0i8)); /// } /// ``` - pub fn downcast(self) -> Result, Box> { - >::downcast(self).map_err(|s| unsafe { + pub fn downcast(self) -> Result, Box> { + >::downcast(self).map_err(|s| unsafe { // reapply the Send marker - Box::from_raw(Box::into_raw(s) as *mut (Any + Send)) + Box::from_raw(Box::into_raw(s) as *mut (dyn Any + Send)) }) } } @@ -641,7 +645,7 @@ impl FnBox for F #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl<'a, A, R> FnOnce for Box + 'a> { +impl<'a, A, R> FnOnce for Box + 'a> { type Output = R; extern "rust-call" fn call_once(self, args: A) -> R { @@ -651,7 +655,7 @@ impl<'a, A, R> FnOnce for Box + 'a> { #[unstable(feature = "fnbox", reason = "will be deprecated if and when `Box` becomes usable", issue = "28796")] -impl<'a, A, R> FnOnce for Box + Send + 'a> { +impl<'a, A, R> FnOnce for Box + Send + 'a> { type Output = R; extern "rust-call" fn call_once(self, args: A) -> R { @@ -755,6 +759,7 @@ impl Generator for Box /// A pinned, heap allocated reference. #[unstable(feature = "pin", issue = "49150")] #[fundamental] +#[repr(transparent)] pub struct PinBox { inner: Box, } @@ -771,14 +776,72 @@ impl PinBox { #[unstable(feature = "pin", issue = "49150")] impl PinBox { /// Get a pinned reference to the data in this PinBox. - pub fn as_pin<'a>(&'a mut self) -> Pin<'a, T> { - unsafe { Pin::new_unchecked(&mut *self.inner) } + #[inline] + pub fn as_pin_mut<'a>(&'a mut self) -> PinMut<'a, T> { + unsafe { PinMut::new_unchecked(&mut *self.inner) } + } + + /// Constructs a `PinBox` from a raw pointer. + /// + /// After calling this function, the raw pointer is owned by the + /// resulting `PinBox`. Specifically, the `PinBox` destructor will call + /// the destructor of `T` and free the allocated memory. Since the + /// way `PinBox` allocates and releases memory is unspecified, the + /// only valid pointer to pass to this function is the one taken + /// from another `PinBox` via the [`PinBox::into_raw`] function. + /// + /// This function is unsafe because improper use may lead to + /// memory problems. For example, a double-free may occur if the + /// function is called twice on the same raw pointer. + /// + /// [`PinBox::into_raw`]: struct.PinBox.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(pin)] + /// use std::boxed::PinBox; + /// let x = PinBox::new(5); + /// let ptr = PinBox::into_raw(x); + /// let x = unsafe { PinBox::from_raw(ptr) }; + /// ``` + #[inline] + pub unsafe fn from_raw(raw: *mut T) -> Self { + PinBox { inner: Box::from_raw(raw) } + } + + /// Consumes the `PinBox`, returning the wrapped raw pointer. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `PinBox`. In particular, the + /// caller should properly destroy `T` and release the memory. The + /// proper way to do so is to convert the raw pointer back into a + /// `PinBox` with the [`PinBox::from_raw`] function. + /// + /// Note: this is an associated function, which means that you have + /// to call it as `PinBox::into_raw(b)` instead of `b.into_raw()`. This + /// is so that there is no conflict with a method on the inner type. + /// + /// [`PinBox::from_raw`]: struct.PinBox.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// #![feature(pin)] + /// use std::boxed::PinBox; + /// let x = PinBox::new(5); + /// let ptr = PinBox::into_raw(x); + /// ``` + #[inline] + pub fn into_raw(b: PinBox) -> *mut T { + Box::into_raw(b.inner) } /// Get a mutable reference to the data inside this PinBox. /// /// This function is unsafe. Users must guarantee that the data is never /// moved out of this reference. + #[inline] pub unsafe fn get_mut<'a>(this: &'a mut PinBox) -> &'a mut T { &mut *this.inner } @@ -787,6 +850,7 @@ impl PinBox { /// /// This function is unsafe. Users must guarantee that the data is never /// moved out of the box. + #[inline] pub unsafe fn unpin(this: PinBox) -> Box { this.inner } @@ -850,4 +914,101 @@ impl fmt::Pointer for PinBox { impl, U: ?Sized> CoerceUnsized> for PinBox {} #[unstable(feature = "pin", issue = "49150")] -unsafe impl Unpin for PinBox {} +impl Unpin for PinBox {} + +#[unstable(feature = "futures_api", issue = "50547")] +impl Future for Box { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut Context) -> Poll { + PinMut::new(&mut **self).poll(cx) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl Future for PinBox { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut Context) -> Poll { + self.as_pin_mut().poll(cx) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for Box + where F: Future + 'a +{ + fn into_raw(self) -> *mut () { + Box::into_raw(self) as *mut () + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + let ptr = ptr as *mut F; + let pin: PinMut = PinMut::new_unchecked(&mut *ptr); + pin.poll(cx) + } + + unsafe fn drop(ptr: *mut ()) { + drop(Box::from_raw(ptr as *mut F)) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinBox + where F: Future + 'a +{ + fn into_raw(self) -> *mut () { + PinBox::into_raw(self) as *mut () + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + let ptr = ptr as *mut F; + let pin: PinMut = PinMut::new_unchecked(&mut *ptr); + pin.poll(cx) + } + + unsafe fn drop(ptr: *mut ()) { + drop(PinBox::from_raw(ptr as *mut F)) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl Executor for Box + where E: Executor + ?Sized +{ + fn spawn_obj(&mut self, task: FutureObj<'static, ()>) -> Result<(), SpawnObjError> { + (**self).spawn_obj(task) + } + + fn status(&self) -> Result<(), SpawnErrorKind> { + (**self).status() + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: Future + Send + 'a> From> for FutureObj<'a, ()> { + fn from(boxed: PinBox) -> Self { + FutureObj::new(boxed) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: Future + Send + 'a> From> for FutureObj<'a, ()> { + fn from(boxed: Box) -> Self { + FutureObj::new(boxed) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: Future + 'a> From> for LocalFutureObj<'a, ()> { + fn from(boxed: PinBox) -> Self { + LocalFutureObj::new(boxed) + } +} + +#[unstable(feature = "futures_api", issue = "50547")] +impl<'a, F: Future + 'a> From> for LocalFutureObj<'a, ()> { + fn from(boxed: Box) -> Self { + LocalFutureObj::new(boxed) + } +} diff --git a/src/liballoc/boxed_test.rs b/src/liballoc/boxed_test.rs index 837f8dfaca13a..55995742a4a7d 100644 --- a/src/liballoc/boxed_test.rs +++ b/src/liballoc/boxed_test.rs @@ -31,8 +31,8 @@ struct Test; #[test] fn any_move() { - let a = Box::new(8) as Box; - let b = Box::new(Test) as Box; + let a = Box::new(8) as Box; + let b = Box::new(Test) as Box; match a.downcast::() { Ok(a) => { @@ -47,8 +47,8 @@ fn any_move() { Err(..) => panic!(), } - let a = Box::new(8) as Box; - let b = Box::new(Test) as Box; + let a = Box::new(8) as Box; + let b = Box::new(Test) as Box; assert!(a.downcast::>().is_err()); assert!(b.downcast::>().is_err()); @@ -56,8 +56,8 @@ fn any_move() { #[test] fn test_show() { - let a = Box::new(8) as Box; - let b = Box::new(Test) as Box; + let a = Box::new(8) as Box; + let b = Box::new(Test) as Box; let a_str = format!("{:?}", a); let b_str = format!("{:?}", b); assert_eq!(a_str, "Any"); @@ -65,8 +65,8 @@ fn test_show() { static EIGHT: usize = 8; static TEST: Test = Test; - let a = &EIGHT as &Any; - let b = &TEST as &Any; + let a = &EIGHT as &dyn Any; + let b = &TEST as &dyn Any; let s = format!("{:?}", a); assert_eq!(s, "Any"); let s = format!("{:?}", b); @@ -110,12 +110,12 @@ fn raw_trait() { } } - let x: Box = Box::new(Bar(17)); + let x: Box = Box::new(Bar(17)); let p = Box::into_raw(x); unsafe { assert_eq!(17, (*p).get()); (*p).set(19); - let y: Box = Box::from_raw(p); + let y: Box = Box::from_raw(p); assert_eq!(19, y.get()); } } diff --git a/src/liballoc/binary_heap.rs b/src/liballoc/collections/binary_heap.rs similarity index 99% rename from src/liballoc/binary_heap.rs rename to src/liballoc/collections/binary_heap.rs index 668b61c51d8bc..fcadcb544c431 100644 --- a/src/liballoc/binary_heap.rs +++ b/src/liballoc/collections/binary_heap.rs @@ -157,7 +157,7 @@ use core::ops::{Deref, DerefMut}; use core::iter::{FromIterator, FusedIterator}; -use core::mem::{swap, size_of}; +use core::mem::{swap, size_of, ManuallyDrop}; use core::ptr; use core::fmt; @@ -864,8 +864,7 @@ impl BinaryHeap { /// position with the value that was originally removed. struct Hole<'a, T: 'a> { data: &'a mut [T], - /// `elt` is always `Some` from new until drop. - elt: Option, + elt: ManuallyDrop, pos: usize, } @@ -879,7 +878,7 @@ impl<'a, T> Hole<'a, T> { let elt = ptr::read(&data[pos]); Hole { data, - elt: Some(elt), + elt: ManuallyDrop::new(elt), pos, } } @@ -892,7 +891,7 @@ impl<'a, T> Hole<'a, T> { /// Returns a reference to the element removed. #[inline] fn element(&self) -> &T { - self.elt.as_ref().unwrap() + &self.elt } /// Returns a reference to the element at `index`. @@ -925,7 +924,7 @@ impl<'a, T> Drop for Hole<'a, T> { // fill the hole again unsafe { let pos = self.pos; - ptr::write(self.data.get_unchecked_mut(pos), self.elt.take().unwrap()); + ptr::copy_nonoverlapping(&*self.elt, self.data.get_unchecked_mut(pos), 1); } } } diff --git a/src/liballoc/btree/map.rs b/src/liballoc/collections/btree/map.rs similarity index 97% rename from src/liballoc/btree/map.rs rename to src/liballoc/collections/btree/map.rs index 3984379ea860d..8c950cd06d9e3 100644 --- a/src/liballoc/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -149,12 +149,11 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for BTreeMap { fn clone(&self) -> BTreeMap { - fn clone_subtree(node: node::NodeRef) - -> BTreeMap { - + fn clone_subtree<'a, K: Clone, V: Clone>( + node: node::NodeRef, K, V, marker::LeafOrInternal> + ) -> BTreeMap + where K: 'a, V: 'a, + { match node.force() { Leaf(leaf) => { let mut out_tree = BTreeMap { @@ -213,7 +212,16 @@ impl Clone for BTreeMap { } } - clone_subtree(self.root.as_ref()) + if self.len() == 0 { + // Ideally we'd call `BTreeMap::new` here, but that has the `K: + // Ord` constraint, which this method lacks. + BTreeMap { + root: node::Root::shared_empty_root(), + length: 0, + } + } else { + clone_subtree(self.root.as_ref()) + } } } @@ -246,6 +254,7 @@ impl super::Recover for BTreeMap } fn replace(&mut self, key: K) -> Option { + self.ensure_root_is_owned(); match search::search_tree::(self.root.as_mut(), &key) { Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)), GoDown(handle) => { @@ -523,7 +532,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> BTreeMap { BTreeMap { - root: node::Root::new_leaf(), + root: node::Root::shared_empty_root(), length: 0, } } @@ -544,7 +553,6 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { - // FIXME(gereeter) .clear() allocates *self = BTreeMap::new(); } @@ -890,6 +898,8 @@ impl BTreeMap { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry { + // FIXME(@porglezomp) Avoid allocating if we don't insert + self.ensure_root_is_owned(); match search::search_tree(self.root.as_mut(), &key) { Found(handle) => { Occupied(OccupiedEntry { @@ -910,6 +920,7 @@ impl BTreeMap { } fn from_sorted_iter>(&mut self, iter: I) { + self.ensure_root_is_owned(); let mut cur_node = last_leaf_edge(self.root.as_mut()).into_node(); // Iterate through all key-value pairs, pushing them into nodes at the right level. for (key, value) in iter { @@ -1019,6 +1030,7 @@ impl BTreeMap { let total_num = self.len(); let mut right = Self::new(); + right.root = node::Root::new_leaf(); for _ in 0..(self.root.as_ref().height()) { right.root.push_level(); } @@ -1067,7 +1079,11 @@ impl BTreeMap { /// Calculates the number of elements if it is incorrect. fn recalc_length(&mut self) { - fn dfs(node: NodeRef) -> usize { + fn dfs<'a, K, V>( + node: NodeRef, K, V, marker::LeafOrInternal> + ) -> usize + where K: 'a, V: 'a + { let mut res = node.len(); if let Internal(node) = node.force() { @@ -1153,6 +1169,13 @@ impl BTreeMap { self.fix_top(); } + + /// If the root node is the shared root node, allocate our own node. + fn ensure_root_is_owned(&mut self) { + if self.root.is_shared_root() { + self.root = node::Root::new_leaf(); + } + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1290,6 +1313,10 @@ impl Drop for IntoIter { self.for_each(drop); unsafe { let leaf_node = ptr::read(&self.front).into_node(); + if leaf_node.is_shared_root() { + return; + } + if let Some(first_parent) = leaf_node.deallocate_and_ascend() { let mut cur_node = first_parent.into_node(); while let Some(parent) = cur_node.deallocate_and_ascend() { @@ -1819,7 +1846,7 @@ fn range_search>( Handle, marker::Edge>) where Q: Ord, K: Borrow { - match (range.start(), range.end()) { + match (range.start_bound(), range.end_bound()) { (Excluded(s), Excluded(e)) if s==e => panic!("range start and end are equal and excluded in BTreeMap"), (Included(s), Included(e)) | @@ -1837,7 +1864,7 @@ fn range_search>( let mut diverged = false; loop { - let min_edge = match (min_found, range.start()) { + let min_edge = match (min_found, range.start_bound()) { (false, Included(key)) => match search::search_linear(&min_node, key) { (i, true) => { min_found = true; i }, (i, false) => i, @@ -1851,7 +1878,7 @@ fn range_search>( (true, Excluded(_)) => 0, }; - let max_edge = match (max_found, range.end()) { + let max_edge = match (max_found, range.end_bound()) { (false, Included(key)) => match search::search_linear(&max_node, key) { (i, true) => { max_found = true; i+1 }, (i, false) => i, @@ -2169,14 +2196,13 @@ impl<'a, K: Ord, V> Entry<'a, K, V> { } impl<'a, K: Ord, V: Default> Entry<'a, K, V> { - #[unstable(feature = "entry_or_default", issue = "44324")] + #[stable(feature = "entry_or_default", since = "1.28.0")] /// Ensures a value is in the entry by inserting the default value if empty, /// and returns a mutable reference to the value in the entry. /// /// # Examples /// /// ``` - /// #![feature(entry_or_default)] /// # fn main() { /// use std::collections::BTreeMap; /// @@ -2354,6 +2380,11 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// Gets a mutable reference to the value in the entry. /// + /// If you need a reference to the `OccupiedEntry` which may outlive the + /// destruction of the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: #method.into_mut + /// /// # Examples /// /// ``` @@ -2365,9 +2396,13 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// /// assert_eq!(map["poneyland"], 12); /// if let Entry::Occupied(mut o) = map.entry("poneyland") { - /// *o.get_mut() += 10; + /// *o.get_mut() += 10; + /// assert_eq!(*o.get(), 22); + /// + /// // We can use the same Entry multiple times. + /// *o.get_mut() += 2; /// } - /// assert_eq!(map["poneyland"], 22); + /// assert_eq!(map["poneyland"], 24); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn get_mut(&mut self) -> &mut V { @@ -2376,6 +2411,10 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// Converts the entry into a mutable reference to its value. /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: #method.get_mut + /// /// # Examples /// /// ``` diff --git a/src/liballoc/btree/mod.rs b/src/liballoc/collections/btree/mod.rs similarity index 100% rename from src/liballoc/btree/mod.rs rename to src/liballoc/collections/btree/mod.rs diff --git a/src/liballoc/btree/node.rs b/src/liballoc/collections/btree/node.rs similarity index 92% rename from src/liballoc/btree/node.rs rename to src/liballoc/collections/btree/node.rs index d6346662314e6..0ae45b3123259 100644 --- a/src/liballoc/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -60,12 +60,12 @@ pub const CAPACITY: usize = 2 * B - 1; /// /// See also rust-lang/rfcs#197, which would make this structure significantly more safe by /// avoiding accidentally dropping unused and uninitialized keys and values. +/// +/// We put the metadata first so that its position is the same for every `K` and `V`, in order +/// to statically allocate a single dummy node to avoid allocations. This struct is `repr(C)` to +/// prevent them from being reordered. +#[repr(C)] struct LeafNode { - /// The arrays storing the actual data of the node. Only the first `len` elements of each - /// array are initialized and valid. - keys: [K; CAPACITY], - vals: [V; CAPACITY], - /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. /// This either points to an actual node or is null. parent: *const InternalNode, @@ -77,10 +77,14 @@ struct LeafNode { /// The number of keys and values this node stores. /// - /// This is at the end of the node's representation and next to `parent_idx` to encourage - /// the compiler to join `len` and `parent_idx` into the same 32-bit word, reducing space - /// overhead. + /// This next to `parent_idx` to encourage the compiler to join `len` and + /// `parent_idx` into the same 32-bit word, reducing space overhead. len: u16, + + /// The arrays storing the actual data of the node. Only the first `len` elements of each + /// array are initialized and valid. + keys: [K; CAPACITY], + vals: [V; CAPACITY], } impl LeafNode { @@ -97,8 +101,26 @@ impl LeafNode { len: 0 } } + + fn is_shared_root(&self) -> bool { + ptr::eq(self, &EMPTY_ROOT_NODE as *const _ as *const _) + } } +// We need to implement Sync here in order to make a static instance. +unsafe impl Sync for LeafNode<(), ()> {} + +// An empty node used as a placeholder for the root node, to avoid allocations. +// We use () in order to save space, since no operation on an empty tree will +// ever take a pointer past the first key. +static EMPTY_ROOT_NODE: LeafNode<(), ()> = LeafNode { + parent: ptr::null(), + parent_idx: 0, + len: 0, + keys: [(); CAPACITY], + vals: [(); CAPACITY], +}; + /// The underlying representation of internal nodes. As with `LeafNode`s, these should be hidden /// behind `BoxedNode`s to prevent dropping uninitialized keys and values. Any pointer to an /// `InternalNode` can be directly casted to a pointer to the underlying `LeafNode` portion of the @@ -168,6 +190,21 @@ unsafe impl Sync for Root { } unsafe impl Send for Root { } impl Root { + pub fn is_shared_root(&self) -> bool { + self.as_ref().is_shared_root() + } + + pub fn shared_empty_root() -> Self { + Root { + node: unsafe { + BoxedNode::from_ptr(NonNull::new_unchecked( + &EMPTY_ROOT_NODE as *const _ as *const LeafNode as *mut _ + )) + }, + height: 0, + } + } + pub fn new_leaf() -> Self { Root { node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })), @@ -209,6 +246,7 @@ impl Root { /// new node the root. This increases the height by 1 and is the opposite of `pop_level`. pub fn push_level(&mut self) -> NodeRef { + debug_assert!(!self.is_shared_root()); let mut new_node = Box::new(unsafe { InternalNode::new() }); new_node.edges[0] = unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }; @@ -249,7 +287,7 @@ impl Root { self.as_mut().as_leaf_mut().parent = ptr::null(); unsafe { - Global.dealloc(NonNull::from(top).as_opaque(), Layout::new::>()); + Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); } } } @@ -353,12 +391,16 @@ impl NodeRef { } } + pub fn is_shared_root(&self) -> bool { + self.as_leaf().is_shared_root() + } + pub fn keys(&self) -> &[K] { - self.reborrow().into_slices().0 + self.reborrow().into_key_slice() } - pub fn vals(&self) -> &[V] { - self.reborrow().into_slices().1 + fn vals(&self) -> &[V] { + self.reborrow().into_val_slice() } /// Finds the parent of the current node. Returns `Ok(handle)` if the current @@ -433,9 +475,10 @@ impl NodeRef { marker::Edge > > { + debug_assert!(!self.is_shared_root()); let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_opaque(), Layout::new::>()); + Global.dealloc(node.cast(), Layout::new::>()); ret } } @@ -456,7 +499,7 @@ impl NodeRef { > { let node = self.node; let ret = self.ascend().ok(); - Global.dealloc(node.as_opaque(), Layout::new::>()); + Global.dealloc(node.cast(), Layout::new::>()); ret } } @@ -500,30 +543,51 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { } } - pub fn keys_mut(&mut self) -> &mut [K] { - unsafe { self.reborrow_mut().into_slices_mut().0 } + fn keys_mut(&mut self) -> &mut [K] { + unsafe { self.reborrow_mut().into_key_slice_mut() } } - pub fn vals_mut(&mut self) -> &mut [V] { - unsafe { self.reborrow_mut().into_slices_mut().1 } + fn vals_mut(&mut self) -> &mut [V] { + unsafe { self.reborrow_mut().into_val_slice_mut() } } } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - pub fn into_slices(self) -> (&'a [K], &'a [V]) { - unsafe { - ( + fn into_key_slice(self) -> &'a [K] { + // When taking a pointer to the keys, if our key has a stricter + // alignment requirement than the shared root does, then the pointer + // would be out of bounds, which LLVM assumes will not happen. If the + // alignment is more strict, we need to make an empty slice that doesn't + // use an out of bounds pointer. + if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { + &[] + } else { + // Here either it's not the root, or the alignment is less strict, + // in which case the keys pointer will point "one-past-the-end" of + // the node, which is allowed by LLVM. + unsafe { slice::from_raw_parts( self.as_leaf().keys.as_ptr(), self.len() - ), - slice::from_raw_parts( - self.as_leaf().vals.as_ptr(), - self.len() ) + } + } + } + + fn into_val_slice(self) -> &'a [V] { + debug_assert!(!self.is_shared_root()); + unsafe { + slice::from_raw_parts( + self.as_leaf().vals.as_ptr(), + self.len() ) } } + + fn into_slices(self) -> (&'a [K], &'a [V]) { + let k = unsafe { ptr::read(&self) }; + (k.into_key_slice(), self.into_val_slice()) + } } impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { @@ -535,20 +599,33 @@ impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { } } - pub fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) { - unsafe { - ( + fn into_key_slice_mut(mut self) -> &'a mut [K] { + if mem::align_of::() > mem::align_of::>() && self.is_shared_root() { + &mut [] + } else { + unsafe { slice::from_raw_parts_mut( &mut self.as_leaf_mut().keys as *mut [K] as *mut K, self.len() - ), - slice::from_raw_parts_mut( - &mut self.as_leaf_mut().vals as *mut [V] as *mut V, - self.len() ) + } + } + } + + fn into_val_slice_mut(mut self) -> &'a mut [V] { + debug_assert!(!self.is_shared_root()); + unsafe { + slice::from_raw_parts_mut( + &mut self.as_leaf_mut().vals as *mut [V] as *mut V, + self.len() ) } } + + fn into_slices_mut(self) -> (&'a mut [K], &'a mut [V]) { + let k = unsafe { ptr::read(&self) }; + (k.into_key_slice_mut(), self.into_val_slice_mut()) + } } impl<'a, K, V> NodeRef, K, V, marker::Leaf> { @@ -556,6 +633,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { pub fn push(&mut self, key: K, val: V) { // Necessary for correctness, but this is an internal module debug_assert!(self.len() < CAPACITY); + debug_assert!(!self.is_shared_root()); let idx = self.len(); @@ -571,6 +649,7 @@ impl<'a, K, V> NodeRef, K, V, marker::Leaf> { pub fn push_front(&mut self, key: K, val: V) { // Necessary for correctness, but this is an internal module debug_assert!(self.len() < CAPACITY); + debug_assert!(!self.is_shared_root()); unsafe { slice_insert(self.keys_mut(), 0, key); @@ -884,6 +963,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge fn insert_fit(&mut self, key: K, val: V) -> *mut V { // Necessary for correctness, but in a private module debug_assert!(self.node.len() < CAPACITY); + debug_assert!(!self.node.is_shared_root()); unsafe { slice_insert(self.node.keys_mut(), self.idx, key); @@ -1061,6 +1141,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> /// allocated node. pub fn split(mut self) -> (NodeRef, K, V, marker::Leaf>, K, V, Root) { + debug_assert!(!self.node.is_shared_root()); unsafe { let mut new_node = Box::new(LeafNode::new()); @@ -1098,6 +1179,7 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> /// now adjacent key/value pairs to the left and right of this handle. pub fn remove(mut self) -> (Handle, K, V, marker::Leaf>, marker::Edge>, K, V) { + debug_assert!(!self.node.is_shared_root()); unsafe { let k = slice_remove(self.node.keys_mut(), self.idx); let v = slice_remove(self.node.vals_mut(), self.idx); @@ -1239,12 +1321,12 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } Global.dealloc( - right_node.node.as_opaque(), + right_node.node.cast(), Layout::new::>(), ); } else { Global.dealloc( - right_node.node.as_opaque(), + right_node.node.cast(), Layout::new::>(), ); } diff --git a/src/liballoc/btree/search.rs b/src/liballoc/collections/btree/search.rs similarity index 100% rename from src/liballoc/btree/search.rs rename to src/liballoc/collections/btree/search.rs diff --git a/src/liballoc/btree/set.rs b/src/liballoc/collections/btree/set.rs similarity index 99% rename from src/liballoc/btree/set.rs rename to src/liballoc/collections/btree/set.rs index 2aad476d3153a..af9a7074e4a4f 100644 --- a/src/liballoc/btree/set.rs +++ b/src/liballoc/collections/btree/set.rs @@ -19,7 +19,7 @@ use core::iter::{Peekable, FromIterator, FusedIterator}; use core::ops::{BitOr, BitAnd, BitXor, Sub, RangeBounds}; use borrow::Borrow; -use btree_map::{BTreeMap, Keys}; +use collections::btree_map::{self, BTreeMap, Keys}; use super::Recover; // FIXME(conventions): implement bounded iterators @@ -104,7 +104,7 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for Iter<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] #[derive(Debug)] pub struct IntoIter { - iter: ::btree_map::IntoIter, + iter: btree_map::IntoIter, } /// An iterator over a sub-range of items in a `BTreeSet`. @@ -117,7 +117,7 @@ pub struct IntoIter { #[derive(Debug)] #[stable(feature = "btree_range", since = "1.17.0")] pub struct Range<'a, T: 'a> { - iter: ::btree_map::Range<'a, T, ()>, + iter: btree_map::Range<'a, T, ()>, } /// A lazy iterator producing elements in the difference of `BTreeSet`s. diff --git a/src/liballoc/linked_list.rs b/src/liballoc/collections/linked_list.rs similarity index 100% rename from src/liballoc/linked_list.rs rename to src/liballoc/collections/linked_list.rs diff --git a/src/liballoc/collections/mod.rs b/src/liballoc/collections/mod.rs new file mode 100644 index 0000000000000..96e0eb633b2f5 --- /dev/null +++ b/src/liballoc/collections/mod.rs @@ -0,0 +1,88 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Collection types. + +#![stable(feature = "rust1", since = "1.0.0")] + +pub mod binary_heap; +mod btree; +pub mod linked_list; +pub mod vec_deque; + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod btree_map { + //! A map based on a B-Tree. + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::btree::map::*; +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub mod btree_set { + //! A set based on a B-Tree. + #[stable(feature = "rust1", since = "1.0.0")] + pub use super::btree::set::*; +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::binary_heap::BinaryHeap; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::btree_map::BTreeMap; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::btree_set::BTreeSet; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::linked_list::LinkedList; + +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(no_inline)] +pub use self::vec_deque::VecDeque; + +use alloc::{AllocErr, LayoutErr}; + +/// Augments `AllocErr` with a CapacityOverflow variant. +#[derive(Clone, PartialEq, Eq, Debug)] +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +pub enum CollectionAllocErr { + /// Error due to the computed capacity exceeding the collection's maximum + /// (usually `isize::MAX` bytes). + CapacityOverflow, + /// Error due to the allocator (see the `AllocErr` type's docs). + AllocErr, +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(AllocErr: AllocErr) -> Self { + CollectionAllocErr::AllocErr + } +} + +#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] +impl From for CollectionAllocErr { + #[inline] + fn from(_: LayoutErr) -> Self { + CollectionAllocErr::CapacityOverflow + } +} + +/// An intermediate trait for specialization of `Extend`. +#[doc(hidden)] +trait SpecExtend { + /// Extends `self` with the contents of the given iterator. + fn spec_extend(&mut self, iter: I); +} diff --git a/src/liballoc/vec_deque.rs b/src/liballoc/collections/vec_deque.rs similarity index 99% rename from src/liballoc/vec_deque.rs rename to src/liballoc/collections/vec_deque.rs index ff82b3a469caf..ba92b886138c0 100644 --- a/src/liballoc/vec_deque.rs +++ b/src/liballoc/collections/vec_deque.rs @@ -30,7 +30,7 @@ use core::slice; use core::hash::{Hash, Hasher}; use core::cmp; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use raw_vec::RawVec; use vec::Vec; @@ -980,12 +980,12 @@ impl VecDeque { // and the head/tail values will be restored correctly. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, @@ -2891,7 +2891,7 @@ mod tests { #[test] fn test_from_vec() { - use super::super::vec::Vec; + use vec::Vec; for cap in 0..35 { for len in 0..cap + 1 { let mut vec = Vec::with_capacity(cap); @@ -2907,7 +2907,7 @@ mod tests { #[test] fn test_vec_from_vecdeque() { - use super::super::vec::Vec; + use vec::Vec; fn create_vec_and_test_convert(cap: usize, offset: usize, len: usize) { let mut vd = VecDeque::with_capacity(cap); diff --git a/src/liballoc/fmt.rs b/src/liballoc/fmt.rs index b2c4582e8406f..b49ec0ae25212 100644 --- a/src/liballoc/fmt.rs +++ b/src/liballoc/fmt.rs @@ -340,7 +340,8 @@ //! //! ## Fill/Alignment //! -//! The fill character is provided normally in conjunction with the `width` +//! The fill character is provided normally in conjunction with the +//! [`width`](#width) //! parameter. This indicates that if the value being formatted is smaller than //! `width` some extra characters will be printed around it. The extra //! characters are specified by `fill`, and the alignment can be one of the @@ -388,7 +389,8 @@ //! padding specified by fill/alignment will be used to take up the required //! space. //! -//! The default fill/alignment for non-numerics is a space and left-aligned. The +//! The default [fill/alignment](#fillalignment) for non-numerics is a space and +//! left-aligned. The //! defaults for numeric formatters is also a space but with right-alignment. If //! the `0` flag is specified for numerics, then the implicit fill character is //! `0`. @@ -529,6 +531,8 @@ pub use core::fmt::Error; pub use core::fmt::{write, ArgumentV1, Arguments}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::fmt::{DebugList, DebugMap, DebugSet, DebugStruct, DebugTuple}; +#[stable(feature = "fmt_flags_align", since = "1.28.0")] +pub use core::fmt::{Alignment}; use string; diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs deleted file mode 100644 index 16f0630b91134..0000000000000 --- a/src/liballoc/heap.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(deprecated)] - -pub use alloc::{Layout, AllocErr, CannotReallocInPlace, Opaque}; -use core::alloc::Alloc as CoreAlloc; -use core::ptr::NonNull; - -#[doc(hidden)] -pub mod __core { - pub use core::*; -} - -#[derive(Debug)] -pub struct Excess(pub *mut u8, pub usize); - -/// Compatibility with older versions of #[global_allocator] during bootstrap -pub unsafe trait Alloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout); - fn oom(&mut self, err: AllocErr) -> !; - fn usable_size(&self, layout: &Layout) -> (usize, usize); - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr>; - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result; - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result; - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace>; - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace>; -} - -unsafe impl Alloc for T where T: CoreAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc(self, layout).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn dealloc(&mut self, ptr: *mut u8, layout: Layout) { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); - CoreAlloc::dealloc(self, ptr, layout) - } - - fn oom(&mut self, _: AllocErr) -> ! { - unsafe { ::core::intrinsics::abort() } - } - - fn usable_size(&self, layout: &Layout) -> (usize, usize) { - CoreAlloc::usable_size(self, layout) - } - - unsafe fn realloc(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<*mut u8, AllocErr> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); - CoreAlloc::realloc(self, ptr, layout, new_layout.size()).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<*mut u8, AllocErr> { - CoreAlloc::alloc_zeroed(self, layout).map(|ptr| ptr.cast().as_ptr()) - } - - unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { - CoreAlloc::alloc_excess(self, layout) - .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) - } - - unsafe fn realloc_excess(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); - CoreAlloc::realloc_excess(self, ptr, layout, new_layout.size()) - .map(|e| Excess(e.0 .cast().as_ptr(), e.1)) - } - - unsafe fn grow_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); - CoreAlloc::grow_in_place(self, ptr, layout, new_layout.size()) - } - - unsafe fn shrink_in_place(&mut self, - ptr: *mut u8, - layout: Layout, - new_layout: Layout) -> Result<(), CannotReallocInPlace> { - let ptr = NonNull::new_unchecked(ptr as *mut Opaque); - CoreAlloc::shrink_in_place(self, ptr, layout, new_layout.size()) - } -} diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index da4b76a4d527d..ef619527e064a 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -13,10 +13,10 @@ //! This library provides smart pointers and collections for managing //! heap-allocated values. //! -//! This library, like libcore, is not intended for general usage, but rather as -//! a building block of other libraries. The types and interfaces in this -//! library are re-exported through the [standard library](../std/index.html), -//! and should not be used through this library. +//! This library, like libcore, normally doesn’t need to be used directly +//! since its contents are re-exported in the [`std` crate](../std/index.html). +//! Crates that use the `#![no_std]` attribute however will typically +//! not depend on `std`, so they’d use this crate instead. //! //! ## Boxed values //! @@ -40,7 +40,7 @@ //! //! ## Atomically reference counted pointers //! -//! The [`Arc`](arc/index.html) type is the threadsafe equivalent of the `Rc` +//! The [`Arc`](sync/index.html) type is the threadsafe equivalent of the `Rc` //! type. It provides all the same functionality of `Rc`, except it requires //! that the contained type `T` is shareable. Additionally, `Arc` is itself //! sendable while `Rc` is not. @@ -75,12 +75,12 @@ #![deny(missing_debug_implementations)] #![cfg_attr(test, allow(deprecated))] // rand -#![cfg_attr(all(not(test), stage0), feature(float_internals))] #![cfg_attr(not(test), feature(exact_size_is_empty))] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(rand, test))] #![feature(allocator_api)] #![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types)] #![feature(ascii_ctype)] #![feature(box_into_raw_non_null)] #![feature(box_patterns)] @@ -90,27 +90,24 @@ #![feature(collections_range)] #![feature(const_fn)] #![feature(core_intrinsics)] -#![cfg_attr(stage0, feature(core_slice_ext))] -#![cfg_attr(stage0, feature(core_str_ext))] #![feature(custom_attribute)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(fmt_internals)] -#![cfg_attr(stage0, feature(fn_must_use))] #![feature(from_ref)] #![feature(fundamental)] +#![feature(futures_api)] #![feature(lang_items)] #![feature(libc)] #![feature(needs_allocator)] -#![feature(nonzero)] #![feature(optin_builtin_traits)] #![feature(pattern)] #![feature(pin)] #![feature(ptr_internals)] #![feature(ptr_offset_from)] #![feature(rustc_attrs)] -#![feature(slice_get_slice)] #![feature(specialization)] +#![feature(split_ascii_whitespace)] #![feature(staged_api)] #![feature(str_internals)] #![feature(trusted_len)] @@ -123,8 +120,8 @@ #![feature(exact_chunks)] #![feature(pointer_methods)] #![feature(inclusive_range_methods)] -#![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(rustc_const_unstable)] +#![feature(const_vec_new)] #![cfg_attr(not(test), feature(fn_traits, i128))] #![cfg_attr(test, feature(test))] @@ -143,30 +140,14 @@ extern crate rand; #[macro_use] mod macros; -#[rustc_deprecated(since = "1.27.0", reason = "use the heap module in core, alloc, or std instead")] -#[unstable(feature = "allocator_api", issue = "32838")] -/// Use the `alloc` module instead. -pub mod allocator { - pub use alloc::*; -} - // Heaps provided for low-level allocation strategies pub mod alloc; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -#[cfg(not(stage0))] -pub mod heap { - pub use alloc::*; -} - -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -#[cfg(stage0)] -pub mod heap; - +#[unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] +pub mod task; // Primitive types using the heaps above // Need to conditionally define the mod from `boxed.rs` to avoid @@ -180,60 +161,23 @@ mod boxed { } #[cfg(test)] mod boxed_test; -#[cfg(target_has_atomic = "ptr")] -pub mod arc; +pub mod collections; +#[cfg(any( + all(stage0, target_has_atomic = "ptr"), + all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas") +))] +pub mod sync; pub mod rc; pub mod raw_vec; - -// collections modules -pub mod binary_heap; -mod btree; +pub mod prelude; pub mod borrow; pub mod fmt; -pub mod linked_list; pub mod slice; pub mod str; pub mod string; pub mod vec; -pub mod vec_deque; - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod btree_map { - //! A map based on a B-Tree. - #[stable(feature = "rust1", since = "1.0.0")] - pub use btree::map::*; -} - -#[stable(feature = "rust1", since = "1.0.0")] -pub mod btree_set { - //! A set based on a B-Tree. - #[stable(feature = "rust1", since = "1.0.0")] - pub use btree::set::*; -} #[cfg(not(test))] mod std { pub use core::ops; // RangeFull } - -/// An intermediate trait for specialization of `Extend`. -#[doc(hidden)] -trait SpecExtend { - /// Extends `self` with the contents of the given iterator. - fn spec_extend(&mut self, iter: I); -} - -#[doc(no_inline)] -pub use binary_heap::BinaryHeap; -#[doc(no_inline)] -pub use btree_map::BTreeMap; -#[doc(no_inline)] -pub use btree_set::BTreeSet; -#[doc(no_inline)] -pub use linked_list::LinkedList; -#[doc(no_inline)] -pub use vec_deque::VecDeque; -#[doc(no_inline)] -pub use string::String; -#[doc(no_inline)] -pub use vec::Vec; diff --git a/src/liballoc/prelude.rs b/src/liballoc/prelude.rs new file mode 100644 index 0000000000000..53b5e93a66e26 --- /dev/null +++ b/src/liballoc/prelude.rs @@ -0,0 +1,29 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The alloc Prelude +//! +//! The purpose of this module is to alleviate imports of commonly-used +//! items of the `alloc` crate by adding a glob import to the top of modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! # #![feature(alloc)] +//! extern crate alloc; +//! use alloc::prelude::*; +//! ``` + +#![unstable(feature = "alloc", issue = "27783")] + +#[unstable(feature = "alloc", issue = "27783")] pub use borrow::ToOwned; +#[unstable(feature = "alloc", issue = "27783")] pub use boxed::Box; +#[unstable(feature = "alloc", issue = "27783")] pub use slice::SliceConcatExt; +#[unstable(feature = "alloc", issue = "27783")] pub use string::{String, ToString}; +#[unstable(feature = "alloc", issue = "27783")] pub use vec::Vec; diff --git a/src/liballoc/raw_vec.rs b/src/liballoc/raw_vec.rs index eb25ae1751170..4f2686abf4515 100644 --- a/src/liballoc/raw_vec.rs +++ b/src/liballoc/raw_vec.rs @@ -8,15 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![unstable(feature = "raw_vec_internals", reason = "implemention detail", issue = "0")] +#![doc(hidden)] + use core::cmp; use core::mem; use core::ops::Drop; use core::ptr::{self, NonNull, Unique}; use core::slice; -use alloc::{Alloc, Layout, Global, oom}; -use alloc::CollectionAllocErr; -use alloc::CollectionAllocErr::*; +use alloc::{Alloc, Layout, Global, handle_alloc_error}; +use collections::CollectionAllocErr; +use collections::CollectionAllocErr::*; use boxed::Box; /// A low-level utility for more ergonomically allocating, reallocating, and deallocating @@ -93,22 +96,23 @@ impl RawVec { // handles ZSTs and `cap = 0` alike let ptr = if alloc_size == 0 { - NonNull::::dangling().as_opaque() + NonNull::::dangling() } else { let align = mem::align_of::(); + let layout = Layout::from_size_align(alloc_size, align).unwrap(); let result = if zeroed { - a.alloc_zeroed(Layout::from_size_align(alloc_size, align).unwrap()) + a.alloc_zeroed(layout) } else { - a.alloc(Layout::from_size_align(alloc_size, align).unwrap()) + a.alloc(layout) }; match result { - Ok(ptr) => ptr, - Err(_) => oom(), + Ok(ptr) => ptr.cast(), + Err(_) => handle_alloc_error(layout), } }; RawVec { - ptr: ptr.cast().into(), + ptr: ptr.into(), cap, a, } @@ -263,7 +267,7 @@ impl RawVec { /// # Examples /// /// ``` - /// # #![feature(alloc)] + /// # #![feature(alloc, raw_vec_internals)] /// # extern crate alloc; /// # use std::ptr; /// # use alloc::raw_vec::RawVec; @@ -313,12 +317,14 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); - let ptr_res = self.a.realloc(NonNull::from(self.ptr).as_opaque(), + let ptr_res = self.a.realloc(NonNull::from(self.ptr).cast(), cur, new_size); match ptr_res { Ok(ptr) => (new_cap, ptr.cast().into()), - Err(_) => oom(), + Err(_) => handle_alloc_error( + Layout::from_size_align_unchecked(new_size, cur.align()) + ), } } None => { @@ -327,7 +333,7 @@ impl RawVec { let new_cap = if elem_size > (!0) / 8 { 1 } else { 4 }; match self.a.alloc_array::(new_cap) { Ok(ptr) => (new_cap, ptr.into()), - Err(_) => oom(), + Err(_) => handle_alloc_error(Layout::array::(new_cap).unwrap()), } } }; @@ -372,7 +378,7 @@ impl RawVec { let new_cap = 2 * self.cap; let new_size = new_cap * elem_size; alloc_guard(new_size).unwrap_or_else(|_| capacity_overflow()); - match self.a.grow_in_place(NonNull::from(self.ptr).as_opaque(), old_layout, new_size) { + match self.a.grow_in_place(NonNull::from(self.ptr).cast(), old_layout, new_size) { Ok(_) => { // We can't directly divide `size`. self.cap = new_cap; @@ -385,6 +391,13 @@ impl RawVec { } } + /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. + pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) + -> Result<(), CollectionAllocErr> { + + self.reserve_internal(used_cap, needed_extra_cap, Fallible, Exact) + } + /// Ensures that the buffer contains at least enough space to hold /// `used_cap + needed_extra_cap` elements. If it doesn't already, /// will reallocate the minimum possible amount of memory necessary. @@ -405,46 +418,10 @@ impl RawVec { /// # Aborts /// /// Aborts on OOM - pub fn try_reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) - -> Result<(), CollectionAllocErr> { - - unsafe { - // NOTE: we don't early branch on ZSTs here because we want this - // to actually catch "asking for more than usize::MAX" in that case. - // If we make it past the first branch then we are guaranteed to - // panic. - - // Don't actually need any more capacity. - // Wrapping in case they gave a bad `used_cap`. - if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { - return Ok(()); - } - - // Nothing we can really do about these checks :( - let new_cap = used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?; - let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; - - alloc_guard(new_layout.size())?; - - let res = match self.current_layout() { - Some(layout) => { - debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) - } - None => self.a.alloc(new_layout), - }; - - self.ptr = res?.cast().into(); - self.cap = new_cap; - - Ok(()) - } - } - pub fn reserve_exact(&mut self, used_cap: usize, needed_extra_cap: usize) { - match self.try_reserve_exact(used_cap, needed_extra_cap) { + match self.reserve_internal(used_cap, needed_extra_cap, Infallible, Exact) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => oom(), + Err(AllocErr) => unreachable!(), Ok(()) => { /* yay */ } } } @@ -463,6 +440,12 @@ impl RawVec { Ok(cmp::max(double_cap, required_cap)) } + /// The same as `reserve`, but returns on errors instead of panicking or aborting. + pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize) + -> Result<(), CollectionAllocErr> { + self.reserve_internal(used_cap, needed_extra_cap, Fallible, Amortized) + } + /// Ensures that the buffer contains at least enough space to hold /// `used_cap + needed_extra_cap` elements. If it doesn't already have /// enough capacity, will reallocate enough space plus comfortable slack @@ -488,7 +471,7 @@ impl RawVec { /// # Examples /// /// ``` - /// # #![feature(alloc)] + /// # #![feature(alloc, raw_vec_internals)] /// # extern crate alloc; /// # use std::ptr; /// # use alloc::raw_vec::RawVec; @@ -515,49 +498,13 @@ impl RawVec { /// # vector.push_all(&[1, 3, 5, 7, 9]); /// # } /// ``` - pub fn try_reserve(&mut self, used_cap: usize, needed_extra_cap: usize) - -> Result<(), CollectionAllocErr> { - unsafe { - // NOTE: we don't early branch on ZSTs here because we want this - // to actually catch "asking for more than usize::MAX" in that case. - // If we make it past the first branch then we are guaranteed to - // panic. - - // Don't actually need any more capacity. - // Wrapping in case they give a bad `used_cap` - if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { - return Ok(()); - } - - let new_cap = self.amortized_new_size(used_cap, needed_extra_cap)?; - let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; - - // FIXME: may crash and burn on over-reserve - alloc_guard(new_layout.size())?; - - let res = match self.current_layout() { - Some(layout) => { - debug_assert!(new_layout.align() == layout.align()); - self.a.realloc(NonNull::from(self.ptr).as_opaque(), layout, new_layout.size()) - } - None => self.a.alloc(new_layout), - }; - - self.ptr = res?.cast().into(); - self.cap = new_cap; - - Ok(()) - } - } - - /// The same as try_reserve, but errors are lowered to a call to oom(). pub fn reserve(&mut self, used_cap: usize, needed_extra_cap: usize) { - match self.try_reserve(used_cap, needed_extra_cap) { + match self.reserve_internal(used_cap, needed_extra_cap, Infallible, Amortized) { Err(CapacityOverflow) => capacity_overflow(), - Err(AllocErr) => oom(), + Err(AllocErr) => unreachable!(), Ok(()) => { /* yay */ } - } - } + } + } /// Attempts to ensure that the buffer contains at least enough space to hold /// `used_cap + needed_extra_cap` elements. If it doesn't already have /// enough capacity, will reallocate in place enough space plus comfortable slack @@ -604,7 +551,7 @@ impl RawVec { // FIXME: may crash and burn on over-reserve alloc_guard(new_layout.size()).unwrap_or_else(|_| capacity_overflow()); match self.a.grow_in_place( - NonNull::from(self.ptr).as_opaque(), old_layout, new_layout.size(), + NonNull::from(self.ptr).cast(), old_layout, new_layout.size(), ) { Ok(_) => { self.cap = new_cap; @@ -665,11 +612,13 @@ impl RawVec { let new_size = elem_size * amount; let align = mem::align_of::(); let old_layout = Layout::from_size_align_unchecked(old_size, align); - match self.a.realloc(NonNull::from(self.ptr).as_opaque(), + match self.a.realloc(NonNull::from(self.ptr).cast(), old_layout, new_size) { Ok(p) => self.ptr = p.cast().into(), - Err(_) => oom(), + Err(_) => handle_alloc_error( + Layout::from_size_align_unchecked(new_size, align) + ), } } self.cap = amount; @@ -677,6 +626,73 @@ impl RawVec { } } +enum Fallibility { + Fallible, + Infallible, +} + +use self::Fallibility::*; + +enum ReserveStrategy { + Exact, + Amortized, +} + +use self::ReserveStrategy::*; + +impl RawVec { + fn reserve_internal( + &mut self, + used_cap: usize, + needed_extra_cap: usize, + fallibility: Fallibility, + strategy: ReserveStrategy, + ) -> Result<(), CollectionAllocErr> { + unsafe { + use alloc::AllocErr; + + // NOTE: we don't early branch on ZSTs here because we want this + // to actually catch "asking for more than usize::MAX" in that case. + // If we make it past the first branch then we are guaranteed to + // panic. + + // Don't actually need any more capacity. + // Wrapping in case they gave a bad `used_cap`. + if self.cap().wrapping_sub(used_cap) >= needed_extra_cap { + return Ok(()); + } + + // Nothing we can really do about these checks :( + let new_cap = match strategy { + Exact => used_cap.checked_add(needed_extra_cap).ok_or(CapacityOverflow)?, + Amortized => self.amortized_new_size(used_cap, needed_extra_cap)?, + }; + let new_layout = Layout::array::(new_cap).map_err(|_| CapacityOverflow)?; + + alloc_guard(new_layout.size())?; + + let res = match self.current_layout() { + Some(layout) => { + debug_assert!(new_layout.align() == layout.align()); + self.a.realloc(NonNull::from(self.ptr).cast(), layout, new_layout.size()) + } + None => self.a.alloc(new_layout), + }; + + match (&res, fallibility) { + (Err(AllocErr), Infallible) => handle_alloc_error(new_layout), + _ => {} + } + + self.ptr = res?.cast().into(); + self.cap = new_cap; + + Ok(()) + } + } + +} + impl RawVec { /// Converts the entire buffer into `Box<[T]>`. /// @@ -701,7 +717,7 @@ impl RawVec { let elem_size = mem::size_of::(); if elem_size != 0 { if let Some(layout) = self.current_layout() { - self.a.dealloc(NonNull::from(self.ptr).as_opaque(), layout); + self.a.dealloc(NonNull::from(self.ptr).cast(), layout); } } } @@ -744,11 +760,10 @@ fn capacity_overflow() -> ! { #[cfg(test)] mod tests { use super::*; - use alloc::Opaque; #[test] fn allocator_param() { - use allocator::{Alloc, AllocErr}; + use alloc::AllocErr; // Writing a test of integration between third-party // allocators and RawVec is a little tricky because the RawVec @@ -764,7 +779,7 @@ mod tests { // before allocation attempts start failing. struct BoundedAlloc { fuel: usize } unsafe impl Alloc for BoundedAlloc { - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); if size > self.fuel { return Err(AllocErr); @@ -774,7 +789,7 @@ mod tests { err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { Global.dealloc(ptr, layout) } } diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs index d0188c6e82858..be049eb6e5ef3 100644 --- a/src/liballoc/rc.rs +++ b/src/liballoc/rc.rs @@ -253,13 +253,14 @@ use core::hash::{Hash, Hasher}; use core::intrinsics::abort; use core::marker; use core::marker::{Unsize, PhantomData}; -use core::mem::{self, align_of_val, forget, size_of_val, uninitialized}; +use core::mem::{self, align_of_val, forget, size_of_val}; use core::ops::Deref; use core::ops::CoerceUnsized; use core::ptr::{self, NonNull}; use core::convert::From; +use core::usize; -use alloc::{Global, Alloc, Layout, Opaque, box_free, oom}; +use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; use string::String; use vec::Vec; @@ -449,6 +450,8 @@ impl Rc { #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak { this.inc_weak(); + // Make sure we do not create a dangling Weak + debug_assert!(!is_dangling(this.ptr)); Weak { ptr: this.ptr } } @@ -618,15 +621,14 @@ impl Rc { } } -impl Rc { +impl Rc { #[inline] - #[unstable(feature = "rc_downcast", issue = "44608")] + #[stable(feature = "rc_downcast", since = "1.29.0")] /// Attempt to downcast the `Rc` to a concrete type. /// /// # Examples /// /// ``` - /// #![feature(rc_downcast)] /// use std::any::Any; /// use std::rc::Rc; /// @@ -642,17 +644,11 @@ impl Rc { /// print_if_string(Rc::new(0i8)); /// } /// ``` - pub fn downcast(self) -> Result, Rc> { + pub fn downcast(self) -> Result, Rc> { if (*self).is::() { - // avoid the pointer arithmetic in from_raw - unsafe { - let raw: *const RcBox = self.ptr.as_ptr(); - forget(self); - Ok(Rc { - ptr: NonNull::new_unchecked(raw as *const RcBox as *mut _), - phantom: PhantomData, - }) - } + let ptr = self.ptr.cast::>(); + forget(self); + Ok(Rc { ptr, phantom: PhantomData }) } else { Err(self) } @@ -668,7 +664,7 @@ impl Rc { let layout = Layout::for_value(&*fake_ptr); let mem = Global.alloc(layout) - .unwrap_or_else(|_| oom()); + .unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the real RcBox let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut RcBox; @@ -738,7 +734,7 @@ impl RcFromSlice for Rc<[T]> { // In the event of a panic, elements that have been written // into the new RcBox will be dropped, then the memory freed. struct Guard { - mem: NonNull, + mem: NonNull, elems: *mut T, layout: Layout, n_elems: usize, @@ -761,7 +757,7 @@ impl RcFromSlice for Rc<[T]> { let v_ptr = v as *const [T]; let ptr = Self::allocate_for_ptr(v_ptr); - let mem = ptr as *mut _ as *mut Opaque; + let mem = ptr as *mut _ as *mut u8; let layout = Layout::for_value(&*ptr); // Pointer to first element @@ -845,7 +841,7 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { self.dec_weak(); if self.weak() == 0 { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -1159,6 +1155,11 @@ impl From> for Rc<[T]> { /// [`None`]: ../../std/option/enum.Option.html#variant.None #[stable(feature = "rc_weak", since = "1.4.0")] pub struct Weak { + // This is a `NonNull` to allow optimizing the size of this type in enums, + // but it is not necessarily a valid pointer. + // `Weak::new` sets this to `usize::MAX` so that it doesn’t need + // to allocate space on the heap. That's not a value a real pointer + // will ever have because RcBox has alignment at least 2. ptr: NonNull>, } @@ -1171,8 +1172,8 @@ impl !marker::Sync for Weak {} impl, U: ?Sized> CoerceUnsized> for Weak {} impl Weak { - /// Constructs a new `Weak`, allocating memory for `T` without initializing - /// it. Calling [`upgrade`] on the return value always gives [`None`]. + /// Constructs a new `Weak`, without allocating any memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. /// /// [`upgrade`]: struct.Weak.html#method.upgrade /// [`None`]: ../../std/option/enum.Option.html @@ -1187,18 +1188,17 @@ impl Weak { /// ``` #[stable(feature = "downgraded_weak", since = "1.10.0")] pub fn new() -> Weak { - unsafe { - Weak { - ptr: Box::into_raw_non_null(box RcBox { - strong: Cell::new(0), - weak: Cell::new(1), - value: uninitialized(), - }), - } + Weak { + ptr: NonNull::new(usize::MAX as *mut RcBox).expect("MAX is not 0"), } } } +pub(crate) fn is_dangling(ptr: NonNull) -> bool { + let address = ptr.as_ptr() as *mut () as usize; + address == usize::MAX +} + impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], extending /// the lifetime of the value if successful. @@ -1228,13 +1228,25 @@ impl Weak { /// ``` #[stable(feature = "rc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option> { - if self.strong() == 0 { + let inner = self.inner()?; + if inner.strong() == 0 { None } else { - self.inc_strong(); + inner.inc_strong(); Some(Rc { ptr: self.ptr, phantom: PhantomData }) } } + + /// Return `None` when the pointer is dangling and there is no allocated `RcBox`, + /// i.e. this `Weak` was created by `Weak::new` + #[inline] + fn inner(&self) -> Option<&RcBox> { + if is_dangling(self.ptr) { + None + } else { + Some(unsafe { self.ptr.as_ref() }) + } + } } #[stable(feature = "rc_weak", since = "1.4.0")] @@ -1264,12 +1276,14 @@ impl Drop for Weak { /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { - unsafe { - self.dec_weak(); + if let Some(inner) = self.inner() { + inner.dec_weak(); // the weak count starts at 1, and will only go to zero if all // the strong pointers have disappeared. - if self.weak() == 0 { - Global.dealloc(self.ptr.as_opaque(), Layout::for_value(self.ptr.as_ref())); + if inner.weak() == 0 { + unsafe { + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); + } } } } @@ -1290,7 +1304,9 @@ impl Clone for Weak { /// ``` #[inline] fn clone(&self) -> Weak { - self.inc_weak(); + if let Some(inner) = self.inner() { + inner.inc_weak() + } Weak { ptr: self.ptr } } } @@ -1323,7 +1339,7 @@ impl Default for Weak { } } -// NOTE: We checked_add here to deal with mem::forget safety. In particular +// NOTE: We checked_add here to deal with mem::forget safely. In particular // if you mem::forget Rcs (or Weaks), the ref-count can overflow, and then // you can free the allocation while outstanding Rcs (or Weaks) exist. // We abort because this is such a degenerate scenario that we don't care about @@ -1376,12 +1392,10 @@ impl RcBoxPtr for Rc { } } -impl RcBoxPtr for Weak { +impl RcBoxPtr for RcBox { #[inline(always)] fn inner(&self) -> &RcBox { - unsafe { - self.ptr.as_ref() - } + self } } @@ -1543,7 +1557,7 @@ mod tests { assert_eq!(unsafe { &*ptr }, "foo"); assert_eq!(rc, rc2); - let rc: Rc = Rc::new(123); + let rc: Rc = Rc::new(123); let ptr = Rc::into_raw(rc.clone()); let rc2 = unsafe { Rc::from_raw(ptr) }; @@ -1744,8 +1758,8 @@ mod tests { use std::fmt::Display; use std::string::ToString; - let b: Box = box 123; - let r: Rc = Rc::from(b); + let b: Box = box 123; + let r: Rc = Rc::from(b); assert_eq!(r.to_string(), "123"); } @@ -1754,8 +1768,8 @@ mod tests { fn test_from_box_trait_zero_sized() { use std::fmt::Debug; - let b: Box = box (); - let r: Rc = Rc::from(b); + let b: Box = box (); + let r: Rc = Rc::from(b); assert_eq!(format!("{:?}", r), "()"); } @@ -1772,8 +1786,8 @@ mod tests { fn test_downcast() { use std::any::Any; - let r1: Rc = Rc::new(i32::max_value()); - let r2: Rc = Rc::new("abc"); + let r1: Rc = Rc::new(i32::max_value()); + let r2: Rc = Rc::new("abc"); assert!(r1.clone().downcast::().is_err()); diff --git a/src/liballoc/repeat-generic-slice.rs b/src/liballoc/repeat-generic-slice.rs deleted file mode 100644 index 5c14ee4fd83b4..0000000000000 --- a/src/liballoc/repeat-generic-slice.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![feature(repeat_generic_slice)] - -fn main() { - assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]); - assert_eq!([1, 2, 3, 4].repeat(0), vec![]); - assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]); - assert_eq!([1, 2, 3, 4].repeat(3), - vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]); -} diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs index d50a3458f20d1..c27c596e7975a 100644 --- a/src/liballoc/slice.rs +++ b/src/liballoc/slice.rs @@ -10,6 +10,8 @@ //! A dynamically-sized view into a contiguous sequence, `[T]`. //! +//! *[See also the slice primitive type](../../std/primitive.slice.html).* +//! //! Slices are a view into a block of memory represented as a pointer and a //! length. //! @@ -78,8 +80,6 @@ //! * Further methods that return iterators are [`.split`], [`.splitn`], //! [`.chunks`], [`.windows`] and more. //! -//! *[See also the slice primitive type](../../std/primitive.slice.html).* -//! //! [`Clone`]: ../../std/clone/trait.Clone.html //! [`Eq`]: ../../std/cmp/trait.Eq.html //! [`Ord`]: ../../std/cmp/trait.Ord.html @@ -101,7 +101,6 @@ use core::cmp::Ordering::{self, Less}; use core::mem::size_of; use core::mem; use core::ptr; -#[cfg(stage0)] use core::slice::SliceExt; use core::{u8, u16, u32}; use borrow::{Borrow, BorrowMut, ToOwned}; @@ -120,9 +119,9 @@ pub use core::slice::{SplitN, RSplitN, SplitNMut, RSplitNMut}; pub use core::slice::{RSplit, RSplitMut}; #[stable(feature = "rust1", since = "1.0.0")] pub use core::slice::{from_raw_parts, from_raw_parts_mut}; -#[unstable(feature = "from_ref", issue = "45703")] -pub use core::slice::{from_ref, from_ref_mut}; -#[unstable(feature = "slice_get_slice", issue = "35729")] +#[stable(feature = "from_ref", since = "1.28.0")] +pub use core::slice::{from_ref, from_mut}; +#[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[unstable(feature = "exact_chunks", issue = "47115")] pub use core::slice::{ExactChunks, ExactChunksMut}; @@ -171,13 +170,9 @@ mod hack { } } -#[cfg_attr(stage0, lang = "slice")] -#[cfg_attr(not(stage0), lang = "slice_alloc")] +#[lang = "slice_alloc"] #[cfg(not(test))] impl [T] { - #[cfg(stage0)] - slice_core_methods!(); - /// Sorts the slice. /// /// This sort is stable (i.e. does not reorder equal elements) and `O(n log n)` worst-case. @@ -467,8 +462,7 @@ impl [T] { } } -#[cfg_attr(stage0, lang = "slice_u8")] -#[cfg_attr(not(stage0), lang = "slice_u8_alloc")] +#[lang = "slice_u8_alloc"] #[cfg(not(test))] impl [u8] { /// Returns a vector containing a copy of this slice where each byte @@ -504,9 +498,6 @@ impl [u8] { me.make_ascii_lowercase(); me } - - #[cfg(stage0)] - slice_u8_core_methods!(); } //////////////////////////////////////////////////////////////////////////////// @@ -575,15 +566,17 @@ impl> SliceConcatExt for [V] { } fn join(&self, sep: &T) -> Vec { + let mut iter = self.iter(); + let first = match iter.next() { + Some(first) => first, + None => return vec![], + }; let size = self.iter().fold(0, |acc, v| acc + v.borrow().len()); let mut result = Vec::with_capacity(size + self.len()); - let mut first = true; - for v in self { - if first { - first = false - } else { - result.push(sep.clone()) - } + result.extend_from_slice(first.borrow()); + + for v in iter { + result.push(sep.clone()); result.extend_from_slice(v.borrow()) } result diff --git a/src/liballoc/str.rs b/src/liballoc/str.rs index 0cbe65db53cad..870bf971cd3f6 100644 --- a/src/liballoc/str.rs +++ b/src/liballoc/str.rs @@ -10,6 +10,8 @@ //! Unicode string slices. //! +//! *[See also the `str` primitive type](../../std/primitive.str.html).* +//! //! The `&str` type is one of the two main string types, the other being `String`. //! Unlike its `String` counterpart, its contents are borrowed. //! @@ -29,8 +31,6 @@ //! ``` //! let hello_world: &'static str = "Hello, world!"; //! ``` -//! -//! *[See also the `str` primitive type](../../std/primitive.str.html).* #![stable(feature = "rust1", since = "1.0.0")] @@ -40,19 +40,18 @@ use core::fmt; use core::str as core_str; -#[cfg(stage0)] use core::str::StrExt; use core::str::pattern::Pattern; use core::str::pattern::{Searcher, ReverseSearcher, DoubleEndedSearcher}; use core::mem; use core::ptr; use core::iter::FusedIterator; +use core::unicode::conversions; use borrow::{Borrow, ToOwned}; use boxed::Box; use slice::{SliceConcatExt, SliceIndex}; use string::String; use vec::Vec; -use vec_deque::VecDeque; #[stable(feature = "rust1", since = "1.0.0")] pub use core::str::{FromStr, Utf8Error}; @@ -79,6 +78,8 @@ pub use core::str::SplitWhitespace; pub use core::str::pattern; #[stable(feature = "encode_utf16", since = "1.8.0")] pub use core::str::EncodeUtf16; +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +pub use core::str::SplitAsciiWhitespace; #[unstable(feature = "slice_concat_ext", reason = "trait should not have to exist", @@ -87,52 +88,108 @@ impl> SliceConcatExt for [S] { type Output = String; fn concat(&self) -> String { - if self.is_empty() { - return String::new(); - } - - // `len` calculation may overflow but push_str will check boundaries - let len = self.iter().map(|s| s.borrow().len()).sum(); - let mut result = String::with_capacity(len); - - for s in self { - result.push_str(s.borrow()) - } - - result + self.join("") } fn join(&self, sep: &str) -> String { - if self.is_empty() { - return String::new(); - } - - // concat is faster - if sep.is_empty() { - return self.concat(); + unsafe { + String::from_utf8_unchecked( join_generic_copy(self, sep.as_bytes()) ) } + } - // this is wrong without the guarantee that `self` is non-empty - // `len` calculation may overflow but push_str but will check boundaries - let len = sep.len() * (self.len() - 1) + - self.iter().map(|s| s.borrow().len()).sum::(); - let mut result = String::with_capacity(len); - let mut first = true; + fn connect(&self, sep: &str) -> String { + self.join(sep) + } +} - for s in self { - if first { - first = false; - } else { - result.push_str(sep); +macro_rules! spezialize_for_lengths { + ($separator:expr, $target:expr, $iter:expr; $($num:expr),*) => { + let mut target = $target; + let iter = $iter; + let sep_bytes = $separator; + match $separator.len() { + $( + // loops with hardcoded sizes run much faster + // specialize the cases with small separator lengths + $num => { + for s in iter { + copy_slice_and_advance!(target, sep_bytes); + copy_slice_and_advance!(target, s.borrow().as_ref()); + } + }, + )* + _ => { + // arbitrary non-zero size fallback + for s in iter { + copy_slice_and_advance!(target, sep_bytes); + copy_slice_and_advance!(target, s.borrow().as_ref()); + } } - result.push_str(s.borrow()); } - result + }; +} + +macro_rules! copy_slice_and_advance { + ($target:expr, $bytes:expr) => { + let len = $bytes.len(); + let (head, tail) = {$target}.split_at_mut(len); + head.copy_from_slice($bytes); + $target = tail; } +} - fn connect(&self, sep: &str) -> String { - self.join(sep) +// Optimized join implementation that works for both Vec (T: Copy) and String's inner vec +// Currently (2018-05-13) there is a bug with type inference and specialization (see issue #36262) +// For this reason SliceConcatExt is not specialized for T: Copy and SliceConcatExt is the +// only user of this function. It is left in place for the time when that is fixed. +// +// the bounds for String-join are S: Borrow and for Vec-join Borrow<[T]> +// [T] and str both impl AsRef<[T]> for some T +// => s.borrow().as_ref() and we always have slices +fn join_generic_copy(slice: &[S], sep: &[T]) -> Vec +where + T: Copy, + B: AsRef<[T]> + ?Sized, + S: Borrow, +{ + let sep_len = sep.len(); + let mut iter = slice.iter(); + + // the first slice is the only one without a separator preceding it + let first = match iter.next() { + Some(first) => first, + None => return vec![], + }; + + // compute the exact total length of the joined Vec + // if the `len` calculation overflows, we'll panic + // we would have run out of memory anyway and the rest of the function requires + // the entire Vec pre-allocated for safety + let len = sep_len.checked_mul(iter.len()).and_then(|n| { + slice.iter() + .map(|s| s.borrow().as_ref().len()) + .try_fold(n, usize::checked_add) + }).expect("attempt to join into collection with len > usize::MAX"); + + // crucial for safety + let mut result = Vec::with_capacity(len); + assert!(result.capacity() >= len); + + result.extend_from_slice(first.borrow().as_ref()); + + unsafe { + { + let pos = result.len(); + let target = result.get_unchecked_mut(pos..len); + + // copy separator and slices over without bounds checks + // generate loops with hardcoded offsets for small separators + // massive improvements possible (~ x2) + spezialize_for_lengths!(sep, target, iter; 0, 1, 2, 3, 4); + } + result.set_len(len); } + result } #[stable(feature = "rust1", since = "1.0.0")] @@ -158,13 +215,9 @@ impl ToOwned for str { } /// Methods for string slices. -#[cfg_attr(stage0, lang = "str")] -#[cfg_attr(not(stage0), lang = "str_alloc")] +#[lang = "str_alloc"] #[cfg(not(test))] impl str { - #[cfg(stage0)] - str_core_methods!(); - /// Converts a `Box` into a `Box<[u8]>` without copying or allocating. /// /// # Examples @@ -207,18 +260,19 @@ impl str { /// let s = "this is old"; /// assert_eq!(s, s.replace("cookie monster", "little lamb")); /// ``` - #[must_use] + #[must_use = "this returns the replaced string as a new allocation, \ + without modifying the original"] #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn replace<'a, P: Pattern<'a>>(&'a self, from: P, to: &str) -> String { let mut result = String::new(); let mut last_end = 0; for (start, part) in self.match_indices(from) { - result.push_str(unsafe { self.slice_unchecked(last_end, start) }); + result.push_str(unsafe { self.get_unchecked(last_end..start) }); result.push_str(to); last_end = start + part.len(); } - result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); + result.push_str(unsafe { self.get_unchecked(last_end..self.len()) }); result } @@ -247,18 +301,19 @@ impl str { /// let s = "this is old"; /// assert_eq!(s, s.replacen("cookie monster", "little lamb", 10)); /// ``` - #[must_use] + #[must_use = "this returns the replaced string as a new allocation, \ + without modifying the original"] #[stable(feature = "str_replacen", since = "1.16.0")] pub fn replacen<'a, P: Pattern<'a>>(&'a self, pat: P, to: &str, count: usize) -> String { // Hope to reduce the times of re-allocation let mut result = String::with_capacity(32); let mut last_end = 0; for (start, part) in self.match_indices(pat).take(count) { - result.push_str(unsafe { self.slice_unchecked(last_end, start) }); + result.push_str(unsafe { self.get_unchecked(last_end..start) }); result.push_str(to); last_end = start + part.len(); } - result.push_str(unsafe { self.slice_unchecked(last_end, self.len()) }); + result.push_str(unsafe { self.get_unchecked(last_end..self.len()) }); result } @@ -315,7 +370,18 @@ impl str { // See https://github.com/rust-lang/rust/issues/26035 map_uppercase_sigma(self, i, &mut s) } else { - s.extend(c.to_lowercase()); + match conversions::to_lower(c) { + [a, '\0', _] => s.push(a), + [a, b, '\0'] => { + s.push(a); + s.push(b); + } + [a, b, c] => { + s.push(a); + s.push(b); + s.push(c); + } + } } } return s; @@ -369,18 +435,40 @@ impl str { #[stable(feature = "unicode_case_mapping", since = "1.2.0")] pub fn to_uppercase(&self) -> String { let mut s = String::with_capacity(self.len()); - s.extend(self.chars().flat_map(|c| c.to_uppercase())); + for c in self[..].chars() { + match conversions::to_upper(c) { + [a, '\0', _] => s.push(a), + [a, b, '\0'] => { + s.push(a); + s.push(b); + } + [a, b, c] => { + s.push(a); + s.push(b); + s.push(c); + } + } + } return s; } /// Escapes each char in `s` with [`char::escape_debug`]. /// + /// Note: only extended grapheme codepoints that begin the string will be + /// escaped. + /// /// [`char::escape_debug`]: primitive.char.html#method.escape_debug #[unstable(feature = "str_escape", reason = "return type may change to be an iterator", issue = "27791")] pub fn escape_debug(&self) -> String { - self.chars().flat_map(|c| c.escape_debug()).collect() + let mut string = String::with_capacity(self.len()); + let mut chars = self.chars(); + if let Some(first) = chars.next() { + string.extend(first.escape_debug_ext(true)) + } + string.extend(chars.flat_map(|c| c.escape_debug_ext(false))); + string } /// Escapes each char in `s` with [`char::escape_default`]. diff --git a/src/liballoc/string.rs b/src/liballoc/string.rs index 2f84d5f7f8676..631779a17a165 100644 --- a/src/liballoc/string.rs +++ b/src/liballoc/string.rs @@ -66,7 +66,7 @@ use core::ptr; use core::str::pattern::Pattern; use core::str::lossy; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use borrow::{Cow, ToOwned}; use boxed::Box; use str::{self, from_boxed_utf8_unchecked, FromStr, Utf8Error, Chars}; @@ -380,7 +380,8 @@ impl String { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn new() -> String { + #[rustc_const_unstable(feature = "const_string_new")] + pub const fn new() -> String { String { vec: Vec::new() } } @@ -1221,7 +1222,7 @@ impl String { while idx < len { let ch = unsafe { - self.slice_unchecked(idx, len).chars().next().unwrap() + self.get_unchecked(idx..len).chars().next().unwrap() }; let ch_len = ch.len_utf8(); @@ -1492,12 +1493,12 @@ impl String { // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, @@ -1550,12 +1551,12 @@ impl String { // Replace_range does not have the memory safety issues of a vector Splice. // of the vector version. The data is just plain bytes. - match range.start() { + match range.start_bound() { Included(&n) => assert!(self.is_char_boundary(n)), Excluded(&n) => assert!(self.is_char_boundary(n + 1)), Unbounded => {}, }; - match range.end() { + match range.end_bound() { Included(&n) => assert!(self.is_char_boundary(n + 1)), Excluded(&n) => assert!(self.is_char_boundary(n)), Unbounded => {}, @@ -2239,6 +2240,14 @@ impl<'a> From for Cow<'a, str> { } } +#[stable(feature = "cow_from_string_ref", since = "1.28.0")] +impl<'a> From<&'a String> for Cow<'a, str> { + #[inline] + fn from(s: &'a String) -> Cow<'a, str> { + Cow::Borrowed(s.as_str()) + } +} + #[stable(feature = "cow_str_from_iter", since = "1.12.0")] impl<'a> FromIterator for Cow<'a, str> { fn from_iter>(it: I) -> Cow<'a, str> { diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs new file mode 100644 index 0000000000000..a00b6b4e435f0 --- /dev/null +++ b/src/liballoc/sync.rs @@ -0,0 +1,1944 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![stable(feature = "rust1", since = "1.0.0")] + +//! Thread-safe reference-counting pointers. +//! +//! See the [`Arc`][arc] documentation for more details. +//! +//! [arc]: struct.Arc.html + +use core::any::Any; +use core::sync::atomic; +use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; +use core::borrow; +use core::fmt; +use core::cmp::Ordering; +use core::intrinsics::abort; +use core::mem::{self, align_of_val, size_of_val}; +use core::ops::Deref; +use core::ops::CoerceUnsized; +use core::ptr::{self, NonNull}; +use core::marker::{Unsize, PhantomData}; +use core::hash::{Hash, Hasher}; +use core::{isize, usize}; +use core::convert::From; + +use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error}; +use boxed::Box; +use rc::is_dangling; +use string::String; +use vec::Vec; + +/// A soft limit on the amount of references that may be made to an `Arc`. +/// +/// Going above this limit will abort your program (although not +/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references. +const MAX_REFCOUNT: usize = (isize::MAX) as usize; + +/// A thread-safe reference-counting pointer. 'Arc' stands for 'Atomically +/// Reference Counted'. +/// +/// The type `Arc` provides shared ownership of a value of type `T`, +/// allocated in the heap. Invoking [`clone`][clone] on `Arc` produces +/// a new pointer to the same value in the heap. When the last `Arc` +/// pointer to a given value is destroyed, the pointed-to value is +/// also destroyed. +/// +/// Shared references in Rust disallow mutation by default, and `Arc` is no +/// exception: you cannot generally obtain a mutable reference to something +/// inside an `Arc`. If you need to mutate through an `Arc`, use +/// [`Mutex`][mutex], [`RwLock`][rwlock], or one of the [`Atomic`][atomic] +/// types. +/// +/// ## Thread Safety +/// +/// Unlike [`Rc`], `Arc` uses atomic operations for its reference +/// counting. This means that it is thread-safe. The disadvantage is that +/// atomic operations are more expensive than ordinary memory accesses. If you +/// are not sharing reference-counted values between threads, consider using +/// [`Rc`] for lower overhead. [`Rc`] is a safe default, because the +/// compiler will catch any attempt to send an [`Rc`] between threads. +/// However, a library might choose `Arc` in order to give library consumers +/// more flexibility. +/// +/// `Arc` will implement [`Send`] and [`Sync`] as long as the `T` implements +/// [`Send`] and [`Sync`]. Why can't you put a non-thread-safe type `T` in an +/// `Arc` to make it thread-safe? This may be a bit counter-intuitive at +/// first: after all, isn't the point of `Arc` thread safety? The key is +/// this: `Arc` makes it thread safe to have multiple ownership of the same +/// data, but it doesn't add thread safety to its data. Consider +/// `Arc<`[`RefCell`]`>`. [`RefCell`] isn't [`Sync`], and if `Arc` was always +/// [`Send`], `Arc<`[`RefCell`]`>` would be as well. But then we'd have a problem: +/// [`RefCell`] is not thread safe; it keeps track of the borrowing count using +/// non-atomic operations. +/// +/// In the end, this means that you may need to pair `Arc` with some sort of +/// [`std::sync`] type, usually [`Mutex`][mutex]. +/// +/// ## Breaking cycles with `Weak` +/// +/// The [`downgrade`][downgrade] method can be used to create a non-owning +/// [`Weak`][weak] pointer. A [`Weak`][weak] pointer can be [`upgrade`][upgrade]d +/// to an `Arc`, but this will return [`None`] if the value has already been +/// dropped. +/// +/// A cycle between `Arc` pointers will never be deallocated. For this reason, +/// [`Weak`][weak] is used to break cycles. For example, a tree could have +/// strong `Arc` pointers from parent nodes to children, and [`Weak`][weak] +/// pointers from children back to their parents. +/// +/// # Cloning references +/// +/// Creating a new reference from an existing reference counted pointer is done using the +/// `Clone` trait implemented for [`Arc`][arc] and [`Weak`][weak]. +/// +/// ``` +/// use std::sync::Arc; +/// let foo = Arc::new(vec![1.0, 2.0, 3.0]); +/// // The two syntaxes below are equivalent. +/// let a = foo.clone(); +/// let b = Arc::clone(&foo); +/// // a and b both point to the same memory location as foo. +/// ``` +/// +/// The [`Arc::clone(&from)`] syntax is the most idiomatic because it conveys more explicitly +/// the meaning of the code. In the example above, this syntax makes it easier to see that +/// this code is creating a new reference rather than copying the whole content of foo. +/// +/// ## `Deref` behavior +/// +/// `Arc` automatically dereferences to `T` (via the [`Deref`][deref] trait), +/// so you can call `T`'s methods on a value of type `Arc`. To avoid name +/// clashes with `T`'s methods, the methods of `Arc` itself are [associated +/// functions][assoc], called using function-like syntax: +/// +/// ``` +/// use std::sync::Arc; +/// let my_arc = Arc::new(()); +/// +/// Arc::downgrade(&my_arc); +/// ``` +/// +/// [`Weak`][weak] does not auto-dereference to `T`, because the value may have +/// already been destroyed. +/// +/// [arc]: struct.Arc.html +/// [weak]: struct.Weak.html +/// [`Rc`]: ../../std/rc/struct.Rc.html +/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone +/// [mutex]: ../../std/sync/struct.Mutex.html +/// [rwlock]: ../../std/sync/struct.RwLock.html +/// [atomic]: ../../std/sync/atomic/index.html +/// [`Send`]: ../../std/marker/trait.Send.html +/// [`Sync`]: ../../std/marker/trait.Sync.html +/// [deref]: ../../std/ops/trait.Deref.html +/// [downgrade]: struct.Arc.html#method.downgrade +/// [upgrade]: struct.Weak.html#method.upgrade +/// [`None`]: ../../std/option/enum.Option.html#variant.None +/// [assoc]: ../../book/first-edition/method-syntax.html#associated-functions +/// [`RefCell`]: ../../std/cell/struct.RefCell.html +/// [`std::sync`]: ../../std/sync/index.html +/// [`Arc::clone(&from)`]: #method.clone +/// +/// # Examples +/// +/// Sharing some immutable data between threads: +/// +// Note that we **do not** run these tests here. The windows builders get super +// unhappy if a thread outlives the main thread and then exits at the same time +// (something deadlocks) so we just avoid this entirely by not running these +// tests. +/// ```no_run +/// use std::sync::Arc; +/// use std::thread; +/// +/// let five = Arc::new(5); +/// +/// for _ in 0..10 { +/// let five = Arc::clone(&five); +/// +/// thread::spawn(move || { +/// println!("{:?}", five); +/// }); +/// } +/// ``` +/// +/// Sharing a mutable [`AtomicUsize`]: +/// +/// [`AtomicUsize`]: ../../std/sync/atomic/struct.AtomicUsize.html +/// +/// ```no_run +/// use std::sync::Arc; +/// use std::sync::atomic::{AtomicUsize, Ordering}; +/// use std::thread; +/// +/// let val = Arc::new(AtomicUsize::new(5)); +/// +/// for _ in 0..10 { +/// let val = Arc::clone(&val); +/// +/// thread::spawn(move || { +/// let v = val.fetch_add(1, Ordering::SeqCst); +/// println!("{:?}", v); +/// }); +/// } +/// ``` +/// +/// See the [`rc` documentation][rc_examples] for more examples of reference +/// counting in general. +/// +/// [rc_examples]: ../../std/rc/index.html#examples +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Arc { + ptr: NonNull>, + phantom: PhantomData, +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for Arc {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for Arc {} + +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U: ?Sized> CoerceUnsized> for Arc {} + +/// `Weak` is a version of [`Arc`] that holds a non-owning reference to the +/// managed value. The value is accessed by calling [`upgrade`] on the `Weak` +/// pointer, which returns an [`Option`]`<`[`Arc`]`>`. +/// +/// Since a `Weak` reference does not count towards ownership, it will not +/// prevent the inner value from being dropped, and `Weak` itself makes no +/// guarantees about the value still being present and may return [`None`] +/// when [`upgrade`]d. +/// +/// A `Weak` pointer is useful for keeping a temporary reference to the value +/// within [`Arc`] without extending its lifetime. It is also used to prevent +/// circular references between [`Arc`] pointers, since mutual owning references +/// would never allow either [`Arc`] to be dropped. For example, a tree could +/// have strong [`Arc`] pointers from parent nodes to children, and `Weak` +/// pointers from children back to their parents. +/// +/// The typical way to obtain a `Weak` pointer is to call [`Arc::downgrade`]. +/// +/// [`Arc`]: struct.Arc.html +/// [`Arc::downgrade`]: struct.Arc.html#method.downgrade +/// [`upgrade`]: struct.Weak.html#method.upgrade +/// [`Option`]: ../../std/option/enum.Option.html +/// [`None`]: ../../std/option/enum.Option.html#variant.None +#[stable(feature = "arc_weak", since = "1.4.0")] +pub struct Weak { + // This is a `NonNull` to allow optimizing the size of this type in enums, + // but it is not necessarily a valid pointer. + // `Weak::new` sets this to `usize::MAX` so that it doesn’t need + // to allocate space on the heap. That's not a value a real pointer + // will ever have because RcBox has alignment at least 2. + ptr: NonNull>, +} + +#[stable(feature = "arc_weak", since = "1.4.0")] +unsafe impl Send for Weak {} +#[stable(feature = "arc_weak", since = "1.4.0")] +unsafe impl Sync for Weak {} + +#[unstable(feature = "coerce_unsized", issue = "27732")] +impl, U: ?Sized> CoerceUnsized> for Weak {} + +#[stable(feature = "arc_weak", since = "1.4.0")] +impl fmt::Debug for Weak { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "(Weak)") + } +} + +struct ArcInner { + strong: atomic::AtomicUsize, + + // the value usize::MAX acts as a sentinel for temporarily "locking" the + // ability to upgrade weak pointers or downgrade strong ones; this is used + // to avoid races in `make_mut` and `get_mut`. + weak: atomic::AtomicUsize, + + data: T, +} + +unsafe impl Send for ArcInner {} +unsafe impl Sync for ArcInner {} + +impl Arc { + /// Constructs a new `Arc`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + pub fn new(data: T) -> Arc { + // Start the weak pointer count as 1 which is the weak pointer that's + // held by all the strong pointers (kinda), see std/rc.rs for more info + let x: Box<_> = box ArcInner { + strong: atomic::AtomicUsize::new(1), + weak: atomic::AtomicUsize::new(1), + data, + }; + Arc { ptr: Box::into_raw_non_null(x), phantom: PhantomData } + } + + /// Returns the contained value, if the `Arc` has exactly one strong reference. + /// + /// Otherwise, an [`Err`][result] is returned with the same `Arc` that was + /// passed in. + /// + /// This will succeed even if there are outstanding weak references. + /// + /// [result]: ../../std/result/enum.Result.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new(3); + /// assert_eq!(Arc::try_unwrap(x), Ok(3)); + /// + /// let x = Arc::new(4); + /// let _y = Arc::clone(&x); + /// assert_eq!(*Arc::try_unwrap(x).unwrap_err(), 4); + /// ``` + #[inline] + #[stable(feature = "arc_unique", since = "1.4.0")] + pub fn try_unwrap(this: Self) -> Result { + // See `drop` for why all these atomics are like this + if this.inner().strong.compare_exchange(1, 0, Release, Relaxed).is_err() { + return Err(this); + } + + atomic::fence(Acquire); + + unsafe { + let elem = ptr::read(&this.ptr.as_ref().data); + + // Make a weak pointer to clean up the implicit strong-weak reference + let _weak = Weak { ptr: this.ptr }; + mem::forget(this); + + Ok(elem) + } + } +} + +impl Arc { + /// Consumes the `Arc`, returning the wrapped pointer. + /// + /// To avoid a memory leak the pointer must be converted back to an `Arc` using + /// [`Arc::from_raw`][from_raw]. + /// + /// [from_raw]: struct.Arc.html#method.from_raw + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// assert_eq!(unsafe { *x_ptr }, 10); + /// ``` + #[stable(feature = "rc_raw", since = "1.17.0")] + pub fn into_raw(this: Self) -> *const T { + let ptr: *const T = &*this; + mem::forget(this); + ptr + } + + /// Constructs an `Arc` from a raw pointer. + /// + /// The raw pointer must have been previously returned by a call to a + /// [`Arc::into_raw`][into_raw]. + /// + /// This function is unsafe because improper use may lead to memory problems. For example, a + /// double-free may occur if the function is called twice on the same raw pointer. + /// + /// [into_raw]: struct.Arc.html#method.into_raw + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x = Arc::new(10); + /// let x_ptr = Arc::into_raw(x); + /// + /// unsafe { + /// // Convert back to an `Arc` to prevent leak. + /// let x = Arc::from_raw(x_ptr); + /// assert_eq!(*x, 10); + /// + /// // Further calls to `Arc::from_raw(x_ptr)` would be memory unsafe. + /// } + /// + /// // The memory was freed when `x` went out of scope above, so `x_ptr` is now dangling! + /// ``` + #[stable(feature = "rc_raw", since = "1.17.0")] + pub unsafe fn from_raw(ptr: *const T) -> Self { + // Align the unsized value to the end of the ArcInner. + // Because it is ?Sized, it will always be the last field in memory. + let align = align_of_val(&*ptr); + let layout = Layout::new::>(); + let offset = (layout.size() + layout.padding_needed_for(align)) as isize; + + // Reverse the offset to find the original ArcInner. + let fake_ptr = ptr as *mut ArcInner; + let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + + Arc { + ptr: NonNull::new_unchecked(arc_ptr), + phantom: PhantomData, + } + } + + /// Creates a new [`Weak`][weak] pointer to this value. + /// + /// [weak]: struct.Weak.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// let weak_five = Arc::downgrade(&five); + /// ``` + #[stable(feature = "arc_weak", since = "1.4.0")] + pub fn downgrade(this: &Self) -> Weak { + // This Relaxed is OK because we're checking the value in the CAS + // below. + let mut cur = this.inner().weak.load(Relaxed); + + loop { + // check if the weak counter is currently "locked"; if so, spin. + if cur == usize::MAX { + cur = this.inner().weak.load(Relaxed); + continue; + } + + // NOTE: this code currently ignores the possibility of overflow + // into usize::MAX; in general both Rc and Arc need to be adjusted + // to deal with overflow. + + // Unlike with Clone(), we need this to be an Acquire read to + // synchronize with the write coming from `is_unique`, so that the + // events prior to that write happen before this read. + match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) { + Ok(_) => { + // Make sure we do not create a dangling Weak + debug_assert!(!is_dangling(this.ptr)); + return Weak { ptr: this.ptr }; + } + Err(old) => cur = old, + } + } + } + + /// Gets the number of [`Weak`][weak] pointers to this value. + /// + /// [weak]: struct.Weak.html + /// + /// # Safety + /// + /// This method by itself is safe, but using it correctly requires extra care. + /// Another thread can change the weak count at any time, + /// including potentially between calling this method and acting on the result. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let _weak_five = Arc::downgrade(&five); + /// + /// // This assertion is deterministic because we haven't shared + /// // the `Arc` or `Weak` between threads. + /// assert_eq!(1, Arc::weak_count(&five)); + /// ``` + #[inline] + #[stable(feature = "arc_counts", since = "1.15.0")] + pub fn weak_count(this: &Self) -> usize { + let cnt = this.inner().weak.load(SeqCst); + // If the weak count is currently locked, the value of the + // count was 0 just before taking the lock. + if cnt == usize::MAX { 0 } else { cnt - 1 } + } + + /// Gets the number of strong (`Arc`) pointers to this value. + /// + /// # Safety + /// + /// This method by itself is safe, but using it correctly requires extra care. + /// Another thread can change the strong count at any time, + /// including potentially between calling this method and acting on the result. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let _also_five = Arc::clone(&five); + /// + /// // This assertion is deterministic because we haven't shared + /// // the `Arc` between threads. + /// assert_eq!(2, Arc::strong_count(&five)); + /// ``` + #[inline] + #[stable(feature = "arc_counts", since = "1.15.0")] + pub fn strong_count(this: &Self) -> usize { + this.inner().strong.load(SeqCst) + } + + #[inline] + fn inner(&self) -> &ArcInner { + // This unsafety is ok because while this arc is alive we're guaranteed + // that the inner pointer is valid. Furthermore, we know that the + // `ArcInner` structure itself is `Sync` because the inner data is + // `Sync` as well, so we're ok loaning out an immutable pointer to these + // contents. + unsafe { self.ptr.as_ref() } + } + + // Non-inlined part of `drop`. + #[inline(never)] + unsafe fn drop_slow(&mut self) { + // Destroy the data at this time, even though we may not free the box + // allocation itself (there may still be weak pointers lying around). + ptr::drop_in_place(&mut self.ptr.as_mut().data); + + if self.inner().weak.fetch_sub(1, Release) == 1 { + atomic::fence(Acquire); + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) + } + } + + #[inline] + #[stable(feature = "ptr_eq", since = "1.17.0")] + /// Returns true if the two `Arc`s point to the same value (not + /// just values that compare as equal). + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// let same_five = Arc::clone(&five); + /// let other_five = Arc::new(5); + /// + /// assert!(Arc::ptr_eq(&five, &same_five)); + /// assert!(!Arc::ptr_eq(&five, &other_five)); + /// ``` + pub fn ptr_eq(this: &Self, other: &Self) -> bool { + this.ptr.as_ptr() == other.ptr.as_ptr() + } +} + +impl Arc { + // Allocates an `ArcInner` with sufficient space for an unsized value + unsafe fn allocate_for_ptr(ptr: *const T) -> *mut ArcInner { + // Create a fake ArcInner to find allocation size and alignment + let fake_ptr = ptr as *mut ArcInner; + + let layout = Layout::for_value(&*fake_ptr); + + let mem = Global.alloc(layout) + .unwrap_or_else(|_| handle_alloc_error(layout)); + + // Initialize the real ArcInner + let inner = set_data_ptr(ptr as *mut T, mem.as_ptr() as *mut u8) as *mut ArcInner; + + ptr::write(&mut (*inner).strong, atomic::AtomicUsize::new(1)); + ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); + + inner + } + + fn from_box(v: Box) -> Arc { + unsafe { + let box_unique = Box::into_unique(v); + let bptr = box_unique.as_ptr(); + + let value_size = size_of_val(&*bptr); + let ptr = Self::allocate_for_ptr(bptr); + + // Copy value as bytes + ptr::copy_nonoverlapping( + bptr as *const T as *const u8, + &mut (*ptr).data as *mut _ as *mut u8, + value_size); + + // Free the allocation without dropping its contents + box_free(box_unique); + + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } + } + } +} + +// Sets the data pointer of a `?Sized` raw pointer. +// +// For a slice/trait object, this sets the `data` field and leaves the rest +// unchanged. For a sized raw pointer, this simply sets the pointer. +unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { + ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); + ptr +} + +impl Arc<[T]> { + // Copy elements from slice into newly allocated Arc<[T]> + // + // Unsafe because the caller must either take ownership or bind `T: Copy` + unsafe fn copy_from_slice(v: &[T]) -> Arc<[T]> { + let v_ptr = v as *const [T]; + let ptr = Self::allocate_for_ptr(v_ptr); + + ptr::copy_nonoverlapping( + v.as_ptr(), + &mut (*ptr).data as *mut [T] as *mut T, + v.len()); + + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } + } +} + +// Specialization trait used for From<&[T]> +trait ArcFromSlice { + fn from_slice(slice: &[T]) -> Self; +} + +impl ArcFromSlice for Arc<[T]> { + #[inline] + default fn from_slice(v: &[T]) -> Self { + // Panic guard while cloning T elements. + // In the event of a panic, elements that have been written + // into the new ArcInner will be dropped, then the memory freed. + struct Guard { + mem: NonNull, + elems: *mut T, + layout: Layout, + n_elems: usize, + } + + impl Drop for Guard { + fn drop(&mut self) { + use core::slice::from_raw_parts_mut; + + unsafe { + let slice = from_raw_parts_mut(self.elems, self.n_elems); + ptr::drop_in_place(slice); + + Global.dealloc(self.mem.cast(), self.layout.clone()); + } + } + } + + unsafe { + let v_ptr = v as *const [T]; + let ptr = Self::allocate_for_ptr(v_ptr); + + let mem = ptr as *mut _ as *mut u8; + let layout = Layout::for_value(&*ptr); + + // Pointer to first element + let elems = &mut (*ptr).data as *mut [T] as *mut T; + + let mut guard = Guard{ + mem: NonNull::new_unchecked(mem), + elems: elems, + layout: layout, + n_elems: 0, + }; + + for (i, item) in v.iter().enumerate() { + ptr::write(elems.offset(i as isize), item.clone()); + guard.n_elems += 1; + } + + // All clear. Forget the guard so it doesn't free the new ArcInner. + mem::forget(guard); + + Arc { ptr: NonNull::new_unchecked(ptr), phantom: PhantomData } + } + } +} + +impl ArcFromSlice for Arc<[T]> { + #[inline] + fn from_slice(v: &[T]) -> Self { + unsafe { Arc::copy_from_slice(v) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Arc { + /// Makes a clone of the `Arc` pointer. + /// + /// This creates another pointer to the same inner value, increasing the + /// strong reference count. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// Arc::clone(&five); + /// ``` + #[inline] + fn clone(&self) -> Arc { + // Using a relaxed ordering is alright here, as knowledge of the + // original reference prevents other threads from erroneously deleting + // the object. + // + // As explained in the [Boost documentation][1], Increasing the + // reference counter can always be done with memory_order_relaxed: New + // references to an object can only be formed from an existing + // reference, and passing an existing reference from one thread to + // another must already provide any required synchronization. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + let old_size = self.inner().strong.fetch_add(1, Relaxed); + + // However we need to guard against massive refcounts in case someone + // is `mem::forget`ing Arcs. If we don't do this the count can overflow + // and users will use-after free. We racily saturate to `isize::MAX` on + // the assumption that there aren't ~2 billion threads incrementing + // the reference count at once. This branch will never be taken in + // any realistic program. + // + // We abort because such a program is incredibly degenerate, and we + // don't care to support it. + if old_size > MAX_REFCOUNT { + unsafe { + abort(); + } + } + + Arc { ptr: self.ptr, phantom: PhantomData } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Deref for Arc { + type Target = T; + + #[inline] + fn deref(&self) -> &T { + &self.inner().data + } +} + +impl Arc { + /// Makes a mutable reference into the given `Arc`. + /// + /// If there are other `Arc` or [`Weak`][weak] pointers to the same value, + /// then `make_mut` will invoke [`clone`][clone] on the inner value to + /// ensure unique ownership. This is also referred to as clone-on-write. + /// + /// See also [`get_mut`][get_mut], which will fail rather than cloning. + /// + /// [weak]: struct.Weak.html + /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone + /// [get_mut]: struct.Arc.html#method.get_mut + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let mut data = Arc::new(5); + /// + /// *Arc::make_mut(&mut data) += 1; // Won't clone anything + /// let mut other_data = Arc::clone(&data); // Won't clone inner data + /// *Arc::make_mut(&mut data) += 1; // Clones inner data + /// *Arc::make_mut(&mut data) += 1; // Won't clone anything + /// *Arc::make_mut(&mut other_data) *= 2; // Won't clone anything + /// + /// // Now `data` and `other_data` point to different values. + /// assert_eq!(*data, 8); + /// assert_eq!(*other_data, 12); + /// ``` + #[inline] + #[stable(feature = "arc_unique", since = "1.4.0")] + pub fn make_mut(this: &mut Self) -> &mut T { + // Note that we hold both a strong reference and a weak reference. + // Thus, releasing our strong reference only will not, by itself, cause + // the memory to be deallocated. + // + // Use Acquire to ensure that we see any writes to `weak` that happen + // before release writes (i.e., decrements) to `strong`. Since we hold a + // weak count, there's no chance the ArcInner itself could be + // deallocated. + if this.inner().strong.compare_exchange(1, 0, Acquire, Relaxed).is_err() { + // Another strong pointer exists; clone + *this = Arc::new((**this).clone()); + } else if this.inner().weak.load(Relaxed) != 1 { + // Relaxed suffices in the above because this is fundamentally an + // optimization: we are always racing with weak pointers being + // dropped. Worst case, we end up allocated a new Arc unnecessarily. + + // We removed the last strong ref, but there are additional weak + // refs remaining. We'll move the contents to a new Arc, and + // invalidate the other weak refs. + + // Note that it is not possible for the read of `weak` to yield + // usize::MAX (i.e., locked), since the weak count can only be + // locked by a thread with a strong reference. + + // Materialize our own implicit weak pointer, so that it can clean + // up the ArcInner as needed. + let weak = Weak { ptr: this.ptr }; + + // mark the data itself as already deallocated + unsafe { + // there is no data race in the implicit write caused by `read` + // here (due to zeroing) because data is no longer accessed by + // other threads (due to there being no more strong refs at this + // point). + let mut swap = Arc::new(ptr::read(&weak.ptr.as_ref().data)); + mem::swap(this, &mut swap); + mem::forget(swap); + } + } else { + // We were the sole reference of either kind; bump back up the + // strong ref count. + this.inner().strong.store(1, Release); + } + + // As with `get_mut()`, the unsafety is ok because our reference was + // either unique to begin with, or became one upon cloning the contents. + unsafe { + &mut this.ptr.as_mut().data + } + } +} + +impl Arc { + /// Returns a mutable reference to the inner value, if there are + /// no other `Arc` or [`Weak`][weak] pointers to the same value. + /// + /// Returns [`None`][option] otherwise, because it is not safe to + /// mutate a shared value. + /// + /// See also [`make_mut`][make_mut], which will [`clone`][clone] + /// the inner value when it's shared. + /// + /// [weak]: struct.Weak.html + /// [option]: ../../std/option/enum.Option.html + /// [make_mut]: struct.Arc.html#method.make_mut + /// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let mut x = Arc::new(3); + /// *Arc::get_mut(&mut x).unwrap() = 4; + /// assert_eq!(*x, 4); + /// + /// let _y = Arc::clone(&x); + /// assert!(Arc::get_mut(&mut x).is_none()); + /// ``` + #[inline] + #[stable(feature = "arc_unique", since = "1.4.0")] + pub fn get_mut(this: &mut Self) -> Option<&mut T> { + if this.is_unique() { + // This unsafety is ok because we're guaranteed that the pointer + // returned is the *only* pointer that will ever be returned to T. Our + // reference count is guaranteed to be 1 at this point, and we required + // the Arc itself to be `mut`, so we're returning the only possible + // reference to the inner data. + unsafe { + Some(&mut this.ptr.as_mut().data) + } + } else { + None + } + } + + /// Determine whether this is the unique reference (including weak refs) to + /// the underlying data. + /// + /// Note that this requires locking the weak ref count. + fn is_unique(&mut self) -> bool { + // lock the weak pointer count if we appear to be the sole weak pointer + // holder. + // + // The acquire label here ensures a happens-before relationship with any + // writes to `strong` (in particular in `Weak::upgrade`) prior to decrements + // of the `weak` count (via `Weak::drop`, which uses release). If the upgraded + // weak ref was never dropped, the CAS here will fail so we do not care to synchronize. + if self.inner().weak.compare_exchange(1, usize::MAX, Acquire, Relaxed).is_ok() { + // This needs to be an `Acquire` to synchronize with the decrement of the `strong` + // counter in `drop` -- the only access that happens when any but the last reference + // is being dropped. + let unique = self.inner().strong.load(Acquire) == 1; + + // The release write here synchronizes with a read in `downgrade`, + // effectively preventing the above read of `strong` from happening + // after the write. + self.inner().weak.store(1, Release); // release the lock + unique + } else { + false + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl<#[may_dangle] T: ?Sized> Drop for Arc { + /// Drops the `Arc`. + /// + /// This will decrement the strong reference count. If the strong reference + /// count reaches zero then the only other references (if any) are + /// [`Weak`][weak], so we `drop` the inner value. + /// + /// [weak]: struct.Weak.html + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Arc::new(Foo); + /// let foo2 = Arc::clone(&foo); + /// + /// drop(foo); // Doesn't print anything + /// drop(foo2); // Prints "dropped!" + /// ``` + #[inline] + fn drop(&mut self) { + // Because `fetch_sub` is already atomic, we do not need to synchronize + // with other threads unless we are going to delete the object. This + // same logic applies to the below `fetch_sub` to the `weak` count. + if self.inner().strong.fetch_sub(1, Release) != 1 { + return; + } + + // This fence is needed to prevent reordering of use of the data and + // deletion of the data. Because it is marked `Release`, the decreasing + // of the reference count synchronizes with this `Acquire` fence. This + // means that use of the data happens before decreasing the reference + // count, which happens before this fence, which happens before the + // deletion of the data. + // + // As explained in the [Boost documentation][1], + // + // > It is important to enforce any possible access to the object in one + // > thread (through an existing reference) to *happen before* deleting + // > the object in a different thread. This is achieved by a "release" + // > operation after dropping a reference (any access to the object + // > through this reference must obviously happened before), and an + // > "acquire" operation before deleting the object. + // + // In particular, while the contents of an Arc are usually immutable, it's + // possible to have interior writes to something like a Mutex. Since a + // Mutex is not acquired when it is deleted, we can't rely on its + // synchronization logic to make writes in thread A visible to a destructor + // running in thread B. + // + // Also note that the Acquire fence here could probably be replaced with an + // Acquire load, which could improve performance in highly-contended + // situations. See [2]. + // + // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) + // [2]: (https://github.com/rust-lang/rust/pull/41714) + atomic::fence(Acquire); + + unsafe { + self.drop_slow(); + } + } +} + +impl Arc { + #[inline] + #[stable(feature = "rc_downcast", since = "1.29.0")] + /// Attempt to downcast the `Arc` to a concrete type. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// use std::sync::Arc; + /// + /// fn print_if_string(value: Arc) { + /// if let Ok(string) = value.downcast::() { + /// println!("String ({}): {}", string.len(), string); + /// } + /// } + /// + /// fn main() { + /// let my_string = "Hello World".to_string(); + /// print_if_string(Arc::new(my_string)); + /// print_if_string(Arc::new(0i8)); + /// } + /// ``` + pub fn downcast(self) -> Result, Self> + where + T: Any + Send + Sync + 'static, + { + if (*self).is::() { + let ptr = self.ptr.cast::>(); + mem::forget(self); + Ok(Arc { ptr, phantom: PhantomData }) + } else { + Err(self) + } + } +} + +impl Weak { + /// Constructs a new `Weak`, without allocating any memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::sync::Weak; + /// + /// let empty: Weak = Weak::new(); + /// assert!(empty.upgrade().is_none()); + /// ``` + #[stable(feature = "downgraded_weak", since = "1.10.0")] + pub fn new() -> Weak { + Weak { + ptr: NonNull::new(usize::MAX as *mut ArcInner).expect("MAX is not 0"), + } + } +} + +impl Weak { + /// Attempts to upgrade the `Weak` pointer to an [`Arc`], extending + /// the lifetime of the value if successful. + /// + /// Returns [`None`] if the value has since been dropped. + /// + /// [`Arc`]: struct.Arc.html + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// let weak_five = Arc::downgrade(&five); + /// + /// let strong_five: Option> = weak_five.upgrade(); + /// assert!(strong_five.is_some()); + /// + /// // Destroy all strong pointers. + /// drop(strong_five); + /// drop(five); + /// + /// assert!(weak_five.upgrade().is_none()); + /// ``` + #[stable(feature = "arc_weak", since = "1.4.0")] + pub fn upgrade(&self) -> Option> { + // We use a CAS loop to increment the strong count instead of a + // fetch_add because once the count hits 0 it must never be above 0. + let inner = self.inner()?; + + // Relaxed load because any write of 0 that we can observe + // leaves the field in a permanently zero state (so a + // "stale" read of 0 is fine), and any other value is + // confirmed via the CAS below. + let mut n = inner.strong.load(Relaxed); + + loop { + if n == 0 { + return None; + } + + // See comments in `Arc::clone` for why we do this (for `mem::forget`). + if n > MAX_REFCOUNT { + unsafe { + abort(); + } + } + + // Relaxed is valid for the same reason it is on Arc's Clone impl + match inner.strong.compare_exchange_weak(n, n + 1, Relaxed, Relaxed) { + Ok(_) => return Some(Arc { + // null checked above + ptr: self.ptr, + phantom: PhantomData, + }), + Err(old) => n = old, + } + } + } + + /// Return `None` when the pointer is dangling and there is no allocated `ArcInner`, + /// i.e. this `Weak` was created by `Weak::new` + #[inline] + fn inner(&self) -> Option<&ArcInner> { + if is_dangling(self.ptr) { + None + } else { + Some(unsafe { self.ptr.as_ref() }) + } + } +} + +#[stable(feature = "arc_weak", since = "1.4.0")] +impl Clone for Weak { + /// Makes a clone of the `Weak` pointer that points to the same value. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Weak}; + /// + /// let weak_five = Arc::downgrade(&Arc::new(5)); + /// + /// Weak::clone(&weak_five); + /// ``` + #[inline] + fn clone(&self) -> Weak { + let inner = if let Some(inner) = self.inner() { + inner + } else { + return Weak { ptr: self.ptr }; + }; + // See comments in Arc::clone() for why this is relaxed. This can use a + // fetch_add (ignoring the lock) because the weak count is only locked + // where are *no other* weak pointers in existence. (So we can't be + // running this code in that case). + let old_size = inner.weak.fetch_add(1, Relaxed); + + // See comments in Arc::clone() for why we do this (for mem::forget). + if old_size > MAX_REFCOUNT { + unsafe { + abort(); + } + } + + return Weak { ptr: self.ptr }; + } +} + +#[stable(feature = "downgraded_weak", since = "1.10.0")] +impl Default for Weak { + /// Constructs a new `Weak`, without allocating memory. + /// Calling [`upgrade`] on the return value always gives [`None`]. + /// + /// [`upgrade`]: struct.Weak.html#method.upgrade + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::sync::Weak; + /// + /// let empty: Weak = Default::default(); + /// assert!(empty.upgrade().is_none()); + /// ``` + fn default() -> Weak { + Weak::new() + } +} + +#[stable(feature = "arc_weak", since = "1.4.0")] +impl Drop for Weak { + /// Drops the `Weak` pointer. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Weak}; + /// + /// struct Foo; + /// + /// impl Drop for Foo { + /// fn drop(&mut self) { + /// println!("dropped!"); + /// } + /// } + /// + /// let foo = Arc::new(Foo); + /// let weak_foo = Arc::downgrade(&foo); + /// let other_weak_foo = Weak::clone(&weak_foo); + /// + /// drop(weak_foo); // Doesn't print anything + /// drop(foo); // Prints "dropped!" + /// + /// assert!(other_weak_foo.upgrade().is_none()); + /// ``` + fn drop(&mut self) { + // If we find out that we were the last weak pointer, then its time to + // deallocate the data entirely. See the discussion in Arc::drop() about + // the memory orderings + // + // It's not necessary to check for the locked state here, because the + // weak count can only be locked if there was precisely one weak ref, + // meaning that drop could only subsequently run ON that remaining weak + // ref, which can only happen after the lock is released. + let inner = if let Some(inner) = self.inner() { + inner + } else { + return + }; + + if inner.weak.fetch_sub(1, Release) == 1 { + atomic::fence(Acquire); + unsafe { + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())) + } + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for Arc { + /// Equality for two `Arc`s. + /// + /// Two `Arc`s are equal if their inner values are equal. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five == Arc::new(5)); + /// ``` + fn eq(&self, other: &Arc) -> bool { + *(*self) == *(*other) + } + + /// Inequality for two `Arc`s. + /// + /// Two `Arc`s are unequal if their inner values are unequal. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five != Arc::new(6)); + /// ``` + fn ne(&self, other: &Arc) -> bool { + *(*self) != *(*other) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for Arc { + /// Partial comparison for two `Arc`s. + /// + /// The two are compared by calling `partial_cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// use std::cmp::Ordering; + /// + /// let five = Arc::new(5); + /// + /// assert_eq!(Some(Ordering::Less), five.partial_cmp(&Arc::new(6))); + /// ``` + fn partial_cmp(&self, other: &Arc) -> Option { + (**self).partial_cmp(&**other) + } + + /// Less-than comparison for two `Arc`s. + /// + /// The two are compared by calling `<` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five < Arc::new(6)); + /// ``` + fn lt(&self, other: &Arc) -> bool { + *(*self) < *(*other) + } + + /// 'Less than or equal to' comparison for two `Arc`s. + /// + /// The two are compared by calling `<=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five <= Arc::new(5)); + /// ``` + fn le(&self, other: &Arc) -> bool { + *(*self) <= *(*other) + } + + /// Greater-than comparison for two `Arc`s. + /// + /// The two are compared by calling `>` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five > Arc::new(4)); + /// ``` + fn gt(&self, other: &Arc) -> bool { + *(*self) > *(*other) + } + + /// 'Greater than or equal to' comparison for two `Arc`s. + /// + /// The two are compared by calling `>=` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let five = Arc::new(5); + /// + /// assert!(five >= Arc::new(5)); + /// ``` + fn ge(&self, other: &Arc) -> bool { + *(*self) >= *(*other) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for Arc { + /// Comparison for two `Arc`s. + /// + /// The two are compared by calling `cmp()` on their inner values. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// use std::cmp::Ordering; + /// + /// let five = Arc::new(5); + /// + /// assert_eq!(Ordering::Less, five.cmp(&Arc::new(6))); + /// ``` + fn cmp(&self, other: &Arc) -> Ordering { + (**self).cmp(&**other) + } +} +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for Arc {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Arc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&**self, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Arc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&**self, f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Pointer for Arc { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Pointer::fmt(&(&**self as *const T), f) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Default for Arc { + /// Creates a new `Arc`, with the `Default` value for `T`. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Arc; + /// + /// let x: Arc = Default::default(); + /// assert_eq!(*x, 0); + /// ``` + fn default() -> Arc { + Arc::new(Default::default()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for Arc { + fn hash(&self, state: &mut H) { + (**self).hash(state) + } +} + +#[stable(feature = "from_for_ptrs", since = "1.6.0")] +impl From for Arc { + fn from(t: T) -> Self { + Arc::new(t) + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl<'a, T: Clone> From<&'a [T]> for Arc<[T]> { + #[inline] + fn from(v: &[T]) -> Arc<[T]> { + >::from_slice(v) + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl<'a> From<&'a str> for Arc { + #[inline] + fn from(v: &str) -> Arc { + let arc = Arc::<[u8]>::from(v.as_bytes()); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const str) } + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From for Arc { + #[inline] + fn from(v: String) -> Arc { + Arc::from(&v[..]) + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From> for Arc { + #[inline] + fn from(v: Box) -> Arc { + Arc::from_box(v) + } +} + +#[stable(feature = "shared_from_slice", since = "1.21.0")] +impl From> for Arc<[T]> { + #[inline] + fn from(mut v: Vec) -> Arc<[T]> { + unsafe { + let arc = Arc::copy_from_slice(&v); + + // Allow the Vec to free its memory, but not destroy its contents + v.set_len(0); + + arc + } + } +} + +#[cfg(test)] +mod tests { + use std::boxed::Box; + use std::clone::Clone; + use std::sync::mpsc::channel; + use std::mem::drop; + use std::ops::Drop; + use std::option::Option; + use std::option::Option::{None, Some}; + use std::sync::atomic; + use std::sync::atomic::Ordering::{Acquire, SeqCst}; + use std::thread; + use std::sync::Mutex; + use std::convert::From; + + use super::{Arc, Weak}; + use vec::Vec; + + struct Canary(*mut atomic::AtomicUsize); + + impl Drop for Canary { + fn drop(&mut self) { + unsafe { + match *self { + Canary(c) => { + (*c).fetch_add(1, SeqCst); + } + } + } + } + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn manually_share_arc() { + let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let arc_v = Arc::new(v); + + let (tx, rx) = channel(); + + let _t = thread::spawn(move || { + let arc_v: Arc> = rx.recv().unwrap(); + assert_eq!((*arc_v)[3], 4); + }); + + tx.send(arc_v.clone()).unwrap(); + + assert_eq!((*arc_v)[2], 3); + assert_eq!((*arc_v)[4], 5); + } + + #[test] + fn test_arc_get_mut() { + let mut x = Arc::new(3); + *Arc::get_mut(&mut x).unwrap() = 4; + assert_eq!(*x, 4); + let y = x.clone(); + assert!(Arc::get_mut(&mut x).is_none()); + drop(y); + assert!(Arc::get_mut(&mut x).is_some()); + let _w = Arc::downgrade(&x); + assert!(Arc::get_mut(&mut x).is_none()); + } + + #[test] + fn try_unwrap() { + let x = Arc::new(3); + assert_eq!(Arc::try_unwrap(x), Ok(3)); + let x = Arc::new(4); + let _y = x.clone(); + assert_eq!(Arc::try_unwrap(x), Err(Arc::new(4))); + let x = Arc::new(5); + let _w = Arc::downgrade(&x); + assert_eq!(Arc::try_unwrap(x), Ok(5)); + } + + #[test] + fn into_from_raw() { + let x = Arc::new(box "hello"); + let y = x.clone(); + + let x_ptr = Arc::into_raw(x); + drop(y); + unsafe { + assert_eq!(**x_ptr, "hello"); + + let x = Arc::from_raw(x_ptr); + assert_eq!(**x, "hello"); + + assert_eq!(Arc::try_unwrap(x).map(|x| *x), Ok("hello")); + } + } + + #[test] + fn test_into_from_raw_unsized() { + use std::fmt::Display; + use std::string::ToString; + + let arc: Arc = Arc::from("foo"); + + let ptr = Arc::into_raw(arc.clone()); + let arc2 = unsafe { Arc::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }, "foo"); + assert_eq!(arc, arc2); + + let arc: Arc = Arc::new(123); + + let ptr = Arc::into_raw(arc.clone()); + let arc2 = unsafe { Arc::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }.to_string(), "123"); + assert_eq!(arc2.to_string(), "123"); + } + + #[test] + fn test_cowarc_clone_make_mut() { + let mut cow0 = Arc::new(75); + let mut cow1 = cow0.clone(); + let mut cow2 = cow1.clone(); + + assert!(75 == *Arc::make_mut(&mut cow0)); + assert!(75 == *Arc::make_mut(&mut cow1)); + assert!(75 == *Arc::make_mut(&mut cow2)); + + *Arc::make_mut(&mut cow0) += 1; + *Arc::make_mut(&mut cow1) += 2; + *Arc::make_mut(&mut cow2) += 3; + + assert!(76 == *cow0); + assert!(77 == *cow1); + assert!(78 == *cow2); + + // none should point to the same backing memory + assert!(*cow0 != *cow1); + assert!(*cow0 != *cow2); + assert!(*cow1 != *cow2); + } + + #[test] + fn test_cowarc_clone_unique2() { + let mut cow0 = Arc::new(75); + let cow1 = cow0.clone(); + let cow2 = cow1.clone(); + + assert!(75 == *cow0); + assert!(75 == *cow1); + assert!(75 == *cow2); + + *Arc::make_mut(&mut cow0) += 1; + assert!(76 == *cow0); + assert!(75 == *cow1); + assert!(75 == *cow2); + + // cow1 and cow2 should share the same contents + // cow0 should have a unique reference + assert!(*cow0 != *cow1); + assert!(*cow0 != *cow2); + assert!(*cow1 == *cow2); + } + + #[test] + fn test_cowarc_clone_weak() { + let mut cow0 = Arc::new(75); + let cow1_weak = Arc::downgrade(&cow0); + + assert!(75 == *cow0); + assert!(75 == *cow1_weak.upgrade().unwrap()); + + *Arc::make_mut(&mut cow0) += 1; + + assert!(76 == *cow0); + assert!(cow1_weak.upgrade().is_none()); + } + + #[test] + fn test_live() { + let x = Arc::new(5); + let y = Arc::downgrade(&x); + assert!(y.upgrade().is_some()); + } + + #[test] + fn test_dead() { + let x = Arc::new(5); + let y = Arc::downgrade(&x); + drop(x); + assert!(y.upgrade().is_none()); + } + + #[test] + fn weak_self_cyclic() { + struct Cycle { + x: Mutex>>, + } + + let a = Arc::new(Cycle { x: Mutex::new(None) }); + let b = Arc::downgrade(&a.clone()); + *a.x.lock().unwrap() = Some(b); + + // hopefully we don't double-free (or leak)... + } + + #[test] + fn drop_arc() { + let mut canary = atomic::AtomicUsize::new(0); + let x = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); + drop(x); + assert!(canary.load(Acquire) == 1); + } + + #[test] + fn drop_arc_weak() { + let mut canary = atomic::AtomicUsize::new(0); + let arc = Arc::new(Canary(&mut canary as *mut atomic::AtomicUsize)); + let arc_weak = Arc::downgrade(&arc); + assert!(canary.load(Acquire) == 0); + drop(arc); + assert!(canary.load(Acquire) == 1); + drop(arc_weak); + } + + #[test] + fn test_strong_count() { + let a = Arc::new(0); + assert!(Arc::strong_count(&a) == 1); + let w = Arc::downgrade(&a); + assert!(Arc::strong_count(&a) == 1); + let b = w.upgrade().expect(""); + assert!(Arc::strong_count(&b) == 2); + assert!(Arc::strong_count(&a) == 2); + drop(w); + drop(a); + assert!(Arc::strong_count(&b) == 1); + let c = b.clone(); + assert!(Arc::strong_count(&b) == 2); + assert!(Arc::strong_count(&c) == 2); + } + + #[test] + fn test_weak_count() { + let a = Arc::new(0); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 0); + let w = Arc::downgrade(&a); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 1); + let x = w.clone(); + assert!(Arc::weak_count(&a) == 2); + drop(w); + drop(x); + assert!(Arc::strong_count(&a) == 1); + assert!(Arc::weak_count(&a) == 0); + let c = a.clone(); + assert!(Arc::strong_count(&a) == 2); + assert!(Arc::weak_count(&a) == 0); + let d = Arc::downgrade(&c); + assert!(Arc::weak_count(&c) == 1); + assert!(Arc::strong_count(&c) == 2); + + drop(a); + drop(c); + drop(d); + } + + #[test] + fn show_arc() { + let a = Arc::new(5); + assert_eq!(format!("{:?}", a), "5"); + } + + // Make sure deriving works with Arc + #[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Debug, Default)] + struct Foo { + inner: Arc, + } + + #[test] + fn test_unsized() { + let x: Arc<[i32]> = Arc::new([1, 2, 3]); + assert_eq!(format!("{:?}", x), "[1, 2, 3]"); + let y = Arc::downgrade(&x.clone()); + drop(x); + assert!(y.upgrade().is_none()); + } + + #[test] + fn test_from_owned() { + let foo = 123; + let foo_arc = Arc::from(foo); + assert!(123 == *foo_arc); + } + + #[test] + fn test_new_weak() { + let foo: Weak = Weak::new(); + assert!(foo.upgrade().is_none()); + } + + #[test] + fn test_ptr_eq() { + let five = Arc::new(5); + let same_five = five.clone(); + let other_five = Arc::new(5); + + assert!(Arc::ptr_eq(&five, &same_five)); + assert!(!Arc::ptr_eq(&five, &other_five)); + } + + #[test] + #[cfg_attr(target_os = "emscripten", ignore)] + fn test_weak_count_locked() { + let mut a = Arc::new(atomic::AtomicBool::new(false)); + let a2 = a.clone(); + let t = thread::spawn(move || { + for _i in 0..1000000 { + Arc::get_mut(&mut a); + } + a.store(true, SeqCst); + }); + + while !a2.load(SeqCst) { + let n = Arc::weak_count(&a2); + assert!(n < 2, "bad weak count: {}", n); + } + t.join().unwrap(); + } + + #[test] + fn test_from_str() { + let r: Arc = Arc::from("foo"); + + assert_eq!(&r[..], "foo"); + } + + #[test] + fn test_copy_from_slice() { + let s: &[u32] = &[1, 2, 3]; + let r: Arc<[u32]> = Arc::from(s); + + assert_eq!(&r[..], [1, 2, 3]); + } + + #[test] + fn test_clone_from_slice() { + #[derive(Clone, Debug, Eq, PartialEq)] + struct X(u32); + + let s: &[X] = &[X(1), X(2), X(3)]; + let r: Arc<[X]> = Arc::from(s); + + assert_eq!(&r[..], s); + } + + #[test] + #[should_panic] + fn test_clone_from_slice_panic() { + use std::string::{String, ToString}; + + struct Fail(u32, String); + + impl Clone for Fail { + fn clone(&self) -> Fail { + if self.0 == 2 { + panic!(); + } + Fail(self.0, self.1.clone()) + } + } + + let s: &[Fail] = &[ + Fail(0, "foo".to_string()), + Fail(1, "bar".to_string()), + Fail(2, "baz".to_string()), + ]; + + // Should panic, but not cause memory corruption + let _r: Arc<[Fail]> = Arc::from(s); + } + + #[test] + fn test_from_box() { + let b: Box = box 123; + let r: Arc = Arc::from(b); + + assert_eq!(*r, 123); + } + + #[test] + fn test_from_box_str() { + use std::string::String; + + let s = String::from("foo").into_boxed_str(); + let r: Arc = Arc::from(s); + + assert_eq!(&r[..], "foo"); + } + + #[test] + fn test_from_box_slice() { + let s = vec![1, 2, 3].into_boxed_slice(); + let r: Arc<[u32]> = Arc::from(s); + + assert_eq!(&r[..], [1, 2, 3]); + } + + #[test] + fn test_from_box_trait() { + use std::fmt::Display; + use std::string::ToString; + + let b: Box = box 123; + let r: Arc = Arc::from(b); + + assert_eq!(r.to_string(), "123"); + } + + #[test] + fn test_from_box_trait_zero_sized() { + use std::fmt::Debug; + + let b: Box = box (); + let r: Arc = Arc::from(b); + + assert_eq!(format!("{:?}", r), "()"); + } + + #[test] + fn test_from_vec() { + let v = vec![1, 2, 3]; + let r: Arc<[u32]> = Arc::from(v); + + assert_eq!(&r[..], [1, 2, 3]); + } + + #[test] + fn test_downcast() { + use std::any::Any; + + let r1: Arc = Arc::new(i32::max_value()); + let r2: Arc = Arc::new("abc"); + + assert!(r1.clone().downcast::().is_err()); + + let r1i32 = r1.downcast::(); + assert!(r1i32.is_ok()); + assert_eq!(r1i32.unwrap(), Arc::new(i32::max_value())); + + assert!(r2.clone().downcast::().is_err()); + + let r2str = r2.downcast::<&'static str>(); + assert!(r2str.is_ok()); + assert_eq!(r2str.unwrap(), Arc::new("abc")); + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl borrow::Borrow for Arc { + fn borrow(&self) -> &T { + &**self + } +} + +#[stable(since = "1.5.0", feature = "smart_ptr_as_ref")] +impl AsRef for Arc { + fn as_ref(&self) -> &T { + &**self + } +} diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs new file mode 100644 index 0000000000000..9792d52dd66d2 --- /dev/null +++ b/src/liballoc/task.rs @@ -0,0 +1,149 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Types and Traits for working with asynchronous tasks. + +pub use core::task::*; + +#[cfg(any( + all(stage0, target_has_atomic = "ptr"), + all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas") +))] +pub use self::if_arc::*; + +#[cfg(any( + all(stage0, target_has_atomic = "ptr"), + all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas") +))] +mod if_arc { + use super::*; + use core::marker::PhantomData; + use core::mem; + use core::ptr::{self, NonNull}; + use sync::Arc; + + /// A way of waking up a specific task. + /// + /// Any task executor must provide a way of signaling that a task it owns + /// is ready to be `poll`ed again. Executors do so by implementing this trait. + pub trait Wake: Send + Sync { + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake` should place + /// the associated task onto this queue. + fn wake(arc_self: &Arc); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. This function is like `wake`, but can only be called from the + /// thread on which this `Wake` was created. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place + /// the associated task onto this queue. + #[inline] + unsafe fn wake_local(arc_self: &Arc) { + Self::wake(arc_self); + } + } + + #[cfg(any( + all(stage0, target_has_atomic = "ptr"), + all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas") + ))] + struct ArcWrapped(PhantomData); + + unsafe impl UnsafeWake for ArcWrapped { + #[inline] + unsafe fn clone_raw(&self) -> Waker { + let me: *const ArcWrapped = self; + let arc = (*(&me as *const *const ArcWrapped as *const Arc)).clone(); + Waker::from(arc) + } + + #[inline] + unsafe fn drop_raw(&self) { + let mut me: *const ArcWrapped = self; + let me = &mut me as *mut *const ArcWrapped as *mut Arc; + ptr::drop_in_place(me); + } + + #[inline] + unsafe fn wake(&self) { + let me: *const ArcWrapped = self; + T::wake(&*(&me as *const *const ArcWrapped as *const Arc)) + } + + #[inline] + unsafe fn wake_local(&self) { + let me: *const ArcWrapped = self; + T::wake_local(&*(&me as *const *const ArcWrapped as *const Arc)) + } + } + + impl From> for Waker + where T: Wake + 'static, + { + fn from(rc: Arc) -> Self { + unsafe { + let ptr = mem::transmute::, NonNull>>(rc); + Waker::new(ptr) + } + } + } + + /// Creates a `LocalWaker` from a local `wake`. + /// + /// This function requires that `wake` is "local" (created on the current thread). + /// The resulting `LocalWaker` will call `wake.wake_local()` when awoken, and + /// will call `wake.wake()` if awoken after being converted to a `Waker`. + #[inline] + pub unsafe fn local_waker(wake: Arc) -> LocalWaker { + let ptr = mem::transmute::, NonNull>>(wake); + LocalWaker::new(ptr) + } + + struct NonLocalAsLocal(ArcWrapped); + + unsafe impl UnsafeWake for NonLocalAsLocal { + #[inline] + unsafe fn clone_raw(&self) -> Waker { + self.0.clone_raw() + } + + #[inline] + unsafe fn drop_raw(&self) { + self.0.drop_raw() + } + + #[inline] + unsafe fn wake(&self) { + self.0.wake() + } + + #[inline] + unsafe fn wake_local(&self) { + // Since we're nonlocal, we can't call wake_local + self.0.wake() + } + } + + /// Creates a `LocalWaker` from a non-local `wake`. + /// + /// This function is similar to `local_waker`, but does not require that `wake` + /// is local to the current thread. The resulting `LocalWaker` will call + /// `wake.wake()` when awoken. + #[inline] + pub fn local_waker_from_nonlocal(wake: Arc) -> LocalWaker { + unsafe { + let ptr = mem::transmute::, NonNull>>(wake); + LocalWaker::new(ptr) + } + } +} diff --git a/src/liballoc/tests/arc.rs b/src/liballoc/tests/arc.rs new file mode 100644 index 0000000000000..d90c22a3b1892 --- /dev/null +++ b/src/liballoc/tests/arc.rs @@ -0,0 +1,55 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::any::Any; +use std::sync::{Arc, Weak}; + +#[test] +fn uninhabited() { + enum Void {} + let mut a = Weak::::new(); + a = a.clone(); + assert!(a.upgrade().is_none()); + + let mut a: Weak = a; // Unsizing + a = a.clone(); + assert!(a.upgrade().is_none()); +} + +#[test] +fn slice() { + let a: Arc<[u32; 3]> = Arc::new([3, 2, 1]); + let a: Arc<[u32]> = a; // Unsizing + let b: Arc<[u32]> = Arc::from(&[3, 2, 1][..]); // Conversion + assert_eq!(a, b); + + // Exercise is_dangling() with a DST + let mut a = Arc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); +} + +#[test] +fn trait_object() { + let a: Arc = Arc::new(4); + let a: Arc = a; // Unsizing + + // Exercise is_dangling() with a DST + let mut a = Arc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); + + let mut b = Weak::::new(); + b = b.clone(); + assert!(b.upgrade().is_none()); + let mut b: Weak = b; // Unsizing + b = b.clone(); + assert!(b.upgrade().is_none()); +} diff --git a/src/liballoc/tests/btree/set.rs b/src/liballoc/tests/btree/set.rs index 6171b8ba624cd..0330bda5e3238 100644 --- a/src/liballoc/tests/btree/set.rs +++ b/src/liballoc/tests/btree/set.rs @@ -40,7 +40,7 @@ fn test_hash() { } fn check(a: &[i32], b: &[i32], expected: &[i32], f: F) - where F: FnOnce(&BTreeSet, &BTreeSet, &mut FnMut(&i32) -> bool) -> bool + where F: FnOnce(&BTreeSet, &BTreeSet, &mut dyn FnMut(&i32) -> bool) -> bool { let mut set_a = BTreeSet::new(); let mut set_b = BTreeSet::new(); diff --git a/src/liballoc/tests/lib.rs b/src/liballoc/tests/lib.rs index 1c8ff316e55aa..618aff963f22d 100644 --- a/src/liballoc/tests/lib.rs +++ b/src/liballoc/tests/lib.rs @@ -15,7 +15,6 @@ #![feature(const_fn)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] -#![feature(iterator_step_by)] #![feature(pattern)] #![feature(rand)] #![feature(slice_sort_by_cached_key)] @@ -25,7 +24,7 @@ #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(exact_chunks)] -#![feature(inclusive_range_methods)] +#![feature(repeat_generic_slice)] extern crate alloc_system; extern crate core; @@ -34,12 +33,14 @@ extern crate rand; use std::hash::{Hash, Hasher}; use std::collections::hash_map::DefaultHasher; +mod arc; mod binary_heap; mod btree; mod cow_str; mod fmt; mod heap; mod linked_list; +mod rc; mod slice; mod str; mod string; @@ -63,7 +64,7 @@ fn test_boxed_hasher() { 5u32.hash(&mut hasher_1); assert_eq!(ordinary_hash, hasher_1.finish()); - let mut hasher_2 = Box::new(DefaultHasher::new()) as Box; + let mut hasher_2 = Box::new(DefaultHasher::new()) as Box; 5u32.hash(&mut hasher_2); assert_eq!(ordinary_hash, hasher_2.finish()); } diff --git a/src/liballoc/tests/rc.rs b/src/liballoc/tests/rc.rs new file mode 100644 index 0000000000000..9ec7c831444d1 --- /dev/null +++ b/src/liballoc/tests/rc.rs @@ -0,0 +1,55 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::any::Any; +use std::rc::{Rc, Weak}; + +#[test] +fn uninhabited() { + enum Void {} + let mut a = Weak::::new(); + a = a.clone(); + assert!(a.upgrade().is_none()); + + let mut a: Weak = a; // Unsizing + a = a.clone(); + assert!(a.upgrade().is_none()); +} + +#[test] +fn slice() { + let a: Rc<[u32; 3]> = Rc::new([3, 2, 1]); + let a: Rc<[u32]> = a; // Unsizing + let b: Rc<[u32]> = Rc::from(&[3, 2, 1][..]); // Conversion + assert_eq!(a, b); + + // Exercise is_dangling() with a DST + let mut a = Rc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); +} + +#[test] +fn trait_object() { + let a: Rc = Rc::new(4); + let a: Rc = a; // Unsizing + + // Exercise is_dangling() with a DST + let mut a = Rc::downgrade(&a); + a = a.clone(); + assert!(a.upgrade().is_some()); + + let mut b = Weak::::new(); + b = b.clone(); + assert!(b.upgrade().is_none()); + let mut b: Weak = b; // Unsizing + b = b.clone(); + assert!(b.upgrade().is_none()); +} diff --git a/src/liballoc/tests/slice.rs b/src/liballoc/tests/slice.rs index 6fd0b33f02a60..df5e18a9a184e 100644 --- a/src/liballoc/tests/slice.rs +++ b/src/liballoc/tests/slice.rs @@ -609,6 +609,15 @@ fn test_join() { assert_eq!(v.join(&0), [1, 0, 2, 0, 3]); } +#[test] +fn test_join_nocopy() { + let v: [String; 0] = []; + assert_eq!(v.join(","), ""); + assert_eq!(["a".to_string(), "ab".into()].join(","), "a,ab"); + assert_eq!(["a".to_string(), "ab".into(), "abc".into()].join(","), "a,ab,abc"); + assert_eq!(["a".to_string(), "ab".into(), "".into()].join(","), "a,ab,"); +} + #[test] fn test_insert() { let mut a = vec![1, 2, 4]; @@ -1520,3 +1529,14 @@ fn panic_safe() { } } } + +#[test] +fn repeat_generic_slice() { + assert_eq!([1, 2].repeat(2), vec![1, 2, 1, 2]); + assert_eq!([1, 2, 3, 4].repeat(0), vec![]); + assert_eq!([1, 2, 3, 4].repeat(1), vec![1, 2, 3, 4]); + assert_eq!( + [1, 2, 3, 4].repeat(3), + vec![1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4] + ); +} diff --git a/src/liballoc/tests/str.rs b/src/liballoc/tests/str.rs index a03b61ec97e51..6275c7bb11206 100644 --- a/src/liballoc/tests/str.rs +++ b/src/liballoc/tests/str.rs @@ -162,11 +162,24 @@ fn test_join_for_different_lengths() { test_join!("-a-bc", ["", "a", "bc"], "-"); } +// join has fast paths for small separators up to 4 bytes +// this tests the slow paths. +#[test] +fn test_join_for_different_lengths_with_long_separator() { + assert_eq!("~~~~~".len(), 15); + + let empty: &[&str] = &[]; + test_join!("", empty, "~~~~~"); + test_join!("a", ["a"], "~~~~~"); + test_join!("a~~~~~b", ["a", "b"], "~~~~~"); + test_join!("~~~~~a~~~~~bc", ["", "a", "bc"], "~~~~~"); +} + #[test] fn test_unsafe_slice() { - assert_eq!("ab", unsafe {"abc".slice_unchecked(0, 2)}); - assert_eq!("bc", unsafe {"abc".slice_unchecked(1, 3)}); - assert_eq!("", unsafe {"abc".slice_unchecked(1, 1)}); + assert_eq!("ab", unsafe {"abc".get_unchecked(0..2)}); + assert_eq!("bc", unsafe {"abc".get_unchecked(1..3)}); + assert_eq!("", unsafe {"abc".get_unchecked(1..1)}); fn a_million_letter_a() -> String { let mut i = 0; let mut rs = String::new(); @@ -187,7 +200,7 @@ fn test_unsafe_slice() { } let letters = a_million_letter_a(); assert_eq!(half_a_million_letter_a(), - unsafe { letters.slice_unchecked(0, 500000)}); + unsafe { letters.get_unchecked(0..500000)}); } #[test] @@ -291,113 +304,379 @@ fn test_replace_pattern() { assert_eq!(data.replace(|c| c == 'γ', "😺😺😺"), "abcdαβ😺😺😺δabcdαβ😺😺😺δ"); } -#[test] -fn test_slice() { - assert_eq!("ab", &"abc"[0..2]); - assert_eq!("bc", &"abc"[1..3]); - assert_eq!("", &"abc"[1..1]); - assert_eq!("\u{65e5}", &"\u{65e5}\u{672c}"[0..3]); +// The current implementation of SliceIndex fails to handle methods +// orthogonally from range types; therefore, it is worth testing +// all of the indexing operations on each input. +mod slice_index { + // Test a slicing operation **that should succeed,** + // testing it on all of the indexing methods. + // + // This is not suitable for testing failure on invalid inputs. + macro_rules! assert_range_eq { + ($s:expr, $range:expr, $expected:expr) + => { + let mut s: String = $s.to_owned(); + let mut expected: String = $expected.to_owned(); + { + let s: &str = &s; + let expected: &str = &expected; + + assert_eq!(&s[$range], expected, "(in assertion for: index)"); + assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); + unsafe { + assert_eq!( + s.get_unchecked($range), expected, + "(in assertion for: get_unchecked)", + ); + } + } + { + let s: &mut str = &mut s; + let expected: &mut str = &mut expected; + + assert_eq!( + &mut s[$range], expected, + "(in assertion for: index_mut)", + ); + assert_eq!( + s.get_mut($range), Some(&mut expected[..]), + "(in assertion for: get_mut)", + ); + unsafe { + assert_eq!( + s.get_unchecked_mut($range), expected, + "(in assertion for: get_unchecked_mut)", + ); + } + } + } + } - let data = "ประเทศไทย中华"; - assert_eq!("ป", &data[0..3]); - assert_eq!("ร", &data[3..6]); - assert_eq!("", &data[3..3]); - assert_eq!("华", &data[30..33]); + // Make sure the macro can actually detect bugs, + // because if it can't, then what are we even doing here? + // + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method that panics, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "out of bounds")] + fn assert_range_eq_can_fail_by_panic() { + assert_range_eq!("abc", 0..5, "abc"); + } - fn a_million_letter_x() -> String { - let mut i = 0; - let mut rs = String::new(); - while i < 100000 { - rs.push_str("华华华华华华华华华华"); - i += 1; + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method it calls, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "==")] + fn assert_range_eq_can_fail_by_inequality() { + assert_range_eq!("abc", 0..2, "abc"); + } + + // Generates test cases for bad index operations. + // + // This generates `should_panic` test cases for Index/IndexMut + // and `None` test cases for get/get_mut. + macro_rules! panic_cases { + ($( + in mod $case_name:ident { + data: $data:expr; + + // optional: + // + // a similar input for which DATA[input] succeeds, and the corresponding + // output str. This helps validate "critical points" where an input range + // straddles the boundary between valid and invalid. + // (such as the input `len..len`, which is just barely valid) + $( + good: data[$good:expr] == $output:expr; + )* + + bad: data[$bad:expr]; + message: $expect_msg:expr; // must be a literal + } + )*) => {$( + mod $case_name { + #[test] + fn pass() { + let mut v: String = $data.into(); + + $( assert_range_eq!(v, $good, $output); )* + + { + let v: &str = &v; + assert_eq!(v.get($bad), None, "(in None assertion for get)"); + } + + { + let v: &mut str = &mut v; + assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); + } + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_fail() { + let v: String = $data.into(); + let v: &str = &v; + let _v = &v[$bad]; + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_mut_fail() { + let mut v: String = $data.into(); + let v: &mut str = &mut v; + let _v = &mut v[$bad]; + } + } + )*}; + } + + #[test] + fn simple_ascii() { + assert_range_eq!("abc", .., "abc"); + + assert_range_eq!("abc", 0..2, "ab"); + assert_range_eq!("abc", 0..=1, "ab"); + assert_range_eq!("abc", ..2, "ab"); + assert_range_eq!("abc", ..=1, "ab"); + + assert_range_eq!("abc", 1..3, "bc"); + assert_range_eq!("abc", 1..=2, "bc"); + assert_range_eq!("abc", 1..1, ""); + assert_range_eq!("abc", 1..=0, ""); + } + + #[test] + fn simple_unicode() { + // 日本 + assert_range_eq!("\u{65e5}\u{672c}", .., "\u{65e5}\u{672c}"); + + assert_range_eq!("\u{65e5}\u{672c}", 0..3, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", 0..=2, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", ..3, "\u{65e5}"); + assert_range_eq!("\u{65e5}\u{672c}", ..=2, "\u{65e5}"); + + assert_range_eq!("\u{65e5}\u{672c}", 3..6, "\u{672c}"); + assert_range_eq!("\u{65e5}\u{672c}", 3..=5, "\u{672c}"); + assert_range_eq!("\u{65e5}\u{672c}", 3.., "\u{672c}"); + + let data = "ประเทศไทย中华"; + assert_range_eq!(data, 0..3, "ป"); + assert_range_eq!(data, 3..6, "ร"); + assert_range_eq!(data, 3..3, ""); + assert_range_eq!(data, 30..33, "华"); + + /*0: 中 + 3: 华 + 6: V + 7: i + 8: ệ + 11: t + 12: + 13: N + 14: a + 15: m */ + let ss = "中华Việt Nam"; + assert_range_eq!(ss, 3..6, "华"); + assert_range_eq!(ss, 6..16, "Việt Nam"); + assert_range_eq!(ss, 6..=15, "Việt Nam"); + assert_range_eq!(ss, 6.., "Việt Nam"); + + assert_range_eq!(ss, 0..3, "中"); + assert_range_eq!(ss, 3..7, "华V"); + assert_range_eq!(ss, 3..=6, "华V"); + assert_range_eq!(ss, 3..3, ""); + assert_range_eq!(ss, 3..=2, ""); + } + + #[test] + #[cfg(not(target_arch = "asmjs"))] // hits an OOM + fn simple_big() { + fn a_million_letter_x() -> String { + let mut i = 0; + let mut rs = String::new(); + while i < 100000 { + rs.push_str("华华华华华华华华华华"); + i += 1; + } + rs } - rs + fn half_a_million_letter_x() -> String { + let mut i = 0; + let mut rs = String::new(); + while i < 100000 { + rs.push_str("华华华华华"); + i += 1; + } + rs + } + let letters = a_million_letter_x(); + assert_range_eq!(letters, 0..3 * 500000, half_a_million_letter_x()); } - fn half_a_million_letter_x() -> String { - let mut i = 0; - let mut rs = String::new(); - while i < 100000 { - rs.push_str("华华华华华"); - i += 1; + + #[test] + #[should_panic] + fn test_slice_fail() { + &"中华Việt Nam"[0..2]; + } + + panic_cases! { + in mod rangefrom_len { + data: "abcdef"; + good: data[6..] == ""; + bad: data[7..]; + message: "out of bounds"; + } + + in mod rangeto_len { + data: "abcdef"; + good: data[..6] == "abcdef"; + bad: data[..7]; + message: "out of bounds"; + } + + in mod rangetoinclusive_len { + data: "abcdef"; + good: data[..=5] == "abcdef"; + bad: data[..=6]; + message: "out of bounds"; + } + + in mod range_len_len { + data: "abcdef"; + good: data[6..6] == ""; + bad: data[7..7]; + message: "out of bounds"; + } + + in mod rangeinclusive_len_len { + data: "abcdef"; + good: data[6..=5] == ""; + bad: data[7..=6]; + message: "out of bounds"; } - rs } - let letters = a_million_letter_x(); - assert_eq!(half_a_million_letter_x(), &letters[0..3 * 500000]); -} -#[test] -fn test_slice_2() { - let ss = "中华Việt Nam"; + panic_cases! { + in mod range_neg_width { + data: "abcdef"; + good: data[4..4] == ""; + bad: data[4..3]; + message: "begin <= end (4 <= 3)"; + } - assert_eq!("华", &ss[3..6]); - assert_eq!("Việt Nam", &ss[6..16]); + in mod rangeinclusive_neg_width { + data: "abcdef"; + good: data[4..=3] == ""; + bad: data[4..=2]; + message: "begin <= end (4 <= 3)"; + } + } - assert_eq!("ab", &"abc"[0..2]); - assert_eq!("bc", &"abc"[1..3]); - assert_eq!("", &"abc"[1..1]); + mod overflow { + panic_cases! { + in mod rangeinclusive { + data: "hello"; + // note: using 0 specifically ensures that the result of overflowing is 0..0, + // so that `get` doesn't simply return None for the wrong reason. + bad: data[0..=usize::max_value()]; + message: "maximum usize"; + } - assert_eq!("中", &ss[0..3]); - assert_eq!("华V", &ss[3..7]); - assert_eq!("", &ss[3..3]); - /*0: 中 - 3: 华 - 6: V - 7: i - 8: ệ - 11: t - 12: - 13: N - 14: a - 15: m */ -} + in mod rangetoinclusive { + data: "hello"; + bad: data[..=usize::max_value()]; + message: "maximum usize"; + } + } + } -#[test] -#[should_panic] -fn test_slice_fail() { - &"中华Việt Nam"[0..2]; -} + mod boundary { + const DATA: &'static str = "abcαβγ"; + + const BAD_START: usize = 4; + const GOOD_START: usize = 3; + const BAD_END: usize = 6; + const GOOD_END: usize = 7; + const BAD_END_INCL: usize = BAD_END - 1; + const GOOD_END_INCL: usize = GOOD_END - 1; + + // it is especially important to test all of the different range types here + // because some of the logic may be duplicated as part of micro-optimizations + // to dodge unicode boundary checks on half-ranges. + panic_cases! { + in mod range_1 { + data: super::DATA; + bad: data[super::BAD_START..super::GOOD_END]; + message: + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + } -#[test] -#[should_panic] -fn test_str_slice_rangetoinclusive_max_panics() { - &"hello"[..=usize::max_value()]; -} + in mod range_2 { + data: super::DATA; + bad: data[super::GOOD_START..super::BAD_END]; + message: + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + } -#[test] -#[should_panic] -fn test_str_slice_rangeinclusive_max_panics() { - &"hello"[1..=usize::max_value()]; -} + in mod rangefrom { + data: super::DATA; + bad: data[super::BAD_START..]; + message: + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + } -#[test] -#[should_panic] -fn test_str_slicemut_rangetoinclusive_max_panics() { - let mut s = "hello".to_owned(); - let s: &mut str = &mut s; - &mut s[..=usize::max_value()]; -} + in mod rangeto { + data: super::DATA; + bad: data[..super::BAD_END]; + message: + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + } -#[test] -#[should_panic] -fn test_str_slicemut_rangeinclusive_max_panics() { - let mut s = "hello".to_owned(); - let s: &mut str = &mut s; - &mut s[1..=usize::max_value()]; -} + in mod rangeinclusive_1 { + data: super::DATA; + bad: data[super::BAD_START..=super::GOOD_END_INCL]; + message: + "byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of"; + } -#[test] -fn test_str_get_maxinclusive() { - let mut s = "hello".to_owned(); - { - let s: &str = &s; - assert_eq!(s.get(..=usize::max_value()), None); - assert_eq!(s.get(1..=usize::max_value()), None); + in mod rangeinclusive_2 { + data: super::DATA; + bad: data[super::GOOD_START..=super::BAD_END_INCL]; + message: + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + } + + in mod rangetoinclusive { + data: super::DATA; + bad: data[..=super::BAD_END_INCL]; + message: + "byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of"; + } + } } - { - let s: &mut str = &mut s; - assert_eq!(s.get(..=usize::max_value()), None); - assert_eq!(s.get(1..=usize::max_value()), None); + + const LOREM_PARAGRAPH: &'static str = "\ + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem \ + sit amet dolor ultricies condimentum. Praesent iaculis purus elit, ac malesuada \ + quam malesuada in. Duis sed orci eros. Suspendisse sit amet magna mollis, mollis \ + nunc luctus, imperdiet mi. Integer fringilla non sem ut lacinia. Fusce varius \ + tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec tempus vel, \ + gravida nec quam."; + + // check the panic includes the prefix of the sliced string + #[test] + #[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")] + fn test_slice_fail_truncated_1() { + &LOREM_PARAGRAPH[..1024]; + } + // check the truncation in the panic message + #[test] + #[should_panic(expected="luctus, im`[...]")] + fn test_slice_fail_truncated_2() { + &LOREM_PARAGRAPH[..1024]; } } @@ -446,50 +725,6 @@ fn test_is_char_boundary() { } } } -const LOREM_PARAGRAPH: &'static str = "\ -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse quis lorem sit amet dolor \ -ultricies condimentum. Praesent iaculis purus elit, ac malesuada quam malesuada in. Duis sed orci \ -eros. Suspendisse sit amet magna mollis, mollis nunc luctus, imperdiet mi. Integer fringilla non \ -sem ut lacinia. Fusce varius tortor a risus porttitor hendrerit. Morbi mauris dui, ultricies nec \ -tempus vel, gravida nec quam."; - -// check the panic includes the prefix of the sliced string -#[test] -#[should_panic(expected="byte index 1024 is out of bounds of `Lorem ipsum dolor sit amet")] -fn test_slice_fail_truncated_1() { - &LOREM_PARAGRAPH[..1024]; -} -// check the truncation in the panic message -#[test] -#[should_panic(expected="luctus, im`[...]")] -fn test_slice_fail_truncated_2() { - &LOREM_PARAGRAPH[..1024]; -} - -#[test] -#[should_panic(expected="byte index 4 is not a char boundary; it is inside 'α' (bytes 3..5) of")] -fn test_slice_fail_boundary_1() { - &"abcαβγ"[4..]; -} - -#[test] -#[should_panic(expected="byte index 6 is not a char boundary; it is inside 'β' (bytes 5..7) of")] -fn test_slice_fail_boundary_2() { - &"abcαβγ"[2..6]; -} - -#[test] -fn test_slice_from() { - assert_eq!(&"abcd"[0..], "abcd"); - assert_eq!(&"abcd"[2..], "cd"); - assert_eq!(&"abcd"[4..], ""); -} -#[test] -fn test_slice_to() { - assert_eq!(&"abcd"[..0], ""); - assert_eq!(&"abcd"[..2], "ab"); - assert_eq!(&"abcd"[..4], "abcd"); -} #[test] fn test_trim_left_matches() { @@ -767,6 +1002,12 @@ fn test_escape_unicode() { #[test] fn test_escape_debug() { + // Note that there are subtleties with the number of backslashes + // on the left- and right-hand sides. In particular, Unicode code points + // are usually escaped with two backslashes on the right-hand side, as + // they are escaped. However, when the character is unescaped (e.g. for + // printable characters), only a single backslash appears (as the character + // itself appears in the debug string). assert_eq!("abc".escape_debug(), "abc"); assert_eq!("a c".escape_debug(), "a c"); assert_eq!("éèê".escape_debug(), "éèê"); @@ -777,6 +1018,7 @@ fn test_escape_debug() { assert_eq!("\u{10000}\u{10ffff}".escape_debug(), "\u{10000}\\u{10ffff}"); assert_eq!("ab\u{200b}".escape_debug(), "ab\\u{200b}"); assert_eq!("\u{10d4ea}\r".escape_debug(), "\\u{10d4ea}\\r"); + assert_eq!("\u{301}a\u{301}bé\u{e000}".escape_debug(), "\\u{301}a\u{301}bé\\u{e000}"); } #[test] @@ -1084,6 +1326,7 @@ fn test_str_default() { t::<&str>(); t::(); + t::<&mut str>(); } #[test] diff --git a/src/liballoc/vec.rs b/src/liballoc/vec.rs index 35d0a69a05abe..5efe1e23309a7 100644 --- a/src/liballoc/vec.rs +++ b/src/liballoc/vec.rs @@ -73,9 +73,6 @@ use core::intrinsics::{arith_offset, assume}; use core::iter::{FromIterator, FusedIterator, TrustedLen}; use core::marker::PhantomData; use core::mem; -#[cfg(not(test))] -#[cfg(stage0)] -use core::num::Float; use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, IndexMut, RangeBounds}; use core::ops; @@ -83,7 +80,7 @@ use core::ptr; use core::ptr::NonNull; use core::slice; -use alloc::CollectionAllocErr; +use collections::CollectionAllocErr; use borrow::ToOwned; use borrow::Cow; use boxed::Box; @@ -812,9 +809,15 @@ impl Vec { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap_remove(&mut self, index: usize) -> T { - let length = self.len(); - self.swap(index, length - 1); - self.pop().unwrap() + unsafe { + // We replace self[index] with the last element. Note that if the + // bounds check on hole succeeds there must be a last element (which + // can be self[index] itself). + let hole: *mut T = &mut self[index]; + let last = ptr::read(self.get_unchecked(self.len - 1)); + self.len -= 1; + ptr::replace(hole, last) + } } /// Inserts an element at position `index` within the vector, shifting all @@ -840,7 +843,7 @@ impl Vec { // space for the new element if len == self.buf.cap() { - self.buf.double(); + self.reserve(1); } unsafe { @@ -1060,7 +1063,7 @@ impl Vec { // This will panic or abort if we would allocate > isize::MAX bytes // or if the length increment would overflow for zero-sized types. if self.len == self.buf.cap() { - self.buf.double(); + self.reserve(1); } unsafe { let end = self.as_mut_ptr().offset(self.len as isize); @@ -1169,12 +1172,12 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, @@ -1696,7 +1699,10 @@ impl Hash for Vec { } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] +#[rustc_on_unimplemented( + message="vector indices are of type `usize` or ranges of `usize`", + label="vector indices are of type `usize` or ranges of `usize`", +)] impl Index for Vec where I: ::core::slice::SliceIndex<[T]>, @@ -1710,7 +1716,10 @@ where } #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "vector indices are of type `usize` or ranges of `usize`"] +#[rustc_on_unimplemented( + message="vector indices are of type `usize` or ranges of `usize`", + label="vector indices are of type `usize` or ranges of `usize`", +)] impl IndexMut for Vec where I: ::core::slice::SliceIndex<[T]>, @@ -2286,6 +2295,13 @@ impl<'a, T: Clone> From> for Cow<'a, [T]> { } } +#[stable(feature = "cow_from_vec_ref", since = "1.28.0")] +impl<'a, T: Clone> From<&'a Vec> for Cow<'a, [T]> { + fn from(v: &'a Vec) -> Cow<'a, [T]> { + Cow::Borrowed(v.as_slice()) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> FromIterator for Cow<'a, [T]> where T: Clone { fn from_iter>(it: I) -> Cow<'a, [T]> { @@ -2533,9 +2549,11 @@ impl<'a, T> Drop for Drain<'a, T> { // memmove back untouched tail, update to new length let start = source_vec.len(); let tail = self.tail_start; - let src = source_vec.as_ptr().offset(tail as isize); - let dst = source_vec.as_mut_ptr().offset(start as isize); - ptr::copy(src, dst, self.tail_len); + if tail != start { + let src = source_vec.as_ptr().offset(tail as isize); + let dst = source_vec.as_mut_ptr().offset(start as isize); + ptr::copy(src, dst, self.tail_len); + } source_vec.set_len(start + self.tail_len); } } diff --git a/src/liballoc_jemalloc/lib.rs b/src/liballoc_jemalloc/lib.rs index 4b8755877de4b..b3b20715511a7 100644 --- a/src/liballoc_jemalloc/lib.rs +++ b/src/liballoc_jemalloc/lib.rs @@ -11,9 +11,8 @@ #![no_std] #![allow(unused_attributes)] #![unstable(feature = "alloc_jemalloc", - reason = "this library is unlikely to be stabilized in its current \ - form or name", - issue = "27783")] + reason = "implementation detail of std, does not provide any public API", + issue = "0")] #![feature(core_intrinsics)] #![feature(libc)] #![feature(linkage)] @@ -97,13 +96,6 @@ mod contents { ptr } - #[cfg(stage0)] - #[no_mangle] - #[rustc_std_internal_symbol] - pub unsafe extern fn __rde_oom() -> ! { - ::core::intrinsics::abort(); - } - #[no_mangle] #[rustc_std_internal_symbol] pub unsafe extern fn __rde_dealloc(ptr: *mut u8, diff --git a/src/liballoc_system/lib.rs b/src/liballoc_system/lib.rs index 7376ac0f15dd0..64348e05de7db 100644 --- a/src/liballoc_system/lib.rs +++ b/src/liballoc_system/lib.rs @@ -14,7 +14,6 @@ reason = "this library is unlikely to be stabilized in its current \ form or name", issue = "32838")] -#![feature(global_allocator)] #![feature(allocator_api)] #![feature(core_intrinsics)] #![feature(staged_api)] @@ -41,81 +40,78 @@ const MIN_ALIGN: usize = 8; #[allow(dead_code)] const MIN_ALIGN: usize = 16; -use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout, Opaque}; +use core::alloc::{Alloc, GlobalAlloc, AllocErr, Layout}; use core::ptr::NonNull; -#[unstable(feature = "allocator_api", issue = "32838")] +/// The default memory allocator provided by the operating system. +/// +/// This is based on `malloc` on Unix platforms and `HeapAlloc` on Windows, +/// plus related functions. +/// +/// This type can be used in a `static` item +/// with the `#[global_allocator]` attribute +/// to force the global allocator to be the system’s one. +/// (The default is jemalloc for executables, on some platforms.) +/// +/// ```rust +/// use std::alloc::System; +/// +/// #[global_allocator] +/// static A: System = System; +/// +/// fn main() { +/// let a = Box::new(4); // Allocates from the system allocator. +/// println!("{}", a); +/// } +/// ``` +/// +/// It can also be used directly to allocate memory +/// independently of the standard library’s global allocator. +#[stable(feature = "alloc_system_type", since = "1.28.0")] pub struct System; #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl Alloc for System { #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { NonNull::new(GlobalAlloc::alloc_zeroed(self, layout)).ok_or(AllocErr) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } #[inline] unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { NonNull::new(GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) } } -#[cfg(stage0)] -#[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl<'a> Alloc for &'a System { - #[inline] - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc(*self, layout)).ok_or(AllocErr) - } - - #[inline] - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::alloc_zeroed(*self, layout)).ok_or(AllocErr) - } - - #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { - GlobalAlloc::dealloc(*self, ptr.as_ptr(), layout) - } - - #[inline] - unsafe fn realloc(&mut self, - ptr: NonNull, - layout: Layout, - new_size: usize) -> Result, AllocErr> { - NonNull::new(GlobalAlloc::realloc(*self, ptr.as_ptr(), layout, new_size)).ok_or(AllocErr) - } -} - #[cfg(any(windows, unix, target_os = "cloudabi", target_os = "redox"))] mod realloc_fallback { - use core::alloc::{GlobalAlloc, Opaque, Layout}; + use core::alloc::{GlobalAlloc, Layout}; use core::cmp; use core::ptr; impl super::System { - pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut Opaque, old_layout: Layout, - new_size: usize) -> *mut Opaque { + pub(crate) unsafe fn realloc_fallback(&self, ptr: *mut u8, old_layout: Layout, + new_size: usize) -> *mut u8 { // Docs for GlobalAlloc::realloc require this to be valid: let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align()); let new_ptr = GlobalAlloc::alloc(self, new_layout); if !new_ptr.is_null() { let size = cmp::min(old_layout.size(), new_size); - ptr::copy_nonoverlapping(ptr as *mut u8, new_ptr as *mut u8, size); + ptr::copy_nonoverlapping(ptr, new_ptr, size); GlobalAlloc::dealloc(self, ptr, old_layout); } new_ptr @@ -131,21 +127,19 @@ mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Layout, Opaque}; + use core::alloc::{GlobalAlloc, Layout}; - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::malloc(layout.size()) as *mut Opaque + libc::malloc(layout.size()) as *mut u8 } else { #[cfg(target_os = "macos")] { if layout.align() > (1 << 31) { - // FIXME: use Opaque::null_mut - // https://github.com/rust-lang/rust/issues/49659 - return 0 as *mut Opaque + return ptr::null_mut() } } aligned_malloc(&layout) @@ -153,27 +147,27 @@ mod platform { } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { - libc::calloc(layout.size(), 1) as *mut Opaque + libc::calloc(layout.size(), 1) as *mut u8 } else { let ptr = self.alloc(layout.clone()); if !ptr.is_null() { - ptr::write_bytes(ptr as *mut u8, 0, layout.size()); + ptr::write_bytes(ptr, 0, layout.size()); } ptr } } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, _layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) { libc::free(ptr as *mut libc::c_void) } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN && layout.align() <= new_size { - libc::realloc(ptr as *mut libc::c_void, new_size) as *mut Opaque + libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8 } else { self.realloc_fallback(ptr, layout, new_size) } @@ -182,7 +176,7 @@ mod platform { #[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { // On android we currently target API level 9 which unfortunately // doesn't have the `posix_memalign` API used below. Instead we use // `memalign`, but this unfortunately has the property on some systems @@ -200,19 +194,18 @@ mod platform { // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579 // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/ // /memory/aligned_memory.cc - libc::memalign(layout.align(), layout.size()) as *mut Opaque + libc::memalign(layout.align(), layout.size()) as *mut u8 } #[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] #[inline] - unsafe fn aligned_malloc(layout: &Layout) -> *mut Opaque { + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { let mut out = ptr::null_mut(); let ret = libc::posix_memalign(&mut out, layout.align(), layout.size()); if ret != 0 { - // FIXME: use Opaque::null_mut https://github.com/rust-lang/rust/issues/49659 - 0 as *mut Opaque + ptr::null_mut() } else { - out as *mut Opaque + out as *mut u8 } } } @@ -222,7 +215,7 @@ mod platform { mod platform { use MIN_ALIGN; use System; - use core::alloc::{GlobalAlloc, Opaque, Layout}; + use core::alloc::{GlobalAlloc, Layout}; type LPVOID = *mut u8; type HANDLE = LPVOID; @@ -254,7 +247,7 @@ mod platform { } #[inline] - unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut Opaque { + unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 { let ptr = if layout.align() <= MIN_ALIGN { HeapAlloc(GetProcessHeap(), flags, layout.size()) } else { @@ -266,29 +259,29 @@ mod platform { align_ptr(ptr, layout.align()) } }; - ptr as *mut Opaque + ptr as *mut u8 } - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { allocate_with_flags(layout, 0) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { allocate_with_flags(layout, HEAP_ZERO_MEMORY) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { if layout.align() <= MIN_ALIGN { let err = HeapFree(GetProcessHeap(), 0, ptr as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); } else { - let header = get_header(ptr as *mut u8); + let header = get_header(ptr); let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID); debug_assert!(err != 0, "Failed to free heap memory: {}", GetLastError()); @@ -296,9 +289,9 @@ mod platform { } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { if layout.align() <= MIN_ALIGN { - HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut Opaque + HeapReAlloc(GetProcessHeap(), 0, ptr as LPVOID, new_size) as *mut u8 } else { self.realloc_fallback(ptr, layout, new_size) } @@ -327,32 +320,32 @@ mod platform { mod platform { extern crate dlmalloc; - use core::alloc::{GlobalAlloc, Layout, Opaque}; + use core::alloc::{GlobalAlloc, Layout}; use System; // No need for synchronization here as wasm is currently single-threaded static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::DLMALLOC_INIT; - #[unstable(feature = "allocator_api", issue = "32838")] + #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque { - DLMALLOC.malloc(layout.size(), layout.align()) as *mut Opaque + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + DLMALLOC.malloc(layout.size(), layout.align()) } #[inline] - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { - DLMALLOC.calloc(layout.size(), layout.align()) as *mut Opaque + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { + DLMALLOC.calloc(layout.size(), layout.align()) } #[inline] - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout) { - DLMALLOC.free(ptr as *mut u8, layout.size(), layout.align()) + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + DLMALLOC.free(ptr, layout.size(), layout.align()) } #[inline] - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { - DLMALLOC.realloc(ptr as *mut u8, layout.size(), layout.align(), new_size) as *mut Opaque + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { + DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) } } } diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index c79e0e14e3d8b..0f4a5d16e1759 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -26,7 +26,7 @@ #![feature(alloc)] #![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![cfg_attr(stage0, feature(generic_param_attrs))] +#![feature(raw_vec_internals)] #![cfg_attr(test, feature(test))] #![allow(deprecated)] @@ -315,8 +315,7 @@ impl DroplessArena { false } - fn align_for(&self) { - let align = mem::align_of::(); + fn align(&self, align: usize) { let final_address = ((self.ptr.get() as usize) + align - 1) & !(align - 1); self.ptr.set(final_address as *mut u8); assert!(self.ptr <= self.end); @@ -324,8 +323,7 @@ impl DroplessArena { #[inline(never)] #[cold] - fn grow(&self, n: usize) { - let needed_bytes = n * mem::size_of::(); + fn grow(&self, needed_bytes: usize) { unsafe { let mut chunks = self.chunks.borrow_mut(); let (chunk, mut new_capacity); @@ -357,25 +355,38 @@ impl DroplessArena { } #[inline] - pub fn alloc(&self, object: T) -> &mut T { + pub fn alloc_raw(&self, bytes: usize, align: usize) -> &mut [u8] { unsafe { - assert!(!mem::needs_drop::()); - assert!(mem::size_of::() != 0); + assert!(bytes != 0); + + self.align(align); - self.align_for::(); - let future_end = intrinsics::arith_offset(self.ptr.get(), mem::size_of::() as isize); + let future_end = intrinsics::arith_offset(self.ptr.get(), bytes as isize); if (future_end as *mut u8) >= self.end.get() { - self.grow::(1) + self.grow(bytes); } let ptr = self.ptr.get(); // Set the pointer past ourselves self.ptr.set( - intrinsics::arith_offset(self.ptr.get(), mem::size_of::() as isize) as *mut u8, + intrinsics::arith_offset(self.ptr.get(), bytes as isize) as *mut u8, ); + slice::from_raw_parts_mut(ptr, bytes) + } + } + + #[inline] + pub fn alloc(&self, object: T) -> &mut T { + assert!(!mem::needs_drop::()); + + let mem = self.alloc_raw( + mem::size_of::(), + mem::align_of::()) as *mut _ as *mut T; + + unsafe { // Write into uninitialized memory. - ptr::write(ptr as *mut T, object); - &mut *(ptr as *mut T) + ptr::write(mem, object); + &mut *mem } } @@ -394,21 +405,13 @@ impl DroplessArena { assert!(!mem::needs_drop::()); assert!(mem::size_of::() != 0); assert!(slice.len() != 0); - self.align_for::(); - let future_end = unsafe { - intrinsics::arith_offset(self.ptr.get(), (slice.len() * mem::size_of::()) as isize) - }; - if (future_end as *mut u8) >= self.end.get() { - self.grow::(slice.len()); - } + let mem = self.alloc_raw( + slice.len() * mem::size_of::(), + mem::align_of::()) as *mut _ as *mut T; unsafe { - let arena_slice = slice::from_raw_parts_mut(self.ptr.get() as *mut T, slice.len()); - self.ptr.set(intrinsics::arith_offset( - self.ptr.get(), - (slice.len() * mem::size_of::()) as isize, - ) as *mut u8); + let arena_slice = slice::from_raw_parts_mut(mem, slice.len()); arena_slice.copy_from_slice(slice); arena_slice } @@ -465,6 +468,12 @@ impl SyncDroplessArena { self.lock.lock().in_arena(ptr) } + #[inline(always)] + pub fn alloc_raw(&self, bytes: usize, align: usize) -> &mut [u8] { + // Extend the lifetime of the result since it's limited to the lock guard + unsafe { &mut *(self.lock.lock().alloc_raw(bytes, align) as *mut [u8]) } + } + #[inline(always)] pub fn alloc(&self, object: T) -> &mut T { // Extend the lifetime of the result since it's limited to the lock guard diff --git a/src/libbacktrace b/src/libbacktrace new file mode 160000 index 0000000000000..f4d02bbdbf8a2 --- /dev/null +++ b/src/libbacktrace @@ -0,0 +1 @@ +Subproject commit f4d02bbdbf8a2c5a31f0801dfef597a86caad9e3 diff --git a/src/libbacktrace/ChangeLog b/src/libbacktrace/ChangeLog deleted file mode 100644 index acc07047f6729..0000000000000 --- a/src/libbacktrace/ChangeLog +++ /dev/null @@ -1,590 +0,0 @@ -2016-05-18 Uros Bizjak - - PR target/71161 - * elf.c (phdr_callback) [__i386__]: Add - __attribute__((__force_align_arg_pointer__)). - -2016-03-02 Maxim Ostapenko - - * elf.c (backtrace_initialize): Properly initialize elf_fileline_fn to - avoid possible crash. - (elf_add): Don't set *fileline_fn to elf_nodebug value in case of - missing debug info anymore. - -2016-02-06 John David Anglin - - * mmap.c (MAP_FAILED): Define if not defined. - -2016-01-04 Jakub Jelinek - - Update copyright years. - -2015-12-18 Andris Pavenis - - * configure.ac: Specify that DJGPP do not have mmap - even when sys/mman.h exists. - * configure: Regenerate - -2015-12-09 John David Anglin - - PR libgfortran/68115 - * configure.ac: Set libbacktrace_cv_sys_sync to no on hppa*-*-hpux*. - * configure: Regenerate. - * elf.c (backtrace_initialize): Cast __sync_bool_compare_and_swap call - to void. - -2015-09-17 Ian Lance Taylor - - * posix.c (backtrace_open): Cast second argument of open() to int. - -2015-09-11 Ian Lance Taylor - - * Makefile.am (backtrace.lo): Depend on internal.h. - (sort.lo, stest.lo): Add explicit dependencies. - * Makefile.in: Rebuild. - -2015-09-09 Hans-Peter Nilsson - - * backtrace.c: #include . - -2015-09-08 Ian Lance Taylor - - PR other/67457 - * backtrace.c: #include "internal.h". - (struct backtrace_data): Add can_alloc field. - (unwind): If can_alloc is false, don't try to get file/line - information. - (backtrace_full): Set can_alloc field in bdata. - * alloc.c (backtrace_alloc): Don't call error_callback if it is - NULL. - * mmap.c (backtrace_alloc): Likewise. - * internal.h: Update comments for backtrace_alloc and - backtrace_free. - -2015-09-08 Ian Lance Taylor - - PR other/67457 - * mmap.c (backtrace_alloc): Correct test for mmap failure. - -2015-08-31 Ulrich Weigand - - * configure.ac: For spu-*-* targets, set have_fcntl to no. - * configure: Regenerate. - -2015-08-27 Ulrich Weigand - - * configure.ac: Remove [disable-shared] argument to LT_INIT. - Remove setting PIC_FLAG when building as target library. - * configure: Regenerate. - -2015-08-26 Hans-Peter Nilsson - - * configure.ac: Only compile with -fPIC if the target - supports it. - * configure: Regenerate. - -2015-08-24 Ulrich Weigand - - * configure.ac: Set have_mmap to no on spu-*-* targets. - * configure: Regenerate. - -2015-08-13 Ian Lance Taylor - - * dwarf.c (read_function_entry): Add vec_inlined parameter. - Change all callers. - -2015-06-11 Martin Sebor - - PR sanitizer/65479 - * dwarf.c (struct line): Add new field idx. - (line_compare): Use it. - (add_line): Set it. - (read_line_info): Reset it. - -2015-05-29 Tristan Gingold - - * pecoff.c: New file. - * Makefile.am (FORMAT_FILES): Add pecoff.c and dependencies. - * Makefile.in: Regenerate. - * filetype.awk: Detect pecoff. - * configure.ac: Define BACKTRACE_SUPPORTS_DATA on elf platforms. - Add pecoff. - * btest.c (test5): Test enabled only if BACKTRACE_SUPPORTS_DATA is - true. - * backtrace-supported.h.in (BACKTRACE_SUPPORTS_DATA): Define. - * configure: Regenerate. - * pecoff.c: New file. - -2015-05-13 Michael Haubenwallner - - * Makefile.in: Regenerated with automake-1.11.6. - * aclocal.m4: Likewise. - * configure: Likewise. - -2015-01-24 Matthias Klose - - * configure.ac: Move AM_ENABLE_MULTILIB before AC_PROG_CC. - * configure: Regenerate. - -2015-01-05 Jakub Jelinek - - Update copyright years. - -2014-11-21 H.J. Lu - - PR bootstrap/63784 - * configure: Regenerated. - -2014-11-11 David Malcolm - - * ChangeLog.jit: New. - -2014-11-11 Francois-Xavier Coudert - - PR target/63610 - * configure: Regenerate. - -2014-10-23 Ian Lance Taylor - - * internal.h (backtrace_atomic_load_pointer) [no atomic or sync]: - Fix to return void *. - -2014-05-08 Ian Lance Taylor - - * mmap.c (backtrace_free): If freeing a large aligned block of - memory, call munmap rather than holding onto it. - (backtrace_vector_grow): When growing a vector, double the number - of pages requested. When releasing the old version of a grown - vector, pass the correct size to backtrace_free. - -2014-03-07 Ian Lance Taylor - - * sort.c (backtrace_qsort): Use middle element as pivot. - -2014-03-06 Ian Lance Taylor - - * sort.c: New file. - * stest.c: New file. - * internal.h (backtrace_qsort): Declare. - * dwarf.c (read_abbrevs): Call backtrace_qsort instead of qsort. - (read_line_info, read_function_entry): Likewise. - (read_function_info, build_dwarf_data): Likewise. - * elf.c (elf_initialize_syminfo): Likewise. - * Makefile.am (libbacktrace_la_SOURCES): Add sort.c. - (stest_SOURCES, stest_LDADD): Define. - (check_PROGRAMS): Add stest. - -2014-02-07 Misty De Meo - - PR target/58710 - * configure.ac: Use AC_LINK_IFELSE in check for - _Unwind_GetIPInfo. - * configure: Regenerate. - -2014-01-02 Richard Sandiford - - Update copyright years - -2013-12-06 Jakub Jelinek - - * elf.c (ET_DYN): Undefine and define again. - (elf_add): Add exe argument, if true and ehdr.e_type is ET_DYN, - return early -1 without closing the descriptor. - (struct phdr_data): Add exe_descriptor. - (phdr_callback): If pd->exe_descriptor is not -1, for very first - call if dlpi_name is NULL just call elf_add with the exe_descriptor, - otherwise backtrace_close the exe_descriptor if not -1. Adjust - call to elf_add. - (backtrace_initialize): Adjust call to elf_add. If it returns - -1, set pd.exe_descriptor to descriptor, otherwise set it to -1. - -2013-12-05 Ian Lance Taylor - - * alloc.c (backtrace_vector_finish): Add error_callback and data - parameters. Call backtrace_vector_release. Return address base. - * mmap.c (backtrace_vector_finish): Add error_callback and data - parameters. Return address base. - * dwarf.c (read_function_info): Get new address base from - backtrace_vector_finish. - * internal.h (backtrace_vector_finish): Update declaration. - -2013-11-27 Ian Lance Taylor - - * dwarf.c (find_address_ranges): New static function, broken out - of build_address_map. - (build_address_map): Call it. - * btest.c (check): Check for missing filename or function, rather - than crashing. - (f3): Check that enough frames were returned. - -2013-11-19 Jakub Jelinek - - * backtrace.h (backtrace_syminfo_callback): Add symsize argument. - * elf.c (elf_syminfo): Pass 0 or sym->size to the callback as - last argument. - * btest.c (struct symdata): Add size field. - (callback_three): Add symsize argument. Copy it to the data->size - field. - (f23): Set symdata.size to 0. - (test5): Likewise. If sizeof (int) > 1, lookup address of - ((uintptr_t) &global) + 1. Verify symdata.val and symdata.size - values. - - * atomic.c: Include sys/types.h. - -2013-11-18 Ian Lance Taylor - - * configure.ac: Check for support of __atomic extensions. - * internal.h: Declare or #define atomic functions for use in - backtrace code. - * atomic.c: New file. - * dwarf.c (dwarf_lookup_pc): Use atomic functions. - (dwarf_fileline, backtrace_dwarf_add): Likewise. - * elf.c (elf_add_syminfo_data, elf_syminfo): Likewise. - (backtrace_initialize): Likewise. - * fileline.c (fileline_initialize): Likewise. - * Makefile.am (libbacktrace_la_SOURCES): Add atomic.c. - * configure, config.h.in, Makefile.in: Rebuild. - -2013-11-18 Jakub Jelinek - - * elf.c (SHN_UNDEF): Define. - (elf_initialize_syminfo): Add base_address argument. Ignore symbols - with st_shndx == SHN_UNDEF. Add base_address to address fields. - (elf_add): Adjust caller. - - * elf.c (phdr_callback): Process info->dlpi_addr == 0 normally. - -2013-11-16 Ian Lance Taylor - - * backtrace.h (backtrace_create_state): Correct comment about - threading. - -2013-11-15 Ian Lance Taylor - - * backtrace.h (backtrace_syminfo): Update comment and parameter - name to take any address, not just a PC value. - * elf.c (STT_OBJECT): Define. - (elf_nosyms): Rename parameter pc to addr. - (elf_symbol_search): Rename local variable pc to addr. - (elf_initialize_syminfo): Add STT_OBJECT symbols to elf_symbols. - (elf_syminfo): Rename parameter pc to addr. - * btest.c (global): New global variable. - (test5): New test. - (main): Call test5. - -2013-10-17 Ian Lance Taylor - - * elf.c (elf_add): Don't get the wrong offsets if a debug section - is missing. - -2013-10-15 David Malcolm - - * configure.ac: Add --enable-host-shared, setting up - pre-existing PIC_FLAG variable within Makefile.am et al. - * configure: Regenerate. - -2013-09-20 Alan Modra - - * configure: Regenerate. - -2013-07-23 Alexander Monakov - - * elf.c (elf_syminfo): Loop over the elf_syminfo_data chain. - -2013-07-23 Alexander Monakov - - * elf.c (backtrace_initialize): Pass elf_fileline_fn to - dl_iterate_phdr callbacks. - -2013-03-25 Ian Lance Taylor - - * alloc.c: #include . - * mmap.c: Likewise. - -2013-01-31 Ian Lance Taylor - - * dwarf.c (read_function_info): Permit fvec parameter to be NULL. - (dwarf_lookup_pc): Don't use ddata->fvec if threaded. - -2013-01-25 Jakub Jelinek - - PR other/56076 - * dwarf.c (read_line_header): Don't crash if DW_AT_comp_dir - attribute was not seen. - -2013-01-16 Ian Lance Taylor - - * dwarf.c (struct unit): Add filename and abs_filename fields. - (build_address_map): Set new fields when reading unit. - (dwarf_lookup_pc): If we don't find an entry in the line table, - just return the main file name. - -2013-01-14 Richard Sandiford - - Update copyright years. - -2013-01-01 Ian Lance Taylor - - PR bootstrap/54834 - * Makefile.am (AM_CPPFLAGS): Remove -I ../gcc/include and -I - $(MULTIBUILDTOP)/../../gcc/include. - * Makefile.in: Rebuild. - -2013-01-01 Ian Lance Taylor - - PR other/55536 - * mmap.c (backtrace_alloc): Don't call sync functions if not - threaded. - (backtrace_free): Likewise. - -2012-12-12 John David Anglin - - * mmapio.c: Define MAP_FAILED if not defined. - -2012-12-11 Jakub Jelinek - - PR bootstrap/54926 - * Makefile.am (AM_CFLAGS): Remove -frandom-seed=$@. - * configure.ac: If --with-target-subdir, add -frandom-seed=$@ - to EXTRA_FLAGS unconditionally, otherwise check whether the compiler - accepts it. - * Makefile.in: Regenerated. - * configure: Regenerated. - -2012-12-07 Jakub Jelinek - - PR bootstrap/54926 - * Makefile.am (AM_CFLAGS): Add -frandom-seed=$@. - * Makefile.in: Regenerated. - -2012-11-20 Ian Lance Taylor - - * dwarf.c (read_attribute): Always clear val. - -2012-11-13 Ian Lance Taylor - - PR other/55312 - * configure.ac: Only add -Werror if building a target library. - * configure: Rebuild. - -2012-11-12 Ian Lance Taylor - Rainer Orth - Gerald Pfeifer - - * configure.ac: Check for getexecname. - * fileline.c: #include . Define getexecname if not - available. - (fileline_initialize): Try to find the executable in a few - different ways. - * print.c (error_callback): Only print the filename if it came - from the backtrace state. - * configure, config.h.in: Rebuild. - -2012-10-29 Ian Lance Taylor - - * mmap.c (backtrace_vector_release): Correct last patch: add - aligned, not size. - -2012-10-29 Ian Lance Taylor - - * mmap.c (backtrace_vector_release): Make sure freed block is - aligned on 8-byte boundary. - -2012-10-26 Ian Lance Taylor - - PR other/55087 - * posix.c (backtrace_open): Add does_not_exist parameter. - * elf.c (phdr_callback): Do not warn if shared library could not - be opened. - * fileline.c (fileline_initialize): Update calls to - backtrace_open. - * internal.h (backtrace_open): Update declaration. - -2012-10-26 Jack Howarth - - PR target/55061 - * configure.ac: Check for _Unwind_GetIPInfo function declaration. - * configure: Regenerate. - -2012-10-24 Ian Lance Taylor - - PR target/55061 - * configure.ac: Check whether -funwind-tables option works. - * configure: Rebuild. - -2012-10-11 Ian Lance Taylor - - * configure.ac: Do not use dl_iterate_phdr on Solaris 10. - * configure: Rebuild. - -2012-10-10 Ian Lance Taylor - - * elf.c: Rename all Elf typedefs to start with b_elf, and be all - lower case. - -2012-10-10 Hans-Peter Nilsson - - * elf.c (elf_add_syminfo_data): Add casts to avoid warning. - -2012-10-09 Ian Lance Taylor - - * dwarf.c (dwarf_fileline): Add cast to avoid warning. - (backtrace_dwarf_add): Likewise. - -2012-10-09 Ian Lance Taylor - - Add support for tracing through shared libraries. - * configure.ac: Check for link.h and dl_iterate_phdr. - * elf.c: #include if system has dl_iterate_phdr. #undef - ELF macros before #defining them. - (dl_phdr_info, dl_iterate_phdr): Define if system does not have - dl_iterate_phdr. - (struct elf_syminfo_data): Add next field. - (elf_initialize_syminfo): Initialize next field. - (elf_add_syminfo_data): New static function. - (elf_add): New static function, broken out of - backtrace_initialize. Call backtrace_dwarf_add instead of - backtrace_dwarf_initialize. - (struct phdr_data): Define. - (phdr_callback): New static function. - (backtrace_initialize): Call elf_add. - * dwarf.c (struct dwarf_data): Add next and base_address fields. - (add_unit_addr): Add base_address parameter. Change all callers. - (add_unit_ranges, build_address_map): Likewise. - (add_line): Add ddata parameter. Change all callers. - (read_line_program, add_function_range): Likewise. - (dwarf_lookup_pc): New static function, broken out of - dwarf_fileline. - (dwarf_fileline): Call dwarf_lookup_pc. - (build_dwarf_data): New static function. - (backtrace_dwarf_add): New function. - (backtrace_dwarf_initialize): Remove. - * internal.h (backtrace_dwarf_initialize): Don't declare. - (backtrace_dwarf_add): Declare. - * configure, config.h.in: Rebuild. - -2012-10-04 Gerald Pfeifer - - * btest.c (f23): Avoid uninitialized variable warning. - -2012-10-04 Ian Lance Taylor - - * dwarf.c: If the system header files do not declare strnlen, - provide our own version. - -2012-10-03 Ian Lance Taylor - - * dwarf.c (read_uleb128): Fix overflow test. - (read_sleb128): Likewise. - (build_address_map): Don't change unit_buf.start. - -2012-10-02 Uros Bizjak - - PR other/54761 - * configure.ac (EXTRA_FLAGS): New. - * Makefile.am (AM_FLAGS): Add $(EXTRA_FLAGS). - * configure, Makefile.in: Regenerate. - -2012-09-29 Ian Lance Taylor - - PR other/54749 - * fileline.c (fileline_initialize): Pass errnum as -1 when - reporting that we could not read executable information after a - previous failure. - -2012-09-27 Ian Lance Taylor - - PR bootstrap/54732 - * configure.ac: Add no-dependencies to AM_INIT_AUTOMAKE. - * Makefile.am: Add dependencies for all objects. - * configure, aclocal.m4, Makefile.in: Rebuild. - -2012-09-27 Ian Lance Taylor - - PR other/54726 - * elf.c (backtrace_initialize): Set *fileln_fn, not - state->fileln_fn. - -2012-09-19 Ian Lance Taylor - - * configure.ac: Only use GCC_CHECK_UNWIND_GETIPINFO when compiled - as a target library. - * configure: Rebuild. - -2012-09-19 Rainer Orth - Ian Lance Taylor - - * configure.ac (GCC_HEADER_STDINT): Invoke. - * backtrace.h: If we can't find , use "gstdint.h". - * btest.c: Don't include . - * dwarf.c: Likewise. - * configure, aclocal.m4, Makefile.in, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - PR bootstrap/54623 - * Makefile.am (AM_CPPFLAGS): Define. - (AM_CFLAGS): Remove -I options. - * Makefile.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * posix.c (O_BINARY): Define if not defined. - (backtrace_open): Pass O_BINARY to open. Only call fcntl if - HAVE_FCNTL is defined. - * configure.ac: Test for the fcntl function. - * configure, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * btest.c (test1, test2, test3, test4): Add the unused attribute. - -2012-09-18 Ian Lance Taylor - - * dwarf.c: Correct test of HAVE_DECL_STRNLEN. - -2012-09-18 Ian Lance Taylor - - * configure.ac: Add AC_USE_SYSTEM_EXTENSIONS. - * mmapio.c: Don't define _GNU_SOURCE. - * configure, config.h.in: Rebuild. - -2012-09-18 Ian Lance Taylor - - * configure.ac: Check whether strnlen is declared. - * dwarf.c: Declare strnlen if not declared. - * configure, config.h.in: Rebuild. - -2012-09-18 Rainer Orth - - * fileline.c: Include . - * mmap.c: Likewise. - -2012-09-17 Ian Lance Taylor - - PR bootstrap/54611 - * nounwind.c (backtrace_full): Rename from backtrace. Add state - parameter. - -2012-09-17 Gerald Pfeifer - - PR bootstrap/54611 - * nounwind.c (backtrace_simple): Add state parameter. - -2012-09-17 Ian Lance Taylor - - PR bootstrap/54609 - * unknown.c (unknown_fileline): Add state parameter, remove - fileline_data parameter, name error_callback parameter. - (backtrace_initialize): Add state parameter. - -2012-09-17 Ian Lance Taylor - - * Initial implementation. - -Copyright (C) 2012-2016 Free Software Foundation, Inc. - -Copying and distribution of this file, with or without modification, -are permitted in any medium without royalty provided the copyright -notice and this notice are preserved. diff --git a/src/libbacktrace/ChangeLog.jit b/src/libbacktrace/ChangeLog.jit deleted file mode 100644 index 6b60e3b3b0738..0000000000000 --- a/src/libbacktrace/ChangeLog.jit +++ /dev/null @@ -1,14 +0,0 @@ -2014-09-24 David Malcolm - - * ChangeLog.jit: Add copyright footer. - -2013-10-03 David Malcolm - - * configure.ac: Add --enable-host-shared. - * configure: Regenerate. - -Copyright (C) 2013-2014 Free Software Foundation, Inc. - -Copying and distribution of this file, with or without modification, -are permitted in any medium without royalty provided the copyright -notice and this notice are preserved. diff --git a/src/libbacktrace/Makefile.am b/src/libbacktrace/Makefile.am deleted file mode 100644 index a7df025909822..0000000000000 --- a/src/libbacktrace/Makefile.am +++ /dev/null @@ -1,136 +0,0 @@ -# Makefile.am -- Backtrace Makefile. -# Copyright (C) 2012-2016 Free Software Foundation, Inc. - -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: - -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. - -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. - -# (3) The name of the author may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. - -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -ACLOCAL_AMFLAGS = -I .. -I ../config - -AM_CPPFLAGS = -I $(top_srcdir)/../include -I $(top_srcdir)/../libgcc \ - -I ../libgcc - -AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG) - -noinst_LTLIBRARIES = libbacktrace.la - -libbacktrace_la_SOURCES = \ - backtrace.h \ - atomic.c \ - dwarf.c \ - fileline.c \ - internal.h \ - posix.c \ - print.c \ - sort.c \ - state.c - -BACKTRACE_FILES = \ - backtrace.c \ - simple.c \ - nounwind.c - -FORMAT_FILES = \ - elf.c \ - pecoff.c \ - unknown.c - -VIEW_FILES = \ - read.c \ - mmapio.c - -ALLOC_FILES = \ - alloc.c \ - mmap.c - -EXTRA_libbacktrace_la_SOURCES = \ - $(BACKTRACE_FILES) \ - $(FORMAT_FILES) \ - $(VIEW_FILES) \ - $(ALLOC_FILES) - -libbacktrace_la_LIBADD = \ - $(BACKTRACE_FILE) \ - $(FORMAT_FILE) \ - $(VIEW_FILE) \ - $(ALLOC_FILE) - -libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD) - -# Testsuite. - -check_PROGRAMS = - -TESTS = $(check_PROGRAMS) - -if NATIVE - -btest_SOURCES = btest.c -btest_CFLAGS = $(AM_CFLAGS) -g -O -btest_LDADD = libbacktrace.la - -check_PROGRAMS += btest - -stest_SOURCES = stest.c -stest_LDADD = libbacktrace.la - -check_PROGRAMS += stest - -endif NATIVE - -# We can't use automake's automatic dependency tracking, because it -# breaks when using bootstrap-lean. Automatic dependency tracking -# with GCC bootstrap will cause some of the objects to depend on -# header files in prev-gcc/include, e.g., stddef.h and stdarg.h. When -# using bootstrap-lean, prev-gcc is removed after each stage. When -# running "make install", those header files will be gone, causing the -# library to be rebuilt at install time. That may not succeed. - -# These manual dependencies do not include dependencies on unwind.h, -# even though that is part of GCC, because where to find it depends on -# whether we are being built as a host library or a target library. - -INCDIR = $(top_srcdir)/../include -alloc.lo: config.h backtrace.h internal.h -backtrace.lo: config.h backtrace.h internal.h -btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h -dwarf.lo: config.h $(INCDIR)/dwarf2.h $(INCDIR)/dwarf2.def \ - $(INCDIR)/filenames.h backtrace.h internal.h -elf.lo: config.h backtrace.h internal.h -fileline.lo: config.h backtrace.h internal.h -mmap.lo: config.h backtrace.h internal.h -mmapio.lo: config.h backtrace.h internal.h -nounwind.lo: config.h internal.h -pecoff.lo: config.h backtrace.h internal.h -posix.lo: config.h backtrace.h internal.h -print.lo: config.h backtrace.h internal.h -read.lo: config.h backtrace.h internal.h -simple.lo: config.h backtrace.h internal.h -sort.lo: config.h backtrace.h internal.h -stest.lo: config.h backtrace.h internal.h -state.lo: config.h backtrace.h backtrace-supported.h internal.h -unknown.lo: config.h backtrace.h internal.h diff --git a/src/libbacktrace/Makefile.in b/src/libbacktrace/Makefile.in deleted file mode 100644 index 586b6a6eaa10e..0000000000000 --- a/src/libbacktrace/Makefile.in +++ /dev/null @@ -1,770 +0,0 @@ -# Makefile.in generated by automake 1.11.6 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, -# 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software -# Foundation, Inc. -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -# Makefile.am -- Backtrace Makefile. -# Copyright (C) 2012-2015 Free Software Foundation, Inc. - -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: - -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. - -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. - -# (3) The name of the author may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. - -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -VPATH = @srcdir@ -am__make_dryrun = \ - { \ - am__dry=no; \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \ - | grep '^AM OK$$' >/dev/null || am__dry=yes;; \ - *) \ - for am__flg in $$MAKEFLAGS; do \ - case $$am__flg in \ - *=*|--*) ;; \ - *n*) am__dry=yes; break;; \ - esac; \ - done;; \ - esac; \ - test $$am__dry = yes; \ - } -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -target_triplet = @target@ -check_PROGRAMS = $(am__EXEEXT_1) -@NATIVE_TRUE@am__append_1 = btest stest -subdir = . -DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \ - $(srcdir)/Makefile.am $(top_srcdir)/configure \ - $(am__configure_deps) $(srcdir)/config.h.in \ - $(srcdir)/../mkinstalldirs $(srcdir)/backtrace-supported.h.in -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/../config/lead-dot.m4 \ - $(top_srcdir)/../config/multi.m4 \ - $(top_srcdir)/../config/override.m4 \ - $(top_srcdir)/../config/stdint.m4 \ - $(top_srcdir)/../config/unwind_ipinfo.m4 \ - $(top_srcdir)/../config/warnings.m4 \ - $(top_srcdir)/../libtool.m4 $(top_srcdir)/../ltoptions.m4 \ - $(top_srcdir)/../ltsugar.m4 $(top_srcdir)/../ltversion.m4 \ - $(top_srcdir)/../lt~obsolete.m4 $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ - configure.lineno config.status.lineno -mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs -CONFIG_HEADER = config.h -CONFIG_CLEAN_FILES = backtrace-supported.h -CONFIG_CLEAN_VPATH_FILES = -LTLIBRARIES = $(noinst_LTLIBRARIES) -am__DEPENDENCIES_1 = -am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \ - print.lo sort.lo state.lo -libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS) -@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) -@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) -btest_OBJECTS = $(am_btest_OBJECTS) -@NATIVE_TRUE@btest_DEPENDENCIES = libbacktrace.la -btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -@NATIVE_TRUE@am_stest_OBJECTS = stest.$(OBJEXT) -stest_OBJECTS = $(am_stest_OBJECTS) -@NATIVE_TRUE@stest_DEPENDENCIES = libbacktrace.la -DEFAULT_INCLUDES = -I.@am__isrc@ -depcomp = -am__depfiles_maybe = -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ - $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -CCLD = $(CC) -LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \ - --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \ - $(LDFLAGS) -o $@ -SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \ - $(btest_SOURCES) $(stest_SOURCES) -MULTISRCTOP = -MULTIBUILDTOP = -MULTIDIRS = -MULTISUBDIR = -MULTIDO = true -MULTICLEAN = true -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -ETAGS = etags -CTAGS = ctags -am__tty_colors = \ -red=; grn=; lgn=; blu=; std= -ACLOCAL = @ACLOCAL@ -ALLOC_FILE = @ALLOC_FILE@ -AMTAR = @AMTAR@ -AR = @AR@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AWK = @AWK@ -BACKTRACE_FILE = @BACKTRACE_FILE@ -BACKTRACE_SUPPORTED = @BACKTRACE_SUPPORTED@ -BACKTRACE_SUPPORTS_DATA = @BACKTRACE_SUPPORTS_DATA@ -BACKTRACE_SUPPORTS_THREADS = @BACKTRACE_SUPPORTS_THREADS@ -BACKTRACE_USES_MALLOC = @BACKTRACE_USES_MALLOC@ -CC = @CC@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -EXTRA_FLAGS = @EXTRA_FLAGS@ -FGREP = @FGREP@ -FORMAT_FILE = @FORMAT_FILE@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAKEINFO = @MAKEINFO@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PIC_FLAG = @PIC_FLAG@ -RANLIB = @RANLIB@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -STRIP = @STRIP@ -VERSION = @VERSION@ -VIEW_FILE = @VIEW_FILE@ -WARN_FLAGS = @WARN_FLAGS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__leading_dot = @am__leading_dot@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -libtool_VERSION = @libtool_VERSION@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -multi_basedir = @multi_basedir@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target = @target@ -target_alias = @target_alias@ -target_cpu = @target_cpu@ -target_os = @target_os@ -target_vendor = @target_vendor@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -ACLOCAL_AMFLAGS = -I .. -I ../config -AM_CPPFLAGS = -I $(top_srcdir)/../include -I $(top_srcdir)/../libgcc \ - -I ../libgcc - -AM_CFLAGS = $(EXTRA_FLAGS) $(WARN_FLAGS) $(PIC_FLAG) -noinst_LTLIBRARIES = libbacktrace.la -libbacktrace_la_SOURCES = \ - backtrace.h \ - atomic.c \ - dwarf.c \ - fileline.c \ - internal.h \ - posix.c \ - print.c \ - sort.c \ - state.c - -BACKTRACE_FILES = \ - backtrace.c \ - simple.c \ - nounwind.c - -FORMAT_FILES = \ - elf.c \ - pecoff.c \ - unknown.c - -VIEW_FILES = \ - read.c \ - mmapio.c - -ALLOC_FILES = \ - alloc.c \ - mmap.c - -EXTRA_libbacktrace_la_SOURCES = \ - $(BACKTRACE_FILES) \ - $(FORMAT_FILES) \ - $(VIEW_FILES) \ - $(ALLOC_FILES) - -libbacktrace_la_LIBADD = \ - $(BACKTRACE_FILE) \ - $(FORMAT_FILE) \ - $(VIEW_FILE) \ - $(ALLOC_FILE) - -libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD) -TESTS = $(check_PROGRAMS) -@NATIVE_TRUE@btest_SOURCES = btest.c -@NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O -@NATIVE_TRUE@btest_LDADD = libbacktrace.la -@NATIVE_TRUE@stest_SOURCES = stest.c -@NATIVE_TRUE@stest_LDADD = libbacktrace.la - -# We can't use automake's automatic dependency tracking, because it -# breaks when using bootstrap-lean. Automatic dependency tracking -# with GCC bootstrap will cause some of the objects to depend on -# header files in prev-gcc/include, e.g., stddef.h and stdarg.h. When -# using bootstrap-lean, prev-gcc is removed after each stage. When -# running "make install", those header files will be gone, causing the -# library to be rebuilt at install time. That may not succeed. - -# These manual dependencies do not include dependencies on unwind.h, -# even though that is part of GCC, because where to find it depends on -# whether we are being built as a host library or a target library. -INCDIR = $(top_srcdir)/../include -all: config.h - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -am--refresh: Makefile - @: -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - echo ' cd $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps'; \ - $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign --ignore-deps \ - && exit 0; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign --ignore-deps Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign --ignore-deps Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - echo ' $(SHELL) ./config.status'; \ - $(SHELL) ./config.status;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - $(SHELL) ./config.status --recheck - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - $(am__cd) $(srcdir) && $(AUTOCONF) -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) -$(am__aclocal_m4_deps): - -config.h: stamp-h1 - @if test ! -f $@; then rm -f stamp-h1; else :; fi - @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi - -stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status - @rm -f stamp-h1 - cd $(top_builddir) && $(SHELL) ./config.status config.h -$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) - rm -f stamp-h1 - touch $@ - -distclean-hdr: - -rm -f config.h stamp-h1 -backtrace-supported.h: $(top_builddir)/config.status $(srcdir)/backtrace-supported.h.in - cd $(top_builddir) && $(SHELL) ./config.status $@ - -clean-noinstLTLIBRARIES: - -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) - @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ - dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ - test "$$dir" != "$$p" || dir=.; \ - echo "rm -f \"$${dir}/so_locations\""; \ - rm -f "$${dir}/so_locations"; \ - done -libbacktrace.la: $(libbacktrace_la_OBJECTS) $(libbacktrace_la_DEPENDENCIES) $(EXTRA_libbacktrace_la_DEPENDENCIES) - $(LINK) $(libbacktrace_la_OBJECTS) $(libbacktrace_la_LIBADD) $(LIBS) - -clean-checkPROGRAMS: - @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ - echo " rm -f" $$list; \ - rm -f $$list || exit $$?; \ - test -n "$(EXEEXT)" || exit 0; \ - list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ - echo " rm -f" $$list; \ - rm -f $$list -btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES) - @rm -f btest$(EXEEXT) - $(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS) -stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIES) - @rm -f stest$(EXEEXT) - $(LINK) $(stest_OBJECTS) $(stest_LDADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -.c.o: - $(COMPILE) -c $< - -.c.obj: - $(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: - $(LTCOMPILE) -c -o $@ $< - -btest-btest.o: btest.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c - -btest-btest.obj: btest.c - $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi` - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -distclean-libtool: - -rm -f libtool config.lt - -# GNU Make needs to see an explicit $(MAKE) variable in the command it -# runs to enable its job server during parallel builds. Hence the -# comments below. -all-multi: - $(MULTIDO) $(AM_MAKEFLAGS) DO=all multi-do # $(MAKE) -install-multi: - $(MULTIDO) $(AM_MAKEFLAGS) DO=install multi-do # $(MAKE) - -mostlyclean-multi: - $(MULTICLEAN) $(AM_MAKEFLAGS) DO=mostlyclean multi-clean # $(MAKE) -clean-multi: - $(MULTICLEAN) $(AM_MAKEFLAGS) DO=clean multi-clean # $(MAKE) -distclean-multi: - $(MULTICLEAN) $(AM_MAKEFLAGS) DO=distclean multi-clean # $(MAKE) -maintainer-clean-multi: - $(MULTICLEAN) $(AM_MAKEFLAGS) DO=maintainer-clean multi-clean # $(MAKE) - -ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) - list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - mkid -fID $$unique -tags: TAGS - -TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - set x; \ - here=`pwd`; \ - list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: CTAGS -CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ - $(TAGS_FILES) $(LISP) - list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | \ - $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in files) print i; }; }'`; \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -check-TESTS: $(TESTS) - @failed=0; all=0; xfail=0; xpass=0; skip=0; \ - srcdir=$(srcdir); export srcdir; \ - list=' $(TESTS) '; \ - $(am__tty_colors); \ - if test -n "$$list"; then \ - for tst in $$list; do \ - if test -f ./$$tst; then dir=./; \ - elif test -f $$tst; then dir=; \ - else dir="$(srcdir)/"; fi; \ - if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ - all=`expr $$all + 1`; \ - case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$tst[\ \ ]*) \ - xpass=`expr $$xpass + 1`; \ - failed=`expr $$failed + 1`; \ - col=$$red; res=XPASS; \ - ;; \ - *) \ - col=$$grn; res=PASS; \ - ;; \ - esac; \ - elif test $$? -ne 77; then \ - all=`expr $$all + 1`; \ - case " $(XFAIL_TESTS) " in \ - *[\ \ ]$$tst[\ \ ]*) \ - xfail=`expr $$xfail + 1`; \ - col=$$lgn; res=XFAIL; \ - ;; \ - *) \ - failed=`expr $$failed + 1`; \ - col=$$red; res=FAIL; \ - ;; \ - esac; \ - else \ - skip=`expr $$skip + 1`; \ - col=$$blu; res=SKIP; \ - fi; \ - echo "$${col}$$res$${std}: $$tst"; \ - done; \ - if test "$$all" -eq 1; then \ - tests="test"; \ - All=""; \ - else \ - tests="tests"; \ - All="All "; \ - fi; \ - if test "$$failed" -eq 0; then \ - if test "$$xfail" -eq 0; then \ - banner="$$All$$all $$tests passed"; \ - else \ - if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ - banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ - fi; \ - else \ - if test "$$xpass" -eq 0; then \ - banner="$$failed of $$all $$tests failed"; \ - else \ - if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ - banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ - fi; \ - fi; \ - dashes="$$banner"; \ - skipped=""; \ - if test "$$skip" -ne 0; then \ - if test "$$skip" -eq 1; then \ - skipped="($$skip test was not run)"; \ - else \ - skipped="($$skip tests were not run)"; \ - fi; \ - test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ - dashes="$$skipped"; \ - fi; \ - report=""; \ - if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ - report="Please report to $(PACKAGE_BUGREPORT)"; \ - test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ - dashes="$$report"; \ - fi; \ - dashes=`echo "$$dashes" | sed s/./=/g`; \ - if test "$$failed" -eq 0; then \ - col="$$grn"; \ - else \ - col="$$red"; \ - fi; \ - echo "$${col}$$dashes$${std}"; \ - echo "$${col}$$banner$${std}"; \ - test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ - test -z "$$report" || echo "$${col}$$report$${std}"; \ - echo "$${col}$$dashes$${std}"; \ - test "$$failed" -eq 0; \ - else :; fi -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) - $(MAKE) $(AM_MAKEFLAGS) check-TESTS -check: check-am -all-am: Makefile $(LTLIBRARIES) all-multi config.h -installdirs: -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am clean-multi - -clean-am: clean-checkPROGRAMS clean-generic clean-libtool \ - clean-noinstLTLIBRARIES mostlyclean-am - -distclean: distclean-am distclean-multi - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-hdr distclean-libtool distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-multi - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am maintainer-clean-multi - -rm -f $(am__CONFIG_DISTCLEAN_FILES) - -rm -rf $(top_srcdir)/autom4te.cache - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am mostlyclean-multi - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: - -.MAKE: all all-multi check-am clean-multi distclean-multi install-am \ - install-multi install-strip maintainer-clean-multi \ - mostlyclean-multi - -.PHONY: CTAGS GTAGS all all-am all-multi am--refresh check check-TESTS \ - check-am clean clean-checkPROGRAMS clean-generic clean-libtool \ - clean-multi clean-noinstLTLIBRARIES ctags distclean \ - distclean-compile distclean-generic distclean-hdr \ - distclean-libtool distclean-multi distclean-tags dvi dvi-am \ - html html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-multi install-pdf \ - install-pdf-am install-ps install-ps-am install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic maintainer-clean-multi mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - mostlyclean-multi pdf pdf-am ps ps-am tags uninstall \ - uninstall-am - -alloc.lo: config.h backtrace.h internal.h -backtrace.lo: config.h backtrace.h internal.h -btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h -dwarf.lo: config.h $(INCDIR)/dwarf2.h $(INCDIR)/dwarf2.def \ - $(INCDIR)/filenames.h backtrace.h internal.h -elf.lo: config.h backtrace.h internal.h -fileline.lo: config.h backtrace.h internal.h -mmap.lo: config.h backtrace.h internal.h -mmapio.lo: config.h backtrace.h internal.h -nounwind.lo: config.h internal.h -pecoff.lo: config.h backtrace.h internal.h -posix.lo: config.h backtrace.h internal.h -print.lo: config.h backtrace.h internal.h -read.lo: config.h backtrace.h internal.h -simple.lo: config.h backtrace.h internal.h -sort.lo: config.h backtrace.h internal.h -stest.lo: config.h backtrace.h internal.h -state.lo: config.h backtrace.h backtrace-supported.h internal.h -unknown.lo: config.h backtrace.h internal.h - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/src/libbacktrace/README b/src/libbacktrace/README deleted file mode 100644 index e8b225745c9c6..0000000000000 --- a/src/libbacktrace/README +++ /dev/null @@ -1,23 +0,0 @@ -The libbacktrace library -Initially written by Ian Lance Taylor - -The libbacktrace library may be linked into a program or library and -used to produce symbolic backtraces. Sample uses would be to print a -detailed backtrace when an error occurs or to gather detailed -profiling information. - -The libbacktrace library is provided under a BSD license. See the -source files for the exact license text. - -The public functions are declared and documented in the header file -backtrace.h, which should be #include'd by a user of the library. - -Building libbacktrace will generate a file backtrace-supported.h, -which a user of the library may use to determine whether backtraces -will work. See the source file backtrace-supported.h.in for the -macros that it defines. - -As of September 2012, libbacktrace only supports ELF executables with -DWARF debugging information. The library is written to make it -straightforward to add support for other object file and debugging -formats. diff --git a/src/libbacktrace/aclocal.m4 b/src/libbacktrace/aclocal.m4 deleted file mode 100644 index 8e84ddd1f1013..0000000000000 --- a/src/libbacktrace/aclocal.m4 +++ /dev/null @@ -1,683 +0,0 @@ -# generated automatically by aclocal 1.11.6 -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, -# Inc. -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],, -[m4_warning([this file was generated for autoconf 2.64. -You have another version of autoconf. It may work, but is not guaranteed to. -If you have problems, you may need to regenerate the build system entirely. -To do so, use the procedure documented by the package, typically `autoreconf'.])]) - -# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software -# Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 1 - -# AM_AUTOMAKE_VERSION(VERSION) -# ---------------------------- -# Automake X.Y traces this macro to ensure aclocal.m4 has been -# generated from the m4 files accompanying Automake X.Y. -# (This private macro should not be called outside this file.) -AC_DEFUN([AM_AUTOMAKE_VERSION], -[am__api_version='1.11' -dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to -dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.11.6], [], - [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl -]) - -# _AM_AUTOCONF_VERSION(VERSION) -# ----------------------------- -# aclocal traces this macro to find the Autoconf version. -# This is a private macro too. Using m4_define simplifies -# the logic in aclocal, which can simply ignore this definition. -m4_define([_AM_AUTOCONF_VERSION], []) - -# AM_SET_CURRENT_AUTOMAKE_VERSION -# ------------------------------- -# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. -# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. -AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.11.6])dnl -m4_ifndef([AC_AUTOCONF_VERSION], - [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) - -# AM_AUX_DIR_EXPAND -*- Autoconf -*- - -# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 1 - -# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets -# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to -# `$srcdir', `$srcdir/..', or `$srcdir/../..'. -# -# Of course, Automake must honor this variable whenever it calls a -# tool from the auxiliary directory. The problem is that $srcdir (and -# therefore $ac_aux_dir as well) can be either absolute or relative, -# depending on how configure is run. This is pretty annoying, since -# it makes $ac_aux_dir quite unusable in subdirectories: in the top -# source directory, any form will work fine, but in subdirectories a -# relative path needs to be adjusted first. -# -# $ac_aux_dir/missing -# fails when called from a subdirectory if $ac_aux_dir is relative -# $top_srcdir/$ac_aux_dir/missing -# fails if $ac_aux_dir is absolute, -# fails when called from a subdirectory in a VPATH build with -# a relative $ac_aux_dir -# -# The reason of the latter failure is that $top_srcdir and $ac_aux_dir -# are both prefixed by $srcdir. In an in-source build this is usually -# harmless because $srcdir is `.', but things will broke when you -# start a VPATH build or use an absolute $srcdir. -# -# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, -# iff we strip the leading $srcdir from $ac_aux_dir. That would be: -# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` -# and then we would define $MISSING as -# MISSING="\${SHELL} $am_aux_dir/missing" -# This will work as long as MISSING is not called from configure, because -# unfortunately $(top_srcdir) has no meaning in configure. -# However there are other variables, like CC, which are often used in -# configure, and could therefore not use this "fixed" $ac_aux_dir. -# -# Another solution, used here, is to always expand $ac_aux_dir to an -# absolute PATH. The drawback is that using absolute paths prevent a -# configured tree to be moved without reconfiguration. - -AC_DEFUN([AM_AUX_DIR_EXPAND], -[dnl Rely on autoconf to set up CDPATH properly. -AC_PREREQ([2.50])dnl -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` -]) - -# AM_CONDITIONAL -*- Autoconf -*- - -# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 9 - -# AM_CONDITIONAL(NAME, SHELL-CONDITION) -# ------------------------------------- -# Define a conditional. -AC_DEFUN([AM_CONDITIONAL], -[AC_PREREQ(2.52)dnl - ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], - [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl -AC_SUBST([$1_TRUE])dnl -AC_SUBST([$1_FALSE])dnl -_AM_SUBST_NOTMAKE([$1_TRUE])dnl -_AM_SUBST_NOTMAKE([$1_FALSE])dnl -m4_define([_AM_COND_VALUE_$1], [$2])dnl -if $2; then - $1_TRUE= - $1_FALSE='#' -else - $1_TRUE='#' - $1_FALSE= -fi -AC_CONFIG_COMMANDS_PRE( -[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then - AC_MSG_ERROR([[conditional "$1" was never defined. -Usually this means the macro was only invoked conditionally.]]) -fi])]) - -# Do all the work for Automake. -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, -# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 16 - -# This macro actually does too much. Some checks are only needed if -# your package does certain things. But this isn't really a big deal. - -# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) -# AM_INIT_AUTOMAKE([OPTIONS]) -# ----------------------------------------------- -# The call with PACKAGE and VERSION arguments is the old style -# call (pre autoconf-2.50), which is being phased out. PACKAGE -# and VERSION should now be passed to AC_INIT and removed from -# the call to AM_INIT_AUTOMAKE. -# We support both call styles for the transition. After -# the next Automake release, Autoconf can make the AC_INIT -# arguments mandatory, and then we can depend on a new Autoconf -# release and drop the old call support. -AC_DEFUN([AM_INIT_AUTOMAKE], -[AC_PREREQ([2.62])dnl -dnl Autoconf wants to disallow AM_ names. We explicitly allow -dnl the ones we care about. -m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl -AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl -AC_REQUIRE([AC_PROG_INSTALL])dnl -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi -AC_SUBST([CYGPATH_W]) - -# Define the identity of the package. -dnl Distinguish between old-style and new-style calls. -m4_ifval([$2], -[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl - AC_SUBST([PACKAGE], [$1])dnl - AC_SUBST([VERSION], [$2])], -[_AM_SET_OPTIONS([$1])dnl -dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. -m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, - [m4_fatal([AC_INIT should be called with package and version arguments])])dnl - AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl - AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl - -_AM_IF_OPTION([no-define],, -[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) - AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl - -# Some tools Automake needs. -AC_REQUIRE([AM_SANITY_CHECK])dnl -AC_REQUIRE([AC_ARG_PROGRAM])dnl -AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) -AM_MISSING_PROG(AUTOCONF, autoconf) -AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) -AM_MISSING_PROG(AUTOHEADER, autoheader) -AM_MISSING_PROG(MAKEINFO, makeinfo) -AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl -AC_REQUIRE([AM_PROG_MKDIR_P])dnl -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. -AC_REQUIRE([AC_PROG_AWK])dnl -AC_REQUIRE([AC_PROG_MAKE_SET])dnl -AC_REQUIRE([AM_SET_LEADING_DOT])dnl -_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], - [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], - [_AM_PROG_TAR([v7])])]) -_AM_IF_OPTION([no-dependencies],, -[AC_PROVIDE_IFELSE([AC_PROG_CC], - [_AM_DEPENDENCIES(CC)], - [define([AC_PROG_CC], - defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_CXX], - [_AM_DEPENDENCIES(CXX)], - [define([AC_PROG_CXX], - defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl -AC_PROVIDE_IFELSE([AC_PROG_OBJC], - [_AM_DEPENDENCIES(OBJC)], - [define([AC_PROG_OBJC], - defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl -]) -_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl -dnl The `parallel-tests' driver may need to know about EXEEXT, so add the -dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro -dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. -AC_CONFIG_COMMANDS_PRE(dnl -[m4_provide_if([_AM_COMPILER_EXEEXT], - [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl -]) - -dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not -dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further -dnl mangled by Autoconf and run in a shell conditional statement. -m4_define([_AC_COMPILER_EXEEXT], -m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) - - -# When config.status generates a header, we must update the stamp-h file. -# This file resides in the same directory as the config header -# that is generated. The stamp files are numbered to have different names. - -# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the -# loop where config.status creates the headers, so we can generate -# our stamp files there. -AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], -[# Compute $1's index in $config_headers. -_am_arg=$1 -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) - -# Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, -# Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 1 - -# AM_PROG_INSTALL_SH -# ------------------ -# Define $install_sh. -AC_DEFUN([AM_PROG_INSTALL_SH], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -if test x"${install_sh}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi -AC_SUBST(install_sh)]) - -# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- -# From Jim Meyering - -# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, -# 2011 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 5 - -# AM_MAINTAINER_MODE([DEFAULT-MODE]) -# ---------------------------------- -# Control maintainer-specific portions of Makefiles. -# Default is to disable them, unless `enable' is passed literally. -# For symmetry, `disable' may be passed as well. Anyway, the user -# can override the default with the --enable/--disable switch. -AC_DEFUN([AM_MAINTAINER_MODE], -[m4_case(m4_default([$1], [disable]), - [enable], [m4_define([am_maintainer_other], [disable])], - [disable], [m4_define([am_maintainer_other], [enable])], - [m4_define([am_maintainer_other], [enable]) - m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) -AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) - dnl maintainer-mode's default is 'disable' unless 'enable' is passed - AC_ARG_ENABLE([maintainer-mode], -[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful - (and sometimes confusing) to the casual installer], - [USE_MAINTAINER_MODE=$enableval], - [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) - AC_MSG_RESULT([$USE_MAINTAINER_MODE]) - AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) - MAINT=$MAINTAINER_MODE_TRUE - AC_SUBST([MAINT])dnl -] -) - -AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) - -# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- - -# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 6 - -# AM_MISSING_PROG(NAME, PROGRAM) -# ------------------------------ -AC_DEFUN([AM_MISSING_PROG], -[AC_REQUIRE([AM_MISSING_HAS_RUN]) -$1=${$1-"${am_missing_run}$2"} -AC_SUBST($1)]) - - -# AM_MISSING_HAS_RUN -# ------------------ -# Define MISSING if not defined so far and test if it supports --run. -# If it does, set am_missing_run to use it, otherwise, to nothing. -AC_DEFUN([AM_MISSING_HAS_RUN], -[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl -AC_REQUIRE_AUX_FILE([missing])dnl -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac -fi -# Use eval to expand $SHELL -if eval "$MISSING --run true"; then - am_missing_run="$MISSING --run " -else - am_missing_run= - AC_MSG_WARN([`missing' script is too old or missing]) -fi -]) - -# Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, -# Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 1 - -# AM_PROG_MKDIR_P -# --------------- -# Check for `mkdir -p'. -AC_DEFUN([AM_PROG_MKDIR_P], -[AC_PREREQ([2.60])dnl -AC_REQUIRE([AC_PROG_MKDIR_P])dnl -dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, -dnl while keeping a definition of mkdir_p for backward compatibility. -dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. -dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of -dnl Makefile.ins that do not define MKDIR_P, so we do our own -dnl adjustment using top_builddir (which is defined more often than -dnl MKDIR_P). -AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl -case $mkdir_p in - [[\\/$]]* | ?:[[\\/]]*) ;; - */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; -esac -]) - -# Helper functions for option handling. -*- Autoconf -*- - -# Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software -# Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 5 - -# _AM_MANGLE_OPTION(NAME) -# ----------------------- -AC_DEFUN([_AM_MANGLE_OPTION], -[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) - -# _AM_SET_OPTION(NAME) -# -------------------- -# Set option NAME. Presently that only means defining a flag for this option. -AC_DEFUN([_AM_SET_OPTION], -[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) - -# _AM_SET_OPTIONS(OPTIONS) -# ------------------------ -# OPTIONS is a space-separated list of Automake options. -AC_DEFUN([_AM_SET_OPTIONS], -[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) - -# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) -# ------------------------------------------- -# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. -AC_DEFUN([_AM_IF_OPTION], -[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) - -# Check to make sure that the build environment is sane. -*- Autoconf -*- - -# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 -# Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 5 - -# AM_SANITY_CHECK -# --------------- -AC_DEFUN([AM_SANITY_CHECK], -[AC_MSG_CHECKING([whether build environment is sane]) -# Just in case -sleep 1 -echo timestamp > conftest.file -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[[\\\"\#\$\&\'\`$am_lf]]*) - AC_MSG_ERROR([unsafe absolute working directory name]);; -esac -case $srcdir in - *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) - AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; -esac - -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$[*]" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - rm -f conftest.file - if test "$[*]" != "X $srcdir/configure conftest.file" \ - && test "$[*]" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken -alias in your environment]) - fi - - test "$[2]" = conftest.file - ) -then - # Ok. - : -else - AC_MSG_ERROR([newly created file is older than distributed files! -Check your system clock]) -fi -AC_MSG_RESULT(yes)]) - -# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 1 - -# AM_PROG_INSTALL_STRIP -# --------------------- -# One issue with vendor `install' (even GNU) is that you can't -# specify the program used to strip binaries. This is especially -# annoying in cross-compiling environments, where the build's strip -# is unlikely to handle the host's binaries. -# Fortunately install-sh will honor a STRIPPROG variable, so we -# always use install-sh in `make install-strip', and initialize -# STRIPPROG with the value of the STRIP variable (set by the user). -AC_DEFUN([AM_PROG_INSTALL_STRIP], -[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -dnl Don't test for $cross_compiling = yes, because it might be `maybe'. -if test "$cross_compiling" != no; then - AC_CHECK_TOOL([STRIP], [strip], :) -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" -AC_SUBST([INSTALL_STRIP_PROGRAM])]) - -# Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 3 - -# _AM_SUBST_NOTMAKE(VARIABLE) -# --------------------------- -# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. -# This macro is traced by Automake. -AC_DEFUN([_AM_SUBST_NOTMAKE]) - -# AM_SUBST_NOTMAKE(VARIABLE) -# -------------------------- -# Public sister of _AM_SUBST_NOTMAKE. -AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) - -# Check how to create a tarball. -*- Autoconf -*- - -# Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. -# -# This file is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# serial 2 - -# _AM_PROG_TAR(FORMAT) -# -------------------- -# Check how to create a tarball in format FORMAT. -# FORMAT should be one of `v7', `ustar', or `pax'. -# -# Substitute a variable $(am__tar) that is a command -# writing to stdout a FORMAT-tarball containing the directory -# $tardir. -# tardir=directory && $(am__tar) > result.tar -# -# Substitute a variable $(am__untar) that extract such -# a tarball read from stdin. -# $(am__untar) < result.tar -AC_DEFUN([_AM_PROG_TAR], -[# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AC_SUBST([AMTAR], ['$${TAR-tar}']) -m4_if([$1], [v7], - [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], - [m4_case([$1], [ustar],, [pax],, - [m4_fatal([Unknown tar format])]) -AC_MSG_CHECKING([how to create a $1 tar archive]) -# Loop over all known methods to create a tar archive until one works. -_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' -_am_tools=${am_cv_prog_tar_$1-$_am_tools} -# Do not fold the above two line into one, because Tru64 sh and -# Solaris sh will not grok spaces in the rhs of `-'. -for _am_tool in $_am_tools -do - case $_am_tool in - gnutar) - for _am_tar in tar gnutar gtar; - do - AM_RUN_LOG([$_am_tar --version]) && break - done - am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' - am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' - am__untar="$_am_tar -xf -" - ;; - plaintar) - # Must skip GNU tar: if it does not support --format= it doesn't create - # ustar tarball either. - (tar --version) >/dev/null 2>&1 && continue - am__tar='tar chf - "$$tardir"' - am__tar_='tar chf - "$tardir"' - am__untar='tar xf -' - ;; - pax) - am__tar='pax -L -x $1 -w "$$tardir"' - am__tar_='pax -L -x $1 -w "$tardir"' - am__untar='pax -r' - ;; - cpio) - am__tar='find "$$tardir" -print | cpio -o -H $1 -L' - am__tar_='find "$tardir" -print | cpio -o -H $1 -L' - am__untar='cpio -i -H $1 -d' - ;; - none) - am__tar=false - am__tar_=false - am__untar=false - ;; - esac - - # If the value was cached, stop now. We just wanted to have am__tar - # and am__untar set. - test -n "${am_cv_prog_tar_$1}" && break - - # tar/untar a dummy directory, and stop if the command works - rm -rf conftest.dir - mkdir conftest.dir - echo GrepMe > conftest.dir/file - AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) - rm -rf conftest.dir - if test -s conftest.tar; then - AM_RUN_LOG([$am__untar /dev/null 2>&1 && break - fi -done -rm -rf conftest.dir - -AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) -AC_MSG_RESULT([$am_cv_prog_tar_$1])]) -AC_SUBST([am__tar]) -AC_SUBST([am__untar]) -]) # _AM_PROG_TAR - -m4_include([../config/lead-dot.m4]) -m4_include([../config/multi.m4]) -m4_include([../config/override.m4]) -m4_include([../config/stdint.m4]) -m4_include([../config/unwind_ipinfo.m4]) -m4_include([../config/warnings.m4]) -m4_include([../libtool.m4]) -m4_include([../ltoptions.m4]) -m4_include([../ltsugar.m4]) -m4_include([../ltversion.m4]) -m4_include([../lt~obsolete.m4]) diff --git a/src/libbacktrace/alloc.c b/src/libbacktrace/alloc.c deleted file mode 100644 index a9f07a013f8fe..0000000000000 --- a/src/libbacktrace/alloc.c +++ /dev/null @@ -1,156 +0,0 @@ -/* alloc.c -- Memory allocation without mmap. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Allocation routines to use on systems that do not support anonymous - mmap. This implementation just uses malloc, which means that the - backtrace functions may not be safely invoked from a signal - handler. */ - -/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't - report an error. */ - -void * -backtrace_alloc (struct backtrace_state *state ATTRIBUTE_UNUSED, - size_t size, backtrace_error_callback error_callback, - void *data) -{ - void *ret; - - ret = malloc (size); - if (ret == NULL) - { - if (error_callback) - error_callback (data, "malloc", errno); - } - return ret; -} - -/* Free memory. */ - -void -backtrace_free (struct backtrace_state *state ATTRIBUTE_UNUSED, - void *p, size_t size ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - free (p); -} - -/* Grow VEC by SIZE bytes. */ - -void * -backtrace_vector_grow (struct backtrace_state *state ATTRIBUTE_UNUSED, - size_t size, backtrace_error_callback error_callback, - void *data, struct backtrace_vector *vec) -{ - void *ret; - - if (size > vec->alc) - { - size_t alc; - void *base; - - if (vec->size == 0) - alc = 32 * size; - else if (vec->size >= 4096) - alc = vec->size + 4096; - else - alc = 2 * vec->size; - - if (alc < vec->size + size) - alc = vec->size + size; - - base = realloc (vec->base, alc); - if (base == NULL) - { - error_callback (data, "realloc", errno); - return NULL; - } - - vec->base = base; - vec->alc = alc - vec->size; - } - - ret = (char *) vec->base + vec->size; - vec->size += size; - vec->alc -= size; - return ret; -} - -/* Finish the current allocation on VEC. */ - -void * -backtrace_vector_finish (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data) -{ - void *ret; - - /* With this allocator we call realloc in backtrace_vector_grow, - which means we can't easily reuse the memory here. So just - release it. */ - if (!backtrace_vector_release (state, vec, error_callback, data)) - return NULL; - ret = vec->base; - vec->base = NULL; - vec->size = 0; - vec->alc = 0; - return ret; -} - -/* Release any extra space allocated for VEC. */ - -int -backtrace_vector_release (struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data) -{ - vec->base = realloc (vec->base, vec->size); - if (vec->base == NULL) - { - error_callback (data, "realloc", errno); - return 0; - } - vec->alc = 0; - return 1; -} diff --git a/src/libbacktrace/ansidecl.h b/src/libbacktrace/ansidecl.h deleted file mode 100644 index 4087dd7291750..0000000000000 --- a/src/libbacktrace/ansidecl.h +++ /dev/null @@ -1,329 +0,0 @@ -/* ANSI and traditional C compatibility macros - Copyright (C) 1991-2015 Free Software Foundation, Inc. - This file is part of the GNU C Library. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -/* ANSI and traditional C compatibility macros - - ANSI C is assumed if __STDC__ is #defined. - - Macro ANSI C definition Traditional C definition - ----- ---- - ---------- ----------- - ---------- - PTR `void *' `char *' - const not defined `' - volatile not defined `' - signed not defined `' - - For ease of writing code which uses GCC extensions but needs to be - portable to other compilers, we provide the GCC_VERSION macro that - simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various - wrappers around __attribute__. Also, __extension__ will be #defined - to nothing if it doesn't work. See below. */ - -#ifndef _ANSIDECL_H -#define _ANSIDECL_H 1 - -#ifdef __cplusplus -extern "C" { -#endif - -/* Every source file includes this file, - so they will all get the switch for lint. */ -/* LINTLIBRARY */ - -/* Using MACRO(x,y) in cpp #if conditionals does not work with some - older preprocessors. Thus we can't define something like this: - -#define HAVE_GCC_VERSION(MAJOR, MINOR) \ - (__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR))) - -and then test "#if HAVE_GCC_VERSION(2,7)". - -So instead we use the macro below and test it against specific values. */ - -/* This macro simplifies testing whether we are using gcc, and if it - is of a particular minimum version. (Both major & minor numbers are - significant.) This macro will evaluate to 0 if we are not using - gcc at all. */ -#ifndef GCC_VERSION -#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) -#endif /* GCC_VERSION */ - -#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32) -/* All known AIX compilers implement these things (but don't always - define __STDC__). The RISC/OS MIPS compiler defines these things - in SVR4 mode, but does not define __STDC__. */ -/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other - C++ compilers, does not define __STDC__, though it acts as if this - was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */ - -#define PTR void * - -#undef const -#undef volatile -#undef signed - -/* inline requires special treatment; it's in C99, and GCC >=2.7 supports - it too, but it's not in C89. */ -#undef inline -#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__)) -/* it's a keyword */ -#else -# if GCC_VERSION >= 2007 -# define inline __inline__ /* __inline__ prevents -pedantic warnings */ -# else -# define inline /* nothing */ -# endif -#endif - -#else /* Not ANSI C. */ - -#define PTR char * - -/* some systems define these in header files for non-ansi mode */ -#undef const -#undef volatile -#undef signed -#undef inline -#define const -#define volatile -#define signed -#define inline - -#endif /* ANSI C. */ - -/* Define macros for some gcc attributes. This permits us to use the - macros freely, and know that they will come into play for the - version of gcc in which they are supported. */ - -#if (GCC_VERSION < 2007) -# define __attribute__(x) -#endif - -/* Attribute __malloc__ on functions was valid as of gcc 2.96. */ -#ifndef ATTRIBUTE_MALLOC -# if (GCC_VERSION >= 2096) -# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) -# else -# define ATTRIBUTE_MALLOC -# endif /* GNUC >= 2.96 */ -#endif /* ATTRIBUTE_MALLOC */ - -/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For - g++ an attribute on a label must be followed by a semicolon. */ -#ifndef ATTRIBUTE_UNUSED_LABEL -# ifndef __cplusplus -# if GCC_VERSION >= 2093 -# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED -# else -# define ATTRIBUTE_UNUSED_LABEL -# endif -# else -# if GCC_VERSION >= 4005 -# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ; -# else -# define ATTRIBUTE_UNUSED_LABEL -# endif -# endif -#endif - -/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend - couldn't parse attributes placed after the identifier name, and now - the entire compiler is built with C++. */ -#ifndef ATTRIBUTE_UNUSED -#if GCC_VERSION >= 3004 -# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#else -#define ATTRIBUTE_UNUSED -#endif -#endif /* ATTRIBUTE_UNUSED */ - -/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the - identifier name. */ -#if ! defined(__cplusplus) || (GCC_VERSION >= 3004) -# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED -#else /* !__cplusplus || GNUC >= 3.4 */ -# define ARG_UNUSED(NAME) NAME -#endif /* !__cplusplus || GNUC >= 3.4 */ - -#ifndef ATTRIBUTE_NORETURN -#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__)) -#endif /* ATTRIBUTE_NORETURN */ - -/* Attribute `nonnull' was valid as of gcc 3.3. */ -#ifndef ATTRIBUTE_NONNULL -# if (GCC_VERSION >= 3003) -# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m))) -# else -# define ATTRIBUTE_NONNULL(m) -# endif /* GNUC >= 3.3 */ -#endif /* ATTRIBUTE_NONNULL */ - -/* Attribute `returns_nonnull' was valid as of gcc 4.9. */ -#ifndef ATTRIBUTE_RETURNS_NONNULL -# if (GCC_VERSION >= 4009) -# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__)) -# else -# define ATTRIBUTE_RETURNS_NONNULL -# endif /* GNUC >= 4.9 */ -#endif /* ATTRIBUTE_RETURNS_NONNULL */ - -/* Attribute `pure' was valid as of gcc 3.0. */ -#ifndef ATTRIBUTE_PURE -# if (GCC_VERSION >= 3000) -# define ATTRIBUTE_PURE __attribute__ ((__pure__)) -# else -# define ATTRIBUTE_PURE -# endif /* GNUC >= 3.0 */ -#endif /* ATTRIBUTE_PURE */ - -/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL. - This was the case for the `printf' format attribute by itself - before GCC 3.3, but as of 3.3 we need to add the `nonnull' - attribute to retain this behavior. */ -#ifndef ATTRIBUTE_PRINTF -#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m) -#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2) -#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3) -#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4) -#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5) -#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6) -#endif /* ATTRIBUTE_PRINTF */ - -/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on - a function pointer. Format attributes were allowed on function - pointers as of gcc 3.1. */ -#ifndef ATTRIBUTE_FPTR_PRINTF -# if (GCC_VERSION >= 3001) -# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n) -# else -# define ATTRIBUTE_FPTR_PRINTF(m, n) -# endif /* GNUC >= 3.1 */ -# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2) -# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3) -# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4) -# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5) -# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6) -#endif /* ATTRIBUTE_FPTR_PRINTF */ - -/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A - NULL format specifier was allowed as of gcc 3.3. */ -#ifndef ATTRIBUTE_NULL_PRINTF -# if (GCC_VERSION >= 3003) -# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) -# else -# define ATTRIBUTE_NULL_PRINTF(m, n) -# endif /* GNUC >= 3.3 */ -# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2) -# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3) -# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4) -# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5) -# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6) -#endif /* ATTRIBUTE_NULL_PRINTF */ - -/* Attribute `sentinel' was valid as of gcc 3.5. */ -#ifndef ATTRIBUTE_SENTINEL -# if (GCC_VERSION >= 3005) -# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__)) -# else -# define ATTRIBUTE_SENTINEL -# endif /* GNUC >= 3.5 */ -#endif /* ATTRIBUTE_SENTINEL */ - - -#ifndef ATTRIBUTE_ALIGNED_ALIGNOF -# if (GCC_VERSION >= 3000) -# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m)))) -# else -# define ATTRIBUTE_ALIGNED_ALIGNOF(m) -# endif /* GNUC >= 3.0 */ -#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */ - -/* Useful for structures whose layout must much some binary specification - regardless of the alignment and padding qualities of the compiler. */ -#ifndef ATTRIBUTE_PACKED -# define ATTRIBUTE_PACKED __attribute__ ((packed)) -#endif - -/* Attribute `hot' and `cold' was valid as of gcc 4.3. */ -#ifndef ATTRIBUTE_COLD -# if (GCC_VERSION >= 4003) -# define ATTRIBUTE_COLD __attribute__ ((__cold__)) -# else -# define ATTRIBUTE_COLD -# endif /* GNUC >= 4.3 */ -#endif /* ATTRIBUTE_COLD */ -#ifndef ATTRIBUTE_HOT -# if (GCC_VERSION >= 4003) -# define ATTRIBUTE_HOT __attribute__ ((__hot__)) -# else -# define ATTRIBUTE_HOT -# endif /* GNUC >= 4.3 */ -#endif /* ATTRIBUTE_HOT */ - -/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */ -#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED -# if (GCC_VERSION >= 4009) -# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined)) -# else -# define ATTRIBUTE_NO_SANITIZE_UNDEFINED -# endif /* GNUC >= 4.9 */ -#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */ - -/* We use __extension__ in some places to suppress -pedantic warnings - about GCC extensions. This feature didn't work properly before - gcc 2.8. */ -#if GCC_VERSION < 2008 -#define __extension__ -#endif - -/* This is used to declare a const variable which should be visible - outside of the current compilation unit. Use it as - EXPORTED_CONST int i = 1; - This is because the semantics of const are different in C and C++. - "extern const" is permitted in C but it looks strange, and gcc - warns about it when -Wc++-compat is not used. */ -#ifdef __cplusplus -#define EXPORTED_CONST extern const -#else -#define EXPORTED_CONST const -#endif - -/* Be conservative and only use enum bitfields with C++ or GCC. - FIXME: provide a complete autoconf test for buggy enum bitfields. */ - -#ifdef __cplusplus -#define ENUM_BITFIELD(TYPE) enum TYPE -#elif (GCC_VERSION > 2000) -#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE -#else -#define ENUM_BITFIELD(TYPE) unsigned int -#endif - - /* This is used to mark a class or virtual function as final. */ -#if __cplusplus >= 201103L -#define GCC_FINAL final -#elif GCC_VERSION >= 4007 -#define GCC_FINAL __final -#else -#define GCC_FINAL -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ansidecl.h */ diff --git a/src/libbacktrace/atomic.c b/src/libbacktrace/atomic.c deleted file mode 100644 index cb0ad0298e68a..0000000000000 --- a/src/libbacktrace/atomic.c +++ /dev/null @@ -1,113 +0,0 @@ -/* atomic.c -- Support for atomic functions if not present. - Copyright (C) 2013-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include - -#include "backtrace.h" -#include "backtrace-supported.h" -#include "internal.h" - -/* This file holds implementations of the atomic functions that are - used if the host compiler has the sync functions but not the atomic - functions, as is true of versions of GCC before 4.7. */ - -#if !defined (HAVE_ATOMIC_FUNCTIONS) && defined (HAVE_SYNC_FUNCTIONS) - -/* Do an atomic load of a pointer. */ - -void * -backtrace_atomic_load_pointer (void *arg) -{ - void **pp; - void *p; - - pp = (void **) arg; - p = *pp; - while (!__sync_bool_compare_and_swap (pp, p, p)) - p = *pp; - return p; -} - -/* Do an atomic load of an int. */ - -int -backtrace_atomic_load_int (int *p) -{ - int i; - - i = *p; - while (!__sync_bool_compare_and_swap (p, i, i)) - i = *p; - return i; -} - -/* Do an atomic store of a pointer. */ - -void -backtrace_atomic_store_pointer (void *arg, void *p) -{ - void **pp; - void *old; - - pp = (void **) arg; - old = *pp; - while (!__sync_bool_compare_and_swap (pp, old, p)) - old = *pp; -} - -/* Do an atomic store of a size_t value. */ - -void -backtrace_atomic_store_size_t (size_t *p, size_t v) -{ - size_t old; - - old = *p; - while (!__sync_bool_compare_and_swap (p, old, v)) - old = *p; -} - -/* Do an atomic store of a int value. */ - -void -backtrace_atomic_store_int (int *p, int v) -{ - size_t old; - - old = *p; - while (!__sync_bool_compare_and_swap (p, old, v)) - old = *p; -} - -#endif diff --git a/src/libbacktrace/backtrace-supported.h.in b/src/libbacktrace/backtrace-supported.h.in deleted file mode 100644 index ab34199fcd362..0000000000000 --- a/src/libbacktrace/backtrace-supported.h.in +++ /dev/null @@ -1,66 +0,0 @@ -/* backtrace-supported.h.in -- Whether stack backtrace is supported. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -/* The file backtrace-supported.h.in is used by configure to generate - the file backtrace-supported.h. The file backtrace-supported.h may - be #include'd to see whether the backtrace library will be able to - get a backtrace and produce symbolic information. */ - - -/* BACKTRACE_SUPPORTED will be #define'd as 1 if the backtrace library - should work, 0 if it will not. Libraries may #include this to make - other arrangements. */ - -#define BACKTRACE_SUPPORTED @BACKTRACE_SUPPORTED@ - -/* BACKTRACE_USES_MALLOC will be #define'd as 1 if the backtrace - library will call malloc as it works, 0 if it will call mmap - instead. This may be used to determine whether it is safe to call - the backtrace functions from a signal handler. In general this - only applies to calls like backtrace and backtrace_pcinfo. It does - not apply to backtrace_simple, which never calls malloc. It does - not apply to backtrace_print, which always calls fprintf and - therefore malloc. */ - -#define BACKTRACE_USES_MALLOC @BACKTRACE_USES_MALLOC@ - -/* BACKTRACE_SUPPORTS_THREADS will be #define'd as 1 if the backtrace - library is configured with threading support, 0 if not. If this is - 0, the threaded parameter to backtrace_create_state must be passed - as 0. */ - -#define BACKTRACE_SUPPORTS_THREADS @BACKTRACE_SUPPORTS_THREADS@ - -/* BACKTRACE_SUPPORTS_DATA will be #defined'd as 1 if the backtrace_syminfo - will work for variables. It will always work for functions. */ - -#define BACKTRACE_SUPPORTS_DATA @BACKTRACE_SUPPORTS_DATA@ diff --git a/src/libbacktrace/backtrace.c b/src/libbacktrace/backtrace.c deleted file mode 100644 index b89bf554ac548..0000000000000 --- a/src/libbacktrace/backtrace.c +++ /dev/null @@ -1,129 +0,0 @@ -/* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include - -#include "unwind.h" -#include "backtrace.h" -#include "internal.h" - -/* The main backtrace_full routine. */ - -/* Data passed through _Unwind_Backtrace. */ - -struct backtrace_data -{ - /* Number of frames to skip. */ - int skip; - /* Library state. */ - struct backtrace_state *state; - /* Callback routine. */ - backtrace_full_callback callback; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data to pass to callback routines. */ - void *data; - /* Value to return from backtrace_full. */ - int ret; - /* Whether there is any memory available. */ - int can_alloc; -}; - -/* Unwind library callback routine. This is passed to - _Unwind_Backtrace. */ - -static _Unwind_Reason_Code -unwind (struct _Unwind_Context *context, void *vdata) -{ - struct backtrace_data *bdata = (struct backtrace_data *) vdata; - uintptr_t pc; - int ip_before_insn = 0; - -#ifdef HAVE_GETIPINFO - pc = _Unwind_GetIPInfo (context, &ip_before_insn); -#else - pc = _Unwind_GetIP (context); -#endif - - if (bdata->skip > 0) - { - --bdata->skip; - return _URC_NO_REASON; - } - - if (!ip_before_insn) - --pc; - - if (!bdata->can_alloc) - bdata->ret = bdata->callback (bdata->data, pc, NULL, 0, NULL); - else - bdata->ret = backtrace_pcinfo (bdata->state, pc, bdata->callback, - bdata->error_callback, bdata->data); - if (bdata->ret != 0) - return _URC_END_OF_STACK; - - return _URC_NO_REASON; -} - -/* Get a stack backtrace. */ - -int -backtrace_full (struct backtrace_state *state, int skip, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct backtrace_data bdata; - void *p; - - bdata.skip = skip + 1; - bdata.state = state; - bdata.callback = callback; - bdata.error_callback = error_callback; - bdata.data = data; - bdata.ret = 0; - - /* If we can't allocate any memory at all, don't try to produce - file/line information. */ - p = backtrace_alloc (state, 4096, NULL, NULL); - if (p == NULL) - bdata.can_alloc = 0; - else - { - backtrace_free (state, p, 4096, NULL, NULL); - bdata.can_alloc = 1; - } - - _Unwind_Backtrace (unwind, &bdata); - return bdata.ret; -} diff --git a/src/libbacktrace/backtrace.h b/src/libbacktrace/backtrace.h deleted file mode 100644 index d209219d9a419..0000000000000 --- a/src/libbacktrace/backtrace.h +++ /dev/null @@ -1,199 +0,0 @@ -/* backtrace.h -- Public header file for stack backtrace library. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef BACKTRACE_H -#define BACKTRACE_H - -#include -#include - -/* We want to get a definition for uintptr_t, but we still care about - systems that don't have . */ -#if defined(__GLIBC__) && __GLIBC__ >= 2 - -#include - -#elif defined(HAVE_STDINT_H) - -#include - -#else - -/* Systems that don't have must provide gstdint.h, e.g., - from GCC_HEADER_STDINT in configure.ac. */ -#include "gstdint.h" - -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/* The backtrace state. This struct is intentionally not defined in - the public interface. */ - -struct backtrace_state; - -/* The type of the error callback argument to backtrace functions. - This function, if not NULL, will be called for certain error cases. - The DATA argument is passed to the function that calls this one. - The MSG argument is an error message. The ERRNUM argument, if - greater than 0, holds an errno value. The MSG buffer may become - invalid after this function returns. - - As a special case, the ERRNUM argument will be passed as -1 if no - debug info can be found for the executable, but the function - requires debug info (e.g., backtrace_full, backtrace_pcinfo). The - MSG in this case will be something along the lines of "no debug - info". Similarly, ERRNUM will be passed as -1 if there is no - symbol table, but the function requires a symbol table (e.g., - backtrace_syminfo). This may be used as a signal that some other - approach should be tried. */ - -typedef void (*backtrace_error_callback) (void *data, const char *msg, - int errnum); - -/* Create state information for the backtrace routines. This must be - called before any of the other routines, and its return value must - be passed to all of the other routines. FILENAME is the path name - of the executable file; if it is NULL the library will try - system-specific path names. If not NULL, FILENAME must point to a - permanent buffer. If THREADED is non-zero the state may be - accessed by multiple threads simultaneously, and the library will - use appropriate atomic operations. If THREADED is zero the state - may only be accessed by one thread at a time. This returns a state - pointer on success, NULL on error. If an error occurs, this will - call the ERROR_CALLBACK routine. */ - -extern struct backtrace_state *backtrace_create_state ( - const char *filename, int threaded, - backtrace_error_callback error_callback, void *data); - -/* The type of the callback argument to the backtrace_full function. - DATA is the argument passed to backtrace_full. PC is the program - counter. FILENAME is the name of the file containing PC, or NULL - if not available. LINENO is the line number in FILENAME containing - PC, or 0 if not available. FUNCTION is the name of the function - containing PC, or NULL if not available. This should return 0 to - continuing tracing. The FILENAME and FUNCTION buffers may become - invalid after this function returns. */ - -typedef int (*backtrace_full_callback) (void *data, uintptr_t pc, - const char *filename, int lineno, - const char *function); - -/* Get a full stack backtrace. SKIP is the number of frames to skip; - passing 0 will start the trace with the function calling - backtrace_full. DATA is passed to the callback routine. If any - call to CALLBACK returns a non-zero value, the stack backtrace - stops, and backtrace returns that value; this may be used to limit - the number of stack frames desired. If all calls to CALLBACK - return 0, backtrace returns 0. The backtrace_full function will - make at least one call to either CALLBACK or ERROR_CALLBACK. This - function requires debug info for the executable. */ - -extern int backtrace_full (struct backtrace_state *state, int skip, - backtrace_full_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* The type of the callback argument to the backtrace_simple function. - DATA is the argument passed to simple_backtrace. PC is the program - counter. This should return 0 to continue tracing. */ - -typedef int (*backtrace_simple_callback) (void *data, uintptr_t pc); - -/* Get a simple backtrace. SKIP is the number of frames to skip, as - in backtrace. DATA is passed to the callback routine. If any call - to CALLBACK returns a non-zero value, the stack backtrace stops, - and backtrace_simple returns that value. Otherwise - backtrace_simple returns 0. The backtrace_simple function will - make at least one call to either CALLBACK or ERROR_CALLBACK. This - function does not require any debug info for the executable. */ - -extern int backtrace_simple (struct backtrace_state *state, int skip, - backtrace_simple_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* Print the current backtrace in a user readable format to a FILE. - SKIP is the number of frames to skip, as in backtrace_full. Any - error messages are printed to stderr. This function requires debug - info for the executable. */ - -extern void backtrace_print (struct backtrace_state *state, int skip, FILE *); - -/* Given PC, a program counter in the current program, call the - callback function with filename, line number, and function name - information. This will normally call the callback function exactly - once. However, if the PC happens to describe an inlined call, and - the debugging information contains the necessary information, then - this may call the callback function multiple times. This will make - at least one call to either CALLBACK or ERROR_CALLBACK. This - returns the first non-zero value returned by CALLBACK, or 0. */ - -extern int backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, - void *data); - -/* The type of the callback argument to backtrace_syminfo. DATA and - PC are the arguments passed to backtrace_syminfo. SYMNAME is the - name of the symbol for the corresponding code. SYMVAL is the - value and SYMSIZE is the size of the symbol. SYMNAME will be NULL - if no error occurred but the symbol could not be found. */ - -typedef void (*backtrace_syminfo_callback) (void *data, uintptr_t pc, - const char *symname, - uintptr_t symval, - uintptr_t symsize); - -/* Given ADDR, an address or program counter in the current program, - call the callback information with the symbol name and value - describing the function or variable in which ADDR may be found. - This will call either CALLBACK or ERROR_CALLBACK exactly once. - This returns 1 on success, 0 on failure. This function requires - the symbol table but does not require the debug info. Note that if - the symbol table is present but ADDR could not be found in the - table, CALLBACK will be called with a NULL SYMNAME argument. - Returns 1 on success, 0 on error. */ - -extern int backtrace_syminfo (struct backtrace_state *state, uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, - void *data); - -#ifdef __cplusplus -} /* End extern "C". */ -#endif - -#endif diff --git a/src/libbacktrace/btest.c b/src/libbacktrace/btest.c deleted file mode 100644 index 0506d2b112186..0000000000000 --- a/src/libbacktrace/btest.c +++ /dev/null @@ -1,721 +0,0 @@ -/* btest.c -- Test for libbacktrace library - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -/* This program tests the externally visible interfaces of the - libbacktrace library. */ - -#include -#include -#include -#include - -#include "filenames.h" - -#include "backtrace.h" -#include "backtrace-supported.h" - -/* Portable attribute syntax. Actually some of these tests probably - won't work if the attributes are not recognized. */ - -#ifndef GCC_VERSION -# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) -#endif - -#if (GCC_VERSION < 2007) -# define __attribute__(x) -#endif - -#ifndef ATTRIBUTE_UNUSED -# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif - -/* Used to collect backtrace info. */ - -struct info -{ - char *filename; - int lineno; - char *function; -}; - -/* Passed to backtrace callback function. */ - -struct bdata -{ - struct info *all; - size_t index; - size_t max; - int failed; -}; - -/* Passed to backtrace_simple callback function. */ - -struct sdata -{ - uintptr_t *addrs; - size_t index; - size_t max; - int failed; -}; - -/* Passed to backtrace_syminfo callback function. */ - -struct symdata -{ - const char *name; - uintptr_t val, size; - int failed; -}; - -/* The backtrace state. */ - -static void *state; - -/* The number of failures. */ - -static int failures; - -/* Return the base name in a path. */ - -static const char * -base (const char *p) -{ - const char *last; - const char *s; - - last = NULL; - for (s = p; *s != '\0'; ++s) - { - if (IS_DIR_SEPARATOR (*s)) - last = s + 1; - } - return last != NULL ? last : p; -} - -/* Check an entry in a struct info array. */ - -static void -check (const char *name, int index, const struct info *all, int want_lineno, - const char *want_function, int *failed) -{ - if (*failed) - return; - if (all[index].filename == NULL || all[index].function == NULL) - { - fprintf (stderr, "%s: [%d]: missing file name or function name\n", - name, index); - *failed = 1; - return; - } - if (strcmp (base (all[index].filename), "btest.c") != 0) - { - fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index, - all[index].filename); - *failed = 1; - } - if (all[index].lineno != want_lineno) - { - fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index, - all[index].lineno, want_lineno); - *failed = 1; - } - if (strcmp (all[index].function, want_function) != 0) - { - fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index, - all[index].function, want_function); - *failed = 1; - } -} - -/* The backtrace callback function. */ - -static int -callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, - const char *filename, int lineno, const char *function) -{ - struct bdata *data = (struct bdata *) vdata; - struct info *p; - - if (data->index >= data->max) - { - fprintf (stderr, "callback_one: callback called too many times\n"); - data->failed = 1; - return 1; - } - - p = &data->all[data->index]; - if (filename == NULL) - p->filename = NULL; - else - { - p->filename = strdup (filename); - assert (p->filename != NULL); - } - p->lineno = lineno; - if (function == NULL) - p->function = NULL; - else - { - p->function = strdup (function); - assert (p->function != NULL); - } - ++data->index; - - return 0; -} - -/* An error callback passed to backtrace. */ - -static void -error_callback_one (void *vdata, const char *msg, int errnum) -{ - struct bdata *data = (struct bdata *) vdata; - - fprintf (stderr, "%s", msg); - if (errnum > 0) - fprintf (stderr, ": %s", strerror (errnum)); - fprintf (stderr, "\n"); - data->failed = 1; -} - -/* The backtrace_simple callback function. */ - -static int -callback_two (void *vdata, uintptr_t pc) -{ - struct sdata *data = (struct sdata *) vdata; - - if (data->index >= data->max) - { - fprintf (stderr, "callback_two: callback called too many times\n"); - data->failed = 1; - return 1; - } - - data->addrs[data->index] = pc; - ++data->index; - - return 0; -} - -/* An error callback passed to backtrace_simple. */ - -static void -error_callback_two (void *vdata, const char *msg, int errnum) -{ - struct sdata *data = (struct sdata *) vdata; - - fprintf (stderr, "%s", msg); - if (errnum > 0) - fprintf (stderr, ": %s", strerror (errnum)); - fprintf (stderr, "\n"); - data->failed = 1; -} - -/* The backtrace_syminfo callback function. */ - -static void -callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, - const char *symname, uintptr_t symval, - uintptr_t symsize) -{ - struct symdata *data = (struct symdata *) vdata; - - if (symname == NULL) - data->name = NULL; - else - { - data->name = strdup (symname); - assert (data->name != NULL); - } - data->val = symval; - data->size = symsize; -} - -/* The backtrace_syminfo error callback function. */ - -static void -error_callback_three (void *vdata, const char *msg, int errnum) -{ - struct symdata *data = (struct symdata *) vdata; - - fprintf (stderr, "%s", msg); - if (errnum > 0) - fprintf (stderr, ": %s", strerror (errnum)); - fprintf (stderr, "\n"); - data->failed = 1; -} - -/* Test the backtrace function with non-inlined functions. */ - -static int test1 (void) __attribute__ ((noinline, unused)); -static int f2 (int) __attribute__ ((noinline)); -static int f3 (int, int) __attribute__ ((noinline)); - -static int -test1 (void) -{ - /* Returning a value here and elsewhere avoids a tailcall which - would mess up the backtrace. */ - return f2 (__LINE__) + 1; -} - -static int -f2 (int f1line) -{ - return f3 (f1line, __LINE__) + 2; -} - -static int -f3 (int f1line, int f2line) -{ - struct info all[20]; - struct bdata data; - int f3line; - int i; - - data.all = &all[0]; - data.index = 0; - data.max = 20; - data.failed = 0; - - f3line = __LINE__ + 1; - i = backtrace_full (state, 0, callback_one, error_callback_one, &data); - - if (i != 0) - { - fprintf (stderr, "test1: unexpected return value %d\n", i); - data.failed = 1; - } - - if (data.index < 3) - { - fprintf (stderr, - "test1: not enough frames; got %zu, expected at least 3\n", - data.index); - data.failed = 1; - } - - check ("test1", 0, all, f3line, "f3", &data.failed); - check ("test1", 1, all, f2line, "f2", &data.failed); - check ("test1", 2, all, f1line, "test1", &data.failed); - - printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS"); - - if (data.failed) - ++failures; - - return failures; -} - -/* Test the backtrace function with inlined functions. */ - -static inline int test2 (void) __attribute__ ((always_inline, unused)); -static inline int f12 (int) __attribute__ ((always_inline)); -static inline int f13 (int, int) __attribute__ ((always_inline)); - -static inline int -test2 (void) -{ - return f12 (__LINE__) + 1; -} - -static inline int -f12 (int f1line) -{ - return f13 (f1line, __LINE__) + 2; -} - -static inline int -f13 (int f1line, int f2line) -{ - struct info all[20]; - struct bdata data; - int f3line; - int i; - - data.all = &all[0]; - data.index = 0; - data.max = 20; - data.failed = 0; - - f3line = __LINE__ + 1; - i = backtrace_full (state, 0, callback_one, error_callback_one, &data); - - if (i != 0) - { - fprintf (stderr, "test2: unexpected return value %d\n", i); - data.failed = 1; - } - - check ("test2", 0, all, f3line, "f13", &data.failed); - check ("test2", 1, all, f2line, "f12", &data.failed); - check ("test2", 2, all, f1line, "test2", &data.failed); - - printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS"); - - if (data.failed) - ++failures; - - return failures; -} - -/* Test the backtrace_simple function with non-inlined functions. */ - -static int test3 (void) __attribute__ ((noinline, unused)); -static int f22 (int) __attribute__ ((noinline)); -static int f23 (int, int) __attribute__ ((noinline)); - -static int -test3 (void) -{ - return f22 (__LINE__) + 1; -} - -static int -f22 (int f1line) -{ - return f23 (f1line, __LINE__) + 2; -} - -static int -f23 (int f1line, int f2line) -{ - uintptr_t addrs[20]; - struct sdata data; - int f3line; - int i; - - data.addrs = &addrs[0]; - data.index = 0; - data.max = 20; - data.failed = 0; - - f3line = __LINE__ + 1; - i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); - - if (i != 0) - { - fprintf (stderr, "test3: unexpected return value %d\n", i); - data.failed = 1; - } - - if (!data.failed) - { - struct info all[20]; - struct bdata bdata; - int j; - - bdata.all = &all[0]; - bdata.index = 0; - bdata.max = 20; - bdata.failed = 0; - - for (j = 0; j < 3; ++j) - { - i = backtrace_pcinfo (state, addrs[j], callback_one, - error_callback_one, &bdata); - if (i != 0) - { - fprintf (stderr, - ("test3: unexpected return value " - "from backtrace_pcinfo %d\n"), - i); - bdata.failed = 1; - } - if (!bdata.failed && bdata.index != (size_t) (j + 1)) - { - fprintf (stderr, - ("wrong number of calls from backtrace_pcinfo " - "got %u expected %d\n"), - (unsigned int) bdata.index, j + 1); - bdata.failed = 1; - } - } - - check ("test3", 0, all, f3line, "f23", &bdata.failed); - check ("test3", 1, all, f2line, "f22", &bdata.failed); - check ("test3", 2, all, f1line, "test3", &bdata.failed); - - if (bdata.failed) - data.failed = 1; - - for (j = 0; j < 3; ++j) - { - struct symdata symdata; - - symdata.name = NULL; - symdata.val = 0; - symdata.size = 0; - symdata.failed = 0; - - i = backtrace_syminfo (state, addrs[j], callback_three, - error_callback_three, &symdata); - if (i == 0) - { - fprintf (stderr, - ("test3: [%d]: unexpected return value " - "from backtrace_syminfo %d\n"), - j, i); - symdata.failed = 1; - } - - if (!symdata.failed) - { - const char *expected; - - switch (j) - { - case 0: - expected = "f23"; - break; - case 1: - expected = "f22"; - break; - case 2: - expected = "test3"; - break; - default: - assert (0); - } - - if (symdata.name == NULL) - { - fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j); - symdata.failed = 1; - } - /* Use strncmp, not strcmp, because GCC might create a - clone. */ - else if (strncmp (symdata.name, expected, strlen (expected)) - != 0) - { - fprintf (stderr, - ("test3: [%d]: unexpected syminfo name " - "got %s expected %s\n"), - j, symdata.name, expected); - symdata.failed = 1; - } - } - - if (symdata.failed) - data.failed = 1; - } - } - - printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS"); - - if (data.failed) - ++failures; - - return failures; -} - -/* Test the backtrace_simple function with inlined functions. */ - -static inline int test4 (void) __attribute__ ((always_inline, unused)); -static inline int f32 (int) __attribute__ ((always_inline)); -static inline int f33 (int, int) __attribute__ ((always_inline)); - -static inline int -test4 (void) -{ - return f32 (__LINE__) + 1; -} - -static inline int -f32 (int f1line) -{ - return f33 (f1line, __LINE__) + 2; -} - -static inline int -f33 (int f1line, int f2line) -{ - uintptr_t addrs[20]; - struct sdata data; - int f3line; - int i; - - data.addrs = &addrs[0]; - data.index = 0; - data.max = 20; - data.failed = 0; - - f3line = __LINE__ + 1; - i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); - - if (i != 0) - { - fprintf (stderr, "test3: unexpected return value %d\n", i); - data.failed = 1; - } - - if (!data.failed) - { - struct info all[20]; - struct bdata bdata; - - bdata.all = &all[0]; - bdata.index = 0; - bdata.max = 20; - bdata.failed = 0; - - i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one, - &bdata); - if (i != 0) - { - fprintf (stderr, - ("test4: unexpected return value " - "from backtrace_pcinfo %d\n"), - i); - bdata.failed = 1; - } - - check ("test4", 0, all, f3line, "f33", &bdata.failed); - check ("test4", 1, all, f2line, "f32", &bdata.failed); - check ("test4", 2, all, f1line, "test4", &bdata.failed); - - if (bdata.failed) - data.failed = 1; - } - - printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS"); - - if (data.failed) - ++failures; - - return failures; -} - -#if BACKTRACE_SUPPORTS_DATA - -int global = 1; - -static int -test5 (void) -{ - struct symdata symdata; - int i; - uintptr_t addr = (uintptr_t) &global; - - if (sizeof (global) > 1) - addr += 1; - - symdata.name = NULL; - symdata.val = 0; - symdata.size = 0; - symdata.failed = 0; - - i = backtrace_syminfo (state, addr, callback_three, - error_callback_three, &symdata); - if (i == 0) - { - fprintf (stderr, - "test5: unexpected return value from backtrace_syminfo %d\n", - i); - symdata.failed = 1; - } - - if (!symdata.failed) - { - if (symdata.name == NULL) - { - fprintf (stderr, "test5: NULL syminfo name\n"); - symdata.failed = 1; - } - else if (strcmp (symdata.name, "global") != 0) - { - fprintf (stderr, - "test5: unexpected syminfo name got %s expected %s\n", - symdata.name, "global"); - symdata.failed = 1; - } - else if (symdata.val != (uintptr_t) &global) - { - fprintf (stderr, - "test5: unexpected syminfo value got %lx expected %lx\n", - (unsigned long) symdata.val, - (unsigned long) (uintptr_t) &global); - symdata.failed = 1; - } - else if (symdata.size != sizeof (global)) - { - fprintf (stderr, - "test5: unexpected syminfo size got %lx expected %lx\n", - (unsigned long) symdata.size, - (unsigned long) sizeof (global)); - symdata.failed = 1; - } - } - - printf ("%s: backtrace_syminfo variable\n", - symdata.failed ? "FAIL" : "PASS"); - - if (symdata.failed) - ++failures; - - return failures; -} - -#endif /* BACKTRACE_SUPPORTS_DATA */ - -static void -error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg, - int errnum) -{ - fprintf (stderr, "%s", msg); - if (errnum > 0) - fprintf (stderr, ": %s", strerror (errnum)); - fprintf (stderr, "\n"); - exit (EXIT_FAILURE); -} - -/* Run all the tests. */ - -int -main (int argc ATTRIBUTE_UNUSED, char **argv) -{ - state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS, - error_callback_create, NULL); - -#if BACKTRACE_SUPPORTED - test1 (); - test2 (); - test3 (); - test4 (); -#if BACKTRACE_SUPPORTS_DATA - test5 (); -#endif -#endif - - exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); -} diff --git a/src/libbacktrace/config.h.in b/src/libbacktrace/config.h.in deleted file mode 100644 index 87cb805984d4f..0000000000000 --- a/src/libbacktrace/config.h.in +++ /dev/null @@ -1,134 +0,0 @@ -/* config.h.in. Generated from configure.ac by autoheader. */ - -/* ELF size: 32 or 64 */ -#undef BACKTRACE_ELF_SIZE - -/* Define to 1 if you have the __atomic functions */ -#undef HAVE_ATOMIC_FUNCTIONS - -/* Define to 1 if you have the declaration of `strnlen', and to 0 if you - don't. */ -#undef HAVE_DECL_STRNLEN - -/* Define to 1 if you have the header file. */ -#undef HAVE_DLFCN_H - -/* Define if dl_iterate_phdr is available. */ -#undef HAVE_DL_ITERATE_PHDR - -/* Define to 1 if you have the fcntl function */ -#undef HAVE_FCNTL - -/* Define if getexecname is available. */ -#undef HAVE_GETEXECNAME - -/* Define if _Unwind_GetIPInfo is available. */ -#undef HAVE_GETIPINFO - -/* Define to 1 if you have the header file. */ -#undef HAVE_INTTYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_LINK_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_MEMORY_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDINT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STDLIB_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRINGS_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_STRING_H - -/* Define to 1 if you have the __sync functions */ -#undef HAVE_SYNC_FUNCTIONS - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_MMAN_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_STAT_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_SYS_TYPES_H - -/* Define to 1 if you have the header file. */ -#undef HAVE_UNISTD_H - -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#undef LT_OBJDIR - -/* Define to the address where bug reports for this package should be sent. */ -#undef PACKAGE_BUGREPORT - -/* Define to the full name of this package. */ -#undef PACKAGE_NAME - -/* Define to the full name and version of this package. */ -#undef PACKAGE_STRING - -/* Define to the one symbol short name of this package. */ -#undef PACKAGE_TARNAME - -/* Define to the home page for this package. */ -#undef PACKAGE_URL - -/* Define to the version of this package. */ -#undef PACKAGE_VERSION - -/* The size of `char', as computed by sizeof. */ -#undef SIZEOF_CHAR - -/* The size of `int', as computed by sizeof. */ -#undef SIZEOF_INT - -/* The size of `long', as computed by sizeof. */ -#undef SIZEOF_LONG - -/* The size of `short', as computed by sizeof. */ -#undef SIZEOF_SHORT - -/* The size of `void *', as computed by sizeof. */ -#undef SIZEOF_VOID_P - -/* Define to 1 if you have the ANSI C header files. */ -#undef STDC_HEADERS - -/* Enable extensions on AIX 3, Interix. */ -#ifndef _ALL_SOURCE -# undef _ALL_SOURCE -#endif -/* Enable GNU extensions on systems that have them. */ -#ifndef _GNU_SOURCE -# undef _GNU_SOURCE -#endif -/* Enable threading extensions on Solaris. */ -#ifndef _POSIX_PTHREAD_SEMANTICS -# undef _POSIX_PTHREAD_SEMANTICS -#endif -/* Enable extensions on HP NonStop. */ -#ifndef _TANDEM_SOURCE -# undef _TANDEM_SOURCE -#endif -/* Enable general extensions on Solaris. */ -#ifndef __EXTENSIONS__ -# undef __EXTENSIONS__ -#endif - - -/* Define to 1 if on MINIX. */ -#undef _MINIX - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -#undef _POSIX_1_SOURCE - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -#undef _POSIX_SOURCE diff --git a/src/libbacktrace/config.sub b/src/libbacktrace/config.sub deleted file mode 100644 index 40ea5dfe1152f..0000000000000 --- a/src/libbacktrace/config.sub +++ /dev/null @@ -1,1836 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright 1992-2017 Free Software Foundation, Inc. - -timestamp='2017-04-02' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, see . -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that -# program. This Exception is an additional permission under section 7 -# of the GNU General Public License, version 3 ("GPLv3"). - - -# Please send patches to . -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS - -Canonicalize a configuration name. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to ." - -version="\ -GNU config.sub ($timestamp) - -Copyright 1992-2017 Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo $1 - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | cloudabi*-eabi* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray | -microblaze*) - os= - basic_machine=$1 - ;; - -bluegene*) - os=-cnk - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*178) - os=-lynxos178 - ;; - -lynx*5) - os=-lynxos5 - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. -case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | ba \ - | be32 | be64 \ - | bfin \ - | c4x | c8051 | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | e2k | epiphany \ - | fido | fr30 | frv | ft32 \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia16 | ia64 \ - | ip2k | iq2000 \ - | k1om \ - | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ - | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ - | ns16k | ns32k \ - | open8 | or1k | or1knd | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pru \ - | pyramid \ - | riscv32 | riscv64 \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | visium \ - | wasm32 \ - | we32k \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown - ;; - c54x) - basic_machine=tic54x-unknown - ;; - c55x) - basic_machine=tic55x-unknown - ;; - c6x) - basic_machine=tic6x-unknown - ;; - leon|leon[3-9]) - basic_machine=sparc-$basic_machine - ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) - basic_machine=$basic_machine-unknown - os=-none - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) - ;; - ms1) - basic_machine=mt-unknown - ;; - - strongarm | thumb | xscale) - basic_machine=arm-unknown - ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none - ;; - xscaleeb) - basic_machine=armeb-unknown - ;; - - xscaleel) - basic_machine=armel-unknown - ;; - - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | ba-* \ - | be32-* | be64-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | e2k-* | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ - | i*86-* | i860-* | i960-* | ia16-* | ia64-* \ - | ip2k-* | iq2000-* \ - | k1om-* \ - | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa32r6-* | mipsisa32r6el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64r6-* | mipsisa64r6el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | or1k*-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pru-* \ - | pyramid-* \ - | riscv32-* | riscv64-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ - | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ - | tron-* \ - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ - | visium-* \ - | wasm32-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - asmjs) - basic_machine=asmjs-unknown - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; - blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - bluegene*) - basic_machine=powerpc-ibm - os=-cnk - ;; - c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - e500v[12]) - basic_machine=powerpc-unknown - os=$os"spe" - ;; - e500v[12]-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - os=$os"spe" - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; - i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - leon-*|leon[3-9]-*) - basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux - ;; - m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - microblaze*) - basic_machine=microblaze-xilinx - ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould - ;; - neo-tandem) - basic_machine=neo-tandem - ;; - nse-tandem) - basic_machine=nse-tandem - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - nsx-tandem) - basic_machine=nsx-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc | ppcbe) basic_machine=powerpc-unknown - ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - strongarm-* | thumb-*) - basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tile*) - basic_machine=$basic_machine-unknown - os=-linux-gnu - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - wasm32) - basic_machine=wasm32-unknown - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - xscale-* | xscalee[bl]-*) - basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - z80-*-coff) - basic_machine=z80-unknown - os=-sim - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - romp) - basic_machine=romp-ibm - ;; - mmix) - basic_machine=mmix-knuth - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown - ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; - *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` - ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if [ x"$os" != x"" ] -then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux - ;; - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` - ;; - -solaris) - os=-solaris2 - ;; - -svr4*) - os=-sysv4 - ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) - os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` - ;; - # First accept the basic system types. - # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ - | -sym* | -kopensolaris* | -plan9* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* | -cloudabi* | -sortix* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \ - | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ - | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ - | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -qnx*) - case $basic_machine in - x86-* | i*86-*) - ;; - *) - os=-nto$os - ;; - esac - ;; - -nto-qnx*) - ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` - ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` - ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) - os=`echo $os | sed -e 's|linux|linux-gnu|'` - ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` - ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` - ;; - -opened*) - os=-openedition - ;; - -os400*) - os=-os400 - ;; - -wince*) - os=-wince - ;; - -osfrose*) - os=-osfrose - ;; - -osf*) - os=-osf - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -atheos*) - os=-atheos - ;; - -syllable*) - os=-syllable - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -nova*) - os=-rtmk-nova - ;; - -ns2 ) - os=-nextstep2 - ;; - -nsk*) - os=-nsk - ;; - # Preserve the version number of sinix5. - -sinix5.*) - os=`echo $os | sed -e 's|sinix|sysv|'` - ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -es1800*) - os=-ose - ;; - -xenix) - os=-xenix - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint - ;; - -aros*) - os=-aros - ;; - -zvmoe) - os=-zvmoe - ;; - -dicos*) - os=-dicos - ;; - -nacl*) - ;; - -ios) - ;; - -none) - ;; - *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 - exit 1 - ;; -esac -else - -# Here we handle the default operating systems that come with various machines. -# The value should be what the vendor currently ships out the door with their -# machine or put another way, the most popular os provided with the machine. - -# Note that if you're going to try to match "-MANUFACTURER" here (say, -# "-sun"), then you have to tell the case statement up towards the top -# that MANUFACTURER isn't an operating system. Otherwise, code above -# will signal an error saying that MANUFACTURER isn't an operating -# system, and we'll never get to this point. - -case $basic_machine in - score-*) - os=-elf - ;; - spu-*) - os=-elf - ;; - *-acorn) - os=-riscix1.2 - ;; - arm*-rebel) - os=-linux - ;; - arm*-semi) - os=-aout - ;; - c4x-* | tic4x-*) - os=-coff - ;; - c8051-*) - os=-elf - ;; - hexagon-*) - os=-elf - ;; - tic54x-*) - os=-coff - ;; - tic55x-*) - os=-coff - ;; - tic6x-*) - os=-coff - ;; - # This must come before the *-dec entry. - pdp10-*) - os=-tops20 - ;; - pdp11-*) - os=-none - ;; - *-dec | vax-*) - os=-ultrix4.2 - ;; - m68*-apollo) - os=-domain - ;; - i386-sun) - os=-sunos4.0.2 - ;; - m68000-sun) - os=-sunos3 - ;; - m68*-cisco) - os=-aout - ;; - mep-*) - os=-elf - ;; - mips*-cisco) - os=-elf - ;; - mips*-*) - os=-elf - ;; - or32-*) - os=-coff - ;; - *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 - ;; - sparc-* | *-sun) - os=-sunos4.1.1 - ;; - pru-*) - os=-elf - ;; - *-be) - os=-beos - ;; - *-haiku) - os=-haiku - ;; - *-ibm) - os=-aix - ;; - *-knuth) - os=-mmixware - ;; - *-wec) - os=-proelf - ;; - *-winbond) - os=-proelf - ;; - *-oki) - os=-proelf - ;; - *-hp) - os=-hpux - ;; - *-hitachi) - os=-hiux - ;; - i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv - ;; - *-cbm) - os=-amigaos - ;; - *-dg) - os=-dgux - ;; - *-dolphin) - os=-sysv3 - ;; - m68k-ccur) - os=-rtu - ;; - m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 - ;; - *-gould) - os=-sysv - ;; - *-highlevel) - os=-bsd - ;; - *-encore) - os=-bsd - ;; - *-sgi) - os=-irix - ;; - *-siemens) - os=-sysv4 - ;; - *-masscomp) - os=-rtu - ;; - f30[01]-fujitsu | f700-fujitsu) - os=-uxpv - ;; - *-rom68k) - os=-coff - ;; - *-*bug) - os=-coff - ;; - *-apple) - os=-macos - ;; - *-atari*) - os=-mint - ;; - *) - os=-none - ;; -esac -fi - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) - vendor=acorn - ;; - -sunos*) - vendor=sun - ;; - -cnk*|-aix*) - vendor=ibm - ;; - -beos*) - vendor=be - ;; - -hpux*) - vendor=hp - ;; - -mpeix*) - vendor=hp - ;; - -hiux*) - vendor=hitachi - ;; - -unos*) - vendor=crds - ;; - -dgux*) - vendor=dg - ;; - -luna*) - vendor=omron - ;; - -genix*) - vendor=ns - ;; - -mvs* | -opened*) - vendor=ibm - ;; - -os400*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -tpf*) - vendor=ibm - ;; - -vxsim* | -vxworks* | -windiss*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - vendor=atari - ;; - -vos*) - vendor=stratus - ;; - esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` - ;; -esac - -echo $basic_machine$os -exit - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/src/libbacktrace/configure b/src/libbacktrace/configure deleted file mode 100755 index 8bdb29d25606f..0000000000000 --- a/src/libbacktrace/configure +++ /dev/null @@ -1,15199 +0,0 @@ -#! /bin/sh -# Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.64 for package-unused version-unused. -# -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software -# Foundation, Inc. -# -# This configure script is free software; the Free Software Foundation -# gives unlimited permission to copy, distribute and modify it. -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi -" - as_required="as_fn_return () { (exit \$1); } -as_fn_success () { as_fn_return 0; } -as_fn_failure () { as_fn_return 1; } -as_fn_ret_success () { return 0; } -as_fn_ret_failure () { return 1; } - -exitcode=0 -as_fn_success || { exitcode=1; echo as_fn_success failed.; } -as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } -as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } -as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } -if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : - -else - exitcode=1; echo positional parameters were not saved. -fi -test x\$exitcode = x0 || exit 1" - as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO - as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO - eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && - test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 -test \$(( 1 + 1 )) = 2 || exit 1 - - test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( - ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO - PATH=/empty FPATH=/empty; export PATH FPATH - test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ - || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1" - if (eval "$as_required") 2>/dev/null; then : - as_have_required=yes -else - as_have_required=no -fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : - -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -as_found=false -for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - as_found=: - case $as_dir in #( - /*) - for as_base in sh bash ksh sh5; do - # Try only shells that exist, to save several forks. - as_shell=$as_dir/$as_base - if { test -f "$as_shell" || test -f "$as_shell.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : - CONFIG_SHELL=$as_shell as_have_required=yes - if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : - break 2 -fi -fi - done;; - esac - as_found=false -done -$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && - { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : - CONFIG_SHELL=$SHELL as_have_required=yes -fi; } -IFS=$as_save_IFS - - - if test "x$CONFIG_SHELL" != x; then : - # We cannot yet assume a decent shell, so we have to provide a - # neutralization value for shells without unset; and this also - # works around shells that cannot unset nonexistent variables. - BASH_ENV=/dev/null - ENV=/dev/null - (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV - export CONFIG_SHELL - exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} -fi - - if test x$as_have_required = xno; then : - $as_echo "$0: This script requires a shell more modern than all" - $as_echo "$0: the shells that I found on your system." - if test x${ZSH_VERSION+set} = xset ; then - $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" - $as_echo "$0: be upgraded to zsh 4.3.4 or later." - else - $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, -$0: including any error possibly output before this -$0: message. Then install a modern shell, or manually run -$0: the script under such a shell if you do have one." - fi - exit 1 -fi -fi -fi -SHELL=${CONFIG_SHELL-/bin/sh} -export SHELL -# Unset more variables known to interfere with behavior of common tools. -CLICOLOR_FORCE= GREP_OPTIONS= -unset CLICOLOR_FORCE GREP_OPTIONS - -## --------------------- ## -## M4sh Shell Functions. ## -## --------------------- ## -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with status $?, using 1 if that was 0. -as_fn_error () -{ - as_status=$?; test $as_status -eq 0 && as_status=1 - if test "$3"; then - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 - fi - $as_echo "$as_me: error: $1" >&2 - as_fn_exit $as_status -} # as_fn_error - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - - - as_lineno_1=$LINENO as_lineno_1a=$LINENO - as_lineno_2=$LINENO as_lineno_2a=$LINENO - eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && - test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { - # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) - sed -n ' - p - /[$]LINENO/= - ' <$as_myself | - sed ' - s/[$]LINENO.*/&-/ - t lineno - b - :lineno - N - :loop - s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ - t loop - s/-\n.*// - ' >$as_me.lineno && - chmod +x "$as_me.lineno" || - { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } - - # Don't try to exec as it changes $[0], causing all sort of problems - # (the dirname of $[0] is not the place where we might find the - # original and so on. Autoconf is especially sensitive to this). - . "./$as_me.lineno" - # Exit status is that of the last command. - exit -} - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -p' - fi -else - as_ln_s='cp -p' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - -SHELL=${CONFIG_SHELL-/bin/sh} - - -exec 7<&0 &1 - -# Name of the host. -# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, -# so uname gets run too. -ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` - -# -# Initializations. -# -ac_default_prefix=/usr/local -ac_clean_files= -ac_config_libobj_dir=. -LIBOBJS= -cross_compiling=no -subdirs= -MFLAGS= -MAKEFLAGS= - -# Identity of this package. -PACKAGE_NAME='package-unused' -PACKAGE_TARNAME='libbacktrace' -PACKAGE_VERSION='version-unused' -PACKAGE_STRING='package-unused version-unused' -PACKAGE_BUGREPORT='' -PACKAGE_URL='' - -ac_unique_file="backtrace.h" -# Factoring default headers for most tests. -ac_includes_default="\ -#include -#ifdef HAVE_SYS_TYPES_H -# include -#endif -#ifdef HAVE_SYS_STAT_H -# include -#endif -#ifdef STDC_HEADERS -# include -# include -#else -# ifdef HAVE_STDLIB_H -# include -# endif -#endif -#ifdef HAVE_STRING_H -# if !defined STDC_HEADERS && defined HAVE_MEMORY_H -# include -# endif -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif -#ifdef HAVE_INTTYPES_H -# include -#endif -#ifdef HAVE_STDINT_H -# include -#endif -#ifdef HAVE_UNISTD_H -# include -#endif" - -ac_subst_vars='am__EXEEXT_FALSE -am__EXEEXT_TRUE -LTLIBOBJS -LIBOBJS -NATIVE_FALSE -NATIVE_TRUE -BACKTRACE_USES_MALLOC -ALLOC_FILE -VIEW_FILE -BACKTRACE_SUPPORTS_DATA -BACKTRACE_SUPPORTED -FORMAT_FILE -BACKTRACE_SUPPORTS_THREADS -PIC_FLAG -WARN_FLAGS -EXTRA_FLAGS -BACKTRACE_FILE -OTOOL64 -OTOOL -LIPO -NMEDIT -DSYMUTIL -AR -OBJDUMP -LN_S -NM -ac_ct_DUMPBIN -DUMPBIN -LD -FGREP -SED -LIBTOOL -RANLIB -MAINT -MAINTAINER_MODE_FALSE -MAINTAINER_MODE_TRUE -am__untar -am__tar -AMTAR -am__leading_dot -SET_MAKE -AWK -mkdir_p -MKDIR_P -INSTALL_STRIP_PROGRAM -STRIP -install_sh -MAKEINFO -AUTOHEADER -AUTOMAKE -AUTOCONF -ACLOCAL -VERSION -PACKAGE -CYGPATH_W -am__isrc -INSTALL_DATA -INSTALL_SCRIPT -INSTALL_PROGRAM -libtool_VERSION -EGREP -GREP -CPP -OBJEXT -EXEEXT -ac_ct_CC -CPPFLAGS -LDFLAGS -CFLAGS -CC -target_os -target_vendor -target_cpu -target -host_os -host_vendor -host_cpu -host -build_os -build_vendor -build_cpu -build -multi_basedir -target_alias -host_alias -build_alias -LIBS -ECHO_T -ECHO_N -ECHO_C -DEFS -mandir -localedir -libdir -psdir -pdfdir -dvidir -htmldir -infodir -docdir -oldincludedir -includedir -localstatedir -sharedstatedir -sysconfdir -datadir -datarootdir -libexecdir -sbindir -bindir -program_transform_name -prefix -exec_prefix -PACKAGE_URL -PACKAGE_BUGREPORT -PACKAGE_STRING -PACKAGE_VERSION -PACKAGE_TARNAME -PACKAGE_NAME -PATH_SEPARATOR -SHELL' -ac_subst_files='' -ac_user_opts=' -enable_option_checking -enable_multilib -enable_maintainer_mode -with_target_subdir -enable_shared -enable_static -with_pic -enable_fast_install -with_gnu_ld -enable_libtool_lock -with_system_libunwind -enable_host_shared -' - ac_precious_vars='build_alias -host_alias -target_alias -CC -CFLAGS -LDFLAGS -LIBS -CPPFLAGS -CPP' - - -# Initialize some variables set by options. -ac_init_help= -ac_init_version=false -ac_unrecognized_opts= -ac_unrecognized_sep= -# The variables have the same names as the options, with -# dashes changed to underlines. -cache_file=/dev/null -exec_prefix=NONE -no_create= -no_recursion= -prefix=NONE -program_prefix=NONE -program_suffix=NONE -program_transform_name=s,x,x, -silent= -site= -srcdir= -verbose= -x_includes=NONE -x_libraries=NONE - -# Installation directory options. -# These are left unexpanded so users can "make install exec_prefix=/foo" -# and all the variables that are supposed to be based on exec_prefix -# by default will actually change. -# Use braces instead of parens because sh, perl, etc. also accept them. -# (The list follows the same order as the GNU Coding Standards.) -bindir='${exec_prefix}/bin' -sbindir='${exec_prefix}/sbin' -libexecdir='${exec_prefix}/libexec' -datarootdir='${prefix}/share' -datadir='${datarootdir}' -sysconfdir='${prefix}/etc' -sharedstatedir='${prefix}/com' -localstatedir='${prefix}/var' -includedir='${prefix}/include' -oldincludedir='/usr/include' -docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' -infodir='${datarootdir}/info' -htmldir='${docdir}' -dvidir='${docdir}' -pdfdir='${docdir}' -psdir='${docdir}' -libdir='${exec_prefix}/lib' -localedir='${datarootdir}/locale' -mandir='${datarootdir}/man' - -ac_prev= -ac_dashdash= -for ac_option -do - # If the previous option needs an argument, assign it. - if test -n "$ac_prev"; then - eval $ac_prev=\$ac_option - ac_prev= - continue - fi - - case $ac_option in - *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *) ac_optarg=yes ;; - esac - - # Accept the important Cygnus configure options, so we can diagnose typos. - - case $ac_dashdash$ac_option in - --) - ac_dashdash=yes ;; - - -bindir | --bindir | --bindi | --bind | --bin | --bi) - ac_prev=bindir ;; - -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) - bindir=$ac_optarg ;; - - -build | --build | --buil | --bui | --bu) - ac_prev=build_alias ;; - -build=* | --build=* | --buil=* | --bui=* | --bu=*) - build_alias=$ac_optarg ;; - - -cache-file | --cache-file | --cache-fil | --cache-fi \ - | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) - ac_prev=cache_file ;; - -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ - | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) - cache_file=$ac_optarg ;; - - --config-cache | -C) - cache_file=config.cache ;; - - -datadir | --datadir | --datadi | --datad) - ac_prev=datadir ;; - -datadir=* | --datadir=* | --datadi=* | --datad=*) - datadir=$ac_optarg ;; - - -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ - | --dataroo | --dataro | --datar) - ac_prev=datarootdir ;; - -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ - | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) - datarootdir=$ac_optarg ;; - - -disable-* | --disable-*) - ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=no ;; - - -docdir | --docdir | --docdi | --doc | --do) - ac_prev=docdir ;; - -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) - docdir=$ac_optarg ;; - - -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) - ac_prev=dvidir ;; - -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) - dvidir=$ac_optarg ;; - - -enable-* | --enable-*) - ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid feature name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"enable_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval enable_$ac_useropt=\$ac_optarg ;; - - -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ - | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ - | --exec | --exe | --ex) - ac_prev=exec_prefix ;; - -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ - | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ - | --exec=* | --exe=* | --ex=*) - exec_prefix=$ac_optarg ;; - - -gas | --gas | --ga | --g) - # Obsolete; use --with-gas. - with_gas=yes ;; - - -help | --help | --hel | --he | -h) - ac_init_help=long ;; - -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) - ac_init_help=recursive ;; - -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) - ac_init_help=short ;; - - -host | --host | --hos | --ho) - ac_prev=host_alias ;; - -host=* | --host=* | --hos=* | --ho=*) - host_alias=$ac_optarg ;; - - -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) - ac_prev=htmldir ;; - -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ - | --ht=*) - htmldir=$ac_optarg ;; - - -includedir | --includedir | --includedi | --included | --include \ - | --includ | --inclu | --incl | --inc) - ac_prev=includedir ;; - -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ - | --includ=* | --inclu=* | --incl=* | --inc=*) - includedir=$ac_optarg ;; - - -infodir | --infodir | --infodi | --infod | --info | --inf) - ac_prev=infodir ;; - -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) - infodir=$ac_optarg ;; - - -libdir | --libdir | --libdi | --libd) - ac_prev=libdir ;; - -libdir=* | --libdir=* | --libdi=* | --libd=*) - libdir=$ac_optarg ;; - - -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ - | --libexe | --libex | --libe) - ac_prev=libexecdir ;; - -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ - | --libexe=* | --libex=* | --libe=*) - libexecdir=$ac_optarg ;; - - -localedir | --localedir | --localedi | --localed | --locale) - ac_prev=localedir ;; - -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) - localedir=$ac_optarg ;; - - -localstatedir | --localstatedir | --localstatedi | --localstated \ - | --localstate | --localstat | --localsta | --localst | --locals) - ac_prev=localstatedir ;; - -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ - | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) - localstatedir=$ac_optarg ;; - - -mandir | --mandir | --mandi | --mand | --man | --ma | --m) - ac_prev=mandir ;; - -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) - mandir=$ac_optarg ;; - - -nfp | --nfp | --nf) - # Obsolete; use --without-fp. - with_fp=no ;; - - -no-create | --no-create | --no-creat | --no-crea | --no-cre \ - | --no-cr | --no-c | -n) - no_create=yes ;; - - -no-recursion | --no-recursion | --no-recursio | --no-recursi \ - | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) - no_recursion=yes ;; - - -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ - | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ - | --oldin | --oldi | --old | --ol | --o) - ac_prev=oldincludedir ;; - -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ - | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ - | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) - oldincludedir=$ac_optarg ;; - - -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) - ac_prev=prefix ;; - -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) - prefix=$ac_optarg ;; - - -program-prefix | --program-prefix | --program-prefi | --program-pref \ - | --program-pre | --program-pr | --program-p) - ac_prev=program_prefix ;; - -program-prefix=* | --program-prefix=* | --program-prefi=* \ - | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) - program_prefix=$ac_optarg ;; - - -program-suffix | --program-suffix | --program-suffi | --program-suff \ - | --program-suf | --program-su | --program-s) - ac_prev=program_suffix ;; - -program-suffix=* | --program-suffix=* | --program-suffi=* \ - | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) - program_suffix=$ac_optarg ;; - - -program-transform-name | --program-transform-name \ - | --program-transform-nam | --program-transform-na \ - | --program-transform-n | --program-transform- \ - | --program-transform | --program-transfor \ - | --program-transfo | --program-transf \ - | --program-trans | --program-tran \ - | --progr-tra | --program-tr | --program-t) - ac_prev=program_transform_name ;; - -program-transform-name=* | --program-transform-name=* \ - | --program-transform-nam=* | --program-transform-na=* \ - | --program-transform-n=* | --program-transform-=* \ - | --program-transform=* | --program-transfor=* \ - | --program-transfo=* | --program-transf=* \ - | --program-trans=* | --program-tran=* \ - | --progr-tra=* | --program-tr=* | --program-t=*) - program_transform_name=$ac_optarg ;; - - -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) - ac_prev=pdfdir ;; - -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) - pdfdir=$ac_optarg ;; - - -psdir | --psdir | --psdi | --psd | --ps) - ac_prev=psdir ;; - -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) - psdir=$ac_optarg ;; - - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - silent=yes ;; - - -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) - ac_prev=sbindir ;; - -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ - | --sbi=* | --sb=*) - sbindir=$ac_optarg ;; - - -sharedstatedir | --sharedstatedir | --sharedstatedi \ - | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ - | --sharedst | --shareds | --shared | --share | --shar \ - | --sha | --sh) - ac_prev=sharedstatedir ;; - -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ - | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ - | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ - | --sha=* | --sh=*) - sharedstatedir=$ac_optarg ;; - - -site | --site | --sit) - ac_prev=site ;; - -site=* | --site=* | --sit=*) - site=$ac_optarg ;; - - -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) - ac_prev=srcdir ;; - -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) - srcdir=$ac_optarg ;; - - -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ - | --syscon | --sysco | --sysc | --sys | --sy) - ac_prev=sysconfdir ;; - -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ - | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) - sysconfdir=$ac_optarg ;; - - -target | --target | --targe | --targ | --tar | --ta | --t) - ac_prev=target_alias ;; - -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) - target_alias=$ac_optarg ;; - - -v | -verbose | --verbose | --verbos | --verbo | --verb) - verbose=yes ;; - - -version | --version | --versio | --versi | --vers | -V) - ac_init_version=: ;; - - -with-* | --with-*) - ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=\$ac_optarg ;; - - -without-* | --without-*) - ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` - # Reject names that are not valid shell variable names. - expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error "invalid package name: $ac_useropt" - ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` - case $ac_user_opts in - *" -"with_$ac_useropt" -"*) ;; - *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" - ac_unrecognized_sep=', ';; - esac - eval with_$ac_useropt=no ;; - - --x) - # Obsolete; use --with-x. - with_x=yes ;; - - -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ - | --x-incl | --x-inc | --x-in | --x-i) - ac_prev=x_includes ;; - -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ - | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) - x_includes=$ac_optarg ;; - - -x-libraries | --x-libraries | --x-librarie | --x-librari \ - | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) - ac_prev=x_libraries ;; - -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ - | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) - x_libraries=$ac_optarg ;; - - -*) as_fn_error "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information." - ;; - - *=*) - ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` - # Reject names that are not valid shell variable names. - case $ac_envvar in #( - '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error "invalid variable name: \`$ac_envvar'" ;; - esac - eval $ac_envvar=\$ac_optarg - export $ac_envvar ;; - - *) - # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 - expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && - $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 - : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} - ;; - - esac -done - -if test -n "$ac_prev"; then - ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error "missing argument to $ac_option" -fi - -if test -n "$ac_unrecognized_opts"; then - case $enable_option_checking in - no) ;; - fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; - *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; - esac -fi - -# Check all directory arguments for consistency. -for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ - datadir sysconfdir sharedstatedir localstatedir includedir \ - oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ - libdir localedir mandir -do - eval ac_val=\$$ac_var - # Remove trailing slashes. - case $ac_val in - */ ) - ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` - eval $ac_var=\$ac_val;; - esac - # Be sure to have absolute directory names. - case $ac_val in - [\\/$]* | ?:[\\/]* ) continue;; - NONE | '' ) case $ac_var in *prefix ) continue;; esac;; - esac - as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" -done - -# There might be people who depend on the old broken behavior: `$host' -# used to hold the argument of --host etc. -# FIXME: To remove some day. -build=$build_alias -host=$host_alias -target=$target_alias - -# FIXME: To remove some day. -if test "x$host_alias" != x; then - if test "x$build_alias" = x; then - cross_compiling=maybe - $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used." >&2 - elif test "x$build_alias" != "x$host_alias"; then - cross_compiling=yes - fi -fi - -ac_tool_prefix= -test -n "$host_alias" && ac_tool_prefix=$host_alias- - -test "$silent" = yes && exec 6>/dev/null - - -ac_pwd=`pwd` && test -n "$ac_pwd" && -ac_ls_di=`ls -di .` && -ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error "working directory cannot be determined" -test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error "pwd does not report name of working directory" - - -# Find the source files, if location was not specified. -if test -z "$srcdir"; then - ac_srcdir_defaulted=yes - # Try the directory containing this script, then the parent directory. - ac_confdir=`$as_dirname -- "$as_myself" || -$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_myself" : 'X\(//\)[^/]' \| \ - X"$as_myself" : 'X\(//\)$' \| \ - X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_myself" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - srcdir=$ac_confdir - if test ! -r "$srcdir/$ac_unique_file"; then - srcdir=.. - fi -else - ac_srcdir_defaulted=no -fi -if test ! -r "$srcdir/$ac_unique_file"; then - test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" -fi -ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" -ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" - pwd)` -# When building in place, set srcdir=. -if test "$ac_abs_confdir" = "$ac_pwd"; then - srcdir=. -fi -# Remove unnecessary trailing slashes from srcdir. -# Double slashes in file names in object file debugging info -# mess up M-x gdb in Emacs. -case $srcdir in -*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; -esac -for ac_var in $ac_precious_vars; do - eval ac_env_${ac_var}_set=\${${ac_var}+set} - eval ac_env_${ac_var}_value=\$${ac_var} - eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} - eval ac_cv_env_${ac_var}_value=\$${ac_var} -done - -# -# Report the --help message. -# -if test "$ac_init_help" = "long"; then - # Omit some internal or obsolete options to make the list less imposing. - # This message is too long to be a string in the A/UX 3.1 sh. - cat <<_ACEOF -\`configure' configures package-unused version-unused to adapt to many kinds of systems. - -Usage: $0 [OPTION]... [VAR=VALUE]... - -To assign environment variables (e.g., CC, CFLAGS...), specify them as -VAR=VALUE. See below for descriptions of some of the useful variables. - -Defaults for the options are specified in brackets. - -Configuration: - -h, --help display this help and exit - --help=short display options specific to this package - --help=recursive display the short help of all the included packages - -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking...' messages - --cache-file=FILE cache test results in FILE [disabled] - -C, --config-cache alias for \`--cache-file=config.cache' - -n, --no-create do not create output files - --srcdir=DIR find the sources in DIR [configure dir or \`..'] - -Installation directories: - --prefix=PREFIX install architecture-independent files in PREFIX - [$ac_default_prefix] - --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX - [PREFIX] - -By default, \`make install' will install all the files in -\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify -an installation prefix other than \`$ac_default_prefix' using \`--prefix', -for instance \`--prefix=\$HOME'. - -For better control, use the options below. - -Fine tuning of the installation directories: - --bindir=DIR user executables [EPREFIX/bin] - --sbindir=DIR system admin executables [EPREFIX/sbin] - --libexecdir=DIR program executables [EPREFIX/libexec] - --sysconfdir=DIR read-only single-machine data [PREFIX/etc] - --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] - --localstatedir=DIR modifiable single-machine data [PREFIX/var] - --libdir=DIR object code libraries [EPREFIX/lib] - --includedir=DIR C header files [PREFIX/include] - --oldincludedir=DIR C header files for non-gcc [/usr/include] - --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] - --datadir=DIR read-only architecture-independent data [DATAROOTDIR] - --infodir=DIR info documentation [DATAROOTDIR/info] - --localedir=DIR locale-dependent data [DATAROOTDIR/locale] - --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root [DATAROOTDIR/doc/libbacktrace] - --htmldir=DIR html documentation [DOCDIR] - --dvidir=DIR dvi documentation [DOCDIR] - --pdfdir=DIR pdf documentation [DOCDIR] - --psdir=DIR ps documentation [DOCDIR] -_ACEOF - - cat <<\_ACEOF - -Program names: - --program-prefix=PREFIX prepend PREFIX to installed program names - --program-suffix=SUFFIX append SUFFIX to installed program names - --program-transform-name=PROGRAM run sed PROGRAM on installed program names - -System types: - --build=BUILD configure for building on BUILD [guessed] - --host=HOST cross-compile to build programs to run on HOST [BUILD] - --target=TARGET configure for building compilers for TARGET [HOST] -_ACEOF -fi - -if test -n "$ac_init_help"; then - case $ac_init_help in - short | recursive ) echo "Configuration of package-unused version-unused:";; - esac - cat <<\_ACEOF - -Optional Features: - --disable-option-checking ignore unrecognized --enable/--with options - --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) - --enable-FEATURE[=ARG] include FEATURE [ARG=yes] - --enable-multilib build many library versions (default) - --enable-maintainer-mode enable make rules and dependencies not useful - (and sometimes confusing) to the casual installer - --enable-shared[=PKGS] build shared libraries [default=yes] - --enable-static[=PKGS] build static libraries [default=yes] - --enable-fast-install[=PKGS] - optimize for fast installation [default=yes] - --disable-libtool-lock avoid locking (might break parallel builds) - --enable-host-shared build host code as shared libraries - -Optional Packages: - --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] - --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-target-subdir=SUBDIR Configuring in a subdirectory for target - --with-pic try to use only PIC/non-PIC objects [default=use - both] - --with-gnu-ld assume the C compiler uses GNU ld [default=no] - --with-system-libunwind use installed libunwind - -Some influential environment variables: - CC C compiler command - CFLAGS C compiler flags - LDFLAGS linker flags, e.g. -L if you have libraries in a - nonstandard directory - LIBS libraries to pass to the linker, e.g. -l - CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if - you have headers in a nonstandard directory - CPP C preprocessor - -Use these variables to override the choices made by `configure' or to help -it to find libraries and programs with nonstandard names/locations. - -Report bugs to the package provider. -_ACEOF -ac_status=$? -fi - -if test "$ac_init_help" = "recursive"; then - # If there are subdirs, report their specific --help. - for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue - test -d "$ac_dir" || - { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || - continue - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. - if test -f "$ac_srcdir/configure.gnu"; then - echo && - $SHELL "$ac_srcdir/configure.gnu" --help=recursive - elif test -f "$ac_srcdir/configure"; then - echo && - $SHELL "$ac_srcdir/configure" --help=recursive - else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 - fi || ac_status=$? - cd "$ac_pwd" || { ac_status=$?; break; } - done -fi - -test -n "$ac_init_help" && exit $ac_status -if $ac_init_version; then - cat <<\_ACEOF -package-unused configure version-unused -generated by GNU Autoconf 2.64 - -Copyright (C) 2009 Free Software Foundation, Inc. -This configure script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it. -_ACEOF - exit -fi - -## ------------------------ ## -## Autoconf initialization. ## -## ------------------------ ## - -# ac_fn_c_try_compile LINENO -# -------------------------- -# Try to compile conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext - if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest.$ac_objext; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - return $ac_retval - -} # ac_fn_c_try_compile - -# ac_fn_c_try_cpp LINENO -# ---------------------- -# Try to preprocess conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_cpp () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_cpp conftest.$ac_ext" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } >/dev/null && { - test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || - test ! -s conftest.err - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - return $ac_retval - -} # ac_fn_c_try_cpp - -# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists, giving a warning if it cannot be compiled using -# the include files in INCLUDES and setting the cache variable VAR -# accordingly. -ac_fn_c_check_header_mongrel () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -else - # Is the header compilable? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 -$as_echo_n "checking $2 usability... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_header_compiler=yes -else - ac_header_compiler=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 -$as_echo "$ac_header_compiler" >&6; } - -# Is the header present? -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 -$as_echo_n "checking $2 presence... " >&6; } -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include <$2> -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ac_header_preproc=yes -else - ac_header_preproc=no -fi -rm -f conftest.err conftest.$ac_ext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 -$as_echo "$ac_header_preproc" >&6; } - -# So? What about this header? -case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( - yes:no: ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 -$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; - no:yes:* ) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 -$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 -$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 -$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 -$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 -$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} - ;; -esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=\$ac_header_compiler" -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } -fi - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - -} # ac_fn_c_check_header_mongrel - -# ac_fn_c_try_run LINENO -# ---------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes -# that executables *can* be run. -ac_fn_c_try_run () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then : - ac_retval=0 -else - $as_echo "$as_me: program exited with status $ac_status" >&5 - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=$ac_status -fi - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - return $ac_retval - -} # ac_fn_c_try_run - -# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES -# ------------------------------------------------------- -# Tests whether HEADER exists and can be compiled using the include files in -# INCLUDES, setting the cache variable VAR accordingly. -ac_fn_c_check_header_compile () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -#include <$2> -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - -} # ac_fn_c_check_header_compile - -# ac_fn_c_try_link LINENO -# ----------------------- -# Try to link conftest.$ac_ext, and return whether this succeeded. -ac_fn_c_try_link () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext conftest$ac_exeext - if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - grep -v '^ *+' conftest.err >conftest.er1 - cat conftest.er1 >&5 - mv -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && { - test -z "$ac_c_werror_flag" || - test ! -s conftest.err - } && test -s conftest$ac_exeext && { - test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext - }; then : - ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - - ac_retval=1 -fi - # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information - # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would - # interfere with the next link command; also delete a directory that is - # left behind by Apple's compiler. We do this before executing the actions. - rm -rf conftest.dSYM conftest_ipa8_conftest.oo - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - return $ac_retval - -} # ac_fn_c_try_link - -# ac_fn_c_check_func LINENO FUNC VAR -# ---------------------------------- -# Tests whether FUNC exists, setting the cache variable VAR accordingly -ac_fn_c_check_func () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -/* Define $2 to an innocuous variant, in case declares $2. - For example, HP-UX 11i declares gettimeofday. */ -#define $2 innocuous_$2 - -/* System header to define __stub macros and hopefully few prototypes, - which can conflict with char $2 (); below. - Prefer to if __STDC__ is defined, since - exists even on freestanding compilers. */ - -#ifdef __STDC__ -# include -#else -# include -#endif - -#undef $2 - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char $2 (); -/* The GNU C library defines this for functions which it implements - to always fail with ENOSYS. Some functions are actually named - something starting with __ and the normal name is an alias. */ -#if defined __stub_$2 || defined __stub___$2 -choke me -#endif - -int -main () -{ -return $2 (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - -} # ac_fn_c_check_func - -# ac_fn_c_check_type LINENO TYPE VAR INCLUDES -# ------------------------------------------- -# Tests whether TYPE exists after having included INCLUDES, setting cache -# variable VAR accordingly. -ac_fn_c_check_type () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 -$as_echo_n "checking for $2... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - eval "$3=no" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof ($2)) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -if (sizeof (($2))) - return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - eval "$3=yes" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - -} # ac_fn_c_check_type - -# ac_fn_c_compute_int LINENO EXPR VAR INCLUDES -# -------------------------------------------- -# Tries to find the compile-time value of EXPR in a program that includes -# INCLUDES, setting VAR accordingly. Returns whether the value could be -# computed -ac_fn_c_compute_int () -{ - as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if test "$cross_compiling" = yes; then - # Depending upon the size, compute the lo and hi bounds. -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=0 ac_mid=0 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid; break -else - as_fn_arith $ac_mid + 1 && ac_lo=$as_val - if test $ac_lo -le $ac_mid; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid + 1 && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) < 0)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=-1 ac_mid=-1 - while :; do - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) >= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_lo=$ac_mid; break -else - as_fn_arith '(' $ac_mid ')' - 1 && ac_hi=$as_val - if test $ac_mid -le $ac_hi; then - ac_lo= ac_hi= - break - fi - as_fn_arith 2 '*' $ac_mid && ac_mid=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - done -else - ac_lo= ac_hi= -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -# Binary search between lo and hi bounds. -while test "x$ac_lo" != "x$ac_hi"; do - as_fn_arith '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo && ac_mid=$as_val - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -static int test_array [1 - 2 * !(($2) <= $ac_mid)]; -test_array [0] = 0 - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_hi=$ac_mid -else - as_fn_arith '(' $ac_mid ')' + 1 && ac_lo=$as_val -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -done -case $ac_lo in #(( -?*) eval "$3=\$ac_lo"; ac_retval=0 ;; -'') ac_retval=1 ;; -esac - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -static long int longval () { return $2; } -static unsigned long int ulongval () { return $2; } -#include -#include -int -main () -{ - - FILE *f = fopen ("conftest.val", "w"); - if (! f) - return 1; - if (($2) < 0) - { - long int i = longval (); - if (i != ($2)) - return 1; - fprintf (f, "%ld", i); - } - else - { - unsigned long int i = ulongval (); - if (i != ($2)) - return 1; - fprintf (f, "%lu", i); - } - /* Do not output a trailing newline, as this causes \r\n confusion - on some platforms. */ - return ferror (f) || fclose (f) != 0; - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - echo >>conftest.val; read $3 &5 -$as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -$4 -int -main () -{ -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$3=yes" -else - eval "$3=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -eval ac_res=\$$3 - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} - -} # ac_fn_c_check_decl -cat >config.log <<_ACEOF -This file contains any messages produced by compilers while -running configure, to aid debugging if configure makes a mistake. - -It was created by package-unused $as_me version-unused, which was -generated by GNU Autoconf 2.64. Invocation command line was - - $ $0 $@ - -_ACEOF -exec 5>>config.log -{ -cat <<_ASUNAME -## --------- ## -## Platform. ## -## --------- ## - -hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` - -/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` -/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` -/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` -/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` - -_ASUNAME - -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - $as_echo "PATH: $as_dir" - done -IFS=$as_save_IFS - -} >&5 - -cat >&5 <<_ACEOF - - -## ----------- ## -## Core tests. ## -## ----------- ## - -_ACEOF - - -# Keep a trace of the command line. -# Strip out --no-create and --no-recursion so they do not pile up. -# Strip out --silent because we don't want to record it for future runs. -# Also quote any args containing shell meta-characters. -# Make two passes to allow for proper duplicate-argument suppression. -ac_configure_args= -ac_configure_args0= -ac_configure_args1= -ac_must_keep_next=false -for ac_pass in 1 2 -do - for ac_arg - do - case $ac_arg in - -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil) - continue ;; - *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - case $ac_pass in - 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; - 2) - as_fn_append ac_configure_args1 " '$ac_arg'" - if test $ac_must_keep_next = true; then - ac_must_keep_next=false # Got value, back to normal. - else - case $ac_arg in - *=* | --config-cache | -C | -disable-* | --disable-* \ - | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ - | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ - | -with-* | --with-* | -without-* | --without-* | --x) - case "$ac_configure_args0 " in - "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; - esac - ;; - -* ) ac_must_keep_next=true ;; - esac - fi - as_fn_append ac_configure_args " '$ac_arg'" - ;; - esac - done -done -{ ac_configure_args0=; unset ac_configure_args0;} -{ ac_configure_args1=; unset ac_configure_args1;} - -# When interrupted or exit'd, cleanup temporary files, and complete -# config.log. We remove comments because anyway the quotes in there -# would cause problems or look ugly. -# WARNING: Use '\'' to represent an apostrophe within the trap. -# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. -trap 'exit_status=$? - # Save into config.log some information that might help in debugging. - { - echo - - cat <<\_ASBOX -## ---------------- ## -## Cache variables. ## -## ---------------- ## -_ASBOX - echo - # The following way of writing the cache mishandles newlines in values, -( - for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - (set) 2>&1 | - case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - sed -n \ - "s/'\''/'\''\\\\'\'''\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" - ;; #( - *) - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) - echo - - cat <<\_ASBOX -## ----------------- ## -## Output variables. ## -## ----------------- ## -_ASBOX - echo - for ac_var in $ac_subst_vars - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - - if test -n "$ac_subst_files"; then - cat <<\_ASBOX -## ------------------- ## -## File substitutions. ## -## ------------------- ## -_ASBOX - echo - for ac_var in $ac_subst_files - do - eval ac_val=\$$ac_var - case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; - esac - $as_echo "$ac_var='\''$ac_val'\''" - done | sort - echo - fi - - if test -s confdefs.h; then - cat <<\_ASBOX -## ----------- ## -## confdefs.h. ## -## ----------- ## -_ASBOX - echo - cat confdefs.h - echo - fi - test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" - } >&5 - rm -f core *.core core.conftest.* && - rm -f -r conftest* confdefs* conf$$* $ac_clean_files && - exit $exit_status -' 0 -for ac_signal in 1 2 13 15; do - trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal -done -ac_signal=0 - -# confdefs.h avoids OS command line length limits that DEFS can exceed. -rm -f -r conftest* confdefs.h - -$as_echo "/* confdefs.h */" > confdefs.h - -# Predefined preprocessor variables. - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF - -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF - - -# Let the site file select an alternate cache file if it wants to. -# Prefer an explicitly selected file to automatically selected ones. -ac_site_file1=NONE -ac_site_file2=NONE -if test -n "$CONFIG_SITE"; then - ac_site_file1=$CONFIG_SITE -elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site -else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site -fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" -do - test "x$ac_site_file" = xNONE && continue - if test -r "$ac_site_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 -$as_echo "$as_me: loading site script $ac_site_file" >&6;} - sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" - fi -done - -if test -r "$cache_file"; then - # Some versions of bash will fail to source /dev/null (special - # files actually), so we avoid doing that. - if test -f "$cache_file"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 -$as_echo "$as_me: loading cache $cache_file" >&6;} - case $cache_file in - [\\/]* | ?:[\\/]* ) . "$cache_file";; - *) . "./$cache_file";; - esac - fi -else - { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 -$as_echo "$as_me: creating cache $cache_file" >&6;} - >$cache_file -fi - -# Check that the precious variables saved in the cache have kept the same -# value. -ac_cache_corrupted=false -for ac_var in $ac_precious_vars; do - eval ac_old_set=\$ac_cv_env_${ac_var}_set - eval ac_new_set=\$ac_env_${ac_var}_set - eval ac_old_val=\$ac_cv_env_${ac_var}_value - eval ac_new_val=\$ac_env_${ac_var}_value - case $ac_old_set,$ac_new_set in - set,) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,set) - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 -$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} - ac_cache_corrupted=: ;; - ,);; - *) - if test "x$ac_old_val" != "x$ac_new_val"; then - # differences in whitespace do not lead to failure. - ac_old_val_w=`echo x $ac_old_val` - ac_new_val_w=`echo x $ac_new_val` - if test "$ac_old_val_w" != "$ac_new_val_w"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 -$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} - ac_cache_corrupted=: - else - { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 -$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} - eval $ac_var=\$ac_old_val - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 -$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 -$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} - fi;; - esac - # Pass precious variables to config.status. - if test "$ac_new_set" = set; then - case $ac_new_val in - *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; - *) ac_arg=$ac_var=$ac_new_val ;; - esac - case " $ac_configure_args " in - *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. - *) as_fn_append ac_configure_args " '$ac_arg'" ;; - esac - fi -done -if $ac_cache_corrupted; then - { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} - { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 -$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 -fi -## -------------------- ## -## Main body of script. ## -## -------------------- ## - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - - -ac_config_headers="$ac_config_headers config.h" - - -if test -n "${with_target_subdir}"; then - # Default to --enable-multilib -# Check whether --enable-multilib was given. -if test "${enable_multilib+set}" = set; then : - enableval=$enable_multilib; case "$enableval" in - yes) multilib=yes ;; - no) multilib=no ;; - *) as_fn_error "bad value $enableval for multilib option" "$LINENO" 5 ;; - esac -else - multilib=yes -fi - - -# We may get other options which we leave undocumented: -# --with-target-subdir, --with-multisrctop, --with-multisubdir -# See config-ml.in if you want the gory details. - -if test "$srcdir" = "."; then - if test "$with_target_subdir" != "."; then - multi_basedir="$srcdir/$with_multisrctop../.." - else - multi_basedir="$srcdir/$with_multisrctop.." - fi -else - multi_basedir="$srcdir/.." -fi - - -# Even if the default multilib is not a cross compilation, -# it may be that some of the other multilibs are. -if test $cross_compiling = no && test $multilib = yes \ - && test "x${with_multisubdir}" != x ; then - cross_compiling=maybe -fi - -ac_config_commands="$ac_config_commands default-1" - -fi - -ac_aux_dir= -for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - for ac_t in install-sh install.sh shtool; do - if test -f "$ac_dir/$ac_t"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/$ac_t -c" - break 2 - fi - done -done -if test -z "$ac_aux_dir"; then - as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 -fi - -# These three variables are undocumented and unsupported, -# and are intended to be withdrawn in a future Autoconf release. -# They can cause serious problems if a builder's source tree is in a directory -# whose full name contains unusual characters. -ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. -ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. -ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. - - -# Make sure we can run config.sub. -$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || - as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 -$as_echo_n "checking build system type... " >&6; } -if test "${ac_cv_build+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_build_alias=$build_alias -test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` -test "x$ac_build_alias" = x && - as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 -ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || - as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 -$as_echo "$ac_cv_build" >&6; } -case $ac_cv_build in -*-*-*) ;; -*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; -esac -build=$ac_cv_build -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_build -shift -build_cpu=$1 -build_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -build_os=$* -IFS=$ac_save_IFS -case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 -$as_echo_n "checking host system type... " >&6; } -if test "${ac_cv_host+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test "x$host_alias" = x; then - ac_cv_host=$ac_cv_build -else - ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || - as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 -$as_echo "$ac_cv_host" >&6; } -case $ac_cv_host in -*-*-*) ;; -*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; -esac -host=$ac_cv_host -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_host -shift -host_cpu=$1 -host_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -host_os=$* -IFS=$ac_save_IFS -case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 -$as_echo_n "checking target system type... " >&6; } -if test "${ac_cv_target+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test "x$target_alias" = x; then - ac_cv_target=$ac_cv_host -else - ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || - as_fn_error "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 -$as_echo "$ac_cv_target" >&6; } -case $ac_cv_target in -*-*-*) ;; -*) as_fn_error "invalid value of canonical target" "$LINENO" 5;; -esac -target=$ac_cv_target -ac_save_IFS=$IFS; IFS='-' -set x $ac_cv_target -shift -target_cpu=$1 -target_vendor=$2 -shift; shift -# Remember, the first character of IFS is used to create $*, -# except with old shells: -target_os=$* -IFS=$ac_save_IFS -case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac - - -# The aliases save the names the user supplied, while $host etc. -# will get canonicalized. -test -n "$target_alias" && - test "$program_prefix$program_suffix$program_transform_name" = \ - NONENONEs,x,x, && - program_prefix=${target_alias}- - -target_alias=${target_alias-$host_alias} - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "no acceptable C compiler found in \$PATH -See \`config.log' for more details." "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - rm -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" -# Try to create an executable without -o first, disregard a.out. -# It will help us diagnose broken compilers, and finding out an intuition -# of exeext. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 -$as_echo_n "checking for C compiler default output file name... " >&6; } -ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` - -# The possible output files: -ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" - -ac_rmfiles= -for ac_file in $ac_files -do - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - * ) ac_rmfiles="$ac_rmfiles $ac_file";; - esac -done -rm -f $ac_rmfiles - -if { { ac_try="$ac_link_default" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link_default") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. -# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' -# in a Makefile. We should not override ac_cv_exeext if it was cached, -# so that the user can short-circuit this test for compilers unknown to -# Autoconf. -for ac_file in $ac_files '' -do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) - ;; - [ab].out ) - # We found the default executable, but exeext='' is most - # certainly right. - break;; - *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; - then :; else - ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - fi - # We set ac_cv_exeext here because the later test for it is not - # safe: cross compilers may not add the suffix if given an `-o' - # argument, so we may need to know it at that point already. - # Even if this section looks crufty: it has the advantage of - # actually working. - break;; - * ) - break;; - esac -done -test "$ac_cv_exeext" = no && ac_cv_exeext= - -else - ac_file='' -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 -$as_echo "$ac_file" >&6; } -if test -z "$ac_file"; then : - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "C compiler cannot create executables -See \`config.log' for more details." "$LINENO" 5; }; } -fi -ac_exeext=$ac_cv_exeext - -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 -$as_echo_n "checking whether the C compiler works... " >&6; } -# If not cross compiling, check that we can run a simple program. -if test "$cross_compiling" != yes; then - if { ac_try='./$ac_file' - { { case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_try") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; }; then - cross_compiling=no - else - if test "$cross_compiling" = maybe; then - cross_compiling=yes - else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot run C compiled programs. -If you meant to cross compile, use \`--host'. -See \`config.log' for more details." "$LINENO" 5; } - fi - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - -rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out -ac_clean_files=$ac_clean_files_save -# Check that the compiler produces executables we can run. If not, either -# the compiler is broken, or we cross compile. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 -$as_echo_n "checking whether we are cross compiling... " >&6; } -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 -$as_echo "$cross_compiling" >&6; } - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 -$as_echo_n "checking for suffix of executables... " >&6; } -if { { ac_try="$ac_link" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_link") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - # If both `conftest.exe' and `conftest' are `present' (well, observable) -# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will -# work properly (i.e., refer to `conftest.exe'), while it won't with -# `rm'. -for ac_file in conftest.exe conftest conftest.*; do - test -f "$ac_file" || continue - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; - *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` - break;; - * ) break;; - esac -done -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details." "$LINENO" 5; } -fi -rm -f conftest$ac_cv_exeext -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 -$as_echo "$ac_cv_exeext" >&6; } - -rm -f conftest.$ac_ext -EXEEXT=$ac_cv_exeext -ac_exeext=$EXEEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 -$as_echo_n "checking for suffix of object files... " >&6; } -if test "${ac_cv_objext+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -rm -f conftest.o conftest.obj -if { { ac_try="$ac_compile" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compile") 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then : - for ac_file in conftest.o conftest.obj conftest.*; do - test -f "$ac_file" || continue; - case $ac_file in - *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; - *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` - break;; - esac -done -else - $as_echo "$as_me: failed program was:" >&5 -sed 's/^/| /' conftest.$ac_ext >&5 - -{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "cannot compute suffix of object files: cannot compile -See \`config.log' for more details." "$LINENO" 5; } -fi -rm -f conftest.$ac_cv_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 -$as_echo "$ac_cv_objext" >&6; } -OBJEXT=$ac_cv_objext -ac_objext=$OBJEXT -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 -$as_echo_n "checking how to run the C preprocessor... " >&6; } -# On Suns, sometimes $CPP names a directory. -if test -n "$CPP" && test -d "$CPP"; then - CPP= -fi -if test -z "$CPP"; then - if test "${ac_cv_prog_CPP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - # Double quotes because CPP needs to be expanded - for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" - do - ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - break -fi - - done - ac_cv_prog_CPP=$CPP - -fi - CPP=$ac_cv_prog_CPP -else - ac_cv_prog_CPP=$CPP -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 -$as_echo "$CPP" >&6; } -ac_preproc_ok=false -for ac_c_preproc_warn_flag in '' yes -do - # Use a header file that comes with gcc, so configuring glibc - # with a fresh cross-compiler works. - # Prefer to if __STDC__ is defined, since - # exists even on freestanding compilers. - # On the NeXT, cc -E runs the code through the compiler's parser, - # not just through cpp. "Syntax error" is here to catch this case. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#ifdef __STDC__ -# include -#else -# include -#endif - Syntax error -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - -else - # Broken: fails on valid input. -continue -fi -rm -f conftest.err conftest.$ac_ext - - # OK, works on sane cases. Now check whether nonexistent headers - # can be detected and how. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - # Broken: success on invalid input. -continue -else - # Passes both tests. -ac_preproc_ok=: -break -fi -rm -f conftest.err conftest.$ac_ext - -done -# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.err conftest.$ac_ext -if $ac_preproc_ok; then : - -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details." "$LINENO" 5; } -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 -$as_echo_n "checking for grep that handles long lines and -e... " >&6; } -if test "${ac_cv_path_GREP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$GREP"; then - ac_path_GREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in grep ggrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue -# Check for GNU ac_path_GREP and select it if it is found. - # Check for GNU $ac_path_GREP -case `"$ac_path_GREP" --version 2>&1` in -*GNU*) - ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'GREP' >> "conftest.nl" - "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_GREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_GREP="$ac_path_GREP" - ac_path_GREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_GREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_GREP"; then - as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_GREP=$GREP -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 -$as_echo "$ac_cv_path_GREP" >&6; } - GREP="$ac_cv_path_GREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 -$as_echo_n "checking for egrep... " >&6; } -if test "${ac_cv_path_EGREP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 - then ac_cv_path_EGREP="$GREP -E" - else - if test -z "$EGREP"; then - ac_path_EGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in egrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue -# Check for GNU ac_path_EGREP and select it if it is found. - # Check for GNU $ac_path_EGREP -case `"$ac_path_EGREP" --version 2>&1` in -*GNU*) - ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'EGREP' >> "conftest.nl" - "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_EGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_EGREP="$ac_path_EGREP" - ac_path_EGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_EGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_EGREP"; then - as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_EGREP=$EGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 -$as_echo "$ac_cv_path_EGREP" >&6; } - EGREP="$ac_cv_path_EGREP" - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 -$as_echo_n "checking for ANSI C header files... " >&6; } -if test "${ac_cv_header_stdc+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_header_stdc=yes -else - ac_cv_header_stdc=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -if test $ac_cv_header_stdc = yes; then - # SunOS 4.x string.h does not declare mem*, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "memchr" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "free" >/dev/null 2>&1; then : - -else - ac_cv_header_stdc=no -fi -rm -f conftest* - -fi - -if test $ac_cv_header_stdc = yes; then - # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. - if test "$cross_compiling" = yes; then : - : -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#if ((' ' & 0x0FF) == 0x020) -# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') -# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) -#else -# define ISLOWER(c) \ - (('a' <= (c) && (c) <= 'i') \ - || ('j' <= (c) && (c) <= 'r') \ - || ('s' <= (c) && (c) <= 'z')) -# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) -#endif - -#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) -int -main () -{ - int i; - for (i = 0; i < 256; i++) - if (XOR (islower (i), ISLOWER (i)) - || toupper (i) != TOUPPER (i)) - return 2; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - -else - ac_cv_header_stdc=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 -$as_echo "$ac_cv_header_stdc" >&6; } -if test $ac_cv_header_stdc = yes; then - -$as_echo "#define STDC_HEADERS 1" >>confdefs.h - -fi - -# On IRIX 5.3, sys/types and inttypes.h are conflicting. -for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ - inttypes.h stdint.h unistd.h -do : - as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` -ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default -" -eval as_val=\$$as_ac_Header - if test "x$as_val" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 -_ACEOF - -fi - -done - - - - ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" -if test "x$ac_cv_header_minix_config_h" = x""yes; then : - MINIX=yes -else - MINIX= -fi - - - if test "$MINIX" = yes; then - -$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h - - -$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h - - -$as_echo "#define _MINIX 1" >>confdefs.h - - fi - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 -$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } -if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -# define __EXTENSIONS__ 1 - $ac_includes_default -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_safe_to_define___extensions__=yes -else - ac_cv_safe_to_define___extensions__=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 -$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } - test $ac_cv_safe_to_define___extensions__ = yes && - $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h - - $as_echo "#define _ALL_SOURCE 1" >>confdefs.h - - $as_echo "#define _GNU_SOURCE 1" >>confdefs.h - - $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h - - $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h - - - -libtool_VERSION=1:0:0 - - -# 1.11.1: Require that version of automake. -# foreign: Don't require README, INSTALL, NEWS, etc. -# no-define: Don't define PACKAGE and VERSION. -# no-dependencies: Don't generate automatic dependencies. -# (because it breaks when using bootstrap-lean, since some of the -# headers are gone at "make install" time). -# -Wall: Issue all automake warnings. -# -Wno-portability: Don't warn about constructs supported by GNU make. -# (because GCC requires GNU make anyhow). -am__api_version='1.11' - -# Find a good install program. We prefer a C program (faster), -# so one script is as good as another. But avoid the broken or -# incompatible versions: -# SysV /etc/install, /usr/sbin/install -# SunOS /usr/etc/install -# IRIX /sbin/install -# AIX /bin/install -# AmigaOS /C/install, which installs bootblocks on floppy discs -# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag -# AFS /usr/afsws/bin/install, which mishandles nonexistent args -# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" -# OS/2's system install, which has a completely different semantic -# ./install, which can be erroneously created by make from ./install.sh. -# Reject install programs that cannot install multiple files. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 -$as_echo_n "checking for a BSD-compatible install... " >&6; } -if test -z "$INSTALL"; then -if test "${ac_cv_path_install+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - # Account for people who put trailing slashes in PATH elements. -case $as_dir/ in #(( - ./ | .// | /[cC]/* | \ - /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ - ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ - /usr/ucb/* ) ;; - *) - # OSF1 and SCO ODT 3.0 have their own names for install. - # Don't use installbsd from OSF since it installs stuff as root - # by default. - for ac_prog in ginstall scoinst install; do - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then - if test $ac_prog = install && - grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # AIX install. It has an incompatible calling convention. - : - elif test $ac_prog = install && - grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then - # program-specific install script used by HP pwplus--don't use. - : - else - rm -rf conftest.one conftest.two conftest.dir - echo one > conftest.one - echo two > conftest.two - mkdir conftest.dir - if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && - test -s conftest.one && test -s conftest.two && - test -s conftest.dir/conftest.one && - test -s conftest.dir/conftest.two - then - ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" - break 3 - fi - fi - fi - done - done - ;; -esac - - done -IFS=$as_save_IFS - -rm -rf conftest.one conftest.two conftest.dir - -fi - if test "${ac_cv_path_install+set}" = set; then - INSTALL=$ac_cv_path_install - else - # As a last resort, use the slow shell script. Don't cache a - # value for INSTALL within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - INSTALL=$ac_install_sh - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } - -# Use test -z because SunOS4 sh mishandles braces in ${var-val}. -# It thinks the first close brace ends the variable substitution. -test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' - -test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' - -test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 -$as_echo_n "checking whether build environment is sane... " >&6; } -# Just in case -sleep 1 -echo timestamp > conftest.file -# Reject unsafe characters in $srcdir or the absolute working directory -# name. Accept space and tab only in the latter. -am_lf=' -' -case `pwd` in - *[\\\"\#\$\&\'\`$am_lf]*) - as_fn_error "unsafe absolute working directory name" "$LINENO" 5;; -esac -case $srcdir in - *[\\\"\#\$\&\'\`$am_lf\ \ ]*) - as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; -esac - -# Do `set' in a subshell so we don't clobber the current shell's -# arguments. Must try -L first in case configure is actually a -# symlink; some systems play weird games with the mod time of symlinks -# (eg FreeBSD returns the mod time of the symlink's containing -# directory). -if ( - set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` - if test "$*" = "X"; then - # -L didn't work. - set X `ls -t "$srcdir/configure" conftest.file` - fi - rm -f conftest.file - if test "$*" != "X $srcdir/configure conftest.file" \ - && test "$*" != "X conftest.file $srcdir/configure"; then - - # If neither matched, then we have a broken ls. This can happen - # if, for instance, CONFIG_SHELL is bash and it inherits a - # broken ls alias from the environment. This has actually - # happened. Such a system could not be considered "sane". - as_fn_error "ls -t appears to fail. Make sure there is not a broken -alias in your environment" "$LINENO" 5 - fi - - test "$2" = conftest.file - ) -then - # Ok. - : -else - as_fn_error "newly created file is older than distributed files! -Check your system clock" "$LINENO" 5 -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -test "$program_prefix" != NONE && - program_transform_name="s&^&$program_prefix&;$program_transform_name" -# Use a double $ so make ignores it. -test "$program_suffix" != NONE && - program_transform_name="s&\$&$program_suffix&;$program_transform_name" -# Double any \ or $. -# By default was `s,x,x', remove it if useless. -ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' -program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` - -# expand $ac_aux_dir to an absolute path -am_aux_dir=`cd $ac_aux_dir && pwd` - -if test x"${MISSING+set}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; - *) - MISSING="\${SHELL} $am_aux_dir/missing" ;; - esac -fi -# Use eval to expand $SHELL -if eval "$MISSING --run true"; then - am_missing_run="$MISSING --run " -else - am_missing_run= - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 -$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} -fi - -if test x"${install_sh}" != xset; then - case $am_aux_dir in - *\ * | *\ *) - install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; - *) - install_sh="\${SHELL} $am_aux_dir/install-sh" - esac -fi - -# Installed binaries are usually stripped using `strip' when the user -# run `make install-strip'. However `strip' might not be the right -# tool to use in cross-compilation environments, therefore Automake -# will honor the `STRIP' environment variable to overrule this program. -if test "$cross_compiling" != no; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -fi -INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 -$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } -if test -z "$MKDIR_P"; then - if test "${ac_cv_path_mkdir+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in mkdir gmkdir; do - for ac_exec_ext in '' $ac_executable_extensions; do - { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue - case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( - 'mkdir (GNU coreutils) '* | \ - 'mkdir (coreutils) '* | \ - 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext - break 3;; - esac - done - done - done -IFS=$as_save_IFS - -fi - - if test "${ac_cv_path_mkdir+set}" = set; then - MKDIR_P="$ac_cv_path_mkdir -p" - else - # As a last resort, use the slow shell script. Don't cache a - # value for MKDIR_P within a source directory, because that will - # break other packages using the cache if that directory is - # removed, or if the value is a relative name. - test -d ./--version && rmdir ./--version - MKDIR_P="$ac_install_sh -d" - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -$as_echo "$MKDIR_P" >&6; } - -mkdir_p="$MKDIR_P" -case $mkdir_p in - [\\/$]* | ?:[\\/]*) ;; - */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; -esac - -for ac_prog in gawk mawk nawk awk -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AWK+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -$as_echo "$AWK" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AWK" && break -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 -$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } -set x ${MAKE-make} -ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` -if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - cat >conftest.make <<\_ACEOF -SHELL = /bin/sh -all: - @echo '@@@%%%=$(MAKE)=@@@%%%' -_ACEOF -# GNU make sometimes prints "make[1]: Entering...", which would confuse us. -case `${MAKE-make} -f conftest.make 2>/dev/null` in - *@@@%%%=?*=@@@%%%*) - eval ac_cv_prog_make_${ac_make}_set=yes;; - *) - eval ac_cv_prog_make_${ac_make}_set=no;; -esac -rm -f conftest.make -fi -if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - SET_MAKE= -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - SET_MAKE="MAKE=${MAKE-make}" -fi - -rm -rf .tst 2>/dev/null -mkdir .tst 2>/dev/null -if test -d .tst; then - am__leading_dot=. -else - am__leading_dot=_ -fi -rmdir .tst 2>/dev/null - -if test "`cd $srcdir && pwd`" != "`pwd`"; then - # Use -I$(srcdir) only when $(srcdir) != ., so that make's output - # is not polluted with repeated "-I." - am__isrc=' -I$(srcdir)' - # test to see if srcdir already configured - if test -f $srcdir/config.status; then - as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 - fi -fi - -# test whether we have cygpath -if test -z "$CYGPATH_W"; then - if (cygpath --version) >/dev/null 2>/dev/null; then - CYGPATH_W='cygpath -w' - else - CYGPATH_W=echo - fi -fi - - -# Define the identity of the package. - PACKAGE='libbacktrace' - VERSION='version-unused' - - -# Some tools Automake needs. - -ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} - - -AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} - - -AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} - - -AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} - - -MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} - -# We need awk for the "check" target. The system "awk" is bad on -# some platforms. -# Always define AMTAR for backward compatibility. Yes, it's still used -# in the wild :-( We should find a proper way to deprecate it ... -AMTAR='$${TAR-tar}' - -am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 -$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } - # Check whether --enable-maintainer-mode was given. -if test "${enable_maintainer_mode+set}" = set; then : - enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval -else - USE_MAINTAINER_MODE=no -fi - - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 -$as_echo "$USE_MAINTAINER_MODE" >&6; } - if test $USE_MAINTAINER_MODE = yes; then - MAINTAINER_MODE_TRUE= - MAINTAINER_MODE_FALSE='#' -else - MAINTAINER_MODE_TRUE='#' - MAINTAINER_MODE_FALSE= -fi - - MAINT=$MAINTAINER_MODE_TRUE - - - - -# Check whether --with-target-subdir was given. -if test "${with_target_subdir+set}" = set; then : - withval=$with_target_subdir; -fi - - -# We must force CC to /not/ be precious variables; otherwise -# the wrong, non-multilib-adjusted value will be used in multilibs. -# As a side effect, we have to subst CFLAGS ourselves. - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. -set dummy ${ac_tool_prefix}gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="${ac_tool_prefix}gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_CC"; then - ac_ct_CC=$CC - # Extract the first word of "gcc", so it can be a program name with args. -set dummy gcc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_CC="gcc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -else - CC="$ac_cv_prog_CC" -fi - -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. -set dummy ${ac_tool_prefix}cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="${ac_tool_prefix}cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - fi -fi -if test -z "$CC"; then - # Extract the first word of "cc", so it can be a program name with args. -set dummy cc; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else - ac_prog_rejected=no -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then - ac_prog_rejected=yes - continue - fi - ac_cv_prog_CC="cc" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -if test $ac_prog_rejected = yes; then - # We found a bogon in the path, so make sure we never use it. - set dummy $ac_cv_prog_CC - shift - if test $# != 0; then - # We chose a different compiler from the bogus one. - # However, it has the same basename, so the bogon will be chosen - # first if we set CC to just the basename; use the full file name. - shift - ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" - fi -fi -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$CC"; then - if test -n "$ac_tool_prefix"; then - for ac_prog in cl.exe - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$CC"; then - ac_cv_prog_CC="$CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_CC="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -CC=$ac_cv_prog_CC -if test -n "$CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 -$as_echo "$CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$CC" && break - done -fi -if test -z "$CC"; then - ac_ct_CC=$CC - for ac_prog in cl.exe -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_CC"; then - ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_CC="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_CC=$ac_cv_prog_ac_ct_CC -if test -n "$ac_ct_CC"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 -$as_echo "$ac_ct_CC" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_CC" && break -done - - if test "x$ac_ct_CC" = x; then - CC="" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - CC=$ac_ct_CC - fi -fi - -fi - - -test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "no acceptable C compiler found in \$PATH -See \`config.log' for more details." "$LINENO" 5; } - -# Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 -set X $ac_compile -ac_compiler=$2 -for ac_option in --version -v -V -qversion; do - { { ac_try="$ac_compiler $ac_option >&5" -case "(($ac_try" in - *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; - *) ac_try_echo=$ac_try;; -esac -eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 - (eval "$ac_compiler $ac_option >&5") 2>conftest.err - ac_status=$? - if test -s conftest.err; then - sed '10a\ -... rest of stderr output deleted ... - 10q' conftest.err >conftest.er1 - cat conftest.er1 >&5 - rm -f conftest.er1 conftest.err - fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } -done - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 -$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } -if test "${ac_cv_c_compiler_gnu+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -#ifndef __GNUC__ - choke me -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_compiler_gnu=yes -else - ac_compiler_gnu=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -ac_cv_c_compiler_gnu=$ac_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 -$as_echo "$ac_cv_c_compiler_gnu" >&6; } -if test $ac_compiler_gnu = yes; then - GCC=yes -else - GCC= -fi -ac_test_CFLAGS=${CFLAGS+set} -ac_save_CFLAGS=$CFLAGS -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 -$as_echo_n "checking whether $CC accepts -g... " >&6; } -if test "${ac_cv_prog_cc_g+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_save_c_werror_flag=$ac_c_werror_flag - ac_c_werror_flag=yes - ac_cv_prog_cc_g=no - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -else - CFLAGS="" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - -else - ac_c_werror_flag=$ac_save_c_werror_flag - CFLAGS="-g" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_g=yes -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - ac_c_werror_flag=$ac_save_c_werror_flag -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 -$as_echo "$ac_cv_prog_cc_g" >&6; } -if test "$ac_test_CFLAGS" = set; then - CFLAGS=$ac_save_CFLAGS -elif test $ac_cv_prog_cc_g = yes; then - if test "$GCC" = yes; then - CFLAGS="-g -O2" - else - CFLAGS="-g" - fi -else - if test "$GCC" = yes; then - CFLAGS="-O2" - else - CFLAGS= - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 -$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } -if test "${ac_cv_prog_cc_c89+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_cv_prog_cc_c89=no -ac_save_CC=$CC -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include -#include -#include -#include -/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ -struct buf { int x; }; -FILE * (*rcsopen) (struct buf *, struct stat *, int); -static char *e (p, i) - char **p; - int i; -{ - return p[i]; -} -static char *f (char * (*g) (char **, int), char **p, ...) -{ - char *s; - va_list v; - va_start (v,p); - s = g (p, va_arg (v,int)); - va_end (v); - return s; -} - -/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has - function prototypes and stuff, but not '\xHH' hex character constants. - These don't provoke an error unfortunately, instead are silently treated - as 'x'. The following induces an error, until -std is added to get - proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an - array size at least. It's necessary to write '\x00'==0 to get something - that's true only with -std. */ -int osf4_cc_array ['\x00' == 0 ? 1 : -1]; - -/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters - inside strings and character constants. */ -#define FOO(x) 'x' -int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; - -int test (int i, double x); -struct s1 {int (*f) (int a);}; -struct s2 {int (*f) (double a);}; -int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); -int argc; -char **argv; -int -main () -{ -return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; - ; - return 0; -} -_ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" -do - CC="$ac_save_CC $ac_arg" - if ac_fn_c_try_compile "$LINENO"; then : - ac_cv_prog_cc_c89=$ac_arg -fi -rm -f core conftest.err conftest.$ac_objext - test "x$ac_cv_prog_cc_c89" != "xno" && break -done -rm -f conftest.$ac_ext -CC=$ac_save_CC - -fi -# AC_CACHE_VAL -case "x$ac_cv_prog_cc_c89" in - x) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 -$as_echo "none needed" >&6; } ;; - xno) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 -$as_echo "unsupported" >&6; } ;; - *) - CC="$CC $ac_cv_prog_cc_c89" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 -$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; -esac -if test "x$ac_cv_prog_cc_c89" != xno; then : - -fi - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - - -for ac_prog in gawk mawk nawk awk -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AWK+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AWK"; then - ac_cv_prog_AWK="$AWK" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_AWK="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AWK=$ac_cv_prog_AWK -if test -n "$AWK"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 -$as_echo "$AWK" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$AWK" && break -done - -case "$AWK" in -"") as_fn_error "can't build without awk" "$LINENO" 5 ;; -esac - -case `pwd` in - *\ * | *\ *) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 -$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; -esac - - - -macro_version='2.2.7a' -macro_revision='1.3134' - - - - - - - - - - - - - -ltmain="$ac_aux_dir/ltmain.sh" - -# Backslashify metacharacters that are still active within -# double-quoted strings. -sed_quote_subst='s/\(["`$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Sed substitution to delay expansion of an escaped shell variable in a -# double_quote_subst'ed string. -delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' - -# Sed substitution to delay expansion of an escaped single quote. -delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' - -# Sed substitution to avoid accidental globbing in evaled expressions -no_glob_subst='s/\*/\\\*/g' - -ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO -ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 -$as_echo_n "checking how to print strings... " >&6; } -# Test print first, because it will be a builtin if present. -if test "X`print -r -- -n 2>/dev/null`" = X-n && \ - test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='print -r --' -elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then - ECHO='printf %s\n' -else - # Use this function as a fallback that always works. - func_fallback_echo () - { - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' - } - ECHO='func_fallback_echo' -fi - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "" -} - -case "$ECHO" in - printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 -$as_echo "printf" >&6; } ;; - print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 -$as_echo "print -r" >&6; } ;; - *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 -$as_echo "cat" >&6; } ;; -esac - - - - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 -$as_echo_n "checking for a sed that does not truncate output... " >&6; } -if test "${ac_cv_path_SED+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ - for ac_i in 1 2 3 4 5 6 7; do - ac_script="$ac_script$as_nl$ac_script" - done - echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed - { ac_script=; unset ac_script;} - if test -z "$SED"; then - ac_path_SED_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in sed gsed; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_SED" && $as_test_x "$ac_path_SED"; } || continue -# Check for GNU ac_path_SED and select it if it is found. - # Check for GNU $ac_path_SED -case `"$ac_path_SED" --version 2>&1` in -*GNU*) - ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo '' >> "conftest.nl" - "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_SED_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_SED="$ac_path_SED" - ac_path_SED_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_SED_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_SED"; then - as_fn_error "no acceptable sed could be found in \$PATH" "$LINENO" 5 - fi -else - ac_cv_path_SED=$SED -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 -$as_echo "$ac_cv_path_SED" >&6; } - SED="$ac_cv_path_SED" - rm -f conftest.sed - -test -z "$SED" && SED=sed -Xsed="$SED -e 1s/^X//" - - - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 -$as_echo_n "checking for fgrep... " >&6; } -if test "${ac_cv_path_FGREP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 - then ac_cv_path_FGREP="$GREP -F" - else - if test -z "$FGREP"; then - ac_path_FGREP_found=false - # Loop through the user's path and test for each of PROGNAME-LIST - as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_prog in fgrep; do - for ac_exec_ext in '' $ac_executable_extensions; do - ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_FGREP" && $as_test_x "$ac_path_FGREP"; } || continue -# Check for GNU ac_path_FGREP and select it if it is found. - # Check for GNU $ac_path_FGREP -case `"$ac_path_FGREP" --version 2>&1` in -*GNU*) - ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; -*) - ac_count=0 - $as_echo_n 0123456789 >"conftest.in" - while : - do - cat "conftest.in" "conftest.in" >"conftest.tmp" - mv "conftest.tmp" "conftest.in" - cp "conftest.in" "conftest.nl" - $as_echo 'FGREP' >> "conftest.nl" - "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break - diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break - as_fn_arith $ac_count + 1 && ac_count=$as_val - if test $ac_count -gt ${ac_path_FGREP_max-0}; then - # Best one so far, save it but keep looking for a better one - ac_cv_path_FGREP="$ac_path_FGREP" - ac_path_FGREP_max=$ac_count - fi - # 10*(2^10) chars as input seems more than enough - test $ac_count -gt 10 && break - done - rm -f conftest.in conftest.tmp conftest.nl conftest.out;; -esac - - $ac_path_FGREP_found && break 3 - done - done - done -IFS=$as_save_IFS - if test -z "$ac_cv_path_FGREP"; then - as_fn_error "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 - fi -else - ac_cv_path_FGREP=$FGREP -fi - - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 -$as_echo "$ac_cv_path_FGREP" >&6; } - FGREP="$ac_cv_path_FGREP" - - -test -z "$GREP" && GREP=grep - - - - - - - - - - - - - - - - - - - -# Check whether --with-gnu-ld was given. -if test "${with_gnu_ld+set}" = set; then : - withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes -else - with_gnu_ld=no -fi - -ac_prog=ld -if test "$GCC" = yes; then - # Check if gcc -print-prog-name=ld gives a path. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 -$as_echo_n "checking for ld used by $CC... " >&6; } - case $host in - *-*-mingw*) - # gcc leaves a trailing carriage return which upsets mingw - ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; - *) - ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; - esac - case $ac_prog in - # Accept absolute paths. - [\\/]* | ?:[\\/]*) - re_direlt='/[^/][^/]*/\.\./' - # Canonicalize the pathname of ld - ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` - while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do - ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` - done - test -z "$LD" && LD="$ac_prog" - ;; - "") - # If it fails, then pretend we aren't using GCC. - ac_prog=ld - ;; - *) - # If it is relative, then search for the first ld in PATH. - with_gnu_ld=unknown - ;; - esac -elif test "$with_gnu_ld" = yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 -$as_echo_n "checking for GNU ld... " >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 -$as_echo_n "checking for non-GNU ld... " >&6; } -fi -if test "${lt_cv_path_LD+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -z "$LD"; then - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then - lt_cv_path_LD="$ac_dir/$ac_prog" - # Check to see if the program is GNU ld. I'd rather use --version, - # but apparently some variants of GNU ld only accept -v. - # Break only if it was the GNU/non-GNU ld that we prefer. - case `"$lt_cv_path_LD" -v 2>&1 &5 -$as_echo "$LD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi -test -z "$LD" && as_fn_error "no acceptable ld found in \$PATH" "$LINENO" 5 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 -$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } -if test "${lt_cv_prog_gnu_ld+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - # I'd rather use --version here, but apparently some GNU lds only accept -v. -case `$LD -v 2>&1 &5 -$as_echo "$lt_cv_prog_gnu_ld" >&6; } -with_gnu_ld=$lt_cv_prog_gnu_ld - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 -$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } -if test "${lt_cv_path_NM+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$NM"; then - # Let the user override the test. - lt_cv_path_NM="$NM" -else - lt_nm_to_check="${ac_tool_prefix}nm" - if test -n "$ac_tool_prefix" && test "$build" = "$host"; then - lt_nm_to_check="$lt_nm_to_check nm" - fi - for lt_tmp_nm in $lt_nm_to_check; do - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - tmp_nm="$ac_dir/$lt_tmp_nm" - if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then - # Check to see if the nm accepts a BSD-compat flag. - # Adding the `sed 1q' prevents false positives on HP-UX, which says: - # nm: unknown option "B" ignored - # Tru64's nm complains that /dev/null is an invalid object file - case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in - */dev/null* | *'Invalid file or object type'*) - lt_cv_path_NM="$tmp_nm -B" - break - ;; - *) - case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in - */dev/null*) - lt_cv_path_NM="$tmp_nm -p" - break - ;; - *) - lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but - continue # so that we can try to find one that supports BSD flags - ;; - esac - ;; - esac - fi - done - IFS="$lt_save_ifs" - done - : ${lt_cv_path_NM=no} -fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 -$as_echo "$lt_cv_path_NM" >&6; } -if test "$lt_cv_path_NM" != "no"; then - NM="$lt_cv_path_NM" -else - # Didn't find any BSD compatible name lister, look for dumpbin. - if test -n "$DUMPBIN"; then : - # Let the user override the test. - else - if test -n "$ac_tool_prefix"; then - for ac_prog in dumpbin "link -dump" - do - # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. -set dummy $ac_tool_prefix$ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DUMPBIN+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DUMPBIN"; then - ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DUMPBIN=$ac_cv_prog_DUMPBIN -if test -n "$DUMPBIN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 -$as_echo "$DUMPBIN" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$DUMPBIN" && break - done -fi -if test -z "$DUMPBIN"; then - ac_ct_DUMPBIN=$DUMPBIN - for ac_prog in dumpbin "link -dump" -do - # Extract the first word of "$ac_prog", so it can be a program name with args. -set dummy $ac_prog; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_DUMPBIN+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DUMPBIN"; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN -if test -n "$ac_ct_DUMPBIN"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 -$as_echo "$ac_ct_DUMPBIN" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - test -n "$ac_ct_DUMPBIN" && break -done - - if test "x$ac_ct_DUMPBIN" = x; then - DUMPBIN=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DUMPBIN=$ac_ct_DUMPBIN - fi -fi - - case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in - *COFF*) - DUMPBIN="$DUMPBIN -symbols" - ;; - *) - DUMPBIN=: - ;; - esac - fi - - if test "$DUMPBIN" != ":"; then - NM="$DUMPBIN" - fi -fi -test -z "$NM" && NM=nm - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 -$as_echo_n "checking the name lister ($NM) interface... " >&6; } -if test "${lt_cv_nm_interface+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_nm_interface="BSD nm" - echo "int some_variable = 0;" > conftest.$ac_ext - (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) - (eval "$ac_compile" 2>conftest.err) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) - (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) - cat conftest.err >&5 - (eval echo "\"\$as_me:$LINENO: output\"" >&5) - cat conftest.out >&5 - if $GREP 'External.*some_variable' conftest.out > /dev/null; then - lt_cv_nm_interface="MS dumpbin" - fi - rm -f conftest* -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 -$as_echo "$lt_cv_nm_interface" >&6; } - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 -$as_echo_n "checking whether ln -s works... " >&6; } -LN_S=$as_ln_s -if test "$LN_S" = "ln -s"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 -$as_echo "no, using $LN_S" >&6; } -fi - -# find the maximum length of command line arguments -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 -$as_echo_n "checking the maximum length of command line arguments... " >&6; } -if test "${lt_cv_sys_max_cmd_len+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - i=0 - teststring="ABCD" - - case $build_os in - msdosdjgpp*) - # On DJGPP, this test can blow up pretty badly due to problems in libc - # (any single argument exceeding 2000 bytes causes a buffer overrun - # during glob expansion). Even if it were fixed, the result of this - # check would be larger than it should be. - lt_cv_sys_max_cmd_len=12288; # 12K is about right - ;; - - gnu*) - # Under GNU Hurd, this test is not required because there is - # no limit to the length of command line arguments. - # Libtool will interpret -1 as no limit whatsoever - lt_cv_sys_max_cmd_len=-1; - ;; - - cygwin* | mingw* | cegcc*) - # On Win9x/ME, this test blows up -- it succeeds, but takes - # about 5 minutes as the teststring grows exponentially. - # Worse, since 9x/ME are not pre-emptively multitasking, - # you end up with a "frozen" computer, even though with patience - # the test eventually succeeds (with a max line length of 256k). - # Instead, let's just punt: use the minimum linelength reported by - # all of the supported platforms: 8192 (on NT/2K/XP). - lt_cv_sys_max_cmd_len=8192; - ;; - - mint*) - # On MiNT this can take a long time and run out of memory. - lt_cv_sys_max_cmd_len=8192; - ;; - - amigaos*) - # On AmigaOS with pdksh, this test takes hours, literally. - # So we just punt and use a minimum line length of 8192. - lt_cv_sys_max_cmd_len=8192; - ;; - - netbsd* | freebsd* | openbsd* | darwin* | dragonfly* | bitrig*) - # This has been around since 386BSD, at least. Likely further. - if test -x /sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` - elif test -x /usr/sbin/sysctl; then - lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` - else - lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs - fi - # And add a safety zone - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - ;; - - interix*) - # We know the value 262144 and hardcode it with a safety zone (like BSD) - lt_cv_sys_max_cmd_len=196608 - ;; - - osf*) - # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure - # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not - # nice to cause kernel panics so lets avoid the loop below. - # First set a reasonable default. - lt_cv_sys_max_cmd_len=16384 - # - if test -x /sbin/sysconfig; then - case `/sbin/sysconfig -q proc exec_disable_arg_limit` in - *1*) lt_cv_sys_max_cmd_len=-1 ;; - esac - fi - ;; - sco3.2v5*) - lt_cv_sys_max_cmd_len=102400 - ;; - sysv5* | sco5v6* | sysv4.2uw2*) - kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` - if test -n "$kargmax"; then - lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` - else - lt_cv_sys_max_cmd_len=32768 - fi - ;; - *) - lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` - if test -n "$lt_cv_sys_max_cmd_len"; then - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` - else - # Make teststring a little bigger before we do anything with it. - # a 1K string should be a reasonable start. - for i in 1 2 3 4 5 6 7 8 ; do - teststring=$teststring$teststring - done - SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} - # If test is not a shell built-in, we'll probably end up computing a - # maximum length that is only half of the actual maximum length, but - # we can't tell. - while { test "X"`func_fallback_echo "$teststring$teststring" 2>/dev/null` \ - = "X$teststring$teststring"; } >/dev/null 2>&1 && - test $i != 17 # 1/2 MB should be enough - do - i=`expr $i + 1` - teststring=$teststring$teststring - done - # Only check the string length outside the loop. - lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` - teststring= - # Add a significant safety factor because C++ compilers can tack on - # massive amounts of additional arguments before passing them to the - # linker. It appears as though 1/2 is a usable value. - lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` - fi - ;; - esac - -fi - -if test -n $lt_cv_sys_max_cmd_len ; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 -$as_echo "$lt_cv_sys_max_cmd_len" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 -$as_echo "none" >&6; } -fi -max_cmd_len=$lt_cv_sys_max_cmd_len - - - - - - -: ${CP="cp -f"} -: ${MV="mv -f"} -: ${RM="rm -f"} - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 -$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } -# Try some XSI features -xsi_shell=no -( _lt_dummy="a/b/c" - test "${_lt_dummy##*/},${_lt_dummy%/*},"${_lt_dummy%"$_lt_dummy"}, \ - = c,a/b,, \ - && eval 'test $(( 1 + 1 )) -eq 2 \ - && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ - && xsi_shell=yes -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 -$as_echo "$xsi_shell" >&6; } - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 -$as_echo_n "checking whether the shell understands \"+=\"... " >&6; } -lt_shell_append=no -( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ - >/dev/null 2>&1 \ - && lt_shell_append=yes -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 -$as_echo "$lt_shell_append" >&6; } - - -if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then - lt_unset=unset -else - lt_unset=false -fi - - - - - -# test EBCDIC or ASCII -case `echo X|tr X '\101'` in - A) # ASCII based system - # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr - lt_SP2NL='tr \040 \012' - lt_NL2SP='tr \015\012 \040\040' - ;; - *) # EBCDIC based system - lt_SP2NL='tr \100 \n' - lt_NL2SP='tr \r\n \100\100' - ;; -esac - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 -$as_echo_n "checking for $LD option to reload object files... " >&6; } -if test "${lt_cv_ld_reload_flag+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_reload_flag='-r' -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 -$as_echo "$lt_cv_ld_reload_flag" >&6; } -reload_flag=$lt_cv_ld_reload_flag -case $reload_flag in -"" | " "*) ;; -*) reload_flag=" $reload_flag" ;; -esac -reload_cmds='$LD$reload_flag -o $output$reload_objs' -case $host_os in - darwin*) - if test "$GCC" = yes; then - reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' - else - reload_cmds='$LD$reload_flag -o $output$reload_objs' - fi - ;; -esac - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. -set dummy ${ac_tool_prefix}objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OBJDUMP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OBJDUMP"; then - ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OBJDUMP=$ac_cv_prog_OBJDUMP -if test -n "$OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 -$as_echo "$OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OBJDUMP"; then - ac_ct_OBJDUMP=$OBJDUMP - # Extract the first word of "objdump", so it can be a program name with args. -set dummy objdump; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OBJDUMP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OBJDUMP"; then - ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_OBJDUMP="objdump" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP -if test -n "$ac_ct_OBJDUMP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 -$as_echo "$ac_ct_OBJDUMP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OBJDUMP" = x; then - OBJDUMP="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OBJDUMP=$ac_ct_OBJDUMP - fi -else - OBJDUMP="$ac_cv_prog_OBJDUMP" -fi - -test -z "$OBJDUMP" && OBJDUMP=objdump - - - - - - - - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 -$as_echo_n "checking how to recognize dependent libraries... " >&6; } -if test "${lt_cv_deplibs_check_method+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_file_magic_cmd='$MAGIC_CMD' -lt_cv_file_magic_test_file= -lt_cv_deplibs_check_method='unknown' -# Need to set the preceding variable on all platforms that support -# interlibrary dependencies. -# 'none' -- dependencies not supported. -# `unknown' -- same as none, but documents that we really don't know. -# 'pass_all' -- all dependencies passed with no checks. -# 'test_compile' -- check by making test program. -# 'file_magic [[regex]]' -- check by looking for files in library path -# which responds to the $file_magic_cmd with a given extended regex. -# If you have `file' or equivalent on your system and you're not sure -# whether `pass_all' will *always* work, you probably want this one. - -case $host_os in -aix[4-9]*) - lt_cv_deplibs_check_method=pass_all - ;; - -beos*) - lt_cv_deplibs_check_method=pass_all - ;; - -bsdi[45]*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' - lt_cv_file_magic_cmd='/usr/bin/file -L' - lt_cv_file_magic_test_file=/shlib/libc.so - ;; - -cygwin*) - # func_win32_libid is a shell function defined in ltmain.sh - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - ;; - -mingw* | pw32*) - # Base MSYS/MinGW do not provide the 'file' command needed by - # func_win32_libid shell function, so use a weaker test based on 'objdump', - # unless we find 'file', for example because we are cross-compiling. - # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. - if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then - lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' - lt_cv_file_magic_cmd='func_win32_libid' - else - lt_cv_deplibs_check_method='file_magic file format pei*-i386(.*architecture: i386)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - fi - ;; - -cegcc*) - # use the weaker test based on 'objdump'. See mingw*. - lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' - lt_cv_file_magic_cmd='$OBJDUMP -f' - ;; - -darwin* | rhapsody*) - lt_cv_deplibs_check_method=pass_all - ;; - -freebsd* | dragonfly*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - case $host_cpu in - i*86 ) - # Not sure whether the presence of OpenBSD here was a mistake. - # Let's accept both of them until this is cleared up. - lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` - ;; - esac - else - lt_cv_deplibs_check_method=pass_all - fi - ;; - -gnu*) - lt_cv_deplibs_check_method=pass_all - ;; - -haiku*) - lt_cv_deplibs_check_method=pass_all - ;; - -hpux10.20* | hpux11*) - lt_cv_file_magic_cmd=/usr/bin/file - case $host_cpu in - ia64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' - lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so - ;; - hppa*64*) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' - lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl - ;; - *) - lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' - lt_cv_file_magic_test_file=/usr/lib/libc.sl - ;; - esac - ;; - -interix[3-9]*) - # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' - ;; - -irix5* | irix6* | nonstopux*) - case $LD in - *-32|*"-32 ") libmagic=32-bit;; - *-n32|*"-n32 ") libmagic=N32;; - *-64|*"-64 ") libmagic=64-bit;; - *) libmagic=never-match;; - esac - lt_cv_deplibs_check_method=pass_all - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu) - lt_cv_deplibs_check_method=pass_all - ;; - -netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' - fi - ;; - -newos6*) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' - lt_cv_file_magic_cmd=/usr/bin/file - lt_cv_file_magic_test_file=/usr/lib/libnls.so - ;; - -*nto* | *qnx*) - lt_cv_deplibs_check_method=pass_all - ;; - -openbsd*) - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' - else - lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' - fi - ;; - -osf3* | osf4* | osf5*) - lt_cv_deplibs_check_method=pass_all - ;; - -rdos*) - lt_cv_deplibs_check_method=pass_all - ;; - -solaris*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - lt_cv_deplibs_check_method=pass_all - ;; - -sysv4 | sysv4.3*) - case $host_vendor in - motorola) - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' - lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` - ;; - ncr) - lt_cv_deplibs_check_method=pass_all - ;; - sequent) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' - ;; - sni) - lt_cv_file_magic_cmd='/bin/file' - lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" - lt_cv_file_magic_test_file=/lib/libc.so - ;; - siemens) - lt_cv_deplibs_check_method=pass_all - ;; - pc) - lt_cv_deplibs_check_method=pass_all - ;; - esac - ;; - -tpf*) - lt_cv_deplibs_check_method=pass_all - ;; -esac - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 -$as_echo "$lt_cv_deplibs_check_method" >&6; } -file_magic_cmd=$lt_cv_file_magic_cmd -deplibs_check_method=$lt_cv_deplibs_check_method -test -z "$deplibs_check_method" && deplibs_check_method=unknown - - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args. -set dummy ${ac_tool_prefix}ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_AR+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$AR"; then - ac_cv_prog_AR="$AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_AR="${ac_tool_prefix}ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -AR=$ac_cv_prog_AR -if test -n "$AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 -$as_echo "$AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_AR"; then - ac_ct_AR=$AR - # Extract the first word of "ar", so it can be a program name with args. -set dummy ar; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_AR+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_AR"; then - ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_AR="ar" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_AR=$ac_cv_prog_ac_ct_AR -if test -n "$ac_ct_AR"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 -$as_echo "$ac_ct_AR" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_AR" = x; then - AR="false" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - AR=$ac_ct_AR - fi -else - AR="$ac_cv_prog_AR" -fi - -test -z "$AR" && AR=ar -test -z "$AR_FLAGS" && AR_FLAGS=cru - - - - - - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. -set dummy ${ac_tool_prefix}strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_STRIP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$STRIP"; then - ac_cv_prog_STRIP="$STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_STRIP="${ac_tool_prefix}strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -STRIP=$ac_cv_prog_STRIP -if test -n "$STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 -$as_echo "$STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_STRIP"; then - ac_ct_STRIP=$STRIP - # Extract the first word of "strip", so it can be a program name with args. -set dummy strip; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_STRIP"; then - ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_STRIP="strip" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP -if test -n "$ac_ct_STRIP"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 -$as_echo "$ac_ct_STRIP" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_STRIP" = x; then - STRIP=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - STRIP=$ac_ct_STRIP - fi -else - STRIP="$ac_cv_prog_STRIP" -fi - -test -z "$STRIP" && STRIP=: - - - - - - -if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. -set dummy ${ac_tool_prefix}ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_RANLIB+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$RANLIB"; then - ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -RANLIB=$ac_cv_prog_RANLIB -if test -n "$RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 -$as_echo "$RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_RANLIB"; then - ac_ct_RANLIB=$RANLIB - # Extract the first word of "ranlib", so it can be a program name with args. -set dummy ranlib; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_RANLIB"; then - ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_RANLIB="ranlib" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB -if test -n "$ac_ct_RANLIB"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 -$as_echo "$ac_ct_RANLIB" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_RANLIB" = x; then - RANLIB=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - RANLIB=$ac_ct_RANLIB - fi -else - RANLIB="$ac_cv_prog_RANLIB" -fi - -test -z "$RANLIB" && RANLIB=: - - - - - - -# Determine commands to create old-style static archives. -old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' -old_postinstall_cmds='chmod 644 $oldlib' -old_postuninstall_cmds= - -if test -n "$RANLIB"; then - case $host_os in - openbsd*) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$oldlib" - ;; - *) - old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$oldlib" - ;; - esac - old_archive_cmds="$old_archive_cmds~\$RANLIB \$oldlib" -fi - -case $host_os in - darwin*) - lock_old_archive_extraction=yes ;; - *) - lock_old_archive_extraction=no ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - - -# Check for command to grab the raw symbol name followed by C symbol from nm. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 -$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } -if test "${lt_cv_sys_global_symbol_pipe+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - -# These are sane defaults that work on at least a few old systems. -# [They come from Ultrix. What could be older than Ultrix?!! ;)] - -# Character class describing NM global symbol codes. -symcode='[BCDEGRST]' - -# Regexp to match symbols that can be accessed directly from C. -sympat='\([_A-Za-z][_A-Za-z0-9]*\)' - -# Define system-specific variables. -case $host_os in -aix*) - symcode='[BCDT]' - ;; -cygwin* | mingw* | pw32* | cegcc*) - symcode='[ABCDGISTW]' - ;; -hpux*) - if test "$host_cpu" = ia64; then - symcode='[ABCDEGRST]' - fi - ;; -irix* | nonstopux*) - symcode='[BCDEGRST]' - ;; -osf*) - symcode='[BCDEGQRST]' - ;; -solaris*) - symcode='[BDRT]' - ;; -sco3.2v5*) - symcode='[DT]' - ;; -sysv4.2uw2*) - symcode='[DT]' - ;; -sysv5* | sco5v6* | unixware* | OpenUNIX*) - symcode='[ABDT]' - ;; -sysv4) - symcode='[DFNSTU]' - ;; -esac - -# If we're using GNU nm, then use its standard symbol codes. -case `$NM -V 2>&1` in -*GNU* | *'with BFD'*) - symcode='[ABCDGIRSTW]' ;; -esac - -# Transform an extracted symbol line into a proper C declaration. -# Some systems (esp. on ia64) link data and code symbols differently, -# so use this general approach. -lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" - -# Transform an extracted symbol line into symbol name and symbol address -lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\) $/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" - -# Handle CRLF in mingw tool chain -opt_cr= -case $build_os in -mingw*) - opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp - ;; -esac - -# Try without a prefix underscore, then with it. -for ac_symprfx in "" "_"; do - - # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. - symxfrm="\\1 $ac_symprfx\\2 \\2" - - # Write the raw and C identifiers. - if test "$lt_cv_nm_interface" = "MS dumpbin"; then - # Fake it for dumpbin and say T for any non-static function - # and D for any global variable. - # Also find C++ and __fastcall symbols from MSVC++, - # which start with @ or ?. - lt_cv_sys_global_symbol_pipe="$AWK '"\ -" {last_section=section; section=\$ 3};"\ -" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ -" \$ 0!~/External *\|/{next};"\ -" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ -" {if(hide[section]) next};"\ -" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ -" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ -" s[1]~/^[@?]/{print s[1], s[1]; next};"\ -" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ -" ' prfx=^$ac_symprfx" - else - lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" - fi - - # Check to see that the pipe works correctly. - pipe_works=no - - rm -f conftest* - cat > conftest.$ac_ext <<_LT_EOF -#ifdef __cplusplus -extern "C" { -#endif -char nm_test_var; -void nm_test_func(void); -void nm_test_func(void){} -#ifdef __cplusplus -} -#endif -int main(){nm_test_var='a';nm_test_func();return(0);} -_LT_EOF - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - # Now try to grab the symbols. - nlist=conftest.nm - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 - (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s "$nlist"; then - # Try sorting and uniquifying the output. - if sort "$nlist" | uniq > "$nlist"T; then - mv -f "$nlist"T "$nlist" - else - rm -f "$nlist"T - fi - - # Make sure that we snagged all the symbols we need. - if $GREP ' nm_test_var$' "$nlist" >/dev/null; then - if $GREP ' nm_test_func$' "$nlist" >/dev/null; then - cat <<_LT_EOF > conftest.$ac_ext -#ifdef __cplusplus -extern "C" { -#endif - -_LT_EOF - # Now generate the symbol file. - eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' - - cat <<_LT_EOF >> conftest.$ac_ext - -/* The mapping between symbol names and symbols. */ -const struct { - const char *name; - void *address; -} -lt__PROGRAM__LTX_preloaded_symbols[] = -{ - { "@PROGRAM@", (void *) 0 }, -_LT_EOF - $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext - cat <<\_LT_EOF >> conftest.$ac_ext - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt__PROGRAM__LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif -_LT_EOF - # Now try linking the two files. - mv conftest.$ac_objext conftstm.$ac_objext - lt_save_LIBS="$LIBS" - lt_save_CFLAGS="$CFLAGS" - LIBS="conftstm.$ac_objext" - CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext}; then - pipe_works=yes - fi - LIBS="$lt_save_LIBS" - CFLAGS="$lt_save_CFLAGS" - else - echo "cannot find nm_test_func in $nlist" >&5 - fi - else - echo "cannot find nm_test_var in $nlist" >&5 - fi - else - echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 - fi - else - echo "$progname: failed program was:" >&5 - cat conftest.$ac_ext >&5 - fi - rm -rf conftest* conftst* - - # Do not use the global_symbol_pipe unless it works. - if test "$pipe_works" = yes; then - break - else - lt_cv_sys_global_symbol_pipe= - fi -done - -fi - -if test -z "$lt_cv_sys_global_symbol_pipe"; then - lt_cv_sys_global_symbol_to_cdecl= -fi -if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 -$as_echo "failed" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 -$as_echo "ok" >&6; } -fi - - - - - - - - - - - - - - - - - - - - - - -# Check whether --enable-libtool-lock was given. -if test "${enable_libtool_lock+set}" = set; then : - enableval=$enable_libtool_lock; -fi - -test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes - -# Some flags need to be propagated to the compiler or linker for good -# libtool support. -case $host in -ia64-*-hpux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.$ac_objext` in - *ELF-32*) - HPUX_IA64_MODE="32" - ;; - *ELF-64*) - HPUX_IA64_MODE="64" - ;; - esac - fi - rm -rf conftest* - ;; -*-*-irix6*) - # Find out which ABI we are using. - echo '#line '$LINENO' "configure"' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - if test "$lt_cv_prog_gnu_ld" = yes; then - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -melf32bsmip" - ;; - *N32*) - LD="${LD-ld} -melf32bmipn32" - ;; - *64-bit*) - LD="${LD-ld} -melf64bmip" - ;; - esac - else - case `/usr/bin/file conftest.$ac_objext` in - *32-bit*) - LD="${LD-ld} -32" - ;; - *N32*) - LD="${LD-ld} -n32" - ;; - *64-bit*) - LD="${LD-ld} -64" - ;; - esac - fi - fi - rm -rf conftest* - ;; - -x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \ -s390*-*linux*|s390*-*tpf*|sparc*-*linux*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.o` in - *32-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_i386_fbsd" - ;; - x86_64-*linux*) - case `/usr/bin/file conftest.o` in - *x86-64*) - LD="${LD-ld} -m elf32_x86_64" - ;; - *) - LD="${LD-ld} -m elf_i386" - ;; - esac - ;; - powerpc64le-*linux*) - LD="${LD-ld} -m elf32lppclinux" - ;; - powerpc64-*linux*) - LD="${LD-ld} -m elf32ppclinux" - ;; - s390x-*linux*) - LD="${LD-ld} -m elf_s390" - ;; - sparc64-*linux*) - LD="${LD-ld} -m elf32_sparc" - ;; - esac - ;; - *64-bit*) - case $host in - x86_64-*kfreebsd*-gnu) - LD="${LD-ld} -m elf_x86_64_fbsd" - ;; - x86_64-*linux*) - LD="${LD-ld} -m elf_x86_64" - ;; - powerpcle-*linux*) - LD="${LD-ld} -m elf64lppc" - ;; - powerpc-*linux*) - LD="${LD-ld} -m elf64ppc" - ;; - s390*-*linux*|s390*-*tpf*) - LD="${LD-ld} -m elf64_s390" - ;; - sparc*-*linux*) - LD="${LD-ld} -m elf64_sparc" - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; - -*-*-sco3.2v5*) - # On SCO OpenServer 5, we need -belf to get full-featured binaries. - SAVE_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -belf" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 -$as_echo_n "checking whether the C compiler needs -belf... " >&6; } -if test "${lt_cv_cc_needs_belf+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - lt_cv_cc_needs_belf=yes -else - lt_cv_cc_needs_belf=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 -$as_echo "$lt_cv_cc_needs_belf" >&6; } - if test x"$lt_cv_cc_needs_belf" != x"yes"; then - # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf - CFLAGS="$SAVE_CFLAGS" - fi - ;; -sparc*-*solaris*) - # Find out which ABI we are using. - echo 'int i;' > conftest.$ac_ext - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; }; then - case `/usr/bin/file conftest.o` in - *64-bit*) - case $lt_cv_prog_gnu_ld in - yes*) LD="${LD-ld} -m elf64_sparc" ;; - *) - if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then - LD="${LD-ld} -64" - fi - ;; - esac - ;; - esac - fi - rm -rf conftest* - ;; -esac - -need_locks="$enable_libtool_lock" - - - case $host_os in - rhapsody* | darwin*) - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. -set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_DSYMUTIL+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$DSYMUTIL"; then - ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -DSYMUTIL=$ac_cv_prog_DSYMUTIL -if test -n "$DSYMUTIL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 -$as_echo "$DSYMUTIL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_DSYMUTIL"; then - ac_ct_DSYMUTIL=$DSYMUTIL - # Extract the first word of "dsymutil", so it can be a program name with args. -set dummy dsymutil; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_DSYMUTIL+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_DSYMUTIL"; then - ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL -if test -n "$ac_ct_DSYMUTIL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 -$as_echo "$ac_ct_DSYMUTIL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_DSYMUTIL" = x; then - DSYMUTIL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - DSYMUTIL=$ac_ct_DSYMUTIL - fi -else - DSYMUTIL="$ac_cv_prog_DSYMUTIL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. -set dummy ${ac_tool_prefix}nmedit; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_NMEDIT+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$NMEDIT"; then - ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -NMEDIT=$ac_cv_prog_NMEDIT -if test -n "$NMEDIT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 -$as_echo "$NMEDIT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_NMEDIT"; then - ac_ct_NMEDIT=$NMEDIT - # Extract the first word of "nmedit", so it can be a program name with args. -set dummy nmedit; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_NMEDIT+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_NMEDIT"; then - ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_NMEDIT="nmedit" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT -if test -n "$ac_ct_NMEDIT"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 -$as_echo "$ac_ct_NMEDIT" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_NMEDIT" = x; then - NMEDIT=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - NMEDIT=$ac_ct_NMEDIT - fi -else - NMEDIT="$ac_cv_prog_NMEDIT" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. -set dummy ${ac_tool_prefix}lipo; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_LIPO+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$LIPO"; then - ac_cv_prog_LIPO="$LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_LIPO="${ac_tool_prefix}lipo" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -LIPO=$ac_cv_prog_LIPO -if test -n "$LIPO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 -$as_echo "$LIPO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_LIPO"; then - ac_ct_LIPO=$LIPO - # Extract the first word of "lipo", so it can be a program name with args. -set dummy lipo; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_LIPO+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_LIPO"; then - ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_LIPO="lipo" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO -if test -n "$ac_ct_LIPO"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 -$as_echo "$ac_ct_LIPO" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_LIPO" = x; then - LIPO=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - LIPO=$ac_ct_LIPO - fi -else - LIPO="$ac_cv_prog_LIPO" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OTOOL+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OTOOL"; then - ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_OTOOL="${ac_tool_prefix}otool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OTOOL=$ac_cv_prog_OTOOL -if test -n "$OTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 -$as_echo "$OTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL"; then - ac_ct_OTOOL=$OTOOL - # Extract the first word of "otool", so it can be a program name with args. -set dummy otool; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OTOOL+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OTOOL"; then - ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_OTOOL="otool" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL -if test -n "$ac_ct_OTOOL"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 -$as_echo "$ac_ct_OTOOL" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OTOOL" = x; then - OTOOL=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL=$ac_ct_OTOOL - fi -else - OTOOL="$ac_cv_prog_OTOOL" -fi - - if test -n "$ac_tool_prefix"; then - # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. -set dummy ${ac_tool_prefix}otool64; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_OTOOL64+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$OTOOL64"; then - ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -OTOOL64=$ac_cv_prog_OTOOL64 -if test -n "$OTOOL64"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 -$as_echo "$OTOOL64" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - -fi -if test -z "$ac_cv_prog_OTOOL64"; then - ac_ct_OTOOL64=$OTOOL64 - # Extract the first word of "otool64", so it can be a program name with args. -set dummy otool64; ac_word=$2 -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 -$as_echo_n "checking for $ac_word... " >&6; } -if test "${ac_cv_prog_ac_ct_OTOOL64+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "$ac_ct_OTOOL64"; then - ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. -else -as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then - ac_cv_prog_ac_ct_OTOOL64="otool64" - $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 - break 2 - fi -done - done -IFS=$as_save_IFS - -fi -fi -ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 -if test -n "$ac_ct_OTOOL64"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 -$as_echo "$ac_ct_OTOOL64" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - if test "x$ac_ct_OTOOL64" = x; then - OTOOL64=":" - else - case $cross_compiling:$ac_tool_warned in -yes:) -{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 -$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} -ac_tool_warned=yes ;; -esac - OTOOL64=$ac_ct_OTOOL64 - fi -else - OTOOL64="$ac_cv_prog_OTOOL64" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 -$as_echo_n "checking for -single_module linker flag... " >&6; } -if test "${lt_cv_apple_cc_single_mod+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_apple_cc_single_mod=no - if test -z "${LT_MULTI_MODULE}"; then - # By default we will add the -single_module flag. You can override - # by either setting the environment variable LT_MULTI_MODULE - # non-empty at configure time, or by adding -multi_module to the - # link flags. - rm -rf libconftest.dylib* - echo "int foo(void){return 1;}" > conftest.c - echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ --dynamiclib -Wl,-single_module conftest.c" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ - -dynamiclib -Wl,-single_module conftest.c 2>conftest.err - _lt_result=$? - if test -f libconftest.dylib && test ! -s conftest.err && test $_lt_result = 0; then - lt_cv_apple_cc_single_mod=yes - else - cat conftest.err >&5 - fi - rm -rf libconftest.dylib* - rm -f conftest.* - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 -$as_echo "$lt_cv_apple_cc_single_mod" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 -$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } -if test "${lt_cv_ld_exported_symbols_list+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_exported_symbols_list=no - save_LDFLAGS=$LDFLAGS - echo "_main" > conftest.sym - LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - lt_cv_ld_exported_symbols_list=yes -else - lt_cv_ld_exported_symbols_list=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 -$as_echo "$lt_cv_ld_exported_symbols_list" >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 -$as_echo_n "checking for -force_load linker flag... " >&6; } -if test "${lt_cv_ld_force_load+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_ld_force_load=no - cat > conftest.c << _LT_EOF -int forced_loaded() { return 2;} -_LT_EOF - echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 - $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 - echo "$AR cru libconftest.a conftest.o" >&5 - $AR cru libconftest.a conftest.o 2>&5 - cat > conftest.c << _LT_EOF -int main() { return 0;} -_LT_EOF - echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 - $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err - _lt_result=$? - if test -f conftest && test ! -s conftest.err && test $_lt_result = 0 && $GREP forced_load conftest 2>&1 >/dev/null; then - lt_cv_ld_force_load=yes - else - cat conftest.err >&5 - fi - rm -f conftest.err libconftest.a conftest conftest.c - rm -rf conftest.dSYM - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 -$as_echo "$lt_cv_ld_force_load" >&6; } - case $host_os in - rhapsody* | darwin1.[012]) - _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; - darwin1.*) - _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; - darwin*) # darwin 5.x on - # if running on 10.5 or later, the deployment target defaults - # to the OS version, if on x86, and 10.4, the deployment - # target defaults to 10.4. Don't you love it? - case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in - 10.0,*86*-darwin8*|10.0,*-darwin[91]*) - _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; - 10.[012][,.]*) - _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; - 10.*) - _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; - esac - ;; - esac - if test "$lt_cv_apple_cc_single_mod" = "yes"; then - _lt_dar_single_mod='$single_module' - fi - if test "$lt_cv_ld_exported_symbols_list" = "yes"; then - _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' - else - _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' - fi - if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then - _lt_dsymutil='~$DSYMUTIL $lib || :' - else - _lt_dsymutil= - fi - ;; - esac - -for ac_header in dlfcn.h -do : - ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default -" -if test "x$ac_cv_header_dlfcn_h" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_DLFCN_H 1 -_ACEOF - -fi - -done - - - - - -# Set options - - - - enable_dlopen=no - - - enable_win32_dll=no - - - # Check whether --enable-shared was given. -if test "${enable_shared+set}" = set; then : - enableval=$enable_shared; p=${PACKAGE-default} - case $enableval in - yes) enable_shared=yes ;; - no) enable_shared=no ;; - *) - enable_shared=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_shared=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_shared=yes -fi - - - - - - - - - - # Check whether --enable-static was given. -if test "${enable_static+set}" = set; then : - enableval=$enable_static; p=${PACKAGE-default} - case $enableval in - yes) enable_static=yes ;; - no) enable_static=no ;; - *) - enable_static=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_static=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_static=yes -fi - - - - - - - - - - -# Check whether --with-pic was given. -if test "${with_pic+set}" = set; then : - withval=$with_pic; pic_mode="$withval" -else - pic_mode=default -fi - - -test -z "$pic_mode" && pic_mode=default - - - - - - - - # Check whether --enable-fast-install was given. -if test "${enable_fast_install+set}" = set; then : - enableval=$enable_fast_install; p=${PACKAGE-default} - case $enableval in - yes) enable_fast_install=yes ;; - no) enable_fast_install=no ;; - *) - enable_fast_install=no - # Look at the argument we got. We use all the common list separators. - lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," - for pkg in $enableval; do - IFS="$lt_save_ifs" - if test "X$pkg" = "X$p"; then - enable_fast_install=yes - fi - done - IFS="$lt_save_ifs" - ;; - esac -else - enable_fast_install=yes -fi - - - - - - - - - - - -# This can be used to rebuild libtool when needed -LIBTOOL_DEPS="$ltmain" - -# Always use our own libtool. -LIBTOOL='$(SHELL) $(top_builddir)/libtool' - - - - - - - - - - - - - - - - - - - - - - - - - - -test -z "$LN_S" && LN_S="ln -s" - - - - - - - - - - - - - - -if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 -$as_echo_n "checking for objdir... " >&6; } -if test "${lt_cv_objdir+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - rm -f .libs 2>/dev/null -mkdir .libs 2>/dev/null -if test -d .libs; then - lt_cv_objdir=.libs -else - # MS-DOS does not allow filenames that begin with a dot. - lt_cv_objdir=_libs -fi -rmdir .libs 2>/dev/null -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 -$as_echo "$lt_cv_objdir" >&6; } -objdir=$lt_cv_objdir - - - - - -cat >>confdefs.h <<_ACEOF -#define LT_OBJDIR "$lt_cv_objdir/" -_ACEOF - - - - -case $host_os in -aix3*) - # AIX sometimes has problems with the GCC collect2 program. For some - # reason, if we set the COLLECT_NAMES environment variable, the problems - # vanish in a puff of smoke. - if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES - fi - ;; -esac - -# Global variables: -ofile=libtool -can_build_shared=yes - -# All known linkers require a `.a' archive for static linking (except MSVC, -# which needs '.lib'). -libext=a - -with_gnu_ld="$lt_cv_prog_gnu_ld" - -old_CC="$CC" -old_CFLAGS="$CFLAGS" - -# Set sane defaults for various variables -test -z "$CC" && CC=cc -test -z "$LTCC" && LTCC=$CC -test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS -test -z "$LD" && LD=ld -test -z "$ac_objext" && ac_objext=o - -for cc_temp in $compiler""; do - case $cc_temp in - compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; - distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; - \-*) ;; - *) break;; - esac -done -cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` - - -# Only perform the check for file, if the check method requires it -test -z "$MAGIC_CMD" && MAGIC_CMD=file -case $deplibs_check_method in -file_magic*) - if test "$file_magic_cmd" = '$MAGIC_CMD'; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 -$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/${ac_tool_prefix}file; then - lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac -fi - -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -$as_echo "$MAGIC_CMD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - - - -if test -z "$lt_cv_path_MAGIC_CMD"; then - if test -n "$ac_tool_prefix"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 -$as_echo_n "checking for file... " >&6; } -if test "${lt_cv_path_MAGIC_CMD+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - case $MAGIC_CMD in -[\\/*] | ?:[\\/]*) - lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. - ;; -*) - lt_save_MAGIC_CMD="$MAGIC_CMD" - lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR - ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" - for ac_dir in $ac_dummy; do - IFS="$lt_save_ifs" - test -z "$ac_dir" && ac_dir=. - if test -f $ac_dir/file; then - lt_cv_path_MAGIC_CMD="$ac_dir/file" - if test -n "$file_magic_test_file"; then - case $deplibs_check_method in - "file_magic "*) - file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` - MAGIC_CMD="$lt_cv_path_MAGIC_CMD" - if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | - $EGREP "$file_magic_regex" > /dev/null; then - : - else - cat <<_LT_EOF 1>&2 - -*** Warning: the command libtool uses to detect shared libraries, -*** $file_magic_cmd, produces output that libtool cannot recognize. -*** The result is that libtool may fail to recognize shared libraries -*** as such. This will affect the creation of libtool libraries that -*** depend on shared libraries, but programs linked with such libtool -*** libraries will work regardless of this problem. Nevertheless, you -*** may want to report the problem to your system manager and/or to -*** bug-libtool@gnu.org - -_LT_EOF - fi ;; - esac - fi - break - fi - done - IFS="$lt_save_ifs" - MAGIC_CMD="$lt_save_MAGIC_CMD" - ;; -esac -fi - -MAGIC_CMD="$lt_cv_path_MAGIC_CMD" -if test -n "$MAGIC_CMD"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 -$as_echo "$MAGIC_CMD" >&6; } -else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } -fi - - - else - MAGIC_CMD=: - fi -fi - - fi - ;; -esac - -# Use C for the default configuration in the libtool script - -lt_save_CC="$CC" -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - -# Source file extension for C test sources. -ac_ext=c - -# Object file extension for compiled C test sources. -objext=o -objext=$objext - -# Code to be used in simple compile tests -lt_simple_compile_test_code="int some_variable = 0;" - -# Code to be used in simple link tests -lt_simple_link_test_code='int main(){return(0);}' - - - - - - - -# If no C compiler was specified, use CC. -LTCC=${LTCC-"$CC"} - -# If no C compiler flags were specified, use CFLAGS. -LTCFLAGS=${LTCFLAGS-"$CFLAGS"} - -# Allow CC to be a program name with arguments. -compiler=$CC - -# Save the default compiler, since it gets overwritten when the other -# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. -compiler_DEFAULT=$CC - -# save warnings/boilerplate of simple test code -ac_outfile=conftest.$ac_objext -echo "$lt_simple_compile_test_code" >conftest.$ac_ext -eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_compiler_boilerplate=`cat conftest.err` -$RM conftest* - -ac_outfile=conftest.$ac_objext -echo "$lt_simple_link_test_code" >conftest.$ac_ext -eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err -_lt_linker_boilerplate=`cat conftest.err` -$RM -r conftest* - - -## CAVEAT EMPTOR: -## There is no encapsulation within the following macros, do not change -## the running order or otherwise move them around unless you know exactly -## what you are doing... -if test -n "$compiler"; then - -lt_prog_compiler_no_builtin_flag= - -if test "$GCC" = yes; then - case $cc_basename in - nvcc*) - lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; - *) - lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; - esac - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 -$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } -if test "${lt_cv_prog_compiler_rtti_exceptions+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_rtti_exceptions=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="-fno-rtti -fno-exceptions" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_rtti_exceptions=yes - fi - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 -$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } - -if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then - lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" -else - : -fi - -fi - - - - - - - lt_prog_compiler_wl= -lt_prog_compiler_pic= -lt_prog_compiler_static= - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 -$as_echo_n "checking for $compiler option to produce PIC... " >&6; } - - if test "$GCC" = yes; then - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_static='-static' - - case $host_os in - aix*) - # All AIX code is PIC. - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - fi - lt_prog_compiler_pic='-fPIC' - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - lt_prog_compiler_pic='-fPIC' - ;; - m68k) - # FIXME: we need at least 68020 code to build shared libraries, but - # adding the `-m68020' flag to GCC prevents building anything better, - # like `-m68040'. - lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' - ;; - esac - ;; - - beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) - # PIC is the default for these OSes. - ;; - - mingw* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - # Although the cygwin gcc ignores -fPIC, still need this for old-style - # (--disable-auto-import) libraries - lt_prog_compiler_pic='-DDLL_EXPORT' - ;; - - darwin* | rhapsody*) - # PIC is the default on this platform - # Common symbols not allowed in MH_DYLIB files - lt_prog_compiler_pic='-fno-common' - ;; - - haiku*) - # PIC is the default for Haiku. - # The "-static" flag exists, but is broken. - lt_prog_compiler_static= - ;; - - hpux*) - # PIC is the default for 64-bit PA HP-UX, but not for 32-bit - # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag - # sets the default TLS model and affects inlining. - case $host_cpu in - hppa*64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - ;; - - interix[3-9]*) - # Interix 3.x gcc -fpic/-fPIC options generate broken code. - # Instead, we relocate shared libraries at runtime. - ;; - - msdosdjgpp*) - # Just because we use GCC doesn't mean we suddenly get shared libraries - # on systems that don't support them. - lt_prog_compiler_can_build_shared=no - enable_shared=no - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - lt_prog_compiler_pic=-Kconform_pic - fi - ;; - - *) - lt_prog_compiler_pic='-fPIC' - ;; - esac - - case $cc_basename in - nvcc*) # Cuda Compiler Driver 2.2 - lt_prog_compiler_wl='-Xlinker ' - lt_prog_compiler_pic='-Xcompiler -fPIC' - ;; - esac - else - # PORTME Check for flag to pass linker flags through the system compiler. - case $host_os in - aix*) - lt_prog_compiler_wl='-Wl,' - if test "$host_cpu" = ia64; then - # AIX 5 now supports IA64 processor - lt_prog_compiler_static='-Bstatic' - else - lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' - fi - ;; - - mingw* | cygwin* | pw32* | os2* | cegcc*) - # This hack is so that the source file can tell whether it is being - # built for inclusion in a dll (and should export symbols for example). - lt_prog_compiler_pic='-DDLL_EXPORT' - ;; - - hpux9* | hpux10* | hpux11*) - lt_prog_compiler_wl='-Wl,' - # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but - # not for PA HP-UX. - case $host_cpu in - hppa*64*|ia64*) - # +Z the default - ;; - *) - lt_prog_compiler_pic='+Z' - ;; - esac - # Is there a better lt_prog_compiler_static that works with the bundled CC? - lt_prog_compiler_static='${wl}-a ${wl}archive' - ;; - - irix5* | irix6* | nonstopux*) - lt_prog_compiler_wl='-Wl,' - # PIC (with -KPIC) is the default. - lt_prog_compiler_static='-non_shared' - ;; - - linux* | k*bsd*-gnu | kopensolaris*-gnu) - case $cc_basename in - # old Intel for x86_64 which still supported -KPIC. - ecc*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-static' - ;; - # icc used to be incompatible with GCC. - # ICC 10 doesn't accept -KPIC any more. - icc* | ifort*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fPIC' - lt_prog_compiler_static='-static' - ;; - # Lahey Fortran 8.1. - lf95*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='--shared' - lt_prog_compiler_static='--static' - ;; - pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group compilers (*not* the Pentium gcc compiler, - # which looks to be a dead project) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-fpic' - lt_prog_compiler_static='-Bstatic' - ;; - ccc*) - lt_prog_compiler_wl='-Wl,' - # All Alpha code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - xl* | bgxl* | bgf* | mpixl*) - # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-qpic' - lt_prog_compiler_static='-qstaticlink' - ;; - *) - case `$CC -V 2>&1 | sed 5q` in - *Sun\ F* | *Sun*Fortran*) - # Sun Fortran 8.3 passes all unrecognized flags to the linker - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='' - ;; - *Sun\ C*) - # Sun C 5.9 - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - lt_prog_compiler_wl='-Wl,' - ;; - esac - ;; - esac - ;; - - newsos6) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - *nto* | *qnx*) - # QNX uses GNU C++, but need to define -shared option too, otherwise - # it will coredump. - lt_prog_compiler_pic='-fPIC -shared' - ;; - - osf3* | osf4* | osf5*) - lt_prog_compiler_wl='-Wl,' - # All OSF/1 code is PIC. - lt_prog_compiler_static='-non_shared' - ;; - - rdos*) - lt_prog_compiler_static='-non_shared' - ;; - - solaris*) - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - case $cc_basename in - f77* | f90* | f95*) - lt_prog_compiler_wl='-Qoption ld ';; - *) - lt_prog_compiler_wl='-Wl,';; - esac - ;; - - sunos4*) - lt_prog_compiler_wl='-Qoption ld ' - lt_prog_compiler_pic='-PIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4 | sysv4.2uw2* | sysv4.3*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - sysv4*MP*) - if test -d /usr/nec ;then - lt_prog_compiler_pic='-Kconform_pic' - lt_prog_compiler_static='-Bstatic' - fi - ;; - - sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_pic='-KPIC' - lt_prog_compiler_static='-Bstatic' - ;; - - unicos*) - lt_prog_compiler_wl='-Wl,' - lt_prog_compiler_can_build_shared=no - ;; - - uts4*) - lt_prog_compiler_pic='-pic' - lt_prog_compiler_static='-Bstatic' - ;; - - *) - lt_prog_compiler_can_build_shared=no - ;; - esac - fi - -case $host_os in - # For platforms which do not support PIC, -DPIC is meaningless: - *djgpp*) - lt_prog_compiler_pic= - ;; - *) - lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" - ;; -esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_prog_compiler_pic" >&5 -$as_echo "$lt_prog_compiler_pic" >&6; } - - - - - - -# -# Check to make sure the PIC flag actually works. -# -if test -n "$lt_prog_compiler_pic"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 -$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } -if test "${lt_cv_prog_compiler_pic_works+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_pic_works=no - ac_outfile=conftest.$ac_objext - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - lt_compiler_flag="$lt_prog_compiler_pic -DPIC" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - # The option is referenced via a variable to avoid confusing sed. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>conftest.err) - ac_status=$? - cat conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s "$ac_outfile"; then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings other than the usual output. - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_pic_works=yes - fi - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 -$as_echo "$lt_cv_prog_compiler_pic_works" >&6; } - -if test x"$lt_cv_prog_compiler_pic_works" = xyes; then - case $lt_prog_compiler_pic in - "" | " "*) ;; - *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; - esac -else - lt_prog_compiler_pic= - lt_prog_compiler_can_build_shared=no -fi - -fi - - - - - - -# -# Check to make sure the static flag actually works. -# -wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 -$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } -if test "${lt_cv_prog_compiler_static_works+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_static_works=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS $lt_tmp_static_flag" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler_static_works=yes - fi - else - lt_cv_prog_compiler_static_works=yes - fi - fi - $RM -r conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 -$as_echo "$lt_cv_prog_compiler_static_works" >&6; } - -if test x"$lt_cv_prog_compiler_static_works" = xyes; then - : -else - lt_prog_compiler_static= -fi - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -$as_echo "$lt_cv_prog_compiler_c_o" >&6; } - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 -$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } -if test "${lt_cv_prog_compiler_c_o+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler_c_o=no - $RM -r conftest 2>/dev/null - mkdir conftest - cd conftest - mkdir out - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - lt_compiler_flag="-o out/conftest2.$ac_objext" - # Insert the option either (1) after the last *FLAGS variable, or - # (2) before a word containing "conftest.", or (3) at the end. - # Note that $ac_compile itself does not contain backslashes and begins - # with a dollar sign (not a hyphen), so the echo should work correctly. - lt_compile=`echo "$ac_compile" | $SED \ - -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ - -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ - -e 's:$: $lt_compiler_flag:'` - (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) - (eval "$lt_compile" 2>out/conftest.err) - ac_status=$? - cat out/conftest.err >&5 - echo "$as_me:$LINENO: \$? = $ac_status" >&5 - if (exit $ac_status) && test -s out/conftest2.$ac_objext - then - # The compiler can only warn and ignore the option if not recognized - # So say no if there are warnings - $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp - $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 - if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then - lt_cv_prog_compiler_c_o=yes - fi - fi - chmod u+w . 2>&5 - $RM conftest* - # SGI C++ compiler will create directory out/ii_files/ for - # template instantiation - test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files - $RM out/* && rmdir out - cd .. - $RM -r conftest - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 -$as_echo "$lt_cv_prog_compiler_c_o" >&6; } - - - - -hard_links="nottested" -if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then - # do not overwrite the value of need_locks provided by the user - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 -$as_echo_n "checking if we can lock with hard links... " >&6; } - hard_links=yes - $RM conftest* - ln conftest.a conftest.b 2>/dev/null && hard_links=no - touch conftest.a - ln conftest.a conftest.b 2>&5 || hard_links=no - ln conftest.a conftest.b 2>/dev/null && hard_links=no - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 -$as_echo "$hard_links" >&6; } - if test "$hard_links" = no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 -$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} - need_locks=warn - fi -else - need_locks=no -fi - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 -$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } - - runpath_var= - allow_undefined_flag= - always_export_symbols=no - archive_cmds= - archive_expsym_cmds= - compiler_needs_object=no - enable_shared_with_static_runtimes=no - export_dynamic_flag_spec= - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' - hardcode_automatic=no - hardcode_direct=no - hardcode_direct_absolute=no - hardcode_libdir_flag_spec= - hardcode_libdir_flag_spec_ld= - hardcode_libdir_separator= - hardcode_minus_L=no - hardcode_shlibpath_var=unsupported - inherit_rpath=no - link_all_deplibs=unknown - module_cmds= - module_expsym_cmds= - old_archive_from_new_cmds= - old_archive_from_expsyms_cmds= - thread_safe_flag_spec= - whole_archive_flag_spec= - # include_expsyms should be a list of space-separated symbols to be *always* - # included in the symbol list - include_expsyms= - # exclude_expsyms can be an extended regexp of symbols to exclude - # it will be wrapped by ` (' and `)$', so one must not match beginning or - # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', - # as well as any symbol that contains `d'. - exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' - # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out - # platforms (ab)use it in PIC code, but their linkers get confused if - # the symbol is explicitly referenced. Since portable code cannot - # rely on this symbol name, it's probably fine to never include it in - # preloaded symbol tables. - # Exclude shared library initialization/finalization symbols. - extract_expsyms_cmds= - - case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - # FIXME: the MSVC++ port hasn't been tested in a loooong time - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - if test "$GCC" != yes; then - with_gnu_ld=no - fi - ;; - interix*) - # we just hope/assume this is gcc and not c89 (= MSVC++) - with_gnu_ld=yes - ;; - openbsd*) - with_gnu_ld=no - ;; - esac - - ld_shlibs=yes - - # On some targets, GNU ld is compatible enough with the native linker - # that we're better off using the native interface for both. - lt_use_gnu_ld_interface=no - if test "$with_gnu_ld" = yes; then - case $host_os in - aix*) - # The AIX port of GNU ld has always aspired to compatibility - # with the native linker. However, as the warning in the GNU ld - # block says, versions before 2.19.5* couldn't really create working - # shared libraries, regardless of the interface used. - case `$LD -v 2>&1` in - *\ \(GNU\ Binutils\)\ 2.19.5*) ;; - *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; - *\ \(GNU\ Binutils\)\ [3-9]*) ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - ;; - *) - lt_use_gnu_ld_interface=yes - ;; - esac - fi - - if test "$lt_use_gnu_ld_interface" = yes; then - # If archive_cmds runs LD, not CC, wlarc should be empty - wlarc='${wl}' - - # Set some defaults for GNU ld with shared library support. These - # are reset later if shared libraries are not supported. Putting them - # here allows them to be overridden if necessary. - runpath_var=LD_RUN_PATH - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - export_dynamic_flag_spec='${wl}--export-dynamic' - # ancient GNU ld didn't support --whole-archive et. al. - if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then - whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' - else - whole_archive_flag_spec= - fi - supports_anon_versioning=no - case `$LD -v 2>&1` in - *GNU\ gold*) supports_anon_versioning=yes ;; - *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 - *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... - *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... - *\ 2.11.*) ;; # other 2.11 versions - *) supports_anon_versioning=yes ;; - esac - - # See if GNU ld supports shared libraries. - case $host_os in - aix[3-9]*) - # On AIX/PPC, the GNU linker is very broken - if test "$host_cpu" != ia64; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: the GNU linker, at least up to release 2.19, is reported -*** to be unable to reliably create shared libraries on AIX. -*** Therefore, libtool is disabling shared libraries support. If you -*** really care for shared libraries, you may want to install binutils -*** 2.20 or above, or modify your PATH so that a non-GNU linker is found. -*** You will then need to restart the configuration process. - -_LT_EOF - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - beos*) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - allow_undefined_flag=unsupported - # Joseph Beckenbach says some releases of gcc - # support --undefined. This deserves some investigation. FIXME - archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - else - ld_shlibs=no - fi - ;; - - cygwin* | mingw* | pw32* | cegcc*) - # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, - # as there is no search path for DLLs. - hardcode_libdir_flag_spec='-L$libdir' - export_dynamic_flag_spec='${wl}--export-all-symbols' - allow_undefined_flag=unsupported - always_export_symbols=no - enable_shared_with_static_runtimes=yes - export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' - - if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - # If the export-symbols file already is a .def file (1st line - # is EXPORTS), use it as is; otherwise, prepend... - archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then - cp $export_symbols $output_objdir/$soname.def; - else - echo EXPORTS > $output_objdir/$soname.def; - cat $export_symbols >> $output_objdir/$soname.def; - fi~ - $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' - else - ld_shlibs=no - fi - ;; - - haiku*) - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - link_all_deplibs=yes - ;; - - interix[3-9]*) - hardcode_direct=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' - # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. - # Instead, shared libraries are loaded at an image base (0x10000000 by - # default) and relocated if they conflict, which is a slow very memory - # consuming and fragmenting process. To avoid this, we pick a random, - # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link - # time. Moving up from 0x10000000 also allows more sbrk(2) space. - archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' - ;; - - gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) - tmp_diet=no - if test "$host_os" = linux-dietlibc; then - case $cc_basename in - diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) - esac - fi - if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ - && test "$tmp_diet" = no - then - tmp_addflag=' $pic_flag' - tmp_sharedflag='-shared' - case $cc_basename,$host_cpu in - pgcc*) # Portland Group C compiler - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag' - ;; - pgf77* | pgf90* | pgf95* | pgfortran*) - # Portland Group f77 and f90 compilers - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - tmp_addflag=' $pic_flag -Mnomain' ;; - ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 - tmp_addflag=' -i_dynamic' ;; - efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 - tmp_addflag=' -i_dynamic -nofor_main' ;; - ifc* | ifort*) # Intel Fortran compiler - tmp_addflag=' -nofor_main' ;; - lf95*) # Lahey Fortran 8.1 - whole_archive_flag_spec= - tmp_sharedflag='--shared' ;; - xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) - tmp_sharedflag='-qmkshrobj' - tmp_addflag= ;; - nvcc*) # Cuda Compiler Driver 2.2 - whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - compiler_needs_object=yes - ;; - esac - case `$CC -V 2>&1 | sed 5q` in - *Sun\ C*) # Sun C 5.9 - whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' - compiler_needs_object=yes - tmp_sharedflag='-G' ;; - *Sun\ F*) # Sun Fortran 8.3 - tmp_sharedflag='-G' ;; - esac - archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - - if test "x$supports_anon_versioning" = xyes; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' - fi - - case $cc_basename in - xlf* | bgf* | bgxlf* | mpixlf*) - # IBM XL Fortran 10.1 on PPC cannot create shared libs itself - whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' - hardcode_libdir_flag_spec= - hardcode_libdir_flag_spec_ld='-rpath $libdir' - archive_cmds='$LD -shared $libobjs $deplibs $compiler_flags -soname $soname -o $lib' - if test "x$supports_anon_versioning" = xyes; then - archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ - cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ - echo "local: *; };" >> $output_objdir/$libname.ver~ - $LD -shared $libobjs $deplibs $compiler_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' - fi - ;; - esac - else - ld_shlibs=no - fi - ;; - - netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' - wlarc= - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - fi - ;; - - solaris*) - if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: The releases 2.8.* of the GNU linker cannot reliably -*** create shared libraries on Solaris systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.9.1 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - - sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) - case `$LD -v 2>&1` in - *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) - ld_shlibs=no - cat <<_LT_EOF 1>&2 - -*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not -*** reliably create shared libraries on SCO systems. Therefore, libtool -*** is disabling shared libraries support. We urge you to upgrade GNU -*** binutils to release 2.16.91.0.3 or newer. Another option is to modify -*** your PATH or compiler configuration so that the native linker is -*** used, and then restart. - -_LT_EOF - ;; - *) - # For security reasons, it is highly recommended that you always - # use absolute paths for naming shared libraries, and exclude the - # DT_RUNPATH tag from executables and libraries. But doing so - # requires that you compile everything twice, which is a pain. - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - ;; - - sunos4*) - archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' - wlarc= - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - *) - if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' - else - ld_shlibs=no - fi - ;; - esac - - if test "$ld_shlibs" = no; then - runpath_var= - hardcode_libdir_flag_spec= - export_dynamic_flag_spec= - whole_archive_flag_spec= - fi - else - # PORTME fill in a description of your system's linker (not GNU ld) - case $host_os in - aix3*) - allow_undefined_flag=unsupported - always_export_symbols=yes - archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' - # Note: this linker hardcodes the directories in LIBPATH if there - # are no directories specified by -L. - hardcode_minus_L=yes - if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then - # Neither direct hardcoding nor static linking is supported with a - # broken collect2. - hardcode_direct=unsupported - fi - ;; - - aix[4-9]*) - if test "$host_cpu" = ia64; then - # On IA64, the linker does run time linking by default, so we don't - # have to do anything special. - aix_use_runtimelinking=no - exp_sym_flag='-Bexport' - no_entry_flag="" - else - # If we're using GNU nm, then we don't want the "-C" option. - # -C means demangle to AIX nm, but means don't demangle with GNU nm - # Also, AIX nm treats weak defined symbols like other global - # defined symbols, whereas GNU nm marks them as "W". - if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then - export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - else - export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' - fi - aix_use_runtimelinking=no - - # Test if we are trying to use run time linking or normal - # AIX style linking. If -brtl is somewhere in LDFLAGS, we - # need to do runtime linking. - case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) - for ld_flag in $LDFLAGS; do - if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then - aix_use_runtimelinking=yes - break - fi - done - ;; - esac - - exp_sym_flag='-bexport' - no_entry_flag='-bnoentry' - fi - - # When large executables or shared objects are built, AIX ld can - # have problems creating the table of contents. If linking a library - # or program results in "error TOC overflow" add -mminimal-toc to - # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not - # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. - - archive_cmds='' - hardcode_direct=yes - hardcode_direct_absolute=yes - hardcode_libdir_separator=':' - link_all_deplibs=yes - file_list_spec='${wl}-f,' - - if test "$GCC" = yes; then - case $host_os in aix4.[012]|aix4.[012].*) - # We only want to do this on AIX 4.2 and lower, the check - # below for broken collect2 doesn't work under 4.3+ - collect2name=`${CC} -print-prog-name=collect2` - if test -f "$collect2name" && - strings "$collect2name" | $GREP resolve_lib_name >/dev/null - then - # We have reworked collect2 - : - else - # We have old collect2 - hardcode_direct=unsupported - # It fails to find uninstalled libraries when the uninstalled - # path is not listed in the libpath. Setting hardcode_minus_L - # to unsupported forces relinking - hardcode_minus_L=yes - hardcode_libdir_flag_spec='-L$libdir' - hardcode_libdir_separator= - fi - ;; - esac - shared_flag='-shared' - if test "$aix_use_runtimelinking" = yes; then - shared_flag="$shared_flag "'${wl}-G' - fi - else - # not using gcc - if test "$host_cpu" = ia64; then - # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release - # chokes on -Wl,-G. The following line is correct: - shared_flag='-G' - else - if test "$aix_use_runtimelinking" = yes; then - shared_flag='${wl}-G' - else - shared_flag='${wl}-bM:SRE' - fi - fi - fi - - export_dynamic_flag_spec='${wl}-bexpall' - # It seems that -bexpall does not export symbols beginning with - # underscore (_), so it is better to generate a list of symbols to export. - always_export_symbols=yes - if test "$aix_use_runtimelinking" = yes; then - # Warning - without using the other runtime loading flags (-brtl), - # -berok will link without error, but may produce a broken library. - allow_undefined_flag='-berok' - # Determine the default libpath from the value encoded in an - # empty executable. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" - else - if test "$host_cpu" = ia64; then - hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' - allow_undefined_flag="-z nodefs" - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" - else - # Determine the default libpath from the value encoded in an - # empty executable. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - -lt_aix_libpath_sed=' - /Import File Strings/,/^$/ { - /^0/ { - s/^0 *\(.*\)$/\1/ - p - } - }' -aix_libpath=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -# Check for a 64-bit object if we didn't find anything. -if test -z "$aix_libpath"; then - aix_libpath=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` -fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -if test -z "$aix_libpath"; then aix_libpath="/usr/lib:/lib"; fi - - hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" - # Warning - without using the other run time loading flags, - # -berok will link without error, but may produce a broken library. - no_undefined_flag=' ${wl}-bernotok' - allow_undefined_flag=' ${wl}-berok' - if test "$with_gnu_ld" = yes; then - # We only use this code for GNU lds that support --whole-archive. - whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' - else - # Exported symbols can be pulled into shared objects from archives - whole_archive_flag_spec='$convenience' - fi - archive_cmds_need_lc=yes - # This is similar to how AIX traditionally builds its shared libraries. - archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' - fi - fi - ;; - - amigaos*) - case $host_cpu in - powerpc) - # see comment about AmigaOS4 .so support - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' - archive_expsym_cmds='' - ;; - m68k) - archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - ;; - esac - ;; - - bsdi[45]*) - export_dynamic_flag_spec=-rdynamic - ;; - - cygwin* | mingw* | pw32* | cegcc*) - # When not using gcc, we currently assume that we are using - # Microsoft Visual C++. - # hardcode_libdir_flag_spec is actually meaningless, as there is - # no search path for DLLs. - hardcode_libdir_flag_spec=' ' - allow_undefined_flag=unsupported - # Tell ltmain to make .lib files, not .a files. - libext=lib - # Tell ltmain to make .dll files, not .so files. - shrext_cmds=".dll" - # FIXME: Setting linknames here is a bad hack. - archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' - # The linker will automatically build a .lib file if we build a DLL. - old_archive_from_new_cmds='true' - # FIXME: Should let the user specify the lib program. - old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' - fix_srcfile_path='`cygpath -w "$srcfile"`' - enable_shared_with_static_runtimes=yes - ;; - - darwin* | rhapsody*) - - - archive_cmds_need_lc=no - hardcode_direct=no - hardcode_automatic=yes - hardcode_shlibpath_var=unsupported - if test "$lt_cv_ld_force_load" = "yes"; then - whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' - else - whole_archive_flag_spec='' - fi - link_all_deplibs=yes - allow_undefined_flag="$_lt_dar_allow_undefined" - case $cc_basename in - ifort*) _lt_dar_can_shared=yes ;; - *) _lt_dar_can_shared=$GCC ;; - esac - if test "$_lt_dar_can_shared" = "yes"; then - output_verbose_link_cmd=func_echo_all - archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" - module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" - archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" - module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" - - else - ld_shlibs=no - fi - - ;; - - dgux*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor - # support. Future versions do this automatically, but an explicit c++rt0.o - # does not break anything, and helps significantly (at the cost of a little - # extra space). - freebsd2.2*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - # Unfortunately, older versions of FreeBSD 2 do not have this feature. - freebsd2.*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - # FreeBSD 3 and greater uses gcc -shared to do shared libraries. - freebsd* | dragonfly* | openbsd* | bitrig*) - archive_cmds='$CC -shared -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - hpux9*) - if test "$GCC" = yes; then - archive_cmds='$RM $output_objdir/$soname~$CC -shared -fPIC ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - else - archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' - fi - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - export_dynamic_flag_spec='${wl}-E' - ;; - - hpux10*) - if test "$GCC" = yes && test "$with_gnu_ld" = no; then - archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_flag_spec_ld='+b $libdir' - hardcode_libdir_separator=: - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='${wl}-E' - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - fi - ;; - - hpux11*) - if test "$GCC" = yes && test "$with_gnu_ld" = no; then - case $host_cpu in - hppa*64*) - archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - archive_cmds='$CC -shared -fPIC ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' - ;; - esac - else - case $host_cpu in - hppa*64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - ;; - ia64*) - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' - ;; - *) - - # Older versions of the 11.00 compiler do not understand -b yet - # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 -$as_echo_n "checking if $CC understands -b... " >&6; } -if test "${lt_cv_prog_compiler__b+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_prog_compiler__b=no - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -b" - echo "$lt_simple_link_test_code" > conftest.$ac_ext - if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then - # The linker can only warn and ignore the option if not recognized - # So say no if there are warnings - if test -s conftest.err; then - # Append any errors to the config.log. - cat conftest.err 1>&5 - $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp - $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 - if diff conftest.exp conftest.er2 >/dev/null; then - lt_cv_prog_compiler__b=yes - fi - else - lt_cv_prog_compiler__b=yes - fi - fi - $RM -r conftest* - LDFLAGS="$save_LDFLAGS" - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 -$as_echo "$lt_cv_prog_compiler__b" >&6; } - -if test x"$lt_cv_prog_compiler__b" = xyes; then - archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' -else - archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' -fi - - ;; - esac - fi - if test "$with_gnu_ld" = no; then - hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' - hardcode_libdir_separator=: - - case $host_cpu in - hppa*64*|ia64*) - hardcode_direct=no - hardcode_shlibpath_var=no - ;; - *) - hardcode_direct=yes - hardcode_direct_absolute=yes - export_dynamic_flag_spec='${wl}-E' - - # hardcode_minus_L: Not really in the search PATH, - # but as the default location of the library. - hardcode_minus_L=yes - ;; - esac - fi - ;; - - irix5* | irix6* | nonstopux*) - if test "$GCC" = yes; then - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - # Try to use the -exported_symbol ld option, if it does not - # work, assume that -exports_file does not work either and - # implicitly export all symbols. - save_LDFLAGS="$LDFLAGS" - LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int foo(void) {} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' - -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS="$save_LDFLAGS" - else - archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - inherit_rpath=yes - link_all_deplibs=yes - ;; - - netbsd*) - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out - else - archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_direct=yes - hardcode_shlibpath_var=no - ;; - - newsos6) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - hardcode_shlibpath_var=no - ;; - - *nto* | *qnx*) - ;; - - openbsd*) - if test -f /usr/libexec/ld.so; then - hardcode_direct=yes - hardcode_shlibpath_var=no - hardcode_direct_absolute=yes - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - export_dynamic_flag_spec='${wl}-E' - else - case $host_os in - openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) - archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-R$libdir' - ;; - *) - archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' - hardcode_libdir_flag_spec='${wl}-rpath,$libdir' - ;; - esac - fi - else - ld_shlibs=no - fi - ;; - - os2*) - hardcode_libdir_flag_spec='-L$libdir' - hardcode_minus_L=yes - allow_undefined_flag=unsupported - archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' - old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' - ;; - - osf3*) - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - fi - archive_cmds_need_lc='no' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - hardcode_libdir_separator=: - ;; - - osf4* | osf5*) # as osf3* with the addition of -msym flag - if test "$GCC" = yes; then - allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' - hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' - else - allow_undefined_flag=' -expect_unresolved \*' - archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' - archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ - $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' - - # Both c and cxx compiler support -rpath directly - hardcode_libdir_flag_spec='-rpath $libdir' - fi - archive_cmds_need_lc='no' - hardcode_libdir_separator=: - ;; - - solaris*) - no_undefined_flag=' -z defs' - if test "$GCC" = yes; then - wlarc='${wl}' - archive_cmds='$CC -shared ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -shared ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - else - case `$CC -V 2>&1` in - *"Compilers 5.0"*) - wlarc='' - archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' - ;; - *) - wlarc='${wl}' - archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ - $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' - ;; - esac - fi - hardcode_libdir_flag_spec='-R$libdir' - hardcode_shlibpath_var=no - case $host_os in - solaris2.[0-5] | solaris2.[0-5].*) ;; - *) - # The compiler driver will combine and reorder linker options, - # but understands `-z linker_flag'. GCC discards it without `$wl', - # but is careful enough not to reorder. - # Supported since Solaris 2.6 (maybe 2.5.1?) - if test "$GCC" = yes; then - whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' - else - whole_archive_flag_spec='-z allextract$convenience -z defaultextract' - fi - ;; - esac - link_all_deplibs=yes - ;; - - sunos4*) - if test "x$host_vendor" = xsequent; then - # Use $CC to link under sequent, because it throws in some extra .o - # files that make .init and .fini sections work. - archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' - fi - hardcode_libdir_flag_spec='-L$libdir' - hardcode_direct=yes - hardcode_minus_L=yes - hardcode_shlibpath_var=no - ;; - - sysv4) - case $host_vendor in - sni) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=yes # is this really true??? - ;; - siemens) - ## LD is ld it makes a PLAMLIB - ## CC just makes a GrossModule. - archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' - reload_cmds='$CC -r -o $output$reload_objs' - hardcode_direct=no - ;; - motorola) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_direct=no #Motorola manual says yes, but my tests say they lie - ;; - esac - runpath_var='LD_RUN_PATH' - hardcode_shlibpath_var=no - ;; - - sysv4.3*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - export_dynamic_flag_spec='-Bexport' - ;; - - sysv4*MP*) - if test -d /usr/nec; then - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_shlibpath_var=no - runpath_var=LD_RUN_PATH - hardcode_runpath_var=yes - ld_shlibs=yes - fi - ;; - - sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) - no_undefined_flag='${wl}-z,text' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - sysv5* | sco3.2v5* | sco5v6*) - # Note: We can NOT use -z defs as we might desire, because we do not - # link with -lc, and that would cause any symbols used from libc to - # always be unresolved, which means just about no library would - # ever link correctly. If we're not using GNU ld we use -z text - # though, which does catch some bad symbols but isn't as heavy-handed - # as -z defs. - no_undefined_flag='${wl}-z,text' - allow_undefined_flag='${wl}-z,nodefs' - archive_cmds_need_lc=no - hardcode_shlibpath_var=no - hardcode_libdir_flag_spec='${wl}-R,$libdir' - hardcode_libdir_separator=':' - link_all_deplibs=yes - export_dynamic_flag_spec='${wl}-Bexport' - runpath_var='LD_RUN_PATH' - - if test "$GCC" = yes; then - archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - else - archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' - fi - ;; - - uts4*) - archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' - hardcode_libdir_flag_spec='-L$libdir' - hardcode_shlibpath_var=no - ;; - - *) - ld_shlibs=no - ;; - esac - - if test x$host_vendor = xsni; then - case $host in - sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) - export_dynamic_flag_spec='${wl}-Blargedynsym' - ;; - esac - fi - fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 -$as_echo "$ld_shlibs" >&6; } -test "$ld_shlibs" = no && can_build_shared=no - -with_gnu_ld=$with_gnu_ld - - - - - - - - - - - - - - - -# -# Do we need to explicitly link libc? -# -case "x$archive_cmds_need_lc" in -x|xyes) - # Assume -lc should be added - archive_cmds_need_lc=yes - - if test "$enable_shared" = yes && test "$GCC" = yes; then - case $archive_cmds in - *'~'*) - # FIXME: we may have to deal with multi-command sequences. - ;; - '$CC '*) - # Test whether the compiler implicitly links with -lc since on some - # systems, -lgcc has to come before -lc. If gcc already passes -lc - # to ld, don't add -lc before -lgcc. - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 -$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } -if test "${lt_cv_archive_cmds_need_lc+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - $RM conftest* - echo "$lt_simple_compile_test_code" > conftest.$ac_ext - - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 - (eval $ac_compile) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } 2>conftest.err; then - soname=conftest - lib=conftest - libobjs=conftest.$ac_objext - deplibs= - wl=$lt_prog_compiler_wl - pic_flag=$lt_prog_compiler_pic - compiler_flags=-v - linker_flags=-v - verstring= - output_objdir=. - libname=conftest - lt_save_allow_undefined_flag=$allow_undefined_flag - allow_undefined_flag= - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 - (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } - then - lt_cv_archive_cmds_need_lc=no - else - lt_cv_archive_cmds_need_lc=yes - fi - allow_undefined_flag=$lt_save_allow_undefined_flag - else - cat conftest.err 1>&5 - fi - $RM conftest* - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 -$as_echo "$lt_cv_archive_cmds_need_lc" >&6; } - archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc - ;; - esac - fi - ;; -esac - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 -$as_echo_n "checking dynamic linker characteristics... " >&6; } - -if test "$GCC" = yes; then - case $host_os in - darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; - *) lt_awk_arg="/^libraries:/" ;; - esac - case $host_os in - mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; - *) lt_sed_strip_eq="s,=/,/,g" ;; - esac - lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` - case $lt_search_path_spec in - *\;*) - # if the path contains ";" then we assume it to be the separator - # otherwise default to the standard path separator (i.e. ":") - it is - # assumed that no part of a normal pathname contains ";" but that should - # okay in the real world where ";" in dirpaths is itself problematic. - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` - ;; - *) - lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` - ;; - esac - # Ok, now we have the path, separated by spaces, we can step through it - # and add multilib dir if necessary. - lt_tmp_lt_search_path_spec= - lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` - for lt_sys_path in $lt_search_path_spec; do - if test -d "$lt_sys_path/$lt_multi_os_dir"; then - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" - else - test -d "$lt_sys_path" && \ - lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" - fi - done - lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' -BEGIN {RS=" "; FS="/|\n";} { - lt_foo=""; - lt_count=0; - for (lt_i = NF; lt_i > 0; lt_i--) { - if ($lt_i != "" && $lt_i != ".") { - if ($lt_i == "..") { - lt_count++; - } else { - if (lt_count == 0) { - lt_foo="/" $lt_i lt_foo; - } else { - lt_count--; - } - } - } - } - if (lt_foo != "") { lt_freq[lt_foo]++; } - if (lt_freq[lt_foo] == 1) { print lt_foo; } -}'` - # AWK program above erroneously prepends '/' to C:/dos/paths - # for these hosts. - case $host_os in - mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ - $SED 's,/\([A-Za-z]:\),\1,g'` ;; - esac - sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` -else - sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" -fi -library_names_spec= -libname_spec='lib$name' -soname_spec= -shrext_cmds=".so" -postinstall_cmds= -postuninstall_cmds= -finish_cmds= -finish_eval= -shlibpath_var= -shlibpath_overrides_runpath=unknown -version_type=none -dynamic_linker="$host_os ld.so" -sys_lib_dlsearch_path_spec="/lib /usr/lib" -need_lib_prefix=unknown -hardcode_into_libs=no - -# when you set need_version to no, make sure it does not cause -set_version -# flags to be left without arguments -need_version=unknown - -case $host_os in -aix3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' - shlibpath_var=LIBPATH - - # AIX 3 has no versioning support, so we append a major version to the name. - soname_spec='${libname}${release}${shared_ext}$major' - ;; - -aix[4-9]*) - version_type=linux - need_lib_prefix=no - need_version=no - hardcode_into_libs=yes - if test "$host_cpu" = ia64; then - # AIX 5 supports IA64 - library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - else - # With GCC up to 2.95.x, collect2 would create an import file - # for dependence libraries. The import file would start with - # the line `#! .'. This would cause the generated library to - # depend on `.', always an invalid library. This was fixed in - # development snapshots of GCC prior to 3.0. - case $host_os in - aix4 | aix4.[01] | aix4.[01].*) - if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' - echo ' yes ' - echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then - : - else - can_build_shared=no - fi - ;; - esac - # AIX (on Power*) has no versioning support, so currently we can not hardcode correct - # soname into executable. Probably we can add versioning support to - # collect2, so additional links can be useful in future. - if test "$aix_use_runtimelinking" = yes; then - # If using run time linking (on AIX 4.2 or later) use lib.so - # instead of lib.a to let people know that these are not - # typical AIX shared libraries. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - else - # We preserve .a as extension for shared libraries through AIX4.2 - # and later when we are not doing run time linking. - library_names_spec='${libname}${release}.a $libname.a' - soname_spec='${libname}${release}${shared_ext}$major' - fi - shlibpath_var=LIBPATH - fi - ;; - -amigaos*) - case $host_cpu in - powerpc) - # Since July 2007 AmigaOS4 officially supports .so libraries. - # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - ;; - m68k) - library_names_spec='$libname.ixlibrary $libname.a' - # Create ${libname}_ixlibrary.a entries in /sys/libs. - finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' - ;; - esac - ;; - -beos*) - library_names_spec='${libname}${shared_ext}' - dynamic_linker="$host_os ld.so" - shlibpath_var=LIBRARY_PATH - ;; - -bsdi[45]*) - version_type=linux - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" - sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" - # the default ld.so.conf also contains /usr/contrib/lib and - # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow - # libtool to hard-code these into programs - ;; - -cygwin* | mingw* | pw32* | cegcc*) - version_type=windows - shrext_cmds=".dll" - need_version=no - need_lib_prefix=no - - case $GCC,$host_os in - yes,cygwin* | yes,mingw* | yes,pw32* | yes,cegcc*) - library_names_spec='$libname.dll.a' - # DLL is installed to $(libdir)/../bin by postinstall_cmds - postinstall_cmds='base_file=`basename \${file}`~ - dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ - dldir=$destdir/`dirname \$dlpath`~ - test -d \$dldir || mkdir -p \$dldir~ - $install_prog $dir/$dlname \$dldir/$dlname~ - chmod a+x \$dldir/$dlname~ - if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then - eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; - fi' - postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ - dlpath=$dir/\$dldll~ - $RM \$dlpath' - shlibpath_overrides_runpath=yes - - case $host_os in - cygwin*) - # Cygwin DLLs use 'cyg' prefix rather than 'lib' - soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" - ;; - mingw* | cegcc*) - # MinGW DLLs use traditional 'lib' prefix - soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - pw32*) - # pw32 DLLs use 'pw' prefix rather than 'lib' - library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' - ;; - esac - ;; - - *) - library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' - ;; - esac - dynamic_linker='Win32 ld.exe' - # FIXME: first we should search . and the directory the executable is in - shlibpath_var=PATH - ;; - -darwin* | rhapsody*) - dynamic_linker="$host_os dyld" - version_type=darwin - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' - soname_spec='${libname}${release}${major}$shared_ext' - shlibpath_overrides_runpath=yes - shlibpath_var=DYLD_LIBRARY_PATH - shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' - - sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" - sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' - ;; - -dgux*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -freebsd* | dragonfly*) - # DragonFly does not have aout. When/if they implement a new - # versioning mechanism, adjust this. - if test -x /usr/bin/objformat; then - objformat=`/usr/bin/objformat` - else - case $host_os in - freebsd[23].*) objformat=aout ;; - *) objformat=elf ;; - esac - fi - version_type=freebsd-$objformat - case $version_type in - freebsd-elf*) - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - need_version=no - need_lib_prefix=no - ;; - freebsd-*) - library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' - need_version=yes - ;; - esac - shlibpath_var=LD_LIBRARY_PATH - case $host_os in - freebsd2.*) - shlibpath_overrides_runpath=yes - ;; - freebsd3.[01]* | freebsdelf3.[01]*) - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ - freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - *) # from 4.6 on, and DragonFly - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - esac - ;; - -gnu*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - hardcode_into_libs=yes - ;; - -haiku*) - version_type=linux - need_lib_prefix=no - need_version=no - dynamic_linker="$host_os runtime_loader" - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LIBRARY_PATH - shlibpath_overrides_runpath=yes - sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/beos/system/lib' - hardcode_into_libs=yes - ;; - -hpux9* | hpux10* | hpux11*) - # Give a soname corresponding to the major version so that dld.sl refuses to - # link against other versions. - version_type=sunos - need_lib_prefix=no - need_version=no - case $host_cpu in - ia64*) - shrext_cmds='.so' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.so" - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - if test "X$HPUX_IA64_MODE" = X32; then - sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" - else - sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" - fi - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - hppa*64*) - shrext_cmds='.sl' - hardcode_into_libs=yes - dynamic_linker="$host_os dld.sl" - shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH - shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" - sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec - ;; - *) - shrext_cmds='.sl' - dynamic_linker="$host_os dld.sl" - shlibpath_var=SHLIB_PATH - shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - ;; - esac - # HP-UX runs *really* slowly unless shared libraries are mode 555, ... - postinstall_cmds='chmod 555 $lib' - # or fails outright, so override atomically: - install_override_mode=555 - ;; - -interix[3-9]*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -irix5* | irix6* | nonstopux*) - case $host_os in - nonstopux*) version_type=nonstopux ;; - *) - if test "$lt_cv_prog_gnu_ld" = yes; then - version_type=linux - else - version_type=irix - fi ;; - esac - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' - case $host_os in - irix5* | nonstopux*) - libsuff= shlibsuff= - ;; - *) - case $LD in # libtool.m4 will add one of these switches to LD - *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") - libsuff= shlibsuff= libmagic=32-bit;; - *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") - libsuff=32 shlibsuff=N32 libmagic=N32;; - *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") - libsuff=64 shlibsuff=64 libmagic=64-bit;; - *) libsuff= shlibsuff= libmagic=never-match;; - esac - ;; - esac - shlibpath_var=LD_LIBRARY${shlibsuff}_PATH - shlibpath_overrides_runpath=no - sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" - sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" - hardcode_into_libs=yes - ;; - -# No shared lib support for Linux oldld, aout, or coff. -linux*oldld* | linux*aout* | linux*coff*) - dynamic_linker=no - ;; - -# This must be Linux ELF. -linux* | k*bsd*-gnu | kopensolaris*-gnu) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - - # Some binutils ld are patched to set DT_RUNPATH - if test "${lt_cv_shlibpath_overrides_runpath+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - lt_cv_shlibpath_overrides_runpath=no - save_LDFLAGS=$LDFLAGS - save_libdir=$libdir - eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ - LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : - lt_cv_shlibpath_overrides_runpath=yes -fi -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - LDFLAGS=$save_LDFLAGS - libdir=$save_libdir - -fi - - shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath - - # This implies no fast_install, which is unacceptable. - # Some rework will be needed to allow for fast_install - # before this can be enabled. - hardcode_into_libs=yes - - # Append ld.so.conf contents to the search path - if test -f /etc/ld.so.conf; then - lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` - sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" - fi - - # We used to test for /lib/ld.so.1 and disable shared libraries on - # powerpc, because MkLinux only supported shared libraries with the - # GNU dynamic linker. Since this was broken with cross compilers, - # most powerpc-linux boxes support dynamic linking these days and - # people can always --disable-shared, the test was removed, and we - # assume the GNU/Linux dynamic linker is in use. - dynamic_linker='GNU/Linux ld.so' - ;; - -netbsd*) - version_type=sunos - need_lib_prefix=no - need_version=no - if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - dynamic_linker='NetBSD (a.out) ld.so' - else - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - dynamic_linker='NetBSD ld.elf_so' - fi - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - ;; - -newsos6) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - ;; - -*nto* | *qnx*) - version_type=qnx - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - dynamic_linker='ldqnx.so' - ;; - -openbsd*) - version_type=sunos - sys_lib_dlsearch_path_spec="/usr/lib" - need_lib_prefix=no - # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. - case $host_os in - openbsd3.3 | openbsd3.3.*) need_version=yes ;; - *) need_version=no ;; - esac - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' - shlibpath_var=LD_LIBRARY_PATH - if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then - case $host_os in - openbsd2.[89] | openbsd2.[89].*) - shlibpath_overrides_runpath=no - ;; - *) - shlibpath_overrides_runpath=yes - ;; - esac - else - shlibpath_overrides_runpath=yes - fi - ;; - -os2*) - libname_spec='$name' - shrext_cmds=".dll" - need_lib_prefix=no - library_names_spec='$libname${shared_ext} $libname.a' - dynamic_linker='OS/2 ld.exe' - shlibpath_var=LIBPATH - ;; - -osf3* | osf4* | osf5*) - version_type=osf - need_lib_prefix=no - need_version=no - soname_spec='${libname}${release}${shared_ext}$major' - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" - sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" - ;; - -rdos*) - dynamic_linker=no - ;; - -solaris*) - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - # ldd complains unless libraries are executable - postinstall_cmds='chmod +x $lib' - ;; - -sunos4*) - version_type=sunos - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' - finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - if test "$with_gnu_ld" = yes; then - need_lib_prefix=no - fi - need_version=yes - ;; - -sysv4 | sysv4.3*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - case $host_vendor in - sni) - shlibpath_overrides_runpath=no - need_lib_prefix=no - runpath_var=LD_RUN_PATH - ;; - siemens) - need_lib_prefix=no - ;; - motorola) - need_lib_prefix=no - need_version=no - shlibpath_overrides_runpath=no - sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' - ;; - esac - ;; - -sysv4*MP*) - if test -d /usr/nec ;then - version_type=linux - library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' - soname_spec='$libname${shared_ext}.$major' - shlibpath_var=LD_LIBRARY_PATH - fi - ;; - -sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) - version_type=freebsd-elf - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=yes - hardcode_into_libs=yes - if test "$with_gnu_ld" = yes; then - sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' - else - sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' - case $host_os in - sco3.2v5*) - sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" - ;; - esac - fi - sys_lib_dlsearch_path_spec='/usr/lib' - ;; - -tpf*) - # TPF is a cross-target only. Preferred cross-host = GNU/Linux. - version_type=linux - need_lib_prefix=no - need_version=no - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - shlibpath_var=LD_LIBRARY_PATH - shlibpath_overrides_runpath=no - hardcode_into_libs=yes - ;; - -uts4*) - version_type=linux - library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' - soname_spec='${libname}${release}${shared_ext}$major' - shlibpath_var=LD_LIBRARY_PATH - ;; - -*) - dynamic_linker=no - ;; -esac -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 -$as_echo "$dynamic_linker" >&6; } -test "$dynamic_linker" = no && can_build_shared=no - -variables_saved_for_relink="PATH $shlibpath_var $runpath_var" -if test "$GCC" = yes; then - variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" -fi - -if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then - sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" -fi -if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then - sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" -fi - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 -$as_echo_n "checking how to hardcode library paths into programs... " >&6; } -hardcode_action= -if test -n "$hardcode_libdir_flag_spec" || - test -n "$runpath_var" || - test "X$hardcode_automatic" = "Xyes" ; then - - # We can hardcode non-existent directories. - if test "$hardcode_direct" != no && - # If the only mechanism to avoid hardcoding is shlibpath_var, we - # have to relink, otherwise we might link with an installed library - # when we should be linking with a yet-to-be-installed one - ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && - test "$hardcode_minus_L" != no; then - # Linking always hardcodes the temporary library directory. - hardcode_action=relink - else - # We can link without hardcoding, and we can hardcode nonexisting dirs. - hardcode_action=immediate - fi -else - # We cannot hardcode anything, or else we can only hardcode existing - # directories. - hardcode_action=unsupported -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 -$as_echo "$hardcode_action" >&6; } - -if test "$hardcode_action" = relink || - test "$inherit_rpath" = yes; then - # Fast installation is not supported - enable_fast_install=no -elif test "$shlibpath_overrides_runpath" = yes || - test "$enable_shared" = no; then - # Fast installation is not necessary - enable_fast_install=needless -fi - - - - - - - if test "x$enable_dlopen" != xyes; then - enable_dlopen=unknown - enable_dlopen_self=unknown - enable_dlopen_self_static=unknown -else - lt_cv_dlopen=no - lt_cv_dlopen_libs= - - case $host_os in - beos*) - lt_cv_dlopen="load_add_on" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - ;; - - mingw* | pw32* | cegcc*) - lt_cv_dlopen="LoadLibrary" - lt_cv_dlopen_libs= - ;; - - cygwin*) - lt_cv_dlopen="dlopen" - lt_cv_dlopen_libs= - ;; - - darwin*) - # if libdl is installed we need to link against it - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_dlopen=yes -else - ac_cv_lib_dl_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - - lt_cv_dlopen="dyld" - lt_cv_dlopen_libs= - lt_cv_dlopen_self=yes - -fi - - ;; - - *) - ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" -if test "x$ac_cv_func_shl_load" = x""yes; then : - lt_cv_dlopen="shl_load" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 -$as_echo_n "checking for shl_load in -ldld... " >&6; } -if test "${ac_cv_lib_dld_shl_load+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char shl_load (); -int -main () -{ -return shl_load (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dld_shl_load=yes -else - ac_cv_lib_dld_shl_load=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 -$as_echo "$ac_cv_lib_dld_shl_load" >&6; } -if test "x$ac_cv_lib_dld_shl_load" = x""yes; then : - lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" -else - ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" -if test "x$ac_cv_func_dlopen" = x""yes; then : - lt_cv_dlopen="dlopen" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 -$as_echo_n "checking for dlopen in -ldl... " >&6; } -if test "${ac_cv_lib_dl_dlopen+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldl $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dl_dlopen=yes -else - ac_cv_lib_dl_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 -$as_echo "$ac_cv_lib_dl_dlopen" >&6; } -if test "x$ac_cv_lib_dl_dlopen" = x""yes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 -$as_echo_n "checking for dlopen in -lsvld... " >&6; } -if test "${ac_cv_lib_svld_dlopen+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-lsvld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dlopen (); -int -main () -{ -return dlopen (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_svld_dlopen=yes -else - ac_cv_lib_svld_dlopen=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 -$as_echo "$ac_cv_lib_svld_dlopen" >&6; } -if test "x$ac_cv_lib_svld_dlopen" = x""yes; then : - lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 -$as_echo_n "checking for dld_link in -ldld... " >&6; } -if test "${ac_cv_lib_dld_dld_link+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - ac_check_lib_save_LIBS=$LIBS -LIBS="-ldld $LIBS" -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -/* Override any GCC internal prototype to avoid an error. - Use char because int might match the return type of a GCC - builtin and then its argument prototype would still apply. */ -#ifdef __cplusplus -extern "C" -#endif -char dld_link (); -int -main () -{ -return dld_link (); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_dld_dld_link=yes -else - ac_cv_lib_dld_dld_link=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext -LIBS=$ac_check_lib_save_LIBS -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 -$as_echo "$ac_cv_lib_dld_dld_link" >&6; } -if test "x$ac_cv_lib_dld_dld_link" = x""yes; then : - lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" -fi - - -fi - - -fi - - -fi - - -fi - - -fi - - ;; - esac - - if test "x$lt_cv_dlopen" != xno; then - enable_dlopen=yes - else - enable_dlopen=no - fi - - case $lt_cv_dlopen in - dlopen) - save_CPPFLAGS="$CPPFLAGS" - test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" - - save_LDFLAGS="$LDFLAGS" - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" - - save_LIBS="$LIBS" - LIBS="$lt_cv_dlopen_libs $LIBS" - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 -$as_echo_n "checking whether a program can dlopen itself... " >&6; } -if test "${lt_cv_dlopen_self+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - lt_cv_dlopen_self=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line 11134 "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisbility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -void fnord () __attribute__((visibility("default"))); -#endif - -void fnord () { int i=42; } -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self=no - fi -fi -rm -fr conftest* - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 -$as_echo "$lt_cv_dlopen_self" >&6; } - - if test "x$lt_cv_dlopen_self" = xyes; then - wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 -$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } -if test "${lt_cv_dlopen_self_static+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - lt_cv_dlopen_self_static=cross -else - lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 - lt_status=$lt_dlunknown - cat > conftest.$ac_ext <<_LT_EOF -#line 11240 "configure" -#include "confdefs.h" - -#if HAVE_DLFCN_H -#include -#endif - -#include - -#ifdef RTLD_GLOBAL -# define LT_DLGLOBAL RTLD_GLOBAL -#else -# ifdef DL_GLOBAL -# define LT_DLGLOBAL DL_GLOBAL -# else -# define LT_DLGLOBAL 0 -# endif -#endif - -/* We may have to define LT_DLLAZY_OR_NOW in the command line if we - find out it does not work in some platform. */ -#ifndef LT_DLLAZY_OR_NOW -# ifdef RTLD_LAZY -# define LT_DLLAZY_OR_NOW RTLD_LAZY -# else -# ifdef DL_LAZY -# define LT_DLLAZY_OR_NOW DL_LAZY -# else -# ifdef RTLD_NOW -# define LT_DLLAZY_OR_NOW RTLD_NOW -# else -# ifdef DL_NOW -# define LT_DLLAZY_OR_NOW DL_NOW -# else -# define LT_DLLAZY_OR_NOW 0 -# endif -# endif -# endif -# endif -#endif - -/* When -fvisbility=hidden is used, assume the code has been annotated - correspondingly for the symbols needed. */ -#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) -void fnord () __attribute__((visibility("default"))); -#endif - -void fnord () { int i=42; } -int main () -{ - void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); - int status = $lt_dlunknown; - - if (self) - { - if (dlsym (self,"fnord")) status = $lt_dlno_uscore; - else - { - if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; - else puts (dlerror ()); - } - /* dlclose (self); */ - } - else - puts (dlerror ()); - - return status; -} -_LT_EOF - if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 - (eval $ac_link) 2>&5 - ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then - (./conftest; exit; ) >&5 2>/dev/null - lt_status=$? - case x$lt_status in - x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; - x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; - esac - else : - # compilation failed - lt_cv_dlopen_self_static=no - fi -fi -rm -fr conftest* - - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 -$as_echo "$lt_cv_dlopen_self_static" >&6; } - fi - - CPPFLAGS="$save_CPPFLAGS" - LDFLAGS="$save_LDFLAGS" - LIBS="$save_LIBS" - ;; - esac - - case $lt_cv_dlopen_self in - yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; - *) enable_dlopen_self=unknown ;; - esac - - case $lt_cv_dlopen_self_static in - yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; - *) enable_dlopen_self_static=unknown ;; - esac -fi - - - - - - - - - - - - - - - - - -striplib= -old_striplib= -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 -$as_echo_n "checking whether stripping libraries is possible... " >&6; } -if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then - test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" - test -z "$striplib" && striplib="$STRIP --strip-unneeded" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } -else -# FIXME - insert some real tests, host_os isn't really good enough - case $host_os in - darwin*) - if test -n "$STRIP" ; then - striplib="$STRIP -x" - old_striplib="$STRIP -S" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 -$as_echo "yes" >&6; } - else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - fi - ;; - *) - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } - ;; - esac -fi - - - - - - - - - - - - - # Report which library types will actually be built - { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 -$as_echo_n "checking if libtool supports shared libraries... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 -$as_echo "$can_build_shared" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 -$as_echo_n "checking whether to build shared libraries... " >&6; } - test "$can_build_shared" = "no" && enable_shared=no - - # On AIX, shared libraries and static libraries use the same namespace, and - # are all built from PIC. - case $host_os in - aix3*) - test "$enable_shared" = yes && enable_static=no - if test -n "$RANLIB"; then - archive_cmds="$archive_cmds~\$RANLIB \$lib" - postinstall_cmds='$RANLIB $lib' - fi - ;; - - aix[4-9]*) - if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then - test "$enable_shared" = yes && enable_static=no - fi - ;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 -$as_echo "$enable_shared" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 -$as_echo_n "checking whether to build static libraries... " >&6; } - # Make sure either enable_shared or enable_static is yes. - test "$enable_shared" = yes || enable_static=yes - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 -$as_echo "$enable_static" >&6; } - - - - -fi -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -CC="$lt_save_CC" - - - - - - - - - - - - - - ac_config_commands="$ac_config_commands libtool" - - - - -# Only expand once: - - - - -backtrace_supported=yes - -if test -n "${with_target_subdir}"; then - # We are compiling a GCC library. We can assume that the unwind - # library exists. - BACKTRACE_FILE="backtrace.lo simple.lo" -else - ac_fn_c_check_header_mongrel "$LINENO" "unwind.h" "ac_cv_header_unwind_h" "$ac_includes_default" -if test "x$ac_cv_header_unwind_h" = x""yes; then : - ac_fn_c_check_func "$LINENO" "_Unwind_Backtrace" "ac_cv_func__Unwind_Backtrace" -if test "x$ac_cv_func__Unwind_Backtrace" = x""yes; then : - BACKTRACE_FILE="backtrace.lo simple.lo" -else - BACKTRACE_FILE="nounwind.lo" - backtrace_supported=no -fi - -else - BACKTRACE_FILE="nounwind.lo" - backtrace_supported=no -fi - - -fi - - -EXTRA_FLAGS= -if test -n "${with_target_subdir}"; then - EXTRA_FLAGS="-funwind-tables -frandom-seed=\$@" -else - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -funwind-tables option" >&5 -$as_echo_n "checking for -funwind-tables option... " >&6; } -if test "${libbacktrace_cv_c_unwind_tables+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - CFLAGS_hold="$CFLAGS" - CFLAGS="$CFLAGS -funwind-tables" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -static int f() { return 0; } -int -main () -{ -return f(); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - libbacktrace_cv_c_unwind_tables=yes -else - libbacktrace_cv_c_unwind_tables=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$CFLAGS_hold" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_c_unwind_tables" >&5 -$as_echo "$libbacktrace_cv_c_unwind_tables" >&6; } - if test "$libbacktrace_cv_c_unwind_tables" = "yes"; then - EXTRA_FLAGS=-funwind-tables - fi - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -frandom-seed=string option" >&5 -$as_echo_n "checking for -frandom-seed=string option... " >&6; } -if test "${libbacktrace_cv_c_random_seed_string+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - CFLAGS_hold="$CFLAGS" - CFLAGS="$CFLAGS -frandom-seed=conftest.lo" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - libbacktrace_cv_c_random_seed_string=yes -else - libbacktrace_cv_c_random_seed_string=no -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - CFLAGS="$CFLAGS_hold" -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_c_random_seed_string" >&5 -$as_echo "$libbacktrace_cv_c_random_seed_string" >&6; } - if test "$libbacktrace_cv_c_random_seed_string" = "yes"; then - EXTRA_FLAGS="$EXTRA_FLAGS -frandom-seed=\$@" - fi -fi - - -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - -WARN_FLAGS= -save_CFLAGS="$CFLAGS" -for real_option in -W -Wall -Wwrite-strings -Wstrict-prototypes \ - -Wmissing-prototypes -Wold-style-definition \ - -Wmissing-format-attribute -Wcast-qual; do - # Do the check with the no- prefix removed since gcc silently - # accepts any -Wno-* option on purpose - case $real_option in - -Wno-*) option=-W`expr x$real_option : 'x-Wno-\(.*\)'` ;; - *) option=$real_option ;; - esac - as_acx_Woption=`$as_echo "acx_cv_prog_cc_warning_$option" | $as_tr_sh` - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports $option" >&5 -$as_echo_n "checking whether $CC supports $option... " >&6; } -if { as_var=$as_acx_Woption; eval "test \"\${$as_var+set}\" = set"; }; then : - $as_echo_n "(cached) " >&6 -else - CFLAGS="$option" - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - eval "$as_acx_Woption=yes" -else - eval "$as_acx_Woption=no" -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - -fi -eval ac_res=\$$as_acx_Woption - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 -$as_echo "$ac_res" >&6; } - if test `eval 'as_val=${'$as_acx_Woption'};$as_echo "$as_val"'` = yes; then : - WARN_FLAGS="$WARN_FLAGS${WARN_FLAGS:+ }$real_option" -fi - done -CFLAGS="$save_CFLAGS" -ac_ext=c -ac_cpp='$CPP $CPPFLAGS' -ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' -ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' -ac_compiler_gnu=$ac_cv_c_compiler_gnu - - - -if test -n "${with_target_subdir}"; then - WARN_FLAGS="$WARN_FLAGS -Werror" -fi - - - -if test -n "${with_target_subdir}"; then - - -# Check whether --with-system-libunwind was given. -if test "${with_system_libunwind+set}" = set; then : - withval=$with_system_libunwind; -fi - - # If system-libunwind was not specifically set, pick a default setting. - if test x$with_system_libunwind = x; then - case ${target} in - ia64-*-hpux*) with_system_libunwind=yes ;; - *) with_system_libunwind=no ;; - esac - fi - # Based on system-libunwind and target, do we have ipinfo? - if test x$with_system_libunwind = xyes; then - case ${target} in - ia64-*-*) have_unwind_getipinfo=no ;; - *) have_unwind_getipinfo=yes ;; - esac - else - # Darwin before version 9 does not have _Unwind_GetIPInfo. - - case ${target} in - *-*-darwin[3-8]|*-*-darwin[3-8].*) have_unwind_getipinfo=no ;; - *) have_unwind_getipinfo=yes ;; - esac - - fi - - if test x$have_unwind_getipinfo = xyes; then - -$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h - - fi - -else - ac_save_CFFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror-implicit-function-declaration" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _Unwind_GetIPInfo" >&5 -$as_echo_n "checking for _Unwind_GetIPInfo... " >&6; } - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include "unwind.h" - struct _Unwind_Context *context; - int ip_before_insn = 0; -int -main () -{ -return _Unwind_GetIPInfo (context, &ip_before_insn); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - have_unwind_getipinfo=yes -else - have_unwind_getipinfo=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - CFLAGS="$ac_save_CFLAGS" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_unwind_getipinfo" >&5 -$as_echo "$have_unwind_getipinfo" >&6; } - if test "$have_unwind_getipinfo" = "yes"; then - -$as_echo "#define HAVE_GETIPINFO 1" >>confdefs.h - - fi -fi - -# Enable --enable-host-shared. -# Check whether --enable-host-shared was given. -if test "${enable_host_shared+set}" = set; then : - enableval=$enable_host_shared; PIC_FLAG=-fPIC -else - PIC_FLAG= -fi - - - -# Test for __sync support. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking __sync extensions" >&5 -$as_echo_n "checking __sync extensions... " >&6; } -if test "${libbacktrace_cv_sys_sync+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "${with_target_subdir}"; then - case "${host}" in - hppa*-*-hpux*) libbacktrace_cv_sys_sync=no ;; - *) libbacktrace_cv_sys_sync=yes ;; - esac - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main () -{ -__sync_bool_compare_and_swap (&i, i, i); - __sync_lock_test_and_set (&i, 1); - __sync_lock_release (&i); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - libbacktrace_cv_sys_sync=yes -else - libbacktrace_cv_sys_sync=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_sync" >&5 -$as_echo "$libbacktrace_cv_sys_sync" >&6; } -BACKTRACE_SUPPORTS_THREADS=0 -if test "$libbacktrace_cv_sys_sync" = "yes"; then - BACKTRACE_SUPPORTS_THREADS=1 - -$as_echo "#define HAVE_SYNC_FUNCTIONS 1" >>confdefs.h - -fi - - -# Test for __atomic support. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking __atomic extensions" >&5 -$as_echo_n "checking __atomic extensions... " >&6; } -if test "${libbacktrace_cv_sys_atomic+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test -n "${with_target_subdir}"; then - libbacktrace_cv_sys_atomic=yes - else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main () -{ -__atomic_load_n (&i, __ATOMIC_ACQUIRE); - __atomic_store_n (&i, 1, __ATOMIC_RELEASE); - ; - return 0; -} -_ACEOF -if ac_fn_c_try_link "$LINENO"; then : - libbacktrace_cv_sys_atomic=yes -else - libbacktrace_cv_sys_atomic=no -fi -rm -f core conftest.err conftest.$ac_objext \ - conftest$ac_exeext conftest.$ac_ext - fi -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_atomic" >&5 -$as_echo "$libbacktrace_cv_sys_atomic" >&6; } -if test "$libbacktrace_cv_sys_atomic" = "yes"; then - -$as_echo "#define HAVE_ATOMIC_FUNCTIONS 1" >>confdefs.h - -fi - -# The library needs to be able to read the executable itself. Compile -# a file to determine the executable format. The awk script -# filetype.awk prints out the file type. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking output filetype" >&5 -$as_echo_n "checking output filetype... " >&6; } -if test "${libbacktrace_cv_sys_filetype+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - filetype= -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -int i; -int -main () -{ -int j; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - filetype=`${AWK} -f $srcdir/filetype.awk conftest.$ac_objext` -else - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error "compiler failed -See \`config.log' for more details." "$LINENO" 5; } -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext -libbacktrace_cv_sys_filetype=$filetype -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_filetype" >&5 -$as_echo "$libbacktrace_cv_sys_filetype" >&6; } - -# Match the file type to decide what files to compile. -FORMAT_FILE= -backtrace_supports_data=yes -case "$libbacktrace_cv_sys_filetype" in -elf*) FORMAT_FILE="elf.lo" ;; -pecoff) FORMAT_FILE="pecoff.lo" - backtrace_supports_data=no - ;; -macho*) FORMAT_FILE="macho.lo" - backtrace_supports_data=no - ;; -*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not determine output file type" >&5 -$as_echo "$as_me: WARNING: could not determine output file type" >&2;} - FORMAT_FILE="unknown.lo" - backtrace_supported=no - ;; -esac - - -# ELF defines. -elfsize= -case "$libbacktrace_cv_sys_filetype" in -elf32) elfsize=32 ;; -elf64) elfsize=64 ;; -*) elfsize=unused -esac - -cat >>confdefs.h <<_ACEOF -#define BACKTRACE_ELF_SIZE $elfsize -_ACEOF - - -BACKTRACE_SUPPORTED=0 -if test "$backtrace_supported" = "yes"; then - BACKTRACE_SUPPORTED=1 -fi - - -BACKTRACE_SUPPORTS_DATA=0 -if test "$backtrace_supports_data" = "yes"; then - BACKTRACE_SUPPORTS_DATA=1 -fi - - - - -inttype_headers=`echo inttypes.h sys/inttypes.h | sed -e 's/,/ /g'` - -acx_cv_header_stdint=stddef.h -acx_cv_header_stdint_kind="(already complete)" -for i in stdint.h $inttype_headers; do - unset ac_cv_type_uintptr_t - unset ac_cv_type_uintmax_t - unset ac_cv_type_int_least32_t - unset ac_cv_type_int_fast32_t - unset ac_cv_type_uint64_t - $as_echo_n "looking for a compliant stdint.h in $i, " >&6 - ac_fn_c_check_type "$LINENO" "uintmax_t" "ac_cv_type_uintmax_t" "#include -#include <$i> -" -if test "x$ac_cv_type_uintmax_t" = x""yes; then : - acx_cv_header_stdint=$i -else - continue -fi - - ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "#include -#include <$i> -" -if test "x$ac_cv_type_uintptr_t" = x""yes; then : - -else - acx_cv_header_stdint_kind="(mostly complete)" -fi - - ac_fn_c_check_type "$LINENO" "int_least32_t" "ac_cv_type_int_least32_t" "#include -#include <$i> -" -if test "x$ac_cv_type_int_least32_t" = x""yes; then : - -else - acx_cv_header_stdint_kind="(mostly complete)" -fi - - ac_fn_c_check_type "$LINENO" "int_fast32_t" "ac_cv_type_int_fast32_t" "#include -#include <$i> -" -if test "x$ac_cv_type_int_fast32_t" = x""yes; then : - -else - acx_cv_header_stdint_kind="(mostly complete)" -fi - - ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "#include -#include <$i> -" -if test "x$ac_cv_type_uint64_t" = x""yes; then : - -else - acx_cv_header_stdint_kind="(lacks uint64_t)" -fi - - break -done -if test "$acx_cv_header_stdint" = stddef.h; then - acx_cv_header_stdint_kind="(lacks uintmax_t)" - for i in stdint.h $inttype_headers; do - unset ac_cv_type_uintptr_t - unset ac_cv_type_uint32_t - unset ac_cv_type_uint64_t - $as_echo_n "looking for an incomplete stdint.h in $i, " >&6 - ac_fn_c_check_type "$LINENO" "uint32_t" "ac_cv_type_uint32_t" "#include -#include <$i> -" -if test "x$ac_cv_type_uint32_t" = x""yes; then : - acx_cv_header_stdint=$i -else - continue -fi - - ac_fn_c_check_type "$LINENO" "uint64_t" "ac_cv_type_uint64_t" "#include -#include <$i> -" -if test "x$ac_cv_type_uint64_t" = x""yes; then : - -fi - - ac_fn_c_check_type "$LINENO" "uintptr_t" "ac_cv_type_uintptr_t" "#include -#include <$i> -" -if test "x$ac_cv_type_uintptr_t" = x""yes; then : - -fi - - break - done -fi -if test "$acx_cv_header_stdint" = stddef.h; then - acx_cv_header_stdint_kind="(u_intXX_t style)" - for i in sys/types.h $inttype_headers; do - unset ac_cv_type_u_int32_t - unset ac_cv_type_u_int64_t - $as_echo_n "looking for u_intXX_t types in $i, " >&6 - ac_fn_c_check_type "$LINENO" "u_int32_t" "ac_cv_type_u_int32_t" "#include -#include <$i> -" -if test "x$ac_cv_type_u_int32_t" = x""yes; then : - acx_cv_header_stdint=$i -else - continue -fi - - ac_fn_c_check_type "$LINENO" "u_int64_t" "ac_cv_type_u_int64_t" "#include -#include <$i> -" -if test "x$ac_cv_type_u_int64_t" = x""yes; then : - -fi - - break - done -fi -if test "$acx_cv_header_stdint" = stddef.h; then - acx_cv_header_stdint_kind="(using manual detection)" -fi - -test -z "$ac_cv_type_uintptr_t" && ac_cv_type_uintptr_t=no -test -z "$ac_cv_type_uint64_t" && ac_cv_type_uint64_t=no -test -z "$ac_cv_type_u_int64_t" && ac_cv_type_u_int64_t=no -test -z "$ac_cv_type_int_least32_t" && ac_cv_type_int_least32_t=no -test -z "$ac_cv_type_int_fast32_t" && ac_cv_type_int_fast32_t=no - -# ----------------- Summarize what we found so far - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking what to include in gstdint.h" >&5 -$as_echo_n "checking what to include in gstdint.h... " >&6; } - -case `$as_basename -- gstdint.h || -$as_expr X/gstdint.h : '.*/\([^/][^/]*\)/*$' \| \ - Xgstdint.h : 'X\(//\)$' \| \ - Xgstdint.h : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/gstdint.h | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` in - stdint.h) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: are you sure you want it there?" >&5 -$as_echo "$as_me: WARNING: are you sure you want it there?" >&2;} ;; - inttypes.h) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: are you sure you want it there?" >&5 -$as_echo "$as_me: WARNING: are you sure you want it there?" >&2;} ;; - *) ;; -esac - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_header_stdint $acx_cv_header_stdint_kind" >&5 -$as_echo "$acx_cv_header_stdint $acx_cv_header_stdint_kind" >&6; } - -# ----------------- done included file, check C basic types -------- - -# Lacking an uintptr_t? Test size of void * -case "$acx_cv_header_stdint:$ac_cv_type_uintptr_t" in - stddef.h:* | *:no) # The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of void *" >&5 -$as_echo_n "checking size of void *... " >&6; } -if test "${ac_cv_sizeof_void_p+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (void *))" "ac_cv_sizeof_void_p" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_void_p" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (void *) -See \`config.log' for more details." "$LINENO" 5; }; } - else - ac_cv_sizeof_void_p=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_void_p" >&5 -$as_echo "$ac_cv_sizeof_void_p" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_VOID_P $ac_cv_sizeof_void_p -_ACEOF - - ;; -esac - -# Lacking an uint64_t? Test size of long -case "$acx_cv_header_stdint:$ac_cv_type_uint64_t:$ac_cv_type_u_int64_t" in - stddef.h:*:* | *:no:no) # The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of long" >&5 -$as_echo_n "checking size of long... " >&6; } -if test "${ac_cv_sizeof_long+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (long))" "ac_cv_sizeof_long" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_long" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (long) -See \`config.log' for more details." "$LINENO" 5; }; } - else - ac_cv_sizeof_long=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_long" >&5 -$as_echo "$ac_cv_sizeof_long" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_LONG $ac_cv_sizeof_long -_ACEOF - - ;; -esac - -if test $acx_cv_header_stdint = stddef.h; then - # Lacking a good header? Test size of everything and deduce all types. - # The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of int" >&5 -$as_echo_n "checking size of int... " >&6; } -if test "${ac_cv_sizeof_int+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (int))" "ac_cv_sizeof_int" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_int" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (int) -See \`config.log' for more details." "$LINENO" 5; }; } - else - ac_cv_sizeof_int=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_int" >&5 -$as_echo "$ac_cv_sizeof_int" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_INT $ac_cv_sizeof_int -_ACEOF - - - # The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of short" >&5 -$as_echo_n "checking size of short... " >&6; } -if test "${ac_cv_sizeof_short+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (short))" "ac_cv_sizeof_short" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_short" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (short) -See \`config.log' for more details." "$LINENO" 5; }; } - else - ac_cv_sizeof_short=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_short" >&5 -$as_echo "$ac_cv_sizeof_short" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_SHORT $ac_cv_sizeof_short -_ACEOF - - - # The cast to long int works around a bug in the HP C Compiler -# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects -# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. -# This bug is HP SR number 8606223364. -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of char" >&5 -$as_echo_n "checking size of char... " >&6; } -if test "${ac_cv_sizeof_char+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (char))" "ac_cv_sizeof_char" "$ac_includes_default"; then : - -else - if test "$ac_cv_type_char" = yes; then - { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -{ as_fn_set_status 77 -as_fn_error "cannot compute sizeof (char) -See \`config.log' for more details." "$LINENO" 5; }; } - else - ac_cv_sizeof_char=0 - fi -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_char" >&5 -$as_echo "$ac_cv_sizeof_char" >&6; } - - - -cat >>confdefs.h <<_ACEOF -#define SIZEOF_CHAR $ac_cv_sizeof_char -_ACEOF - - - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int8_t" >&5 -$as_echo_n "checking for type equivalent to int8_t... " >&6; } - case "$ac_cv_sizeof_char" in - 1) acx_cv_type_int8_t=char ;; - *) as_fn_error "no 8-bit type, please report a bug" "$LINENO" 5 - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int8_t" >&5 -$as_echo "$acx_cv_type_int8_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int16_t" >&5 -$as_echo_n "checking for type equivalent to int16_t... " >&6; } - case "$ac_cv_sizeof_int:$ac_cv_sizeof_short" in - 2:*) acx_cv_type_int16_t=int ;; - *:2) acx_cv_type_int16_t=short ;; - *) as_fn_error "no 16-bit type, please report a bug" "$LINENO" 5 - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int16_t" >&5 -$as_echo "$acx_cv_type_int16_t" >&6; } - - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int32_t" >&5 -$as_echo_n "checking for type equivalent to int32_t... " >&6; } - case "$ac_cv_sizeof_int:$ac_cv_sizeof_long" in - 4:*) acx_cv_type_int32_t=int ;; - *:4) acx_cv_type_int32_t=long ;; - *) as_fn_error "no 32-bit type, please report a bug" "$LINENO" 5 - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_int32_t" >&5 -$as_echo "$acx_cv_type_int32_t" >&6; } -fi - -# These tests are here to make the output prettier - -if test "$ac_cv_type_uint64_t" != yes && test "$ac_cv_type_u_int64_t" != yes; then - case "$ac_cv_sizeof_long" in - 8) acx_cv_type_int64_t=long ;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to int64_t" >&5 -$as_echo_n "checking for type equivalent to int64_t... " >&6; } - { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${acx_cv_type_int64_t-'using preprocessor symbols'}" >&5 -$as_echo "${acx_cv_type_int64_t-'using preprocessor symbols'}" >&6; } -fi - -# Now we can use the above types - -if test "$ac_cv_type_uintptr_t" != yes; then - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for type equivalent to intptr_t" >&5 -$as_echo_n "checking for type equivalent to intptr_t... " >&6; } - case $ac_cv_sizeof_void_p in - 2) acx_cv_type_intptr_t=int16_t ;; - 4) acx_cv_type_intptr_t=int32_t ;; - 8) acx_cv_type_intptr_t=int64_t ;; - *) as_fn_error "no equivalent for intptr_t, please report a bug" "$LINENO" 5 - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $acx_cv_type_intptr_t" >&5 -$as_echo "$acx_cv_type_intptr_t" >&6; } -fi - -# ----------------- done all checks, emit header ------------- -ac_config_commands="$ac_config_commands gstdint.h" - - - - -for ac_header in sys/mman.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" -if test "x$ac_cv_header_sys_mman_h" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_SYS_MMAN_H 1 -_ACEOF - -fi - -done - -if test "$ac_cv_header_sys_mman_h" = "no"; then - have_mmap=no -else - if test -n "${with_target_subdir}"; then - # When built as a GCC target library, we can't do a link test. We - # simply assume that if we have mman.h, we have mmap. - have_mmap=yes - case "${host}" in - spu-*-*|*-*-msdosdjgpp) - # The SPU does not have mmap, but it has a sys/mman.h header file - # containing "mmap_eaddr" and the mmap flags, confusing the test. - # DJGPP also has sys/man.h, but no mmap - have_mmap=no ;; - esac - else - ac_fn_c_check_func "$LINENO" "mmap" "ac_cv_func_mmap" -if test "x$ac_cv_func_mmap" = x""yes; then : - have_mmap=yes -else - have_mmap=no -fi - - fi -fi - -case "${host_os}" in -darwin*) - have_mmap=no ;; -esac - -if test "$have_mmap" = "no"; then - VIEW_FILE=read.lo - ALLOC_FILE=alloc.lo -else - VIEW_FILE=mmapio.lo - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#if !defined(MAP_ANONYMOUS) && !defined(MAP_ANON) - #error no MAP_ANONYMOUS -#endif - -_ACEOF -if ac_fn_c_try_cpp "$LINENO"; then : - ALLOC_FILE=alloc.lo -else - ALLOC_FILE=alloc.lo -fi -rm -f conftest.err conftest.$ac_ext -fi - - - -BACKTRACE_USES_MALLOC=0 -if test "$ALLOC_FILE" = "alloc.lo"; then - BACKTRACE_USES_MALLOC=1 -fi - - -# Check for dl_iterate_phdr. -for ac_header in link.h -do : - ac_fn_c_check_header_mongrel "$LINENO" "link.h" "ac_cv_header_link_h" "$ac_includes_default" -if test "x$ac_cv_header_link_h" = x""yes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LINK_H 1 -_ACEOF - -fi - -done - -if test "$ac_cv_header_link_h" = "no"; then - have_dl_iterate_phdr=no -else - if test -n "${with_target_subdir}"; then - # When built as a GCC target library, we can't do a link test. - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ -#include - -_ACEOF -if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | - $EGREP "dl_iterate_phdr" >/dev/null 2>&1; then : - have_dl_iterate_phdr=yes -else - have_dl_iterate_phdr=no -fi -rm -f conftest* - - case "${host}" in - *-*-solaris2.10*) - # Avoid dl_iterate_phdr on Solaris 10, where it is in the - # header file but is only in -ldl. - have_dl_iterate_phdr=no ;; - esac - else - ac_fn_c_check_func "$LINENO" "dl_iterate_phdr" "ac_cv_func_dl_iterate_phdr" -if test "x$ac_cv_func_dl_iterate_phdr" = x""yes; then : - have_dl_iterate_phdr=yes -else - have_dl_iterate_phdr=no -fi - - fi -fi -if test "$have_dl_iterate_phdr" = "yes"; then - -$as_echo "#define HAVE_DL_ITERATE_PHDR 1" >>confdefs.h - -fi - -# Check for the fcntl function. -if test -n "${with_target_subdir}"; then - case "${host}" in - *-*-mingw*) have_fcntl=no ;; - spu-*-*) have_fcntl=no ;; - *) have_fcntl=yes ;; - esac -else - ac_fn_c_check_func "$LINENO" "fcntl" "ac_cv_func_fcntl" -if test "x$ac_cv_func_fcntl" = x""yes; then : - have_fcntl=yes -else - have_fcntl=no -fi - -fi -if test "$have_fcntl" = "yes"; then - -$as_echo "#define HAVE_FCNTL 1" >>confdefs.h - -fi - -ac_fn_c_check_decl "$LINENO" "strnlen" "ac_cv_have_decl_strnlen" "$ac_includes_default" -if test "x$ac_cv_have_decl_strnlen" = x""yes; then : - ac_have_decl=1 -else - ac_have_decl=0 -fi - -cat >>confdefs.h <<_ACEOF -#define HAVE_DECL_STRNLEN $ac_have_decl -_ACEOF - - -# Check for getexecname function. -if test -n "${with_target_subdir}"; then - case "${host}" in - *-*-solaris2*) have_getexecname=yes ;; - *) have_getexecname=no ;; - esac -else - ac_fn_c_check_func "$LINENO" "getexecname" "ac_cv_func_getexecname" -if test "x$ac_cv_func_getexecname" = x""yes; then : - have_getexecname=yes -else - have_getexecname=no -fi - -fi -if test "$have_getexecname" = "yes"; then - -$as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h - -fi - -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tests can run" >&5 -$as_echo_n "checking whether tests can run... " >&6; } -if test "${libbacktrace_cv_sys_native+set}" = set; then : - $as_echo_n "(cached) " >&6 -else - if test "$cross_compiling" = yes; then : - libbacktrace_cv_sys_native=no -else - cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -int -main () -{ -return 0; - ; - return 0; -} -_ACEOF -if ac_fn_c_try_run "$LINENO"; then : - libbacktrace_cv_sys_native=yes -else - libbacktrace_cv_sys_native=no -fi -rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ - conftest.$ac_objext conftest.beam conftest.$ac_ext -fi - -fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_sys_native" >&5 -$as_echo "$libbacktrace_cv_sys_native" >&6; } - if test "$libbacktrace_cv_sys_native" = "yes"; then - NATIVE_TRUE= - NATIVE_FALSE='#' -else - NATIVE_TRUE='#' - NATIVE_FALSE= -fi - - -if test "${multilib}" = "yes"; then - multilib_arg="--enable-multilib" -else - multilib_arg= -fi - -ac_config_files="$ac_config_files Makefile backtrace-supported.h" - - -# We need multilib support, but only if configuring for the target. -ac_config_commands="$ac_config_commands default" - - -cat >confcache <<\_ACEOF -# This file is a shell script that caches the results of configure -# tests run on this system so they can be shared between configure -# scripts and configure runs, see configure's option --config-cache. -# It is not useful on other systems. If it contains results you don't -# want to keep, you may remove or edit it. -# -# config.status only pays attention to the cache file if you give it -# the --recheck option to rerun configure. -# -# `ac_cv_env_foo' variables (set or unset) will be overridden when -# loading this file, other *unset* `ac_cv_foo' will be assigned the -# following values. - -_ACEOF - -# The following way of writing the cache mishandles newlines in values, -# but we know of no workaround that is simple, portable, and efficient. -# So, we kill variables containing newlines. -# Ultrix sh set writes to stderr and can't be redirected directly, -# and sets the high bit in the cache file unless we assign to the vars. -( - for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do - eval ac_val=\$$ac_var - case $ac_val in #( - *${as_nl}*) - case $ac_var in #( - *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 -$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; - esac - case $ac_var in #( - _ | IFS | as_nl) ;; #( - BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( - *) { eval $ac_var=; unset $ac_var;} ;; - esac ;; - esac - done - - (set) 2>&1 | - case $as_nl`(ac_space=' '; set) 2>&1` in #( - *${as_nl}ac_space=\ *) - # `set' does not quote correctly, so add quotes: double-quote - # substitution turns \\\\ into \\, and sed turns \\ into \. - sed -n \ - "s/'/'\\\\''/g; - s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" - ;; #( - *) - # `set' quotes correctly as required by POSIX, so do not add quotes. - sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" - ;; - esac | - sort -) | - sed ' - /^ac_cv_env_/b end - t clear - :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ - t end - s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ - :end' >>confcache -if diff "$cache_file" confcache >/dev/null 2>&1; then :; else - if test -w "$cache_file"; then - test "x$cache_file" != "x/dev/null" && - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} - cat confcache >$cache_file - else - { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 -$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} - fi -fi -rm -f confcache - -test "x$prefix" = xNONE && prefix=$ac_default_prefix -# Let make expand exec_prefix. -test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' - -DEFS=-DHAVE_CONFIG_H - -ac_libobjs= -ac_ltlibobjs= -for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue - # 1. Remove the extension, and $U if already installed. - ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' - ac_i=`$as_echo "$ac_i" | sed "$ac_script"` - # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR - # will be set to the directory where LIBOBJS objects are built. - as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" - as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' -done -LIBOBJS=$ac_libobjs - -LTLIBOBJS=$ac_ltlibobjs - - - if test -n "$EXEEXT"; then - am__EXEEXT_TRUE= - am__EXEEXT_FALSE='#' -else - am__EXEEXT_TRUE='#' - am__EXEEXT_FALSE= -fi - -if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then - as_fn_error "conditional \"MAINTAINER_MODE\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi -if test -z "${NATIVE_TRUE}" && test -z "${NATIVE_FALSE}"; then - as_fn_error "conditional \"NATIVE\" was never defined. -Usually this means the macro was only invoked conditionally." "$LINENO" 5 -fi - -: ${CONFIG_STATUS=./config.status} -ac_write_fail=0 -ac_clean_files_save=$ac_clean_files -ac_clean_files="$ac_clean_files $CONFIG_STATUS" -{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 -$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} -as_write_fail=0 -cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 -#! $SHELL -# Generated by $as_me. -# Run this file to recreate the current configuration. -# Compiler output produced by configure, useful for debugging -# configure, is in config.log if it exists. - -debug=false -ac_cs_recheck=false -ac_cs_silent=false - -SHELL=\${CONFIG_SHELL-$SHELL} -export SHELL -_ASEOF -cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 -## -------------------- ## -## M4sh Initialization. ## -## -------------------- ## - -# Be more Bourne compatible -DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : - emulate sh - NULLCMD=: - # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in #( - *posix*) : - set -o posix ;; #( - *) : - ;; -esac -fi - - -as_nl=' -' -export as_nl -# Printing a long string crashes Solaris 7 /usr/bin/printf. -as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo -as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo -# Prefer a ksh shell builtin over an external printf program on Solaris, -# but without wasting forks for bash or zsh. -if test -z "$BASH_VERSION$ZSH_VERSION" \ - && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='print -r --' - as_echo_n='print -rn --' -elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then - as_echo='printf %s\n' - as_echo_n='printf %s' -else - if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then - as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' - as_echo_n='/usr/ucb/echo -n' - else - as_echo_body='eval expr "X$1" : "X\\(.*\\)"' - as_echo_n_body='eval - arg=$1; - case $arg in #( - *"$as_nl"*) - expr "X$arg" : "X\\(.*\\)$as_nl"; - arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; - esac; - expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" - ' - export as_echo_n_body - as_echo_n='sh -c $as_echo_n_body as_echo' - fi - export as_echo_body - as_echo='sh -c $as_echo_body as_echo' -fi - -# The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then - PATH_SEPARATOR=: - (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { - (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || - PATH_SEPARATOR=';' - } -fi - - -# IFS -# We need space, tab and new line, in precisely that order. Quoting is -# there to prevent editors from complaining about space-tab. -# (If _AS_PATH_WALK were called with IFS unset, it would disable word -# splitting by setting IFS to empty value.) -IFS=" "" $as_nl" - -# Find who we are. Look in the path if we contain no directory separator. -case $0 in #(( - *[\\/]* ) as_myself=$0 ;; - *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR -for as_dir in $PATH -do - IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. - test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break - done -IFS=$as_save_IFS - - ;; -esac -# We did not find ourselves, most probably we were run as `sh COMMAND' -# in which case we are not to be found in the path. -if test "x$as_myself" = x; then - as_myself=$0 -fi -if test ! -f "$as_myself"; then - $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 - exit 1 -fi - -# Unset variables that we do not need and which cause bugs (e.g. in -# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" -# suppresses any "Segmentation fault" message there. '((' could -# trigger a bug in pdksh 5.2.14. -for as_var in BASH_ENV ENV MAIL MAILPATH -do eval test x\${$as_var+set} = xset \ - && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : -done -PS1='$ ' -PS2='> ' -PS4='+ ' - -# NLS nuisances. -LC_ALL=C -export LC_ALL -LANGUAGE=C -export LANGUAGE - -# CDPATH. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - - -# as_fn_error ERROR [LINENO LOG_FD] -# --------------------------------- -# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are -# provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with status $?, using 1 if that was 0. -as_fn_error () -{ - as_status=$?; test $as_status -eq 0 && as_status=1 - if test "$3"; then - as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 - fi - $as_echo "$as_me: error: $1" >&2 - as_fn_exit $as_status -} # as_fn_error - - -# as_fn_set_status STATUS -# ----------------------- -# Set $? to STATUS, without forking. -as_fn_set_status () -{ - return $1 -} # as_fn_set_status - -# as_fn_exit STATUS -# ----------------- -# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. -as_fn_exit () -{ - set +e - as_fn_set_status $1 - exit $1 -} # as_fn_exit - -# as_fn_unset VAR -# --------------- -# Portably unset VAR. -as_fn_unset () -{ - { eval $1=; unset $1;} -} -as_unset=as_fn_unset -# as_fn_append VAR VALUE -# ---------------------- -# Append the text in VALUE to the end of the definition contained in VAR. Take -# advantage of any shell optimizations that allow amortized linear growth over -# repeated appends, instead of the typical quadratic growth present in naive -# implementations. -if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : - eval 'as_fn_append () - { - eval $1+=\$2 - }' -else - as_fn_append () - { - eval $1=\$$1\$2 - } -fi # as_fn_append - -# as_fn_arith ARG... -# ------------------ -# Perform arithmetic evaluation on the ARGs, and store the result in the -# global $as_val. Take advantage of shells that can avoid forks. The arguments -# must be portable across $(()) and expr. -if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : - eval 'as_fn_arith () - { - as_val=$(( $* )) - }' -else - as_fn_arith () - { - as_val=`expr "$@" || test $? -eq 1` - } -fi # as_fn_arith - - -if expr a : '\(a\)' >/dev/null 2>&1 && - test "X`expr 00001 : '.*\(...\)'`" = X001; then - as_expr=expr -else - as_expr=false -fi - -if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then - as_basename=basename -else - as_basename=false -fi - -if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then - as_dirname=dirname -else - as_dirname=false -fi - -as_me=`$as_basename -- "$0" || -$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ - X"$0" : 'X\(//\)$' \| \ - X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | - sed '/^.*\/\([^/][^/]*\)\/*$/{ - s//\1/ - q - } - /^X\/\(\/\/\)$/{ - s//\1/ - q - } - /^X\/\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - -# Avoid depending upon Character Ranges. -as_cr_letters='abcdefghijklmnopqrstuvwxyz' -as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' -as_cr_Letters=$as_cr_letters$as_cr_LETTERS -as_cr_digits='0123456789' -as_cr_alnum=$as_cr_Letters$as_cr_digits - -ECHO_C= ECHO_N= ECHO_T= -case `echo -n x` in #((((( --n*) - case `echo 'xy\c'` in - *c*) ECHO_T=' ';; # ECHO_T is single tab character. - xy) ECHO_C='\c';; - *) echo `echo ksh88 bug on AIX 6.1` > /dev/null - ECHO_T=' ';; - esac;; -*) - ECHO_N='-n';; -esac - -rm -f conf$$ conf$$.exe conf$$.file -if test -d conf$$.dir; then - rm -f conf$$.dir/conf$$.file -else - rm -f conf$$.dir - mkdir conf$$.dir 2>/dev/null -fi -if (echo >conf$$.file) 2>/dev/null; then - if ln -s conf$$.file conf$$ 2>/dev/null; then - as_ln_s='ln -s' - # ... but there are two gotchas: - # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. - # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. - ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' - elif ln conf$$.file conf$$ 2>/dev/null; then - as_ln_s=ln - else - as_ln_s='cp -p' - fi -else - as_ln_s='cp -p' -fi -rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file -rmdir conf$$.dir 2>/dev/null - - -# as_fn_mkdir_p -# ------------- -# Create "$as_dir" as a directory, including parents if necessary. -as_fn_mkdir_p () -{ - - case $as_dir in #( - -*) as_dir=./$as_dir;; - esac - test -d "$as_dir" || eval $as_mkdir_p || { - as_dirs= - while :; do - case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( - *) as_qdir=$as_dir;; - esac - as_dirs="'$as_qdir' $as_dirs" - as_dir=`$as_dirname -- "$as_dir" || -$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$as_dir" : 'X\(//\)[^/]' \| \ - X"$as_dir" : 'X\(//\)$' \| \ - X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$as_dir" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - test -d "$as_dir" && break - done - test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" - - -} # as_fn_mkdir_p -if mkdir -p . 2>/dev/null; then - as_mkdir_p='mkdir -p "$as_dir"' -else - test -d ./-p && rmdir ./-p - as_mkdir_p=false -fi - -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x - -# Sed expression to map a string onto a valid CPP name. -as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" - -# Sed expression to map a string onto a valid variable name. -as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" - - -exec 6>&1 -## ----------------------------------- ## -## Main body of $CONFIG_STATUS script. ## -## ----------------------------------- ## -_ASEOF -test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# Save the log message, to keep $0 and so on meaningful, and to -# report actual input values of CONFIG_FILES etc. instead of their -# values after options handling. -ac_log=" -This file was extended by package-unused $as_me version-unused, which was -generated by GNU Autoconf 2.64. Invocation command line was - - CONFIG_FILES = $CONFIG_FILES - CONFIG_HEADERS = $CONFIG_HEADERS - CONFIG_LINKS = $CONFIG_LINKS - CONFIG_COMMANDS = $CONFIG_COMMANDS - $ $0 $@ - -on `(hostname || uname -n) 2>/dev/null | sed 1q` -" - -_ACEOF - -case $ac_config_files in *" -"*) set x $ac_config_files; shift; ac_config_files=$*;; -esac - -case $ac_config_headers in *" -"*) set x $ac_config_headers; shift; ac_config_headers=$*;; -esac - - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" -config_commands="$ac_config_commands" - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -ac_cs_usage="\ -\`$as_me' instantiates files and other configuration actions -from templates according to the current configuration. Unless the files -and actions are specified as TAGs, all are instantiated by default. - -Usage: $0 [OPTION]... [TAG]... - - -h, --help print this help, then exit - -V, --version print version number and configuration settings, then exit - -q, --quiet, --silent - do not print progress messages - -d, --debug don't remove temporary files - --recheck update $as_me by reconfiguring in the same conditions - --file=FILE[:TEMPLATE] - instantiate the configuration file FILE - --header=FILE[:TEMPLATE] - instantiate the configuration header FILE - -Configuration files: -$config_files - -Configuration headers: -$config_headers - -Configuration commands: -$config_commands - -Report bugs to the package provider." - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_version="\\ -package-unused config.status version-unused -configured by $0, generated by GNU Autoconf 2.64, - with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" - -Copyright (C) 2009 Free Software Foundation, Inc. -This config.status script is free software; the Free Software Foundation -gives unlimited permission to copy, distribute and modify it." - -ac_pwd='$ac_pwd' -srcdir='$srcdir' -INSTALL='$INSTALL' -MKDIR_P='$MKDIR_P' -AWK='$AWK' -test -n "\$AWK" || AWK=awk -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# The default lists apply if the user does not specify any file. -ac_need_defaults=: -while test $# != 0 -do - case $1 in - --*=*) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` - ac_shift=: - ;; - *) - ac_option=$1 - ac_optarg=$2 - ac_shift=shift - ;; - esac - - case $ac_option in - # Handling of the options. - -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) - ac_cs_recheck=: ;; - --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) - $as_echo "$ac_cs_version"; exit ;; - --debug | --debu | --deb | --de | --d | -d ) - debug=: ;; - --file | --fil | --fi | --f ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_FILES " '$ac_optarg'" - ac_need_defaults=false;; - --header | --heade | --head | --hea ) - $ac_shift - case $ac_optarg in - *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - esac - as_fn_append CONFIG_HEADERS " '$ac_optarg'" - ac_need_defaults=false;; - --he | --h) - # Conflict between --help and --header - as_fn_error "ambiguous option: \`$1' -Try \`$0 --help' for more information.";; - --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; - -q | -quiet | --quiet | --quie | --qui | --qu | --q \ - | -silent | --silent | --silen | --sile | --sil | --si | --s) - ac_cs_silent=: ;; - - # This is an error. - -*) as_fn_error "unrecognized option: \`$1' -Try \`$0 --help' for more information." ;; - - *) as_fn_append ac_config_targets " $1" - ac_need_defaults=false ;; - - esac - shift -done - -ac_configure_extra_args= - -if $ac_cs_silent; then - exec 6>/dev/null - ac_configure_extra_args="$ac_configure_extra_args --silent" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -if \$ac_cs_recheck; then - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion - shift - \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 - CONFIG_SHELL='$SHELL' - export CONFIG_SHELL - exec "\$@" -fi - -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -exec 5>>config.log -{ - echo - sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX -## Running $as_me. ## -_ASBOX - $as_echo "$ac_log" -} >&5 - -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -# -# INIT-COMMANDS -# - -srcdir="$srcdir" -host="$host" -target="$target" -with_multisubdir="$with_multisubdir" -with_multisrctop="$with_multisrctop" -with_target_subdir="$with_target_subdir" -ac_configure_args="${multilib_arg} ${ac_configure_args}" -multi_basedir="$multi_basedir" -CONFIG_SHELL=${CONFIG_SHELL-/bin/sh} -CC="$CC" -CXX="$CXX" -GFORTRAN="$GFORTRAN" -GCJ="$GCJ" - - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -sed_quote_subst='$sed_quote_subst' -double_quote_subst='$double_quote_subst' -delay_variable_subst='$delay_variable_subst' -macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' -macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' -enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' -enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' -pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' -enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' -SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' -ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' -host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' -host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' -host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' -build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' -build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' -build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' -SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' -Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' -GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' -EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' -FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' -LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' -NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' -LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' -max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' -ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' -exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' -lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' -lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' -lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' -reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' -reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' -OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' -deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' -file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' -AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' -AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' -STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' -RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' -old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' -old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' -lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' -CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' -CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' -compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' -GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' -objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' -MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' -lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' -lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' -need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' -DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' -NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' -LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' -OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' -OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' -libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' -shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' -extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' -enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' -export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' -whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' -compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' -old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' -old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' -archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' -archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' -module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' -module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' -with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' -allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' -no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_flag_spec_ld='`$ECHO "$hardcode_libdir_flag_spec_ld" | $SED "$delay_single_quote_subst"`' -hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' -hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' -hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' -hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' -hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' -hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' -inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' -link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' -fix_srcfile_path='`$ECHO "$fix_srcfile_path" | $SED "$delay_single_quote_subst"`' -always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' -export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' -exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' -include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' -prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' -file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' -variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' -need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' -need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' -version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' -runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' -shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' -libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' -library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' -soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' -install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' -postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' -postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' -finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' -finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' -hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' -sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' -sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' -hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' -enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' -enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' -old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' -striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' - -LTCC='$LTCC' -LTCFLAGS='$LTCFLAGS' -compiler='$compiler_DEFAULT' - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - -# Quote evaled strings. -for var in SHELL \ -ECHO \ -SED \ -GREP \ -EGREP \ -FGREP \ -LD \ -NM \ -LN_S \ -lt_SP2NL \ -lt_NL2SP \ -reload_flag \ -OBJDUMP \ -deplibs_check_method \ -file_magic_cmd \ -AR \ -AR_FLAGS \ -STRIP \ -RANLIB \ -CC \ -CFLAGS \ -compiler \ -lt_cv_sys_global_symbol_pipe \ -lt_cv_sys_global_symbol_to_cdecl \ -lt_cv_sys_global_symbol_to_c_name_address \ -lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ -lt_prog_compiler_no_builtin_flag \ -lt_prog_compiler_wl \ -lt_prog_compiler_pic \ -lt_prog_compiler_static \ -lt_cv_prog_compiler_c_o \ -need_locks \ -DSYMUTIL \ -NMEDIT \ -LIPO \ -OTOOL \ -OTOOL64 \ -shrext_cmds \ -export_dynamic_flag_spec \ -whole_archive_flag_spec \ -compiler_needs_object \ -with_gnu_ld \ -allow_undefined_flag \ -no_undefined_flag \ -hardcode_libdir_flag_spec \ -hardcode_libdir_flag_spec_ld \ -hardcode_libdir_separator \ -fix_srcfile_path \ -exclude_expsyms \ -include_expsyms \ -file_list_spec \ -variables_saved_for_relink \ -libname_spec \ -library_names_spec \ -soname_spec \ -install_override_mode \ -finish_eval \ -old_striplib \ -striplib; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -# Double-quote double-evaled strings. -for var in reload_cmds \ -old_postinstall_cmds \ -old_postuninstall_cmds \ -old_archive_cmds \ -extract_expsyms_cmds \ -old_archive_from_new_cmds \ -old_archive_from_expsyms_cmds \ -archive_cmds \ -archive_expsym_cmds \ -module_cmds \ -module_expsym_cmds \ -export_symbols_cmds \ -prelink_cmds \ -postinstall_cmds \ -postuninstall_cmds \ -finish_cmds \ -sys_lib_search_path_spec \ -sys_lib_dlsearch_path_spec; do - case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in - *[\\\\\\\`\\"\\\$]*) - eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" - ;; - *) - eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" - ;; - esac -done - -ac_aux_dir='$ac_aux_dir' -xsi_shell='$xsi_shell' -lt_shell_append='$lt_shell_append' - -# See if we are running on zsh, and set the options which allow our -# commands through without removal of \ escapes INIT. -if test -n "\${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST -fi - - - PACKAGE='$PACKAGE' - VERSION='$VERSION' - TIMESTAMP='$TIMESTAMP' - RM='$RM' - ofile='$ofile' - - - - -GCC="$GCC" -CC="$CC" -acx_cv_header_stdint="$acx_cv_header_stdint" -acx_cv_type_int8_t="$acx_cv_type_int8_t" -acx_cv_type_int16_t="$acx_cv_type_int16_t" -acx_cv_type_int32_t="$acx_cv_type_int32_t" -acx_cv_type_int64_t="$acx_cv_type_int64_t" -acx_cv_type_intptr_t="$acx_cv_type_intptr_t" -ac_cv_type_uintmax_t="$ac_cv_type_uintmax_t" -ac_cv_type_uintptr_t="$ac_cv_type_uintptr_t" -ac_cv_type_uint64_t="$ac_cv_type_uint64_t" -ac_cv_type_u_int64_t="$ac_cv_type_u_int64_t" -ac_cv_type_u_int32_t="$ac_cv_type_u_int32_t" -ac_cv_type_int_least32_t="$ac_cv_type_int_least32_t" -ac_cv_type_int_fast32_t="$ac_cv_type_int_fast32_t" -ac_cv_sizeof_void_p="$ac_cv_sizeof_void_p" - - -# Variables needed in config.status (file generation) which aren't already -# passed by autoconf. -SUBDIRS="$SUBDIRS" - - -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - -# Handling of arguments. -for ac_config_target in $ac_config_targets -do - case $ac_config_target in - "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; - "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; - "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; - "gstdint.h") CONFIG_COMMANDS="$CONFIG_COMMANDS gstdint.h" ;; - "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; - "backtrace-supported.h") CONFIG_FILES="$CONFIG_FILES backtrace-supported.h" ;; - "default") CONFIG_COMMANDS="$CONFIG_COMMANDS default" ;; - - *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; - esac -done - - -# If the user did not use the arguments to specify the items to instantiate, -# then the envvar interface is used. Set only those that are not. -# We use the long form for the default assignment because of an extremely -# bizarre bug on SunOS 4.1.3. -if $ac_need_defaults; then - test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files - test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers - test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands -fi - -# Have a temporary directory for convenience. Make it in the build tree -# simply because there is no reason against having it here, and in addition, -# creating and moving files from /tmp can sometimes cause problems. -# Hook for its removal unless debugging. -# Note that there is a small window in which the directory will not be cleaned: -# after its creation but before its name has been assigned to `$tmp'. -$debug || -{ - tmp= - trap 'exit_status=$? - { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status -' 0 - trap 'as_fn_exit 1' 1 2 13 15 -} -# Create a (secure) tmp directory for tmp files. - -{ - tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && - test -n "$tmp" && test -d "$tmp" -} || -{ - tmp=./conf$$-$RANDOM - (umask 077 && mkdir "$tmp") -} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 - -# Set up the scripts for CONFIG_FILES section. -# No need to generate them if there are no CONFIG_FILES. -# This happens for instance with `./config.status config.h'. -if test -n "$CONFIG_FILES"; then - - -ac_cr=`echo X | tr X '\015'` -# On cygwin, bash can eat \r inside `` if the user requested igncr. -# But we know of no other shell where ac_cr would be empty at this -# point, so we can use a bashism as a fallback. -if test "x$ac_cr" = x; then - eval ac_cr=\$\'\\r\' -fi -ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` -if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\r' -else - ac_cs_awk_cr=$ac_cr -fi - -echo 'BEGIN {' >"$tmp/subs1.awk" && -_ACEOF - - -{ - echo "cat >conf$$subs.awk <<_ACEOF" && - echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && - echo "_ACEOF" -} >conf$$subs.sh || - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` -ac_delim='%!_!# ' -for ac_last_try in false false false false false :; do - . ./conf$$subs.sh || - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 - - ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` - if test $ac_delim_n = $ac_delim_num; then - break - elif $ac_last_try; then - as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done -rm -f conf$$subs.sh - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -cat >>"\$tmp/subs1.awk" <<\\_ACAWK && -_ACEOF -sed -n ' -h -s/^/S["/; s/!.*/"]=/ -p -g -s/^[^!]*!// -:repl -t repl -s/'"$ac_delim"'$// -t delim -:nl -h -s/\(.\{148\}\).*/\1/ -t more1 -s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ -p -n -b repl -:more1 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t nl -:delim -h -s/\(.\{148\}\).*/\1/ -t more2 -s/["\\]/\\&/g; s/^/"/; s/$/"/ -p -b -:more2 -s/["\\]/\\&/g; s/^/"/; s/$/"\\/ -p -g -s/.\{148\}// -t delim -' >$CONFIG_STATUS || ac_write_fail=1 -rm -f conf$$subs.awk -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -_ACAWK -cat >>"\$tmp/subs1.awk" <<_ACAWK && - for (key in S) S_is_set[key] = 1 - FS = "" - -} -{ - line = $ 0 - nfields = split(line, field, "@") - substed = 0 - len = length(field[1]) - for (i = 2; i < nfields; i++) { - key = field[i] - keylen = length(key) - if (S_is_set[key]) { - value = S[key] - line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) - len += length(value) + length(field[++i]) - substed = 1 - } else - len += 1 + keylen - } - - print line -} - -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then - sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" -else - cat -fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || as_fn_error "could not setup config files machinery" "$LINENO" 5 -_ACEOF - -# VPATH may cause trouble with some makes, so we remove $(srcdir), -# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and -# trailing colons and then remove the whole line if VPATH becomes empty -# (actually we leave an empty line to preserve line numbers). -if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=/{ -s/:*\$(srcdir):*/:/ -s/:*\${srcdir}:*/:/ -s/:*@srcdir@:*/:/ -s/^\([^=]*=[ ]*\):*/\1/ -s/:*$// -s/^[^=]*=[ ]*$// -}' -fi - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -fi # test -n "$CONFIG_FILES" - -# Set up the scripts for CONFIG_HEADERS section. -# No need to generate them if there are no CONFIG_HEADERS. -# This happens for instance with `./config.status Makefile'. -if test -n "$CONFIG_HEADERS"; then -cat >"$tmp/defines.awk" <<\_ACAWK || -BEGIN { -_ACEOF - -# Transform confdefs.h into an awk script `defines.awk', embedded as -# here-document in config.status, that substitutes the proper values into -# config.h.in to produce config.h. - -# Create a delimiter string that does not exist in confdefs.h, to ease -# handling of long lines. -ac_delim='%!_!# ' -for ac_last_try in false false :; do - ac_t=`sed -n "/$ac_delim/p" confdefs.h` - if test -z "$ac_t"; then - break - elif $ac_last_try; then - as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 - else - ac_delim="$ac_delim!$ac_delim _$ac_delim!! " - fi -done - -# For the awk script, D is an array of macro values keyed by name, -# likewise P contains macro parameters if any. Preserve backslash -# newline sequences. - -ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* -sed -n ' -s/.\{148\}/&'"$ac_delim"'/g -t rset -:rset -s/^[ ]*#[ ]*define[ ][ ]*/ / -t def -d -:def -s/\\$// -t bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3"/p -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p -d -:bsnl -s/["\\]/\\&/g -s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ -D["\1"]=" \3\\\\\\n"\\/p -t cont -s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p -t cont -d -:cont -n -s/.\{148\}/&'"$ac_delim"'/g -t clear -:clear -s/\\$// -t bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/"/p -d -:bsnlc -s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p -b cont -' >$CONFIG_STATUS || ac_write_fail=1 - -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - for (key in D) D_is_set[key] = 1 - FS = "" -} -/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { - line = \$ 0 - split(line, arg, " ") - if (arg[1] == "#") { - defundef = arg[2] - mac1 = arg[3] - } else { - defundef = substr(arg[1], 2) - mac1 = arg[2] - } - split(mac1, mac2, "(") #) - macro = mac2[1] - prefix = substr(line, 1, index(line, defundef) - 1) - if (D_is_set[macro]) { - # Preserve the white space surrounding the "#". - print prefix "define", macro P[macro] D[macro] - next - } else { - # Replace #undef with comments. This is necessary, for example, - # in the case of _POSIX_SOURCE, which is predefined and required - # on some systems where configure will not decide to define it. - if (defundef == "undef") { - print "/*", prefix defundef, macro, "*/" - next - } - } -} -{ print } -_ACAWK -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error "could not setup config headers machinery" "$LINENO" 5 -fi # test -n "$CONFIG_HEADERS" - - -eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" -shift -for ac_tag -do - case $ac_tag in - :[FHLC]) ac_mode=$ac_tag; continue;; - esac - case $ac_mode$ac_tag in - :[FHL]*:*);; - :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; - :[FH]-) ac_tag=-:-;; - :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; - esac - ac_save_IFS=$IFS - IFS=: - set x $ac_tag - IFS=$ac_save_IFS - shift - ac_file=$1 - shift - - case $ac_mode in - :L) ac_source=$1;; - :[FH]) - ac_file_inputs= - for ac_f - do - case $ac_f in - -) ac_f="$tmp/stdin";; - *) # Look for the file first in the build tree, then in the source tree - # (if the path is not absolute). The absolute path cannot be DOS-style, - # because $ac_f cannot contain `:'. - test -f "$ac_f" || - case $ac_f in - [\\/$]*) false;; - *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; - esac || - as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; - esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac - as_fn_append ac_file_inputs " '$ac_f'" - done - - # Let's still pretend it is `configure' which instantiates (i.e., don't - # use $as_me), people would be surprised to read: - # /* config.h. Generated by config.status. */ - configure_input='Generated from '` - $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' - `' by configure.' - if test x"$ac_file" != x-; then - configure_input="$ac_file. $configure_input" - { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 -$as_echo "$as_me: creating $ac_file" >&6;} - fi - # Neutralize special characters interpreted by sed in replacement strings. - case $configure_input in #( - *\&* | *\|* | *\\* ) - ac_sed_conf_input=`$as_echo "$configure_input" | - sed 's/[\\\\&|]/\\\\&/g'`;; #( - *) ac_sed_conf_input=$configure_input;; - esac - - case $ac_tag in - *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; - esac - ;; - esac - - ac_dir=`$as_dirname -- "$ac_file" || -$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$ac_file" : 'X\(//\)[^/]' \| \ - X"$ac_file" : 'X\(//\)$' \| \ - X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$ac_file" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'` - as_dir="$ac_dir"; as_fn_mkdir_p - ac_builddir=. - -case "$ac_dir" in -.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; -*) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` - # A ".." for each directory in $ac_dir_suffix. - ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` - case $ac_top_builddir_sub in - "") ac_top_builddir_sub=. ac_top_build_prefix= ;; - *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; - esac ;; -esac -ac_abs_top_builddir=$ac_pwd -ac_abs_builddir=$ac_pwd$ac_dir_suffix -# for backward compatibility: -ac_top_builddir=$ac_top_build_prefix - -case $srcdir in - .) # We are building in place. - ac_srcdir=. - ac_top_srcdir=$ac_top_builddir_sub - ac_abs_top_srcdir=$ac_pwd ;; - [\\/]* | ?:[\\/]* ) # Absolute name. - ac_srcdir=$srcdir$ac_dir_suffix; - ac_top_srcdir=$srcdir - ac_abs_top_srcdir=$srcdir ;; - *) # Relative name. - ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix - ac_top_srcdir=$ac_top_build_prefix$srcdir - ac_abs_top_srcdir=$ac_pwd/$srcdir ;; -esac -ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix - - - case $ac_mode in - :F) - # - # CONFIG_FILE - # - - case $INSTALL in - [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; - *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; - esac - ac_MKDIR_P=$MKDIR_P - case $MKDIR_P in - [\\/$]* | ?:[\\/]* ) ;; - */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; - esac -_ACEOF - -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -# If the template does not know about datarootdir, expand it. -# FIXME: This hack should be removed a few years after 2.60. -ac_datarootdir_hack=; ac_datarootdir_seen= -ac_sed_dataroot=' -/datarootdir/ { - p - q -} -/@datadir@/p -/@docdir@/p -/@infodir@/p -/@localedir@/p -/@mandir@/p' -case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in -*datarootdir*) ac_datarootdir_seen=yes;; -*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 -$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} -_ACEOF -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 - ac_datarootdir_hack=' - s&@datadir@&$datadir&g - s&@docdir@&$docdir&g - s&@infodir@&$infodir&g - s&@localedir@&$localedir&g - s&@mandir@&$mandir&g - s&\\\${datarootdir}&$datarootdir&g' ;; -esac -_ACEOF - -# Neutralize VPATH when `$srcdir' = `.'. -# Shell code in configure.ac might set extrasub. -# FIXME: do we really want to maintain this feature? -cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_sed_extra="$ac_vpsub -$extrasub -_ACEOF -cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 -:t -/@[a-zA-Z_][a-zA-Z_0-9]*@/!b -s|@configure_input@|$ac_sed_conf_input|;t t -s&@top_builddir@&$ac_top_builddir_sub&;t t -s&@top_build_prefix@&$ac_top_build_prefix&;t t -s&@srcdir@&$ac_srcdir&;t t -s&@abs_srcdir@&$ac_abs_srcdir&;t t -s&@top_srcdir@&$ac_top_srcdir&;t t -s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t -s&@builddir@&$ac_builddir&;t t -s&@abs_builddir@&$ac_abs_builddir&;t t -s&@abs_top_builddir@&$ac_abs_top_builddir&;t t -s&@INSTALL@&$ac_INSTALL&;t t -s&@MKDIR_P@&$ac_MKDIR_P&;t t -$ac_datarootdir_hack -" -eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 - -test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && - { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && - { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&5 -$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined." >&2;} - - rm -f "$tmp/stdin" - case $ac_file in - -) cat "$tmp/out" && rm -f "$tmp/out";; - *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; - esac \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 - ;; - :H) - # - # CONFIG_HEADER - # - if test x"$ac_file" != x-; then - { - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" - } >"$tmp/config.h" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 - if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then - { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 -$as_echo "$as_me: $ac_file is unchanged" >&6;} - else - rm -f "$ac_file" - mv "$tmp/config.h" "$ac_file" \ - || as_fn_error "could not create $ac_file" "$LINENO" 5 - fi - else - $as_echo "/* $configure_input */" \ - && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error "could not create -" "$LINENO" 5 - fi -# Compute "$ac_file"'s index in $config_headers. -_am_arg="$ac_file" -_am_stamp_count=1 -for _am_header in $config_headers :; do - case $_am_header in - $_am_arg | $_am_arg:* ) - break ;; - * ) - _am_stamp_count=`expr $_am_stamp_count + 1` ;; - esac -done -echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || -$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$_am_arg" : 'X\(//\)[^/]' \| \ - X"$_am_arg" : 'X\(//\)$' \| \ - X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X"$_am_arg" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q'`/stamp-h$_am_stamp_count - ;; - - :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -$as_echo "$as_me: executing $ac_file commands" >&6;} - ;; - esac - - - case $ac_file$ac_mode in - "default-1":C) -# Only add multilib support code if we just rebuilt the top-level -# Makefile. -case " $CONFIG_FILES " in - *" Makefile "*) - ac_file=Makefile . ${multi_basedir}/config-ml.in - ;; -esac ;; - "libtool":C) - - # See if we are running on zsh, and set the options which allow our - # commands through without removal of \ escapes. - if test -n "${ZSH_VERSION+set}" ; then - setopt NO_GLOB_SUBST - fi - - cfgfile="${ofile}T" - trap "$RM \"$cfgfile\"; exit 1" 1 2 15 - $RM "$cfgfile" - - cat <<_LT_EOF >> "$cfgfile" -#! $SHELL - -# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. -# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION -# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: -# NOTE: Changes made to this file will be lost: look at ltmain.sh. -# -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, -# 2006, 2007, 2008, 2009 Free Software Foundation, Inc. -# Written by Gordon Matzigkeit, 1996 -# -# This file is part of GNU Libtool. -# -# GNU Libtool is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; either version 2 of -# the License, or (at your option) any later version. -# -# As a special exception to the GNU General Public License, -# if you distribute this file as part of a program or library that -# is built using GNU Libtool, you may include this file under the -# same distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Libtool; see the file COPYING. If not, a copy -# can be downloaded from http://www.gnu.org/licenses/gpl.html, or -# obtained by writing to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - -# The names of the tagged configurations supported by this script. -available_tags="" - -# ### BEGIN LIBTOOL CONFIG - -# Which release of libtool.m4 was used? -macro_version=$macro_version -macro_revision=$macro_revision - -# Whether or not to build shared libraries. -build_libtool_libs=$enable_shared - -# Whether or not to build static libraries. -build_old_libs=$enable_static - -# What type of objects to build. -pic_mode=$pic_mode - -# Whether or not to optimize for fast installation. -fast_install=$enable_fast_install - -# Shell to use when invoking shell scripts. -SHELL=$lt_SHELL - -# An echo program that protects backslashes. -ECHO=$lt_ECHO - -# The host system. -host_alias=$host_alias -host=$host -host_os=$host_os - -# The build system. -build_alias=$build_alias -build=$build -build_os=$build_os - -# A sed program that does not truncate output. -SED=$lt_SED - -# Sed that helps us avoid accidentally triggering echo(1) options like -n. -Xsed="\$SED -e 1s/^X//" - -# A grep program that handles long lines. -GREP=$lt_GREP - -# An ERE matcher. -EGREP=$lt_EGREP - -# A literal string matcher. -FGREP=$lt_FGREP - -# A BSD- or MS-compatible name lister. -NM=$lt_NM - -# Whether we need soft or hard links. -LN_S=$lt_LN_S - -# What is the maximum length of a command? -max_cmd_len=$max_cmd_len - -# Object file suffix (normally "o"). -objext=$ac_objext - -# Executable file suffix (normally ""). -exeext=$exeext - -# whether the shell understands "unset". -lt_unset=$lt_unset - -# turn spaces into newlines. -SP2NL=$lt_lt_SP2NL - -# turn newlines into spaces. -NL2SP=$lt_lt_NL2SP - -# An object symbol dumper. -OBJDUMP=$lt_OBJDUMP - -# Method to check whether dependent libraries are shared objects. -deplibs_check_method=$lt_deplibs_check_method - -# Command to use when deplibs_check_method == "file_magic". -file_magic_cmd=$lt_file_magic_cmd - -# The archiver. -AR=$lt_AR -AR_FLAGS=$lt_AR_FLAGS - -# A symbol stripping program. -STRIP=$lt_STRIP - -# Commands used to install an old-style archive. -RANLIB=$lt_RANLIB -old_postinstall_cmds=$lt_old_postinstall_cmds -old_postuninstall_cmds=$lt_old_postuninstall_cmds - -# Whether to use a lock for old archive extraction. -lock_old_archive_extraction=$lock_old_archive_extraction - -# A C compiler. -LTCC=$lt_CC - -# LTCC compiler flags. -LTCFLAGS=$lt_CFLAGS - -# Take the output of nm and produce a listing of raw symbols and C names. -global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe - -# Transform the output of nm in a proper C declaration. -global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl - -# Transform the output of nm in a C name address pair. -global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address - -# Transform the output of nm in a C name address pair when lib prefix is needed. -global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix - -# The name of the directory that contains temporary libtool files. -objdir=$objdir - -# Used to examine libraries when file_magic_cmd begins with "file". -MAGIC_CMD=$MAGIC_CMD - -# Must we lock files when doing compilation? -need_locks=$lt_need_locks - -# Tool to manipulate archived DWARF debug symbol files on Mac OS X. -DSYMUTIL=$lt_DSYMUTIL - -# Tool to change global to local symbols on Mac OS X. -NMEDIT=$lt_NMEDIT - -# Tool to manipulate fat objects and archives on Mac OS X. -LIPO=$lt_LIPO - -# ldd/readelf like tool for Mach-O binaries on Mac OS X. -OTOOL=$lt_OTOOL - -# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. -OTOOL64=$lt_OTOOL64 - -# Old archive suffix (normally "a"). -libext=$libext - -# Shared library suffix (normally ".so"). -shrext_cmds=$lt_shrext_cmds - -# The commands to extract the exported symbol list from a shared archive. -extract_expsyms_cmds=$lt_extract_expsyms_cmds - -# Variables whose values should be saved in libtool wrapper scripts and -# restored at link time. -variables_saved_for_relink=$lt_variables_saved_for_relink - -# Do we need the "lib" prefix for modules? -need_lib_prefix=$need_lib_prefix - -# Do we need a version for libraries? -need_version=$need_version - -# Library versioning type. -version_type=$version_type - -# Shared library runtime path variable. -runpath_var=$runpath_var - -# Shared library path variable. -shlibpath_var=$shlibpath_var - -# Is shlibpath searched before the hard-coded library search path? -shlibpath_overrides_runpath=$shlibpath_overrides_runpath - -# Format of library name prefix. -libname_spec=$lt_libname_spec - -# List of archive names. First name is the real one, the rest are links. -# The last name is the one that the linker finds with -lNAME -library_names_spec=$lt_library_names_spec - -# The coded name of the library, if different from the real name. -soname_spec=$lt_soname_spec - -# Permission mode override for installation of shared libraries. -install_override_mode=$lt_install_override_mode - -# Command to use after installation of a shared archive. -postinstall_cmds=$lt_postinstall_cmds - -# Command to use after uninstallation of a shared archive. -postuninstall_cmds=$lt_postuninstall_cmds - -# Commands used to finish a libtool library installation in a directory. -finish_cmds=$lt_finish_cmds - -# As "finish_cmds", except a single script fragment to be evaled but -# not shown. -finish_eval=$lt_finish_eval - -# Whether we should hardcode library paths into libraries. -hardcode_into_libs=$hardcode_into_libs - -# Compile-time system search path for libraries. -sys_lib_search_path_spec=$lt_sys_lib_search_path_spec - -# Run-time system search path for libraries. -sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec - -# Whether dlopen is supported. -dlopen_support=$enable_dlopen - -# Whether dlopen of programs is supported. -dlopen_self=$enable_dlopen_self - -# Whether dlopen of statically linked programs is supported. -dlopen_self_static=$enable_dlopen_self_static - -# Commands to strip libraries. -old_striplib=$lt_old_striplib -striplib=$lt_striplib - - -# The linker used to build libraries. -LD=$lt_LD - -# How to create reloadable object files. -reload_flag=$lt_reload_flag -reload_cmds=$lt_reload_cmds - -# Commands used to build an old-style archive. -old_archive_cmds=$lt_old_archive_cmds - -# A language specific compiler. -CC=$lt_compiler - -# Is the compiler the GNU compiler? -with_gcc=$GCC - -# Compiler flag to turn off builtin functions. -no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag - -# How to pass a linker flag through the compiler. -wl=$lt_lt_prog_compiler_wl - -# Additional compiler flags for building library objects. -pic_flag=$lt_lt_prog_compiler_pic - -# Compiler flag to prevent dynamic linking. -link_static_flag=$lt_lt_prog_compiler_static - -# Does compiler simultaneously support -c and -o options? -compiler_c_o=$lt_lt_cv_prog_compiler_c_o - -# Whether or not to add -lc for building shared libraries. -build_libtool_need_lc=$archive_cmds_need_lc - -# Whether or not to disallow shared libs when runtime libs are static. -allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes - -# Compiler flag to allow reflexive dlopens. -export_dynamic_flag_spec=$lt_export_dynamic_flag_spec - -# Compiler flag to generate shared objects directly from archives. -whole_archive_flag_spec=$lt_whole_archive_flag_spec - -# Whether the compiler copes with passing no objects directly. -compiler_needs_object=$lt_compiler_needs_object - -# Create an old-style archive from a shared archive. -old_archive_from_new_cmds=$lt_old_archive_from_new_cmds - -# Create a temporary old-style archive to link instead of a shared archive. -old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds - -# Commands used to build a shared archive. -archive_cmds=$lt_archive_cmds -archive_expsym_cmds=$lt_archive_expsym_cmds - -# Commands used to build a loadable module if different from building -# a shared archive. -module_cmds=$lt_module_cmds -module_expsym_cmds=$lt_module_expsym_cmds - -# Whether we are building with GNU ld or not. -with_gnu_ld=$lt_with_gnu_ld - -# Flag that allows shared libraries with undefined symbols to be built. -allow_undefined_flag=$lt_allow_undefined_flag - -# Flag that enforces no undefined symbols. -no_undefined_flag=$lt_no_undefined_flag - -# Flag to hardcode \$libdir into a binary during linking. -# This must work even if \$libdir does not exist -hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec - -# If ld is used when linking, flag to hardcode \$libdir into a binary -# during linking. This must work even if \$libdir does not exist. -hardcode_libdir_flag_spec_ld=$lt_hardcode_libdir_flag_spec_ld - -# Whether we need a single "-rpath" flag with a separated argument. -hardcode_libdir_separator=$lt_hardcode_libdir_separator - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary. -hardcode_direct=$hardcode_direct - -# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes -# DIR into the resulting binary and the resulting library dependency is -# "absolute",i.e impossible to change by setting \${shlibpath_var} if the -# library is relocated. -hardcode_direct_absolute=$hardcode_direct_absolute - -# Set to "yes" if using the -LDIR flag during linking hardcodes DIR -# into the resulting binary. -hardcode_minus_L=$hardcode_minus_L - -# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR -# into the resulting binary. -hardcode_shlibpath_var=$hardcode_shlibpath_var - -# Set to "yes" if building a shared library automatically hardcodes DIR -# into the library and all subsequent libraries and executables linked -# against it. -hardcode_automatic=$hardcode_automatic - -# Set to yes if linker adds runtime paths of dependent libraries -# to runtime path list. -inherit_rpath=$inherit_rpath - -# Whether libtool must link a program against all its dependency libraries. -link_all_deplibs=$link_all_deplibs - -# Fix the shell variable \$srcfile for the compiler. -fix_srcfile_path=$lt_fix_srcfile_path - -# Set to "yes" if exported symbols are required. -always_export_symbols=$always_export_symbols - -# The commands to list exported symbols. -export_symbols_cmds=$lt_export_symbols_cmds - -# Symbols that should not be listed in the preloaded symbols. -exclude_expsyms=$lt_exclude_expsyms - -# Symbols that must always be exported. -include_expsyms=$lt_include_expsyms - -# Commands necessary for linking programs (against libraries) with templates. -prelink_cmds=$lt_prelink_cmds - -# Specify filename containing input files. -file_list_spec=$lt_file_list_spec - -# How to hardcode a shared library path into an executable. -hardcode_action=$hardcode_action - -# ### END LIBTOOL CONFIG - -_LT_EOF - - case $host_os in - aix3*) - cat <<\_LT_EOF >> "$cfgfile" -# AIX sometimes has problems with the GCC collect2 program. For some -# reason, if we set the COLLECT_NAMES environment variable, the problems -# vanish in a puff of smoke. -if test "X${COLLECT_NAMES+set}" != Xset; then - COLLECT_NAMES= - export COLLECT_NAMES -fi -_LT_EOF - ;; - esac - - -ltmain="$ac_aux_dir/ltmain.sh" - - - # We use sed instead of cat because bash on DJGPP gets confused if - # if finds mixed CR/LF and LF-only lines. Since sed operates in - # text mode, it properly converts lines to CR/LF. This bash problem - # is reportedly fixed, but why not run on old versions too? - sed '/^# Generated shell functions inserted here/q' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - case $xsi_shell in - yes) - cat << \_LT_EOF >> "$cfgfile" - -# func_dirname file append nondir_replacement -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -func_dirname () -{ - case ${1} in - */*) func_dirname_result="${1%/*}${2}" ;; - * ) func_dirname_result="${3}" ;; - esac -} - -# func_basename file -func_basename () -{ - func_basename_result="${1##*/}" -} - -# func_dirname_and_basename file append nondir_replacement -# perform func_basename and func_dirname in a single function -# call: -# dirname: Compute the dirname of FILE. If nonempty, -# add APPEND to the result, otherwise set result -# to NONDIR_REPLACEMENT. -# value returned in "$func_dirname_result" -# basename: Compute filename of FILE. -# value returned in "$func_basename_result" -# Implementation must be kept synchronized with func_dirname -# and func_basename. For efficiency, we do not delegate to -# those functions but instead duplicate the functionality here. -func_dirname_and_basename () -{ - case ${1} in - */*) func_dirname_result="${1%/*}${2}" ;; - * ) func_dirname_result="${3}" ;; - esac - func_basename_result="${1##*/}" -} - -# func_stripname prefix suffix name -# strip PREFIX and SUFFIX off of NAME. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -func_stripname () -{ - # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are - # positional parameters, so assign one to ordinary parameter first. - func_stripname_result=${3} - func_stripname_result=${func_stripname_result#"${1}"} - func_stripname_result=${func_stripname_result%"${2}"} -} - -# func_opt_split -func_opt_split () -{ - func_opt_split_opt=${1%%=*} - func_opt_split_arg=${1#*=} -} - -# func_lo2o object -func_lo2o () -{ - case ${1} in - *.lo) func_lo2o_result=${1%.lo}.${objext} ;; - *) func_lo2o_result=${1} ;; - esac -} - -# func_xform libobj-or-source -func_xform () -{ - func_xform_result=${1%.*}.lo -} - -# func_arith arithmetic-term... -func_arith () -{ - func_arith_result=$(( $* )) -} - -# func_len string -# STRING may not start with a hyphen. -func_len () -{ - func_len_result=${#1} -} - -_LT_EOF - ;; - *) # Bourne compatible functions. - cat << \_LT_EOF >> "$cfgfile" - -# func_dirname file append nondir_replacement -# Compute the dirname of FILE. If nonempty, add APPEND to the result, -# otherwise set result to NONDIR_REPLACEMENT. -func_dirname () -{ - # Extract subdirectory from the argument. - func_dirname_result=`$ECHO "${1}" | $SED "$dirname"` - if test "X$func_dirname_result" = "X${1}"; then - func_dirname_result="${3}" - else - func_dirname_result="$func_dirname_result${2}" - fi -} - -# func_basename file -func_basename () -{ - func_basename_result=`$ECHO "${1}" | $SED "$basename"` -} - - -# func_stripname prefix suffix name -# strip PREFIX and SUFFIX off of NAME. -# PREFIX and SUFFIX must not contain globbing or regex special -# characters, hashes, percent signs, but SUFFIX may contain a leading -# dot (in which case that matches only a dot). -# func_strip_suffix prefix name -func_stripname () -{ - case ${2} in - .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; - *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; - esac -} - -# sed scripts: -my_sed_long_opt='1s/^\(-[^=]*\)=.*/\1/;q' -my_sed_long_arg='1s/^-[^=]*=//' - -# func_opt_split -func_opt_split () -{ - func_opt_split_opt=`$ECHO "${1}" | $SED "$my_sed_long_opt"` - func_opt_split_arg=`$ECHO "${1}" | $SED "$my_sed_long_arg"` -} - -# func_lo2o object -func_lo2o () -{ - func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"` -} - -# func_xform libobj-or-source -func_xform () -{ - func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'` -} - -# func_arith arithmetic-term... -func_arith () -{ - func_arith_result=`expr "$@"` -} - -# func_len string -# STRING may not start with a hyphen. -func_len () -{ - func_len_result=`expr "$1" : ".*" 2>/dev/null || echo $max_cmd_len` -} - -_LT_EOF -esac - -case $lt_shell_append in - yes) - cat << \_LT_EOF >> "$cfgfile" - -# func_append var value -# Append VALUE to the end of shell variable VAR. -func_append () -{ - eval "$1+=\$2" -} -_LT_EOF - ;; - *) - cat << \_LT_EOF >> "$cfgfile" - -# func_append var value -# Append VALUE to the end of shell variable VAR. -func_append () -{ - eval "$1=\$$1\$2" -} - -_LT_EOF - ;; - esac - - - sed -n '/^# Generated shell functions inserted here/,$p' "$ltmain" >> "$cfgfile" \ - || (rm -f "$cfgfile"; exit 1) - - mv -f "$cfgfile" "$ofile" || - (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") - chmod +x "$ofile" - - ;; - "gstdint.h":C) -if test "$GCC" = yes; then - echo "/* generated for " `$CC --version | sed 1q` "*/" > tmp-stdint.h -else - echo "/* generated for $CC */" > tmp-stdint.h -fi - -sed 's/^ *//' >> tmp-stdint.h < -EOF - -if test "$acx_cv_header_stdint" != stdint.h; then - echo "#include " >> tmp-stdint.h -fi -if test "$acx_cv_header_stdint" != stddef.h; then - echo "#include <$acx_cv_header_stdint>" >> tmp-stdint.h -fi - -sed 's/^ *//' >> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <= 199901L - #ifndef _INT64_T - #define _INT64_T - #ifndef __int64_t_defined - #ifndef int64_t - typedef long long int64_t; - #endif - #endif - #endif - #ifndef _UINT64_T - #define _UINT64_T - #ifndef uint64_t - typedef unsigned long long uint64_t; - #endif - #endif - - #elif defined __GNUC__ && defined (__STDC__) && __STDC__-0 - /* NextStep 2.0 cc is really gcc 1.93 but it defines __GNUC__ = 2 and - does not implement __extension__. But that compiler doesn't define - __GNUC_MINOR__. */ - # if __GNUC__ < 2 || (__NeXT__ && !__GNUC_MINOR__) - # define __extension__ - # endif - - # ifndef _INT64_T - # define _INT64_T - # ifndef int64_t - __extension__ typedef long long int64_t; - # endif - # endif - # ifndef _UINT64_T - # define _UINT64_T - # ifndef uint64_t - __extension__ typedef unsigned long long uint64_t; - # endif - # endif - - #elif !defined __STRICT_ANSI__ - # if defined _MSC_VER || defined __WATCOMC__ || defined __BORLANDC__ - - # ifndef _INT64_T - # define _INT64_T - # ifndef int64_t - typedef __int64 int64_t; - # endif - # endif - # ifndef _UINT64_T - # define _UINT64_T - # ifndef uint64_t - typedef unsigned __int64 uint64_t; - # endif - # endif - # endif /* compiler */ - - #endif /* ANSI version */ -EOF -fi - -# ------------- done int64_t types, emit intptr types ------------ -if test "$ac_cv_type_uintptr_t" != yes; then - sed 's/^ *//' >> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h <> tmp-stdint.h < - # srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually - # append it here. Only modify Makefiles that have just been created. - # - # Also, get rid of this simulated-VPATH thing that automake does. - cat > vpsed << \_EOF - s!`test -f '$<' || echo '$(srcdir)/'`!! -_EOF - for i in $SUBDIRS; do - case $CONFIG_FILES in - *${i}/Makefile*) - #echo "Adding MULTISUBDIR to $i/Makefile" - sed -f vpsed $i/Makefile > tmp - grep '^MULTISUBDIR =' Makefile >> tmp - mv tmp $i/Makefile - ;; - esac - done - rm vpsed - fi - fi - ;; - - esac -done # for ac_tag - - -as_fn_exit 0 -_ACEOF -ac_clean_files=$ac_clean_files_save - -test $ac_write_fail = 0 || - as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 - - -# configure is writing to config.log, and then calls config.status. -# config.status does its own redirection, appending to config.log. -# Unfortunately, on DOS this fails, as config.log is still kept open -# by configure, so config.status won't be able to write to it; its -# output is simply discarded. So we exec the FD to /dev/null, -# effectively closing config.log, so it can be properly (re)opened and -# appended to by config.status. When coming back to configure, we -# need to make the FD available again. -if test "$no_create" != yes; then - ac_cs_success=: - ac_config_status_args= - test "$silent" = yes && - ac_config_status_args="$ac_config_status_args --quiet" - exec 5>/dev/null - $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false - exec 5>>config.log - # Use ||, not &&, to avoid exiting from the if with $? = 1, which - # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit $? -fi -if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 -$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} -fi - diff --git a/src/libbacktrace/configure.ac b/src/libbacktrace/configure.ac deleted file mode 100644 index ea1b27d807e13..0000000000000 --- a/src/libbacktrace/configure.ac +++ /dev/null @@ -1,418 +0,0 @@ -# configure.ac -- Backtrace configure script. -# Copyright (C) 2012-2016 Free Software Foundation, Inc. - -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: - -# (1) Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. - -# (2) Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in -# the documentation and/or other materials provided with the -# distribution. - -# (3) The name of the author may not be used to -# endorse or promote products derived from this software without -# specific prior written permission. - -# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. - -AC_PREREQ(2.64) -AC_INIT(package-unused, version-unused,, libbacktrace) -AC_CONFIG_SRCDIR(backtrace.h) -AC_CONFIG_HEADER(config.h) - -if test -n "${with_target_subdir}"; then - AM_ENABLE_MULTILIB(, ..) -fi - -AC_CANONICAL_SYSTEM -target_alias=${target_alias-$host_alias} - -AC_USE_SYSTEM_EXTENSIONS - -libtool_VERSION=1:0:0 -AC_SUBST(libtool_VERSION) - -# 1.11.1: Require that version of automake. -# foreign: Don't require README, INSTALL, NEWS, etc. -# no-define: Don't define PACKAGE and VERSION. -# no-dependencies: Don't generate automatic dependencies. -# (because it breaks when using bootstrap-lean, since some of the -# headers are gone at "make install" time). -# -Wall: Issue all automake warnings. -# -Wno-portability: Don't warn about constructs supported by GNU make. -# (because GCC requires GNU make anyhow). -AM_INIT_AUTOMAKE([1.11.1 foreign no-dist no-define no-dependencies -Wall -Wno-portability]) - -AM_MAINTAINER_MODE - -AC_ARG_WITH(target-subdir, -[ --with-target-subdir=SUBDIR Configuring in a subdirectory for target]) - -# We must force CC to /not/ be precious variables; otherwise -# the wrong, non-multilib-adjusted value will be used in multilibs. -# As a side effect, we have to subst CFLAGS ourselves. -m4_rename([_AC_ARG_VAR_PRECIOUS],[backtrace_PRECIOUS]) -m4_define([_AC_ARG_VAR_PRECIOUS],[]) -AC_PROG_CC -m4_rename_force([backtrace_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) - -AC_SUBST(CFLAGS) - -AC_PROG_RANLIB - -AC_PROG_AWK -case "$AWK" in -"") AC_MSG_ERROR([can't build without awk]) ;; -esac - -LT_INIT -AM_PROG_LIBTOOL - -backtrace_supported=yes - -if test -n "${with_target_subdir}"; then - # We are compiling a GCC library. We can assume that the unwind - # library exists. - BACKTRACE_FILE="backtrace.lo simple.lo" -else - AC_CHECK_HEADER([unwind.h], - [AC_CHECK_FUNC([_Unwind_Backtrace], - [BACKTRACE_FILE="backtrace.lo simple.lo"], - [BACKTRACE_FILE="nounwind.lo" - backtrace_supported=no])], - [BACKTRACE_FILE="nounwind.lo" - backtrace_supported=no]) -fi -AC_SUBST(BACKTRACE_FILE) - -EXTRA_FLAGS= -if test -n "${with_target_subdir}"; then - EXTRA_FLAGS="-funwind-tables -frandom-seed=\$@" -else - AC_CACHE_CHECK([for -funwind-tables option], - [libbacktrace_cv_c_unwind_tables], - [CFLAGS_hold="$CFLAGS" - CFLAGS="$CFLAGS -funwind-tables" - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([static int f() { return 0; }], [return f();])], - [libbacktrace_cv_c_unwind_tables=yes], - [libbacktrace_cv_c_unwind_tables=no]) - CFLAGS="$CFLAGS_hold"]) - if test "$libbacktrace_cv_c_unwind_tables" = "yes"; then - EXTRA_FLAGS=-funwind-tables - fi - AC_CACHE_CHECK([for -frandom-seed=string option], - [libbacktrace_cv_c_random_seed_string], - [CFLAGS_hold="$CFLAGS" - CFLAGS="$CFLAGS -frandom-seed=conftest.lo" - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([], [return 0;])], - [libbacktrace_cv_c_random_seed_string=yes], - [libbacktrace_cv_c_random_seed_string=no]) - CFLAGS="$CFLAGS_hold"]) - if test "$libbacktrace_cv_c_random_seed_string" = "yes"; then - EXTRA_FLAGS="$EXTRA_FLAGS -frandom-seed=\$@" - fi -fi -AC_SUBST(EXTRA_FLAGS) - -ACX_PROG_CC_WARNING_OPTS([-W -Wall -Wwrite-strings -Wstrict-prototypes \ - -Wmissing-prototypes -Wold-style-definition \ - -Wmissing-format-attribute -Wcast-qual], - [WARN_FLAGS]) - -if test -n "${with_target_subdir}"; then - WARN_FLAGS="$WARN_FLAGS -Werror" -fi - -AC_SUBST(WARN_FLAGS) - -if test -n "${with_target_subdir}"; then - GCC_CHECK_UNWIND_GETIPINFO -else - ac_save_CFFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -Werror-implicit-function-declaration" - AC_MSG_CHECKING([for _Unwind_GetIPInfo]) - AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [#include "unwind.h" - struct _Unwind_Context *context; - int ip_before_insn = 0;], - [return _Unwind_GetIPInfo (context, &ip_before_insn);])], - [have_unwind_getipinfo=yes], [have_unwind_getipinfo=no]) - CFLAGS="$ac_save_CFLAGS" - AC_MSG_RESULT([$have_unwind_getipinfo]) - if test "$have_unwind_getipinfo" = "yes"; then - AC_DEFINE(HAVE_GETIPINFO, 1, [Define if _Unwind_GetIPInfo is available.]) - fi -fi - -# Enable --enable-host-shared. -AC_ARG_ENABLE(host-shared, -[AS_HELP_STRING([--enable-host-shared], - [build host code as shared libraries])], -[PIC_FLAG=-fPIC], [PIC_FLAG=]) -AC_SUBST(PIC_FLAG) - -# Test for __sync support. -AC_CACHE_CHECK([__sync extensions], -[libbacktrace_cv_sys_sync], -[if test -n "${with_target_subdir}"; then - case "${host}" in - hppa*-*-hpux*) libbacktrace_cv_sys_sync=no ;; - *) libbacktrace_cv_sys_sync=yes ;; - esac - else - AC_LINK_IFELSE( - [AC_LANG_PROGRAM([int i;], - [__sync_bool_compare_and_swap (&i, i, i); - __sync_lock_test_and_set (&i, 1); - __sync_lock_release (&i);])], - [libbacktrace_cv_sys_sync=yes], - [libbacktrace_cv_sys_sync=no]) - fi]) -BACKTRACE_SUPPORTS_THREADS=0 -if test "$libbacktrace_cv_sys_sync" = "yes"; then - BACKTRACE_SUPPORTS_THREADS=1 - AC_DEFINE([HAVE_SYNC_FUNCTIONS], 1, - [Define to 1 if you have the __sync functions]) -fi -AC_SUBST(BACKTRACE_SUPPORTS_THREADS) - -# Test for __atomic support. -AC_CACHE_CHECK([__atomic extensions], -[libbacktrace_cv_sys_atomic], -[if test -n "${with_target_subdir}"; then - libbacktrace_cv_sys_atomic=yes - else - AC_LINK_IFELSE( - [AC_LANG_PROGRAM([int i;], - [__atomic_load_n (&i, __ATOMIC_ACQUIRE); - __atomic_store_n (&i, 1, __ATOMIC_RELEASE);])], - [libbacktrace_cv_sys_atomic=yes], - [libbacktrace_cv_sys_atomic=no]) - fi]) -if test "$libbacktrace_cv_sys_atomic" = "yes"; then - AC_DEFINE([HAVE_ATOMIC_FUNCTIONS], 1, - [Define to 1 if you have the __atomic functions]) -fi - -# The library needs to be able to read the executable itself. Compile -# a file to determine the executable format. The awk script -# filetype.awk prints out the file type. -AC_CACHE_CHECK([output filetype], -[libbacktrace_cv_sys_filetype], -[filetype= -AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([int i;], [int j;])], - [filetype=`${AWK} -f $srcdir/filetype.awk conftest.$ac_objext`], - [AC_MSG_FAILURE([compiler failed])]) -libbacktrace_cv_sys_filetype=$filetype]) - -# Match the file type to decide what files to compile. -FORMAT_FILE= -backtrace_supports_data=yes -case "$libbacktrace_cv_sys_filetype" in -elf*) FORMAT_FILE="elf.lo" ;; -pecoff) FORMAT_FILE="pecoff.lo" - backtrace_supports_data=no - ;; -macho*) FORMAT_FILE="macho.lo" - backtrace_supports_data=no - ;; -*) AC_MSG_WARN([could not determine output file type]) - FORMAT_FILE="unknown.lo" - backtrace_supported=no - ;; -esac -AC_SUBST(FORMAT_FILE) - -# ELF defines. -elfsize= -case "$libbacktrace_cv_sys_filetype" in -elf32) elfsize=32 ;; -elf64) elfsize=64 ;; -*) elfsize=unused -esac -AC_DEFINE_UNQUOTED([BACKTRACE_ELF_SIZE], [$elfsize], [ELF size: 32 or 64]) - -BACKTRACE_SUPPORTED=0 -if test "$backtrace_supported" = "yes"; then - BACKTRACE_SUPPORTED=1 -fi -AC_SUBST(BACKTRACE_SUPPORTED) - -BACKTRACE_SUPPORTS_DATA=0 -if test "$backtrace_supports_data" = "yes"; then - BACKTRACE_SUPPORTS_DATA=1 -fi -AC_SUBST(BACKTRACE_SUPPORTS_DATA) - -GCC_HEADER_STDINT(gstdint.h) - -AC_CHECK_HEADERS(sys/mman.h) -if test "$ac_cv_header_sys_mman_h" = "no"; then - have_mmap=no -else - if test -n "${with_target_subdir}"; then - # When built as a GCC target library, we can't do a link test. We - # simply assume that if we have mman.h, we have mmap. - have_mmap=yes - case "${host}" in - spu-*-*|*-*-msdosdjgpp) - # The SPU does not have mmap, but it has a sys/mman.h header file - # containing "mmap_eaddr" and the mmap flags, confusing the test. - # DJGPP also has sys/man.h, but no mmap - have_mmap=no ;; - esac - else - AC_CHECK_FUNC(mmap, [have_mmap=yes], [have_mmap=no]) - fi -fi - -case "${host_os}" in -darwin*) - have_mmap=no ;; -esac - -if test "$have_mmap" = "no"; then - VIEW_FILE=read.lo - ALLOC_FILE=alloc.lo -else - VIEW_FILE=mmapio.lo - AC_PREPROC_IFELSE([ -#include -#if !defined(MAP_ANONYMOUS) && !defined(MAP_ANON) - #error no MAP_ANONYMOUS -#endif -], [ALLOC_FILE=mmap.lo], [ALLOC_FILE=alloc.lo]) -fi -AC_SUBST(VIEW_FILE) -AC_SUBST(ALLOC_FILE) - -BACKTRACE_USES_MALLOC=0 -if test "$ALLOC_FILE" = "alloc.lo"; then - BACKTRACE_USES_MALLOC=1 -fi -AC_SUBST(BACKTRACE_USES_MALLOC) - -# Check for dl_iterate_phdr. -AC_CHECK_HEADERS(link.h) -if test "$ac_cv_header_link_h" = "no"; then - have_dl_iterate_phdr=no -else - if test -n "${with_target_subdir}"; then - # When built as a GCC target library, we can't do a link test. - AC_EGREP_HEADER([dl_iterate_phdr], [link.h], [have_dl_iterate_phdr=yes], - [have_dl_iterate_phdr=no]) - case "${host}" in - *-*-solaris2.10*) - # Avoid dl_iterate_phdr on Solaris 10, where it is in the - # header file but is only in -ldl. - have_dl_iterate_phdr=no ;; - esac - else - AC_CHECK_FUNC([dl_iterate_phdr], [have_dl_iterate_phdr=yes], - [have_dl_iterate_phdr=no]) - fi -fi -if test "$have_dl_iterate_phdr" = "yes"; then - AC_DEFINE(HAVE_DL_ITERATE_PHDR, 1, [Define if dl_iterate_phdr is available.]) -fi - -# Check for the fcntl function. -if test -n "${with_target_subdir}"; then - case "${host}" in - *-*-mingw*) have_fcntl=no ;; - spu-*-*) have_fcntl=no ;; - *) have_fcntl=yes ;; - esac -else - AC_CHECK_FUNC(fcntl, [have_fcntl=yes], [have_fcntl=no]) -fi -if test "$have_fcntl" = "yes"; then - AC_DEFINE([HAVE_FCNTL], 1, - [Define to 1 if you have the fcntl function]) -fi - -AC_CHECK_DECLS(strnlen) - -# Check for getexecname function. -if test -n "${with_target_subdir}"; then - case "${host}" in - *-*-solaris2*) have_getexecname=yes ;; - *) have_getexecname=no ;; - esac -else - AC_CHECK_FUNC(getexecname, [have_getexecname=yes], [have_getexecname=no]) -fi -if test "$have_getexecname" = "yes"; then - AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.]) -fi - -AC_CACHE_CHECK([whether tests can run], - [libbacktrace_cv_sys_native], - [AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])], - [libbacktrace_cv_sys_native=yes], - [libbacktrace_cv_sys_native=no], - [libbacktrace_cv_sys_native=no])]) -AM_CONDITIONAL(NATIVE, test "$libbacktrace_cv_sys_native" = "yes") - -if test "${multilib}" = "yes"; then - multilib_arg="--enable-multilib" -else - multilib_arg= -fi - -AC_CONFIG_FILES(Makefile backtrace-supported.h) - -# We need multilib support, but only if configuring for the target. -AC_CONFIG_COMMANDS([default], -[if test -n "$CONFIG_FILES"; then - if test -n "${with_target_subdir}"; then - # Multilibs need MULTISUBDIR defined correctly in certain makefiles so - # that multilib installs will end up installed in the correct place. - # The testsuite needs it for multilib-aware ABI baseline files. - # To work around this not being passed down from config-ml.in -> - # srcdir/Makefile.am -> srcdir/{src,libsupc++,...}/Makefile.am, manually - # append it here. Only modify Makefiles that have just been created. - # - # Also, get rid of this simulated-VPATH thing that automake does. - cat > vpsed << \_EOF - s!`test -f '$<' || echo '$(srcdir)/'`!! -_EOF - for i in $SUBDIRS; do - case $CONFIG_FILES in - *${i}/Makefile*) - #echo "Adding MULTISUBDIR to $i/Makefile" - sed -f vpsed $i/Makefile > tmp - grep '^MULTISUBDIR =' Makefile >> tmp - mv tmp $i/Makefile - ;; - esac - done - rm vpsed - fi - fi -], -[ -# Variables needed in config.status (file generation) which aren't already -# passed by autoconf. -SUBDIRS="$SUBDIRS" -]) - -AC_OUTPUT diff --git a/src/libbacktrace/dwarf.c b/src/libbacktrace/dwarf.c deleted file mode 100644 index 55b8d7dc2a56d..0000000000000 --- a/src/libbacktrace/dwarf.c +++ /dev/null @@ -1,3038 +0,0 @@ -/* dwarf.c -- Get file/line information from DWARF for backtraces. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include - -#include "dwarf2.h" -#include "filenames.h" - -#include "backtrace.h" -#include "internal.h" - -#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN - -/* If strnlen is not declared, provide our own version. */ - -static size_t -xstrnlen (const char *s, size_t maxlen) -{ - size_t i; - - for (i = 0; i < maxlen; ++i) - if (s[i] == '\0') - break; - return i; -} - -#define strnlen xstrnlen - -#endif - -/* A buffer to read DWARF info. */ - -struct dwarf_buf -{ - /* Buffer name for error messages. */ - const char *name; - /* Start of the buffer. */ - const unsigned char *start; - /* Next byte to read. */ - const unsigned char *buf; - /* The number of bytes remaining. */ - size_t left; - /* Whether the data is big-endian. */ - int is_bigendian; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data for error_callback. */ - void *data; - /* Non-zero if we've reported an underflow error. */ - int reported_underflow; -}; - -/* A single attribute in a DWARF abbreviation. */ - -struct attr -{ - /* The attribute name. */ - enum dwarf_attribute name; - /* The attribute form. */ - enum dwarf_form form; -}; - -/* A single DWARF abbreviation. */ - -struct abbrev -{ - /* The abbrev code--the number used to refer to the abbrev. */ - uint64_t code; - /* The entry tag. */ - enum dwarf_tag tag; - /* Non-zero if this abbrev has child entries. */ - int has_children; - /* The number of attributes. */ - size_t num_attrs; - /* The attributes. */ - struct attr *attrs; -}; - -/* The DWARF abbreviations for a compilation unit. This structure - only exists while reading the compilation unit. Most DWARF readers - seem to a hash table to map abbrev ID's to abbrev entries. - However, we primarily care about GCC, and GCC simply issues ID's in - numerical order starting at 1. So we simply keep a sorted vector, - and try to just look up the code. */ - -struct abbrevs -{ - /* The number of abbrevs in the vector. */ - size_t num_abbrevs; - /* The abbrevs, sorted by the code field. */ - struct abbrev *abbrevs; -}; - -/* The different kinds of attribute values. */ - -enum attr_val_encoding -{ - /* An address. */ - ATTR_VAL_ADDRESS, - /* A unsigned integer. */ - ATTR_VAL_UINT, - /* A sigd integer. */ - ATTR_VAL_SINT, - /* A string. */ - ATTR_VAL_STRING, - /* An offset to other data in the containing unit. */ - ATTR_VAL_REF_UNIT, - /* An offset to other data within the .dwarf_info section. */ - ATTR_VAL_REF_INFO, - /* An offset to data in some other section. */ - ATTR_VAL_REF_SECTION, - /* A type signature. */ - ATTR_VAL_REF_TYPE, - /* A block of data (not represented). */ - ATTR_VAL_BLOCK, - /* An expression (not represented). */ - ATTR_VAL_EXPR, -}; - -/* An attribute value. */ - -struct attr_val -{ - /* How the value is stored in the field u. */ - enum attr_val_encoding encoding; - union - { - /* ATTR_VAL_ADDRESS, ATTR_VAL_UINT, ATTR_VAL_REF*. */ - uint64_t uint; - /* ATTR_VAL_SINT. */ - int64_t sint; - /* ATTR_VAL_STRING. */ - const char *string; - /* ATTR_VAL_BLOCK not stored. */ - } u; -}; - -/* The line number program header. */ - -struct line_header -{ - /* The version of the line number information. */ - int version; - /* The minimum instruction length. */ - unsigned int min_insn_len; - /* The maximum number of ops per instruction. */ - unsigned int max_ops_per_insn; - /* The line base for special opcodes. */ - int line_base; - /* The line range for special opcodes. */ - unsigned int line_range; - /* The opcode base--the first special opcode. */ - unsigned int opcode_base; - /* Opcode lengths, indexed by opcode - 1. */ - const unsigned char *opcode_lengths; - /* The number of directory entries. */ - size_t dirs_count; - /* The directory entries. */ - const char **dirs; - /* The number of filenames. */ - size_t filenames_count; - /* The filenames. */ - const char **filenames; -}; - -/* Map a single PC value to a file/line. We will keep a vector of - these sorted by PC value. Each file/line will be correct from the - PC up to the PC of the next entry if there is one. We allocate one - extra entry at the end so that we can use bsearch. */ - -struct line -{ - /* PC. */ - uintptr_t pc; - /* File name. Many entries in the array are expected to point to - the same file name. */ - const char *filename; - /* Line number. */ - int lineno; - /* Index of the object in the original array read from the DWARF - section, before it has been sorted. The index makes it possible - to use Quicksort and maintain stability. */ - int idx; -}; - -/* A growable vector of line number information. This is used while - reading the line numbers. */ - -struct line_vector -{ - /* Memory. This is an array of struct line. */ - struct backtrace_vector vec; - /* Number of valid mappings. */ - size_t count; -}; - -/* A function described in the debug info. */ - -struct function -{ - /* The name of the function. */ - const char *name; - /* If this is an inlined function, the filename of the call - site. */ - const char *caller_filename; - /* If this is an inlined function, the line number of the call - site. */ - int caller_lineno; - /* Map PC ranges to inlined functions. */ - struct function_addrs *function_addrs; - size_t function_addrs_count; -}; - -/* An address range for a function. This maps a PC value to a - specific function. */ - -struct function_addrs -{ - /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; - /* Function for this address range. */ - struct function *function; -}; - -/* A growable vector of function address ranges. */ - -struct function_vector -{ - /* Memory. This is an array of struct function_addrs. */ - struct backtrace_vector vec; - /* Number of address ranges present. */ - size_t count; -}; - -/* A DWARF compilation unit. This only holds the information we need - to map a PC to a file and line. */ - -struct unit -{ - /* The first entry for this compilation unit. */ - const unsigned char *unit_data; - /* The length of the data for this compilation unit. */ - size_t unit_data_len; - /* The offset of UNIT_DATA from the start of the information for - this compilation unit. */ - size_t unit_data_offset; - /* DWARF version. */ - int version; - /* Whether unit is DWARF64. */ - int is_dwarf64; - /* Address size. */ - int addrsize; - /* Offset into line number information. */ - off_t lineoff; - /* Primary source file. */ - const char *filename; - /* Compilation command working directory. */ - const char *comp_dir; - /* Absolute file name, only set if needed. */ - const char *abs_filename; - /* The abbreviations for this unit. */ - struct abbrevs abbrevs; - - /* The fields above this point are read in during initialization and - may be accessed freely. The fields below this point are read in - as needed, and therefore require care, as different threads may - try to initialize them simultaneously. */ - - /* PC to line number mapping. This is NULL if the values have not - been read. This is (struct line *) -1 if there was an error - reading the values. */ - struct line *lines; - /* Number of entries in lines. */ - size_t lines_count; - /* PC ranges to function. */ - struct function_addrs *function_addrs; - size_t function_addrs_count; -}; - -/* An address range for a compilation unit. This maps a PC value to a - specific compilation unit. Note that we invert the representation - in DWARF: instead of listing the units and attaching a list of - ranges, we list the ranges and have each one point to the unit. - This lets us do a binary search to find the unit. */ - -struct unit_addrs -{ - /* Range is LOW <= PC < HIGH. */ - uint64_t low; - uint64_t high; - /* Compilation unit for this address range. */ - struct unit *u; -}; - -/* A growable vector of compilation unit address ranges. */ - -struct unit_addrs_vector -{ - /* Memory. This is an array of struct unit_addrs. */ - struct backtrace_vector vec; - /* Number of address ranges present. */ - size_t count; -}; - -/* The information we need to map a PC to a file and line. */ - -struct dwarf_data -{ - /* The data for the next file we know about. */ - struct dwarf_data *next; - /* The base address for this file. */ - uintptr_t base_address; - /* A sorted list of address ranges. */ - struct unit_addrs *addrs; - /* Number of address ranges in list. */ - size_t addrs_count; - /* The unparsed .debug_info section. */ - const unsigned char *dwarf_info; - size_t dwarf_info_size; - /* The unparsed .debug_line section. */ - const unsigned char *dwarf_line; - size_t dwarf_line_size; - /* The unparsed .debug_ranges section. */ - const unsigned char *dwarf_ranges; - size_t dwarf_ranges_size; - /* The unparsed .debug_str section. */ - const unsigned char *dwarf_str; - size_t dwarf_str_size; - /* Whether the data is big-endian or not. */ - int is_bigendian; - /* A vector used for function addresses. We keep this here so that - we can grow the vector as we read more functions. */ - struct function_vector fvec; -}; - -/* Report an error for a DWARF buffer. */ - -static void -dwarf_buf_error (struct dwarf_buf *buf, const char *msg) -{ - char b[200]; - - snprintf (b, sizeof b, "%s in %s at %d", - msg, buf->name, (int) (buf->buf - buf->start)); - buf->error_callback (buf->data, b, 0); -} - -/* Require at least COUNT bytes in BUF. Return 1 if all is well, 0 on - error. */ - -static int -require (struct dwarf_buf *buf, size_t count) -{ - if (buf->left >= count) - return 1; - - if (!buf->reported_underflow) - { - dwarf_buf_error (buf, "DWARF underflow"); - buf->reported_underflow = 1; - } - - return 0; -} - -/* Advance COUNT bytes in BUF. Return 1 if all is well, 0 on - error. */ - -static int -advance (struct dwarf_buf *buf, size_t count) -{ - if (!require (buf, count)) - return 0; - buf->buf += count; - buf->left -= count; - return 1; -} - -/* Read one byte from BUF and advance 1 byte. */ - -static unsigned char -read_byte (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 1)) - return 0; - return p[0]; -} - -/* Read a signed char from BUF and advance 1 byte. */ - -static signed char -read_sbyte (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 1)) - return 0; - return (*p ^ 0x80) - 0x80; -} - -/* Read a uint16 from BUF and advance 2 bytes. */ - -static uint16_t -read_uint16 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 2)) - return 0; - if (buf->is_bigendian) - return ((uint16_t) p[0] << 8) | (uint16_t) p[1]; - else - return ((uint16_t) p[1] << 8) | (uint16_t) p[0]; -} - -/* Read a uint32 from BUF and advance 4 bytes. */ - -static uint32_t -read_uint32 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 4)) - return 0; - if (buf->is_bigendian) - return (((uint32_t) p[0] << 24) | ((uint32_t) p[1] << 16) - | ((uint32_t) p[2] << 8) | (uint32_t) p[3]); - else - return (((uint32_t) p[3] << 24) | ((uint32_t) p[2] << 16) - | ((uint32_t) p[1] << 8) | (uint32_t) p[0]); -} - -/* Read a uint64 from BUF and advance 8 bytes. */ - -static uint64_t -read_uint64 (struct dwarf_buf *buf) -{ - const unsigned char *p = buf->buf; - - if (!advance (buf, 8)) - return 0; - if (buf->is_bigendian) - return (((uint64_t) p[0] << 56) | ((uint64_t) p[1] << 48) - | ((uint64_t) p[2] << 40) | ((uint64_t) p[3] << 32) - | ((uint64_t) p[4] << 24) | ((uint64_t) p[5] << 16) - | ((uint64_t) p[6] << 8) | (uint64_t) p[7]); - else - return (((uint64_t) p[7] << 56) | ((uint64_t) p[6] << 48) - | ((uint64_t) p[5] << 40) | ((uint64_t) p[4] << 32) - | ((uint64_t) p[3] << 24) | ((uint64_t) p[2] << 16) - | ((uint64_t) p[1] << 8) | (uint64_t) p[0]); -} - -/* Read an offset from BUF and advance the appropriate number of - bytes. */ - -static uint64_t -read_offset (struct dwarf_buf *buf, int is_dwarf64) -{ - if (is_dwarf64) - return read_uint64 (buf); - else - return read_uint32 (buf); -} - -/* Read an address from BUF and advance the appropriate number of - bytes. */ - -static uint64_t -read_address (struct dwarf_buf *buf, int addrsize) -{ - switch (addrsize) - { - case 1: - return read_byte (buf); - case 2: - return read_uint16 (buf); - case 4: - return read_uint32 (buf); - case 8: - return read_uint64 (buf); - default: - dwarf_buf_error (buf, "unrecognized address size"); - return 0; - } -} - -/* Return whether a value is the highest possible address, given the - address size. */ - -static int -is_highest_address (uint64_t address, int addrsize) -{ - switch (addrsize) - { - case 1: - return address == (unsigned char) -1; - case 2: - return address == (uint16_t) -1; - case 4: - return address == (uint32_t) -1; - case 8: - return address == (uint64_t) -1; - default: - return 0; - } -} - -/* Read an unsigned LEB128 number. */ - -static uint64_t -read_uleb128 (struct dwarf_buf *buf) -{ - uint64_t ret; - unsigned int shift; - int overflow; - unsigned char b; - - ret = 0; - shift = 0; - overflow = 0; - do - { - const unsigned char *p; - - p = buf->buf; - if (!advance (buf, 1)) - return 0; - b = *p; - if (shift < 64) - ret |= ((uint64_t) (b & 0x7f)) << shift; - else if (!overflow) - { - dwarf_buf_error (buf, "LEB128 overflows uint64_t"); - overflow = 1; - } - shift += 7; - } - while ((b & 0x80) != 0); - - return ret; -} - -/* Read a signed LEB128 number. */ - -static int64_t -read_sleb128 (struct dwarf_buf *buf) -{ - uint64_t val; - unsigned int shift; - int overflow; - unsigned char b; - - val = 0; - shift = 0; - overflow = 0; - do - { - const unsigned char *p; - - p = buf->buf; - if (!advance (buf, 1)) - return 0; - b = *p; - if (shift < 64) - val |= ((uint64_t) (b & 0x7f)) << shift; - else if (!overflow) - { - dwarf_buf_error (buf, "signed LEB128 overflows uint64_t"); - overflow = 1; - } - shift += 7; - } - while ((b & 0x80) != 0); - - if ((b & 0x40) != 0 && shift < 64) - val |= ((uint64_t) -1) << shift; - - return (int64_t) val; -} - -/* Return the length of an LEB128 number. */ - -static size_t -leb128_len (const unsigned char *p) -{ - size_t ret; - - ret = 1; - while ((*p & 0x80) != 0) - { - ++p; - ++ret; - } - return ret; -} - -/* Free an abbreviations structure. */ - -static void -free_abbrevs (struct backtrace_state *state, struct abbrevs *abbrevs, - backtrace_error_callback error_callback, void *data) -{ - size_t i; - - for (i = 0; i < abbrevs->num_abbrevs; ++i) - backtrace_free (state, abbrevs->abbrevs[i].attrs, - abbrevs->abbrevs[i].num_attrs * sizeof (struct attr), - error_callback, data); - backtrace_free (state, abbrevs->abbrevs, - abbrevs->num_abbrevs * sizeof (struct abbrev), - error_callback, data); - abbrevs->num_abbrevs = 0; - abbrevs->abbrevs = NULL; -} - -/* Read an attribute value. Returns 1 on success, 0 on failure. If - the value can be represented as a uint64_t, sets *VAL and sets - *IS_VALID to 1. We don't try to store the value of other attribute - forms, because we don't care about them. */ - -static int -read_attribute (enum dwarf_form form, struct dwarf_buf *buf, - int is_dwarf64, int version, int addrsize, - const unsigned char *dwarf_str, size_t dwarf_str_size, - struct attr_val *val) -{ - /* Avoid warnings about val.u.FIELD may be used uninitialized if - this function is inlined. The warnings aren't valid but can - occur because the different fields are set and used - conditionally. */ - memset (val, 0, sizeof *val); - - switch (form) - { - case DW_FORM_addr: - val->encoding = ATTR_VAL_ADDRESS; - val->u.uint = read_address (buf, addrsize); - return 1; - case DW_FORM_block2: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uint16 (buf)); - case DW_FORM_block4: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uint32 (buf)); - case DW_FORM_data2: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint16 (buf); - return 1; - case DW_FORM_data4: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint32 (buf); - return 1; - case DW_FORM_data8: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_string: - val->encoding = ATTR_VAL_STRING; - val->u.string = (const char *) buf->buf; - return advance (buf, strnlen ((const char *) buf->buf, buf->left) + 1); - case DW_FORM_block: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_uleb128 (buf)); - case DW_FORM_block1: - val->encoding = ATTR_VAL_BLOCK; - return advance (buf, read_byte (buf)); - case DW_FORM_data1: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_flag: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_sdata: - val->encoding = ATTR_VAL_SINT; - val->u.sint = read_sleb128 (buf); - return 1; - case DW_FORM_strp: - { - uint64_t offset; - - offset = read_offset (buf, is_dwarf64); - if (offset >= dwarf_str_size) - { - dwarf_buf_error (buf, "DW_FORM_strp out of range"); - return 0; - } - val->encoding = ATTR_VAL_STRING; - val->u.string = (const char *) dwarf_str + offset; - return 1; - } - case DW_FORM_udata: - val->encoding = ATTR_VAL_UINT; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_ref_addr: - val->encoding = ATTR_VAL_REF_INFO; - if (version == 2) - val->u.uint = read_address (buf, addrsize); - else - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - case DW_FORM_ref1: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_byte (buf); - return 1; - case DW_FORM_ref2: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint16 (buf); - return 1; - case DW_FORM_ref4: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint32 (buf); - return 1; - case DW_FORM_ref8: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_ref_udata: - val->encoding = ATTR_VAL_REF_UNIT; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_indirect: - { - uint64_t form; - - form = read_uleb128 (buf); - return read_attribute ((enum dwarf_form) form, buf, is_dwarf64, - version, addrsize, dwarf_str, dwarf_str_size, - val); - } - case DW_FORM_sec_offset: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - case DW_FORM_exprloc: - val->encoding = ATTR_VAL_EXPR; - return advance (buf, read_uleb128 (buf)); - case DW_FORM_flag_present: - val->encoding = ATTR_VAL_UINT; - val->u.uint = 1; - return 1; - case DW_FORM_ref_sig8: - val->encoding = ATTR_VAL_REF_TYPE; - val->u.uint = read_uint64 (buf); - return 1; - case DW_FORM_GNU_addr_index: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_GNU_str_index: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_uleb128 (buf); - return 1; - case DW_FORM_GNU_ref_alt: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - case DW_FORM_GNU_strp_alt: - val->encoding = ATTR_VAL_REF_SECTION; - val->u.uint = read_offset (buf, is_dwarf64); - return 1; - default: - dwarf_buf_error (buf, "unrecognized DWARF form"); - return 0; - } -} - -/* Compare function_addrs for qsort. When ranges are nested, make the - smallest one sort last. */ - -static int -function_addrs_compare (const void *v1, const void *v2) -{ - const struct function_addrs *a1 = (const struct function_addrs *) v1; - const struct function_addrs *a2 = (const struct function_addrs *) v2; - - if (a1->low < a2->low) - return -1; - if (a1->low > a2->low) - return 1; - if (a1->high < a2->high) - return 1; - if (a1->high > a2->high) - return -1; - return strcmp (a1->function->name, a2->function->name); -} - -/* Compare a PC against a function_addrs for bsearch. Note that if - there are multiple ranges containing PC, which one will be returned - is unpredictable. We compensate for that in dwarf_fileline. */ - -static int -function_addrs_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct function_addrs *entry = (const struct function_addrs *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->low) - return -1; - else if (pc >= entry->high) - return 1; - else - return 0; -} - -/* Add a new compilation unit address range to a vector. Returns 1 on - success, 0 on failure. */ - -static int -add_unit_addr (struct backtrace_state *state, uintptr_t base_address, - struct unit_addrs addrs, - backtrace_error_callback error_callback, void *data, - struct unit_addrs_vector *vec) -{ - struct unit_addrs *p; - - /* Add in the base address of the module here, so that we can look - up the PC directly. */ - addrs.low += base_address; - addrs.high += base_address; - - /* Try to merge with the last entry. */ - if (vec->count > 0) - { - p = (struct unit_addrs *) vec->vec.base + (vec->count - 1); - if ((addrs.low == p->high || addrs.low == p->high + 1) - && addrs.u == p->u) - { - if (addrs.high > p->high) - p->high = addrs.high; - return 1; - } - } - - p = ((struct unit_addrs *) - backtrace_vector_grow (state, sizeof (struct unit_addrs), - error_callback, data, &vec->vec)); - if (p == NULL) - return 0; - - *p = addrs; - ++vec->count; - return 1; -} - -/* Free a unit address vector. */ - -static void -free_unit_addrs_vector (struct backtrace_state *state, - struct unit_addrs_vector *vec, - backtrace_error_callback error_callback, void *data) -{ - struct unit_addrs *addrs; - size_t i; - - addrs = (struct unit_addrs *) vec->vec.base; - for (i = 0; i < vec->count; ++i) - free_abbrevs (state, &addrs[i].u->abbrevs, error_callback, data); -} - -/* Compare unit_addrs for qsort. When ranges are nested, make the - smallest one sort last. */ - -static int -unit_addrs_compare (const void *v1, const void *v2) -{ - const struct unit_addrs *a1 = (const struct unit_addrs *) v1; - const struct unit_addrs *a2 = (const struct unit_addrs *) v2; - - if (a1->low < a2->low) - return -1; - if (a1->low > a2->low) - return 1; - if (a1->high < a2->high) - return 1; - if (a1->high > a2->high) - return -1; - if (a1->u->lineoff < a2->u->lineoff) - return -1; - if (a1->u->lineoff > a2->u->lineoff) - return 1; - return 0; -} - -/* Compare a PC against a unit_addrs for bsearch. Note that if there - are multiple ranges containing PC, which one will be returned is - unpredictable. We compensate for that in dwarf_fileline. */ - -static int -unit_addrs_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct unit_addrs *entry = (const struct unit_addrs *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->low) - return -1; - else if (pc >= entry->high) - return 1; - else - return 0; -} - -/* Sort the line vector by PC. We want a stable sort here to maintain - the order of lines for the same PC values. Since the sequence is - being sorted in place, their addresses cannot be relied on to - maintain stability. That is the purpose of the index member. */ - -static int -line_compare (const void *v1, const void *v2) -{ - const struct line *ln1 = (const struct line *) v1; - const struct line *ln2 = (const struct line *) v2; - - if (ln1->pc < ln2->pc) - return -1; - else if (ln1->pc > ln2->pc) - return 1; - else if (ln1->idx < ln2->idx) - return -1; - else if (ln1->idx > ln2->idx) - return 1; - else - return 0; -} - -/* Find a PC in a line vector. We always allocate an extra entry at - the end of the lines vector, so that this routine can safely look - at the next entry. Note that when there are multiple mappings for - the same PC value, this will return the last one. */ - -static int -line_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct line *entry = (const struct line *) ventry; - uintptr_t pc; - - pc = *key; - if (pc < entry->pc) - return -1; - else if (pc >= (entry + 1)->pc) - return 1; - else - return 0; -} - -/* Sort the abbrevs by the abbrev code. This function is passed to - both qsort and bsearch. */ - -static int -abbrev_compare (const void *v1, const void *v2) -{ - const struct abbrev *a1 = (const struct abbrev *) v1; - const struct abbrev *a2 = (const struct abbrev *) v2; - - if (a1->code < a2->code) - return -1; - else if (a1->code > a2->code) - return 1; - else - { - /* This really shouldn't happen. It means there are two - different abbrevs with the same code, and that means we don't - know which one lookup_abbrev should return. */ - return 0; - } -} - -/* Read the abbreviation table for a compilation unit. Returns 1 on - success, 0 on failure. */ - -static int -read_abbrevs (struct backtrace_state *state, uint64_t abbrev_offset, - const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, - int is_bigendian, backtrace_error_callback error_callback, - void *data, struct abbrevs *abbrevs) -{ - struct dwarf_buf abbrev_buf; - struct dwarf_buf count_buf; - size_t num_abbrevs; - - abbrevs->num_abbrevs = 0; - abbrevs->abbrevs = NULL; - - if (abbrev_offset >= dwarf_abbrev_size) - { - error_callback (data, "abbrev offset out of range", 0); - return 0; - } - - abbrev_buf.name = ".debug_abbrev"; - abbrev_buf.start = dwarf_abbrev; - abbrev_buf.buf = dwarf_abbrev + abbrev_offset; - abbrev_buf.left = dwarf_abbrev_size - abbrev_offset; - abbrev_buf.is_bigendian = is_bigendian; - abbrev_buf.error_callback = error_callback; - abbrev_buf.data = data; - abbrev_buf.reported_underflow = 0; - - /* Count the number of abbrevs in this list. */ - - count_buf = abbrev_buf; - num_abbrevs = 0; - while (read_uleb128 (&count_buf) != 0) - { - if (count_buf.reported_underflow) - return 0; - ++num_abbrevs; - // Skip tag. - read_uleb128 (&count_buf); - // Skip has_children. - read_byte (&count_buf); - // Skip attributes. - while (read_uleb128 (&count_buf) != 0) - read_uleb128 (&count_buf); - // Skip form of last attribute. - read_uleb128 (&count_buf); - } - - if (count_buf.reported_underflow) - return 0; - - if (num_abbrevs == 0) - return 1; - - abbrevs->num_abbrevs = num_abbrevs; - abbrevs->abbrevs = ((struct abbrev *) - backtrace_alloc (state, - num_abbrevs * sizeof (struct abbrev), - error_callback, data)); - if (abbrevs->abbrevs == NULL) - return 0; - memset (abbrevs->abbrevs, 0, num_abbrevs * sizeof (struct abbrev)); - - num_abbrevs = 0; - while (1) - { - uint64_t code; - struct abbrev a; - size_t num_attrs; - struct attr *attrs; - - if (abbrev_buf.reported_underflow) - goto fail; - - code = read_uleb128 (&abbrev_buf); - if (code == 0) - break; - - a.code = code; - a.tag = (enum dwarf_tag) read_uleb128 (&abbrev_buf); - a.has_children = read_byte (&abbrev_buf); - - count_buf = abbrev_buf; - num_attrs = 0; - while (read_uleb128 (&count_buf) != 0) - { - ++num_attrs; - read_uleb128 (&count_buf); - } - - if (num_attrs == 0) - { - attrs = NULL; - read_uleb128 (&abbrev_buf); - read_uleb128 (&abbrev_buf); - } - else - { - attrs = ((struct attr *) - backtrace_alloc (state, num_attrs * sizeof *attrs, - error_callback, data)); - if (attrs == NULL) - goto fail; - num_attrs = 0; - while (1) - { - uint64_t name; - uint64_t form; - - name = read_uleb128 (&abbrev_buf); - form = read_uleb128 (&abbrev_buf); - if (name == 0) - break; - attrs[num_attrs].name = (enum dwarf_attribute) name; - attrs[num_attrs].form = (enum dwarf_form) form; - ++num_attrs; - } - } - - a.num_attrs = num_attrs; - a.attrs = attrs; - - abbrevs->abbrevs[num_abbrevs] = a; - ++num_abbrevs; - } - - backtrace_qsort (abbrevs->abbrevs, abbrevs->num_abbrevs, - sizeof (struct abbrev), abbrev_compare); - - return 1; - - fail: - free_abbrevs (state, abbrevs, error_callback, data); - return 0; -} - -/* Return the abbrev information for an abbrev code. */ - -static const struct abbrev * -lookup_abbrev (struct abbrevs *abbrevs, uint64_t code, - backtrace_error_callback error_callback, void *data) -{ - struct abbrev key; - void *p; - - /* With GCC, where abbrevs are simply numbered in order, we should - be able to just look up the entry. */ - if (code - 1 < abbrevs->num_abbrevs - && abbrevs->abbrevs[code - 1].code == code) - return &abbrevs->abbrevs[code - 1]; - - /* Otherwise we have to search. */ - memset (&key, 0, sizeof key); - key.code = code; - p = bsearch (&key, abbrevs->abbrevs, abbrevs->num_abbrevs, - sizeof (struct abbrev), abbrev_compare); - if (p == NULL) - { - error_callback (data, "invalid abbreviation code", 0); - return NULL; - } - return (const struct abbrev *) p; -} - -/* Add non-contiguous address ranges for a compilation unit. Returns - 1 on success, 0 on failure. */ - -static int -add_unit_ranges (struct backtrace_state *state, uintptr_t base_address, - struct unit *u, uint64_t ranges, uint64_t base, - int is_bigendian, const unsigned char *dwarf_ranges, - size_t dwarf_ranges_size, - backtrace_error_callback error_callback, void *data, - struct unit_addrs_vector *addrs) -{ - struct dwarf_buf ranges_buf; - - if (ranges >= dwarf_ranges_size) - { - error_callback (data, "ranges offset out of range", 0); - return 0; - } - - ranges_buf.name = ".debug_ranges"; - ranges_buf.start = dwarf_ranges; - ranges_buf.buf = dwarf_ranges + ranges; - ranges_buf.left = dwarf_ranges_size - ranges; - ranges_buf.is_bigendian = is_bigendian; - ranges_buf.error_callback = error_callback; - ranges_buf.data = data; - ranges_buf.reported_underflow = 0; - - while (1) - { - uint64_t low; - uint64_t high; - - if (ranges_buf.reported_underflow) - return 0; - - low = read_address (&ranges_buf, u->addrsize); - high = read_address (&ranges_buf, u->addrsize); - - if (low == 0 && high == 0) - break; - - if (is_highest_address (low, u->addrsize)) - base = high; - else - { - struct unit_addrs a; - - a.low = low + base; - a.high = high + base; - a.u = u; - if (!add_unit_addr (state, base_address, a, error_callback, data, - addrs)) - return 0; - } - } - - if (ranges_buf.reported_underflow) - return 0; - - return 1; -} - -/* Find the address range covered by a compilation unit, reading from - UNIT_BUF and adding values to U. Returns 1 if all data could be - read, 0 if there is some error. */ - -static int -find_address_ranges (struct backtrace_state *state, uintptr_t base_address, - struct dwarf_buf *unit_buf, - const unsigned char *dwarf_str, size_t dwarf_str_size, - const unsigned char *dwarf_ranges, - size_t dwarf_ranges_size, - int is_bigendian, backtrace_error_callback error_callback, - void *data, struct unit *u, - struct unit_addrs_vector *addrs) -{ - while (unit_buf->left > 0) - { - uint64_t code; - const struct abbrev *abbrev; - uint64_t lowpc; - int have_lowpc; - uint64_t highpc; - int have_highpc; - int highpc_is_relative; - uint64_t ranges; - int have_ranges; - size_t i; - - code = read_uleb128 (unit_buf); - if (code == 0) - return 1; - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return 0; - - lowpc = 0; - have_lowpc = 0; - highpc = 0; - have_highpc = 0; - highpc_is_relative = 0; - ranges = 0; - have_ranges = 0; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, unit_buf, - u->is_dwarf64, u->version, u->addrsize, - dwarf_str, dwarf_str_size, &val)) - return 0; - - switch (abbrev->attrs[i].name) - { - case DW_AT_low_pc: - if (val.encoding == ATTR_VAL_ADDRESS) - { - lowpc = val.u.uint; - have_lowpc = 1; - } - break; - - case DW_AT_high_pc: - if (val.encoding == ATTR_VAL_ADDRESS) - { - highpc = val.u.uint; - have_highpc = 1; - } - else if (val.encoding == ATTR_VAL_UINT) - { - highpc = val.u.uint; - have_highpc = 1; - highpc_is_relative = 1; - } - break; - - case DW_AT_ranges: - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_SECTION) - { - ranges = val.u.uint; - have_ranges = 1; - } - break; - - case DW_AT_stmt_list: - if (abbrev->tag == DW_TAG_compile_unit - && (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_SECTION)) - u->lineoff = val.u.uint; - break; - - case DW_AT_name: - if (abbrev->tag == DW_TAG_compile_unit - && val.encoding == ATTR_VAL_STRING) - u->filename = val.u.string; - break; - - case DW_AT_comp_dir: - if (abbrev->tag == DW_TAG_compile_unit - && val.encoding == ATTR_VAL_STRING) - u->comp_dir = val.u.string; - break; - - default: - break; - } - } - - if (abbrev->tag == DW_TAG_compile_unit - || abbrev->tag == DW_TAG_subprogram) - { - if (have_ranges) - { - if (!add_unit_ranges (state, base_address, u, ranges, lowpc, - is_bigendian, dwarf_ranges, - dwarf_ranges_size, error_callback, - data, addrs)) - return 0; - } - else if (have_lowpc && have_highpc) - { - struct unit_addrs a; - - if (highpc_is_relative) - highpc += lowpc; - a.low = lowpc; - a.high = highpc; - a.u = u; - - if (!add_unit_addr (state, base_address, a, error_callback, data, - addrs)) - return 0; - } - - /* If we found the PC range in the DW_TAG_compile_unit, we - can stop now. */ - if (abbrev->tag == DW_TAG_compile_unit - && (have_ranges || (have_lowpc && have_highpc))) - return 1; - } - - if (abbrev->has_children) - { - if (!find_address_ranges (state, base_address, unit_buf, - dwarf_str, dwarf_str_size, - dwarf_ranges, dwarf_ranges_size, - is_bigendian, error_callback, data, - u, addrs)) - return 0; - } - } - - return 1; -} - -/* Build a mapping from address ranges to the compilation units where - the line number information for that range can be found. Returns 1 - on success, 0 on failure. */ - -static int -build_address_map (struct backtrace_state *state, uintptr_t base_address, - const unsigned char *dwarf_info, size_t dwarf_info_size, - const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, - const unsigned char *dwarf_str, size_t dwarf_str_size, - int is_bigendian, backtrace_error_callback error_callback, - void *data, struct unit_addrs_vector *addrs) -{ - struct dwarf_buf info; - struct abbrevs abbrevs; - - memset (&addrs->vec, 0, sizeof addrs->vec); - addrs->count = 0; - - /* Read through the .debug_info section. FIXME: Should we use the - .debug_aranges section? gdb and addr2line don't use it, but I'm - not sure why. */ - - info.name = ".debug_info"; - info.start = dwarf_info; - info.buf = dwarf_info; - info.left = dwarf_info_size; - info.is_bigendian = is_bigendian; - info.error_callback = error_callback; - info.data = data; - info.reported_underflow = 0; - - memset (&abbrevs, 0, sizeof abbrevs); - while (info.left > 0) - { - const unsigned char *unit_data_start; - uint64_t len; - int is_dwarf64; - struct dwarf_buf unit_buf; - int version; - uint64_t abbrev_offset; - int addrsize; - struct unit *u; - - if (info.reported_underflow) - goto fail; - - unit_data_start = info.buf; - - is_dwarf64 = 0; - len = read_uint32 (&info); - if (len == 0xffffffff) - { - len = read_uint64 (&info); - is_dwarf64 = 1; - } - - unit_buf = info; - unit_buf.left = len; - - if (!advance (&info, len)) - goto fail; - - version = read_uint16 (&unit_buf); - if (version < 2 || version > 4) - { - dwarf_buf_error (&unit_buf, "unrecognized DWARF version"); - goto fail; - } - - abbrev_offset = read_offset (&unit_buf, is_dwarf64); - if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size, - is_bigendian, error_callback, data, &abbrevs)) - goto fail; - - addrsize = read_byte (&unit_buf); - - u = ((struct unit *) - backtrace_alloc (state, sizeof *u, error_callback, data)); - if (u == NULL) - goto fail; - u->unit_data = unit_buf.buf; - u->unit_data_len = unit_buf.left; - u->unit_data_offset = unit_buf.buf - unit_data_start; - u->version = version; - u->is_dwarf64 = is_dwarf64; - u->addrsize = addrsize; - u->filename = NULL; - u->comp_dir = NULL; - u->abs_filename = NULL; - u->lineoff = 0; - u->abbrevs = abbrevs; - memset (&abbrevs, 0, sizeof abbrevs); - - /* The actual line number mappings will be read as needed. */ - u->lines = NULL; - u->lines_count = 0; - u->function_addrs = NULL; - u->function_addrs_count = 0; - - if (!find_address_ranges (state, base_address, &unit_buf, - dwarf_str, dwarf_str_size, - dwarf_ranges, dwarf_ranges_size, - is_bigendian, error_callback, data, - u, addrs)) - { - free_abbrevs (state, &u->abbrevs, error_callback, data); - backtrace_free (state, u, sizeof *u, error_callback, data); - goto fail; - } - - if (unit_buf.reported_underflow) - { - free_abbrevs (state, &u->abbrevs, error_callback, data); - backtrace_free (state, u, sizeof *u, error_callback, data); - goto fail; - } - } - if (info.reported_underflow) - goto fail; - - return 1; - - fail: - free_abbrevs (state, &abbrevs, error_callback, data); - free_unit_addrs_vector (state, addrs, error_callback, data); - return 0; -} - -/* Add a new mapping to the vector of line mappings that we are - building. Returns 1 on success, 0 on failure. */ - -static int -add_line (struct backtrace_state *state, struct dwarf_data *ddata, - uintptr_t pc, const char *filename, int lineno, - backtrace_error_callback error_callback, void *data, - struct line_vector *vec) -{ - struct line *ln; - - /* If we are adding the same mapping, ignore it. This can happen - when using discriminators. */ - if (vec->count > 0) - { - ln = (struct line *) vec->vec.base + (vec->count - 1); - if (pc == ln->pc && filename == ln->filename && lineno == ln->lineno) - return 1; - } - - ln = ((struct line *) - backtrace_vector_grow (state, sizeof (struct line), error_callback, - data, &vec->vec)); - if (ln == NULL) - return 0; - - /* Add in the base address here, so that we can look up the PC - directly. */ - ln->pc = pc + ddata->base_address; - - ln->filename = filename; - ln->lineno = lineno; - ln->idx = vec->count; - - ++vec->count; - - return 1; -} - -/* Free the line header information. If FREE_FILENAMES is true we - free the file names themselves, otherwise we leave them, as there - may be line structures pointing to them. */ - -static void -free_line_header (struct backtrace_state *state, struct line_header *hdr, - backtrace_error_callback error_callback, void *data) -{ - backtrace_free (state, hdr->dirs, hdr->dirs_count * sizeof (const char *), - error_callback, data); - backtrace_free (state, hdr->filenames, - hdr->filenames_count * sizeof (char *), - error_callback, data); -} - -/* Read the line header. Return 1 on success, 0 on failure. */ - -static int -read_line_header (struct backtrace_state *state, struct unit *u, - int is_dwarf64, struct dwarf_buf *line_buf, - struct line_header *hdr) -{ - uint64_t hdrlen; - struct dwarf_buf hdr_buf; - const unsigned char *p; - const unsigned char *pend; - size_t i; - - hdr->version = read_uint16 (line_buf); - if (hdr->version < 2 || hdr->version > 4) - { - dwarf_buf_error (line_buf, "unsupported line number version"); - return 0; - } - - hdrlen = read_offset (line_buf, is_dwarf64); - - hdr_buf = *line_buf; - hdr_buf.left = hdrlen; - - if (!advance (line_buf, hdrlen)) - return 0; - - hdr->min_insn_len = read_byte (&hdr_buf); - if (hdr->version < 4) - hdr->max_ops_per_insn = 1; - else - hdr->max_ops_per_insn = read_byte (&hdr_buf); - - /* We don't care about default_is_stmt. */ - read_byte (&hdr_buf); - - hdr->line_base = read_sbyte (&hdr_buf); - hdr->line_range = read_byte (&hdr_buf); - - hdr->opcode_base = read_byte (&hdr_buf); - hdr->opcode_lengths = hdr_buf.buf; - if (!advance (&hdr_buf, hdr->opcode_base - 1)) - return 0; - - /* Count the number of directory entries. */ - hdr->dirs_count = 0; - p = hdr_buf.buf; - pend = p + hdr_buf.left; - while (p < pend && *p != '\0') - { - p += strnlen((const char *) p, pend - p) + 1; - ++hdr->dirs_count; - } - - hdr->dirs = ((const char **) - backtrace_alloc (state, - hdr->dirs_count * sizeof (const char *), - line_buf->error_callback, line_buf->data)); - if (hdr->dirs == NULL) - return 0; - - i = 0; - while (*hdr_buf.buf != '\0') - { - if (hdr_buf.reported_underflow) - return 0; - - hdr->dirs[i] = (const char *) hdr_buf.buf; - ++i; - if (!advance (&hdr_buf, - strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1)) - return 0; - } - if (!advance (&hdr_buf, 1)) - return 0; - - /* Count the number of file entries. */ - hdr->filenames_count = 0; - p = hdr_buf.buf; - pend = p + hdr_buf.left; - while (p < pend && *p != '\0') - { - p += strnlen ((const char *) p, pend - p) + 1; - p += leb128_len (p); - p += leb128_len (p); - p += leb128_len (p); - ++hdr->filenames_count; - } - - hdr->filenames = ((const char **) - backtrace_alloc (state, - hdr->filenames_count * sizeof (char *), - line_buf->error_callback, - line_buf->data)); - if (hdr->filenames == NULL) - return 0; - i = 0; - while (*hdr_buf.buf != '\0') - { - const char *filename; - uint64_t dir_index; - - if (hdr_buf.reported_underflow) - return 0; - - filename = (const char *) hdr_buf.buf; - if (!advance (&hdr_buf, - strnlen ((const char *) hdr_buf.buf, hdr_buf.left) + 1)) - return 0; - dir_index = read_uleb128 (&hdr_buf); - if (IS_ABSOLUTE_PATH (filename) - || (dir_index == 0 && u->comp_dir == NULL)) - hdr->filenames[i] = filename; - else - { - const char *dir; - size_t dir_len; - size_t filename_len; - char *s; - - if (dir_index == 0) - dir = u->comp_dir; - else if (dir_index - 1 < hdr->dirs_count) - dir = hdr->dirs[dir_index - 1]; - else - { - dwarf_buf_error (line_buf, - ("invalid directory index in " - "line number program header")); - return 0; - } - dir_len = strlen (dir); - filename_len = strlen (filename); - s = ((char *) - backtrace_alloc (state, dir_len + filename_len + 2, - line_buf->error_callback, line_buf->data)); - if (s == NULL) - return 0; - memcpy (s, dir, dir_len); - /* FIXME: If we are on a DOS-based file system, and the - directory or the file name use backslashes, then we - should use a backslash here. */ - s[dir_len] = '/'; - memcpy (s + dir_len + 1, filename, filename_len + 1); - hdr->filenames[i] = s; - } - - /* Ignore the modification time and size. */ - read_uleb128 (&hdr_buf); - read_uleb128 (&hdr_buf); - - ++i; - } - - if (hdr_buf.reported_underflow) - return 0; - - return 1; -} - -/* Read the line program, adding line mappings to VEC. Return 1 on - success, 0 on failure. */ - -static int -read_line_program (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, const struct line_header *hdr, - struct dwarf_buf *line_buf, struct line_vector *vec) -{ - uint64_t address; - unsigned int op_index; - const char *reset_filename; - const char *filename; - int lineno; - - address = 0; - op_index = 0; - if (hdr->filenames_count > 0) - reset_filename = hdr->filenames[0]; - else - reset_filename = ""; - filename = reset_filename; - lineno = 1; - while (line_buf->left > 0) - { - unsigned int op; - - op = read_byte (line_buf); - if (op >= hdr->opcode_base) - { - unsigned int advance; - - /* Special opcode. */ - op -= hdr->opcode_base; - advance = op / hdr->line_range; - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - lineno += hdr->line_base + (int) (op % hdr->line_range); - add_line (state, ddata, address, filename, lineno, - line_buf->error_callback, line_buf->data, vec); - } - else if (op == DW_LNS_extended_op) - { - uint64_t len; - - len = read_uleb128 (line_buf); - op = read_byte (line_buf); - switch (op) - { - case DW_LNE_end_sequence: - /* FIXME: Should we mark the high PC here? It seems - that we already have that information from the - compilation unit. */ - address = 0; - op_index = 0; - filename = reset_filename; - lineno = 1; - break; - case DW_LNE_set_address: - address = read_address (line_buf, u->addrsize); - break; - case DW_LNE_define_file: - { - const char *f; - unsigned int dir_index; - - f = (const char *) line_buf->buf; - if (!advance (line_buf, strnlen (f, line_buf->left) + 1)) - return 0; - dir_index = read_uleb128 (line_buf); - /* Ignore that time and length. */ - read_uleb128 (line_buf); - read_uleb128 (line_buf); - if (IS_ABSOLUTE_PATH (f)) - filename = f; - else - { - const char *dir; - size_t dir_len; - size_t f_len; - char *p; - - if (dir_index == 0) - dir = u->comp_dir; - else if (dir_index - 1 < hdr->dirs_count) - dir = hdr->dirs[dir_index - 1]; - else - { - dwarf_buf_error (line_buf, - ("invalid directory index " - "in line number program")); - return 0; - } - dir_len = strlen (dir); - f_len = strlen (f); - p = ((char *) - backtrace_alloc (state, dir_len + f_len + 2, - line_buf->error_callback, - line_buf->data)); - if (p == NULL) - return 0; - memcpy (p, dir, dir_len); - /* FIXME: If we are on a DOS-based file system, - and the directory or the file name use - backslashes, then we should use a backslash - here. */ - p[dir_len] = '/'; - memcpy (p + dir_len + 1, f, f_len + 1); - filename = p; - } - } - break; - case DW_LNE_set_discriminator: - /* We don't care about discriminators. */ - read_uleb128 (line_buf); - break; - default: - if (!advance (line_buf, len - 1)) - return 0; - break; - } - } - else - { - switch (op) - { - case DW_LNS_copy: - add_line (state, ddata, address, filename, lineno, - line_buf->error_callback, line_buf->data, vec); - break; - case DW_LNS_advance_pc: - { - uint64_t advance; - - advance = read_uleb128 (line_buf); - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - } - break; - case DW_LNS_advance_line: - lineno += (int) read_sleb128 (line_buf); - break; - case DW_LNS_set_file: - { - uint64_t fileno; - - fileno = read_uleb128 (line_buf); - if (fileno == 0) - filename = ""; - else - { - if (fileno - 1 >= hdr->filenames_count) - { - dwarf_buf_error (line_buf, - ("invalid file number in " - "line number program")); - return 0; - } - filename = hdr->filenames[fileno - 1]; - } - } - break; - case DW_LNS_set_column: - read_uleb128 (line_buf); - break; - case DW_LNS_negate_stmt: - break; - case DW_LNS_set_basic_block: - break; - case DW_LNS_const_add_pc: - { - unsigned int advance; - - op = 255 - hdr->opcode_base; - advance = op / hdr->line_range; - address += (hdr->min_insn_len * (op_index + advance) - / hdr->max_ops_per_insn); - op_index = (op_index + advance) % hdr->max_ops_per_insn; - } - break; - case DW_LNS_fixed_advance_pc: - address += read_uint16 (line_buf); - op_index = 0; - break; - case DW_LNS_set_prologue_end: - break; - case DW_LNS_set_epilogue_begin: - break; - case DW_LNS_set_isa: - read_uleb128 (line_buf); - break; - default: - { - unsigned int i; - - for (i = hdr->opcode_lengths[op - 1]; i > 0; --i) - read_uleb128 (line_buf); - } - break; - } - } - } - - return 1; -} - -/* Read the line number information for a compilation unit. Returns 1 - on success, 0 on failure. */ - -static int -read_line_info (struct backtrace_state *state, struct dwarf_data *ddata, - backtrace_error_callback error_callback, void *data, - struct unit *u, struct line_header *hdr, struct line **lines, - size_t *lines_count) -{ - struct line_vector vec; - struct dwarf_buf line_buf; - uint64_t len; - int is_dwarf64; - struct line *ln; - - memset (&vec.vec, 0, sizeof vec.vec); - vec.count = 0; - - memset (hdr, 0, sizeof *hdr); - - if (u->lineoff != (off_t) (size_t) u->lineoff - || (size_t) u->lineoff >= ddata->dwarf_line_size) - { - error_callback (data, "unit line offset out of range", 0); - goto fail; - } - - line_buf.name = ".debug_line"; - line_buf.start = ddata->dwarf_line; - line_buf.buf = ddata->dwarf_line + u->lineoff; - line_buf.left = ddata->dwarf_line_size - u->lineoff; - line_buf.is_bigendian = ddata->is_bigendian; - line_buf.error_callback = error_callback; - line_buf.data = data; - line_buf.reported_underflow = 0; - - is_dwarf64 = 0; - len = read_uint32 (&line_buf); - if (len == 0xffffffff) - { - len = read_uint64 (&line_buf); - is_dwarf64 = 1; - } - line_buf.left = len; - - if (!read_line_header (state, u, is_dwarf64, &line_buf, hdr)) - goto fail; - - if (!read_line_program (state, ddata, u, hdr, &line_buf, &vec)) - goto fail; - - if (line_buf.reported_underflow) - goto fail; - - if (vec.count == 0) - { - /* This is not a failure in the sense of a generating an error, - but it is a failure in that sense that we have no useful - information. */ - goto fail; - } - - /* Allocate one extra entry at the end. */ - ln = ((struct line *) - backtrace_vector_grow (state, sizeof (struct line), error_callback, - data, &vec.vec)); - if (ln == NULL) - goto fail; - ln->pc = (uintptr_t) -1; - ln->filename = NULL; - ln->lineno = 0; - ln->idx = 0; - - if (!backtrace_vector_release (state, &vec.vec, error_callback, data)) - goto fail; - - ln = (struct line *) vec.vec.base; - backtrace_qsort (ln, vec.count, sizeof (struct line), line_compare); - - *lines = ln; - *lines_count = vec.count; - - return 1; - - fail: - vec.vec.alc += vec.vec.size; - vec.vec.size = 0; - backtrace_vector_release (state, &vec.vec, error_callback, data); - free_line_header (state, hdr, error_callback, data); - *lines = (struct line *) (uintptr_t) -1; - *lines_count = 0; - return 0; -} - -/* Read the name of a function from a DIE referenced by a - DW_AT_abstract_origin or DW_AT_specification tag. OFFSET is within - the same compilation unit. */ - -static const char * -read_referenced_name (struct dwarf_data *ddata, struct unit *u, - uint64_t offset, backtrace_error_callback error_callback, - void *data) -{ - struct dwarf_buf unit_buf; - uint64_t code; - const struct abbrev *abbrev; - const char *ret; - size_t i; - - /* OFFSET is from the start of the data for this compilation unit. - U->unit_data is the data, but it starts U->unit_data_offset bytes - from the beginning. */ - - if (offset < u->unit_data_offset - || offset - u->unit_data_offset >= u->unit_data_len) - { - error_callback (data, - "abstract origin or specification out of range", - 0); - return NULL; - } - - offset -= u->unit_data_offset; - - unit_buf.name = ".debug_info"; - unit_buf.start = ddata->dwarf_info; - unit_buf.buf = u->unit_data + offset; - unit_buf.left = u->unit_data_len - offset; - unit_buf.is_bigendian = ddata->is_bigendian; - unit_buf.error_callback = error_callback; - unit_buf.data = data; - unit_buf.reported_underflow = 0; - - code = read_uleb128 (&unit_buf); - if (code == 0) - { - dwarf_buf_error (&unit_buf, "invalid abstract origin or specification"); - return NULL; - } - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return NULL; - - ret = NULL; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, &unit_buf, - u->is_dwarf64, u->version, u->addrsize, - ddata->dwarf_str, ddata->dwarf_str_size, - &val)) - return NULL; - - switch (abbrev->attrs[i].name) - { - case DW_AT_name: - /* We prefer the linkage name if get one. */ - if (val.encoding == ATTR_VAL_STRING) - ret = val.u.string; - break; - - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - if (val.encoding == ATTR_VAL_STRING) - return val.u.string; - break; - - case DW_AT_specification: - if (abbrev->attrs[i].form == DW_FORM_ref_addr - || abbrev->attrs[i].form == DW_FORM_ref_sig8) - { - /* This refers to a specification defined in some other - compilation unit. We can handle this case if we - must, but it's harder. */ - break; - } - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_UNIT) - { - const char *name; - - name = read_referenced_name (ddata, u, val.u.uint, - error_callback, data); - if (name != NULL) - ret = name; - } - break; - - default: - break; - } - } - - return ret; -} - -/* Add a single range to U that maps to function. Returns 1 on - success, 0 on error. */ - -static int -add_function_range (struct backtrace_state *state, struct dwarf_data *ddata, - struct function *function, uint64_t lowpc, uint64_t highpc, - backtrace_error_callback error_callback, - void *data, struct function_vector *vec) -{ - struct function_addrs *p; - - /* Add in the base address here, so that we can look up the PC - directly. */ - lowpc += ddata->base_address; - highpc += ddata->base_address; - - if (vec->count > 0) - { - p = (struct function_addrs *) vec->vec.base + vec->count - 1; - if ((lowpc == p->high || lowpc == p->high + 1) - && function == p->function) - { - if (highpc > p->high) - p->high = highpc; - return 1; - } - } - - p = ((struct function_addrs *) - backtrace_vector_grow (state, sizeof (struct function_addrs), - error_callback, data, &vec->vec)); - if (p == NULL) - return 0; - - p->low = lowpc; - p->high = highpc; - p->function = function; - ++vec->count; - return 1; -} - -/* Add PC ranges to U that map to FUNCTION. Returns 1 on success, 0 - on error. */ - -static int -add_function_ranges (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, struct function *function, - uint64_t ranges, uint64_t base, - backtrace_error_callback error_callback, void *data, - struct function_vector *vec) -{ - struct dwarf_buf ranges_buf; - - if (ranges >= ddata->dwarf_ranges_size) - { - error_callback (data, "function ranges offset out of range", 0); - return 0; - } - - ranges_buf.name = ".debug_ranges"; - ranges_buf.start = ddata->dwarf_ranges; - ranges_buf.buf = ddata->dwarf_ranges + ranges; - ranges_buf.left = ddata->dwarf_ranges_size - ranges; - ranges_buf.is_bigendian = ddata->is_bigendian; - ranges_buf.error_callback = error_callback; - ranges_buf.data = data; - ranges_buf.reported_underflow = 0; - - while (1) - { - uint64_t low; - uint64_t high; - - if (ranges_buf.reported_underflow) - return 0; - - low = read_address (&ranges_buf, u->addrsize); - high = read_address (&ranges_buf, u->addrsize); - - if (low == 0 && high == 0) - break; - - if (is_highest_address (low, u->addrsize)) - base = high; - else - { - if (!add_function_range (state, ddata, function, low + base, - high + base, error_callback, data, vec)) - return 0; - } - } - - if (ranges_buf.reported_underflow) - return 0; - - return 1; -} - -/* Read one entry plus all its children. Add function addresses to - VEC. Returns 1 on success, 0 on error. */ - -static int -read_function_entry (struct backtrace_state *state, struct dwarf_data *ddata, - struct unit *u, uint64_t base, struct dwarf_buf *unit_buf, - const struct line_header *lhdr, - backtrace_error_callback error_callback, void *data, - struct function_vector *vec_function, - struct function_vector *vec_inlined) -{ - while (unit_buf->left > 0) - { - uint64_t code; - const struct abbrev *abbrev; - int is_function; - struct function *function; - struct function_vector *vec; - size_t i; - uint64_t lowpc; - int have_lowpc; - uint64_t highpc; - int have_highpc; - int highpc_is_relative; - uint64_t ranges; - int have_ranges; - - code = read_uleb128 (unit_buf); - if (code == 0) - return 1; - - abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data); - if (abbrev == NULL) - return 0; - - is_function = (abbrev->tag == DW_TAG_subprogram - || abbrev->tag == DW_TAG_entry_point - || abbrev->tag == DW_TAG_inlined_subroutine); - - if (abbrev->tag == DW_TAG_inlined_subroutine) - vec = vec_inlined; - else - vec = vec_function; - - function = NULL; - if (is_function) - { - function = ((struct function *) - backtrace_alloc (state, sizeof *function, - error_callback, data)); - if (function == NULL) - return 0; - memset (function, 0, sizeof *function); - } - - lowpc = 0; - have_lowpc = 0; - highpc = 0; - have_highpc = 0; - highpc_is_relative = 0; - ranges = 0; - have_ranges = 0; - for (i = 0; i < abbrev->num_attrs; ++i) - { - struct attr_val val; - - if (!read_attribute (abbrev->attrs[i].form, unit_buf, - u->is_dwarf64, u->version, u->addrsize, - ddata->dwarf_str, ddata->dwarf_str_size, - &val)) - return 0; - - /* The compile unit sets the base address for any address - ranges in the function entries. */ - if (abbrev->tag == DW_TAG_compile_unit - && abbrev->attrs[i].name == DW_AT_low_pc - && val.encoding == ATTR_VAL_ADDRESS) - base = val.u.uint; - - if (is_function) - { - switch (abbrev->attrs[i].name) - { - case DW_AT_call_file: - if (val.encoding == ATTR_VAL_UINT) - { - if (val.u.uint == 0) - function->caller_filename = ""; - else - { - if (val.u.uint - 1 >= lhdr->filenames_count) - { - dwarf_buf_error (unit_buf, - ("invalid file number in " - "DW_AT_call_file attribute")); - return 0; - } - function->caller_filename = - lhdr->filenames[val.u.uint - 1]; - } - } - break; - - case DW_AT_call_line: - if (val.encoding == ATTR_VAL_UINT) - function->caller_lineno = val.u.uint; - break; - - case DW_AT_abstract_origin: - case DW_AT_specification: - if (abbrev->attrs[i].form == DW_FORM_ref_addr - || abbrev->attrs[i].form == DW_FORM_ref_sig8) - { - /* This refers to an abstract origin defined in - some other compilation unit. We can handle - this case if we must, but it's harder. */ - break; - } - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_UNIT) - { - const char *name; - - name = read_referenced_name (ddata, u, val.u.uint, - error_callback, data); - if (name != NULL) - function->name = name; - } - break; - - case DW_AT_name: - if (val.encoding == ATTR_VAL_STRING) - { - /* Don't override a name we found in some other - way, as it will normally be more - useful--e.g., this name is normally not - mangled. */ - if (function->name == NULL) - function->name = val.u.string; - } - break; - - case DW_AT_linkage_name: - case DW_AT_MIPS_linkage_name: - if (val.encoding == ATTR_VAL_STRING) - function->name = val.u.string; - break; - - case DW_AT_low_pc: - if (val.encoding == ATTR_VAL_ADDRESS) - { - lowpc = val.u.uint; - have_lowpc = 1; - } - break; - - case DW_AT_high_pc: - if (val.encoding == ATTR_VAL_ADDRESS) - { - highpc = val.u.uint; - have_highpc = 1; - } - else if (val.encoding == ATTR_VAL_UINT) - { - highpc = val.u.uint; - have_highpc = 1; - highpc_is_relative = 1; - } - break; - - case DW_AT_ranges: - if (val.encoding == ATTR_VAL_UINT - || val.encoding == ATTR_VAL_REF_SECTION) - { - ranges = val.u.uint; - have_ranges = 1; - } - break; - - default: - break; - } - } - } - - /* If we couldn't find a name for the function, we have no use - for it. */ - if (is_function && function->name == NULL) - { - backtrace_free (state, function, sizeof *function, - error_callback, data); - is_function = 0; - } - - if (is_function) - { - if (have_ranges) - { - if (!add_function_ranges (state, ddata, u, function, ranges, - base, error_callback, data, vec)) - return 0; - } - else if (have_lowpc && have_highpc) - { - if (highpc_is_relative) - highpc += lowpc; - if (!add_function_range (state, ddata, function, lowpc, highpc, - error_callback, data, vec)) - return 0; - } - else - { - backtrace_free (state, function, sizeof *function, - error_callback, data); - is_function = 0; - } - } - - if (abbrev->has_children) - { - if (!is_function) - { - if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, - error_callback, data, vec_function, - vec_inlined)) - return 0; - } - else - { - struct function_vector fvec; - - /* Gather any information for inlined functions in - FVEC. */ - - memset (&fvec, 0, sizeof fvec); - - if (!read_function_entry (state, ddata, u, base, unit_buf, lhdr, - error_callback, data, vec_function, - &fvec)) - return 0; - - if (fvec.count > 0) - { - struct function_addrs *faddrs; - - if (!backtrace_vector_release (state, &fvec.vec, - error_callback, data)) - return 0; - - faddrs = (struct function_addrs *) fvec.vec.base; - backtrace_qsort (faddrs, fvec.count, - sizeof (struct function_addrs), - function_addrs_compare); - - function->function_addrs = faddrs; - function->function_addrs_count = fvec.count; - } - } - } - } - - return 1; -} - -/* Read function name information for a compilation unit. We look - through the whole unit looking for function tags. */ - -static void -read_function_info (struct backtrace_state *state, struct dwarf_data *ddata, - const struct line_header *lhdr, - backtrace_error_callback error_callback, void *data, - struct unit *u, struct function_vector *fvec, - struct function_addrs **ret_addrs, - size_t *ret_addrs_count) -{ - struct function_vector lvec; - struct function_vector *pfvec; - struct dwarf_buf unit_buf; - struct function_addrs *addrs; - size_t addrs_count; - - /* Use FVEC if it is not NULL. Otherwise use our own vector. */ - if (fvec != NULL) - pfvec = fvec; - else - { - memset (&lvec, 0, sizeof lvec); - pfvec = &lvec; - } - - unit_buf.name = ".debug_info"; - unit_buf.start = ddata->dwarf_info; - unit_buf.buf = u->unit_data; - unit_buf.left = u->unit_data_len; - unit_buf.is_bigendian = ddata->is_bigendian; - unit_buf.error_callback = error_callback; - unit_buf.data = data; - unit_buf.reported_underflow = 0; - - while (unit_buf.left > 0) - { - if (!read_function_entry (state, ddata, u, 0, &unit_buf, lhdr, - error_callback, data, pfvec, pfvec)) - return; - } - - if (pfvec->count == 0) - return; - - addrs_count = pfvec->count; - - if (fvec == NULL) - { - if (!backtrace_vector_release (state, &lvec.vec, error_callback, data)) - return; - addrs = (struct function_addrs *) pfvec->vec.base; - } - else - { - /* Finish this list of addresses, but leave the remaining space in - the vector available for the next function unit. */ - addrs = ((struct function_addrs *) - backtrace_vector_finish (state, &fvec->vec, - error_callback, data)); - if (addrs == NULL) - return; - fvec->count = 0; - } - - backtrace_qsort (addrs, addrs_count, sizeof (struct function_addrs), - function_addrs_compare); - - *ret_addrs = addrs; - *ret_addrs_count = addrs_count; -} - -/* See if PC is inlined in FUNCTION. If it is, print out the inlined - information, and update FILENAME and LINENO for the caller. - Returns whatever CALLBACK returns, or 0 to keep going. */ - -static int -report_inlined_functions (uintptr_t pc, struct function *function, - backtrace_full_callback callback, void *data, - const char **filename, int *lineno) -{ - struct function_addrs *function_addrs; - struct function *inlined; - int ret; - - if (function->function_addrs_count == 0) - return 0; - - function_addrs = ((struct function_addrs *) - bsearch (&pc, function->function_addrs, - function->function_addrs_count, - sizeof (struct function_addrs), - function_addrs_search)); - if (function_addrs == NULL) - return 0; - - while (((size_t) (function_addrs - function->function_addrs) + 1 - < function->function_addrs_count) - && pc >= (function_addrs + 1)->low - && pc < (function_addrs + 1)->high) - ++function_addrs; - - /* We found an inlined call. */ - - inlined = function_addrs->function; - - /* Report any calls inlined into this one. */ - ret = report_inlined_functions (pc, inlined, callback, data, - filename, lineno); - if (ret != 0) - return ret; - - /* Report this inlined call. */ - ret = callback (data, pc, *filename, *lineno, inlined->name); - if (ret != 0) - return ret; - - /* Our caller will report the caller of the inlined function; tell - it the appropriate filename and line number. */ - *filename = inlined->caller_filename; - *lineno = inlined->caller_lineno; - - return 0; -} - -/* Look for a PC in the DWARF mapping for one module. On success, - call CALLBACK and return whatever it returns. On error, call - ERROR_CALLBACK and return 0. Sets *FOUND to 1 if the PC is found, - 0 if not. */ - -static int -dwarf_lookup_pc (struct backtrace_state *state, struct dwarf_data *ddata, - uintptr_t pc, backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data, - int *found) -{ - struct unit_addrs *entry; - struct unit *u; - int new_data; - struct line *lines; - struct line *ln; - struct function_addrs *function_addrs; - struct function *function; - const char *filename; - int lineno; - int ret; - - *found = 1; - - /* Find an address range that includes PC. */ - entry = bsearch (&pc, ddata->addrs, ddata->addrs_count, - sizeof (struct unit_addrs), unit_addrs_search); - - if (entry == NULL) - { - *found = 0; - return 0; - } - - /* If there are multiple ranges that contain PC, use the last one, - in order to produce predictable results. If we assume that all - ranges are properly nested, then the last range will be the - smallest one. */ - while ((size_t) (entry - ddata->addrs) + 1 < ddata->addrs_count - && pc >= (entry + 1)->low - && pc < (entry + 1)->high) - ++entry; - - /* We need the lines, lines_count, function_addrs, - function_addrs_count fields of u. If they are not set, we need - to set them. When running in threaded mode, we need to allow for - the possibility that some other thread is setting them - simultaneously. */ - - u = entry->u; - lines = u->lines; - - /* Skip units with no useful line number information by walking - backward. Useless line number information is marked by setting - lines == -1. */ - while (entry > ddata->addrs - && pc >= (entry - 1)->low - && pc < (entry - 1)->high) - { - if (state->threaded) - lines = (struct line *) backtrace_atomic_load_pointer (&u->lines); - - if (lines != (struct line *) (uintptr_t) -1) - break; - - --entry; - - u = entry->u; - lines = u->lines; - } - - if (state->threaded) - lines = backtrace_atomic_load_pointer (&u->lines); - - new_data = 0; - if (lines == NULL) - { - size_t function_addrs_count; - struct line_header lhdr; - size_t count; - - /* We have never read the line information for this unit. Read - it now. */ - - function_addrs = NULL; - function_addrs_count = 0; - if (read_line_info (state, ddata, error_callback, data, entry->u, &lhdr, - &lines, &count)) - { - struct function_vector *pfvec; - - /* If not threaded, reuse DDATA->FVEC for better memory - consumption. */ - if (state->threaded) - pfvec = NULL; - else - pfvec = &ddata->fvec; - read_function_info (state, ddata, &lhdr, error_callback, data, - entry->u, pfvec, &function_addrs, - &function_addrs_count); - free_line_header (state, &lhdr, error_callback, data); - new_data = 1; - } - - /* Atomically store the information we just read into the unit. - If another thread is simultaneously writing, it presumably - read the same information, and we don't care which one we - wind up with; we just leak the other one. We do have to - write the lines field last, so that the acquire-loads above - ensure that the other fields are set. */ - - if (!state->threaded) - { - u->lines_count = count; - u->function_addrs = function_addrs; - u->function_addrs_count = function_addrs_count; - u->lines = lines; - } - else - { - backtrace_atomic_store_size_t (&u->lines_count, count); - backtrace_atomic_store_pointer (&u->function_addrs, function_addrs); - backtrace_atomic_store_size_t (&u->function_addrs_count, - function_addrs_count); - backtrace_atomic_store_pointer (&u->lines, lines); - } - } - - /* Now all fields of U have been initialized. */ - - if (lines == (struct line *) (uintptr_t) -1) - { - /* If reading the line number information failed in some way, - try again to see if there is a better compilation unit for - this PC. */ - if (new_data) - return dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, found); - return callback (data, pc, NULL, 0, NULL); - } - - /* Search for PC within this unit. */ - - ln = (struct line *) bsearch (&pc, lines, entry->u->lines_count, - sizeof (struct line), line_search); - if (ln == NULL) - { - /* The PC is between the low_pc and high_pc attributes of the - compilation unit, but no entry in the line table covers it. - This implies that the start of the compilation unit has no - line number information. */ - - if (entry->u->abs_filename == NULL) - { - const char *filename; - - filename = entry->u->filename; - if (filename != NULL - && !IS_ABSOLUTE_PATH (filename) - && entry->u->comp_dir != NULL) - { - size_t filename_len; - const char *dir; - size_t dir_len; - char *s; - - filename_len = strlen (filename); - dir = entry->u->comp_dir; - dir_len = strlen (dir); - s = (char *) backtrace_alloc (state, dir_len + filename_len + 2, - error_callback, data); - if (s == NULL) - { - *found = 0; - return 0; - } - memcpy (s, dir, dir_len); - /* FIXME: Should use backslash if DOS file system. */ - s[dir_len] = '/'; - memcpy (s + dir_len + 1, filename, filename_len + 1); - filename = s; - } - entry->u->abs_filename = filename; - } - - return callback (data, pc, entry->u->abs_filename, 0, NULL); - } - - /* Search for function name within this unit. */ - - if (entry->u->function_addrs_count == 0) - return callback (data, pc, ln->filename, ln->lineno, NULL); - - function_addrs = ((struct function_addrs *) - bsearch (&pc, entry->u->function_addrs, - entry->u->function_addrs_count, - sizeof (struct function_addrs), - function_addrs_search)); - if (function_addrs == NULL) - return callback (data, pc, ln->filename, ln->lineno, NULL); - - /* If there are multiple function ranges that contain PC, use the - last one, in order to produce predictable results. */ - - while (((size_t) (function_addrs - entry->u->function_addrs + 1) - < entry->u->function_addrs_count) - && pc >= (function_addrs + 1)->low - && pc < (function_addrs + 1)->high) - ++function_addrs; - - function = function_addrs->function; - - filename = ln->filename; - lineno = ln->lineno; - - ret = report_inlined_functions (pc, function, callback, data, - &filename, &lineno); - if (ret != 0) - return ret; - - return callback (data, pc, filename, lineno, function->name); -} - - -/* Return the file/line information for a PC using the DWARF mapping - we built earlier. */ - -static int -dwarf_fileline (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct dwarf_data *ddata; - int found; - int ret; - - if (!state->threaded) - { - for (ddata = (struct dwarf_data *) state->fileline_data; - ddata != NULL; - ddata = ddata->next) - { - ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, &found); - if (ret != 0 || found) - return ret; - } - } - else - { - struct dwarf_data **pp; - - pp = (struct dwarf_data **) (void *) &state->fileline_data; - while (1) - { - ddata = backtrace_atomic_load_pointer (pp); - if (ddata == NULL) - break; - - ret = dwarf_lookup_pc (state, ddata, pc, callback, error_callback, - data, &found); - if (ret != 0 || found) - return ret; - - pp = &ddata->next; - } - } - - /* FIXME: See if any libraries have been dlopen'ed. */ - - return callback (data, pc, NULL, 0, NULL); -} - -/* Initialize our data structures from the DWARF debug info for a - file. Return NULL on failure. */ - -static struct dwarf_data * -build_dwarf_data (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char *dwarf_info, - size_t dwarf_info_size, - const unsigned char *dwarf_line, - size_t dwarf_line_size, - const unsigned char *dwarf_abbrev, - size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, - size_t dwarf_ranges_size, - const unsigned char *dwarf_str, - size_t dwarf_str_size, - int is_bigendian, - backtrace_error_callback error_callback, - void *data) -{ - struct unit_addrs_vector addrs_vec; - struct unit_addrs *addrs; - size_t addrs_count; - struct dwarf_data *fdata; - - if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size, - dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges, - dwarf_ranges_size, dwarf_str, dwarf_str_size, - is_bigendian, error_callback, data, &addrs_vec)) - return NULL; - - if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data)) - return NULL; - addrs = (struct unit_addrs *) addrs_vec.vec.base; - addrs_count = addrs_vec.count; - backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), - unit_addrs_compare); - - fdata = ((struct dwarf_data *) - backtrace_alloc (state, sizeof (struct dwarf_data), - error_callback, data)); - if (fdata == NULL) - return NULL; - - fdata->next = NULL; - fdata->base_address = base_address; - fdata->addrs = addrs; - fdata->addrs_count = addrs_count; - fdata->dwarf_info = dwarf_info; - fdata->dwarf_info_size = dwarf_info_size; - fdata->dwarf_line = dwarf_line; - fdata->dwarf_line_size = dwarf_line_size; - fdata->dwarf_ranges = dwarf_ranges; - fdata->dwarf_ranges_size = dwarf_ranges_size; - fdata->dwarf_str = dwarf_str; - fdata->dwarf_str_size = dwarf_str_size; - fdata->is_bigendian = is_bigendian; - memset (&fdata->fvec, 0, sizeof fdata->fvec); - - return fdata; -} - -/* Build our data structures from the DWARF sections for a module. - Set FILELINE_FN and STATE->FILELINE_DATA. Return 1 on success, 0 - on failure. */ - -int -backtrace_dwarf_add (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char *dwarf_info, - size_t dwarf_info_size, - const unsigned char *dwarf_line, - size_t dwarf_line_size, - const unsigned char *dwarf_abbrev, - size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, - size_t dwarf_ranges_size, - const unsigned char *dwarf_str, - size_t dwarf_str_size, - int is_bigendian, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn) -{ - struct dwarf_data *fdata; - - fdata = build_dwarf_data (state, base_address, dwarf_info, dwarf_info_size, - dwarf_line, dwarf_line_size, dwarf_abbrev, - dwarf_abbrev_size, dwarf_ranges, dwarf_ranges_size, - dwarf_str, dwarf_str_size, is_bigendian, - error_callback, data); - if (fdata == NULL) - return 0; - - if (!state->threaded) - { - struct dwarf_data **pp; - - for (pp = (struct dwarf_data **) (void *) &state->fileline_data; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = fdata; - } - else - { - while (1) - { - struct dwarf_data **pp; - - pp = (struct dwarf_data **) (void *) &state->fileline_data; - - while (1) - { - struct dwarf_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, fdata)) - break; - } - } - - *fileline_fn = dwarf_fileline; - - return 1; -} diff --git a/src/libbacktrace/dwarf2.def b/src/libbacktrace/dwarf2.def deleted file mode 100644 index 2dfee5666dea6..0000000000000 --- a/src/libbacktrace/dwarf2.def +++ /dev/null @@ -1,713 +0,0 @@ -/* -*- c -*- - Declarations and definitions of codes relating to the DWARF2 and - DWARF3 symbolic debugging information formats. - Copyright (C) 1992-2015 Free Software Foundation, Inc. - - Written by Gary Funck (gary@intrepid.com) The Ada Joint Program - Office (AJPO), Florida State University and Silicon Graphics Inc. - provided support for this effort -- June 21, 1995. - - Derived from the DWARF 1 implementation written by Ron Guilmette - (rfg@netcom.com), November 1990. - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 3, or (at your option) any later - version. - - GCC is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* This file is derived from the DWARF specification (a public document) - Revision 2.0.0 (July 27, 1993) developed by the UNIX International - Programming Languages Special Interest Group (UI/PLSIG) and distributed - by UNIX International. Copies of this specification are available from - UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. - - This file also now contains definitions from the DWARF 3 specification - published Dec 20, 2005, available from: http://dwarf.freestandards.org. - - This file also now contains definitions from the DWARF 4 - specification, available from: http://dwarfstd.org/ */ - -/* This file declares various DWARF-related constants using a set of - macros which can be redefined by the including file. - - The macros are in sections. Each section corresponds to a single - set of DWARF constants and has a corresponding key. The key is - used in all the macro names. - - The sections are TAG (for DW_TAG_ constants), FORM (DW_FORM_), AT - (DW_AT_), OP (DW_OP_), ATE (DW_ATE_), and CFA (DW_CFA_). - - Using TAG as an example, the following macros may be used for each - key: - - DW_FIRST_TAG(name, value) - Introduce the first DW_TAG constant. - - DW_TAG(name, value) - Define a subsequent constant. - - DW_TAG_DUP(name, value) - Define a subsequent constant whose value - is a duplicate of some other constant. Not all keys use the _DUP - macro form. If more than one name shares a value, then the base - (DW_TAG) form will be the preferred name and DW_TAG_DUP will hold - any alternate names. - - DW_END_TAG - Invoked at the end of the DW_TAG constants. */ - -DW_FIRST_TAG (DW_TAG_padding, 0x00) -DW_TAG (DW_TAG_array_type, 0x01) -DW_TAG (DW_TAG_class_type, 0x02) -DW_TAG (DW_TAG_entry_point, 0x03) -DW_TAG (DW_TAG_enumeration_type, 0x04) -DW_TAG (DW_TAG_formal_parameter, 0x05) -DW_TAG (DW_TAG_imported_declaration, 0x08) -DW_TAG (DW_TAG_label, 0x0a) -DW_TAG (DW_TAG_lexical_block, 0x0b) -DW_TAG (DW_TAG_member, 0x0d) -DW_TAG (DW_TAG_pointer_type, 0x0f) -DW_TAG (DW_TAG_reference_type, 0x10) -DW_TAG (DW_TAG_compile_unit, 0x11) -DW_TAG (DW_TAG_string_type, 0x12) -DW_TAG (DW_TAG_structure_type, 0x13) -DW_TAG (DW_TAG_subroutine_type, 0x15) -DW_TAG (DW_TAG_typedef, 0x16) -DW_TAG (DW_TAG_union_type, 0x17) -DW_TAG (DW_TAG_unspecified_parameters, 0x18) -DW_TAG (DW_TAG_variant, 0x19) -DW_TAG (DW_TAG_common_block, 0x1a) -DW_TAG (DW_TAG_common_inclusion, 0x1b) -DW_TAG (DW_TAG_inheritance, 0x1c) -DW_TAG (DW_TAG_inlined_subroutine, 0x1d) -DW_TAG (DW_TAG_module, 0x1e) -DW_TAG (DW_TAG_ptr_to_member_type, 0x1f) -DW_TAG (DW_TAG_set_type, 0x20) -DW_TAG (DW_TAG_subrange_type, 0x21) -DW_TAG (DW_TAG_with_stmt, 0x22) -DW_TAG (DW_TAG_access_declaration, 0x23) -DW_TAG (DW_TAG_base_type, 0x24) -DW_TAG (DW_TAG_catch_block, 0x25) -DW_TAG (DW_TAG_const_type, 0x26) -DW_TAG (DW_TAG_constant, 0x27) -DW_TAG (DW_TAG_enumerator, 0x28) -DW_TAG (DW_TAG_file_type, 0x29) -DW_TAG (DW_TAG_friend, 0x2a) -DW_TAG (DW_TAG_namelist, 0x2b) -DW_TAG (DW_TAG_namelist_item, 0x2c) -DW_TAG (DW_TAG_packed_type, 0x2d) -DW_TAG (DW_TAG_subprogram, 0x2e) -DW_TAG (DW_TAG_template_type_param, 0x2f) -DW_TAG (DW_TAG_template_value_param, 0x30) -DW_TAG (DW_TAG_thrown_type, 0x31) -DW_TAG (DW_TAG_try_block, 0x32) -DW_TAG (DW_TAG_variant_part, 0x33) -DW_TAG (DW_TAG_variable, 0x34) -DW_TAG (DW_TAG_volatile_type, 0x35) -/* DWARF 3. */ -DW_TAG (DW_TAG_dwarf_procedure, 0x36) -DW_TAG (DW_TAG_restrict_type, 0x37) -DW_TAG (DW_TAG_interface_type, 0x38) -DW_TAG (DW_TAG_namespace, 0x39) -DW_TAG (DW_TAG_imported_module, 0x3a) -DW_TAG (DW_TAG_unspecified_type, 0x3b) -DW_TAG (DW_TAG_partial_unit, 0x3c) -DW_TAG (DW_TAG_imported_unit, 0x3d) -DW_TAG (DW_TAG_condition, 0x3f) -DW_TAG (DW_TAG_shared_type, 0x40) -/* DWARF 4. */ -DW_TAG (DW_TAG_type_unit, 0x41) -DW_TAG (DW_TAG_rvalue_reference_type, 0x42) -DW_TAG (DW_TAG_template_alias, 0x43) -/* DWARF 5. */ -DW_TAG (DW_TAG_atomic_type, 0x47) - -DW_TAG_DUP (DW_TAG_lo_user, 0x4080) -DW_TAG_DUP (DW_TAG_hi_user, 0xffff) - -/* SGI/MIPS Extensions. */ -DW_TAG (DW_TAG_MIPS_loop, 0x4081) - -/* HP extensions. See: ftp://ftp.hp.com/pub/lang/tools/WDB/wdb-4.0.tar.gz . */ -DW_TAG (DW_TAG_HP_array_descriptor, 0x4090) -DW_TAG (DW_TAG_HP_Bliss_field, 0x4091) -DW_TAG (DW_TAG_HP_Bliss_field_set, 0x4092) - -/* GNU extensions. */ -DW_TAG (DW_TAG_format_label, 0x4101) /* For FORTRAN 77 and Fortran 90. */ -DW_TAG (DW_TAG_function_template, 0x4102) /* For C++. */ -DW_TAG (DW_TAG_class_template, 0x4103) /* For C++. */ -DW_TAG (DW_TAG_GNU_BINCL, 0x4104) -DW_TAG (DW_TAG_GNU_EINCL, 0x4105) -/* Template template parameter. - See http://gcc.gnu.org/wiki/TemplateParmsDwarf . */ -DW_TAG (DW_TAG_GNU_template_template_param, 0x4106) - -/* Template parameter pack extension, specified at - http://wiki.dwarfstd.org/index.php?title=C%2B%2B0x:_Variadic_templates - The values of these two TAGS are in the DW_TAG_GNU_* space until the tags - are properly part of DWARF 5. */ -DW_TAG (DW_TAG_GNU_template_parameter_pack, 0x4107) -DW_TAG (DW_TAG_GNU_formal_parameter_pack, 0x4108) -/* The GNU call site extension, specified at - http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open . - The values of these two TAGS are in the DW_TAG_GNU_* space until the tags - are properly part of DWARF 5. */ -DW_TAG (DW_TAG_GNU_call_site, 0x4109) -DW_TAG (DW_TAG_GNU_call_site_parameter, 0x410a) -/* Extensions for UPC. See: http://dwarfstd.org/doc/DWARF4.pdf. */ -DW_TAG (DW_TAG_upc_shared_type, 0x8765) -DW_TAG (DW_TAG_upc_strict_type, 0x8766) -DW_TAG (DW_TAG_upc_relaxed_type, 0x8767) -/* PGI (STMicroelectronics) extensions. No documentation available. */ -DW_TAG (DW_TAG_PGI_kanji_type, 0xA000) -DW_TAG (DW_TAG_PGI_interface_block, 0xA020) -DW_END_TAG - -DW_FIRST_FORM (DW_FORM_addr, 0x01) -DW_FORM (DW_FORM_block2, 0x03) -DW_FORM (DW_FORM_block4, 0x04) -DW_FORM (DW_FORM_data2, 0x05) -DW_FORM (DW_FORM_data4, 0x06) -DW_FORM (DW_FORM_data8, 0x07) -DW_FORM (DW_FORM_string, 0x08) -DW_FORM (DW_FORM_block, 0x09) -DW_FORM (DW_FORM_block1, 0x0a) -DW_FORM (DW_FORM_data1, 0x0b) -DW_FORM (DW_FORM_flag, 0x0c) -DW_FORM (DW_FORM_sdata, 0x0d) -DW_FORM (DW_FORM_strp, 0x0e) -DW_FORM (DW_FORM_udata, 0x0f) -DW_FORM (DW_FORM_ref_addr, 0x10) -DW_FORM (DW_FORM_ref1, 0x11) -DW_FORM (DW_FORM_ref2, 0x12) -DW_FORM (DW_FORM_ref4, 0x13) -DW_FORM (DW_FORM_ref8, 0x14) -DW_FORM (DW_FORM_ref_udata, 0x15) -DW_FORM (DW_FORM_indirect, 0x16) -/* DWARF 4. */ -DW_FORM (DW_FORM_sec_offset, 0x17) -DW_FORM (DW_FORM_exprloc, 0x18) -DW_FORM (DW_FORM_flag_present, 0x19) -DW_FORM (DW_FORM_ref_sig8, 0x20) -/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ -DW_FORM (DW_FORM_GNU_addr_index, 0x1f01) -DW_FORM (DW_FORM_GNU_str_index, 0x1f02) -/* Extensions for DWZ multifile. - See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open . */ -DW_FORM (DW_FORM_GNU_ref_alt, 0x1f20) -DW_FORM (DW_FORM_GNU_strp_alt, 0x1f21) -DW_END_FORM - -DW_FIRST_AT (DW_AT_sibling, 0x01) -DW_AT (DW_AT_location, 0x02) -DW_AT (DW_AT_name, 0x03) -DW_AT (DW_AT_ordering, 0x09) -DW_AT (DW_AT_subscr_data, 0x0a) -DW_AT (DW_AT_byte_size, 0x0b) -DW_AT (DW_AT_bit_offset, 0x0c) -DW_AT (DW_AT_bit_size, 0x0d) -DW_AT (DW_AT_element_list, 0x0f) -DW_AT (DW_AT_stmt_list, 0x10) -DW_AT (DW_AT_low_pc, 0x11) -DW_AT (DW_AT_high_pc, 0x12) -DW_AT (DW_AT_language, 0x13) -DW_AT (DW_AT_member, 0x14) -DW_AT (DW_AT_discr, 0x15) -DW_AT (DW_AT_discr_value, 0x16) -DW_AT (DW_AT_visibility, 0x17) -DW_AT (DW_AT_import, 0x18) -DW_AT (DW_AT_string_length, 0x19) -DW_AT (DW_AT_common_reference, 0x1a) -DW_AT (DW_AT_comp_dir, 0x1b) -DW_AT (DW_AT_const_value, 0x1c) -DW_AT (DW_AT_containing_type, 0x1d) -DW_AT (DW_AT_default_value, 0x1e) -DW_AT (DW_AT_inline, 0x20) -DW_AT (DW_AT_is_optional, 0x21) -DW_AT (DW_AT_lower_bound, 0x22) -DW_AT (DW_AT_producer, 0x25) -DW_AT (DW_AT_prototyped, 0x27) -DW_AT (DW_AT_return_addr, 0x2a) -DW_AT (DW_AT_start_scope, 0x2c) -DW_AT (DW_AT_bit_stride, 0x2e) -DW_AT (DW_AT_upper_bound, 0x2f) -DW_AT (DW_AT_abstract_origin, 0x31) -DW_AT (DW_AT_accessibility, 0x32) -DW_AT (DW_AT_address_class, 0x33) -DW_AT (DW_AT_artificial, 0x34) -DW_AT (DW_AT_base_types, 0x35) -DW_AT (DW_AT_calling_convention, 0x36) -DW_AT (DW_AT_count, 0x37) -DW_AT (DW_AT_data_member_location, 0x38) -DW_AT (DW_AT_decl_column, 0x39) -DW_AT (DW_AT_decl_file, 0x3a) -DW_AT (DW_AT_decl_line, 0x3b) -DW_AT (DW_AT_declaration, 0x3c) -DW_AT (DW_AT_discr_list, 0x3d) -DW_AT (DW_AT_encoding, 0x3e) -DW_AT (DW_AT_external, 0x3f) -DW_AT (DW_AT_frame_base, 0x40) -DW_AT (DW_AT_friend, 0x41) -DW_AT (DW_AT_identifier_case, 0x42) -DW_AT (DW_AT_macro_info, 0x43) -DW_AT (DW_AT_namelist_items, 0x44) -DW_AT (DW_AT_priority, 0x45) -DW_AT (DW_AT_segment, 0x46) -DW_AT (DW_AT_specification, 0x47) -DW_AT (DW_AT_static_link, 0x48) -DW_AT (DW_AT_type, 0x49) -DW_AT (DW_AT_use_location, 0x4a) -DW_AT (DW_AT_variable_parameter, 0x4b) -DW_AT (DW_AT_virtuality, 0x4c) -DW_AT (DW_AT_vtable_elem_location, 0x4d) -/* DWARF 3 values. */ -DW_AT (DW_AT_allocated, 0x4e) -DW_AT (DW_AT_associated, 0x4f) -DW_AT (DW_AT_data_location, 0x50) -DW_AT (DW_AT_byte_stride, 0x51) -DW_AT (DW_AT_entry_pc, 0x52) -DW_AT (DW_AT_use_UTF8, 0x53) -DW_AT (DW_AT_extension, 0x54) -DW_AT (DW_AT_ranges, 0x55) -DW_AT (DW_AT_trampoline, 0x56) -DW_AT (DW_AT_call_column, 0x57) -DW_AT (DW_AT_call_file, 0x58) -DW_AT (DW_AT_call_line, 0x59) -DW_AT (DW_AT_description, 0x5a) -DW_AT (DW_AT_binary_scale, 0x5b) -DW_AT (DW_AT_decimal_scale, 0x5c) -DW_AT (DW_AT_small, 0x5d) -DW_AT (DW_AT_decimal_sign, 0x5e) -DW_AT (DW_AT_digit_count, 0x5f) -DW_AT (DW_AT_picture_string, 0x60) -DW_AT (DW_AT_mutable, 0x61) -DW_AT (DW_AT_threads_scaled, 0x62) -DW_AT (DW_AT_explicit, 0x63) -DW_AT (DW_AT_object_pointer, 0x64) -DW_AT (DW_AT_endianity, 0x65) -DW_AT (DW_AT_elemental, 0x66) -DW_AT (DW_AT_pure, 0x67) -DW_AT (DW_AT_recursive, 0x68) -/* DWARF 4. */ -DW_AT (DW_AT_signature, 0x69) -DW_AT (DW_AT_main_subprogram, 0x6a) -DW_AT (DW_AT_data_bit_offset, 0x6b) -DW_AT (DW_AT_const_expr, 0x6c) -DW_AT (DW_AT_enum_class, 0x6d) -DW_AT (DW_AT_linkage_name, 0x6e) -/* DWARF 5. */ -DW_AT (DW_AT_noreturn, 0x87) - -DW_AT_DUP (DW_AT_lo_user, 0x2000) /* Implementation-defined range start. */ -DW_AT_DUP (DW_AT_hi_user, 0x3fff) /* Implementation-defined range end. */ - -/* SGI/MIPS extensions. */ -DW_AT (DW_AT_MIPS_fde, 0x2001) -DW_AT (DW_AT_MIPS_loop_begin, 0x2002) -DW_AT (DW_AT_MIPS_tail_loop_begin, 0x2003) -DW_AT (DW_AT_MIPS_epilog_begin, 0x2004) -DW_AT (DW_AT_MIPS_loop_unroll_factor, 0x2005) -DW_AT (DW_AT_MIPS_software_pipeline_depth, 0x2006) -DW_AT (DW_AT_MIPS_linkage_name, 0x2007) -DW_AT (DW_AT_MIPS_stride, 0x2008) -DW_AT (DW_AT_MIPS_abstract_name, 0x2009) -DW_AT (DW_AT_MIPS_clone_origin, 0x200a) -DW_AT (DW_AT_MIPS_has_inlines, 0x200b) -/* HP extensions. */ -DW_AT (DW_AT_HP_block_index, 0x2000) -DW_AT_DUP (DW_AT_HP_unmodifiable, 0x2001) /* Same as DW_AT_MIPS_fde. */ -DW_AT_DUP (DW_AT_HP_prologue, 0x2005) /* Same as DW_AT_MIPS_loop_unroll. */ -DW_AT_DUP (DW_AT_HP_epilogue, 0x2008) /* Same as DW_AT_MIPS_stride. */ -DW_AT (DW_AT_HP_actuals_stmt_list, 0x2010) -DW_AT (DW_AT_HP_proc_per_section, 0x2011) -DW_AT (DW_AT_HP_raw_data_ptr, 0x2012) -DW_AT (DW_AT_HP_pass_by_reference, 0x2013) -DW_AT (DW_AT_HP_opt_level, 0x2014) -DW_AT (DW_AT_HP_prof_version_id, 0x2015) -DW_AT (DW_AT_HP_opt_flags, 0x2016) -DW_AT (DW_AT_HP_cold_region_low_pc, 0x2017) -DW_AT (DW_AT_HP_cold_region_high_pc, 0x2018) -DW_AT (DW_AT_HP_all_variables_modifiable, 0x2019) -DW_AT (DW_AT_HP_linkage_name, 0x201a) -DW_AT (DW_AT_HP_prof_flags, 0x201b) /* In comp unit of procs_info for -g. */ -DW_AT (DW_AT_HP_unit_name, 0x201f) -DW_AT (DW_AT_HP_unit_size, 0x2020) -DW_AT (DW_AT_HP_widened_byte_size, 0x2021) -DW_AT (DW_AT_HP_definition_points, 0x2022) -DW_AT (DW_AT_HP_default_location, 0x2023) -DW_AT (DW_AT_HP_is_result_param, 0x2029) - -/* GNU extensions. */ -DW_AT (DW_AT_sf_names, 0x2101) -DW_AT (DW_AT_src_info, 0x2102) -DW_AT (DW_AT_mac_info, 0x2103) -DW_AT (DW_AT_src_coords, 0x2104) -DW_AT (DW_AT_body_begin, 0x2105) -DW_AT (DW_AT_body_end, 0x2106) -DW_AT (DW_AT_GNU_vector, 0x2107) -/* Thread-safety annotations. - See http://gcc.gnu.org/wiki/ThreadSafetyAnnotation . */ -DW_AT (DW_AT_GNU_guarded_by, 0x2108) -DW_AT (DW_AT_GNU_pt_guarded_by, 0x2109) -DW_AT (DW_AT_GNU_guarded, 0x210a) -DW_AT (DW_AT_GNU_pt_guarded, 0x210b) -DW_AT (DW_AT_GNU_locks_excluded, 0x210c) -DW_AT (DW_AT_GNU_exclusive_locks_required, 0x210d) -DW_AT (DW_AT_GNU_shared_locks_required, 0x210e) -/* One-definition rule violation detection. - See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo . */ -DW_AT (DW_AT_GNU_odr_signature, 0x210f) -/* Template template argument name. - See http://gcc.gnu.org/wiki/TemplateParmsDwarf . */ -DW_AT (DW_AT_GNU_template_name, 0x2110) -/* The GNU call site extension. - See http://www.dwarfstd.org/ShowIssue.php?issue=100909.2&type=open . */ -DW_AT (DW_AT_GNU_call_site_value, 0x2111) -DW_AT (DW_AT_GNU_call_site_data_value, 0x2112) -DW_AT (DW_AT_GNU_call_site_target, 0x2113) -DW_AT (DW_AT_GNU_call_site_target_clobbered, 0x2114) -DW_AT (DW_AT_GNU_tail_call, 0x2115) -DW_AT (DW_AT_GNU_all_tail_call_sites, 0x2116) -DW_AT (DW_AT_GNU_all_call_sites, 0x2117) -DW_AT (DW_AT_GNU_all_source_call_sites, 0x2118) -/* Section offset into .debug_macro section. */ -DW_AT (DW_AT_GNU_macros, 0x2119) -/* Attribute for C++ deleted special member functions (= delete;). */ -DW_AT (DW_AT_GNU_deleted, 0x211a) -/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ -DW_AT (DW_AT_GNU_dwo_name, 0x2130) -DW_AT (DW_AT_GNU_dwo_id, 0x2131) -DW_AT (DW_AT_GNU_ranges_base, 0x2132) -DW_AT (DW_AT_GNU_addr_base, 0x2133) -DW_AT (DW_AT_GNU_pubnames, 0x2134) -DW_AT (DW_AT_GNU_pubtypes, 0x2135) -/* Attribute for discriminator. - See http://gcc.gnu.org/wiki/Discriminator */ -DW_AT (DW_AT_GNU_discriminator, 0x2136) -/* VMS extensions. */ -DW_AT (DW_AT_VMS_rtnbeg_pd_address, 0x2201) -/* GNAT extensions. */ -/* GNAT descriptive type. - See http://gcc.gnu.org/wiki/DW_AT_GNAT_descriptive_type . */ -DW_AT (DW_AT_use_GNAT_descriptive_type, 0x2301) -DW_AT (DW_AT_GNAT_descriptive_type, 0x2302) -/* Rational constant extension. - See https://gcc.gnu.org/wiki/DW_AT_GNU_numerator_denominator . */ -DW_TAG (DW_AT_GNU_numerator, 0x2303) -DW_TAG (DW_AT_GNU_denominator, 0x2304) -/* Biased integer extension. - See https://gcc.gnu.org/wiki/DW_AT_GNU_bias . */ -DW_TAG (DW_AT_GNU_bias, 0x2305) -/* UPC extension. */ -DW_AT (DW_AT_upc_threads_scaled, 0x3210) -/* PGI (STMicroelectronics) extensions. */ -DW_AT (DW_AT_PGI_lbase, 0x3a00) -DW_AT (DW_AT_PGI_soffset, 0x3a01) -DW_AT (DW_AT_PGI_lstride, 0x3a02) -/* Apple extensions. */ -DW_AT (DW_AT_APPLE_optimized, 0x3fe1) -DW_AT (DW_AT_APPLE_flags, 0x3fe2) -DW_AT (DW_AT_APPLE_isa, 0x3fe3) -DW_AT (DW_AT_APPLE_block, 0x3fe4) -DW_AT (DW_AT_APPLE_major_runtime_vers, 0x3fe5) -DW_AT (DW_AT_APPLE_runtime_class, 0x3fe6) -DW_AT (DW_AT_APPLE_omit_frame_ptr, 0x3fe7) -DW_AT (DW_AT_APPLE_property_name, 0x3fe8) -DW_AT (DW_AT_APPLE_property_getter, 0x3fe9) -DW_AT (DW_AT_APPLE_property_setter, 0x3fea) -DW_AT (DW_AT_APPLE_property_attribute, 0x3feb) -DW_AT (DW_AT_APPLE_objc_complete_type, 0x3fec) -DW_AT (DW_AT_APPLE_property, 0x3fed) -DW_END_AT - -DW_FIRST_OP (DW_OP_addr, 0x03) -DW_OP (DW_OP_deref, 0x06) -DW_OP (DW_OP_const1u, 0x08) -DW_OP (DW_OP_const1s, 0x09) -DW_OP (DW_OP_const2u, 0x0a) -DW_OP (DW_OP_const2s, 0x0b) -DW_OP (DW_OP_const4u, 0x0c) -DW_OP (DW_OP_const4s, 0x0d) -DW_OP (DW_OP_const8u, 0x0e) -DW_OP (DW_OP_const8s, 0x0f) -DW_OP (DW_OP_constu, 0x10) -DW_OP (DW_OP_consts, 0x11) -DW_OP (DW_OP_dup, 0x12) -DW_OP (DW_OP_drop, 0x13) -DW_OP (DW_OP_over, 0x14) -DW_OP (DW_OP_pick, 0x15) -DW_OP (DW_OP_swap, 0x16) -DW_OP (DW_OP_rot, 0x17) -DW_OP (DW_OP_xderef, 0x18) -DW_OP (DW_OP_abs, 0x19) -DW_OP (DW_OP_and, 0x1a) -DW_OP (DW_OP_div, 0x1b) -DW_OP (DW_OP_minus, 0x1c) -DW_OP (DW_OP_mod, 0x1d) -DW_OP (DW_OP_mul, 0x1e) -DW_OP (DW_OP_neg, 0x1f) -DW_OP (DW_OP_not, 0x20) -DW_OP (DW_OP_or, 0x21) -DW_OP (DW_OP_plus, 0x22) -DW_OP (DW_OP_plus_uconst, 0x23) -DW_OP (DW_OP_shl, 0x24) -DW_OP (DW_OP_shr, 0x25) -DW_OP (DW_OP_shra, 0x26) -DW_OP (DW_OP_xor, 0x27) -DW_OP (DW_OP_bra, 0x28) -DW_OP (DW_OP_eq, 0x29) -DW_OP (DW_OP_ge, 0x2a) -DW_OP (DW_OP_gt, 0x2b) -DW_OP (DW_OP_le, 0x2c) -DW_OP (DW_OP_lt, 0x2d) -DW_OP (DW_OP_ne, 0x2e) -DW_OP (DW_OP_skip, 0x2f) -DW_OP (DW_OP_lit0, 0x30) -DW_OP (DW_OP_lit1, 0x31) -DW_OP (DW_OP_lit2, 0x32) -DW_OP (DW_OP_lit3, 0x33) -DW_OP (DW_OP_lit4, 0x34) -DW_OP (DW_OP_lit5, 0x35) -DW_OP (DW_OP_lit6, 0x36) -DW_OP (DW_OP_lit7, 0x37) -DW_OP (DW_OP_lit8, 0x38) -DW_OP (DW_OP_lit9, 0x39) -DW_OP (DW_OP_lit10, 0x3a) -DW_OP (DW_OP_lit11, 0x3b) -DW_OP (DW_OP_lit12, 0x3c) -DW_OP (DW_OP_lit13, 0x3d) -DW_OP (DW_OP_lit14, 0x3e) -DW_OP (DW_OP_lit15, 0x3f) -DW_OP (DW_OP_lit16, 0x40) -DW_OP (DW_OP_lit17, 0x41) -DW_OP (DW_OP_lit18, 0x42) -DW_OP (DW_OP_lit19, 0x43) -DW_OP (DW_OP_lit20, 0x44) -DW_OP (DW_OP_lit21, 0x45) -DW_OP (DW_OP_lit22, 0x46) -DW_OP (DW_OP_lit23, 0x47) -DW_OP (DW_OP_lit24, 0x48) -DW_OP (DW_OP_lit25, 0x49) -DW_OP (DW_OP_lit26, 0x4a) -DW_OP (DW_OP_lit27, 0x4b) -DW_OP (DW_OP_lit28, 0x4c) -DW_OP (DW_OP_lit29, 0x4d) -DW_OP (DW_OP_lit30, 0x4e) -DW_OP (DW_OP_lit31, 0x4f) -DW_OP (DW_OP_reg0, 0x50) -DW_OP (DW_OP_reg1, 0x51) -DW_OP (DW_OP_reg2, 0x52) -DW_OP (DW_OP_reg3, 0x53) -DW_OP (DW_OP_reg4, 0x54) -DW_OP (DW_OP_reg5, 0x55) -DW_OP (DW_OP_reg6, 0x56) -DW_OP (DW_OP_reg7, 0x57) -DW_OP (DW_OP_reg8, 0x58) -DW_OP (DW_OP_reg9, 0x59) -DW_OP (DW_OP_reg10, 0x5a) -DW_OP (DW_OP_reg11, 0x5b) -DW_OP (DW_OP_reg12, 0x5c) -DW_OP (DW_OP_reg13, 0x5d) -DW_OP (DW_OP_reg14, 0x5e) -DW_OP (DW_OP_reg15, 0x5f) -DW_OP (DW_OP_reg16, 0x60) -DW_OP (DW_OP_reg17, 0x61) -DW_OP (DW_OP_reg18, 0x62) -DW_OP (DW_OP_reg19, 0x63) -DW_OP (DW_OP_reg20, 0x64) -DW_OP (DW_OP_reg21, 0x65) -DW_OP (DW_OP_reg22, 0x66) -DW_OP (DW_OP_reg23, 0x67) -DW_OP (DW_OP_reg24, 0x68) -DW_OP (DW_OP_reg25, 0x69) -DW_OP (DW_OP_reg26, 0x6a) -DW_OP (DW_OP_reg27, 0x6b) -DW_OP (DW_OP_reg28, 0x6c) -DW_OP (DW_OP_reg29, 0x6d) -DW_OP (DW_OP_reg30, 0x6e) -DW_OP (DW_OP_reg31, 0x6f) -DW_OP (DW_OP_breg0, 0x70) -DW_OP (DW_OP_breg1, 0x71) -DW_OP (DW_OP_breg2, 0x72) -DW_OP (DW_OP_breg3, 0x73) -DW_OP (DW_OP_breg4, 0x74) -DW_OP (DW_OP_breg5, 0x75) -DW_OP (DW_OP_breg6, 0x76) -DW_OP (DW_OP_breg7, 0x77) -DW_OP (DW_OP_breg8, 0x78) -DW_OP (DW_OP_breg9, 0x79) -DW_OP (DW_OP_breg10, 0x7a) -DW_OP (DW_OP_breg11, 0x7b) -DW_OP (DW_OP_breg12, 0x7c) -DW_OP (DW_OP_breg13, 0x7d) -DW_OP (DW_OP_breg14, 0x7e) -DW_OP (DW_OP_breg15, 0x7f) -DW_OP (DW_OP_breg16, 0x80) -DW_OP (DW_OP_breg17, 0x81) -DW_OP (DW_OP_breg18, 0x82) -DW_OP (DW_OP_breg19, 0x83) -DW_OP (DW_OP_breg20, 0x84) -DW_OP (DW_OP_breg21, 0x85) -DW_OP (DW_OP_breg22, 0x86) -DW_OP (DW_OP_breg23, 0x87) -DW_OP (DW_OP_breg24, 0x88) -DW_OP (DW_OP_breg25, 0x89) -DW_OP (DW_OP_breg26, 0x8a) -DW_OP (DW_OP_breg27, 0x8b) -DW_OP (DW_OP_breg28, 0x8c) -DW_OP (DW_OP_breg29, 0x8d) -DW_OP (DW_OP_breg30, 0x8e) -DW_OP (DW_OP_breg31, 0x8f) -DW_OP (DW_OP_regx, 0x90) -DW_OP (DW_OP_fbreg, 0x91) -DW_OP (DW_OP_bregx, 0x92) -DW_OP (DW_OP_piece, 0x93) -DW_OP (DW_OP_deref_size, 0x94) -DW_OP (DW_OP_xderef_size, 0x95) -DW_OP (DW_OP_nop, 0x96) -/* DWARF 3 extensions. */ -DW_OP (DW_OP_push_object_address, 0x97) -DW_OP (DW_OP_call2, 0x98) -DW_OP (DW_OP_call4, 0x99) -DW_OP (DW_OP_call_ref, 0x9a) -DW_OP (DW_OP_form_tls_address, 0x9b) -DW_OP (DW_OP_call_frame_cfa, 0x9c) -DW_OP (DW_OP_bit_piece, 0x9d) - -/* DWARF 4 extensions. */ -DW_OP (DW_OP_implicit_value, 0x9e) -DW_OP (DW_OP_stack_value, 0x9f) - -DW_OP_DUP (DW_OP_lo_user, 0xe0) /* Implementation-defined range start. */ -DW_OP_DUP (DW_OP_hi_user, 0xff) /* Implementation-defined range end. */ - -/* GNU extensions. */ -DW_OP (DW_OP_GNU_push_tls_address, 0xe0) -/* The following is for marking variables that are uninitialized. */ -DW_OP (DW_OP_GNU_uninit, 0xf0) -DW_OP (DW_OP_GNU_encoded_addr, 0xf1) -/* The GNU implicit pointer extension. - See http://www.dwarfstd.org/ShowIssue.php?issue=100831.1&type=open . */ -DW_OP (DW_OP_GNU_implicit_pointer, 0xf2) -/* The GNU entry value extension. - See http://www.dwarfstd.org/ShowIssue.php?issue=100909.1&type=open . */ -DW_OP (DW_OP_GNU_entry_value, 0xf3) -/* The GNU typed stack extension. - See http://www.dwarfstd.org/doc/040408.1.html . */ -DW_OP (DW_OP_GNU_const_type, 0xf4) -DW_OP (DW_OP_GNU_regval_type, 0xf5) -DW_OP (DW_OP_GNU_deref_type, 0xf6) -DW_OP (DW_OP_GNU_convert, 0xf7) -DW_OP (DW_OP_GNU_reinterpret, 0xf9) -/* The GNU parameter ref extension. */ -DW_OP (DW_OP_GNU_parameter_ref, 0xfa) -/* Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ -DW_OP (DW_OP_GNU_addr_index, 0xfb) -DW_OP (DW_OP_GNU_const_index, 0xfc) -/* HP extensions. */ -DW_OP_DUP (DW_OP_HP_unknown, 0xe0) /* Ouch, the same as GNU_push_tls_address. */ -DW_OP (DW_OP_HP_is_value, 0xe1) -DW_OP (DW_OP_HP_fltconst4, 0xe2) -DW_OP (DW_OP_HP_fltconst8, 0xe3) -DW_OP (DW_OP_HP_mod_range, 0xe4) -DW_OP (DW_OP_HP_unmod_range, 0xe5) -DW_OP (DW_OP_HP_tls, 0xe6) -/* PGI (STMicroelectronics) extensions. */ -DW_OP (DW_OP_PGI_omp_thread_num, 0xf8) -DW_END_OP - -DW_FIRST_ATE (DW_ATE_void, 0x0) -DW_ATE (DW_ATE_address, 0x1) -DW_ATE (DW_ATE_boolean, 0x2) -DW_ATE (DW_ATE_complex_float, 0x3) -DW_ATE (DW_ATE_float, 0x4) -DW_ATE (DW_ATE_signed, 0x5) -DW_ATE (DW_ATE_signed_char, 0x6) -DW_ATE (DW_ATE_unsigned, 0x7) -DW_ATE (DW_ATE_unsigned_char, 0x8) -/* DWARF 3. */ -DW_ATE (DW_ATE_imaginary_float, 0x9) -DW_ATE (DW_ATE_packed_decimal, 0xa) -DW_ATE (DW_ATE_numeric_string, 0xb) -DW_ATE (DW_ATE_edited, 0xc) -DW_ATE (DW_ATE_signed_fixed, 0xd) -DW_ATE (DW_ATE_unsigned_fixed, 0xe) -DW_ATE (DW_ATE_decimal_float, 0xf) -/* DWARF 4. */ -DW_ATE (DW_ATE_UTF, 0x10) - -DW_ATE_DUP (DW_ATE_lo_user, 0x80) -DW_ATE_DUP (DW_ATE_hi_user, 0xff) - -/* HP extensions. */ -DW_ATE (DW_ATE_HP_float80, 0x80) /* Floating-point (80 bit). */ -DW_ATE (DW_ATE_HP_complex_float80, 0x81) /* Complex floating-point (80 bit). */ -DW_ATE (DW_ATE_HP_float128, 0x82) /* Floating-point (128 bit). */ -DW_ATE (DW_ATE_HP_complex_float128, 0x83) /* Complex fp (128 bit). */ -DW_ATE (DW_ATE_HP_floathpintel, 0x84) /* Floating-point (82 bit IA64). */ -DW_ATE (DW_ATE_HP_imaginary_float80, 0x85) -DW_ATE (DW_ATE_HP_imaginary_float128, 0x86) -DW_ATE (DW_ATE_HP_VAX_float, 0x88) /* F or G floating. */ -DW_ATE (DW_ATE_HP_VAX_float_d, 0x89) /* D floating. */ -DW_ATE (DW_ATE_HP_packed_decimal, 0x8a) /* Cobol. */ -DW_ATE (DW_ATE_HP_zoned_decimal, 0x8b) /* Cobol. */ -DW_ATE (DW_ATE_HP_edited, 0x8c) /* Cobol. */ -DW_ATE (DW_ATE_HP_signed_fixed, 0x8d) /* Cobol. */ -DW_ATE (DW_ATE_HP_unsigned_fixed, 0x8e) /* Cobol. */ -DW_ATE (DW_ATE_HP_VAX_complex_float, 0x8f) /* F or G floating complex. */ -DW_ATE (DW_ATE_HP_VAX_complex_float_d, 0x90) /* D floating complex. */ - -DW_END_ATE - -DW_FIRST_CFA (DW_CFA_advance_loc, 0x40) -DW_CFA (DW_CFA_offset, 0x80) -DW_CFA (DW_CFA_restore, 0xc0) -DW_CFA (DW_CFA_nop, 0x00) -DW_CFA (DW_CFA_set_loc, 0x01) -DW_CFA (DW_CFA_advance_loc1, 0x02) -DW_CFA (DW_CFA_advance_loc2, 0x03) -DW_CFA (DW_CFA_advance_loc4, 0x04) -DW_CFA (DW_CFA_offset_extended, 0x05) -DW_CFA (DW_CFA_restore_extended, 0x06) -DW_CFA (DW_CFA_undefined, 0x07) -DW_CFA (DW_CFA_same_value, 0x08) -DW_CFA (DW_CFA_register, 0x09) -DW_CFA (DW_CFA_remember_state, 0x0a) -DW_CFA (DW_CFA_restore_state, 0x0b) -DW_CFA (DW_CFA_def_cfa, 0x0c) -DW_CFA (DW_CFA_def_cfa_register, 0x0d) -DW_CFA (DW_CFA_def_cfa_offset, 0x0e) -/* DWARF 3. */ -DW_CFA (DW_CFA_def_cfa_expression, 0x0f) -DW_CFA (DW_CFA_expression, 0x10) -DW_CFA (DW_CFA_offset_extended_sf, 0x11) -DW_CFA (DW_CFA_def_cfa_sf, 0x12) -DW_CFA (DW_CFA_def_cfa_offset_sf, 0x13) -DW_CFA (DW_CFA_val_offset, 0x14) -DW_CFA (DW_CFA_val_offset_sf, 0x15) -DW_CFA (DW_CFA_val_expression, 0x16) - -DW_CFA (DW_CFA_lo_user, 0x1c) -DW_CFA (DW_CFA_hi_user, 0x3f) - -/* SGI/MIPS specific. */ -DW_CFA (DW_CFA_MIPS_advance_loc8, 0x1d) -/* GNU extensions. */ -DW_CFA (DW_CFA_GNU_window_save, 0x2d) -DW_CFA (DW_CFA_GNU_args_size, 0x2e) -DW_CFA (DW_CFA_GNU_negative_offset_extended, 0x2f) - -DW_END_CFA diff --git a/src/libbacktrace/dwarf2.h b/src/libbacktrace/dwarf2.h deleted file mode 100644 index 4ada87162fa86..0000000000000 --- a/src/libbacktrace/dwarf2.h +++ /dev/null @@ -1,430 +0,0 @@ -/* Declarations and definitions of codes relating to the DWARF2 and - DWARF3 symbolic debugging information formats. - Copyright (C) 1992-2015 Free Software Foundation, Inc. - - Written by Gary Funck (gary@intrepid.com) The Ada Joint Program - Office (AJPO), Florida State University and Silicon Graphics Inc. - provided support for this effort -- June 21, 1995. - - Derived from the DWARF 1 implementation written by Ron Guilmette - (rfg@netcom.com), November 1990. - - This file is part of GCC. - - GCC is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free - Software Foundation; either version 3, or (at your option) any later - version. - - GCC is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public - License for more details. - - Under Section 7 of GPL version 3, you are granted additional - permissions described in the GCC Runtime Library Exception, version - 3.1, as published by the Free Software Foundation. - - You should have received a copy of the GNU General Public License and - a copy of the GCC Runtime Library Exception along with this program; - see the files COPYING3 and COPYING.RUNTIME respectively. If not, see - . */ - -/* This file is derived from the DWARF specification (a public document) - Revision 2.0.0 (July 27, 1993) developed by the UNIX International - Programming Languages Special Interest Group (UI/PLSIG) and distributed - by UNIX International. Copies of this specification are available from - UNIX International, 20 Waterview Boulevard, Parsippany, NJ, 07054. - - This file also now contains definitions from the DWARF 3 specification - published Dec 20, 2005, available from: http://dwarf.freestandards.org. */ - -#ifndef _DWARF2_H -#define _DWARF2_H - -#define DW_TAG(name, value) , name = value -#define DW_TAG_DUP(name, value) , name = value -#define DW_FORM(name, value) , name = value -#define DW_AT(name, value) , name = value -#define DW_AT_DUP(name, value) , name = value -#define DW_OP(name, value) , name = value -#define DW_OP_DUP(name, value) , name = value -#define DW_ATE(name, value) , name = value -#define DW_ATE_DUP(name, value) , name = value -#define DW_CFA(name, value) , name = value - -#define DW_FIRST_TAG(name, value) enum dwarf_tag { \ - name = value -#define DW_END_TAG }; -#define DW_FIRST_FORM(name, value) enum dwarf_form { \ - name = value -#define DW_END_FORM }; -#define DW_FIRST_AT(name, value) enum dwarf_attribute { \ - name = value -#define DW_END_AT }; -#define DW_FIRST_OP(name, value) enum dwarf_location_atom { \ - name = value -#define DW_END_OP }; -#define DW_FIRST_ATE(name, value) enum dwarf_type { \ - name = value -#define DW_END_ATE }; -#define DW_FIRST_CFA(name, value) enum dwarf_call_frame_info { \ - name = value -#define DW_END_CFA }; - -#include "dwarf2.def" - -#undef DW_FIRST_TAG -#undef DW_END_TAG -#undef DW_FIRST_FORM -#undef DW_END_FORM -#undef DW_FIRST_AT -#undef DW_END_AT -#undef DW_FIRST_OP -#undef DW_END_OP -#undef DW_FIRST_ATE -#undef DW_END_ATE -#undef DW_FIRST_CFA -#undef DW_END_CFA - -#undef DW_TAG -#undef DW_TAG_DUP -#undef DW_FORM -#undef DW_AT -#undef DW_AT_DUP -#undef DW_OP -#undef DW_OP_DUP -#undef DW_ATE -#undef DW_ATE_DUP -#undef DW_CFA - -/* Flag that tells whether entry has a child or not. */ -#define DW_children_no 0 -#define DW_children_yes 1 - -#define DW_AT_stride_size DW_AT_bit_stride /* Note: The use of DW_AT_stride_size is deprecated. */ -#define DW_AT_stride DW_AT_byte_stride /* Note: The use of DW_AT_stride is deprecated. */ - -/* Decimal sign encodings. */ -enum dwarf_decimal_sign_encoding - { - /* DWARF 3. */ - DW_DS_unsigned = 0x01, - DW_DS_leading_overpunch = 0x02, - DW_DS_trailing_overpunch = 0x03, - DW_DS_leading_separate = 0x04, - DW_DS_trailing_separate = 0x05 - }; - -/* Endianity encodings. */ -enum dwarf_endianity_encoding - { - /* DWARF 3. */ - DW_END_default = 0x00, - DW_END_big = 0x01, - DW_END_little = 0x02, - - DW_END_lo_user = 0x40, - DW_END_hi_user = 0xff - }; - -/* Array ordering names and codes. */ -enum dwarf_array_dim_ordering - { - DW_ORD_row_major = 0, - DW_ORD_col_major = 1 - }; - -/* Access attribute. */ -enum dwarf_access_attribute - { - DW_ACCESS_public = 1, - DW_ACCESS_protected = 2, - DW_ACCESS_private = 3 - }; - -/* Visibility. */ -enum dwarf_visibility_attribute - { - DW_VIS_local = 1, - DW_VIS_exported = 2, - DW_VIS_qualified = 3 - }; - -/* Virtuality. */ -enum dwarf_virtuality_attribute - { - DW_VIRTUALITY_none = 0, - DW_VIRTUALITY_virtual = 1, - DW_VIRTUALITY_pure_virtual = 2 - }; - -/* Case sensitivity. */ -enum dwarf_id_case - { - DW_ID_case_sensitive = 0, - DW_ID_up_case = 1, - DW_ID_down_case = 2, - DW_ID_case_insensitive = 3 - }; - -/* Calling convention. */ -enum dwarf_calling_convention - { - DW_CC_normal = 0x1, - DW_CC_program = 0x2, - DW_CC_nocall = 0x3, - - DW_CC_lo_user = 0x40, - DW_CC_hi_user = 0xff, - - DW_CC_GNU_renesas_sh = 0x40, - DW_CC_GNU_borland_fastcall_i386 = 0x41, - - /* This DW_CC_ value is not currently generated by any toolchain. It is - used internally to GDB to indicate OpenCL C functions that have been - compiled with the IBM XL C for OpenCL compiler and use a non-platform - calling convention for passing OpenCL C vector types. This value may - be changed freely as long as it does not conflict with any other DW_CC_ - value defined here. */ - DW_CC_GDB_IBM_OpenCL = 0xff - }; - -/* Inline attribute. */ -enum dwarf_inline_attribute - { - DW_INL_not_inlined = 0, - DW_INL_inlined = 1, - DW_INL_declared_not_inlined = 2, - DW_INL_declared_inlined = 3 - }; - -/* Discriminant lists. */ -enum dwarf_discrim_list - { - DW_DSC_label = 0, - DW_DSC_range = 1 - }; - -/* Line number opcodes. */ -enum dwarf_line_number_ops - { - DW_LNS_extended_op = 0, - DW_LNS_copy = 1, - DW_LNS_advance_pc = 2, - DW_LNS_advance_line = 3, - DW_LNS_set_file = 4, - DW_LNS_set_column = 5, - DW_LNS_negate_stmt = 6, - DW_LNS_set_basic_block = 7, - DW_LNS_const_add_pc = 8, - DW_LNS_fixed_advance_pc = 9, - /* DWARF 3. */ - DW_LNS_set_prologue_end = 10, - DW_LNS_set_epilogue_begin = 11, - DW_LNS_set_isa = 12 - }; - -/* Line number extended opcodes. */ -enum dwarf_line_number_x_ops - { - DW_LNE_end_sequence = 1, - DW_LNE_set_address = 2, - DW_LNE_define_file = 3, - DW_LNE_set_discriminator = 4, - /* HP extensions. */ - DW_LNE_HP_negate_is_UV_update = 0x11, - DW_LNE_HP_push_context = 0x12, - DW_LNE_HP_pop_context = 0x13, - DW_LNE_HP_set_file_line_column = 0x14, - DW_LNE_HP_set_routine_name = 0x15, - DW_LNE_HP_set_sequence = 0x16, - DW_LNE_HP_negate_post_semantics = 0x17, - DW_LNE_HP_negate_function_exit = 0x18, - DW_LNE_HP_negate_front_end_logical = 0x19, - DW_LNE_HP_define_proc = 0x20, - DW_LNE_HP_source_file_correlation = 0x80, - - DW_LNE_lo_user = 0x80, - DW_LNE_hi_user = 0xff - }; - -/* Sub-opcodes for DW_LNE_HP_source_file_correlation. */ -enum dwarf_line_number_hp_sfc_ops - { - DW_LNE_HP_SFC_formfeed = 1, - DW_LNE_HP_SFC_set_listing_line = 2, - DW_LNE_HP_SFC_associate = 3 - }; - -/* Type codes for location list entries. - Extension for Fission. See http://gcc.gnu.org/wiki/DebugFission. */ - -enum dwarf_location_list_entry_type - { - DW_LLE_GNU_end_of_list_entry = 0, - DW_LLE_GNU_base_address_selection_entry = 1, - DW_LLE_GNU_start_end_entry = 2, - DW_LLE_GNU_start_length_entry = 3 - }; - -#define DW_CIE_ID 0xffffffff -#define DW64_CIE_ID 0xffffffffffffffffULL -#define DW_CIE_VERSION 1 - -#define DW_CFA_extended 0 - -#define DW_CHILDREN_no 0x00 -#define DW_CHILDREN_yes 0x01 - -#define DW_ADDR_none 0 - -/* Source language names and codes. */ -enum dwarf_source_language - { - DW_LANG_C89 = 0x0001, - DW_LANG_C = 0x0002, - DW_LANG_Ada83 = 0x0003, - DW_LANG_C_plus_plus = 0x0004, - DW_LANG_Cobol74 = 0x0005, - DW_LANG_Cobol85 = 0x0006, - DW_LANG_Fortran77 = 0x0007, - DW_LANG_Fortran90 = 0x0008, - DW_LANG_Pascal83 = 0x0009, - DW_LANG_Modula2 = 0x000a, - /* DWARF 3. */ - DW_LANG_Java = 0x000b, - DW_LANG_C99 = 0x000c, - DW_LANG_Ada95 = 0x000d, - DW_LANG_Fortran95 = 0x000e, - DW_LANG_PLI = 0x000f, - DW_LANG_ObjC = 0x0010, - DW_LANG_ObjC_plus_plus = 0x0011, - DW_LANG_UPC = 0x0012, - DW_LANG_D = 0x0013, - /* DWARF 4. */ - DW_LANG_Python = 0x0014, - /* DWARF 5. */ - DW_LANG_Go = 0x0016, - - DW_LANG_C_plus_plus_11 = 0x001a, /* dwarf5.20141029.pdf DRAFT */ - DW_LANG_C11 = 0x001d, - DW_LANG_C_plus_plus_14 = 0x0021, - DW_LANG_Fortran03 = 0x0022, - DW_LANG_Fortran08 = 0x0023, - - DW_LANG_lo_user = 0x8000, /* Implementation-defined range start. */ - DW_LANG_hi_user = 0xffff, /* Implementation-defined range start. */ - - /* MIPS. */ - DW_LANG_Mips_Assembler = 0x8001, - /* UPC. */ - DW_LANG_Upc = 0x8765, - /* HP extensions. */ - DW_LANG_HP_Bliss = 0x8003, - DW_LANG_HP_Basic91 = 0x8004, - DW_LANG_HP_Pascal91 = 0x8005, - DW_LANG_HP_IMacro = 0x8006, - DW_LANG_HP_Assembler = 0x8007 - }; - -/* Names and codes for macro information. */ -enum dwarf_macinfo_record_type - { - DW_MACINFO_define = 1, - DW_MACINFO_undef = 2, - DW_MACINFO_start_file = 3, - DW_MACINFO_end_file = 4, - DW_MACINFO_vendor_ext = 255 - }; - -/* Names and codes for new style macro information. */ -enum dwarf_macro_record_type - { - DW_MACRO_GNU_define = 1, - DW_MACRO_GNU_undef = 2, - DW_MACRO_GNU_start_file = 3, - DW_MACRO_GNU_end_file = 4, - DW_MACRO_GNU_define_indirect = 5, - DW_MACRO_GNU_undef_indirect = 6, - DW_MACRO_GNU_transparent_include = 7, - /* Extensions for DWZ multifile. - See http://www.dwarfstd.org/ShowIssue.php?issue=120604.1&type=open . */ - DW_MACRO_GNU_define_indirect_alt = 8, - DW_MACRO_GNU_undef_indirect_alt = 9, - DW_MACRO_GNU_transparent_include_alt = 10, - DW_MACRO_GNU_lo_user = 0xe0, - DW_MACRO_GNU_hi_user = 0xff - }; - -/* @@@ For use with GNU frame unwind information. */ - -#define DW_EH_PE_absptr 0x00 -#define DW_EH_PE_omit 0xff - -#define DW_EH_PE_uleb128 0x01 -#define DW_EH_PE_udata2 0x02 -#define DW_EH_PE_udata4 0x03 -#define DW_EH_PE_udata8 0x04 -#define DW_EH_PE_sleb128 0x09 -#define DW_EH_PE_sdata2 0x0A -#define DW_EH_PE_sdata4 0x0B -#define DW_EH_PE_sdata8 0x0C -#define DW_EH_PE_signed 0x08 - -#define DW_EH_PE_pcrel 0x10 -#define DW_EH_PE_textrel 0x20 -#define DW_EH_PE_datarel 0x30 -#define DW_EH_PE_funcrel 0x40 -#define DW_EH_PE_aligned 0x50 - -#define DW_EH_PE_indirect 0x80 - -/* Codes for the debug sections in a dwarf package (.dwp) file. - Extensions for Fission. See http://gcc.gnu.org/wiki/DebugFissionDWP. */ -enum dwarf_sect - { - DW_SECT_INFO = 1, - DW_SECT_TYPES = 2, - DW_SECT_ABBREV = 3, - DW_SECT_LINE = 4, - DW_SECT_LOC = 5, - DW_SECT_STR_OFFSETS = 6, - DW_SECT_MACINFO = 7, - DW_SECT_MACRO = 8, - DW_SECT_MAX = 8 - }; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* Return the name of a DW_TAG_ constant, or NULL if the value is not - recognized. */ -extern const char *get_DW_TAG_name (unsigned int tag); - -/* Return the name of a DW_AT_ constant, or NULL if the value is not - recognized. */ -extern const char *get_DW_AT_name (unsigned int attr); - -/* Return the name of a DW_FORM_ constant, or NULL if the value is not - recognized. */ -extern const char *get_DW_FORM_name (unsigned int form); - -/* Return the name of a DW_OP_ constant, or NULL if the value is not - recognized. */ -extern const char *get_DW_OP_name (unsigned int op); - -/* Return the name of a DW_ATE_ constant, or NULL if the value is not - recognized. */ -extern const char *get_DW_ATE_name (unsigned int enc); - -/* Return the name of a DW_CFA_ constant, or NULL if the value is not - recognized. */ -extern const char *get_DW_CFA_name (unsigned int opc); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* _DWARF2_H */ diff --git a/src/libbacktrace/elf.c b/src/libbacktrace/elf.c deleted file mode 100644 index 81ba3440ab7d1..0000000000000 --- a/src/libbacktrace/elf.c +++ /dev/null @@ -1,979 +0,0 @@ -/* elf.c -- Get debug data from an ELF file for backtraces. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include - -#ifdef HAVE_DL_ITERATE_PHDR -#include -#endif - -#include "backtrace.h" -#include "internal.h" - -#ifndef HAVE_DL_ITERATE_PHDR - -/* Dummy version of dl_iterate_phdr for systems that don't have it. */ - -#define dl_phdr_info x_dl_phdr_info -#define dl_iterate_phdr x_dl_iterate_phdr - -struct dl_phdr_info -{ - uintptr_t dlpi_addr; - const char *dlpi_name; -}; - -static int -dl_iterate_phdr (int (*callback) (struct dl_phdr_info *, - size_t, void *) ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - return 0; -} - -#endif /* ! defined (HAVE_DL_ITERATE_PHDR) */ - -/* The configure script must tell us whether we are 32-bit or 64-bit - ELF. We could make this code test and support either possibility, - but there is no point. This code only works for the currently - running executable, which means that we know the ELF mode at - configure mode. */ - -#if BACKTRACE_ELF_SIZE != 32 && BACKTRACE_ELF_SIZE != 64 -#error "Unknown BACKTRACE_ELF_SIZE" -#endif - -/* might #include which might define our constants - with slightly different values. Undefine them to be safe. */ - -#undef EI_NIDENT -#undef EI_MAG0 -#undef EI_MAG1 -#undef EI_MAG2 -#undef EI_MAG3 -#undef EI_CLASS -#undef EI_DATA -#undef EI_VERSION -#undef ELF_MAG0 -#undef ELF_MAG1 -#undef ELF_MAG2 -#undef ELF_MAG3 -#undef ELFCLASS32 -#undef ELFCLASS64 -#undef ELFDATA2LSB -#undef ELFDATA2MSB -#undef EV_CURRENT -#undef ET_DYN -#undef SHN_LORESERVE -#undef SHN_XINDEX -#undef SHN_UNDEF -#undef SHT_SYMTAB -#undef SHT_STRTAB -#undef SHT_DYNSYM -#undef STT_OBJECT -#undef STT_FUNC - -/* Basic types. */ - -typedef uint16_t b_elf_half; /* Elf_Half. */ -typedef uint32_t b_elf_word; /* Elf_Word. */ -typedef int32_t b_elf_sword; /* Elf_Sword. */ - -#if BACKTRACE_ELF_SIZE == 32 - -typedef uint32_t b_elf_addr; /* Elf_Addr. */ -typedef uint32_t b_elf_off; /* Elf_Off. */ - -typedef uint32_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ - -#else - -typedef uint64_t b_elf_addr; /* Elf_Addr. */ -typedef uint64_t b_elf_off; /* Elf_Off. */ -typedef uint64_t b_elf_xword; /* Elf_Xword. */ -typedef int64_t b_elf_sxword; /* Elf_Sxword. */ - -typedef uint64_t b_elf_wxword; /* 32-bit Elf_Word, 64-bit ELF_Xword. */ - -#endif - -/* Data structures and associated constants. */ - -#define EI_NIDENT 16 - -typedef struct { - unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ - b_elf_half e_type; /* Identifies object file type */ - b_elf_half e_machine; /* Specifies required architecture */ - b_elf_word e_version; /* Identifies object file version */ - b_elf_addr e_entry; /* Entry point virtual address */ - b_elf_off e_phoff; /* Program header table file offset */ - b_elf_off e_shoff; /* Section header table file offset */ - b_elf_word e_flags; /* Processor-specific flags */ - b_elf_half e_ehsize; /* ELF header size in bytes */ - b_elf_half e_phentsize; /* Program header table entry size */ - b_elf_half e_phnum; /* Program header table entry count */ - b_elf_half e_shentsize; /* Section header table entry size */ - b_elf_half e_shnum; /* Section header table entry count */ - b_elf_half e_shstrndx; /* Section header string table index */ -} b_elf_ehdr; /* Elf_Ehdr. */ - -#define EI_MAG0 0 -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 - -#define ELFMAG0 0x7f -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' - -#define ELFCLASS32 1 -#define ELFCLASS64 2 - -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EV_CURRENT 1 - -#define ET_DYN 3 - -typedef struct { - b_elf_word sh_name; /* Section name, index in string tbl */ - b_elf_word sh_type; /* Type of section */ - b_elf_wxword sh_flags; /* Miscellaneous section attributes */ - b_elf_addr sh_addr; /* Section virtual addr at execution */ - b_elf_off sh_offset; /* Section file offset */ - b_elf_wxword sh_size; /* Size of section in bytes */ - b_elf_word sh_link; /* Index of another section */ - b_elf_word sh_info; /* Additional section information */ - b_elf_wxword sh_addralign; /* Section alignment */ - b_elf_wxword sh_entsize; /* Entry size if section holds table */ -} b_elf_shdr; /* Elf_Shdr. */ - -#define SHN_UNDEF 0x0000 /* Undefined section */ -#define SHN_LORESERVE 0xFF00 /* Begin range of reserved indices */ -#define SHN_XINDEX 0xFFFF /* Section index is held elsewhere */ - -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_DYNSYM 11 - -#if BACKTRACE_ELF_SIZE == 32 - -typedef struct -{ - b_elf_word st_name; /* Symbol name, index in string tbl */ - b_elf_addr st_value; /* Symbol value */ - b_elf_word st_size; /* Symbol size */ - unsigned char st_info; /* Symbol binding and type */ - unsigned char st_other; /* Visibility and other data */ - b_elf_half st_shndx; /* Symbol section index */ -} b_elf_sym; /* Elf_Sym. */ - -#else /* BACKTRACE_ELF_SIZE != 32 */ - -typedef struct -{ - b_elf_word st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Symbol binding and type */ - unsigned char st_other; /* Visibility and other data */ - b_elf_half st_shndx; /* Symbol section index */ - b_elf_addr st_value; /* Symbol value */ - b_elf_xword st_size; /* Symbol size */ -} b_elf_sym; /* Elf_Sym. */ - -#endif /* BACKTRACE_ELF_SIZE != 32 */ - -#define STT_OBJECT 1 -#define STT_FUNC 2 - -/* An index of ELF sections we care about. */ - -enum debug_section -{ - DEBUG_INFO, - DEBUG_LINE, - DEBUG_ABBREV, - DEBUG_RANGES, - DEBUG_STR, - DEBUG_MAX -}; - -/* Names of sections, indexed by enum elf_section. */ - -static const char * const debug_section_names[DEBUG_MAX] = -{ - ".debug_info", - ".debug_line", - ".debug_abbrev", - ".debug_ranges", - ".debug_str" -}; - -/* Information we gather for the sections we care about. */ - -struct debug_section_info -{ - /* Section file offset. */ - off_t offset; - /* Section size. */ - size_t size; - /* Section contents, after read from file. */ - const unsigned char *data; -}; - -/* Information we keep for an ELF symbol. */ - -struct elf_symbol -{ - /* The name of the symbol. */ - const char *name; - /* The address of the symbol. */ - uintptr_t address; - /* The size of the symbol. */ - size_t size; -}; - -/* Information to pass to elf_syminfo. */ - -struct elf_syminfo_data -{ - /* Symbols for the next module. */ - struct elf_syminfo_data *next; - /* The ELF symbols, sorted by address. */ - struct elf_symbol *symbols; - /* The number of symbols. */ - size_t count; -}; - -/* A dummy callback function used when we can't find any debug info. */ - -static int -elf_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc ATTRIBUTE_UNUSED, - backtrace_full_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no debug info in ELF executable", -1); - return 0; -} - -/* A dummy callback function used when we can't find a symbol - table. */ - -static void -elf_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t addr ATTRIBUTE_UNUSED, - backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no symbol table in ELF executable", -1); -} - -/* Compare struct elf_symbol for qsort. */ - -static int -elf_symbol_compare (const void *v1, const void *v2) -{ - const struct elf_symbol *e1 = (const struct elf_symbol *) v1; - const struct elf_symbol *e2 = (const struct elf_symbol *) v2; - - if (e1->address < e2->address) - return -1; - else if (e1->address > e2->address) - return 1; - else - return 0; -} - -/* Compare an ADDR against an elf_symbol for bsearch. We allocate one - extra entry in the array so that this can look safely at the next - entry. */ - -static int -elf_symbol_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct elf_symbol *entry = (const struct elf_symbol *) ventry; - uintptr_t addr; - - addr = *key; - if (addr < entry->address) - return -1; - else if (addr >= entry->address + entry->size) - return 1; - else - return 0; -} - -/* Initialize the symbol table info for elf_syminfo. */ - -static int -elf_initialize_syminfo (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char *symtab_data, size_t symtab_size, - const unsigned char *strtab, size_t strtab_size, - backtrace_error_callback error_callback, - void *data, struct elf_syminfo_data *sdata) -{ - size_t sym_count; - const b_elf_sym *sym; - size_t elf_symbol_count; - size_t elf_symbol_size; - struct elf_symbol *elf_symbols; - size_t i; - unsigned int j; - - sym_count = symtab_size / sizeof (b_elf_sym); - - /* We only care about function symbols. Count them. */ - sym = (const b_elf_sym *) symtab_data; - elf_symbol_count = 0; - for (i = 0; i < sym_count; ++i, ++sym) - { - int info; - - info = sym->st_info & 0xf; - if ((info == STT_FUNC || info == STT_OBJECT) - && sym->st_shndx != SHN_UNDEF) - ++elf_symbol_count; - } - - elf_symbol_size = elf_symbol_count * sizeof (struct elf_symbol); - elf_symbols = ((struct elf_symbol *) - backtrace_alloc (state, elf_symbol_size, error_callback, - data)); - if (elf_symbols == NULL) - return 0; - - sym = (const b_elf_sym *) symtab_data; - j = 0; - for (i = 0; i < sym_count; ++i, ++sym) - { - int info; - - info = sym->st_info & 0xf; - if (info != STT_FUNC && info != STT_OBJECT) - continue; - if (sym->st_shndx == SHN_UNDEF) - continue; - if (sym->st_name >= strtab_size) - { - error_callback (data, "symbol string index out of range", 0); - backtrace_free (state, elf_symbols, elf_symbol_size, error_callback, - data); - return 0; - } - elf_symbols[j].name = (const char *) strtab + sym->st_name; - elf_symbols[j].address = sym->st_value + base_address; - elf_symbols[j].size = sym->st_size; - ++j; - } - - backtrace_qsort (elf_symbols, elf_symbol_count, sizeof (struct elf_symbol), - elf_symbol_compare); - - sdata->next = NULL; - sdata->symbols = elf_symbols; - sdata->count = elf_symbol_count; - - return 1; -} - -/* Add EDATA to the list in STATE. */ - -static void -elf_add_syminfo_data (struct backtrace_state *state, - struct elf_syminfo_data *edata) -{ - if (!state->threaded) - { - struct elf_syminfo_data **pp; - - for (pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = edata; - } - else - { - while (1) - { - struct elf_syminfo_data **pp; - - pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - - while (1) - { - struct elf_syminfo_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, edata)) - break; - } - } -} - -/* Return the symbol name and value for an ADDR. */ - -static void -elf_syminfo (struct backtrace_state *state, uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data) -{ - struct elf_syminfo_data *edata; - struct elf_symbol *sym = NULL; - - if (!state->threaded) - { - for (edata = (struct elf_syminfo_data *) state->syminfo_data; - edata != NULL; - edata = edata->next) - { - sym = ((struct elf_symbol *) - bsearch (&addr, edata->symbols, edata->count, - sizeof (struct elf_symbol), elf_symbol_search)); - if (sym != NULL) - break; - } - } - else - { - struct elf_syminfo_data **pp; - - pp = (struct elf_syminfo_data **) (void *) &state->syminfo_data; - while (1) - { - edata = backtrace_atomic_load_pointer (pp); - if (edata == NULL) - break; - - sym = ((struct elf_symbol *) - bsearch (&addr, edata->symbols, edata->count, - sizeof (struct elf_symbol), elf_symbol_search)); - if (sym != NULL) - break; - - pp = &edata->next; - } - } - - if (sym == NULL) - callback (data, addr, NULL, 0, 0); - else - callback (data, addr, sym->name, sym->address, sym->size); -} - -/* Add the backtrace data for one ELF file. Returns 1 on success, - 0 on failure (in both cases descriptor is closed) or -1 if exe - is non-zero and the ELF file is ET_DYN, which tells the caller that - elf_add will need to be called on the descriptor again after - base_address is determined. */ - -static int -elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address, - backtrace_error_callback error_callback, void *data, - fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe) -{ - struct backtrace_view ehdr_view; - b_elf_ehdr ehdr; - off_t shoff; - unsigned int shnum; - unsigned int shstrndx; - struct backtrace_view shdrs_view; - int shdrs_view_valid; - const b_elf_shdr *shdrs; - const b_elf_shdr *shstrhdr; - size_t shstr_size; - off_t shstr_off; - struct backtrace_view names_view; - int names_view_valid; - const char *names; - unsigned int symtab_shndx; - unsigned int dynsym_shndx; - unsigned int i; - struct debug_section_info sections[DEBUG_MAX]; - struct backtrace_view symtab_view; - int symtab_view_valid; - struct backtrace_view strtab_view; - int strtab_view_valid; - off_t min_offset; - off_t max_offset; - struct backtrace_view debug_view; - int debug_view_valid; - - *found_sym = 0; - *found_dwarf = 0; - - shdrs_view_valid = 0; - names_view_valid = 0; - symtab_view_valid = 0; - strtab_view_valid = 0; - debug_view_valid = 0; - - if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback, - data, &ehdr_view)) - goto fail; - - memcpy (&ehdr, ehdr_view.data, sizeof ehdr); - - backtrace_release_view (state, &ehdr_view, error_callback, data); - - if (ehdr.e_ident[EI_MAG0] != ELFMAG0 - || ehdr.e_ident[EI_MAG1] != ELFMAG1 - || ehdr.e_ident[EI_MAG2] != ELFMAG2 - || ehdr.e_ident[EI_MAG3] != ELFMAG3) - { - error_callback (data, "executable file is not ELF", 0); - goto fail; - } - if (ehdr.e_ident[EI_VERSION] != EV_CURRENT) - { - error_callback (data, "executable file is unrecognized ELF version", 0); - goto fail; - } - -#if BACKTRACE_ELF_SIZE == 32 -#define BACKTRACE_ELFCLASS ELFCLASS32 -#else -#define BACKTRACE_ELFCLASS ELFCLASS64 -#endif - - if (ehdr.e_ident[EI_CLASS] != BACKTRACE_ELFCLASS) - { - error_callback (data, "executable file is unexpected ELF class", 0); - goto fail; - } - - if (ehdr.e_ident[EI_DATA] != ELFDATA2LSB - && ehdr.e_ident[EI_DATA] != ELFDATA2MSB) - { - error_callback (data, "executable file has unknown endianness", 0); - goto fail; - } - - /* If the executable is ET_DYN, it is either a PIE, or we are running - directly a shared library with .interp. We need to wait for - dl_iterate_phdr in that case to determine the actual base_address. */ - if (exe && ehdr.e_type == ET_DYN) - return -1; - - shoff = ehdr.e_shoff; - shnum = ehdr.e_shnum; - shstrndx = ehdr.e_shstrndx; - - if ((shnum == 0 || shstrndx == SHN_XINDEX) - && shoff != 0) - { - struct backtrace_view shdr_view; - const b_elf_shdr *shdr; - - if (!backtrace_get_view (state, descriptor, shoff, sizeof shdr, - error_callback, data, &shdr_view)) - goto fail; - - shdr = (const b_elf_shdr *) shdr_view.data; - - if (shnum == 0) - shnum = shdr->sh_size; - - if (shstrndx == SHN_XINDEX) - { - shstrndx = shdr->sh_link; - - /* Versions of the GNU binutils between 2.12 and 2.18 did - not handle objects with more than SHN_LORESERVE sections - correctly. All large section indexes were offset by - 0x100. There is more information at - http://sourceware.org/bugzilla/show_bug.cgi?id-5900 . - Fortunately these object files are easy to detect, as the - GNU binutils always put the section header string table - near the end of the list of sections. Thus if the - section header string table index is larger than the - number of sections, then we know we have to subtract - 0x100 to get the real section index. */ - if (shstrndx >= shnum && shstrndx >= SHN_LORESERVE + 0x100) - shstrndx -= 0x100; - } - - backtrace_release_view (state, &shdr_view, error_callback, data); - } - - /* To translate PC to file/line when using DWARF, we need to find - the .debug_info and .debug_line sections. */ - - /* Read the section headers, skipping the first one. */ - - if (!backtrace_get_view (state, descriptor, shoff + sizeof (b_elf_shdr), - (shnum - 1) * sizeof (b_elf_shdr), - error_callback, data, &shdrs_view)) - goto fail; - shdrs_view_valid = 1; - shdrs = (const b_elf_shdr *) shdrs_view.data; - - /* Read the section names. */ - - shstrhdr = &shdrs[shstrndx - 1]; - shstr_size = shstrhdr->sh_size; - shstr_off = shstrhdr->sh_offset; - - if (!backtrace_get_view (state, descriptor, shstr_off, shstr_size, - error_callback, data, &names_view)) - goto fail; - names_view_valid = 1; - names = (const char *) names_view.data; - - symtab_shndx = 0; - dynsym_shndx = 0; - - memset (sections, 0, sizeof sections); - - /* Look for the symbol table. */ - for (i = 1; i < shnum; ++i) - { - const b_elf_shdr *shdr; - unsigned int sh_name; - const char *name; - int j; - - shdr = &shdrs[i - 1]; - - if (shdr->sh_type == SHT_SYMTAB) - symtab_shndx = i; - else if (shdr->sh_type == SHT_DYNSYM) - dynsym_shndx = i; - - sh_name = shdr->sh_name; - if (sh_name >= shstr_size) - { - error_callback (data, "ELF section name out of range", 0); - goto fail; - } - - name = names + sh_name; - - for (j = 0; j < (int) DEBUG_MAX; ++j) - { - if (strcmp (name, debug_section_names[j]) == 0) - { - sections[j].offset = shdr->sh_offset; - sections[j].size = shdr->sh_size; - break; - } - } - } - - if (symtab_shndx == 0) - symtab_shndx = dynsym_shndx; - if (symtab_shndx != 0) - { - const b_elf_shdr *symtab_shdr; - unsigned int strtab_shndx; - const b_elf_shdr *strtab_shdr; - struct elf_syminfo_data *sdata; - - symtab_shdr = &shdrs[symtab_shndx - 1]; - strtab_shndx = symtab_shdr->sh_link; - if (strtab_shndx >= shnum) - { - error_callback (data, - "ELF symbol table strtab link out of range", 0); - goto fail; - } - strtab_shdr = &shdrs[strtab_shndx - 1]; - - if (!backtrace_get_view (state, descriptor, symtab_shdr->sh_offset, - symtab_shdr->sh_size, error_callback, data, - &symtab_view)) - goto fail; - symtab_view_valid = 1; - - if (!backtrace_get_view (state, descriptor, strtab_shdr->sh_offset, - strtab_shdr->sh_size, error_callback, data, - &strtab_view)) - goto fail; - strtab_view_valid = 1; - - sdata = ((struct elf_syminfo_data *) - backtrace_alloc (state, sizeof *sdata, error_callback, data)); - if (sdata == NULL) - goto fail; - - if (!elf_initialize_syminfo (state, base_address, - symtab_view.data, symtab_shdr->sh_size, - strtab_view.data, strtab_shdr->sh_size, - error_callback, data, sdata)) - { - backtrace_free (state, sdata, sizeof *sdata, error_callback, data); - goto fail; - } - - /* We no longer need the symbol table, but we hold on to the - string table permanently. */ - backtrace_release_view (state, &symtab_view, error_callback, data); - - *found_sym = 1; - - elf_add_syminfo_data (state, sdata); - } - - /* FIXME: Need to handle compressed debug sections. */ - - backtrace_release_view (state, &shdrs_view, error_callback, data); - shdrs_view_valid = 0; - backtrace_release_view (state, &names_view, error_callback, data); - names_view_valid = 0; - - /* Read all the debug sections in a single view, since they are - probably adjacent in the file. We never release this view. */ - - min_offset = 0; - max_offset = 0; - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - off_t end; - - if (sections[i].size == 0) - continue; - if (min_offset == 0 || sections[i].offset < min_offset) - min_offset = sections[i].offset; - end = sections[i].offset + sections[i].size; - if (end > max_offset) - max_offset = end; - } - if (min_offset == 0 || max_offset == 0) - { - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - return 1; - } - - if (!backtrace_get_view (state, descriptor, min_offset, - max_offset - min_offset, - error_callback, data, &debug_view)) - goto fail; - debug_view_valid = 1; - - /* We've read all we need from the executable. */ - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - descriptor = -1; - - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - if (sections[i].size == 0) - sections[i].data = NULL; - else - sections[i].data = ((const unsigned char *) debug_view.data - + (sections[i].offset - min_offset)); - } - - if (!backtrace_dwarf_add (state, base_address, - sections[DEBUG_INFO].data, - sections[DEBUG_INFO].size, - sections[DEBUG_LINE].data, - sections[DEBUG_LINE].size, - sections[DEBUG_ABBREV].data, - sections[DEBUG_ABBREV].size, - sections[DEBUG_RANGES].data, - sections[DEBUG_RANGES].size, - sections[DEBUG_STR].data, - sections[DEBUG_STR].size, - ehdr.e_ident[EI_DATA] == ELFDATA2MSB, - error_callback, data, fileline_fn)) - goto fail; - - *found_dwarf = 1; - - return 1; - - fail: - if (shdrs_view_valid) - backtrace_release_view (state, &shdrs_view, error_callback, data); - if (names_view_valid) - backtrace_release_view (state, &names_view, error_callback, data); - if (symtab_view_valid) - backtrace_release_view (state, &symtab_view, error_callback, data); - if (strtab_view_valid) - backtrace_release_view (state, &strtab_view, error_callback, data); - if (debug_view_valid) - backtrace_release_view (state, &debug_view, error_callback, data); - if (descriptor != -1) - backtrace_close (descriptor, error_callback, data); - return 0; -} - -/* Data passed to phdr_callback. */ - -struct phdr_data -{ - struct backtrace_state *state; - backtrace_error_callback error_callback; - void *data; - fileline *fileline_fn; - int *found_sym; - int *found_dwarf; - int exe_descriptor; -}; - -/* Callback passed to dl_iterate_phdr. Load debug info from shared - libraries. */ - -static int -#ifdef __i386__ -__attribute__ ((__force_align_arg_pointer__)) -#endif -phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED, - void *pdata) -{ - struct phdr_data *pd = (struct phdr_data *) pdata; - int descriptor; - int does_not_exist; - fileline elf_fileline_fn; - int found_dwarf; - - /* There is not much we can do if we don't have the module name, - unless executable is ET_DYN, where we expect the very first - phdr_callback to be for the PIE. */ - if (info->dlpi_name == NULL || info->dlpi_name[0] == '\0') - { - if (pd->exe_descriptor == -1) - return 0; - descriptor = pd->exe_descriptor; - pd->exe_descriptor = -1; - } - else - { - if (pd->exe_descriptor != -1) - { - backtrace_close (pd->exe_descriptor, pd->error_callback, pd->data); - pd->exe_descriptor = -1; - } - - descriptor = backtrace_open (info->dlpi_name, pd->error_callback, - pd->data, &does_not_exist); - if (descriptor < 0) - return 0; - } - - if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback, - pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0)) - { - if (found_dwarf) - { - *pd->found_dwarf = 1; - *pd->fileline_fn = elf_fileline_fn; - } - } - - return 0; -} - -/* Initialize the backtrace data we need from an ELF executable. At - the ELF level, all we need to do is find the debug info - sections. */ - -int -backtrace_initialize (struct backtrace_state *state, int descriptor, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn) -{ - int ret; - int found_sym; - int found_dwarf; - fileline elf_fileline_fn = elf_nodebug; - struct phdr_data pd; - - ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn, - &found_sym, &found_dwarf, 1); - if (!ret) - return 0; - - pd.state = state; - pd.error_callback = error_callback; - pd.data = data; - pd.fileline_fn = &elf_fileline_fn; - pd.found_sym = &found_sym; - pd.found_dwarf = &found_dwarf; - pd.exe_descriptor = ret < 0 ? descriptor : -1; - - dl_iterate_phdr (phdr_callback, (void *) &pd); - - if (!state->threaded) - { - if (found_sym) - state->syminfo_fn = elf_syminfo; - else if (state->syminfo_fn == NULL) - state->syminfo_fn = elf_nosyms; - } - else - { - if (found_sym) - backtrace_atomic_store_pointer (&state->syminfo_fn, elf_syminfo); - else - (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, - elf_nosyms); - } - - if (!state->threaded) - { - if (state->fileline_fn == NULL || state->fileline_fn == elf_nodebug) - *fileline_fn = elf_fileline_fn; - } - else - { - fileline current_fn; - - current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - if (current_fn == NULL || current_fn == elf_nodebug) - *fileline_fn = elf_fileline_fn; - } - - return 1; -} diff --git a/src/libbacktrace/fileline.c b/src/libbacktrace/fileline.c deleted file mode 100644 index 27ebbedc21ccf..0000000000000 --- a/src/libbacktrace/fileline.c +++ /dev/null @@ -1,194 +0,0 @@ -/* fileline.c -- Get file and line number information in a backtrace. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef HAVE_GETEXECNAME -#define getexecname() NULL -#endif - -/* Initialize the fileline information from the executable. Returns 1 - on success, 0 on failure. */ - -static int -fileline_initialize (struct backtrace_state *state, - backtrace_error_callback error_callback, void *data) -{ - int failed; - fileline fileline_fn; - int pass; - int called_error_callback; - int descriptor; - - if (!state->threaded) - failed = state->fileline_initialization_failed; - else - failed = backtrace_atomic_load_int (&state->fileline_initialization_failed); - - if (failed) - { - error_callback (data, "failed to read executable information", -1); - return 0; - } - - if (!state->threaded) - fileline_fn = state->fileline_fn; - else - fileline_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - if (fileline_fn != NULL) - return 1; - - /* We have not initialized the information. Do it now. */ - - descriptor = -1; - called_error_callback = 0; - for (pass = 0; pass < 4; ++pass) - { - const char *filename; - int does_not_exist; - - switch (pass) - { - case 0: - filename = state->filename; - break; - case 1: - filename = getexecname (); - break; - case 2: - filename = "/proc/self/exe"; - break; - case 3: - filename = "/proc/curproc/file"; - break; - default: - abort (); - } - - if (filename == NULL) - continue; - - descriptor = backtrace_open (filename, error_callback, data, - &does_not_exist); - if (descriptor < 0 && !does_not_exist) - { - called_error_callback = 1; - break; - } - if (descriptor >= 0) - break; - } - - if (descriptor < 0) - { - if (!called_error_callback) - { - if (state->filename != NULL) - error_callback (data, state->filename, ENOENT); - else - error_callback (data, - "libbacktrace could not find executable to open", - 0); - } - failed = 1; - } - - if (!failed) - { - if (!backtrace_initialize (state, descriptor, error_callback, data, - &fileline_fn)) - failed = 1; - } - - if (failed) - { - if (!state->threaded) - state->fileline_initialization_failed = 1; - else - backtrace_atomic_store_int (&state->fileline_initialization_failed, 1); - return 0; - } - - if (!state->threaded) - state->fileline_fn = fileline_fn; - else - { - backtrace_atomic_store_pointer (&state->fileline_fn, fileline_fn); - - /* Note that if two threads initialize at once, one of the data - sets may be leaked. */ - } - - return 1; -} - -/* Given a PC, find the file name, line number, and function name. */ - -int -backtrace_pcinfo (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data) -{ - if (!fileline_initialize (state, error_callback, data)) - return 0; - - if (state->fileline_initialization_failed) - return 0; - - return state->fileline_fn (state, pc, callback, error_callback, data); -} - -/* Given a PC, find the symbol for it, and its value. */ - -int -backtrace_syminfo (struct backtrace_state *state, uintptr_t pc, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, void *data) -{ - if (!fileline_initialize (state, error_callback, data)) - return 0; - - if (state->fileline_initialization_failed) - return 0; - - state->syminfo_fn (state, pc, callback, error_callback, data); - return 1; -} diff --git a/src/libbacktrace/filenames.h b/src/libbacktrace/filenames.h deleted file mode 100644 index 1161daaa4f358..0000000000000 --- a/src/libbacktrace/filenames.h +++ /dev/null @@ -1,99 +0,0 @@ -/* Macros for taking apart, interpreting and processing file names. - - These are here because some non-Posix (a.k.a. DOSish) systems have - drive letter brain-damage at the beginning of an absolute file name, - use forward- and back-slash in path names interchangeably, and - some of them have case-insensitive file names. - - Copyright (C) 2000-2015 Free Software Foundation, Inc. - -This file is part of BFD, the Binary File Descriptor library. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -#ifndef FILENAMES_H -#define FILENAMES_H - -#include "hashtab.h" /* for hashval_t */ - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__) -# ifndef HAVE_DOS_BASED_FILE_SYSTEM -# define HAVE_DOS_BASED_FILE_SYSTEM 1 -# endif -# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM -# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 -# endif -# define HAS_DRIVE_SPEC(f) HAS_DOS_DRIVE_SPEC (f) -# define IS_DIR_SEPARATOR(c) IS_DOS_DIR_SEPARATOR (c) -# define IS_ABSOLUTE_PATH(f) IS_DOS_ABSOLUTE_PATH (f) -#else /* not DOSish */ -# if defined(__APPLE__) -# ifndef HAVE_CASE_INSENSITIVE_FILE_SYSTEM -# define HAVE_CASE_INSENSITIVE_FILE_SYSTEM 1 -# endif -# endif /* __APPLE__ */ -# define HAS_DRIVE_SPEC(f) (0) -# define IS_DIR_SEPARATOR(c) IS_UNIX_DIR_SEPARATOR (c) -# define IS_ABSOLUTE_PATH(f) IS_UNIX_ABSOLUTE_PATH (f) -#endif - -#define IS_DIR_SEPARATOR_1(dos_based, c) \ - (((c) == '/') \ - || (((c) == '\\') && (dos_based))) - -#define HAS_DRIVE_SPEC_1(dos_based, f) \ - ((f)[0] && ((f)[1] == ':') && (dos_based)) - -/* Remove the drive spec from F, assuming HAS_DRIVE_SPEC (f). - The result is a pointer to the remainder of F. */ -#define STRIP_DRIVE_SPEC(f) ((f) + 2) - -#define IS_DOS_DIR_SEPARATOR(c) IS_DIR_SEPARATOR_1 (1, c) -#define IS_DOS_ABSOLUTE_PATH(f) IS_ABSOLUTE_PATH_1 (1, f) -#define HAS_DOS_DRIVE_SPEC(f) HAS_DRIVE_SPEC_1 (1, f) - -#define IS_UNIX_DIR_SEPARATOR(c) IS_DIR_SEPARATOR_1 (0, c) -#define IS_UNIX_ABSOLUTE_PATH(f) IS_ABSOLUTE_PATH_1 (0, f) - -/* Note that when DOS_BASED is true, IS_ABSOLUTE_PATH accepts d:foo as - well, although it is only semi-absolute. This is because the users - of IS_ABSOLUTE_PATH want to know whether to prepend the current - working directory to a file name, which should not be done with a - name like d:foo. */ -#define IS_ABSOLUTE_PATH_1(dos_based, f) \ - (IS_DIR_SEPARATOR_1 (dos_based, (f)[0]) \ - || HAS_DRIVE_SPEC_1 (dos_based, f)) - -extern int filename_cmp (const char *s1, const char *s2); -#define FILENAME_CMP(s1, s2) filename_cmp(s1, s2) - -extern int filename_ncmp (const char *s1, const char *s2, - size_t n); - -extern hashval_t filename_hash (const void *s); - -extern int filename_eq (const void *s1, const void *s2); - -extern int canonical_filename_eq (const char *a, const char *b); - -#ifdef __cplusplus -} -#endif - -#endif /* FILENAMES_H */ diff --git a/src/libbacktrace/filetype.awk b/src/libbacktrace/filetype.awk deleted file mode 100644 index a5f6c8cc1800f..0000000000000 --- a/src/libbacktrace/filetype.awk +++ /dev/null @@ -1,11 +0,0 @@ -# An awk script to determine the type of a file. -/\177ELF\001/ { if (NR == 1) { print "elf32"; exit } } -/\177ELF\002/ { if (NR == 1) { print "elf64"; exit } } -/\114\001/ { if (NR == 1) { print "pecoff"; exit } } -/\144\206/ { if (NR == 1) { print "pecoff"; exit } } -/\xFE\xED\xFA\xCE/ { if (NR == 1) { print "macho32"; exit } } -/\xCE\xFA\xED\xFE/ { if (NR == 1) { print "macho32"; exit } } -/\xFE\xED\xFA\xCF/ { if (NR == 1) { print "macho64"; exit } } -/\xCF\xFA\xED\xFE/ { if (NR == 1) { print "macho64"; exit } } -/\xCA\xFE\xBA\xBE/ { if (NR == 1) { print "macho-fat"; exit } } -/\xBE\xBA\xFE\xCA/ { if (NR == 1) { print "macho-fat"; exit } } diff --git a/src/libbacktrace/hashtab.h b/src/libbacktrace/hashtab.h deleted file mode 100644 index b1b5877aae7ca..0000000000000 --- a/src/libbacktrace/hashtab.h +++ /dev/null @@ -1,204 +0,0 @@ -/* An expandable hash tables datatype. - Copyright (C) 1999-2015 Free Software Foundation, Inc. - Contributed by Vladimir Makarov (vmakarov@cygnus.com). - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ - -/* This package implements basic hash table functionality. It is possible - to search for an entry, create an entry and destroy an entry. - - Elements in the table are generic pointers. - - The size of the table is not fixed; if the occupancy of the table - grows too high the hash table will be expanded. - - The abstract data implementation is based on generalized Algorithm D - from Knuth's book "The art of computer programming". Hash table is - expanded by creation of new hash table and transferring elements from - the old table to the new table. */ - -#ifndef __HASHTAB_H__ -#define __HASHTAB_H__ - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#include "ansidecl.h" - -/* The type for a hash code. */ -typedef unsigned int hashval_t; - -/* Callback function pointer types. */ - -/* Calculate hash of a table entry. */ -typedef hashval_t (*htab_hash) (const void *); - -/* Compare a table entry with a possible entry. The entry already in - the table always comes first, so the second element can be of a - different type (but in this case htab_find and htab_find_slot - cannot be used; instead the variants that accept a hash value - must be used). */ -typedef int (*htab_eq) (const void *, const void *); - -/* Cleanup function called whenever a live element is removed from - the hash table. */ -typedef void (*htab_del) (void *); - -/* Function called by htab_traverse for each live element. The first - arg is the slot of the element (which can be passed to htab_clear_slot - if desired), the second arg is the auxiliary pointer handed to - htab_traverse. Return 1 to continue scan, 0 to stop. */ -typedef int (*htab_trav) (void **, void *); - -/* Memory-allocation function, with the same functionality as calloc(). - Iff it returns NULL, the hash table implementation will pass an error - code back to the user, so if your code doesn't handle errors, - best if you use xcalloc instead. */ -typedef void *(*htab_alloc) (size_t, size_t); - -/* We also need a free() routine. */ -typedef void (*htab_free) (void *); - -/* Memory allocation and deallocation; variants which take an extra - argument. */ -typedef void *(*htab_alloc_with_arg) (void *, size_t, size_t); -typedef void (*htab_free_with_arg) (void *, void *); - -/* This macro defines reserved value for empty table entry. */ - -#define HTAB_EMPTY_ENTRY ((PTR) 0) - -/* This macro defines reserved value for table entry which contained - a deleted element. */ - -#define HTAB_DELETED_ENTRY ((PTR) 1) - -/* Hash tables are of the following type. The structure - (implementation) of this type is not needed for using the hash - tables. All work with hash table should be executed only through - functions mentioned below. The size of this structure is subject to - change. */ - -struct htab { - /* Pointer to hash function. */ - htab_hash hash_f; - - /* Pointer to comparison function. */ - htab_eq eq_f; - - /* Pointer to cleanup function. */ - htab_del del_f; - - /* Table itself. */ - void **entries; - - /* Current size (in entries) of the hash table. */ - size_t size; - - /* Current number of elements including also deleted elements. */ - size_t n_elements; - - /* Current number of deleted elements in the table. */ - size_t n_deleted; - - /* The following member is used for debugging. Its value is number - of all calls of `htab_find_slot' for the hash table. */ - unsigned int searches; - - /* The following member is used for debugging. Its value is number - of collisions fixed for time of work with the hash table. */ - unsigned int collisions; - - /* Pointers to allocate/free functions. */ - htab_alloc alloc_f; - htab_free free_f; - - /* Alternate allocate/free functions, which take an extra argument. */ - void *alloc_arg; - htab_alloc_with_arg alloc_with_arg_f; - htab_free_with_arg free_with_arg_f; - - /* Current size (in entries) of the hash table, as an index into the - table of primes. */ - unsigned int size_prime_index; -}; - -typedef struct htab *htab_t; - -/* An enum saying whether we insert into the hash table or not. */ -enum insert_option {NO_INSERT, INSERT}; - -/* The prototypes of the package functions. */ - -extern htab_t htab_create_alloc (size_t, htab_hash, - htab_eq, htab_del, - htab_alloc, htab_free); - -extern htab_t htab_create_alloc_ex (size_t, htab_hash, - htab_eq, htab_del, - void *, htab_alloc_with_arg, - htab_free_with_arg); - -extern htab_t htab_create_typed_alloc (size_t, htab_hash, htab_eq, htab_del, - htab_alloc, htab_alloc, htab_free); - -/* Backward-compatibility functions. */ -extern htab_t htab_create (size_t, htab_hash, htab_eq, htab_del); -extern htab_t htab_try_create (size_t, htab_hash, htab_eq, htab_del); - -extern void htab_set_functions_ex (htab_t, htab_hash, - htab_eq, htab_del, - void *, htab_alloc_with_arg, - htab_free_with_arg); - -extern void htab_delete (htab_t); -extern void htab_empty (htab_t); - -extern void * htab_find (htab_t, const void *); -extern void ** htab_find_slot (htab_t, const void *, enum insert_option); -extern void * htab_find_with_hash (htab_t, const void *, hashval_t); -extern void ** htab_find_slot_with_hash (htab_t, const void *, - hashval_t, enum insert_option); -extern void htab_clear_slot (htab_t, void **); -extern void htab_remove_elt (htab_t, void *); -extern void htab_remove_elt_with_hash (htab_t, void *, hashval_t); - -extern void htab_traverse (htab_t, htab_trav, void *); -extern void htab_traverse_noresize (htab_t, htab_trav, void *); - -extern size_t htab_size (htab_t); -extern size_t htab_elements (htab_t); -extern double htab_collisions (htab_t); - -/* A hash function for pointers. */ -extern htab_hash htab_hash_pointer; - -/* An equality function for pointers. */ -extern htab_eq htab_eq_pointer; - -/* A hash function for null-terminated strings. */ -extern hashval_t htab_hash_string (const void *); - -/* An iterative hash function for arbitrary data. */ -extern hashval_t iterative_hash (const void *, size_t, hashval_t); -/* Shorthand for hashing something with an intrinsic size. */ -#define iterative_hash_object(OB,INIT) iterative_hash (&OB, sizeof (OB), INIT) - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __HASHTAB_H */ diff --git a/src/libbacktrace/install-sh b/src/libbacktrace/install-sh deleted file mode 100644 index 0b0fdcbba69ab..0000000000000 --- a/src/libbacktrace/install-sh +++ /dev/null @@ -1,501 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2013-12-25.23; # UTC - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# 'make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -tab=' ' -nl=' -' -IFS=" $tab$nl" - -# Set DOITPROG to "echo" to test this script. - -doit=${DOITPROG-} -doit_exec=${doit:-exec} - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -is_target_a_directory=possibly - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve the last data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -s $stripprog installed files. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -s) stripcmd=$stripprog;; - - -t) - is_target_a_directory=always - dst_arg=$2 - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - shift;; - - -T) is_target_a_directory=never;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -# We allow the use of options -d and -T together, by making -d -# take the precedence; this is for compatibility with GNU install. - -if test -n "$dir_arg"; then - if test -n "$dst_arg"; then - echo "$0: target directory not allowed when installing a directory." >&2 - exit 1 - fi -fi - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - # Protect names problematic for 'test' and other utilities. - case $dst_arg in - -* | [=\(\)!]) dst_arg=./$dst_arg;; - esac - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call 'install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - if test $# -gt 1 || test "$is_target_a_directory" = always; then - if test ! -d "$dst_arg"; then - echo "$0: $dst_arg: Is not a directory." >&2 - exit 1 - fi - fi -fi - -if test -z "$dir_arg"; then - do_exit='(exit $ret); exit $ret' - trap "ret=129; $do_exit" 1 - trap "ret=130; $do_exit" 2 - trap "ret=141; $do_exit" 13 - trap "ret=143; $do_exit" 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names problematic for 'test' and other utilities. - case $src in - -* | [=\(\)!]) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - dst=$dst_arg - - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. - if test -d "$dst"; then - if test "$is_target_a_directory" = never; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dst=$dstdir/`basename "$src"` - dstdir_status=0 - else - dstdir=`dirname "$dst"` - test -d "$dstdir" - dstdir_status=$? - fi - fi - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # The umask is ridiculous, or mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - [-=\(\)!]*) prefix='./';; - *) prefix='';; - esac - - oIFS=$IFS - IFS=/ - set -f - set fnord $dstdir - shift - set +f - IFS=$oIFS - - prefixes= - - for d - do - test X"$d" = X && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - set +f && - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-time-zone: "UTC" -# time-stamp-end: "; # UTC" -# End: diff --git a/src/libbacktrace/internal.h b/src/libbacktrace/internal.h deleted file mode 100644 index 73728da3f5664..0000000000000 --- a/src/libbacktrace/internal.h +++ /dev/null @@ -1,294 +0,0 @@ -/* internal.h -- Internal header file for stack backtrace library. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#ifndef BACKTRACE_INTERNAL_H -#define BACKTRACE_INTERNAL_H - -/* We assume that and "backtrace.h" have already been - included. */ - -#ifndef GCC_VERSION -# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) -#endif - -#if (GCC_VERSION < 2007) -# define __attribute__(x) -#endif - -#ifndef ATTRIBUTE_UNUSED -# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) -#endif - -#ifndef ATTRIBUTE_MALLOC -# if (GCC_VERSION >= 2096) -# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) -# else -# define ATTRIBUTE_MALLOC -# endif -#endif - -#ifndef HAVE_SYNC_FUNCTIONS - -/* Define out the sync functions. These should never be called if - they are not available. */ - -#define __sync_bool_compare_and_swap(A, B, C) (abort(), 1) -#define __sync_lock_test_and_set(A, B) (abort(), 0) -#define __sync_lock_release(A) abort() - -#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ - -#ifdef HAVE_ATOMIC_FUNCTIONS - -/* We have the atomic builtin functions. */ - -#define backtrace_atomic_load_pointer(p) \ - __atomic_load_n ((p), __ATOMIC_ACQUIRE) -#define backtrace_atomic_load_int(p) \ - __atomic_load_n ((p), __ATOMIC_ACQUIRE) -#define backtrace_atomic_store_pointer(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) -#define backtrace_atomic_store_size_t(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) -#define backtrace_atomic_store_int(p, v) \ - __atomic_store_n ((p), (v), __ATOMIC_RELEASE) - -#else /* !defined (HAVE_ATOMIC_FUNCTIONS) */ -#ifdef HAVE_SYNC_FUNCTIONS - -/* We have the sync functions but not the atomic functions. Define - the atomic ones in terms of the sync ones. */ - -extern void *backtrace_atomic_load_pointer (void *); -extern int backtrace_atomic_load_int (int *); -extern void backtrace_atomic_store_pointer (void *, void *); -extern void backtrace_atomic_store_size_t (size_t *, size_t); -extern void backtrace_atomic_store_int (int *, int); - -#else /* !defined (HAVE_SYNC_FUNCTIONS) */ - -/* We have neither the sync nor the atomic functions. These will - never be called. */ - -#define backtrace_atomic_load_pointer(p) (abort(), (void *) NULL) -#define backtrace_atomic_load_int(p) (abort(), 0) -#define backtrace_atomic_store_pointer(p, v) abort() -#define backtrace_atomic_store_size_t(p, v) abort() -#define backtrace_atomic_store_int(p, v) abort() - -#endif /* !defined (HAVE_SYNC_FUNCTIONS) */ -#endif /* !defined (HAVE_ATOMIC_FUNCTIONS) */ - -/* The type of the function that collects file/line information. This - is like backtrace_pcinfo. */ - -typedef int (*fileline) (struct backtrace_state *state, uintptr_t pc, - backtrace_full_callback callback, - backtrace_error_callback error_callback, void *data); - -/* The type of the function that collects symbol information. This is - like backtrace_syminfo. */ - -typedef void (*syminfo) (struct backtrace_state *state, uintptr_t pc, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback, void *data); - -/* What the backtrace state pointer points to. */ - -struct backtrace_state -{ - /* The name of the executable. */ - const char *filename; - /* Non-zero if threaded. */ - int threaded; - /* The master lock for fileline_fn, fileline_data, syminfo_fn, - syminfo_data, fileline_initialization_failed and everything the - data pointers point to. */ - void *lock; - /* The function that returns file/line information. */ - fileline fileline_fn; - /* The data to pass to FILELINE_FN. */ - void *fileline_data; - /* The function that returns symbol information. */ - syminfo syminfo_fn; - /* The data to pass to SYMINFO_FN. */ - void *syminfo_data; - /* Whether initializing the file/line information failed. */ - int fileline_initialization_failed; - /* The lock for the freelist. */ - int lock_alloc; - /* The freelist when using mmap. */ - struct backtrace_freelist_struct *freelist; -}; - -/* Open a file for reading. Returns -1 on error. If DOES_NOT_EXIST - is not NULL, *DOES_NOT_EXIST will be set to 0 normally and set to 1 - if the file does not exist. If the file does not exist and - DOES_NOT_EXIST is not NULL, the function will return -1 and will - not call ERROR_CALLBACK. On other errors, or if DOES_NOT_EXIST is - NULL, the function will call ERROR_CALLBACK before returning. */ -extern int backtrace_open (const char *filename, - backtrace_error_callback error_callback, - void *data, - int *does_not_exist); - -/* A view of the contents of a file. This supports mmap when - available. A view will remain in memory even after backtrace_close - is called on the file descriptor from which the view was - obtained. */ - -struct backtrace_view -{ - /* The data that the caller requested. */ - const void *data; - /* The base of the view. */ - void *base; - /* The total length of the view. */ - size_t len; -}; - -/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. Store the - result in *VIEW. Returns 1 on success, 0 on error. */ -extern int backtrace_get_view (struct backtrace_state *state, int descriptor, - off_t offset, size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_view *view); - -/* Release a view created by backtrace_get_view. */ -extern void backtrace_release_view (struct backtrace_state *state, - struct backtrace_view *view, - backtrace_error_callback error_callback, - void *data); - -/* Close a file opened by backtrace_open. Returns 1 on success, 0 on - error. */ - -extern int backtrace_close (int descriptor, - backtrace_error_callback error_callback, - void *data); - -/* Sort without using memory. */ - -extern void backtrace_qsort (void *base, size_t count, size_t size, - int (*compar) (const void *, const void *)); - -/* Allocate memory. This is like malloc. If ERROR_CALLBACK is NULL, - this does not report an error, it just returns NULL. */ - -extern void *backtrace_alloc (struct backtrace_state *state, size_t size, - backtrace_error_callback error_callback, - void *data) ATTRIBUTE_MALLOC; - -/* Free memory allocated by backtrace_alloc. If ERROR_CALLBACK is - NULL, this does not report an error. */ - -extern void backtrace_free (struct backtrace_state *state, void *mem, - size_t size, - backtrace_error_callback error_callback, - void *data); - -/* A growable vector of some struct. This is used for more efficient - allocation when we don't know the final size of some group of data - that we want to represent as an array. */ - -struct backtrace_vector -{ - /* The base of the vector. */ - void *base; - /* The number of bytes in the vector. */ - size_t size; - /* The number of bytes available at the current allocation. */ - size_t alc; -}; - -/* Grow VEC by SIZE bytes. Return a pointer to the newly allocated - bytes. Note that this may move the entire vector to a new memory - location. Returns NULL on failure. */ - -extern void *backtrace_vector_grow (struct backtrace_state *state, size_t size, - backtrace_error_callback error_callback, - void *data, - struct backtrace_vector *vec); - -/* Finish the current allocation on VEC. Prepare to start a new - allocation. The finished allocation will never be freed. Returns - a pointer to the base of the finished entries, or NULL on - failure. */ - -extern void* backtrace_vector_finish (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data); - -/* Release any extra space allocated for VEC. This may change - VEC->base. Returns 1 on success, 0 on failure. */ - -extern int backtrace_vector_release (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data); - -/* Read initial debug data from a descriptor, and set the - fileline_data, syminfo_fn, and syminfo_data fields of STATE. - Return the fileln_fn field in *FILELN_FN--this is done this way so - that the synchronization code is only implemented once. This is - called after the descriptor has first been opened. It will close - the descriptor if it is no longer needed. Returns 1 on success, 0 - on error. There will be multiple implementations of this function, - for different file formats. Each system will compile the - appropriate one. */ - -extern int backtrace_initialize (struct backtrace_state *state, - int descriptor, - backtrace_error_callback error_callback, - void *data, - fileline *fileline_fn); - -/* Add file/line information for a DWARF module. */ - -extern int backtrace_dwarf_add (struct backtrace_state *state, - uintptr_t base_address, - const unsigned char* dwarf_info, - size_t dwarf_info_size, - const unsigned char *dwarf_line, - size_t dwarf_line_size, - const unsigned char *dwarf_abbrev, - size_t dwarf_abbrev_size, - const unsigned char *dwarf_ranges, - size_t dwarf_range_size, - const unsigned char *dwarf_str, - size_t dwarf_str_size, - int is_bigendian, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn); - -#endif diff --git a/src/libbacktrace/ltmain.sh b/src/libbacktrace/ltmain.sh deleted file mode 100644 index fd23815fc617a..0000000000000 --- a/src/libbacktrace/ltmain.sh +++ /dev/null @@ -1,8636 +0,0 @@ -# Generated from ltmain.m4sh. - -# libtool (GNU libtool 1.3134 2009-11-29) 2.2.7a -# Written by Gordon Matzigkeit , 1996 - -# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, -# 2007, 2008, 2009 Free Software Foundation, Inc. -# This is free software; see the source for copying conditions. There is NO -# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - -# GNU Libtool is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# As a special exception to the GNU General Public License, -# if you distribute this file as part of a program or library that -# is built using GNU Libtool, you may include this file under the -# same distribution terms that you use for the rest of that program. -# -# GNU Libtool is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with GNU Libtool; see the file COPYING. If not, a copy -# can be downloaded from http://www.gnu.org/licenses/gpl.html, -# or obtained by writing to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -# Usage: $progname [OPTION]... [MODE-ARG]... -# -# Provide generalized library-building support services. -# -# --config show all configuration variables -# --debug enable verbose shell tracing -# -n, --dry-run display commands without modifying any files -# --features display basic configuration information and exit -# --mode=MODE use operation mode MODE -# --no-finish let install mode avoid finish commands -# --preserve-dup-deps don't remove duplicate dependency libraries -# --quiet, --silent don't print informational messages -# --no-quiet, --no-silent -# print informational messages (default) -# --tag=TAG use configuration variables from tag TAG -# -v, --verbose print more informational messages than default -# --no-verbose don't print the extra informational messages -# --version print version information -# -h, --help, --help-all print short, long, or detailed help message -# -# MODE must be one of the following: -# -# clean remove files from the build directory -# compile compile a source file into a libtool object -# execute automatically set library path, then run a program -# finish complete the installation of libtool libraries -# install install libraries or executables -# link create a library or an executable -# uninstall remove libraries from an installed directory -# -# MODE-ARGS vary depending on the MODE. When passed as first option, -# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that. -# Try `$progname --help --mode=MODE' for a more detailed description of MODE. -# -# When reporting a bug, please describe a test case to reproduce it and -# include the following information: -# -# host-triplet: $host -# shell: $SHELL -# compiler: $LTCC -# compiler flags: $LTCFLAGS -# linker: $LD (gnu? $with_gnu_ld) -# $progname: (GNU libtool 1.3134 2009-11-29) 2.2.7a -# automake: $automake_version -# autoconf: $autoconf_version -# -# Report bugs to . - -PROGRAM=libtool -PACKAGE=libtool -VERSION=2.2.7a -TIMESTAMP=" 1.3134 2009-11-29" -package_revision=1.3134 - -# Be Bourne compatible -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which - # is contrary to our usage. Disable this feature. - alias -g '${1+"$@"}'='"$@"' - setopt NO_GLOB_SUBST -else - case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -$1 -_LTECHO_EOF' -} - -# NLS nuisances: We save the old values to restore during execute mode. -# Only set LANG and LC_ALL to C if already set. -# These must not be set unconditionally because not all systems understand -# e.g. LANG=C (notably SCO). -lt_user_locale= -lt_safe_locale= -for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES -do - eval "if test \"\${$lt_var+set}\" = set; then - save_$lt_var=\$$lt_var - $lt_var=C - export $lt_var - lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\" - lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\" - fi" -done - -$lt_unset CDPATH - - - - - - - -# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh -# is ksh but when the shell is invoked as "sh" and the current value of -# the _XPG environment variable is not equal to 1 (one), the special -# positional parameter $0, within a function call, is the name of the -# function. -progpath="$0" - - - -: ${CP="cp -f"} -: ${ECHO=$as_echo} -: ${EGREP="/bin/grep -E"} -: ${FGREP="/bin/grep -F"} -: ${GREP="/bin/grep"} -: ${LN_S="ln -s"} -: ${MAKE="make"} -: ${MKDIR="mkdir"} -: ${MV="mv -f"} -: ${RM="rm -f"} -: ${SED="/mount/endor/wildenhu/local-x86_64/bin/sed"} -: ${SHELL="${CONFIG_SHELL-/bin/sh}"} -: ${Xsed="$SED -e 1s/^X//"} - -# Global variables: -EXIT_SUCCESS=0 -EXIT_FAILURE=1 -EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing. -EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake. - -exit_status=$EXIT_SUCCESS - -# Make sure IFS has a sensible default -lt_nl=' -' -IFS=" $lt_nl" - -dirname="s,/[^/]*$,," -basename="s,^.*/,," - -# func_dirname_and_basename file append nondir_replacement -# perform func_basename and func_dirname in a single function -# call: -# dirname: Compute the dirname of FILE. If nonempty, -# add APPEND to the result, otherwise set result -# to NONDIR_REPLACEMENT. -# value returned in "$func_dirname_result" -# basename: Compute filename of FILE. -# value returned in "$func_basename_result" -# Implementation must be kept synchronized with func_dirname -# and func_basename. For efficiency, we do not delegate to -# those functions but instead duplicate the functionality here. -func_dirname_and_basename () -{ - # Extract subdirectory from the argument. - func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"` - if test "X$func_dirname_result" = "X${1}"; then - func_dirname_result="${3}" - else - func_dirname_result="$func_dirname_result${2}" - fi - func_basename_result=`$ECHO "${1}" | $SED -e "$basename"` -} - -# Generated shell functions inserted here. - -# These SED scripts presuppose an absolute path with a trailing slash. -pathcar='s,^/\([^/]*\).*$,\1,' -pathcdr='s,^/[^/]*,,' -removedotparts=':dotsl - s@/\./@/@g - t dotsl - s,/\.$,/,' -collapseslashes='s@/\{1,\}@/@g' -finalslash='s,/*$,/,' - -# func_normal_abspath PATH -# Remove doubled-up and trailing slashes, "." path components, -# and cancel out any ".." path components in PATH after making -# it an absolute path. -# value returned in "$func_normal_abspath_result" -func_normal_abspath () -{ - # Start from root dir and reassemble the path. - func_normal_abspath_result= - func_normal_abspath_tpath=$1 - func_normal_abspath_altnamespace= - case $func_normal_abspath_tpath in - "") - # Empty path, that just means $cwd. - func_stripname '' '/' "`pwd`" - func_normal_abspath_result=$func_stripname_result - return - ;; - # The next three entries are used to spot a run of precisely - # two leading slashes without using negated character classes; - # we take advantage of case's first-match behaviour. - ///*) - # Unusual form of absolute path, do nothing. - ;; - //*) - # Not necessarily an ordinary path; POSIX reserves leading '//' - # and for example Cygwin uses it to access remote file shares - # over CIFS/SMB, so we conserve a leading double slash if found. - func_normal_abspath_altnamespace=/ - ;; - /*) - # Absolute path, do nothing. - ;; - *) - # Relative path, prepend $cwd. - func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath - ;; - esac - # Cancel out all the simple stuff to save iterations. We also want - # the path to end with a slash for ease of parsing, so make sure - # there is one (and only one) here. - func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"` - while :; do - # Processed it all yet? - if test "$func_normal_abspath_tpath" = / ; then - # If we ascended to the root using ".." the result may be empty now. - if test -z "$func_normal_abspath_result" ; then - func_normal_abspath_result=/ - fi - break - fi - func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$pathcar"` - func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \ - -e "$pathcdr"` - # Figure out what to do with it - case $func_normal_abspath_tcomponent in - "") - # Trailing empty path component, ignore it. - ;; - ..) - # Parent dir; strip last assembled component from result. - func_dirname "$func_normal_abspath_result" - func_normal_abspath_result=$func_dirname_result - ;; - *) - # Actual path component, append it. - func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent - ;; - esac - done - # Restore leading double-slash if one was found on entry. - func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result -} - -# func_relative_path SRCDIR DSTDIR -# generates a relative path from SRCDIR to DSTDIR, with a trailing -# slash if non-empty, suitable for immediately appending a filename -# without needing to append a separator. -# value returned in "$func_relative_path_result" -func_relative_path () -{ - func_relative_path_result= - func_normal_abspath "$1" - func_relative_path_tlibdir=$func_normal_abspath_result - func_normal_abspath "$2" - func_relative_path_tbindir=$func_normal_abspath_result - - # Ascend the tree starting from libdir - while :; do - # check if we have found a prefix of bindir - case $func_relative_path_tbindir in - $func_relative_path_tlibdir) - # found an exact match - func_relative_path_tcancelled= - break - ;; - $func_relative_path_tlibdir*) - # found a matching prefix - func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir" - func_relative_path_tcancelled=$func_stripname_result - if test -z "$func_relative_path_result"; then - func_relative_path_result=. - fi - break - ;; - *) - func_dirname $func_relative_path_tlibdir - func_relative_path_tlibdir=${func_dirname_result} - if test "x$func_relative_path_tlibdir" = x ; then - # Have to descend all the way to the root! - func_relative_path_result=../$func_relative_path_result - func_relative_path_tcancelled=$func_relative_path_tbindir - break - fi - func_relative_path_result=../$func_relative_path_result - ;; - esac - done - - # Now calculate path; take care to avoid doubling-up slashes. - func_stripname '' '/' "$func_relative_path_result" - func_relative_path_result=$func_stripname_result - func_stripname '/' '/' "$func_relative_path_tcancelled" - if test "x$func_stripname_result" != x ; then - func_relative_path_result=${func_relative_path_result}/${func_stripname_result} - fi - - # Normalisation. If bindir is libdir, return empty string, - # else relative path ending with a slash; either way, target - # file name can be directly appended. - if test ! -z "$func_relative_path_result"; then - func_stripname './' '' "$func_relative_path_result/" - func_relative_path_result=$func_stripname_result - fi -} - -# The name of this program: -func_dirname_and_basename "$progpath" -progname=$func_basename_result - -# Make sure we have an absolute path for reexecution: -case $progpath in - [\\/]*|[A-Za-z]:\\*) ;; - *[\\/]*) - progdir=$func_dirname_result - progdir=`cd "$progdir" && pwd` - progpath="$progdir/$progname" - ;; - *) - save_IFS="$IFS" - IFS=: - for progdir in $PATH; do - IFS="$save_IFS" - test -x "$progdir/$progname" && break - done - IFS="$save_IFS" - test -n "$progdir" || progdir=`pwd` - progpath="$progdir/$progname" - ;; -esac - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -Xsed="${SED}"' -e 1s/^X//' -sed_quote_subst='s/\([`"$\\]\)/\\\1/g' - -# Same as above, but do not quote variable references. -double_quote_subst='s/\(["`\\]\)/\\\1/g' - -# Re-`\' parameter expansions in output of double_quote_subst that were -# `\'-ed in input to the same. If an odd number of `\' preceded a '$' -# in input to double_quote_subst, that '$' was protected from expansion. -# Since each input `\' is now two `\'s, look for any number of runs of -# four `\'s followed by two `\'s and then a '$'. `\' that '$'. -bs='\\' -bs2='\\\\' -bs4='\\\\\\\\' -dollar='\$' -sed_double_backslash="\ - s/$bs4/&\\ -/g - s/^$bs2$dollar/$bs&/ - s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g - s/\n//g" - -# Standard options: -opt_dry_run=false -opt_help=false -opt_quiet=false -opt_verbose=false -opt_warning=: - -# func_echo arg... -# Echo program name prefixed message, along with the current mode -# name if it has been set yet. -func_echo () -{ - $ECHO "$progname${mode+: }$mode: $*" -} - -# func_verbose arg... -# Echo program name prefixed message in verbose mode only. -func_verbose () -{ - $opt_verbose && func_echo ${1+"$@"} - - # A bug in bash halts the script if the last line of a function - # fails when set -e is in force, so we need another command to - # work around that: - : -} - -# func_echo_all arg... -# Invoke $ECHO with all args, space-separated. -func_echo_all () -{ - $ECHO "$*" -} - -# func_error arg... -# Echo program name prefixed message to standard error. -func_error () -{ - $ECHO "$progname${mode+: }$mode: "${1+"$@"} 1>&2 -} - -# func_warning arg... -# Echo program name prefixed warning message to standard error. -func_warning () -{ - $opt_warning && $ECHO "$progname${mode+: }$mode: warning: "${1+"$@"} 1>&2 - - # bash bug again: - : -} - -# func_fatal_error arg... -# Echo program name prefixed message to standard error, and exit. -func_fatal_error () -{ - func_error ${1+"$@"} - exit $EXIT_FAILURE -} - -# func_fatal_help arg... -# Echo program name prefixed message to standard error, followed by -# a help hint, and exit. -func_fatal_help () -{ - func_error ${1+"$@"} - func_fatal_error "$help" -} -help="Try \`$progname --help' for more information." ## default - - -# func_grep expression filename -# Check whether EXPRESSION matches any line of FILENAME, without output. -func_grep () -{ - $GREP "$1" "$2" >/dev/null 2>&1 -} - - -# func_mkdir_p directory-path -# Make sure the entire path to DIRECTORY-PATH is available. -func_mkdir_p () -{ - my_directory_path="$1" - my_dir_list= - - if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then - - # Protect directory names starting with `-' - case $my_directory_path in - -*) my_directory_path="./$my_directory_path" ;; - esac - - # While some portion of DIR does not yet exist... - while test ! -d "$my_directory_path"; do - # ...make a list in topmost first order. Use a colon delimited - # list in case some portion of path contains whitespace. - my_dir_list="$my_directory_path:$my_dir_list" - - # If the last portion added has no slash in it, the list is done - case $my_directory_path in */*) ;; *) break ;; esac - - # ...otherwise throw away the child directory and loop - my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"` - done - my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'` - - save_mkdir_p_IFS="$IFS"; IFS=':' - for my_dir in $my_dir_list; do - IFS="$save_mkdir_p_IFS" - # mkdir can fail with a `File exist' error if two processes - # try to create one of the directories concurrently. Don't - # stop in that case! - $MKDIR "$my_dir" 2>/dev/null || : - done - IFS="$save_mkdir_p_IFS" - - # Bail out if we (or some other process) failed to create a directory. - test -d "$my_directory_path" || \ - func_fatal_error "Failed to create \`$1'" - fi -} - - -# func_mktempdir [string] -# Make a temporary directory that won't clash with other running -# libtool processes, and avoids race conditions if possible. If -# given, STRING is the basename for that directory. -func_mktempdir () -{ - my_template="${TMPDIR-/tmp}/${1-$progname}" - - if test "$opt_dry_run" = ":"; then - # Return a directory name, but don't create it in dry-run mode - my_tmpdir="${my_template}-$$" - else - - # If mktemp works, use that first and foremost - my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null` - - if test ! -d "$my_tmpdir"; then - # Failing that, at least try and use $RANDOM to avoid a race - my_tmpdir="${my_template}-${RANDOM-0}$$" - - save_mktempdir_umask=`umask` - umask 0077 - $MKDIR "$my_tmpdir" - umask $save_mktempdir_umask - fi - - # If we're not in dry-run mode, bomb out on failure - test -d "$my_tmpdir" || \ - func_fatal_error "cannot create temporary directory \`$my_tmpdir'" - fi - - $ECHO "$my_tmpdir" -} - - -# func_quote_for_eval arg -# Aesthetically quote ARG to be evaled later. -# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT -# is double-quoted, suitable for a subsequent eval, whereas -# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters -# which are still active within double quotes backslashified. -func_quote_for_eval () -{ - case $1 in - *[\\\`\"\$]*) - func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;; - *) - func_quote_for_eval_unquoted_result="$1" ;; - esac - - case $func_quote_for_eval_unquoted_result in - # Double-quote args containing shell metacharacters to delay - # word splitting, command substitution and and variable - # expansion for a subsequent eval. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\"" - ;; - *) - func_quote_for_eval_result="$func_quote_for_eval_unquoted_result" - esac -} - - -# func_quote_for_expand arg -# Aesthetically quote ARG to be evaled later; same as above, -# but do not quote variable references. -func_quote_for_expand () -{ - case $1 in - *[\\\`\"]*) - my_arg=`$ECHO "$1" | $SED \ - -e "$double_quote_subst" -e "$sed_double_backslash"` ;; - *) - my_arg="$1" ;; - esac - - case $my_arg in - # Double-quote args containing shell metacharacters to delay - # word splitting and command substitution for a subsequent eval. - # Many Bourne shells cannot handle close brackets correctly - # in scan sets, so we specify it separately. - *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"") - my_arg="\"$my_arg\"" - ;; - esac - - func_quote_for_expand_result="$my_arg" -} - - -# func_show_eval cmd [fail_exp] -# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is -# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP -# is given, then evaluate it. -func_show_eval () -{ - my_cmd="$1" - my_fail_exp="${2-:}" - - ${opt_silent-false} || { - func_quote_for_expand "$my_cmd" - eval "func_echo $func_quote_for_expand_result" - } - - if ${opt_dry_run-false}; then :; else - eval "$my_cmd" - my_status=$? - if test "$my_status" -eq 0; then :; else - eval "(exit $my_status); $my_fail_exp" - fi - fi -} - - -# func_show_eval_locale cmd [fail_exp] -# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is -# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP -# is given, then evaluate it. Use the saved locale for evaluation. -func_show_eval_locale () -{ - my_cmd="$1" - my_fail_exp="${2-:}" - - ${opt_silent-false} || { - func_quote_for_expand "$my_cmd" - eval "func_echo $func_quote_for_expand_result" - } - - if ${opt_dry_run-false}; then :; else - eval "$lt_user_locale - $my_cmd" - my_status=$? - eval "$lt_safe_locale" - if test "$my_status" -eq 0; then :; else - eval "(exit $my_status); $my_fail_exp" - fi - fi -} - - - - - -# func_version -# Echo version message to standard output and exit. -func_version () -{ - $SED -n '/(C)/!b go - :more - /\./!{ - N - s/\n# // - b more - } - :go - /^# '$PROGRAM' (GNU /,/# warranty; / { - s/^# // - s/^# *$// - s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/ - p - }' < "$progpath" - exit $? -} - -# func_usage -# Echo short help message to standard output and exit. -func_usage () -{ - $SED -n '/^# Usage:/,/^# *-h/ { - s/^# // - s/^# *$// - s/\$progname/'$progname'/ - p - }' < "$progpath" - echo - $ECHO "run \`$progname --help | more' for full usage" - exit $? -} - -# func_help [NOEXIT] -# Echo long help message to standard output and exit, -# unless 'noexit' is passed as argument. -func_help () -{ - $SED -n '/^# Usage:/,/# Report bugs to/ { - s/^# // - s/^# *$// - s*\$progname*'$progname'* - s*\$host*'"$host"'* - s*\$SHELL*'"$SHELL"'* - s*\$LTCC*'"$LTCC"'* - s*\$LTCFLAGS*'"$LTCFLAGS"'* - s*\$LD*'"$LD"'* - s/\$with_gnu_ld/'"$with_gnu_ld"'/ - s/\$automake_version/'"`(automake --version) 2>/dev/null |$SED 1q`"'/ - s/\$autoconf_version/'"`(autoconf --version) 2>/dev/null |$SED 1q`"'/ - p - }' < "$progpath" - ret=$? - if test -z "$1"; then - exit $ret - fi -} - -# func_missing_arg argname -# Echo program name prefixed message to standard error and set global -# exit_cmd. -func_missing_arg () -{ - func_error "missing argument for $1" - exit_cmd=exit -} - -exit_cmd=: - - - - - - -magic="%%%MAGIC variable%%%" -magic_exe="%%%MAGIC EXE variable%%%" - -# Global variables. -# $mode is unset -nonopt= -execute_dlfiles= -preserve_args= -lo2o="s/\\.lo\$/.${objext}/" -o2lo="s/\\.${objext}\$/.lo/" -extracted_archives= -extracted_serial=0 - -opt_dry_run=false -opt_finish=: -opt_duplicate_deps=false -opt_silent=false -opt_debug=: - -# If this variable is set in any of the actions, the command in it -# will be execed at the end. This prevents here-documents from being -# left over by shells. -exec_cmd= - -# func_fatal_configuration arg... -# Echo program name prefixed message to standard error, followed by -# a configuration failure hint, and exit. -func_fatal_configuration () -{ - func_error ${1+"$@"} - func_error "See the $PACKAGE documentation for more information." - func_fatal_error "Fatal configuration error." -} - - -# func_config -# Display the configuration for all the tags in this script. -func_config () -{ - re_begincf='^# ### BEGIN LIBTOOL' - re_endcf='^# ### END LIBTOOL' - - # Default configuration. - $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath" - - # Now print the configurations for the tags. - for tagname in $taglist; do - $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath" - done - - exit $? -} - -# func_features -# Display the features supported by this script. -func_features () -{ - echo "host: $host" - if test "$build_libtool_libs" = yes; then - echo "enable shared libraries" - else - echo "disable shared libraries" - fi - if test "$build_old_libs" = yes; then - echo "enable static libraries" - else - echo "disable static libraries" - fi - - exit $? -} - -# func_enable_tag tagname -# Verify that TAGNAME is valid, and either flag an error and exit, or -# enable the TAGNAME tag. We also add TAGNAME to the global $taglist -# variable here. -func_enable_tag () -{ - # Global variable: - tagname="$1" - - re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$" - re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$" - sed_extractcf="/$re_begincf/,/$re_endcf/p" - - # Validate tagname. - case $tagname in - *[!-_A-Za-z0-9,/]*) - func_fatal_error "invalid tag name: $tagname" - ;; - esac - - # Don't test for the "default" C tag, as we know it's - # there but not specially marked. - case $tagname in - CC) ;; - *) - if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then - taglist="$taglist $tagname" - - # Evaluate the configuration. Be careful to quote the path - # and the sed script, to avoid splitting on whitespace, but - # also don't use non-portable quotes within backquotes within - # quotes we have to do it in 2 steps: - extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"` - eval "$extractedcf" - else - func_error "ignoring unknown tag $tagname" - fi - ;; - esac -} - -# Parse options once, thoroughly. This comes as soon as possible in -# the script to make things like `libtool --version' happen quickly. -{ - - # Shorthand for --mode=foo, only valid as the first argument - case $1 in - clean|clea|cle|cl) - shift; set dummy --mode clean ${1+"$@"}; shift - ;; - compile|compil|compi|comp|com|co|c) - shift; set dummy --mode compile ${1+"$@"}; shift - ;; - execute|execut|execu|exec|exe|ex|e) - shift; set dummy --mode execute ${1+"$@"}; shift - ;; - finish|finis|fini|fin|fi|f) - shift; set dummy --mode finish ${1+"$@"}; shift - ;; - install|instal|insta|inst|ins|in|i) - shift; set dummy --mode install ${1+"$@"}; shift - ;; - link|lin|li|l) - shift; set dummy --mode link ${1+"$@"}; shift - ;; - uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u) - shift; set dummy --mode uninstall ${1+"$@"}; shift - ;; - esac - - # Parse non-mode specific arguments: - while test "$#" -gt 0; do - opt="$1" - shift - - case $opt in - --config) func_config ;; - - --debug) preserve_args="$preserve_args $opt" - func_echo "enabling shell trace mode" - opt_debug='set -x' - $opt_debug - ;; - - -dlopen) test "$#" -eq 0 && func_missing_arg "$opt" && break - execute_dlfiles="$execute_dlfiles $1" - shift - ;; - - --dry-run | -n) opt_dry_run=: ;; - --features) func_features ;; - --finish) mode="finish" ;; - --no-finish) opt_finish=false ;; - - --mode) test "$#" -eq 0 && func_missing_arg "$opt" && break - case $1 in - # Valid mode arguments: - clean) ;; - compile) ;; - execute) ;; - finish) ;; - install) ;; - link) ;; - relink) ;; - uninstall) ;; - - # Catch anything else as an error - *) func_error "invalid argument for $opt" - exit_cmd=exit - break - ;; - esac - - mode="$1" - shift - ;; - - --preserve-dup-deps) - opt_duplicate_deps=: ;; - - --quiet|--silent) preserve_args="$preserve_args $opt" - opt_silent=: - opt_verbose=false - ;; - - --no-quiet|--no-silent) - preserve_args="$preserve_args $opt" - opt_silent=false - ;; - - --verbose| -v) preserve_args="$preserve_args $opt" - opt_silent=false - opt_verbose=: - ;; - - --no-verbose) preserve_args="$preserve_args $opt" - opt_verbose=false - ;; - - --tag) test "$#" -eq 0 && func_missing_arg "$opt" && break - preserve_args="$preserve_args $opt $1" - func_enable_tag "$1" # tagname is set here - shift - ;; - - # Separate optargs to long options: - -dlopen=*|--mode=*|--tag=*) - func_opt_split "$opt" - set dummy "$func_opt_split_opt" "$func_opt_split_arg" ${1+"$@"} - shift - ;; - - -\?|-h) func_usage ;; - --help) opt_help=: ;; - --help-all) opt_help=': help-all' ;; - --version) func_version ;; - - -*) func_fatal_help "unrecognized option \`$opt'" ;; - - *) nonopt="$opt" - break - ;; - esac - done - - - case $host in - *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* ) - # don't eliminate duplications in $postdeps and $predeps - opt_duplicate_compiler_generated_deps=: - ;; - *) - opt_duplicate_compiler_generated_deps=$opt_duplicate_deps - ;; - esac - - # Having warned about all mis-specified options, bail out if - # anything was wrong. - $exit_cmd $EXIT_FAILURE -} - -# func_check_version_match -# Ensure that we are using m4 macros, and libtool script from the same -# release of libtool. -func_check_version_match () -{ - if test "$package_revision" != "$macro_revision"; then - if test "$VERSION" != "$macro_version"; then - if test -z "$macro_version"; then - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from an older release. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, but the -$progname: definition of this LT_INIT comes from $PACKAGE $macro_version. -$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION -$progname: and run autoconf again. -_LT_EOF - fi - else - cat >&2 <<_LT_EOF -$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision, -$progname: but the definition of this LT_INIT comes from revision $macro_revision. -$progname: You should recreate aclocal.m4 with macros from revision $package_revision -$progname: of $PACKAGE $VERSION and run autoconf again. -_LT_EOF - fi - - exit $EXIT_MISMATCH - fi -} - - -## ----------- ## -## Main. ## -## ----------- ## - -$opt_help || { - # Sanity checks first: - func_check_version_match - - if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then - func_fatal_configuration "not configured to build any kind of library" - fi - - test -z "$mode" && func_fatal_error "error: you must specify a MODE." - - - # Darwin sucks - eval "std_shrext=\"$shrext_cmds\"" - - - # Only execute mode is allowed to have -dlopen flags. - if test -n "$execute_dlfiles" && test "$mode" != execute; then - func_error "unrecognized option \`-dlopen'" - $ECHO "$help" 1>&2 - exit $EXIT_FAILURE - fi - - # Change the help message to a mode-specific one. - generic_help="$help" - help="Try \`$progname --help --mode=$mode' for more information." -} - - -# func_lalib_p file -# True iff FILE is a libtool `.la' library or `.lo' object file. -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_lalib_p () -{ - test -f "$1" && - $SED -e 4q "$1" 2>/dev/null \ - | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1 -} - -# func_lalib_unsafe_p file -# True iff FILE is a libtool `.la' library or `.lo' object file. -# This function implements the same check as func_lalib_p without -# resorting to external programs. To this end, it redirects stdin and -# closes it afterwards, without saving the original file descriptor. -# As a safety measure, use it only where a negative result would be -# fatal anyway. Works if `file' does not exist. -func_lalib_unsafe_p () -{ - lalib_p=no - if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then - for lalib_p_l in 1 2 3 4 - do - read lalib_p_line - case "$lalib_p_line" in - \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;; - esac - done - exec 0<&5 5<&- - fi - test "$lalib_p" = yes -} - -# func_ltwrapper_script_p file -# True iff FILE is a libtool wrapper script -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_script_p () -{ - func_lalib_p "$1" -} - -# func_ltwrapper_executable_p file -# True iff FILE is a libtool wrapper executable -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_executable_p () -{ - func_ltwrapper_exec_suffix= - case $1 in - *.exe) ;; - *) func_ltwrapper_exec_suffix=.exe ;; - esac - $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1 -} - -# func_ltwrapper_scriptname file -# Assumes file is an ltwrapper_executable -# uses $file to determine the appropriate filename for a -# temporary ltwrapper_script. -func_ltwrapper_scriptname () -{ - func_ltwrapper_scriptname_result="" - if func_ltwrapper_executable_p "$1"; then - func_dirname_and_basename "$1" "" "." - func_stripname '' '.exe' "$func_basename_result" - func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper" - fi -} - -# func_ltwrapper_p file -# True iff FILE is a libtool wrapper script or wrapper executable -# This function is only a basic sanity check; it will hardly flush out -# determined imposters. -func_ltwrapper_p () -{ - func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1" -} - - -# func_execute_cmds commands fail_cmd -# Execute tilde-delimited COMMANDS. -# If FAIL_CMD is given, eval that upon failure. -# FAIL_CMD may read-access the current command in variable CMD! -func_execute_cmds () -{ - $opt_debug - save_ifs=$IFS; IFS='~' - for cmd in $1; do - IFS=$save_ifs - eval "cmd=\"$cmd\"" - func_show_eval "$cmd" "${2-:}" - done - IFS=$save_ifs -} - - -# func_source file -# Source FILE, adding directory component if necessary. -# Note that it is not necessary on cygwin/mingw to append a dot to -# FILE even if both FILE and FILE.exe exist: automatic-append-.exe -# behavior happens only for exec(3), not for open(2)! Also, sourcing -# `FILE.' does not work on cygwin managed mounts. -func_source () -{ - $opt_debug - case $1 in - */* | *\\*) . "$1" ;; - *) . "./$1" ;; - esac -} - - -# func_infer_tag arg -# Infer tagged configuration to use if any are available and -# if one wasn't chosen via the "--tag" command line option. -# Only attempt this if the compiler in the base compile -# command doesn't match the default compiler. -# arg is usually of the form 'gcc ...' -func_infer_tag () -{ - $opt_debug - if test -n "$available_tags" && test -z "$tagname"; then - CC_quoted= - for arg in $CC; do - func_quote_for_eval "$arg" - CC_quoted="$CC_quoted $func_quote_for_eval_result" - done - CC_expanded=`func_echo_all $CC` - CC_quoted_expanded=`func_echo_all $CC_quoted` - case $@ in - # Blanks in the command may have been stripped by the calling shell, - # but not from the CC environment variable when configure was run. - " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ - " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;; - # Blanks at the start of $base_compile will cause this to fail - # if we don't check for them as well. - *) - for z in $available_tags; do - if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then - # Evaluate the configuration. - eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`" - CC_quoted= - for arg in $CC; do - # Double-quote args containing other shell metacharacters. - func_quote_for_eval "$arg" - CC_quoted="$CC_quoted $func_quote_for_eval_result" - done - CC_expanded=`func_echo_all $CC` - CC_quoted_expanded=`func_echo_all $CC_quoted` - case "$@ " in - " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \ - " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) - # The compiler in the base compile command matches - # the one in the tagged configuration. - # Assume this is the tagged configuration we want. - tagname=$z - break - ;; - esac - fi - done - # If $tagname still isn't set, then no tagged configuration - # was found and let the user know that the "--tag" command - # line option must be used. - if test -z "$tagname"; then - func_echo "unable to infer tagged configuration" - func_fatal_error "specify a tag with \`--tag'" -# else -# func_verbose "using $tagname tagged configuration" - fi - ;; - esac - fi -} - - - -# func_write_libtool_object output_name pic_name nonpic_name -# Create a libtool object file (analogous to a ".la" file), -# but don't create it if we're doing a dry run. -func_write_libtool_object () -{ - write_libobj=${1} - if test "$build_libtool_libs" = yes; then - write_lobj=\'${2}\' - else - write_lobj=none - fi - - if test "$build_old_libs" = yes; then - write_oldobj=\'${3}\' - else - write_oldobj=none - fi - - $opt_dry_run || { - cat >${write_libobj}T <?"'"'"' &()|`$[]' \ - && func_warning "libobj name \`$libobj' may not contain shell special characters." - func_dirname_and_basename "$obj" "/" "" - objname="$func_basename_result" - xdir="$func_dirname_result" - lobj=${xdir}$objdir/$objname - - test -z "$base_compile" && \ - func_fatal_help "you must specify a compilation command" - - # Delete any leftover library objects. - if test "$build_old_libs" = yes; then - removelist="$obj $lobj $libobj ${libobj}T" - else - removelist="$lobj $libobj ${libobj}T" - fi - - # On Cygwin there's no "real" PIC flag so we must build both object types - case $host_os in - cygwin* | mingw* | pw32* | os2* | cegcc*) - pic_mode=default - ;; - esac - if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then - # non-PIC code in shared libraries is not supported - pic_mode=default - fi - - # Calculate the filename of the output object if compiler does - # not support -o with -c - if test "$compiler_c_o" = no; then - output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext} - lockfile="$output_obj.lock" - else - output_obj= - need_locks=no - lockfile= - fi - - # Lock this critical section if it is needed - # We use this script file to make the link, it avoids creating a new file - if test "$need_locks" = yes; then - until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do - func_echo "Waiting for $lockfile to be removed" - sleep 2 - done - elif test "$need_locks" = warn; then - if test -f "$lockfile"; then - $ECHO "\ -*** ERROR, $lockfile exists and contains: -`cat $lockfile 2>/dev/null` - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - removelist="$removelist $output_obj" - $ECHO "$srcfile" > "$lockfile" - fi - - $opt_dry_run || $RM $removelist - removelist="$removelist $lockfile" - trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15 - - if test -n "$fix_srcfile_path"; then - eval "srcfile=\"$fix_srcfile_path\"" - fi - func_quote_for_eval "$srcfile" - qsrcfile=$func_quote_for_eval_result - - # Only build a PIC object if we are building libtool libraries. - if test "$build_libtool_libs" = yes; then - # Without this assignment, base_compile gets emptied. - fbsd_hideous_sh_bug=$base_compile - - if test "$pic_mode" != no; then - command="$base_compile $qsrcfile $pic_flag" - else - # Don't build PIC code - command="$base_compile $qsrcfile" - fi - - func_mkdir_p "$xdir$objdir" - - if test -z "$output_obj"; then - # Place PIC objects in $objdir - command="$command -o $lobj" - fi - - func_show_eval_locale "$command" \ - 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE' - - if test "$need_locks" = warn && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $ECHO "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed, then go on to compile the next one - if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then - func_show_eval '$MV "$output_obj" "$lobj"' \ - 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi - - # Allow error messages only from the first compilation. - if test "$suppress_opt" = yes; then - suppress_output=' >/dev/null 2>&1' - fi - fi - - # Only build a position-dependent object if we build old libraries. - if test "$build_old_libs" = yes; then - if test "$pic_mode" != yes; then - # Don't build PIC code - command="$base_compile $qsrcfile$pie_flag" - else - command="$base_compile $qsrcfile $pic_flag" - fi - if test "$compiler_c_o" = yes; then - command="$command -o $obj" - fi - - # Suppress compiler output if we already did a PIC compilation. - command="$command$suppress_output" - func_show_eval_locale "$command" \ - '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' - - if test "$need_locks" = warn && - test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then - $ECHO "\ -*** ERROR, $lockfile contains: -`cat $lockfile 2>/dev/null` - -but it should contain: -$srcfile - -This indicates that another process is trying to use the same -temporary object file, and libtool could not work around it because -your compiler does not support \`-c' and \`-o' together. If you -repeat this compilation, it may succeed, by chance, but you had better -avoid parallel builds (make -j) in this platform, or get a better -compiler." - - $opt_dry_run || $RM $removelist - exit $EXIT_FAILURE - fi - - # Just move the object if needed - if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then - func_show_eval '$MV "$output_obj" "$obj"' \ - 'error=$?; $opt_dry_run || $RM $removelist; exit $error' - fi - fi - - $opt_dry_run || { - func_write_libtool_object "$libobj" "$objdir/$objname" "$objname" - - # Unlock the critical section if it was locked - if test "$need_locks" != no; then - removelist=$lockfile - $RM "$lockfile" - fi - } - - exit $EXIT_SUCCESS -} - -$opt_help || { - test "$mode" = compile && func_mode_compile ${1+"$@"} -} - -func_mode_help () -{ - # We need to display help for each of the modes. - case $mode in - "") - # Generic help is extracted from the usage comments - # at the start of this file. - func_help - ;; - - clean) - $ECHO \ -"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE... - -Remove files from the build directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, object or program, all the files associated -with it are deleted. Otherwise, only FILE itself is deleted using RM." - ;; - - compile) - $ECHO \ -"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE - -Compile a source file into a libtool library object. - -This mode accepts the following additional options: - - -o OUTPUT-FILE set the output file name to OUTPUT-FILE - -no-suppress do not suppress compiler output for multiple passes - -prefer-pic try to building PIC objects only - -prefer-non-pic try to building non-PIC objects only - -shared do not build a \`.o' file suitable for static linking - -static only build a \`.o' file suitable for static linking - -Wc,FLAG pass FLAG directly to the compiler - -COMPILE-COMMAND is a command to be used in creating a \`standard' object file -from the given SOURCEFILE. - -The output file name is determined by removing the directory component from -SOURCEFILE, then substituting the C source code suffix \`.c' with the -library object suffix, \`.lo'." - ;; - - execute) - $ECHO \ -"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]... - -Automatically set library path, then run a program. - -This mode accepts the following additional options: - - -dlopen FILE add the directory containing FILE to the library path - -This mode sets the library path environment variable according to \`-dlopen' -flags. - -If any of the ARGS are libtool executable wrappers, then they are translated -into their corresponding uninstalled binary, and any of their required library -directories are added to the library path. - -Then, COMMAND is executed, with ARGS as arguments." - ;; - - finish) - $ECHO \ -"Usage: $progname [OPTION]... --mode=finish [LIBDIR]... - -Complete the installation of libtool libraries. - -Each LIBDIR is a directory that contains libtool libraries. - -The commands that this mode executes may require superuser privileges. Use -the \`--dry-run' option if you just want to see what would be executed." - ;; - - install) - $ECHO \ -"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND... - -Install executables or libraries. - -INSTALL-COMMAND is the installation command. The first component should be -either the \`install' or \`cp' program. - -The following components of INSTALL-COMMAND are treated specially: - - -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation - -The rest of the components are interpreted as arguments to that command (only -BSD-compatible install options are recognized)." - ;; - - link) - $ECHO \ -"Usage: $progname [OPTION]... --mode=link LINK-COMMAND... - -Link object files or libraries together to form another library, or to -create an executable program. - -LINK-COMMAND is a command using the C compiler that you would use to create -a program from several object files. - -The following components of LINK-COMMAND are treated specially: - - -all-static do not do any dynamic linking at all - -avoid-version do not add a version suffix if possible - -bindir BINDIR specify path to binaries directory (for systems where - libraries must be found in the PATH setting at runtime) - -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime - -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols - -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3) - -export-symbols SYMFILE - try to export only the symbols listed in SYMFILE - -export-symbols-regex REGEX - try to export only the symbols matching REGEX - -LLIBDIR search LIBDIR for required installed libraries - -lNAME OUTPUT-FILE requires the installed library libNAME - -module build a library that can dlopened - -no-fast-install disable the fast-install mode - -no-install link a not-installable executable - -no-undefined declare that a library does not refer to external symbols - -o OUTPUT-FILE create OUTPUT-FILE from the specified objects - -objectlist FILE Use a list of object files found in FILE to specify objects - -precious-files-regex REGEX - don't remove output files matching REGEX - -release RELEASE specify package release information - -rpath LIBDIR the created library will eventually be installed in LIBDIR - -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries - -shared only do dynamic linking of libtool libraries - -shrext SUFFIX override the standard shared library file extension - -static do not do any dynamic linking of uninstalled libtool libraries - -static-libtool-libs - do not do any dynamic linking of libtool libraries - -version-info CURRENT[:REVISION[:AGE]] - specify library version info [each variable defaults to 0] - -weak LIBNAME declare that the target provides the LIBNAME interface - -Wc,FLAG - -Xcompiler FLAG pass linker-specific FLAG directly to the compiler - -Wl,FLAG - -Xlinker FLAG pass linker-specific FLAG directly to the linker - -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC) - -All other options (arguments beginning with \`-') are ignored. - -Every other argument is treated as a filename. Files ending in \`.la' are -treated as uninstalled libtool libraries, other files are standard or library -object files. - -If the OUTPUT-FILE ends in \`.la', then a libtool library is created, -only library objects (\`.lo' files) may be specified, and \`-rpath' is -required, except when creating a convenience library. - -If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created -using \`ar' and \`ranlib', or on Windows using \`lib'. - -If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file -is created, otherwise an executable program is created." - ;; - - uninstall) - $ECHO \ -"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE... - -Remove libraries from an installation directory. - -RM is the name of the program to use to delete files associated with each FILE -(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed -to RM. - -If FILE is a libtool library, all the files associated with it are deleted. -Otherwise, only FILE itself is deleted using RM." - ;; - - *) - func_fatal_help "invalid operation mode \`$mode'" - ;; - esac - - echo - $ECHO "Try \`$progname --help' for more information about other modes." -} - -# Now that we've collected a possible --mode arg, show help if necessary -if $opt_help; then - if test "$opt_help" = :; then - func_mode_help - else - { - func_help noexit - for mode in compile link execute install finish uninstall clean; do - func_mode_help - done - } | sed -n '1p; 2,$s/^Usage:/ or: /p' - { - func_help noexit - for mode in compile link execute install finish uninstall clean; do - echo - func_mode_help - done - } | - sed '1d - /^When reporting/,/^Report/{ - H - d - } - $x - /information about other modes/d - /more detailed .*MODE/d - s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/' - fi - exit $? -fi - - -# func_mode_execute arg... -func_mode_execute () -{ - $opt_debug - # The first argument is the command name. - cmd="$nonopt" - test -z "$cmd" && \ - func_fatal_help "you must specify a COMMAND" - - # Handle -dlopen flags immediately. - for file in $execute_dlfiles; do - test -f "$file" \ - || func_fatal_help "\`$file' is not a file" - - dir= - case $file in - *.la) - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$file" \ - || func_fatal_help "\`$lib' is not a valid libtool archive" - - # Read the libtool library. - dlname= - library_names= - func_source "$file" - - # Skip this library if it cannot be dlopened. - if test -z "$dlname"; then - # Warn if it was a shared library. - test -n "$library_names" && \ - func_warning "\`$file' was not linked with \`-export-dynamic'" - continue - fi - - func_dirname "$file" "" "." - dir="$func_dirname_result" - - if test -f "$dir/$objdir/$dlname"; then - dir="$dir/$objdir" - else - if test ! -f "$dir/$dlname"; then - func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'" - fi - fi - ;; - - *.lo) - # Just add the directory containing the .lo file. - func_dirname "$file" "" "." - dir="$func_dirname_result" - ;; - - *) - func_warning "\`-dlopen' is ignored for non-libtool libraries and objects" - continue - ;; - esac - - # Get the absolute pathname. - absdir=`cd "$dir" && pwd` - test -n "$absdir" && dir="$absdir" - - # Now add the directory to shlibpath_var. - if eval test -z \"\$$shlibpath_var\"; then - eval $shlibpath_var=\$dir - else - eval $shlibpath_var=\$dir:\$$shlibpath_var - fi - done - - # This variable tells wrapper scripts just to set shlibpath_var - # rather than running their programs. - libtool_execute_magic="$magic" - - # Check if any of the arguments is a wrapper script. - args= - for file - do - case $file in - -* | *.la | *.lo ) ;; - *) - # Do a test to see if this is really a libtool program. - if func_ltwrapper_script_p "$file"; then - func_source "$file" - # Transform arg to wrapped name. - file="$progdir/$program" - elif func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - func_source "$func_ltwrapper_scriptname_result" - # Transform arg to wrapped name. - file="$progdir/$program" - fi - ;; - esac - # Quote arguments (to preserve shell metacharacters). - func_quote_for_eval "$file" - args="$args $func_quote_for_eval_result" - done - - if test "X$opt_dry_run" = Xfalse; then - if test -n "$shlibpath_var"; then - # Export the shlibpath_var. - eval "export $shlibpath_var" - fi - - # Restore saved environment variables - for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES - do - eval "if test \"\${save_$lt_var+set}\" = set; then - $lt_var=\$save_$lt_var; export $lt_var - else - $lt_unset $lt_var - fi" - done - - # Now prepare to actually exec the command. - exec_cmd="\$cmd$args" - else - # Display what would be done. - if test -n "$shlibpath_var"; then - eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\"" - echo "export $shlibpath_var" - fi - $ECHO "$cmd$args" - exit $EXIT_SUCCESS - fi -} - -test "$mode" = execute && func_mode_execute ${1+"$@"} - - -# func_mode_finish arg... -func_mode_finish () -{ - $opt_debug - libdirs="$nonopt" - admincmds= - - if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then - for dir - do - libdirs="$libdirs $dir" - done - - for libdir in $libdirs; do - if test -n "$finish_cmds"; then - # Do each command in the finish commands. - func_execute_cmds "$finish_cmds" 'admincmds="$admincmds -'"$cmd"'"' - fi - if test -n "$finish_eval"; then - # Do the single finish_eval. - eval cmds=\"$finish_eval\" - $opt_dry_run || eval "$cmds" || admincmds="$admincmds - $cmds" - fi - done - fi - - # Exit here if they wanted silent mode. - $opt_silent && exit $EXIT_SUCCESS - - echo "----------------------------------------------------------------------" - echo "Libraries have been installed in:" - for libdir in $libdirs; do - $ECHO " $libdir" - done - echo - echo "If you ever happen to want to link against installed libraries" - echo "in a given directory, LIBDIR, you must either use libtool, and" - echo "specify the full pathname of the library, or use the \`-LLIBDIR'" - echo "flag during linking and do at least one of the following:" - if test -n "$shlibpath_var"; then - echo " - add LIBDIR to the \`$shlibpath_var' environment variable" - echo " during execution" - fi - if test -n "$runpath_var"; then - echo " - add LIBDIR to the \`$runpath_var' environment variable" - echo " during linking" - fi - if test -n "$hardcode_libdir_flag_spec"; then - libdir=LIBDIR - eval "flag=\"$hardcode_libdir_flag_spec\"" - - $ECHO " - use the \`$flag' linker flag" - fi - if test -n "$admincmds"; then - $ECHO " - have your system administrator run these commands:$admincmds" - fi - if test -f /etc/ld.so.conf; then - echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'" - fi - echo - - echo "See any operating system documentation about shared libraries for" - case $host in - solaris2.[6789]|solaris2.1[0-9]) - echo "more information, such as the ld(1), crle(1) and ld.so(8) manual" - echo "pages." - ;; - *) - echo "more information, such as the ld(1) and ld.so(8) manual pages." - ;; - esac - echo "----------------------------------------------------------------------" - exit $EXIT_SUCCESS -} - -test "$mode" = finish && func_mode_finish ${1+"$@"} - - -# func_mode_install arg... -func_mode_install () -{ - $opt_debug - # There may be an optional sh(1) argument at the beginning of - # install_prog (especially on Windows NT). - if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh || - # Allow the use of GNU shtool's install command. - case $nonopt in *shtool*) :;; *) false;; esac; then - # Aesthetically quote it. - func_quote_for_eval "$nonopt" - install_prog="$func_quote_for_eval_result " - arg=$1 - shift - else - install_prog= - arg=$nonopt - fi - - # The real first argument should be the name of the installation program. - # Aesthetically quote it. - func_quote_for_eval "$arg" - install_prog="$install_prog$func_quote_for_eval_result" - install_shared_prog=$install_prog - case " $install_prog " in - *[\\\ /]cp\ *) install_cp=: ;; - *) install_cp=false ;; - esac - - # We need to accept at least all the BSD install flags. - dest= - files= - opts= - prev= - install_type= - isdir=no - stripme= - no_mode=: - for arg - do - arg2= - if test -n "$dest"; then - files="$files $dest" - dest=$arg - continue - fi - - case $arg in - -d) isdir=yes ;; - -f) - if $install_cp; then :; else - prev=$arg - fi - ;; - -g | -m | -o) - prev=$arg - ;; - -s) - stripme=" -s" - continue - ;; - -*) - ;; - *) - # If the previous option needed an argument, then skip it. - if test -n "$prev"; then - if test "x$prev" = x-m && test -n "$install_override_mode"; then - arg2=$install_override_mode - no_mode=false - fi - prev= - else - dest=$arg - continue - fi - ;; - esac - - # Aesthetically quote the argument. - func_quote_for_eval "$arg" - install_prog="$install_prog $func_quote_for_eval_result" - if test -n "$arg2"; then - func_quote_for_eval "$arg2" - fi - install_shared_prog="$install_shared_prog $func_quote_for_eval_result" - done - - test -z "$install_prog" && \ - func_fatal_help "you must specify an install program" - - test -n "$prev" && \ - func_fatal_help "the \`$prev' option requires an argument" - - if test -n "$install_override_mode" && $no_mode; then - if $install_cp; then :; else - func_quote_for_eval "$install_override_mode" - install_shared_prog="$install_shared_prog -m $func_quote_for_eval_result" - fi - fi - - if test -z "$files"; then - if test -z "$dest"; then - func_fatal_help "no file or destination specified" - else - func_fatal_help "you must specify a destination" - fi - fi - - # Strip any trailing slash from the destination. - func_stripname '' '/' "$dest" - dest=$func_stripname_result - - # Check to see that the destination is a directory. - test -d "$dest" && isdir=yes - if test "$isdir" = yes; then - destdir="$dest" - destname= - else - func_dirname_and_basename "$dest" "" "." - destdir="$func_dirname_result" - destname="$func_basename_result" - - # Not a directory, so check to see that there is only one file specified. - set dummy $files; shift - test "$#" -gt 1 && \ - func_fatal_help "\`$dest' is not a directory" - fi - case $destdir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - for file in $files; do - case $file in - *.lo) ;; - *) - func_fatal_help "\`$destdir' must be an absolute directory name" - ;; - esac - done - ;; - esac - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - staticlibs= - future_libdirs= - current_libdirs= - for file in $files; do - - # Do each installation. - case $file in - *.$libext) - # Do the static libraries later. - staticlibs="$staticlibs $file" - ;; - - *.la) - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$file" \ - || func_fatal_help "\`$file' is not a valid libtool archive" - - library_names= - old_library= - relink_command= - func_source "$file" - - # Add the libdir to current_libdirs if it is the destination. - if test "X$destdir" = "X$libdir"; then - case "$current_libdirs " in - *" $libdir "*) ;; - *) current_libdirs="$current_libdirs $libdir" ;; - esac - else - # Note the libdir as a future libdir. - case "$future_libdirs " in - *" $libdir "*) ;; - *) future_libdirs="$future_libdirs $libdir" ;; - esac - fi - - func_dirname "$file" "/" "" - dir="$func_dirname_result" - dir="$dir$objdir" - - if test -n "$relink_command"; then - # Determine the prefix the user has applied to our future dir. - inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"` - - # Don't allow the user to place us outside of our expected - # location b/c this prevents finding dependent libraries that - # are installed to the same prefix. - # At present, this check doesn't affect windows .dll's that - # are installed into $libdir/../bin (currently, that works fine) - # but it's something to keep an eye on. - test "$inst_prefix_dir" = "$destdir" && \ - func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir" - - if test -n "$inst_prefix_dir"; then - # Stick the inst_prefix_dir data into the link command. - relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"` - else - relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"` - fi - - func_warning "relinking \`$file'" - func_show_eval "$relink_command" \ - 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"' - fi - - # See the names of the shared library. - set dummy $library_names; shift - if test -n "$1"; then - realname="$1" - shift - - srcname="$realname" - test -n "$relink_command" && srcname="$realname"T - - # Install the shared library and build the symlinks. - func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \ - 'exit $?' - tstripme="$stripme" - case $host_os in - cygwin* | mingw* | pw32* | cegcc*) - case $realname in - *.dll.a) - tstripme="" - ;; - esac - ;; - esac - if test -n "$tstripme" && test -n "$striplib"; then - func_show_eval "$striplib $destdir/$realname" 'exit $?' - fi - - if test "$#" -gt 0; then - # Delete the old symlinks, and create new ones. - # Try `ln -sf' first, because the `ln' binary might depend on - # the symlink we replace! Solaris /bin/ln does not understand -f, - # so we also need to try rm && ln -s. - for linkname - do - test "$linkname" != "$realname" \ - && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })" - done - fi - - # Do each command in the postinstall commands. - lib="$destdir/$realname" - func_execute_cmds "$postinstall_cmds" 'exit $?' - fi - - # Install the pseudo-library for information purposes. - func_basename "$file" - name="$func_basename_result" - instname="$dir/$name"i - func_show_eval "$install_prog $instname $destdir/$name" 'exit $?' - - # Maybe install the static library, too. - test -n "$old_library" && staticlibs="$staticlibs $dir/$old_library" - ;; - - *.lo) - # Install (i.e. copy) a libtool object. - - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - func_basename "$file" - destfile="$func_basename_result" - destfile="$destdir/$destfile" - fi - - # Deduce the name of the destination old-style object file. - case $destfile in - *.lo) - func_lo2o "$destfile" - staticdest=$func_lo2o_result - ;; - *.$objext) - staticdest="$destfile" - destfile= - ;; - *) - func_fatal_help "cannot copy a libtool object to \`$destfile'" - ;; - esac - - # Install the libtool object if requested. - test -n "$destfile" && \ - func_show_eval "$install_prog $file $destfile" 'exit $?' - - # Install the old object if enabled. - if test "$build_old_libs" = yes; then - # Deduce the name of the old-style object file. - func_lo2o "$file" - staticobj=$func_lo2o_result - func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?' - fi - exit $EXIT_SUCCESS - ;; - - *) - # Figure out destination file name, if it wasn't already specified. - if test -n "$destname"; then - destfile="$destdir/$destname" - else - func_basename "$file" - destfile="$func_basename_result" - destfile="$destdir/$destfile" - fi - - # If the file is missing, and there is a .exe on the end, strip it - # because it is most likely a libtool script we actually want to - # install - stripped_ext="" - case $file in - *.exe) - if test ! -f "$file"; then - func_stripname '' '.exe' "$file" - file=$func_stripname_result - stripped_ext=".exe" - fi - ;; - esac - - # Do a test to see if this is really a libtool program. - case $host in - *cygwin* | *mingw*) - if func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - wrapper=$func_ltwrapper_scriptname_result - else - func_stripname '' '.exe' "$file" - wrapper=$func_stripname_result - fi - ;; - *) - wrapper=$file - ;; - esac - if func_ltwrapper_script_p "$wrapper"; then - notinst_deplibs= - relink_command= - - func_source "$wrapper" - - # Check the variables that should have been set. - test -z "$generated_by_libtool_version" && \ - func_fatal_error "invalid libtool wrapper script \`$wrapper'" - - finalize=yes - for lib in $notinst_deplibs; do - # Check to see that each library is installed. - libdir= - if test -f "$lib"; then - func_source "$lib" - fi - libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test - if test -n "$libdir" && test ! -f "$libfile"; then - func_warning "\`$lib' has not been installed in \`$libdir'" - finalize=no - fi - done - - relink_command= - func_source "$wrapper" - - outputname= - if test "$fast_install" = no && test -n "$relink_command"; then - $opt_dry_run || { - if test "$finalize" = yes; then - tmpdir=`func_mktempdir` - func_basename "$file$stripped_ext" - file="$func_basename_result" - outputname="$tmpdir/$file" - # Replace the output file specification. - relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'` - - $opt_silent || { - func_quote_for_expand "$relink_command" - eval "func_echo $func_quote_for_expand_result" - } - if eval "$relink_command"; then : - else - func_error "error: relink \`$file' with the above command before installing it" - $opt_dry_run || ${RM}r "$tmpdir" - continue - fi - file="$outputname" - else - func_warning "cannot relink \`$file'" - fi - } - else - # Install the binary that we compiled earlier. - file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"` - fi - fi - - # remove .exe since cygwin /usr/bin/install will append another - # one anyway - case $install_prog,$host in - */usr/bin/install*,*cygwin*) - case $file:$destfile in - *.exe:*.exe) - # this is ok - ;; - *.exe:*) - destfile=$destfile.exe - ;; - *:*.exe) - func_stripname '' '.exe' "$destfile" - destfile=$func_stripname_result - ;; - esac - ;; - esac - func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?' - $opt_dry_run || if test -n "$outputname"; then - ${RM}r "$tmpdir" - fi - ;; - esac - done - - for file in $staticlibs; do - func_basename "$file" - name="$func_basename_result" - - # Set up the ranlib parameters. - oldlib="$destdir/$name" - - func_show_eval "$install_prog \$file \$oldlib" 'exit $?' - - if test -n "$stripme" && test -n "$old_striplib"; then - func_show_eval "$old_striplib $oldlib" 'exit $?' - fi - - # Do each command in the postinstall commands. - func_execute_cmds "$old_postinstall_cmds" 'exit $?' - done - - test -n "$future_libdirs" && \ - func_warning "remember to run \`$progname --finish$future_libdirs'" - - if test -n "$current_libdirs" && $opt_finish; then - # Maybe just do a dry run. - $opt_dry_run && current_libdirs=" -n$current_libdirs" - exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs' - else - exit $EXIT_SUCCESS - fi -} - -test "$mode" = install && func_mode_install ${1+"$@"} - - -# func_generate_dlsyms outputname originator pic_p -# Extract symbols from dlprefiles and create ${outputname}S.o with -# a dlpreopen symbol table. -func_generate_dlsyms () -{ - $opt_debug - my_outputname="$1" - my_originator="$2" - my_pic_p="${3-no}" - my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'` - my_dlsyms= - - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - if test -n "$NM" && test -n "$global_symbol_pipe"; then - my_dlsyms="${my_outputname}S.c" - else - func_error "not configured to extract global symbols from dlpreopened files" - fi - fi - - if test -n "$my_dlsyms"; then - case $my_dlsyms in - "") ;; - *.c) - # Discover the nlist of each of the dlfiles. - nlist="$output_objdir/${my_outputname}.nm" - - func_show_eval "$RM $nlist ${nlist}S ${nlist}T" - - # Parse the name list into a source file. - func_verbose "creating $output_objdir/$my_dlsyms" - - $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\ -/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */ -/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */ - -#ifdef __cplusplus -extern \"C\" { -#endif - -#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4)) -#pragma GCC diagnostic ignored \"-Wstrict-prototypes\" -#endif - -/* External symbol declarations for the compiler. */\ -" - - if test "$dlself" = yes; then - func_verbose "generating symbol list for \`$output'" - - $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist" - - # Add our own program objects to the symbol list. - progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP` - for progfile in $progfiles; do - func_verbose "extracting global C symbols from \`$progfile'" - $opt_dry_run || eval "$NM $progfile | $global_symbol_pipe >> '$nlist'" - done - - if test -n "$exclude_expsyms"; then - $opt_dry_run || { - $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $MV "$nlist"T "$nlist" - } - fi - - if test -n "$export_symbols_regex"; then - $opt_dry_run || { - $EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T - $MV "$nlist"T "$nlist" - } - fi - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - export_symbols="$output_objdir/$outputname.exp" - $opt_dry_run || { - $RM $export_symbols - ${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' < "$nlist" > "$export_symbols" - case $host in - *cygwin* | *mingw* | *cegcc* ) - echo EXPORTS > "$output_objdir/$outputname.def" - cat "$export_symbols" >> "$output_objdir/$outputname.def" - ;; - esac - } - else - $opt_dry_run || { - ${SED} -e 's/\([].[*^$]\)/\\\1/g' -e 's/^/ /' -e 's/$/$/' < "$export_symbols" > "$output_objdir/$outputname.exp" - $GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T - $MV "$nlist"T "$nlist" - case $host in - *cygwin* | *mingw* | *cegcc* ) - echo EXPORTS > "$output_objdir/$outputname.def" - cat "$nlist" >> "$output_objdir/$outputname.def" - ;; - esac - } - fi - fi - - for dlprefile in $dlprefiles; do - func_verbose "extracting global C symbols from \`$dlprefile'" - func_basename "$dlprefile" - name="$func_basename_result" - $opt_dry_run || { - $ECHO ": $name " >> "$nlist" - eval "$NM $dlprefile 2>/dev/null | $global_symbol_pipe >> '$nlist'" - } - done - - $opt_dry_run || { - # Make sure we have at least an empty file. - test -f "$nlist" || : > "$nlist" - - if test -n "$exclude_expsyms"; then - $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T - $MV "$nlist"T "$nlist" - fi - - # Try sorting and uniquifying the output. - if $GREP -v "^: " < "$nlist" | - if sort -k 3 /dev/null 2>&1; then - sort -k 3 - else - sort +2 - fi | - uniq > "$nlist"S; then - : - else - $GREP -v "^: " < "$nlist" > "$nlist"S - fi - - if test -f "$nlist"S; then - eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"' - else - echo '/* NONE */' >> "$output_objdir/$my_dlsyms" - fi - - echo >> "$output_objdir/$my_dlsyms" "\ - -/* The mapping between symbol names and symbols. */ -typedef struct { - const char *name; - void *address; -} lt_dlsymlist; -" - case $host in - *cygwin* | *mingw* | *cegcc* ) - echo >> "$output_objdir/$my_dlsyms" "\ -/* DATA imports from DLLs on WIN32 con't be const, because - runtime relocations are performed -- see ld's documentation - on pseudo-relocs. */" - lt_dlsym_const= ;; - *osf5*) - echo >> "$output_objdir/$my_dlsyms" "\ -/* This system does not cope well with relocations in const data */" - lt_dlsym_const= ;; - *) - lt_dlsym_const=const ;; - esac - - echo >> "$output_objdir/$my_dlsyms" "\ -extern $lt_dlsym_const lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[]; -$lt_dlsym_const lt_dlsymlist -lt_${my_prefix}_LTX_preloaded_symbols[] = -{\ - { \"$my_originator\", (void *) 0 }," - - case $need_lib_prefix in - no) - eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms" - ;; - *) - eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms" - ;; - esac - echo >> "$output_objdir/$my_dlsyms" "\ - {0, (void *) 0} -}; - -/* This works around a problem in FreeBSD linker */ -#ifdef FREEBSD_WORKAROUND -static const void *lt_preloaded_setup() { - return lt_${my_prefix}_LTX_preloaded_symbols; -} -#endif - -#ifdef __cplusplus -} -#endif\ -" - } # !$opt_dry_run - - pic_flag_for_symtable= - case "$compile_command " in - *" -static "*) ;; - *) - case $host in - # compiling the symbol table file with pic_flag works around - # a FreeBSD bug that causes programs to crash when -lm is - # linked before any other PIC object. But we must not use - # pic_flag when linking with -static. The problem exists in - # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1. - *-*-freebsd2*|*-*-freebsd3.0*|*-*-freebsdelf3.0*) - pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;; - *-*-hpux*) - pic_flag_for_symtable=" $pic_flag" ;; - *) - if test "X$my_pic_p" != Xno; then - pic_flag_for_symtable=" $pic_flag" - fi - ;; - esac - ;; - esac - symtab_cflags= - for arg in $LTCFLAGS; do - case $arg in - -pie | -fpie | -fPIE) ;; - *) symtab_cflags="$symtab_cflags $arg" ;; - esac - done - - # Now compile the dynamic symbol file. - func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?' - - # Clean up the generated files. - func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"' - - # Transform the symbol file into the correct name. - symfileobj="$output_objdir/${my_outputname}S.$objext" - case $host in - *cygwin* | *mingw* | *cegcc* ) - if test -f "$output_objdir/$my_outputname.def"; then - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"` - else - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` - fi - ;; - *) - compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"` - ;; - esac - ;; - *) - func_fatal_error "unknown suffix for \`$my_dlsyms'" - ;; - esac - else - # We keep going just in case the user didn't refer to - # lt_preloaded_symbols. The linker will fail if global_symbol_pipe - # really was required. - - # Nullify the symbol file. - compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"` - finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"` - fi -} - -# func_win32_libid arg -# return the library type of file 'arg' -# -# Need a lot of goo to handle *both* DLLs and import libs -# Has to be a shell function in order to 'eat' the argument -# that is supplied when $file_magic_command is called. -# Despite the name, also deal with 64 bit binaries. -func_win32_libid () -{ - $opt_debug - win32_libid_type="unknown" - win32_fileres=`file -L $1 2>/dev/null` - case $win32_fileres in - *ar\ archive\ import\ library*) # definitely import - win32_libid_type="x86 archive import" - ;; - *ar\ archive*) # could be an import, or static - if $OBJDUMP -f "$1" | $SED -e '10q' 2>/dev/null | - $EGREP 'file format (pe-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then - win32_nmres=`$NM -f posix -A "$1" | - $SED -n -e ' - 1,100{ - / I /{ - s,.*,import, - p - q - } - }'` - case $win32_nmres in - import*) win32_libid_type="x86 archive import";; - *) win32_libid_type="x86 archive static";; - esac - fi - ;; - *DLL*) - win32_libid_type="x86 DLL" - ;; - *executable*) # but shell scripts are "executable" too... - case $win32_fileres in - *MS\ Windows\ PE\ Intel*) - win32_libid_type="x86 DLL" - ;; - esac - ;; - esac - $ECHO "$win32_libid_type" -} - - - -# func_extract_an_archive dir oldlib -func_extract_an_archive () -{ - $opt_debug - f_ex_an_ar_dir="$1"; shift - f_ex_an_ar_oldlib="$1" - if test "$lock_old_archive_extraction" = yes; then - lockfile=$f_ex_an_ar_oldlib.lock - until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do - func_echo "Waiting for $lockfile to be removed" - sleep 2 - done - fi - func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \ - 'stat=$?; rm -f "$lockfile"; exit $stat' - if test "$lock_old_archive_extraction" = yes; then - $opt_dry_run || rm -f "$lockfile" - fi - if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then - : - else - func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib" - fi -} - - -# func_extract_archives gentop oldlib ... -func_extract_archives () -{ - $opt_debug - my_gentop="$1"; shift - my_oldlibs=${1+"$@"} - my_oldobjs="" - my_xlib="" - my_xabs="" - my_xdir="" - - for my_xlib in $my_oldlibs; do - # Extract the objects. - case $my_xlib in - [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;; - *) my_xabs=`pwd`"/$my_xlib" ;; - esac - func_basename "$my_xlib" - my_xlib="$func_basename_result" - my_xlib_u=$my_xlib - while :; do - case " $extracted_archives " in - *" $my_xlib_u "*) - func_arith $extracted_serial + 1 - extracted_serial=$func_arith_result - my_xlib_u=lt$extracted_serial-$my_xlib ;; - *) break ;; - esac - done - extracted_archives="$extracted_archives $my_xlib_u" - my_xdir="$my_gentop/$my_xlib_u" - - func_mkdir_p "$my_xdir" - - case $host in - *-darwin*) - func_verbose "Extracting $my_xabs" - # Do not bother doing anything if just a dry run - $opt_dry_run || { - darwin_orig_dir=`pwd` - cd $my_xdir || exit $? - darwin_archive=$my_xabs - darwin_curdir=`pwd` - darwin_base_archive=`basename "$darwin_archive"` - darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true` - if test -n "$darwin_arches"; then - darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'` - darwin_arch= - func_verbose "$darwin_base_archive has multiple architectures $darwin_arches" - for darwin_arch in $darwin_arches ; do - func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}" - $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}" - cd "unfat-$$/${darwin_base_archive}-${darwin_arch}" - func_extract_an_archive "`pwd`" "${darwin_base_archive}" - cd "$darwin_curdir" - $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" - done # $darwin_arches - ## Okay now we've a bunch of thin objects, gotta fatten them up :) - darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u` - darwin_file= - darwin_files= - for darwin_file in $darwin_filelist; do - darwin_files=`find unfat-$$ -name $darwin_file -print | $NL2SP` - $LIPO -create -output "$darwin_file" $darwin_files - done # $darwin_filelist - $RM -rf unfat-$$ - cd "$darwin_orig_dir" - else - cd $darwin_orig_dir - func_extract_an_archive "$my_xdir" "$my_xabs" - fi # $darwin_arches - } # !$opt_dry_run - ;; - *) - func_extract_an_archive "$my_xdir" "$my_xabs" - ;; - esac - my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | $NL2SP` - done - - func_extract_archives_result="$my_oldobjs" -} - - -# func_emit_wrapper [arg=no] -# -# Emit a libtool wrapper script on stdout. -# Don't directly open a file because we may want to -# incorporate the script contents within a cygwin/mingw -# wrapper executable. Must ONLY be called from within -# func_mode_link because it depends on a number of variables -# set therein. -# -# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR -# variable will take. If 'yes', then the emitted script -# will assume that the directory in which it is stored is -# the $objdir directory. This is a cygwin/mingw-specific -# behavior. -func_emit_wrapper () -{ - func_emit_wrapper_arg1=${1-no} - - $ECHO "\ -#! $SHELL - -# $output - temporary wrapper script for $objdir/$outputname -# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION -# -# The $output program cannot be directly executed until all the libtool -# libraries that it depends on are installed. -# -# This wrapper script should never be moved out of the build directory. -# If it is, it will not operate correctly. - -# Sed substitution that helps us do robust quoting. It backslashifies -# metacharacters that are still active within double-quoted strings. -sed_quote_subst='$sed_quote_subst' - -# Be Bourne compatible -if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then - emulate sh - NULLCMD=: - # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which - # is contrary to our usage. Disable this feature. - alias -g '\${1+\"\$@\"}'='\"\$@\"' - setopt NO_GLOB_SUBST -else - case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac -fi -BIN_SH=xpg4; export BIN_SH # for Tru64 -DUALCASE=1; export DUALCASE # for MKS sh - -# The HP-UX ksh and POSIX shell print the target directory to stdout -# if CDPATH is set. -(unset CDPATH) >/dev/null 2>&1 && unset CDPATH - -relink_command=\"$relink_command\" - -# This environment variable determines our operation mode. -if test \"\$libtool_install_magic\" = \"$magic\"; then - # install mode needs the following variables: - generated_by_libtool_version='$macro_version' - notinst_deplibs='$notinst_deplibs' -else - # When we are sourced in execute mode, \$file and \$ECHO are already set. - if test \"\$libtool_execute_magic\" != \"$magic\"; then - file=\"\$0\"" - - qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"` - $ECHO "\ - -# A function that is used when there is no print builtin or printf. -func_fallback_echo () -{ - eval 'cat <<_LTECHO_EOF -\$1 -_LTECHO_EOF' -} - ECHO=\"$qECHO\" - fi\ - - # Find the directory that this script lives in. - thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\` - test \"x\$thisdir\" = \"x\$file\" && thisdir=. - - # Follow symbolic links until we get to the real thisdir. - file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\` - while test -n \"\$file\"; do - destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\` - - # If there was a directory component, then change thisdir. - if test \"x\$destdir\" != \"x\$file\"; then - case \"\$destdir\" in - [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;; - *) thisdir=\"\$thisdir/\$destdir\" ;; - esac - fi - - file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\` - file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\` - done - - # Usually 'no', except on cygwin/mingw when embedded into - # the cwrapper. - WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1 - if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then - # special case for '.' - if test \"\$thisdir\" = \".\"; then - thisdir=\`pwd\` - fi - # remove .libs from thisdir - case \"\$thisdir\" in - *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;; - $objdir ) thisdir=. ;; - esac - fi - - # Try to get the absolute directory name. - absdir=\`cd \"\$thisdir\" && pwd\` - test -n \"\$absdir\" && thisdir=\"\$absdir\" -" - - if test "$fast_install" = yes; then - $ECHO "\ - program=lt-'$outputname'$exeext - progdir=\"\$thisdir/$objdir\" - - if test ! -f \"\$progdir/\$program\" || - { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\ - test \"X\$file\" != \"X\$progdir/\$program\"; }; then - - file=\"\$\$-\$program\" - - if test ! -d \"\$progdir\"; then - $MKDIR \"\$progdir\" - else - $RM \"\$progdir/\$file\" - fi" - - $ECHO "\ - - # relink executable if necessary - if test -n \"\$relink_command\"; then - if relink_command_output=\`eval \"\$relink_command\" 2>&1\`; then : - else - $ECHO \"\$relink_command_output\" >&2 - $RM \"\$progdir/\$file\" - exit 1 - fi - fi - - $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null || - { $RM \"\$progdir/\$program\"; - $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; } - $RM \"\$progdir/\$file\" - fi" - else - $ECHO "\ - program='$outputname' - progdir=\"\$thisdir/$objdir\" -" - fi - - $ECHO "\ - - if test -f \"\$progdir/\$program\"; then" - - # Export our shlibpath_var if we have one. - if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then - $ECHO "\ - # Add our own library path to $shlibpath_var - $shlibpath_var=\"$temp_rpath\$$shlibpath_var\" - - # Some systems cannot cope with colon-terminated $shlibpath_var - # The second colon is a workaround for a bug in BeOS R4 sed - $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\` - - export $shlibpath_var -" - fi - - # fixup the dll searchpath if we need to. - if test -n "$dllsearchpath"; then - $ECHO "\ - # Add the dll search path components to the executable PATH - PATH=$dllsearchpath:\$PATH -" - fi - - $ECHO "\ - if test \"\$libtool_execute_magic\" != \"$magic\"; then - # Run the actual program with our arguments. -" - case $host in - # Backslashes separate directories on plain windows - *-*-mingw | *-*-os2* | *-cegcc*) - $ECHO "\ - exec \"\$progdir\\\\\$program\" \${1+\"\$@\"} -" - ;; - - *) - $ECHO "\ - exec \"\$progdir/\$program\" \${1+\"\$@\"} -" - ;; - esac - $ECHO "\ - \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2 - exit 1 - fi - else - # The program doesn't exist. - \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2 - \$ECHO \"This script is just a wrapper for \$program.\" 1>&2 - \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2 - exit 1 - fi -fi\ -" -} - - -# func_to_host_path arg -# -# Convert paths to host format when used with build tools. -# Intended for use with "native" mingw (where libtool itself -# is running under the msys shell), or in the following cross- -# build environments: -# $build $host -# mingw (msys) mingw [e.g. native] -# cygwin mingw -# *nix + wine mingw -# where wine is equipped with the `winepath' executable. -# In the native mingw case, the (msys) shell automatically -# converts paths for any non-msys applications it launches, -# but that facility isn't available from inside the cwrapper. -# Similar accommodations are necessary for $host mingw and -# $build cygwin. Calling this function does no harm for other -# $host/$build combinations not listed above. -# -# ARG is the path (on $build) that should be converted to -# the proper representation for $host. The result is stored -# in $func_to_host_path_result. -func_to_host_path () -{ - func_to_host_path_result="$1" - if test -n "$1"; then - case $host in - *mingw* ) - lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' - case $build in - *mingw* ) # actually, msys - # awkward: cmd appends spaces to result - func_to_host_path_result=`( cmd //c echo "$1" ) 2>/dev/null | - $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` - ;; - *cygwin* ) - func_to_host_path_result=`cygpath -w "$1" | - $SED -e "$lt_sed_naive_backslashify"` - ;; - * ) - # Unfortunately, winepath does not exit with a non-zero - # error code, so we are forced to check the contents of - # stdout. On the other hand, if the command is not - # found, the shell will set an exit code of 127 and print - # *an error message* to stdout. So we must check for both - # error code of zero AND non-empty stdout, which explains - # the odd construction: - func_to_host_path_tmp1=`winepath -w "$1" 2>/dev/null` - if test "$?" -eq 0 && test -n "${func_to_host_path_tmp1}"; then - func_to_host_path_result=`$ECHO "$func_to_host_path_tmp1" | - $SED -e "$lt_sed_naive_backslashify"` - else - # Allow warning below. - func_to_host_path_result= - fi - ;; - esac - if test -z "$func_to_host_path_result" ; then - func_error "Could not determine host path corresponding to" - func_error " \`$1'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback: - func_to_host_path_result="$1" - fi - ;; - esac - fi -} -# end: func_to_host_path - -# func_to_host_pathlist arg -# -# Convert pathlists to host format when used with build tools. -# See func_to_host_path(), above. This function supports the -# following $build/$host combinations (but does no harm for -# combinations not listed here): -# $build $host -# mingw (msys) mingw [e.g. native] -# cygwin mingw -# *nix + wine mingw -# -# Path separators are also converted from $build format to -# $host format. If ARG begins or ends with a path separator -# character, it is preserved (but converted to $host format) -# on output. -# -# ARG is a pathlist (on $build) that should be converted to -# the proper representation on $host. The result is stored -# in $func_to_host_pathlist_result. -func_to_host_pathlist () -{ - func_to_host_pathlist_result="$1" - if test -n "$1"; then - case $host in - *mingw* ) - lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g' - # Remove leading and trailing path separator characters from - # ARG. msys behavior is inconsistent here, cygpath turns them - # into '.;' and ';.', and winepath ignores them completely. - func_stripname : : "$1" - func_to_host_pathlist_tmp1=$func_stripname_result - case $build in - *mingw* ) # Actually, msys. - # Awkward: cmd appends spaces to result. - func_to_host_pathlist_result=` - ( cmd //c echo "$func_to_host_pathlist_tmp1" ) 2>/dev/null | - $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"` - ;; - *cygwin* ) - func_to_host_pathlist_result=`cygpath -w -p "$func_to_host_pathlist_tmp1" | - $SED -e "$lt_sed_naive_backslashify"` - ;; - * ) - # unfortunately, winepath doesn't convert pathlists - func_to_host_pathlist_result="" - func_to_host_pathlist_oldIFS=$IFS - IFS=: - for func_to_host_pathlist_f in $func_to_host_pathlist_tmp1 ; do - IFS=$func_to_host_pathlist_oldIFS - if test -n "$func_to_host_pathlist_f" ; then - func_to_host_path "$func_to_host_pathlist_f" - if test -n "$func_to_host_path_result" ; then - if test -z "$func_to_host_pathlist_result" ; then - func_to_host_pathlist_result="$func_to_host_path_result" - else - func_append func_to_host_pathlist_result ";$func_to_host_path_result" - fi - fi - fi - done - IFS=$func_to_host_pathlist_oldIFS - ;; - esac - if test -z "$func_to_host_pathlist_result"; then - func_error "Could not determine the host path(s) corresponding to" - func_error " \`$1'" - func_error "Continuing, but uninstalled executables may not work." - # Fallback. This may break if $1 contains DOS-style drive - # specifications. The fix is not to complicate the expression - # below, but for the user to provide a working wine installation - # with winepath so that path translation in the cross-to-mingw - # case works properly. - lt_replace_pathsep_nix_to_dos="s|:|;|g" - func_to_host_pathlist_result=`echo "$func_to_host_pathlist_tmp1" |\ - $SED -e "$lt_replace_pathsep_nix_to_dos"` - fi - # Now, add the leading and trailing path separators back - case "$1" in - :* ) func_to_host_pathlist_result=";$func_to_host_pathlist_result" - ;; - esac - case "$1" in - *: ) func_append func_to_host_pathlist_result ";" - ;; - esac - ;; - esac - fi -} -# end: func_to_host_pathlist - -# func_emit_cwrapperexe_src -# emit the source code for a wrapper executable on stdout -# Must ONLY be called from within func_mode_link because -# it depends on a number of variable set therein. -func_emit_cwrapperexe_src () -{ - cat < -#include -#ifdef _MSC_VER -# include -# include -# include -#else -# include -# include -# ifdef __CYGWIN__ -# include -# endif -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -/* declarations of non-ANSI functions */ -#if defined(__MINGW32__) -# ifdef __STRICT_ANSI__ -int _putenv (const char *); -# endif -#elif defined(__CYGWIN__) -# ifdef __STRICT_ANSI__ -char *realpath (const char *, char *); -int putenv (char *); -int setenv (const char *, const char *, int); -# endif -/* #elif defined (other platforms) ... */ -#endif - -/* portability defines, excluding path handling macros */ -#if defined(_MSC_VER) -# define setmode _setmode -# define stat _stat -# define chmod _chmod -# define getcwd _getcwd -# define putenv _putenv -# define S_IXUSR _S_IEXEC -# ifndef _INTPTR_T_DEFINED -# define _INTPTR_T_DEFINED -# define intptr_t int -# endif -#elif defined(__MINGW32__) -# define setmode _setmode -# define stat _stat -# define chmod _chmod -# define getcwd _getcwd -# define putenv _putenv -#elif defined(__CYGWIN__) -# define HAVE_SETENV -# define FOPEN_WB "wb" -/* #elif defined (other platforms) ... */ -#endif - -#if defined(PATH_MAX) -# define LT_PATHMAX PATH_MAX -#elif defined(MAXPATHLEN) -# define LT_PATHMAX MAXPATHLEN -#else -# define LT_PATHMAX 1024 -#endif - -#ifndef S_IXOTH -# define S_IXOTH 0 -#endif -#ifndef S_IXGRP -# define S_IXGRP 0 -#endif - -/* path handling portability macros */ -#ifndef DIR_SEPARATOR -# define DIR_SEPARATOR '/' -# define PATH_SEPARATOR ':' -#endif - -#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \ - defined (__OS2__) -# define HAVE_DOS_BASED_FILE_SYSTEM -# define FOPEN_WB "wb" -# ifndef DIR_SEPARATOR_2 -# define DIR_SEPARATOR_2 '\\' -# endif -# ifndef PATH_SEPARATOR_2 -# define PATH_SEPARATOR_2 ';' -# endif -#endif - -#ifndef DIR_SEPARATOR_2 -# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR) -#else /* DIR_SEPARATOR_2 */ -# define IS_DIR_SEPARATOR(ch) \ - (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2)) -#endif /* DIR_SEPARATOR_2 */ - -#ifndef PATH_SEPARATOR_2 -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR) -#else /* PATH_SEPARATOR_2 */ -# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2) -#endif /* PATH_SEPARATOR_2 */ - -#ifndef FOPEN_WB -# define FOPEN_WB "w" -#endif -#ifndef _O_BINARY -# define _O_BINARY 0 -#endif - -#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type))) -#define XFREE(stale) do { \ - if (stale) { free ((void *) stale); stale = 0; } \ -} while (0) - -#undef LTWRAPPER_DEBUGPRINTF -#if defined LT_DEBUGWRAPPER -# define LTWRAPPER_DEBUGPRINTF(args) ltwrapper_debugprintf args -static void -ltwrapper_debugprintf (const char *fmt, ...) -{ - va_list args; - va_start (args, fmt); - (void) vfprintf (stderr, fmt, args); - va_end (args); -} -#else -# define LTWRAPPER_DEBUGPRINTF(args) -#endif - -const char *program_name = NULL; - -void *xmalloc (size_t num); -char *xstrdup (const char *string); -const char *base_name (const char *name); -char *find_executable (const char *wrapper); -char *chase_symlinks (const char *pathspec); -int make_executable (const char *path); -int check_executable (const char *path); -char *strendzap (char *str, const char *pat); -void lt_fatal (const char *message, ...); -void lt_setenv (const char *name, const char *value); -char *lt_extend_str (const char *orig_value, const char *add, int to_end); -void lt_update_exe_path (const char *name, const char *value); -void lt_update_lib_path (const char *name, const char *value); -char **prepare_spawn (char **argv); -void lt_dump_script (FILE *f); -EOF - - cat <"))); - for (i = 0; i < newargc; i++) - { - LTWRAPPER_DEBUGPRINTF (("(main) newargz[%d] : %s\n", i, (newargz[i] ? newargz[i] : ""))); - } - -EOF - - case $host_os in - mingw*) - cat <<"EOF" - /* execv doesn't actually work on mingw as expected on unix */ - newargz = prepare_spawn (newargz); - rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz); - if (rval == -1) - { - /* failed to start process */ - LTWRAPPER_DEBUGPRINTF (("(main) failed to launch target \"%s\": errno = %d\n", lt_argv_zero, errno)); - return 127; - } - return rval; -EOF - ;; - *) - cat <<"EOF" - execv (lt_argv_zero, newargz); - return rval; /* =127, but avoids unused variable warning */ -EOF - ;; - esac - - cat <<"EOF" -} - -void * -xmalloc (size_t num) -{ - void *p = (void *) malloc (num); - if (!p) - lt_fatal ("Memory exhausted"); - - return p; -} - -char * -xstrdup (const char *string) -{ - return string ? strcpy ((char *) xmalloc (strlen (string) + 1), - string) : NULL; -} - -const char * -base_name (const char *name) -{ - const char *base; - -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - /* Skip over the disk name in MSDOS pathnames. */ - if (isalpha ((unsigned char) name[0]) && name[1] == ':') - name += 2; -#endif - - for (base = name; *name; name++) - if (IS_DIR_SEPARATOR (*name)) - base = name + 1; - return base; -} - -int -check_executable (const char *path) -{ - struct stat st; - - LTWRAPPER_DEBUGPRINTF (("(check_executable) : %s\n", - path ? (*path ? path : "EMPTY!") : "NULL!")); - if ((!path) || (!*path)) - return 0; - - if ((stat (path, &st) >= 0) - && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) - return 1; - else - return 0; -} - -int -make_executable (const char *path) -{ - int rval = 0; - struct stat st; - - LTWRAPPER_DEBUGPRINTF (("(make_executable) : %s\n", - path ? (*path ? path : "EMPTY!") : "NULL!")); - if ((!path) || (!*path)) - return 0; - - if (stat (path, &st) >= 0) - { - rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR); - } - return rval; -} - -/* Searches for the full path of the wrapper. Returns - newly allocated full path name if found, NULL otherwise - Does not chase symlinks, even on platforms that support them. -*/ -char * -find_executable (const char *wrapper) -{ - int has_slash = 0; - const char *p; - const char *p_next; - /* static buffer for getcwd */ - char tmp[LT_PATHMAX + 1]; - int tmp_len; - char *concat_name; - - LTWRAPPER_DEBUGPRINTF (("(find_executable) : %s\n", - wrapper ? (*wrapper ? wrapper : "EMPTY!") : "NULL!")); - - if ((wrapper == NULL) || (*wrapper == '\0')) - return NULL; - - /* Absolute path? */ -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':') - { - concat_name = xstrdup (wrapper); - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } - else - { -#endif - if (IS_DIR_SEPARATOR (wrapper[0])) - { - concat_name = xstrdup (wrapper); - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } -#if defined (HAVE_DOS_BASED_FILE_SYSTEM) - } -#endif - - for (p = wrapper; *p; p++) - if (*p == '/') - { - has_slash = 1; - break; - } - if (!has_slash) - { - /* no slashes; search PATH */ - const char *path = getenv ("PATH"); - if (path != NULL) - { - for (p = path; *p; p = p_next) - { - const char *q; - size_t p_len; - for (q = p; *q; q++) - if (IS_PATH_SEPARATOR (*q)) - break; - p_len = q - p; - p_next = (*q == '\0' ? q : q + 1); - if (p_len == 0) - { - /* empty path: current directory */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); - tmp_len = strlen (tmp); - concat_name = - XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - } - else - { - concat_name = - XMALLOC (char, p_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, p, p_len); - concat_name[p_len] = '/'; - strcpy (concat_name + p_len + 1, wrapper); - } - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - } - } - /* not found in PATH; assume curdir */ - } - /* Relative path | not found in path: prepend cwd */ - if (getcwd (tmp, LT_PATHMAX) == NULL) - lt_fatal ("getcwd failed"); - tmp_len = strlen (tmp); - concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1); - memcpy (concat_name, tmp, tmp_len); - concat_name[tmp_len] = '/'; - strcpy (concat_name + tmp_len + 1, wrapper); - - if (check_executable (concat_name)) - return concat_name; - XFREE (concat_name); - return NULL; -} - -char * -chase_symlinks (const char *pathspec) -{ -#ifndef S_ISLNK - return xstrdup (pathspec); -#else - char buf[LT_PATHMAX]; - struct stat s; - char *tmp_pathspec = xstrdup (pathspec); - char *p; - int has_symlinks = 0; - while (strlen (tmp_pathspec) && !has_symlinks) - { - LTWRAPPER_DEBUGPRINTF (("checking path component for symlinks: %s\n", - tmp_pathspec)); - if (lstat (tmp_pathspec, &s) == 0) - { - if (S_ISLNK (s.st_mode) != 0) - { - has_symlinks = 1; - break; - } - - /* search backwards for last DIR_SEPARATOR */ - p = tmp_pathspec + strlen (tmp_pathspec) - 1; - while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) - p--; - if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p))) - { - /* no more DIR_SEPARATORS left */ - break; - } - *p = '\0'; - } - else - { - char *errstr = strerror (errno); - lt_fatal ("Error accessing file %s (%s)", tmp_pathspec, errstr); - } - } - XFREE (tmp_pathspec); - - if (!has_symlinks) - { - return xstrdup (pathspec); - } - - tmp_pathspec = realpath (pathspec, buf); - if (tmp_pathspec == 0) - { - lt_fatal ("Could not follow symlinks for %s", pathspec); - } - return xstrdup (tmp_pathspec); -#endif -} - -char * -strendzap (char *str, const char *pat) -{ - size_t len, patlen; - - assert (str != NULL); - assert (pat != NULL); - - len = strlen (str); - patlen = strlen (pat); - - if (patlen <= len) - { - str += len - patlen; - if (strcmp (str, pat) == 0) - *str = '\0'; - } - return str; -} - -static void -lt_error_core (int exit_status, const char *mode, - const char *message, va_list ap) -{ - fprintf (stderr, "%s: %s: ", program_name, mode); - vfprintf (stderr, message, ap); - fprintf (stderr, ".\n"); - - if (exit_status >= 0) - exit (exit_status); -} - -void -lt_fatal (const char *message, ...) -{ - va_list ap; - va_start (ap, message); - lt_error_core (EXIT_FAILURE, "FATAL", message, ap); - va_end (ap); -} - -void -lt_setenv (const char *name, const char *value) -{ - LTWRAPPER_DEBUGPRINTF (("(lt_setenv) setting '%s' to '%s'\n", - (name ? name : ""), - (value ? value : ""))); - { -#ifdef HAVE_SETENV - /* always make a copy, for consistency with !HAVE_SETENV */ - char *str = xstrdup (value); - setenv (name, str, 1); -#else - int len = strlen (name) + 1 + strlen (value) + 1; - char *str = XMALLOC (char, len); - sprintf (str, "%s=%s", name, value); - if (putenv (str) != EXIT_SUCCESS) - { - XFREE (str); - } -#endif - } -} - -char * -lt_extend_str (const char *orig_value, const char *add, int to_end) -{ - char *new_value; - if (orig_value && *orig_value) - { - int orig_value_len = strlen (orig_value); - int add_len = strlen (add); - new_value = XMALLOC (char, add_len + orig_value_len + 1); - if (to_end) - { - strcpy (new_value, orig_value); - strcpy (new_value + orig_value_len, add); - } - else - { - strcpy (new_value, add); - strcpy (new_value + add_len, orig_value); - } - } - else - { - new_value = xstrdup (add); - } - return new_value; -} - -void -lt_update_exe_path (const char *name, const char *value) -{ - LTWRAPPER_DEBUGPRINTF (("(lt_update_exe_path) modifying '%s' by prepending '%s'\n", - (name ? name : ""), - (value ? value : ""))); - - if (name && *name && value && *value) - { - char *new_value = lt_extend_str (getenv (name), value, 0); - /* some systems can't cope with a ':'-terminated path #' */ - int len = strlen (new_value); - while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1])) - { - new_value[len-1] = '\0'; - } - lt_setenv (name, new_value); - XFREE (new_value); - } -} - -void -lt_update_lib_path (const char *name, const char *value) -{ - LTWRAPPER_DEBUGPRINTF (("(lt_update_lib_path) modifying '%s' by prepending '%s'\n", - (name ? name : ""), - (value ? value : ""))); - - if (name && *name && value && *value) - { - char *new_value = lt_extend_str (getenv (name), value, 0); - lt_setenv (name, new_value); - XFREE (new_value); - } -} - -EOF - case $host_os in - mingw*) - cat <<"EOF" - -/* Prepares an argument vector before calling spawn(). - Note that spawn() does not by itself call the command interpreter - (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") : - ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - GetVersionEx(&v); - v.dwPlatformId == VER_PLATFORM_WIN32_NT; - }) ? "cmd.exe" : "command.com"). - Instead it simply concatenates the arguments, separated by ' ', and calls - CreateProcess(). We must quote the arguments since Win32 CreateProcess() - interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a - special way: - - Space and tab are interpreted as delimiters. They are not treated as - delimiters if they are surrounded by double quotes: "...". - - Unescaped double quotes are removed from the input. Their only effect is - that within double quotes, space and tab are treated like normal - characters. - - Backslashes not followed by double quotes are not special. - - But 2*n+1 backslashes followed by a double quote become - n backslashes followed by a double quote (n >= 0): - \" -> " - \\\" -> \" - \\\\\" -> \\" - */ -#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037" -char ** -prepare_spawn (char **argv) -{ - size_t argc; - char **new_argv; - size_t i; - - /* Count number of arguments. */ - for (argc = 0; argv[argc] != NULL; argc++) - ; - - /* Allocate new argument vector. */ - new_argv = XMALLOC (char *, argc + 1); - - /* Put quoted arguments into the new argument vector. */ - for (i = 0; i < argc; i++) - { - const char *string = argv[i]; - - if (string[0] == '\0') - new_argv[i] = xstrdup ("\"\""); - else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL) - { - int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL); - size_t length; - unsigned int backslashes; - const char *s; - char *quoted_string; - char *p; - - length = 0; - backslashes = 0; - if (quote_around) - length++; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - length += backslashes + 1; - length++; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - length += backslashes + 1; - - quoted_string = XMALLOC (char, length + 1); - - p = quoted_string; - backslashes = 0; - if (quote_around) - *p++ = '"'; - for (s = string; *s != '\0'; s++) - { - char c = *s; - if (c == '"') - { - unsigned int j; - for (j = backslashes + 1; j > 0; j--) - *p++ = '\\'; - } - *p++ = c; - if (c == '\\') - backslashes++; - else - backslashes = 0; - } - if (quote_around) - { - unsigned int j; - for (j = backslashes; j > 0; j--) - *p++ = '\\'; - *p++ = '"'; - } - *p = '\0'; - - new_argv[i] = quoted_string; - } - else - new_argv[i] = (char *) string; - } - new_argv[argc] = NULL; - - return new_argv; -} -EOF - ;; - esac - - cat <<"EOF" -void lt_dump_script (FILE* f) -{ -EOF - func_emit_wrapper yes | - $SED -e 's/\([\\"]\)/\\\1/g' \ - -e 's/^/ fputs ("/' -e 's/$/\\n", f);/' - - cat <<"EOF" -} -EOF -} -# end: func_emit_cwrapperexe_src - -# func_win32_import_lib_p ARG -# True if ARG is an import lib, as indicated by $file_magic_cmd -func_win32_import_lib_p () -{ - $opt_debug - case `eval "$file_magic_cmd \"\$1\" 2>/dev/null" | $SED -e 10q` in - *import*) : ;; - *) false ;; - esac -} - -# func_mode_link arg... -func_mode_link () -{ - $opt_debug - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - # It is impossible to link a dll without this setting, and - # we shouldn't force the makefile maintainer to figure out - # which system we are compiling for in order to pass an extra - # flag for every libtool invocation. - # allow_undefined=no - - # FIXME: Unfortunately, there are problems with the above when trying - # to make a dll which has undefined symbols, in which case not - # even a static library is built. For now, we need to specify - # -no-undefined on the libtool link line when we can be certain - # that all symbols are satisfied, otherwise we get a static library. - allow_undefined=yes - ;; - *) - allow_undefined=yes - ;; - esac - libtool_args=$nonopt - base_compile="$nonopt $@" - compile_command=$nonopt - finalize_command=$nonopt - - compile_rpath= - finalize_rpath= - compile_shlibpath= - finalize_shlibpath= - convenience= - old_convenience= - deplibs= - old_deplibs= - compiler_flags= - linker_flags= - dllsearchpath= - lib_search_path=`pwd` - inst_prefix_dir= - new_inherited_linker_flags= - - avoid_version=no - bindir= - dlfiles= - dlprefiles= - dlself=no - export_dynamic=no - export_symbols= - export_symbols_regex= - generated= - libobjs= - ltlibs= - module=no - no_install=no - objs= - non_pic_objects= - precious_files_regex= - prefer_static_libs=no - preload=no - prev= - prevarg= - release= - rpath= - xrpath= - perm_rpath= - temp_rpath= - thread_safe=no - vinfo= - vinfo_number=no - weak_libs= - single_module="${wl}-single_module" - func_infer_tag $base_compile - - # We need to know -static, to get the right output filenames. - for arg - do - case $arg in - -shared) - test "$build_libtool_libs" != yes && \ - func_fatal_configuration "can not build a shared library" - build_old_libs=no - break - ;; - -all-static | -static | -static-libtool-libs) - case $arg in - -all-static) - if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then - func_warning "complete static linking is impossible in this configuration" - fi - if test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - -static) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=built - ;; - -static-libtool-libs) - if test -z "$pic_flag" && test -n "$link_static_flag"; then - dlopen_self=$dlopen_self_static - fi - prefer_static_libs=yes - ;; - esac - build_libtool_libs=no - build_old_libs=yes - break - ;; - esac - done - - # See if our shared archives depend on static archives. - test -n "$old_archive_from_new_cmds" && build_old_libs=yes - - # Go through the arguments, transforming them on the way. - while test "$#" -gt 0; do - arg="$1" - shift - func_quote_for_eval "$arg" - qarg=$func_quote_for_eval_unquoted_result - func_append libtool_args " $func_quote_for_eval_result" - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - case $prev in - output) - func_append compile_command " @OUTPUT@" - func_append finalize_command " @OUTPUT@" - ;; - esac - - case $prev in - bindir) - bindir="$arg" - prev= - continue - ;; - dlfiles|dlprefiles) - if test "$preload" = no; then - # Add the symbol object into the linking commands. - func_append compile_command " @SYMFILE@" - func_append finalize_command " @SYMFILE@" - preload=yes - fi - case $arg in - *.la | *.lo) ;; # We handle these cases below. - force) - if test "$dlself" = no; then - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - self) - if test "$prev" = dlprefiles; then - dlself=yes - elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then - dlself=yes - else - dlself=needless - export_dynamic=yes - fi - prev= - continue - ;; - *) - if test "$prev" = dlfiles; then - dlfiles="$dlfiles $arg" - else - dlprefiles="$dlprefiles $arg" - fi - prev= - continue - ;; - esac - ;; - expsyms) - export_symbols="$arg" - test -f "$arg" \ - || func_fatal_error "symbol file \`$arg' does not exist" - prev= - continue - ;; - expsyms_regex) - export_symbols_regex="$arg" - prev= - continue - ;; - framework) - case $host in - *-*-darwin*) - case "$deplibs " in - *" $qarg.ltframework "*) ;; - *) deplibs="$deplibs $qarg.ltframework" # this is fixed later - ;; - esac - ;; - esac - prev= - continue - ;; - inst_prefix) - inst_prefix_dir="$arg" - prev= - continue - ;; - objectlist) - if test -f "$arg"; then - save_arg=$arg - moreargs= - for fil in `cat "$save_arg"` - do -# moreargs="$moreargs $fil" - arg=$fil - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if func_lalib_unsafe_p "$arg"; then - pic_object= - non_pic_object= - - # Read the .lo file - func_source "$arg" - - if test -z "$pic_object" || - test -z "$non_pic_object" || - test "$pic_object" = none && - test "$non_pic_object" = none; then - func_fatal_error "cannot find name of object for \`$arg'" - fi - - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir="$func_dirname_result" - - if test "$pic_object" != none; then - # Prepend the subdirectory the object is found in. - pic_object="$xdir$pic_object" - - if test "$prev" = dlfiles; then - if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - dlfiles="$dlfiles $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test "$prev" = dlprefiles; then - # Preload the old-style object. - dlprefiles="$dlprefiles $pic_object" - prev= - fi - - # A PIC object. - func_append libobjs " $pic_object" - arg="$pic_object" - fi - - # Non-PIC object. - if test "$non_pic_object" != none; then - # Prepend the subdirectory the object is found in. - non_pic_object="$xdir$non_pic_object" - - # A standard non-PIC object - func_append non_pic_objects " $non_pic_object" - if test -z "$pic_object" || test "$pic_object" = none ; then - arg="$non_pic_object" - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object="$pic_object" - func_append non_pic_objects " $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if $opt_dry_run; then - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir="$func_dirname_result" - - func_lo2o "$arg" - pic_object=$xdir$objdir/$func_lo2o_result - non_pic_object=$xdir$func_lo2o_result - func_append libobjs " $pic_object" - func_append non_pic_objects " $non_pic_object" - else - func_fatal_error "\`$arg' is not a valid libtool object" - fi - fi - done - else - func_fatal_error "link input file \`$arg' does not exist" - fi - arg=$save_arg - prev= - continue - ;; - precious_regex) - precious_files_regex="$arg" - prev= - continue - ;; - release) - release="-$arg" - prev= - continue - ;; - rpath | xrpath) - # We need an absolute path. - case $arg in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - func_fatal_error "only absolute run-paths are allowed" - ;; - esac - if test "$prev" = rpath; then - case "$rpath " in - *" $arg "*) ;; - *) rpath="$rpath $arg" ;; - esac - else - case "$xrpath " in - *" $arg "*) ;; - *) xrpath="$xrpath $arg" ;; - esac - fi - prev= - continue - ;; - shrext) - shrext_cmds="$arg" - prev= - continue - ;; - weak) - weak_libs="$weak_libs $arg" - prev= - continue - ;; - xcclinker) - linker_flags="$linker_flags $qarg" - compiler_flags="$compiler_flags $qarg" - prev= - func_append compile_command " $qarg" - func_append finalize_command " $qarg" - continue - ;; - xcompiler) - compiler_flags="$compiler_flags $qarg" - prev= - func_append compile_command " $qarg" - func_append finalize_command " $qarg" - continue - ;; - xlinker) - linker_flags="$linker_flags $qarg" - compiler_flags="$compiler_flags $wl$qarg" - prev= - func_append compile_command " $wl$qarg" - func_append finalize_command " $wl$qarg" - continue - ;; - *) - eval "$prev=\"\$arg\"" - prev= - continue - ;; - esac - fi # test -n "$prev" - - prevarg="$arg" - - case $arg in - -all-static) - if test -n "$link_static_flag"; then - # See comment for -static flag below, for more details. - func_append compile_command " $link_static_flag" - func_append finalize_command " $link_static_flag" - fi - continue - ;; - - -allow-undefined) - # FIXME: remove this flag sometime in the future. - func_fatal_error "\`-allow-undefined' must not be used because it is the default" - ;; - - -avoid-version) - avoid_version=yes - continue - ;; - - -bindir) - prev=bindir - continue - ;; - - -dlopen) - prev=dlfiles - continue - ;; - - -dlpreopen) - prev=dlprefiles - continue - ;; - - -export-dynamic) - export_dynamic=yes - continue - ;; - - -export-symbols | -export-symbols-regex) - if test -n "$export_symbols" || test -n "$export_symbols_regex"; then - func_fatal_error "more than one -exported-symbols argument is not allowed" - fi - if test "X$arg" = "X-export-symbols"; then - prev=expsyms - else - prev=expsyms_regex - fi - continue - ;; - - -framework) - prev=framework - continue - ;; - - -inst-prefix-dir) - prev=inst_prefix - continue - ;; - - # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:* - # so, if we see these flags be careful not to treat them like -L - -L[A-Z][A-Z]*:*) - case $with_gcc/$host in - no/*-*-irix* | /*-*-irix*) - func_append compile_command " $arg" - func_append finalize_command " $arg" - ;; - esac - continue - ;; - - -L*) - func_stripname '-L' '' "$arg" - dir=$func_stripname_result - if test -z "$dir"; then - if test "$#" -gt 0; then - func_fatal_error "require no space between \`-L' and \`$1'" - else - func_fatal_error "need path for \`-L' option" - fi - fi - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - absdir=`cd "$dir" && pwd` - test -z "$absdir" && \ - func_fatal_error "cannot determine absolute directory name of \`$dir'" - dir="$absdir" - ;; - esac - case "$deplibs " in - *" -L$dir "*) ;; - *) - deplibs="$deplibs -L$dir" - lib_search_path="$lib_search_path $dir" - ;; - esac - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$dir:"*) ;; - ::) dllsearchpath=$dir;; - *) dllsearchpath="$dllsearchpath:$dir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - ::) dllsearchpath=$testbindir;; - *) dllsearchpath="$dllsearchpath:$testbindir";; - esac - ;; - esac - continue - ;; - - -l*) - if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*) - # These systems don't actually have a C or math library (as such) - continue - ;; - *-*-os2*) - # These systems don't actually have a C library (as such) - test "X$arg" = "X-lc" && continue - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* | *-*-bitrig*) - # Do not include libc due to us having libc/libc_r. - test "X$arg" = "X-lc" && continue - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C and math libraries are in the System framework - deplibs="$deplibs System.ltframework" - continue - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - test "X$arg" = "X-lc" && continue - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - test "X$arg" = "X-lc" && continue - ;; - *-*-linux*) - test "X$arg" = "X-lc" && continue - ;; - esac - elif test "X$arg" = "X-lc_r"; then - case $host in - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc_r directly, use -pthread flag. - continue - ;; - esac - fi - deplibs="$deplibs $arg" - continue - ;; - - -module) - module=yes - continue - ;; - - # Tru64 UNIX uses -model [arg] to determine the layout of C++ - # classes, name mangling, and exception handling. - # Darwin uses the -arch flag to determine output architecture. - -model|-arch|-isysroot) - compiler_flags="$compiler_flags $arg" - func_append compile_command " $arg" - func_append finalize_command " $arg" - prev=xcompiler - continue - ;; - - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) - compiler_flags="$compiler_flags $arg" - func_append compile_command " $arg" - func_append finalize_command " $arg" - case "$new_inherited_linker_flags " in - *" $arg "*) ;; - * ) new_inherited_linker_flags="$new_inherited_linker_flags $arg" ;; - esac - continue - ;; - - -multi_module) - single_module="${wl}-multi_module" - continue - ;; - - -no-fast-install) - fast_install=no - continue - ;; - - -no-install) - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*) - # The PATH hackery in wrapper scripts is required on Windows - # and Darwin in order for the loader to find any dlls it needs. - func_warning "\`-no-install' is ignored for $host" - func_warning "assuming \`-no-fast-install' instead" - fast_install=no - ;; - *) no_install=yes ;; - esac - continue - ;; - - -no-undefined) - allow_undefined=no - continue - ;; - - -objectlist) - prev=objectlist - continue - ;; - - -o) prev=output ;; - - -precious-files-regex) - prev=precious_regex - continue - ;; - - -release) - prev=release - continue - ;; - - -rpath) - prev=rpath - continue - ;; - - -R) - prev=xrpath - continue - ;; - - -R*) - func_stripname '-R' '' "$arg" - dir=$func_stripname_result - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) ;; - *) - func_fatal_error "only absolute run-paths are allowed" - ;; - esac - case "$xrpath " in - *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; - esac - continue - ;; - - -shared) - # The effects of -shared are defined in a previous loop. - continue - ;; - - -shrext) - prev=shrext - continue - ;; - - -static | -static-libtool-libs) - # The effects of -static are defined in a previous loop. - # We used to do the same as -all-static on platforms that - # didn't have a PIC flag, but the assumption that the effects - # would be equivalent was wrong. It would break on at least - # Digital Unix and AIX. - continue - ;; - - -thread-safe) - thread_safe=yes - continue - ;; - - -version-info) - prev=vinfo - continue - ;; - - -version-number) - prev=vinfo - vinfo_number=yes - continue - ;; - - -weak) - prev=weak - continue - ;; - - -Wc,*) - func_stripname '-Wc,' '' "$arg" - args=$func_stripname_result - arg= - save_ifs="$IFS"; IFS=',' - for flag in $args; do - IFS="$save_ifs" - func_quote_for_eval "$flag" - arg="$arg $func_quote_for_eval_result" - compiler_flags="$compiler_flags $func_quote_for_eval_result" - done - IFS="$save_ifs" - func_stripname ' ' '' "$arg" - arg=$func_stripname_result - ;; - - -Wl,*) - func_stripname '-Wl,' '' "$arg" - args=$func_stripname_result - arg= - save_ifs="$IFS"; IFS=',' - for flag in $args; do - IFS="$save_ifs" - func_quote_for_eval "$flag" - arg="$arg $wl$func_quote_for_eval_result" - compiler_flags="$compiler_flags $wl$func_quote_for_eval_result" - linker_flags="$linker_flags $func_quote_for_eval_result" - done - IFS="$save_ifs" - func_stripname ' ' '' "$arg" - arg=$func_stripname_result - ;; - - -Xcompiler) - prev=xcompiler - continue - ;; - - -Xlinker) - prev=xlinker - continue - ;; - - -XCClinker) - prev=xcclinker - continue - ;; - - # -msg_* for osf cc - -msg_*) - func_quote_for_eval "$arg" - arg="$func_quote_for_eval_result" - ;; - - # -64, -mips[0-9] enable 64-bit mode on the SGI compiler - # -r[0-9][0-9]* specifies the processor on the SGI compiler - # -xarch=*, -xtarget=* enable 64-bit mode on the Sun compiler - # +DA*, +DD* enable 64-bit mode on the HP compiler - # -q* pass through compiler args for the IBM compiler - # -m*, -t[45]*, -txscale* pass through architecture-specific - # compiler args for GCC - # -F/path gives path to uninstalled frameworks, gcc on darwin - # -p, -pg, --coverage, -fprofile-* pass through profiling flag for GCC - # @file GCC response files - # -tp=* Portland pgcc target processor selection - -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \ - -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*) - func_quote_for_eval "$arg" - arg="$func_quote_for_eval_result" - func_append compile_command " $arg" - func_append finalize_command " $arg" - compiler_flags="$compiler_flags $arg" - continue - ;; - - # Some other compiler flag. - -* | +*) - func_quote_for_eval "$arg" - arg="$func_quote_for_eval_result" - ;; - - *.$objext) - # A standard object. - objs="$objs $arg" - ;; - - *.lo) - # A libtool-controlled object. - - # Check to see that this really is a libtool object. - if func_lalib_unsafe_p "$arg"; then - pic_object= - non_pic_object= - - # Read the .lo file - func_source "$arg" - - if test -z "$pic_object" || - test -z "$non_pic_object" || - test "$pic_object" = none && - test "$non_pic_object" = none; then - func_fatal_error "cannot find name of object for \`$arg'" - fi - - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir="$func_dirname_result" - - if test "$pic_object" != none; then - # Prepend the subdirectory the object is found in. - pic_object="$xdir$pic_object" - - if test "$prev" = dlfiles; then - if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then - dlfiles="$dlfiles $pic_object" - prev= - continue - else - # If libtool objects are unsupported, then we need to preload. - prev=dlprefiles - fi - fi - - # CHECK ME: I think I busted this. -Ossama - if test "$prev" = dlprefiles; then - # Preload the old-style object. - dlprefiles="$dlprefiles $pic_object" - prev= - fi - - # A PIC object. - func_append libobjs " $pic_object" - arg="$pic_object" - fi - - # Non-PIC object. - if test "$non_pic_object" != none; then - # Prepend the subdirectory the object is found in. - non_pic_object="$xdir$non_pic_object" - - # A standard non-PIC object - func_append non_pic_objects " $non_pic_object" - if test -z "$pic_object" || test "$pic_object" = none ; then - arg="$non_pic_object" - fi - else - # If the PIC object exists, use it instead. - # $xdir was prepended to $pic_object above. - non_pic_object="$pic_object" - func_append non_pic_objects " $non_pic_object" - fi - else - # Only an error if not doing a dry-run. - if $opt_dry_run; then - # Extract subdirectory from the argument. - func_dirname "$arg" "/" "" - xdir="$func_dirname_result" - - func_lo2o "$arg" - pic_object=$xdir$objdir/$func_lo2o_result - non_pic_object=$xdir$func_lo2o_result - func_append libobjs " $pic_object" - func_append non_pic_objects " $non_pic_object" - else - func_fatal_error "\`$arg' is not a valid libtool object" - fi - fi - ;; - - *.$libext) - # An archive. - deplibs="$deplibs $arg" - old_deplibs="$old_deplibs $arg" - continue - ;; - - *.la) - # A libtool-controlled library. - - if test "$prev" = dlfiles; then - # This library was specified with -dlopen. - dlfiles="$dlfiles $arg" - prev= - elif test "$prev" = dlprefiles; then - # The library was specified with -dlpreopen. - dlprefiles="$dlprefiles $arg" - prev= - else - deplibs="$deplibs $arg" - fi - continue - ;; - - # Some other compiler argument. - *) - # Unknown arguments in both finalize_command and compile_command need - # to be aesthetically quoted because they are evaled later. - func_quote_for_eval "$arg" - arg="$func_quote_for_eval_result" - ;; - esac # arg - - # Now actually substitute the argument into the commands. - if test -n "$arg"; then - func_append compile_command " $arg" - func_append finalize_command " $arg" - fi - done # argument parsing loop - - test -n "$prev" && \ - func_fatal_help "the \`$prevarg' option requires an argument" - - if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then - eval "arg=\"$export_dynamic_flag_spec\"" - func_append compile_command " $arg" - func_append finalize_command " $arg" - fi - - oldlibs= - # calculate the name of the file, without its directory - func_basename "$output" - outputname="$func_basename_result" - libobjs_save="$libobjs" - - if test -n "$shlibpath_var"; then - # get the directories listed in $shlibpath_var - eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\` - else - shlib_search_path= - fi - eval "sys_lib_search_path=\"$sys_lib_search_path_spec\"" - eval "sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"" - - func_dirname "$output" "/" "" - output_objdir="$func_dirname_result$objdir" - # Create the object directory. - func_mkdir_p "$output_objdir" - - # Determine the type of output - case $output in - "") - func_fatal_help "you must specify an output file" - ;; - *.$libext) linkmode=oldlib ;; - *.lo | *.$objext) linkmode=obj ;; - *.la) linkmode=lib ;; - *) linkmode=prog ;; # Anything else should be a program. - esac - - specialdeplibs= - - libs= - # Find all interdependent deplibs by searching for libraries - # that are linked more than once (e.g. -la -lb -la) - for deplib in $deplibs; do - if $opt_duplicate_deps ; then - case "$libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - libs="$libs $deplib" - done - - if test "$linkmode" = lib; then - libs="$predeps $libs $compiler_lib_search_path $postdeps" - - # Compute libraries that are listed more than once in $predeps - # $postdeps and mark them as special (i.e., whose duplicates are - # not to be eliminated). - pre_post_deps= - if $opt_duplicate_compiler_generated_deps; then - for pre_post_dep in $predeps $postdeps; do - case "$pre_post_deps " in - *" $pre_post_dep "*) specialdeplibs="$specialdeplibs $pre_post_deps" ;; - esac - pre_post_deps="$pre_post_deps $pre_post_dep" - done - fi - pre_post_deps= - fi - - deplibs= - newdependency_libs= - newlib_search_path= - need_relink=no # whether we're linking any uninstalled libtool libraries - notinst_deplibs= # not-installed libtool libraries - notinst_path= # paths that contain not-installed libtool libraries - - case $linkmode in - lib) - passes="conv dlpreopen link" - for file in $dlfiles $dlprefiles; do - case $file in - *.la) ;; - *) - func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file" - ;; - esac - done - ;; - prog) - compile_deplibs= - finalize_deplibs= - alldeplibs=no - newdlfiles= - newdlprefiles= - passes="conv scan dlopen dlpreopen link" - ;; - *) passes="conv" - ;; - esac - - for pass in $passes; do - # The preopen pass in lib mode reverses $deplibs; put it back here - # so that -L comes before libs that need it for instance... - if test "$linkmode,$pass" = "lib,link"; then - ## FIXME: Find the place where the list is rebuilt in the wrong - ## order, and fix it there properly - tmp_deplibs= - for deplib in $deplibs; do - tmp_deplibs="$deplib $tmp_deplibs" - done - deplibs="$tmp_deplibs" - fi - - if test "$linkmode,$pass" = "lib,link" || - test "$linkmode,$pass" = "prog,scan"; then - libs="$deplibs" - deplibs= - fi - if test "$linkmode" = prog; then - case $pass in - dlopen) libs="$dlfiles" ;; - dlpreopen) libs="$dlprefiles" ;; - link) libs="$deplibs %DEPLIBS% $dependency_libs" ;; - esac - fi - if test "$linkmode,$pass" = "lib,dlpreopen"; then - # Collect and forward deplibs of preopened libtool libs - for lib in $dlprefiles; do - # Ignore non-libtool-libs - dependency_libs= - case $lib in - *.la) func_source "$lib" ;; - esac - - # Collect preopened libtool deplibs, except any this library - # has declared as weak libs - for deplib in $dependency_libs; do - func_basename "$deplib" - deplib_base=$func_basename_result - case " $weak_libs " in - *" $deplib_base "*) ;; - *) deplibs="$deplibs $deplib" ;; - esac - done - done - libs="$dlprefiles" - fi - if test "$pass" = dlopen; then - # Collect dlpreopened libraries - save_deplibs="$deplibs" - deplibs= - fi - - for deplib in $libs; do - lib= - found=no - case $deplib in - -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe|-threads) - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - compiler_flags="$compiler_flags $deplib" - if test "$linkmode" = lib ; then - case "$new_inherited_linker_flags " in - *" $deplib "*) ;; - * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; - esac - fi - fi - continue - ;; - -l*) - if test "$linkmode" != lib && test "$linkmode" != prog; then - func_warning "\`-l' is ignored for archives/objects" - continue - fi - func_stripname '-l' '' "$deplib" - name=$func_stripname_result - if test "$linkmode" = lib; then - searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path" - else - searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path" - fi - for searchdir in $searchdirs; do - for search_ext in .la $std_shrext .so .a; do - # Search the libtool library - lib="$searchdir/lib${name}${search_ext}" - if test -f "$lib"; then - if test "$search_ext" = ".la"; then - found=yes - else - found=no - fi - break 2 - fi - done - done - if test "$found" != yes; then - # deplib doesn't seem to be a libtool library - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" - fi - continue - else # deplib is a libtool library - # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib, - # We need to do some special things here, and not later. - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $deplib "*) - if func_lalib_p "$lib"; then - library_names= - old_library= - func_source "$lib" - for l in $old_library $library_names; do - ll="$l" - done - if test "X$ll" = "X$old_library" ; then # only static version available - found=no - func_dirname "$lib" "" "." - ladir="$func_dirname_result" - lib=$ladir/$old_library - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs" - fi - continue - fi - fi - ;; - *) ;; - esac - fi - fi - ;; # -l - *.ltframework) - if test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - deplibs="$deplib $deplibs" - if test "$linkmode" = lib ; then - case "$new_inherited_linker_flags " in - *" $deplib "*) ;; - * ) new_inherited_linker_flags="$new_inherited_linker_flags $deplib" ;; - esac - fi - fi - continue - ;; - -L*) - case $linkmode in - lib) - deplibs="$deplib $deplibs" - test "$pass" = conv && continue - newdependency_libs="$deplib $newdependency_libs" - func_stripname '-L' '' "$deplib" - newlib_search_path="$newlib_search_path $func_stripname_result" - ;; - prog) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - if test "$pass" = scan; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - func_stripname '-L' '' "$deplib" - newlib_search_path="$newlib_search_path $func_stripname_result" - ;; - *) - func_warning "\`-L' is ignored for archives/objects" - ;; - esac # linkmode - continue - ;; # -L - -R*) - if test "$pass" = link; then - func_stripname '-R' '' "$deplib" - dir=$func_stripname_result - # Make sure the xrpath contains only unique directories. - case "$xrpath " in - *" $dir "*) ;; - *) xrpath="$xrpath $dir" ;; - esac - fi - deplibs="$deplib $deplibs" - continue - ;; - *.la) lib="$deplib" ;; - *.$libext) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - continue - fi - case $linkmode in - lib) - # Linking convenience modules into shared libraries is allowed, - # but linking other static libraries is non-portable. - case " $dlpreconveniencelibs " in - *" $deplib "*) ;; - *) - valid_a_lib=no - case $deplibs_check_method in - match_pattern*) - set dummy $deplibs_check_method; shift - match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` - if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \ - | $EGREP "$match_pattern_regex" > /dev/null; then - valid_a_lib=yes - fi - ;; - pass_all) - valid_a_lib=yes - ;; - esac - if test "$valid_a_lib" != yes; then - echo - $ECHO "*** Warning: Trying to link with static lib archive $deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because the file extensions .$libext of this argument makes me believe" - echo "*** that it is just a static archive that I should not use here." - else - echo - $ECHO "*** Warning: Linking the shared library $output against the" - $ECHO "*** static library $deplib is not portable!" - deplibs="$deplib $deplibs" - fi - ;; - esac - continue - ;; - prog) - if test "$pass" != link; then - deplibs="$deplib $deplibs" - else - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - fi - continue - ;; - esac # linkmode - ;; # *.$libext - *.lo | *.$objext) - if test "$pass" = conv; then - deplibs="$deplib $deplibs" - elif test "$linkmode" = prog; then - if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then - # If there is no dlopen support or we're linking statically, - # we need to preload. - newdlprefiles="$newdlprefiles $deplib" - compile_deplibs="$deplib $compile_deplibs" - finalize_deplibs="$deplib $finalize_deplibs" - else - newdlfiles="$newdlfiles $deplib" - fi - fi - continue - ;; - %DEPLIBS%) - alldeplibs=yes - continue - ;; - esac # case $deplib - - if test "$found" = yes || test -f "$lib"; then : - else - func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'" - fi - - # Check to see that this really is a libtool archive. - func_lalib_unsafe_p "$lib" \ - || func_fatal_error "\`$lib' is not a valid libtool archive" - - func_dirname "$lib" "" "." - ladir="$func_dirname_result" - - dlname= - dlopen= - dlpreopen= - libdir= - library_names= - old_library= - inherited_linker_flags= - # If the library was installed with an old release of libtool, - # it will not redefine variables installed, or shouldnotlink - installed=yes - shouldnotlink=no - avoidtemprpath= - - - # Read the .la file - func_source "$lib" - - # Convert "-framework foo" to "foo.ltframework" - if test -n "$inherited_linker_flags"; then - tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'` - for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do - case " $new_inherited_linker_flags " in - *" $tmp_inherited_linker_flag "*) ;; - *) new_inherited_linker_flags="$new_inherited_linker_flags $tmp_inherited_linker_flag";; - esac - done - fi - dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - if test "$linkmode,$pass" = "lib,link" || - test "$linkmode,$pass" = "prog,scan" || - { test "$linkmode" != prog && test "$linkmode" != lib; }; then - test -n "$dlopen" && dlfiles="$dlfiles $dlopen" - test -n "$dlpreopen" && dlprefiles="$dlprefiles $dlpreopen" - fi - - if test "$pass" = conv; then - # Only check for convenience libraries - deplibs="$lib $deplibs" - if test -z "$libdir"; then - if test -z "$old_library"; then - func_fatal_error "cannot find name of link library for \`$lib'" - fi - # It is a libtool convenience library, so add in its objects. - convenience="$convenience $ladir/$objdir/$old_library" - old_convenience="$old_convenience $ladir/$objdir/$old_library" - elif test "$linkmode" != prog && test "$linkmode" != lib; then - func_fatal_error "\`$lib' is not a convenience library" - fi - tmp_libs= - for deplib in $dependency_libs; do - deplibs="$deplib $deplibs" - if $opt_duplicate_deps ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done - continue - fi # $pass = conv - - - # Get the name of the library we link against. - linklib= - for l in $old_library $library_names; do - linklib="$l" - done - if test -z "$linklib"; then - func_fatal_error "cannot find name of link library for \`$lib'" - fi - - # This library was specified with -dlopen. - if test "$pass" = dlopen; then - if test -z "$libdir"; then - func_fatal_error "cannot -dlopen a convenience library: \`$lib'" - fi - if test -z "$dlname" || - test "$dlopen_support" != yes || - test "$build_libtool_libs" = no; then - # If there is no dlname, no dlopen support or we're linking - # statically, we need to preload. We also need to preload any - # dependent libraries so libltdl's deplib preloader doesn't - # bomb out in the load deplibs phase. - dlprefiles="$dlprefiles $lib $dependency_libs" - else - newdlfiles="$newdlfiles $lib" - fi - continue - fi # $pass = dlopen - - # We need an absolute path. - case $ladir in - [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;; - *) - abs_ladir=`cd "$ladir" && pwd` - if test -z "$abs_ladir"; then - func_warning "cannot determine absolute directory name of \`$ladir'" - func_warning "passing it literally to the linker, although it might fail" - abs_ladir="$ladir" - fi - ;; - esac - func_basename "$lib" - laname="$func_basename_result" - - # Find the relevant object directory and library name. - if test "X$installed" = Xyes; then - if test ! -f "$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then - func_warning "library \`$lib' was moved." - dir="$ladir" - absdir="$abs_ladir" - libdir="$abs_ladir" - else - dir="$libdir" - absdir="$libdir" - fi - test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes - else - if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then - dir="$ladir" - absdir="$abs_ladir" - # Remove this search path later - notinst_path="$notinst_path $abs_ladir" - else - dir="$ladir/$objdir" - absdir="$abs_ladir/$objdir" - # Remove this search path later - notinst_path="$notinst_path $abs_ladir" - fi - fi # $installed = yes - func_stripname 'lib' '.la' "$laname" - name=$func_stripname_result - - # This library was specified with -dlpreopen. - if test "$pass" = dlpreopen; then - if test -z "$libdir" && test "$linkmode" = prog; then - func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'" - fi - # Prefer using a static library (so that no silly _DYNAMIC symbols - # are required to link). - if test -n "$old_library"; then - newdlprefiles="$newdlprefiles $dir/$old_library" - # Keep a list of preopened convenience libraries to check - # that they are being used correctly in the link pass. - test -z "$libdir" && \ - dlpreconveniencelibs="$dlpreconveniencelibs $dir/$old_library" - # Otherwise, use the dlname, so that lt_dlopen finds it. - elif test -n "$dlname"; then - newdlprefiles="$newdlprefiles $dir/$dlname" - else - newdlprefiles="$newdlprefiles $dir/$linklib" - fi - fi # $pass = dlpreopen - - if test -z "$libdir"; then - # Link the convenience library - if test "$linkmode" = lib; then - deplibs="$dir/$old_library $deplibs" - elif test "$linkmode,$pass" = "prog,link"; then - compile_deplibs="$dir/$old_library $compile_deplibs" - finalize_deplibs="$dir/$old_library $finalize_deplibs" - else - deplibs="$lib $deplibs" # used for prog,scan pass - fi - continue - fi - - - if test "$linkmode" = prog && test "$pass" != link; then - newlib_search_path="$newlib_search_path $ladir" - deplibs="$lib $deplibs" - - linkalldeplibs=no - if test "$link_all_deplibs" != no || test -z "$library_names" || - test "$build_libtool_libs" = no; then - linkalldeplibs=yes - fi - - tmp_libs= - for deplib in $dependency_libs; do - case $deplib in - -L*) func_stripname '-L' '' "$deplib" - newlib_search_path="$newlib_search_path $func_stripname_result" - ;; - esac - # Need to link against all dependency_libs? - if test "$linkalldeplibs" = yes; then - deplibs="$deplib $deplibs" - else - # Need to hardcode shared library paths - # or/and link against static libraries - newdependency_libs="$deplib $newdependency_libs" - fi - if $opt_duplicate_deps ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done # for deplib - continue - fi # $linkmode = prog... - - if test "$linkmode,$pass" = "prog,link"; then - if test -n "$library_names" && - { { test "$prefer_static_libs" = no || - test "$prefer_static_libs,$installed" = "built,yes"; } || - test -z "$old_library"; }; then - # We need to hardcode the library path - if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then - # Make sure the rpath contains only unique directories. - case "$temp_rpath:" in - *"$absdir:"*) ;; - *) temp_rpath="$temp_rpath$absdir:" ;; - esac - fi - - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" - esac - ;; - esac - fi # $linkmode,$pass = prog,link... - - if test "$alldeplibs" = yes && - { test "$deplibs_check_method" = pass_all || - { test "$build_libtool_libs" = yes && - test -n "$library_names"; }; }; then - # We only need to search for static libraries - continue - fi - fi - - link_static=no # Whether the deplib will be linked statically - use_static_libs=$prefer_static_libs - if test "$use_static_libs" = built && test "$installed" = yes; then - use_static_libs=no - fi - if test -n "$library_names" && - { test "$use_static_libs" = no || test -z "$old_library"; }; then - case $host in - *cygwin* | *mingw* | *cegcc*) - # No point in relinking DLLs because paths are not encoded - notinst_deplibs="$notinst_deplibs $lib" - need_relink=no - ;; - *) - if test "$installed" = no; then - notinst_deplibs="$notinst_deplibs $lib" - need_relink=yes - fi - ;; - esac - # This is a shared library - - # Warn about portability, can't link against -module's on some - # systems (darwin). Don't bleat about dlopened modules though! - dlopenmodule="" - for dlpremoduletest in $dlprefiles; do - if test "X$dlpremoduletest" = "X$lib"; then - dlopenmodule="$dlpremoduletest" - break - fi - done - if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then - echo - if test "$linkmode" = prog; then - $ECHO "*** Warning: Linking the executable $output against the loadable module" - else - $ECHO "*** Warning: Linking the shared library $output against the loadable module" - fi - $ECHO "*** $linklib is not portable!" - fi - if test "$linkmode" = lib && - test "$hardcode_into_libs" = yes; then - # Hardcode the library path. - # Skip directories that are in the system default run-time - # search path. - case " $sys_lib_dlsearch_path " in - *" $absdir "*) ;; - *) - case "$compile_rpath " in - *" $absdir "*) ;; - *) compile_rpath="$compile_rpath $absdir" - esac - ;; - esac - case " $sys_lib_dlsearch_path " in - *" $libdir "*) ;; - *) - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" - esac - ;; - esac - fi - - if test -n "$old_archive_from_expsyms_cmds"; then - # figure out the soname - set dummy $library_names - shift - realname="$1" - shift - eval "libname=\"$libname_spec\"" - # use dlname if we got it. it's perfectly good, no? - if test -n "$dlname"; then - soname="$dlname" - elif test -n "$soname_spec"; then - # bleh windows - case $host in - *cygwin* | mingw* | *cegcc*) - func_arith $current - $age - major=$func_arith_result - versuffix="-$major" - ;; - esac - eval "soname=\"$soname_spec\"" - else - soname="$realname" - fi - - # Make a new name for the extract_expsyms_cmds to use - soroot="$soname" - func_basename "$soroot" - soname="$func_basename_result" - func_stripname 'lib' '.dll' "$soname" - newlib=libimp-$func_stripname_result.a - - # If the library has no export list, then create one now - if test -f "$output_objdir/$soname-def"; then : - else - func_verbose "extracting exported symbol list from \`$soname'" - func_execute_cmds "$extract_expsyms_cmds" 'exit $?' - fi - - # Create $newlib - if test -f "$output_objdir/$newlib"; then :; else - func_verbose "generating import library for \`$soname'" - func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?' - fi - # make sure the library variables are pointing to the new library - dir=$output_objdir - linklib=$newlib - fi # test -n "$old_archive_from_expsyms_cmds" - - if test "$linkmode" = prog || test "$mode" != relink; then - add_shlibpath= - add_dir= - add= - lib_linked=yes - case $hardcode_action in - immediate | unsupported) - if test "$hardcode_direct" = no; then - add="$dir/$linklib" - case $host in - *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;; - *-*-sysv4*uw2*) add_dir="-L$dir" ;; - *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \ - *-*-unixware7*) add_dir="-L$dir" ;; - *-*-darwin* ) - # if the lib is a (non-dlopened) module then we can not - # link against it, someone is ignoring the earlier warnings - if /usr/bin/file -L $add 2> /dev/null | - $GREP ": [^:]* bundle" >/dev/null ; then - if test "X$dlopenmodule" != "X$lib"; then - $ECHO "*** Warning: lib $linklib is a module, not a shared library" - if test -z "$old_library" ; then - echo - echo "*** And there doesn't seem to be a static archive available" - echo "*** The link will probably fail, sorry" - else - add="$dir/$old_library" - fi - elif test -n "$old_library"; then - add="$dir/$old_library" - fi - fi - esac - elif test "$hardcode_minus_L" = no; then - case $host in - *-*-sunos*) add_shlibpath="$dir" ;; - esac - add_dir="-L$dir" - add="-l$name" - elif test "$hardcode_shlibpath_var" = no; then - add_shlibpath="$dir" - add="-l$name" - else - lib_linked=no - fi - ;; - relink) - if test "$hardcode_direct" = yes && - test "$hardcode_direct_absolute" = no; then - add="$dir/$linklib" - elif test "$hardcode_minus_L" = yes; then - add_dir="-L$absdir" - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in - [\\/]*) - add_dir="$add_dir -L$inst_prefix_dir$libdir" - ;; - esac - fi - add="-l$name" - elif test "$hardcode_shlibpath_var" = yes; then - add_shlibpath="$dir" - add="-l$name" - else - lib_linked=no - fi - ;; - *) lib_linked=no ;; - esac - - if test "$lib_linked" != yes; then - func_fatal_configuration "unsupported hardcode properties" - fi - - if test -n "$add_shlibpath"; then - case :$compile_shlibpath: in - *":$add_shlibpath:"*) ;; - *) compile_shlibpath="$compile_shlibpath$add_shlibpath:" ;; - esac - fi - if test "$linkmode" = prog; then - test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs" - test -n "$add" && compile_deplibs="$add $compile_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - if test "$hardcode_direct" != yes && - test "$hardcode_minus_L" != yes && - test "$hardcode_shlibpath_var" = yes; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; - esac - fi - fi - fi - - if test "$linkmode" = prog || test "$mode" = relink; then - add_shlibpath= - add_dir= - add= - # Finalize command for both is simple: just hardcode it. - if test "$hardcode_direct" = yes && - test "$hardcode_direct_absolute" = no; then - add="$libdir/$linklib" - elif test "$hardcode_minus_L" = yes; then - add_dir="-L$libdir" - add="-l$name" - elif test "$hardcode_shlibpath_var" = yes; then - case :$finalize_shlibpath: in - *":$libdir:"*) ;; - *) finalize_shlibpath="$finalize_shlibpath$libdir:" ;; - esac - add="-l$name" - elif test "$hardcode_automatic" = yes; then - if test -n "$inst_prefix_dir" && - test -f "$inst_prefix_dir$libdir/$linklib" ; then - add="$inst_prefix_dir$libdir/$linklib" - else - add="$libdir/$linklib" - fi - else - # We cannot seem to hardcode it, guess we'll fake it. - add_dir="-L$libdir" - # Try looking first in the location we're being installed to. - if test -n "$inst_prefix_dir"; then - case $libdir in - [\\/]*) - add_dir="$add_dir -L$inst_prefix_dir$libdir" - ;; - esac - fi - add="-l$name" - fi - - if test "$linkmode" = prog; then - test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs" - test -n "$add" && finalize_deplibs="$add $finalize_deplibs" - else - test -n "$add_dir" && deplibs="$add_dir $deplibs" - test -n "$add" && deplibs="$add $deplibs" - fi - fi - elif test "$linkmode" = prog; then - # Here we assume that one of hardcode_direct or hardcode_minus_L - # is not unsupported. This is valid on all known static and - # shared platforms. - if test "$hardcode_direct" != unsupported; then - test -n "$old_library" && linklib="$old_library" - compile_deplibs="$dir/$linklib $compile_deplibs" - finalize_deplibs="$dir/$linklib $finalize_deplibs" - else - compile_deplibs="-l$name -L$dir $compile_deplibs" - finalize_deplibs="-l$name -L$dir $finalize_deplibs" - fi - elif test "$build_libtool_libs" = yes; then - # Not a shared library - if test "$deplibs_check_method" != pass_all; then - # We're trying link a shared library against a static one - # but the system doesn't support it. - - # Just print a warning and add the library to dependency_libs so - # that the program can be linked against the static library. - echo - $ECHO "*** Warning: This system can not link to static lib archive $lib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have." - if test "$module" = yes; then - echo "*** But as you try to build a module library, libtool will still create " - echo "*** a static module, that should work as long as the dlopening application" - echo "*** is linked with the -dlopen flag to resolve symbols at runtime." - if test -z "$global_symbol_pipe"; then - echo - echo "*** However, this would only work if libtool was able to extract symbol" - echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - echo "*** not find such a program. So, this module is probably useless." - echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - else - deplibs="$dir/$old_library $deplibs" - link_static=yes - fi - fi # link shared/static library? - - if test "$linkmode" = lib; then - if test -n "$dependency_libs" && - { test "$hardcode_into_libs" != yes || - test "$build_old_libs" = yes || - test "$link_static" = yes; }; then - # Extract -R from dependency_libs - temp_deplibs= - for libdir in $dependency_libs; do - case $libdir in - -R*) func_stripname '-R' '' "$libdir" - temp_xrpath=$func_stripname_result - case " $xrpath " in - *" $temp_xrpath "*) ;; - *) xrpath="$xrpath $temp_xrpath";; - esac;; - *) temp_deplibs="$temp_deplibs $libdir";; - esac - done - dependency_libs="$temp_deplibs" - fi - - newlib_search_path="$newlib_search_path $absdir" - # Link against this library - test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs" - # ... and its dependency_libs - tmp_libs= - for deplib in $dependency_libs; do - newdependency_libs="$deplib $newdependency_libs" - if $opt_duplicate_deps ; then - case "$tmp_libs " in - *" $deplib "*) specialdeplibs="$specialdeplibs $deplib" ;; - esac - fi - tmp_libs="$tmp_libs $deplib" - done - - if test "$link_all_deplibs" != no; then - # Add the search paths of all dependency libraries - for deplib in $dependency_libs; do - path= - case $deplib in - -L*) path="$deplib" ;; - *.la) - func_dirname "$deplib" "" "." - dir="$func_dirname_result" - # We need an absolute path. - case $dir in - [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;; - *) - absdir=`cd "$dir" && pwd` - if test -z "$absdir"; then - func_warning "cannot determine absolute directory name of \`$dir'" - absdir="$dir" - fi - ;; - esac - if $GREP "^installed=no" $deplib > /dev/null; then - case $host in - *-*-darwin*) - depdepl= - deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib` - if test -n "$deplibrary_names" ; then - for tmp in $deplibrary_names ; do - depdepl=$tmp - done - if test -f "$absdir/$objdir/$depdepl" ; then - depdepl="$absdir/$objdir/$depdepl" - darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` - if test -z "$darwin_install_name"; then - darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'` - fi - compiler_flags="$compiler_flags ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}" - linker_flags="$linker_flags -dylib_file ${darwin_install_name}:${depdepl}" - path= - fi - fi - ;; - *) - path="-L$absdir/$objdir" - ;; - esac - else - libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - test -z "$libdir" && \ - func_fatal_error "\`$deplib' is not a valid libtool archive" - test "$absdir" != "$libdir" && \ - func_warning "\`$deplib' seems to be moved" - - path="-L$absdir" - fi - ;; - esac - case " $deplibs " in - *" $path "*) ;; - *) deplibs="$path $deplibs" ;; - esac - done - fi # link_all_deplibs != no - fi # linkmode = lib - done # for deplib in $libs - if test "$pass" = link; then - if test "$linkmode" = "prog"; then - compile_deplibs="$new_inherited_linker_flags $compile_deplibs" - finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs" - else - compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - fi - fi - dependency_libs="$newdependency_libs" - if test "$pass" = dlpreopen; then - # Link the dlpreopened libraries before other libraries - for deplib in $save_deplibs; do - deplibs="$deplib $deplibs" - done - fi - if test "$pass" != dlopen; then - if test "$pass" != conv; then - # Make sure lib_search_path contains only unique directories. - lib_search_path= - for dir in $newlib_search_path; do - case "$lib_search_path " in - *" $dir "*) ;; - *) lib_search_path="$lib_search_path $dir" ;; - esac - done - newlib_search_path= - fi - - if test "$linkmode,$pass" != "prog,link"; then - vars="deplibs" - else - vars="compile_deplibs finalize_deplibs" - fi - for var in $vars dependency_libs; do - # Add libraries to $var in reverse order - eval tmp_libs=\$$var - new_libs= - for deplib in $tmp_libs; do - # FIXME: Pedantically, this is the right thing to do, so - # that some nasty dependency loop isn't accidentally - # broken: - #new_libs="$deplib $new_libs" - # Pragmatically, this seems to cause very few problems in - # practice: - case $deplib in - -L*) new_libs="$deplib $new_libs" ;; - -R*) ;; - *) - # And here is the reason: when a library appears more - # than once as an explicit dependence of a library, or - # is implicitly linked in more than once by the - # compiler, it is considered special, and multiple - # occurrences thereof are not removed. Compare this - # with having the same library being listed as a - # dependency of multiple other libraries: in this case, - # we know (pedantically, we assume) the library does not - # need to be listed more than once, so we keep only the - # last copy. This is not always right, but it is rare - # enough that we require users that really mean to play - # such unportable linking tricks to link the library - # using -Wl,-lname, so that libtool does not consider it - # for duplicate removal. - case " $specialdeplibs " in - *" $deplib "*) new_libs="$deplib $new_libs" ;; - *) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$deplib $new_libs" ;; - esac - ;; - esac - ;; - esac - done - tmp_libs= - for deplib in $new_libs; do - case $deplib in - -L*) - case " $tmp_libs " in - *" $deplib "*) ;; - *) tmp_libs="$tmp_libs $deplib" ;; - esac - ;; - *) tmp_libs="$tmp_libs $deplib" ;; - esac - done - eval $var=\$tmp_libs - done # for var - fi - # Last step: remove runtime libs from dependency_libs - # (they stay in deplibs) - tmp_libs= - for i in $dependency_libs ; do - case " $predeps $postdeps $compiler_lib_search_path " in - *" $i "*) - i="" - ;; - esac - if test -n "$i" ; then - tmp_libs="$tmp_libs $i" - fi - done - dependency_libs=$tmp_libs - done # for pass - if test "$linkmode" = prog; then - dlfiles="$newdlfiles" - fi - if test "$linkmode" = prog || test "$linkmode" = lib; then - dlprefiles="$newdlprefiles" - fi - - case $linkmode in - oldlib) - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - func_warning "\`-dlopen' is ignored for archives" - fi - - case " $deplibs" in - *\ -l* | *\ -L*) - func_warning "\`-l' and \`-L' are ignored for archives" ;; - esac - - test -n "$rpath" && \ - func_warning "\`-rpath' is ignored for archives" - - test -n "$xrpath" && \ - func_warning "\`-R' is ignored for archives" - - test -n "$vinfo" && \ - func_warning "\`-version-info/-version-number' is ignored for archives" - - test -n "$release" && \ - func_warning "\`-release' is ignored for archives" - - test -n "$export_symbols$export_symbols_regex" && \ - func_warning "\`-export-symbols' is ignored for archives" - - # Now set the variables for building old libraries. - build_libtool_libs=no - oldlibs="$output" - objs="$objs$old_deplibs" - ;; - - lib) - # Make sure we only generate libraries of the form `libNAME.la'. - case $outputname in - lib*) - func_stripname 'lib' '.la' "$outputname" - name=$func_stripname_result - eval "shared_ext=\"$shrext_cmds\"" - eval "libname=\"$libname_spec\"" - ;; - *) - test "$module" = no && \ - func_fatal_help "libtool library \`$output' must begin with \`lib'" - - if test "$need_lib_prefix" != no; then - # Add the "lib" prefix for modules if required - func_stripname '' '.la' "$outputname" - name=$func_stripname_result - eval "shared_ext=\"$shrext_cmds\"" - eval "libname=\"$libname_spec\"" - else - func_stripname '' '.la' "$outputname" - libname=$func_stripname_result - fi - ;; - esac - - if test -n "$objs"; then - if test "$deplibs_check_method" != pass_all; then - func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs" - else - echo - $ECHO "*** Warning: Linking the shared library $output against the non-libtool" - $ECHO "*** objects $objs is not portable!" - libobjs="$libobjs $objs" - fi - fi - - test "$dlself" != no && \ - func_warning "\`-dlopen self' is ignored for libtool libraries" - - set dummy $rpath - shift - test "$#" -gt 1 && \ - func_warning "ignoring multiple \`-rpath's for a libtool library" - - install_libdir="$1" - - oldlibs= - if test -z "$rpath"; then - if test "$build_libtool_libs" = yes; then - # Building a libtool convenience library. - # Some compilers have problems with a `.al' extension so - # convenience libraries should have the same extension an - # archive normally would. - oldlibs="$output_objdir/$libname.$libext $oldlibs" - build_libtool_libs=convenience - build_old_libs=yes - fi - - test -n "$vinfo" && \ - func_warning "\`-version-info/-version-number' is ignored for convenience libraries" - - test -n "$release" && \ - func_warning "\`-release' is ignored for convenience libraries" - else - - # Parse the version information argument. - save_ifs="$IFS"; IFS=':' - set dummy $vinfo 0 0 0 - shift - IFS="$save_ifs" - - test -n "$7" && \ - func_fatal_help "too many parameters to \`-version-info'" - - # convert absolute version numbers to libtool ages - # this retains compatibility with .la files and attempts - # to make the code below a bit more comprehensible - - case $vinfo_number in - yes) - number_major="$1" - number_minor="$2" - number_revision="$3" - # - # There are really only two kinds -- those that - # use the current revision as the major version - # and those that subtract age and use age as - # a minor version. But, then there is irix - # which has an extra 1 added just for fun - # - case $version_type in - darwin|linux|osf|windows|none) - func_arith $number_major + $number_minor - current=$func_arith_result - age="$number_minor" - revision="$number_revision" - ;; - freebsd-aout|freebsd-elf|qnx|sunos) - current="$number_major" - revision="$number_minor" - age="0" - ;; - irix|nonstopux) - func_arith $number_major + $number_minor - current=$func_arith_result - age="$number_minor" - revision="$number_minor" - lt_irix_increment=no - ;; - esac - ;; - no) - current="$1" - revision="$2" - age="$3" - ;; - esac - - # Check that each of the things are valid numbers. - case $current in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "CURRENT \`$current' must be a nonnegative integer" - func_fatal_error "\`$vinfo' is not valid version information" - ;; - esac - - case $revision in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "REVISION \`$revision' must be a nonnegative integer" - func_fatal_error "\`$vinfo' is not valid version information" - ;; - esac - - case $age in - 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;; - *) - func_error "AGE \`$age' must be a nonnegative integer" - func_fatal_error "\`$vinfo' is not valid version information" - ;; - esac - - if test "$age" -gt "$current"; then - func_error "AGE \`$age' is greater than the current interface number \`$current'" - func_fatal_error "\`$vinfo' is not valid version information" - fi - - # Calculate the version variables. - major= - versuffix= - verstring= - case $version_type in - none) ;; - - darwin) - # Like Linux, but with the current version available in - # verstring for coding it into the library header - func_arith $current - $age - major=.$func_arith_result - versuffix="$major.$age.$revision" - # Darwin ld doesn't like 0 for these options... - func_arith $current + 1 - minor_current=$func_arith_result - xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision" - verstring="-compatibility_version $minor_current -current_version $minor_current.$revision" - ;; - - freebsd-aout) - major=".$current" - versuffix=".$current.$revision"; - ;; - - freebsd-elf) - major=".$current" - versuffix=".$current" - ;; - - irix | nonstopux) - if test "X$lt_irix_increment" = "Xno"; then - func_arith $current - $age - else - func_arith $current - $age + 1 - fi - major=$func_arith_result - - case $version_type in - nonstopux) verstring_prefix=nonstopux ;; - *) verstring_prefix=sgi ;; - esac - verstring="$verstring_prefix$major.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$revision - while test "$loop" -ne 0; do - func_arith $revision - $loop - iface=$func_arith_result - func_arith $loop - 1 - loop=$func_arith_result - verstring="$verstring_prefix$major.$iface:$verstring" - done - - # Before this point, $major must not contain `.'. - major=.$major - versuffix="$major.$revision" - ;; - - linux) - func_arith $current - $age - major=.$func_arith_result - versuffix="$major.$age.$revision" - ;; - - osf) - func_arith $current - $age - major=.$func_arith_result - versuffix=".$current.$age.$revision" - verstring="$current.$age.$revision" - - # Add in all the interfaces that we are compatible with. - loop=$age - while test "$loop" -ne 0; do - func_arith $current - $loop - iface=$func_arith_result - func_arith $loop - 1 - loop=$func_arith_result - verstring="$verstring:${iface}.0" - done - - # Make executables depend on our current version. - verstring="$verstring:${current}.0" - ;; - - qnx) - major=".$current" - versuffix=".$current" - ;; - - sunos) - major=".$current" - versuffix=".$current.$revision" - ;; - - windows) - # Use '-' rather than '.', since we only want one - # extension on DOS 8.3 filesystems. - func_arith $current - $age - major=$func_arith_result - versuffix="-$major" - ;; - - *) - func_fatal_configuration "unknown library version type \`$version_type'" - ;; - esac - - # Clear the version info if we defaulted, and they specified a release. - if test -z "$vinfo" && test -n "$release"; then - major= - case $version_type in - darwin) - # we can't check for "0.0" in archive_cmds due to quoting - # problems, so we reset it completely - verstring= - ;; - *) - verstring="0.0" - ;; - esac - if test "$need_version" = no; then - versuffix= - else - versuffix=".0.0" - fi - fi - - # Remove version info from name if versioning should be avoided - if test "$avoid_version" = yes && test "$need_version" = no; then - major= - versuffix= - verstring="" - fi - - # Check to see if the archive will have undefined symbols. - if test "$allow_undefined" = yes; then - if test "$allow_undefined_flag" = unsupported; then - func_warning "undefined symbols not allowed in $host shared libraries" - build_libtool_libs=no - build_old_libs=yes - fi - else - # Don't allow undefined symbols. - allow_undefined_flag="$no_undefined_flag" - fi - - fi - - func_generate_dlsyms "$libname" "$libname" "yes" - libobjs="$libobjs $symfileobj" - test "X$libobjs" = "X " && libobjs= - - if test "$mode" != relink; then - # Remove our outputs, but don't remove object files since they - # may have been created when compiling PIC objects. - removelist= - tempremovelist=`$ECHO "$output_objdir/*"` - for p in $tempremovelist; do - case $p in - *.$objext | *.gcno) - ;; - $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*) - if test "X$precious_files_regex" != "X"; then - if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1 - then - continue - fi - fi - removelist="$removelist $p" - ;; - *) ;; - esac - done - test -n "$removelist" && \ - func_show_eval "${RM}r \$removelist" - fi - - # Now set the variables for building old libraries. - if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then - oldlibs="$oldlibs $output_objdir/$libname.$libext" - - # Transform .lo files to .o files. - oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP` - fi - - # Eliminate all temporary directories. - #for path in $notinst_path; do - # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"` - # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"` - # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"` - #done - - if test -n "$xrpath"; then - # If the user specified any rpath flags, then add them. - temp_xrpath= - for libdir in $xrpath; do - temp_xrpath="$temp_xrpath -R$libdir" - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then - dependency_libs="$temp_xrpath $dependency_libs" - fi - fi - - # Make sure dlfiles contains only unique files that won't be dlpreopened - old_dlfiles="$dlfiles" - dlfiles= - for lib in $old_dlfiles; do - case " $dlprefiles $dlfiles " in - *" $lib "*) ;; - *) dlfiles="$dlfiles $lib" ;; - esac - done - - # Make sure dlprefiles contains only unique files - old_dlprefiles="$dlprefiles" - dlprefiles= - for lib in $old_dlprefiles; do - case "$dlprefiles " in - *" $lib "*) ;; - *) dlprefiles="$dlprefiles $lib" ;; - esac - done - - if test "$build_libtool_libs" = yes; then - if test -n "$rpath"; then - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*) - # these systems don't actually have a c library (as such)! - ;; - *-*-rhapsody* | *-*-darwin1.[012]) - # Rhapsody C library is in the System framework - deplibs="$deplibs System.ltframework" - ;; - *-*-netbsd*) - # Don't link with libc until the a.out ld.so is fixed. - ;; - *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*) - # Do not include libc due to us having libc/libc_r. - ;; - *-*-sco3.2v5* | *-*-sco5v6*) - # Causes problems with __ctype - ;; - *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*) - # Compiler inserts libc in the correct place for threads to work - ;; - *) - # Add libc to deplibs on all other systems if necessary. - if test "$build_libtool_need_lc" = "yes"; then - deplibs="$deplibs -lc" - fi - ;; - esac - fi - - # Transform deplibs into only deplibs that can be linked in shared. - name_save=$name - libname_save=$libname - release_save=$release - versuffix_save=$versuffix - major_save=$major - # I'm not sure if I'm treating the release correctly. I think - # release should show up in the -l (ie -lgmp5) so we don't want to - # add it in twice. Is that correct? - release="" - versuffix="" - major="" - newdeplibs= - droppeddeps=no - case $deplibs_check_method in - pass_all) - # Don't check for shared/static. Everything works. - # This might be a little naive. We might want to check - # whether the library exists or not. But this is on - # osf3 & osf4 and I'm not really sure... Just - # implementing what was already the behavior. - newdeplibs=$deplibs - ;; - test_compile) - # This code stresses the "libraries are programs" paradigm to its - # limits. Maybe even breaks it. We compile a program, linking it - # against the deplibs as a proxy for the library. Then we can check - # whether they linked in statically or dynamically with ldd. - $opt_dry_run || $RM conftest.c - cat > conftest.c </dev/null` - for potent_lib in $potential_libs; do - # Follow soft links. - if ls -lLd "$potent_lib" 2>/dev/null | - $GREP " -> " >/dev/null; then - continue - fi - # The statement above tries to avoid entering an - # endless loop below, in case of cyclic links. - # We might still enter an endless loop, since a link - # loop can be closed while we follow links, - # but so what? - potlib="$potent_lib" - while test -h "$potlib" 2>/dev/null; do - potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'` - case $potliblink in - [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";; - *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";; - esac - done - if eval "$file_magic_cmd \"\$potlib\"" 2>/dev/null | - $SED -e 10q | - $EGREP "$file_magic_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - echo - $ECHO "*** Warning: linker path does not have real file for library $a_deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $ECHO "*** with $libname but no candidates were found. (...for file magic test)" - else - $ECHO "*** with $libname and none of the candidates passed a file format test" - $ECHO "*** using a file magic. Last file checked: $potlib" - fi - fi - ;; - *) - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - ;; - esac - done # Gone through all deplibs. - ;; - match_pattern*) - set dummy $deplibs_check_method; shift - match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"` - for a_deplib in $deplibs; do - case $a_deplib in - -l*) - func_stripname -l '' "$a_deplib" - name=$func_stripname_result - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - case " $predeps $postdeps " in - *" $a_deplib "*) - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - ;; - esac - fi - if test -n "$a_deplib" ; then - eval "libname=\"$libname_spec\"" - for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do - potential_libs=`ls $i/$libname[.-]* 2>/dev/null` - for potent_lib in $potential_libs; do - potlib="$potent_lib" # see symlink-check above in file_magic test - if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \ - $EGREP "$match_pattern_regex" > /dev/null; then - newdeplibs="$newdeplibs $a_deplib" - a_deplib="" - break 2 - fi - done - done - fi - if test -n "$a_deplib" ; then - droppeddeps=yes - echo - $ECHO "*** Warning: linker path does not have real file for library $a_deplib." - echo "*** I have the capability to make that library automatically link in when" - echo "*** you link to this library. But I can only do this if you have a" - echo "*** shared version of the library, which you do not appear to have" - echo "*** because I did check the linker path looking for a file starting" - if test -z "$potlib" ; then - $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)" - else - $ECHO "*** with $libname and none of the candidates passed a file format test" - $ECHO "*** using a regex pattern. Last file checked: $potlib" - fi - fi - ;; - *) - # Add a -L argument. - newdeplibs="$newdeplibs $a_deplib" - ;; - esac - done # Gone through all deplibs. - ;; - none | unknown | *) - newdeplibs="" - tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'` - if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then - for i in $predeps $postdeps ; do - # can't use Xsed below, because $i might contain '/' - tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"` - done - fi - case $tmp_deplibs in - *[!\ \ ]*) - echo - if test "X$deplibs_check_method" = "Xnone"; then - echo "*** Warning: inter-library dependencies are not supported in this platform." - else - echo "*** Warning: inter-library dependencies are not known to be supported." - fi - echo "*** All declared inter-library dependencies are being dropped." - droppeddeps=yes - ;; - esac - ;; - esac - versuffix=$versuffix_save - major=$major_save - release=$release_save - libname=$libname_save - name=$name_save - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library with the System framework - newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'` - ;; - esac - - if test "$droppeddeps" = yes; then - if test "$module" = yes; then - echo - echo "*** Warning: libtool could not satisfy all declared inter-library" - $ECHO "*** dependencies of module $libname. Therefore, libtool will create" - echo "*** a static module, that should work as long as the dlopening" - echo "*** application is linked with the -dlopen flag." - if test -z "$global_symbol_pipe"; then - echo - echo "*** However, this would only work if libtool was able to extract symbol" - echo "*** lists from a program, using \`nm' or equivalent, but libtool could" - echo "*** not find such a program. So, this module is probably useless." - echo "*** \`nm' from GNU binutils and a full rebuild may help." - fi - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - else - echo "*** The inter-library dependencies that have been dropped here will be" - echo "*** automatically added whenever a program is linked with this library" - echo "*** or is declared to -dlopen it." - - if test "$allow_undefined" = no; then - echo - echo "*** Since this library must not contain undefined symbols," - echo "*** because either the platform does not support them or" - echo "*** it was explicitly requested with -no-undefined," - echo "*** libtool will only create a static version of it." - if test "$build_old_libs" = no; then - oldlibs="$output_objdir/$libname.$libext" - build_libtool_libs=module - build_old_libs=yes - else - build_libtool_libs=no - fi - fi - fi - fi - # Done checking deplibs! - deplibs=$newdeplibs - fi - # Time to change all our "foo.ltframework" stuff back to "-framework foo" - case $host in - *-*-darwin*) - newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - ;; - esac - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $deplibs " in - *" -L$path/$objdir "*) - new_libs="$new_libs -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$new_libs $deplib" ;; - esac - ;; - *) new_libs="$new_libs $deplib" ;; - esac - done - deplibs="$new_libs" - - # All the library-specific variables (install_libdir is set above). - library_names= - old_library= - dlname= - - # Test again, we may have decided not to build it any more - if test "$build_libtool_libs" = yes; then - if test "$hardcode_into_libs" = yes; then - # Hardcode the library paths - hardcode_libdirs= - dep_rpath= - rpath="$finalize_rpath" - test "$mode" != relink && rpath="$compile_rpath$rpath" - for libdir in $rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval "flag=\"$hardcode_libdir_flag_spec\"" - dep_rpath="$dep_rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - if test -n "$hardcode_libdir_flag_spec_ld"; then - eval "dep_rpath=\"$hardcode_libdir_flag_spec_ld\"" - else - eval "dep_rpath=\"$hardcode_libdir_flag_spec\"" - fi - fi - if test -n "$runpath_var" && test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - eval $runpath_var=\$rpath\$$runpath_var - export $runpath_var - fi - test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs" - fi - - shlibpath="$finalize_shlibpath" - test "$mode" != relink && shlibpath="$compile_shlibpath$shlibpath" - if test -n "$shlibpath"; then - eval $shlibpath_var=\$shlibpath\$$shlibpath_var - export $shlibpath_var - fi - - # Get the real and link names of the library. - eval "shared_ext=\"$shrext_cmds\"" - eval "library_names=\"$library_names_spec\"" - set dummy $library_names - shift - realname="$1" - shift - - if test -n "$soname_spec"; then - eval "soname=\"$soname_spec\"" - else - soname="$realname" - fi - if test -z "$dlname"; then - dlname=$soname - fi - - lib="$output_objdir/$realname" - linknames= - for link - do - linknames="$linknames $link" - done - - # Use standard objects if they are pic - test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP` - test "X$libobjs" = "X " && libobjs= - - delfiles= - if test -n "$export_symbols" && test -n "$include_expsyms"; then - $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp" - export_symbols="$output_objdir/$libname.uexp" - delfiles="$delfiles $export_symbols" - fi - - orig_export_symbols= - case $host_os in - cygwin* | mingw* | cegcc*) - if test -n "$export_symbols" && test -z "$export_symbols_regex"; then - # exporting using user supplied symfile - if test "x`$SED 1q $export_symbols`" != xEXPORTS; then - # and it's NOT already a .def file. Must figure out - # which of the given symbols are data symbols and tag - # them as such. So, trigger use of export_symbols_cmds. - # export_symbols gets reassigned inside the "prepare - # the list of exported symbols" if statement, so the - # include_expsyms logic still works. - orig_export_symbols="$export_symbols" - export_symbols= - always_export_symbols=yes - fi - fi - ;; - esac - - # Prepare the list of exported symbols - if test -z "$export_symbols"; then - if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then - func_verbose "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $opt_dry_run || $RM $export_symbols - cmds=$export_symbols_cmds - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval "cmd=\"$cmd\"" - func_len " $cmd" - len=$func_len_result - if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then - func_show_eval "$cmd" 'exit $?' - skipped_export=false - else - # The command line is too long to execute in one step. - func_verbose "using reloadable object file for export list..." - skipped_export=: - # Break out early, otherwise skipped_export may be - # set to false by a later but shorter cmd. - break - fi - done - IFS="$save_ifs" - if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then - func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - func_show_eval '$MV "${export_symbols}T" "$export_symbols"' - fi - fi - fi - - if test -n "$export_symbols" && test -n "$include_expsyms"; then - tmp_export_symbols="$export_symbols" - test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" - $opt_dry_run || $ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols" - fi - - if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then - # The given exports_symbols file has to be filtered, so filter it. - func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" - # FIXME: $output_objdir/$libname.filter potentially contains lots of - # 's' commands which not all seds can handle. GNU sed should be fine - # though. Also, the filter scales superlinearly with the number of - # global variables. join(1) would be nice here, but unfortunately - # isn't a blessed tool. - $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter - delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" - export_symbols=$output_objdir/$libname.def - $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols - fi - - tmp_deplibs= - for test_deplib in $deplibs; do - case " $convenience " in - *" $test_deplib "*) ;; - *) - tmp_deplibs="$tmp_deplibs $test_deplib" - ;; - esac - done - deplibs="$tmp_deplibs" - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec" && - test "$compiler_needs_object" = yes && - test -z "$libobjs"; then - # extract the archives, so we have objects to list. - # TODO: could optimize this to just extract one archive. - whole_archive_flag_spec= - fi - if test -n "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - eval "libobjs=\"\$libobjs $whole_archive_flag_spec\"" - test "X$libobjs" = "X " && libobjs= - else - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - func_extract_archives $gentop $convenience - libobjs="$libobjs $func_extract_archives_result" - test "X$libobjs" = "X " && libobjs= - fi - fi - - if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then - eval "flag=\"$thread_safe_flag_spec\"" - linker_flags="$linker_flags $flag" - fi - - # Make a backup of the uninstalled library when relinking - if test "$mode" = relink; then - $opt_dry_run || (cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U) || exit $? - fi - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - eval "test_cmds=\"$module_expsym_cmds\"" - cmds=$module_expsym_cmds - else - eval "test_cmds=\"$module_cmds\"" - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - eval "test_cmds=\"$archive_expsym_cmds\"" - cmds=$archive_expsym_cmds - else - eval "test_cmds=\"$archive_cmds\"" - cmds=$archive_cmds - fi - fi - - if test "X$skipped_export" != "X:" && - func_len " $test_cmds" && - len=$func_len_result && - test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then - : - else - # The command line is too long to link in one step, link piecewise - # or, if using GNU ld and skipped_export is not :, use a linker - # script. - - # Save the value of $output and $libobjs because we want to - # use them later. If we have whole_archive_flag_spec, we - # want to use save_libobjs as it was before - # whole_archive_flag_spec was expanded, because we can't - # assume the linker understands whole_archive_flag_spec. - # This may have to be revisited, in case too many - # convenience libraries get linked in and end up exceeding - # the spec. - if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then - save_libobjs=$libobjs - fi - save_output=$output - func_basename "$output" - output_la=$func_basename_result - - # Clear the reloadable object creation command queue and - # initialize k to one. - test_cmds= - concat_cmds= - objlist= - last_robj= - k=1 - - if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then - output=${output_objdir}/${output_la}.lnkscript - func_verbose "creating GNU ld script: $output" - echo 'INPUT (' > $output - for obj in $save_libobjs - do - $ECHO "$obj" >> $output - done - echo ')' >> $output - delfiles="$delfiles $output" - elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then - output=${output_objdir}/${output_la}.lnk - func_verbose "creating linker input file list: $output" - : > $output - set x $save_libobjs - shift - firstobj= - if test "$compiler_needs_object" = yes; then - firstobj="$1 " - shift - fi - for obj - do - $ECHO "$obj" >> $output - done - delfiles="$delfiles $output" - output=$firstobj\"$file_list_spec$output\" - else - if test -n "$save_libobjs"; then - func_verbose "creating reloadable object files..." - output=$output_objdir/$output_la-${k}.$objext - eval "test_cmds=\"$reload_cmds\"" - func_len " $test_cmds" - len0=$func_len_result - len=$len0 - - # Loop over the list of objects to be linked. - for obj in $save_libobjs - do - func_len " $obj" - func_arith $len + $func_len_result - len=$func_arith_result - if test "X$objlist" = X || - test "$len" -lt "$max_cmd_len"; then - func_append objlist " $obj" - else - # The command $test_cmds is almost too long, add a - # command to the queue. - if test "$k" -eq 1 ; then - # The first file doesn't have a previous command to add. - reload_objs=$objlist - eval "concat_cmds=\"$reload_cmds\"" - else - # All subsequent reloadable object files will link in - # the last one created. - reload_objs="$objlist $last_robj" - eval "concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"" - fi - last_robj=$output_objdir/$output_la-${k}.$objext - func_arith $k + 1 - k=$func_arith_result - output=$output_objdir/$output_la-${k}.$objext - objlist=" $obj" - func_len " $last_robj" - func_arith $len0 + $func_len_result - len=$func_arith_result - fi - done - # Handle the remaining objects by creating one last - # reloadable object file. All subsequent reloadable object - # files will link in the last one created. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - reload_objs="$objlist $last_robj" - eval "concat_cmds=\"\${concat_cmds}$reload_cmds\"" - if test -n "$last_robj"; then - eval "concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"" - fi - delfiles="$delfiles $output" - - else - output= - fi - - if ${skipped_export-false}; then - func_verbose "generating symbol list for \`$libname.la'" - export_symbols="$output_objdir/$libname.exp" - $opt_dry_run || $RM $export_symbols - libobjs=$output - # Append the command to create the export file. - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval "concat_cmds=\"\$concat_cmds$export_symbols_cmds\"" - if test -n "$last_robj"; then - eval "concat_cmds=\"\$concat_cmds~\$RM $last_robj\"" - fi - fi - - test -n "$save_libobjs" && - func_verbose "creating a temporary reloadable object file: $output" - - # Loop through the commands generated above and execute them. - save_ifs="$IFS"; IFS='~' - for cmd in $concat_cmds; do - IFS="$save_ifs" - $opt_silent || { - func_quote_for_expand "$cmd" - eval "func_echo $func_quote_for_expand_result" - } - $opt_dry_run || eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - ( cd "$output_objdir" && \ - $RM "${realname}T" && \ - $MV "${realname}U" "$realname" ) - fi - - exit $lt_exit - } - done - IFS="$save_ifs" - - if test -n "$export_symbols_regex" && ${skipped_export-false}; then - func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"' - func_show_eval '$MV "${export_symbols}T" "$export_symbols"' - fi - fi - - if ${skipped_export-false}; then - if test -n "$export_symbols" && test -n "$include_expsyms"; then - tmp_export_symbols="$export_symbols" - test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols" - $opt_dry_run || $ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols" - fi - - if test -n "$orig_export_symbols"; then - # The given exports_symbols file has to be filtered, so filter it. - func_verbose "filter symbol list for \`$libname.la' to tag DATA exports" - # FIXME: $output_objdir/$libname.filter potentially contains lots of - # 's' commands which not all seds can handle. GNU sed should be fine - # though. Also, the filter scales superlinearly with the number of - # global variables. join(1) would be nice here, but unfortunately - # isn't a blessed tool. - $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter - delfiles="$delfiles $export_symbols $output_objdir/$libname.filter" - export_symbols=$output_objdir/$libname.def - $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols - fi - fi - - libobjs=$output - # Restore the value of output. - output=$save_output - - if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then - eval "libobjs=\"\$libobjs $whole_archive_flag_spec\"" - test "X$libobjs" = "X " && libobjs= - fi - # Expand the library linking commands again to reset the - # value of $libobjs for piecewise linking. - - # Do each of the archive commands. - if test "$module" = yes && test -n "$module_cmds" ; then - if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then - cmds=$module_expsym_cmds - else - cmds=$module_cmds - fi - else - if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then - cmds=$archive_expsym_cmds - else - cmds=$archive_cmds - fi - fi - fi - - if test -n "$delfiles"; then - # Append the command to remove temporary files to $cmds. - eval "cmds=\"\$cmds~\$RM $delfiles\"" - fi - - # Add any objects from preloaded convenience libraries - if test -n "$dlprefiles"; then - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - func_extract_archives $gentop $dlprefiles - libobjs="$libobjs $func_extract_archives_result" - test "X$libobjs" = "X " && libobjs= - fi - - save_ifs="$IFS"; IFS='~' - for cmd in $cmds; do - IFS="$save_ifs" - eval "cmd=\"$cmd\"" - $opt_silent || { - func_quote_for_expand "$cmd" - eval "func_echo $func_quote_for_expand_result" - } - $opt_dry_run || eval "$cmd" || { - lt_exit=$? - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - ( cd "$output_objdir" && \ - $RM "${realname}T" && \ - $MV "${realname}U" "$realname" ) - fi - - exit $lt_exit - } - done - IFS="$save_ifs" - - # Restore the uninstalled library and exit - if test "$mode" = relink; then - $opt_dry_run || (cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname) || exit $? - - if test -n "$convenience"; then - if test -z "$whole_archive_flag_spec"; then - func_show_eval '${RM}r "$gentop"' - fi - fi - - exit $EXIT_SUCCESS - fi - - # Create links to the real library. - for linkname in $linknames; do - if test "$realname" != "$linkname"; then - func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?' - fi - done - - # If -module or -export-dynamic was specified, set the dlname. - if test "$module" = yes || test "$export_dynamic" = yes; then - # On all known operating systems, these are identical. - dlname="$soname" - fi - fi - ;; - - obj) - if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then - func_warning "\`-dlopen' is ignored for objects" - fi - - case " $deplibs" in - *\ -l* | *\ -L*) - func_warning "\`-l' and \`-L' are ignored for objects" ;; - esac - - test -n "$rpath" && \ - func_warning "\`-rpath' is ignored for objects" - - test -n "$xrpath" && \ - func_warning "\`-R' is ignored for objects" - - test -n "$vinfo" && \ - func_warning "\`-version-info' is ignored for objects" - - test -n "$release" && \ - func_warning "\`-release' is ignored for objects" - - case $output in - *.lo) - test -n "$objs$old_deplibs" && \ - func_fatal_error "cannot build library object \`$output' from non-libtool objects" - - libobj=$output - func_lo2o "$libobj" - obj=$func_lo2o_result - ;; - *) - libobj= - obj="$output" - ;; - esac - - # Delete the old objects. - $opt_dry_run || $RM $obj $libobj - - # Objects from convenience libraries. This assumes - # single-version convenience libraries. Whenever we create - # different ones for PIC/non-PIC, this we'll have to duplicate - # the extraction. - reload_conv_objs= - gentop= - # reload_cmds runs $LD directly, so let us get rid of - # -Wl from whole_archive_flag_spec and hope we can get by with - # turning comma into space.. - wl= - - if test -n "$convenience"; then - if test -n "$whole_archive_flag_spec"; then - eval "tmp_whole_archive_flags=\"$whole_archive_flag_spec\"" - reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'` - else - gentop="$output_objdir/${obj}x" - generated="$generated $gentop" - - func_extract_archives $gentop $convenience - reload_conv_objs="$reload_objs $func_extract_archives_result" - fi - fi - - # Create the old-style object. - reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test - - output="$obj" - func_execute_cmds "$reload_cmds" 'exit $?' - - # Exit if we aren't doing a library object file. - if test -z "$libobj"; then - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - exit $EXIT_SUCCESS - fi - - if test "$build_libtool_libs" != yes; then - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - # Create an invalid libtool object if no PIC, so that we don't - # accidentally link it into a program. - # $show "echo timestamp > $libobj" - # $opt_dry_run || echo timestamp > $libobj || exit $? - exit $EXIT_SUCCESS - fi - - if test -n "$pic_flag" || test "$pic_mode" != default; then - # Only do commands if we really have different PIC objects. - reload_objs="$libobjs $reload_conv_objs" - output="$libobj" - func_execute_cmds "$reload_cmds" 'exit $?' - fi - - if test -n "$gentop"; then - func_show_eval '${RM}r "$gentop"' - fi - - exit $EXIT_SUCCESS - ;; - - prog) - case $host in - *cygwin*) func_stripname '' '.exe' "$output" - output=$func_stripname_result.exe;; - esac - test -n "$vinfo" && \ - func_warning "\`-version-info' is ignored for programs" - - test -n "$release" && \ - func_warning "\`-release' is ignored for programs" - - test "$preload" = yes \ - && test "$dlopen_support" = unknown \ - && test "$dlopen_self" = unknown \ - && test "$dlopen_self_static" = unknown && \ - func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support." - - case $host in - *-*-rhapsody* | *-*-darwin1.[012]) - # On Rhapsody replace the C library is the System framework - compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'` - finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'` - ;; - esac - - case $host in - *-*-darwin*) - # Don't allow lazy linking, it breaks C++ global constructors - # But is supposedly fixed on 10.4 or later (yay!). - if test "$tagname" = CXX ; then - case ${MACOSX_DEPLOYMENT_TARGET-10.0} in - 10.[0123]) - compile_command="$compile_command ${wl}-bind_at_load" - finalize_command="$finalize_command ${wl}-bind_at_load" - ;; - esac - fi - # Time to change all our "foo.ltframework" stuff back to "-framework foo" - compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'` - ;; - esac - - - # move library search paths that coincide with paths to not yet - # installed libraries to the beginning of the library search list - new_libs= - for path in $notinst_path; do - case " $new_libs " in - *" -L$path/$objdir "*) ;; - *) - case " $compile_deplibs " in - *" -L$path/$objdir "*) - new_libs="$new_libs -L$path/$objdir" ;; - esac - ;; - esac - done - for deplib in $compile_deplibs; do - case $deplib in - -L*) - case " $new_libs " in - *" $deplib "*) ;; - *) new_libs="$new_libs $deplib" ;; - esac - ;; - *) new_libs="$new_libs $deplib" ;; - esac - done - compile_deplibs="$new_libs" - - - compile_command="$compile_command $compile_deplibs" - finalize_command="$finalize_command $finalize_deplibs" - - if test -n "$rpath$xrpath"; then - # If the user specified any rpath flags, then add them. - for libdir in $rpath $xrpath; do - # This is the magic to use -rpath. - case "$finalize_rpath " in - *" $libdir "*) ;; - *) finalize_rpath="$finalize_rpath $libdir" ;; - esac - done - fi - - # Now hardcode the library paths - rpath= - hardcode_libdirs= - for libdir in $compile_rpath $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval "flag=\"$hardcode_libdir_flag_spec\"" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$perm_rpath " in - *" $libdir "*) ;; - *) perm_rpath="$perm_rpath $libdir" ;; - esac - fi - case $host in - *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*) - testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'` - case :$dllsearchpath: in - *":$libdir:"*) ;; - ::) dllsearchpath=$libdir;; - *) dllsearchpath="$dllsearchpath:$libdir";; - esac - case :$dllsearchpath: in - *":$testbindir:"*) ;; - ::) dllsearchpath=$testbindir;; - *) dllsearchpath="$dllsearchpath:$testbindir";; - esac - ;; - esac - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval "rpath=\" $hardcode_libdir_flag_spec\"" - fi - compile_rpath="$rpath" - - rpath= - hardcode_libdirs= - for libdir in $finalize_rpath; do - if test -n "$hardcode_libdir_flag_spec"; then - if test -n "$hardcode_libdir_separator"; then - if test -z "$hardcode_libdirs"; then - hardcode_libdirs="$libdir" - else - # Just accumulate the unique libdirs. - case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in - *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*) - ;; - *) - hardcode_libdirs="$hardcode_libdirs$hardcode_libdir_separator$libdir" - ;; - esac - fi - else - eval "flag=\"$hardcode_libdir_flag_spec\"" - rpath="$rpath $flag" - fi - elif test -n "$runpath_var"; then - case "$finalize_perm_rpath " in - *" $libdir "*) ;; - *) finalize_perm_rpath="$finalize_perm_rpath $libdir" ;; - esac - fi - done - # Substitute the hardcoded libdirs into the rpath. - if test -n "$hardcode_libdir_separator" && - test -n "$hardcode_libdirs"; then - libdir="$hardcode_libdirs" - eval "rpath=\" $hardcode_libdir_flag_spec\"" - fi - finalize_rpath="$rpath" - - if test -n "$libobjs" && test "$build_old_libs" = yes; then - # Transform all the library objects into standard objects. - compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP` - finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP` - fi - - func_generate_dlsyms "$outputname" "@PROGRAM@" "no" - - # template prelinking step - if test -n "$prelink_cmds"; then - func_execute_cmds "$prelink_cmds" 'exit $?' - fi - - wrappers_required=yes - case $host in - *cegcc* | *mingw32ce*) - # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway. - wrappers_required=no - ;; - *cygwin* | *mingw* ) - if test "$build_libtool_libs" != yes; then - wrappers_required=no - fi - ;; - *) - if test "$need_relink" = no || test "$build_libtool_libs" != yes; then - wrappers_required=no - fi - ;; - esac - if test "$wrappers_required" = no; then - # Replace the output file specification. - compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'` - link_command="$compile_command$compile_rpath" - - # We have no uninstalled library dependencies, so finalize right now. - exit_status=0 - func_show_eval "$link_command" 'exit_status=$?' - - # Delete the generated files. - if test -f "$output_objdir/${outputname}S.${objext}"; then - func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"' - fi - - exit $exit_status - fi - - if test -n "$compile_shlibpath$finalize_shlibpath"; then - compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command" - fi - if test -n "$finalize_shlibpath"; then - finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command" - fi - - compile_var= - finalize_var= - if test -n "$runpath_var"; then - if test -n "$perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $perm_rpath; do - rpath="$rpath$dir:" - done - compile_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - if test -n "$finalize_perm_rpath"; then - # We should set the runpath_var. - rpath= - for dir in $finalize_perm_rpath; do - rpath="$rpath$dir:" - done - finalize_var="$runpath_var=\"$rpath\$$runpath_var\" " - fi - fi - - if test "$no_install" = yes; then - # We don't need to create a wrapper script. - link_command="$compile_var$compile_command$compile_rpath" - # Replace the output file specification. - link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'` - # Delete the old output file. - $opt_dry_run || $RM $output - # Link the executable and exit - func_show_eval "$link_command" 'exit $?' - exit $EXIT_SUCCESS - fi - - if test "$hardcode_action" = relink; then - # Fast installation is not supported - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - - func_warning "this platform does not like uninstalled shared libraries" - func_warning "\`$output' will be relinked during installation" - else - if test "$fast_install" != no; then - link_command="$finalize_var$compile_command$finalize_rpath" - if test "$fast_install" = yes; then - relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'` - else - # fast_install is set to needless - relink_command= - fi - else - link_command="$compile_var$compile_command$compile_rpath" - relink_command="$finalize_var$finalize_command$finalize_rpath" - fi - fi - - # Replace the output file specification. - link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'` - - # Delete the old output files. - $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname - - func_show_eval "$link_command" 'exit $?' - - # Now create the wrapper script. - func_verbose "creating $output" - - # Quote the relink command for shipping. - if test -n "$relink_command"; then - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - func_quote_for_eval "$var_value" - relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" - fi - done - relink_command="(cd `pwd`; $relink_command)" - relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` - fi - - # Only actually do things if not in dry run mode. - $opt_dry_run || { - # win32 will think the script is a binary if it has - # a .exe suffix, so we strip it off here. - case $output in - *.exe) func_stripname '' '.exe' "$output" - output=$func_stripname_result ;; - esac - # test for cygwin because mv fails w/o .exe extensions - case $host in - *cygwin*) - exeext=.exe - func_stripname '' '.exe' "$outputname" - outputname=$func_stripname_result ;; - *) exeext= ;; - esac - case $host in - *cygwin* | *mingw* ) - func_dirname_and_basename "$output" "" "." - output_name=$func_basename_result - output_path=$func_dirname_result - cwrappersource="$output_path/$objdir/lt-$output_name.c" - cwrapper="$output_path/$output_name.exe" - $RM $cwrappersource $cwrapper - trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15 - - func_emit_cwrapperexe_src > $cwrappersource - - # The wrapper executable is built using the $host compiler, - # because it contains $host paths and files. If cross- - # compiling, it, like the target executable, must be - # executed on the $host or under an emulation environment. - $opt_dry_run || { - $LTCC $LTCFLAGS -o $cwrapper $cwrappersource - $STRIP $cwrapper - } - - # Now, create the wrapper script for func_source use: - func_ltwrapper_scriptname $cwrapper - $RM $func_ltwrapper_scriptname_result - trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15 - $opt_dry_run || { - # note: this script will not be executed, so do not chmod. - if test "x$build" = "x$host" ; then - $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result - else - func_emit_wrapper no > $func_ltwrapper_scriptname_result - fi - } - ;; - * ) - $RM $output - trap "$RM $output; exit $EXIT_FAILURE" 1 2 15 - - func_emit_wrapper no > $output - chmod +x $output - ;; - esac - } - exit $EXIT_SUCCESS - ;; - esac - - # See if we need to build an old-fashioned archive. - for oldlib in $oldlibs; do - - if test "$build_libtool_libs" = convenience; then - oldobjs="$libobjs_save $symfileobj" - addlibs="$convenience" - build_libtool_libs=no - else - if test "$build_libtool_libs" = module; then - oldobjs="$libobjs_save" - build_libtool_libs=no - else - oldobjs="$old_deplibs $non_pic_objects" - if test "$preload" = yes && test -f "$symfileobj"; then - oldobjs="$oldobjs $symfileobj" - fi - fi - addlibs="$old_convenience" - fi - - if test -n "$addlibs"; then - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - func_extract_archives $gentop $addlibs - oldobjs="$oldobjs $func_extract_archives_result" - fi - - # Do each command in the archive commands. - if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then - cmds=$old_archive_from_new_cmds - else - - # Add any objects from preloaded convenience libraries - if test -n "$dlprefiles"; then - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - - func_extract_archives $gentop $dlprefiles - oldobjs="$oldobjs $func_extract_archives_result" - fi - - # POSIX demands no paths to be encoded in archives. We have - # to avoid creating archives with duplicate basenames if we - # might have to extract them afterwards, e.g., when creating a - # static archive out of a convenience library, or when linking - # the entirety of a libtool archive into another (currently - # not supported by libtool). - if (for obj in $oldobjs - do - func_basename "$obj" - $ECHO "$func_basename_result" - done | sort | sort -uc >/dev/null 2>&1); then - : - else - echo "copying selected object files to avoid basename conflicts..." - gentop="$output_objdir/${outputname}x" - generated="$generated $gentop" - func_mkdir_p "$gentop" - save_oldobjs=$oldobjs - oldobjs= - counter=1 - for obj in $save_oldobjs - do - func_basename "$obj" - objbase="$func_basename_result" - case " $oldobjs " in - " ") oldobjs=$obj ;; - *[\ /]"$objbase "*) - while :; do - # Make sure we don't pick an alternate name that also - # overlaps. - newobj=lt$counter-$objbase - func_arith $counter + 1 - counter=$func_arith_result - case " $oldobjs " in - *[\ /]"$newobj "*) ;; - *) if test ! -f "$gentop/$newobj"; then break; fi ;; - esac - done - func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj" - oldobjs="$oldobjs $gentop/$newobj" - ;; - *) oldobjs="$oldobjs $obj" ;; - esac - done - fi - eval "cmds=\"$old_archive_cmds\"" - - func_len " $cmds" - len=$func_len_result - if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then - cmds=$old_archive_cmds - else - # the command line is too long to link in one step, link in parts - func_verbose "using piecewise archive linking..." - save_RANLIB=$RANLIB - RANLIB=: - objlist= - concat_cmds= - save_oldobjs=$oldobjs - oldobjs= - # Is there a better way of finding the last object in the list? - for obj in $save_oldobjs - do - last_oldobj=$obj - done - eval "test_cmds=\"$old_archive_cmds\"" - func_len " $test_cmds" - len0=$func_len_result - len=$len0 - for obj in $save_oldobjs - do - func_len " $obj" - func_arith $len + $func_len_result - len=$func_arith_result - func_append objlist " $obj" - if test "$len" -lt "$max_cmd_len"; then - : - else - # the above command should be used before it gets too long - oldobjs=$objlist - if test "$obj" = "$last_oldobj" ; then - RANLIB=$save_RANLIB - fi - test -z "$concat_cmds" || concat_cmds=$concat_cmds~ - eval "concat_cmds=\"\${concat_cmds}$old_archive_cmds\"" - objlist= - len=$len0 - fi - done - RANLIB=$save_RANLIB - oldobjs=$objlist - if test "X$oldobjs" = "X" ; then - eval "cmds=\"\$concat_cmds\"" - else - eval "cmds=\"\$concat_cmds~\$old_archive_cmds\"" - fi - fi - fi - func_execute_cmds "$cmds" 'exit $?' - done - - test -n "$generated" && \ - func_show_eval "${RM}r$generated" - - # Now create the libtool archive. - case $output in - *.la) - old_library= - test "$build_old_libs" = yes && old_library="$libname.$libext" - func_verbose "creating $output" - - # Preserve any variables that may affect compiler behavior - for var in $variables_saved_for_relink; do - if eval test -z \"\${$var+set}\"; then - relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command" - elif eval var_value=\$$var; test -z "$var_value"; then - relink_command="$var=; export $var; $relink_command" - else - func_quote_for_eval "$var_value" - relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command" - fi - done - # Quote the link command for shipping. - relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)" - relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"` - if test "$hardcode_automatic" = yes ; then - relink_command= - fi - - # Only create the output if not a dry run. - $opt_dry_run || { - for installed in no yes; do - if test "$installed" = yes; then - if test -z "$install_libdir"; then - break - fi - output="$output_objdir/$outputname"i - # Replace all uninstalled libtool libraries with the installed ones - newdependency_libs= - for deplib in $dependency_libs; do - case $deplib in - *.la) - func_basename "$deplib" - name="$func_basename_result" - libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib` - test -z "$libdir" && \ - func_fatal_error "\`$deplib' is not a valid libtool archive" - newdependency_libs="$newdependency_libs $libdir/$name" - ;; - *) newdependency_libs="$newdependency_libs $deplib" ;; - esac - done - dependency_libs="$newdependency_libs" - newdlfiles= - - for lib in $dlfiles; do - case $lib in - *.la) - func_basename "$lib" - name="$func_basename_result" - libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - test -z "$libdir" && \ - func_fatal_error "\`$lib' is not a valid libtool archive" - newdlfiles="$newdlfiles $libdir/$name" - ;; - *) newdlfiles="$newdlfiles $lib" ;; - esac - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - *.la) - # Only pass preopened files to the pseudo-archive (for - # eventual linking with the app. that links it) if we - # didn't already link the preopened objects directly into - # the library: - func_basename "$lib" - name="$func_basename_result" - libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib` - test -z "$libdir" && \ - func_fatal_error "\`$lib' is not a valid libtool archive" - newdlprefiles="$newdlprefiles $libdir/$name" - ;; - esac - done - dlprefiles="$newdlprefiles" - else - newdlfiles= - for lib in $dlfiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - newdlfiles="$newdlfiles $abs" - done - dlfiles="$newdlfiles" - newdlprefiles= - for lib in $dlprefiles; do - case $lib in - [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;; - *) abs=`pwd`"/$lib" ;; - esac - newdlprefiles="$newdlprefiles $abs" - done - dlprefiles="$newdlprefiles" - fi - $RM $output - # place dlname in correct position for cygwin - # In fact, it would be nice if we could use this code for all target - # systems that can't hard-code library paths into their executables - # and that have no shared library path variable independent of PATH, - # but it turns out we can't easily determine that from inspecting - # libtool variables, so we have to hard-code the OSs to which it - # applies here; at the moment, that means platforms that use the PE - # object format with DLL files. See the long comment at the top of - # tests/bindir.at for full details. - tdlname=$dlname - case $host,$output,$installed,$module,$dlname in - *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll) - # If a -bindir argument was supplied, place the dll there. - if test "x$bindir" != x ; - then - func_relative_path "$install_libdir" "$bindir" - tdlname=$func_relative_path_result$dlname - else - # Otherwise fall back on heuristic. - tdlname=../bin/$dlname - fi - ;; - esac - $ECHO > $output "\ -# $outputname - a libtool library file -# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION -# -# Please DO NOT delete this file! -# It is necessary for linking the library. - -# The name that we can dlopen(3). -dlname='$tdlname' - -# Names of this library. -library_names='$library_names' - -# The name of the static archive. -old_library='$old_library' - -# Linker flags that can not go in dependency_libs. -inherited_linker_flags='$new_inherited_linker_flags' - -# Libraries that this one depends upon. -dependency_libs='$dependency_libs' - -# Names of additional weak libraries provided by this library -weak_library_names='$weak_libs' - -# Version information for $libname. -current=$current -age=$age -revision=$revision - -# Is this an already installed library? -installed=$installed - -# Should we warn about portability when linking against -modules? -shouldnotlink=$module - -# Files to dlopen/dlpreopen -dlopen='$dlfiles' -dlpreopen='$dlprefiles' - -# Directory that this library needs to be installed in: -libdir='$install_libdir'" - if test "$installed" = no && test "$need_relink" = yes; then - $ECHO >> $output "\ -relink_command=\"$relink_command\"" - fi - done - } - - # Do a symbolic link so that the libtool archive can be found in - # LD_LIBRARY_PATH before the program is installed. - func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?' - ;; - esac - exit $EXIT_SUCCESS -} - -{ test "$mode" = link || test "$mode" = relink; } && - func_mode_link ${1+"$@"} - - -# func_mode_uninstall arg... -func_mode_uninstall () -{ - $opt_debug - RM="$nonopt" - files= - rmforce= - exit_status=0 - - # This variable tells wrapper scripts just to set variables rather - # than running their programs. - libtool_install_magic="$magic" - - for arg - do - case $arg in - -f) RM="$RM $arg"; rmforce=yes ;; - -*) RM="$RM $arg" ;; - *) files="$files $arg" ;; - esac - done - - test -z "$RM" && \ - func_fatal_help "you must specify an RM program" - - rmdirs= - - origobjdir="$objdir" - for file in $files; do - func_dirname "$file" "" "." - dir="$func_dirname_result" - if test "X$dir" = X.; then - objdir="$origobjdir" - else - objdir="$dir/$origobjdir" - fi - func_basename "$file" - name="$func_basename_result" - test "$mode" = uninstall && objdir="$dir" - - # Remember objdir for removal later, being careful to avoid duplicates - if test "$mode" = clean; then - case " $rmdirs " in - *" $objdir "*) ;; - *) rmdirs="$rmdirs $objdir" ;; - esac - fi - - # Don't error if the file doesn't exist and rm -f was used. - if { test -L "$file"; } >/dev/null 2>&1 || - { test -h "$file"; } >/dev/null 2>&1 || - test -f "$file"; then - : - elif test -d "$file"; then - exit_status=1 - continue - elif test "$rmforce" = yes; then - continue - fi - - rmfiles="$file" - - case $name in - *.la) - # Possibly a libtool archive, so verify it. - if func_lalib_p "$file"; then - func_source $dir/$name - - # Delete the libtool libraries and symlinks. - for n in $library_names; do - rmfiles="$rmfiles $objdir/$n" - done - test -n "$old_library" && rmfiles="$rmfiles $objdir/$old_library" - - case "$mode" in - clean) - case " $library_names " in - # " " in the beginning catches empty $dlname - *" $dlname "*) ;; - *) rmfiles="$rmfiles $objdir/$dlname" ;; - esac - test -n "$libdir" && rmfiles="$rmfiles $objdir/$name $objdir/${name}i" - ;; - uninstall) - if test -n "$library_names"; then - # Do each command in the postuninstall commands. - func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' - fi - - if test -n "$old_library"; then - # Do each command in the old_postuninstall commands. - func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1' - fi - # FIXME: should reinstall the best remaining shared library. - ;; - esac - fi - ;; - - *.lo) - # Possibly a libtool object, so verify it. - if func_lalib_p "$file"; then - - # Read the .lo file - func_source $dir/$name - - # Add PIC object to the list of files to remove. - if test -n "$pic_object" && - test "$pic_object" != none; then - rmfiles="$rmfiles $dir/$pic_object" - fi - - # Add non-PIC object to the list of files to remove. - if test -n "$non_pic_object" && - test "$non_pic_object" != none; then - rmfiles="$rmfiles $dir/$non_pic_object" - fi - fi - ;; - - *) - if test "$mode" = clean ; then - noexename=$name - case $file in - *.exe) - func_stripname '' '.exe' "$file" - file=$func_stripname_result - func_stripname '' '.exe' "$name" - noexename=$func_stripname_result - # $file with .exe has already been added to rmfiles, - # add $file without .exe - rmfiles="$rmfiles $file" - ;; - esac - # Do a test to see if this is a libtool program. - if func_ltwrapper_p "$file"; then - if func_ltwrapper_executable_p "$file"; then - func_ltwrapper_scriptname "$file" - relink_command= - func_source $func_ltwrapper_scriptname_result - rmfiles="$rmfiles $func_ltwrapper_scriptname_result" - else - relink_command= - func_source $dir/$noexename - fi - - # note $name still contains .exe if it was in $file originally - # as does the version of $file that was added into $rmfiles - rmfiles="$rmfiles $objdir/$name $objdir/${name}S.${objext}" - if test "$fast_install" = yes && test -n "$relink_command"; then - rmfiles="$rmfiles $objdir/lt-$name" - fi - if test "X$noexename" != "X$name" ; then - rmfiles="$rmfiles $objdir/lt-${noexename}.c" - fi - fi - fi - ;; - esac - func_show_eval "$RM $rmfiles" 'exit_status=1' - done - objdir="$origobjdir" - - # Try to remove the ${objdir}s in the directories where we deleted files - for dir in $rmdirs; do - if test -d "$dir"; then - func_show_eval "rmdir $dir >/dev/null 2>&1" - fi - done - - exit $exit_status -} - -{ test "$mode" = uninstall || test "$mode" = clean; } && - func_mode_uninstall ${1+"$@"} - -test -z "$mode" && { - help="$generic_help" - func_fatal_help "you must specify a MODE" -} - -test -z "$exec_cmd" && \ - func_fatal_help "invalid operation mode \`$mode'" - -if test -n "$exec_cmd"; then - eval exec "$exec_cmd" - exit $EXIT_FAILURE -fi - -exit $exit_status - - -# The TAGs below are defined such that we never get into a situation -# in which we disable both kinds of libraries. Given conflicting -# choices, we go for a static library, that is the most portable, -# since we can't tell whether shared libraries were disabled because -# the user asked for that or because the platform doesn't support -# them. This is particularly important on AIX, because we don't -# support having both static and shared libraries enabled at the same -# time on that platform, so we default to a shared-only configuration. -# If a disable-shared tag is given, we'll fallback to a static-only -# configuration. But we'll never go from static-only to shared-only. - -# ### BEGIN LIBTOOL TAG CONFIG: disable-shared -build_libtool_libs=no -build_old_libs=yes -# ### END LIBTOOL TAG CONFIG: disable-shared - -# ### BEGIN LIBTOOL TAG CONFIG: disable-static -build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac` -# ### END LIBTOOL TAG CONFIG: disable-static - -# Local Variables: -# mode:shell-script -# sh-indentation:2 -# End: -# vi:sw=2 - diff --git a/src/libbacktrace/macho.c b/src/libbacktrace/macho.c deleted file mode 100644 index ba7f94c079f8a..0000000000000 --- a/src/libbacktrace/macho.c +++ /dev/null @@ -1,1416 +0,0 @@ -/* macho.c -- Get debug data from an Mach-O file for backtraces. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by John Colanduoni. - - Pending upstream pull request: - https://github.com/ianlancetaylor/libbacktrace/pull/2 - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -/* We can't use autotools to detect the pointer width of our program because - we may be building a fat Mach-O file containing both 32-bit and 64-bit - variants. However Mach-O runs a limited set of platforms so detection - via preprocessor is not difficult. */ - -#if defined(__MACH__) -#if defined(__LP64__) -#define BACKTRACE_BITS 64 -#else -#define BACKTRACE_BITS 32 -#endif -#else -#error Attempting to build Mach-O support on incorrect platform -#endif - -#if defined(__x86_64__) -#define NATIVE_CPU_TYPE CPU_TYPE_X86_64 -#elif defined(__i386__) -#define NATIVE_CPU_TYPE CPU_TYPE_X86 -#elif defined(__aarch64__) -#define NATIVE_CPU_TYPE CPU_TYPE_ARM64 -#elif defined(__arm__) -#define NATIVE_CPU_TYPE CPU_TYPE_ARM -#else -#error Could not detect native Mach-O cpu_type_t -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -struct macho_commands_view -{ - struct backtrace_view view; - uint32_t commands_count; - uint32_t commands_total_size; - int bytes_swapped; - size_t base_offset; -}; - -enum debug_section -{ - DEBUG_INFO, - DEBUG_LINE, - DEBUG_ABBREV, - DEBUG_RANGES, - DEBUG_STR, - DEBUG_MAX -}; - -static const char *const debug_section_names[DEBUG_MAX] = - { - "__debug_info", - "__debug_line", - "__debug_abbrev", - "__debug_ranges", - "__debug_str" - }; - -struct found_dwarf_section -{ - uint32_t file_offset; - uintptr_t file_size; - const unsigned char *data; -}; - -/* Mach-O symbols don't have a length. As a result we have to infer it - by sorting the symbol addresses for each image and recording the - memory range attributed to each image. */ -struct macho_symbol -{ - uintptr_t addr; - size_t size; - const char *name; -}; - -struct macho_syminfo_data -{ - struct macho_syminfo_data *next; - struct macho_symbol *symbols; - size_t symbol_count; - uintptr_t min_addr; - uintptr_t max_addr; -}; - -uint16_t -macho_file_to_host_u16 (int file_bytes_swapped, uint16_t input) -{ - if (file_bytes_swapped) - return (input >> 8) | (input << 8); - else - return input; -} - -uint32_t -macho_file_to_host_u32 (int file_bytes_swapped, uint32_t input) -{ - if (file_bytes_swapped) - { - return ((input >> 24) & 0x000000FF) - | ((input >> 8) & 0x0000FF00) - | ((input << 8) & 0x00FF0000) - | ((input << 24) & 0xFF000000); - } - else - { - return input; - } -} - -uint64_t -macho_file_to_host_u64 (int file_bytes_swapped, uint64_t input) -{ - if (file_bytes_swapped) - { - return macho_file_to_host_u32 (file_bytes_swapped, - (uint32_t) (input >> 32)) - | (((uint64_t) macho_file_to_host_u32 (file_bytes_swapped, - (uint32_t) input)) << 32); - } - else - { - return input; - } -} - -#if BACKTRACE_BITS == 64 -#define macho_file_to_host_usize macho_file_to_host_u64 -typedef struct mach_header_64 mach_header_native_t; -#define LC_SEGMENT_NATIVE LC_SEGMENT_64 -typedef struct segment_command_64 segment_command_native_t; -typedef struct nlist_64 nlist_native_t; -typedef struct section_64 section_native_t; -#else /* BACKTRACE_BITS == 32 */ -#define macho_file_to_host_usize macho_file_to_host_u32 -typedef struct mach_header mach_header_native_t; -#define LC_SEGMENT_NATIVE LC_SEGMENT -typedef struct segment_command segment_command_native_t; -typedef struct nlist nlist_native_t; -typedef struct section section_native_t; -#endif - -// Gets a view into a Mach-O image, taking any slice offset into account -int -macho_get_view (struct backtrace_state *state, int descriptor, - off_t offset, size_t size, - backtrace_error_callback error_callback, - void *data, struct macho_commands_view *commands_view, - struct backtrace_view *view) -{ - return backtrace_get_view (state, descriptor, - commands_view->base_offset + offset, size, - error_callback, data, view); -} - -int -macho_get_commands (struct backtrace_state *state, int descriptor, - backtrace_error_callback error_callback, - void *data, struct macho_commands_view *commands_view, - int *incompatible) -{ - int ret = 0; - int is_fat = 0; - struct backtrace_view file_header_view; - int file_header_view_valid = 0; - struct backtrace_view fat_archs_view; - int fat_archs_view_valid = 0; - const mach_header_native_t *file_header; - uint64_t commands_offset; - - *incompatible = 0; - - if (!backtrace_get_view (state, descriptor, 0, sizeof (mach_header_native_t), - error_callback, data, &file_header_view)) - goto end; - file_header_view_valid = 1; - - switch (*(uint32_t *) file_header_view.data) - { - case MH_MAGIC: - if (BACKTRACE_BITS == 32) - commands_view->bytes_swapped = 0; - else - { - *incompatible = 1; - goto end; - } - break; - case MH_CIGAM: - if (BACKTRACE_BITS == 32) - commands_view->bytes_swapped = 1; - else - { - *incompatible = 1; - goto end; - } - break; - case MH_MAGIC_64: - if (BACKTRACE_BITS == 64) - commands_view->bytes_swapped = 0; - else - { - *incompatible = 1; - goto end; - } - break; - case MH_CIGAM_64: - if (BACKTRACE_BITS == 64) - commands_view->bytes_swapped = 1; - else - { - *incompatible = 1; - goto end; - } - break; - case FAT_MAGIC: - is_fat = 1; - commands_view->bytes_swapped = 0; - break; - case FAT_CIGAM: - is_fat = 1; - commands_view->bytes_swapped = 1; - break; - default: - goto end; - } - - if (is_fat) - { - uint32_t native_slice_offset; - size_t archs_total_size; - uint32_t arch_count; - const struct fat_header *fat_header; - const struct fat_arch *archs; - uint32_t i; - - fat_header = file_header_view.data; - arch_count = - macho_file_to_host_u32 (commands_view->bytes_swapped, - fat_header->nfat_arch); - - archs_total_size = arch_count * sizeof (struct fat_arch); - - if (!backtrace_get_view (state, descriptor, sizeof (struct fat_header), - archs_total_size, error_callback, - data, &fat_archs_view)) - goto end; - fat_archs_view_valid = 1; - - native_slice_offset = 0; - archs = fat_archs_view.data; - for (i = 0; i < arch_count; i++) - { - const struct fat_arch *raw_arch = archs + i; - int cpu_type = - (int) macho_file_to_host_u32 (commands_view->bytes_swapped, - (uint32_t) raw_arch->cputype); - - if (cpu_type == NATIVE_CPU_TYPE) - { - native_slice_offset = - macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_arch->offset); - - break; - } - } - - if (native_slice_offset == 0) - { - *incompatible = 1; - goto end; - } - - backtrace_release_view (state, &file_header_view, error_callback, data); - file_header_view_valid = 0; - if (!backtrace_get_view (state, descriptor, native_slice_offset, - sizeof (mach_header_native_t), error_callback, - data, &file_header_view)) - goto end; - file_header_view_valid = 1; - - // The endianness of the slice may be different than the fat image - switch (*(uint32_t *) file_header_view.data) - { - case MH_MAGIC: - if (BACKTRACE_BITS == 32) - commands_view->bytes_swapped = 0; - else - goto end; - break; - case MH_CIGAM: - if (BACKTRACE_BITS == 32) - commands_view->bytes_swapped = 1; - else - goto end; - break; - case MH_MAGIC_64: - if (BACKTRACE_BITS == 64) - commands_view->bytes_swapped = 0; - else - goto end; - break; - case MH_CIGAM_64: - if (BACKTRACE_BITS == 64) - commands_view->bytes_swapped = 1; - else - goto end; - break; - default: - goto end; - } - - commands_view->base_offset = native_slice_offset; - } - else - commands_view->base_offset = 0; - - file_header = file_header_view.data; - commands_view->commands_count = - macho_file_to_host_u32 (commands_view->bytes_swapped, - file_header->ncmds); - commands_view->commands_total_size = - macho_file_to_host_u32 (commands_view->bytes_swapped, - file_header->sizeofcmds); - commands_offset = - commands_view->base_offset + sizeof (mach_header_native_t); - - if (!backtrace_get_view (state, descriptor, commands_offset, - commands_view->commands_total_size, error_callback, - data, &commands_view->view)) - goto end; - - ret = 1; - -end: - if (file_header_view_valid) - backtrace_release_view (state, &file_header_view, error_callback, data); - if (fat_archs_view_valid) - backtrace_release_view (state, &fat_archs_view, error_callback, data); - return ret; -} - -int -macho_get_uuid (struct backtrace_state *state ATTRIBUTE_UNUSED, - int descriptor ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, - void *data, struct macho_commands_view *commands_view, - uuid_t *uuid) -{ - size_t offset = 0; - uint32_t i = 0; - - for (i = 0; i < commands_view->commands_count; i++) - { - const struct load_command *raw_command; - struct load_command command; - - if (offset + sizeof (struct load_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - raw_command = - commands_view->view.data + offset; - command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmd); - command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmdsize); - - if (command.cmd == LC_UUID) - { - const struct uuid_command *uuid_command; - - if (offset + sizeof (struct uuid_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - uuid_command = - (struct uuid_command *) raw_command; - memcpy (uuid, uuid_command->uuid, sizeof (uuid_t)); - return 1; - } - - offset += command.cmdsize; - } - - error_callback (data, "executable file is missing an identifying UUID", 0); - return 0; -} - -/* Returns the base address of a Mach-O image, as encoded in the file header. - * WARNING: This does not take ASLR into account, which is ubiquitous on recent - * Darwin platforms. - */ -int -macho_get_addr_range (struct backtrace_state *state ATTRIBUTE_UNUSED, - int descriptor ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, - void *data, struct macho_commands_view *commands_view, - uintptr_t *base_address, uintptr_t *max_address) -{ - size_t offset = 0; - int found_text = 0; - uint32_t i = 0; - - *max_address = 0; - - for (i = 0; i < commands_view->commands_count; i++) - { - const struct load_command *raw_command; - struct load_command command; - - if (offset + sizeof (struct load_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - raw_command = commands_view->view.data + offset; - command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmd); - command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmdsize); - - if (command.cmd == LC_SEGMENT_NATIVE) - { - const segment_command_native_t *raw_segment; - uintptr_t segment_vmaddr; - uintptr_t segment_vmsize; - uintptr_t segment_maxaddr; - uintptr_t text_fileoff; - - if (offset + sizeof (segment_command_native_t) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - raw_segment = (segment_command_native_t *) raw_command; - - segment_vmaddr = macho_file_to_host_usize ( - commands_view->bytes_swapped, raw_segment->vmaddr); - segment_vmsize = macho_file_to_host_usize ( - commands_view->bytes_swapped, raw_segment->vmsize); - segment_maxaddr = segment_vmaddr + segment_vmsize; - - if (strncmp (raw_segment->segname, "__TEXT", - sizeof (raw_segment->segname)) == 0) - { - text_fileoff = macho_file_to_host_usize ( - commands_view->bytes_swapped, raw_segment->fileoff); - *base_address = segment_vmaddr - text_fileoff; - - found_text = 1; - } - - if (segment_maxaddr > *max_address) - *max_address = segment_maxaddr; - } - - offset += command.cmdsize; - } - - if (found_text) - return 1; - else - { - error_callback (data, "executable is missing __TEXT segment", 0); - return 0; - } -} - -static int -macho_symbol_compare_addr (const void *left_raw, const void *right_raw) -{ - const struct macho_symbol *left = left_raw; - const struct macho_symbol *right = right_raw; - - if (left->addr > right->addr) - return 1; - else if (left->addr < right->addr) - return -1; - else - return 0; -} - -int -macho_symbol_type_relevant (uint8_t type) -{ - uint8_t type_field = (uint8_t) (type & N_TYPE); - - return !(type & N_EXT) && - (type_field == N_ABS || type_field == N_SECT); -} - -int -macho_add_symtab (struct backtrace_state *state, - backtrace_error_callback error_callback, - void *data, int descriptor, - struct macho_commands_view *commands_view, - uintptr_t base_address, uintptr_t max_image_address, - intptr_t vmslide, int *found_sym) -{ - struct macho_syminfo_data *syminfo_data; - - int ret = 0; - size_t offset = 0; - struct backtrace_view symtab_view; - int symtab_view_valid = 0; - struct backtrace_view strtab_view; - int strtab_view_valid = 0; - size_t syminfo_index = 0; - size_t function_count = 0; - uint32_t i = 0; - uint32_t j = 0; - uint32_t symtab_index = 0; - - *found_sym = 0; - - for (i = 0; i < commands_view->commands_count; i++) - { - const struct load_command *raw_command; - struct load_command command; - - if (offset + sizeof (struct load_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - raw_command = commands_view->view.data + offset; - command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmd); - command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped, - raw_command->cmdsize); - - if (command.cmd == LC_SYMTAB) - { - const struct symtab_command *symtab_command; - uint32_t symbol_table_offset; - uint32_t symbol_count; - uint32_t string_table_offset; - uint32_t string_table_size; - - if (offset + sizeof (struct symtab_command) - > commands_view->commands_total_size) - { - error_callback (data, - "executable file contains out of range command offset", - 0); - return 0; - } - - symtab_command = (struct symtab_command *) raw_command; - - symbol_table_offset = macho_file_to_host_u32 ( - commands_view->bytes_swapped, symtab_command->symoff); - symbol_count = macho_file_to_host_u32 ( - commands_view->bytes_swapped, symtab_command->nsyms); - string_table_offset = macho_file_to_host_u32 ( - commands_view->bytes_swapped, symtab_command->stroff); - string_table_size = macho_file_to_host_u32 ( - commands_view->bytes_swapped, symtab_command->strsize); - - - if (!macho_get_view (state, descriptor, symbol_table_offset, - symbol_count * sizeof (nlist_native_t), - error_callback, data, commands_view, - &symtab_view)) - goto end; - symtab_view_valid = 1; - - if (!macho_get_view (state, descriptor, string_table_offset, - string_table_size, error_callback, data, - commands_view, &strtab_view)) - goto end; - strtab_view_valid = 1; - - // Count functions first - for (j = 0; j < symbol_count; j++) - { - const nlist_native_t *raw_sym = - ((const nlist_native_t *) symtab_view.data) + j; - - if (macho_symbol_type_relevant (raw_sym->n_type)) - { - function_count += 1; - } - } - - // Allocate space for the: - // (a) macho_syminfo_data for this image - // (b) macho_symbol entries - syminfo_data = - backtrace_alloc (state, - sizeof (struct macho_syminfo_data), - error_callback, data); - if (syminfo_data == NULL) - goto end; - - syminfo_data->symbols = backtrace_alloc ( - state, function_count * sizeof (struct macho_symbol), - error_callback, data); - if (syminfo_data->symbols == NULL) - goto end; - - syminfo_data->symbol_count = function_count; - syminfo_data->next = NULL; - syminfo_data->min_addr = base_address; - syminfo_data->max_addr = max_image_address; - - for (symtab_index = 0; - symtab_index < symbol_count; symtab_index++) - { - const nlist_native_t *raw_sym = - ((const nlist_native_t *) symtab_view.data) + - symtab_index; - - if (macho_symbol_type_relevant (raw_sym->n_type)) - { - size_t strtab_index; - const char *name; - size_t max_len_plus_one; - - syminfo_data->symbols[syminfo_index].addr = - macho_file_to_host_usize (commands_view->bytes_swapped, - raw_sym->n_value) + vmslide; - - strtab_index = macho_file_to_host_u32 ( - commands_view->bytes_swapped, - raw_sym->n_un.n_strx); - - // Check the range of the supposed "string" we've been - // given - if (strtab_index >= string_table_size) - { - error_callback ( - data, - "dSYM file contains out of range string table index", - 0); - goto end; - } - - name = strtab_view.data + strtab_index; - max_len_plus_one = string_table_size - strtab_index; - - if (strnlen (name, max_len_plus_one) >= max_len_plus_one) - { - error_callback ( - data, - "dSYM file contains unterminated string", - 0); - goto end; - } - - // Remove underscore prefixes - if (name[0] == '_') - { - name = name + 1; - } - - syminfo_data->symbols[syminfo_index].name = name; - - syminfo_index += 1; - } - } - - backtrace_qsort (syminfo_data->symbols, - syminfo_data->symbol_count, - sizeof (struct macho_symbol), - macho_symbol_compare_addr); - - // Calculate symbol sizes - for (syminfo_index = 0; - syminfo_index < syminfo_data->symbol_count; syminfo_index++) - { - if (syminfo_index + 1 < syminfo_data->symbol_count) - { - syminfo_data->symbols[syminfo_index].size = - syminfo_data->symbols[syminfo_index + 1].addr - - syminfo_data->symbols[syminfo_index].addr; - } - else - { - syminfo_data->symbols[syminfo_index].size = - max_image_address - - syminfo_data->symbols[syminfo_index].addr; - } - } - - if (!state->threaded) - { - struct macho_syminfo_data **pp; - - for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; - *pp != NULL; - pp = &(*pp)->next); - *pp = syminfo_data; - } - else - { - while (1) - { - struct macho_syminfo_data **pp; - - pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; - - while (1) - { - struct macho_syminfo_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, syminfo_data)) - break; - } - } - - strtab_view_valid = 0; // We need to keep string table around - *found_sym = 1; - ret = 1; - goto end; - } - - offset += command.cmdsize; - } - - // No symbol table here - ret = 1; - goto end; - -end: - if (symtab_view_valid) - backtrace_release_view (state, &symtab_view, error_callback, data); - if (strtab_view_valid) - backtrace_release_view (state, &strtab_view, error_callback, data); - return ret; -} - -int -macho_try_dwarf (struct backtrace_state *state, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, uuid_t *executable_uuid, - uintptr_t base_address, uintptr_t max_image_address, - intptr_t vmslide, char *dwarf_filename, int *matched, - int *found_sym, int *found_dwarf) -{ - uuid_t dwarf_uuid; - - int ret = 0; - int dwarf_descriptor; - int dwarf_descriptor_valid = 0; - struct macho_commands_view commands_view; - int commands_view_valid = 0; - struct backtrace_view dwarf_view; - int dwarf_view_valid = 0; - size_t offset = 0; - struct found_dwarf_section dwarf_sections[DEBUG_MAX]; - uintptr_t min_dwarf_offset = 0; - uintptr_t max_dwarf_offset = 0; - uint32_t i = 0; - uint32_t j = 0; - int k = 0; - - *matched = 0; - *found_sym = 0; - *found_dwarf = 0; - - if ((dwarf_descriptor = backtrace_open (dwarf_filename, error_callback, - data, NULL)) == 0) - goto end; - dwarf_descriptor_valid = 1; - - int incompatible; - if (!macho_get_commands (state, dwarf_descriptor, error_callback, data, - &commands_view, &incompatible)) - { - // Failing to read the header here is fine, because this dSYM may be - // for a different architecture - if (incompatible) - { - ret = 1; - } - goto end; - } - commands_view_valid = 1; - - // Get dSYM UUID and compare - if (!macho_get_uuid (state, dwarf_descriptor, error_callback, data, - &commands_view, &dwarf_uuid)) - { - error_callback (data, "dSYM file is missing an identifying uuid", 0); - goto end; - } - if (memcmp (executable_uuid, &dwarf_uuid, sizeof (uuid_t)) != 0) - { - // DWARF doesn't belong to desired executable - ret = 1; - goto end; - } - - *matched = 1; - - // Read symbol table - if (!macho_add_symtab (state, error_callback, data, dwarf_descriptor, - &commands_view, base_address, max_image_address, - vmslide, found_sym)) - goto end; - - // Get DWARF sections - - memset (dwarf_sections, 0, sizeof (dwarf_sections)); - offset = 0; - for (i = 0; i < commands_view.commands_count; i++) - { - const struct load_command *raw_command; - struct load_command command; - - if (offset + sizeof (struct load_command) - > commands_view.commands_total_size) - { - error_callback (data, - "dSYM file contains out of range command offset", 0); - goto end; - } - - raw_command = commands_view.view.data + offset; - command.cmd = macho_file_to_host_u32 (commands_view.bytes_swapped, - raw_command->cmd); - command.cmdsize = macho_file_to_host_u32 (commands_view.bytes_swapped, - raw_command->cmdsize); - - if (command.cmd == LC_SEGMENT_NATIVE) - { - uint32_t section_count; - size_t section_offset; - const segment_command_native_t *raw_segment; - - if (offset + sizeof (segment_command_native_t) - > commands_view.commands_total_size) - { - error_callback (data, - "dSYM file contains out of range command offset", - 0); - goto end; - } - - raw_segment = (const segment_command_native_t *) raw_command; - - if (strncmp (raw_segment->segname, "__DWARF", - sizeof (raw_segment->segname)) == 0) - { - section_count = macho_file_to_host_u32 ( - commands_view.bytes_swapped, - raw_segment->nsects); - - section_offset = offset + sizeof (segment_command_native_t); - - // Search sections for relevant DWARF section names - for (j = 0; j < section_count; j++) - { - const section_native_t *raw_section; - - if (section_offset + sizeof (section_native_t) > - commands_view.commands_total_size) - { - error_callback (data, - "dSYM file contains out of range command offset", - 0); - goto end; - } - - raw_section = commands_view.view.data + section_offset; - - for (k = 0; k < DEBUG_MAX; k++) - { - uintptr_t dwarf_section_end; - - if (strncmp (raw_section->sectname, - debug_section_names[k], - sizeof (raw_section->sectname)) == 0) - { - *found_dwarf = 1; - - dwarf_sections[k].file_offset = - macho_file_to_host_u32 ( - commands_view.bytes_swapped, - raw_section->offset); - dwarf_sections[k].file_size = - macho_file_to_host_usize ( - commands_view.bytes_swapped, - raw_section->size); - - if (min_dwarf_offset == 0 || - dwarf_sections[k].file_offset < - min_dwarf_offset) - min_dwarf_offset = dwarf_sections[k].file_offset; - - dwarf_section_end = - dwarf_sections[k].file_offset + - dwarf_sections[k].file_size; - if (dwarf_section_end > max_dwarf_offset) - max_dwarf_offset = dwarf_section_end; - - break; - } - } - - section_offset += sizeof (section_native_t); - } - - break; - } - } - - offset += command.cmdsize; - } - - if (!*found_dwarf) - { - // No DWARF in this file - ret = 1; - goto end; - } - - if (!macho_get_view (state, dwarf_descriptor, (off_t) min_dwarf_offset, - max_dwarf_offset - min_dwarf_offset, error_callback, - data, &commands_view, &dwarf_view)) - goto end; - dwarf_view_valid = 1; - - for (i = 0; i < DEBUG_MAX; i++) - { - if (dwarf_sections[i].file_offset == 0) - dwarf_sections[i].data = NULL; - else - dwarf_sections[i].data = - dwarf_view.data + dwarf_sections[i].file_offset - min_dwarf_offset; - } - - if (!backtrace_dwarf_add (state, vmslide, - dwarf_sections[DEBUG_INFO].data, - dwarf_sections[DEBUG_INFO].file_size, - dwarf_sections[DEBUG_LINE].data, - dwarf_sections[DEBUG_LINE].file_size, - dwarf_sections[DEBUG_ABBREV].data, - dwarf_sections[DEBUG_ABBREV].file_size, - dwarf_sections[DEBUG_RANGES].data, - dwarf_sections[DEBUG_RANGES].file_size, - dwarf_sections[DEBUG_STR].data, - dwarf_sections[DEBUG_STR].file_size, - ((__DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN) - ^ commands_view.bytes_swapped), - error_callback, data, fileline_fn)) - goto end; - - // Don't release the DWARF view because it is still in use - dwarf_descriptor_valid = 0; - dwarf_view_valid = 0; - ret = 1; - -end: - if (dwarf_descriptor_valid) - backtrace_close (dwarf_descriptor, error_callback, data); - if (commands_view_valid) - backtrace_release_view (state, &commands_view.view, error_callback, data); - if (dwarf_view_valid) - backtrace_release_view (state, &dwarf_view, error_callback, data); - return ret; -} - -int -macho_try_dsym (struct backtrace_state *state, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn, uuid_t *executable_uuid, - uintptr_t base_address, uintptr_t max_image_address, - intptr_t vmslide, char *dsym_filename, int *matched, - int *found_sym, int *found_dwarf) -{ - int ret = 0; - char dwarf_image_dir_path[PATH_MAX]; - DIR *dwarf_image_dir; - int dwarf_image_dir_valid = 0; - struct dirent *directory_entry; - char dwarf_filename[PATH_MAX]; - int dwarf_matched; - int dwarf_had_sym; - int dwarf_had_dwarf; - - *matched = 0; - *found_sym = 0; - *found_dwarf = 0; - - strncpy (dwarf_image_dir_path, dsym_filename, PATH_MAX); - strncat (dwarf_image_dir_path, "/Contents/Resources/DWARF", PATH_MAX); - - if (!(dwarf_image_dir = opendir (dwarf_image_dir_path))) - { - error_callback (data, "could not open DWARF directory in dSYM", - 0); - goto end; - } - dwarf_image_dir_valid = 1; - - while ((directory_entry = readdir (dwarf_image_dir))) - { - if (directory_entry->d_type != DT_REG) - continue; - - strncpy (dwarf_filename, dwarf_image_dir_path, PATH_MAX); - strncat (dwarf_filename, "/", PATH_MAX); - strncat (dwarf_filename, directory_entry->d_name, PATH_MAX); - - if (!macho_try_dwarf (state, error_callback, data, fileline_fn, - executable_uuid, base_address, max_image_address, - vmslide, dwarf_filename, - &dwarf_matched, &dwarf_had_sym, &dwarf_had_dwarf)) - goto end; - - if (dwarf_matched) - { - *matched = 1; - *found_sym = dwarf_had_sym; - *found_dwarf = dwarf_had_dwarf; - ret = 1; - goto end; - } - } - - // No matching DWARF in this dSYM - ret = 1; - goto end; - -end: - if (dwarf_image_dir_valid) - closedir (dwarf_image_dir); - return ret; -} - -int -macho_add (struct backtrace_state *state, - backtrace_error_callback error_callback, void *data, int descriptor, - const char *filename, fileline *fileline_fn, intptr_t vmslide, - int *found_sym, int *found_dwarf) -{ - uuid_t image_uuid; - uintptr_t image_file_base_address; - uintptr_t image_file_max_address; - uintptr_t image_actual_base_address = 0; - uintptr_t image_actual_max_address = 0; - - int ret = 0; - struct macho_commands_view commands_view; - int commands_view_valid = 0; - char executable_dirname[PATH_MAX]; - size_t filename_len; - DIR *executable_dir = NULL; - int executable_dir_valid = 0; - struct dirent *directory_entry; - char dsym_full_path[PATH_MAX]; - static const char *extension; - size_t extension_len; - ssize_t i; - - *found_sym = 0; - *found_dwarf = 0; - - // Find Mach-O commands list - int incompatible; - if (!macho_get_commands (state, descriptor, error_callback, data, - &commands_view, &incompatible)) - goto end; - commands_view_valid = 1; - - // First we need to get the uuid of our file so we can hunt down the correct - // dSYM - if (!macho_get_uuid (state, descriptor, error_callback, data, &commands_view, - &image_uuid)) - goto end; - - // Now we need to find the in memory base address. Step one is to find out - // what the executable thinks the base address is - if (!macho_get_addr_range (state, descriptor, error_callback, data, - &commands_view, - &image_file_base_address, - &image_file_max_address)) - goto end; - - image_actual_base_address = - image_file_base_address + vmslide; - image_actual_max_address = - image_file_max_address + vmslide; - - if (image_actual_base_address == 0) - { - error_callback (data, "executable file is not loaded", 0); - goto end; - } - - // Look for dSYM in our executable's directory - strncpy (executable_dirname, filename, PATH_MAX); - filename_len = strlen (executable_dirname); - for (i = filename_len - 1; i >= 0; i--) - { - if (executable_dirname[i] == '/') - { - executable_dirname[i] = '\0'; - break; - } - else if (i == 0) - { - executable_dirname[0] = '.'; - executable_dirname[1] = '\0'; - break; - } - } - - if (!(executable_dir = opendir (executable_dirname))) - { - error_callback (data, "could not open directory containing executable", - 0); - goto end; - } - executable_dir_valid = 1; - - extension = ".dSYM"; - extension_len = strlen (extension); - while ((directory_entry = readdir (executable_dir))) - { - if (directory_entry->d_namlen < extension_len) - continue; - if (strncasecmp (directory_entry->d_name + directory_entry->d_namlen - - extension_len, extension, extension_len) == 0) - { - int matched; - int dsym_had_sym; - int dsym_had_dwarf; - - // Found a dSYM - strncpy (dsym_full_path, executable_dirname, PATH_MAX); - strncat (dsym_full_path, "/", PATH_MAX); - strncat (dsym_full_path, directory_entry->d_name, PATH_MAX); - - if (!macho_try_dsym (state, error_callback, data, - fileline_fn, &image_uuid, - image_actual_base_address, - image_actual_max_address, vmslide, - dsym_full_path, - &matched, &dsym_had_sym, &dsym_had_dwarf)) - goto end; - - if (matched) - { - *found_sym = dsym_had_sym; - *found_dwarf = dsym_had_dwarf; - ret = 1; - goto end; - } - } - } - - // No matching dSYM - ret = 1; - goto end; - -end: - if (commands_view_valid) - backtrace_release_view (state, &commands_view.view, error_callback, - data); - if (executable_dir_valid) - closedir (executable_dir); - return ret; -} - -static int -macho_symbol_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct macho_symbol *entry = (const struct macho_symbol *) ventry; - uintptr_t addr; - - addr = *key; - if (addr < entry->addr) - return -1; - else if (addr >= entry->addr + entry->size) - return 1; - else - return 0; -} - -static void -macho_syminfo (struct backtrace_state *state, - uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data) -{ - struct macho_syminfo_data *edata; - struct macho_symbol *sym = NULL; - - if (!state->threaded) - { - for (edata = (struct macho_syminfo_data *) state->syminfo_data; - edata != NULL; - edata = edata->next) - { - if (addr >= edata->min_addr && addr <= edata->max_addr) - { - sym = ((struct macho_symbol *) - bsearch (&addr, edata->symbols, edata->symbol_count, - sizeof (struct macho_symbol), macho_symbol_search)); - if (sym != NULL) - break; - } - } - } - else - { - struct macho_syminfo_data **pp; - - pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data; - while (1) - { - edata = backtrace_atomic_load_pointer (pp); - if (edata == NULL) - break; - - if (addr >= edata->min_addr && addr <= edata->max_addr) - { - sym = ((struct macho_symbol *) - bsearch (&addr, edata->symbols, edata->symbol_count, - sizeof (struct macho_symbol), macho_symbol_search)); - if (sym != NULL) - break; - } - - pp = &edata->next; - } - } - - if (sym == NULL) - callback (data, addr, NULL, 0, 0); - else - callback (data, addr, sym->name, sym->addr, sym->size); -} - - -static int -macho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc ATTRIBUTE_UNUSED, - backtrace_full_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no debug info in Mach-O executable", -1); - return 0; -} - -static void -macho_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t addr ATTRIBUTE_UNUSED, - backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no symbol table in Mach-O executable", -1); -} - -int -backtrace_initialize (struct backtrace_state *state, int descriptor, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn) -{ - int ret; - fileline macho_fileline_fn = macho_nodebug; - int found_sym = 0; - int found_dwarf = 0; - uint32_t i = 0; - uint32_t loaded_image_count; - - // Add all loaded images - loaded_image_count = _dyld_image_count (); - for (i = 0; i < loaded_image_count; i++) - { - int current_found_sym; - int current_found_dwarf; - int current_descriptor; - intptr_t current_vmslide; - const char *current_name; - - current_vmslide = _dyld_get_image_vmaddr_slide (i); - current_name = _dyld_get_image_name (i); - - if (current_name == NULL || (i != 0 && current_vmslide == 0)) - continue; - - if (!(current_descriptor = - backtrace_open (current_name, error_callback, data, NULL))) - { - continue; - } - - if (macho_add (state, error_callback, data, current_descriptor, - current_name, &macho_fileline_fn, current_vmslide, - ¤t_found_sym, ¤t_found_dwarf)) - { - found_sym = found_sym || current_found_sym; - found_dwarf = found_dwarf || current_found_dwarf; - } - - backtrace_close (current_descriptor, error_callback, data); - } - - if (!state->threaded) - { - if (found_sym) - state->syminfo_fn = macho_syminfo; - else if (state->syminfo_fn == NULL) - state->syminfo_fn = macho_nosyms; - } - else - { - if (found_sym) - backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo); - else - (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, - macho_nosyms); - } - - if (!state->threaded) - { - if (state->fileline_fn == NULL || state->fileline_fn == macho_nodebug) - *fileline_fn = macho_fileline_fn; - } - else - { - fileline current_fn; - - current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - if (current_fn == NULL || current_fn == macho_nodebug) - *fileline_fn = macho_fileline_fn; - } - - return 1; -} - diff --git a/src/libbacktrace/mmap.c b/src/libbacktrace/mmap.c deleted file mode 100644 index 138ef70711a02..0000000000000 --- a/src/libbacktrace/mmap.c +++ /dev/null @@ -1,303 +0,0 @@ -/* mmap.c -- Memory allocation with mmap. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Memory allocation on systems that provide anonymous mmap. This - permits the backtrace functions to be invoked from a signal - handler, assuming that mmap is async-signal safe. */ - -#ifndef MAP_ANONYMOUS -#define MAP_ANONYMOUS MAP_ANON -#endif - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -/* A list of free memory blocks. */ - -struct backtrace_freelist_struct -{ - /* Next on list. */ - struct backtrace_freelist_struct *next; - /* Size of this block, including this structure. */ - size_t size; -}; - -/* Free memory allocated by backtrace_alloc. */ - -static void -backtrace_free_locked (struct backtrace_state *state, void *addr, size_t size) -{ - /* Just leak small blocks. We don't have to be perfect. */ - if (size >= sizeof (struct backtrace_freelist_struct)) - { - struct backtrace_freelist_struct *p; - - p = (struct backtrace_freelist_struct *) addr; - p->next = state->freelist; - p->size = size; - state->freelist = p; - } -} - -/* Allocate memory like malloc. If ERROR_CALLBACK is NULL, don't - report an error. */ - -void * -backtrace_alloc (struct backtrace_state *state, - size_t size, backtrace_error_callback error_callback, - void *data) -{ - void *ret; - int locked; - struct backtrace_freelist_struct **pp; - size_t pagesize; - size_t asksize; - void *page; - - ret = NULL; - - /* If we can acquire the lock, then see if there is space on the - free list. If we can't acquire the lock, drop straight into - using mmap. __sync_lock_test_and_set returns the old state of - the lock, so we have acquired it if it returns 0. */ - - if (!state->threaded) - locked = 1; - else - locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; - - if (locked) - { - for (pp = &state->freelist; *pp != NULL; pp = &(*pp)->next) - { - if ((*pp)->size >= size) - { - struct backtrace_freelist_struct *p; - - p = *pp; - *pp = p->next; - - /* Round for alignment; we assume that no type we care about - is more than 8 bytes. */ - size = (size + 7) & ~ (size_t) 7; - if (size < p->size) - backtrace_free_locked (state, (char *) p + size, - p->size - size); - - ret = (void *) p; - - break; - } - } - - if (state->threaded) - __sync_lock_release (&state->lock_alloc); - } - - if (ret == NULL) - { - /* Allocate a new page. */ - - pagesize = getpagesize (); - asksize = (size + pagesize - 1) & ~ (pagesize - 1); - page = mmap (NULL, asksize, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - if (page == MAP_FAILED) - { - if (error_callback) - error_callback (data, "mmap", errno); - } - else - { - size = (size + 7) & ~ (size_t) 7; - if (size < asksize) - backtrace_free (state, (char *) page + size, asksize - size, - error_callback, data); - - ret = page; - } - } - - return ret; -} - -/* Free memory allocated by backtrace_alloc. */ - -void -backtrace_free (struct backtrace_state *state, void *addr, size_t size, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - int locked; - - /* If we are freeing a large aligned block, just release it back to - the system. This case arises when growing a vector for a large - binary with lots of debug info. Calling munmap here may cause us - to call mmap again if there is also a large shared library; we - just live with that. */ - if (size >= 16 * 4096) - { - size_t pagesize; - - pagesize = getpagesize (); - if (((uintptr_t) addr & (pagesize - 1)) == 0 - && (size & (pagesize - 1)) == 0) - { - /* If munmap fails for some reason, just add the block to - the freelist. */ - if (munmap (addr, size) == 0) - return; - } - } - - /* If we can acquire the lock, add the new space to the free list. - If we can't acquire the lock, just leak the memory. - __sync_lock_test_and_set returns the old state of the lock, so we - have acquired it if it returns 0. */ - - if (!state->threaded) - locked = 1; - else - locked = __sync_lock_test_and_set (&state->lock_alloc, 1) == 0; - - if (locked) - { - backtrace_free_locked (state, addr, size); - - if (state->threaded) - __sync_lock_release (&state->lock_alloc); - } -} - -/* Grow VEC by SIZE bytes. */ - -void * -backtrace_vector_grow (struct backtrace_state *state,size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_vector *vec) -{ - void *ret; - - if (size > vec->alc) - { - size_t pagesize; - size_t alc; - void *base; - - pagesize = getpagesize (); - alc = vec->size + size; - if (vec->size == 0) - alc = 16 * size; - else if (alc < pagesize) - { - alc *= 2; - if (alc > pagesize) - alc = pagesize; - } - else - { - alc *= 2; - alc = (alc + pagesize - 1) & ~ (pagesize - 1); - } - base = backtrace_alloc (state, alc, error_callback, data); - if (base == NULL) - return NULL; - if (vec->base != NULL) - { - memcpy (base, vec->base, vec->size); - backtrace_free (state, vec->base, vec->size + vec->alc, - error_callback, data); - } - vec->base = base; - vec->alc = alc - vec->size; - } - - ret = (char *) vec->base + vec->size; - vec->size += size; - vec->alc -= size; - return ret; -} - -/* Finish the current allocation on VEC. */ - -void * -backtrace_vector_finish ( - struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_vector *vec, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED) -{ - void *ret; - - ret = vec->base; - vec->base = (char *) vec->base + vec->size; - vec->size = 0; - return ret; -} - -/* Release any extra space allocated for VEC. */ - -int -backtrace_vector_release (struct backtrace_state *state, - struct backtrace_vector *vec, - backtrace_error_callback error_callback, - void *data) -{ - size_t size; - size_t alc; - size_t aligned; - - /* Make sure that the block that we free is aligned on an 8-byte - boundary. */ - size = vec->size; - alc = vec->alc; - aligned = (size + 7) & ~ (size_t) 7; - alc -= aligned - size; - - backtrace_free (state, (char *) vec->base + aligned, alc, - error_callback, data); - vec->alc = 0; - return 1; -} diff --git a/src/libbacktrace/mmapio.c b/src/libbacktrace/mmapio.c deleted file mode 100644 index dfdaf6fa52e6e..0000000000000 --- a/src/libbacktrace/mmapio.c +++ /dev/null @@ -1,100 +0,0 @@ -/* mmapio.c -- File views using mmap. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef MAP_FAILED -#define MAP_FAILED ((void *)-1) -#endif - -/* This file implements file views and memory allocation when mmap is - available. */ - -/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */ - -int -backtrace_get_view (struct backtrace_state *state ATTRIBUTE_UNUSED, - int descriptor, off_t offset, size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_view *view) -{ - size_t pagesize; - unsigned int inpage; - off_t pageoff; - void *map; - - pagesize = getpagesize (); - inpage = offset % pagesize; - pageoff = offset - inpage; - - size += inpage; - size = (size + (pagesize - 1)) & ~ (pagesize - 1); - - map = mmap (NULL, size, PROT_READ, MAP_PRIVATE, descriptor, pageoff); - if (map == MAP_FAILED) - { - error_callback (data, "mmap", errno); - return 0; - } - - view->data = (char *) map + inpage; - view->base = map; - view->len = size; - - return 1; -} - -/* Release a view read by backtrace_get_view. */ - -void -backtrace_release_view (struct backtrace_state *state ATTRIBUTE_UNUSED, - struct backtrace_view *view, - backtrace_error_callback error_callback, - void *data) -{ - union { - const void *cv; - void *v; - } const_cast; - - const_cast.cv = view->base; - if (munmap (const_cast.v, view->len) < 0) - error_callback (data, "munmap", errno); -} diff --git a/src/libbacktrace/nounwind.c b/src/libbacktrace/nounwind.c deleted file mode 100644 index 448a2049f1d1b..0000000000000 --- a/src/libbacktrace/nounwind.c +++ /dev/null @@ -1,66 +0,0 @@ -/* backtrace.c -- Entry point for stack backtrace library. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include - -#include "backtrace.h" - -#include "internal.h" - -/* This source file is compiled if the unwind library is not - available. */ - -int -backtrace_full (struct backtrace_state *state ATTRIBUTE_UNUSED, - int skip ATTRIBUTE_UNUSED, - backtrace_full_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, - "no stack trace because unwind library not available", - 0); - return 0; -} - -int -backtrace_simple (struct backtrace_state *state ATTRIBUTE_UNUSED, - int skip ATTRIBUTE_UNUSED, - backtrace_simple_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, - "no stack trace because unwind library not available", - 0); - return 0; -} diff --git a/src/libbacktrace/pecoff.c b/src/libbacktrace/pecoff.c deleted file mode 100644 index 2d6a9877219dc..0000000000000 --- a/src/libbacktrace/pecoff.c +++ /dev/null @@ -1,942 +0,0 @@ -/* pecoff.c -- Get debug data from a PE/COFFF file for backtraces. - Copyright (C) 2015-2016 Free Software Foundation, Inc. - Adapted from elf.c by Tristan Gingold, AdaCore. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Coff file header. */ - -typedef struct { - uint16_t machine; - uint16_t number_of_sections; - uint32_t time_date_stamp; - uint32_t pointer_to_symbol_table; - uint32_t number_of_symbols; - uint16_t size_of_optional_header; - uint16_t characteristics; -} b_coff_file_header; - -/* Coff optional header. */ - -typedef struct { - uint16_t magic; - uint8_t major_linker_version; - uint8_t minor_linker_version; - uint32_t size_of_code; - uint32_t size_of_initialized_data; - uint32_t size_of_uninitialized_data; - uint32_t address_of_entry_point; - uint32_t base_of_code; - union { - struct { - uint32_t base_of_data; - uint32_t image_base; - } pe; - struct { - uint64_t image_base; - } pep; - } u; -} b_coff_optional_header; - -/* Values of magic in optional header. */ - -#define PE_MAGIC 0x10b /* PE32 executable. */ -#define PEP_MAGIC 0x20b /* PE32+ executable (for 64bit targets). */ - -/* Coff section header. */ - -typedef struct { - char name[8]; - uint32_t virtual_size; - uint32_t virtual_address; - uint32_t size_of_raw_data; - uint32_t pointer_to_raw_data; - uint32_t pointer_to_relocations; - uint32_t pointer_to_line_numbers; - uint16_t number_of_relocations; - uint16_t number_of_line_numbers; - uint32_t characteristics; -} b_coff_section_header; - -/* Coff symbol name. */ - -typedef union { - char short_name[8]; - struct { - unsigned char zeroes[4]; - unsigned char off[4]; - } long_name; -} b_coff_name; - -/* Coff symbol (external representation which is unaligned). */ - -typedef struct { - b_coff_name name; - unsigned char value[4]; - unsigned char section_number[2]; - unsigned char type[2]; - unsigned char storage_class; - unsigned char number_of_aux_symbols; -} b_coff_external_symbol; - -/* Symbol types. */ - -#define N_TBSHFT 4 /* Shift for the derived type. */ -#define IMAGE_SYM_DTYPE_FUNCTION 2 /* Function derived type. */ - -/* Size of a coff symbol. */ - -#define SYM_SZ 18 - -/* Coff symbol, internal representation (aligned). */ - -typedef struct { - const char *name; - uint32_t value; - int16_t sec; - uint16_t type; - uint16_t sc; -} b_coff_internal_symbol; - -/* An index of sections we care about. */ - -enum debug_section -{ - DEBUG_INFO, - DEBUG_LINE, - DEBUG_ABBREV, - DEBUG_RANGES, - DEBUG_STR, - DEBUG_MAX -}; - -/* Names of sections, indexed by enum debug_section. */ - -static const char * const debug_section_names[DEBUG_MAX] = -{ - ".debug_info", - ".debug_line", - ".debug_abbrev", - ".debug_ranges", - ".debug_str" -}; - -/* Information we gather for the sections we care about. */ - -struct debug_section_info -{ - /* Section file offset. */ - off_t offset; - /* Section size. */ - size_t size; - /* Section contents, after read from file. */ - const unsigned char *data; -}; - -/* Information we keep for an coff symbol. */ - -struct coff_symbol -{ - /* The name of the symbol. */ - const char *name; - /* The address of the symbol. */ - uintptr_t address; -}; - -/* Information to pass to coff_syminfo. */ - -struct coff_syminfo_data -{ - /* Symbols for the next module. */ - struct coff_syminfo_data *next; - /* The COFF symbols, sorted by address. */ - struct coff_symbol *symbols; - /* The number of symbols. */ - size_t count; -}; - -/* A dummy callback function used when we can't find any debug info. */ - -static int -coff_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc ATTRIBUTE_UNUSED, - backtrace_full_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no debug info in PE/COFF executable", -1); - return 0; -} - -/* A dummy callback function used when we can't find a symbol - table. */ - -static void -coff_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t addr ATTRIBUTE_UNUSED, - backtrace_syminfo_callback callback ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback, void *data) -{ - error_callback (data, "no symbol table in PE/COFF executable", -1); -} - -/* Read a potentially unaligned 4 byte word at P, using native endianness. */ - -static uint32_t -coff_read4 (const unsigned char *p) -{ - uint32_t res; - - memcpy (&res, p, 4); - return res; -} - -/* Read a potentially unaligned 2 byte word at P, using native endianness. - All 2 byte word in symbols are always aligned, but for coherency all - fields are declared as char arrays. */ - -static uint16_t -coff_read2 (const unsigned char *p) -{ - uint16_t res; - - memcpy (&res, p, sizeof (res)); - return res; -} - -/* Return the length (without the trailing 0) of a COFF short name. */ - -static size_t -coff_short_name_len (const char *name) -{ - int i; - - for (i = 0; i < 8; i++) - if (name[i] == 0) - return i; - return 8; -} - -/* Return true iff COFF short name CNAME is the same as NAME (a NUL-terminated - string). */ - -static int -coff_short_name_eq (const char *name, const char *cname) -{ - int i; - - for (i = 0; i < 8; i++) - { - if (name[i] != cname[i]) - return 0; - if (name[i] == 0) - return 1; - } - return name[8] == 0; -} - -/* Return true iff NAME is the same as string at offset OFF. */ - -static int -coff_long_name_eq (const char *name, unsigned int off, - struct backtrace_view *str_view) -{ - if (off >= str_view->len) - return 0; - return strcmp (name, (const char *)str_view->data + off) == 0; -} - -/* Compare struct coff_symbol for qsort. */ - -static int -coff_symbol_compare (const void *v1, const void *v2) -{ - const struct coff_symbol *e1 = (const struct coff_symbol *) v1; - const struct coff_symbol *e2 = (const struct coff_symbol *) v2; - - if (e1->address < e2->address) - return -1; - else if (e1->address > e2->address) - return 1; - else - return 0; -} - -/* Convert SYM to internal (and aligned) format ISYM, using string table - from STRTAB and STRTAB_SIZE, and number of sections SECTS_NUM. - Return -1 in case of error (invalid section number or string index). */ - -static int -coff_expand_symbol (b_coff_internal_symbol *isym, - const b_coff_external_symbol *sym, - uint16_t sects_num, - const unsigned char *strtab, size_t strtab_size) -{ - isym->type = coff_read2 (sym->type); - isym->sec = coff_read2 (sym->section_number); - isym->sc = sym->storage_class; - - if (isym->sec > 0 && (uint16_t) isym->sec > sects_num) - return -1; - if (sym->name.short_name[0] != 0) - isym->name = sym->name.short_name; - else - { - uint32_t off = coff_read4 (sym->name.long_name.off); - - if (off >= strtab_size) - return -1; - isym->name = (const char *) strtab + off; - } - return 0; -} - -/* Return true iff SYM is a defined symbol for a function. Data symbols - aren't considered because they aren't easily identified (same type as - section names, presence of symbols defined by the linker script). */ - -static int -coff_is_function_symbol (const b_coff_internal_symbol *isym) -{ - return (isym->type >> N_TBSHFT) == IMAGE_SYM_DTYPE_FUNCTION - && isym->sec > 0; -} - -/* Initialize the symbol table info for coff_syminfo. */ - -static int -coff_initialize_syminfo (struct backtrace_state *state, - uintptr_t base_address, - const b_coff_section_header *sects, size_t sects_num, - const b_coff_external_symbol *syms, size_t syms_size, - const unsigned char *strtab, size_t strtab_size, - backtrace_error_callback error_callback, - void *data, struct coff_syminfo_data *sdata) -{ - size_t syms_count; - char *coff_symstr; - size_t coff_symstr_len; - size_t coff_symbol_count; - size_t coff_symbol_size; - struct coff_symbol *coff_symbols; - struct coff_symbol *coff_sym; - char *coff_str; - size_t i; - - syms_count = syms_size / SYM_SZ; - - /* We only care about function symbols. Count them. Also count size of - strings for in-symbol names. */ - coff_symbol_count = 0; - coff_symstr_len = 0; - for (i = 0; i < syms_count; ++i) - { - const b_coff_external_symbol *asym = &syms[i]; - b_coff_internal_symbol isym; - - if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size) < 0) - { - error_callback (data, "invalid section or offset in coff symbol", 0); - return 0; - } - if (coff_is_function_symbol (&isym)) - { - ++coff_symbol_count; - if (asym->name.short_name[0] != 0) - coff_symstr_len += coff_short_name_len (asym->name.short_name) + 1; - } - - i += asym->number_of_aux_symbols; - } - - coff_symbol_size = (coff_symbol_count + 1) * sizeof (struct coff_symbol); - coff_symbols = ((struct coff_symbol *) - backtrace_alloc (state, coff_symbol_size, error_callback, - data)); - if (coff_symbols == NULL) - return 0; - - /* Allocate memory for symbols strings. */ - if (coff_symstr_len > 0) - { - coff_symstr = ((char *) - backtrace_alloc (state, coff_symstr_len, error_callback, - data)); - if (coff_symstr == NULL) - { - backtrace_free (state, coff_symbols, coff_symbol_size, - error_callback, data); - return 0; - } - } - else - coff_symstr = NULL; - - /* Copy symbols. */ - coff_sym = coff_symbols; - coff_str = coff_symstr; - for (i = 0; i < syms_count; ++i) - { - const b_coff_external_symbol *asym = &syms[i]; - b_coff_internal_symbol isym; - - if (coff_expand_symbol (&isym, asym, sects_num, strtab, strtab_size)) - { - /* Should not fail, as it was already tested in the previous - loop. */ - abort (); - } - if (coff_is_function_symbol (&isym)) - { - const char *name; - int16_t secnum; - - if (asym->name.short_name[0] != 0) - { - size_t len = coff_short_name_len (isym.name); - name = coff_str; - memcpy (coff_str, isym.name, len); - coff_str[len] = 0; - coff_str += len + 1; - } - else - name = isym.name; - - /* Strip leading '_'. */ - if (name[0] == '_') - name++; - - /* Symbol value is section relative, so we need to read the address - of its section. */ - secnum = coff_read2 (asym->section_number); - - coff_sym->name = name; - coff_sym->address = (coff_read4 (asym->value) - + sects[secnum - 1].virtual_address - + base_address); - coff_sym++; - } - - i += asym->number_of_aux_symbols; - } - - /* End of symbols marker. */ - coff_sym->name = NULL; - coff_sym->address = -1; - - backtrace_qsort (coff_symbols, coff_symbol_count, - sizeof (struct coff_symbol), coff_symbol_compare); - - sdata->next = NULL; - sdata->symbols = coff_symbols; - sdata->count = coff_symbol_count; - - return 1; -} - -/* Add EDATA to the list in STATE. */ - -static void -coff_add_syminfo_data (struct backtrace_state *state, - struct coff_syminfo_data *sdata) -{ - if (!state->threaded) - { - struct coff_syminfo_data **pp; - - for (pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; - *pp != NULL; - pp = &(*pp)->next) - ; - *pp = sdata; - } - else - { - while (1) - { - struct coff_syminfo_data **pp; - - pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; - - while (1) - { - struct coff_syminfo_data *p; - - p = backtrace_atomic_load_pointer (pp); - - if (p == NULL) - break; - - pp = &p->next; - } - - if (__sync_bool_compare_and_swap (pp, NULL, sdata)) - break; - } - } -} - -/* Compare an ADDR against an elf_symbol for bsearch. We allocate one - extra entry in the array so that this can look safely at the next - entry. */ - -static int -coff_symbol_search (const void *vkey, const void *ventry) -{ - const uintptr_t *key = (const uintptr_t *) vkey; - const struct coff_symbol *entry = (const struct coff_symbol *) ventry; - uintptr_t addr; - - addr = *key; - if (addr < entry->address) - return -1; - else if (addr >= entry[1].address) - return 1; - else - return 0; -} - -/* Return the symbol name and value for an ADDR. */ - -static void -coff_syminfo (struct backtrace_state *state, uintptr_t addr, - backtrace_syminfo_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data) -{ - struct coff_syminfo_data *sdata; - struct coff_symbol *sym = NULL; - - if (!state->threaded) - { - for (sdata = (struct coff_syminfo_data *) state->syminfo_data; - sdata != NULL; - sdata = sdata->next) - { - sym = ((struct coff_symbol *) - bsearch (&addr, sdata->symbols, sdata->count, - sizeof (struct coff_symbol), coff_symbol_search)); - if (sym != NULL) - break; - } - } - else - { - struct coff_syminfo_data **pp; - - pp = (struct coff_syminfo_data **) (void *) &state->syminfo_data; - while (1) - { - sdata = backtrace_atomic_load_pointer (pp); - if (sdata == NULL) - break; - - sym = ((struct coff_symbol *) - bsearch (&addr, sdata->symbols, sdata->count, - sizeof (struct coff_symbol), coff_symbol_search)); - if (sym != NULL) - break; - - pp = &sdata->next; - } - } - - if (sym == NULL) - callback (data, addr, NULL, 0, 0); - else - callback (data, addr, sym->name, sym->address, 0); -} - -/* Add the backtrace data for one PE/COFF file. Returns 1 on success, - 0 on failure (in both cases descriptor is closed). */ - -static int -coff_add (struct backtrace_state *state, int descriptor, - backtrace_error_callback error_callback, void *data, - fileline *fileline_fn, int *found_sym, int *found_dwarf) -{ - struct backtrace_view fhdr_view; - off_t fhdr_off; - int magic_ok; - b_coff_file_header fhdr; - off_t opt_sects_off; - size_t opt_sects_size; - unsigned int sects_num; - struct backtrace_view sects_view; - int sects_view_valid; - const b_coff_optional_header *opt_hdr; - const b_coff_section_header *sects; - struct backtrace_view str_view; - int str_view_valid; - // NOTE: upstream this is a `size_t` but this was fixed in Rust commit - // 55e2b7e1b, see #33729 for more info. If you see this in a diff - // against the upstream libbacktrace, that's what's going on. - uint32_t str_size; - off_t str_off; - // NOTE: upstream doesn't have `{0}`, this is a fix for Rust issue #39468. - // If syms_view is not initialized, then `free(syms_view.base)` may segfault later. - struct backtrace_view syms_view = {0}; - off_t syms_off; - size_t syms_size; - int syms_view_valid; - unsigned int syms_num; - unsigned int i; - struct debug_section_info sections[DEBUG_MAX]; - off_t min_offset; - off_t max_offset; - struct backtrace_view debug_view; - int debug_view_valid; - uintptr_t image_base; - - *found_sym = 0; - *found_dwarf = 0; - - sects_view_valid = 0; - syms_view_valid = 0; - str_view_valid = 0; - debug_view_valid = 0; - - /* Map the MS-DOS stub (if any) and extract file header offset. */ - if (!backtrace_get_view (state, descriptor, 0, 0x40, error_callback, - data, &fhdr_view)) - goto fail; - - { - const char *vptr = (const char *)fhdr_view.data; - - if (vptr[0] == 'M' && vptr[1] == 'Z') - memcpy (&fhdr_off, vptr + 0x3c, 4); - else - fhdr_off = 0; - } - - backtrace_release_view (state, &fhdr_view, error_callback, data); - - /* Map the coff file header. */ - if (!backtrace_get_view (state, descriptor, fhdr_off, - sizeof (b_coff_file_header) + 4, - error_callback, data, &fhdr_view)) - goto fail; - - if (fhdr_off != 0) - { - const char *magic = (const char *) fhdr_view.data; - magic_ok = memcmp (magic, "PE\0", 4) == 0; - fhdr_off += 4; - - memcpy (&fhdr, fhdr_view.data + 4, sizeof fhdr); - } - else - { - memcpy (&fhdr, fhdr_view.data, sizeof fhdr); - /* TODO: test fhdr.machine for coff but non-PE platforms. */ - magic_ok = 0; - } - backtrace_release_view (state, &fhdr_view, error_callback, data); - - if (!magic_ok) - { - error_callback (data, "executable file is not COFF", 0); - goto fail; - } - - sects_num = fhdr.number_of_sections; - syms_num = fhdr.number_of_symbols; - - opt_sects_off = fhdr_off + sizeof (fhdr); - opt_sects_size = (fhdr.size_of_optional_header - + sects_num * sizeof (b_coff_section_header)); - - /* To translate PC to file/line when using DWARF, we need to find - the .debug_info and .debug_line sections. */ - - /* Read the optional header and the section headers. */ - - if (!backtrace_get_view (state, descriptor, opt_sects_off, opt_sects_size, - error_callback, data, §s_view)) - goto fail; - sects_view_valid = 1; - opt_hdr = (const b_coff_optional_header *) sects_view.data; - sects = (const b_coff_section_header *) - (sects_view.data + fhdr.size_of_optional_header); - - if (fhdr.size_of_optional_header > sizeof (*opt_hdr)) - { - if (opt_hdr->magic == PE_MAGIC) - image_base = opt_hdr->u.pe.image_base; - else if (opt_hdr->magic == PEP_MAGIC) - image_base = opt_hdr->u.pep.image_base; - else - { - error_callback (data, "bad magic in PE optional header", 0); - goto fail; - } - } - else - image_base = 0; - - /* Read the symbol table and the string table. */ - - if (fhdr.pointer_to_symbol_table == 0) - { - /* No symbol table, no string table. */ - str_off = 0; - str_size = 0; - syms_num = 0; - syms_size = 0; - } - else - { - /* Symbol table is followed by the string table. The string table - starts with its length (on 4 bytes). - Map the symbol table and the length of the string table. */ - syms_off = fhdr.pointer_to_symbol_table; - syms_size = syms_num * SYM_SZ; - - if (!backtrace_get_view (state, descriptor, syms_off, syms_size + 4, - error_callback, data, &syms_view)) - goto fail; - syms_view_valid = 1; - - memcpy (&str_size, syms_view.data + syms_size, 4); - - str_off = syms_off + syms_size; - - if (str_size > 4) - { - /* Map string table (including the length word). */ - - if (!backtrace_get_view (state, descriptor, str_off, str_size, - error_callback, data, &str_view)) - goto fail; - str_view_valid = 1; - } - } - - memset (sections, 0, sizeof sections); - - /* Look for the symbol table. */ - for (i = 0; i < sects_num; ++i) - { - const b_coff_section_header *s = sects + i; - unsigned int str_off; - int j; - - if (s->name[0] == '/') - { - /* Extended section name. */ - str_off = atoi (s->name + 1); - } - else - str_off = 0; - - for (j = 0; j < (int) DEBUG_MAX; ++j) - { - const char *dbg_name = debug_section_names[j]; - int match; - - if (str_off != 0) - match = coff_long_name_eq (dbg_name, str_off, &str_view); - else - match = coff_short_name_eq (dbg_name, s->name); - if (match) - { - sections[j].offset = s->pointer_to_raw_data; - sections[j].size = s->virtual_size <= s->size_of_raw_data ? - s->virtual_size : s->size_of_raw_data; - break; - } - } - } - - if (syms_num != 0) - { - struct coff_syminfo_data *sdata; - - sdata = ((struct coff_syminfo_data *) - backtrace_alloc (state, sizeof *sdata, error_callback, data)); - if (sdata == NULL) - goto fail; - - if (!coff_initialize_syminfo (state, image_base, - sects, sects_num, - syms_view.data, syms_size, - str_view.data, str_size, - error_callback, data, sdata)) - { - backtrace_free (state, sdata, sizeof *sdata, error_callback, data); - goto fail; - } - - *found_sym = 1; - - coff_add_syminfo_data (state, sdata); - } - - backtrace_release_view (state, §s_view, error_callback, data); - sects_view_valid = 0; - backtrace_release_view (state, &syms_view, error_callback, data); - syms_view_valid = 0; - - /* Read all the debug sections in a single view, since they are - probably adjacent in the file. We never release this view. */ - - min_offset = 0; - max_offset = 0; - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - off_t end; - - if (sections[i].size == 0) - continue; - if (min_offset == 0 || sections[i].offset < min_offset) - min_offset = sections[i].offset; - end = sections[i].offset + sections[i].size; - if (end > max_offset) - max_offset = end; - } - if (min_offset == 0 || max_offset == 0) - { - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - *fileline_fn = coff_nodebug; - return 1; - } - - if (!backtrace_get_view (state, descriptor, min_offset, - max_offset - min_offset, - error_callback, data, &debug_view)) - goto fail; - debug_view_valid = 1; - - /* We've read all we need from the executable. */ - if (!backtrace_close (descriptor, error_callback, data)) - goto fail; - descriptor = -1; - - for (i = 0; i < (int) DEBUG_MAX; ++i) - { - if (sections[i].size == 0) - sections[i].data = NULL; - else - sections[i].data = ((const unsigned char *) debug_view.data - + (sections[i].offset - min_offset)); - } - - if (!backtrace_dwarf_add (state, /* base_address */ 0, - sections[DEBUG_INFO].data, - sections[DEBUG_INFO].size, - sections[DEBUG_LINE].data, - sections[DEBUG_LINE].size, - sections[DEBUG_ABBREV].data, - sections[DEBUG_ABBREV].size, - sections[DEBUG_RANGES].data, - sections[DEBUG_RANGES].size, - sections[DEBUG_STR].data, - sections[DEBUG_STR].size, - 0, /* FIXME */ - error_callback, data, fileline_fn)) - goto fail; - - *found_dwarf = 1; - - return 1; - - fail: - if (sects_view_valid) - backtrace_release_view (state, §s_view, error_callback, data); - if (str_view_valid) - backtrace_release_view (state, &str_view, error_callback, data); - if (syms_view_valid) - backtrace_release_view (state, &syms_view, error_callback, data); - if (debug_view_valid) - backtrace_release_view (state, &debug_view, error_callback, data); - if (descriptor != -1) - backtrace_close (descriptor, error_callback, data); - return 0; -} - -/* Initialize the backtrace data we need from an ELF executable. At - the ELF level, all we need to do is find the debug info - sections. */ - -int -backtrace_initialize (struct backtrace_state *state, int descriptor, - backtrace_error_callback error_callback, - void *data, fileline *fileline_fn) -{ - int ret; - int found_sym; - int found_dwarf; - fileline coff_fileline_fn; - - ret = coff_add (state, descriptor, error_callback, data, - &coff_fileline_fn, &found_sym, &found_dwarf); - if (!ret) - return 0; - - if (!state->threaded) - { - if (found_sym) - state->syminfo_fn = coff_syminfo; - else if (state->syminfo_fn == NULL) - state->syminfo_fn = coff_nosyms; - } - else - { - if (found_sym) - backtrace_atomic_store_pointer (&state->syminfo_fn, coff_syminfo); - else - __sync_bool_compare_and_swap (&state->syminfo_fn, NULL, coff_nosyms); - } - - if (!state->threaded) - { - if (state->fileline_fn == NULL || state->fileline_fn == coff_nodebug) - *fileline_fn = coff_fileline_fn; - } - else - { - fileline current_fn; - - current_fn = backtrace_atomic_load_pointer (&state->fileline_fn); - if (current_fn == NULL || current_fn == coff_nodebug) - *fileline_fn = coff_fileline_fn; - } - - return 1; -} diff --git a/src/libbacktrace/posix.c b/src/libbacktrace/posix.c deleted file mode 100644 index 09f5e95a6e42d..0000000000000 --- a/src/libbacktrace/posix.c +++ /dev/null @@ -1,100 +0,0 @@ -/* posix.c -- POSIX file I/O routines for the backtrace library. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -#ifndef O_BINARY -#define O_BINARY 0 -#endif - -#ifndef O_CLOEXEC -#define O_CLOEXEC 0 -#endif - -#ifndef FD_CLOEXEC -#define FD_CLOEXEC 1 -#endif - -/* Open a file for reading. */ - -int -backtrace_open (const char *filename, backtrace_error_callback error_callback, - void *data, int *does_not_exist) -{ - int descriptor; - - if (does_not_exist != NULL) - *does_not_exist = 0; - - descriptor = open (filename, (int) (O_RDONLY | O_BINARY | O_CLOEXEC)); - if (descriptor < 0) - { - if (does_not_exist != NULL && errno == ENOENT) - *does_not_exist = 1; - else - error_callback (data, filename, errno); - return -1; - } - -#ifdef HAVE_FCNTL - /* Set FD_CLOEXEC just in case the kernel does not support - O_CLOEXEC. It doesn't matter if this fails for some reason. - FIXME: At some point it should be safe to only do this if - O_CLOEXEC == 0. */ - fcntl (descriptor, F_SETFD, FD_CLOEXEC); -#endif - - return descriptor; -} - -/* Close DESCRIPTOR. */ - -int -backtrace_close (int descriptor, backtrace_error_callback error_callback, - void *data) -{ - if (close (descriptor) < 0) - { - error_callback (data, "close", errno); - return 0; - } - return 1; -} diff --git a/src/libbacktrace/print.c b/src/libbacktrace/print.c deleted file mode 100644 index 74c8fcbee5a1f..0000000000000 --- a/src/libbacktrace/print.c +++ /dev/null @@ -1,92 +0,0 @@ -/* print.c -- Print the current backtrace. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Passed to callbacks. */ - -struct print_data -{ - struct backtrace_state *state; - FILE *f; -}; - -/* Print one level of a backtrace. */ - -static int -print_callback (void *data, uintptr_t pc, const char *filename, int lineno, - const char *function) -{ - struct print_data *pdata = (struct print_data *) data; - - fprintf (pdata->f, "0x%lx %s\n\t%s:%d\n", - (unsigned long) pc, - function == NULL ? "???" : function, - filename == NULL ? "???" : filename, - lineno); - return 0; -} - -/* Print errors to stderr. */ - -static void -error_callback (void *data, const char *msg, int errnum) -{ - struct print_data *pdata = (struct print_data *) data; - - if (pdata->state->filename != NULL) - fprintf (stderr, "%s: ", pdata->state->filename); - fprintf (stderr, "libbacktrace: %s", msg); - if (errnum > 0) - fprintf (stderr, ": %s", strerror (errnum)); - fputc ('\n', stderr); -} - -/* Print a backtrace. */ - -void -backtrace_print (struct backtrace_state *state, int skip, FILE *f) -{ - struct print_data data; - - data.state = state; - data.f = f; - backtrace_full (state, skip + 1, print_callback, error_callback, - (void *) &data); -} diff --git a/src/libbacktrace/read.c b/src/libbacktrace/read.c deleted file mode 100644 index 7f0317c3a8ce9..0000000000000 --- a/src/libbacktrace/read.c +++ /dev/null @@ -1,96 +0,0 @@ -/* read.c -- File views without mmap. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* This file implements file views when mmap is not available. */ - -/* Create a view of SIZE bytes from DESCRIPTOR at OFFSET. */ - -int -backtrace_get_view (struct backtrace_state *state, int descriptor, - off_t offset, size_t size, - backtrace_error_callback error_callback, - void *data, struct backtrace_view *view) -{ - ssize_t got; - - if (lseek (descriptor, offset, SEEK_SET) < 0) - { - error_callback (data, "lseek", errno); - return 0; - } - - view->base = backtrace_alloc (state, size, error_callback, data); - if (view->base == NULL) - return 0; - view->data = view->base; - view->len = size; - - got = read (descriptor, view->base, size); - if (got < 0) - { - error_callback (data, "read", errno); - free (view->base); - return 0; - } - - if ((size_t) got < size) - { - error_callback (data, "file too short", 0); - free (view->base); - return 0; - } - - return 1; -} - -/* Release a view read by backtrace_get_view. */ - -void -backtrace_release_view (struct backtrace_state *state, - struct backtrace_view *view, - backtrace_error_callback error_callback, - void *data) -{ - backtrace_free (state, view->base, view->len, error_callback, data); - view->data = NULL; - view->base = NULL; -} diff --git a/src/libbacktrace/simple.c b/src/libbacktrace/simple.c deleted file mode 100644 index 018773a7e5dbd..0000000000000 --- a/src/libbacktrace/simple.c +++ /dev/null @@ -1,108 +0,0 @@ -/* simple.c -- The backtrace_simple function. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include "unwind.h" -#include "backtrace.h" - -/* The simple_backtrace routine. */ - -/* Data passed through _Unwind_Backtrace. */ - -struct backtrace_simple_data -{ - /* Number of frames to skip. */ - int skip; - /* Library state. */ - struct backtrace_state *state; - /* Callback routine. */ - backtrace_simple_callback callback; - /* Error callback routine. */ - backtrace_error_callback error_callback; - /* Data to pass to callback routine. */ - void *data; - /* Value to return from backtrace. */ - int ret; -}; - -/* Unwind library callback routine. This is passd to - _Unwind_Backtrace. */ - -static _Unwind_Reason_Code -simple_unwind (struct _Unwind_Context *context, void *vdata) -{ - struct backtrace_simple_data *bdata = (struct backtrace_simple_data *) vdata; - uintptr_t pc; - int ip_before_insn = 0; - -#ifdef HAVE_GETIPINFO - pc = _Unwind_GetIPInfo (context, &ip_before_insn); -#else - pc = _Unwind_GetIP (context); -#endif - - if (bdata->skip > 0) - { - --bdata->skip; - return _URC_NO_REASON; - } - - if (!ip_before_insn) - --pc; - - bdata->ret = bdata->callback (bdata->data, pc); - - if (bdata->ret != 0) - return _URC_END_OF_STACK; - - return _URC_NO_REASON; -} - -/* Get a simple stack backtrace. */ - -int -backtrace_simple (struct backtrace_state *state, int skip, - backtrace_simple_callback callback, - backtrace_error_callback error_callback, void *data) -{ - struct backtrace_simple_data bdata; - - bdata.skip = skip + 1; - bdata.state = state; - bdata.callback = callback; - bdata.error_callback = error_callback; - bdata.data = data; - bdata.ret = 0; - _Unwind_Backtrace (simple_unwind, &bdata); - return bdata.ret; -} diff --git a/src/libbacktrace/sort.c b/src/libbacktrace/sort.c deleted file mode 100644 index 68a7df65a47f6..0000000000000 --- a/src/libbacktrace/sort.c +++ /dev/null @@ -1,108 +0,0 @@ -/* sort.c -- Sort without allocating memory - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* The GNU glibc version of qsort allocates memory, which we must not - do if we are invoked by a signal handler. So provide our own - sort. */ - -static void -swap (char *a, char *b, size_t size) -{ - size_t i; - - for (i = 0; i < size; i++, a++, b++) - { - char t; - - t = *a; - *a = *b; - *b = t; - } -} - -void -backtrace_qsort (void *basearg, size_t count, size_t size, - int (*compar) (const void *, const void *)) -{ - char *base = (char *) basearg; - size_t i; - size_t mid; - - tail_recurse: - if (count < 2) - return; - - /* The symbol table and DWARF tables, which is all we use this - routine for, tend to be roughly sorted. Pick the middle element - in the array as our pivot point, so that we are more likely to - cut the array in half for each recursion step. */ - swap (base, base + (count / 2) * size, size); - - mid = 0; - for (i = 1; i < count; i++) - { - if ((*compar) (base, base + i * size) > 0) - { - ++mid; - if (i != mid) - swap (base + mid * size, base + i * size, size); - } - } - - if (mid > 0) - swap (base, base + mid * size, size); - - /* Recurse with the smaller array, loop with the larger one. That - ensures that our maximum stack depth is log count. */ - if (2 * mid < count) - { - backtrace_qsort (base, mid, size, compar); - base += (mid + 1) * size; - count -= mid + 1; - goto tail_recurse; - } - else - { - backtrace_qsort (base + (mid + 1) * size, count - (mid + 1), - size, compar); - count = mid; - goto tail_recurse; - } -} diff --git a/src/libbacktrace/state.c b/src/libbacktrace/state.c deleted file mode 100644 index 93420d9c61b19..0000000000000 --- a/src/libbacktrace/state.c +++ /dev/null @@ -1,72 +0,0 @@ -/* state.c -- Create the backtrace state. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include - -#include "backtrace.h" -#include "backtrace-supported.h" -#include "internal.h" - -/* Create the backtrace state. This will then be passed to all the - other routines. */ - -struct backtrace_state * -backtrace_create_state (const char *filename, int threaded, - backtrace_error_callback error_callback, - void *data) -{ - struct backtrace_state init_state; - struct backtrace_state *state; - -#ifndef HAVE_SYNC_FUNCTIONS - if (threaded) - { - error_callback (data, "backtrace library does not support threads", 0); - return NULL; - } -#endif - - memset (&init_state, 0, sizeof init_state); - init_state.filename = filename; - init_state.threaded = threaded; - - state = ((struct backtrace_state *) - backtrace_alloc (&init_state, sizeof *state, error_callback, data)); - if (state == NULL) - return NULL; - *state = init_state; - - return state; -} diff --git a/src/libbacktrace/stest.c b/src/libbacktrace/stest.c deleted file mode 100644 index 55ec31d10bc81..0000000000000 --- a/src/libbacktrace/stest.c +++ /dev/null @@ -1,137 +0,0 @@ -/* stest.c -- Test for libbacktrace internal sort function - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include -#include -#include -#include - -#include "backtrace.h" -#include "internal.h" - -/* Test the local qsort implementation. */ - -#define MAX 10 - -struct test -{ - size_t count; - int input[MAX]; - int output[MAX]; -}; - -static struct test tests[] = - { - { - 10, - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } - }, - { - 9, - { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, - { 1, 2, 3, 4, 5, 6, 7, 8, 9 } - }, - { - 10, - { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 }, - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, - }, - { - 9, - { 9, 8, 7, 6, 5, 4, 3, 2, 1 }, - { 1, 2, 3, 4, 5, 6, 7, 8, 9 }, - }, - { - 10, - { 2, 4, 6, 8, 10, 1, 3, 5, 7, 9 }, - { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, - }, - { - 5, - { 4, 5, 3, 1, 2 }, - { 1, 2, 3, 4, 5 }, - }, - { - 5, - { 1, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 1 }, - }, - { - 5, - { 1, 1, 2, 1, 1 }, - { 1, 1, 1, 1, 2 }, - }, - { - 5, - { 2, 1, 1, 1, 1 }, - { 1, 1, 1, 1, 2 }, - }, - }; - -static int -compare (const void *a, const void *b) -{ - const int *ai = (const int *) a; - const int *bi = (const int *) b; - - return *ai - *bi; -} - -int -main (int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED) -{ - int failures; - size_t i; - int a[MAX]; - - failures = 0; - for (i = 0; i < sizeof tests / sizeof tests[0]; i++) - { - memcpy (a, tests[i].input, tests[i].count * sizeof (int)); - backtrace_qsort (a, tests[i].count, sizeof (int), compare); - if (memcmp (a, tests[i].output, tests[i].count * sizeof (int)) != 0) - { - size_t j; - - fprintf (stderr, "test %d failed:", (int) i); - for (j = 0; j < tests[i].count; j++) - fprintf (stderr, " %d", a[j]); - fprintf (stderr, "\n"); - ++failures; - } - } - - exit (failures > 0 ? EXIT_FAILURE : EXIT_SUCCESS); -} diff --git a/src/libbacktrace/unknown.c b/src/libbacktrace/unknown.c deleted file mode 100644 index 8d06c31549f70..0000000000000 --- a/src/libbacktrace/unknown.c +++ /dev/null @@ -1,64 +0,0 @@ -/* unknown.c -- used when backtrace configury does not know file format. - Copyright (C) 2012-2016 Free Software Foundation, Inc. - Written by Ian Lance Taylor, Google. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - (1) Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - (2) Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - (3) The name of the author may not be used to - endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. */ - -#include "config.h" - -#include - -#include "backtrace.h" -#include "internal.h" - -/* A trivial routine that always fails to find fileline data. */ - -static int -unknown_fileline (struct backtrace_state *state ATTRIBUTE_UNUSED, - uintptr_t pc, backtrace_full_callback callback, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data) - -{ - return callback (data, pc, NULL, 0, NULL); -} - -/* Initialize the backtrace data when we don't know how to read the - debug info. */ - -int -backtrace_initialize (struct backtrace_state *state ATTRIBUTE_UNUSED, - int descriptor ATTRIBUTE_UNUSED, - backtrace_error_callback error_callback ATTRIBUTE_UNUSED, - void *data ATTRIBUTE_UNUSED, fileline *fileline_fn) -{ - state->fileline_data = NULL; - *fileline_fn = unknown_fileline; - return 1; -} diff --git a/src/libcompiler_builtins b/src/libcompiler_builtins index 2a2f6d96c8dc5..52a6a4d7087d1 160000 --- a/src/libcompiler_builtins +++ b/src/libcompiler_builtins @@ -1 +1 @@ -Subproject commit 2a2f6d96c8dc578d2474742f14c9bab0b36b0408 +Subproject commit 52a6a4d7087d14a35d44a11c39c77fa79d71378d diff --git a/src/libcore/Cargo.toml b/src/libcore/Cargo.toml index 24529f7a9d8d4..321ed892ea9a9 100644 --- a/src/libcore/Cargo.toml +++ b/src/libcore/Cargo.toml @@ -2,6 +2,8 @@ authors = ["The Rust Project Developers"] name = "core" version = "0.0.0" +autotests = false +autobenches = false [lib] name = "core" diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 674c4fb57c7f0..b6ac248b79f86 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -8,43 +8,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![unstable(feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked \ - slightly, especially to possibly take into account the \ - types being stored to make room for a future \ - tracing garbage collector", - issue = "32838")] +//! Memory allocation APIs + +#![stable(feature = "alloc_module", since = "1.28.0")] use cmp; use fmt; use mem; use usize; use ptr::{self, NonNull}; +use num::NonZeroUsize; -extern { - /// An opaque, unsized type. Used for pointers to allocated memory. - /// - /// This type can only be used behind a pointer like `*mut Opaque` or `ptr::NonNull`. - /// Such pointers are similar to C’s `void*` type. - pub type Opaque; -} - -impl Opaque { - /// Similar to `std::ptr::null`, which requires `T: Sized`. - pub fn null() -> *const Self { - 0 as _ - } - - /// Similar to `std::ptr::null_mut`, which requires `T: Sized`. - pub fn null_mut() -> *mut Self { - 0 as _ - } -} +#[unstable(feature = "alloc_internals", issue = "0")] +#[cfg(stage0)] +pub type Opaque = u8; /// Represents the combination of a starting address and /// a total capacity of the returned block. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Debug)] -pub struct Excess(pub NonNull, pub usize); +pub struct Excess(pub NonNull, pub usize); fn size_align() -> (usize, usize) { (mem::size_of::(), mem::align_of::()) @@ -63,10 +46,12 @@ fn size_align() -> (usize, usize) { /// requests have positive size. A caller to the `Alloc::alloc` /// method must either ensure that conditions like this are met, or /// use specific allocators with looser requirements.) +#[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(not(stage0), lang = "alloc_layout")] pub struct Layout { // size of the requested block of memory, measured in bytes. - size: usize, + size_: usize, // alignment of the requested block of memory, measured in bytes. // we ensure that this is always a power-of-two, because API's @@ -75,24 +60,22 @@ pub struct Layout { // // (However, we do not analogously require `align >= sizeof(void*)`, // even though that is *also* a requirement of `posix_memalign`.) - align: usize, + align_: NonZeroUsize, } - -// FIXME: audit default implementations for overflow errors, -// (potentially switching to overflowing_add and -// overflowing_mul as necessary). - impl Layout { /// Constructs a `Layout` from a given `size` and `align`, - /// or returns `None` if either of the following conditions + /// or returns `LayoutErr` if either of the following conditions /// are not met: /// + /// * `align` must not be zero, + /// /// * `align` must be a power of two, /// /// * `size`, when rounded up to the nearest multiple of `align`, /// must not overflow (i.e. the rounded value must be less than /// `usize::MAX`). + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub fn from_size_align(size: usize, align: usize) -> Result { if !align.is_power_of_two() { @@ -126,23 +109,27 @@ impl Layout { /// /// # Safety /// - /// This function is unsafe as it does not verify that `align` is - /// a power-of-two nor `size` aligned to `align` fits within the - /// address space (i.e. the `Layout::from_size_align` preconditions). + /// This function is unsafe as it does not verify the preconditions from + /// [`Layout::from_size_align`](#method.from_size_align). + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] pub unsafe fn from_size_align_unchecked(size: usize, align: usize) -> Self { - Layout { size: size, align: align } + Layout { size_: size, align_: NonZeroUsize::new_unchecked(align) } } /// The minimum size in bytes for a memory block of this layout. + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] - pub fn size(&self) -> usize { self.size } + pub fn size(&self) -> usize { self.size_ } /// The minimum byte alignment for a memory block of this layout. + #[stable(feature = "alloc_layout", since = "1.28.0")] #[inline] - pub fn align(&self) -> usize { self.align } + pub fn align(&self) -> usize { self.align_.get() } /// Constructs a `Layout` suitable for holding a value of type `T`. + #[stable(feature = "alloc_layout", since = "1.28.0")] + #[inline] pub fn new() -> Self { let (size, align) = size_align::(); // Note that the align is guaranteed by rustc to be a power of two and @@ -158,6 +145,8 @@ impl Layout { /// Produces layout describing a record that could be used to /// allocate backing structure for `T` (which could be a trait /// or other unsized type like a slice). + #[stable(feature = "alloc_layout", since = "1.28.0")] + #[inline] pub fn for_value(t: &T) -> Self { let (size, align) = (mem::size_of_val(t), mem::align_of_val(t)); // See rationale in `new` for why this us using an unsafe variant below @@ -181,18 +170,20 @@ impl Layout { /// /// # Panics /// - /// Panics if the combination of `self.size` and the given `align` - /// violates the conditions listed in `from_size_align`. + /// Panics if the combination of `self.size()` and the given `align` + /// violates the conditions listed in + /// [`Layout::from_size_align`](#method.from_size_align). + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn align_to(&self, align: usize) -> Self { - Layout::from_size_align(self.size, cmp::max(self.align, align)).unwrap() + Layout::from_size_align(self.size(), cmp::max(self.align(), align)).unwrap() } /// Returns the amount of padding we must insert after `self` /// to ensure that the following address will satisfy `align` /// (measured in bytes). /// - /// E.g. if `self.size` is 9, then `self.padding_needed_for(4)` + /// E.g. if `self.size()` is 9, then `self.padding_needed_for(4)` /// returns 3, because that is the minimum number of bytes of /// padding required to get a 4-aligned address (assuming that the /// corresponding memory block starts at a 4-aligned address). @@ -203,7 +194,8 @@ impl Layout { /// Note that the utility of the returned value requires `align` /// to be less than or equal to the alignment of the starting /// address for the whole allocated block of memory. One way to - /// satisfy this constraint is to ensure `align <= self.align`. + /// satisfy this constraint is to ensure `align <= self.align()`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn padding_needed_for(&self, align: usize) -> usize { let len = self.size(); @@ -227,7 +219,8 @@ impl Layout { // size and padding overflow in the above manner should cause // the allocator to yield an error anyway.) - let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1); + let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) + & !align.wrapping_sub(1); return len_rounded_up.wrapping_sub(len); } @@ -238,14 +231,20 @@ impl Layout { /// layout of the array and `offs` is the distance between the start /// of each element in the array. /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] #[inline] pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> { - let padded_size = self.size.checked_add(self.padding_needed_for(self.align)) + let padded_size = self.size().checked_add(self.padding_needed_for(self.align())) .ok_or(LayoutErr { private: () })?; let alloc_size = padded_size.checked_mul(n) .ok_or(LayoutErr { private: () })?; - Ok((Layout::from_size_align(alloc_size, self.align)?, padded_size)) + + unsafe { + // self.align is already known to be valid and alloc_size has been + // padded already. + Ok((Layout::from_size_align_unchecked(alloc_size, self.align()), padded_size)) + } } /// Creates a layout describing the record for `self` followed by @@ -258,16 +257,16 @@ impl Layout { /// start of the `next` embedded within the concatenated record /// (assuming that the record itself starts at offset 0). /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] pub fn extend(&self, next: Self) -> Result<(Self, usize), LayoutErr> { - let new_align = cmp::max(self.align, next.align); - let realigned = Layout::from_size_align(self.size, new_align)?; + let new_align = cmp::max(self.align(), next.align()); + let pad = self.padding_needed_for(next.align()); - let pad = realigned.padding_needed_for(next.align); - - let offset = self.size.checked_add(pad) + let offset = self.size().checked_add(pad) .ok_or(LayoutErr { private: () })?; - let new_size = offset.checked_add(next.size) + let new_size = offset.checked_add(next.size()) .ok_or(LayoutErr { private: () })?; let layout = Layout::from_size_align(new_size, new_align)?; @@ -285,10 +284,12 @@ impl Layout { /// guaranteed that all elements in the array will be properly /// aligned. /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] pub fn repeat_packed(&self, n: usize) -> Result { let size = self.size().checked_mul(n).ok_or(LayoutErr { private: () })?; - Layout::from_size_align(size, self.align) + Layout::from_size_align(size, self.align()) } /// Creates a layout describing the record for `self` followed by @@ -305,17 +306,21 @@ impl Layout { /// signature out of convenience in matching the signature of /// `extend`.) /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] pub fn extend_packed(&self, next: Self) -> Result<(Self, usize), LayoutErr> { let new_size = self.size().checked_add(next.size()) .ok_or(LayoutErr { private: () })?; - let layout = Layout::from_size_align(new_size, self.align)?; + let layout = Layout::from_size_align(new_size, self.align())?; Ok((layout, self.size())) } /// Creates a layout describing the record for a `[T; n]`. /// - /// On arithmetic overflow, returns `None`. + /// On arithmetic overflow, returns `LayoutErr`. + #[unstable(feature = "allocator_api", issue = "32838")] + #[inline] pub fn array(n: usize) -> Result { Layout::new::() .repeat(n) @@ -326,28 +331,33 @@ impl Layout { } } -/// The parameters given to `Layout::from_size_align` do not satisfy -/// its documented constraints. +/// The parameters given to `Layout::from_size_align` +/// or some other `Layout` constructor +/// do not satisfy its documented constraints. +#[stable(feature = "alloc_layout", since = "1.28.0")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutErr { private: () } // (we need this for downstream impl of trait Error) +#[stable(feature = "alloc_layout", since = "1.28.0")] impl fmt::Display for LayoutErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("invalid parameters to Layout::from_size_align") } } -/// The `AllocErr` error specifies whether an allocation failure is -/// specifically due to resource exhaustion or if it is due to +/// The `AllocErr` error indicates an allocation failure +/// that may be due to resource exhaustion or to /// something wrong when combining the given input arguments with this /// allocator. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct AllocErr; // (we need this for downstream impl of trait Error) +#[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for AllocErr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("memory allocation failed") @@ -357,9 +367,11 @@ impl fmt::Display for AllocErr { /// The `CannotReallocInPlace` error is used when `grow_in_place` or /// `shrink_in_place` were unable to reuse the given memory block for /// a requested layout. +#[unstable(feature = "allocator_api", issue = "32838")] #[derive(Clone, PartialEq, Eq, Debug)] pub struct CannotReallocInPlace; +#[unstable(feature = "allocator_api", issue = "32838")] impl CannotReallocInPlace { pub fn description(&self) -> &str { "cannot reallocate allocator's memory in place" @@ -367,57 +379,141 @@ impl CannotReallocInPlace { } // (we need this for downstream impl of trait Error) +#[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for CannotReallocInPlace { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) } } -/// Augments `AllocErr` with a CapacityOverflow variant. -#[derive(Clone, PartialEq, Eq, Debug)] -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -pub enum CollectionAllocErr { - /// Error due to the computed capacity exceeding the collection's maximum - /// (usually `isize::MAX` bytes). - CapacityOverflow, - /// Error due to the allocator (see the `AllocErr` type's docs). - AllocErr, -} - -#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] -impl From for CollectionAllocErr { - #[inline] - fn from(AllocErr: AllocErr) -> Self { - CollectionAllocErr::AllocErr - } -} - -/// A memory allocator that can be registered to be the one backing `std::alloc::Global` +/// A memory allocator that can be registered as the standard library’s default /// though the `#[global_allocator]` attributes. +/// +/// Some of the methods require that a memory block be *currently +/// allocated* via an allocator. This means that: +/// +/// * the starting address for that memory block was previously +/// returned by a previous call to an allocation method +/// such as `alloc`, and +/// +/// * the memory block has not been subsequently deallocated, where +/// blocks are deallocated either by being passed to a deallocation +/// method such as `dealloc` or by being +/// passed to a reallocation method that returns a non-null pointer. +/// +/// +/// # Example +/// +/// ```no_run +/// use std::alloc::{GlobalAlloc, Layout, alloc}; +/// use std::ptr::null_mut; +/// +/// struct MyAllocator; +/// +/// unsafe impl GlobalAlloc for MyAllocator { +/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() } +/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} +/// } +/// +/// #[global_allocator] +/// static A: MyAllocator = MyAllocator; +/// +/// fn main() { +/// unsafe { +/// assert!(alloc(Layout::new::()).is_null()) +/// } +/// } +/// ``` +/// +/// # Unsafety +/// +/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and +/// implementors must ensure that they adhere to these contracts: +/// +/// * It's undefined behavior if global allocators unwind. This restriction may +/// be lifted in the future, but currently a panic from any of these +/// functions may lead to memory unsafety. +/// +/// * `Layout` queries and calculations in general must be correct. Callers of +/// this trait are allowed to rely on the contracts defined on each method, +/// and implementors must ensure such contracts remain true. +#[stable(feature = "global_alloc", since = "1.28.0")] pub unsafe trait GlobalAlloc { /// Allocate memory as described by the given `layout`. /// /// Returns a pointer to newly-allocated memory, - /// or NULL to indicate allocation failure. + /// or null to indicate allocation failure. /// /// # Safety /// - /// **FIXME:** what are the exact requirements? - unsafe fn alloc(&self, layout: Layout) -> *mut Opaque; + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure that `layout` has non-zero size. + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// The allocated block of memory may or may not be initialized. + /// + /// # Errors + /// + /// Returning a null pointer indicates that either memory is exhausted + /// or `layout` does not meet allocator's size or alignment constraints. + /// + /// Implementations are encouraged to return null on memory + /// exhaustion rather than aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + #[stable(feature = "global_alloc", since = "1.28.0")] + unsafe fn alloc(&self, layout: Layout) -> *mut u8; /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. /// /// # Safety /// - /// **FIXME:** what are the exact requirements? - /// In particular around layout *fit*. (See docs for the `Alloc` trait.) - unsafe fn dealloc(&self, ptr: *mut Opaque, layout: Layout); + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must denote a block of memory currently allocated via + /// this allocator, + /// + /// * `layout` must be the same layout that was used + /// to allocated that block of memory, + #[stable(feature = "global_alloc", since = "1.28.0")] + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); - unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut Opaque { + /// Behaves like `alloc`, but also ensures that the contents + /// are set to zero before being returned. + /// + /// # Safety + /// + /// This function is unsafe for the same reasons that `alloc` is. + /// However the allocated block of memory is guaranteed to be initialized. + /// + /// # Errors + /// + /// Returning a null pointer indicates that either memory is exhausted + /// or `layout` does not meet allocator's size or alignment constraints, + /// just as in `alloc`. + /// + /// Clients wishing to abort computation in response to an + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + #[stable(feature = "global_alloc", since = "1.28.0")] + unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { let size = layout.size(); let ptr = self.alloc(layout); if !ptr.is_null() { - ptr::write_bytes(ptr as *mut u8, 0, size); + ptr::write_bytes(ptr, 0, size); } ptr } @@ -425,26 +521,61 @@ pub unsafe trait GlobalAlloc { /// Shink or grow a block of memory to the given `new_size`. /// The block is described by the given `ptr` pointer and `layout`. /// - /// Return a new pointer (which may or may not be the same as `ptr`), - /// or NULL to indicate reallocation failure. + /// If this returns a non-null pointer, then ownership of the memory block + /// referenced by `ptr` has been transferred to this alloctor. + /// The memory may or may not have been deallocated, + /// and should be considered unusable (unless of course it was + /// transferred back to the caller again via the return value of + /// this method). /// - /// If reallocation is successful, the old `ptr` pointer is considered - /// to have been deallocated. + /// If this method returns null, then ownership of the memory + /// block has not been transferred to this allocator, and the + /// contents of the memory block are unaltered. /// /// # Safety /// - /// `new_size`, when rounded up to the nearest multiple of `old_layout.align()`, - /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). + /// This function is unsafe because undefined behavior can result + /// if the caller does not ensure all of the following: + /// + /// * `ptr` must be currently allocated via this allocator, + /// + /// * `layout` must be the same layout that was used + /// to allocated that block of memory, + /// + /// * `new_size` must be greater than zero. /// - /// **FIXME:** what are the exact requirements? - /// In particular around layout *fit*. (See docs for the `Alloc` trait.) - unsafe fn realloc(&self, ptr: *mut Opaque, layout: Layout, new_size: usize) -> *mut Opaque { + /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, + /// must not overflow (i.e. the rounded value must be less than `usize::MAX`). + /// + /// (Extension subtraits might provide more specific bounds on + /// behavior, e.g. guarantee a sentinel address or a null pointer + /// in response to a zero-size allocation request.) + /// + /// # Errors + /// + /// Returns null if the new layout does not meet the size + /// and alignment constraints of the allocator, or if reallocation + /// otherwise fails. + /// + /// Implementations are encouraged to return null on memory + /// exhaustion rather than panicking or aborting, but this is not + /// a strict requirement. (Specifically: it is *legal* to + /// implement this trait atop an underlying native allocation + /// library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + #[stable(feature = "global_alloc", since = "1.28.0")] + unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let new_ptr = self.alloc(new_layout); if !new_ptr.is_null() { ptr::copy_nonoverlapping( - ptr as *const u8, - new_ptr as *mut u8, + ptr, + new_ptr, cmp::min(layout.size(), new_size), ); self.dealloc(ptr, layout); @@ -526,27 +657,22 @@ pub unsafe trait GlobalAlloc { /// retain their validity until at least the instance of `Alloc` is dropped /// itself. /// -/// * It's undefined behavior if global allocators unwind. This restriction may -/// be lifted in the future, but currently a panic from any of these -/// functions may lead to memory unsafety. Note that as of the time of this -/// writing allocators *not* intending to be global allocators can still panic -/// in their implementation without violating memory safety. -/// /// * `Layout` queries and calculations in general must be correct. Callers of /// this trait are allowed to rely on the contracts defined on each method, /// and implementors must ensure such contracts remain true. /// /// Note that this list may get tweaked over time as clarifications are made in -/// the future. Additionally global allocators may gain unique requirements for -/// how to safely implement one in the future as well. +/// the future. +#[unstable(feature = "allocator_api", issue = "32838")] pub unsafe trait Alloc { - // (Note: existing allocators have unspecified but well-defined + // (Note: some existing allocators have unspecified but well-defined // behavior in response to a zero size allocation request ; // e.g. in C, `malloc` of 0 will either return a null pointer or a // unique pointer, but will not have arbitrary undefined - // behavior. Rust should consider revising the alloc::heap crate - // to reflect this reality.) + // behavior. + // However in jemalloc for example, + // `mallocx(0)` is documented as undefined behavior.) /// Returns a pointer meeting the size and alignment guarantees of /// `layout`. @@ -582,9 +708,11 @@ pub unsafe trait Alloc { /// library that aborts on memory exhaustion.) /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; /// Deallocate the memory referenced by `ptr`. /// @@ -601,7 +729,7 @@ pub unsafe trait Alloc { /// * In addition to fitting the block of memory `layout`, the /// alignment of the `layout` must match the alignment used /// to allocate that block of memory. - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); // == ALLOCATOR-SPECIFIC QUANTITIES AND LIMITS == // usable_size @@ -689,13 +817,15 @@ pub unsafe trait Alloc { /// implement this trait atop an underlying native allocation /// library that aborts on memory exhaustion.) /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, - new_size: usize) -> Result, AllocErr> { + new_size: usize) -> Result, AllocErr> { let old_size = layout.size(); if new_size >= old_size { @@ -712,8 +842,8 @@ pub unsafe trait Alloc { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); let result = self.alloc(new_layout); if let Ok(new_ptr) = result { - ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, - new_ptr.as_ptr() as *mut u8, + ptr::copy_nonoverlapping(ptr.as_ptr(), + new_ptr.as_ptr(), cmp::min(old_size, new_size)); self.dealloc(ptr, layout); } @@ -734,13 +864,15 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. - unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); let p = self.alloc(layout); if let Ok(p) = p { - ptr::write_bytes(p.as_ptr() as *mut u8, 0, size); + ptr::write_bytes(p.as_ptr(), 0, size); } p } @@ -760,8 +892,10 @@ pub unsafe trait Alloc { /// constraints, just as in `alloc`. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn alloc_excess(&mut self, layout: Layout) -> Result { let usable_size = self.usable_size(&layout); self.alloc(layout).map(|p| Excess(p, usable_size.1)) @@ -781,11 +915,13 @@ pub unsafe trait Alloc { /// `layout` does not meet allocator's size or alignment /// constraints, just as in `realloc`. /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc_excess(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result { let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); @@ -825,16 +961,16 @@ pub unsafe trait Alloc { /// unable to assert that the memory block referenced by `ptr` /// could fit `layout`. /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from + /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` + /// function; clients are expected either to be able to recover from /// `grow_in_place` failures without aborting, or to fall back on /// another reallocation method before resorting to an abort. unsafe fn grow_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_size >= layout.size); + debug_assert!(new_size >= layout.size()); let (_l, u) = self.usable_size(&layout); // _l <= layout.size() [guaranteed by usable_size()] // layout.size() <= new_layout.size() [required by this method] @@ -880,16 +1016,16 @@ pub unsafe trait Alloc { /// unable to assert that the memory block referenced by `ptr` /// could fit `layout`. /// - /// Note that one cannot pass `CannotReallocInPlace` to the `oom` - /// method; clients are expected either to be able to recover from + /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error` + /// function; clients are expected either to be able to recover from /// `shrink_in_place` failures without aborting, or to fall back /// on another reallocation method before resorting to an abort. unsafe fn shrink_in_place(&mut self, - ptr: NonNull, + ptr: NonNull, layout: Layout, new_size: usize) -> Result<(), CannotReallocInPlace> { let _ = ptr; // this default implementation doesn't care about the actual address. - debug_assert!(new_size <= layout.size); + debug_assert!(new_size <= layout.size()); let (l, _u) = self.usable_size(&layout); // layout.size() <= _u [guaranteed by usable_size()] // new_layout.size() <= layout.size() [required by this method] @@ -929,8 +1065,10 @@ pub unsafe trait Alloc { /// will *not* yield undefined behavior. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html fn alloc_one(&mut self) -> Result, AllocErr> where Self: Sized { @@ -964,7 +1102,7 @@ pub unsafe trait Alloc { { let k = Layout::new::(); if k.size() > 0 { - self.dealloc(ptr.as_opaque(), k); + self.dealloc(ptr.cast(), k); } } @@ -996,8 +1134,10 @@ pub unsafe trait Alloc { /// Always returns `Err` on arithmetic overflow. /// /// Clients wishing to abort computation in response to an - /// allocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// allocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html fn alloc_array(&mut self, n: usize) -> Result, AllocErr> where Self: Sized { @@ -1040,9 +1180,11 @@ pub unsafe trait Alloc { /// /// Always returns `Err` on arithmetic overflow. /// - /// Clients wishing to abort computation in response to an - /// reallocation error are encouraged to call the allocator's `oom` - /// method, rather than directly invoking `panic!` or similar. + /// Clients wishing to abort computation in response to a + /// reallocation error are encouraged to call the [`handle_alloc_error`] function, + /// rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn realloc_array(&mut self, ptr: NonNull, n_old: usize, @@ -1052,7 +1194,7 @@ pub unsafe trait Alloc { match (Layout::array::(n_old), Layout::array::(n_new)) { (Ok(ref k_old), Ok(ref k_new)) if k_old.size() > 0 && k_new.size() > 0 => { debug_assert!(k_old.align() == k_new.align()); - self.realloc(ptr.as_opaque(), k_old.clone(), k_new.size()).map(NonNull::cast) + self.realloc(ptr.cast(), k_old.clone(), k_new.size()).map(NonNull::cast) } _ => { Err(AllocErr) @@ -1085,7 +1227,7 @@ pub unsafe trait Alloc { { match Layout::array::(n) { Ok(ref k) if k.size() > 0 => { - Ok(self.dealloc(ptr.as_opaque(), k.clone())) + Ok(self.dealloc(ptr.cast(), k.clone())) } _ => { Err(AllocErr) diff --git a/src/libcore/any.rs b/src/libcore/any.rs index a6ba53087ac30..6b26093439e4f 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -120,7 +120,7 @@ impl Any for T { /////////////////////////////////////////////////////////////////////////////// #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Any { +impl fmt::Debug for dyn Any { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Any") } @@ -130,13 +130,20 @@ impl fmt::Debug for Any { // hence used with `unwrap`. May eventually no longer be needed if // dispatch works with upcasting. #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Any + Send { +impl fmt::Debug for dyn Any + Send { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.pad("Any") } } -impl Any { +#[stable(feature = "any_send_sync_methods", since = "1.28.0")] +impl fmt::Debug for dyn Any + Send + Sync { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Any") + } +} + +impl dyn Any { /// Returns `true` if the boxed type is the same as `T`. /// /// # Examples @@ -196,7 +203,7 @@ impl Any { pub fn downcast_ref(&self) -> Option<&T> { if self.is::() { unsafe { - Some(&*(self as *const Any as *const T)) + Some(&*(self as *const dyn Any as *const T)) } } else { None @@ -233,7 +240,7 @@ impl Any { pub fn downcast_mut(&mut self) -> Option<&mut T> { if self.is::() { unsafe { - Some(&mut *(self as *mut Any as *mut T)) + Some(&mut *(self as *mut dyn Any as *mut T)) } } else { None @@ -241,7 +248,7 @@ impl Any { } } -impl Any+Send { +impl dyn Any+Send { /// Forwards to the method defined on the type `Any`. /// /// # Examples @@ -301,7 +308,7 @@ impl Any+Send { /// ``` /// use std::any::Any; /// - /// fn modify_if_u32(s: &mut (Any+ Send)) { + /// fn modify_if_u32(s: &mut (Any + Send)) { /// if let Some(num) = s.downcast_mut::() { /// *num = 42; /// } @@ -325,6 +332,89 @@ impl Any+Send { } } +impl dyn Any+Send+Sync { + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn is_string(s: &(Any + Send + Sync)) { + /// if s.is::() { + /// println!("It's a string!"); + /// } else { + /// println!("Not a string..."); + /// } + /// } + /// + /// fn main() { + /// is_string(&0); + /// is_string(&"cookie monster".to_string()); + /// } + /// ``` + #[stable(feature = "any_send_sync_methods", since = "1.28.0")] + #[inline] + pub fn is(&self) -> bool { + Any::is::(self) + } + + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn print_if_string(s: &(Any + Send + Sync)) { + /// if let Some(string) = s.downcast_ref::() { + /// println!("It's a string({}): '{}'", string.len(), string); + /// } else { + /// println!("Not a string..."); + /// } + /// } + /// + /// fn main() { + /// print_if_string(&0); + /// print_if_string(&"cookie monster".to_string()); + /// } + /// ``` + #[stable(feature = "any_send_sync_methods", since = "1.28.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + Any::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `Any`. + /// + /// # Examples + /// + /// ``` + /// use std::any::Any; + /// + /// fn modify_if_u32(s: &mut (Any + Send + Sync)) { + /// if let Some(num) = s.downcast_mut::() { + /// *num = 42; + /// } + /// } + /// + /// fn main() { + /// let mut x = 10u32; + /// let mut s = "starlord".to_string(); + /// + /// modify_if_u32(&mut x); + /// modify_if_u32(&mut s); + /// + /// assert_eq!(x, 42); + /// assert_eq!(&s, "starlord"); + /// } + /// ``` + #[stable(feature = "any_send_sync_methods", since = "1.28.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + Any::downcast_mut::(self) + } +} /////////////////////////////////////////////////////////////////////////////// // TypeID and its methods @@ -341,7 +431,7 @@ impl Any+Send { /// /// While `TypeId` implements `Hash`, `PartialOrd`, and `Ord`, it is worth /// noting that the hashes and ordering will vary between Rust releases. Beware -/// of relying on them outside of your code! +/// of relying on them inside of your code! #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct TypeId { diff --git a/src/libcore/ascii.rs b/src/libcore/ascii.rs index e6b0569281f89..6ee91e0b22ff0 100644 --- a/src/libcore/ascii.rs +++ b/src/libcore/ascii.rs @@ -108,7 +108,7 @@ pub fn escape_default(c: u8) -> EscapeDefault { b'\\' => ([b'\\', b'\\', 0, 0], 2), b'\'' => ([b'\\', b'\'', 0, 0], 2), b'"' => ([b'\\', b'"', 0, 0], 2), - b'\x20' ... b'\x7e' => ([c, 0, 0, 0], 1), + b'\x20' ..= b'\x7e' => ([c, 0, 0, 0], 1), _ => ([b'\\', b'x', hexify(c >> 4), hexify(c & 0xf)], 4), }; @@ -116,7 +116,7 @@ pub fn escape_default(c: u8) -> EscapeDefault { fn hexify(b: u8) -> u8 { match b { - 0 ... 9 => b'0' + b, + 0 ..= 9 => b'0' + b, _ => b'a' + b - 10, } } diff --git a/src/libcore/cell.rs b/src/libcore/cell.rs index 1ff187ed3f109..137e9fe2c1533 100644 --- a/src/libcore/cell.rs +++ b/src/libcore/cell.rs @@ -235,7 +235,8 @@ use ptr; /// /// See the [module-level documentation](index.html) for more. #[stable(feature = "rust1", since = "1.0.0")] -pub struct Cell { +#[repr(transparent)] +pub struct Cell { value: UnsafeCell, } @@ -286,10 +287,10 @@ impl Cell { } #[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Cell where T: Send {} +unsafe impl Send for Cell where T: Send {} #[stable(feature = "rust1", since = "1.0.0")] -impl !Sync for Cell {} +impl !Sync for Cell {} #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Cell { @@ -380,46 +381,6 @@ impl Cell { } } - /// Returns a raw pointer to the underlying data in this cell. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let c = Cell::new(5); - /// - /// let ptr = c.as_ptr(); - /// ``` - #[inline] - #[stable(feature = "cell_as_ptr", since = "1.12.0")] - pub fn as_ptr(&self) -> *mut T { - self.value.get() - } - - /// Returns a mutable reference to the underlying data. - /// - /// This call borrows `Cell` mutably (at compile-time) which guarantees - /// that we possess the only reference. - /// - /// # Examples - /// - /// ``` - /// use std::cell::Cell; - /// - /// let mut c = Cell::new(5); - /// *c.get_mut() += 1; - /// - /// assert_eq!(c.get(), 6); - /// ``` - #[inline] - #[stable(feature = "cell_get_mut", since = "1.11.0")] - pub fn get_mut(&mut self) -> &mut T { - unsafe { - &mut *self.value.get() - } - } - /// Sets the contained value. /// /// # Examples @@ -498,6 +459,70 @@ impl Cell { } } +impl Cell { + /// Returns a raw pointer to the underlying data in this cell. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let c = Cell::new(5); + /// + /// let ptr = c.as_ptr(); + /// ``` + #[inline] + #[stable(feature = "cell_as_ptr", since = "1.12.0")] + pub fn as_ptr(&self) -> *mut T { + self.value.get() + } + + /// Returns a mutable reference to the underlying data. + /// + /// This call borrows `Cell` mutably (at compile-time) which guarantees + /// that we possess the only reference. + /// + /// # Examples + /// + /// ``` + /// use std::cell::Cell; + /// + /// let mut c = Cell::new(5); + /// *c.get_mut() += 1; + /// + /// assert_eq!(c.get(), 6); + /// ``` + #[inline] + #[stable(feature = "cell_get_mut", since = "1.11.0")] + pub fn get_mut(&mut self) -> &mut T { + unsafe { + &mut *self.value.get() + } + } + + /// Returns a `&Cell` from a `&mut T` + /// + /// # Examples + /// + /// ``` + /// #![feature(as_cell)] + /// use std::cell::Cell; + /// + /// let slice: &mut [i32] = &mut [1, 2, 3]; + /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); + /// let slice_cell: &[Cell] = cell_slice.as_slice_of_cells(); + /// + /// assert_eq!(slice_cell.len(), 3); + /// ``` + #[inline] + #[unstable(feature = "as_cell", issue="43038")] + pub fn from_mut(t: &mut T) -> &Cell { + unsafe { + &*(t as *mut T as *const Cell) + } + } +} + impl Cell { /// Takes the value of the cell, leaving `Default::default()` in its place. /// @@ -521,6 +546,29 @@ impl Cell { #[unstable(feature = "coerce_unsized", issue = "27732")] impl, U> CoerceUnsized> for Cell {} +impl Cell<[T]> { + /// Returns a `&[Cell]` from a `&Cell<[T]>` + /// + /// # Examples + /// + /// ``` + /// #![feature(as_cell)] + /// use std::cell::Cell; + /// + /// let slice: &mut [i32] = &mut [1, 2, 3]; + /// let cell_slice: &Cell<[i32]> = Cell::from_mut(slice); + /// let slice_cell: &[Cell] = cell_slice.as_slice_of_cells(); + /// + /// assert_eq!(slice_cell.len(), 3); + /// ``` + #[unstable(feature = "as_cell", issue="43038")] + pub fn as_slice_of_cells(&self) -> &[Cell] { + unsafe { + &*(self as *const Cell<[T]> as *const [Cell]) + } + } +} + /// A mutable memory location with dynamically checked borrow rules /// /// See the [module-level documentation](index.html) for more. @@ -570,11 +618,31 @@ impl Display for BorrowMutError { } } -// Values [1, MAX-1] represent the number of `Ref` active -// (will not outgrow its range since `usize` is the size of the address space) -type BorrowFlag = usize; +// Positive values represent the number of `Ref` active. Negative values +// represent the number of `RefMut` active. Multiple `RefMut`s can only be +// active at a time if they refer to distinct, nonoverlapping components of a +// `RefCell` (e.g., different ranges of a slice). +// +// `Ref` and `RefMut` are both two words in size, and so there will likely never +// be enough `Ref`s or `RefMut`s in existence to overflow half of the `usize` +// range. Thus, a `BorrowFlag` will probably never overflow or underflow. +// However, this is not a guarantee, as a pathological program could repeatedly +// create and then mem::forget `Ref`s or `RefMut`s. Thus, all code must +// explicitly check for overflow and underflow in order to avoid unsafety, or at +// least behave correctly in the event that overflow or underflow happens (e.g., +// see BorrowRef::new). +type BorrowFlag = isize; const UNUSED: BorrowFlag = 0; -const WRITING: BorrowFlag = !0; + +#[inline(always)] +fn is_writing(x: BorrowFlag) -> bool { + x < UNUSED +} + +#[inline(always)] +fn is_reading(x: BorrowFlag) -> bool { + x > UNUSED +} impl RefCell { /// Creates a new `RefCell` containing `value`. @@ -775,8 +843,9 @@ impl RefCell { /// Mutably borrows the wrapped value. /// - /// The borrow lasts until the returned `RefMut` exits scope. The value - /// cannot be borrowed while this borrow is active. + /// The borrow lasts until the returned `RefMut` or all `RefMut`s derived + /// from it exit scope. The value cannot be borrowed while this borrow is + /// active. /// /// # Panics /// @@ -818,8 +887,9 @@ impl RefCell { /// Mutably borrows the wrapped value, returning an error if the value is currently borrowed. /// - /// The borrow lasts until the returned `RefMut` exits scope. The value cannot be borrowed - /// while this borrow is active. + /// The borrow lasts until the returned `RefMut` or all `RefMut`s derived + /// from it exit scope. The value cannot be borrowed while this borrow is + /// active. /// /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut). /// @@ -1010,12 +1080,14 @@ struct BorrowRef<'b> { impl<'b> BorrowRef<'b> { #[inline] fn new(borrow: &'b Cell) -> Option> { - match borrow.get() { - WRITING => None, - b => { - borrow.set(b + 1); - Some(BorrowRef { borrow: borrow }) - }, + let b = borrow.get(); + if is_writing(b) || b == isize::max_value() { + // If there's currently a writing borrow, or if incrementing the + // refcount would overflow into a writing borrow. + None + } else { + borrow.set(b + 1); + Some(BorrowRef { borrow }) } } } @@ -1024,7 +1096,7 @@ impl<'b> Drop for BorrowRef<'b> { #[inline] fn drop(&mut self) { let borrow = self.borrow.get(); - debug_assert!(borrow != WRITING && borrow != UNUSED); + debug_assert!(is_reading(borrow)); self.borrow.set(borrow - 1); } } @@ -1033,11 +1105,12 @@ impl<'b> Clone for BorrowRef<'b> { #[inline] fn clone(&self) -> BorrowRef<'b> { // Since this Ref exists, we know the borrow flag - // is not set to WRITING. + // is a reading borrow. let borrow = self.borrow.get(); - debug_assert!(borrow != UNUSED); - // Prevent the borrow counter from overflowing. - assert!(borrow != WRITING); + debug_assert!(is_reading(borrow)); + // Prevent the borrow counter from overflowing into + // a writing borrow. + assert!(borrow != isize::max_value()); self.borrow.set(borrow + 1); BorrowRef { borrow: self.borrow } } @@ -1109,6 +1182,37 @@ impl<'b, T: ?Sized> Ref<'b, T> { borrow: orig.borrow, } } + + /// Split a `Ref` into multiple `Ref`s for different components of the + /// borrowed data. + /// + /// The `RefCell` is already immutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `Ref::map_split(...)`. A method would interfere with methods of the same + /// name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(refcell_map_split)] + /// use std::cell::{Ref, RefCell}; + /// + /// let cell = RefCell::new([1, 2, 3, 4]); + /// let borrow = cell.borrow(); + /// let (begin, end) = Ref::map_split(borrow, |slice| slice.split_at(2)); + /// assert_eq!(*begin, [1, 2]); + /// assert_eq!(*end, [3, 4]); + /// ``` + #[unstable(feature = "refcell_map_split", issue = "51476")] + #[inline] + pub fn map_split(orig: Ref<'b, T>, f: F) -> (Ref<'b, U>, Ref<'b, V>) + where F: FnOnce(&T) -> (&U, &V) + { + let (a, b) = f(orig.value); + let borrow = orig.borrow.clone(); + (Ref { value: a, borrow }, Ref { value: b, borrow: orig.borrow }) + } } #[unstable(feature = "coerce_unsized", issue = "27732")] @@ -1157,6 +1261,44 @@ impl<'b, T: ?Sized> RefMut<'b, T> { borrow: borrow, } } + + /// Split a `RefMut` into multiple `RefMut`s for different components of the + /// borrowed data. + /// + /// The underlying `RefCell` will remain mutably borrowed until both + /// returned `RefMut`s go out of scope. + /// + /// The `RefCell` is already mutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RefMut::map_split(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(refcell_map_split)] + /// use std::cell::{RefCell, RefMut}; + /// + /// let cell = RefCell::new([1, 2, 3, 4]); + /// let borrow = cell.borrow_mut(); + /// let (mut begin, mut end) = RefMut::map_split(borrow, |slice| slice.split_at_mut(2)); + /// assert_eq!(*begin, [1, 2]); + /// assert_eq!(*end, [3, 4]); + /// begin.copy_from_slice(&[4, 3]); + /// end.copy_from_slice(&[2, 1]); + /// ``` + #[unstable(feature = "refcell_map_split", issue = "51476")] + #[inline] + pub fn map_split( + orig: RefMut<'b, T>, f: F + ) -> (RefMut<'b, U>, RefMut<'b, V>) + where F: FnOnce(&mut T) -> (&mut U, &mut V) + { + let (a, b) = f(orig.value); + let borrow = orig.borrow.clone(); + (RefMut { value: a, borrow }, RefMut { value: b, borrow: orig.borrow }) + } } struct BorrowRefMut<'b> { @@ -1167,22 +1309,41 @@ impl<'b> Drop for BorrowRefMut<'b> { #[inline] fn drop(&mut self) { let borrow = self.borrow.get(); - debug_assert!(borrow == WRITING); - self.borrow.set(UNUSED); + debug_assert!(is_writing(borrow)); + self.borrow.set(borrow + 1); } } impl<'b> BorrowRefMut<'b> { #[inline] fn new(borrow: &'b Cell) -> Option> { + // NOTE: Unlike BorrowRefMut::clone, new is called to create the initial + // mutable reference, and so there must currently be no existing + // references. Thus, while clone increments the mutable refcount, here + // we explicitly only allow going from UNUSED to UNUSED - 1. match borrow.get() { UNUSED => { - borrow.set(WRITING); + borrow.set(UNUSED - 1); Some(BorrowRefMut { borrow: borrow }) }, _ => None, } } + + // Clone a `BorrowRefMut`. + // + // This is only valid if each `BorrowRefMut` is used to track a mutable + // reference to a distinct, nonoverlapping range of the original object. + // This isn't in a Clone impl so that code doesn't call this implicitly. + #[inline] + fn clone(&self) -> BorrowRefMut<'b> { + let borrow = self.borrow.get(); + debug_assert!(is_writing(borrow)); + // Prevent the borrow counter from underflowing. + assert!(borrow != isize::min_value()); + self.borrow.set(borrow - 1); + BorrowRefMut { borrow: self.borrow } + } } /// A wrapper type for a mutably borrowed value from a `RefCell`. @@ -1231,38 +1392,39 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// /// If you have a reference `&SomeStruct`, then normally in Rust all fields of `SomeStruct` are /// immutable. The compiler makes optimizations based on the knowledge that `&T` is not mutably -/// aliased or mutated, and that `&mut T` is unique. `UnsafeCel` is the only core language +/// aliased or mutated, and that `&mut T` is unique. `UnsafeCell` is the only core language /// feature to work around this restriction. All other types that allow internal mutability, such as -/// `Cell` and `RefCell` use `UnsafeCell` to wrap their internal data. +/// `Cell` and `RefCell`, use `UnsafeCell` to wrap their internal data. /// /// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to /// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// -/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` reference) that -/// is accessible by safe code (for example, because you returned it), then you must not access -/// the data in any way that contradicts that reference for the remainder of `'a`. For example, that -/// means that if you take the `*mut T` from an `UnsafeCell` and case it to an `&T`, then until -/// that reference's lifetime expires, the data in `T` must remain immutable (modulo any -/// `UnsafeCell` data found within `T`, of course). Similarly, if you create an `&mut T` reference -/// that is released to safe code, then you must not access the data within the `UnsafeCell` until -/// that reference expires. +/// - If you create a safe reference with lifetime `'a` (either a `&T` or `&mut T` +/// reference) that is accessible by safe code (for example, because you returned it), +/// then you must not access the data in any way that contradicts that reference for the +/// remainder of `'a`. For example, this means that if you take the `*mut T` from an +/// `UnsafeCell` and cast it to an `&T`, then the data in `T` must remain immutable +/// (modulo any `UnsafeCell` data found within `T`, of course) until that reference's +/// lifetime expires. Similarly, if you create a `&mut T` reference that is released to +/// safe code, then you must not access the data within the `UnsafeCell` until that +/// reference expires. /// -/// - At all times, you must avoid data races, meaning that if multiple threads have access to +/// - At all times, you must avoid data races. If multiple threads have access to /// the same `UnsafeCell`, then any writes must have a proper happens-before relation to all other /// accesses (or use atomics). /// /// To assist with proper design, the following scenarios are explicitly declared legal /// for single-threaded code: /// -/// 1. A `&T` reference can be released to safe code and there it can co-exit with other `&T` +/// 1. A `&T` reference can be released to safe code and there it can co-exist with other `&T` /// references, but not with a `&mut T` /// -/// 2. A `&mut T` reference may be released to safe code, provided neither other `&mut T` nor `&T` +/// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T` /// co-exist with it. A `&mut T` must always be unique. /// -/// Note that while mutating or mutably aliasing the contents of an `& UnsafeCell` is +/// Note that while mutating or mutably aliasing the contents of an `&UnsafeCell` is /// okay (provided you enforce the invariants some other way), it is still undefined behavior /// to have multiple `&mut UnsafeCell` aliases. /// @@ -1281,6 +1443,7 @@ impl<'a, T: ?Sized + fmt::Display> fmt::Display for RefMut<'a, T> { /// ``` #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(transparent)] pub struct UnsafeCell { value: T, } @@ -1369,7 +1532,7 @@ impl, U> CoerceUnsized> for UnsafeCell {} #[allow(unused)] fn assert_coerce_unsized(a: UnsafeCell<&i32>, b: Cell<&i32>, c: RefCell<&i32>) { - let _: UnsafeCell<&Send> = a; - let _: Cell<&Send> = b; - let _: RefCell<&Send> = c; + let _: UnsafeCell<&dyn Send> = a; + let _: Cell<&dyn Send> = b; + let _: RefCell<&dyn Send> = c; } diff --git a/src/libcore/char/decode.rs b/src/libcore/char/decode.rs index 45a73191db2f2..0b8dce19dffa1 100644 --- a/src/libcore/char/decode.rs +++ b/src/libcore/char/decode.rs @@ -64,7 +64,7 @@ impl> Iterator for DecodeUtf8 { } } macro_rules! continuation_byte { - () => { continuation_byte!(0x80...0xBF) }; + () => { continuation_byte!(0x80..=0xBF) }; ($range: pat) => { match self.0.peek() { Some(&byte @ $range) => { @@ -77,35 +77,35 @@ impl> Iterator for DecodeUtf8 { } match first_byte { - 0x00...0x7F => { + 0x00..=0x7F => { first_byte!(0b1111_1111); } - 0xC2...0xDF => { + 0xC2..=0xDF => { first_byte!(0b0001_1111); continuation_byte!(); } 0xE0 => { first_byte!(0b0000_1111); - continuation_byte!(0xA0...0xBF); // 0x80...0x9F here are overlong + continuation_byte!(0xA0..=0xBF); // 0x80..=0x9F here are overlong continuation_byte!(); } - 0xE1...0xEC | 0xEE...0xEF => { + 0xE1..=0xEC | 0xEE..=0xEF => { first_byte!(0b0000_1111); continuation_byte!(); continuation_byte!(); } 0xED => { first_byte!(0b0000_1111); - continuation_byte!(0x80...0x9F); // 0xA0..0xBF here are surrogates + continuation_byte!(0x80..=0x9F); // 0xA0..0xBF here are surrogates continuation_byte!(); } 0xF0 => { first_byte!(0b0000_0111); - continuation_byte!(0x90...0xBF); // 0x80..0x8F here are overlong + continuation_byte!(0x90..=0xBF); // 0x80..0x8F here are overlong continuation_byte!(); continuation_byte!(); } - 0xF1...0xF3 => { + 0xF1..=0xF3 => { first_byte!(0b0000_0111); continuation_byte!(); continuation_byte!(); @@ -113,7 +113,7 @@ impl> Iterator for DecodeUtf8 { } 0xF4 => { first_byte!(0b0000_0111); - continuation_byte!(0x80...0x8F); // 0x90..0xBF here are beyond char::MAX + continuation_byte!(0x80..=0x8F); // 0x90..0xBF here are beyond char::MAX continuation_byte!(); continuation_byte!(); } diff --git a/src/libcore/char/methods.rs b/src/libcore/char/methods.rs index 374adafef647d..eee78de903628 100644 --- a/src/libcore/char/methods.rs +++ b/src/libcore/char/methods.rs @@ -125,9 +125,9 @@ impl char { panic!("to_digit: radix is too high (maximum 36)"); } let val = match self { - '0' ... '9' => self as u32 - '0' as u32, - 'a' ... 'z' => self as u32 - 'a' as u32 + 10, - 'A' ... 'Z' => self as u32 - 'A' as u32 + 10, + '0' ..= '9' => self as u32 - '0' as u32, + 'a' ..= 'z' => self as u32 - 'a' as u32 + 10, + 'A' ..= 'Z' => self as u32 - 'A' as u32 + 10, _ => return None, }; if val < radix { Some(val) } @@ -187,6 +187,27 @@ impl char { } } + /// An extended version of `escape_debug` that optionally permits escaping + /// Extended Grapheme codepoints. This allows us to format characters like + /// nonspacing marks better when they're at the start of a string. + #[doc(hidden)] + #[unstable(feature = "str_internals", issue = "0")] + #[inline] + pub fn escape_debug_ext(self, escape_grapheme_extended: bool) -> EscapeDebug { + let init_state = match self { + '\t' => EscapeDefaultState::Backslash('t'), + '\r' => EscapeDefaultState::Backslash('r'), + '\n' => EscapeDefaultState::Backslash('n'), + '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), + _ if escape_grapheme_extended && self.is_grapheme_extended() => { + EscapeDefaultState::Unicode(self.escape_unicode()) + } + _ if is_printable(self) => EscapeDefaultState::Char(self), + _ => EscapeDefaultState::Unicode(self.escape_unicode()), + }; + EscapeDebug(EscapeDefault { state: init_state }) + } + /// Returns an iterator that yields the literal escape code of a character /// as `char`s. /// @@ -224,15 +245,7 @@ impl char { #[stable(feature = "char_escape_debug", since = "1.20.0")] #[inline] pub fn escape_debug(self) -> EscapeDebug { - let init_state = match self { - '\t' => EscapeDefaultState::Backslash('t'), - '\r' => EscapeDefaultState::Backslash('r'), - '\n' => EscapeDefaultState::Backslash('n'), - '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - c if is_printable(c) => EscapeDefaultState::Char(c), - c => EscapeDefaultState::Unicode(c.escape_unicode()), - }; - EscapeDebug(EscapeDefault { state: init_state }) + self.escape_debug_ext(true) } /// Returns an iterator that yields the literal escape code of a character @@ -292,7 +305,7 @@ impl char { '\r' => EscapeDefaultState::Backslash('r'), '\n' => EscapeDefaultState::Backslash('n'), '\\' | '\'' | '"' => EscapeDefaultState::Backslash(self), - '\x20' ... '\x7e' => EscapeDefaultState::Char(self), + '\x20' ..= '\x7e' => EscapeDefaultState::Char(self), _ => EscapeDefaultState::Unicode(self.escape_unicode()) }; EscapeDefault { state: init_state } @@ -530,7 +543,7 @@ impl char { #[inline] pub fn is_alphabetic(self) -> bool { match self { - 'a'...'z' | 'A'...'Z' => true, + 'a'..='z' | 'A'..='Z' => true, c if c > '\x7f' => derived_property::Alphabetic(c), _ => false, } @@ -586,7 +599,7 @@ impl char { #[inline] pub fn is_lowercase(self) -> bool { match self { - 'a'...'z' => true, + 'a'..='z' => true, c if c > '\x7f' => derived_property::Lowercase(c), _ => false, } @@ -614,7 +627,7 @@ impl char { #[inline] pub fn is_uppercase(self) -> bool { match self { - 'A'...'Z' => true, + 'A'..='Z' => true, c if c > '\x7f' => derived_property::Uppercase(c), _ => false, } @@ -641,7 +654,7 @@ impl char { #[inline] pub fn is_whitespace(self) -> bool { match self { - ' ' | '\x09'...'\x0d' => true, + ' ' | '\x09'..='\x0d' => true, c if c > '\x7f' => property::White_Space(c), _ => false, } @@ -692,6 +705,15 @@ impl char { general_category::Cc(self) } + /// Returns true if this `char` is an extended grapheme character, and false otherwise. + /// + /// 'Extended grapheme character' is defined in terms of the Unicode Shaping and Rendering + /// Category `Grapheme_Extend`. + #[inline] + pub(crate) fn is_grapheme_extended(self) -> bool { + derived_property::Grapheme_Extend(self) + } + /// Returns true if this `char` is numeric, and false otherwise. /// /// 'Numeric'-ness is defined in terms of the Unicode General Categories @@ -715,7 +737,7 @@ impl char { #[inline] pub fn is_numeric(self) -> bool { match self { - '0'...'9' => true, + '0'..='9' => true, c if c > '\x7f' => general_category::N(c), _ => false, } diff --git a/src/libcore/char/mod.rs b/src/libcore/char/mod.rs index 4f6c302247dd2..59bcf1383f47a 100644 --- a/src/libcore/char/mod.rs +++ b/src/libcore/char/mod.rs @@ -60,10 +60,10 @@ use fmt::{self, Write}; use iter::FusedIterator; // UTF-8 ranges and tags for encoding characters -const TAG_CONT: u8 = 0b1000_0000; -const TAG_TWO_B: u8 = 0b1100_0000; -const TAG_THREE_B: u8 = 0b1110_0000; -const TAG_FOUR_B: u8 = 0b1111_0000; +const TAG_CONT: u8 = 0b1000_0000; +const TAG_TWO_B: u8 = 0b1100_0000; +const TAG_THREE_B: u8 = 0b1110_0000; +const TAG_FOUR_B: u8 = 0b1111_0000; const MAX_ONE_B: u32 = 0x80; const MAX_TWO_B: u32 = 0x800; const MAX_THREE_B: u32 = 0x10000; diff --git a/src/libcore/clone.rs b/src/libcore/clone.rs index f79f73516989f..3b15ba2b4ab1f 100644 --- a/src/libcore/clone.rs +++ b/src/libcore/clone.rs @@ -153,7 +153,6 @@ pub struct AssertParamIsCopy { _field: ::marker::PhantomData { /// This method tests for `self` and `other` values to be equal, and is used /// by `==`. @@ -611,7 +614,10 @@ impl PartialOrd for Ordering { #[doc(alias = "<")] #[doc(alias = "<=")] #[doc(alias = ">=")] -#[rustc_on_unimplemented = "can't compare `{Self}` with `{Rhs}`"] +#[rustc_on_unimplemented( + message="can't compare `{Self}` with `{Rhs}`", + label="no implementation for `{Self} < {Rhs}` and `{Self} > {Rhs}`", +)] pub trait PartialOrd: PartialEq { /// This method returns an ordering between `self` and `other` values if one exists. /// diff --git a/src/libcore/convert.rs b/src/libcore/convert.rs index 7324df95bc5d5..11cc4ffecf005 100644 --- a/src/libcore/convert.rs +++ b/src/libcore/convert.rs @@ -63,9 +63,9 @@ /// /// The key difference between the two traits is the intention: /// -/// - Use `AsRef` when goal is to simply convert into a reference -/// - Use `Borrow` when goal is related to writing code that is agnostic to the -/// type of borrow and if is reference or value +/// - Use `AsRef` when the goal is to simply convert into a reference +/// - Use `Borrow` when the goal is related to writing code that is agnostic to +/// the type of borrow and whether it is a reference or value /// /// See [the book][book] for a more detailed comparison. /// diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index a1f4c6995dae0..3c5f934d4d8c7 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -11,7 +11,7 @@ use fmt; struct PadAdapter<'a> { - buf: &'a mut (fmt::Write + 'a), + buf: &'a mut (dyn fmt::Write + 'a), on_newline: bool, } @@ -84,7 +84,7 @@ impl<'a> fmt::Write for PadAdapter<'a> { /// // prints "Foo { bar: 10, baz: "Hello World" }" /// println!("{:?}", Foo { bar: 10, baz: "Hello World".to_string() }); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugStruct<'a, 'b: 'a> { @@ -107,7 +107,7 @@ pub fn debug_struct_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// Adds a new field to the generated struct output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn field(&mut self, name: &str, value: &fmt::Debug) -> &mut DebugStruct<'a, 'b> { + pub fn field(&mut self, name: &str, value: &dyn fmt::Debug) -> &mut DebugStruct<'a, 'b> { self.result = self.result.and_then(|_| { let prefix = if self.has_fields { "," @@ -181,7 +181,7 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// // prints "Foo(10, "Hello World")" /// println!("{:?}", Foo(10, "Hello World".to_string())); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugTuple<'a, 'b: 'a> { @@ -204,7 +204,7 @@ pub fn debug_tuple_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>, name: &str) -> D impl<'a, 'b: 'a> DebugTuple<'a, 'b> { /// Adds a new field to the generated tuple struct output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn field(&mut self, value: &fmt::Debug) -> &mut DebugTuple<'a, 'b> { + pub fn field(&mut self, value: &dyn fmt::Debug) -> &mut DebugTuple<'a, 'b> { self.result = self.result.and_then(|_| { let (prefix, space) = if self.fields > 0 { (",", " ") @@ -258,7 +258,7 @@ struct DebugInner<'a, 'b: 'a> { } impl<'a, 'b: 'a> DebugInner<'a, 'b> { - fn entry(&mut self, entry: &fmt::Debug) { + fn entry(&mut self, entry: &dyn fmt::Debug) { self.result = self.result.and_then(|_| { if self.is_pretty() { let mut slot = None; @@ -319,7 +319,7 @@ impl<'a, 'b: 'a> DebugInner<'a, 'b> { /// // prints "{10, 11}" /// println!("{:?}", Foo(vec![10, 11])); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugSet<'a, 'b: 'a> { @@ -340,7 +340,7 @@ pub fn debug_set_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugSet<'a, 'b impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// Adds a new entry to the set output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugSet<'a, 'b> { + pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut DebugSet<'a, 'b> { self.inner.entry(entry); self } @@ -390,7 +390,7 @@ impl<'a, 'b: 'a> DebugSet<'a, 'b> { /// // prints "[10, 11]" /// println!("{:?}", Foo(vec![10, 11])); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugList<'a, 'b: 'a> { @@ -411,7 +411,7 @@ pub fn debug_list_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugList<'a, impl<'a, 'b: 'a> DebugList<'a, 'b> { /// Adds a new entry to the list output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn entry(&mut self, entry: &fmt::Debug) -> &mut DebugList<'a, 'b> { + pub fn entry(&mut self, entry: &dyn fmt::Debug) -> &mut DebugList<'a, 'b> { self.inner.entry(entry); self } @@ -461,7 +461,7 @@ impl<'a, 'b: 'a> DebugList<'a, 'b> { /// // prints "{"A": 10, "B": 11}" /// println!("{:?}", Foo(vec![("A".to_string(), 10), ("B".to_string(), 11)])); /// ``` -#[must_use] +#[must_use = "must eventually call `finish()` on Debug builders"] #[allow(missing_debug_implementations)] #[stable(feature = "debug_builders", since = "1.2.0")] pub struct DebugMap<'a, 'b: 'a> { @@ -482,7 +482,7 @@ pub fn debug_map_new<'a, 'b>(fmt: &'a mut fmt::Formatter<'b>) -> DebugMap<'a, 'b impl<'a, 'b: 'a> DebugMap<'a, 'b> { /// Adds a new entry to the map output. #[stable(feature = "debug_builders", since = "1.2.0")] - pub fn entry(&mut self, key: &fmt::Debug, value: &fmt::Debug) -> &mut DebugMap<'a, 'b> { + pub fn entry(&mut self, key: &dyn fmt::Debug, value: &dyn fmt::Debug) -> &mut DebugMap<'a, 'b> { self.result = self.result.and_then(|_| { if self.is_pretty() { let mut slot = None; diff --git a/src/libcore/fmt/mod.rs b/src/libcore/fmt/mod.rs index 5820fe58932c6..928f95e3ba2ea 100644 --- a/src/libcore/fmt/mod.rs +++ b/src/libcore/fmt/mod.rs @@ -25,18 +25,19 @@ mod float; mod num; mod builders; -#[unstable(feature = "fmt_flags_align", issue = "27726")] +#[stable(feature = "fmt_flags_align", since = "1.28.0")] /// Possible alignments returned by `Formatter::align` #[derive(Debug)] pub enum Alignment { + #[stable(feature = "fmt_flags_align", since = "1.28.0")] /// Indication that contents should be left-aligned. Left, + #[stable(feature = "fmt_flags_align", since = "1.28.0")] /// Indication that contents should be right-aligned. Right, + #[stable(feature = "fmt_flags_align", since = "1.28.0")] /// Indication that contents should be center-aligned. Center, - /// No alignment was requested. - Unknown, } #[stable(feature = "debug_builders", since = "1.2.0")] @@ -254,7 +255,7 @@ pub struct Formatter<'a> { width: Option, precision: Option, - buf: &'a mut (Write+'a), + buf: &'a mut (dyn Write+'a), curarg: slice::Iter<'a, ArgumentV1<'a>>, args: &'a [ArgumentV1<'a>], } @@ -271,7 +272,7 @@ struct Void { /// /// It was added after #45197 showed that one could share a `!Sync` /// object across threads by passing it into `format_args!`. - _oibit_remover: PhantomData<*mut Fn()>, + _oibit_remover: PhantomData<*mut dyn Fn()>, } /// This struct represents the generic "argument" which is taken by the Xprintf @@ -1019,7 +1020,7 @@ pub trait UpperExp { /// /// [`write!`]: ../../std/macro.write.html #[stable(feature = "rust1", since = "1.0.0")] -pub fn write(output: &mut Write, args: Arguments) -> Result { +pub fn write(output: &mut dyn Write, args: Arguments) -> Result { let mut formatter = Formatter { flags: 0, width: None, @@ -1061,7 +1062,7 @@ pub fn write(output: &mut Write, args: Arguments) -> Result { impl<'a> Formatter<'a> { fn wrap_buf<'b, 'c, F>(&'b mut self, wrap: F) -> Formatter<'c> - where 'b: 'c, F: FnOnce(&'b mut (Write+'b)) -> &'c mut (Write+'c) + where 'b: 'c, F: FnOnce(&'b mut (dyn Write+'b)) -> &'c mut (dyn Write+'c) { Formatter { // We want to change this @@ -1202,6 +1203,23 @@ impl<'a> Formatter<'a> { /// is longer than this length /// /// Notably this function ignores the `flag` parameters. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// formatter.pad("Foo") + /// } + /// } + /// + /// assert_eq!(&format!("{:<4}", Foo), "Foo "); + /// assert_eq!(&format!("{:0>4}", Foo), "0Foo"); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn pad(&mut self, s: &str) -> Result { // Make sure there's a fast path up front @@ -1324,7 +1342,7 @@ impl<'a> Formatter<'a> { } fn write_formatted_parts(&mut self, formatted: &flt2dec::Formatted) -> Result { - fn write_bytes(buf: &mut Write, s: &[u8]) -> Result { + fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result { buf.write_str(unsafe { str::from_utf8_unchecked(s) }) } @@ -1368,7 +1386,7 @@ impl<'a> Formatter<'a> { self.buf.write_str(data) } - /// Writes some formatted information into this instance + /// Writes some formatted information into this instance. #[stable(feature = "rust1", since = "1.0.0")] pub fn write_fmt(&mut self, fmt: Arguments) -> Result { write(self.buf, fmt) @@ -1381,19 +1399,76 @@ impl<'a> Formatter<'a> { or `sign_aware_zero_pad` methods instead")] pub fn flags(&self) -> u32 { self.flags } - /// Character used as 'fill' whenever there is alignment + /// Character used as 'fill' whenever there is alignment. + /// + /// # Examples + /// + /// ``` + /// use std::fmt; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// let c = formatter.fill(); + /// if let Some(width) = formatter.width() { + /// for _ in 0..width { + /// write!(formatter, "{}", c)?; + /// } + /// Ok(()) + /// } else { + /// write!(formatter, "{}", c) + /// } + /// } + /// } + /// + /// // We set alignment to the left with ">". + /// assert_eq!(&format!("{:G>3}", Foo), "GGG"); + /// assert_eq!(&format!("{:t>6}", Foo), "tttttt"); + /// ``` #[stable(feature = "fmt_flags", since = "1.5.0")] pub fn fill(&self) -> char { self.fill } - /// Flag indicating what form of alignment was requested - #[unstable(feature = "fmt_flags_align", reason = "method was just created", - issue = "27726")] - pub fn align(&self) -> Alignment { + /// Flag indicating what form of alignment was requested. + /// + /// # Examples + /// + /// ``` + /// extern crate core; + /// + /// use std::fmt::{self, Alignment}; + /// + /// struct Foo; + /// + /// impl fmt::Display for Foo { + /// fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + /// let s = if let Some(s) = formatter.align() { + /// match s { + /// Alignment::Left => "left", + /// Alignment::Right => "right", + /// Alignment::Center => "center", + /// } + /// } else { + /// "into the void" + /// }; + /// write!(formatter, "{}", s) + /// } + /// } + /// + /// fn main() { + /// assert_eq!(&format!("{:<}", Foo), "left"); + /// assert_eq!(&format!("{:>}", Foo), "right"); + /// assert_eq!(&format!("{:^}", Foo), "center"); + /// assert_eq!(&format!("{}", Foo), "into the void"); + /// } + /// ``` + #[stable(feature = "fmt_flags_align", since = "1.28.0")] + pub fn align(&self) -> Option { match self.align { - rt::v1::Alignment::Left => Alignment::Left, - rt::v1::Alignment::Right => Alignment::Right, - rt::v1::Alignment::Center => Alignment::Center, - rt::v1::Alignment::Unknown => Alignment::Unknown, + rt::v1::Alignment::Left => Some(Alignment::Left), + rt::v1::Alignment::Right => Some(Alignment::Right), + rt::v1::Alignment::Center => Some(Alignment::Center), + rt::v1::Alignment::Unknown => None, } } diff --git a/src/libcore/fmt/num.rs b/src/libcore/fmt/num.rs index 4451ab445cc5c..51391fa50d56f 100644 --- a/src/libcore/fmt/num.rs +++ b/src/libcore/fmt/num.rs @@ -121,19 +121,19 @@ macro_rules! radix { fn digit(x: u8) -> u8 { match x { $($x => $conv,)+ - x => panic!("number not in the range 0..{}: {}", Self::BASE - 1, x), + x => panic!("number not in the range 0..={}: {}", Self::BASE - 1, x), } } } } } -radix! { Binary, 2, "0b", x @ 0 ... 1 => b'0' + x } -radix! { Octal, 8, "0o", x @ 0 ... 7 => b'0' + x } -radix! { LowerHex, 16, "0x", x @ 0 ... 9 => b'0' + x, - x @ 10 ... 15 => b'a' + (x - 10) } -radix! { UpperHex, 16, "0x", x @ 0 ... 9 => b'0' + x, - x @ 10 ... 15 => b'A' + (x - 10) } +radix! { Binary, 2, "0b", x @ 0 ..= 1 => b'0' + x } +radix! { Octal, 8, "0o", x @ 0 ..= 7 => b'0' + x } +radix! { LowerHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, + x @ 10 ..= 15 => b'a' + (x - 10) } +radix! { UpperHex, 16, "0x", x @ 0 ..= 9 => b'0' + x, + x @ 10 ..= 15 => b'A' + (x - 10) } macro_rules! int_base { ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs new file mode 100644 index 0000000000000..10b4ca9b0b27a --- /dev/null +++ b/src/libcore/future/future.rs @@ -0,0 +1,112 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use mem::PinMut; +use marker::Unpin; +use task::{self, Poll}; + +/// A future represents an asychronous computation. +/// +/// A future is a value that may not have finished computing yet. This kind of +/// "asynchronous value" makes it possible for a thread to continue doing useful +/// work while it waits for the value to become available. +/// +/// # The `poll` method +/// +/// The core method of future, `poll`, *attempts* to resolve the future into a +/// final value. This method does not block if the value is not ready. Instead, +/// the current task is scheduled to be woken up when it's possible to make +/// further progress by `poll`ing again. The wake up is performed using +/// `cx.waker()`, a handle for waking up the current task. +/// +/// When using a future, you generally won't call `poll` directly, but instead +/// `await!` the value. +pub trait Future { + /// The result of the `Future`. + type Output; + + /// Attempt to resolve the future to a final value, registering + /// the current task for wakeup if the value is not yet available. + /// + /// # Return value + /// + /// This function returns: + /// + /// - [`Poll::Pending`] if the future is not ready yet + /// - [`Poll::Ready(val)`] with the result `val` of this future if it + /// finished successfully. + /// + /// Once a future has finished, clients should not `poll` it again. + /// + /// When a future is not ready yet, `poll` returns + /// `Poll::Pending`. The future will *also* register the + /// interest of the current task in the value being produced. For example, + /// if the future represents the availability of data on a socket, then the + /// task is recorded so that when data arrives, it is woken up (via + /// [`cx.waker()`]). Once a task has been woken up, + /// it should attempt to `poll` the future again, which may or may not + /// produce a final value. + /// + /// Note that if `Pending` is returned it only means that the *current* task + /// (represented by the argument `cx`) will receive a notification. Tasks + /// from previous calls to `poll` will *not* receive notifications. + /// + /// # Runtime characteristics + /// + /// Futures alone are *inert*; they must be *actively* `poll`ed to make + /// progress, meaning that each time the current task is woken up, it should + /// actively re-`poll` pending futures that it still has an interest in. + /// + /// The `poll` function is not called repeatedly in a tight loop for + /// futures, but only whenever the future itself is ready, as signaled via + /// the `Waker` inside `task::Context`. If you're familiar with the + /// `poll(2)` or `select(2)` syscalls on Unix it's worth noting that futures + /// typically do *not* suffer the same problems of "all wakeups must poll + /// all events"; they are more like `epoll(4)`. + /// + /// An implementation of `poll` should strive to return quickly, and must + /// *never* block. Returning quickly prevents unnecessarily clogging up + /// threads or event loops. If it is known ahead of time that a call to + /// `poll` may end up taking awhile, the work should be offloaded to a + /// thread pool (or something similar) to ensure that `poll` can return + /// quickly. + /// + /// # Panics + /// + /// Once a future has completed (returned `Ready` from `poll`), + /// then any future calls to `poll` may panic, block forever, or otherwise + /// cause bad behavior. The `Future` trait itself provides no guarantees + /// about the behavior of `poll` after a future has completed. + /// + /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending + /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready + /// [`cx.waker()`]: ../task/struct.Context.html#method.waker + fn poll(self: PinMut, cx: &mut task::Context) -> Poll; +} + +impl<'a, F: ?Sized + Future + Unpin> Future for &'a mut F { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + F::poll(PinMut::new(&mut **self), cx) + } +} + +impl<'a, F: ?Sized + Future> Future for PinMut<'a, F> { + type Output = F::Output; + + fn poll(mut self: PinMut, cx: &mut task::Context) -> Poll { + F::poll((*self).reborrow(), cx) + } +} diff --git a/src/libcore/future/future_obj.rs b/src/libcore/future/future_obj.rs new file mode 100644 index 0000000000000..98c504a3f7bef --- /dev/null +++ b/src/libcore/future/future_obj.rs @@ -0,0 +1,179 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use future::Future; +use marker::{PhantomData, Unpin}; +use mem::PinMut; +use task::{Context, Poll}; + +/// A custom trait object for polling futures, roughly akin to +/// `Box + 'a>`. +/// +/// This custom trait object was introduced for two reasons: +/// - Currently it is not possible to take `dyn Trait` by value and +/// `Box` is not available in no_std contexts. +/// - The `Future` trait is currently not object safe: The `Future::poll` +/// method makes uses the arbitrary self types feature and traits in which +/// this feature is used are currently not object safe due to current compiler +/// limitations. (See tracking issue for arbitray self types for more +/// information #44874) +pub struct LocalFutureObj<'a, T> { + ptr: *mut (), + poll_fn: unsafe fn(*mut (), &mut Context) -> Poll, + drop_fn: unsafe fn(*mut ()), + _marker: PhantomData<&'a ()>, +} + +impl<'a, T> LocalFutureObj<'a, T> { + /// Create a `LocalFutureObj` from a custom trait object representation. + #[inline] + pub fn new + 'a>(f: F) -> LocalFutureObj<'a, T> { + LocalFutureObj { + ptr: f.into_raw(), + poll_fn: F::poll, + drop_fn: F::drop, + _marker: PhantomData, + } + } + + /// Converts the `LocalFutureObj` into a `FutureObj` + /// To make this operation safe one has to ensure that the `UnsafeFutureObj` + /// instance from which this `LocalFutureObj` was created actually + /// implements `Send`. + #[inline] + pub unsafe fn into_future_obj(self) -> FutureObj<'a, T> { + FutureObj(self) + } +} + +impl<'a, T> fmt::Debug for LocalFutureObj<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("LocalFutureObj") + .finish() + } +} + +impl<'a, T> From> for LocalFutureObj<'a, T> { + #[inline] + fn from(f: FutureObj<'a, T>) -> LocalFutureObj<'a, T> { + f.0 + } +} + +impl<'a, T> Future for LocalFutureObj<'a, T> { + type Output = T; + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll { + unsafe { + (self.poll_fn)(self.ptr, cx) + } + } +} + +impl<'a, T> Drop for LocalFutureObj<'a, T> { + fn drop(&mut self) { + unsafe { + (self.drop_fn)(self.ptr) + } + } +} + +/// A custom trait object for polling futures, roughly akin to +/// `Box + Send + 'a>`. +/// +/// This custom trait object was introduced for two reasons: +/// - Currently it is not possible to take `dyn Trait` by value and +/// `Box` is not available in no_std contexts. +/// - The `Future` trait is currently not object safe: The `Future::poll` +/// method makes uses the arbitrary self types feature and traits in which +/// this feature is used are currently not object safe due to current compiler +/// limitations. (See tracking issue for arbitray self types for more +/// information #44874) +pub struct FutureObj<'a, T>(LocalFutureObj<'a, T>); + +unsafe impl<'a, T> Send for FutureObj<'a, T> {} + +impl<'a, T> FutureObj<'a, T> { + /// Create a `FutureObj` from a custom trait object representation. + #[inline] + pub fn new + Send>(f: F) -> FutureObj<'a, T> { + FutureObj(LocalFutureObj::new(f)) + } +} + +impl<'a, T> fmt::Debug for FutureObj<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FutureObj") + .finish() + } +} + +impl<'a, T> Future for FutureObj<'a, T> { + type Output = T; + + #[inline] + fn poll(self: PinMut, cx: &mut Context) -> Poll { + let pinned_field = unsafe { PinMut::map_unchecked(self, |x| &mut x.0) }; + pinned_field.poll(cx) + } +} + +/// A custom implementation of a future trait object for `FutureObj`, providing +/// a hand-rolled vtable. +/// +/// This custom representation is typically used only in `no_std` contexts, +/// where the default `Box`-based implementation is not available. +/// +/// The implementor must guarantee that it is safe to call `poll` repeatedly (in +/// a non-concurrent fashion) with the result of `into_raw` until `drop` is +/// called. +pub unsafe trait UnsafeFutureObj<'a, T>: 'a { + /// Convert an owned instance into a (conceptually owned) void pointer. + fn into_raw(self) -> *mut (); + + /// Poll the future represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to repeatedly call + /// `poll` with the result of `into_raw` until `drop` is called; such calls + /// are not, however, allowed to race with each other or with calls to + /// `drop`. + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll; + + /// Drops the future represented by the given void pointer. + /// + /// # Safety + /// + /// The trait implementor must guarantee that it is safe to call this + /// function once per `into_raw` invocation; that call cannot race with + /// other calls to `drop` or `poll`. + unsafe fn drop(ptr: *mut ()); +} + +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for &'a mut F + where F: Future + Unpin + 'a +{ + fn into_raw(self) -> *mut () { + self as *mut F as *mut () + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx) + } + + unsafe fn drop(_ptr: *mut ()) {} +} diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs new file mode 100644 index 0000000000000..f9361a0f4e7a3 --- /dev/null +++ b/src/libcore/future/mod.rs @@ -0,0 +1,21 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Asynchronous values. + +mod future; +pub use self::future::Future; + +mod future_obj; +pub use self::future_obj::{FutureObj, LocalFutureObj, UnsafeFutureObj}; diff --git a/src/libcore/hash/mod.rs b/src/libcore/hash/mod.rs index 3e1f21cafe412..e7907e0344493 100644 --- a/src/libcore/hash/mod.rs +++ b/src/libcore/hash/mod.rs @@ -542,6 +542,16 @@ impl Default for BuildHasherDefault { } } +#[stable(since = "1.29.0", feature = "build_hasher_eq")] +impl PartialEq for BuildHasherDefault { + fn eq(&self, _other: &BuildHasherDefault) -> bool { + true + } +} + +#[stable(since = "1.29.0", feature = "build_hasher_eq")] +impl Eq for BuildHasherDefault {} + ////////////////////////////////////////////////////////////////////////////// mod impls { @@ -603,6 +613,13 @@ mod impls { } } + #[stable(feature = "never_hash", since = "1.29.0")] + impl Hash for ! { + fn hash(&self, _: &mut H) { + *self + } + } + macro_rules! impl_hash_tuple { () => ( #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libcore/internal_macros.rs b/src/libcore/internal_macros.rs index 58eef6492877a..db75f9bf210fc 100644 --- a/src/libcore/internal_macros.rs +++ b/src/libcore/internal_macros.rs @@ -86,17 +86,3 @@ macro_rules! forward_ref_op_assign { } } } - -#[cfg(stage0)] -macro_rules! public_in_stage0 { - ( { $(#[$attr:meta])* } $($Item: tt)*) => { - $(#[$attr])* pub $($Item)* - } -} - -#[cfg(not(stage0))] -macro_rules! public_in_stage0 { - ( { $(#[$attr:meta])* } $($Item: tt)*) => { - $(#[$attr])* pub(crate) $($Item)* - } -} diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index fb0d2d9c88219..854cb5f4e3b3f 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -10,7 +10,7 @@ //! rustc compiler intrinsics. //! -//! The corresponding definitions are in librustc_trans/intrinsic.rs. +//! The corresponding definitions are in librustc_codegen_llvm/intrinsic.rs. //! //! # Volatiles //! @@ -717,7 +717,7 @@ extern "rust-intrinsic" { /// Reinterprets the bits of a value of one type as another type. /// /// Both types must have the same size. Neither the original, nor the result, - /// may be an [invalid value](../../nomicon/meet-safe-and-unsafe.html). + /// may be an [invalid value](../../nomicon/what-unsafe-does.html). /// /// `transmute` is semantically equivalent to a bitwise move of one type /// into another. It copies the bits from the source value into the @@ -1085,6 +1085,15 @@ extern "rust-intrinsic" { /// [`std::ptr::write_volatile`](../../std/ptr/fn.write_volatile.html). pub fn volatile_store(dst: *mut T, val: T); + /// Perform a volatile load from the `src` pointer + /// The pointer is not required to be aligned. + #[cfg(not(stage0))] + pub fn unaligned_volatile_load(src: *const T) -> T; + /// Perform a volatile store to the `dst` pointer. + /// The pointer is not required to be aligned. + #[cfg(not(stage0))] + pub fn unaligned_volatile_store(dst: *mut T, val: T); + /// Returns the square root of an `f32` pub fn sqrtf32(x: f32) -> f32; /// Returns the square root of an `f64` @@ -1364,40 +1373,6 @@ extern "rust-intrinsic" { /// source as well as std's catch implementation. pub fn try(f: fn(*mut u8), data: *mut u8, local_ptr: *mut u8) -> i32; - /// Computes the byte offset that needs to be applied to `ptr` in order to - /// make it aligned to `align`. - /// If it is not possible to align `ptr`, the implementation returns - /// `usize::max_value()`. - /// - /// There are no guarantees whatsover that offsetting the pointer will not - /// overflow or go beyond the allocation that `ptr` points into. - /// It is up to the caller to ensure that the returned offset is correct - /// in all terms other than alignment. - /// - /// # Examples - /// - /// Accessing adjacent `u8` as `u16` - /// - /// ``` - /// # #![feature(core_intrinsics)] - /// # fn foo(n: usize) { - /// # use std::intrinsics::align_offset; - /// # use std::mem::align_of; - /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; - /// let offset = align_offset(ptr as *const (), align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.offset(offset as isize) as *const u16; - /// assert_ne!(*u16_ptr, 500); - /// } else { - /// // while the pointer can be aligned via `offset`, it would point - /// // outside the allocation - /// } - /// # } } - /// ``` - pub fn align_offset(ptr: *const (), align: usize) -> usize; - /// Emits a `!nontemporal` store according to LLVM (see their docs). /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); diff --git a/src/libcore/iter/iterator.rs b/src/libcore/iter/iterator.rs index b27bd3142e1ed..48c6eb9414429 100644 --- a/src/libcore/iter/iterator.rs +++ b/src/libcore/iter/iterator.rs @@ -11,14 +11,14 @@ use cmp::Ordering; use ops::Try; -use super::{AlwaysOk, LoopState}; +use super::LoopState; use super::{Chain, Cycle, Cloned, Enumerate, Filter, FilterMap, Fuse}; use super::{Flatten, FlatMap, flatten_compat}; use super::{Inspect, Map, Peekable, Scan, Skip, SkipWhile, StepBy, Take, TakeWhile, Rev}; use super::{Zip, Sum, Product}; use super::{ChainState, FromIterator, ZipImpl}; -fn _assert_is_object_safe(_: &Iterator) {} +fn _assert_is_object_safe(_: &dyn Iterator) {} /// An interface for dealing with iterators. /// @@ -271,9 +271,30 @@ pub trait Iterator { /// Creates an iterator starting at the same point, but stepping by /// the given amount at each iteration. /// - /// Note that it will always return the first element of the iterator, + /// Note 1: The first element of the iterator will always be returned, /// regardless of the step given. /// + /// Note 2: The time at which ignored elements are pulled is not fixed. + /// `StepBy` behaves like the sequence `next(), nth(step-1), nth(step-1), …`, + /// but is also free to behave like the sequence + /// `advance_n_and_return_first(step), advance_n_and_return_first(step), …` + /// Which way is used may change for some iterators for performance reasons. + /// The second way will advance the iterator earlier and may consume more items. + /// + /// `advance_n_and_return_first` is the equivalent of: + /// ``` + /// fn advance_n_and_return_first(iter: &mut I, total_step: usize) -> Option + /// where + /// I: Iterator, + /// { + /// let next = iter.next(); + /// if total_step > 1 { + /// iter.nth(total_step-2); + /// } + /// next + /// } + /// ``` + /// /// # Panics /// /// The method will panic if the given step is `0`. @@ -283,7 +304,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iterator_step_by)] /// let a = [0, 1, 2, 3, 4, 5]; /// let mut iter = a.into_iter().step_by(2); /// @@ -293,9 +313,7 @@ pub trait Iterator { /// assert_eq!(iter.next(), None); /// ``` #[inline] - #[unstable(feature = "iterator_step_by", - reason = "unstable replacement of Range::step_by", - issue = "27741")] + #[stable(feature = "iterator_step_by", since = "1.28.0")] fn step_by(self, step: usize) -> StepBy where Self: Sized { assert!(step != 0); StepBy{iter: self, step: step - 1, first_take: true} @@ -366,8 +384,9 @@ pub trait Iterator { /// /// In other words, it zips two iterators together, into a single one. /// - /// When either iterator returns [`None`], all further calls to [`next`] - /// will return [`None`]. + /// If either iterator returns [`None`], [`next`] from the zipped iterator + /// will return [`None`]. If the first iterator returns [`None`], `zip` will + /// short-circuit and `next` will not be called on the second iterator. /// /// # Examples /// @@ -1040,8 +1059,6 @@ pub trait Iterator { /// Basic usage: /// /// ``` - /// #![feature(iterator_flatten)] - /// /// let data = vec![vec![1, 2, 3, 4], vec![5, 6]]; /// let flattened = data.into_iter().flatten().collect::>(); /// assert_eq!(flattened, &[1, 2, 3, 4, 5, 6]); @@ -1050,8 +1067,6 @@ pub trait Iterator { /// Mapping and then flattening: /// /// ``` - /// #![feature(iterator_flatten)] - /// /// let words = ["alpha", "beta", "gamma"]; /// /// // chars() returns an iterator @@ -1078,8 +1093,6 @@ pub trait Iterator { /// Flattening once only removes one level of nesting: /// /// ``` - /// #![feature(iterator_flatten)] - /// /// let d3 = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]; /// /// let d2 = d3.iter().flatten().collect::>(); @@ -1097,7 +1110,7 @@ pub trait Iterator { /// /// [`flat_map()`]: #method.flat_map #[inline] - #[unstable(feature = "iterator_flatten", issue = "48213")] + #[stable(feature = "iterator_flatten", since = "1.29")] fn flatten(self) -> Flatten where Self: Sized, Self::Item: IntoIterator { Flatten { inner: flatten_compat(self) } @@ -1170,8 +1183,9 @@ pub trait Iterator { /// happening at various parts in the pipeline. To do that, insert /// a call to `inspect()`. /// - /// It's much more common for `inspect()` to be used as a debugging tool - /// than to exist in your final code, but never say never. + /// It's more common for `inspect()` to be used as a debugging tool than to + /// exist in your final code, but applications may find it useful in certain + /// situations when errors need to be logged before being discarded. /// /// # Examples /// @@ -1211,6 +1225,32 @@ pub trait Iterator { /// about to filter: 3 /// 6 /// ``` + /// + /// Logging errors before discarding them: + /// + /// ``` + /// let lines = ["1", "2", "a"]; + /// + /// let sum: i32 = lines + /// .iter() + /// .map(|line| line.parse::()) + /// .inspect(|num| { + /// if let Err(ref e) = *num { + /// println!("Parsing error: {}", e); + /// } + /// }) + /// .filter_map(Result::ok) + /// .sum(); + /// + /// println!("Sum: {}", sum); + /// ``` + /// + /// This will print: + /// + /// ```text + /// Parsing error: invalid digit found in string + /// Sum: 3 + /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn inspect(self, f: F) -> Inspect where @@ -1591,7 +1631,7 @@ pub trait Iterator { fn fold(mut self, init: B, mut f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - self.try_fold(init, move |acc, x| AlwaysOk(f(acc, x))).0 + self.try_fold(init, move |acc, x| Ok::(f(acc, x))).unwrap() } /// Tests if every element of the iterator matches a predicate. diff --git a/src/libcore/iter/mod.rs b/src/libcore/iter/mod.rs index 1e8476d3880c8..35ae77411069c 100644 --- a/src/libcore/iter/mod.rs +++ b/src/libcore/iter/mod.rs @@ -319,9 +319,10 @@ use cmp; use fmt; use iter_private::TrustedRandomAccess; -use ops::Try; +use ops::{self, Try}; use usize; use intrinsics; +use mem; #[stable(feature = "rust1", since = "1.0.0")] pub use self::iterator::Iterator; @@ -333,7 +334,7 @@ pub use self::range::Step; #[stable(feature = "rust1", since = "1.0.0")] pub use self::sources::{Repeat, repeat}; -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub use self::sources::{RepeatWith, repeat_with}; #[stable(feature = "iter_empty", since = "1.2.0")] pub use self::sources::{Empty, empty}; @@ -354,21 +355,6 @@ mod range; mod sources; mod traits; -/// Transparent newtype used to implement foo methods in terms of try_foo. -/// Important until #43278 is fixed; might be better as `Result` later. -struct AlwaysOk(pub T); - -impl Try for AlwaysOk { - type Ok = T; - type Error = !; - #[inline] - fn into_result(self) -> Result { Ok(self.0) } - #[inline] - fn from_error(v: Self::Error) -> Self { v } - #[inline] - fn from_ok(v: Self::Ok) -> Self { AlwaysOk(v) } -} - /// Used to make try_fold closures more like normal loops #[derive(PartialEq)] enum LoopState { @@ -673,9 +659,7 @@ impl FusedIterator for Cycle where I: Clone + Iterator {} /// [`step_by`]: trait.Iterator.html#method.step_by /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[unstable(feature = "iterator_step_by", - reason = "unstable replacement of Range::step_by", - issue = "27741")] +#[stable(feature = "iterator_step_by", since = "1.28.0")] #[derive(Clone, Debug)] pub struct StepBy { iter: I, @@ -683,20 +667,13 @@ pub struct StepBy { first_take: bool, } -#[unstable(feature = "iterator_step_by", - reason = "unstable replacement of Range::step_by", - issue = "27741")] +#[stable(feature = "iterator_step_by", since = "1.28.0")] impl Iterator for StepBy where I: Iterator { type Item = I::Item; #[inline] fn next(&mut self) -> Option { - if self.first_take { - self.first_take = false; - self.iter.next() - } else { - self.iter.nth(self.step) - } + ::spec_next(self) } #[inline] @@ -756,10 +733,80 @@ impl Iterator for StepBy where I: Iterator { } } +// hidden trait for specializing iterator methods +// could be generalized but is currently only used for StepBy +trait StepBySpecIterator { + type Item; + fn spec_next(&mut self) -> Option; +} + +impl StepBySpecIterator for StepBy +where + I: Iterator, +{ + type Item = I::Item; + + #[inline] + default fn spec_next(&mut self) -> Option { + if self.first_take { + self.first_take = false; + self.iter.next() + } else { + self.iter.nth(self.step) + } + } +} + +impl StepBySpecIterator for StepBy> +where + T: Step, +{ + #[inline] + fn spec_next(&mut self) -> Option { + self.first_take = false; + if !(self.iter.start < self.iter.end) { + return None; + } + // add 1 to self.step to get original step size back + // it was decremented for the general case on construction + if let Some(n) = self.iter.start.add_usize(self.step+1) { + let next = mem::replace(&mut self.iter.start, n); + Some(next) + } else { + let last = self.iter.start.clone(); + self.iter.start = self.iter.end.clone(); + Some(last) + } + } +} + +impl StepBySpecIterator for StepBy> +where + T: Step, +{ + #[inline] + fn spec_next(&mut self) -> Option { + self.first_take = false; + self.iter.compute_is_empty(); + if self.iter.is_empty.unwrap_or_default() { + return None; + } + // add 1 to self.step to get original step size back + // it was decremented for the general case on construction + if let Some(n) = self.iter.start.add_usize(self.step+1) { + self.iter.is_empty = Some(!(n <= self.iter.end)); + let next = mem::replace(&mut self.iter.start, n); + Some(next) + } else { + let last = self.iter.start.clone(); + self.iter.is_empty = Some(true); + Some(last) + } + } +} + // StepBy can only make the iterator shorter, so the len will still fit. -#[unstable(feature = "iterator_step_by", - reason = "unstable replacement of Range::step_by", - issue = "27741")] +#[stable(feature = "iterator_step_by", since = "1.28.0")] impl ExactSizeIterator for StepBy where I: ExactSizeIterator {} /// An iterator that strings two iterators together. @@ -2530,13 +2577,13 @@ impl FusedIterator for FlatMap /// [`flatten`]: trait.Iterator.html#method.flatten /// [`Iterator`]: trait.Iterator.html #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] pub struct Flatten where I::Item: IntoIterator { inner: FlattenCompat::IntoIter>, } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl fmt::Debug for Flatten where I: Iterator + fmt::Debug, U: Iterator + fmt::Debug, I::Item: IntoIterator, @@ -2546,7 +2593,7 @@ impl fmt::Debug for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl Clone for Flatten where I: Iterator + Clone, U: Iterator + Clone, I::Item: IntoIterator, @@ -2554,7 +2601,7 @@ impl Clone for Flatten fn clone(&self) -> Self { Flatten { inner: self.inner.clone() } } } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl Iterator for Flatten where I: Iterator, U: Iterator, I::Item: IntoIterator @@ -2582,7 +2629,7 @@ impl Iterator for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl DoubleEndedIterator for Flatten where I: DoubleEndedIterator, U: DoubleEndedIterator, I::Item: IntoIterator @@ -2605,7 +2652,7 @@ impl DoubleEndedIterator for Flatten } } -#[unstable(feature = "iterator_flatten", issue = "48213")] +#[stable(feature = "iterator_flatten", since = "1.29")] impl FusedIterator for Flatten where I: FusedIterator, U: Iterator, I::Item: IntoIterator {} diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index 5896322f111f8..651c7a35d413c 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -10,7 +10,7 @@ use convert::TryFrom; use mem; -use ops::{self, Add, Sub, Try}; +use ops::{self, Add, Sub}; use usize; use super::{FusedIterator, TrustedLen}; @@ -91,7 +91,7 @@ macro_rules! step_impl_unsigned { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$t>::private_try_from(n) { + match <$t>::try_from(n) { Ok(n_as_t) => self.checked_add(n_as_t), Err(_) => None, } @@ -123,7 +123,7 @@ macro_rules! step_impl_signed { #[inline] #[allow(unreachable_patterns)] fn add_usize(&self, n: usize) -> Option { - match <$unsigned>::private_try_from(n) { + match <$unsigned>::try_from(n) { Ok(n_as_unsigned) => { // Wrapping in unsigned space handles cases like // `-120_i8.add_usize(200) == Some(80_i8)`, @@ -330,23 +330,23 @@ impl Iterator for ops::RangeInclusive { #[inline] fn next(&mut self) -> Option { - if self.start <= self.end { - if self.start < self.end { - let n = self.start.add_one(); - Some(mem::replace(&mut self.start, n)) - } else { - let last = self.start.replace_one(); - self.end.replace_zero(); - Some(last) - } - } else { - None + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { + return None; } + let is_iterating = self.start < self.end; + self.is_empty = Some(!is_iterating); + Some(if is_iterating { + let n = self.start.add_one(); + mem::replace(&mut self.start, n) + } else { + self.start.clone() + }) } #[inline] fn size_hint(&self) -> (usize, Option) { - if !(self.start <= self.end) { + if self.is_empty() { return (0, Some(0)); } @@ -358,25 +358,29 @@ impl Iterator for ops::RangeInclusive { #[inline] fn nth(&mut self, n: usize) -> Option { + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { + return None; + } + if let Some(plus_n) = self.start.add_usize(n) { use cmp::Ordering::*; match plus_n.partial_cmp(&self.end) { Some(Less) => { + self.is_empty = Some(false); self.start = plus_n.add_one(); return Some(plus_n) } Some(Equal) => { - self.start.replace_one(); - self.end.replace_zero(); + self.is_empty = Some(true); return Some(plus_n) } _ => {} } } - self.start.replace_one(); - self.end.replace_zero(); + self.is_empty = Some(true); None } @@ -394,141 +398,26 @@ impl Iterator for ops::RangeInclusive { fn max(mut self) -> Option { self.next_back() } - - #[inline] - fn try_fold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - let mut accum = init; - if self.start <= self.end { - loop { - let (x, done) = - if self.start < self.end { - let n = self.start.add_one(); - (mem::replace(&mut self.start, n), false) - } else { - self.end.replace_zero(); - (self.start.replace_one(), true) - }; - accum = f(accum, x)?; - if done { break } - } - } - Try::from_ok(accum) - } } #[stable(feature = "inclusive_range", since = "1.26.0")] impl DoubleEndedIterator for ops::RangeInclusive { #[inline] fn next_back(&mut self) -> Option { - if self.start <= self.end { - if self.start < self.end { - let n = self.end.sub_one(); - Some(mem::replace(&mut self.end, n)) - } else { - let last = self.end.replace_zero(); - self.start.replace_one(); - Some(last) - } - } else { - None + self.compute_is_empty(); + if self.is_empty.unwrap_or_default() { + return None; } - } - - #[inline] - fn try_rfold(&mut self, init: B, mut f: F) -> R where - Self: Sized, F: FnMut(B, Self::Item) -> R, R: Try - { - let mut accum = init; - if self.start <= self.end { - loop { - let (x, done) = - if self.start < self.end { - let n = self.end.sub_one(); - (mem::replace(&mut self.end, n), false) - } else { - self.start.replace_one(); - (self.end.replace_zero(), true) - }; - accum = f(accum, x)?; - if done { break } - } - } - Try::from_ok(accum) + let is_iterating = self.start < self.end; + self.is_empty = Some(!is_iterating); + Some(if is_iterating { + let n = self.end.sub_one(); + mem::replace(&mut self.end, n) + } else { + self.end.clone() + }) } } #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for ops::RangeInclusive {} - -/// Compensate removal of some impls per -/// https://github.com/rust-lang/rust/pull/49305#issuecomment-376293243 -trait PrivateTryFromUsize: Sized { - fn private_try_from(n: usize) -> Result; -} - -impl PrivateTryFromUsize for T where T: TryFrom { - #[inline] - fn private_try_from(n: usize) -> Result { - T::try_from(n).map_err(|_| ()) - } -} - -// no possible bounds violation -macro_rules! try_from_unbounded { - ($($target:ty),*) => {$( - impl PrivateTryFromUsize for $target { - #[inline] - fn private_try_from(value: usize) -> Result { - Ok(value as $target) - } - } - )*} -} - -// unsigned to signed (only positive bound) -#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] -macro_rules! try_from_upper_bounded { - ($($target:ty),*) => {$( - impl PrivateTryFromUsize for $target { - #[inline] - fn private_try_from(u: usize) -> Result<$target, ()> { - if u > (<$target>::max_value() as usize) { - Err(()) - } else { - Ok(u as $target) - } - } - } - )*} -} - - -#[cfg(target_pointer_width = "16")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_unbounded!(u16, u32, u64, u128); - try_from_unbounded!(i32, i64, i128); -} - -#[cfg(target_pointer_width = "32")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_upper_bounded!(u16); - try_from_unbounded!(u32, u64, u128); - try_from_upper_bounded!(i32); - try_from_unbounded!(i64, i128); -} - -#[cfg(target_pointer_width = "64")] -mod ptr_try_from_impls { - use super::PrivateTryFromUsize; - - try_from_upper_bounded!(u16, u32); - try_from_unbounded!(u64, u128); - try_from_upper_bounded!(i32, i64); - try_from_unbounded!(i128); -} diff --git a/src/libcore/iter/sources.rs b/src/libcore/iter/sources.rs index 0fc1a3aa8ac06..d500cc99fa13c 100644 --- a/src/libcore/iter/sources.rs +++ b/src/libcore/iter/sources.rs @@ -113,12 +113,12 @@ pub fn repeat(elt: T) -> Repeat { /// /// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub struct RepeatWith { repeater: F } -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] impl A> Iterator for RepeatWith { type Item = A; @@ -129,13 +129,7 @@ impl A> Iterator for RepeatWith { fn size_hint(&self) -> (usize, Option) { (usize::MAX, None) } } -#[unstable(feature = "iterator_repeat_with", issue = "48169")] -impl A> DoubleEndedIterator for RepeatWith { - #[inline] - fn next_back(&mut self) -> Option { self.next() } -} - -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] impl A> FusedIterator for RepeatWith {} #[unstable(feature = "trusted_len", issue = "37572")] @@ -158,19 +152,15 @@ unsafe impl A> TrustedLen for RepeatWith {} /// /// [`repeat`]: fn.repeat.html /// -/// An iterator produced by `repeat_with()` is a `DoubleEndedIterator`. -/// It is important to note that reversing `repeat_with(f)` will produce -/// the exact same sequence as the non-reversed iterator. In other words, -/// `repeat_with(f).rev().collect::>()` is equivalent to -/// `repeat_with(f).collect::>()`. +/// An iterator produced by `repeat_with()` is not a `DoubleEndedIterator`. +/// If you need `repeat_with()` to return a `DoubleEndedIterator`, +/// please open a GitHub issue explaining your use case. /// /// # Examples /// /// Basic usage: /// /// ``` -/// #![feature(iterator_repeat_with)] -/// /// use std::iter; /// /// // let's assume we have some value of a type that is not `Clone` @@ -191,8 +181,6 @@ unsafe impl A> TrustedLen for RepeatWith {} /// Using mutation and going finite: /// /// ```rust -/// #![feature(iterator_repeat_with)] -/// /// use std::iter; /// /// // From the zeroth to the third power of two: @@ -209,7 +197,7 @@ unsafe impl A> TrustedLen for RepeatWith {} /// assert_eq!(None, pow2.next()); /// ``` #[inline] -#[unstable(feature = "iterator_repeat_with", issue = "48169")] +#[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub fn repeat_with A>(repeater: F) -> RepeatWith { RepeatWith { repeater } } diff --git a/src/libcore/iter/traits.rs b/src/libcore/iter/traits.rs index ddbb59989424f..4b2c1aa551e99 100644 --- a/src/libcore/iter/traits.rs +++ b/src/libcore/iter/traits.rs @@ -10,7 +10,7 @@ use ops::{Mul, Add, Try}; use num::Wrapping; -use super::{AlwaysOk, LoopState}; +use super::LoopState; /// Conversion from an `Iterator`. /// @@ -104,8 +104,11 @@ use super::{AlwaysOk, LoopState}; /// assert_eq!(c.0, vec![0, 1, 2, 3, 4]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented="a collection of type `{Self}` cannot be \ - built from an iterator over elements of type `{A}`"] +#[rustc_on_unimplemented( + message="a collection of type `{Self}` cannot be built from an iterator \ + over elements of type `{A}`", + label="a collection of type `{Self}` cannot be built from `std::iter::Iterator`", +)] pub trait FromIterator: Sized { /// Creates a value from an iterator. /// @@ -352,6 +355,13 @@ pub trait Extend { fn extend>(&mut self, iter: T); } +#[stable(feature = "extend_for_unit", since = "1.28.0")] +impl Extend<()> for () { + fn extend>(&mut self, iter: T) { + iter.into_iter().for_each(drop) + } +} + /// An iterator able to yield elements from both ends. /// /// Something that implements `DoubleEndedIterator` has one extra capability @@ -517,7 +527,7 @@ pub trait DoubleEndedIterator: Iterator { fn rfold(mut self, accum: B, mut f: F) -> B where Self: Sized, F: FnMut(B, Self::Item) -> B, { - self.try_rfold(accum, move |acc, x| AlwaysOk(f(acc, x))).0 + self.try_rfold(accum, move |acc, x| Ok::(f(acc, x))).unwrap() } /// Searches for an element of an iterator from the back that satisfies a predicate. @@ -587,7 +597,7 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { /// that information can be useful. For example, if you want to iterate /// backwards, a good start is to know where the end is. /// -/// When implementing an `ExactSizeIterator`, You must also implement +/// When implementing an `ExactSizeIterator`, you must also implement /// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* /// return the exact size of the iterator. /// diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 54f35d17974fb..72074e1dbce18 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -41,7 +41,7 @@ //! dictate the panic message, the file at which panic was invoked, and the //! line and column inside the file. It is up to consumers of this core //! library to define this panic function; it is only required to never -//! return. This requires a `lang` attribute named `panic_fmt`. +//! return. This requires a `lang` attribute named `panic_impl`. //! //! * `rust_eh_personality` - is used by the failure mechanisms of the //! compiler. This is often mapped to GCC's personality function, but crates @@ -74,12 +74,14 @@ #![deny(missing_debug_implementations)] #![feature(allow_internal_unstable)] +#![feature(arbitrary_self_types)] #![feature(asm)] #![feature(associated_type_defaults)] #![feature(attr_literals)] #![feature(cfg_target_has_atomic)] #![feature(concat_idents)] #![feature(const_fn)] +#![feature(const_int_ops)] #![feature(core_float)] #![feature(custom_attribute)] #![feature(doc_cfg)] @@ -87,8 +89,6 @@ #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] -#![feature(iterator_flatten)] -#![feature(iterator_repeat_with)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(never_type)] @@ -112,18 +112,16 @@ #![feature(unwind_attributes)] #![feature(doc_alias)] #![feature(inclusive_range_methods)] - -#![cfg_attr(not(stage0), feature(mmx_target_feature))] -#![cfg_attr(not(stage0), feature(tbm_target_feature))] -#![cfg_attr(not(stage0), feature(sse4a_target_feature))] -#![cfg_attr(not(stage0), feature(arm_target_feature))] -#![cfg_attr(not(stage0), feature(powerpc_target_feature))] -#![cfg_attr(not(stage0), feature(mips_target_feature))] -#![cfg_attr(not(stage0), feature(aarch64_target_feature))] - -#![cfg_attr(stage0, feature(target_feature))] -#![cfg_attr(stage0, feature(cfg_target_feature))] -#![cfg_attr(stage0, feature(fn_must_use))] +#![feature(mmx_target_feature)] +#![feature(tbm_target_feature)] +#![feature(sse4a_target_feature)] +#![feature(arm_target_feature)] +#![feature(powerpc_target_feature)] +#![feature(mips_target_feature)] +#![feature(aarch64_target_feature)] +#![feature(const_slice_len)] +#![feature(const_str_as_bytes)] +#![feature(const_str_len)] #[prelude_import] #[allow(unused)] @@ -148,14 +146,14 @@ mod uint_macros; #[path = "num/i16.rs"] pub mod i16; #[path = "num/i32.rs"] pub mod i32; #[path = "num/i64.rs"] pub mod i64; -#[path = "num/i128.rs"] pub mod i128; +#[path = "num/i128.rs"] pub mod i128; #[path = "num/usize.rs"] pub mod usize; #[path = "num/u8.rs"] pub mod u8; #[path = "num/u16.rs"] pub mod u16; #[path = "num/u32.rs"] pub mod u32; #[path = "num/u64.rs"] pub mod u64; -#[path = "num/u128.rs"] pub mod u128; +#[path = "num/u128.rs"] pub mod u128; #[path = "num/f32.rs"] pub mod f32; #[path = "num/f64.rs"] pub mod f64; @@ -171,7 +169,6 @@ pub mod prelude; pub mod intrinsics; pub mod mem; -pub mod nonzero; pub mod ptr; pub mod hint; @@ -208,19 +205,17 @@ pub mod time; pub mod unicode; +/* Async */ +pub mod future; +pub mod task; + /* Heap memory allocator trait */ #[allow(missing_docs)] pub mod alloc; -#[unstable(feature = "allocator_api", issue = "32838")] -#[rustc_deprecated(since = "1.27.0", reason = "module renamed to `alloc`")] -/// Use the `alloc` module instead. -pub mod heap { - pub use alloc::*; -} - // note: does not need to be public mod iter_private; +mod nonzero; mod tuple; mod unit; @@ -249,9 +244,6 @@ macro_rules! vector_impl { ($([$f:ident, $($args:tt)*]),*) => { $($f!($($args)*) #[cfg(not(stage0))] // allow changes to how stdsimd works in stage0 mod coresimd; -#[unstable(feature = "stdsimd", issue = "48556")] -#[cfg(not(stage0))] -pub use coresimd::simd; #[stable(feature = "simd_arch", since = "1.27.0")] #[cfg(not(stage0))] pub use coresimd::arch; diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index c830c22ee5f50..83f9dfea8f267 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -543,6 +543,7 @@ macro_rules! unimplemented { /// into libsyntax itself. /// /// For more information, see documentation for `std`'s macros. +#[cfg(dox)] mod builtin { /// Unconditionally causes compilation to fail with the given error message when encountered. @@ -551,8 +552,7 @@ mod builtin { /// /// [`std::compile_error!`]: ../std/macro.compile_error.html #[stable(feature = "compile_error_macro", since = "1.20.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! compile_error { ($msg:expr) => ({ /* compiler built-in */ }); ($msg:expr,) => ({ /* compiler built-in */ }); @@ -564,8 +564,7 @@ mod builtin { /// /// [`std::format_args!`]: ../std/macro.format_args.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! format_args { ($fmt:expr) => ({ /* compiler built-in */ }); ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ }); @@ -577,8 +576,7 @@ mod builtin { /// /// [`std::env!`]: ../std/macro.env.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -590,8 +588,7 @@ mod builtin { /// /// [`std::option_env!`]: ../std/macro.option_env.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! option_env { ($name:expr) => ({ /* compiler built-in */ }); ($name:expr,) => ({ /* compiler built-in */ }); @@ -603,8 +600,7 @@ mod builtin { /// /// [`std::concat_idents!`]: ../std/macro.concat_idents.html #[unstable(feature = "concat_idents_macro", issue = "29599")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! concat_idents { ($($e:ident),+) => ({ /* compiler built-in */ }); ($($e:ident,)+) => ({ /* compiler built-in */ }); @@ -616,8 +612,7 @@ mod builtin { /// /// [`std::concat!`]: ../std/macro.concat.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! concat { ($($e:expr),*) => ({ /* compiler built-in */ }); ($($e:expr,)*) => ({ /* compiler built-in */ }); @@ -629,8 +624,7 @@ mod builtin { /// /// [`std::line!`]: ../std/macro.line.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! line { () => ({ /* compiler built-in */ }) } /// A macro which expands to the column number on which it was invoked. @@ -639,8 +633,7 @@ mod builtin { /// /// [`std::column!`]: ../std/macro.column.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! column { () => ({ /* compiler built-in */ }) } /// A macro which expands to the file name from which it was invoked. @@ -649,8 +642,7 @@ mod builtin { /// /// [`std::file!`]: ../std/macro.file.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! file { () => ({ /* compiler built-in */ }) } /// A macro which stringifies its arguments. @@ -659,8 +651,7 @@ mod builtin { /// /// [`std::stringify!`]: ../std/macro.stringify.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! stringify { ($($t:tt)*) => ({ /* compiler built-in */ }) } /// Includes a utf8-encoded file as a string. @@ -669,8 +660,7 @@ mod builtin { /// /// [`std::include_str!`]: ../std/macro.include_str.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include_str { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -682,8 +672,7 @@ mod builtin { /// /// [`std::include_bytes!`]: ../std/macro.include_bytes.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include_bytes { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -695,8 +684,7 @@ mod builtin { /// /// [`std::module_path!`]: ../std/macro.module_path.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! module_path { () => ({ /* compiler built-in */ }) } /// Boolean evaluation of configuration flags, at compile-time. @@ -705,8 +693,7 @@ mod builtin { /// /// [`std::cfg!`]: ../std/macro.cfg.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! cfg { ($($cfg:tt)*) => ({ /* compiler built-in */ }) } /// Parse a file as an expression or an item according to the context. @@ -715,8 +702,7 @@ mod builtin { /// /// [`std::include!`]: ../std/macro.include.html #[stable(feature = "rust1", since = "1.0.0")] - #[macro_export] - #[cfg(dox)] + #[rustc_doc_only_macro] macro_rules! include { ($file:expr) => ({ /* compiler built-in */ }); ($file:expr,) => ({ /* compiler built-in */ }); @@ -727,9 +713,8 @@ mod builtin { /// For more information, see the documentation for [`std::assert!`]. /// /// [`std::assert!`]: ../std/macro.assert.html - #[macro_export] + #[rustc_doc_only_macro] #[stable(feature = "rust1", since = "1.0.0")] - #[cfg(dox)] macro_rules! assert { ($cond:expr) => ({ /* compiler built-in */ }); ($cond:expr,) => ({ /* compiler built-in */ }); diff --git a/src/libcore/manually_drop_stage0.rs b/src/libcore/manually_drop_stage0.rs new file mode 100644 index 0000000000000..8643219cb6115 --- /dev/null +++ b/src/libcore/manually_drop_stage0.rs @@ -0,0 +1,195 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// +/// This wrapper is 0-cost. +/// +/// # Examples +/// +/// This wrapper helps with explicitly documenting the drop order dependencies between fields of +/// the type: +/// +/// ```rust +/// use std::mem::ManuallyDrop; +/// struct Peach; +/// struct Banana; +/// struct Melon; +/// struct FruitBox { +/// // Immediately clear there’s something non-trivial going on with these fields. +/// peach: ManuallyDrop, +/// melon: Melon, // Field that’s independent of the other two. +/// banana: ManuallyDrop, +/// } +/// +/// impl Drop for FruitBox { +/// fn drop(&mut self) { +/// unsafe { +/// // Explicit ordering in which field destructors are run specified in the intuitive +/// // location – the destructor of the structure containing the fields. +/// // Moreover, one can now reorder fields within the struct however much they want. +/// ManuallyDrop::drop(&mut self.peach); +/// ManuallyDrop::drop(&mut self.banana); +/// } +/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets +/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. +/// } +/// } +/// ``` +#[stable(feature = "manually_drop", since = "1.20.0")] +#[allow(unions_with_drop_fields)] +#[derive(Copy)] +pub union ManuallyDrop{ value: T } + +impl ManuallyDrop { + /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// ManuallyDrop::new(Box::new(())); + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_manually_drop_new")] + #[inline] + pub const fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value: value } + } + + /// Extract the value from the ManuallyDrop container. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline] + pub fn into_inner(slot: ManuallyDrop) -> T { + unsafe { + slot.value + } + } + + /// Manually drops the contained value. + /// + /// # Safety + /// + /// This function runs the destructor of the contained value and thus the wrapped value + /// now represents uninitialized data. It is up to the user of this method to ensure the + /// uninitialized data is not actually used. + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline] + pub unsafe fn drop(slot: &mut ManuallyDrop) { + ptr::drop_in_place(&mut slot.value) + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl Deref for ManuallyDrop { + type Target = T; + #[inline] + fn deref(&self) -> &Self::Target { + unsafe { + &self.value + } + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl DerefMut for ManuallyDrop { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { + &mut self.value + } + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl ::fmt::Debug for ManuallyDrop { + fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result { + unsafe { + fmt.debug_tuple("ManuallyDrop").field(&self.value).finish() + } + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl Clone for ManuallyDrop { + fn clone(&self) -> Self { + ManuallyDrop::new(self.deref().clone()) + } + + fn clone_from(&mut self, source: &Self) { + self.deref_mut().clone_from(source); + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl Default for ManuallyDrop { + fn default() -> Self { + ManuallyDrop::new(Default::default()) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl PartialEq for ManuallyDrop { + fn eq(&self, other: &Self) -> bool { + self.deref().eq(other) + } + + fn ne(&self, other: &Self) -> bool { + self.deref().ne(other) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl Eq for ManuallyDrop {} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl PartialOrd for ManuallyDrop { + fn partial_cmp(&self, other: &Self) -> Option<::cmp::Ordering> { + self.deref().partial_cmp(other) + } + + fn lt(&self, other: &Self) -> bool { + self.deref().lt(other) + } + + fn le(&self, other: &Self) -> bool { + self.deref().le(other) + } + + fn gt(&self, other: &Self) -> bool { + self.deref().gt(other) + } + + fn ge(&self, other: &Self) -> bool { + self.deref().ge(other) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl Ord for ManuallyDrop { + fn cmp(&self, other: &Self) -> ::cmp::Ordering { + self.deref().cmp(other) + } +} + +#[stable(feature = "manually_drop_impls", since = "1.22.0")] +impl ::hash::Hash for ManuallyDrop { + fn hash(&self, state: &mut H) { + self.deref().hash(state); + } +} diff --git a/src/libcore/marker.rs b/src/libcore/marker.rs index c074adfd570e3..4f37b462583d1 100644 --- a/src/libcore/marker.rs +++ b/src/libcore/marker.rs @@ -39,7 +39,10 @@ use hash::Hasher; /// [arc]: ../../std/sync/struct.Arc.html /// [ub]: ../../reference/behavior-considered-undefined.html #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_on_unimplemented = "`{Self}` cannot be sent between threads safely"] +#[rustc_on_unimplemented( + message="`{Self}` cannot be sent between threads safely", + label="`{Self}` cannot be sent between threads safely" +)] pub unsafe auto trait Send { // empty. } @@ -88,7 +91,12 @@ impl !Send for *mut T { } /// [trait object]: ../../book/first-edition/trait-objects.html #[stable(feature = "rust1", since = "1.0.0")] #[lang = "sized"] -#[rustc_on_unimplemented = "`{Self}` does not have a constant size known at compile-time"] +#[rustc_on_unimplemented( + message="the size for values of type `{Self}` cannot be known at compilation time", + label="doesn't have a size known at compile-time", + note="to learn more, visit ", +)] #[fundamental] // for Default, for example, which requires that `[T]: !Default` be evaluatable pub trait Sized { // Empty. @@ -294,7 +302,7 @@ pub trait Copy : Clone { /// This trait is automatically implemented when the compiler determines /// it's appropriate. /// -/// The precise definition is: a type `T` is `Sync` if `&T` is +/// The precise definition is: a type `T` is `Sync` if and only if `&T` is /// [`Send`][send]. In other words, if there is no possibility of /// [undefined behavior][ub] (including data races) when passing /// `&T` references between threads. @@ -595,23 +603,38 @@ unsafe impl Freeze for *mut T {} unsafe impl<'a, T: ?Sized> Freeze for &'a T {} unsafe impl<'a, T: ?Sized> Freeze for &'a mut T {} -/// Types which can be moved out of a `Pin`. +/// Types which can be moved out of a `PinMut`. /// -/// The `Unpin` trait is used to control the behavior of the [`Pin`] type. If a +/// The `Unpin` trait is used to control the behavior of the [`PinMut`] type. If a /// type implements `Unpin`, it is safe to move a value of that type out of the -/// `Pin` pointer. +/// `PinMut` pointer. /// /// This trait is automatically implemented for almost every type. /// -/// [`Pin`]: ../mem/struct.Pin.html +/// [`PinMut`]: ../mem/struct.PinMut.html +#[unstable(feature = "pin", issue = "49150")] +pub auto trait Unpin {} + +/// A type which does not implement `Unpin`. +/// +/// If a type contains a `Pinned`, it will not implement `Unpin` by default. +#[unstable(feature = "pin", issue = "49150")] +#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub struct Pinned; + +#[unstable(feature = "pin", issue = "49150")] +impl !Unpin for Pinned {} + +#[unstable(feature = "pin", issue = "49150")] +impl<'a, T: ?Sized + 'a> Unpin for &'a T {} + #[unstable(feature = "pin", issue = "49150")] -pub unsafe auto trait Unpin {} +impl<'a, T: ?Sized + 'a> Unpin for &'a mut T {} /// Implementations of `Copy` for primitive types. /// /// Implementations that cannot be described in Rust /// are implemented in `SelectionContext::copy_clone_conditions()` in librustc. -#[cfg(not(stage0))] mod copy_impls { use super::Copy; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index 10efab82ddff5..1a54f03bb0067 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -18,10 +18,12 @@ use clone; use cmp; use fmt; +use future::{Future, UnsafeFutureObj}; use hash; use intrinsics; use marker::{Copy, PhantomData, Sized, Unpin, Unsize}; use ptr; +use task::{Context, Poll}; use ops::{Deref, DerefMut, CoerceUnsized}; #[stable(feature = "rust1", since = "1.0.0")] @@ -194,10 +196,12 @@ pub fn forget(t: T) { /// u16 | 2 /// u32 | 4 /// u64 | 8 +/// u128 | 16 /// i8 | 1 /// i16 | 2 /// i32 | 4 /// i64 | 8 +/// i128 | 16 /// f32 | 4 /// f64 | 8 /// char | 4 @@ -225,6 +229,8 @@ pub fn forget(t: T) { /// 2. Round up the current size to the nearest multiple of the next field's [alignment]. /// /// Finally, round the size of the struct to the nearest multiple of its [alignment]. +/// The alignment of the struct is usually the largest alignment of all its +/// fields; this can be changed with the use of `repr(align(N))`. /// /// Unlike `C`, zero sized structs are not rounded up to one byte in size. /// @@ -279,7 +285,8 @@ pub fn forget(t: T) { /// // The size of the second field is 2, so add 2 to the size. Size is 4. /// // The alignment of the third field is 1, so add 0 to the size for padding. Size is 4. /// // The size of the third field is 1, so add 1 to the size. Size is 5. -/// // Finally, the alignment of the struct is 2, so add 1 to the size for padding. Size is 6. +/// // Finally, the alignment of the struct is 2 (because the largest alignment amongst its +/// // fields is 2), so add 1 to the size for padding. Size is 6. /// assert_eq!(6, mem::size_of::()); /// /// #[repr(C)] @@ -631,12 +638,13 @@ pub unsafe fn uninitialized() -> T { #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { unsafe { - ptr::swap_nonoverlapping(x, y, 1); + ptr::swap_nonoverlapping_one(x, y); } } -/// Replaces the value at a mutable location with a new one, returning the old value, without -/// deinitializing either one. +/// Moves `src` into the referenced `dest`, returning the previous `dest` value. +/// +/// Neither value is dropped. /// /// # Examples /// @@ -835,7 +843,9 @@ pub unsafe fn transmute_copy(src: &T) -> U { /// Opaque type representing the discriminant of an enum. /// -/// See the `discriminant` function in this module for more information. +/// See the [`discriminant`] function in this module for more information. +/// +/// [`discriminant`]: fn.discriminant.html #[stable(feature = "discriminant_value", since = "1.21.0")] pub struct Discriminant(u64, PhantomData T>); @@ -908,7 +918,6 @@ pub fn discriminant(v: &T) -> Discriminant { } } - /// A wrapper to inhibit compiler from automatically calling `T`’s destructor. /// /// This wrapper is 0-cost. @@ -944,11 +953,18 @@ pub fn discriminant(v: &T) -> Discriminant { /// } /// } /// ``` +#[cfg(not(stage0))] #[stable(feature = "manually_drop", since = "1.20.0")] -#[allow(unions_with_drop_fields)] -#[derive(Copy)] -pub union ManuallyDrop{ value: T } +#[lang = "manually_drop"] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ManuallyDrop { + value: T, +} +#[cfg(stage0)] +include!("manually_drop_stage0.rs"); + +#[cfg(not(stage0))] impl ManuallyDrop { /// Wrap a value to be manually dropped. /// @@ -959,9 +975,10 @@ impl ManuallyDrop { /// ManuallyDrop::new(Box::new(())); /// ``` #[stable(feature = "manually_drop", since = "1.20.0")] + #[rustc_const_unstable(feature = "const_manually_drop_new")] #[inline] - pub fn new(value: T) -> ManuallyDrop { - ManuallyDrop { value: value } + pub const fn new(value: T) -> ManuallyDrop { + ManuallyDrop { value } } /// Extract the value from the ManuallyDrop container. @@ -976,9 +993,7 @@ impl ManuallyDrop { #[stable(feature = "manually_drop", since = "1.20.0")] #[inline] pub fn into_inner(slot: ManuallyDrop) -> T { - unsafe { - slot.value - } + slot.value } /// Manually drops the contained value. @@ -995,102 +1010,22 @@ impl ManuallyDrop { } } +#[cfg(not(stage0))] #[stable(feature = "manually_drop", since = "1.20.0")] impl Deref for ManuallyDrop { type Target = T; #[inline] fn deref(&self) -> &Self::Target { - unsafe { - &self.value - } + &self.value } } +#[cfg(not(stage0))] #[stable(feature = "manually_drop", since = "1.20.0")] impl DerefMut for ManuallyDrop { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { - unsafe { - &mut self.value - } - } -} - -#[stable(feature = "manually_drop", since = "1.20.0")] -impl ::fmt::Debug for ManuallyDrop { - fn fmt(&self, fmt: &mut ::fmt::Formatter) -> ::fmt::Result { - unsafe { - fmt.debug_tuple("ManuallyDrop").field(&self.value).finish() - } - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl Clone for ManuallyDrop { - fn clone(&self) -> Self { - ManuallyDrop::new(self.deref().clone()) - } - - fn clone_from(&mut self, source: &Self) { - self.deref_mut().clone_from(source); - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl Default for ManuallyDrop { - fn default() -> Self { - ManuallyDrop::new(Default::default()) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl PartialEq for ManuallyDrop { - fn eq(&self, other: &Self) -> bool { - self.deref().eq(other) - } - - fn ne(&self, other: &Self) -> bool { - self.deref().ne(other) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl Eq for ManuallyDrop {} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl PartialOrd for ManuallyDrop { - fn partial_cmp(&self, other: &Self) -> Option<::cmp::Ordering> { - self.deref().partial_cmp(other) - } - - fn lt(&self, other: &Self) -> bool { - self.deref().lt(other) - } - - fn le(&self, other: &Self) -> bool { - self.deref().le(other) - } - - fn gt(&self, other: &Self) -> bool { - self.deref().gt(other) - } - - fn ge(&self, other: &Self) -> bool { - self.deref().ge(other) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl Ord for ManuallyDrop { - fn cmp(&self, other: &Self) -> ::cmp::Ordering { - self.deref().cmp(other) - } -} - -#[stable(feature = "manually_drop_impls", since = "1.22.0")] -impl ::hash::Hash for ManuallyDrop { - fn hash(&self, state: &mut H) { - self.deref().hash(state); + &mut self.value } } @@ -1101,69 +1036,86 @@ impl ::hash::Hash for ManuallyDrop { /// value implements the `Unpin` trait. #[unstable(feature = "pin", issue = "49150")] #[fundamental] -pub struct Pin<'a, T: ?Sized + 'a> { +pub struct PinMut<'a, T: ?Sized + 'a> { inner: &'a mut T, } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unpin> Pin<'a, T> { - /// Construct a new `Pin` around a reference to some data of a type that +impl<'a, T: ?Sized + Unpin> PinMut<'a, T> { + /// Construct a new `PinMut` around a reference to some data of a type that /// implements `Unpin`. #[unstable(feature = "pin", issue = "49150")] - pub fn new(reference: &'a mut T) -> Pin<'a, T> { - Pin { inner: reference } + pub fn new(reference: &'a mut T) -> PinMut<'a, T> { + PinMut { inner: reference } + } + + /// Get a mutable reference to the data inside of this `PinMut`. + #[unstable(feature = "pin", issue = "49150")] + pub fn get_mut(this: PinMut<'a, T>) -> &'a mut T { + this.inner } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Pin<'a, T> { - /// Construct a new `Pin` around a reference to some data of a type that +impl<'a, T: ?Sized> PinMut<'a, T> { + /// Construct a new `PinMut` around a reference to some data of a type that /// may or may not implement `Unpin`. /// /// This constructor is unsafe because we do not know what will happen with /// that data after the reference ends. If you cannot guarantee that the /// data will never move again, calling this constructor is invalid. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn new_unchecked(reference: &'a mut T) -> Pin<'a, T> { - Pin { inner: reference } + pub unsafe fn new_unchecked(reference: &'a mut T) -> PinMut<'a, T> { + PinMut { inner: reference } } - /// Borrow a Pin for a shorter lifetime than it already has. + /// Reborrow a `PinMut` for a shorter lifetime. + /// + /// For example, `PinMut::get_mut(x.reborrow())` (unsafely) returns a + /// short-lived mutable reference reborrowing from `x`. #[unstable(feature = "pin", issue = "49150")] - pub fn borrow<'b>(this: &'b mut Pin<'a, T>) -> Pin<'b, T> { - Pin { inner: this.inner } + pub fn reborrow<'b>(&'b mut self) -> PinMut<'b, T> { + PinMut { inner: self.inner } } - /// Get a mutable reference to the data inside of this `Pin`. + /// Get a mutable reference to the data inside of this `PinMut`. /// /// This function is unsafe. You must guarantee that you will never move /// the data out of the mutable reference you receive when you call this /// function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn get_mut<'b>(this: &'b mut Pin<'a, T>) -> &'b mut T { + pub unsafe fn get_mut_unchecked(this: PinMut<'a, T>) -> &'a mut T { this.inner } /// Construct a new pin by mapping the interior value. /// - /// For example, if you wanted to get a `Pin` of a field of something, you - /// could use this to get access to that field in one line of code. + /// For example, if you wanted to get a `PinMut` of a field of something, + /// you could use this to get access to that field in one line of code. /// /// This function is unsafe. You must guarantee that the data you return /// will not move so long as the argument value does not move (for example, /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. #[unstable(feature = "pin", issue = "49150")] - pub unsafe fn map<'b, U, F>(this: &'b mut Pin<'a, T>, f: F) -> Pin<'b, U> where + pub unsafe fn map_unchecked(this: PinMut<'a, T>, f: F) -> PinMut<'a, U> where F: FnOnce(&mut T) -> &mut U { - Pin { inner: f(this.inner) } + PinMut { inner: f(this.inner) } + } + + /// Assign a new value to the memory behind the pinned reference. + #[unstable(feature = "pin", issue = "49150")] + pub fn set(this: PinMut<'a, T>, value: T) + where T: Sized, + { + *this.inner = value; } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> Deref for Pin<'a, T> { +impl<'a, T: ?Sized> Deref for PinMut<'a, T> { type Target = T; fn deref(&self) -> &T { @@ -1172,35 +1124,50 @@ impl<'a, T: ?Sized> Deref for Pin<'a, T> { } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unpin> DerefMut for Pin<'a, T> { +impl<'a, T: ?Sized + Unpin> DerefMut for PinMut<'a, T> { fn deref_mut(&mut self) -> &mut T { self.inner } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for Pin<'a, T> { +impl<'a, T: fmt::Debug + ?Sized> fmt::Debug for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Debug::fmt(&**self, f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: fmt::Display + ?Sized> fmt::Display for Pin<'a, T> { +impl<'a, T: fmt::Display + ?Sized> fmt::Display for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&**self, f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized> fmt::Pointer for Pin<'a, T> { +impl<'a, T: ?Sized> fmt::Pointer for PinMut<'a, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Pointer::fmt(&(&*self.inner as *const T), f) } } #[unstable(feature = "pin", issue = "49150")] -impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for Pin<'a, T> {} +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PinMut<'a, T> {} #[unstable(feature = "pin", issue = "49150")] -unsafe impl<'a, T: ?Sized> Unpin for Pin<'a, T> {} +impl<'a, T: ?Sized> Unpin for PinMut<'a, T> {} + +#[unstable(feature = "futures_api", issue = "50547")] +unsafe impl<'a, T, F> UnsafeFutureObj<'a, T> for PinMut<'a, F> + where F: Future + 'a +{ + fn into_raw(self) -> *mut () { + unsafe { PinMut::get_mut_unchecked(self) as *mut F as *mut () } + } + + unsafe fn poll(ptr: *mut (), cx: &mut Context) -> Poll { + PinMut::new_unchecked(&mut *(ptr as *mut F)).poll(cx) + } + + unsafe fn drop(_ptr: *mut ()) {} +} diff --git a/src/libcore/nonzero.rs b/src/libcore/nonzero.rs index 19836d98844e2..cc36ea7f71391 100644 --- a/src/libcore/nonzero.rs +++ b/src/libcore/nonzero.rs @@ -9,103 +9,14 @@ // except according to those terms. //! Exposes the NonZero lang item which provides optimization hints. -#![unstable(feature = "nonzero", reason = "deprecated", issue = "49137")] -#![rustc_deprecated(reason = "use `std::ptr::NonNull` or `std::num::NonZero*` instead", - since = "1.26.0")] -#![allow(deprecated)] use ops::CoerceUnsized; -/// Unsafe trait to indicate what types are usable with the NonZero struct -pub unsafe trait Zeroable { - /// Whether this value is zero - fn is_zero(&self) -> bool; -} - -macro_rules! impl_zeroable_for_pointer_types { - ( $( $Ptr: ty )+ ) => { - $( - /// For fat pointers to be considered "zero", only the "data" part needs to be null. - unsafe impl Zeroable for $Ptr { - #[inline] - fn is_zero(&self) -> bool { - (*self).is_null() - } - } - )+ - } -} - -macro_rules! impl_zeroable_for_integer_types { - ( $( $Int: ty )+ ) => { - $( - unsafe impl Zeroable for $Int { - #[inline] - fn is_zero(&self) -> bool { - *self == 0 - } - } - )+ - } -} - -impl_zeroable_for_pointer_types! { - *const T - *mut T -} - -impl_zeroable_for_integer_types! { - usize u8 u16 u32 u64 u128 - isize i8 i16 i32 i64 i128 -} - /// A wrapper type for raw pointers and integers that will never be /// NULL or 0 that might allow certain optimizations. #[lang = "non_zero"] -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)] -pub struct NonZero(pub(crate) T); - -impl NonZero { - /// Creates an instance of NonZero with the provided value. - /// You must indeed ensure that the value is actually "non-zero". - #[inline] - pub const unsafe fn new_unchecked(inner: T) -> Self { - NonZero(inner) - } - - /// Creates an instance of NonZero with the provided value. - #[inline] - pub fn new(inner: T) -> Option { - if inner.is_zero() { - None - } else { - Some(NonZero(inner)) - } - } - - /// Gets the inner value. - pub fn get(self) -> T { - self.0 - } -} - -impl, U: Zeroable> CoerceUnsized> for NonZero {} - -impl<'a, T: ?Sized> From<&'a mut T> for NonZero<*mut T> { - fn from(reference: &'a mut T) -> Self { - NonZero(reference) - } -} - -impl<'a, T: ?Sized> From<&'a mut T> for NonZero<*const T> { - fn from(reference: &'a mut T) -> Self { - let ptr: *mut T = reference; - NonZero(ptr) - } -} +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); -impl<'a, T: ?Sized> From<&'a T> for NonZero<*const T> { - fn from(reference: &'a T) -> Self { - NonZero(reference) - } -} +impl, U> CoerceUnsized> for NonZero {} diff --git a/src/libcore/num/dec2flt/rawfp.rs b/src/libcore/num/dec2flt/rawfp.rs index 77180233a2389..456d0e956d42a 100644 --- a/src/libcore/num/dec2flt/rawfp.rs +++ b/src/libcore/num/dec2flt/rawfp.rs @@ -33,7 +33,7 @@ use ops::{Add, Mul, Div, Neg}; use fmt::{Debug, LowerExp}; use num::diy_float::Fp; use num::FpCategory::{Infinite, Zero, Subnormal, Normal, Nan}; -use num::Float; +use num::FpCategory; use num::dec2flt::num::{self, Big}; use num::dec2flt::table; @@ -54,24 +54,29 @@ impl Unpacked { /// See the parent module's doc comment for why this is necessary. /// /// Should **never ever** be implemented for other types or be used outside the dec2flt module. -/// Inherits from `Float` because there is some overlap, but all the reused methods are trivial. pub trait RawFloat - : Float - + Copy + : Copy + Debug + LowerExp + Mul + Div + Neg -where - Self: Float::RawBits> { const INFINITY: Self; const NAN: Self; const ZERO: Self; - /// Same as `Float::Bits` with extra traits. - type RawBits: Add + From + TryFrom; + /// Type used by `to_bits` and `from_bits`. + type Bits: Add + From + TryFrom; + + /// Raw transmutation to integer. + fn to_bits(self) -> Self::Bits; + + /// Raw transmutation from integer. + fn from_bits(v: Self::Bits) -> Self; + + /// Returns the category that this number falls into. + fn classify(self) -> FpCategory; /// Returns the mantissa, exponent and sign as integers. fn integer_decode(self) -> (u64, i16, i8); @@ -153,7 +158,7 @@ macro_rules! other_constants { } impl RawFloat for f32 { - type RawBits = u32; + type Bits = u32; const SIG_BITS: u8 = 24; const EXP_BITS: u8 = 8; @@ -192,11 +197,15 @@ impl RawFloat for f32 { fn short_fast_pow10(e: usize) -> Self { table::F32_SHORT_POWERS[e] } + + fn classify(self) -> FpCategory { self.classify() } + fn to_bits(self) -> Self::Bits { self.to_bits() } + fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) } } impl RawFloat for f64 { - type RawBits = u64; + type Bits = u64; const SIG_BITS: u8 = 53; const EXP_BITS: u8 = 11; @@ -235,6 +244,10 @@ impl RawFloat for f64 { fn short_fast_pow10(e: usize) -> Self { table::F64_SHORT_POWERS[e] } + + fn classify(self) -> FpCategory { self.classify() } + fn to_bits(self) -> Self::Bits { self.to_bits() } + fn from_bits(v: Self::Bits) -> Self { Self::from_bits(v) } } /// Convert an Fp to the closest machine float type. diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 8d5f6f601daf8..577c823f9a060 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -11,16 +11,14 @@ //! This module provides constants which are specific to the implementation //! of the `f32` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f32` primitive type](../../std/primitive.f32.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] use mem; -use num::Float; -#[cfg(not(stage0))] use num::FpCategory; -use num::FpCategory as Fp; +use num::FpCategory; /// The radix or base of the internal representation of `f32`. #[stable(feature = "rust1", since = "1.0.0")] @@ -33,7 +31,11 @@ pub const MANTISSA_DIGITS: u32 = 24; #[stable(feature = "rust1", since = "1.0.0")] pub const DIGITS: u32 = 6; -/// Difference between `1.0` and the next largest representable number. +/// [Machine epsilon] value for `f32`. +/// +/// This is the difference between `1.0` and the next largest representable number. +/// +/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon #[stable(feature = "rust1", since = "1.0.0")] pub const EPSILON: f32 = 1.19209290e-07_f32; @@ -128,10 +130,18 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const LOG2_E: f32 = 1.44269504088896340735992468100189214_f32; + /// log2(10) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG2_10: f32 = 3.32192809488736234787031942948939018_f32; + /// log10(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG10_E: f32 = 0.434294481903251827651128918916605082_f32; + /// log10(2) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG10_2: f32 = 0.301029995663981195213738894724493027_f32; + /// ln(2) #[stable(feature = "rust1", since = "1.0.0")] pub const LN_2: f32 = 0.693147180559945309417232121458176568_f32; @@ -141,137 +151,9 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] -impl Float for f32 { - type Bits = u32; - - /// Returns `true` if the number is NaN. - #[inline] - fn is_nan(self) -> bool { - self != self - } - - /// Returns `true` if the number is infinite. - #[inline] - fn is_infinite(self) -> bool { - self == INFINITY || self == NEG_INFINITY - } - - /// Returns `true` if the number is neither infinite or NaN. - #[inline] - fn is_finite(self) -> bool { - !(self.is_nan() || self.is_infinite()) - } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN. - #[inline] - fn is_normal(self) -> bool { - self.classify() == Fp::Normal - } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - fn classify(self) -> Fp { - const EXP_MASK: u32 = 0x7f800000; - const MAN_MASK: u32 = 0x007fffff; - - let bits = self.to_bits(); - match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => Fp::Zero, - (_, 0) => Fp::Subnormal, - (0, EXP_MASK) => Fp::Infinite, - (_, EXP_MASK) => Fp::Nan, - _ => Fp::Normal, - } - } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - #[inline] - fn is_sign_positive(self) -> bool { - !self.is_sign_negative() - } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - #[inline] - fn is_sign_negative(self) -> bool { - // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus - // applies to zeros and NaNs as well. - self.to_bits() & 0x8000_0000 != 0 - } - - /// Returns the reciprocal (multiplicative inverse) of the number. - #[inline] - fn recip(self) -> f32 { - 1.0 / self - } - - /// Converts to degrees, assuming the number is in radians. - #[inline] - fn to_degrees(self) -> f32 { - // Use a constant for better precision. - const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; - self * PIS_IN_180 - } - - /// Converts to radians, assuming the number is in degrees. - #[inline] - fn to_radians(self) -> f32 { - let value: f32 = consts::PI; - self * (value / 180.0f32) - } - - /// Returns the maximum of the two numbers. - #[inline] - fn max(self, other: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self.is_nan() || self < other { other } else { self }) * 1.0 - } - - /// Returns the minimum of the two numbers. - #[inline] - fn min(self, other: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if other.is_nan() || self < other { self } else { other }) * 1.0 - } - - /// Raw transmutation to `u32`. - #[inline] - fn to_bits(self) -> u32 { - unsafe { mem::transmute(self) } - } - - /// Raw transmutation from `u32`. - #[inline] - fn from_bits(v: u32) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { mem::transmute(v) } - } -} - -// FIXME: remove (inline) this macro and the Float trait -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_float", issue = "32110")] -macro_rules! f32_core_methods { () => { +#[lang = "f32"] +#[cfg(not(test))] +impl f32 { /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` @@ -285,7 +167,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_nan(self) -> bool { Float::is_nan(self) } + pub fn is_nan(self) -> bool { + self != self + } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -306,7 +190,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + pub fn is_infinite(self) -> bool { + self == INFINITY || self == NEG_INFINITY + } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -326,7 +212,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_finite(self) -> bool { Float::is_finite(self) } + pub fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -351,7 +239,9 @@ macro_rules! f32_core_methods { () => { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_normal(self) -> bool { Float::is_normal(self) } + pub fn is_normal(self) -> bool { + self.classify() == FpCategory::Normal + } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific @@ -368,8 +258,19 @@ macro_rules! f32_core_methods { () => { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { Float::classify(self) } + pub fn classify(self) -> FpCategory { + const EXP_MASK: u32 = 0x7f800000; + const MAN_MASK: u32 = 0x007fffff; + + let bits = self.to_bits(); + match (bits & MAN_MASK, bits & EXP_MASK) { + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + (0, EXP_MASK) => FpCategory::Infinite, + (_, EXP_MASK) => FpCategory::Nan, + _ => FpCategory::Normal, + } + } /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. @@ -383,7 +284,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with /// negative sign bit and negative infinity. @@ -397,7 +300,11 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_sign_negative(self) -> bool { + // IEEE754 says: isSignMinus(x) is true if and only if x has negative sign. isSignMinus + // applies to zeros and NaNs as well. + self.to_bits() & 0x8000_0000 != 0 + } /// Takes the reciprocal (inverse) of a number, `1/x`. /// @@ -411,7 +318,9 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn recip(self) -> f32 { Float::recip(self) } + pub fn recip(self) -> f32 { + 1.0 / self + } /// Converts radians to degrees. /// @@ -426,7 +335,11 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] #[inline] - pub fn to_degrees(self) -> f32 { Float::to_degrees(self) } + pub fn to_degrees(self) -> f32 { + // Use a constant for better precision. + const PIS_IN_180: f32 = 57.2957795130823208767981548141051703_f32; + self * PIS_IN_180 + } /// Converts degrees to radians. /// @@ -441,7 +354,10 @@ macro_rules! f32_core_methods { () => { /// ``` #[stable(feature = "f32_deg_rad_conversions", since="1.7.0")] #[inline] - pub fn to_radians(self) -> f32 { Float::to_radians(self) } + pub fn to_radians(self) -> f32 { + let value: f32 = consts::PI; + self * (value / 180.0f32) + } /// Returns the maximum of the two numbers. /// @@ -456,7 +372,15 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f32) -> f32 { - Float::max(self, other) + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self.is_nan() || self < other { other } else { self }) * 1.0 } /// Returns the minimum of the two numbers. @@ -472,7 +396,15 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f32) -> f32 { - Float::min(self, other) + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if other.is_nan() || self < other { self } else { other }) * 1.0 } /// Raw transmutation to `u32`. @@ -495,7 +427,7 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u32 { - Float::to_bits(self) + unsafe { mem::transmute(self) } } /// Raw transmutation from `u32`. @@ -539,13 +471,7 @@ macro_rules! f32_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u32) -> Self { - Float::from_bits(v) + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { mem::transmute(v) } } -}} - -#[lang = "f32"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl f32 { - f32_core_methods!(); } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 08b869734d496..b8e3dd6ed646c 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -11,16 +11,14 @@ //! This module provides constants which are specific to the implementation //! of the `f64` floating point data type. //! -//! Mathematically significant numbers are provided in the `consts` sub-module. -//! //! *[See also the `f64` primitive type](../../std/primitive.f64.html).* +//! +//! Mathematically significant numbers are provided in the `consts` sub-module. #![stable(feature = "rust1", since = "1.0.0")] use mem; -use num::Float; -#[cfg(not(stage0))] use num::FpCategory; -use num::FpCategory as Fp; +use num::FpCategory; /// The radix or base of the internal representation of `f64`. #[stable(feature = "rust1", since = "1.0.0")] @@ -33,7 +31,11 @@ pub const MANTISSA_DIGITS: u32 = 53; #[stable(feature = "rust1", since = "1.0.0")] pub const DIGITS: u32 = 15; -/// Difference between `1.0` and the next largest representable number. +/// [Machine epsilon] value for `f64`. +/// +/// This is the difference between `1.0` and the next largest representable number. +/// +/// [Machine epsilon]: https://en.wikipedia.org/wiki/Machine_epsilon #[stable(feature = "rust1", since = "1.0.0")] pub const EPSILON: f64 = 2.2204460492503131e-16_f64; @@ -124,10 +126,18 @@ pub mod consts { #[stable(feature = "rust1", since = "1.0.0")] pub const E: f64 = 2.71828182845904523536028747135266250_f64; + /// log2(10) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG2_10: f64 = 3.32192809488736234787031942948939018_f64; + /// log2(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG2_E: f64 = 1.44269504088896340735992468100189214_f64; + /// log10(2) + #[unstable(feature = "extra_log_consts", issue = "50540")] + pub const LOG10_2: f64 = 0.301029995663981195213738894724493027_f64; + /// log10(e) #[stable(feature = "rust1", since = "1.0.0")] pub const LOG10_E: f64 = 0.434294481903251827651128918916605082_f64; @@ -141,136 +151,9 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } -#[unstable(feature = "core_float", - reason = "stable interface is via `impl f{32,64}` in later crates", - issue = "32110")] -impl Float for f64 { - type Bits = u64; - - /// Returns `true` if the number is NaN. - #[inline] - fn is_nan(self) -> bool { - self != self - } - - /// Returns `true` if the number is infinite. - #[inline] - fn is_infinite(self) -> bool { - self == INFINITY || self == NEG_INFINITY - } - - /// Returns `true` if the number is neither infinite or NaN. - #[inline] - fn is_finite(self) -> bool { - !(self.is_nan() || self.is_infinite()) - } - - /// Returns `true` if the number is neither zero, infinite, subnormal or NaN. - #[inline] - fn is_normal(self) -> bool { - self.classify() == Fp::Normal - } - - /// Returns the floating point category of the number. If only one property - /// is going to be tested, it is generally faster to use the specific - /// predicate instead. - fn classify(self) -> Fp { - const EXP_MASK: u64 = 0x7ff0000000000000; - const MAN_MASK: u64 = 0x000fffffffffffff; - - let bits = self.to_bits(); - match (bits & MAN_MASK, bits & EXP_MASK) { - (0, 0) => Fp::Zero, - (_, 0) => Fp::Subnormal, - (0, EXP_MASK) => Fp::Infinite, - (_, EXP_MASK) => Fp::Nan, - _ => Fp::Normal, - } - } - - /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with - /// positive sign bit and positive infinity. - #[inline] - fn is_sign_positive(self) -> bool { - !self.is_sign_negative() - } - - /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with - /// negative sign bit and negative infinity. - #[inline] - fn is_sign_negative(self) -> bool { - self.to_bits() & 0x8000_0000_0000_0000 != 0 - } - - /// Returns the reciprocal (multiplicative inverse) of the number. - #[inline] - fn recip(self) -> f64 { - 1.0 / self - } - - /// Converts to degrees, assuming the number is in radians. - #[inline] - fn to_degrees(self) -> f64 { - // The division here is correctly rounded with respect to the true - // value of 180/π. (This differs from f32, where a constant must be - // used to ensure a correctly rounded result.) - self * (180.0f64 / consts::PI) - } - - /// Converts to radians, assuming the number is in degrees. - #[inline] - fn to_radians(self) -> f64 { - let value: f64 = consts::PI; - self * (value / 180.0) - } - - /// Returns the maximum of the two numbers. - #[inline] - fn max(self, other: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self.is_nan() || self < other { other } else { self }) * 1.0 - } - - /// Returns the minimum of the two numbers. - #[inline] - fn min(self, other: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if other.is_nan() || self < other { self } else { other }) * 1.0 - } - - /// Raw transmutation to `u64`. - #[inline] - fn to_bits(self) -> u64 { - unsafe { mem::transmute(self) } - } - - /// Raw transmutation from `u64`. - #[inline] - fn from_bits(v: u64) -> Self { - // It turns out the safety issues with sNaN were overblown! Hooray! - unsafe { mem::transmute(v) } - } -} - -// FIXME: remove (inline) this macro and the Float trait -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_float", issue = "32110")] -macro_rules! f64_core_methods { () => { +#[lang = "f64"] +#[cfg(not(test))] +impl f64 { /// Returns `true` if this value is `NaN` and false otherwise. /// /// ``` @@ -284,7 +167,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_nan(self) -> bool { Float::is_nan(self) } + pub fn is_nan(self) -> bool { + self != self + } /// Returns `true` if this value is positive infinity or negative infinity and /// false otherwise. @@ -305,7 +190,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_infinite(self) -> bool { Float::is_infinite(self) } + pub fn is_infinite(self) -> bool { + self == INFINITY || self == NEG_INFINITY + } /// Returns `true` if this number is neither infinite nor `NaN`. /// @@ -325,7 +212,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_finite(self) -> bool { Float::is_finite(self) } + pub fn is_finite(self) -> bool { + !(self.is_nan() || self.is_infinite()) + } /// Returns `true` if the number is neither zero, infinite, /// [subnormal][subnormal], or `NaN`. @@ -350,7 +239,9 @@ macro_rules! f64_core_methods { () => { /// [subnormal]: https://en.wikipedia.org/wiki/Denormal_number #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_normal(self) -> bool { Float::is_normal(self) } + pub fn is_normal(self) -> bool { + self.classify() == FpCategory::Normal + } /// Returns the floating point category of the number. If only one property /// is going to be tested, it is generally faster to use the specific @@ -367,8 +258,19 @@ macro_rules! f64_core_methods { () => { /// assert_eq!(inf.classify(), FpCategory::Infinite); /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn classify(self) -> FpCategory { Float::classify(self) } + pub fn classify(self) -> FpCategory { + const EXP_MASK: u64 = 0x7ff0000000000000; + const MAN_MASK: u64 = 0x000fffffffffffff; + + let bits = self.to_bits(); + match (bits & MAN_MASK, bits & EXP_MASK) { + (0, 0) => FpCategory::Zero, + (_, 0) => FpCategory::Subnormal, + (0, EXP_MASK) => FpCategory::Infinite, + (_, EXP_MASK) => FpCategory::Nan, + _ => FpCategory::Normal, + } + } /// Returns `true` if and only if `self` has a positive sign, including `+0.0`, `NaN`s with /// positive sign bit and positive infinity. @@ -382,13 +284,17 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_sign_positive(self) -> bool { + !self.is_sign_negative() + } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_positive")] #[inline] #[doc(hidden)] - pub fn is_positive(self) -> bool { Float::is_sign_positive(self) } + pub fn is_positive(self) -> bool { + self.is_sign_positive() + } /// Returns `true` if and only if `self` has a negative sign, including `-0.0`, `NaN`s with /// negative sign bit and negative infinity. @@ -402,13 +308,17 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_sign_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_sign_negative(self) -> bool { + self.to_bits() & 0x8000_0000_0000_0000 != 0 + } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated(since = "1.0.0", reason = "renamed to is_sign_negative")] #[inline] #[doc(hidden)] - pub fn is_negative(self) -> bool { Float::is_sign_negative(self) } + pub fn is_negative(self) -> bool { + self.is_sign_negative() + } /// Takes the reciprocal (inverse) of a number, `1/x`. /// @@ -420,7 +330,9 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn recip(self) -> f64 { Float::recip(self) } + pub fn recip(self) -> f64 { + 1.0 / self + } /// Converts radians to degrees. /// @@ -435,7 +347,12 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_degrees(self) -> f64 { Float::to_degrees(self) } + pub fn to_degrees(self) -> f64 { + // The division here is correctly rounded with respect to the true + // value of 180/π. (This differs from f32, where a constant must be + // used to ensure a correctly rounded result.) + self * (180.0f64 / consts::PI) + } /// Converts degrees to radians. /// @@ -450,7 +367,10 @@ macro_rules! f64_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn to_radians(self) -> f64 { Float::to_radians(self) } + pub fn to_radians(self) -> f64 { + let value: f64 = consts::PI; + self * (value / 180.0) + } /// Returns the maximum of the two numbers. /// @@ -465,7 +385,15 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn max(self, other: f64) -> f64 { - Float::max(self, other) + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if self.is_nan() || self < other { other } else { self }) * 1.0 } /// Returns the minimum of the two numbers. @@ -481,7 +409,15 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn min(self, other: f64) -> f64 { - Float::min(self, other) + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if other.is_nan() || self < other { self } else { other }) * 1.0 } /// Raw transmutation to `u64`. @@ -504,7 +440,7 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn to_bits(self) -> u64 { - Float::to_bits(self) + unsafe { mem::transmute(self) } } /// Raw transmutation from `u64`. @@ -548,13 +484,7 @@ macro_rules! f64_core_methods { () => { #[stable(feature = "float_bits_conv", since = "1.20.0")] #[inline] pub fn from_bits(v: u64) -> Self { - Float::from_bits(v) + // It turns out the safety issues with sNaN were overblown! Hooray! + unsafe { mem::transmute(v) } } -}} - -#[lang = "f64"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl f64 { - f64_core_methods!(); } diff --git a/src/libcore/num/flt2dec/strategy/dragon.rs b/src/libcore/num/flt2dec/strategy/dragon.rs index 6aa4f297e75ba..aa6a08cb2057e 100644 --- a/src/libcore/num/flt2dec/strategy/dragon.rs +++ b/src/libcore/num/flt2dec/strategy/dragon.rs @@ -8,12 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! -Almost direct (but slightly optimized) Rust translation of Figure 3 of [1]. - -[1] Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers - quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. -*/ +//! Almost direct (but slightly optimized) Rust translation of Figure 3 of "Printing +//! Floating-Point Numbers Quickly and Accurately"[^1]. +//! +//! [^1]: Burger, R. G. and Dybvig, R. K. 1996. Printing floating-point numbers +//! quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. use cmp::Ordering; diff --git a/src/libcore/num/flt2dec/strategy/grisu.rs b/src/libcore/num/flt2dec/strategy/grisu.rs index cf70a1978f5e6..f33186e59c2e6 100644 --- a/src/libcore/num/flt2dec/strategy/grisu.rs +++ b/src/libcore/num/flt2dec/strategy/grisu.rs @@ -8,13 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -/*! -Rust adaptation of Grisu3 algorithm described in [1]. It uses about -1KB of precomputed table, and in turn, it's very quick for most inputs. - -[1] Florian Loitsch. 2010. Printing floating-point numbers quickly and - accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. -*/ +//! Rust adaptation of the Grisu3 algorithm described in "Printing Floating-Point Numbers Quickly +//! and Accurately with Integers"[^1]. It uses about 1KB of precomputed table, and in turn, it's +//! very quick for most inputs. +//! +//! [^1]: Florian Loitsch. 2010. Printing floating-point numbers quickly and +//! accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. use num::diy_float::Fp; use num::flt2dec::{Decoded, MAX_SIG_DIGITS, round_up}; diff --git a/src/libcore/num/mod.rs b/src/libcore/num/mod.rs index a062fbda5bad0..0b8f8f0703df7 100644 --- a/src/libcore/num/mod.rs +++ b/src/libcore/num/mod.rs @@ -16,15 +16,14 @@ use convert::TryFrom; use fmt; use intrinsics; use mem; -#[allow(deprecated)] use nonzero::NonZero; +use nonzero::NonZero; use ops; use str::FromStr; macro_rules! impl_nonzero_fmt { - ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + ( ( $( $Trait: ident ),+ ) for $Ty: ident ) => { $( - #[$stability] - #[allow(deprecated)] + #[stable(feature = "nonzero", since = "1.28.0")] impl fmt::$Trait for $Ty { #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -36,38 +35,36 @@ macro_rules! impl_nonzero_fmt { } macro_rules! nonzero_integers { - ( #[$stability: meta] #[$deprecation: meta] $( $Ty: ident($Int: ty); )+ ) => { + ( $( $Ty: ident($Int: ty); )+ ) => { $( /// An integer that is known not to equal zero. /// - /// This may enable some memory layout optimization such as: + /// This enables some memory layout optimization. + /// For example, `Option` is the same size as `u32`: /// /// ```rust - /// # #![feature(nonzero)] /// use std::mem::size_of; /// assert_eq!(size_of::>(), size_of::()); /// ``` - #[$stability] - #[$deprecation] - #[allow(deprecated)] + #[stable(feature = "nonzero", since = "1.28.0")] #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + #[repr(transparent)] pub struct $Ty(NonZero<$Int>); - #[allow(deprecated)] impl $Ty { /// Create a non-zero without checking the value. /// /// # Safety /// /// The value must not be zero. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { $Ty(NonZero(n)) } /// Create a non-zero if the given value is not zero. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub fn new(n: $Int) -> Option { if n != 0 { @@ -78,7 +75,7 @@ macro_rules! nonzero_integers { } /// Returns the value as a primitive type. - #[$stability] + #[stable(feature = "nonzero", since = "1.28.0")] #[inline] pub fn get(self) -> $Int { self.0 .0 @@ -87,7 +84,6 @@ macro_rules! nonzero_integers { } impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty } )+ @@ -95,8 +91,6 @@ macro_rules! nonzero_integers { } nonzero_integers! { - #[unstable(feature = "nonzero", issue = "49137")] - #[allow(deprecated)] // Redundant, works around "error: inconsistent lockstep iteration" NonZeroU8(u8); NonZeroU16(u16); NonZeroU32(u32); @@ -105,19 +99,6 @@ nonzero_integers! { NonZeroUsize(usize); } -nonzero_integers! { - #[unstable(feature = "nonzero", issue = "49137")] - #[rustc_deprecated(since = "1.26.0", reason = "\ - signed non-zero integers are considered for removal due to lack of known use cases. \ - If you’re using them, please comment on https://github.com/rust-lang/rust/issues/49137")] - NonZeroI8(i8); - NonZeroI16(i16); - NonZeroI32(i32); - NonZeroI64(i64); - NonZeroI128(i128); - NonZeroIsize(isize); -} - /// Provides intentionally-wrapped arithmetic on `T`. /// /// Operations like `+` on `u32` values is intended to never overflow, @@ -143,6 +124,7 @@ nonzero_integers! { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] +#[repr(transparent)] pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); @@ -188,8 +170,6 @@ impl fmt::UpperHex for Wrapping { } } -mod wrapping; - // All these modules are technically private and only exposed for coretests: pub mod flt2dec; pub mod dec2flt; @@ -203,6 +183,8 @@ macro_rules! doc_comment { }; } +mod wrapping; + // `Int` + `SignedInt` implemented for signed integers macro_rules! int_impl { ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, @@ -252,7 +234,7 @@ depending on `radix`: * `0-9` * `a-z` - * `a-z` + * `A-Z` # Panics @@ -287,8 +269,9 @@ $EndFeature, " ``` "), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } + pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } doc_comment! { @@ -302,8 +285,9 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 1);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn count_zeros(self) -> u32 { + pub const fn count_zeros(self) -> u32 { (!self).count_ones() } } @@ -322,8 +306,9 @@ assert_eq!(n.leading_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn leading_zeros(self) -> u32 { + pub const fn leading_zeros(self) -> u32 { (self as $UnsignedT).leading_zeros() } } @@ -342,8 +327,9 @@ assert_eq!(n.trailing_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn trailing_zeros(self) -> u32 { + pub const fn trailing_zeros(self) -> u32 { (self as $UnsignedT).trailing_zeros() } } @@ -416,8 +402,9 @@ $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn swap_bytes(self) -> Self { + pub const fn swap_bytes(self) -> Self { (self as $UnsignedT).swap_bytes() as Self } @@ -442,7 +429,6 @@ $EndFeature, " /// assert_eq!(m, -22016); /// ``` #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg(not(stage0))] #[inline] pub fn reverse_bits(self) -> Self { (self as $UnsignedT).reverse_bits() as Self @@ -468,9 +454,17 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } } } @@ -494,9 +488,17 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } } } @@ -520,9 +522,17 @@ if cfg!(target_endian = \"big\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } } } @@ -546,9 +556,17 @@ if cfg!(target_endian = \"little\") { $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } } } @@ -1885,12 +1903,10 @@ $EndFeature, " /// # Examples /// /// ``` - /// #![feature(int_to_from_bytes)] - /// /// let bytes = i32::min_value().to_be().to_bytes(); /// assert_eq!(bytes, [0x80, 0, 0, 0]); /// ``` - #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[stable(feature = "int_to_from_bytes", since = "1.29.0")] #[inline] pub fn to_bytes(self) -> [u8; mem::size_of::()] { unsafe { mem::transmute(self) } @@ -1907,12 +1923,10 @@ $EndFeature, " /// # Examples /// /// ``` - /// #![feature(int_to_from_bytes)] - /// /// let int = i32::from_be(i32::from_bytes([0x80, 0, 0, 0])); /// assert_eq!(int, i32::min_value()); /// ``` - #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[stable(feature = "int_to_from_bytes", since = "1.29.0")] #[inline] pub fn from_bytes(bytes: [u8; mem::size_of::()]) -> Self { unsafe { mem::transmute(bytes) } @@ -1964,6 +1978,19 @@ impl isize { int_impl! { isize, i64, u64, 64, -9223372036854775808, 9223372036854775807, "", "" } } +// Emits the correct `cttz` call, depending on the size of the type. +macro_rules! uint_cttz_call { + // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic + // emits two conditional moves on x86_64. By promoting the value to + // u16 and setting bit 8, we get better code without any conditional + // operations. + // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) + // pending, remove this workaround once LLVM generates better code + // for cttz8. + ($value:expr, 8) => { intrinsics::cttz($value as u16 | 0x100) }; + ($value:expr, $_BITS:expr) => { intrinsics::cttz($value) } +} + // `Int` + `UnsignedInt` implemented for unsigned integers macro_rules! uint_impl { ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature:expr) => { @@ -2041,8 +2068,9 @@ Basic usage: assert_eq!(n.count_ones(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn count_ones(self) -> u32 { + pub const fn count_ones(self) -> u32 { unsafe { intrinsics::ctpop(self as $ActualT) as u32 } } } @@ -2058,8 +2086,9 @@ Basic usage: ", $Feature, "assert_eq!(", stringify!($SelfT), "::max_value().count_zeros(), 0);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn count_zeros(self) -> u32 { + pub const fn count_zeros(self) -> u32 { (!self).count_ones() } } @@ -2077,8 +2106,9 @@ Basic usage: assert_eq!(n.leading_zeros(), 2);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn leading_zeros(self) -> u32 { + pub const fn leading_zeros(self) -> u32 { unsafe { intrinsics::ctlz(self as $ActualT) as u32 } } } @@ -2097,22 +2127,10 @@ Basic usage: assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn trailing_zeros(self) -> u32 { - // As of LLVM 3.6 the codegen for the zero-safe cttz8 intrinsic - // emits two conditional moves on x86_64. By promoting the value to - // u16 and setting bit 8, we get better code without any conditional - // operations. - // FIXME: There's a LLVM patch (http://reviews.llvm.org/D9284) - // pending, remove this workaround once LLVM generates better code - // for cttz8. - unsafe { - if $BITS == 8 { - intrinsics::cttz(self as u16 | 0x100) as u32 - } else { - intrinsics::cttz(self) as u32 - } - } + pub const fn trailing_zeros(self) -> u32 { + unsafe { uint_cttz_call!(self, $BITS) as u32 } } } @@ -2188,8 +2206,9 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 21760); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn swap_bytes(self) -> Self { + pub const fn swap_bytes(self) -> Self { unsafe { intrinsics::bswap(self as $ActualT) as Self } } @@ -2214,7 +2233,6 @@ assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " /// assert_eq!(m, 43520); /// ``` #[unstable(feature = "reverse_bits", issue = "48763")] - #[cfg(not(stage0))] #[inline] pub fn reverse_bits(self) -> Self { unsafe { intrinsics::bitreverse(self as $ActualT) as Self } @@ -2240,9 +2258,17 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn from_be(x: Self) -> Self { - if cfg!(target_endian = "big") { x } else { x.swap_bytes() } + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } } } @@ -2266,9 +2292,17 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn from_le(x: Self) -> Self { - if cfg!(target_endian = "little") { x } else { x.swap_bytes() } + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } } } @@ -2292,9 +2326,17 @@ if cfg!(target_endian = \"big\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn to_be(self) -> Self { // or not to be? - if cfg!(target_endian = "big") { self } else { self.swap_bytes() } + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } } } @@ -2318,9 +2360,17 @@ if cfg!(target_endian = \"little\") { }", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_ops")] #[inline] - pub fn to_le(self) -> Self { - if cfg!(target_endian = "little") { self } else { self.swap_bytes() } + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } } } @@ -2335,7 +2385,7 @@ Basic usage: ``` ", $Feature, "assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(1), ", "Some(", stringify!($SelfT), "::max_value() - 1)); -assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3),None);", $EndFeature, " +assert_eq!((", stringify!($SelfT), "::max_value() - 2).checked_add(3), None);", $EndFeature, " ```"), #[stable(feature = "rust1", since = "1.0.0")] #[inline] @@ -3423,6 +3473,30 @@ $EndFeature, " } } + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +the return value is wrapped to `0`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_next_power_of_two)] +", $Feature, " +assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); +assert_eq!(", stringify!($SelfT), "::max_value().wrapping_next_power_of_two(), 0);", +$EndFeature, " +```"), + #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", + reason = "needs decision on wrapping behaviour")] + pub fn wrapping_next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two().wrapping_add(1) + } + } + /// Return the memory representation of this integer as a byte array. /// /// The target platform’s native endianness is used. @@ -3434,12 +3508,10 @@ $EndFeature, " /// # Examples /// /// ``` - /// #![feature(int_to_from_bytes)] - /// /// let bytes = 0x1234_5678_u32.to_be().to_bytes(); /// assert_eq!(bytes, [0x12, 0x34, 0x56, 0x78]); /// ``` - #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[stable(feature = "int_to_from_bytes", since = "1.29.0")] #[inline] pub fn to_bytes(self) -> [u8; mem::size_of::()] { unsafe { mem::transmute(self) } @@ -3456,12 +3528,10 @@ $EndFeature, " /// # Examples /// /// ``` - /// #![feature(int_to_from_bytes)] - /// /// let int = u32::from_be(u32::from_bytes([0x12, 0x34, 0x56, 0x78])); /// assert_eq!(int, 0x1234_5678_u32); /// ``` - #[unstable(feature = "int_to_from_bytes", issue = "49792")] + #[stable(feature = "int_to_from_bytes", since = "1.29.0")] #[inline] pub fn from_bytes(bytes: [u8; mem::size_of::()]) -> Self { unsafe { mem::transmute(bytes) } @@ -4102,61 +4172,6 @@ pub enum FpCategory { Normal, } -// Technically private and only exposed for coretests: -#[doc(hidden)] -#[unstable(feature = "float_internals", - reason = "internal routines only exposed for testing", - issue = "0")] -pub trait Float: Sized { - /// Type used by `to_bits` and `from_bits`. - type Bits; - - /// Returns `true` if this value is NaN and false otherwise. - fn is_nan(self) -> bool; - - /// Returns `true` if this value is positive infinity or negative infinity and - /// false otherwise. - fn is_infinite(self) -> bool; - - /// Returns `true` if this number is neither infinite nor NaN. - fn is_finite(self) -> bool; - - /// Returns `true` if this number is neither zero, infinite, denormal, or NaN. - fn is_normal(self) -> bool; - - /// Returns the category that this number falls into. - fn classify(self) -> FpCategory; - - /// Returns `true` if `self` is positive, including `+0.0` and - /// `Float::infinity()`. - fn is_sign_positive(self) -> bool; - - /// Returns `true` if `self` is negative, including `-0.0` and - /// `Float::neg_infinity()`. - fn is_sign_negative(self) -> bool; - - /// Take the reciprocal (inverse) of a number, `1/x`. - fn recip(self) -> Self; - - /// Convert radians to degrees. - fn to_degrees(self) -> Self; - - /// Convert degrees to radians. - fn to_radians(self) -> Self; - - /// Returns the maximum of the two numbers. - fn max(self, other: Self) -> Self; - - /// Returns the minimum of the two numbers. - fn min(self, other: Self) -> Self; - - /// Raw transmutation to integer. - fn to_bits(self) -> Self::Bits; - - /// Raw transmutation from integer. - fn from_bits(v: Self::Bits) -> Self; -} - macro_rules! from_str_radix_int_impl { ($($t:ty)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] @@ -4200,6 +4215,21 @@ impl From for TryFromIntError { } } +// no possible bounds violation +macro_rules! try_from_unbounded { + ($source:ty, $($target:ty),*) => {$( + #[unstable(feature = "try_from", issue = "33417")] + impl TryFrom<$source> for $target { + type Error = TryFromIntError; + + #[inline] + fn try_from(value: $source) -> Result { + Ok(value as $target) + } + } + )*} +} + // only negative bounds macro_rules! try_from_lower_bounded { ($source:ty, $($target:ty),*) => {$( @@ -4298,20 +4328,27 @@ try_from_both_bounded!(i128, u64, u32, u16, u8); try_from_upper_bounded!(usize, isize); try_from_lower_bounded!(isize, usize); -try_from_upper_bounded!(usize, u8); -try_from_upper_bounded!(usize, i8, i16); -try_from_both_bounded!(isize, u8); -try_from_both_bounded!(isize, i8); - #[cfg(target_pointer_width = "16")] mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs + try_from_upper_bounded!(usize, u8); + try_from_unbounded!(usize, u16, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16); + try_from_unbounded!(usize, i32, i64, i128); + + try_from_both_bounded!(isize, u8); try_from_lower_bounded!(isize, u16, u32, u64, u128); + try_from_both_bounded!(isize, i8); + try_from_unbounded!(isize, i16, i32, i64, i128); + + rev!(try_from_upper_bounded, usize, u32, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16); rev!(try_from_both_bounded, usize, i32, i64, i128); + + rev!(try_from_upper_bounded, isize, u16, u32, u64, u128); + rev!(try_from_both_bounded, isize, i32, i64, i128); } #[cfg(target_pointer_width = "32")] @@ -4319,11 +4356,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs - try_from_both_bounded!(isize, u16); + try_from_upper_bounded!(usize, u8, u16); + try_from_unbounded!(usize, u32, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32); + try_from_unbounded!(usize, i64, i128); + + try_from_both_bounded!(isize, u8, u16); try_from_lower_bounded!(isize, u32, u64, u128); + try_from_both_bounded!(isize, i8, i16); + try_from_unbounded!(isize, i32, i64, i128); + + rev!(try_from_unbounded, usize, u32); + rev!(try_from_upper_bounded, usize, u64, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32); rev!(try_from_both_bounded, usize, i64, i128); + + rev!(try_from_unbounded, isize, u16); + rev!(try_from_upper_bounded, isize, u32, u64, u128); + rev!(try_from_unbounded, isize, i32); + rev!(try_from_both_bounded, isize, i64, i128); } #[cfg(target_pointer_width = "64")] @@ -4331,11 +4382,25 @@ mod ptr_try_from_impls { use super::TryFromIntError; use convert::TryFrom; - // Fallible across platfoms, only implementation differs - try_from_both_bounded!(isize, u16, u32); + try_from_upper_bounded!(usize, u8, u16, u32); + try_from_unbounded!(usize, u64, u128); + try_from_upper_bounded!(usize, i8, i16, i32, i64); + try_from_unbounded!(usize, i128); + + try_from_both_bounded!(isize, u8, u16, u32); try_from_lower_bounded!(isize, u64, u128); + try_from_both_bounded!(isize, i8, i16, i32); + try_from_unbounded!(isize, i64, i128); + + rev!(try_from_unbounded, usize, u32, u64); + rev!(try_from_upper_bounded, usize, u128); rev!(try_from_lower_bounded, usize, i8, i16, i32, i64); rev!(try_from_both_bounded, usize, i128); + + rev!(try_from_unbounded, isize, u16, u32); + rev!(try_from_upper_bounded, isize, u64, u128); + rev!(try_from_unbounded, isize, i32, i64); + rev!(try_from_both_bounded, isize, i128); } #[doc(hidden)] @@ -4496,17 +4561,57 @@ pub use num::dec2flt::ParseFloatError; // Conversions T -> T are covered by a blanket impl and therefore excluded // Some conversions from and to usize/isize are not implemented due to portability concerns macro_rules! impl_from { - ($Small: ty, $Large: ty, #[$attr:meta]) => { + ($Small: ty, $Large: ty, #[$attr:meta], $doc: expr) => { #[$attr] + #[doc = $doc] impl From<$Small> for $Large { #[inline] fn from(small: $Small) -> $Large { small as $Large } } + }; + ($Small: ty, $Large: ty, #[$attr:meta]) => { + impl_from!($Small, + $Large, + #[$attr], + concat!("Converts `", + stringify!($Small), + "` to `", + stringify!($Large), + "` losslessly.")); } } +macro_rules! impl_from_bool { + ($target: ty, #[$attr:meta]) => { + impl_from!(bool, $target, #[$attr], concat!("Converts a `bool` to a `", + stringify!($target), "`. The resulting value is `0` for `false` and `1` for `true` +values. + +# Examples + +``` +assert_eq!(", stringify!($target), "::from(true), 1); +assert_eq!(", stringify!($target), "::from(false), 0); +```")); + }; +} + +// Bool -> Any +impl_from_bool! { u8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { u128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { usize, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i8, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i16, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i32, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i64, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { i128, #[stable(feature = "from_bool", since = "1.28.0")] } +impl_from_bool! { isize, #[stable(feature = "from_bool", since = "1.28.0")] } + // Unsigned -> Unsigned impl_from! { u8, u16, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } impl_from! { u8, u32, #[stable(feature = "lossless_int_conv", since = "1.5.0")] } diff --git a/src/libcore/num/wrapping.rs b/src/libcore/num/wrapping.rs index 826883fdc3f01..1c826c2fa76bd 100644 --- a/src/libcore/num/wrapping.rs +++ b/src/libcore/num/wrapping.rs @@ -112,17 +112,19 @@ macro_rules! sh_impl_all { //sh_impl_unsigned! { $t, u16 } //sh_impl_unsigned! { $t, u32 } //sh_impl_unsigned! { $t, u64 } + //sh_impl_unsigned! { $t, u128 } sh_impl_unsigned! { $t, usize } //sh_impl_signed! { $t, i8 } //sh_impl_signed! { $t, i16 } //sh_impl_signed! { $t, i32 } //sh_impl_signed! { $t, i64 } + //sh_impl_signed! { $t, i128 } //sh_impl_signed! { $t, isize } )*) } -sh_impl_all! { u8 u16 u32 u64 usize i8 i16 i32 i64 isize } +sh_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } // FIXME(30524): impl Op for Wrapping, impl OpAssign for Wrapping macro_rules! wrapping_impl { @@ -326,88 +328,111 @@ wrapping_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } macro_rules! wrapping_int_impl { ($($t:ty)*) => ($( impl Wrapping<$t> { - /// Returns the number of ones in the binary representation of - /// `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(-0b1000_0000); - /// - /// assert_eq!(n.count_ones(), 1); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn count_ones(self) -> u32 { - self.0.count_ones() + doc_comment! { + concat!("Returns the smallest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(>::min_value(), ", +"Wrapping(", stringify!($t), "::min_value())); +```"), + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + #[inline] + pub const fn min_value() -> Self { + Wrapping(<$t>::min_value()) + } } - /// Returns the number of zeros in the binary representation of - /// `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(-0b1000_0000); - /// - /// assert_eq!(n.count_zeros(), 7); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn count_zeros(self) -> u32 { - self.0.count_zeros() + doc_comment! { + concat!("Returns the largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(>::max_value(), ", +"Wrapping(", stringify!($t), "::max_value())); +```"), + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + #[inline] + pub const fn max_value() -> Self { + Wrapping(<$t>::max_value()) + } } - /// Returns the number of leading zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(-1); - /// - /// assert_eq!(n.leading_zeros(), 0); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn leading_zeros(self) -> u32 { - self.0.leading_zeros() + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0b01001100", stringify!($t), "); + +assert_eq!(n.count_ones(), 3); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn count_ones(self) -> u32 { + self.0.count_ones() + } } - /// Returns the number of trailing zeros in the binary representation - /// of `self`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(-4); - /// - /// assert_eq!(n.trailing_zeros(), 2); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn trailing_zeros(self) -> u32 { - self.0.trailing_zeros() + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(!0", stringify!($t), ").count_zeros(), 0); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn count_zeros(self) -> u32 { + self.0.count_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0b0101000", stringify!($t), "); + +assert_eq!(n.trailing_zeros(), 3); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn trailing_zeros(self) -> u32 { + self.0.trailing_zeros() + } } /// Shifts the bits to the left by a specified amount, `n`, @@ -484,145 +509,177 @@ macro_rules! wrapping_int_impl { Wrapping(self.0.swap_bytes()) } - /// Converts an integer from big endian to the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. + /// Reverses the bit pattern of the integer. /// /// # Examples /// + /// Please note that this example is shared between integer types. + /// Which explains why `i16` is used here. + /// /// Basic usage: /// /// ``` - /// #![feature(wrapping_int_impl)] + /// #![feature(reverse_bits)] /// use std::num::Wrapping; /// - /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); + /// let n = Wrapping(0b0000000_01010101i16); + /// assert_eq!(n, Wrapping(85)); + /// + /// let m = n.reverse_bits(); /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(Wrapping::::from_be(n), n); - /// } else { - /// assert_eq!(Wrapping::::from_be(n), n.swap_bytes()); - /// } + /// assert_eq!(m.0 as u16, 0b10101010_00000000); + /// assert_eq!(m, Wrapping(-22016)); /// ``` + #[unstable(feature = "reverse_bits", issue = "48763")] #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn from_be(x: Self) -> Self { - Wrapping(<$t>::from_be(x.0)) + pub fn reverse_bits(self) -> Self { + Wrapping(self.0.reverse_bits()) } - /// Converts an integer from little endian to the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(Wrapping::::from_le(n), n); - /// } else { - /// assert_eq!(Wrapping::::from_le(n), n.swap_bytes()); - /// } - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn from_le(x: Self) -> Self { - Wrapping(<$t>::from_le(x.0)) + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0x1A", stringify!($t), "); + +if cfg!(target_endian = \"big\") { + assert_eq!(>::from_be(n), n) +} else { + assert_eq!(>::from_be(n), n.swap_bytes()) +} +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn from_be(x: Self) -> Self { + Wrapping(<$t>::from_be(x.0)) + } } - /// Converts `self` to big endian from the target's endianness. - /// - /// On big endian this is a no-op. On little endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); - /// - /// if cfg!(target_endian = "big") { - /// assert_eq!(n.to_be(), n); - /// } else { - /// assert_eq!(n.to_be(), n.swap_bytes()); - /// } - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn to_be(self) -> Self { - Wrapping(self.0.to_be()) + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0x1A", stringify!($t), "); + +if cfg!(target_endian = \"little\") { + assert_eq!(>::from_le(n), n) +} else { + assert_eq!(>::from_le(n), n.swap_bytes()) +} +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn from_le(x: Self) -> Self { + Wrapping(<$t>::from_le(x.0)) + } } - /// Converts `self` to little endian from the target's endianness. - /// - /// On little endian this is a no-op. On big endian the bytes are - /// swapped. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let n: Wrapping = Wrapping(0x0123456789ABCDEF); - /// - /// if cfg!(target_endian = "little") { - /// assert_eq!(n.to_le(), n); - /// } else { - /// assert_eq!(n.to_le(), n.swap_bytes()); - /// } - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn to_le(self) -> Self { - Wrapping(self.0.to_le()) + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0x1A", stringify!($t), "); + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +} +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn to_be(self) -> Self { + Wrapping(self.0.to_be()) + } } - /// Raises self to the power of `exp`, using exponentiation by - /// squaring. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// let x: Wrapping = Wrapping(2); // or any other integer type - /// - /// assert_eq!(x.pow(4), Wrapping(16)); - /// ``` - /// - /// Results that are too large are wrapped: - /// - /// ``` - /// #![feature(wrapping_int_impl)] - /// use std::num::Wrapping; - /// - /// // 5 ^ 4 = 625, which is too big for a u8 - /// let x: Wrapping = Wrapping(5); - /// - /// assert_eq!(x.pow(4).0, 113); - /// ``` - #[inline] - #[unstable(feature = "wrapping_int_impl", issue = "32463")] - pub fn pow(self, exp: u32) -> Self { - Wrapping(self.0.wrapping_pow(exp)) + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(0x1A", stringify!($t), "); + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +} +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn to_le(self) -> Self { + Wrapping(self.0.to_le()) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(3", stringify!($t), ").pow(4), Wrapping(81)); +``` + +Results that are too large are wrapped: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(3i8).pow(5), Wrapping(-13)); +assert_eq!(Wrapping(3i8).pow(6), Wrapping(-39)); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn pow(self, exp: u32) -> Self { + Wrapping(self.0.wrapping_pow(exp)) + } } } )*) @@ -630,6 +687,211 @@ macro_rules! wrapping_int_impl { wrapping_int_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } +macro_rules! wrapping_int_impl_signed { + ($($t:ty)*) => ($( + impl Wrapping<$t> { + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(", stringify!($t), "::max_value()) >> 2; + +assert_eq!(n.leading_zeros(), 3); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn leading_zeros(self) -> u32 { + self.0.leading_zeros() + } + } + + doc_comment! { + concat!("Computes the absolute value of `self`, wrapping around at +the boundary of the type. + +The only case where such wrapping can occur is when one takes the absolute value of the negative +minimal value for the type this is a positive value that is too large to represent in the type. In +such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(100", stringify!($t), ").abs(), Wrapping(100)); +assert_eq!(Wrapping(-100", stringify!($t), ").abs(), Wrapping(100)); +assert_eq!(Wrapping(", stringify!($t), "::min_value()).abs(), Wrapping(", stringify!($t), +"::min_value())); +assert_eq!(Wrapping(-128i8).abs().0 as u8, 128u8); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn abs(self) -> Wrapping<$t> { + Wrapping(self.0.wrapping_abs()) + } + } + + doc_comment! { + concat!("Returns a number representing sign of `self`. + + - `0` if the number is zero + - `1` if the number is positive + - `-1` if the number is negative + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert_eq!(Wrapping(10", stringify!($t), ").signum(), Wrapping(1)); +assert_eq!(Wrapping(0", stringify!($t), ").signum(), Wrapping(0)); +assert_eq!(Wrapping(-10", stringify!($t), ").signum(), Wrapping(-1)); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn signum(self) -> Wrapping<$t> { + Wrapping(self.0.signum()) + } + } + + doc_comment! { + concat!("Returns `true` if `self` is positive and `false` if the number is zero or +negative. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert!(Wrapping(10", stringify!($t), ").is_positive()); +assert!(!Wrapping(-10", stringify!($t), ").is_positive()); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn is_positive(self) -> bool { + self.0.is_positive() + } + } + + doc_comment! { + concat!("Returns `true` if `self` is negative and `false` if the number is zero or +positive. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert!(Wrapping(-10", stringify!($t), ").is_negative()); +assert!(!Wrapping(10", stringify!($t), ").is_negative()); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn is_negative(self) -> bool { + self.0.is_negative() + } + } + } + )*) +} + +wrapping_int_impl_signed! { isize i8 i16 i32 i64 i128 } + +macro_rules! wrapping_int_impl_unsigned { + ($($t:ty)*) => ($( + impl Wrapping<$t> { + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +let n = Wrapping(", stringify!($t), "::max_value()) >> 2; + +assert_eq!(n.leading_zeros(), 2); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn leading_zeros(self) -> u32 { + self.0.leading_zeros() + } + } + + doc_comment! { + concat!("Returns `true` if and only if `self == 2^k` for some `k`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_int_impl)] +use std::num::Wrapping; + +assert!(Wrapping(16", stringify!($t), ").is_power_of_two()); +assert!(!Wrapping(10", stringify!($t), ").is_power_of_two()); +```"), + #[inline] + #[unstable(feature = "wrapping_int_impl", issue = "32463")] + pub fn is_power_of_two(self) -> bool { + self.0.is_power_of_two() + } + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `self`. + +When return value overflows (i.e. `self > (1 << (N-1))` for type +`uN`), overflows to `2^N = 0`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_next_power_of_two)] +use std::num::Wrapping; + +assert_eq!(Wrapping(2", stringify!($t), ").next_power_of_two(), Wrapping(2)); +assert_eq!(Wrapping(3", stringify!($t), ").next_power_of_two(), Wrapping(4)); +assert_eq!(Wrapping(200_u8).next_power_of_two(), Wrapping(0)); +```"), + #[inline] + #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", + reason = "needs decision on wrapping behaviour")] + pub fn next_power_of_two(self) -> Self { + Wrapping(self.0.wrapping_next_power_of_two()) + } + } + } + )*) +} + +wrapping_int_impl_unsigned! { usize u8 u16 u32 u64 u128 } mod shift_max { #![allow(non_upper_case_globals)] @@ -656,11 +918,13 @@ mod shift_max { pub const i16: u32 = (1 << 4) - 1; pub const i32: u32 = (1 << 5) - 1; pub const i64: u32 = (1 << 6) - 1; + pub const i128: u32 = (1 << 7) - 1; pub use self::platform::isize; pub const u8: u32 = i8; pub const u16: u32 = i16; pub const u32: u32 = i32; pub const u64: u32 = i64; + pub const u128: u32 = i128; pub use self::platform::usize; } diff --git a/src/libcore/ops/index.rs b/src/libcore/ops/index.rs index 0a0e92a918006..1ac80ecc96ffe 100644 --- a/src/libcore/ops/index.rs +++ b/src/libcore/ops/index.rs @@ -60,7 +60,10 @@ /// assert_eq!(nucleotide_count[Nucleotide::T], 12); /// ``` #[lang = "index"] -#[rustc_on_unimplemented = "the type `{Self}` cannot be indexed by `{Idx}`"] +#[rustc_on_unimplemented( + message="the type `{Self}` cannot be indexed by `{Idx}`", + label="`{Self}` cannot be indexed by `{Idx}`", +)] #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "]")] #[doc(alias = "[")] @@ -147,7 +150,10 @@ pub trait Index { /// balance[Side::Left] = Weight::Kilogram(3.0); /// ``` #[lang = "index_mut"] -#[rustc_on_unimplemented = "the type `{Self}` cannot be mutably indexed by `{Idx}`"] +#[rustc_on_unimplemented( + message="the type `{Self}` cannot be mutably indexed by `{Idx}`", + label="`{Self}` cannot be mutably indexed by `{Idx}`", +)] #[stable(feature = "rust1", since = "1.0.0")] #[doc(alias = "[")] #[doc(alias = "]")] diff --git a/src/libcore/ops/range.rs b/src/libcore/ops/range.rs index b01a769eda7fd..9c635678d7aa0 100644 --- a/src/libcore/ops/range.rs +++ b/src/libcore/ops/range.rs @@ -9,6 +9,7 @@ // except according to those terms. use fmt; +use hash::{Hash, Hasher}; /// An unbounded range (`..`). /// @@ -318,8 +319,6 @@ impl> RangeTo { /// # Examples /// /// ``` -/// #![feature(inclusive_range_methods)] -/// /// assert_eq!((3..=5), std::ops::RangeInclusive::new(3, 5)); /// assert_eq!(3 + 4 + 5, (3..=5).sum()); /// @@ -328,25 +327,56 @@ impl> RangeTo { /// assert_eq!(arr[1..=2], [ 1,2 ]); // RangeInclusive /// ``` #[doc(alias = "..=")] -#[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 +#[derive(Clone)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] pub struct RangeInclusive { - // FIXME: The current representation follows RFC 1980, - // but it is known that LLVM is not able to optimize loops following that RFC. - // Consider adding an extra `bool` field to indicate emptiness of the range. - // See #45222 for performance test cases. - #[cfg(not(stage0))] pub(crate) start: Idx, - #[cfg(not(stage0))] pub(crate) end: Idx, - /// The lower bound of the range (inclusive). - #[cfg(stage0)] - #[unstable(feature = "inclusive_range_fields", issue = "49022")] - pub start: Idx, - /// The upper bound of the range (inclusive). - #[cfg(stage0)] - #[unstable(feature = "inclusive_range_fields", issue = "49022")] - pub end: Idx, + pub(crate) is_empty: Option, + // This field is: + // - `None` when next() or next_back() was never called + // - `Some(false)` when `start <= end` assuming no overflow + // - `Some(true)` otherwise + // The field cannot be a simple `bool` because the `..=` constructor can + // accept non-PartialOrd types, also we want the constructor to be const. +} + +trait RangeInclusiveEquality: Sized { + fn canonicalized_is_empty(range: &RangeInclusive) -> bool; +} +impl RangeInclusiveEquality for T { + #[inline] + default fn canonicalized_is_empty(range: &RangeInclusive) -> bool { + range.is_empty.unwrap_or_default() + } +} +impl RangeInclusiveEquality for T { + #[inline] + fn canonicalized_is_empty(range: &RangeInclusive) -> bool { + range.is_empty() + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl PartialEq for RangeInclusive { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.start == other.start && self.end == other.end + && RangeInclusiveEquality::canonicalized_is_empty(self) + == RangeInclusiveEquality::canonicalized_is_empty(other) + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl Eq for RangeInclusive {} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl Hash for RangeInclusive { + fn hash(&self, state: &mut H) { + self.start.hash(state); + self.end.hash(state); + RangeInclusiveEquality::canonicalized_is_empty(self).hash(state); + } } impl RangeInclusive { @@ -355,15 +385,14 @@ impl RangeInclusive { /// # Examples /// /// ``` - /// #![feature(inclusive_range_methods)] /// use std::ops::RangeInclusive; /// /// assert_eq!(3..=5, RangeInclusive::new(3, 5)); /// ``` - #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub const fn new(start: Idx, end: Idx) -> Self { - Self { start, end } + Self { start, end, is_empty: None } } /// Returns the lower bound of the range (inclusive). @@ -373,17 +402,18 @@ impl RangeInclusive { /// whether the inclusive range is empty, use the [`is_empty()`] method /// instead of comparing `start() > end()`. /// + /// Note: the value returned by this method is unspecified after the range + /// has been iterated to exhaustion. + /// /// [`end()`]: #method.end /// [`is_empty()`]: #method.is_empty /// /// # Examples /// /// ``` - /// #![feature(inclusive_range_methods)] - /// /// assert_eq!((3..=5).start(), &3); /// ``` - #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub fn start(&self) -> &Idx { &self.start @@ -396,21 +426,38 @@ impl RangeInclusive { /// whether the inclusive range is empty, use the [`is_empty()`] method /// instead of comparing `start() > end()`. /// + /// Note: the value returned by this method is unspecified after the range + /// has been iterated to exhaustion. + /// /// [`start()`]: #method.start /// [`is_empty()`]: #method.is_empty /// /// # Examples /// /// ``` - /// #![feature(inclusive_range_methods)] - /// /// assert_eq!((3..=5).end(), &5); /// ``` - #[unstable(feature = "inclusive_range_methods", issue = "49022")] + #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] pub fn end(&self) -> &Idx { &self.end } + + /// Destructures the `RangeInclusive` into (lower bound, upper (inclusive) bound). + /// + /// Note: the value returned by this method is unspecified after the range + /// has been iterated to exhaustion. + /// + /// # Examples + /// + /// ``` + /// assert_eq!((3..=5).into_inner(), (3, 5)); + /// ``` + #[stable(feature = "inclusive_range_methods", since = "1.27.0")] + #[inline] + pub fn into_inner(self) -> (Idx, Idx) { + (self.start, self.end) + } } #[stable(feature = "inclusive_range", since = "1.26.0")] @@ -487,8 +534,17 @@ impl> RangeInclusive { /// assert!(r.is_empty()); /// ``` #[unstable(feature = "range_is_empty", reason = "recently added", issue = "48111")] + #[inline] pub fn is_empty(&self) -> bool { - !(self.start <= self.end) + self.is_empty.unwrap_or_else(|| !(self.start <= self.end)) + } + + // If this range's `is_empty` is field is unknown (`None`), update it to be a concrete value. + #[inline] + pub(crate) fn compute_is_empty(&mut self) { + if self.is_empty.is_none() { + self.is_empty = Some(!(self.start <= self.end)); + } } } @@ -583,14 +639,12 @@ impl> RangeToInclusive { /// `Bound`s are range endpoints: /// /// ``` -/// #![feature(collections_range)] -/// /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// -/// assert_eq!((..100).start(), Unbounded); -/// assert_eq!((1..12).start(), Included(&1)); -/// assert_eq!((1..12).end(), Excluded(&12)); +/// assert_eq!((..100).start_bound(), Unbounded); +/// assert_eq!((1..12).start_bound(), Included(&1)); +/// assert_eq!((1..12).end_bound(), Excluded(&12)); /// ``` /// /// Using a tuple of `Bound`s as an argument to [`BTreeMap::range`]. @@ -627,9 +681,7 @@ pub enum Bound { Unbounded, } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] /// `RangeBounds` is implemented by Rust's built-in range types, produced /// by range syntax like `..`, `a..`, `..b` or `c..d`. pub trait RangeBounds { @@ -640,17 +692,16 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(collections_range)] - /// /// # fn main() { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// - /// assert_eq!((..10).start(), Unbounded); - /// assert_eq!((3..10).start(), Included(&3)); + /// assert_eq!((..10).start_bound(), Unbounded); + /// assert_eq!((3..10).start_bound(), Included(&3)); /// # } /// ``` - fn start(&self) -> Bound<&T>; + #[stable(feature = "collections_range", since = "1.28.0")] + fn start_bound(&self) -> Bound<&T>; /// End index bound. /// @@ -659,17 +710,16 @@ pub trait RangeBounds { /// # Examples /// /// ``` - /// #![feature(collections_range)] - /// /// # fn main() { /// use std::ops::Bound::*; /// use std::ops::RangeBounds; /// - /// assert_eq!((3..).end(), Unbounded); - /// assert_eq!((3..10).end(), Excluded(&10)); + /// assert_eq!((3..).end_bound(), Unbounded); + /// assert_eq!((3..10).end_bound(), Excluded(&10)); /// # } /// ``` - fn end(&self) -> Bound<&T>; + #[stable(feature = "collections_range", since = "1.28.0")] + fn end_bound(&self) -> Bound<&T>; /// Returns `true` if `item` is contained in the range. @@ -694,13 +744,13 @@ pub trait RangeBounds { T: PartialOrd, U: ?Sized + PartialOrd, { - (match self.start() { + (match self.start_bound() { Included(ref start) => *start <= item, Excluded(ref start) => *start < item, Unbounded => true, }) && - (match self.end() { + (match self.end_bound() { Included(ref end) => item <= *end, Excluded(ref end) => item < *end, Unbounded => true, @@ -710,83 +760,69 @@ pub trait RangeBounds { use self::Bound::{Excluded, Included, Unbounded}; -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeFull { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeFrom { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeTo { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for Range { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeInclusive { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(&self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for RangeToInclusive { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(&self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl RangeBounds for (Bound, Bound) { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { match *self { (Included(ref start), _) => Included(start), (Excluded(ref start), _) => Excluded(start), @@ -794,7 +830,7 @@ impl RangeBounds for (Bound, Bound) { } } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { match *self { (_, Included(ref end)) => Included(end), (_, Excluded(ref end)) => Excluded(end), @@ -803,75 +839,63 @@ impl RangeBounds for (Bound, Bound) { } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T: ?Sized + 'a> RangeBounds for (Bound<&'a T>, Bound<&'a T>) { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { self.0 } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { self.1 } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeFrom<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Unbounded } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeTo<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for Range<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Excluded(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeInclusive<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Included(self.start) } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(self.end) } } -#[unstable(feature = "collections_range", - reason = "might be replaced with `Into<_>` and a type containing two `Bound` values", - issue = "30877")] +#[stable(feature = "collections_range", since = "1.28.0")] impl<'a, T> RangeBounds for RangeToInclusive<&'a T> { - fn start(&self) -> Bound<&T> { + fn start_bound(&self) -> Bound<&T> { Unbounded } - fn end(&self) -> Bound<&T> { + fn end_bound(&self) -> Bound<&T> { Included(self.end) } } diff --git a/src/libcore/option.rs b/src/libcore/option.rs index deb0380171c4e..2b6c376f8a71c 100644 --- a/src/libcore/option.rs +++ b/src/libcore/option.rs @@ -146,7 +146,8 @@ #![stable(feature = "rust1", since = "1.0.0")] use iter::{FromIterator, FusedIterator, TrustedLen}; -use {mem, ops::{self, Deref}}; +use {hint, mem, ops::{self, Deref}}; +use mem::PinMut; // Note that this is not a lang item per se, but it has a hidden dependency on // `Iterator`, which is one. The compiler assumes that the `next` method of @@ -269,6 +270,15 @@ impl Option { } } + /// Converts from `Option` to `Option>` + #[inline] + #[unstable(feature = "pin", issue = "49150")] + pub fn as_pin_mut<'a>(self: PinMut<'a, Self>) -> Option> { + unsafe { + PinMut::get_mut_unchecked(self).as_mut().map(|x| PinMut::new_unchecked(x)) + } + } + ///////////////////////////////////////////////////////////////////////// // Getting to contained values ///////////////////////////////////////////////////////////////////////// @@ -705,6 +715,42 @@ impl Option { } } + /// Returns [`Some`] if exactly one of `self`, `optb` is [`Some`], otherwise returns `None`. + /// + /// [`Some`]: #variant.Some + /// [`None`]: #variant.None + /// + /// # Examples + /// + /// ``` + /// #![feature(option_xor)] + /// + /// let x = Some(2); + /// let y: Option = None; + /// assert_eq!(x.xor(y), Some(2)); + /// + /// let x: Option = None; + /// let y = Some(2); + /// assert_eq!(x.xor(y), Some(2)); + /// + /// let x = Some(2); + /// let y = Some(2); + /// assert_eq!(x.xor(y), None); + /// + /// let x: Option = None; + /// let y: Option = None; + /// assert_eq!(x.xor(y), None); + /// ``` + #[inline] + #[unstable(feature = "option_xor", issue = "50512")] + pub fn xor(self, optb: Option) -> Option { + match (self, optb) { + (Some(a), None) => Some(a), + (None, Some(b)) => Some(b), + _ => None, + } + } + ///////////////////////////////////////////////////////////////////////// // Entry-like operations to insert if None and return a reference ///////////////////////////////////////////////////////////////////////// @@ -738,7 +784,7 @@ impl Option { match *self { Some(ref mut v) => v, - _ => unreachable!(), + None => unsafe { hint::unreachable_unchecked() }, } } @@ -771,7 +817,7 @@ impl Option { match *self { Some(ref mut v) => v, - _ => unreachable!(), + None => unsafe { hint::unreachable_unchecked() }, } } @@ -787,18 +833,47 @@ impl Option { /// /// ``` /// let mut x = Some(2); - /// x.take(); + /// let y = x.take(); /// assert_eq!(x, None); + /// assert_eq!(y, Some(2)); /// /// let mut x: Option = None; - /// x.take(); + /// let y = x.take(); /// assert_eq!(x, None); + /// assert_eq!(y, None); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn take(&mut self) -> Option { mem::replace(self, None) } + + /// Replaces the actual value in the option by the value given in parameter, + /// returning the old value if present, + /// leaving a [`Some`] in its place without deinitializing either one. + /// + /// [`Some`]: #variant.Some + /// + /// # Examples + /// + /// ``` + /// #![feature(option_replace)] + /// + /// let mut x = Some(2); + /// let old = x.replace(5); + /// assert_eq!(x, Some(5)); + /// assert_eq!(old, Some(2)); + /// + /// let mut x = None; + /// let old = x.replace(3); + /// assert_eq!(x, Some(3)); + /// assert_eq!(old, None); + /// ``` + #[inline] + #[unstable(feature = "option_replace", issue = "51998")] + pub fn replace(&mut self, value: T) -> Option { + mem::replace(self, Some(value)) + } } impl<'a, T: Clone> Option<&'a T> { diff --git a/src/libcore/panic.rs b/src/libcore/panic.rs index 27ec4aaac75de..17cac5aa0a05f 100644 --- a/src/libcore/panic.rs +++ b/src/libcore/panic.rs @@ -30,15 +30,20 @@ use fmt; /// use std::panic; /// /// panic::set_hook(Box::new(|panic_info| { -/// println!("panic occurred: {:?}", panic_info.payload().downcast_ref::<&str>().unwrap()); +/// if let Some(s) = panic_info.payload().downcast_ref::<&str>() { +/// println!("panic occurred: {:?}", s); +/// } else { +/// println!("panic occurred"); +/// } /// })); /// /// panic!("Normal panic"); /// ``` +#[lang = "panic_info"] #[stable(feature = "panic_hooks", since = "1.10.0")] #[derive(Debug)] pub struct PanicInfo<'a> { - payload: &'a (Any + Send), + payload: &'a (dyn Any + Send), message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>, } @@ -53,12 +58,13 @@ impl<'a> PanicInfo<'a> { pub fn internal_constructor(message: Option<&'a fmt::Arguments<'a>>, location: Location<'a>) -> Self { - PanicInfo { payload: &(), location, message } + struct NoPayload; + PanicInfo { payload: &NoPayload, location, message } } #[doc(hidden)] #[inline] - pub fn set_payload(&mut self, info: &'a (Any + Send)) { + pub fn set_payload(&mut self, info: &'a (dyn Any + Send)) { self.payload = info; } @@ -80,7 +86,7 @@ impl<'a> PanicInfo<'a> { /// panic!("Normal panic"); /// ``` #[stable(feature = "panic_hooks", since = "1.10.0")] - pub fn payload(&self) -> &(Any + Send) { + pub fn payload(&self) -> &(dyn Any + Send) { self.payload } @@ -121,7 +127,7 @@ impl<'a> PanicInfo<'a> { #[stable(feature = "panic_hooks", since = "1.10.0")] pub fn location(&self) -> Option<&Location> { // NOTE: If this is changed to sometimes return None, - // deal with that case in std::panicking::default_hook. + // deal with that case in std::panicking::default_hook and std::panicking::begin_panic_fmt. Some(&self.location) } } @@ -264,6 +270,6 @@ impl<'a> fmt::Display for Location<'a> { #[unstable(feature = "std_internals", issue = "0")] #[doc(hidden)] pub unsafe trait BoxMeUp { - fn box_me_up(&mut self) -> *mut (Any + Send); - fn get(&mut self) -> &(Any + Send); + fn box_me_up(&mut self) -> *mut (dyn Any + Send); + fn get(&mut self) -> &(dyn Any + Send); } diff --git a/src/libcore/panicking.rs b/src/libcore/panicking.rs index 6b3dc75af4633..58407de9566e9 100644 --- a/src/libcore/panicking.rs +++ b/src/libcore/panicking.rs @@ -37,6 +37,7 @@ issue = "0")] use fmt; +use panic::{Location, PanicInfo}; #[cold] #[inline(never)] // this is the slow path, always #[lang = "panic"] @@ -61,12 +62,17 @@ fn panic_bounds_check(file_line_col: &(&'static str, u32, u32), #[cold] #[inline(never)] pub fn panic_fmt(fmt: fmt::Arguments, file_line_col: &(&'static str, u32, u32)) -> ! { - #[allow(improper_ctypes)] - extern { - #[lang = "panic_fmt"] - #[unwind(allowed)] - fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !; + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + #[allow(improper_ctypes)] // PanicInfo contains a trait object which is not FFI safe + extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo) -> !; } + let (file, line, col) = *file_line_col; - unsafe { panic_impl(fmt, file, line, col) } + let pi = PanicInfo::internal_constructor( + Some(&fmt), + Location::internal_constructor(file, line, col), + ); + unsafe { panic_impl(&pi) } } diff --git a/src/libcore/prelude/v1.rs b/src/libcore/prelude/v1.rs index 8212648f2d8fb..45f629a64424c 100644 --- a/src/libcore/prelude/v1.rs +++ b/src/libcore/prelude/v1.rs @@ -54,13 +54,3 @@ pub use option::Option::{self, Some, None}; #[stable(feature = "core_prelude", since = "1.4.0")] #[doc(no_inline)] pub use result::Result::{self, Ok, Err}; - -// Re-exported extension traits for primitive types -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -#[cfg(stage0)] -pub use slice::SliceExt; -#[stable(feature = "core_prelude", since = "1.4.0")] -#[doc(no_inline)] -#[cfg(stage0)] -pub use str::StrExt; diff --git a/src/libcore/ptr.rs b/src/libcore/ptr.rs index 5d0b675e8e4c5..fe5914c72e1ac 100644 --- a/src/libcore/ptr.rs +++ b/src/libcore/ptr.rs @@ -23,7 +23,7 @@ use fmt; use hash; use marker::{PhantomData, Unsize}; use mem; -#[allow(deprecated)] use nonzero::NonZero; +use nonzero::NonZero; use cmp::Ordering::{self, Less, Equal, Greater}; @@ -187,6 +187,19 @@ pub unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { swap_nonoverlapping_bytes(x, y, len) } +#[inline] +pub(crate) unsafe fn swap_nonoverlapping_one(x: *mut T, y: *mut T) { + // For types smaller than the block optimization below, + // just swap directly to avoid pessimizing codegen. + if mem::size_of::() < 32 { + let z = read(x); + copy_nonoverlapping(y, x, 1); + write(y, z); + } else { + swap_nonoverlapping(x, y, 1); + } +} + #[inline] unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { // The approach here is to utilize simd to swap x & y efficiently. Testing reveals @@ -239,8 +252,9 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { } } -/// Replaces the value at `dest` with `src`, returning the old -/// value, without dropping either. +/// Moves `src` into the pointed `dest`, returning the previous `dest` value. +/// +/// Neither value is dropped. /// /// # Safety /// @@ -577,7 +591,7 @@ impl *const T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of an allocated object. + /// byte past the end of *the same* allocated object. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -629,9 +643,15 @@ impl *const T { /// /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). + /// In particular, the resulting pointer may *not* be used to access a + /// different allocated object than the one `self` points to. In other + /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// *not* the same as `y`, and dereferencing it is undefined behavior + /// unless `x` and `y` point into the same allocated object. /// /// Always use `.offset(count)` instead when possible, because `offset` - /// allows the compiler to optimize better. + /// allows the compiler to optimize better. If you need to cross object + /// boundaries, cast the pointer to an integer and do the arithmetic there. /// /// # Examples /// @@ -1142,8 +1162,8 @@ impl *const T { /// /// Care must be taken with the ownership of `self` and `dest`. /// This method semantically moves the values of `self` into `dest`. - /// However it does not drop the contents of `self`, or prevent the contents - /// of `dest` from being dropped or used. + /// However it does not drop the contents of `dest`, or prevent the contents + /// of `self` from being dropped or used. /// /// # Examples /// @@ -1203,15 +1223,22 @@ impl *const T { copy_nonoverlapping(self, dest, count) } - /// Computes the byte offset that needs to be applied in order to - /// make the pointer aligned to `align`. + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// /// If it is not possible to align the pointer, the implementation returns /// `usize::max_value()`. /// - /// There are no guarantees whatsover that offsetting the pointer will not - /// overflow or go beyond the allocation that the pointer points into. - /// It is up to the caller to ensure that the returned offset is correct - /// in all terms other than alignment. + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `offset` or `offset_to` methods. + /// + /// There are no guarantees whatsover that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. /// /// # Examples /// @@ -1235,13 +1262,17 @@ impl *const T { /// # } } /// ``` #[unstable(feature = "align_offset", issue = "44488")] - pub fn align_offset(self, align: usize) -> usize { + pub fn align_offset(self, align: usize) -> usize where T: Sized { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } unsafe { - intrinsics::align_offset(self as *const _, align) + align_offset(self, align) } } } + #[lang = "mut_ptr"] impl *mut T { /// Returns `true` if the pointer is null. @@ -1315,7 +1346,7 @@ impl *mut T { /// Behavior: /// /// * Both the starting and resulting pointer must be either in bounds or one - /// byte past the end of an allocated object. + /// byte past the end of *the same* allocated object. /// /// * The computed offset, **in bytes**, cannot overflow an `isize`. /// @@ -1366,9 +1397,15 @@ impl *mut T { /// /// The resulting pointer does not need to be in bounds, but it is /// potentially hazardous to dereference (which requires `unsafe`). + /// In particular, the resulting pointer may *not* be used to access a + /// different allocated object than the one `self` points to. In other + /// words, `x.wrapping_offset(y.wrapping_offset_from(x))` is + /// *not* the same as `y`, and dereferencing it is undefined behavior + /// unless `x` and `y` point into the same allocated object. /// /// Always use `.offset(count)` instead when possible, because `offset` - /// allows the compiler to optimize better. + /// allows the compiler to optimize better. If you need to cross object + /// boundaries, cast the pointer to an integer and do the arithmetic there. /// /// # Examples /// @@ -1574,44 +1611,6 @@ impl *mut T { (self as *const T).wrapping_offset_from(origin) } - /// Computes the byte offset that needs to be applied in order to - /// make the pointer aligned to `align`. - /// If it is not possible to align the pointer, the implementation returns - /// `usize::max_value()`. - /// - /// There are no guarantees whatsover that offsetting the pointer will not - /// overflow or go beyond the allocation that the pointer points into. - /// It is up to the caller to ensure that the returned offset is correct - /// in all terms other than alignment. - /// - /// # Examples - /// - /// Accessing adjacent `u8` as `u16` - /// - /// ``` - /// # #![feature(align_offset)] - /// # fn foo(n: usize) { - /// # use std::mem::align_of; - /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; - /// let offset = ptr.align_offset(align_of::()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.offset(offset as isize) as *const u16; - /// assert_ne!(*u16_ptr, 500); - /// } else { - /// // while the pointer can be aligned via `offset`, it would point - /// // outside the allocation - /// } - /// # } } - /// ``` - #[unstable(feature = "align_offset", issue = "44488")] - pub fn align_offset(self, align: usize) -> usize { - unsafe { - intrinsics::align_offset(self as *const _, align) - } - } - /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). /// /// `count` is in units of T; e.g. a `count` of 3 represents a pointer @@ -2281,8 +2280,186 @@ impl *mut T { { swap(self, with) } + + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// + /// If it is not possible to align the pointer, the implementation returns + /// `usize::max_value()`. + /// + /// The offset is expressed in number of `T` elements, and not bytes. The value returned can be + /// used with the `offset` or `offset_to` methods. + /// + /// There are no guarantees whatsover that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// # #![feature(align_offset)] + /// # fn foo(n: usize) { + /// # use std::mem::align_of; + /// # unsafe { + /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; + /// let ptr = &x[n] as *const u8; + /// let offset = ptr.align_offset(align_of::()); + /// if offset < x.len() - n - 1 { + /// let u16_ptr = ptr.offset(offset as isize) as *const u16; + /// assert_ne!(*u16_ptr, 500); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } } + /// ``` + #[unstable(feature = "align_offset", issue = "44488")] + pub fn align_offset(self, align: usize) -> usize where T: Sized { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + unsafe { + align_offset(self, align) + } + } } +/// Align pointer `p`. +/// +/// Calculate offset (in terms of elements of `stride` stride) that has to be applied +/// to pointer `p` so that pointer `p` would get aligned to `a`. +/// +/// Note: This implementation has been carefully tailored to not panic. It is UB for this to panic. +/// The only real change that can be made here is change of `INV_TABLE_MOD_16` and associated +/// constants. +/// +/// If we ever decide to make it possible to call the intrinsic with `a` that is not a +/// power-of-two, it will probably be more prudent to just change to a naive implementation rather +/// than trying to adapt this to accomodate that change. +/// +/// Any questions go to @nagisa. +#[lang="align_offset"] +pub(crate) unsafe fn align_offset(p: *const T, a: usize) -> usize { + /// Calculate multiplicative modular inverse of `x` modulo `m`. + /// + /// This implementation is tailored for align_offset and has following preconditions: + /// + /// * `m` is a power-of-two; + /// * `x < m`; (if `x ≥ m`, pass in `x % m` instead) + /// + /// Implementation of this function shall not panic. Ever. + #[inline] + fn mod_inv(x: usize, m: usize) -> usize { + /// Multiplicative modular inverse table modulo 2⁴ = 16. + /// + /// Note, that this table does not contain values where inverse does not exist (i.e. for + /// `0⁻¹ mod 16`, `2⁻¹ mod 16`, etc.) + const INV_TABLE_MOD_16: [usize; 8] = [1, 11, 13, 7, 9, 3, 5, 15]; + /// Modulo for which the `INV_TABLE_MOD_16` is intended. + const INV_TABLE_MOD: usize = 16; + /// INV_TABLE_MOD² + const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD; + + let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1]; + if m <= INV_TABLE_MOD { + return table_inverse & (m - 1); + } else { + // We iterate "up" using the following formula: + // + // $$ xy ≡ 1 (mod 2ⁿ) → xy (2 - xy) ≡ 1 (mod 2²ⁿ) $$ + // + // until 2²ⁿ ≥ m. Then we can reduce to our desired `m` by taking the result `mod m`. + let mut inverse = table_inverse; + let mut going_mod = INV_TABLE_MOD_SQUARED; + loop { + // y = y * (2 - xy) mod n + // + // Note, that we use wrapping operations here intentionally – the original formula + // uses e.g. subtraction `mod n`. It is entirely fine to do them `mod + // usize::max_value()` instead, because we take the result `mod n` at the end + // anyway. + inverse = inverse.wrapping_mul( + 2usize.wrapping_sub(x.wrapping_mul(inverse)) + ) & (going_mod - 1); + if going_mod > m { + return inverse & (m - 1); + } + going_mod = going_mod.wrapping_mul(going_mod); + } + } + } + + let stride = ::mem::size_of::(); + let a_minus_one = a.wrapping_sub(1); + let pmoda = p as usize & a_minus_one; + + if pmoda == 0 { + // Already aligned. Yay! + return 0; + } + + if stride <= 1 { + return if stride == 0 { + // If the pointer is not aligned, and the element is zero-sized, then no amount of + // elements will ever align the pointer. + !0 + } else { + a.wrapping_sub(pmoda) + }; + } + + let smoda = stride & a_minus_one; + // a is power-of-two so cannot be 0. stride = 0 is handled above. + let gcdpow = intrinsics::cttz_nonzero(stride).min(intrinsics::cttz_nonzero(a)); + let gcd = 1usize << gcdpow; + + if gcd == 1 { + // This branch solves for the variable $o$ in following linear congruence equation: + // + // ⎰ p + o ≡ 0 (mod a) # $p + o$ must be aligned to specified alignment $a$ + // ⎱ o ≡ 0 (mod s) # offset $o$ must be a multiple of stride $s$ + // + // where + // + // * a, s are co-prime + // + // This gives us the formula below: + // + // o = (a - (p mod a)) * (s⁻¹ mod a) * s + // + // The first term is “the relative alignment of p to a”, the second term is “how does + // incrementing p by one s change the relative alignment of p”, the third term is + // translating change in units of s to a byte count. + // + // Furthermore, the result produced by this solution is not “minimal”, so it is necessary + // to take the result $o mod lcm(s, a)$. Since $s$ and $a$ are co-prime (i.e. $gcd(s, a) = + // 1$) and $lcm(s, a) = s * a / gcd(s, a)$, we can replace $lcm(s, a)$ with just a $s * a$. + // + // (Author note: we decided later on to express the offset in "elements" rather than bytes, + // which drops the multiplication by `s` on both sides of the modulo.) + return intrinsics::unchecked_rem(a.wrapping_sub(pmoda).wrapping_mul(mod_inv(smoda, a)), a); + } + + if p as usize & (gcd - 1) == 0 { + // This can be aligned, but `a` and `stride` are not co-prime, so a somewhat adapted + // formula is used. + let j = a.wrapping_sub(pmoda) >> gcdpow; + let k = smoda >> gcdpow; + return intrinsics::unchecked_rem(j.wrapping_mul(mod_inv(k, a)), a >> gcdpow); + } + + // Cannot be aligned at all. + return usize::max_value(); +} + + + // Equality for pointers #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for *const T { @@ -2512,8 +2689,8 @@ impl PartialOrd for *mut T { #[unstable(feature = "ptr_internals", issue = "0", reason = "use NonNull instead and consider PhantomData \ (if you also use #[may_dangle]), Send, and/or Sync")] -#[allow(deprecated)] #[doc(hidden)] +#[repr(transparent)] pub struct Unique { pointer: NonZero<*const T>, // NOTE: this marker has no consequences for variance, but is necessary @@ -2551,6 +2728,11 @@ impl Unique { /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. + /// + /// Note that the pointer value may potentially represent a valid pointer to + /// a `T`, which means this must not be used as a "not yet initialized" + /// sentinel value. Types that lazily allocate must track initialization by + /// some other means. // FIXME: rename to dangling() to match NonNull? pub const fn empty() -> Self { unsafe { @@ -2560,7 +2742,6 @@ impl Unique { } #[unstable(feature = "ptr_internals", issue = "0")] -#[allow(deprecated)] impl Unique { /// Creates a new `Unique`. /// @@ -2625,7 +2806,6 @@ impl fmt::Pointer for Unique { } #[unstable(feature = "ptr_internals", issue = "0")] -#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for Unique { fn from(reference: &'a mut T) -> Self { Unique { pointer: NonZero(reference as _), _marker: PhantomData } @@ -2633,7 +2813,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for Unique { } #[unstable(feature = "ptr_internals", issue = "0")] -#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for Unique { fn from(reference: &'a T) -> Self { Unique { pointer: NonZero(reference as _), _marker: PhantomData } @@ -2665,8 +2844,9 @@ impl<'a, T: ?Sized> From> for Unique { /// such as Box, Rc, Arc, Vec, and LinkedList. This is the case because they /// provide a public API that follows the normal shared XOR mutable rules of Rust. #[stable(feature = "nonnull", since = "1.25.0")] +#[repr(transparent)] pub struct NonNull { - #[allow(deprecated)] pointer: NonZero<*const T>, + pointer: NonZero<*const T>, } /// `NonNull` pointers are not `Send` because the data they reference may be aliased. @@ -2684,6 +2864,11 @@ impl NonNull { /// /// This is useful for initializing types which lazily allocate, like /// `Vec::new` does. + /// + /// Note that the pointer value may potentially represent a valid pointer to + /// a `T`, which means this must not be used as a "not yet initialized" + /// sentinel value. Types that lazily allocate must track initialization by + /// some other means. #[stable(feature = "nonnull", since = "1.25.0")] pub fn dangling() -> Self { unsafe { @@ -2693,7 +2878,6 @@ impl NonNull { } } -#[allow(deprecated)] impl NonNull { /// Creates a new `NonNull`. /// @@ -2748,14 +2932,6 @@ impl NonNull { NonNull::new_unchecked(self.as_ptr() as *mut U) } } - - /// Cast to an `Opaque` pointer - #[unstable(feature = "allocator_api", issue = "32838")] - pub fn as_opaque(self) -> NonNull<::alloc::Opaque> { - unsafe { - NonNull::new_unchecked(self.as_ptr() as _) - } - } } #[stable(feature = "nonnull", since = "1.25.0")] @@ -2824,7 +3000,6 @@ impl From> for NonNull { } #[stable(feature = "nonnull", since = "1.25.0")] -#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a mut T> for NonNull { fn from(reference: &'a mut T) -> Self { NonNull { pointer: NonZero(reference as _) } @@ -2832,7 +3007,6 @@ impl<'a, T: ?Sized> From<&'a mut T> for NonNull { } #[stable(feature = "nonnull", since = "1.25.0")] -#[allow(deprecated)] impl<'a, T: ?Sized> From<&'a T> for NonNull { fn from(reference: &'a T) -> Self { NonNull { pointer: NonZero(reference as _) } diff --git a/src/libcore/result.rs b/src/libcore/result.rs index c545064aadb29..fb496836c2c10 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -251,7 +251,7 @@ use ops::{self, Deref}; /// [`Ok`]: enum.Result.html#variant.Ok /// [`Err`]: enum.Result.html#variant.Err #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] -#[must_use] +#[must_use = "this `Result` may be an `Err` variant, which should be handled"] #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { /// Contains the success value diff --git a/src/libcore/slice/memchr.rs b/src/libcore/slice/memchr.rs index 7b62e7b0620fd..72e7b57a6cb3c 100644 --- a/src/libcore/slice/memchr.rs +++ b/src/libcore/slice/memchr.rs @@ -102,16 +102,13 @@ pub fn memrchr(x: u8, text: &[u8]) -> Option { let ptr = text.as_ptr(); let usize_bytes = mem::size_of::(); - // search to an aligned boundary - let end_align = (ptr as usize + len) & (usize_bytes - 1); - let mut offset; - if end_align > 0 { - offset = if end_align >= len { 0 } else { len - end_align }; - if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { - return Some(offset + index); - } - } else { - offset = len; + let mut offset = { + // We call this just to obtain the length of the suffix + let (_, _, suffix) = unsafe { text.align_to::() }; + len - suffix.len() + }; + if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { + return Some(offset + index); } // search the body of the text diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 83e8a6e4b683a..b766140ffe99a 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -59,710 +59,63 @@ mod rotate; mod sort; #[repr(C)] -struct Repr { - pub data: *const T, - pub len: usize, +union Repr<'a, T: 'a> { + rust: &'a [T], + rust_mut: &'a mut [T], + raw: FatPtr, } -// -// Extension traits -// - -public_in_stage0! { -{ -/// Extension methods for slices. -#[unstable(feature = "core_slice_ext", - reason = "stable interface provided by `impl [T]` in later crates", - issue = "32110")] -#[allow(missing_docs)] // documented elsewhere -} -trait SliceExt { - type Item; - - #[stable(feature = "core", since = "1.6.0")] - fn split_at(&self, mid: usize) -> (&[Self::Item], &[Self::Item]); - - #[stable(feature = "core", since = "1.6.0")] - fn iter(&self) -> Iter; - - #[stable(feature = "core", since = "1.6.0")] - fn split

(&self, pred: P) -> Split - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "slice_rsplit", since = "1.27.0")] - fn rsplit

(&self, pred: P) -> RSplit - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn splitn

(&self, n: usize, pred: P) -> SplitN - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn

(&self, n: usize, pred: P) -> RSplitN - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn windows(&self, size: usize) -> Windows; - - #[stable(feature = "core", since = "1.6.0")] - fn chunks(&self, size: usize) -> Chunks; - - #[unstable(feature = "exact_chunks", issue = "47115")] - fn exact_chunks(&self, size: usize) -> ExactChunks; - - #[stable(feature = "core", since = "1.6.0")] - fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn first(&self) -> Option<&Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_first(&self) -> Option<(&Self::Item, &[Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_last(&self) -> Option<(&Self::Item, &[Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn last(&self) -> Option<&Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn as_ptr(&self) -> *const Self::Item; - - #[stable(feature = "core", since = "1.6.0")] - fn binary_search(&self, x: &Self::Item) -> Result - where Self::Item: Ord; - - #[stable(feature = "core", since = "1.6.0")] - fn binary_search_by<'a, F>(&'a self, f: F) -> Result - where F: FnMut(&'a Self::Item) -> Ordering; - - #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] - fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result - where F: FnMut(&'a Self::Item) -> B, - B: Ord; - - #[stable(feature = "core", since = "1.6.0")] - fn len(&self) -> usize; - - #[stable(feature = "core", since = "1.6.0")] - fn is_empty(&self) -> bool { self.len() == 0 } - - #[stable(feature = "core", since = "1.6.0")] - fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn iter_mut(&mut self) -> IterMut; - - #[stable(feature = "core", since = "1.6.0")] - fn first_mut(&mut self) -> Option<&mut Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_first_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_last_mut(&mut self) -> Option<(&mut Self::Item, &mut [Self::Item])>; - - #[stable(feature = "core", since = "1.6.0")] - fn last_mut(&mut self) -> Option<&mut Self::Item>; - - #[stable(feature = "core", since = "1.6.0")] - fn split_mut

(&mut self, pred: P) -> SplitMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "slice_rsplit", since = "1.27.0")] - fn rsplit_mut

(&mut self, pred: P) -> RSplitMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn_mut

(&mut self, n: usize, pred: P) -> RSplitNMut - where P: FnMut(&Self::Item) -> bool; - - #[stable(feature = "core", since = "1.6.0")] - fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut; - - #[unstable(feature = "exact_chunks", issue = "47115")] - fn exact_chunks_mut(&mut self, size: usize) -> ExactChunksMut; - - #[stable(feature = "core", since = "1.6.0")] - fn swap(&mut self, a: usize, b: usize); - - #[stable(feature = "core", since = "1.6.0")] - fn split_at_mut(&mut self, mid: usize) -> (&mut [Self::Item], &mut [Self::Item]); - - #[stable(feature = "core", since = "1.6.0")] - fn reverse(&mut self); - - #[stable(feature = "core", since = "1.6.0")] - unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex; - #[stable(feature = "core", since = "1.6.0")] - fn as_mut_ptr(&mut self) -> *mut Self::Item; - - #[stable(feature = "core", since = "1.6.0")] - fn contains(&self, x: &Self::Item) -> bool where Self::Item: PartialEq; - - #[stable(feature = "core", since = "1.6.0")] - fn starts_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - - #[stable(feature = "core", since = "1.6.0")] - fn ends_with(&self, needle: &[Self::Item]) -> bool where Self::Item: PartialEq; - - #[stable(feature = "slice_rotate", since = "1.26.0")] - fn rotate_left(&mut self, mid: usize); - - #[stable(feature = "slice_rotate", since = "1.26.0")] - fn rotate_right(&mut self, k: usize); - - #[stable(feature = "clone_from_slice", since = "1.7.0")] - fn clone_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Clone; - - #[stable(feature = "copy_from_slice", since = "1.9.0")] - fn copy_from_slice(&mut self, src: &[Self::Item]) where Self::Item: Copy; - - #[stable(feature = "swap_with_slice", since = "1.27.0")] - fn swap_with_slice(&mut self, src: &mut [Self::Item]); - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable(&mut self) - where Self::Item: Ord; - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable_by(&mut self, compare: F) - where F: FnMut(&Self::Item, &Self::Item) -> Ordering; - - #[stable(feature = "sort_unstable", since = "1.20.0")] - fn sort_unstable_by_key(&mut self, f: F) - where F: FnMut(&Self::Item) -> B, - B: Ord; -}} - -// Use macros to be generic over const/mut -macro_rules! slice_offset { - ($ptr:expr, $by:expr) => {{ - let ptr = $ptr; - if size_from_ptr(ptr) == 0 { - (ptr as *mut i8).wrapping_offset($by) as _ - } else { - ptr.offset($by) - } - }}; -} - -// make a &T from a *const T -macro_rules! make_ref { - ($ptr:expr) => {{ - let ptr = $ptr; - if size_from_ptr(ptr) == 0 { - // Use a non-null pointer value - &*(1 as *mut _) - } else { - &*ptr - } - }}; -} - -// make a &mut T from a *mut T -macro_rules! make_ref_mut { - ($ptr:expr) => {{ - let ptr = $ptr; - if size_from_ptr(ptr) == 0 { - // Use a non-null pointer value - &mut *(1 as *mut _) - } else { - &mut *ptr - } - }}; -} - -#[unstable(feature = "core_slice_ext", - reason = "stable interface provided by `impl [T]` in later crates", - issue = "32110")] -impl SliceExt for [T] { - type Item = T; - - #[inline] - fn split_at(&self, mid: usize) -> (&[T], &[T]) { - (&self[..mid], &self[mid..]) - } - - #[inline] - fn iter(&self) -> Iter { - unsafe { - let p = if mem::size_of::() == 0 { - 1 as *const _ - } else { - let p = self.as_ptr(); - assume(!p.is_null()); - p - }; - - Iter { - ptr: p, - end: slice_offset!(p, self.len() as isize), - _marker: marker::PhantomData - } - } - } - - #[inline] - fn split

(&self, pred: P) -> Split - where P: FnMut(&T) -> bool - { - Split { - v: self, - pred, - finished: false - } - } - - #[inline] - fn rsplit

(&self, pred: P) -> RSplit - where P: FnMut(&T) -> bool - { - RSplit { inner: self.split(pred) } - } - - #[inline] - fn splitn

(&self, n: usize, pred: P) -> SplitN - where P: FnMut(&T) -> bool - { - SplitN { - inner: GenericSplitN { - iter: self.split(pred), - count: n - } - } - } - - #[inline] - fn rsplitn

(&self, n: usize, pred: P) -> RSplitN - where P: FnMut(&T) -> bool - { - RSplitN { - inner: GenericSplitN { - iter: self.rsplit(pred), - count: n - } - } - } - - #[inline] - fn windows(&self, size: usize) -> Windows { - assert!(size != 0); - Windows { v: self, size: size } - } - - #[inline] - fn chunks(&self, chunk_size: usize) -> Chunks { - assert!(chunk_size != 0); - Chunks { v: self, chunk_size: chunk_size } - } - - #[inline] - fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { - assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - ExactChunks { v: &self[..len], chunk_size: chunk_size} - } - - #[inline] - fn get(&self, index: I) -> Option<&I::Output> - where I: SliceIndex<[T]> - { - index.get(self) - } - - #[inline] - fn first(&self) -> Option<&T> { - if self.is_empty() { None } else { Some(&self[0]) } - } - - #[inline] - fn split_first(&self) -> Option<(&T, &[T])> { - if self.is_empty() { None } else { Some((&self[0], &self[1..])) } - } - - #[inline] - fn split_last(&self) -> Option<(&T, &[T])> { - let len = self.len(); - if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) } - } - - #[inline] - fn last(&self) -> Option<&T> { - if self.is_empty() { None } else { Some(&self[self.len() - 1]) } - } - - #[inline] - unsafe fn get_unchecked(&self, index: I) -> &I::Output - where I: SliceIndex<[T]> - { - index.get_unchecked(self) - } - - #[inline] - fn as_ptr(&self) -> *const T { - self as *const [T] as *const T - } - - fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result - where F: FnMut(&'a T) -> Ordering - { - let s = self; - let mut size = s.len(); - if size == 0 { - return Err(0); - } - let mut base = 0usize; - while size > 1 { - let half = size / 2; - let mid = base + half; - // mid is always in [0, size), that means mid is >= 0 and < size. - // mid >= 0: by definition - // mid < size: mid = size / 2 + size / 4 + size / 8 ... - let cmp = f(unsafe { s.get_unchecked(mid) }); - base = if cmp == Greater { base } else { mid }; - size -= half; - } - // base is always in [0, size) because base <= mid. - let cmp = f(unsafe { s.get_unchecked(base) }); - if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) } - } - - #[inline] - fn len(&self) -> usize { - unsafe { - mem::transmute::<&[T], Repr>(self).len - } - } - - #[inline] - fn get_mut(&mut self, index: I) -> Option<&mut I::Output> - where I: SliceIndex<[T]> - { - index.get_mut(self) - } - - #[inline] - fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - let len = self.len(); - let ptr = self.as_mut_ptr(); - - unsafe { - assert!(mid <= len); - - (from_raw_parts_mut(ptr, mid), - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) - } - } - - #[inline] - fn iter_mut(&mut self) -> IterMut { - unsafe { - let p = if mem::size_of::() == 0 { - 1 as *mut _ - } else { - let p = self.as_mut_ptr(); - assume(!p.is_null()); - p - }; - - IterMut { - ptr: p, - end: slice_offset!(p, self.len() as isize), - _marker: marker::PhantomData - } - } - } - - #[inline] - fn last_mut(&mut self) -> Option<&mut T> { - let len = self.len(); - if len == 0 { return None; } - Some(&mut self[len - 1]) - } - - #[inline] - fn first_mut(&mut self) -> Option<&mut T> { - if self.is_empty() { None } else { Some(&mut self[0]) } - } - - #[inline] - fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { - if self.is_empty() { None } else { - let split = self.split_at_mut(1); - Some((&mut split.0[0], split.1)) - } - } - - #[inline] - fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { - let len = self.len(); - if len == 0 { None } else { - let split = self.split_at_mut(len - 1); - Some((&mut split.1[0], split.0)) - } - } - - #[inline] - fn split_mut

(&mut self, pred: P) -> SplitMut - where P: FnMut(&T) -> bool - { - SplitMut { v: self, pred: pred, finished: false } - } - - #[inline] - fn rsplit_mut

(&mut self, pred: P) -> RSplitMut - where P: FnMut(&T) -> bool - { - RSplitMut { inner: self.split_mut(pred) } - } - - #[inline] - fn splitn_mut

(&mut self, n: usize, pred: P) -> SplitNMut - where P: FnMut(&T) -> bool - { - SplitNMut { - inner: GenericSplitN { - iter: self.split_mut(pred), - count: n - } - } - } - - #[inline] - fn rsplitn_mut

(&mut self, n: usize, pred: P) -> RSplitNMut where - P: FnMut(&T) -> bool, - { - RSplitNMut { - inner: GenericSplitN { - iter: self.rsplit_mut(pred), - count: n - } - } - } - - #[inline] - fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { - assert!(chunk_size != 0); - ChunksMut { v: self, chunk_size: chunk_size } - } - - #[inline] - fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { - assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - ExactChunksMut { v: &mut self[..len], chunk_size: chunk_size} - } - - #[inline] - fn swap(&mut self, a: usize, b: usize) { - unsafe { - // Can't take two mutable loans from one vector, so instead just cast - // them to their raw pointers to do the swap - let pa: *mut T = &mut self[a]; - let pb: *mut T = &mut self[b]; - ptr::swap(pa, pb); - } - } - - fn reverse(&mut self) { - let mut i: usize = 0; - let ln = self.len(); - - // For very small types, all the individual reads in the normal - // path perform poorly. We can do better, given efficient unaligned - // load/store, by loading a larger chunk and reversing a register. - - // Ideally LLVM would do this for us, as it knows better than we do - // whether unaligned reads are efficient (since that changes between - // different ARM versions, for example) and what the best chunk size - // would be. Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls - // the loop, so we need to do this ourselves. (Hypothesis: reverse - // is troublesome because the sides can be aligned differently -- - // will be, when the length is odd -- so there's no way of emitting - // pre- and postludes to use fully-aligned SIMD in the middle.) - - let fast_unaligned = - cfg!(any(target_arch = "x86", target_arch = "x86_64")); - - if fast_unaligned && mem::size_of::() == 1 { - // Use the llvm.bswap intrinsic to reverse u8s in a usize - let chunk = mem::size_of::(); - while i + chunk - 1 < ln / 2 { - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); - let va = ptr::read_unaligned(pa as *mut usize); - let vb = ptr::read_unaligned(pb as *mut usize); - ptr::write_unaligned(pa as *mut usize, vb.swap_bytes()); - ptr::write_unaligned(pb as *mut usize, va.swap_bytes()); - } - i += chunk; - } - } - - if fast_unaligned && mem::size_of::() == 2 { - // Use rotate-by-16 to reverse u16s in a u32 - let chunk = mem::size_of::() / 2; - while i + chunk - 1 < ln / 2 { - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); - let va = ptr::read_unaligned(pa as *mut u32); - let vb = ptr::read_unaligned(pb as *mut u32); - ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16)); - ptr::write_unaligned(pb as *mut u32, va.rotate_left(16)); - } - i += chunk; - } - } - - while i < ln / 2 { - // Unsafe swap to avoid the bounds check in safe swap. - unsafe { - let pa: *mut T = self.get_unchecked_mut(i); - let pb: *mut T = self.get_unchecked_mut(ln - i - 1); - ptr::swap(pa, pb); - } - i += 1; - } - } - - #[inline] - unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output - where I: SliceIndex<[T]> - { - index.get_unchecked_mut(self) - } - - #[inline] - fn as_mut_ptr(&mut self) -> *mut T { - self as *mut [T] as *mut T - } - - #[inline] - fn contains(&self, x: &T) -> bool where T: PartialEq { - x.slice_contains(self) - } - - #[inline] - fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq { - let n = needle.len(); - self.len() >= n && needle == &self[..n] - } - - #[inline] - fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq { - let (m, n) = (self.len(), needle.len()); - m >= n && needle == &self[m-n..] - } - - fn binary_search(&self, x: &T) -> Result - where T: Ord - { - self.binary_search_by(|p| p.cmp(x)) - } - - fn rotate_left(&mut self, mid: usize) { - assert!(mid <= self.len()); - let k = self.len() - mid; - - unsafe { - let p = self.as_mut_ptr(); - rotate::ptr_rotate(mid, p.offset(mid as isize), k); - } - } - - fn rotate_right(&mut self, k: usize) { - assert!(k <= self.len()); - let mid = self.len() - k; +#[repr(C)] +struct FatPtr { + data: *const T, + len: usize, +} - unsafe { - let p = self.as_mut_ptr(); - rotate::ptr_rotate(mid, p.offset(mid as isize), k); - } - } +// +// Extension traits +// - #[inline] - fn clone_from_slice(&mut self, src: &[T]) where T: Clone { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - // NOTE: We need to explicitly slice them to the same length - // for bounds checking to be elided, and the optimizer will - // generate memcpy for simple cases (for example T = u8). - let len = self.len(); - let src = &src[..len]; - for i in 0..len { - self[i].clone_from(&src[i]); +// Use macros to be generic over const/mut +macro_rules! slice_offset { + ($ptr:expr, $by:expr) => {{ + let ptr = $ptr; + if size_from_ptr(ptr) == 0 { + (ptr as *mut i8).wrapping_offset($by) as _ + } else { + ptr.offset($by) } - } + }}; +} - #[inline] - fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - unsafe { - ptr::copy_nonoverlapping( - src.as_ptr(), self.as_mut_ptr(), self.len()); +// make a &T from a *const T +macro_rules! make_ref { + ($ptr:expr) => {{ + let ptr = $ptr; + if size_from_ptr(ptr) == 0 { + // Use a non-null pointer value + &*(1 as *mut _) + } else { + &*ptr } - } + }}; +} - #[inline] - fn swap_with_slice(&mut self, src: &mut [T]) { - assert!(self.len() == src.len(), - "destination and source slices have different lengths"); - unsafe { - ptr::swap_nonoverlapping( - self.as_mut_ptr(), src.as_mut_ptr(), self.len()); +// make a &mut T from a *mut T +macro_rules! make_ref_mut { + ($ptr:expr) => {{ + let ptr = $ptr; + if size_from_ptr(ptr) == 0 { + // Use a non-null pointer value + &mut *(1 as *mut _) + } else { + &mut *ptr } - } - - #[inline] - fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result - where F: FnMut(&'a Self::Item) -> B, - B: Ord - { - self.binary_search_by(|k| f(k).cmp(b)) - } - - #[inline] - fn sort_unstable(&mut self) - where Self::Item: Ord - { - sort::quicksort(self, |a, b| a.lt(b)); - } - - #[inline] - fn sort_unstable_by(&mut self, mut compare: F) - where F: FnMut(&Self::Item, &Self::Item) -> Ordering - { - sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); - } - - #[inline] - fn sort_unstable_by_key(&mut self, mut f: F) - where F: FnMut(&Self::Item) -> B, - B: Ord - { - sort::quicksort(self, |a, b| f(a).lt(&f(b))); - } + }}; } -// FIXME: remove (inline) this macro and the SliceExt trait -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_slice_ext", issue = "32110")] -macro_rules! slice_core_methods { () => { +#[lang = "slice"] +#[cfg(not(test))] +impl [T] { /// Returns the number of elements in the slice. /// /// # Examples @@ -773,8 +126,11 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn len(&self) -> usize { - SliceExt::len(self) + #[rustc_const_unstable(feature = "const_slice_len")] + pub const fn len(&self) -> usize { + unsafe { + Repr { rust: self }.raw.len + } } /// Returns `true` if the slice has a length of 0. @@ -787,8 +143,9 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn is_empty(&self) -> bool { - SliceExt::is_empty(self) + #[rustc_const_unstable(feature = "const_slice_len")] + pub const fn is_empty(&self) -> bool { + self.len() == 0 } /// Returns the first element of the slice, or `None` if it is empty. @@ -805,7 +162,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn first(&self) -> Option<&T> { - SliceExt::first(self) + if self.is_empty() { None } else { Some(&self[0]) } } /// Returns a mutable pointer to the first element of the slice, or `None` if it is empty. @@ -823,7 +180,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn first_mut(&mut self) -> Option<&mut T> { - SliceExt::first_mut(self) + if self.is_empty() { None } else { Some(&mut self[0]) } } /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. @@ -841,7 +198,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_first(&self) -> Option<(&T, &[T])> { - SliceExt::split_first(self) + if self.is_empty() { None } else { Some((&self[0], &self[1..])) } } /// Returns the first and all the rest of the elements of the slice, or `None` if it is empty. @@ -861,7 +218,10 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_first_mut(&mut self) -> Option<(&mut T, &mut [T])> { - SliceExt::split_first_mut(self) + if self.is_empty() { None } else { + let split = self.split_at_mut(1); + Some((&mut split.0[0], split.1)) + } } /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. @@ -879,7 +239,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_last(&self) -> Option<(&T, &[T])> { - SliceExt::split_last(self) + let len = self.len(); + if len == 0 { None } else { Some((&self[len - 1], &self[..(len - 1)])) } } /// Returns the last and all the rest of the elements of the slice, or `None` if it is empty. @@ -899,7 +260,12 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "slice_splits", since = "1.5.0")] #[inline] pub fn split_last_mut(&mut self) -> Option<(&mut T, &mut [T])> { - SliceExt::split_last_mut(self) + let len = self.len(); + if len == 0 { None } else { + let split = self.split_at_mut(len - 1); + Some((&mut split.1[0], split.0)) + } + } /// Returns the last element of the slice, or `None` if it is empty. @@ -916,7 +282,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn last(&self) -> Option<&T> { - SliceExt::last(self) + if self.is_empty() { None } else { Some(&self[self.len() - 1]) } } /// Returns a mutable pointer to the last item in the slice. @@ -934,7 +300,9 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn last_mut(&mut self) -> Option<&mut T> { - SliceExt::last_mut(self) + let len = self.len(); + if len == 0 { return None; } + Some(&mut self[len - 1]) } /// Returns a reference to an element or subslice depending on the type of @@ -959,7 +327,7 @@ macro_rules! slice_core_methods { () => { pub fn get(&self, index: I) -> Option<&I::Output> where I: SliceIndex { - SliceExt::get(self, index) + index.get(self) } /// Returns a mutable reference to an element or subslice depending on the @@ -982,7 +350,7 @@ macro_rules! slice_core_methods { () => { pub fn get_mut(&mut self, index: I) -> Option<&mut I::Output> where I: SliceIndex { - SliceExt::get_mut(self, index) + index.get_mut(self) } /// Returns a reference to an element or subslice, without doing bounds @@ -1007,7 +375,7 @@ macro_rules! slice_core_methods { () => { pub unsafe fn get_unchecked(&self, index: I) -> &I::Output where I: SliceIndex { - SliceExt::get_unchecked(self, index) + index.get_unchecked(self) } /// Returns a mutable reference to an element or subslice, without doing @@ -1034,7 +402,7 @@ macro_rules! slice_core_methods { () => { pub unsafe fn get_unchecked_mut(&mut self, index: I) -> &mut I::Output where I: SliceIndex { - SliceExt::get_unchecked_mut(self, index) + index.get_unchecked_mut(self) } /// Returns a raw pointer to the slice's buffer. @@ -1059,8 +427,9 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn as_ptr(&self) -> *const T { - SliceExt::as_ptr(self) + #[rustc_const_unstable(feature = "const_slice_as_ptr")] + pub const fn as_ptr(&self) -> *const T { + self as *const [T] as *const T } /// Returns an unsafe mutable pointer to the slice's buffer. @@ -1087,7 +456,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn as_mut_ptr(&mut self) -> *mut T { - SliceExt::as_mut_ptr(self) + self as *mut [T] as *mut T } /// Swaps two elements in the slice. @@ -1111,7 +480,13 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn swap(&mut self, a: usize, b: usize) { - SliceExt::swap(self, a, b) + unsafe { + // Can't take two mutable loans from one vector, so instead just cast + // them to their raw pointers to do the swap + let pa: *mut T = &mut self[a]; + let pb: *mut T = &mut self[b]; + ptr::swap(pa, pb); + } } /// Reverses the order of elements in the slice, in place. @@ -1126,7 +501,66 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn reverse(&mut self) { - SliceExt::reverse(self) + let mut i: usize = 0; + let ln = self.len(); + + // For very small types, all the individual reads in the normal + // path perform poorly. We can do better, given efficient unaligned + // load/store, by loading a larger chunk and reversing a register. + + // Ideally LLVM would do this for us, as it knows better than we do + // whether unaligned reads are efficient (since that changes between + // different ARM versions, for example) and what the best chunk size + // would be. Unfortunately, as of LLVM 4.0 (2017-05) it only unrolls + // the loop, so we need to do this ourselves. (Hypothesis: reverse + // is troublesome because the sides can be aligned differently -- + // will be, when the length is odd -- so there's no way of emitting + // pre- and postludes to use fully-aligned SIMD in the middle.) + + let fast_unaligned = + cfg!(any(target_arch = "x86", target_arch = "x86_64")); + + if fast_unaligned && mem::size_of::() == 1 { + // Use the llvm.bswap intrinsic to reverse u8s in a usize + let chunk = mem::size_of::(); + while i + chunk - 1 < ln / 2 { + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let va = ptr::read_unaligned(pa as *mut usize); + let vb = ptr::read_unaligned(pb as *mut usize); + ptr::write_unaligned(pa as *mut usize, vb.swap_bytes()); + ptr::write_unaligned(pb as *mut usize, va.swap_bytes()); + } + i += chunk; + } + } + + if fast_unaligned && mem::size_of::() == 2 { + // Use rotate-by-16 to reverse u16s in a u32 + let chunk = mem::size_of::() / 2; + while i + chunk - 1 < ln / 2 { + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - chunk); + let va = ptr::read_unaligned(pa as *mut u32); + let vb = ptr::read_unaligned(pb as *mut u32); + ptr::write_unaligned(pa as *mut u32, vb.rotate_left(16)); + ptr::write_unaligned(pb as *mut u32, va.rotate_left(16)); + } + i += chunk; + } + } + + while i < ln / 2 { + // Unsafe swap to avoid the bounds check in safe swap. + unsafe { + let pa: *mut T = self.get_unchecked_mut(i); + let pb: *mut T = self.get_unchecked_mut(ln - i - 1); + ptr::swap(pa, pb); + } + i += 1; + } } /// Returns an iterator over the slice. @@ -1145,7 +579,21 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter(&self) -> Iter { - SliceExt::iter(self) + unsafe { + let p = if mem::size_of::() == 0 { + 1 as *const _ + } else { + let p = self.as_ptr(); + assume(!p.is_null()); + p + }; + + Iter { + ptr: p, + end: slice_offset!(p, self.len() as isize), + _marker: marker::PhantomData + } + } } /// Returns an iterator that allows modifying each value. @@ -1162,7 +610,21 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter_mut(&mut self) -> IterMut { - SliceExt::iter_mut(self) + unsafe { + let p = if mem::size_of::() == 0 { + 1 as *mut _ + } else { + let p = self.as_mut_ptr(); + assume(!p.is_null()); + p + }; + + IterMut { + ptr: p, + end: slice_offset!(p, self.len() as isize), + _marker: marker::PhantomData + } + } } /// Returns an iterator over all contiguous windows of length @@ -1194,7 +656,8 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn windows(&self, size: usize) -> Windows { - SliceExt::windows(self, size) + assert!(size != 0); + Windows { v: self, size: size } } /// Returns an iterator over `chunk_size` elements of the slice at a @@ -1202,39 +665,8 @@ macro_rules! slice_core_methods { () => { /// not divide the length of the slice, then the last chunk will /// not have length `chunk_size`. /// - /// See [`exact_chunks`] for a variant of this iterator that returns chunks - /// of always exactly `chunk_size` elements. - /// - /// # Panics - /// - /// Panics if `chunk_size` is 0. - /// - /// # Examples - /// - /// ``` - /// let slice = ['l', 'o', 'r', 'e', 'm']; - /// let mut iter = slice.chunks(2); - /// assert_eq!(iter.next().unwrap(), &['l', 'o']); - /// assert_eq!(iter.next().unwrap(), &['r', 'e']); - /// assert_eq!(iter.next().unwrap(), &['m']); - /// assert!(iter.next().is_none()); - /// ``` - /// - /// [`exact_chunks`]: #method.exact_chunks - #[stable(feature = "rust1", since = "1.0.0")] - #[inline] - pub fn chunks(&self, chunk_size: usize) -> Chunks { - SliceExt::chunks(self, chunk_size) - } - - /// Returns an iterator over `chunk_size` elements of the slice at a - /// time. The chunks are slices and do not overlap. If `chunk_size` does - /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. - /// - /// Due to each chunk having exactly `chunk_size` elements, the compiler - /// can often optimize the resulting code better than in the case of - /// [`chunks`]. + /// See [`exact_chunks`] for a variant of this iterator that returns chunks + /// of always exactly `chunk_size` elements. /// /// # Panics /// @@ -1243,20 +675,20 @@ macro_rules! slice_core_methods { () => { /// # Examples /// /// ``` - /// #![feature(exact_chunks)] - /// /// let slice = ['l', 'o', 'r', 'e', 'm']; - /// let mut iter = slice.exact_chunks(2); + /// let mut iter = slice.chunks(2); /// assert_eq!(iter.next().unwrap(), &['l', 'o']); /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert_eq!(iter.next().unwrap(), &['m']); /// assert!(iter.next().is_none()); /// ``` /// - /// [`chunks`]: #method.chunks - #[unstable(feature = "exact_chunks", issue = "47115")] + /// [`exact_chunks`]: #method.exact_chunks + #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { - SliceExt::exact_chunks(self, chunk_size) + pub fn chunks(&self, chunk_size: usize) -> Chunks { + assert!(chunk_size != 0); + Chunks { v: self, chunk_size: chunk_size } } /// Returns an iterator over `chunk_size` elements of the slice at a time. @@ -1290,14 +722,52 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut { - SliceExt::chunks_mut(self, chunk_size) + assert!(chunk_size != 0); + ChunksMut { v: self, chunk_size: chunk_size } + } + + /// Returns an iterator over `chunk_size` elements of the slice at a + /// time. The chunks are slices and do not overlap. If `chunk_size` does + /// not divide the length of the slice, then the last up to `chunk_size-1` + /// elements will be omitted and can be retrieved from the `remainder` + /// function of the iterator. + /// + /// Due to each chunk having exactly `chunk_size` elements, the compiler + /// can often optimize the resulting code better than in the case of + /// [`chunks`]. + /// + /// # Panics + /// + /// Panics if `chunk_size` is 0. + /// + /// # Examples + /// + /// ``` + /// #![feature(exact_chunks)] + /// + /// let slice = ['l', 'o', 'r', 'e', 'm']; + /// let mut iter = slice.exact_chunks(2); + /// assert_eq!(iter.next().unwrap(), &['l', 'o']); + /// assert_eq!(iter.next().unwrap(), &['r', 'e']); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`chunks`]: #method.chunks + #[unstable(feature = "exact_chunks", issue = "47115")] + #[inline] + pub fn exact_chunks(&self, chunk_size: usize) -> ExactChunks { + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let len = self.len() - rem; + let (fst, snd) = self.split_at(len); + ExactChunks { v: fst, rem: snd, chunk_size: chunk_size} } /// Returns an iterator over `chunk_size` elements of the slice at a time. /// The chunks are mutable slices, and do not overlap. If `chunk_size` does /// not divide the length of the slice, then the last up to `chunk_size-1` - /// elements will be omitted. - /// + /// elements will be omitted and can be retrieved from the `into_remainder` + /// function of the iterator. /// /// Due to each chunk having exactly `chunk_size` elements, the compiler /// can often optimize the resulting code better than in the case of @@ -1328,7 +798,11 @@ macro_rules! slice_core_methods { () => { #[unstable(feature = "exact_chunks", issue = "47115")] #[inline] pub fn exact_chunks_mut(&mut self, chunk_size: usize) -> ExactChunksMut { - SliceExt::exact_chunks_mut(self, chunk_size) + assert!(chunk_size != 0); + let rem = self.len() % chunk_size; + let len = self.len() - rem; + let (fst, snd) = self.split_at_mut(len); + ExactChunksMut { v: fst, rem: snd, chunk_size: chunk_size} } /// Divides one slice into two at an index. @@ -1367,7 +841,7 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { - SliceExt::split_at(self, mid) + (&self[..mid], &self[mid..]) } /// Divides one mutable slice into two at an index. @@ -1397,7 +871,15 @@ macro_rules! slice_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { - SliceExt::split_at_mut(self, mid) + let len = self.len(); + let ptr = self.as_mut_ptr(); + + unsafe { + assert!(mid <= len); + + (from_raw_parts_mut(ptr, mid), + from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + } } /// Returns an iterator over subslices separated by elements that match @@ -1445,7 +927,11 @@ macro_rules! slice_core_methods { () => { pub fn split(&self, pred: F) -> Split where F: FnMut(&T) -> bool { - SliceExt::split(self, pred) + Split { + v: self, + pred, + finished: false + } } /// Returns an iterator over mutable subslices separated by elements that @@ -1466,7 +952,7 @@ macro_rules! slice_core_methods { () => { pub fn split_mut(&mut self, pred: F) -> SplitMut where F: FnMut(&T) -> bool { - SliceExt::split_mut(self, pred) + SplitMut { v: self, pred: pred, finished: false } } /// Returns an iterator over subslices separated by elements that match @@ -1501,7 +987,7 @@ macro_rules! slice_core_methods { () => { pub fn rsplit(&self, pred: F) -> RSplit where F: FnMut(&T) -> bool { - SliceExt::rsplit(self, pred) + RSplit { inner: self.split(pred) } } /// Returns an iterator over mutable subslices separated by elements that @@ -1526,7 +1012,7 @@ macro_rules! slice_core_methods { () => { pub fn rsplit_mut(&mut self, pred: F) -> RSplitMut where F: FnMut(&T) -> bool { - SliceExt::rsplit_mut(self, pred) + RSplitMut { inner: self.split_mut(pred) } } /// Returns an iterator over subslices separated by elements that match @@ -1553,7 +1039,12 @@ macro_rules! slice_core_methods { () => { pub fn splitn(&self, n: usize, pred: F) -> SplitN where F: FnMut(&T) -> bool { - SliceExt::splitn(self, n, pred) + SplitN { + inner: GenericSplitN { + iter: self.split(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1578,7 +1069,12 @@ macro_rules! slice_core_methods { () => { pub fn splitn_mut(&mut self, n: usize, pred: F) -> SplitNMut where F: FnMut(&T) -> bool { - SliceExt::splitn_mut(self, n, pred) + SplitNMut { + inner: GenericSplitN { + iter: self.split_mut(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1606,7 +1102,12 @@ macro_rules! slice_core_methods { () => { pub fn rsplitn(&self, n: usize, pred: F) -> RSplitN where F: FnMut(&T) -> bool { - SliceExt::rsplitn(self, n, pred) + RSplitN { + inner: GenericSplitN { + iter: self.rsplit(pred), + count: n + } + } } /// Returns an iterator over subslices separated by elements that match @@ -1632,7 +1133,12 @@ macro_rules! slice_core_methods { () => { pub fn rsplitn_mut(&mut self, n: usize, pred: F) -> RSplitNMut where F: FnMut(&T) -> bool { - SliceExt::rsplitn_mut(self, n, pred) + RSplitNMut { + inner: GenericSplitN { + iter: self.rsplit_mut(pred), + count: n + } + } } /// Returns `true` if the slice contains an element with the given value. @@ -1648,7 +1154,7 @@ macro_rules! slice_core_methods { () => { pub fn contains(&self, x: &T) -> bool where T: PartialEq { - SliceExt::contains(self, x) + x.slice_contains(self) } /// Returns `true` if `needle` is a prefix of the slice. @@ -1675,7 +1181,8 @@ macro_rules! slice_core_methods { () => { pub fn starts_with(&self, needle: &[T]) -> bool where T: PartialEq { - SliceExt::starts_with(self, needle) + let n = needle.len(); + self.len() >= n && needle == &self[..n] } /// Returns `true` if `needle` is a suffix of the slice. @@ -1702,7 +1209,8 @@ macro_rules! slice_core_methods { () => { pub fn ends_with(&self, needle: &[T]) -> bool where T: PartialEq { - SliceExt::ends_with(self, needle) + let (m, n) = (self.len(), needle.len()); + m >= n && needle == &self[m-n..] } /// Binary searches this sorted slice for a given element. @@ -1725,13 +1233,13 @@ macro_rules! slice_core_methods { () => { /// assert_eq!(s.binary_search(&4), Err(7)); /// assert_eq!(s.binary_search(&100), Err(13)); /// let r = s.binary_search(&1); - /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn binary_search(&self, x: &T) -> Result where T: Ord { - SliceExt::binary_search(self, x) + self.binary_search_by(|p| p.cmp(x)) } /// Binary searches this sorted slice with a comparator function. @@ -1763,14 +1271,33 @@ macro_rules! slice_core_methods { () => { /// assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13)); /// let seek = 1; /// let r = s.binary_search_by(|probe| probe.cmp(&seek)); - /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn binary_search_by<'a, F>(&'a self, f: F) -> Result + pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result where F: FnMut(&'a T) -> Ordering { - SliceExt::binary_search_by(self, f) + let s = self; + let mut size = s.len(); + if size == 0 { + return Err(0); + } + let mut base = 0usize; + while size > 1 { + let half = size / 2; + let mid = base + half; + // mid is always in [0, size), that means mid is >= 0 and < size. + // mid >= 0: by definition + // mid < size: mid = size / 2 + size / 4 + size / 8 ... + let cmp = f(unsafe { s.get_unchecked(mid) }); + base = if cmp == Greater { base } else { mid }; + size -= half; + } + // base is always in [0, size) because base <= mid. + let cmp = f(unsafe { s.get_unchecked(base) }); + if cmp == Equal { Ok(base) } else { Err(base + (cmp == Less) as usize) } + } /// Binary searches this sorted slice with a key extraction function. @@ -1801,15 +1328,15 @@ macro_rules! slice_core_methods { () => { /// assert_eq!(s.binary_search_by_key(&4, |&(a,b)| b), Err(7)); /// assert_eq!(s.binary_search_by_key(&100, |&(a,b)| b), Err(13)); /// let r = s.binary_search_by_key(&1, |&(a,b)| b); - /// assert!(match r { Ok(1...4) => true, _ => false, }); + /// assert!(match r { Ok(1..=4) => true, _ => false, }); /// ``` #[stable(feature = "slice_binary_search_by_key", since = "1.10.0")] #[inline] - pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, f: F) -> Result + pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result where F: FnMut(&'a T) -> B, B: Ord { - SliceExt::binary_search_by_key(self, b, f) + self.binary_search_by(|k| f(k).cmp(b)) } /// Sorts the slice, but may not preserve the order of equal elements. @@ -1843,7 +1370,7 @@ macro_rules! slice_core_methods { () => { pub fn sort_unstable(&mut self) where T: Ord { - SliceExt::sort_unstable(self); + sort::quicksort(self, |a, b| a.lt(b)); } /// Sorts the slice with a comparator function, but may not preserve the order of equal @@ -1878,10 +1405,10 @@ macro_rules! slice_core_methods { () => { /// [pdqsort]: https://github.com/orlp/pdqsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] - pub fn sort_unstable_by(&mut self, compare: F) + pub fn sort_unstable_by(&mut self, mut compare: F) where F: FnMut(&T, &T) -> Ordering { - SliceExt::sort_unstable_by(self, compare); + sort::quicksort(self, |a, b| compare(a, b) == Ordering::Less); } /// Sorts the slice with a key extraction function, but may not preserve the order of equal @@ -1910,10 +1437,10 @@ macro_rules! slice_core_methods { () => { /// [pdqsort]: https://github.com/orlp/pdqsort #[stable(feature = "sort_unstable", since = "1.20.0")] #[inline] - pub fn sort_unstable_by_key(&mut self, f: F) + pub fn sort_unstable_by_key(&mut self, mut f: F) where F: FnMut(&T) -> K, K: Ord { - SliceExt::sort_unstable_by_key(self, f); + sort::quicksort(self, |a, b| f(a).lt(&f(b))); } /// Rotates the slice in-place such that the first `mid` elements of the @@ -1948,7 +1475,13 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_left(&mut self, mid: usize) { - SliceExt::rotate_left(self, mid); + assert!(mid <= self.len()); + let k = self.len() - mid; + + unsafe { + let p = self.as_mut_ptr(); + rotate::ptr_rotate(mid, p.offset(mid as isize), k); + } } /// Rotates the slice in-place such that the first `self.len() - k` @@ -1983,7 +1516,13 @@ macro_rules! slice_core_methods { () => { /// ``` #[stable(feature = "slice_rotate", since = "1.26.0")] pub fn rotate_right(&mut self, k: usize) { - SliceExt::rotate_right(self, k); + assert!(k <= self.len()); + let mid = self.len() - k; + + unsafe { + let p = self.as_mut_ptr(); + rotate::ptr_rotate(mid, p.offset(mid as isize), k); + } } /// Copies the elements from `src` into `self`. @@ -2005,6 +1544,9 @@ macro_rules! slice_core_methods { () => { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. /// dst.clone_from_slice(&src[2..]); /// /// assert_eq!(src, [1, 2, 3, 4]); @@ -2040,7 +1582,17 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "clone_from_slice", since = "1.7.0")] pub fn clone_from_slice(&mut self, src: &[T]) where T: Clone { - SliceExt::clone_from_slice(self, src) + assert!(self.len() == src.len(), + "destination and source slices have different lengths"); + // NOTE: We need to explicitly slice them to the same length + // for bounds checking to be elided, and the optimizer will + // generate memcpy for simple cases (for example T = u8). + let len = self.len(); + let src = &src[..len]; + for i in 0..len { + self[i].clone_from(&src[i]); + } + } /// Copies all elements from `src` into `self`, using a memcpy. @@ -2061,6 +1613,9 @@ macro_rules! slice_core_methods { () => { /// let src = [1, 2, 3, 4]; /// let mut dst = [0, 0]; /// + /// // Because the slices have to be the same length, + /// // we slice the source slice from four elements + /// // to two. It will panic if we don't do this. /// dst.copy_from_slice(&src[2..]); /// /// assert_eq!(src, [1, 2, 3, 4]); @@ -2096,7 +1651,12 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "copy_from_slice", since = "1.9.0")] pub fn copy_from_slice(&mut self, src: &[T]) where T: Copy { - SliceExt::copy_from_slice(self, src) + assert_eq!(self.len(), src.len(), + "destination and source slices have different lengths"); + unsafe { + ptr::copy_nonoverlapping( + src.as_ptr(), self.as_mut_ptr(), self.len()); + } } /// Swaps all elements in `self` with those in `other`. @@ -2148,22 +1708,183 @@ macro_rules! slice_core_methods { () => { /// [`split_at_mut`]: #method.split_at_mut #[stable(feature = "swap_with_slice", since = "1.27.0")] pub fn swap_with_slice(&mut self, other: &mut [T]) { - SliceExt::swap_with_slice(self, other) + assert!(self.len() == other.len(), + "destination and source slices have different lengths"); + unsafe { + ptr::swap_nonoverlapping( + self.as_mut_ptr(), other.as_mut_ptr(), self.len()); + } } -}} -#[lang = "slice"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl [T] { - slice_core_methods!(); + /// Function to calculate lenghts of the middle and trailing slice for `align_to{,_mut}`. + fn align_to_offsets(&self) -> (usize, usize) { + // What we gonna do about `rest` is figure out what multiple of `U`s we can put in a + // lowest number of `T`s. And how many `T`s we need for each such "multiple". + // + // Consider for example T=u8 U=u16. Then we can put 1 U in 2 Ts. Simple. Now, consider + // for example a case where size_of:: = 16, size_of:: = 24. We can put 2 Us in + // place of every 3 Ts in the `rest` slice. A bit more complicated. + // + // Formula to calculate this is: + // + // Us = lcm(size_of::, size_of::) / size_of:: + // Ts = lcm(size_of::, size_of::) / size_of:: + // + // Expanded and simplified: + // + // Us = size_of:: / gcd(size_of::, size_of::) + // Ts = size_of:: / gcd(size_of::, size_of::) + // + // Luckily since all this is constant-evaluated... performance here matters not! + #[inline] + fn gcd(a: usize, b: usize) -> usize { + // iterative stein’s algorithm + // We should still make this `const fn` (and revert to recursive algorithm if we do) + // because relying on llvm to consteval all this is… well, it makes me + let (ctz_a, mut ctz_b) = unsafe { + if a == 0 { return b; } + if b == 0 { return a; } + (::intrinsics::cttz_nonzero(a), ::intrinsics::cttz_nonzero(b)) + }; + let k = ctz_a.min(ctz_b); + let mut a = a >> ctz_a; + let mut b = b; + loop { + // remove all factors of 2 from b + b >>= ctz_b; + if a > b { + ::mem::swap(&mut a, &mut b); + } + b = b - a; + unsafe { + if b == 0 { + break; + } + ctz_b = ::intrinsics::cttz_nonzero(b); + } + } + return a << k; + } + let gcd: usize = gcd(::mem::size_of::(), ::mem::size_of::()); + let ts: usize = ::mem::size_of::() / gcd; + let us: usize = ::mem::size_of::() / gcd; + + // Armed with this knowledge, we can find how many `U`s we can fit! + let us_len = self.len() / ts * us; + // And how many `T`s will be in the trailing slice! + let ts_len = self.len() % ts; + return (us_len, ts_len); + } + + /// Transmute the slice to a slice of another type, ensuring aligment of the types is + /// maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle slice will have the greatest length + /// possible for a given type and input slice. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Unsafety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(slice_align_to)] + /// unsafe { + /// let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[unstable(feature = "slice_align_to", issue = "44488")] + pub unsafe fn align_to(&self) -> (&[T], &[U], &[T]) { + // Note that most of this function will be constant-evaluated, + if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { + // handle ZSTs specially, which is – don't handle them at all. + return (self, &[], &[]); + } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + let offset = ::ptr::align_offset(ptr, ::mem::align_of::()); + if offset > self.len() { + return (self, &[], &[]); + } else { + let (left, rest) = self.split_at(offset); + let (us_len, ts_len) = rest.align_to_offsets::(); + return (left, + from_raw_parts(rest.as_ptr() as *const U, us_len), + from_raw_parts(rest.as_ptr().offset((rest.len() - ts_len) as isize), ts_len)) + } + } + + /// Transmute the slice to a slice of another type, ensuring aligment of the types is + /// maintained. + /// + /// This method splits the slice into three distinct slices: prefix, correctly aligned middle + /// slice of a new type, and the suffix slice. The middle slice will have the greatest length + /// possible for a given type and input slice. + /// + /// This method has no purpose when either input element `T` or output element `U` are + /// zero-sized and will return the original slice without splitting anything. + /// + /// # Unsafety + /// + /// This method is essentially a `transmute` with respect to the elements in the returned + /// middle slice, so all the usual caveats pertaining to `transmute::` also apply here. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(slice_align_to)] + /// unsafe { + /// let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7]; + /// let (prefix, shorts, suffix) = bytes.align_to_mut::(); + /// // less_efficient_algorithm_for_bytes(prefix); + /// // more_efficient_algorithm_for_aligned_shorts(shorts); + /// // less_efficient_algorithm_for_bytes(suffix); + /// } + /// ``` + #[unstable(feature = "slice_align_to", issue = "44488")] + pub unsafe fn align_to_mut(&mut self) -> (&mut [T], &mut [U], &mut [T]) { + // Note that most of this function will be constant-evaluated, + if ::mem::size_of::() == 0 || ::mem::size_of::() == 0 { + // handle ZSTs specially, which is – don't handle them at all. + return (self, &mut [], &mut []); + } + + // First, find at what point do we split between the first and 2nd slice. Easy with + // ptr.align_offset. + let ptr = self.as_ptr(); + let offset = ::ptr::align_offset(ptr, ::mem::align_of::()); + if offset > self.len() { + return (self, &mut [], &mut []); + } else { + let (left, rest) = self.split_at_mut(offset); + let (us_len, ts_len) = rest.align_to_offsets::(); + let mut_ptr = rest.as_mut_ptr(); + return (left, + from_raw_parts_mut(mut_ptr as *mut U, us_len), + from_raw_parts_mut(mut_ptr.offset((rest.len() - ts_len) as isize), ts_len)) + } + } } -// FIXME: remove (inline) this macro -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_slice_ext", issue = "32110")] -macro_rules! slice_u8_core_methods { () => { +#[lang = "slice_u8"] +#[cfg(not(test))] +impl [u8] { /// Checks if all bytes in this slice are within the ASCII range. #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] #[inline] @@ -2217,13 +1938,7 @@ macro_rules! slice_u8_core_methods { () => { byte.make_ascii_lowercase(); } } -}} -#[lang = "slice_u8"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl [u8] { - slice_u8_core_methods!(); } #[stable(feature = "rust1", since = "1.0.0")] @@ -2262,35 +1977,69 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! { panic!("slice index starts at {} but ends at {}", index, end); } +#[inline(never)] +#[cold] +fn slice_index_overflow_fail() -> ! { + panic!("attempted to index slice up to maximum usize"); +} + +mod private_slice_index { + use super::ops; + #[stable(feature = "slice_get_slice", since = "1.28.0")] + pub trait Sealed {} + + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for usize {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::Range {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeTo {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFrom {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFull {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeInclusive {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeToInclusive {} +} + /// A helper trait used for indexing operations. -#[unstable(feature = "slice_get_slice", issue = "35729")] +#[stable(feature = "slice_get_slice", since = "1.28.0")] #[rustc_on_unimplemented = "slice indices are of type `usize` or ranges of `usize`"] -pub trait SliceIndex { +pub trait SliceIndex: private_slice_index::Sealed { /// The output type returned by methods. + #[stable(feature = "slice_get_slice", since = "1.28.0")] type Output: ?Sized; /// Returns a shared reference to the output at this location, if in /// bounds. + #[unstable(feature = "slice_index_methods", issue = "0")] fn get(self, slice: &T) -> Option<&Self::Output>; /// Returns a mutable reference to the output at this location, if in /// bounds. + #[unstable(feature = "slice_index_methods", issue = "0")] fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; /// Returns a shared reference to the output at this location, without /// performing any bounds checking. + #[unstable(feature = "slice_index_methods", issue = "0")] unsafe fn get_unchecked(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, without /// performing any bounds checking. + #[unstable(feature = "slice_index_methods", issue = "0")] unsafe fn get_unchecked_mut(self, slice: &mut T) -> &mut Self::Output; /// Returns a shared reference to the output at this location, panicking /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "0")] fn index(self, slice: &T) -> &Self::Output; /// Returns a mutable reference to the output at this location, panicking /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "0")] fn index_mut(self, slice: &mut T) -> &mut Self::Output; } @@ -2516,38 +2265,36 @@ impl SliceIndex<[T]> for ops::RangeInclusive { #[inline] fn get(self, slice: &[T]) -> Option<&[T]> { - if self.end == usize::max_value() { None } - else { (self.start..self.end + 1).get(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end() + 1).get(slice) } } #[inline] fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if self.end == usize::max_value() { None } - else { (self.start..self.end + 1).get_mut(slice) } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end() + 1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &[T]) -> &[T] { - (self.start..self.end + 1).get_unchecked(slice) + (*self.start()..self.end() + 1).get_unchecked(slice) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut [T]) -> &mut [T] { - (self.start..self.end + 1).get_unchecked_mut(slice) + (*self.start()..self.end() + 1).get_unchecked_mut(slice) } #[inline] fn index(self, slice: &[T]) -> &[T] { - assert!(self.end != usize::max_value(), - "attempted to index slice up to maximum usize"); - (self.start..self.end + 1).index(slice) + if *self.end() == usize::max_value() { slice_index_overflow_fail(); } + (*self.start()..self.end() + 1).index(slice) } #[inline] fn index_mut(self, slice: &mut [T]) -> &mut [T] { - assert!(self.end != usize::max_value(), - "attempted to index slice up to maximum usize"); - (self.start..self.end + 1).index_mut(slice) + if *self.end() == usize::max_value() { slice_index_overflow_fail(); } + (*self.start()..self.end() + 1).index_mut(slice) } } @@ -2800,6 +2547,12 @@ macro_rules! iterator { accum } } + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, T> FusedIterator for $name<'a, T> {} + + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl<'a, T> TrustedLen for $name<'a, T> {} } } @@ -2926,12 +2679,6 @@ impl<'a, T> ExactSizeIterator for Iter<'a, T> { } } -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for Iter<'a, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T> TrustedLen for Iter<'a, T> {} - #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> Clone for Iter<'a, T> { fn clone(&self) -> Iter<'a, T> { Iter { ptr: self.ptr, end: self.end, _marker: self._marker } } @@ -2993,9 +2740,7 @@ impl<'a, T> IterMut<'a, T> { /// View the underlying data as a subslice of the original data. /// /// To avoid creating `&mut` references that alias, this is forced - /// to consume the iterator. Consider using the `Slice` and - /// `SliceMut` implementations for obtaining slices with more - /// restricted lifetimes that do not consume the iterator. + /// to consume the iterator. /// /// # Examples /// @@ -3054,13 +2799,6 @@ impl<'a, T> ExactSizeIterator for IterMut<'a, T> { } } -#[stable(feature = "fused", since = "1.26.0")] -impl<'a, T> FusedIterator for IterMut<'a, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<'a, T> TrustedLen for IterMut<'a, T> {} - - // Return the number of elements of `T` from `start` to `end`. // Return the arithmetic difference if `T` is zero size. #[inline(always)] @@ -3658,6 +3396,9 @@ impl<'a, T> DoubleEndedIterator for Windows<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Windows<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for Windows<'a, T> {} + #[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Windows<'a, T> {} @@ -3777,6 +3518,9 @@ impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for Chunks<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for Chunks<'a, T> {} + #[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for Chunks<'a, T> {} @@ -3893,6 +3637,9 @@ impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { #[stable(feature = "rust1", since = "1.0.0")] impl<'a, T> ExactSizeIterator for ChunksMut<'a, T> {} +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for ChunksMut<'a, T> {} + #[stable(feature = "fused", since = "1.26.0")] impl<'a, T> FusedIterator for ChunksMut<'a, T> {} @@ -3913,25 +3660,39 @@ unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { /// time). /// /// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted. +/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. /// /// This struct is created by the [`exact_chunks`] method on [slices]. /// /// [`exact_chunks`]: ../../std/primitive.slice.html#method.exact_chunks +/// [`remainder`]: ../../std/slice/struct.ExactChunks.html#method.remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] #[unstable(feature = "exact_chunks", issue = "47115")] pub struct ExactChunks<'a, T:'a> { v: &'a [T], + rem: &'a [T], chunk_size: usize } +#[unstable(feature = "exact_chunks", issue = "47115")] +impl<'a, T> ExactChunks<'a, T> { + /// Return the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + // FIXME(#26925) Remove in favor of `#[derive(Clone)]` #[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> Clone for ExactChunks<'a, T> { fn clone(&self) -> ExactChunks<'a, T> { ExactChunks { v: self.v, + rem: self.rem, chunk_size: self.chunk_size, } } @@ -4003,6 +3764,9 @@ impl<'a, T> ExactSizeIterator for ExactChunks<'a, T> { } } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for ExactChunks<'a, T> {} + #[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunks<'a, T> {} @@ -4016,20 +3780,35 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunks<'a, T> { } /// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time). When the slice len is not evenly divided by the chunk -/// size, the last up to `chunk_size-1` elements will be omitted. +/// elements at a time). +/// +/// When the slice len is not evenly divided by the chunk size, the last up to +/// `chunk_size-1` elements will be omitted but can be retrieved from the +/// [`into_remainder`] function from the iterator. /// /// This struct is created by the [`exact_chunks_mut`] method on [slices]. /// /// [`exact_chunks_mut`]: ../../std/primitive.slice.html#method.exact_chunks_mut +/// [`into_remainder`]: ../../std/slice/struct.ExactChunksMut.html#method.into_remainder /// [slices]: ../../std/primitive.slice.html #[derive(Debug)] #[unstable(feature = "exact_chunks", issue = "47115")] pub struct ExactChunksMut<'a, T:'a> { v: &'a mut [T], + rem: &'a mut [T], chunk_size: usize } +#[unstable(feature = "exact_chunks", issue = "47115")] +impl<'a, T> ExactChunksMut<'a, T> { + /// Return the remainder of the original slice that is not going to be + /// returned by the iterator. The returned slice has at most `chunk_size-1` + /// elements. + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + #[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> Iterator for ExactChunksMut<'a, T> { type Item = &'a mut [T]; @@ -4100,6 +3879,9 @@ impl<'a, T> ExactSizeIterator for ExactChunksMut<'a, T> { } } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<'a, T> TrustedLen for ExactChunksMut<'a, T> {} + #[unstable(feature = "exact_chunks", issue = "47115")] impl<'a, T> FusedIterator for ExactChunksMut<'a, T> {} @@ -4126,10 +3908,11 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> { /// valid for `len` elements, nor whether the lifetime inferred is a suitable /// lifetime for the returned slice. /// -/// `p` must be non-null, even for zero-length slices, because non-zero bits -/// are required to distinguish between a zero-length slice within `Some()` -/// from `None`. `p` can be a bogus non-dereferencable pointer, such as `0x1`, -/// for zero-length slices, though. +/// `data` must be non-null and aligned, even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. /// /// # Caveat /// @@ -4151,10 +3934,12 @@ unsafe impl<'a, T> TrustedRandomAccess for ExactChunksMut<'a, T> { /// let slice = slice::from_raw_parts(ptr, amt); /// } /// ``` +/// +/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] { - mem::transmute(Repr { data: p, len: len }) +pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + Repr { raw: FatPtr { data, len } }.rust } /// Performs the same functionality as `from_raw_parts`, except that a mutable @@ -4162,16 +3947,16 @@ pub unsafe fn from_raw_parts<'a, T>(p: *const T, len: usize) -> &'a [T] { /// /// This function is unsafe for the same reasons as `from_raw_parts`, as well /// as not being able to provide a non-aliasing guarantee of the returned -/// mutable slice. `p` must be non-null even for zero-length slices as with -/// `from_raw_parts`. +/// mutable slice. `data` must be non-null and aligned even for zero-length +/// slices as with `from_raw_parts`. #[inline] #[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts_mut<'a, T>(p: *mut T, len: usize) -> &'a mut [T] { - mem::transmute(Repr { data: p, len: len }) +pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + Repr { raw: FatPtr { data, len} }.rust_mut } /// Converts a reference to T into a slice of length 1 (without copying). -#[unstable(feature = "from_ref", issue = "45703")] +#[stable(feature = "from_ref", since = "1.28.0")] pub fn from_ref(s: &T) -> &[T] { unsafe { from_raw_parts(s, 1) @@ -4179,8 +3964,8 @@ pub fn from_ref(s: &T) -> &[T] { } /// Converts a reference to T into a slice of length 1 (without copying). -#[unstable(feature = "from_ref", issue = "45703")] -pub fn from_ref_mut(s: &mut T) -> &mut [T] { +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_mut(s: &mut T) -> &mut [T] { unsafe { from_raw_parts_mut(s, 1) } diff --git a/src/libcore/slice/rotate.rs b/src/libcore/slice/rotate.rs index e4a4e33c1729e..28ef53ccb5cb6 100644 --- a/src/libcore/slice/rotate.rs +++ b/src/libcore/slice/rotate.rs @@ -48,7 +48,6 @@ impl RawArray { /// # Safety /// /// The specified range must be valid for reading and writing. -/// The type `T` must have non-zero size. /// /// # Algorithm /// @@ -73,6 +72,7 @@ pub unsafe fn ptr_rotate(mut left: usize, mid: *mut T, mut right: usize) { loop { let delta = cmp::min(left, right); if delta <= RawArray::::cap() { + // We will always hit this immediately for ZST. break; } diff --git a/src/libcore/str/lossy.rs b/src/libcore/str/lossy.rs index 30b7267da7c5e..5cfb36d3b195b 100644 --- a/src/libcore/str/lossy.rs +++ b/src/libcore/str/lossy.rs @@ -101,10 +101,10 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { } 3 => { match (byte, safe_get(self.source, i)) { - (0xE0, 0xA0 ... 0xBF) => (), - (0xE1 ... 0xEC, 0x80 ... 0xBF) => (), - (0xED, 0x80 ... 0x9F) => (), - (0xEE ... 0xEF, 0x80 ... 0xBF) => (), + (0xE0, 0xA0 ..= 0xBF) => (), + (0xE1 ..= 0xEC, 0x80 ..= 0xBF) => (), + (0xED, 0x80 ..= 0x9F) => (), + (0xEE ..= 0xEF, 0x80 ..= 0xBF) => (), _ => { error!(); } @@ -117,9 +117,9 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { } 4 => { match (byte, safe_get(self.source, i)) { - (0xF0, 0x90 ... 0xBF) => (), - (0xF1 ... 0xF3, 0x80 ... 0xBF) => (), - (0xF4, 0x80 ... 0x8F) => (), + (0xF0, 0x90 ..= 0xBF) => (), + (0xF1 ..= 0xF3, 0x80 ..= 0xBF) => (), + (0xF4, 0x80 ..= 0x8F) => (), _ => { error!(); } diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs index b39d9feb35b7e..86b8349fa3c89 100644 --- a/src/libcore/str/mod.rs +++ b/src/libcore/str/mod.rs @@ -21,7 +21,7 @@ use char; use fmt; use iter::{Map, Cloned, FusedIterator, TrustedLen, Filter}; use iter_private::TrustedRandomAccess; -use slice::{self, SliceIndex}; +use slice::{self, SliceIndex, Split as SliceSplit}; use mem; pub mod pattern; @@ -376,37 +376,6 @@ pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { Ok(unsafe { from_utf8_unchecked_mut(v) }) } -/// Forms a str from a pointer and a length. -/// -/// The `len` argument is the number of bytes in the string. -/// -/// # Safety -/// -/// This function is unsafe as there is no guarantee that the given pointer is -/// valid for `len` bytes, nor whether the lifetime inferred is a suitable -/// lifetime for the returned str. -/// -/// The data must be valid UTF-8 -/// -/// `p` must be non-null, even for zero-length strs, because non-zero bits -/// are required to distinguish between a zero-length str within `Some()` -/// from `None`. `p` can be a bogus non-dereferencable pointer, such as `0x1`, -/// for zero-length strs, though. -/// -/// # Caveat -/// -/// The lifetime for the returned str is inferred from its usage. To -/// prevent accidental misuse, it's suggested to tie the lifetime to whichever -/// source lifetime is safe in the context, such as by providing a helper -/// function taking the lifetime of a host value for the str, or by explicit -/// annotation. -/// Performs the same functionality as `from_raw_parts`, except that a mutable -/// str is returned. -/// -unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str { - from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len)) -} - /// Converts a slice of bytes to a string slice without checking /// that the string contains valid UTF-8. /// @@ -727,13 +696,10 @@ impl<'a> Iterator for CharIndices<'a> { impl<'a> DoubleEndedIterator for CharIndices<'a> { #[inline] fn next_back(&mut self) -> Option<(usize, char)> { - match self.iter.next_back() { - None => None, - Some(ch) => { - let index = self.front_offset + self.iter.iter.len(); - Some((index, ch)) - } - } + self.iter.next_back().map(|ch| { + let index = self.front_offset + self.iter.iter.len(); + (index, ch) + }) } } @@ -1086,7 +1052,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { self.finished = true; unsafe { - let string = self.matcher.haystack().slice_unchecked(self.start, self.end); + let string = self.matcher.haystack().get_unchecked(self.start..self.end); Some(string) } } else { @@ -1101,7 +1067,7 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { let haystack = self.matcher.haystack(); match self.matcher.next_match() { Some((a, b)) => unsafe { - let elt = haystack.slice_unchecked(self.start, a); + let elt = haystack.get_unchecked(self.start..a); self.start = b; Some(elt) }, @@ -1126,13 +1092,13 @@ impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { let haystack = self.matcher.haystack(); match self.matcher.next_match_back() { Some((a, b)) => unsafe { - let elt = haystack.slice_unchecked(b, self.end); + let elt = haystack.get_unchecked(b..self.end); self.end = a; Some(elt) }, None => unsafe { self.finished = true; - Some(haystack.slice_unchecked(self.start, self.end)) + Some(haystack.get_unchecked(self.start..self.end)) }, } } @@ -1253,7 +1219,7 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { #[inline] fn next(&mut self) -> Option<(usize, &'a str)> { self.0.next_match().map(|(start, end)| unsafe { - (start, self.0.haystack().slice_unchecked(start, end)) + (start, self.0.haystack().get_unchecked(start..end)) }) } @@ -1262,7 +1228,7 @@ impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { where P::Searcher: ReverseSearcher<'a> { self.0.next_match_back().map(|(start, end)| unsafe { - (start, self.0.haystack().slice_unchecked(start, end)) + (start, self.0.haystack().get_unchecked(start..end)) }) } } @@ -1305,7 +1271,7 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { fn next(&mut self) -> Option<&'a str> { self.0.next_match().map(|(a, b)| unsafe { // Indices are known to be on utf8 boundaries - self.0.haystack().slice_unchecked(a, b) + self.0.haystack().get_unchecked(a..b) }) } @@ -1315,7 +1281,7 @@ impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { { self.0.next_match_back().map(|(a, b)| unsafe { // Indices are known to be on utf8 boundaries - self.0.haystack().slice_unchecked(a, b) + self.0.haystack().get_unchecked(a..b) }) } } @@ -1515,10 +1481,10 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { }, 3 => { match (first, next!()) { - (0xE0 , 0xA0 ... 0xBF) | - (0xE1 ... 0xEC, 0x80 ... 0xBF) | - (0xED , 0x80 ... 0x9F) | - (0xEE ... 0xEF, 0x80 ... 0xBF) => {} + (0xE0 , 0xA0 ..= 0xBF) | + (0xE1 ..= 0xEC, 0x80 ..= 0xBF) | + (0xED , 0x80 ..= 0x9F) | + (0xEE ..= 0xEF, 0x80 ..= 0xBF) => {} _ => err!(Some(1)) } if next!() & !CONT_MASK != TAG_CONT_U8 { @@ -1527,9 +1493,9 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { } 4 => { match (first, next!()) { - (0xF0 , 0x90 ... 0xBF) | - (0xF1 ... 0xF3, 0x80 ... 0xBF) | - (0xF4 , 0x80 ... 0x8F) => {} + (0xF0 , 0x90 ..= 0xBF) | + (0xF1 ..= 0xF3, 0x80 ..= 0xBF) | + (0xF4 , 0x80 ..= 0x8F) => {} _ => err!(Some(1)) } if next!() & !CONT_MASK != TAG_CONT_U8 { @@ -1849,6 +1815,12 @@ mod traits { } } + #[inline(never)] + #[cold] + fn str_index_overflow_fail() -> ! { + panic!("attempted to index str up to maximum usize"); + } + #[stable(feature = "str_checked_slicing", since = "1.20.0")] impl SliceIndex for ops::RangeFull { type Output = str; @@ -2029,39 +2001,31 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if let Some(end) = self.end.checked_add(1) { - (self.start..end).get(slice) - } else { - None - } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end()+1).get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if let Some(end) = self.end.checked_add(1) { - (self.start..end).get_mut(slice) - } else { - None - } + if *self.end() == usize::max_value() { None } + else { (*self.start()..self.end()+1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - (self.start..self.end+1).get_unchecked(slice) + (*self.start()..self.end()+1).get_unchecked(slice) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - (self.start..self.end+1).get_unchecked_mut(slice) + (*self.start()..self.end()+1).get_unchecked_mut(slice) } #[inline] fn index(self, slice: &str) -> &Self::Output { - assert!(self.end != usize::max_value(), - "attempted to index str up to maximum usize"); - (self.start..self.end+1).index(slice) + if *self.end() == usize::max_value() { str_index_overflow_fail(); } + (*self.start()..self.end()+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - assert!(self.end != usize::max_value(), - "attempted to index str up to maximum usize"); - (self.start..self.end+1).index_mut(slice) + if *self.end() == usize::max_value() { str_index_overflow_fail(); } + (*self.start()..self.end()+1).index_mut(slice) } } @@ -2072,156 +2036,34 @@ mod traits { type Output = str; #[inline] fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) { - Some(unsafe { self.get_unchecked(slice) }) - } else { - None - } + if self.end == usize::max_value() { None } + else { (..self.end+1).get(slice) } } #[inline] fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end < usize::max_value() && slice.is_char_boundary(self.end + 1) { - Some(unsafe { self.get_unchecked_mut(slice) }) - } else { - None - } + if self.end == usize::max_value() { None } + else { (..self.end+1).get_mut(slice) } } #[inline] unsafe fn get_unchecked(self, slice: &str) -> &Self::Output { - let ptr = slice.as_ptr(); - super::from_utf8_unchecked(slice::from_raw_parts(ptr, self.end + 1)) + (..self.end+1).get_unchecked(slice) } #[inline] unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output { - let ptr = slice.as_ptr(); - super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1)) + (..self.end+1).get_unchecked_mut(slice) } #[inline] fn index(self, slice: &str) -> &Self::Output { - assert!(self.end != usize::max_value(), - "attempted to index str up to maximum usize"); + if self.end == usize::max_value() { str_index_overflow_fail(); } (..self.end+1).index(slice) } #[inline] fn index_mut(self, slice: &mut str) -> &mut Self::Output { - assert!(self.end != usize::max_value(), - "attempted to index str up to maximum usize"); + if self.end == usize::max_value() { str_index_overflow_fail(); } (..self.end+1).index_mut(slice) } } - -} - -public_in_stage0! { -{ -/// Methods for string slices -#[allow(missing_docs)] -#[doc(hidden)] -#[unstable(feature = "core_str_ext", - reason = "stable interface provided by `impl str` in later crates", - issue = "32110")] } -trait StrExt { - // NB there are no docs here are they're all located on the StrExt trait in - // liballoc, not here. - - #[stable(feature = "core", since = "1.6.0")] - fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn chars(&self) -> Chars; - #[stable(feature = "core", since = "1.6.0")] - fn bytes(&self) -> Bytes; - #[stable(feature = "core", since = "1.6.0")] - fn char_indices(&self) -> CharIndices; - #[stable(feature = "core", since = "1.6.0")] - fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P>; - #[stable(feature = "core", since = "1.6.0")] - fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn lines(&self) -> Lines; - #[stable(feature = "core", since = "1.6.0")] - #[rustc_deprecated(since = "1.6.0", reason = "use lines() instead now")] - #[allow(deprecated)] - fn lines_any(&self) -> LinesAny; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - fn get>(&self, i: I) -> Option<&I::Output>; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - fn get_mut>(&mut self, i: I) -> Option<&mut I::Output>; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe fn get_unchecked>(&self, i: I) -> &I::Output; - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output; - #[stable(feature = "core", since = "1.6.0")] - unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str; - #[stable(feature = "core", since = "1.6.0")] - unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str; - #[stable(feature = "core", since = "1.6.0")] - fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a>; - #[stable(feature = "core", since = "1.6.0")] - fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str; - #[stable(feature = "core", since = "1.6.0")] - fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a>; - #[stable(feature = "is_char_boundary", since = "1.9.0")] - fn is_char_boundary(&self, index: usize) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn as_bytes(&self) -> &[u8]; - #[stable(feature = "str_mut_extras", since = "1.20.0")] - unsafe fn as_bytes_mut(&mut self) -> &mut [u8]; - #[stable(feature = "core", since = "1.6.0")] - fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; - #[stable(feature = "core", since = "1.6.0")] - fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a>; - fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option; - #[stable(feature = "core", since = "1.6.0")] - fn split_at(&self, mid: usize) -> (&str, &str); - #[stable(feature = "core", since = "1.6.0")] - fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str); - #[stable(feature = "core", since = "1.6.0")] - fn as_ptr(&self) -> *const u8; - #[stable(feature = "core", since = "1.6.0")] - fn len(&self) -> usize; - #[stable(feature = "core", since = "1.6.0")] - fn is_empty(&self) -> bool; - #[stable(feature = "core", since = "1.6.0")] - fn parse(&self) -> Result; - #[stable(feature = "split_whitespace", since = "1.1.0")] - fn split_whitespace<'a>(&'a self) -> SplitWhitespace<'a>; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim(&self) -> &str; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim_left(&self) -> &str; - #[stable(feature = "rust1", since = "1.0.0")] - fn trim_right(&self) -> &str; -}} // truncate `&str` to length at most equal to `max` // return `true` if it were truncated, and the new str. @@ -2267,307 +2109,9 @@ fn slice_error_fail(s: &str, begin: usize, end: usize) -> ! { index, ch, char_range, s_trunc, ellipsis); } -#[stable(feature = "core", since = "1.6.0")] -impl StrExt for str { - #[inline] - fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - pat.is_contained_in(self) - } - - #[inline] - fn chars(&self) -> Chars { - Chars{iter: self.as_bytes().iter()} - } - - #[inline] - fn bytes(&self) -> Bytes { - Bytes(self.as_bytes().iter().cloned()) - } - - #[inline] - fn char_indices(&self) -> CharIndices { - CharIndices { front_offset: 0, iter: self.chars() } - } - - #[inline] - fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - Split(SplitInternal { - start: 0, - end: self.len(), - matcher: pat.into_searcher(self), - allow_trailing_empty: true, - finished: false, - }) - } - - #[inline] - fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplit(self.split(pat).0) - } - - #[inline] - fn splitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> SplitN<'a, P> { - SplitN(SplitNInternal { - iter: self.split(pat).0, - count, - }) - } - - #[inline] - fn rsplitn<'a, P: Pattern<'a>>(&'a self, count: usize, pat: P) -> RSplitN<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplitN(self.splitn(count, pat).0) - } - - #[inline] - fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - SplitTerminator(SplitInternal { - allow_trailing_empty: false, - ..self.split(pat).0 - }) - } - - #[inline] - fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RSplitTerminator(self.split_terminator(pat).0) - } - - #[inline] - fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - Matches(MatchesInternal(pat.into_searcher(self))) - } - - #[inline] - fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RMatches(self.matches(pat).0) - } - - #[inline] - fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) - } - - #[inline] - fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> - where P::Searcher: ReverseSearcher<'a> - { - RMatchIndices(self.match_indices(pat).0) - } - #[inline] - fn lines(&self) -> Lines { - Lines(self.split_terminator('\n').map(LinesAnyMap)) - } - - #[inline] - #[allow(deprecated)] - fn lines_any(&self) -> LinesAny { - LinesAny(self.lines()) - } - - #[inline] - fn get>(&self, i: I) -> Option<&I::Output> { - i.get(self) - } - - #[inline] - fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { - i.get_mut(self) - } - - #[inline] - unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - i.get_unchecked(self) - } - - #[inline] - unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - i.get_unchecked_mut(self) - } - - #[inline] - unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - (begin..end).get_unchecked(self) - } - - #[inline] - unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - (begin..end).get_unchecked_mut(self) - } - - #[inline] - fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - pat.is_prefix_of(self) - } - - #[inline] - fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool - where P::Searcher: ReverseSearcher<'a> - { - pat.is_suffix_of(self) - } - - #[inline] - fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: DoubleEndedSearcher<'a> - { - let mut i = 0; - let mut j = 0; - let mut matcher = pat.into_searcher(self); - if let Some((a, b)) = matcher.next_reject() { - i = a; - j = b; // Remember earliest known match, correct it below if - // last match is different - } - if let Some((_, b)) = matcher.next_reject_back() { - j = b; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(i, j) - } - } - - #[inline] - fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - let mut i = self.len(); - let mut matcher = pat.into_searcher(self); - if let Some((a, _)) = matcher.next_reject() { - i = a; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(i, self.len()) - } - } - - #[inline] - fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str - where P::Searcher: ReverseSearcher<'a> - { - let mut j = 0; - let mut matcher = pat.into_searcher(self); - if let Some((_, b)) = matcher.next_reject_back() { - j = b; - } - unsafe { - // Searcher is known to return valid indices - self.slice_unchecked(0, j) - } - } - - #[inline] - fn is_char_boundary(&self, index: usize) -> bool { - // 0 and len are always ok. - // Test for 0 explicitly so that it can optimize out the check - // easily and skip reading string data for that case. - if index == 0 || index == self.len() { return true; } - match self.as_bytes().get(index) { - None => false, - // This is bit magic equivalent to: b < 128 || b >= 192 - Some(&b) => (b as i8) >= -0x40, - } - } - - #[inline] - fn as_bytes(&self) -> &[u8] { - unsafe { &*(self as *const str as *const [u8]) } - } - - #[inline] - unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - &mut *(self as *mut str as *mut [u8]) - } - - fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - pat.into_searcher(self).next_match().map(|(i, _)| i) - } - - fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option - where P::Searcher: ReverseSearcher<'a> - { - pat.into_searcher(self).next_match_back().map(|(i, _)| i) - } - - fn find_str<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - self.find(pat) - } - - #[inline] - fn split_at(&self, mid: usize) -> (&str, &str) { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(mid) { - unsafe { - (self.slice_unchecked(0, mid), - self.slice_unchecked(mid, self.len())) - } - } else { - slice_error_fail(self, 0, mid) - } - } - - fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - // is_char_boundary checks that the index is in [0, .len()] - if self.is_char_boundary(mid) { - let len = self.len(); - let ptr = self.as_ptr() as *mut u8; - unsafe { - (from_raw_parts_mut(ptr, mid), - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) - } - } else { - slice_error_fail(self, 0, mid) - } - } - - #[inline] - fn as_ptr(&self) -> *const u8 { - self as *const str as *const u8 - } - - #[inline] - fn len(&self) -> usize { - self.as_bytes().len() - } - - #[inline] - fn is_empty(&self) -> bool { self.len() == 0 } - - #[inline] - fn parse(&self) -> Result { FromStr::from_str(self) } - - #[inline] - fn split_whitespace(&self) -> SplitWhitespace { - SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } - } - - #[inline] - fn trim(&self) -> &str { - self.trim_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_left(&self) -> &str { - self.trim_left_matches(|c: char| c.is_whitespace()) - } - - #[inline] - fn trim_right(&self) -> &str { - self.trim_right_matches(|c: char| c.is_whitespace()) - } -} - -// FIXME: remove (inline) this macro and the SliceExt trait -// when updating to a bootstrap compiler that has the new lang items. -#[cfg_attr(stage0, macro_export)] -#[unstable(feature = "core_str_ext", issue = "32110")] -macro_rules! str_core_methods { () => { +#[lang = "str"] +#[cfg(not(test))] +impl str { /// Returns the length of `self`. /// /// This length is in bytes, not [`char`]s or graphemes. In other words, @@ -2588,8 +2132,9 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn len(&self) -> usize { - StrExt::len(self) + #[rustc_const_unstable(feature = "const_str_len")] + pub const fn len(&self) -> usize { + self.as_bytes().len() } /// Returns `true` if `self` has a length of zero bytes. @@ -2607,8 +2152,9 @@ macro_rules! str_core_methods { () => { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - pub fn is_empty(&self) -> bool { - StrExt::is_empty(self) + #[rustc_const_unstable(feature = "const_str_len")] + pub const fn is_empty(&self) -> bool { + self.len() == 0 } /// Checks that `index`-th byte lies at the start and/or end of a @@ -2638,7 +2184,15 @@ macro_rules! str_core_methods { () => { #[stable(feature = "is_char_boundary", since = "1.9.0")] #[inline] pub fn is_char_boundary(&self, index: usize) -> bool { - StrExt::is_char_boundary(self, index) + // 0 and len are always ok. + // Test for 0 explicitly so that it can optimize out the check + // easily and skip reading string data for that case. + if index == 0 || index == self.len() { return true; } + match self.as_bytes().get(index) { + None => false, + // This is bit magic equivalent to: b < 128 || b >= 192 + Some(&b) => (b as i8) >= -0x40, + } } /// Converts a string slice to a byte slice. To convert the byte slice back @@ -2656,8 +2210,13 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline(always)] - pub fn as_bytes(&self) -> &[u8] { - StrExt::as_bytes(self) + #[rustc_const_unstable(feature="const_str_as_bytes")] + pub const fn as_bytes(&self) -> &[u8] { + union Slices<'a> { + str: &'a str, + slice: &'a [u8], + } + unsafe { Slices { str: self }.slice } } /// Converts a mutable string slice to a mutable byte slice. To convert the @@ -2696,7 +2255,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_mut_extras", since = "1.20.0")] #[inline(always)] pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] { - StrExt::as_bytes_mut(self) + &mut *(self as *mut str as *mut [u8]) } /// Converts a string slice to a raw pointer. @@ -2717,8 +2276,9 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] - pub fn as_ptr(&self) -> *const u8 { - StrExt::as_ptr(self) + #[rustc_const_unstable(feature = "const_str_as_ptr")] + pub const fn as_ptr(&self) -> *const u8 { + self as *const str as *const u8 } /// Returns a subslice of `str`. @@ -2745,7 +2305,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub fn get>(&self, i: I) -> Option<&I::Output> { - StrExt::get(self, i) + i.get(self) } /// Returns a mutable subslice of `str`. @@ -2779,7 +2339,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub fn get_mut>(&mut self, i: I) -> Option<&mut I::Output> { - StrExt::get_mut(self, i) + i.get_mut(self) } /// Returns a unchecked subslice of `str`. @@ -2811,7 +2371,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked>(&self, i: I) -> &I::Output { - StrExt::get_unchecked(self, i) + i.get_unchecked(self) } /// Returns a mutable, unchecked subslice of `str`. @@ -2843,7 +2403,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_checked_slicing", since = "1.20.0")] #[inline] pub unsafe fn get_unchecked_mut>(&mut self, i: I) -> &mut I::Output { - StrExt::get_unchecked_mut(self, i) + i.get_unchecked_mut(self) } /// Creates a string slice from another string slice, bypassing safety @@ -2890,9 +2450,10 @@ macro_rules! str_core_methods { () => { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked(begin..end)` instead")] #[inline] pub unsafe fn slice_unchecked(&self, begin: usize, end: usize) -> &str { - StrExt::slice_unchecked(self, begin, end) + (begin..end).get_unchecked(self) } /// Creates a string slice from another string slice, bypassing safety @@ -2920,9 +2481,10 @@ macro_rules! str_core_methods { () => { /// * `begin` and `end` must be byte positions within the string slice. /// * `begin` and `end` must lie on UTF-8 sequence boundaries. #[stable(feature = "str_slice_mut", since = "1.5.0")] + #[rustc_deprecated(since = "1.29.0", reason = "use `get_unchecked_mut(begin..end)` instead")] #[inline] pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str { - StrExt::slice_mut_unchecked(self, begin, end) + (begin..end).get_unchecked_mut(self) } /// Divide one string slice into two at an index. @@ -2958,7 +2520,15 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "str_split_at", since = "1.4.0")] pub fn split_at(&self, mid: usize) -> (&str, &str) { - StrExt::split_at(self, mid) + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + unsafe { + (self.get_unchecked(0..mid), + self.get_unchecked(mid..self.len())) + } + } else { + slice_error_fail(self, 0, mid) + } } /// Divide one mutable string slice into two at an index. @@ -2995,7 +2565,20 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "str_split_at", since = "1.4.0")] pub fn split_at_mut(&mut self, mid: usize) -> (&mut str, &mut str) { - StrExt::split_at_mut(self, mid) + // is_char_boundary checks that the index is in [0, .len()] + if self.is_char_boundary(mid) { + let len = self.len(); + let ptr = self.as_ptr() as *mut u8; + unsafe { + (from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr, mid)), + from_utf8_unchecked_mut(slice::from_raw_parts_mut( + ptr.offset(mid as isize), + len - mid + ))) + } + } else { + slice_error_fail(self, 0, mid) + } } /// Returns an iterator over the [`char`]s of a string slice. @@ -3047,8 +2630,9 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn chars(&self) -> Chars { - StrExt::chars(self) + Chars{iter: self.as_bytes().iter()} } + /// Returns an iterator over the [`char`]s of a string slice, and their /// positions. /// @@ -3103,7 +2687,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn char_indices(&self) -> CharIndices { - StrExt::char_indices(self) + CharIndices { front_offset: 0, iter: self.chars() } } /// An iterator over the bytes of a string slice. @@ -3128,7 +2712,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn bytes(&self) -> Bytes { - StrExt::bytes(self) + Bytes(self.as_bytes().iter().cloned()) } /// Split a string slice by whitespace. @@ -3137,7 +2721,10 @@ macro_rules! str_core_methods { () => { /// the original string slice, separated by any amount of whitespace. /// /// 'Whitespace' is defined according to the terms of the Unicode Derived - /// Core Property `White_Space`. + /// Core Property `White_Space`. If you only want to split on ASCII whitespace + /// instead, use [`split_ascii_whitespace`]. + /// + /// [`split_ascii_whitespace`]: #method.split_ascii_whitespace /// /// # Examples /// @@ -3168,7 +2755,54 @@ macro_rules! str_core_methods { () => { #[stable(feature = "split_whitespace", since = "1.1.0")] #[inline] pub fn split_whitespace(&self) -> SplitWhitespace { - StrExt::split_whitespace(self) + SplitWhitespace { inner: self.split(IsWhitespace).filter(IsNotEmpty) } + } + + /// Split a string slice by ASCII whitespace. + /// + /// The iterator returned will return string slices that are sub-slices of + /// the original string slice, separated by any amount of ASCII whitespace. + /// + /// To split by Unicode `Whitespace` instead, use [`split_whitespace`]. + /// + /// [`split_whitespace`]: #method.split_whitespace + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(split_ascii_whitespace)] + /// let mut iter = "A few words".split_ascii_whitespace(); + /// + /// assert_eq!(Some("A"), iter.next()); + /// assert_eq!(Some("few"), iter.next()); + /// assert_eq!(Some("words"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + /// + /// All kinds of ASCII whitespace are considered: + /// + /// ``` + /// let mut iter = " Mary had\ta little \n\t lamb".split_whitespace(); + /// assert_eq!(Some("Mary"), iter.next()); + /// assert_eq!(Some("had"), iter.next()); + /// assert_eq!(Some("a"), iter.next()); + /// assert_eq!(Some("little"), iter.next()); + /// assert_eq!(Some("lamb"), iter.next()); + /// + /// assert_eq!(None, iter.next()); + /// ``` + #[unstable(feature = "split_ascii_whitespace", issue = "48656")] + #[inline] + pub fn split_ascii_whitespace(&self) -> SplitAsciiWhitespace { + let inner = self + .as_bytes() + .split(IsAsciiWhitespace) + .filter(IsNotEmpty) + .map(UnsafeBytesToStr); + SplitAsciiWhitespace { inner } } /// An iterator over the lines of a string, as string slices. @@ -3210,7 +2844,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn lines(&self) -> Lines { - StrExt::lines(self) + Lines(self.split_terminator('\n').map(LinesAnyMap)) } /// An iterator over the lines of a string. @@ -3219,7 +2853,7 @@ macro_rules! str_core_methods { () => { #[inline] #[allow(deprecated)] pub fn lines_any(&self) -> LinesAny { - StrExt::lines_any(self) + LinesAny(self.lines()) } /// Returns an iterator of `u16` over the string encoded as UTF-16. @@ -3238,7 +2872,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "encode_utf16", since = "1.8.0")] pub fn encode_utf16(&self) -> EncodeUtf16 { - EncodeUtf16::new(self) + EncodeUtf16 { chars: self.chars(), extra: 0 } } /// Returns `true` if the given pattern matches a sub-slice of @@ -3259,7 +2893,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn contains<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - StrExt::contains(self, pat) + pat.is_contained_in(self) } /// Returns `true` if the given pattern matches a prefix of this @@ -3279,7 +2913,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool { - StrExt::starts_with(self, pat) + pat.is_prefix_of(self) } /// Returns `true` if the given pattern matches a suffix of this @@ -3301,7 +2935,7 @@ macro_rules! str_core_methods { () => { pub fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool where P::Searcher: ReverseSearcher<'a> { - StrExt::ends_with(self, pat) + pat.is_suffix_of(self) } /// Returns the byte index of the first character of this string slice that @@ -3349,7 +2983,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option { - StrExt::find(self, pat) + pat.into_searcher(self).next_match().map(|(i, _)| i) } /// Returns the byte index of the last character of this string slice that @@ -3396,7 +3030,7 @@ macro_rules! str_core_methods { () => { pub fn rfind<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option where P::Searcher: ReverseSearcher<'a> { - StrExt::rfind(self, pat) + pat.into_searcher(self).next_match_back().map(|(i, _)| i) } /// An iterator over substrings of this string slice, separated by @@ -3508,7 +3142,13 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> { - StrExt::split(self, pat) + Split(SplitInternal { + start: 0, + end: self.len(), + matcher: pat.into_searcher(self), + allow_trailing_empty: true, + finished: false, + }) } /// An iterator over substrings of the given string slice, separated by @@ -3560,7 +3200,7 @@ macro_rules! str_core_methods { () => { pub fn rsplit<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplit<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplit(self, pat) + RSplit(self.split(pat).0) } /// An iterator over substrings of the given string slice, separated by @@ -3605,7 +3245,10 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> SplitTerminator<'a, P> { - StrExt::split_terminator(self, pat) + SplitTerminator(SplitInternal { + allow_trailing_empty: false, + ..self.split(pat).0 + }) } /// An iterator over substrings of `self`, separated by characters @@ -3651,7 +3294,7 @@ macro_rules! str_core_methods { () => { pub fn rsplit_terminator<'a, P: Pattern<'a>>(&'a self, pat: P) -> RSplitTerminator<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplit_terminator(self, pat) + RSplitTerminator(self.split_terminator(pat).0) } /// An iterator over substrings of the given string slice, separated by a @@ -3702,7 +3345,10 @@ macro_rules! str_core_methods { () => { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn splitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> SplitN<'a, P> { - StrExt::splitn(self, n, pat) + SplitN(SplitNInternal { + iter: self.split(pat).0, + count: n, + }) } /// An iterator over substrings of this string slice, separated by a @@ -3752,7 +3398,7 @@ macro_rules! str_core_methods { () => { pub fn rsplitn<'a, P: Pattern<'a>>(&'a self, n: usize, pat: P) -> RSplitN<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rsplitn(self, n, pat) + RSplitN(self.splitn(n, pat).0) } /// An iterator over the disjoint matches of a pattern within the given string @@ -3791,7 +3437,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_matches", since = "1.2.0")] #[inline] pub fn matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> Matches<'a, P> { - StrExt::matches(self, pat) + Matches(MatchesInternal(pat.into_searcher(self))) } /// An iterator over the disjoint matches of a pattern within this string slice, @@ -3830,7 +3476,7 @@ macro_rules! str_core_methods { () => { pub fn rmatches<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatches<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rmatches(self, pat) + RMatches(self.matches(pat).0) } /// An iterator over the disjoint matches of a pattern within this string @@ -3874,7 +3520,7 @@ macro_rules! str_core_methods { () => { #[stable(feature = "str_match_indices", since = "1.5.0")] #[inline] pub fn match_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> MatchIndices<'a, P> { - StrExt::match_indices(self, pat) + MatchIndices(MatchIndicesInternal(pat.into_searcher(self))) } /// An iterator over the disjoint matches of a pattern within `self`, @@ -3919,7 +3565,7 @@ macro_rules! str_core_methods { () => { pub fn rmatch_indices<'a, P: Pattern<'a>>(&'a self, pat: P) -> RMatchIndices<'a, P> where P::Searcher: ReverseSearcher<'a> { - StrExt::rmatch_indices(self, pat) + RMatchIndices(self.match_indices(pat).0) } /// Returns a string slice with leading and trailing whitespace removed. @@ -3938,7 +3584,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim(&self) -> &str { - StrExt::trim(self) + self.trim_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with leading whitespace removed. @@ -3974,7 +3620,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_left(&self) -> &str { - StrExt::trim_left(self) + self.trim_left_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with trailing whitespace removed. @@ -4010,7 +3656,7 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_right(&self) -> &str { - StrExt::trim_right(self) + self.trim_right_matches(|c: char| c.is_whitespace()) } /// Returns a string slice with all prefixes and suffixes that match a @@ -4042,7 +3688,21 @@ macro_rules! str_core_methods { () => { pub fn trim_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: DoubleEndedSearcher<'a> { - StrExt::trim_matches(self, pat) + let mut i = 0; + let mut j = 0; + let mut matcher = pat.into_searcher(self); + if let Some((a, b)) = matcher.next_reject() { + i = a; + j = b; // Remember earliest known match, correct it below if + // last match is different + } + if let Some((_, b)) = matcher.next_reject_back() { + j = b; + } + unsafe { + // Searcher is known to return valid indices + self.get_unchecked(i..j) + } } /// Returns a string slice with all prefixes that match a pattern @@ -4073,7 +3733,15 @@ macro_rules! str_core_methods { () => { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn trim_left_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str { - StrExt::trim_left_matches(self, pat) + let mut i = self.len(); + let mut matcher = pat.into_searcher(self); + if let Some((a, _)) = matcher.next_reject() { + i = a; + } + unsafe { + // Searcher is known to return valid indices + self.get_unchecked(i..self.len()) + } } /// Returns a string slice with all suffixes that match a pattern @@ -4112,7 +3780,15 @@ macro_rules! str_core_methods { () => { pub fn trim_right_matches<'a, P: Pattern<'a>>(&'a self, pat: P) -> &'a str where P::Searcher: ReverseSearcher<'a> { - StrExt::trim_right_matches(self, pat) + let mut j = 0; + let mut matcher = pat.into_searcher(self); + if let Some((_, b)) = matcher.next_reject_back() { + j = b; + } + unsafe { + // Searcher is known to return valid indices + self.get_unchecked(0..j) + } } /// Parses this string slice into another type. @@ -4162,7 +3838,7 @@ macro_rules! str_core_methods { () => { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn parse(&self) -> Result { - StrExt::parse(self) + FromStr::from_str(self) } /// Checks if all characters in this string are within the ASCII range. @@ -4232,16 +3908,8 @@ macro_rules! str_core_methods { () => { let me = unsafe { self.as_bytes_mut() }; me.make_ascii_lowercase() } -}} - -#[lang = "str"] -#[cfg(not(test))] -#[cfg(not(stage0))] -impl str { - str_core_methods!(); } - #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[u8]> for str { #[inline] @@ -4256,6 +3924,12 @@ impl<'a> Default for &'a str { fn default() -> &'a str { "" } } +#[stable(feature = "default_mut_str", since = "1.28.0")] +impl<'a> Default for &'a mut str { + /// Creates an empty mutable str + fn default() -> &'a mut str { unsafe { from_utf8_unchecked_mut(&mut []) } } +} + /// An iterator over the non-whitespace substrings of a string, /// separated by any amount of whitespace. /// @@ -4270,6 +3944,20 @@ pub struct SplitWhitespace<'a> { inner: Filter, IsNotEmpty>, } +/// An iterator over the non-ASCII-whitespace substrings of a string, +/// separated by any amount of ASCII whitespace. +/// +/// This struct is created by the [`split_ascii_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_ascii_whitespace`]: ../../std/primitive.str.html#method.split_ascii_whitespace +/// [`str`]: ../../std/primitive.str.html +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +#[derive(Clone, Debug)] +pub struct SplitAsciiWhitespace<'a> { + inner: Map, IsNotEmpty>, UnsafeBytesToStr>, +} + #[derive(Clone)] struct IsWhitespace; @@ -4289,6 +3977,25 @@ impl FnMut<(char, )> for IsWhitespace { } } +#[derive(Clone)] +struct IsAsciiWhitespace; + +impl<'a> FnOnce<(&'a u8, )> for IsAsciiWhitespace { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&u8, )) -> bool { + self.call_mut(arg) + } +} + +impl<'a> FnMut<(&'a u8, )> for IsAsciiWhitespace { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&u8, )) -> bool { + arg.0.is_ascii_whitespace() + } +} + #[derive(Clone)] struct IsNotEmpty; @@ -4296,30 +4003,72 @@ impl<'a, 'b> FnOnce<(&'a &'b str, )> for IsNotEmpty { type Output = bool; #[inline] - extern "rust-call" fn call_once(mut self, arg: (&&str, )) -> bool { + extern "rust-call" fn call_once(mut self, arg: (&'a &'b str, )) -> bool { self.call_mut(arg) } } impl<'a, 'b> FnMut<(&'a &'b str, )> for IsNotEmpty { #[inline] - extern "rust-call" fn call_mut(&mut self, arg: (&&str, )) -> bool { + extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b str, )) -> bool { + !arg.0.is_empty() + } +} + +impl<'a, 'b> FnOnce<(&'a &'b [u8], )> for IsNotEmpty { + type Output = bool; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u8], )) -> bool { + self.call_mut(arg) + } +} + +impl<'a, 'b> FnMut<(&'a &'b [u8], )> for IsNotEmpty { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&'a &'b [u8], )) -> bool { !arg.0.is_empty() } } +#[derive(Clone)] +struct UnsafeBytesToStr; + +impl<'a> FnOnce<(&'a [u8], )> for UnsafeBytesToStr { + type Output = &'a str; + + #[inline] + extern "rust-call" fn call_once(mut self, arg: (&'a [u8], )) -> &'a str { + self.call_mut(arg) + } +} + +impl<'a> FnMut<(&'a [u8], )> for UnsafeBytesToStr { + #[inline] + extern "rust-call" fn call_mut(&mut self, arg: (&'a [u8], )) -> &'a str { + unsafe { from_utf8_unchecked(arg.0) } + } +} + #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> Iterator for SplitWhitespace<'a> { type Item = &'a str; + #[inline] fn next(&mut self) -> Option<&'a str> { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } } #[stable(feature = "split_whitespace", since = "1.1.0")] impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { + #[inline] fn next_back(&mut self) -> Option<&'a str> { self.inner.next_back() } @@ -4328,6 +4077,32 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { #[stable(feature = "fused", since = "1.26.0")] impl<'a> FusedIterator for SplitWhitespace<'a> {} +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +impl<'a> Iterator for SplitAsciiWhitespace<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[unstable(feature = "split_ascii_whitespace", issue = "48656")] +impl<'a> FusedIterator for SplitAsciiWhitespace<'a> {} + /// An iterator of [`u16`] over the string encoded as UTF-16. /// /// [`u16`]: ../../std/primitive.u16.html @@ -4344,17 +4119,6 @@ pub struct EncodeUtf16<'a> { extra: u16, } -// FIXME: remove (inline) this method -// when updating to a bootstrap compiler that has the new lang items. -// For grepping purpose: #[cfg(stage0)] -impl<'a> EncodeUtf16<'a> { - #[unstable(feature = "core_str_ext", issue = "32110")] - #[doc(hidden)] - pub fn new(s: &'a str) -> Self { - EncodeUtf16 { chars: s.chars(), extra: 0 } - } -} - #[stable(feature = "collection_debug", since = "1.17.0")] impl<'a> fmt::Debug for EncodeUtf16<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libcore/str/pattern.rs b/src/libcore/str/pattern.rs index 464d57a270241..5e63fa9ff354c 100644 --- a/src/libcore/str/pattern.rs +++ b/src/libcore/str/pattern.rs @@ -354,7 +354,7 @@ unsafe impl<'a> ReverseSearcher<'a> for CharSearcher<'a> { #[inline] fn next_back(&mut self) -> SearchStep { let old_finger = self.finger_back; - let slice = unsafe { self.haystack.slice_unchecked(self.finger, old_finger) }; + let slice = unsafe { self.haystack.get_unchecked(self.finger..old_finger) }; let mut iter = slice.chars(); let old_len = iter.iter.len(); if let Some(ch) = iter.next_back() { diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 7aba8b51cff51..1e2b18bf9b038 100644 --- a/src/libcore/sync/atomic.rs +++ b/src/libcore/sync/atomic.rs @@ -124,6 +124,7 @@ pub fn spin_loop_hint() { /// [`bool`]: ../../../std/primitive.bool.html #[cfg(target_has_atomic = "8")] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(transparent)] pub struct AtomicBool { v: UnsafeCell, } @@ -147,6 +148,7 @@ unsafe impl Sync for AtomicBool {} /// This type has the same in-memory representation as a `*mut T`. #[cfg(target_has_atomic = "ptr")] #[stable(feature = "rust1", since = "1.0.0")] +#[repr(transparent)] pub struct AtomicPtr { p: UnsafeCell<*mut T>, } @@ -371,6 +373,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn swap(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 } } @@ -401,6 +404,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -446,6 +450,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_exchange(&self, current: bool, new: bool, @@ -537,6 +542,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn fetch_and(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_and(self.v.get(), val as u8, order) != 0 } } @@ -568,6 +574,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool { // We can't use atomic_nand here because it can result in a bool with // an invalid value. This happens because the atomic operation is done @@ -610,6 +617,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn fetch_or(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_or(self.v.get(), val as u8, order) != 0 } } @@ -640,6 +648,7 @@ impl AtomicBool { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool { unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 } } @@ -786,6 +795,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T { unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T } } @@ -815,6 +825,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T { match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) { Ok(x) => x, @@ -853,6 +864,7 @@ impl AtomicPtr { /// ``` #[inline] #[stable(feature = "extended_compare_and_swap", since = "1.10.0")] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_exchange(&self, current: *mut T, new: *mut T, @@ -966,6 +978,7 @@ macro_rules! atomic_int { /// /// [module-level documentation]: index.html #[$stable] + #[repr(transparent)] pub struct $atomic_type { v: UnsafeCell<$int_type>, } @@ -1138,6 +1151,7 @@ assert_eq!(some_var.swap(10, Ordering::Relaxed), 5); ```"), #[inline] #[$stable] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type { unsafe { atomic_swap(self.v.get(), val, order) } } @@ -1170,6 +1184,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[inline] #[$stable] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_and_swap(&self, current: $int_type, new: $int_type, @@ -1223,6 +1238,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[inline] #[$stable_cxchg] + #[cfg(any(stage0, target_has_atomic = "cas"))] pub fn compare_exchange(&self, current: $int_type, new: $int_type, @@ -1677,6 +1693,7 @@ atomic_int!{ } #[inline] +#[cfg(any(stage0, target_has_atomic = "cas"))] fn strongest_failure_ordering(order: Ordering) -> Ordering { match order { Release => Relaxed, @@ -1713,6 +1730,7 @@ unsafe fn atomic_load(dst: *const T, order: Ordering) -> T { } #[inline] +#[cfg(any(stage0, target_has_atomic = "cas"))] unsafe fn atomic_swap(dst: *mut T, val: T, order: Ordering) -> T { match order { Acquire => intrinsics::atomic_xchg_acq(dst, val), @@ -1751,6 +1769,7 @@ unsafe fn atomic_sub(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] +#[cfg(any(stage0, target_has_atomic = "cas"))] unsafe fn atomic_compare_exchange(dst: *mut T, old: T, new: T, diff --git a/src/libcore/task/context.rs b/src/libcore/task/context.rs new file mode 100644 index 0000000000000..1fc975cb17881 --- /dev/null +++ b/src/libcore/task/context.rs @@ -0,0 +1,92 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use super::{Executor, Waker, LocalWaker}; + +/// Information about the currently-running task. +/// +/// Contexts are always tied to the stack, since they are set up specifically +/// when performing a single `poll` step on a task. +pub struct Context<'a> { + local_waker: &'a LocalWaker, + executor: &'a mut dyn Executor, +} + +impl<'a> fmt::Debug for Context<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Context") + .finish() + } +} + +impl<'a> Context<'a> { + /// Create a new task `Context` with the provided `local_waker`, `waker`, and `executor`. + #[inline] + pub fn new(local_waker: &'a LocalWaker, executor: &'a mut dyn Executor) -> Context<'a> { + Context { + local_waker, + executor, + } + } + + /// Get the `LocalWaker` associated with the current task. + #[inline] + pub fn local_waker(&self) -> &'a LocalWaker { + self.local_waker + } + + /// Get the `Waker` associated with the current task. + #[inline] + pub fn waker(&self) -> &'a Waker { + unsafe { &*(self.local_waker as *const LocalWaker as *const Waker) } + } + + /// Get the default executor associated with this task. + /// + /// This method is useful primarily if you want to explicitly handle + /// spawn failures. + #[inline] + pub fn executor(&mut self) -> &mut dyn Executor { + self.executor + } + + /// Produce a context like the current one, but using the given waker instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task, where you want to provide some customized + /// wakeup logic. + #[inline] + pub fn with_waker<'b>(&'b mut self, local_waker: &'b LocalWaker) -> Context<'b> { + Context { + local_waker, + executor: self.executor, + } + } + + /// Produce a context like the current one, but using the given executor + /// instead. + /// + /// This advanced method is primarily used when building "internal + /// schedulers" within a task. + #[inline] + pub fn with_executor<'b, E>(&'b mut self, executor: &'b mut E) -> Context<'b> + where E: Executor + { + Context { + local_waker: self.local_waker, + executor: executor, + } + } +} diff --git a/src/libcore/task/executor.rs b/src/libcore/task/executor.rs new file mode 100644 index 0000000000000..affcbf464da22 --- /dev/null +++ b/src/libcore/task/executor.rs @@ -0,0 +1,96 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use fmt; +use future::{FutureObj, LocalFutureObj}; + +/// A task executor. +/// +/// Futures are polled until completion by tasks, a kind of lightweight +/// "thread". A *task executor* is responsible for the creation of these tasks +/// and the coordination of their execution on real operating system threads. In +/// particular, whenever a task signals that it can make further progress via a +/// wake-up notification, it is the responsibility of the task executor to put +/// the task into a queue to continue executing it, i.e. polling the future in +/// it, later. +pub trait Executor { + /// Spawns a new task with the given future. The future will be polled until + /// completion. + /// + /// # Errors + /// + /// The executor may be unable to spawn tasks, either because it has + /// been shut down or is resource-constrained. + fn spawn_obj( + &mut self, + future: FutureObj<'static, ()>, + ) -> Result<(), SpawnObjError>; + + /// Determines whether the executor is able to spawn new tasks. + /// + /// # Returns + /// + /// An `Ok` return means the executor is *likely* (but not guaranteed) + /// to accept a subsequent spawn attempt. Likewise, an `Err` return + /// means that `spawn` is likely, but not guaranteed, to yield an error. + #[inline] + fn status(&self) -> Result<(), SpawnErrorKind> { + Ok(()) + } +} + +/// Provides the reason that an executor was unable to spawn. +pub struct SpawnErrorKind { + _hidden: (), +} + +impl fmt::Debug for SpawnErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("SpawnErrorKind") + .field(&"shutdown") + .finish() + } +} + +impl SpawnErrorKind { + /// Spawning is failing because the executor has been shut down. + pub fn shutdown() -> SpawnErrorKind { + SpawnErrorKind { _hidden: () } + } + + /// Check whether this error is the `shutdown` error. + pub fn is_shutdown(&self) -> bool { + true + } +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The future for which spawning inside a task was attempted + pub future: FutureObj<'static, ()>, +} + +/// The result of a failed spawn +#[derive(Debug)] +pub struct SpawnLocalObjError { + /// The kind of error + pub kind: SpawnErrorKind, + + /// The future for which spawning inside a task was attempted + pub future: LocalFutureObj<'static, ()>, +} diff --git a/src/libcore/task/mod.rs b/src/libcore/task/mod.rs new file mode 100644 index 0000000000000..c4f075361640f --- /dev/null +++ b/src/libcore/task/mod.rs @@ -0,0 +1,29 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +//! Types and Traits for working with asynchronous tasks. + +mod context; +pub use self::context::Context; + +mod executor; +pub use self::executor::{ + Executor, SpawnErrorKind, SpawnObjError, SpawnLocalObjError +}; + +mod poll; +pub use self::poll::Poll; + +mod wake; +pub use self::wake::{Waker, LocalWaker, UnsafeWake}; diff --git a/src/libcore/task/poll.rs b/src/libcore/task/poll.rs new file mode 100644 index 0000000000000..fb027efc6dca0 --- /dev/null +++ b/src/libcore/task/poll.rs @@ -0,0 +1,137 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use ops::Try; +use result::Result; + +/// Indicates whether a value is available or if the current task has been +/// scheduled to receive a wakeup instead. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +pub enum Poll { + /// Represents that a value is immediately ready. + Ready(T), + + /// Represents that a value is not ready yet. + /// + /// When a function returns `Pending`, the function *must* also + /// ensure that the current task is scheduled to be awoken when + /// progress can be made. + Pending, +} + +impl Poll { + /// Change the ready value of this `Poll` with the closure provided + pub fn map(self, f: F) -> Poll + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(t) => Poll::Ready(f(t)), + Poll::Pending => Poll::Pending, + } + } + + /// Returns whether this is `Poll::Ready` + #[inline] + pub fn is_ready(&self) -> bool { + match *self { + Poll::Ready(_) => true, + Poll::Pending => false, + } + } + + /// Returns whether this is `Poll::Pending` + #[inline] + pub fn is_pending(&self) -> bool { + !self.is_ready() + } +} + +impl Poll> { + /// Change the success value of this `Poll` with the closure provided + pub fn map_ok(self, f: F) -> Poll> + where F: FnOnce(T) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(f(t))), + Poll::Ready(Err(e)) => Poll::Ready(Err(e)), + Poll::Pending => Poll::Pending, + } + } + + /// Change the error value of this `Poll` with the closure provided + pub fn map_err(self, f: F) -> Poll> + where F: FnOnce(E) -> U + { + match self { + Poll::Ready(Ok(t)) => Poll::Ready(Ok(t)), + Poll::Ready(Err(e)) => Poll::Ready(Err(f(e))), + Poll::Pending => Poll::Pending, + } + } +} + +impl From for Poll { + fn from(t: T) -> Poll { + Poll::Ready(t) + } +} + +impl Try for Poll> { + type Ok = Poll; + type Error = E; + + #[inline] + fn into_result(self) -> Result { + match self { + Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)), + Poll::Ready(Err(e)) => Err(e), + Poll::Pending => Ok(Poll::Pending), + } + } + + #[inline] + fn from_error(e: Self::Error) -> Self { + Poll::Ready(Err(e)) + } + + #[inline] + fn from_ok(x: Self::Ok) -> Self { + x.map(Ok) + } +} + +impl Try for Poll>> { + type Ok = Poll>; + type Error = E; + + #[inline] + fn into_result(self) -> Result { + match self { + Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))), + Poll::Ready(Some(Err(e))) => Err(e), + Poll::Ready(None) => Ok(Poll::Ready(None)), + Poll::Pending => Ok(Poll::Pending), + } + } + + #[inline] + fn from_error(e: Self::Error) -> Self { + Poll::Ready(Some(Err(e))) + } + + #[inline] + fn from_ok(x: Self::Ok) -> Self { + x.map(|x| x.map(Ok)) + } +} diff --git a/src/libcore/task/wake.rs b/src/libcore/task/wake.rs new file mode 100644 index 0000000000000..321b432d3f430 --- /dev/null +++ b/src/libcore/task/wake.rs @@ -0,0 +1,277 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![unstable(feature = "futures_api", + reason = "futures in libcore are unstable", + issue = "50547")] + +use {fmt, mem}; +use marker::Unpin; +use ptr::NonNull; + +/// A `Waker` is a handle for waking up a task by notifying its executor that it +/// is ready to be run. +/// +/// This handle contains a trait object pointing to an instance of the `UnsafeWake` +/// trait, allowing notifications to get routed through it. +#[repr(transparent)] +pub struct Waker { + inner: NonNull, +} + +impl Unpin for Waker {} +unsafe impl Send for Waker {} +unsafe impl Sync for Waker {} + +impl Waker { + /// Constructs a new `Waker` directly. + /// + /// Note that most code will not need to call this. Implementers of the + /// `UnsafeWake` trait will typically provide a wrapper that calls this + /// but you otherwise shouldn't call it directly. + /// + /// If you're working with the standard library then it's recommended to + /// use the `Waker::from` function instead which works with the safe + /// `Arc` type and the safe `Wake` trait. + #[inline] + pub unsafe fn new(inner: NonNull) -> Self { + Waker { inner: inner } + } + + /// Wake up the task associated with this `Waker`. + #[inline] + pub fn wake(&self) { + unsafe { self.inner.as_ref().wake() } + } + + /// Returns whether or not this `Waker` and `other` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `Waker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake(&self, other: &Waker) -> bool { + self.inner == other.inner + } +} + +impl Clone for Waker { + #[inline] + fn clone(&self) -> Self { + unsafe { + self.inner.as_ref().clone_raw() + } + } +} + +impl fmt::Debug for Waker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Waker") + .finish() + } +} + +impl Drop for Waker { + #[inline] + fn drop(&mut self) { + unsafe { + self.inner.as_ref().drop_raw() + } + } +} + +/// A `LocalWaker` is a handle for waking up a task by notifying its executor that it +/// is ready to be run. +/// +/// This is similar to the `Waker` type, but cannot be sent across threads. +/// Task executors can use this type to implement more optimized singlethreaded wakeup +/// behavior. +#[repr(transparent)] +pub struct LocalWaker { + inner: NonNull, +} + +impl Unpin for LocalWaker {} +impl !Send for LocalWaker {} +impl !Sync for LocalWaker {} + +impl LocalWaker { + /// Constructs a new `LocalWaker` directly. + /// + /// Note that most code will not need to call this. Implementers of the + /// `UnsafeWake` trait will typically provide a wrapper that calls this + /// but you otherwise shouldn't call it directly. + /// + /// If you're working with the standard library then it's recommended to + /// use the `local_waker_from_nonlocal` or `local_waker` to convert a `Waker` + /// into a `LocalWaker`. + /// + /// For this function to be used safely, it must be sound to call `inner.wake_local()` + /// on the current thread. + #[inline] + pub unsafe fn new(inner: NonNull) -> Self { + LocalWaker { inner: inner } + } + + /// Wake up the task associated with this `LocalWaker`. + #[inline] + pub fn wake(&self) { + unsafe { self.inner.as_ref().wake_local() } + } + + /// Returns whether or not this `LocalWaker` and `other` `LocalWaker` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `LocalWaker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake(&self, other: &LocalWaker) -> bool { + self.inner == other.inner + } + + /// Returns whether or not this `LocalWaker` and `other` `Waker` awaken the same task. + /// + /// This function works on a best-effort basis, and may return false even + /// when the `Waker`s would awaken the same task. However, if this function + /// returns true, it is guaranteed that the `LocalWaker`s will awaken the same + /// task. + /// + /// This function is primarily used for optimization purposes. + #[inline] + pub fn will_wake_nonlocal(&self, other: &Waker) -> bool { + self.inner == other.inner + } +} + +impl From for Waker { + #[inline] + fn from(local_waker: LocalWaker) -> Self { + Waker { inner: local_waker.inner } + } +} + +impl Clone for LocalWaker { + #[inline] + fn clone(&self) -> Self { + let waker = unsafe { self.inner.as_ref().clone_raw() }; + let inner = waker.inner; + mem::forget(waker); + LocalWaker { inner } + } +} + +impl fmt::Debug for LocalWaker { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Waker") + .finish() + } +} + +impl Drop for LocalWaker { + #[inline] + fn drop(&mut self) { + unsafe { + self.inner.as_ref().drop_raw() + } + } +} + +/// An unsafe trait for implementing custom memory management for a `Waker` or `LocalWaker`. +/// +/// A `Waker` conceptually is a cloneable trait object for `Wake`, and is +/// most often essentially just `Arc`. However, in some contexts +/// (particularly `no_std`), it's desirable to avoid `Arc` in favor of some +/// custom memory management strategy. This trait is designed to allow for such +/// customization. +/// +/// When using `std`, a default implementation of the `UnsafeWake` trait is provided for +/// `Arc` where `T: Wake`. +pub unsafe trait UnsafeWake: Send + Sync { + /// Creates a clone of this `UnsafeWake` and stores it behind a `Waker`. + /// + /// This function will create a new uniquely owned handle that under the + /// hood references the same notification instance. In other words calls + /// to `wake` on the returned handle should be equivalent to calls to + /// `wake` on this handle. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn clone_raw(&self) -> Waker; + + /// Drops this instance of `UnsafeWake`, deallocating resources + /// associated with it. + /// + /// FIXME(cramertj) + /// This method is intended to have a signature such as: + /// + /// ```ignore (not-a-doctest) + /// fn drop_raw(self: *mut Self); + /// ``` + /// + /// Unfortunately in Rust today that signature is not object safe. + /// Nevertheless it's recommended to implement this function *as if* that + /// were its signature. As such it is not safe to call on an invalid + /// pointer, nor is the validity of the pointer guaranteed after this + /// function returns. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn drop_raw(&self); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake` should place + /// the associated task onto this queue. + /// + /// # Panics + /// + /// Implementations should avoid panicking, but clients should also be prepared + /// for panics. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped. + unsafe fn wake(&self); + + /// Indicates that the associated task is ready to make progress and should + /// be `poll`ed. This function is the same as `wake`, but can only be called + /// from the thread that this `UnsafeWake` is "local" to. This allows for + /// implementors to provide specialized wakeup behavior specific to the current + /// thread. This function is called by `LocalWaker::wake`. + /// + /// Executors generally maintain a queue of "ready" tasks; `wake_local` should place + /// the associated task onto this queue. + /// + /// # Panics + /// + /// Implementations should avoid panicking, but clients should also be prepared + /// for panics. + /// + /// # Unsafety + /// + /// This function is unsafe to call because it's asserting the `UnsafeWake` + /// value is in a consistent state, i.e. hasn't been dropped, and that the + /// `UnsafeWake` hasn't moved from the thread on which it was created. + unsafe fn wake_local(&self) { + self.wake() + } +} diff --git a/src/libcore/tests/any.rs b/src/libcore/tests/any.rs index 2d3e81aa131ed..a80bf93953039 100644 --- a/src/libcore/tests/any.rs +++ b/src/libcore/tests/any.rs @@ -17,7 +17,7 @@ static TEST: &'static str = "Test"; #[test] fn any_referenced() { - let (a, b, c) = (&5 as &Any, &TEST as &Any, &Test as &Any); + let (a, b, c) = (&5 as &dyn Any, &TEST as &dyn Any, &Test as &dyn Any); assert!(a.is::()); assert!(!b.is::()); @@ -34,7 +34,11 @@ fn any_referenced() { #[test] fn any_owning() { - let (a, b, c) = (box 5_usize as Box, box TEST as Box, box Test as Box); + let (a, b, c) = ( + box 5_usize as Box, + box TEST as Box, + box Test as Box, + ); assert!(a.is::()); assert!(!b.is::()); @@ -51,7 +55,7 @@ fn any_owning() { #[test] fn any_downcast_ref() { - let a = &5_usize as &Any; + let a = &5_usize as &dyn Any; match a.downcast_ref::() { Some(&5) => {} @@ -69,9 +73,9 @@ fn any_downcast_mut() { let mut a = 5_usize; let mut b: Box<_> = box 7_usize; - let a_r = &mut a as &mut Any; + let a_r = &mut a as &mut dyn Any; let tmp: &mut usize = &mut *b; - let b_r = tmp as &mut Any; + let b_r = tmp as &mut dyn Any; match a_r.downcast_mut::() { Some(x) => { @@ -113,7 +117,7 @@ fn any_downcast_mut() { #[test] fn any_fixed_vec() { let test = [0_usize; 8]; - let test = &test as &Any; + let test = &test as &dyn Any; assert!(test.is::<[usize; 8]>()); assert!(!test.is::<[usize; 10]>()); } diff --git a/src/libcore/tests/cell.rs b/src/libcore/tests/cell.rs index 962fb2f0e027b..4b7243b9cfc79 100644 --- a/src/libcore/tests/cell.rs +++ b/src/libcore/tests/cell.rs @@ -165,6 +165,64 @@ fn ref_map_does_not_update_flag() { assert!(x.try_borrow_mut().is_ok()); } +#[test] +fn ref_map_split_updates_flag() { + let x = RefCell::new([1, 2]); + { + let b1 = x.borrow(); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + { + let (_b2, _b3) = Ref::map_split(b1, |slc| slc.split_at(1)); + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + + { + let b1 = x.borrow_mut(); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + { + let (_b2, _b3) = RefMut::map_split(b1, |slc| slc.split_at_mut(1)); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + drop(_b2); + assert!(x.try_borrow().is_err()); + assert!(x.try_borrow_mut().is_err()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); + } + assert!(x.try_borrow().is_ok()); + assert!(x.try_borrow_mut().is_ok()); +} + +#[test] +fn ref_map_split() { + let x = RefCell::new([1, 2]); + let (b1, b2) = Ref::map_split(x.borrow(), |slc| slc.split_at(1)); + assert_eq!(*b1, [1]); + assert_eq!(*b2, [2]); +} + +#[test] +fn ref_mut_map_split() { + let x = RefCell::new([1, 2]); + { + let (mut b1, mut b2) = RefMut::map_split(x.borrow_mut(), |slc| slc.split_at_mut(1)); + assert_eq!(*b1, [1]); + assert_eq!(*b2, [2]); + b1[0] = 2; + b2[0] = 1; + } + assert_eq!(*x.borrow(), [2, 1]); +} + #[test] fn ref_map_accessor() { struct X(RefCell<(u32, char)>); diff --git a/src/libcore/tests/char.rs b/src/libcore/tests/char.rs index ab90763abf8d5..d2a9ed75be658 100644 --- a/src/libcore/tests/char.rs +++ b/src/libcore/tests/char.rs @@ -181,6 +181,7 @@ fn test_escape_debug() { assert_eq!(string('\u{ff}'), "\u{ff}"); assert_eq!(string('\u{11b}'), "\u{11b}"); assert_eq!(string('\u{1d4b6}'), "\u{1d4b6}"); + assert_eq!(string('\u{301}'), "\\u{301}"); // combining character assert_eq!(string('\u{200b}'),"\\u{200b}"); // zero width space assert_eq!(string('\u{e000}'), "\\u{e000}"); // private use 1 assert_eq!(string('\u{100000}'), "\\u{100000}"); // private use 2 diff --git a/src/libcore/tests/hash/mod.rs b/src/libcore/tests/hash/mod.rs index 8716421b424de..85c9d41b65b59 100644 --- a/src/libcore/tests/hash/mod.rs +++ b/src/libcore/tests/hash/mod.rs @@ -128,7 +128,7 @@ fn test_custom_state() { fn test_indirect_hasher() { let mut hasher = MyHasher { hash: 0 }; { - let mut indirect_hasher: &mut Hasher = &mut hasher; + let mut indirect_hasher: &mut dyn Hasher = &mut hasher; 5u32.hash(&mut indirect_hasher); } assert_eq!(hasher.hash, 5); diff --git a/src/libcore/tests/intrinsics.rs b/src/libcore/tests/intrinsics.rs index 2b380abf63c58..9f3cba26a62db 100644 --- a/src/libcore/tests/intrinsics.rs +++ b/src/libcore/tests/intrinsics.rs @@ -22,7 +22,7 @@ fn test_typeid_sized_types() { #[test] fn test_typeid_unsized_types() { trait Z {} - struct X(str); struct Y(Z + 'static); + struct X(str); struct Y(dyn Z + 'static); assert_eq!(TypeId::of::(), TypeId::of::()); assert_eq!(TypeId::of::(), TypeId::of::()); diff --git a/src/libcore/tests/iter.rs b/src/libcore/tests/iter.rs index 2abac0cf1d5b9..72b115f8b5f77 100644 --- a/src/libcore/tests/iter.rs +++ b/src/libcore/tests/iter.rs @@ -1618,6 +1618,14 @@ fn test_range_step() { assert_eq!((isize::MIN..isize::MAX).step_by(1).size_hint(), (usize::MAX, Some(usize::MAX))); } +#[test] +fn test_range_inclusive_step() { + assert_eq!((0..=50).step_by(10).collect::>(), [0, 10, 20, 30, 40, 50]); + assert_eq!((0..=5).step_by(1).collect::>(), [0, 1, 2, 3, 4, 5]); + assert_eq!((200..=255u8).step_by(10).collect::>(), [200, 210, 220, 230, 240, 250]); + assert_eq!((250..=255u8).step_by(1).collect::>(), [250, 251, 252, 253, 254, 255]); +} + #[test] fn test_range_last_max() { assert_eq!((0..20).last(), Some(19)); @@ -1722,18 +1730,6 @@ fn test_repeat_with() { assert_eq!(repeat_with(|| NotClone(42)).size_hint(), (usize::MAX, None)); } -#[test] -fn test_repeat_with_rev() { - let mut curr = 1; - let mut pow2 = repeat_with(|| { let tmp = curr; curr *= 2; tmp }) - .rev().take(4); - assert_eq!(pow2.next(), Some(1)); - assert_eq!(pow2.next(), Some(2)); - assert_eq!(pow2.next(), Some(4)); - assert_eq!(pow2.next(), Some(8)); - assert_eq!(pow2.next(), None); -} - #[test] fn test_repeat_with_take() { let mut it = repeat_with(|| 42).take(3); diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index 28dac02654b4c..2323b30a0104a 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -23,13 +23,10 @@ #![feature(flt2dec)] #![feature(fmt_internals)] #![feature(hashmap_internals)] -#![feature(iterator_step_by)] -#![feature(iterator_flatten)] -#![feature(iterator_repeat_with)] -#![feature(nonzero)] #![feature(pattern)] #![feature(range_is_empty)] #![feature(raw)] +#![feature(refcell_map_split)] #![feature(refcell_replace_swap)] #![feature(slice_patterns)] #![feature(slice_rotate)] @@ -42,12 +39,13 @@ #![feature(try_from)] #![feature(try_trait)] #![feature(exact_chunks)] -#![cfg_attr(stage0, feature(atomic_nand))] +#![feature(slice_align_to)] +#![feature(align_offset)] #![feature(reverse_bits)] -#![feature(inclusive_range_methods)] #![feature(iterator_find_map)] #![feature(inner_deref)] #![feature(slice_internals)] +#![feature(option_replace)] extern crate core; extern crate test; @@ -65,6 +63,7 @@ mod fmt; mod hash; mod intrinsics; mod iter; +mod manually_drop; mod mem; mod nonzero; mod num; diff --git a/src/libcore/tests/manually_drop.rs b/src/libcore/tests/manually_drop.rs new file mode 100644 index 0000000000000..96bc9247da6e7 --- /dev/null +++ b/src/libcore/tests/manually_drop.rs @@ -0,0 +1,24 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::mem::ManuallyDrop; + +#[test] +fn smoke() { + struct TypeWithDrop; + impl Drop for TypeWithDrop { + fn drop(&mut self) { + unreachable!("Should not get dropped"); + } + } + + let x = ManuallyDrop::new(TypeWithDrop); + drop(x); +} diff --git a/src/libcore/tests/mem.rs b/src/libcore/tests/mem.rs index f55a1c81463f7..714f2babbdff6 100644 --- a/src/libcore/tests/mem.rs +++ b/src/libcore/tests/mem.rs @@ -109,11 +109,11 @@ fn test_transmute() { trait Foo { fn dummy(&self) { } } impl Foo for isize {} - let a = box 100isize as Box; + let a = box 100isize as Box; unsafe { let x: ::core::raw::TraitObject = transmute(a); assert!(*(x.data as *const isize) == 100); - let _x: Box = transmute(x); + let _x: Box = transmute(x); } unsafe { diff --git a/src/libcore/tests/num/dec2flt/parse.rs b/src/libcore/tests/num/dec2flt/parse.rs index 09acf2bc517b0..3ad694e38adb0 100644 --- a/src/libcore/tests/num/dec2flt/parse.rs +++ b/src/libcore/tests/num/dec2flt/parse.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::iter; use core::num::dec2flt::parse::{Decimal, parse_decimal}; use core::num::dec2flt::parse::ParseResult::{Valid, Invalid}; @@ -46,7 +45,7 @@ fn valid() { assert_eq!(parse_decimal("1.e300"), Valid(Decimal::new(b"1", b"", 300))); assert_eq!(parse_decimal(".1e300"), Valid(Decimal::new(b"", b"1", 300))); assert_eq!(parse_decimal("101e-33"), Valid(Decimal::new(b"101", b"", -33))); - let zeros: String = iter::repeat('0').take(25).collect(); + let zeros = "0".repeat(25); let s = format!("1.5e{}", zeros); assert_eq!(parse_decimal(&s), Valid(Decimal::new(b"1", b"5", 0))); } diff --git a/src/libcore/tests/num/flt2dec/random.rs b/src/libcore/tests/num/flt2dec/random.rs index 315ac4d7d99f5..a1928657dabc4 100644 --- a/src/libcore/tests/num/flt2dec/random.rs +++ b/src/libcore/tests/num/flt2dec/random.rs @@ -11,7 +11,6 @@ #![cfg(not(target_arch = "wasm32"))] use std::i16; -use std::mem; use std::str; use core::num::flt2dec::MAX_SIG_DIGITS; @@ -75,8 +74,7 @@ pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); let f32_range = Range::new(0x0000_0001u32, 0x7f80_0000); iterate("f32_random_equivalence_test", k, n, f, g, |_| { - let i: u32 = f32_range.ind_sample(&mut rng); - let x: f32 = unsafe {mem::transmute(i)}; + let x = f32::from_bits(f32_range.ind_sample(&mut rng)); decode_finite(x) }); } @@ -87,8 +85,7 @@ pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) let mut rng: XorShiftRng = Rand::rand(&mut rand::thread_rng()); let f64_range = Range::new(0x0000_0000_0000_0001u64, 0x7ff0_0000_0000_0000); iterate("f64_random_equivalence_test", k, n, f, g, |_| { - let i: u64 = f64_range.ind_sample(&mut rng); - let x: f64 = unsafe {mem::transmute(i)}; + let x = f64::from_bits(f64_range.ind_sample(&mut rng)); decode_finite(x) }); } @@ -105,7 +102,8 @@ pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) // iterate from 0x0000_0001 to 0x7f7f_ffff, i.e. all finite ranges let (npassed, nignored) = iterate("f32_exhaustive_equivalence_test", k, 0x7f7f_ffff, f, g, |i: usize| { - let x: f32 = unsafe {mem::transmute(i as u32 + 1)}; + + let x = f32::from_bits(i as u32 + 1); decode_finite(x) }); assert_eq!((npassed, nignored), (2121451881, 17643158)); diff --git a/src/libcore/tests/num/mod.rs b/src/libcore/tests/num/mod.rs index c7edb55b378c3..ab96d3126bb22 100644 --- a/src/libcore/tests/num/mod.rs +++ b/src/libcore/tests/num/mod.rs @@ -37,6 +37,15 @@ mod flt2dec; mod dec2flt; mod bignum; + +/// Adds the attribute to all items in the block. +macro_rules! cfg_block { + ($(#[$attr:meta]{$($it:item)*})*) => {$($( + #[$attr] + $it + )*)*} +} + /// Groups items that assume the pointer width is either 16/32/64, and has to be altered if /// support for larger/smaller pointer widths are added in the future. macro_rules! assume_usize_width { @@ -134,6 +143,15 @@ fn test_infallible_try_from_int_error() { } macro_rules! test_impl_from { + ($fn_name:ident, bool, $target: ty) => { + #[test] + fn $fn_name() { + let one: $target = 1; + let zero: $target = 0; + assert_eq!(one, <$target>::from(true)); + assert_eq!(zero, <$target>::from(false)); + } + }; ($fn_name: ident, $Small: ty, $Large: ty) => { #[test] fn $fn_name() { @@ -173,6 +191,18 @@ test_impl_from! { test_u16i32, u16, i32 } test_impl_from! { test_u16i64, u16, i64 } test_impl_from! { test_u32i64, u32, i64 } +// Bool -> Integer +test_impl_from! { test_boolu8, bool, u8 } +test_impl_from! { test_boolu16, bool, u16 } +test_impl_from! { test_boolu32, bool, u32 } +test_impl_from! { test_boolu64, bool, u64 } +test_impl_from! { test_boolu128, bool, u128 } +test_impl_from! { test_booli8, bool, i8 } +test_impl_from! { test_booli16, bool, i16 } +test_impl_from! { test_booli32, bool, i32 } +test_impl_from! { test_booli64, bool, i64 } +test_impl_from! { test_booli128, bool, i128 } + // Signed -> Float test_impl_from! { test_i8f32, i8, f32 } test_impl_from! { test_i8f64, i8, f64 } @@ -309,6 +339,42 @@ assume_usize_width! { test_impl_try_from_always_ok! { test_try_u16usize, u16, usize } test_impl_try_from_always_ok! { test_try_i16isize, i16, isize } + + test_impl_try_from_always_ok! { test_try_usizeu64, usize, u64 } + test_impl_try_from_always_ok! { test_try_usizeu128, usize, u128 } + test_impl_try_from_always_ok! { test_try_usizei128, usize, i128 } + + test_impl_try_from_always_ok! { test_try_isizei64, isize, i64 } + test_impl_try_from_always_ok! { test_try_isizei128, isize, i128 } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_always_ok! { test_try_usizeu16, usize, u16 } + test_impl_try_from_always_ok! { test_try_isizei16, isize, i16 } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_usizei32, usize, i32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_usizeu32, usize, u32 } + test_impl_try_from_always_ok! { test_try_isizei32, isize, i32 } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_usizei64, usize, i64 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_always_ok! { test_try_u16isize, u16, isize } + test_impl_try_from_always_ok! { test_try_u32usize, u32, usize } + test_impl_try_from_always_ok! { test_try_u32isize, u32, isize } + test_impl_try_from_always_ok! { test_try_i32isize, i32, isize } + test_impl_try_from_always_ok! { test_try_u64usize, u64, usize } + test_impl_try_from_always_ok! { test_try_i64isize, i64, isize } + } + ); } /// Conversions where max of $source can be represented as $target, @@ -357,6 +423,24 @@ assume_usize_width! { test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu64, isize, u64 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu128, isize, u128 } test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeusize, isize, usize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_isizeu32, isize, u32 } + + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_upper_ok! { test_try_i64usize, i64, usize } + } + ); } /// Conversions where max of $source can not be represented as $target, @@ -398,9 +482,29 @@ test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i64, u128, i64 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128i128, u128, i128 } assume_usize_width! { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u64isize, u64, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u128isize, u128, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei8, usize, i8 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei16, usize, i16 } test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizeisize, usize, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u16isize, u16, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_u32isize, u32, isize } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei32, usize, i32 } + test_impl_try_from_unsigned_to_signed_upper_err! { test_try_usizei64, usize, i64 } + } + ); } /// Conversions where min/max of $source can not be represented as $target. @@ -460,6 +564,34 @@ test_impl_try_from_same_sign_err! { test_try_i128i64, i128, i64 } assume_usize_width! { test_impl_try_from_same_sign_err! { test_try_usizeu8, usize, u8 } + test_impl_try_from_same_sign_err! { test_try_u128usize, u128, usize } + test_impl_try_from_same_sign_err! { test_try_i128isize, i128, isize } + + cfg_block!( + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_same_sign_err! { test_try_u32usize, u32, usize } + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + + test_impl_try_from_same_sign_err! { test_try_i32isize, i32, isize } + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + } + + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_same_sign_err! { test_try_u64usize, u64, usize } + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + + test_impl_try_from_same_sign_err! { test_try_i64isize, i64, isize } + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + } + + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_same_sign_err! { test_try_usizeu16, usize, u16 } + test_impl_try_from_same_sign_err! { test_try_usizeu32, usize, u32 } + + test_impl_try_from_same_sign_err! { test_try_isizei16, isize, i16 } + test_impl_try_from_same_sign_err! { test_try_isizei32, isize, i32 } + } + ); } /// Conversions where neither the min nor the max of $source can be represented by @@ -504,55 +636,89 @@ test_impl_try_from_signed_to_unsigned_err! { test_try_i128u64, i128, u64 } assume_usize_width! { test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu8, isize, u8 } test_impl_try_from_signed_to_unsigned_err! { test_try_i128usize, i128, usize } + + cfg_block! { + #[cfg(target_pointer_width = "16")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i32usize, i32, usize } + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + } + #[cfg(target_pointer_width = "32")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_i64usize, i64, usize } + + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + } + #[cfg(target_pointer_width = "64")] { + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu16, isize, u16 } + test_impl_try_from_signed_to_unsigned_err! { test_try_isizeu32, isize, u32 } + } + } } macro_rules! test_float { ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { - use core::num::Float; // FIXME(nagisa): these tests should test for sign of -0.0 #[test] fn min() { - assert_eq!(0.0.min(0.0), 0.0); - assert_eq!((-0.0).min(-0.0), -0.0); - assert_eq!(9.0.min(9.0), 9.0); - assert_eq!((-9.0).min(0.0), -9.0); - assert_eq!(0.0.min(9.0), 0.0); - assert_eq!((-0.0).min(-9.0), -9.0); - assert_eq!($inf.min(9.0), 9.0); - assert_eq!(9.0.min($inf), 9.0); - assert_eq!($inf.min(-9.0), -9.0); - assert_eq!((-9.0).min($inf), -9.0); - assert_eq!($neginf.min(9.0), $neginf); - assert_eq!(9.0.min($neginf), $neginf); - assert_eq!($neginf.min(-9.0), $neginf); - assert_eq!((-9.0).min($neginf), $neginf); - assert_eq!($nan.min(9.0), 9.0); - assert_eq!($nan.min(-9.0), -9.0); - assert_eq!(9.0.min($nan), 9.0); - assert_eq!((-9.0).min($nan), -9.0); - assert!($nan.min($nan).is_nan()); + assert_eq!((0.0 as $fty).min(0.0), 0.0); + assert_eq!((-0.0 as $fty).min(-0.0), -0.0); + assert_eq!((9.0 as $fty).min(9.0), 9.0); + assert_eq!((-9.0 as $fty).min(0.0), -9.0); + assert_eq!((0.0 as $fty).min(9.0), 0.0); + assert_eq!((-0.0 as $fty).min(-9.0), -9.0); + assert_eq!(($inf as $fty).min(9.0), 9.0); + assert_eq!((9.0 as $fty).min($inf), 9.0); + assert_eq!(($inf as $fty).min(-9.0), -9.0); + assert_eq!((-9.0 as $fty).min($inf), -9.0); + assert_eq!(($neginf as $fty).min(9.0), $neginf); + assert_eq!((9.0 as $fty).min($neginf), $neginf); + assert_eq!(($neginf as $fty).min(-9.0), $neginf); + assert_eq!((-9.0 as $fty).min($neginf), $neginf); + assert_eq!(($nan as $fty).min(9.0), 9.0); + assert_eq!(($nan as $fty).min(-9.0), -9.0); + assert_eq!((9.0 as $fty).min($nan), 9.0); + assert_eq!((-9.0 as $fty).min($nan), -9.0); + assert!(($nan as $fty).min($nan).is_nan()); } #[test] fn max() { - assert_eq!(0.0.max(0.0), 0.0); - assert_eq!((-0.0).max(-0.0), -0.0); - assert_eq!(9.0.max(9.0), 9.0); - assert_eq!((-9.0).max(0.0), 0.0); - assert_eq!(0.0.max(9.0), 9.0); - assert_eq!((-0.0).max(-9.0), -0.0); - assert_eq!($inf.max(9.0), $inf); - assert_eq!(9.0.max($inf), $inf); - assert_eq!($inf.max(-9.0), $inf); - assert_eq!((-9.0).max($inf), $inf); - assert_eq!($neginf.max(9.0), 9.0); - assert_eq!(9.0.max($neginf), 9.0); - assert_eq!($neginf.max(-9.0), -9.0); - assert_eq!((-9.0).max($neginf), -9.0); - assert_eq!($nan.max(9.0), 9.0); - assert_eq!($nan.max(-9.0), -9.0); - assert_eq!(9.0.max($nan), 9.0); - assert_eq!((-9.0).max($nan), -9.0); - assert!($nan.max($nan).is_nan()); + assert_eq!((0.0 as $fty).max(0.0), 0.0); + assert_eq!((-0.0 as $fty).max(-0.0), -0.0); + assert_eq!((9.0 as $fty).max(9.0), 9.0); + assert_eq!((-9.0 as $fty).max(0.0), 0.0); + assert_eq!((0.0 as $fty).max(9.0), 9.0); + assert_eq!((-0.0 as $fty).max(-9.0), -0.0); + assert_eq!(($inf as $fty).max(9.0), $inf); + assert_eq!((9.0 as $fty).max($inf), $inf); + assert_eq!(($inf as $fty).max(-9.0), $inf); + assert_eq!((-9.0 as $fty).max($inf), $inf); + assert_eq!(($neginf as $fty).max(9.0), 9.0); + assert_eq!((9.0 as $fty).max($neginf), 9.0); + assert_eq!(($neginf as $fty).max(-9.0), -9.0); + assert_eq!((-9.0 as $fty).max($neginf), -9.0); + assert_eq!(($nan as $fty).max(9.0), 9.0); + assert_eq!(($nan as $fty).max(-9.0), -9.0); + assert_eq!((9.0 as $fty).max($nan), 9.0); + assert_eq!((-9.0 as $fty).max($nan), -9.0); + assert!(($nan as $fty).max($nan).is_nan()); + } + #[test] + fn mod_euc() { + let a: $fty = 42.0; + assert!($inf.mod_euc(a).is_nan()); + assert_eq!(a.mod_euc($inf), a); + assert!(a.mod_euc($nan).is_nan()); + assert!($inf.mod_euc($inf).is_nan()); + assert!($inf.mod_euc($nan).is_nan()); + assert!($nan.mod_euc($inf).is_nan()); + } + #[test] + fn div_euc() { + let a: $fty = 42.0; + assert_eq!(a.div_euc($inf), 0.0); + assert!(a.div_euc($nan).is_nan()); + assert!($inf.div_euc($inf).is_nan()); + assert!($inf.div_euc($nan).is_nan()); + assert!($nan.div_euc($inf).is_nan()); } } } } diff --git a/src/libcore/tests/num/uint_macros.rs b/src/libcore/tests/num/uint_macros.rs index 257f6ea20d4ea..ca6906f731047 100644 --- a/src/libcore/tests/num/uint_macros.rs +++ b/src/libcore/tests/num/uint_macros.rs @@ -98,7 +98,6 @@ mod tests { } #[test] - #[cfg(not(stage0))] fn test_reverse_bits() { assert_eq!(A.reverse_bits().reverse_bits(), A); assert_eq!(B.reverse_bits().reverse_bits(), B); diff --git a/src/libcore/tests/option.rs b/src/libcore/tests/option.rs index ced7b03636a09..1324ba2d9a9c3 100644 --- a/src/libcore/tests/option.rs +++ b/src/libcore/tests/option.rs @@ -240,7 +240,7 @@ fn test_collect() { assert!(v == None); // test that it does not take more elements than it needs - let mut functions: [Box Option<()>>; 3] = + let mut functions: [Box Option<()>>; 3] = [box || Some(()), box || None, box || panic!()]; let v: Option> = functions.iter_mut().map(|f| (*f)()).collect(); @@ -313,6 +313,19 @@ fn test_option_deref() { // None: &Option>::None -> None let ref_option: &Option<&i32> = &None; assert_eq!(ref_option.deref(), None); +} + +#[test] +fn test_replace() { + let mut x = Some(2); + let old = x.replace(5); + + assert_eq!(x, Some(5)); + assert_eq!(old, Some(2)); + let mut x = None; + let old = x.replace(3); + assert_eq!(x, Some(3)); + assert_eq!(old, None); } diff --git a/src/libcore/tests/ptr.rs b/src/libcore/tests/ptr.rs index 00f87336f3c80..92160910d8f70 100644 --- a/src/libcore/tests/ptr.rs +++ b/src/libcore/tests/ptr.rs @@ -84,16 +84,16 @@ fn test_is_null() { assert!(nms.is_null()); // Pointers to unsized types -- trait objects - let ci: *const ToString = &3; + let ci: *const dyn ToString = &3; assert!(!ci.is_null()); - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(!mi.is_null()); - let nci: *const ToString = null::(); + let nci: *const dyn ToString = null::(); assert!(nci.is_null()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.is_null()); } @@ -140,16 +140,16 @@ fn test_as_ref() { assert_eq!(nms.as_ref(), None); // Pointers to unsized types -- trait objects - let ci: *const ToString = &3; + let ci: *const dyn ToString = &3; assert!(ci.as_ref().is_some()); - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(mi.as_ref().is_some()); - let nci: *const ToString = null::(); + let nci: *const dyn ToString = null::(); assert!(nci.as_ref().is_none()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.as_ref().is_none()); } } @@ -182,10 +182,10 @@ fn test_as_mut() { assert_eq!(nms.as_mut(), None); // Pointers to unsized types -- trait objects - let mi: *mut ToString = &mut 3; + let mi: *mut dyn ToString = &mut 3; assert!(mi.as_mut().is_some()); - let nmi: *mut ToString = null_mut::(); + let nmi: *mut dyn ToString = null_mut::(); assert!(nmi.as_mut().is_none()); } } @@ -296,3 +296,92 @@ fn write_unaligned_drop() { } DROPS.with(|d| assert_eq!(*d.borrow(), [0])); } + +#[test] +fn align_offset_zst() { + // For pointers of stride = 0, the pointer is already aligned or it cannot be aligned at + // all, because no amount of elements will align the pointer. + let mut p = 1; + while p < 1024 { + assert_eq!((p as *const ()).align_offset(p), 0); + if p != 1 { + assert_eq!(((p + 1) as *const ()).align_offset(p), !0); + } + p = (p + 1).next_power_of_two(); + } +} + +#[test] +fn align_offset_stride1() { + // For pointers of stride = 1, the pointer can always be aligned. The offset is equal to + // number of bytes. + let mut align = 1; + while align < 1024 { + for ptr in 1..2*align { + let expected = ptr % align; + let offset = if expected == 0 { 0 } else { align - expected }; + assert_eq!((ptr as *const u8).align_offset(align), offset, + "ptr = {}, align = {}, size = 1", ptr, align); + } + align = (align + 1).next_power_of_two(); + } +} + +#[test] +fn align_offset_weird_strides() { + #[repr(packed)] + struct A3(u16, u8); + struct A4(u32); + #[repr(packed)] + struct A5(u32, u8); + #[repr(packed)] + struct A6(u32, u16); + #[repr(packed)] + struct A7(u32, u16, u8); + #[repr(packed)] + struct A8(u32, u32); + #[repr(packed)] + struct A9(u32, u32, u8); + #[repr(packed)] + struct A10(u32, u32, u16); + + unsafe fn test_weird_stride(ptr: *const T, align: usize) -> bool { + let numptr = ptr as usize; + let mut expected = usize::max_value(); + // Naive but definitely correct way to find the *first* aligned element of stride::. + for el in 0..align { + if (numptr + el * ::std::mem::size_of::()) % align == 0 { + expected = el; + break; + } + } + let got = ptr.align_offset(align); + if got != expected { + eprintln!("aligning {:p} (with stride of {}) to {}, expected {}, got {}", ptr, + ::std::mem::size_of::(), align, expected, got); + return true; + } + return false; + } + + // For pointers of stride != 1, we verify the algorithm against the naivest possible + // implementation + let mut align = 1; + let mut x = false; + while align < 1024 { + for ptr in 1usize..4*align { + unsafe { + x |= test_weird_stride::(ptr as *const A3, align); + x |= test_weird_stride::(ptr as *const A4, align); + x |= test_weird_stride::(ptr as *const A5, align); + x |= test_weird_stride::(ptr as *const A6, align); + x |= test_weird_stride::(ptr as *const A7, align); + x |= test_weird_stride::(ptr as *const A8, align); + x |= test_weird_stride::(ptr as *const A9, align); + x |= test_weird_stride::(ptr as *const A10, align); + } + } + align = (align + 1).next_power_of_two(); + } + assert!(!x); +} diff --git a/src/libcore/tests/result.rs b/src/libcore/tests/result.rs index f8b5ea5e16e48..0c00992ffd84e 100644 --- a/src/libcore/tests/result.rs +++ b/src/libcore/tests/result.rs @@ -81,7 +81,7 @@ fn test_collect() { assert!(v == Err(2)); // test that it does not take more elements than it needs - let mut functions: [Box Result<(), isize>>; 3] = + let mut functions: [Box Result<(), isize>>; 3] = [box || Ok(()), box || Err(1), box || panic!()]; let v: Result, isize> = functions.iter_mut().map(|f| (*f)()).collect(); @@ -220,13 +220,15 @@ fn test_try() { assert_eq!(try_result_none(), None); fn try_result_ok() -> Result { - let val = Ok(1)?; + let result: Result = Ok(1); + let val = result?; Ok(val) } assert_eq!(try_result_ok(), Ok(1)); fn try_result_err() -> Result { - let val = Err(1)?; + let result: Result = Err(1); + let val = result?; Ok(val) } assert_eq!(try_result_err(), Err(1)); diff --git a/src/libcore/tests/slice.rs b/src/libcore/tests/slice.rs index c81e5e97cbb7a..2b37acdfe3e81 100644 --- a/src/libcore/tests/slice.rs +++ b/src/libcore/tests/slice.rs @@ -60,8 +60,8 @@ fn test_binary_search() { assert_eq!(b.binary_search(&0), Err(0)); assert_eq!(b.binary_search(&1), Ok(0)); assert_eq!(b.binary_search(&2), Err(1)); - assert!(match b.binary_search(&3) { Ok(1...3) => true, _ => false }); - assert!(match b.binary_search(&3) { Ok(1...3) => true, _ => false }); + assert!(match b.binary_search(&3) { Ok(1..=3) => true, _ => false }); + assert!(match b.binary_search(&3) { Ok(1..=3) => true, _ => false }); assert_eq!(b.binary_search(&4), Err(4)); assert_eq!(b.binary_search(&5), Err(4)); assert_eq!(b.binary_search(&6), Err(4)); @@ -259,6 +259,13 @@ fn test_exact_chunks_last() { assert_eq!(c2.last().unwrap(), &[2, 3]); } +#[test] +fn test_exact_chunks_remainder() { + let v: &[i32] = &[0, 1, 2, 3, 4]; + let c = v.exact_chunks(2); + assert_eq!(c.remainder(), &[4]); +} + #[test] fn test_exact_chunks_zip() { let v1: &[i32] = &[0, 1, 2, 3, 4]; @@ -310,6 +317,13 @@ fn test_exact_chunks_mut_last() { assert_eq!(c2.last().unwrap(), &[2, 3]); } +#[test] +fn test_exact_chunks_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.exact_chunks_mut(2); + assert_eq!(c.into_remainder(), &[4]); +} + #[test] fn test_exact_chunks_mut_zip() { let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; @@ -376,48 +390,224 @@ fn test_windows_zip() { assert_eq!(res, [14, 18, 22, 26]); } -#[test] -fn get_range() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - assert_eq!(v.get(..), Some(&[0, 1, 2, 3, 4, 5][..])); - assert_eq!(v.get(..2), Some(&[0, 1][..])); - assert_eq!(v.get(2..), Some(&[2, 3, 4, 5][..])); - assert_eq!(v.get(1..4), Some(&[1, 2, 3][..])); - assert_eq!(v.get(7..), None); - assert_eq!(v.get(7..10), None); -} +// The current implementation of SliceIndex fails to handle methods +// orthogonally from range types; therefore, it is worth testing +// all of the indexing operations on each input. +mod slice_index { + // This checks all six indexing methods, given an input range that + // should succeed. (it is NOT suitable for testing invalid inputs) + macro_rules! assert_range_eq { + ($arr:expr, $range:expr, $expected:expr) + => { + let mut arr = $arr; + let mut expected = $expected; + { + let s: &[_] = &arr; + let expected: &[_] = &expected; + + assert_eq!(&s[$range], expected, "(in assertion for: index)"); + assert_eq!(s.get($range), Some(expected), "(in assertion for: get)"); + unsafe { + assert_eq!( + s.get_unchecked($range), expected, + "(in assertion for: get_unchecked)", + ); + } + } + { + let s: &mut [_] = &mut arr; + let expected: &mut [_] = &mut expected; + + assert_eq!( + &mut s[$range], expected, + "(in assertion for: index_mut)", + ); + assert_eq!( + s.get_mut($range), Some(&mut expected[..]), + "(in assertion for: get_mut)", + ); + unsafe { + assert_eq!( + s.get_unchecked_mut($range), expected, + "(in assertion for: get_unchecked_mut)", + ); + } + } + } + } -#[test] -fn get_mut_range() { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - assert_eq!(v.get_mut(..), Some(&mut [0, 1, 2, 3, 4, 5][..])); - assert_eq!(v.get_mut(..2), Some(&mut [0, 1][..])); - assert_eq!(v.get_mut(2..), Some(&mut [2, 3, 4, 5][..])); - assert_eq!(v.get_mut(1..4), Some(&mut [1, 2, 3][..])); - assert_eq!(v.get_mut(7..), None); - assert_eq!(v.get_mut(7..10), None); -} + // Make sure the macro can actually detect bugs, + // because if it can't, then what are we even doing here? + // + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method that panics, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "out of range")] + fn assert_range_eq_can_fail_by_panic() { + assert_range_eq!([0, 1, 2], 0..5, [0, 1, 2]); + } -#[test] -fn get_unchecked_range() { - unsafe { - let v: &[i32] = &[0, 1, 2, 3, 4, 5]; - assert_eq!(v.get_unchecked(..), &[0, 1, 2, 3, 4, 5][..]); - assert_eq!(v.get_unchecked(..2), &[0, 1][..]); - assert_eq!(v.get_unchecked(2..), &[2, 3, 4, 5][..]); - assert_eq!(v.get_unchecked(1..4), &[1, 2, 3][..]); + // (Be aware this only demonstrates the ability to detect bugs + // in the FIRST method it calls, as the macro is not designed + // to be used in `should_panic`) + #[test] + #[should_panic(expected = "==")] + fn assert_range_eq_can_fail_by_inequality() { + assert_range_eq!([0, 1, 2], 0..2, [0, 1, 2]); } -} -#[test] -fn get_unchecked_mut_range() { - unsafe { - let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; - assert_eq!(v.get_unchecked_mut(..), &mut [0, 1, 2, 3, 4, 5][..]); - assert_eq!(v.get_unchecked_mut(..2), &mut [0, 1][..]); - assert_eq!(v.get_unchecked_mut(2..), &mut[2, 3, 4, 5][..]); - assert_eq!(v.get_unchecked_mut(1..4), &mut [1, 2, 3][..]); + // Test cases for bad index operations. + // + // This generates `should_panic` test cases for Index/IndexMut + // and `None` test cases for get/get_mut. + macro_rules! panic_cases { + ($( + // each test case needs a unique name to namespace the tests + in mod $case_name:ident { + data: $data:expr; + + // optional: + // + // one or more similar inputs for which data[input] succeeds, + // and the corresponding output as an array. This helps validate + // "critical points" where an input range straddles the boundary + // between valid and invalid. + // (such as the input `len..len`, which is just barely valid) + $( + good: data[$good:expr] == $output:expr; + )* + + bad: data[$bad:expr]; + message: $expect_msg:expr; + } + )*) => {$( + mod $case_name { + #[test] + fn pass() { + let mut v = $data; + + $( assert_range_eq!($data, $good, $output); )* + + { + let v: &[_] = &v; + assert_eq!(v.get($bad), None, "(in None assertion for get)"); + } + + { + let v: &mut [_] = &mut v; + assert_eq!(v.get_mut($bad), None, "(in None assertion for get_mut)"); + } + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_fail() { + let v = $data; + let v: &[_] = &v; + let _v = &v[$bad]; + } + + #[test] + #[should_panic(expected = $expect_msg)] + fn index_mut_fail() { + let mut v = $data; + let v: &mut [_] = &mut v; + let _v = &mut v[$bad]; + } + } + )*}; + } + + #[test] + fn simple() { + let v = [0, 1, 2, 3, 4, 5]; + + assert_range_eq!(v, .., [0, 1, 2, 3, 4, 5]); + assert_range_eq!(v, ..2, [0, 1]); + assert_range_eq!(v, ..=1, [0, 1]); + assert_range_eq!(v, 2.., [2, 3, 4, 5]); + assert_range_eq!(v, 1..4, [1, 2, 3]); + assert_range_eq!(v, 1..=3, [1, 2, 3]); + } + + panic_cases! { + in mod rangefrom_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[6..] == []; + bad: data[7..]; + message: "but ends at"; // perhaps not ideal + } + + in mod rangeto_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[..6] == [0, 1, 2, 3, 4, 5]; + bad: data[..7]; + message: "out of range"; + } + + in mod rangetoinclusive_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[..=5] == [0, 1, 2, 3, 4, 5]; + bad: data[..=6]; + message: "out of range"; + } + + in mod range_len_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[6..6] == []; + bad: data[7..7]; + message: "out of range"; + } + + in mod rangeinclusive_len_len { + data: [0, 1, 2, 3, 4, 5]; + + good: data[6..=5] == []; + bad: data[7..=6]; + message: "out of range"; + } } + + panic_cases! { + in mod range_neg_width { + data: [0, 1, 2, 3, 4, 5]; + + good: data[4..4] == []; + bad: data[4..3]; + message: "but ends at"; + } + + in mod rangeinclusive_neg_width { + data: [0, 1, 2, 3, 4, 5]; + + good: data[4..=3] == []; + bad: data[4..=2]; + message: "but ends at"; + } + } + + panic_cases! { + in mod rangeinclusive_overflow { + data: [0, 1]; + + // note: using 0 specifically ensures that the result of overflowing is 0..0, + // so that `get` doesn't simply return None for the wrong reason. + bad: data[0 ..= ::std::usize::MAX]; + message: "maximum usize"; + } + + in mod rangetoinclusive_overflow { + data: [0, 1]; + + bad: data[..= ::std::usize::MAX]; + message: "maximum usize"; + } + } // panic_cases! } #[test] @@ -636,3 +826,37 @@ pub mod memchr { } } } + +#[test] +fn test_align_to_simple() { + let bytes = [1u8, 2, 3, 4, 5, 6, 7]; + let (prefix, aligned, suffix) = unsafe { bytes.align_to::() }; + assert_eq!(aligned.len(), 3); + assert!(prefix == [1] || suffix == [7]); + let expect1 = [1 << 8 | 2, 3 << 8 | 4, 5 << 8 | 6]; + let expect2 = [1 | 2 << 8, 3 | 4 << 8, 5 | 6 << 8]; + let expect3 = [2 << 8 | 3, 4 << 8 | 5, 6 << 8 | 7]; + let expect4 = [2 | 3 << 8, 4 | 5 << 8, 6 | 7 << 8]; + assert!(aligned == expect1 || aligned == expect2 || aligned == expect3 || aligned == expect4, + "aligned={:?} expected={:?} || {:?} || {:?} || {:?}", + aligned, expect1, expect2, expect3, expect4); +} + +#[test] +fn test_align_to_zst() { + let bytes = [1, 2, 3, 4, 5, 6, 7]; + let (prefix, aligned, suffix) = unsafe { bytes.align_to::<()>() }; + assert_eq!(aligned.len(), 0); + assert!(prefix == [1, 2, 3, 4, 5, 6, 7] || suffix == [1, 2, 3, 4, 5, 6, 7]); +} + +#[test] +fn test_align_to_non_trivial() { + #[repr(align(8))] struct U64(u64, u64); + #[repr(align(8))] struct U64U64U32(u64, u64, u32); + let data = [U64(1, 2), U64(3, 4), U64(5, 6), U64(7, 8), U64(9, 10), U64(11, 12), U64(13, 14), + U64(15, 16)]; + let (prefix, aligned, suffix) = unsafe { data.align_to::() }; + assert_eq!(aligned.len(), 4); + assert_eq!(prefix.len() + suffix.len(), 2); +} diff --git a/src/libcore/tests/str.rs b/src/libcore/tests/str.rs index 08daafccc5404..343c9596c5383 100644 --- a/src/libcore/tests/str.rs +++ b/src/libcore/tests/str.rs @@ -8,4 +8,4 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// All `str` tests live in collectionstests::str +// All `str` tests live in liballoc/tests diff --git a/src/libcore/tests/str_lossy.rs b/src/libcore/tests/str_lossy.rs index 69e28256da9c3..56ef3f070c1fa 100644 --- a/src/libcore/tests/str_lossy.rs +++ b/src/libcore/tests/str_lossy.rs @@ -79,7 +79,7 @@ fn chunks() { fn display() { assert_eq!( "Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", - &format!("{}", Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye"))); + &Utf8Lossy::from_bytes(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string()); } #[test] diff --git a/src/libcore/tests/time.rs b/src/libcore/tests/time.rs index 042c523f25f25..466f28f0ef0aa 100644 --- a/src/libcore/tests/time.rs +++ b/src/libcore/tests/time.rs @@ -23,9 +23,43 @@ fn creation() { #[test] fn secs() { assert_eq!(Duration::new(0, 0).as_secs(), 0); + assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0); + assert_eq!(Duration::new(0, 1_050_000_001).as_secs(), 1); assert_eq!(Duration::from_secs(1).as_secs(), 1); assert_eq!(Duration::from_millis(999).as_secs(), 0); assert_eq!(Duration::from_millis(1001).as_secs(), 1); + assert_eq!(Duration::from_micros(999_999).as_secs(), 0); + assert_eq!(Duration::from_micros(1_000_001).as_secs(), 1); + assert_eq!(Duration::from_nanos(999_999_999).as_secs(), 0); + assert_eq!(Duration::from_nanos(1_000_000_001).as_secs(), 1); +} + +#[test] +fn millis() { + assert_eq!(Duration::new(0, 0).subsec_millis(), 0); + assert_eq!(Duration::new(0, 500_000_005).subsec_millis(), 500); + assert_eq!(Duration::new(0, 1_050_000_001).subsec_millis(), 50); + assert_eq!(Duration::from_secs(1).subsec_millis(), 0); + assert_eq!(Duration::from_millis(999).subsec_millis(), 999); + assert_eq!(Duration::from_millis(1001).subsec_millis(), 1); + assert_eq!(Duration::from_micros(999_999).subsec_millis(), 999); + assert_eq!(Duration::from_micros(1_001_000).subsec_millis(), 1); + assert_eq!(Duration::from_nanos(999_999_999).subsec_millis(), 999); + assert_eq!(Duration::from_nanos(1_001_000_000).subsec_millis(), 1); +} + +#[test] +fn micros() { + assert_eq!(Duration::new(0, 0).subsec_micros(), 0); + assert_eq!(Duration::new(0, 500_000_005).subsec_micros(), 500_000); + assert_eq!(Duration::new(0, 1_050_000_001).subsec_micros(), 50_000); + assert_eq!(Duration::from_secs(1).subsec_micros(), 0); + assert_eq!(Duration::from_millis(999).subsec_micros(), 999_000); + assert_eq!(Duration::from_millis(1001).subsec_micros(), 1_000); + assert_eq!(Duration::from_micros(999_999).subsec_micros(), 999_999); + assert_eq!(Duration::from_micros(1_000_001).subsec_micros(), 1); + assert_eq!(Duration::from_nanos(999_999_999).subsec_micros(), 999_999); + assert_eq!(Duration::from_nanos(1_000_001_000).subsec_micros(), 1); } #[test] @@ -34,8 +68,12 @@ fn nanos() { assert_eq!(Duration::new(0, 5).subsec_nanos(), 5); assert_eq!(Duration::new(0, 1_000_000_001).subsec_nanos(), 1); assert_eq!(Duration::from_secs(1).subsec_nanos(), 0); - assert_eq!(Duration::from_millis(999).subsec_nanos(), 999 * 1_000_000); - assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1 * 1_000_000); + assert_eq!(Duration::from_millis(999).subsec_nanos(), 999_000_000); + assert_eq!(Duration::from_millis(1001).subsec_nanos(), 1_000_000); + assert_eq!(Duration::from_micros(999_999).subsec_nanos(), 999_999_000); + assert_eq!(Duration::from_micros(1_000_001).subsec_nanos(), 1000); + assert_eq!(Duration::from_nanos(999_999_999).subsec_nanos(), 999_999_999); + assert_eq!(Duration::from_nanos(1_000_000_001).subsec_nanos(), 1); } #[test] @@ -122,3 +160,145 @@ fn checked_div() { assert_eq!(Duration::new(1, 0).checked_div(2), Some(Duration::new(0, 500_000_000))); assert_eq!(Duration::new(2, 0).checked_div(0), None); } + +#[test] +fn correct_sum() { + let durations = [ + Duration::new(1, 999_999_999), + Duration::new(2, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(0, 999_999_999), + Duration::new(5, 0), + ]; + let sum = durations.iter().sum::(); + assert_eq!(sum, Duration::new(1+2+5+4, 1_000_000_000 - 5)); +} + +#[test] +fn debug_formatting_extreme_values() { + assert_eq!( + format!("{:?}", Duration::new(18_446_744_073_709_551_615, 123_456_789)), + "18446744073709551615.123456789s" + ); +} + +#[test] +fn debug_formatting_secs() { + assert_eq!(format!("{:?}", Duration::new(7, 000_000_000)), "7s"); + assert_eq!(format!("{:?}", Duration::new(7, 100_000_000)), "7.1s"); + assert_eq!(format!("{:?}", Duration::new(7, 000_010_000)), "7.00001s"); + assert_eq!(format!("{:?}", Duration::new(7, 000_000_001)), "7.000000001s"); + assert_eq!(format!("{:?}", Duration::new(7, 123_456_789)), "7.123456789s"); + + assert_eq!(format!("{:?}", Duration::new(88, 000_000_000)), "88s"); + assert_eq!(format!("{:?}", Duration::new(88, 100_000_000)), "88.1s"); + assert_eq!(format!("{:?}", Duration::new(88, 000_010_000)), "88.00001s"); + assert_eq!(format!("{:?}", Duration::new(88, 000_000_001)), "88.000000001s"); + assert_eq!(format!("{:?}", Duration::new(88, 123_456_789)), "88.123456789s"); + + assert_eq!(format!("{:?}", Duration::new(999, 000_000_000)), "999s"); + assert_eq!(format!("{:?}", Duration::new(999, 100_000_000)), "999.1s"); + assert_eq!(format!("{:?}", Duration::new(999, 000_010_000)), "999.00001s"); + assert_eq!(format!("{:?}", Duration::new(999, 000_000_001)), "999.000000001s"); + assert_eq!(format!("{:?}", Duration::new(999, 123_456_789)), "999.123456789s"); +} + +#[test] +fn debug_formatting_millis() { + assert_eq!(format!("{:?}", Duration::new(0, 7_000_000)), "7ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_100_000)), "7.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_000_001)), "7.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 7_123_456)), "7.123456ms"); + + assert_eq!(format!("{:?}", Duration::new(0, 88_000_000)), "88ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_100_000)), "88.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_000_001)), "88.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 88_123_456)), "88.123456ms"); + + assert_eq!(format!("{:?}", Duration::new(0, 999_000_000)), "999ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_100_000)), "999.1ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_000_001)), "999.000001ms"); + assert_eq!(format!("{:?}", Duration::new(0, 999_123_456)), "999.123456ms"); +} + +#[test] +fn debug_formatting_micros() { + assert_eq!(format!("{:?}", Duration::new(0, 7_000)), "7µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_100)), "7.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_001)), "7.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 7_123)), "7.123µs"); + + assert_eq!(format!("{:?}", Duration::new(0, 88_000)), "88µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_100)), "88.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_001)), "88.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 88_123)), "88.123µs"); + + assert_eq!(format!("{:?}", Duration::new(0, 999_000)), "999µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_100)), "999.1µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_001)), "999.001µs"); + assert_eq!(format!("{:?}", Duration::new(0, 999_123)), "999.123µs"); +} + +#[test] +fn debug_formatting_nanos() { + assert_eq!(format!("{:?}", Duration::new(0, 0)), "0ns"); + assert_eq!(format!("{:?}", Duration::new(0, 1)), "1ns"); + assert_eq!(format!("{:?}", Duration::new(0, 88)), "88ns"); + assert_eq!(format!("{:?}", Duration::new(0, 999)), "999ns"); +} + +#[test] +fn debug_formatting_precision_zero() { + assert_eq!(format!("{:.0?}", Duration::new(0, 0)), "0ns"); + assert_eq!(format!("{:.0?}", Duration::new(0, 123)), "123ns"); + + assert_eq!(format!("{:.0?}", Duration::new(0, 1_001)), "1µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_499)), "1µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_500)), "2µs"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_999)), "2µs"); + + assert_eq!(format!("{:.0?}", Duration::new(0, 1_000_001)), "1ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_499_999)), "1ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_500_000)), "2ms"); + assert_eq!(format!("{:.0?}", Duration::new(0, 1_999_999)), "2ms"); + + assert_eq!(format!("{:.0?}", Duration::new(1, 000_000_001)), "1s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 499_999_999)), "1s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 500_000_000)), "2s"); + assert_eq!(format!("{:.0?}", Duration::new(1, 999_999_999)), "2s"); +} + +#[test] +fn debug_formatting_precision_two() { + assert_eq!(format!("{:.2?}", Duration::new(0, 0)), "0.00ns"); + assert_eq!(format!("{:.2?}", Duration::new(0, 123)), "123.00ns"); + + assert_eq!(format!("{:.2?}", Duration::new(0, 1_000)), "1.00µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_001)), "7.00µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_100)), "7.10µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_109)), "7.11µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 7_199)), "7.20µs"); + assert_eq!(format!("{:.2?}", Duration::new(0, 1_999)), "2.00µs"); + + assert_eq!(format!("{:.2?}", Duration::new(0, 1_000_000)), "1.00ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 3_001_000)), "3.00ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 3_100_000)), "3.10ms"); + assert_eq!(format!("{:.2?}", Duration::new(0, 1_999_999)), "2.00ms"); + + assert_eq!(format!("{:.2?}", Duration::new(1, 000_000_000)), "1.00s"); + assert_eq!(format!("{:.2?}", Duration::new(4, 001_000_000)), "4.00s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 100_000_000)), "2.10s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 104_990_000)), "2.10s"); + assert_eq!(format!("{:.2?}", Duration::new(2, 105_000_000)), "2.11s"); + assert_eq!(format!("{:.2?}", Duration::new(8, 999_999_999)), "9.00s"); +} + +#[test] +fn debug_formatting_precision_high() { + assert_eq!(format!("{:.5?}", Duration::new(0, 23_678)), "23.67800µs"); + + assert_eq!(format!("{:.9?}", Duration::new(1, 000_000_000)), "1.000000000s"); + assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s"); + assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); +} diff --git a/src/libcore/time.rs b/src/libcore/time.rs index 8e8b1691c657a..54973b7b7783a 100644 --- a/src/libcore/time.rs +++ b/src/libcore/time.rs @@ -21,6 +21,7 @@ //! assert_eq!(Duration::new(5, 0), Duration::from_secs(5)); //! ``` +use fmt; use iter::Sum; use ops::{Add, Sub, Mul, Div, AddAssign, SubAssign, MulAssign, DivAssign}; @@ -59,7 +60,7 @@ const MICROS_PER_SEC: u64 = 1_000_000; /// let ten_millis = Duration::from_millis(10); /// ``` #[stable(feature = "duration", since = "1.3.0")] -#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash, Default)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] pub struct Duration { secs: u64, nanos: u32, // Always 0 <= nanos < NANOS_PER_SEC @@ -203,10 +204,11 @@ impl Duration { /// /// [`subsec_nanos`]: #method.subsec_nanos #[stable(feature = "duration", since = "1.3.0")] + #[rustc_const_unstable(feature="duration_getters")] #[inline] - pub fn as_secs(&self) -> u64 { self.secs } + pub const fn as_secs(&self) -> u64 { self.secs } - /// Returns the fractional part of this `Duration`, in milliseconds. + /// Returns the fractional part of this `Duration`, in whole milliseconds. /// /// This method does **not** return the length of the duration when /// represented by milliseconds. The returned number always represents a @@ -222,10 +224,11 @@ impl Duration { /// assert_eq!(duration.subsec_millis(), 432); /// ``` #[stable(feature = "duration_extras", since = "1.27.0")] + #[rustc_const_unstable(feature="duration_getters")] #[inline] - pub fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } + pub const fn subsec_millis(&self) -> u32 { self.nanos / NANOS_PER_MILLI } - /// Returns the fractional part of this `Duration`, in microseconds. + /// Returns the fractional part of this `Duration`, in whole microseconds. /// /// This method does **not** return the length of the duration when /// represented by microseconds. The returned number always represents a @@ -241,8 +244,9 @@ impl Duration { /// assert_eq!(duration.subsec_micros(), 234_567); /// ``` #[stable(feature = "duration_extras", since = "1.27.0")] + #[rustc_const_unstable(feature="duration_getters")] #[inline] - pub fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } + pub const fn subsec_micros(&self) -> u32 { self.nanos / NANOS_PER_MICRO } /// Returns the fractional part of this `Duration`, in nanoseconds. /// @@ -260,8 +264,60 @@ impl Duration { /// assert_eq!(duration.subsec_nanos(), 10_000_000); /// ``` #[stable(feature = "duration", since = "1.3.0")] + #[rustc_const_unstable(feature="duration_getters")] #[inline] - pub fn subsec_nanos(&self) -> u32 { self.nanos } + pub const fn subsec_nanos(&self) -> u32 { self.nanos } + + /// Returns the total number of whole milliseconds contained by this `Duration`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(duration_as_u128)] + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_millis(), 5730); + /// ``` + #[unstable(feature = "duration_as_u128", issue = "50202")] + #[inline] + pub fn as_millis(&self) -> u128 { + self.secs as u128 * MILLIS_PER_SEC as u128 + (self.nanos / NANOS_PER_MILLI) as u128 + } + + /// Returns the total number of whole microseconds contained by this `Duration`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(duration_as_u128)] + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_micros(), 5730023); + /// ``` + #[unstable(feature = "duration_as_u128", issue = "50202")] + #[inline] + pub fn as_micros(&self) -> u128 { + self.secs as u128 * MICROS_PER_SEC as u128 + (self.nanos / NANOS_PER_MICRO) as u128 + } + + /// Returns the total number of nanoseconds contained by this `Duration`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(duration_as_u128)] + /// use std::time::Duration; + /// + /// let duration = Duration::new(5, 730023852); + /// assert_eq!(duration.as_nanos(), 5730023852); + /// ``` + #[unstable(feature = "duration_as_u128", issue = "50202")] + #[inline] + pub fn as_nanos(&self) -> u128 { + self.secs as u128 * NANOS_PER_SEC as u128 + self.nanos as u128 + } /// Checked `Duration` addition. Computes `self + other`, returning [`None`] /// if overflow occurred. @@ -468,16 +524,162 @@ impl DivAssign for Duration { } } +macro_rules! sum_durations { + ($iter:expr) => {{ + let mut total_secs: u64 = 0; + let mut total_nanos: u64 = 0; + + for entry in $iter { + total_secs = total_secs + .checked_add(entry.secs) + .expect("overflow in iter::sum over durations"); + total_nanos = match total_nanos.checked_add(entry.nanos as u64) { + Some(n) => n, + None => { + total_secs = total_secs + .checked_add(total_nanos / NANOS_PER_SEC as u64) + .expect("overflow in iter::sum over durations"); + (total_nanos % NANOS_PER_SEC as u64) + entry.nanos as u64 + } + }; + } + total_secs = total_secs + .checked_add(total_nanos / NANOS_PER_SEC as u64) + .expect("overflow in iter::sum over durations"); + total_nanos = total_nanos % NANOS_PER_SEC as u64; + Duration { + secs: total_secs, + nanos: total_nanos as u32, + } + }}; +} + #[stable(feature = "duration_sum", since = "1.16.0")] impl Sum for Duration { fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + b) + sum_durations!(iter) } } #[stable(feature = "duration_sum", since = "1.16.0")] impl<'a> Sum<&'a Duration> for Duration { fn sum>(iter: I) -> Duration { - iter.fold(Duration::new(0, 0), |a, b| a + *b) + sum_durations!(iter) + } +} + +#[stable(feature = "duration_debug_impl", since = "1.27.0")] +impl fmt::Debug for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + /// Formats a floating point number in decimal notation. + /// + /// The number is given as the `integer_part` and a fractional part. + /// The value of the fractional part is `fractional_part / divisor`. So + /// `integer_part` = 3, `fractional_part` = 12 and `divisor` = 100 + /// represents the number `3.012`. Trailing zeros are omitted. + /// + /// `divisor` must not be above 100_000_000. It also should be a power + /// of 10, everything else doesn't make sense. `fractional_part` has + /// to be less than `10 * divisor`! + fn fmt_decimal( + f: &mut fmt::Formatter, + mut integer_part: u64, + mut fractional_part: u32, + mut divisor: u32, + ) -> fmt::Result { + // Encode the fractional part into a temporary buffer. The buffer + // only need to hold 9 elements, because `fractional_part` has to + // be smaller than 10^9. The buffer is prefilled with '0' digits + // to simplify the code below. + let mut buf = [b'0'; 9]; + + // The next digit is written at this position + let mut pos = 0; + + // We keep writing digits into the buffer while there are non-zero + // digits left and we haven't written enough digits yet. + while fractional_part > 0 && pos < f.precision().unwrap_or(9) { + // Write new digit into the buffer + buf[pos] = b'0' + (fractional_part / divisor) as u8; + + fractional_part %= divisor; + divisor /= 10; + pos += 1; + } + + // If a precision < 9 was specified, there may be some non-zero + // digits left that weren't written into the buffer. In that case we + // need to perform rounding to match the semantics of printing + // normal floating point numbers. However, we only need to do work + // when rounding up. This happens if the first digit of the + // remaining ones is >= 5. + if fractional_part > 0 && fractional_part >= divisor * 5 { + // Round up the number contained in the buffer. We go through + // the buffer backwards and keep track of the carry. + let mut rev_pos = pos; + let mut carry = true; + while carry && rev_pos > 0 { + rev_pos -= 1; + + // If the digit in the buffer is not '9', we just need to + // increment it and can stop then (since we don't have a + // carry anymore). Otherwise, we set it to '0' (overflow) + // and continue. + if buf[rev_pos] < b'9' { + buf[rev_pos] += 1; + carry = false; + } else { + buf[rev_pos] = b'0'; + } + } + + // If we still have the carry bit set, that means that we set + // the whole buffer to '0's and need to increment the integer + // part. + if carry { + integer_part += 1; + } + } + + // Determine the end of the buffer: if precision is set, we just + // use as many digits from the buffer (capped to 9). If it isn't + // set, we only use all digits up to the last non-zero one. + let end = f.precision().map(|p| ::cmp::min(p, 9)).unwrap_or(pos); + + // If we haven't emitted a single fractional digit and the precision + // wasn't set to a non-zero value, we don't print the decimal point. + if end == 0 { + write!(f, "{}", integer_part) + } else { + // We are only writing ASCII digits into the buffer and it was + // initialized with '0's, so it contains valid UTF8. + let s = unsafe { + ::str::from_utf8_unchecked(&buf[..end]) + }; + + // If the user request a precision > 9, we pad '0's at the end. + let w = f.precision().unwrap_or(pos); + write!(f, "{}.{:0 0 { + fmt_decimal(f, self.secs, self.nanos, 100_000_000)?; + f.write_str("s") + } else if self.nanos >= 1_000_000 { + fmt_decimal(f, self.nanos as u64 / 1_000_000, self.nanos % 1_000_000, 100_000)?; + f.write_str("ms") + } else if self.nanos >= 1_000 { + fmt_decimal(f, self.nanos as u64 / 1_000, self.nanos % 1_000, 100)?; + f.write_str("µs") + } else { + fmt_decimal(f, self.nanos as u64, 0, 1)?; + f.write_str("ns") + } } } diff --git a/src/libcore/unicode/mod.rs b/src/libcore/unicode/mod.rs index b6b033adc046e..e5cda880f8807 100644 --- a/src/libcore/unicode/mod.rs +++ b/src/libcore/unicode/mod.rs @@ -20,6 +20,9 @@ pub(crate) mod version; pub mod derived_property { pub use unicode::tables::derived_property::{Case_Ignorable, Cased}; } +pub mod conversions { + pub use unicode::tables::conversions::{to_lower, to_upper}; +} // For use in libsyntax pub mod property { diff --git a/src/libcore/unicode/printable.rs b/src/libcore/unicode/printable.rs index 4426c32eebcee..519dd17bb9b3f 100644 --- a/src/libcore/unicode/printable.rs +++ b/src/libcore/unicode/printable.rs @@ -83,14 +83,14 @@ pub(crate) fn is_printable(x: char) -> bool { const SINGLETONS0U: &'static [(u8, u8)] = &[ (0x00, 1), (0x03, 5), - (0x05, 8), + (0x05, 6), (0x06, 3), - (0x07, 4), + (0x07, 6), (0x08, 8), - (0x09, 16), - (0x0a, 27), + (0x09, 17), + (0x0a, 28), (0x0b, 25), - (0x0c, 22), + (0x0c, 20), (0x0d, 18), (0x0e, 22), (0x0f, 4), @@ -102,18 +102,17 @@ const SINGLETONS0U: &'static [(u8, u8)] = &[ (0x18, 2), (0x19, 3), (0x1a, 7), + (0x1c, 2), (0x1d, 1), (0x1f, 22), (0x20, 3), - (0x2b, 5), + (0x2b, 6), (0x2c, 2), (0x2d, 11), (0x2e, 1), (0x30, 3), - (0x31, 3), + (0x31, 2), (0x32, 2), - (0xa7, 1), - (0xa8, 2), (0xa9, 2), (0xaa, 4), (0xab, 8), @@ -125,19 +124,19 @@ const SINGLETONS0U: &'static [(u8, u8)] = &[ ]; const SINGLETONS0L: &'static [u8] = &[ 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, - 0x58, 0x60, 0x88, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, - 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0x2e, 0x2f, 0x3f, + 0x58, 0x8b, 0x8c, 0x90, 0x1c, 0x1d, 0xdd, 0x0e, + 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, 0xba, 0xbb, 0xc5, 0xc6, - 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0x04, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, - 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, - 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, 0xe4, 0xe5, - 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, - 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, - 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, 0xc9, 0xce, - 0xcf, 0x04, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, - 0x64, 0x65, 0x84, 0x8d, 0x91, 0xa9, 0xb4, 0xba, + 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, + 0x3d, 0x49, 0x4a, 0x5d, 0x84, 0x8e, 0x92, 0xa9, + 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, + 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, + 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, + 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, + 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, + 0x57, 0x64, 0x65, 0x8d, 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x04, 0x0d, 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x81, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, 0xd7, 0xf0, @@ -150,18 +149,18 @@ const SINGLETONS0L: &'static [u8] = &[ 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, - 0x7e, 0xae, 0xaf, 0xfa, 0x16, 0x17, 0x1e, 0x1f, - 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, - 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, - 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, 0x75, 0x96, - 0x97, 0xc9, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, - 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, - 0x40, 0x97, 0x98, 0x2f, 0x30, 0x8f, 0x1f, 0xff, - 0xaf, 0xfe, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, - 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, - 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, - 0x90, 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, - 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, + 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, 0x17, + 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, + 0x5c, 0x5e, 0x7e, 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, + 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, 0x74, + 0x75, 0x96, 0x97, 0xc9, 0xff, 0x2f, 0x5f, 0x26, + 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, 0xc7, 0xcf, + 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, + 0x1f, 0xff, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, + 0x07, 0x08, 0x0f, 0x10, 0x27, 0x2f, 0xee, 0xef, + 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, + 0x91, 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, + 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, 0xfe, 0xff, ]; const SINGLETONS1U: &'static [(u8, u8)] = &[ (0x00, 6), @@ -170,17 +169,18 @@ const SINGLETONS1U: &'static [(u8, u8)] = &[ (0x04, 2), (0x08, 8), (0x09, 2), - (0x0a, 3), + (0x0a, 5), (0x0b, 2), (0x10, 1), (0x11, 4), (0x12, 5), - (0x13, 18), + (0x13, 17), (0x14, 2), (0x15, 2), - (0x1a, 3), + (0x17, 2), + (0x1a, 2), (0x1c, 5), - (0x1d, 4), + (0x1d, 8), (0x24, 1), (0x6a, 3), (0x6b, 2), @@ -195,51 +195,49 @@ const SINGLETONS1U: &'static [(u8, u8)] = &[ (0xe8, 2), (0xee, 32), (0xf0, 4), - (0xf1, 1), - (0xf9, 1), + (0xf9, 4), ]; const SINGLETONS1L: &'static [u8] = &[ 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, 0x09, 0x36, 0x3d, 0x3e, - 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x56, - 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, 0x12, 0x87, - 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, - 0x29, 0x31, 0x34, 0x3a, 0x3b, 0x45, 0x46, 0x49, - 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, 0xb6, - 0xb7, 0x84, 0x85, 0x9d, 0x09, 0x37, 0x90, 0x91, - 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x6f, 0x5f, 0xee, - 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, - 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, - 0xba, 0xbc, 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, - 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, - 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, - 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, - 0x3a, 0x48, 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, - 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, - 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, - 0xaf, 0xb0, 0xc0, 0xd0, 0x2f, 0x3f, + 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, + 0x37, 0x56, 0x57, 0xbd, 0x35, 0xce, 0xcf, 0xe0, + 0x12, 0x87, 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, + 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, 0x45, 0x46, + 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5a, 0x5c, + 0xb6, 0xb7, 0x1b, 0x1c, 0x84, 0x85, 0x09, 0x37, + 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, + 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, + 0x62, 0x9a, 0x9b, 0x27, 0x28, 0x55, 0x9d, 0xa0, + 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, + 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, + 0x45, 0x51, 0xa6, 0xa7, 0xcc, 0xcd, 0xa0, 0x07, + 0x19, 0x1a, 0x22, 0x25, 0xc5, 0xc6, 0x04, 0x20, + 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, + 0x4a, 0x4c, 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, + 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, 0x6b, 0x73, + 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, + 0xc0, 0xd0, 0x3f, 0x71, 0x72, 0x7b, ]; const NORMAL0: &'static [u8] = &[ 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, - 0x1b, 0x05, - 0x05, 0x11, + 0x1b, 0x04, + 0x06, 0x11, 0x81, 0xac, 0x0e, - 0x3b, 0x05, - 0x6b, 0x35, - 0x1e, 0x16, - 0x80, 0xdf, 0x03, + 0x80, 0xab, 0x35, + 0x1e, 0x15, + 0x80, 0xe0, 0x03, 0x19, 0x08, 0x01, 0x04, - 0x22, 0x03, - 0x0a, 0x04, + 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, 0x07, 0x06, 0x07, - 0x10, 0x0b, + 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x08, @@ -286,7 +284,7 @@ const NORMAL0: &'static [u8] = &[ 0x6a, 0x06, 0x0a, 0x06, 0x1a, 0x06, - 0x58, 0x08, + 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, @@ -304,8 +302,8 @@ const NORMAL0: &'static [u8] = &[ 0x74, 0x08, 0x3c, 0x03, 0x0f, 0x03, - 0x3c, 0x37, - 0x08, 0x08, + 0x3c, 0x07, + 0x38, 0x08, 0x2a, 0x06, 0x82, 0xff, 0x11, 0x18, 0x08, @@ -316,15 +314,12 @@ const NORMAL0: &'static [u8] = &[ 0x80, 0x8c, 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, - 0x87, 0x5a, 0x03, - 0x16, 0x19, - 0x04, 0x10, - 0x80, 0xf4, 0x05, + 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, 0x07, 0x02, 0x0e, 0x18, 0x09, - 0x80, 0xaa, 0x36, + 0x80, 0xaf, 0x31, 0x74, 0x0c, 0x80, 0xd6, 0x1a, 0x0c, 0x05, @@ -332,12 +327,12 @@ const NORMAL0: &'static [u8] = &[ 0x80, 0xb6, 0x05, 0x24, 0x0c, 0x9b, 0xc6, 0x0a, - 0xd2, 0x2b, 0x15, + 0xd2, 0x30, 0x10, 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, - 0x80, 0xb8, 0x3f, + 0x80, 0xba, 0x3d, 0x35, 0x04, 0x0a, 0x06, 0x38, 0x08, @@ -402,9 +397,8 @@ const NORMAL1: &'static [u8] = &[ 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, - 0x28, 0x04, - 0x03, 0x04, - 0x09, 0x08, + 0x2f, 0x04, + 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, @@ -417,14 +411,17 @@ const NORMAL1: &'static [u8] = &[ 0x49, 0x37, 0x33, 0x0d, 0x33, 0x07, - 0x06, 0x81, 0x60, - 0x1f, 0x81, 0x81, + 0x2e, 0x08, + 0x0a, 0x81, 0x26, + 0x1f, 0x80, 0x81, + 0x28, 0x08, + 0x2a, 0x80, 0xa6, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, 0x19, 0x07, 0x0a, 0x06, - 0x44, 0x0c, + 0x47, 0x09, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, @@ -435,7 +432,7 @@ const NORMAL1: &'static [u8] = &[ 0x01, 0x05, 0x10, 0x03, 0x05, 0x80, 0x8b, - 0x5e, 0x22, + 0x5f, 0x21, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, @@ -444,9 +441,9 @@ const NORMAL1: &'static [u8] = &[ 0x0d, 0x13, 0x38, 0x08, 0x0a, 0x36, - 0x1a, 0x03, - 0x0f, 0x04, - 0x10, 0x81, 0x60, + 0x2c, 0x04, + 0x10, 0x80, 0xc0, + 0x3c, 0x64, 0x53, 0x0c, 0x01, 0x81, 0x00, 0x48, 0x08, @@ -457,7 +454,10 @@ const NORMAL1: &'static [u8] = &[ 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, - 0x0a, 0x82, 0xa6, + 0x0a, 0x06, + 0x39, 0x07, + 0x0a, 0x81, 0x36, + 0x19, 0x81, 0x07, 0x83, 0x9a, 0x66, 0x75, 0x0b, 0x80, 0xc4, 0x8a, 0xbc, @@ -469,12 +469,13 @@ const NORMAL1: &'static [u8] = &[ 0x26, 0x0a, 0x46, 0x0a, 0x28, 0x05, - 0x13, 0x83, 0x70, + 0x13, 0x82, 0xb0, + 0x5b, 0x65, 0x45, 0x0b, 0x2f, 0x10, 0x11, 0x40, 0x02, 0x1e, - 0x97, 0xed, 0x13, + 0x97, 0xf2, 0x0e, 0x82, 0xf3, 0xa5, 0x0d, 0x81, 0x1f, 0x51, 0x81, 0x8c, 0x89, 0x04, @@ -485,9 +486,10 @@ const NORMAL1: &'static [u8] = &[ 0x80, 0xf6, 0x0a, 0x73, 0x08, 0x6e, 0x17, - 0x46, 0x80, 0xba, + 0x46, 0x80, 0x9a, + 0x14, 0x0c, 0x57, 0x09, - 0x12, 0x80, 0x8e, + 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, @@ -495,7 +497,8 @@ const NORMAL1: &'static [u8] = &[ 0x80, 0xd7, 0x29, 0x4b, 0x05, 0x0a, 0x04, - 0x02, 0x84, 0xa0, + 0x02, 0x83, 0x11, + 0x44, 0x81, 0x4b, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, @@ -514,18 +517,19 @@ const NORMAL1: &'static [u8] = &[ 0x06, 0x80, 0x9a, 0x83, 0xd5, 0x0b, 0x0d, 0x03, - 0x09, 0x07, + 0x0a, 0x06, 0x74, 0x0c, - 0x55, 0x2b, + 0x59, 0x27, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x1e, 0x52, 0x0c, 0x04, - 0x3d, 0x03, - 0x1c, 0x14, - 0x18, 0x28, - 0x01, 0x0f, - 0x17, 0x86, 0x19, + 0x67, 0x03, + 0x29, 0x0d, + 0x0a, 0x06, + 0x03, 0x0d, + 0x30, 0x60, + 0x0e, 0x85, 0x92, ]; diff --git a/src/libcore/unicode/tables.rs b/src/libcore/unicode/tables.rs index 3fbbc011bc41d..32668ea93dd8c 100644 --- a/src/libcore/unicode/tables.rs +++ b/src/libcore/unicode/tables.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -19,7 +19,7 @@ use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; /// `char` and `str` methods are based on. #[unstable(feature = "unicode_version", issue = "49726")] pub const UNICODE_VERSION: UnicodeVersion = UnicodeVersion { - major: 10, + major: 11, minor: 0, micro: 0, _priv: (), @@ -105,10 +105,10 @@ pub mod general_category { ], r5: &[ 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 5, 0, 6, 7, 0, 0, 8, 0, 0, 0, 6, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, - 0, 0, 8, 0, 9, 6, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, - 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 6, 0, 5, 7, 0, 0, 8, 0, 0, 0, 5, 0, 0, 0, 0, 0, 8, 0, 8, 0, 0, 0, + 0, 0, 8, 0, 9, 5, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, + 0, 8, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -123,7 +123,7 @@ pub mod general_category { ], r6: &[ 0x0000000000000000, 0x001fffffffffffff, 0x0000000000000402, 0x00000000003e0000, - 0x000003ff00000000, 0x0000ffc000000000, 0x03ff000000000000, 0xffc0000000000000, + 0x000003ff00000000, 0x03ff000000000000, 0x0000ffc000000000, 0xffc0000000000000, 0x0000000003ff0000, 0x00000000000003ff, 0xffffffffffffffff, 0x00007fffffffffff, 0xffffffffffffc000 ], @@ -143,7 +143,7 @@ pub mod derived_property { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, 0x0000000000000000, 0xbcdf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbfff0000000000ff, 0x000707ffffff00b6, + 0xfffeffffffffffff, 0xffffffff027fffff, 0xbfff0000000001ff, 0x000787ffffff00b6, 0xffffffff07ff0000, 0xffffc000feffffff, 0xffffffffffffffff, 0x9c00e1fe1fefffff, 0xffffffffffff0000, 0xffffffffffffe000, 0x0003ffffffffffff, 0x043007fffffffc00 ], @@ -152,10 +152,10 @@ pub mod derived_property { 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 36, 36, 36, 36, 37, 38, 39, 40, 41, 42, 43, 44, 36, 36, 36, 36, 36, 36, 36, 36, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 31, 63, 64, 65, 66, 55, 67, 68, 69, 36, 36, 36, 70, 36, 36, - 36, 36, 71, 72, 73, 74, 31, 75, 76, 31, 77, 78, 68, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 79, 80, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 81, 82, 36, 83, 84, 85, 86, 87, 88, 31, 31, 31, - 31, 31, 31, 31, 89, 44, 90, 91, 92, 36, 93, 94, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, + 36, 36, 71, 72, 73, 74, 31, 75, 76, 31, 77, 78, 79, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 80, 81, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, + 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 82, 83, 36, 84, 85, 86, 87, 88, 89, 31, 31, 31, + 31, 31, 31, 31, 90, 44, 91, 92, 93, 36, 94, 95, 31, 31, 31, 31, 31, 31, 31, 31, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, @@ -175,9 +175,9 @@ pub mod derived_property { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 95, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 96, 97, 36, 36, 36, 36, 98, 99, 36, 100, 101, 36, 102, - 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 95, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 96, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, + 36, 36, 36, 36, 36, 36, 36, 36, 97, 98, 36, 36, 36, 36, 99, 100, 36, 96, 101, 36, 102, + 103, 104, 105, 36, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 36, 117, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, @@ -185,15 +185,15 @@ pub mod derived_property { 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, - 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 117, 118, + 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 118, 119, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 36, 36, 36, 36, 36, 119, 36, 120, 121, 122, 123, 124, 36, 36, 36, 36, 125, 126, 127, - 128, 31, 129, 36, 130, 131, 132, 113, 133 + 36, 36, 36, 36, 36, 120, 36, 121, 122, 123, 124, 125, 36, 36, 36, 36, 126, 127, 128, + 129, 31, 130, 36, 131, 132, 133, 113, 134 ], r3: &[ 0x00001ffffcffffff, 0x000007ff01ffffff, 0x3fdfffff00000000, 0xffff03f8fff00000, @@ -209,27 +209,27 @@ pub mod derived_property { 0xffffffffff3dffff, 0x0000000087ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x000fffff000fdfff, 0x000ddfff000fffff, 0xffcfffffffffffff, 0x00000000108001ff, - 0xffffffff00000000, 0x00ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, + 0xffffffff00000000, 0x01ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, 0x01ff0fff7fffffff, 0x001f3fffffff0000, 0xffff0fffffffffff, 0x00000000000003ff, 0xffffffff0fffffff, 0x001ffffe7fffffff, 0x0000008000000000, 0xffefffffffffffff, 0x0000000000000fef, 0xfc00f3ffffffffff, 0x0003ffbfffffffff, 0x3ffffffffc00e000, - 0x00000000000001ff, 0x006fde0000000000, 0x001fff8000000000, 0xffffffff3f3fffff, + 0xe7ffffffffff01ff, 0x006fde0000000000, 0x001fff8000000000, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, - 0x000000001fff0000, 0xf3ffbd503e2ffc84, 0xffffffff000043e0, 0xffc0000000000000, - 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, - 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, - 0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, - 0xfffe7fffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, - 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x8ff07fffffffffff, - 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, - 0x000000fffffff7bb, 0x000fffffffffffff, 0x28fc00000000002f, 0xffff07fffffffc00, + 0x000000001fff0000, 0xf3ffbd503e2ffc84, 0xffffffff000043e0, 0x00000000000001ff, + 0xffc0000000000000, 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, + 0x000c781fffffffff, 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, + 0xffffffff7f7f7f7f, 0x0000800000000000, 0x1f3e03fe000000e0, 0xfffffffee07fffff, + 0xf7ffffffffffffff, 0xfffeffffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, + 0x0000ffffffffffff, 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, + 0x8ff07fffffffffff, 0xfffffffcff800000, 0x03fffffffffff9ff, 0xff80000000000000, + 0x000000fffffff7bb, 0x000fffffffffffff, 0x68fc00000000002f, 0xffff07fffffffc00, 0x1fffffff0007ffff, 0xfff7ffffffffffff, 0x7c00ffdf00008000, 0x007fffffffffffff, 0xc47fffff00003fff, 0x7fffffffffffffff, 0x003cffff38000005, 0xffff7f7f007e7e7e, - 0xffff003ff7ffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, 0xffff3fffffffffff, - 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0x0003ffffffffffff, - 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, - 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, 0x07fffffe00000000, - 0xffffffc007fffffe, 0x000000001cfcfcfc + 0xffff003ff7ffffff, 0x000007ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, + 0xffff3fffffffffff, 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, + 0x0003ffffffffffff, 0xfffffffffff80000, 0x3fffffffffffffff, 0xffffffffffff0000, + 0xfffffffffffcffff, 0x0fff0000000000ff, 0xffdf000000000000, 0x1fffffffffffffff, + 0x07fffffe00000000, 0xffffffc007fffffe, 0x000000001cfcfcfc ], r4: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 12, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 13, 14, @@ -245,45 +245,45 @@ pub mod derived_property { r5: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, - 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 33, 34, 35, 32, 36, 2, 37, 38, 4, 39, 40, 41, - 42, 4, 4, 2, 43, 2, 44, 4, 4, 45, 46, 47, 48, 28, 4, 49, 4, 4, 4, 4, 4, 50, 51, 4, 4, 4, - 4, 52, 53, 54, 55, 4, 4, 4, 4, 56, 57, 58, 4, 59, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 4, 2, 62, 2, 2, 2, 63, 4, 4, 4, 4, 4, 4, 4, + 32, 33, 4, 4, 4, 4, 4, 4, 4, 34, 35, 4, 4, 2, 35, 36, 37, 32, 38, 2, 39, 40, 4, 41, 42, + 43, 44, 4, 4, 2, 45, 2, 46, 4, 4, 47, 48, 49, 50, 28, 4, 51, 4, 4, 4, 52, 4, 53, 54, 4, + 4, 4, 4, 55, 56, 57, 52, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 63, 4, 4, 4, 4, 64, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 65, 4, 2, 66, 2, 2, 2, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 68, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, - 2, 2, 2, 2, 2, 2, 55, 20, 4, 65, 16, 66, 67, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 68, 69, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 72, 2, 2, 2, 2, 2, 73, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 74, 75, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 76, 77, 78, 79, 80, 2, 2, 2, 2, 81, 82, 83, 84, 85, 86, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 87, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 88, 2, 89, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 90, 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 72, 93, 94, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 52, 20, 4, 69, 16, 70, 71, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, + 4, 2, 72, 73, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 75, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 76, 2, 2, 2, 2, 2, + 77, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 78, 79, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 80, 81, 82, 83, 84, 2, 2, 2, 2, 85, 86, 87, 88, 89, + 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 91, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 92, 2, 93, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 94, 95, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 76, 97, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 95, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 99, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 4, 4, 4, 4, + 2, 100, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 101, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 102, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, @@ -292,18 +292,19 @@ pub mod derived_property { 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, - 0x000ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, + 0x003ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, - 0x0007ffffffffffff, 0x000000000000003f, 0x01fffffffffffffc, 0x000001ffffff0000, - 0x0047ffffffff0000, 0x000000001400001e, 0x409ffffffffbffff, 0xffff01ffbfffbd7f, - 0x000001ffffffffff, 0xe3edfdfffff99fef, 0x0000000fe081199f, 0x00000000000007bb, - 0x00000000000000b3, 0x7f3fffffffffffff, 0x000000003f000000, 0x7fffffffffffffff, - 0x0000000000000011, 0x000007ffe3ffffff, 0xffffffff00000000, 0x80000000ffffffff, - 0x7fe7ffffffffffff, 0xffffffffffff0000, 0x0000000000ffffcf, 0x01ffffffffffffff, - 0x7f7ffffffffffdff, 0xfffc000000000001, 0x007ffefffffcffff, 0xb47ffffffffffb7f, - 0x00000000000000cb, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, + 0x0007ffffffffffff, 0x000000ffffffffff, 0xffff00801fffffff, 0x000000000000003f, + 0x01fffffffffffffc, 0x000001ffffff0000, 0x0047ffffffff0070, 0x000000001400001e, + 0x409ffffffffbffff, 0xffff01ffbfffbd7f, 0x000001ffffffffff, 0xe3edfdfffff99fef, + 0x0000000fe081199f, 0x00000000000007bb, 0x00000000000000b3, 0x7f3fffffffffffff, + 0x000000003f000000, 0x7fffffffffffffff, 0x0000000000000011, 0x000007ffe7ffffff, + 0x01ffffffffffffff, 0xffffffff00000000, 0x80000000ffffffff, 0x7fe7ffffffffffff, + 0xffffffffffff0000, 0x0000000020ffffcf, 0x7f7ffffffffffdff, 0xfffc000000000001, + 0x007ffefffffcffff, 0xb47ffffffffffb7f, 0xfffffdbf000000cb, 0x00000000017b7fff, + 0x007fffff00000000, 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000000ffff, - 0x7fffffffffff001f, 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, + 0x7fffffffffff001f, 0x00000000fff80000, 0x0000000300000000, 0x0003ffffffffffff, 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000043ff01ff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, @@ -327,16 +328,16 @@ pub mod derived_property { 0x0000000000000000, 0x0000000000000000, 0x00000000000003f8, 0x0000000000000000, 0x0000000000000000, 0x0000000002000000, 0xbffffffffffe0000, 0x00100000000000b6, 0x0000000017ff003f, 0x00010000fffff801, 0x0000000000000000, 0x00003dffbfc00000, - 0xffff000000028000, 0x00000000000007ff, 0x0001ffc000000000, 0x043ff80000000000 + 0xffff000000028000, 0x00000000000007ff, 0x0001ffc000000000, 0x243ff80000000000 ], r2: [ - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 7, 2, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 34, 35, 36, 37, 38, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, - 44, 45, 46, 47, 48, 49, 2, 50, 51, 52, 53, 54, 2, 2, 2, 2, 2, 2, 55, 56, 57, 58, 59, 60, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 11, 17, 18, 19, 2, 20, 21, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 34, 35, 36, 37, 38, 39, 40, 2, 41, 2, 2, 2, 42, 43, 44, 2, + 45, 46, 47, 48, 49, 50, 2, 51, 52, 53, 54, 55, 2, 2, 2, 2, 2, 2, 56, 57, 58, 59, 60, 61, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 61, 2, 62, 2, 63, 2, 64, 65, 2, 2, 2, 2, - 2, 2, 2, 66, 2, 67, 68, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 62, 2, 63, 2, 64, 2, 65, 66, 2, 2, 2, 2, + 2, 2, 2, 67, 2, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -351,9 +352,9 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 49, 2, 2, 2, 2, 70, 71, 72, 73, 74, 75, 76, 77, 78, 2, 2, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 2, 88, 2, 89, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 50, 2, 2, 2, 2, 71, 72, 73, 74, 75, 76, 77, 78, 79, 2, 2, 80, 81, + 82, 83, 84, 85, 86, 87, 88, 2, 89, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -364,35 +365,36 @@ pub mod derived_property { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 91, 92, 2, 2, 2, 2, 2, 2, 2, 2, 93, 94, 2, 95, - 96, 97, 98, 99 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 92, 93, 2, 2, 2, 2, 2, 2, 2, 2, 94, 95, 2, 96, + 97, 98, 99, 100 ], r3: &[ - 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffffff00000, - 0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x0000000c0000201e, + 0x00003fffffc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffffff80000, + 0x1400000000000007, 0x0002000c00fe21fe, 0x1000000000000002, 0x4000000c0000201e, 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0x9000000000000002, - 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000001, - 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x00000000005c0400, - 0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, 0x0000000000003f40, - 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, 0x0000000000000040, - 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, 0x1000000000000000, - 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, 0x3fb0000000000000, - 0x00000000208ffe40, 0x0000000000007800, 0x0000000000000008, 0x0000020000000060, - 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff008000000000, - 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, - 0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, 0xfffff00000000000, - 0x010007ffffffffff, 0xfffffffff8000000, 0xfbffffffffffffff, 0xa000000000000000, - 0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, 0x000000001fff0000, - 0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, 0x8000800000000000, - 0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, 0x000000007e000000, - 0x7000000000000000, 0x0000000000200000, 0x0000000000001000, 0xbff7800000000000, - 0x00000000f0000000, 0x0003000000000000, 0x00000003ffffffff, 0x0001000000000000, - 0x0000000000000700, 0x0300000000000000, 0x0000006000000844, 0x0003ffff00000030, - 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, 0x0000006000008000, - 0x00667e0000000000, 0x1001000000001008, 0xc19d000000000000, 0x0058300020000002, - 0x00000000f8000000, 0x0000212000000000, 0x0000000040000000, 0xfffc000000000000, - 0x0000000000000003, 0x0000ffff0008ffff, 0x0000000000240000, 0x8000000000000000, - 0x4000000004004080, 0x0001000000000001, 0x00000000c0000000, 0x0e00000800000000 + 0x0000000c0040201e, 0x0000000000000004, 0x0000000000002001, 0xc000000000000011, + 0x0000000c00603dc1, 0x0000000c00003040, 0x1800000000000003, 0x0000000c0000201e, + 0x00000000005c0400, 0x07f2000000000000, 0x0000000000007fc0, 0x1bf2000000000000, + 0x0000000000003f40, 0x02a0000003000000, 0x7ffe000000000000, 0x1ffffffffeffe0df, + 0x0000000000000040, 0x66fde00000000000, 0x001e0001c3000000, 0x0000000020002064, + 0x1000000000000000, 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, + 0x3fb0000000000000, 0x00000000208ffe40, 0x0000000000007800, 0x0000000000000008, + 0x0000020000000060, 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, + 0x7fff008000000000, 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, + 0x0003a34000000000, 0x00cff00000000000, 0x3f00000000000000, 0x031021fdfff70000, + 0xfffff00000000000, 0x010007ffffffffff, 0xfffffffff8000000, 0xfbffffffffffffff, + 0xa000000000000000, 0x6000e000e000e003, 0x00007c900300f800, 0x8002ffdf00000000, + 0x000000001fff0000, 0x0001ffffffff0000, 0x3000000000000000, 0x0003800000000000, + 0x8000800000000000, 0xffffffff00000000, 0x0000800000000000, 0x083e3c0000000020, + 0x000000007e000000, 0x7000000000000000, 0x0000000000200000, 0x0000000000001000, + 0xbff7800000000000, 0x00000000f0000000, 0x0003000000000000, 0x00000003ffffffff, + 0x0001000000000000, 0x0000000000000700, 0x0300000000000000, 0x0000006000000844, + 0x8003ffff00000030, 0x00003fc000000000, 0x000000000003ff80, 0x13c8000000000007, + 0x0000006000008000, 0x00667e0000000000, 0x1001000000001008, 0xc19d000000000000, + 0x0058300020000002, 0x00000000f8000000, 0x0000212000000000, 0x0000000040000000, + 0xfffc000000000000, 0x0000000000000003, 0x0000ffff0008ffff, 0x0000000000240000, + 0x8000000000000000, 0x4000000004004080, 0x0001000000000001, 0x00000000c0000000, + 0x0e00000800000000 ], r4: [ 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -407,42 +409,43 @@ pub mod derived_property { ], r5: &[ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 6, 7, 8, 0, 9, 10, 11, 12, 13, 0, 0, 14, 15, 16, 0, 0, 17, 18, 19, 20, - 0, 0, 21, 22, 23, 24, 25, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 0, 0, 0, - 0, 0, 30, 0, 31, 0, 32, 33, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 0, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 0, 17, 18, 19, 0, 0, 20, 21, 22, + 23, 0, 0, 24, 25, 26, 27, 28, 0, 29, 0, 0, 0, 30, 0, 0, 0, 0, 0, 0, 0, 31, 32, 33, 0, 0, + 0, 0, 0, 34, 0, 35, 0, 36, 37, 38, 0, 0, 0, 0, 39, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 45, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 47, 0, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 43, 44, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 0, 0, 48, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 53, 0, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 50, 51, 0, 0, 51, 51, 51, 52, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 56, 57, 0, 0, 57, 57, 57, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, - 0x870000000000f06e, 0x0000006000000000, 0xff00000000000002, 0x800000000000007f, - 0x2678000000000003, 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, - 0x0000000000001c00, 0x40d3800000000000, 0x000007f880000000, 0x1000000000000003, - 0x001f1fc000000001, 0xff00000000000000, 0x000000000000005c, 0x85f8000000000000, - 0x000000000000000d, 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, - 0x0000000000000001, 0x00bf280000000000, 0x00000fbce0000000, 0x79f800000000067e, + 0x870000000000f06e, 0x0000006000000000, 0x000000f000000000, 0x000000000001ffc0, + 0xff00000000000002, 0x800000000000007f, 0x2678000000000003, 0x0000000000002000, + 0x001fef8000000007, 0x0008000000000000, 0x7fc0000000000003, 0x0000000000001e00, + 0x40d3800000000000, 0x000007f880000000, 0x1800000000000003, 0x001f1fc000000001, + 0xff00000000000000, 0x000000004000005c, 0x85f8000000000000, 0x000000000000000d, + 0xb03c000000000000, 0x0000000030000001, 0xa7f8000000000000, 0x0000000000000001, + 0x00bf280000000000, 0x00000fbce0000000, 0x06ff800000000000, 0x79f80000000007fe, 0x000000000e7e0080, 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, - 0xb47e000000000000, 0x00000000000000bf, 0x001f000000000000, 0x007f000000000000, - 0x000000000000000f, 0x00000000ffff8000, 0x0000000300000000, 0x0000000f60000000, - 0xfff8038000000000, 0x00003c0000000fe7, 0x000000000000001c, 0xf87fffffffffffff, - 0x00201fffffffffff, 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f0000, - 0x00000000000007f0, 0xf800000000000000, 0xffffffff00000002, 0xffffffffffffffff, - 0x0000ffffffffffff + 0xb47e000000000000, 0x00000000000000bf, 0x0000000000a30000, 0x0018000000000000, + 0x001f000000000000, 0x007f000000000000, 0x000000000000000f, 0x00000000ffff8000, + 0x0000000300000000, 0x0000000f60000000, 0xfff8038000000000, 0x00003c0000000fe7, + 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, + 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, 0xf800000000000000, + 0xffffffff00000002, 0xffffffffffffffff, 0x0000ffffffffffff ], }; @@ -457,7 +460,7 @@ pub mod derived_property { 0xffffffffffffffff, 0xffffffffffffffff, 0x01ffffffffefffff, 0x0000001f00000003, 0x0000000000000000, 0xbccf000000000020, 0xfffffffbffffd740, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe007fffff, 0x00000000000000ff, 0x0000000000000000, + 0xfffeffffffffffff, 0xffffffff007fffff, 0x00000000000001ff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], @@ -499,17 +502,17 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 29, 30, 0, 0 ], r3: &[ - 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x3f3fffffffffffff, - 0x00000000000001ff, 0xffffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, + 0x0000000000000000, 0xffffffff00000000, 0xe7ffffffffff20bf, 0x3f3fffffffffffff, + 0xe7ffffffffff01ff, 0xffffffffffffffff, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf21fbd503e2ffc84, 0xffffffff000043e0, 0x0000000000000018, 0xffc0000000000000, 0x000003ffffffffff, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, 0x000020bfffffffff, 0x00003fffffffffff, 0x000000003fffffff, 0xfffffffc00000000, - 0x00ff7fffffff78ff, 0x0700000000000000, 0xffff000000000000, 0xffff003ff7ffffff, + 0x03ffffffffff78ff, 0x0700000000000000, 0xffff000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, 0x07fffffe00000000, 0x0000000007fffffe ], r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 4, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -527,13 +530,15 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 8, 9, 10, 11, 12, 1, 1, 1, 1, 13, 14, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 8, 9, 10, 11, 12, 1, 1, 1, 1, 13, 14, 15, 16, 17, + 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 3, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0xffffffffffffffff, 0x000000000000ffff, 0xffff000000000000, @@ -549,6 +554,129 @@ pub mod derived_property { Cased_table.lookup(c) } + pub const Grapheme_Extend_table: &super::BoolTrie = &super::BoolTrie { + r1: [ + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, + 0xffffffffffffffff, 0x0000ffffffffffff, 0x0000000000000000, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0x00000000000003f8, 0x0000000000000000, + 0x0000000000000000, 0x0000000000000000, 0xbffffffffffe0000, 0x00000000000000b6, + 0x0000000007ff0000, 0x00010000fffff800, 0x0000000000000000, 0x00003d9f9fc00000, + 0xffff000000020000, 0x00000000000007ff, 0x0001ffc000000000, 0x200ff80000000000 + ], + r2: [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 8, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 2, 21, 22, + 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 34, 35, 36, 37, 38, 2, 39, 2, 40, 2, 2, 2, 41, 42, 43, 2, 44, + 45, 46, 47, 48, 2, 2, 49, 2, 2, 2, 50, 2, 2, 2, 2, 2, 2, 2, 2, 51, 2, 2, 52, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 53, 2, 54, 2, 55, 2, 2, 2, 2, 2, 2, 2, 2, 56, + 2, 57, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 58, 59, 60, 2, 2, 2, 2, 61, 2, 2, 62, 63, 64, 65, 66, 67, 68, + 69, 70, 2, 2, 2, 71, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 72, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 73, 2, 2, 2, 2, 2, 59, 2 + ], + r3: &[ + 0x00003eeffbc00000, 0x000000000e000000, 0x0000000000000000, 0xfffffffbfff80000, + 0x1400000000000007, 0x0000000c00fe21fe, 0x5000000000000002, 0x4000000c0080201e, + 0x1000000000000006, 0x0023000000023986, 0xfc00000c000021be, 0xd000000000000002, + 0x0000000c00c0201e, 0x4000000000000004, 0x0000000000802001, 0xc000000000000011, + 0x0000000c00603dc1, 0x9000000000000002, 0x0000000c00603044, 0x5800000000000003, + 0x0000000c0080201e, 0x00000000805c8400, 0x07f2000000000000, 0x0000000000007f80, + 0x1bf2000000000000, 0x0000000000003f00, 0x02a0000003000000, 0x7ffe000000000000, + 0x1ffffffffeffe0df, 0x0000000000000040, 0x66fde00000000000, 0x001e0001c3000000, + 0x0000000020002064, 0x00000000e0000000, 0x001c0000001c0000, 0x000c0000000c0000, + 0x3fb0000000000000, 0x00000000200ffe40, 0x0000000000003800, 0x0000020000000060, + 0x0e04018700000000, 0x0000000009800000, 0x9ff81fe57f400000, 0x7fff000000000000, + 0x17d000000000000f, 0x000ff80000000004, 0x00003b3c00000003, 0x0003a34000000000, + 0x00cff00000000000, 0x031021fdfff70000, 0xfbffffffffffffff, 0x0000000000001000, + 0x0001ffffffff0000, 0x0003800000000000, 0x8000000000000000, 0xffffffff00000000, + 0x0000fc0000000000, 0x0000000006000000, 0x3ff7800000000000, 0x00000000c0000000, + 0x0003000000000000, 0x0000006000000844, 0x8003ffff00000030, 0x00003fc000000000, + 0x000000000003ff80, 0x13c8000000000007, 0x0000002000000000, 0x00667e0000000000, + 0x1000000000001008, 0xc19d000000000000, 0x0040300000000002, 0x0000212000000000, + 0x0000000040000000, 0x0000ffff0000ffff + ], + r4: [ + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 4, 2, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + ], + r5: &[ + 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, + 0, 0, 0, 7, 0, 0, 8, 9, 10, 0, 11, 12, 13, 14, 15, 0, 0, 16, 17, 18, 0, 0, 19, 20, 21, + 22, 0, 0, 23, 24, 25, 26, 27, 0, 28, 0, 0, 0, 29, 0, 0, 0, 0, 0, 0, 0, 30, 31, 32, 0, 0, + 0, 0, 0, 33, 0, 34, 0, 35, 36, 37, 0, 0, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 46, 47, 48, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 51, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 52, 53, 0, 0, + 53, 53, 53, 54, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0 + ], + r6: &[ + 0x0000000000000000, 0x2000000000000000, 0x0000000100000000, 0x07c0000000000000, + 0x870000000000f06e, 0x0000006000000000, 0x000000f000000000, 0x000000000001ffc0, + 0xff00000000000002, 0x800000000000007f, 0x0678000000000003, 0x001fef8000000007, + 0x0008000000000000, 0x7fc0000000000003, 0x0000000000001e00, 0x40d3800000000000, + 0x000007f880000000, 0x5800000000000003, 0x001f1fc000800001, 0xff00000000000000, + 0x000000004000005c, 0xa5f9000000000000, 0x000000000000000d, 0xb03c800000000000, + 0x0000000030000001, 0xa7f8000000000000, 0x0000000000000001, 0x00bf280000000000, + 0x00000fbce0000000, 0x06ff800000000000, 0x79f80000000007fe, 0x000000000e7e0080, + 0x00000000037ffc00, 0xbf7f000000000000, 0x006dfcfffffc0000, 0xb47e000000000000, + 0x00000000000000bf, 0x0000000000a30000, 0x0018000000000000, 0x001f000000000000, + 0x007f000000000000, 0x0000000000078000, 0x0000000060000000, 0xf807c3a000000000, + 0x00003c0000000fe7, 0x000000000000001c, 0xf87fffffffffffff, 0x00201fffffffffff, + 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f0000, 0x00000000000007f0, + 0xffffffff00000000, 0xffffffffffffffff, 0x0000ffffffffffff + ], + }; + + pub fn Grapheme_Extend(c: char) -> bool { + Grapheme_Extend_table.lookup(c) + } + pub const Lowercase_table: &super::BoolTrie = &super::BoolTrie { r1: [ 0x0000000000000000, 0x07fffffe00000000, 0x0420040000000000, 0xff7fffff80000000, @@ -556,17 +684,17 @@ pub mod derived_property { 0x93faaaaaaaaaaaaa, 0xffffffffffffaa85, 0x01ffffffffefffff, 0x0000001f00000003, 0x0000000000000000, 0x3c8a000000000020, 0xfffff00000010000, 0x192faaaaaae37fff, 0xffff000000000000, 0xaaaaaaaaffffffff, 0xaaaaaaaaaaaaa802, 0xaaaaaaaaaaaad554, - 0x0000aaaaaaaaaaaa, 0xfffffffe00000000, 0x00000000000000ff, 0x0000000000000000, + 0x0000aaaaaaaaaaaa, 0xffffffff00000000, 0x00000000000001ff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 ], r2: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 3, 3, - 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 10, 11, 0, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 16, 17, 4, 18, 19, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 4, 4, 4, + 0, 5, 5, 6, 5, 7, 8, 9, 10, 0, 11, 12, 0, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 17, 18, 5, 19, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -582,8 +710,8 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 21, 0, - 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 26, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 21, 22, + 0, 23, 24, 25, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 27, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -594,21 +722,21 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 28, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 29, 0, 0 ], r3: &[ - 0x0000000000000000, 0x3f00000000000000, 0x00000000000001ff, 0xffffffffffffffff, - 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaabfeaaaaa, 0x00ff00ff003f00ff, 0x3fff00ff00ff003f, - 0x40df00ff00ff00ff, 0x00dc00ff00cf00dc, 0x8002000000000000, 0x000000001fff0000, - 0x321080000008c400, 0xffff0000000043c0, 0x0000000000000010, 0x000003ffffff0000, - 0xffff000000000000, 0x3fda15627fffffff, 0x0008501aaaaaaaaa, 0x000020bfffffffff, - 0x00002aaaaaaaaaaa, 0x000000003aaaaaaa, 0xaaabaaa800000000, 0x95ffaaaaaaaaaaaa, - 0x00a002aaaaba50aa, 0x0700000000000000, 0xffff003ff7ffffff, 0x0000000000f8007f, - 0x0000000007fffffe + 0x0000000000000000, 0xe7ffffffffff0000, 0x3f00000000000000, 0x00000000000001ff, + 0xffffffffffffffff, 0xaaaaaaaaaaaaaaaa, 0xaaaaaaaabfeaaaaa, 0x00ff00ff003f00ff, + 0x3fff00ff00ff003f, 0x40df00ff00ff00ff, 0x00dc00ff00cf00dc, 0x8002000000000000, + 0x000000001fff0000, 0x321080000008c400, 0xffff0000000043c0, 0x0000000000000010, + 0x000003ffffff0000, 0xffff000000000000, 0x3fda15627fffffff, 0x0008501aaaaaaaaa, + 0x000020bfffffffff, 0x00002aaaaaaaaaaa, 0x000000003aaaaaaa, 0xaaabaaa800000000, + 0x95ffaaaaaaaaaaaa, 0x02a082aaaaba50aa, 0x0700000000000000, 0xffff003ff7ffffff, + 0x0000000000f8007f, 0x0000000007fffffe ], r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -626,19 +754,22 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0xffffff0000000000, 0x000000000000ffff, 0x0fffffffff000000, - 0x0007ffffffffffff, 0x00000000ffffffff, 0x000ffffffc000000, 0x000000ffffdfc000, - 0xebc000000ffffffc, 0xfffffc000000ffef, 0x00ffffffc000000f, 0x00000ffffffc0000, - 0xfc000000ffffffc0, 0xffffc000000fffff, 0x0ffffffc000000ff, 0x0000ffffffc00000, - 0x0000003ffffffc00, 0xf0000003f7fffffc, 0xffc000000fdfffff, 0xffff0000003f7fff, - 0xfffffc000000fdff, 0x0000000000000bf7, 0xfffffffc00000000, 0x000000000000000f + 0x0007ffffffffffff, 0x00000000ffffffff, 0xffffffff00000000, 0x000ffffffc000000, + 0x000000ffffdfc000, 0xebc000000ffffffc, 0xfffffc000000ffef, 0x00ffffffc000000f, + 0x00000ffffffc0000, 0xfc000000ffffffc0, 0xffffc000000fffff, 0x0ffffffc000000ff, + 0x0000ffffffc00000, 0x0000003ffffffc00, 0xf0000003f7fffffc, 0xffc000000fdfffff, + 0xffff0000003f7fff, 0xfffffc000000fdff, 0x0000000000000bf7, 0xfffffffc00000000, + 0x000000000000000f ], }; @@ -660,10 +791,10 @@ pub mod derived_property { r2: [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 4, 4, 5, 4, 6, 7, 8, 9, 0, 0, 0, 0, 10, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 13, - 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 15, 16, 4, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, + 0, 5, 5, 6, 5, 7, 8, 9, 10, 0, 0, 0, 0, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, + 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 16, 17, 5, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -679,8 +810,8 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 19, 0, - 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 0, + 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -692,18 +823,19 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 23, 0, 0, 0 + 0, 0, 0, 0, 0, 24, 0, 0, 0 ], r3: &[ 0x0000000000000000, 0xffffffff00000000, 0x00000000000020bf, 0x003fffffffffffff, - 0x5555555555555555, 0x5555555540155555, 0xff00ff003f00ff00, 0x0000ff00aa003f00, - 0x0f00000000000000, 0x0f001f000f000f00, 0xc00f3d503e273884, 0x0000ffff00000020, - 0x0000000000000008, 0xffc0000000000000, 0x000000000000ffff, 0x00007fffffffffff, - 0xc025ea9d00000000, 0x0004280555555555, 0x0000155555555555, 0x0000000005555555, - 0x5554555400000000, 0x6a00555555555555, 0x005f7d5555452855, 0x07fffffe00000000 + 0xe7ffffffffff0000, 0x5555555555555555, 0x5555555540155555, 0xff00ff003f00ff00, + 0x0000ff00aa003f00, 0x0f00000000000000, 0x0f001f000f000f00, 0xc00f3d503e273884, + 0x0000ffff00000020, 0x0000000000000008, 0xffc0000000000000, 0x000000000000ffff, + 0x00007fffffffffff, 0xc025ea9d00000000, 0x0004280555555555, 0x0000155555555555, + 0x0000000005555555, 0x5554555400000000, 0x6a00555555555555, 0x015f7d5555452855, + 0x07fffffe00000000 ], r4: [ - 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, 5, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 0, 1, 2, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 4, 5, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -721,22 +853,24 @@ pub mod derived_property { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, + 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 23, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 24, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ], r6: &[ 0x0000000000000000, 0x000000ffffffffff, 0xffff000000000000, 0x00000000000fffff, - 0x0007ffffffffffff, 0xffffffff00000000, 0xfff0000003ffffff, 0xffffff0000003fff, - 0x003fde64d0000003, 0x000003ffffff0000, 0x7b0000001fdfe7b0, 0xfffff0000001fc5f, - 0x03ffffff0000003f, 0x00003ffffff00000, 0xf0000003ffffff00, 0xffff0000003fffff, - 0xffffff00000003ff, 0x07fffffc00000001, 0x001ffffff0000000, 0x00007fffffc00000, - 0x000001ffffff0000, 0x0000000000000400, 0x00000003ffffffff, 0xffff03ffffff03ff, - 0x00000000000003ff + 0x0007ffffffffffff, 0xffffffff00000000, 0x00000000ffffffff, 0xfff0000003ffffff, + 0xffffff0000003fff, 0x003fde64d0000003, 0x000003ffffff0000, 0x7b0000001fdfe7b0, + 0xfffff0000001fc5f, 0x03ffffff0000003f, 0x00003ffffff00000, 0xf0000003ffffff00, + 0xffff0000003fffff, 0xffffff00000003ff, 0x07fffffc00000001, 0x001ffffff0000000, + 0x00007fffffc00000, 0x000001ffffff0000, 0x0000000000000400, 0x00000003ffffffff, + 0xffff03ffffff03ff, 0x00000000000003ff ], }; @@ -751,19 +885,19 @@ pub mod derived_property { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, 0xffffffffffffffff, 0xb8dfffffffffffff, 0xfffffffbffffd7c0, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffcfb, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0xbffffffffffe00ff, 0x000707ffffff00b6, + 0xfffeffffffffffff, 0xffffffff027fffff, 0xbffffffffffe01ff, 0x000787ffffff00b6, 0xffffffff07ff0000, 0xffffc3ffffffffff, 0xffffffffffffffff, 0x9ffffdff9fefffff, - 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x043fffffffffffff + 0xffffffffffff0000, 0xffffffffffffe7ff, 0x0003ffffffffffff, 0x243fffffffffffff ], r2: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 4, 32, 33, 34, 4, 4, 4, 4, 4, 35, 36, 37, 38, 39, 40, 41, 42, 4, 4, 4, 4, 4, 4, 4, 4, 43, 44, 45, 46, 47, 4, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, 4, 61, 4, 62, 50, 63, 64, 65, 4, 4, 4, 66, 4, 4, 4, 4, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 64, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, + 56, 57, 58, 59, 60, 4, 61, 4, 62, 63, 64, 65, 66, 4, 4, 4, 67, 4, 4, 4, 4, 68, 69, 70, + 71, 72, 73, 74, 75, 76, 77, 78, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 77, 78, 4, 79, 80, 81, 82, 83, 60, 60, 60, 60, 60, 60, 60, 60, 84, - 42, 85, 86, 87, 4, 88, 89, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 60, 60, 60, 60, 60, 79, 80, 4, 81, 82, 83, 84, 85, 60, 60, 60, 60, 60, 60, 60, 60, 86, + 42, 87, 88, 89, 4, 90, 91, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, @@ -778,30 +912,30 @@ pub mod derived_property { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 90, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 91, 92, 4, 4, 4, 4, 93, 94, 4, 95, 96, 4, 97, 98, 99, 62, 4, 100, 101, - 102, 4, 103, 104, 105, 4, 106, 107, 108, 4, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 93, 94, 4, 4, 4, 4, 95, 96, 4, 97, 98, 4, 99, 100, 101, 62, 4, 102, 103, + 104, 4, 105, 106, 107, 4, 108, 109, 110, 4, 111, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 110, 111, 60, 60, 60, 60, 60, 60, 60, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 112, 113, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, - 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 101, 4, 112, - 113, 114, 95, 115, 4, 116, 4, 4, 117, 118, 119, 120, 121, 122, 4, 123, 124, 125, 126, - 127 + 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 4, 4, 4, 4, 4, 103, 4, 114, + 115, 116, 97, 117, 4, 118, 4, 4, 119, 120, 121, 122, 123, 124, 4, 125, 126, 127, 128, + 129 ], r3: &[ - 0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff00000, - 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x1003ffcfb080799f, + 0x00003fffffffffff, 0x000007ff0fffffff, 0x3fdfffff00000000, 0xfffffffbfff80000, + 0xffffffffffffffff, 0xfffeffcfffffffff, 0xf3c5fdfffff99fef, 0x5003ffcfb080799f, 0xd36dfdfffff987ee, 0x003fffc05e023987, 0xf3edfdfffffbbfee, 0xfe00ffcf00013bbf, 0xf3edfdfffff99fee, 0x0002ffcfb0c0399f, 0xc3ffc718d63dc7ec, 0x0000ffc000813dc7, - 0xe3fffdfffffddfef, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf, + 0xe3fffdfffffddfff, 0x0000ffcf07603ddf, 0xf3effdfffffddfef, 0x0006ffcf40603ddf, 0xfffffffffffddfef, 0xfc00ffcf80f07ddf, 0x2ffbfffffc7fffec, 0x000cffc0ff5f847f, 0x07fffffffffffffe, 0x0000000003ff7fff, 0x3bffecaefef02596, 0x00000000f3ff3f5f, 0xc2a003ff03000001, 0xfffe1ffffffffeff, 0x1ffffffffeffffdf, 0x0000000000000040, @@ -809,26 +943,27 @@ pub mod derived_property { 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0003fe00e7ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x001fffff001fdfff, 0x000ddfff000fffff, - 0x000003ff308fffff, 0xffffffff03ff3800, 0x00ffffffffffffff, 0xffff07ffffffffff, + 0x000003ff308fffff, 0xffffffff03ff3800, 0x01ffffffffffffff, 0xffff07ffffffffff, 0x003fffffffffffff, 0x0fff0fff7fffffff, 0x001f3fffffffffc0, 0xffff0fffffffffff, 0x0000000007ff03ff, 0xffffffff0fffffff, 0x9fffffff7fffffff, 0x3fff008003ff03ff, - 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x3fffffffffffe3ff, - 0x00000000000001ff, 0x03fffffffff70000, 0xfbffffffffffffff, 0xffffffff3f3fffff, - 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8000000000000000, - 0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, 0xf3fffd503f2ffc84, - 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000ff81fffffffff, - 0xffff20bfffffffff, 0x800080ffffffffff, 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, - 0x1f3efffe000000e0, 0xfffffffee67fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, - 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, - 0x3fffffffffff0000, 0x00000fffffff1fff, 0xbff0ffffffffffff, 0x0003ffffffffffff, - 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, 0x000000ffffffffff, - 0x28ffffff03ff003f, 0xffff3fffffffffff, 0x1fffffff000fffff, 0x7fffffff03ff8001, - 0x007fffffffffffff, 0xfc7fffff03ff3fff, 0x007cffff38000007, 0xffff7f7f007e7e7e, - 0xffff003ff7ffffff, 0x03ff37ffffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, - 0x0000000003ffffff, 0x5f7ffdffe0f8007f, 0xffffffffffffffdb, 0xfffffffffff80000, - 0xfffffff03fffffff, 0x3fffffffffffffff, 0xffffffffffff0000, 0xfffffffffffcffff, - 0x03ff0000000000ff, 0x0018ffff0000ffff, 0xaa8a00000000e000, 0x1fffffffffffffff, - 0x87fffffe03ff0000, 0xffffffc007fffffe, 0x7fffffffffffffff, 0x000000001cfcfcfc + 0x0000000000000000, 0x000ff80003ff0fff, 0x000fffffffffffff, 0x00ffffffffffffff, + 0x3fffffffffffe3ff, 0xe7ffffffffff01ff, 0x03fffffffff70000, 0xfbffffffffffffff, + 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, + 0x8000000000000000, 0x8002000000100001, 0x000000001fff0000, 0x0001ffe21fff0000, + 0xf3fffd503f2ffc84, 0xffffffff000043e0, 0x00000000000001ff, 0xffff7fffffffffff, + 0xffffffff7fffffff, 0x000ff81fffffffff, 0xffff20bfffffffff, 0x800080ffffffffff, + 0x7f7f7f7f007fffff, 0xffffffff7f7f7f7f, 0x1f3efffe000000e0, 0xfffffffee67fffff, + 0xf7ffffffffffffff, 0xfffeffffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, + 0x0000ffffffffffff, 0x0000000000001fff, 0x3fffffffffff0000, 0x00000fffffff1fff, + 0xbff0ffffffffffff, 0x0003ffffffffffff, 0xfffffffcff800000, 0x03fffffffffff9ff, + 0xff80000000000000, 0x000000ffffffffff, 0xe8ffffff03ff003f, 0xffff3fffffffffff, + 0x1fffffff000fffff, 0x7fffffff03ff8001, 0x007fffffffffffff, 0xfc7fffff03ff3fff, + 0x007cffff38000007, 0xffff7f7f007e7e7e, 0xffff003ff7ffffff, 0x03ff37ffffffffff, + 0xffff000fffffffff, 0x0ffffffffffff87f, 0x0000000003ffffff, 0x5f7ffdffe0f8007f, + 0xffffffffffffffdb, 0xfffffffffff80000, 0xfffffff03fffffff, 0x3fffffffffffffff, + 0xffffffffffff0000, 0xfffffffffffcffff, 0x03ff0000000000ff, 0x0018ffff0000ffff, + 0xaa8a00000000e000, 0x1fffffffffffffff, 0x87fffffe03ff0000, 0xffffffc007fffffe, + 0x7fffffffffffffff, 0x000000001cfcfcfc ], r4: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 5, 5, 9, 5, 10, 11, 5, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 12, 13, @@ -844,45 +979,45 @@ pub mod derived_property { r5: &[ 0, 1, 2, 3, 4, 5, 4, 6, 4, 4, 7, 8, 9, 10, 11, 12, 2, 2, 13, 14, 15, 16, 4, 4, 2, 2, 2, 2, 17, 18, 4, 4, 19, 20, 21, 22, 23, 4, 24, 4, 25, 26, 27, 28, 29, 30, 31, 4, 2, 32, 33, - 33, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 34, 3, 35, 36, 37, 2, 38, 39, 4, 40, 41, 42, - 43, 4, 4, 2, 44, 2, 45, 4, 4, 46, 47, 2, 48, 49, 50, 51, 4, 4, 4, 4, 4, 52, 53, 4, 4, 4, - 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 63, 4, 2, 64, 2, 2, 2, 65, 4, 4, 4, 4, 4, 4, 4, + 33, 34, 4, 4, 4, 4, 4, 4, 4, 35, 36, 4, 4, 2, 37, 3, 38, 39, 40, 2, 41, 42, 4, 43, 44, + 45, 46, 4, 4, 2, 47, 2, 48, 4, 4, 49, 50, 2, 51, 52, 53, 54, 4, 4, 4, 3, 4, 55, 56, 4, + 4, 4, 4, 57, 58, 59, 60, 4, 4, 4, 4, 61, 62, 63, 4, 64, 65, 66, 4, 4, 4, 4, 67, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 68, 4, 2, 69, 2, 2, 2, 70, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 71, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 66, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, - 2, 2, 2, 2, 2, 2, 57, 67, 4, 68, 17, 69, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, - 71, 72, 73, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 60, 72, 4, 73, 17, 74, 75, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, + 4, 2, 76, 77, 78, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 74, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 75, 2, 2, 2, 2, 2, 76, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 77, 78, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 79, 80, 4, 4, 81, 4, 4, 4, 4, 4, 4, 2, 82, 83, 84, 85, 86, 2, 2, 2, 2, 87, 88, 89, 90, - 91, 92, 4, 4, 4, 4, 4, 4, 4, 4, 93, 94, 95, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 96, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 97, 2, 44, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 98, 99, 100, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 101, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 79, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 33, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 21, 80, 2, 2, 2, 2, 2, + 81, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 82, 83, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 84, 85, 4, 4, 86, 4, 4, 4, 4, 4, 4, 2, 87, 88, 89, 90, 91, 2, 2, 2, 2, 92, 93, 94, 95, + 96, 97, 4, 4, 4, 4, 4, 4, 4, 4, 98, 99, 100, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 101, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 102, 2, 103, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 104, 105, 106, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 107, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 11, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 102, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 108, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 103, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 109, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 104, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 105, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 110, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 111, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ 0xb7ffff7fffffefff, 0x000000003fff3fff, 0xffffffffffffffff, 0x07ffffffffffffff, @@ -891,27 +1026,28 @@ pub mod derived_property { 0x00000000003eff0f, 0xffff03ff3fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, - 0xc0ffffffffffffff, 0x870ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, + 0xc0ffffffffffffff, 0x873ffffffeeff06f, 0x1fffffff00000000, 0x000000001fffffff, 0x0000007ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, - 0x00000000000001ff, 0x0007ffffffffffff, 0x8000ffc00000007f, 0x03ff01ffffff0000, - 0xffdfffffffffffff, 0x004fffffffff0000, 0x0000000017ff1c1f, 0x40fffffffffbffff, - 0xffff01ffbfffbd7f, 0x03ff07ffffffffff, 0xf3edfdfffff99fef, 0x001f1fcfe081399f, - 0x0000000003ff07ff, 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001, - 0x0000000003ff0011, 0x00ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe3ffffff, - 0xffffffff00000000, 0x800003ffffffffff, 0x7fffffffffffffff, 0xffffffffffff0080, - 0x0000000003ffffcf, 0x01ffffffffffffff, 0xff7ffffffffffdff, 0xfffc000003ff0001, - 0x007ffefffffcffff, 0xb47ffffffffffb7f, 0x0000000003ff00ff, 0x0000000003ffffff, - 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, 0x000003ff7fffffff, - 0x001f3fffffff0000, 0xe0fffff803ff000f, 0x000000000000ffff, 0x7fffffffffff001f, - 0x00000000ffff8000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, - 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000063ff01ff, 0xf807e3e000000000, - 0x00003c0000000fe7, 0x000000000000001c, 0xffffffffffdfffff, 0xebffde64dfffffff, - 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, - 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, - 0xffffffffffffcff7, 0xf87fffffffffffff, 0x00201fffffffffff, 0x0000fffef8000010, - 0x000007dbf9ffff7f, 0x00000000007f001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, - 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, 0x00000001ffffffff, - 0x000000003fffffff, 0x0000ffffffffffff + 0x00000000000001ff, 0x0007ffffffffffff, 0x03ff00ffffffffff, 0xffff00801fffffff, + 0x000000000001ffff, 0x8000ffc00000007f, 0x03ff01ffffff0000, 0xffdfffffffffffff, + 0x004fffffffff0070, 0x0000000017ff1e1f, 0x40fffffffffbffff, 0xffff01ffbfffbd7f, + 0x03ff07ffffffffff, 0xfbedfdfffff99fef, 0x001f1fcfe081399f, 0x0000000043ff07ff, + 0x0000000003ff00bf, 0xff3fffffffffffff, 0x000000003f000001, 0x0000000003ff0011, + 0x00ffffffffffffff, 0x00000000000003ff, 0x03ff0fffe7ffffff, 0xffffffff00000000, + 0x800003ffffffffff, 0x7fffffffffffffff, 0xffffffffffff0080, 0x0000000023ffffcf, + 0x01ffffffffffffff, 0xff7ffffffffffdff, 0xfffc000003ff0001, 0x007ffefffffcffff, + 0xb47ffffffffffb7f, 0xfffffdbf03ff00ff, 0x000003ff01fb7fff, 0x007fffff00000000, + 0x0000000003ffffff, 0x00007fffffffffff, 0x000000000000000f, 0x000000000000007f, + 0x000003ff7fffffff, 0x001f3fffffff0000, 0xe0fffff803ff000f, 0x000000000000ffff, + 0x7fffffffffff001f, 0x00000000ffff8000, 0x0000000300000000, 0x0003ffffffffffff, + 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000063ff01ff, + 0xf807e3e000000000, 0x00003c0000000fe7, 0x000000000000001c, 0xffffffffffdfffff, + 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, + 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, + 0xfffffdfffffffdff, 0xffffffffffffcff7, 0xf87fffffffffffff, 0x00201fffffffffff, + 0x0000fffef8000010, 0x000007dbf9ffff7f, 0x00000000007f001f, 0x0000000003ff07ff, + 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, + 0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff, 0x0000ffffffffffff ], }; @@ -926,7 +1062,7 @@ pub mod derived_property { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0x0000501f0003ffc3, 0x0000000000000000, 0xb8df000000000000, 0xfffffffbffffd740, 0xffbfffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xfffffffffffffc03, 0xffffffffffffffff, - 0xfffeffffffffffff, 0xfffffffe027fffff, 0x00000000000000ff, 0x000707ffffff0000, + 0xfffeffffffffffff, 0xffffffff027fffff, 0x00000000000001ff, 0x000787ffffff0000, 0xffffffff00000000, 0xfffec000000007ff, 0xffffffffffffffff, 0x9c00c060002fffff, 0x0000fffffffd0000, 0xffffffffffffe000, 0x0002003fffffffff, 0x043007fffffffc00 ], @@ -935,9 +1071,9 @@ pub mod derived_property { 24, 23, 25, 26, 27, 28, 29, 3, 30, 31, 32, 33, 34, 34, 34, 34, 34, 35, 36, 37, 38, 39, 40, 41, 42, 34, 34, 34, 34, 34, 34, 34, 34, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 3, 61, 62, 63, 64, 65, 66, 67, 68, 34, 34, 34, 3, 34, 34, - 34, 34, 69, 70, 71, 72, 3, 73, 74, 3, 75, 76, 67, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 77, - 78, 34, 79, 80, 81, 82, 83, 3, 3, 3, 3, 3, 3, 3, 3, 84, 42, 85, 86, 87, 34, 88, 89, 3, + 34, 34, 69, 70, 71, 72, 3, 73, 74, 3, 75, 76, 77, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 78, + 79, 34, 80, 81, 82, 83, 84, 3, 3, 3, 3, 3, 3, 3, 3, 85, 42, 86, 87, 88, 34, 89, 90, 3, 3, 3, 3, 3, 3, 3, 3, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, @@ -957,9 +1093,9 @@ pub mod derived_property { 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 90, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 92, 34, 34, 34, 34, 93, - 94, 95, 96, 97, 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 91, 34, 34, 34, + 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 92, 93, 34, 34, 34, 34, 94, + 95, 96, 91, 97, 34, 98, 99, 100, 48, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 34, 113, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, @@ -989,20 +1125,20 @@ pub mod derived_property { 0x7f3dffffffff3dff, 0xffffffffff7fff3d, 0xffffffffff3dffff, 0x0000000007ffffff, 0xffffffff0000ffff, 0x3f3fffffffffffff, 0xfffffffffffffffe, 0xffff9fffffffffff, 0xffffffff07fffffe, 0x01ffc7ffffffffff, 0x0003ffff0003dfff, 0x0001dfff0003ffff, - 0x000fffffffffffff, 0x0000000010800000, 0xffffffff00000000, 0x00ffffffffffffff, + 0x000fffffffffffff, 0x0000000010800000, 0xffffffff00000000, 0x01ffffffffffffff, 0xffff05ffffffffff, 0x003fffffffffffff, 0x000000007fffffff, 0x001f3fffffff0000, 0xffff0fffffffffff, 0x00000000000003ff, 0xffffffff007fffff, 0x00000000001fffff, 0x0000008000000000, 0x000fffffffffffe0, 0x0000000000000fe0, 0xfc00c001fffffff8, - 0x0000003fffffffff, 0x0000000fffffffff, 0x3ffffffffc00e000, 0x00000000000001ff, + 0x0000003fffffffff, 0x0000000fffffffff, 0x3ffffffffc00e000, 0xe7ffffffffff01ff, 0x0063de0000000000, 0xffffffff3f3fffff, 0x3fffffffaaff3f3f, 0x5fdfffffffffffff, 0x1fdc1fff0fcf1fdc, 0x8002000000000000, 0x000000001fff0000, 0xf3fffd503f2ffc84, - 0xffffffff000043e0, 0xffff7fffffffffff, 0xffffffff7fffffff, 0x000c781fffffffff, - 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, 0x000000007f7f7f7f, - 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, 0xfffe7fffffffffe0, - 0x07ffffff00007fff, 0xffff000000000000, 0x000007ffffffffff, 0x0000000000001fff, - 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, 0xffffffff3fffffff, - 0x0000ffffffffffff, 0xfffffffcff800000, 0x00ff7ffffffff9ff, 0xff80000000000000, - 0x00000007fffff7bb, 0x000ffffffffffffc, 0x28fc000000000000, 0xffff003ffffffc00, + 0xffffffff000043e0, 0x00000000000001ff, 0xffff7fffffffffff, 0xffffffff7fffffff, + 0x000c781fffffffff, 0xffff20bfffffffff, 0x000080ffffffffff, 0x7f7f7f7f007fffff, + 0x000000007f7f7f7f, 0x1f3e03fe000000e0, 0xfffffffee07fffff, 0xf7ffffffffffffff, + 0xfffeffffffffffe0, 0x07ffffff00007fff, 0xffff000000000000, 0x0000ffffffffffff, + 0x0000000000001fff, 0x3fffffffffff0000, 0x00000c00ffff1fff, 0x80007fffffffffff, + 0xffffffff3fffffff, 0xfffffffcff800000, 0x03fffffffffff9ff, 0xff80000000000000, + 0x00000007fffff7bb, 0x000ffffffffffffc, 0x68fc000000000000, 0xffff003ffffffc00, 0x1fffffff0000007f, 0x0007fffffffffff0, 0x7c00ffdf00008000, 0x000001ffffffffff, 0xc47fffff00000ff7, 0x3e62ffffffffffff, 0x001c07ff38000005, 0xffff7f7f007e7e7e, 0xffff003ff7ffffff, 0x00000007ffffffff, 0xffff000fffffffff, 0x0ffffffffffff87f, @@ -1026,42 +1162,42 @@ pub mod derived_property { r5: &[ 0, 1, 2, 3, 4, 5, 4, 4, 4, 4, 6, 7, 8, 9, 10, 11, 2, 2, 12, 13, 14, 15, 4, 4, 2, 2, 2, 2, 16, 17, 4, 4, 18, 19, 20, 21, 22, 4, 23, 4, 24, 25, 26, 27, 28, 29, 30, 4, 2, 31, 32, - 32, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 33, 4, 34, 35, 36, 37, 38, 39, 40, 4, 41, 20, - 42, 43, 4, 4, 5, 44, 45, 46, 4, 4, 47, 48, 45, 49, 50, 4, 51, 4, 4, 4, 4, 4, 52, 53, 4, - 4, 4, 4, 54, 55, 56, 57, 4, 4, 4, 4, 58, 59, 60, 4, 61, 62, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 51, 4, 2, 47, 2, 2, 2, 63, 4, 4, 4, 4, 4, + 32, 15, 4, 4, 4, 4, 4, 4, 4, 33, 34, 4, 4, 35, 4, 36, 37, 38, 39, 40, 41, 42, 4, 43, 20, + 44, 45, 4, 4, 5, 46, 47, 48, 4, 4, 49, 50, 47, 51, 52, 4, 53, 4, 4, 4, 54, 4, 55, 56, 4, + 4, 4, 4, 57, 58, 59, 60, 4, 4, 4, 4, 61, 62, 63, 4, 64, 65, 66, 4, 4, 4, 4, 67, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 68, 4, 2, 49, 2, 2, 2, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 47, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 49, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 2, 2, 2, 2, 2, 2, 2, 2, 57, 20, 4, 65, 45, 66, 60, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 2, 67, 68, 69, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 60, 20, 4, 71, 47, 72, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 4, + 4, 2, 73, 74, 75, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 70, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 71, 2, 2, 2, 2, 2, - 72, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 2, 73, 74, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 75, 76, 77, 78, 79, 2, 2, 2, 2, 80, 81, 82, 83, 84, - 85, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 76, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 32, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 20, 77, 2, 2, 2, 2, 2, + 78, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 2, 79, 80, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 81, 82, 83, 84, 85, 2, 2, 2, 2, 86, 87, 88, 89, 90, + 91, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 86, 2, 63, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 87, 88, 89, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 92, 2, 69, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 93, 94, 95, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 96, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 5, 2, 2, 2, 10, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 91, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 97, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 92, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 98, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 93, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 2, 2, 2, 2, 2, 99, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 ], r6: &[ @@ -1071,24 +1207,25 @@ pub mod derived_property { 0xffff00003fffffff, 0x0fffffffff0fffff, 0xffff00ffffffffff, 0x0000000fffffffff, 0x007fffffffffffff, 0x000000ff003fffff, 0x91bffffffffffd3f, 0x007fffff003fffff, 0x000000007fffffff, 0x0037ffff00000000, 0x03ffffff003fffff, 0xc0ffffffffffffff, - 0x000ffffffeef0001, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, + 0x003ffffffeef0001, 0x1fffffff00000000, 0x000000001fffffff, 0x0000001ffffffeff, 0x003fffffffffffff, 0x0007ffff003fffff, 0x000000000003ffff, 0x00000000000001ff, - 0x0007ffffffffffff, 0x00fffffffffffff8, 0x0000fffffffffff8, 0x000001ffffff0000, - 0x0000007ffffffff8, 0x0047ffffffff0000, 0x0007fffffffffff8, 0x000000001400001e, - 0x00000ffffffbffff, 0xffff01ffbfffbd7f, 0x23edfdfffff99fe0, 0x00000003e0010000, - 0x0000000000000780, 0x0000ffffffffffff, 0x00000000000000b0, 0x00007fffffffffff, - 0x000000000f000000, 0x0000000000000010, 0x000007ffffffffff, 0x0000000003ffffff, - 0xffffffff00000000, 0x80000000ffffffff, 0x0407fffffffff801, 0xfffffffff0010000, - 0x00000000000003cf, 0x01ffffffffffffff, 0x00007ffffffffdff, 0xfffc000000000001, - 0x000000000000ffff, 0x0001fffffffffb7f, 0x0000000000000040, 0x000000000000000f, - 0x000000000000007f, 0x00003fffffff0000, 0xe0fffff80000000f, 0x000000000001001f, - 0x00000000fff80000, 0x0000000300000000, 0x00001fffffffffff, 0xffff000000000000, - 0x0fffffffffffffff, 0x1fff07ffffffffff, 0x0000000003ff01ff, 0xffffffffffdfffff, - 0xebffde64dfffffff, 0xffffffffffffffef, 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, - 0xffffff3fffffffff, 0xf7fffffff7fffffd, 0xffdfffffffdfffff, 0xffff7fffffff7fff, - 0xfffffdfffffffdff, 0x0000000000000ff7, 0x000000000000001f, 0x0af7fe96ffffffef, - 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, 0x00000000007fffff, 0xffff0003ffffffff, - 0x00000001ffffffff, 0x000000003fffffff + 0x0007ffffffffffff, 0xffff00801fffffff, 0x000000000000003f, 0x00fffffffffffff8, + 0x0000fffffffffff8, 0x000001ffffff0000, 0x0000007ffffffff8, 0x0047ffffffff0010, + 0x0007fffffffffff8, 0x000000001400001e, 0x00000ffffffbffff, 0xffff01ffbfffbd7f, + 0x23edfdfffff99fe0, 0x00000003e0010000, 0x0000000000000780, 0x0000ffffffffffff, + 0x00000000000000b0, 0x00007fffffffffff, 0x000000000f000000, 0x0000000000000010, + 0x000007ffffffffff, 0x0000000007ffffff, 0x00000fffffffffff, 0xffffffff00000000, + 0x80000000ffffffff, 0x0407fffffffff801, 0xfffffffff0010000, 0x00000000200003cf, + 0x01ffffffffffffff, 0x00007ffffffffdff, 0xfffc000000000001, 0x000000000000ffff, + 0x0001fffffffffb7f, 0xfffffdbf00000040, 0x00000000010003ff, 0x0007ffff00000000, + 0x0000000003ffffff, 0x000000000000000f, 0x000000000000007f, 0x00003fffffff0000, + 0xe0fffff80000000f, 0x000000000001001f, 0x00000000fff80000, 0x0000000300000000, + 0x0003ffffffffffff, 0xffff000000000000, 0x0fffffffffffffff, 0x1fff07ffffffffff, + 0x0000000003ff01ff, 0xffffffffffdfffff, 0xebffde64dfffffff, 0xffffffffffffffef, + 0x7bffffffdfdfe7bf, 0xfffffffffffdfc5f, 0xffffff3fffffffff, 0xf7fffffff7fffffd, + 0xffdfffffffdfffff, 0xffff7fffffff7fff, 0xfffffdfffffffdff, 0x0000000000000ff7, + 0x000000000000001f, 0x0af7fe96ffffffef, 0x5ef7f796aa96ea84, 0x0ffffbee0ffffbff, + 0x00000000007fffff, 0xffff0003ffffffff, 0x00000001ffffffff, 0x000000003fffffff ], }; @@ -1413,332 +1550,369 @@ pub mod conversions { ('\u{13ee}', ['\u{abbe}', '\0', '\0']), ('\u{13ef}', ['\u{abbf}', '\0', '\0']), ('\u{13f0}', ['\u{13f8}', '\0', '\0']), ('\u{13f1}', ['\u{13f9}', '\0', '\0']), ('\u{13f2}', ['\u{13fa}', '\0', '\0']), ('\u{13f3}', ['\u{13fb}', '\0', '\0']), ('\u{13f4}', ['\u{13fc}', '\0', - '\0']), ('\u{13f5}', ['\u{13fd}', '\0', '\0']), ('\u{1e00}', ['\u{1e01}', '\0', '\0']), - ('\u{1e02}', ['\u{1e03}', '\0', '\0']), ('\u{1e04}', ['\u{1e05}', '\0', '\0']), ('\u{1e06}', - ['\u{1e07}', '\0', '\0']), ('\u{1e08}', ['\u{1e09}', '\0', '\0']), ('\u{1e0a}', ['\u{1e0b}', - '\0', '\0']), ('\u{1e0c}', ['\u{1e0d}', '\0', '\0']), ('\u{1e0e}', ['\u{1e0f}', '\0', - '\0']), ('\u{1e10}', ['\u{1e11}', '\0', '\0']), ('\u{1e12}', ['\u{1e13}', '\0', '\0']), - ('\u{1e14}', ['\u{1e15}', '\0', '\0']), ('\u{1e16}', ['\u{1e17}', '\0', '\0']), ('\u{1e18}', - ['\u{1e19}', '\0', '\0']), ('\u{1e1a}', ['\u{1e1b}', '\0', '\0']), ('\u{1e1c}', ['\u{1e1d}', - '\0', '\0']), ('\u{1e1e}', ['\u{1e1f}', '\0', '\0']), ('\u{1e20}', ['\u{1e21}', '\0', - '\0']), ('\u{1e22}', ['\u{1e23}', '\0', '\0']), ('\u{1e24}', ['\u{1e25}', '\0', '\0']), - ('\u{1e26}', ['\u{1e27}', '\0', '\0']), ('\u{1e28}', ['\u{1e29}', '\0', '\0']), ('\u{1e2a}', - ['\u{1e2b}', '\0', '\0']), ('\u{1e2c}', ['\u{1e2d}', '\0', '\0']), ('\u{1e2e}', ['\u{1e2f}', - '\0', '\0']), ('\u{1e30}', ['\u{1e31}', '\0', '\0']), ('\u{1e32}', ['\u{1e33}', '\0', - '\0']), ('\u{1e34}', ['\u{1e35}', '\0', '\0']), ('\u{1e36}', ['\u{1e37}', '\0', '\0']), - ('\u{1e38}', ['\u{1e39}', '\0', '\0']), ('\u{1e3a}', ['\u{1e3b}', '\0', '\0']), ('\u{1e3c}', - ['\u{1e3d}', '\0', '\0']), ('\u{1e3e}', ['\u{1e3f}', '\0', '\0']), ('\u{1e40}', ['\u{1e41}', - '\0', '\0']), ('\u{1e42}', ['\u{1e43}', '\0', '\0']), ('\u{1e44}', ['\u{1e45}', '\0', - '\0']), ('\u{1e46}', ['\u{1e47}', '\0', '\0']), ('\u{1e48}', ['\u{1e49}', '\0', '\0']), - ('\u{1e4a}', ['\u{1e4b}', '\0', '\0']), ('\u{1e4c}', ['\u{1e4d}', '\0', '\0']), ('\u{1e4e}', - ['\u{1e4f}', '\0', '\0']), ('\u{1e50}', ['\u{1e51}', '\0', '\0']), ('\u{1e52}', ['\u{1e53}', - '\0', '\0']), ('\u{1e54}', ['\u{1e55}', '\0', '\0']), ('\u{1e56}', ['\u{1e57}', '\0', - '\0']), ('\u{1e58}', ['\u{1e59}', '\0', '\0']), ('\u{1e5a}', ['\u{1e5b}', '\0', '\0']), - ('\u{1e5c}', ['\u{1e5d}', '\0', '\0']), ('\u{1e5e}', ['\u{1e5f}', '\0', '\0']), ('\u{1e60}', - ['\u{1e61}', '\0', '\0']), ('\u{1e62}', ['\u{1e63}', '\0', '\0']), ('\u{1e64}', ['\u{1e65}', - '\0', '\0']), ('\u{1e66}', ['\u{1e67}', '\0', '\0']), ('\u{1e68}', ['\u{1e69}', '\0', - '\0']), ('\u{1e6a}', ['\u{1e6b}', '\0', '\0']), ('\u{1e6c}', ['\u{1e6d}', '\0', '\0']), - ('\u{1e6e}', ['\u{1e6f}', '\0', '\0']), ('\u{1e70}', ['\u{1e71}', '\0', '\0']), ('\u{1e72}', - ['\u{1e73}', '\0', '\0']), ('\u{1e74}', ['\u{1e75}', '\0', '\0']), ('\u{1e76}', ['\u{1e77}', - '\0', '\0']), ('\u{1e78}', ['\u{1e79}', '\0', '\0']), ('\u{1e7a}', ['\u{1e7b}', '\0', - '\0']), ('\u{1e7c}', ['\u{1e7d}', '\0', '\0']), ('\u{1e7e}', ['\u{1e7f}', '\0', '\0']), - ('\u{1e80}', ['\u{1e81}', '\0', '\0']), ('\u{1e82}', ['\u{1e83}', '\0', '\0']), ('\u{1e84}', - ['\u{1e85}', '\0', '\0']), ('\u{1e86}', ['\u{1e87}', '\0', '\0']), ('\u{1e88}', ['\u{1e89}', - '\0', '\0']), ('\u{1e8a}', ['\u{1e8b}', '\0', '\0']), ('\u{1e8c}', ['\u{1e8d}', '\0', - '\0']), ('\u{1e8e}', ['\u{1e8f}', '\0', '\0']), ('\u{1e90}', ['\u{1e91}', '\0', '\0']), - ('\u{1e92}', ['\u{1e93}', '\0', '\0']), ('\u{1e94}', ['\u{1e95}', '\0', '\0']), ('\u{1e9e}', - ['\u{df}', '\0', '\0']), ('\u{1ea0}', ['\u{1ea1}', '\0', '\0']), ('\u{1ea2}', ['\u{1ea3}', - '\0', '\0']), ('\u{1ea4}', ['\u{1ea5}', '\0', '\0']), ('\u{1ea6}', ['\u{1ea7}', '\0', - '\0']), ('\u{1ea8}', ['\u{1ea9}', '\0', '\0']), ('\u{1eaa}', ['\u{1eab}', '\0', '\0']), - ('\u{1eac}', ['\u{1ead}', '\0', '\0']), ('\u{1eae}', ['\u{1eaf}', '\0', '\0']), ('\u{1eb0}', - ['\u{1eb1}', '\0', '\0']), ('\u{1eb2}', ['\u{1eb3}', '\0', '\0']), ('\u{1eb4}', ['\u{1eb5}', - '\0', '\0']), ('\u{1eb6}', ['\u{1eb7}', '\0', '\0']), ('\u{1eb8}', ['\u{1eb9}', '\0', - '\0']), ('\u{1eba}', ['\u{1ebb}', '\0', '\0']), ('\u{1ebc}', ['\u{1ebd}', '\0', '\0']), - ('\u{1ebe}', ['\u{1ebf}', '\0', '\0']), ('\u{1ec0}', ['\u{1ec1}', '\0', '\0']), ('\u{1ec2}', - ['\u{1ec3}', '\0', '\0']), ('\u{1ec4}', ['\u{1ec5}', '\0', '\0']), ('\u{1ec6}', ['\u{1ec7}', - '\0', '\0']), ('\u{1ec8}', ['\u{1ec9}', '\0', '\0']), ('\u{1eca}', ['\u{1ecb}', '\0', - '\0']), ('\u{1ecc}', ['\u{1ecd}', '\0', '\0']), ('\u{1ece}', ['\u{1ecf}', '\0', '\0']), - ('\u{1ed0}', ['\u{1ed1}', '\0', '\0']), ('\u{1ed2}', ['\u{1ed3}', '\0', '\0']), ('\u{1ed4}', - ['\u{1ed5}', '\0', '\0']), ('\u{1ed6}', ['\u{1ed7}', '\0', '\0']), ('\u{1ed8}', ['\u{1ed9}', - '\0', '\0']), ('\u{1eda}', ['\u{1edb}', '\0', '\0']), ('\u{1edc}', ['\u{1edd}', '\0', - '\0']), ('\u{1ede}', ['\u{1edf}', '\0', '\0']), ('\u{1ee0}', ['\u{1ee1}', '\0', '\0']), - ('\u{1ee2}', ['\u{1ee3}', '\0', '\0']), ('\u{1ee4}', ['\u{1ee5}', '\0', '\0']), ('\u{1ee6}', - ['\u{1ee7}', '\0', '\0']), ('\u{1ee8}', ['\u{1ee9}', '\0', '\0']), ('\u{1eea}', ['\u{1eeb}', - '\0', '\0']), ('\u{1eec}', ['\u{1eed}', '\0', '\0']), ('\u{1eee}', ['\u{1eef}', '\0', - '\0']), ('\u{1ef0}', ['\u{1ef1}', '\0', '\0']), ('\u{1ef2}', ['\u{1ef3}', '\0', '\0']), - ('\u{1ef4}', ['\u{1ef5}', '\0', '\0']), ('\u{1ef6}', ['\u{1ef7}', '\0', '\0']), ('\u{1ef8}', - ['\u{1ef9}', '\0', '\0']), ('\u{1efa}', ['\u{1efb}', '\0', '\0']), ('\u{1efc}', ['\u{1efd}', - '\0', '\0']), ('\u{1efe}', ['\u{1eff}', '\0', '\0']), ('\u{1f08}', ['\u{1f00}', '\0', - '\0']), ('\u{1f09}', ['\u{1f01}', '\0', '\0']), ('\u{1f0a}', ['\u{1f02}', '\0', '\0']), - ('\u{1f0b}', ['\u{1f03}', '\0', '\0']), ('\u{1f0c}', ['\u{1f04}', '\0', '\0']), ('\u{1f0d}', - ['\u{1f05}', '\0', '\0']), ('\u{1f0e}', ['\u{1f06}', '\0', '\0']), ('\u{1f0f}', ['\u{1f07}', - '\0', '\0']), ('\u{1f18}', ['\u{1f10}', '\0', '\0']), ('\u{1f19}', ['\u{1f11}', '\0', - '\0']), ('\u{1f1a}', ['\u{1f12}', '\0', '\0']), ('\u{1f1b}', ['\u{1f13}', '\0', '\0']), - ('\u{1f1c}', ['\u{1f14}', '\0', '\0']), ('\u{1f1d}', ['\u{1f15}', '\0', '\0']), ('\u{1f28}', - ['\u{1f20}', '\0', '\0']), ('\u{1f29}', ['\u{1f21}', '\0', '\0']), ('\u{1f2a}', ['\u{1f22}', - '\0', '\0']), ('\u{1f2b}', ['\u{1f23}', '\0', '\0']), ('\u{1f2c}', ['\u{1f24}', '\0', - '\0']), ('\u{1f2d}', ['\u{1f25}', '\0', '\0']), ('\u{1f2e}', ['\u{1f26}', '\0', '\0']), - ('\u{1f2f}', ['\u{1f27}', '\0', '\0']), ('\u{1f38}', ['\u{1f30}', '\0', '\0']), ('\u{1f39}', - ['\u{1f31}', '\0', '\0']), ('\u{1f3a}', ['\u{1f32}', '\0', '\0']), ('\u{1f3b}', ['\u{1f33}', - '\0', '\0']), ('\u{1f3c}', ['\u{1f34}', '\0', '\0']), ('\u{1f3d}', ['\u{1f35}', '\0', - '\0']), ('\u{1f3e}', ['\u{1f36}', '\0', '\0']), ('\u{1f3f}', ['\u{1f37}', '\0', '\0']), - ('\u{1f48}', ['\u{1f40}', '\0', '\0']), ('\u{1f49}', ['\u{1f41}', '\0', '\0']), ('\u{1f4a}', - ['\u{1f42}', '\0', '\0']), ('\u{1f4b}', ['\u{1f43}', '\0', '\0']), ('\u{1f4c}', ['\u{1f44}', - '\0', '\0']), ('\u{1f4d}', ['\u{1f45}', '\0', '\0']), ('\u{1f59}', ['\u{1f51}', '\0', - '\0']), ('\u{1f5b}', ['\u{1f53}', '\0', '\0']), ('\u{1f5d}', ['\u{1f55}', '\0', '\0']), - ('\u{1f5f}', ['\u{1f57}', '\0', '\0']), ('\u{1f68}', ['\u{1f60}', '\0', '\0']), ('\u{1f69}', - ['\u{1f61}', '\0', '\0']), ('\u{1f6a}', ['\u{1f62}', '\0', '\0']), ('\u{1f6b}', ['\u{1f63}', - '\0', '\0']), ('\u{1f6c}', ['\u{1f64}', '\0', '\0']), ('\u{1f6d}', ['\u{1f65}', '\0', - '\0']), ('\u{1f6e}', ['\u{1f66}', '\0', '\0']), ('\u{1f6f}', ['\u{1f67}', '\0', '\0']), - ('\u{1f88}', ['\u{1f80}', '\0', '\0']), ('\u{1f89}', ['\u{1f81}', '\0', '\0']), ('\u{1f8a}', - ['\u{1f82}', '\0', '\0']), ('\u{1f8b}', ['\u{1f83}', '\0', '\0']), ('\u{1f8c}', ['\u{1f84}', - '\0', '\0']), ('\u{1f8d}', ['\u{1f85}', '\0', '\0']), ('\u{1f8e}', ['\u{1f86}', '\0', - '\0']), ('\u{1f8f}', ['\u{1f87}', '\0', '\0']), ('\u{1f98}', ['\u{1f90}', '\0', '\0']), - ('\u{1f99}', ['\u{1f91}', '\0', '\0']), ('\u{1f9a}', ['\u{1f92}', '\0', '\0']), ('\u{1f9b}', - ['\u{1f93}', '\0', '\0']), ('\u{1f9c}', ['\u{1f94}', '\0', '\0']), ('\u{1f9d}', ['\u{1f95}', - '\0', '\0']), ('\u{1f9e}', ['\u{1f96}', '\0', '\0']), ('\u{1f9f}', ['\u{1f97}', '\0', - '\0']), ('\u{1fa8}', ['\u{1fa0}', '\0', '\0']), ('\u{1fa9}', ['\u{1fa1}', '\0', '\0']), - ('\u{1faa}', ['\u{1fa2}', '\0', '\0']), ('\u{1fab}', ['\u{1fa3}', '\0', '\0']), ('\u{1fac}', - ['\u{1fa4}', '\0', '\0']), ('\u{1fad}', ['\u{1fa5}', '\0', '\0']), ('\u{1fae}', ['\u{1fa6}', - '\0', '\0']), ('\u{1faf}', ['\u{1fa7}', '\0', '\0']), ('\u{1fb8}', ['\u{1fb0}', '\0', - '\0']), ('\u{1fb9}', ['\u{1fb1}', '\0', '\0']), ('\u{1fba}', ['\u{1f70}', '\0', '\0']), - ('\u{1fbb}', ['\u{1f71}', '\0', '\0']), ('\u{1fbc}', ['\u{1fb3}', '\0', '\0']), ('\u{1fc8}', - ['\u{1f72}', '\0', '\0']), ('\u{1fc9}', ['\u{1f73}', '\0', '\0']), ('\u{1fca}', ['\u{1f74}', - '\0', '\0']), ('\u{1fcb}', ['\u{1f75}', '\0', '\0']), ('\u{1fcc}', ['\u{1fc3}', '\0', - '\0']), ('\u{1fd8}', ['\u{1fd0}', '\0', '\0']), ('\u{1fd9}', ['\u{1fd1}', '\0', '\0']), - ('\u{1fda}', ['\u{1f76}', '\0', '\0']), ('\u{1fdb}', ['\u{1f77}', '\0', '\0']), ('\u{1fe8}', - ['\u{1fe0}', '\0', '\0']), ('\u{1fe9}', ['\u{1fe1}', '\0', '\0']), ('\u{1fea}', ['\u{1f7a}', - '\0', '\0']), ('\u{1feb}', ['\u{1f7b}', '\0', '\0']), ('\u{1fec}', ['\u{1fe5}', '\0', - '\0']), ('\u{1ff8}', ['\u{1f78}', '\0', '\0']), ('\u{1ff9}', ['\u{1f79}', '\0', '\0']), - ('\u{1ffa}', ['\u{1f7c}', '\0', '\0']), ('\u{1ffb}', ['\u{1f7d}', '\0', '\0']), ('\u{1ffc}', - ['\u{1ff3}', '\0', '\0']), ('\u{2126}', ['\u{3c9}', '\0', '\0']), ('\u{212a}', ['\u{6b}', - '\0', '\0']), ('\u{212b}', ['\u{e5}', '\0', '\0']), ('\u{2132}', ['\u{214e}', '\0', '\0']), - ('\u{2160}', ['\u{2170}', '\0', '\0']), ('\u{2161}', ['\u{2171}', '\0', '\0']), ('\u{2162}', - ['\u{2172}', '\0', '\0']), ('\u{2163}', ['\u{2173}', '\0', '\0']), ('\u{2164}', ['\u{2174}', - '\0', '\0']), ('\u{2165}', ['\u{2175}', '\0', '\0']), ('\u{2166}', ['\u{2176}', '\0', - '\0']), ('\u{2167}', ['\u{2177}', '\0', '\0']), ('\u{2168}', ['\u{2178}', '\0', '\0']), - ('\u{2169}', ['\u{2179}', '\0', '\0']), ('\u{216a}', ['\u{217a}', '\0', '\0']), ('\u{216b}', - ['\u{217b}', '\0', '\0']), ('\u{216c}', ['\u{217c}', '\0', '\0']), ('\u{216d}', ['\u{217d}', - '\0', '\0']), ('\u{216e}', ['\u{217e}', '\0', '\0']), ('\u{216f}', ['\u{217f}', '\0', - '\0']), ('\u{2183}', ['\u{2184}', '\0', '\0']), ('\u{24b6}', ['\u{24d0}', '\0', '\0']), - ('\u{24b7}', ['\u{24d1}', '\0', '\0']), ('\u{24b8}', ['\u{24d2}', '\0', '\0']), ('\u{24b9}', - ['\u{24d3}', '\0', '\0']), ('\u{24ba}', ['\u{24d4}', '\0', '\0']), ('\u{24bb}', ['\u{24d5}', - '\0', '\0']), ('\u{24bc}', ['\u{24d6}', '\0', '\0']), ('\u{24bd}', ['\u{24d7}', '\0', - '\0']), ('\u{24be}', ['\u{24d8}', '\0', '\0']), ('\u{24bf}', ['\u{24d9}', '\0', '\0']), - ('\u{24c0}', ['\u{24da}', '\0', '\0']), ('\u{24c1}', ['\u{24db}', '\0', '\0']), ('\u{24c2}', - ['\u{24dc}', '\0', '\0']), ('\u{24c3}', ['\u{24dd}', '\0', '\0']), ('\u{24c4}', ['\u{24de}', - '\0', '\0']), ('\u{24c5}', ['\u{24df}', '\0', '\0']), ('\u{24c6}', ['\u{24e0}', '\0', - '\0']), ('\u{24c7}', ['\u{24e1}', '\0', '\0']), ('\u{24c8}', ['\u{24e2}', '\0', '\0']), - ('\u{24c9}', ['\u{24e3}', '\0', '\0']), ('\u{24ca}', ['\u{24e4}', '\0', '\0']), ('\u{24cb}', - ['\u{24e5}', '\0', '\0']), ('\u{24cc}', ['\u{24e6}', '\0', '\0']), ('\u{24cd}', ['\u{24e7}', - '\0', '\0']), ('\u{24ce}', ['\u{24e8}', '\0', '\0']), ('\u{24cf}', ['\u{24e9}', '\0', - '\0']), ('\u{2c00}', ['\u{2c30}', '\0', '\0']), ('\u{2c01}', ['\u{2c31}', '\0', '\0']), - ('\u{2c02}', ['\u{2c32}', '\0', '\0']), ('\u{2c03}', ['\u{2c33}', '\0', '\0']), ('\u{2c04}', - ['\u{2c34}', '\0', '\0']), ('\u{2c05}', ['\u{2c35}', '\0', '\0']), ('\u{2c06}', ['\u{2c36}', - '\0', '\0']), ('\u{2c07}', ['\u{2c37}', '\0', '\0']), ('\u{2c08}', ['\u{2c38}', '\0', - '\0']), ('\u{2c09}', ['\u{2c39}', '\0', '\0']), ('\u{2c0a}', ['\u{2c3a}', '\0', '\0']), - ('\u{2c0b}', ['\u{2c3b}', '\0', '\0']), ('\u{2c0c}', ['\u{2c3c}', '\0', '\0']), ('\u{2c0d}', - ['\u{2c3d}', '\0', '\0']), ('\u{2c0e}', ['\u{2c3e}', '\0', '\0']), ('\u{2c0f}', ['\u{2c3f}', - '\0', '\0']), ('\u{2c10}', ['\u{2c40}', '\0', '\0']), ('\u{2c11}', ['\u{2c41}', '\0', - '\0']), ('\u{2c12}', ['\u{2c42}', '\0', '\0']), ('\u{2c13}', ['\u{2c43}', '\0', '\0']), - ('\u{2c14}', ['\u{2c44}', '\0', '\0']), ('\u{2c15}', ['\u{2c45}', '\0', '\0']), ('\u{2c16}', - ['\u{2c46}', '\0', '\0']), ('\u{2c17}', ['\u{2c47}', '\0', '\0']), ('\u{2c18}', ['\u{2c48}', - '\0', '\0']), ('\u{2c19}', ['\u{2c49}', '\0', '\0']), ('\u{2c1a}', ['\u{2c4a}', '\0', - '\0']), ('\u{2c1b}', ['\u{2c4b}', '\0', '\0']), ('\u{2c1c}', ['\u{2c4c}', '\0', '\0']), - ('\u{2c1d}', ['\u{2c4d}', '\0', '\0']), ('\u{2c1e}', ['\u{2c4e}', '\0', '\0']), ('\u{2c1f}', - ['\u{2c4f}', '\0', '\0']), ('\u{2c20}', ['\u{2c50}', '\0', '\0']), ('\u{2c21}', ['\u{2c51}', - '\0', '\0']), ('\u{2c22}', ['\u{2c52}', '\0', '\0']), ('\u{2c23}', ['\u{2c53}', '\0', - '\0']), ('\u{2c24}', ['\u{2c54}', '\0', '\0']), ('\u{2c25}', ['\u{2c55}', '\0', '\0']), - ('\u{2c26}', ['\u{2c56}', '\0', '\0']), ('\u{2c27}', ['\u{2c57}', '\0', '\0']), ('\u{2c28}', - ['\u{2c58}', '\0', '\0']), ('\u{2c29}', ['\u{2c59}', '\0', '\0']), ('\u{2c2a}', ['\u{2c5a}', - '\0', '\0']), ('\u{2c2b}', ['\u{2c5b}', '\0', '\0']), ('\u{2c2c}', ['\u{2c5c}', '\0', - '\0']), ('\u{2c2d}', ['\u{2c5d}', '\0', '\0']), ('\u{2c2e}', ['\u{2c5e}', '\0', '\0']), - ('\u{2c60}', ['\u{2c61}', '\0', '\0']), ('\u{2c62}', ['\u{26b}', '\0', '\0']), ('\u{2c63}', - ['\u{1d7d}', '\0', '\0']), ('\u{2c64}', ['\u{27d}', '\0', '\0']), ('\u{2c67}', ['\u{2c68}', - '\0', '\0']), ('\u{2c69}', ['\u{2c6a}', '\0', '\0']), ('\u{2c6b}', ['\u{2c6c}', '\0', - '\0']), ('\u{2c6d}', ['\u{251}', '\0', '\0']), ('\u{2c6e}', ['\u{271}', '\0', '\0']), - ('\u{2c6f}', ['\u{250}', '\0', '\0']), ('\u{2c70}', ['\u{252}', '\0', '\0']), ('\u{2c72}', - ['\u{2c73}', '\0', '\0']), ('\u{2c75}', ['\u{2c76}', '\0', '\0']), ('\u{2c7e}', ['\u{23f}', - '\0', '\0']), ('\u{2c7f}', ['\u{240}', '\0', '\0']), ('\u{2c80}', ['\u{2c81}', '\0', '\0']), - ('\u{2c82}', ['\u{2c83}', '\0', '\0']), ('\u{2c84}', ['\u{2c85}', '\0', '\0']), ('\u{2c86}', - ['\u{2c87}', '\0', '\0']), ('\u{2c88}', ['\u{2c89}', '\0', '\0']), ('\u{2c8a}', ['\u{2c8b}', - '\0', '\0']), ('\u{2c8c}', ['\u{2c8d}', '\0', '\0']), ('\u{2c8e}', ['\u{2c8f}', '\0', - '\0']), ('\u{2c90}', ['\u{2c91}', '\0', '\0']), ('\u{2c92}', ['\u{2c93}', '\0', '\0']), - ('\u{2c94}', ['\u{2c95}', '\0', '\0']), ('\u{2c96}', ['\u{2c97}', '\0', '\0']), ('\u{2c98}', - ['\u{2c99}', '\0', '\0']), ('\u{2c9a}', ['\u{2c9b}', '\0', '\0']), ('\u{2c9c}', ['\u{2c9d}', - '\0', '\0']), ('\u{2c9e}', ['\u{2c9f}', '\0', '\0']), ('\u{2ca0}', ['\u{2ca1}', '\0', - '\0']), ('\u{2ca2}', ['\u{2ca3}', '\0', '\0']), ('\u{2ca4}', ['\u{2ca5}', '\0', '\0']), - ('\u{2ca6}', ['\u{2ca7}', '\0', '\0']), ('\u{2ca8}', ['\u{2ca9}', '\0', '\0']), ('\u{2caa}', - ['\u{2cab}', '\0', '\0']), ('\u{2cac}', ['\u{2cad}', '\0', '\0']), ('\u{2cae}', ['\u{2caf}', - '\0', '\0']), ('\u{2cb0}', ['\u{2cb1}', '\0', '\0']), ('\u{2cb2}', ['\u{2cb3}', '\0', - '\0']), ('\u{2cb4}', ['\u{2cb5}', '\0', '\0']), ('\u{2cb6}', ['\u{2cb7}', '\0', '\0']), - ('\u{2cb8}', ['\u{2cb9}', '\0', '\0']), ('\u{2cba}', ['\u{2cbb}', '\0', '\0']), ('\u{2cbc}', - ['\u{2cbd}', '\0', '\0']), ('\u{2cbe}', ['\u{2cbf}', '\0', '\0']), ('\u{2cc0}', ['\u{2cc1}', - '\0', '\0']), ('\u{2cc2}', ['\u{2cc3}', '\0', '\0']), ('\u{2cc4}', ['\u{2cc5}', '\0', - '\0']), ('\u{2cc6}', ['\u{2cc7}', '\0', '\0']), ('\u{2cc8}', ['\u{2cc9}', '\0', '\0']), - ('\u{2cca}', ['\u{2ccb}', '\0', '\0']), ('\u{2ccc}', ['\u{2ccd}', '\0', '\0']), ('\u{2cce}', - ['\u{2ccf}', '\0', '\0']), ('\u{2cd0}', ['\u{2cd1}', '\0', '\0']), ('\u{2cd2}', ['\u{2cd3}', - '\0', '\0']), ('\u{2cd4}', ['\u{2cd5}', '\0', '\0']), ('\u{2cd6}', ['\u{2cd7}', '\0', - '\0']), ('\u{2cd8}', ['\u{2cd9}', '\0', '\0']), ('\u{2cda}', ['\u{2cdb}', '\0', '\0']), - ('\u{2cdc}', ['\u{2cdd}', '\0', '\0']), ('\u{2cde}', ['\u{2cdf}', '\0', '\0']), ('\u{2ce0}', - ['\u{2ce1}', '\0', '\0']), ('\u{2ce2}', ['\u{2ce3}', '\0', '\0']), ('\u{2ceb}', ['\u{2cec}', - '\0', '\0']), ('\u{2ced}', ['\u{2cee}', '\0', '\0']), ('\u{2cf2}', ['\u{2cf3}', '\0', - '\0']), ('\u{a640}', ['\u{a641}', '\0', '\0']), ('\u{a642}', ['\u{a643}', '\0', '\0']), - ('\u{a644}', ['\u{a645}', '\0', '\0']), ('\u{a646}', ['\u{a647}', '\0', '\0']), ('\u{a648}', - ['\u{a649}', '\0', '\0']), ('\u{a64a}', ['\u{a64b}', '\0', '\0']), ('\u{a64c}', ['\u{a64d}', - '\0', '\0']), ('\u{a64e}', ['\u{a64f}', '\0', '\0']), ('\u{a650}', ['\u{a651}', '\0', - '\0']), ('\u{a652}', ['\u{a653}', '\0', '\0']), ('\u{a654}', ['\u{a655}', '\0', '\0']), - ('\u{a656}', ['\u{a657}', '\0', '\0']), ('\u{a658}', ['\u{a659}', '\0', '\0']), ('\u{a65a}', - ['\u{a65b}', '\0', '\0']), ('\u{a65c}', ['\u{a65d}', '\0', '\0']), ('\u{a65e}', ['\u{a65f}', - '\0', '\0']), ('\u{a660}', ['\u{a661}', '\0', '\0']), ('\u{a662}', ['\u{a663}', '\0', - '\0']), ('\u{a664}', ['\u{a665}', '\0', '\0']), ('\u{a666}', ['\u{a667}', '\0', '\0']), - ('\u{a668}', ['\u{a669}', '\0', '\0']), ('\u{a66a}', ['\u{a66b}', '\0', '\0']), ('\u{a66c}', - ['\u{a66d}', '\0', '\0']), ('\u{a680}', ['\u{a681}', '\0', '\0']), ('\u{a682}', ['\u{a683}', - '\0', '\0']), ('\u{a684}', ['\u{a685}', '\0', '\0']), ('\u{a686}', ['\u{a687}', '\0', - '\0']), ('\u{a688}', ['\u{a689}', '\0', '\0']), ('\u{a68a}', ['\u{a68b}', '\0', '\0']), - ('\u{a68c}', ['\u{a68d}', '\0', '\0']), ('\u{a68e}', ['\u{a68f}', '\0', '\0']), ('\u{a690}', - ['\u{a691}', '\0', '\0']), ('\u{a692}', ['\u{a693}', '\0', '\0']), ('\u{a694}', ['\u{a695}', - '\0', '\0']), ('\u{a696}', ['\u{a697}', '\0', '\0']), ('\u{a698}', ['\u{a699}', '\0', - '\0']), ('\u{a69a}', ['\u{a69b}', '\0', '\0']), ('\u{a722}', ['\u{a723}', '\0', '\0']), - ('\u{a724}', ['\u{a725}', '\0', '\0']), ('\u{a726}', ['\u{a727}', '\0', '\0']), ('\u{a728}', - ['\u{a729}', '\0', '\0']), ('\u{a72a}', ['\u{a72b}', '\0', '\0']), ('\u{a72c}', ['\u{a72d}', - '\0', '\0']), ('\u{a72e}', ['\u{a72f}', '\0', '\0']), ('\u{a732}', ['\u{a733}', '\0', - '\0']), ('\u{a734}', ['\u{a735}', '\0', '\0']), ('\u{a736}', ['\u{a737}', '\0', '\0']), - ('\u{a738}', ['\u{a739}', '\0', '\0']), ('\u{a73a}', ['\u{a73b}', '\0', '\0']), ('\u{a73c}', - ['\u{a73d}', '\0', '\0']), ('\u{a73e}', ['\u{a73f}', '\0', '\0']), ('\u{a740}', ['\u{a741}', - '\0', '\0']), ('\u{a742}', ['\u{a743}', '\0', '\0']), ('\u{a744}', ['\u{a745}', '\0', - '\0']), ('\u{a746}', ['\u{a747}', '\0', '\0']), ('\u{a748}', ['\u{a749}', '\0', '\0']), - ('\u{a74a}', ['\u{a74b}', '\0', '\0']), ('\u{a74c}', ['\u{a74d}', '\0', '\0']), ('\u{a74e}', - ['\u{a74f}', '\0', '\0']), ('\u{a750}', ['\u{a751}', '\0', '\0']), ('\u{a752}', ['\u{a753}', - '\0', '\0']), ('\u{a754}', ['\u{a755}', '\0', '\0']), ('\u{a756}', ['\u{a757}', '\0', - '\0']), ('\u{a758}', ['\u{a759}', '\0', '\0']), ('\u{a75a}', ['\u{a75b}', '\0', '\0']), - ('\u{a75c}', ['\u{a75d}', '\0', '\0']), ('\u{a75e}', ['\u{a75f}', '\0', '\0']), ('\u{a760}', - ['\u{a761}', '\0', '\0']), ('\u{a762}', ['\u{a763}', '\0', '\0']), ('\u{a764}', ['\u{a765}', - '\0', '\0']), ('\u{a766}', ['\u{a767}', '\0', '\0']), ('\u{a768}', ['\u{a769}', '\0', - '\0']), ('\u{a76a}', ['\u{a76b}', '\0', '\0']), ('\u{a76c}', ['\u{a76d}', '\0', '\0']), - ('\u{a76e}', ['\u{a76f}', '\0', '\0']), ('\u{a779}', ['\u{a77a}', '\0', '\0']), ('\u{a77b}', - ['\u{a77c}', '\0', '\0']), ('\u{a77d}', ['\u{1d79}', '\0', '\0']), ('\u{a77e}', ['\u{a77f}', - '\0', '\0']), ('\u{a780}', ['\u{a781}', '\0', '\0']), ('\u{a782}', ['\u{a783}', '\0', - '\0']), ('\u{a784}', ['\u{a785}', '\0', '\0']), ('\u{a786}', ['\u{a787}', '\0', '\0']), - ('\u{a78b}', ['\u{a78c}', '\0', '\0']), ('\u{a78d}', ['\u{265}', '\0', '\0']), ('\u{a790}', - ['\u{a791}', '\0', '\0']), ('\u{a792}', ['\u{a793}', '\0', '\0']), ('\u{a796}', ['\u{a797}', - '\0', '\0']), ('\u{a798}', ['\u{a799}', '\0', '\0']), ('\u{a79a}', ['\u{a79b}', '\0', - '\0']), ('\u{a79c}', ['\u{a79d}', '\0', '\0']), ('\u{a79e}', ['\u{a79f}', '\0', '\0']), - ('\u{a7a0}', ['\u{a7a1}', '\0', '\0']), ('\u{a7a2}', ['\u{a7a3}', '\0', '\0']), ('\u{a7a4}', - ['\u{a7a5}', '\0', '\0']), ('\u{a7a6}', ['\u{a7a7}', '\0', '\0']), ('\u{a7a8}', ['\u{a7a9}', - '\0', '\0']), ('\u{a7aa}', ['\u{266}', '\0', '\0']), ('\u{a7ab}', ['\u{25c}', '\0', '\0']), - ('\u{a7ac}', ['\u{261}', '\0', '\0']), ('\u{a7ad}', ['\u{26c}', '\0', '\0']), ('\u{a7ae}', - ['\u{26a}', '\0', '\0']), ('\u{a7b0}', ['\u{29e}', '\0', '\0']), ('\u{a7b1}', ['\u{287}', - '\0', '\0']), ('\u{a7b2}', ['\u{29d}', '\0', '\0']), ('\u{a7b3}', ['\u{ab53}', '\0', '\0']), - ('\u{a7b4}', ['\u{a7b5}', '\0', '\0']), ('\u{a7b6}', ['\u{a7b7}', '\0', '\0']), ('\u{ff21}', - ['\u{ff41}', '\0', '\0']), ('\u{ff22}', ['\u{ff42}', '\0', '\0']), ('\u{ff23}', ['\u{ff43}', - '\0', '\0']), ('\u{ff24}', ['\u{ff44}', '\0', '\0']), ('\u{ff25}', ['\u{ff45}', '\0', - '\0']), ('\u{ff26}', ['\u{ff46}', '\0', '\0']), ('\u{ff27}', ['\u{ff47}', '\0', '\0']), - ('\u{ff28}', ['\u{ff48}', '\0', '\0']), ('\u{ff29}', ['\u{ff49}', '\0', '\0']), ('\u{ff2a}', - ['\u{ff4a}', '\0', '\0']), ('\u{ff2b}', ['\u{ff4b}', '\0', '\0']), ('\u{ff2c}', ['\u{ff4c}', - '\0', '\0']), ('\u{ff2d}', ['\u{ff4d}', '\0', '\0']), ('\u{ff2e}', ['\u{ff4e}', '\0', - '\0']), ('\u{ff2f}', ['\u{ff4f}', '\0', '\0']), ('\u{ff30}', ['\u{ff50}', '\0', '\0']), - ('\u{ff31}', ['\u{ff51}', '\0', '\0']), ('\u{ff32}', ['\u{ff52}', '\0', '\0']), ('\u{ff33}', - ['\u{ff53}', '\0', '\0']), ('\u{ff34}', ['\u{ff54}', '\0', '\0']), ('\u{ff35}', ['\u{ff55}', - '\0', '\0']), ('\u{ff36}', ['\u{ff56}', '\0', '\0']), ('\u{ff37}', ['\u{ff57}', '\0', - '\0']), ('\u{ff38}', ['\u{ff58}', '\0', '\0']), ('\u{ff39}', ['\u{ff59}', '\0', '\0']), - ('\u{ff3a}', ['\u{ff5a}', '\0', '\0']), ('\u{10400}', ['\u{10428}', '\0', '\0']), - ('\u{10401}', ['\u{10429}', '\0', '\0']), ('\u{10402}', ['\u{1042a}', '\0', '\0']), - ('\u{10403}', ['\u{1042b}', '\0', '\0']), ('\u{10404}', ['\u{1042c}', '\0', '\0']), - ('\u{10405}', ['\u{1042d}', '\0', '\0']), ('\u{10406}', ['\u{1042e}', '\0', '\0']), - ('\u{10407}', ['\u{1042f}', '\0', '\0']), ('\u{10408}', ['\u{10430}', '\0', '\0']), - ('\u{10409}', ['\u{10431}', '\0', '\0']), ('\u{1040a}', ['\u{10432}', '\0', '\0']), - ('\u{1040b}', ['\u{10433}', '\0', '\0']), ('\u{1040c}', ['\u{10434}', '\0', '\0']), - ('\u{1040d}', ['\u{10435}', '\0', '\0']), ('\u{1040e}', ['\u{10436}', '\0', '\0']), - ('\u{1040f}', ['\u{10437}', '\0', '\0']), ('\u{10410}', ['\u{10438}', '\0', '\0']), - ('\u{10411}', ['\u{10439}', '\0', '\0']), ('\u{10412}', ['\u{1043a}', '\0', '\0']), - ('\u{10413}', ['\u{1043b}', '\0', '\0']), ('\u{10414}', ['\u{1043c}', '\0', '\0']), - ('\u{10415}', ['\u{1043d}', '\0', '\0']), ('\u{10416}', ['\u{1043e}', '\0', '\0']), - ('\u{10417}', ['\u{1043f}', '\0', '\0']), ('\u{10418}', ['\u{10440}', '\0', '\0']), - ('\u{10419}', ['\u{10441}', '\0', '\0']), ('\u{1041a}', ['\u{10442}', '\0', '\0']), - ('\u{1041b}', ['\u{10443}', '\0', '\0']), ('\u{1041c}', ['\u{10444}', '\0', '\0']), - ('\u{1041d}', ['\u{10445}', '\0', '\0']), ('\u{1041e}', ['\u{10446}', '\0', '\0']), - ('\u{1041f}', ['\u{10447}', '\0', '\0']), ('\u{10420}', ['\u{10448}', '\0', '\0']), - ('\u{10421}', ['\u{10449}', '\0', '\0']), ('\u{10422}', ['\u{1044a}', '\0', '\0']), - ('\u{10423}', ['\u{1044b}', '\0', '\0']), ('\u{10424}', ['\u{1044c}', '\0', '\0']), - ('\u{10425}', ['\u{1044d}', '\0', '\0']), ('\u{10426}', ['\u{1044e}', '\0', '\0']), - ('\u{10427}', ['\u{1044f}', '\0', '\0']), ('\u{104b0}', ['\u{104d8}', '\0', '\0']), - ('\u{104b1}', ['\u{104d9}', '\0', '\0']), ('\u{104b2}', ['\u{104da}', '\0', '\0']), - ('\u{104b3}', ['\u{104db}', '\0', '\0']), ('\u{104b4}', ['\u{104dc}', '\0', '\0']), - ('\u{104b5}', ['\u{104dd}', '\0', '\0']), ('\u{104b6}', ['\u{104de}', '\0', '\0']), - ('\u{104b7}', ['\u{104df}', '\0', '\0']), ('\u{104b8}', ['\u{104e0}', '\0', '\0']), - ('\u{104b9}', ['\u{104e1}', '\0', '\0']), ('\u{104ba}', ['\u{104e2}', '\0', '\0']), - ('\u{104bb}', ['\u{104e3}', '\0', '\0']), ('\u{104bc}', ['\u{104e4}', '\0', '\0']), - ('\u{104bd}', ['\u{104e5}', '\0', '\0']), ('\u{104be}', ['\u{104e6}', '\0', '\0']), - ('\u{104bf}', ['\u{104e7}', '\0', '\0']), ('\u{104c0}', ['\u{104e8}', '\0', '\0']), - ('\u{104c1}', ['\u{104e9}', '\0', '\0']), ('\u{104c2}', ['\u{104ea}', '\0', '\0']), - ('\u{104c3}', ['\u{104eb}', '\0', '\0']), ('\u{104c4}', ['\u{104ec}', '\0', '\0']), - ('\u{104c5}', ['\u{104ed}', '\0', '\0']), ('\u{104c6}', ['\u{104ee}', '\0', '\0']), - ('\u{104c7}', ['\u{104ef}', '\0', '\0']), ('\u{104c8}', ['\u{104f0}', '\0', '\0']), - ('\u{104c9}', ['\u{104f1}', '\0', '\0']), ('\u{104ca}', ['\u{104f2}', '\0', '\0']), - ('\u{104cb}', ['\u{104f3}', '\0', '\0']), ('\u{104cc}', ['\u{104f4}', '\0', '\0']), - ('\u{104cd}', ['\u{104f5}', '\0', '\0']), ('\u{104ce}', ['\u{104f6}', '\0', '\0']), - ('\u{104cf}', ['\u{104f7}', '\0', '\0']), ('\u{104d0}', ['\u{104f8}', '\0', '\0']), - ('\u{104d1}', ['\u{104f9}', '\0', '\0']), ('\u{104d2}', ['\u{104fa}', '\0', '\0']), - ('\u{104d3}', ['\u{104fb}', '\0', '\0']), ('\u{10c80}', ['\u{10cc0}', '\0', '\0']), - ('\u{10c81}', ['\u{10cc1}', '\0', '\0']), ('\u{10c82}', ['\u{10cc2}', '\0', '\0']), - ('\u{10c83}', ['\u{10cc3}', '\0', '\0']), ('\u{10c84}', ['\u{10cc4}', '\0', '\0']), - ('\u{10c85}', ['\u{10cc5}', '\0', '\0']), ('\u{10c86}', ['\u{10cc6}', '\0', '\0']), - ('\u{10c87}', ['\u{10cc7}', '\0', '\0']), ('\u{10c88}', ['\u{10cc8}', '\0', '\0']), - ('\u{10c89}', ['\u{10cc9}', '\0', '\0']), ('\u{10c8a}', ['\u{10cca}', '\0', '\0']), - ('\u{10c8b}', ['\u{10ccb}', '\0', '\0']), ('\u{10c8c}', ['\u{10ccc}', '\0', '\0']), - ('\u{10c8d}', ['\u{10ccd}', '\0', '\0']), ('\u{10c8e}', ['\u{10cce}', '\0', '\0']), - ('\u{10c8f}', ['\u{10ccf}', '\0', '\0']), ('\u{10c90}', ['\u{10cd0}', '\0', '\0']), - ('\u{10c91}', ['\u{10cd1}', '\0', '\0']), ('\u{10c92}', ['\u{10cd2}', '\0', '\0']), - ('\u{10c93}', ['\u{10cd3}', '\0', '\0']), ('\u{10c94}', ['\u{10cd4}', '\0', '\0']), - ('\u{10c95}', ['\u{10cd5}', '\0', '\0']), ('\u{10c96}', ['\u{10cd6}', '\0', '\0']), - ('\u{10c97}', ['\u{10cd7}', '\0', '\0']), ('\u{10c98}', ['\u{10cd8}', '\0', '\0']), - ('\u{10c99}', ['\u{10cd9}', '\0', '\0']), ('\u{10c9a}', ['\u{10cda}', '\0', '\0']), - ('\u{10c9b}', ['\u{10cdb}', '\0', '\0']), ('\u{10c9c}', ['\u{10cdc}', '\0', '\0']), - ('\u{10c9d}', ['\u{10cdd}', '\0', '\0']), ('\u{10c9e}', ['\u{10cde}', '\0', '\0']), - ('\u{10c9f}', ['\u{10cdf}', '\0', '\0']), ('\u{10ca0}', ['\u{10ce0}', '\0', '\0']), - ('\u{10ca1}', ['\u{10ce1}', '\0', '\0']), ('\u{10ca2}', ['\u{10ce2}', '\0', '\0']), - ('\u{10ca3}', ['\u{10ce3}', '\0', '\0']), ('\u{10ca4}', ['\u{10ce4}', '\0', '\0']), - ('\u{10ca5}', ['\u{10ce5}', '\0', '\0']), ('\u{10ca6}', ['\u{10ce6}', '\0', '\0']), - ('\u{10ca7}', ['\u{10ce7}', '\0', '\0']), ('\u{10ca8}', ['\u{10ce8}', '\0', '\0']), - ('\u{10ca9}', ['\u{10ce9}', '\0', '\0']), ('\u{10caa}', ['\u{10cea}', '\0', '\0']), - ('\u{10cab}', ['\u{10ceb}', '\0', '\0']), ('\u{10cac}', ['\u{10cec}', '\0', '\0']), - ('\u{10cad}', ['\u{10ced}', '\0', '\0']), ('\u{10cae}', ['\u{10cee}', '\0', '\0']), - ('\u{10caf}', ['\u{10cef}', '\0', '\0']), ('\u{10cb0}', ['\u{10cf0}', '\0', '\0']), - ('\u{10cb1}', ['\u{10cf1}', '\0', '\0']), ('\u{10cb2}', ['\u{10cf2}', '\0', '\0']), - ('\u{118a0}', ['\u{118c0}', '\0', '\0']), ('\u{118a1}', ['\u{118c1}', '\0', '\0']), - ('\u{118a2}', ['\u{118c2}', '\0', '\0']), ('\u{118a3}', ['\u{118c3}', '\0', '\0']), - ('\u{118a4}', ['\u{118c4}', '\0', '\0']), ('\u{118a5}', ['\u{118c5}', '\0', '\0']), - ('\u{118a6}', ['\u{118c6}', '\0', '\0']), ('\u{118a7}', ['\u{118c7}', '\0', '\0']), - ('\u{118a8}', ['\u{118c8}', '\0', '\0']), ('\u{118a9}', ['\u{118c9}', '\0', '\0']), - ('\u{118aa}', ['\u{118ca}', '\0', '\0']), ('\u{118ab}', ['\u{118cb}', '\0', '\0']), - ('\u{118ac}', ['\u{118cc}', '\0', '\0']), ('\u{118ad}', ['\u{118cd}', '\0', '\0']), - ('\u{118ae}', ['\u{118ce}', '\0', '\0']), ('\u{118af}', ['\u{118cf}', '\0', '\0']), - ('\u{118b0}', ['\u{118d0}', '\0', '\0']), ('\u{118b1}', ['\u{118d1}', '\0', '\0']), - ('\u{118b2}', ['\u{118d2}', '\0', '\0']), ('\u{118b3}', ['\u{118d3}', '\0', '\0']), - ('\u{118b4}', ['\u{118d4}', '\0', '\0']), ('\u{118b5}', ['\u{118d5}', '\0', '\0']), - ('\u{118b6}', ['\u{118d6}', '\0', '\0']), ('\u{118b7}', ['\u{118d7}', '\0', '\0']), - ('\u{118b8}', ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']), - ('\u{118ba}', ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']), - ('\u{118bc}', ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']), - ('\u{118be}', ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']), - ('\u{1e900}', ['\u{1e922}', '\0', '\0']), ('\u{1e901}', ['\u{1e923}', '\0', '\0']), - ('\u{1e902}', ['\u{1e924}', '\0', '\0']), ('\u{1e903}', ['\u{1e925}', '\0', '\0']), - ('\u{1e904}', ['\u{1e926}', '\0', '\0']), ('\u{1e905}', ['\u{1e927}', '\0', '\0']), - ('\u{1e906}', ['\u{1e928}', '\0', '\0']), ('\u{1e907}', ['\u{1e929}', '\0', '\0']), - ('\u{1e908}', ['\u{1e92a}', '\0', '\0']), ('\u{1e909}', ['\u{1e92b}', '\0', '\0']), - ('\u{1e90a}', ['\u{1e92c}', '\0', '\0']), ('\u{1e90b}', ['\u{1e92d}', '\0', '\0']), - ('\u{1e90c}', ['\u{1e92e}', '\0', '\0']), ('\u{1e90d}', ['\u{1e92f}', '\0', '\0']), - ('\u{1e90e}', ['\u{1e930}', '\0', '\0']), ('\u{1e90f}', ['\u{1e931}', '\0', '\0']), - ('\u{1e910}', ['\u{1e932}', '\0', '\0']), ('\u{1e911}', ['\u{1e933}', '\0', '\0']), - ('\u{1e912}', ['\u{1e934}', '\0', '\0']), ('\u{1e913}', ['\u{1e935}', '\0', '\0']), - ('\u{1e914}', ['\u{1e936}', '\0', '\0']), ('\u{1e915}', ['\u{1e937}', '\0', '\0']), - ('\u{1e916}', ['\u{1e938}', '\0', '\0']), ('\u{1e917}', ['\u{1e939}', '\0', '\0']), - ('\u{1e918}', ['\u{1e93a}', '\0', '\0']), ('\u{1e919}', ['\u{1e93b}', '\0', '\0']), - ('\u{1e91a}', ['\u{1e93c}', '\0', '\0']), ('\u{1e91b}', ['\u{1e93d}', '\0', '\0']), - ('\u{1e91c}', ['\u{1e93e}', '\0', '\0']), ('\u{1e91d}', ['\u{1e93f}', '\0', '\0']), - ('\u{1e91e}', ['\u{1e940}', '\0', '\0']), ('\u{1e91f}', ['\u{1e941}', '\0', '\0']), - ('\u{1e920}', ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0']) + '\0']), ('\u{13f5}', ['\u{13fd}', '\0', '\0']), ('\u{1c90}', ['\u{10d0}', '\0', '\0']), + ('\u{1c91}', ['\u{10d1}', '\0', '\0']), ('\u{1c92}', ['\u{10d2}', '\0', '\0']), ('\u{1c93}', + ['\u{10d3}', '\0', '\0']), ('\u{1c94}', ['\u{10d4}', '\0', '\0']), ('\u{1c95}', ['\u{10d5}', + '\0', '\0']), ('\u{1c96}', ['\u{10d6}', '\0', '\0']), ('\u{1c97}', ['\u{10d7}', '\0', + '\0']), ('\u{1c98}', ['\u{10d8}', '\0', '\0']), ('\u{1c99}', ['\u{10d9}', '\0', '\0']), + ('\u{1c9a}', ['\u{10da}', '\0', '\0']), ('\u{1c9b}', ['\u{10db}', '\0', '\0']), ('\u{1c9c}', + ['\u{10dc}', '\0', '\0']), ('\u{1c9d}', ['\u{10dd}', '\0', '\0']), ('\u{1c9e}', ['\u{10de}', + '\0', '\0']), ('\u{1c9f}', ['\u{10df}', '\0', '\0']), ('\u{1ca0}', ['\u{10e0}', '\0', + '\0']), ('\u{1ca1}', ['\u{10e1}', '\0', '\0']), ('\u{1ca2}', ['\u{10e2}', '\0', '\0']), + ('\u{1ca3}', ['\u{10e3}', '\0', '\0']), ('\u{1ca4}', ['\u{10e4}', '\0', '\0']), ('\u{1ca5}', + ['\u{10e5}', '\0', '\0']), ('\u{1ca6}', ['\u{10e6}', '\0', '\0']), ('\u{1ca7}', ['\u{10e7}', + '\0', '\0']), ('\u{1ca8}', ['\u{10e8}', '\0', '\0']), ('\u{1ca9}', ['\u{10e9}', '\0', + '\0']), ('\u{1caa}', ['\u{10ea}', '\0', '\0']), ('\u{1cab}', ['\u{10eb}', '\0', '\0']), + ('\u{1cac}', ['\u{10ec}', '\0', '\0']), ('\u{1cad}', ['\u{10ed}', '\0', '\0']), ('\u{1cae}', + ['\u{10ee}', '\0', '\0']), ('\u{1caf}', ['\u{10ef}', '\0', '\0']), ('\u{1cb0}', ['\u{10f0}', + '\0', '\0']), ('\u{1cb1}', ['\u{10f1}', '\0', '\0']), ('\u{1cb2}', ['\u{10f2}', '\0', + '\0']), ('\u{1cb3}', ['\u{10f3}', '\0', '\0']), ('\u{1cb4}', ['\u{10f4}', '\0', '\0']), + ('\u{1cb5}', ['\u{10f5}', '\0', '\0']), ('\u{1cb6}', ['\u{10f6}', '\0', '\0']), ('\u{1cb7}', + ['\u{10f7}', '\0', '\0']), ('\u{1cb8}', ['\u{10f8}', '\0', '\0']), ('\u{1cb9}', ['\u{10f9}', + '\0', '\0']), ('\u{1cba}', ['\u{10fa}', '\0', '\0']), ('\u{1cbd}', ['\u{10fd}', '\0', + '\0']), ('\u{1cbe}', ['\u{10fe}', '\0', '\0']), ('\u{1cbf}', ['\u{10ff}', '\0', '\0']), + ('\u{1e00}', ['\u{1e01}', '\0', '\0']), ('\u{1e02}', ['\u{1e03}', '\0', '\0']), ('\u{1e04}', + ['\u{1e05}', '\0', '\0']), ('\u{1e06}', ['\u{1e07}', '\0', '\0']), ('\u{1e08}', ['\u{1e09}', + '\0', '\0']), ('\u{1e0a}', ['\u{1e0b}', '\0', '\0']), ('\u{1e0c}', ['\u{1e0d}', '\0', + '\0']), ('\u{1e0e}', ['\u{1e0f}', '\0', '\0']), ('\u{1e10}', ['\u{1e11}', '\0', '\0']), + ('\u{1e12}', ['\u{1e13}', '\0', '\0']), ('\u{1e14}', ['\u{1e15}', '\0', '\0']), ('\u{1e16}', + ['\u{1e17}', '\0', '\0']), ('\u{1e18}', ['\u{1e19}', '\0', '\0']), ('\u{1e1a}', ['\u{1e1b}', + '\0', '\0']), ('\u{1e1c}', ['\u{1e1d}', '\0', '\0']), ('\u{1e1e}', ['\u{1e1f}', '\0', + '\0']), ('\u{1e20}', ['\u{1e21}', '\0', '\0']), ('\u{1e22}', ['\u{1e23}', '\0', '\0']), + ('\u{1e24}', ['\u{1e25}', '\0', '\0']), ('\u{1e26}', ['\u{1e27}', '\0', '\0']), ('\u{1e28}', + ['\u{1e29}', '\0', '\0']), ('\u{1e2a}', ['\u{1e2b}', '\0', '\0']), ('\u{1e2c}', ['\u{1e2d}', + '\0', '\0']), ('\u{1e2e}', ['\u{1e2f}', '\0', '\0']), ('\u{1e30}', ['\u{1e31}', '\0', + '\0']), ('\u{1e32}', ['\u{1e33}', '\0', '\0']), ('\u{1e34}', ['\u{1e35}', '\0', '\0']), + ('\u{1e36}', ['\u{1e37}', '\0', '\0']), ('\u{1e38}', ['\u{1e39}', '\0', '\0']), ('\u{1e3a}', + ['\u{1e3b}', '\0', '\0']), ('\u{1e3c}', ['\u{1e3d}', '\0', '\0']), ('\u{1e3e}', ['\u{1e3f}', + '\0', '\0']), ('\u{1e40}', ['\u{1e41}', '\0', '\0']), ('\u{1e42}', ['\u{1e43}', '\0', + '\0']), ('\u{1e44}', ['\u{1e45}', '\0', '\0']), ('\u{1e46}', ['\u{1e47}', '\0', '\0']), + ('\u{1e48}', ['\u{1e49}', '\0', '\0']), ('\u{1e4a}', ['\u{1e4b}', '\0', '\0']), ('\u{1e4c}', + ['\u{1e4d}', '\0', '\0']), ('\u{1e4e}', ['\u{1e4f}', '\0', '\0']), ('\u{1e50}', ['\u{1e51}', + '\0', '\0']), ('\u{1e52}', ['\u{1e53}', '\0', '\0']), ('\u{1e54}', ['\u{1e55}', '\0', + '\0']), ('\u{1e56}', ['\u{1e57}', '\0', '\0']), ('\u{1e58}', ['\u{1e59}', '\0', '\0']), + ('\u{1e5a}', ['\u{1e5b}', '\0', '\0']), ('\u{1e5c}', ['\u{1e5d}', '\0', '\0']), ('\u{1e5e}', + ['\u{1e5f}', '\0', '\0']), ('\u{1e60}', ['\u{1e61}', '\0', '\0']), ('\u{1e62}', ['\u{1e63}', + '\0', '\0']), ('\u{1e64}', ['\u{1e65}', '\0', '\0']), ('\u{1e66}', ['\u{1e67}', '\0', + '\0']), ('\u{1e68}', ['\u{1e69}', '\0', '\0']), ('\u{1e6a}', ['\u{1e6b}', '\0', '\0']), + ('\u{1e6c}', ['\u{1e6d}', '\0', '\0']), ('\u{1e6e}', ['\u{1e6f}', '\0', '\0']), ('\u{1e70}', + ['\u{1e71}', '\0', '\0']), ('\u{1e72}', ['\u{1e73}', '\0', '\0']), ('\u{1e74}', ['\u{1e75}', + '\0', '\0']), ('\u{1e76}', ['\u{1e77}', '\0', '\0']), ('\u{1e78}', ['\u{1e79}', '\0', + '\0']), ('\u{1e7a}', ['\u{1e7b}', '\0', '\0']), ('\u{1e7c}', ['\u{1e7d}', '\0', '\0']), + ('\u{1e7e}', ['\u{1e7f}', '\0', '\0']), ('\u{1e80}', ['\u{1e81}', '\0', '\0']), ('\u{1e82}', + ['\u{1e83}', '\0', '\0']), ('\u{1e84}', ['\u{1e85}', '\0', '\0']), ('\u{1e86}', ['\u{1e87}', + '\0', '\0']), ('\u{1e88}', ['\u{1e89}', '\0', '\0']), ('\u{1e8a}', ['\u{1e8b}', '\0', + '\0']), ('\u{1e8c}', ['\u{1e8d}', '\0', '\0']), ('\u{1e8e}', ['\u{1e8f}', '\0', '\0']), + ('\u{1e90}', ['\u{1e91}', '\0', '\0']), ('\u{1e92}', ['\u{1e93}', '\0', '\0']), ('\u{1e94}', + ['\u{1e95}', '\0', '\0']), ('\u{1e9e}', ['\u{df}', '\0', '\0']), ('\u{1ea0}', ['\u{1ea1}', + '\0', '\0']), ('\u{1ea2}', ['\u{1ea3}', '\0', '\0']), ('\u{1ea4}', ['\u{1ea5}', '\0', + '\0']), ('\u{1ea6}', ['\u{1ea7}', '\0', '\0']), ('\u{1ea8}', ['\u{1ea9}', '\0', '\0']), + ('\u{1eaa}', ['\u{1eab}', '\0', '\0']), ('\u{1eac}', ['\u{1ead}', '\0', '\0']), ('\u{1eae}', + ['\u{1eaf}', '\0', '\0']), ('\u{1eb0}', ['\u{1eb1}', '\0', '\0']), ('\u{1eb2}', ['\u{1eb3}', + '\0', '\0']), ('\u{1eb4}', ['\u{1eb5}', '\0', '\0']), ('\u{1eb6}', ['\u{1eb7}', '\0', + '\0']), ('\u{1eb8}', ['\u{1eb9}', '\0', '\0']), ('\u{1eba}', ['\u{1ebb}', '\0', '\0']), + ('\u{1ebc}', ['\u{1ebd}', '\0', '\0']), ('\u{1ebe}', ['\u{1ebf}', '\0', '\0']), ('\u{1ec0}', + ['\u{1ec1}', '\0', '\0']), ('\u{1ec2}', ['\u{1ec3}', '\0', '\0']), ('\u{1ec4}', ['\u{1ec5}', + '\0', '\0']), ('\u{1ec6}', ['\u{1ec7}', '\0', '\0']), ('\u{1ec8}', ['\u{1ec9}', '\0', + '\0']), ('\u{1eca}', ['\u{1ecb}', '\0', '\0']), ('\u{1ecc}', ['\u{1ecd}', '\0', '\0']), + ('\u{1ece}', ['\u{1ecf}', '\0', '\0']), ('\u{1ed0}', ['\u{1ed1}', '\0', '\0']), ('\u{1ed2}', + ['\u{1ed3}', '\0', '\0']), ('\u{1ed4}', ['\u{1ed5}', '\0', '\0']), ('\u{1ed6}', ['\u{1ed7}', + '\0', '\0']), ('\u{1ed8}', ['\u{1ed9}', '\0', '\0']), ('\u{1eda}', ['\u{1edb}', '\0', + '\0']), ('\u{1edc}', ['\u{1edd}', '\0', '\0']), ('\u{1ede}', ['\u{1edf}', '\0', '\0']), + ('\u{1ee0}', ['\u{1ee1}', '\0', '\0']), ('\u{1ee2}', ['\u{1ee3}', '\0', '\0']), ('\u{1ee4}', + ['\u{1ee5}', '\0', '\0']), ('\u{1ee6}', ['\u{1ee7}', '\0', '\0']), ('\u{1ee8}', ['\u{1ee9}', + '\0', '\0']), ('\u{1eea}', ['\u{1eeb}', '\0', '\0']), ('\u{1eec}', ['\u{1eed}', '\0', + '\0']), ('\u{1eee}', ['\u{1eef}', '\0', '\0']), ('\u{1ef0}', ['\u{1ef1}', '\0', '\0']), + ('\u{1ef2}', ['\u{1ef3}', '\0', '\0']), ('\u{1ef4}', ['\u{1ef5}', '\0', '\0']), ('\u{1ef6}', + ['\u{1ef7}', '\0', '\0']), ('\u{1ef8}', ['\u{1ef9}', '\0', '\0']), ('\u{1efa}', ['\u{1efb}', + '\0', '\0']), ('\u{1efc}', ['\u{1efd}', '\0', '\0']), ('\u{1efe}', ['\u{1eff}', '\0', + '\0']), ('\u{1f08}', ['\u{1f00}', '\0', '\0']), ('\u{1f09}', ['\u{1f01}', '\0', '\0']), + ('\u{1f0a}', ['\u{1f02}', '\0', '\0']), ('\u{1f0b}', ['\u{1f03}', '\0', '\0']), ('\u{1f0c}', + ['\u{1f04}', '\0', '\0']), ('\u{1f0d}', ['\u{1f05}', '\0', '\0']), ('\u{1f0e}', ['\u{1f06}', + '\0', '\0']), ('\u{1f0f}', ['\u{1f07}', '\0', '\0']), ('\u{1f18}', ['\u{1f10}', '\0', + '\0']), ('\u{1f19}', ['\u{1f11}', '\0', '\0']), ('\u{1f1a}', ['\u{1f12}', '\0', '\0']), + ('\u{1f1b}', ['\u{1f13}', '\0', '\0']), ('\u{1f1c}', ['\u{1f14}', '\0', '\0']), ('\u{1f1d}', + ['\u{1f15}', '\0', '\0']), ('\u{1f28}', ['\u{1f20}', '\0', '\0']), ('\u{1f29}', ['\u{1f21}', + '\0', '\0']), ('\u{1f2a}', ['\u{1f22}', '\0', '\0']), ('\u{1f2b}', ['\u{1f23}', '\0', + '\0']), ('\u{1f2c}', ['\u{1f24}', '\0', '\0']), ('\u{1f2d}', ['\u{1f25}', '\0', '\0']), + ('\u{1f2e}', ['\u{1f26}', '\0', '\0']), ('\u{1f2f}', ['\u{1f27}', '\0', '\0']), ('\u{1f38}', + ['\u{1f30}', '\0', '\0']), ('\u{1f39}', ['\u{1f31}', '\0', '\0']), ('\u{1f3a}', ['\u{1f32}', + '\0', '\0']), ('\u{1f3b}', ['\u{1f33}', '\0', '\0']), ('\u{1f3c}', ['\u{1f34}', '\0', + '\0']), ('\u{1f3d}', ['\u{1f35}', '\0', '\0']), ('\u{1f3e}', ['\u{1f36}', '\0', '\0']), + ('\u{1f3f}', ['\u{1f37}', '\0', '\0']), ('\u{1f48}', ['\u{1f40}', '\0', '\0']), ('\u{1f49}', + ['\u{1f41}', '\0', '\0']), ('\u{1f4a}', ['\u{1f42}', '\0', '\0']), ('\u{1f4b}', ['\u{1f43}', + '\0', '\0']), ('\u{1f4c}', ['\u{1f44}', '\0', '\0']), ('\u{1f4d}', ['\u{1f45}', '\0', + '\0']), ('\u{1f59}', ['\u{1f51}', '\0', '\0']), ('\u{1f5b}', ['\u{1f53}', '\0', '\0']), + ('\u{1f5d}', ['\u{1f55}', '\0', '\0']), ('\u{1f5f}', ['\u{1f57}', '\0', '\0']), ('\u{1f68}', + ['\u{1f60}', '\0', '\0']), ('\u{1f69}', ['\u{1f61}', '\0', '\0']), ('\u{1f6a}', ['\u{1f62}', + '\0', '\0']), ('\u{1f6b}', ['\u{1f63}', '\0', '\0']), ('\u{1f6c}', ['\u{1f64}', '\0', + '\0']), ('\u{1f6d}', ['\u{1f65}', '\0', '\0']), ('\u{1f6e}', ['\u{1f66}', '\0', '\0']), + ('\u{1f6f}', ['\u{1f67}', '\0', '\0']), ('\u{1f88}', ['\u{1f80}', '\0', '\0']), ('\u{1f89}', + ['\u{1f81}', '\0', '\0']), ('\u{1f8a}', ['\u{1f82}', '\0', '\0']), ('\u{1f8b}', ['\u{1f83}', + '\0', '\0']), ('\u{1f8c}', ['\u{1f84}', '\0', '\0']), ('\u{1f8d}', ['\u{1f85}', '\0', + '\0']), ('\u{1f8e}', ['\u{1f86}', '\0', '\0']), ('\u{1f8f}', ['\u{1f87}', '\0', '\0']), + ('\u{1f98}', ['\u{1f90}', '\0', '\0']), ('\u{1f99}', ['\u{1f91}', '\0', '\0']), ('\u{1f9a}', + ['\u{1f92}', '\0', '\0']), ('\u{1f9b}', ['\u{1f93}', '\0', '\0']), ('\u{1f9c}', ['\u{1f94}', + '\0', '\0']), ('\u{1f9d}', ['\u{1f95}', '\0', '\0']), ('\u{1f9e}', ['\u{1f96}', '\0', + '\0']), ('\u{1f9f}', ['\u{1f97}', '\0', '\0']), ('\u{1fa8}', ['\u{1fa0}', '\0', '\0']), + ('\u{1fa9}', ['\u{1fa1}', '\0', '\0']), ('\u{1faa}', ['\u{1fa2}', '\0', '\0']), ('\u{1fab}', + ['\u{1fa3}', '\0', '\0']), ('\u{1fac}', ['\u{1fa4}', '\0', '\0']), ('\u{1fad}', ['\u{1fa5}', + '\0', '\0']), ('\u{1fae}', ['\u{1fa6}', '\0', '\0']), ('\u{1faf}', ['\u{1fa7}', '\0', + '\0']), ('\u{1fb8}', ['\u{1fb0}', '\0', '\0']), ('\u{1fb9}', ['\u{1fb1}', '\0', '\0']), + ('\u{1fba}', ['\u{1f70}', '\0', '\0']), ('\u{1fbb}', ['\u{1f71}', '\0', '\0']), ('\u{1fbc}', + ['\u{1fb3}', '\0', '\0']), ('\u{1fc8}', ['\u{1f72}', '\0', '\0']), ('\u{1fc9}', ['\u{1f73}', + '\0', '\0']), ('\u{1fca}', ['\u{1f74}', '\0', '\0']), ('\u{1fcb}', ['\u{1f75}', '\0', + '\0']), ('\u{1fcc}', ['\u{1fc3}', '\0', '\0']), ('\u{1fd8}', ['\u{1fd0}', '\0', '\0']), + ('\u{1fd9}', ['\u{1fd1}', '\0', '\0']), ('\u{1fda}', ['\u{1f76}', '\0', '\0']), ('\u{1fdb}', + ['\u{1f77}', '\0', '\0']), ('\u{1fe8}', ['\u{1fe0}', '\0', '\0']), ('\u{1fe9}', ['\u{1fe1}', + '\0', '\0']), ('\u{1fea}', ['\u{1f7a}', '\0', '\0']), ('\u{1feb}', ['\u{1f7b}', '\0', + '\0']), ('\u{1fec}', ['\u{1fe5}', '\0', '\0']), ('\u{1ff8}', ['\u{1f78}', '\0', '\0']), + ('\u{1ff9}', ['\u{1f79}', '\0', '\0']), ('\u{1ffa}', ['\u{1f7c}', '\0', '\0']), ('\u{1ffb}', + ['\u{1f7d}', '\0', '\0']), ('\u{1ffc}', ['\u{1ff3}', '\0', '\0']), ('\u{2126}', ['\u{3c9}', + '\0', '\0']), ('\u{212a}', ['\u{6b}', '\0', '\0']), ('\u{212b}', ['\u{e5}', '\0', '\0']), + ('\u{2132}', ['\u{214e}', '\0', '\0']), ('\u{2160}', ['\u{2170}', '\0', '\0']), ('\u{2161}', + ['\u{2171}', '\0', '\0']), ('\u{2162}', ['\u{2172}', '\0', '\0']), ('\u{2163}', ['\u{2173}', + '\0', '\0']), ('\u{2164}', ['\u{2174}', '\0', '\0']), ('\u{2165}', ['\u{2175}', '\0', + '\0']), ('\u{2166}', ['\u{2176}', '\0', '\0']), ('\u{2167}', ['\u{2177}', '\0', '\0']), + ('\u{2168}', ['\u{2178}', '\0', '\0']), ('\u{2169}', ['\u{2179}', '\0', '\0']), ('\u{216a}', + ['\u{217a}', '\0', '\0']), ('\u{216b}', ['\u{217b}', '\0', '\0']), ('\u{216c}', ['\u{217c}', + '\0', '\0']), ('\u{216d}', ['\u{217d}', '\0', '\0']), ('\u{216e}', ['\u{217e}', '\0', + '\0']), ('\u{216f}', ['\u{217f}', '\0', '\0']), ('\u{2183}', ['\u{2184}', '\0', '\0']), + ('\u{24b6}', ['\u{24d0}', '\0', '\0']), ('\u{24b7}', ['\u{24d1}', '\0', '\0']), ('\u{24b8}', + ['\u{24d2}', '\0', '\0']), ('\u{24b9}', ['\u{24d3}', '\0', '\0']), ('\u{24ba}', ['\u{24d4}', + '\0', '\0']), ('\u{24bb}', ['\u{24d5}', '\0', '\0']), ('\u{24bc}', ['\u{24d6}', '\0', + '\0']), ('\u{24bd}', ['\u{24d7}', '\0', '\0']), ('\u{24be}', ['\u{24d8}', '\0', '\0']), + ('\u{24bf}', ['\u{24d9}', '\0', '\0']), ('\u{24c0}', ['\u{24da}', '\0', '\0']), ('\u{24c1}', + ['\u{24db}', '\0', '\0']), ('\u{24c2}', ['\u{24dc}', '\0', '\0']), ('\u{24c3}', ['\u{24dd}', + '\0', '\0']), ('\u{24c4}', ['\u{24de}', '\0', '\0']), ('\u{24c5}', ['\u{24df}', '\0', + '\0']), ('\u{24c6}', ['\u{24e0}', '\0', '\0']), ('\u{24c7}', ['\u{24e1}', '\0', '\0']), + ('\u{24c8}', ['\u{24e2}', '\0', '\0']), ('\u{24c9}', ['\u{24e3}', '\0', '\0']), ('\u{24ca}', + ['\u{24e4}', '\0', '\0']), ('\u{24cb}', ['\u{24e5}', '\0', '\0']), ('\u{24cc}', ['\u{24e6}', + '\0', '\0']), ('\u{24cd}', ['\u{24e7}', '\0', '\0']), ('\u{24ce}', ['\u{24e8}', '\0', + '\0']), ('\u{24cf}', ['\u{24e9}', '\0', '\0']), ('\u{2c00}', ['\u{2c30}', '\0', '\0']), + ('\u{2c01}', ['\u{2c31}', '\0', '\0']), ('\u{2c02}', ['\u{2c32}', '\0', '\0']), ('\u{2c03}', + ['\u{2c33}', '\0', '\0']), ('\u{2c04}', ['\u{2c34}', '\0', '\0']), ('\u{2c05}', ['\u{2c35}', + '\0', '\0']), ('\u{2c06}', ['\u{2c36}', '\0', '\0']), ('\u{2c07}', ['\u{2c37}', '\0', + '\0']), ('\u{2c08}', ['\u{2c38}', '\0', '\0']), ('\u{2c09}', ['\u{2c39}', '\0', '\0']), + ('\u{2c0a}', ['\u{2c3a}', '\0', '\0']), ('\u{2c0b}', ['\u{2c3b}', '\0', '\0']), ('\u{2c0c}', + ['\u{2c3c}', '\0', '\0']), ('\u{2c0d}', ['\u{2c3d}', '\0', '\0']), ('\u{2c0e}', ['\u{2c3e}', + '\0', '\0']), ('\u{2c0f}', ['\u{2c3f}', '\0', '\0']), ('\u{2c10}', ['\u{2c40}', '\0', + '\0']), ('\u{2c11}', ['\u{2c41}', '\0', '\0']), ('\u{2c12}', ['\u{2c42}', '\0', '\0']), + ('\u{2c13}', ['\u{2c43}', '\0', '\0']), ('\u{2c14}', ['\u{2c44}', '\0', '\0']), ('\u{2c15}', + ['\u{2c45}', '\0', '\0']), ('\u{2c16}', ['\u{2c46}', '\0', '\0']), ('\u{2c17}', ['\u{2c47}', + '\0', '\0']), ('\u{2c18}', ['\u{2c48}', '\0', '\0']), ('\u{2c19}', ['\u{2c49}', '\0', + '\0']), ('\u{2c1a}', ['\u{2c4a}', '\0', '\0']), ('\u{2c1b}', ['\u{2c4b}', '\0', '\0']), + ('\u{2c1c}', ['\u{2c4c}', '\0', '\0']), ('\u{2c1d}', ['\u{2c4d}', '\0', '\0']), ('\u{2c1e}', + ['\u{2c4e}', '\0', '\0']), ('\u{2c1f}', ['\u{2c4f}', '\0', '\0']), ('\u{2c20}', ['\u{2c50}', + '\0', '\0']), ('\u{2c21}', ['\u{2c51}', '\0', '\0']), ('\u{2c22}', ['\u{2c52}', '\0', + '\0']), ('\u{2c23}', ['\u{2c53}', '\0', '\0']), ('\u{2c24}', ['\u{2c54}', '\0', '\0']), + ('\u{2c25}', ['\u{2c55}', '\0', '\0']), ('\u{2c26}', ['\u{2c56}', '\0', '\0']), ('\u{2c27}', + ['\u{2c57}', '\0', '\0']), ('\u{2c28}', ['\u{2c58}', '\0', '\0']), ('\u{2c29}', ['\u{2c59}', + '\0', '\0']), ('\u{2c2a}', ['\u{2c5a}', '\0', '\0']), ('\u{2c2b}', ['\u{2c5b}', '\0', + '\0']), ('\u{2c2c}', ['\u{2c5c}', '\0', '\0']), ('\u{2c2d}', ['\u{2c5d}', '\0', '\0']), + ('\u{2c2e}', ['\u{2c5e}', '\0', '\0']), ('\u{2c60}', ['\u{2c61}', '\0', '\0']), ('\u{2c62}', + ['\u{26b}', '\0', '\0']), ('\u{2c63}', ['\u{1d7d}', '\0', '\0']), ('\u{2c64}', ['\u{27d}', + '\0', '\0']), ('\u{2c67}', ['\u{2c68}', '\0', '\0']), ('\u{2c69}', ['\u{2c6a}', '\0', + '\0']), ('\u{2c6b}', ['\u{2c6c}', '\0', '\0']), ('\u{2c6d}', ['\u{251}', '\0', '\0']), + ('\u{2c6e}', ['\u{271}', '\0', '\0']), ('\u{2c6f}', ['\u{250}', '\0', '\0']), ('\u{2c70}', + ['\u{252}', '\0', '\0']), ('\u{2c72}', ['\u{2c73}', '\0', '\0']), ('\u{2c75}', ['\u{2c76}', + '\0', '\0']), ('\u{2c7e}', ['\u{23f}', '\0', '\0']), ('\u{2c7f}', ['\u{240}', '\0', '\0']), + ('\u{2c80}', ['\u{2c81}', '\0', '\0']), ('\u{2c82}', ['\u{2c83}', '\0', '\0']), ('\u{2c84}', + ['\u{2c85}', '\0', '\0']), ('\u{2c86}', ['\u{2c87}', '\0', '\0']), ('\u{2c88}', ['\u{2c89}', + '\0', '\0']), ('\u{2c8a}', ['\u{2c8b}', '\0', '\0']), ('\u{2c8c}', ['\u{2c8d}', '\0', + '\0']), ('\u{2c8e}', ['\u{2c8f}', '\0', '\0']), ('\u{2c90}', ['\u{2c91}', '\0', '\0']), + ('\u{2c92}', ['\u{2c93}', '\0', '\0']), ('\u{2c94}', ['\u{2c95}', '\0', '\0']), ('\u{2c96}', + ['\u{2c97}', '\0', '\0']), ('\u{2c98}', ['\u{2c99}', '\0', '\0']), ('\u{2c9a}', ['\u{2c9b}', + '\0', '\0']), ('\u{2c9c}', ['\u{2c9d}', '\0', '\0']), ('\u{2c9e}', ['\u{2c9f}', '\0', + '\0']), ('\u{2ca0}', ['\u{2ca1}', '\0', '\0']), ('\u{2ca2}', ['\u{2ca3}', '\0', '\0']), + ('\u{2ca4}', ['\u{2ca5}', '\0', '\0']), ('\u{2ca6}', ['\u{2ca7}', '\0', '\0']), ('\u{2ca8}', + ['\u{2ca9}', '\0', '\0']), ('\u{2caa}', ['\u{2cab}', '\0', '\0']), ('\u{2cac}', ['\u{2cad}', + '\0', '\0']), ('\u{2cae}', ['\u{2caf}', '\0', '\0']), ('\u{2cb0}', ['\u{2cb1}', '\0', + '\0']), ('\u{2cb2}', ['\u{2cb3}', '\0', '\0']), ('\u{2cb4}', ['\u{2cb5}', '\0', '\0']), + ('\u{2cb6}', ['\u{2cb7}', '\0', '\0']), ('\u{2cb8}', ['\u{2cb9}', '\0', '\0']), ('\u{2cba}', + ['\u{2cbb}', '\0', '\0']), ('\u{2cbc}', ['\u{2cbd}', '\0', '\0']), ('\u{2cbe}', ['\u{2cbf}', + '\0', '\0']), ('\u{2cc0}', ['\u{2cc1}', '\0', '\0']), ('\u{2cc2}', ['\u{2cc3}', '\0', + '\0']), ('\u{2cc4}', ['\u{2cc5}', '\0', '\0']), ('\u{2cc6}', ['\u{2cc7}', '\0', '\0']), + ('\u{2cc8}', ['\u{2cc9}', '\0', '\0']), ('\u{2cca}', ['\u{2ccb}', '\0', '\0']), ('\u{2ccc}', + ['\u{2ccd}', '\0', '\0']), ('\u{2cce}', ['\u{2ccf}', '\0', '\0']), ('\u{2cd0}', ['\u{2cd1}', + '\0', '\0']), ('\u{2cd2}', ['\u{2cd3}', '\0', '\0']), ('\u{2cd4}', ['\u{2cd5}', '\0', + '\0']), ('\u{2cd6}', ['\u{2cd7}', '\0', '\0']), ('\u{2cd8}', ['\u{2cd9}', '\0', '\0']), + ('\u{2cda}', ['\u{2cdb}', '\0', '\0']), ('\u{2cdc}', ['\u{2cdd}', '\0', '\0']), ('\u{2cde}', + ['\u{2cdf}', '\0', '\0']), ('\u{2ce0}', ['\u{2ce1}', '\0', '\0']), ('\u{2ce2}', ['\u{2ce3}', + '\0', '\0']), ('\u{2ceb}', ['\u{2cec}', '\0', '\0']), ('\u{2ced}', ['\u{2cee}', '\0', + '\0']), ('\u{2cf2}', ['\u{2cf3}', '\0', '\0']), ('\u{a640}', ['\u{a641}', '\0', '\0']), + ('\u{a642}', ['\u{a643}', '\0', '\0']), ('\u{a644}', ['\u{a645}', '\0', '\0']), ('\u{a646}', + ['\u{a647}', '\0', '\0']), ('\u{a648}', ['\u{a649}', '\0', '\0']), ('\u{a64a}', ['\u{a64b}', + '\0', '\0']), ('\u{a64c}', ['\u{a64d}', '\0', '\0']), ('\u{a64e}', ['\u{a64f}', '\0', + '\0']), ('\u{a650}', ['\u{a651}', '\0', '\0']), ('\u{a652}', ['\u{a653}', '\0', '\0']), + ('\u{a654}', ['\u{a655}', '\0', '\0']), ('\u{a656}', ['\u{a657}', '\0', '\0']), ('\u{a658}', + ['\u{a659}', '\0', '\0']), ('\u{a65a}', ['\u{a65b}', '\0', '\0']), ('\u{a65c}', ['\u{a65d}', + '\0', '\0']), ('\u{a65e}', ['\u{a65f}', '\0', '\0']), ('\u{a660}', ['\u{a661}', '\0', + '\0']), ('\u{a662}', ['\u{a663}', '\0', '\0']), ('\u{a664}', ['\u{a665}', '\0', '\0']), + ('\u{a666}', ['\u{a667}', '\0', '\0']), ('\u{a668}', ['\u{a669}', '\0', '\0']), ('\u{a66a}', + ['\u{a66b}', '\0', '\0']), ('\u{a66c}', ['\u{a66d}', '\0', '\0']), ('\u{a680}', ['\u{a681}', + '\0', '\0']), ('\u{a682}', ['\u{a683}', '\0', '\0']), ('\u{a684}', ['\u{a685}', '\0', + '\0']), ('\u{a686}', ['\u{a687}', '\0', '\0']), ('\u{a688}', ['\u{a689}', '\0', '\0']), + ('\u{a68a}', ['\u{a68b}', '\0', '\0']), ('\u{a68c}', ['\u{a68d}', '\0', '\0']), ('\u{a68e}', + ['\u{a68f}', '\0', '\0']), ('\u{a690}', ['\u{a691}', '\0', '\0']), ('\u{a692}', ['\u{a693}', + '\0', '\0']), ('\u{a694}', ['\u{a695}', '\0', '\0']), ('\u{a696}', ['\u{a697}', '\0', + '\0']), ('\u{a698}', ['\u{a699}', '\0', '\0']), ('\u{a69a}', ['\u{a69b}', '\0', '\0']), + ('\u{a722}', ['\u{a723}', '\0', '\0']), ('\u{a724}', ['\u{a725}', '\0', '\0']), ('\u{a726}', + ['\u{a727}', '\0', '\0']), ('\u{a728}', ['\u{a729}', '\0', '\0']), ('\u{a72a}', ['\u{a72b}', + '\0', '\0']), ('\u{a72c}', ['\u{a72d}', '\0', '\0']), ('\u{a72e}', ['\u{a72f}', '\0', + '\0']), ('\u{a732}', ['\u{a733}', '\0', '\0']), ('\u{a734}', ['\u{a735}', '\0', '\0']), + ('\u{a736}', ['\u{a737}', '\0', '\0']), ('\u{a738}', ['\u{a739}', '\0', '\0']), ('\u{a73a}', + ['\u{a73b}', '\0', '\0']), ('\u{a73c}', ['\u{a73d}', '\0', '\0']), ('\u{a73e}', ['\u{a73f}', + '\0', '\0']), ('\u{a740}', ['\u{a741}', '\0', '\0']), ('\u{a742}', ['\u{a743}', '\0', + '\0']), ('\u{a744}', ['\u{a745}', '\0', '\0']), ('\u{a746}', ['\u{a747}', '\0', '\0']), + ('\u{a748}', ['\u{a749}', '\0', '\0']), ('\u{a74a}', ['\u{a74b}', '\0', '\0']), ('\u{a74c}', + ['\u{a74d}', '\0', '\0']), ('\u{a74e}', ['\u{a74f}', '\0', '\0']), ('\u{a750}', ['\u{a751}', + '\0', '\0']), ('\u{a752}', ['\u{a753}', '\0', '\0']), ('\u{a754}', ['\u{a755}', '\0', + '\0']), ('\u{a756}', ['\u{a757}', '\0', '\0']), ('\u{a758}', ['\u{a759}', '\0', '\0']), + ('\u{a75a}', ['\u{a75b}', '\0', '\0']), ('\u{a75c}', ['\u{a75d}', '\0', '\0']), ('\u{a75e}', + ['\u{a75f}', '\0', '\0']), ('\u{a760}', ['\u{a761}', '\0', '\0']), ('\u{a762}', ['\u{a763}', + '\0', '\0']), ('\u{a764}', ['\u{a765}', '\0', '\0']), ('\u{a766}', ['\u{a767}', '\0', + '\0']), ('\u{a768}', ['\u{a769}', '\0', '\0']), ('\u{a76a}', ['\u{a76b}', '\0', '\0']), + ('\u{a76c}', ['\u{a76d}', '\0', '\0']), ('\u{a76e}', ['\u{a76f}', '\0', '\0']), ('\u{a779}', + ['\u{a77a}', '\0', '\0']), ('\u{a77b}', ['\u{a77c}', '\0', '\0']), ('\u{a77d}', ['\u{1d79}', + '\0', '\0']), ('\u{a77e}', ['\u{a77f}', '\0', '\0']), ('\u{a780}', ['\u{a781}', '\0', + '\0']), ('\u{a782}', ['\u{a783}', '\0', '\0']), ('\u{a784}', ['\u{a785}', '\0', '\0']), + ('\u{a786}', ['\u{a787}', '\0', '\0']), ('\u{a78b}', ['\u{a78c}', '\0', '\0']), ('\u{a78d}', + ['\u{265}', '\0', '\0']), ('\u{a790}', ['\u{a791}', '\0', '\0']), ('\u{a792}', ['\u{a793}', + '\0', '\0']), ('\u{a796}', ['\u{a797}', '\0', '\0']), ('\u{a798}', ['\u{a799}', '\0', + '\0']), ('\u{a79a}', ['\u{a79b}', '\0', '\0']), ('\u{a79c}', ['\u{a79d}', '\0', '\0']), + ('\u{a79e}', ['\u{a79f}', '\0', '\0']), ('\u{a7a0}', ['\u{a7a1}', '\0', '\0']), ('\u{a7a2}', + ['\u{a7a3}', '\0', '\0']), ('\u{a7a4}', ['\u{a7a5}', '\0', '\0']), ('\u{a7a6}', ['\u{a7a7}', + '\0', '\0']), ('\u{a7a8}', ['\u{a7a9}', '\0', '\0']), ('\u{a7aa}', ['\u{266}', '\0', '\0']), + ('\u{a7ab}', ['\u{25c}', '\0', '\0']), ('\u{a7ac}', ['\u{261}', '\0', '\0']), ('\u{a7ad}', + ['\u{26c}', '\0', '\0']), ('\u{a7ae}', ['\u{26a}', '\0', '\0']), ('\u{a7b0}', ['\u{29e}', + '\0', '\0']), ('\u{a7b1}', ['\u{287}', '\0', '\0']), ('\u{a7b2}', ['\u{29d}', '\0', '\0']), + ('\u{a7b3}', ['\u{ab53}', '\0', '\0']), ('\u{a7b4}', ['\u{a7b5}', '\0', '\0']), ('\u{a7b6}', + ['\u{a7b7}', '\0', '\0']), ('\u{a7b8}', ['\u{a7b9}', '\0', '\0']), ('\u{ff21}', ['\u{ff41}', + '\0', '\0']), ('\u{ff22}', ['\u{ff42}', '\0', '\0']), ('\u{ff23}', ['\u{ff43}', '\0', + '\0']), ('\u{ff24}', ['\u{ff44}', '\0', '\0']), ('\u{ff25}', ['\u{ff45}', '\0', '\0']), + ('\u{ff26}', ['\u{ff46}', '\0', '\0']), ('\u{ff27}', ['\u{ff47}', '\0', '\0']), ('\u{ff28}', + ['\u{ff48}', '\0', '\0']), ('\u{ff29}', ['\u{ff49}', '\0', '\0']), ('\u{ff2a}', ['\u{ff4a}', + '\0', '\0']), ('\u{ff2b}', ['\u{ff4b}', '\0', '\0']), ('\u{ff2c}', ['\u{ff4c}', '\0', + '\0']), ('\u{ff2d}', ['\u{ff4d}', '\0', '\0']), ('\u{ff2e}', ['\u{ff4e}', '\0', '\0']), + ('\u{ff2f}', ['\u{ff4f}', '\0', '\0']), ('\u{ff30}', ['\u{ff50}', '\0', '\0']), ('\u{ff31}', + ['\u{ff51}', '\0', '\0']), ('\u{ff32}', ['\u{ff52}', '\0', '\0']), ('\u{ff33}', ['\u{ff53}', + '\0', '\0']), ('\u{ff34}', ['\u{ff54}', '\0', '\0']), ('\u{ff35}', ['\u{ff55}', '\0', + '\0']), ('\u{ff36}', ['\u{ff56}', '\0', '\0']), ('\u{ff37}', ['\u{ff57}', '\0', '\0']), + ('\u{ff38}', ['\u{ff58}', '\0', '\0']), ('\u{ff39}', ['\u{ff59}', '\0', '\0']), ('\u{ff3a}', + ['\u{ff5a}', '\0', '\0']), ('\u{10400}', ['\u{10428}', '\0', '\0']), ('\u{10401}', + ['\u{10429}', '\0', '\0']), ('\u{10402}', ['\u{1042a}', '\0', '\0']), ('\u{10403}', + ['\u{1042b}', '\0', '\0']), ('\u{10404}', ['\u{1042c}', '\0', '\0']), ('\u{10405}', + ['\u{1042d}', '\0', '\0']), ('\u{10406}', ['\u{1042e}', '\0', '\0']), ('\u{10407}', + ['\u{1042f}', '\0', '\0']), ('\u{10408}', ['\u{10430}', '\0', '\0']), ('\u{10409}', + ['\u{10431}', '\0', '\0']), ('\u{1040a}', ['\u{10432}', '\0', '\0']), ('\u{1040b}', + ['\u{10433}', '\0', '\0']), ('\u{1040c}', ['\u{10434}', '\0', '\0']), ('\u{1040d}', + ['\u{10435}', '\0', '\0']), ('\u{1040e}', ['\u{10436}', '\0', '\0']), ('\u{1040f}', + ['\u{10437}', '\0', '\0']), ('\u{10410}', ['\u{10438}', '\0', '\0']), ('\u{10411}', + ['\u{10439}', '\0', '\0']), ('\u{10412}', ['\u{1043a}', '\0', '\0']), ('\u{10413}', + ['\u{1043b}', '\0', '\0']), ('\u{10414}', ['\u{1043c}', '\0', '\0']), ('\u{10415}', + ['\u{1043d}', '\0', '\0']), ('\u{10416}', ['\u{1043e}', '\0', '\0']), ('\u{10417}', + ['\u{1043f}', '\0', '\0']), ('\u{10418}', ['\u{10440}', '\0', '\0']), ('\u{10419}', + ['\u{10441}', '\0', '\0']), ('\u{1041a}', ['\u{10442}', '\0', '\0']), ('\u{1041b}', + ['\u{10443}', '\0', '\0']), ('\u{1041c}', ['\u{10444}', '\0', '\0']), ('\u{1041d}', + ['\u{10445}', '\0', '\0']), ('\u{1041e}', ['\u{10446}', '\0', '\0']), ('\u{1041f}', + ['\u{10447}', '\0', '\0']), ('\u{10420}', ['\u{10448}', '\0', '\0']), ('\u{10421}', + ['\u{10449}', '\0', '\0']), ('\u{10422}', ['\u{1044a}', '\0', '\0']), ('\u{10423}', + ['\u{1044b}', '\0', '\0']), ('\u{10424}', ['\u{1044c}', '\0', '\0']), ('\u{10425}', + ['\u{1044d}', '\0', '\0']), ('\u{10426}', ['\u{1044e}', '\0', '\0']), ('\u{10427}', + ['\u{1044f}', '\0', '\0']), ('\u{104b0}', ['\u{104d8}', '\0', '\0']), ('\u{104b1}', + ['\u{104d9}', '\0', '\0']), ('\u{104b2}', ['\u{104da}', '\0', '\0']), ('\u{104b3}', + ['\u{104db}', '\0', '\0']), ('\u{104b4}', ['\u{104dc}', '\0', '\0']), ('\u{104b5}', + ['\u{104dd}', '\0', '\0']), ('\u{104b6}', ['\u{104de}', '\0', '\0']), ('\u{104b7}', + ['\u{104df}', '\0', '\0']), ('\u{104b8}', ['\u{104e0}', '\0', '\0']), ('\u{104b9}', + ['\u{104e1}', '\0', '\0']), ('\u{104ba}', ['\u{104e2}', '\0', '\0']), ('\u{104bb}', + ['\u{104e3}', '\0', '\0']), ('\u{104bc}', ['\u{104e4}', '\0', '\0']), ('\u{104bd}', + ['\u{104e5}', '\0', '\0']), ('\u{104be}', ['\u{104e6}', '\0', '\0']), ('\u{104bf}', + ['\u{104e7}', '\0', '\0']), ('\u{104c0}', ['\u{104e8}', '\0', '\0']), ('\u{104c1}', + ['\u{104e9}', '\0', '\0']), ('\u{104c2}', ['\u{104ea}', '\0', '\0']), ('\u{104c3}', + ['\u{104eb}', '\0', '\0']), ('\u{104c4}', ['\u{104ec}', '\0', '\0']), ('\u{104c5}', + ['\u{104ed}', '\0', '\0']), ('\u{104c6}', ['\u{104ee}', '\0', '\0']), ('\u{104c7}', + ['\u{104ef}', '\0', '\0']), ('\u{104c8}', ['\u{104f0}', '\0', '\0']), ('\u{104c9}', + ['\u{104f1}', '\0', '\0']), ('\u{104ca}', ['\u{104f2}', '\0', '\0']), ('\u{104cb}', + ['\u{104f3}', '\0', '\0']), ('\u{104cc}', ['\u{104f4}', '\0', '\0']), ('\u{104cd}', + ['\u{104f5}', '\0', '\0']), ('\u{104ce}', ['\u{104f6}', '\0', '\0']), ('\u{104cf}', + ['\u{104f7}', '\0', '\0']), ('\u{104d0}', ['\u{104f8}', '\0', '\0']), ('\u{104d1}', + ['\u{104f9}', '\0', '\0']), ('\u{104d2}', ['\u{104fa}', '\0', '\0']), ('\u{104d3}', + ['\u{104fb}', '\0', '\0']), ('\u{10c80}', ['\u{10cc0}', '\0', '\0']), ('\u{10c81}', + ['\u{10cc1}', '\0', '\0']), ('\u{10c82}', ['\u{10cc2}', '\0', '\0']), ('\u{10c83}', + ['\u{10cc3}', '\0', '\0']), ('\u{10c84}', ['\u{10cc4}', '\0', '\0']), ('\u{10c85}', + ['\u{10cc5}', '\0', '\0']), ('\u{10c86}', ['\u{10cc6}', '\0', '\0']), ('\u{10c87}', + ['\u{10cc7}', '\0', '\0']), ('\u{10c88}', ['\u{10cc8}', '\0', '\0']), ('\u{10c89}', + ['\u{10cc9}', '\0', '\0']), ('\u{10c8a}', ['\u{10cca}', '\0', '\0']), ('\u{10c8b}', + ['\u{10ccb}', '\0', '\0']), ('\u{10c8c}', ['\u{10ccc}', '\0', '\0']), ('\u{10c8d}', + ['\u{10ccd}', '\0', '\0']), ('\u{10c8e}', ['\u{10cce}', '\0', '\0']), ('\u{10c8f}', + ['\u{10ccf}', '\0', '\0']), ('\u{10c90}', ['\u{10cd0}', '\0', '\0']), ('\u{10c91}', + ['\u{10cd1}', '\0', '\0']), ('\u{10c92}', ['\u{10cd2}', '\0', '\0']), ('\u{10c93}', + ['\u{10cd3}', '\0', '\0']), ('\u{10c94}', ['\u{10cd4}', '\0', '\0']), ('\u{10c95}', + ['\u{10cd5}', '\0', '\0']), ('\u{10c96}', ['\u{10cd6}', '\0', '\0']), ('\u{10c97}', + ['\u{10cd7}', '\0', '\0']), ('\u{10c98}', ['\u{10cd8}', '\0', '\0']), ('\u{10c99}', + ['\u{10cd9}', '\0', '\0']), ('\u{10c9a}', ['\u{10cda}', '\0', '\0']), ('\u{10c9b}', + ['\u{10cdb}', '\0', '\0']), ('\u{10c9c}', ['\u{10cdc}', '\0', '\0']), ('\u{10c9d}', + ['\u{10cdd}', '\0', '\0']), ('\u{10c9e}', ['\u{10cde}', '\0', '\0']), ('\u{10c9f}', + ['\u{10cdf}', '\0', '\0']), ('\u{10ca0}', ['\u{10ce0}', '\0', '\0']), ('\u{10ca1}', + ['\u{10ce1}', '\0', '\0']), ('\u{10ca2}', ['\u{10ce2}', '\0', '\0']), ('\u{10ca3}', + ['\u{10ce3}', '\0', '\0']), ('\u{10ca4}', ['\u{10ce4}', '\0', '\0']), ('\u{10ca5}', + ['\u{10ce5}', '\0', '\0']), ('\u{10ca6}', ['\u{10ce6}', '\0', '\0']), ('\u{10ca7}', + ['\u{10ce7}', '\0', '\0']), ('\u{10ca8}', ['\u{10ce8}', '\0', '\0']), ('\u{10ca9}', + ['\u{10ce9}', '\0', '\0']), ('\u{10caa}', ['\u{10cea}', '\0', '\0']), ('\u{10cab}', + ['\u{10ceb}', '\0', '\0']), ('\u{10cac}', ['\u{10cec}', '\0', '\0']), ('\u{10cad}', + ['\u{10ced}', '\0', '\0']), ('\u{10cae}', ['\u{10cee}', '\0', '\0']), ('\u{10caf}', + ['\u{10cef}', '\0', '\0']), ('\u{10cb0}', ['\u{10cf0}', '\0', '\0']), ('\u{10cb1}', + ['\u{10cf1}', '\0', '\0']), ('\u{10cb2}', ['\u{10cf2}', '\0', '\0']), ('\u{118a0}', + ['\u{118c0}', '\0', '\0']), ('\u{118a1}', ['\u{118c1}', '\0', '\0']), ('\u{118a2}', + ['\u{118c2}', '\0', '\0']), ('\u{118a3}', ['\u{118c3}', '\0', '\0']), ('\u{118a4}', + ['\u{118c4}', '\0', '\0']), ('\u{118a5}', ['\u{118c5}', '\0', '\0']), ('\u{118a6}', + ['\u{118c6}', '\0', '\0']), ('\u{118a7}', ['\u{118c7}', '\0', '\0']), ('\u{118a8}', + ['\u{118c8}', '\0', '\0']), ('\u{118a9}', ['\u{118c9}', '\0', '\0']), ('\u{118aa}', + ['\u{118ca}', '\0', '\0']), ('\u{118ab}', ['\u{118cb}', '\0', '\0']), ('\u{118ac}', + ['\u{118cc}', '\0', '\0']), ('\u{118ad}', ['\u{118cd}', '\0', '\0']), ('\u{118ae}', + ['\u{118ce}', '\0', '\0']), ('\u{118af}', ['\u{118cf}', '\0', '\0']), ('\u{118b0}', + ['\u{118d0}', '\0', '\0']), ('\u{118b1}', ['\u{118d1}', '\0', '\0']), ('\u{118b2}', + ['\u{118d2}', '\0', '\0']), ('\u{118b3}', ['\u{118d3}', '\0', '\0']), ('\u{118b4}', + ['\u{118d4}', '\0', '\0']), ('\u{118b5}', ['\u{118d5}', '\0', '\0']), ('\u{118b6}', + ['\u{118d6}', '\0', '\0']), ('\u{118b7}', ['\u{118d7}', '\0', '\0']), ('\u{118b8}', + ['\u{118d8}', '\0', '\0']), ('\u{118b9}', ['\u{118d9}', '\0', '\0']), ('\u{118ba}', + ['\u{118da}', '\0', '\0']), ('\u{118bb}', ['\u{118db}', '\0', '\0']), ('\u{118bc}', + ['\u{118dc}', '\0', '\0']), ('\u{118bd}', ['\u{118dd}', '\0', '\0']), ('\u{118be}', + ['\u{118de}', '\0', '\0']), ('\u{118bf}', ['\u{118df}', '\0', '\0']), ('\u{16e40}', + ['\u{16e60}', '\0', '\0']), ('\u{16e41}', ['\u{16e61}', '\0', '\0']), ('\u{16e42}', + ['\u{16e62}', '\0', '\0']), ('\u{16e43}', ['\u{16e63}', '\0', '\0']), ('\u{16e44}', + ['\u{16e64}', '\0', '\0']), ('\u{16e45}', ['\u{16e65}', '\0', '\0']), ('\u{16e46}', + ['\u{16e66}', '\0', '\0']), ('\u{16e47}', ['\u{16e67}', '\0', '\0']), ('\u{16e48}', + ['\u{16e68}', '\0', '\0']), ('\u{16e49}', ['\u{16e69}', '\0', '\0']), ('\u{16e4a}', + ['\u{16e6a}', '\0', '\0']), ('\u{16e4b}', ['\u{16e6b}', '\0', '\0']), ('\u{16e4c}', + ['\u{16e6c}', '\0', '\0']), ('\u{16e4d}', ['\u{16e6d}', '\0', '\0']), ('\u{16e4e}', + ['\u{16e6e}', '\0', '\0']), ('\u{16e4f}', ['\u{16e6f}', '\0', '\0']), ('\u{16e50}', + ['\u{16e70}', '\0', '\0']), ('\u{16e51}', ['\u{16e71}', '\0', '\0']), ('\u{16e52}', + ['\u{16e72}', '\0', '\0']), ('\u{16e53}', ['\u{16e73}', '\0', '\0']), ('\u{16e54}', + ['\u{16e74}', '\0', '\0']), ('\u{16e55}', ['\u{16e75}', '\0', '\0']), ('\u{16e56}', + ['\u{16e76}', '\0', '\0']), ('\u{16e57}', ['\u{16e77}', '\0', '\0']), ('\u{16e58}', + ['\u{16e78}', '\0', '\0']), ('\u{16e59}', ['\u{16e79}', '\0', '\0']), ('\u{16e5a}', + ['\u{16e7a}', '\0', '\0']), ('\u{16e5b}', ['\u{16e7b}', '\0', '\0']), ('\u{16e5c}', + ['\u{16e7c}', '\0', '\0']), ('\u{16e5d}', ['\u{16e7d}', '\0', '\0']), ('\u{16e5e}', + ['\u{16e7e}', '\0', '\0']), ('\u{16e5f}', ['\u{16e7f}', '\0', '\0']), ('\u{1e900}', + ['\u{1e922}', '\0', '\0']), ('\u{1e901}', ['\u{1e923}', '\0', '\0']), ('\u{1e902}', + ['\u{1e924}', '\0', '\0']), ('\u{1e903}', ['\u{1e925}', '\0', '\0']), ('\u{1e904}', + ['\u{1e926}', '\0', '\0']), ('\u{1e905}', ['\u{1e927}', '\0', '\0']), ('\u{1e906}', + ['\u{1e928}', '\0', '\0']), ('\u{1e907}', ['\u{1e929}', '\0', '\0']), ('\u{1e908}', + ['\u{1e92a}', '\0', '\0']), ('\u{1e909}', ['\u{1e92b}', '\0', '\0']), ('\u{1e90a}', + ['\u{1e92c}', '\0', '\0']), ('\u{1e90b}', ['\u{1e92d}', '\0', '\0']), ('\u{1e90c}', + ['\u{1e92e}', '\0', '\0']), ('\u{1e90d}', ['\u{1e92f}', '\0', '\0']), ('\u{1e90e}', + ['\u{1e930}', '\0', '\0']), ('\u{1e90f}', ['\u{1e931}', '\0', '\0']), ('\u{1e910}', + ['\u{1e932}', '\0', '\0']), ('\u{1e911}', ['\u{1e933}', '\0', '\0']), ('\u{1e912}', + ['\u{1e934}', '\0', '\0']), ('\u{1e913}', ['\u{1e935}', '\0', '\0']), ('\u{1e914}', + ['\u{1e936}', '\0', '\0']), ('\u{1e915}', ['\u{1e937}', '\0', '\0']), ('\u{1e916}', + ['\u{1e938}', '\0', '\0']), ('\u{1e917}', ['\u{1e939}', '\0', '\0']), ('\u{1e918}', + ['\u{1e93a}', '\0', '\0']), ('\u{1e919}', ['\u{1e93b}', '\0', '\0']), ('\u{1e91a}', + ['\u{1e93c}', '\0', '\0']), ('\u{1e91b}', ['\u{1e93d}', '\0', '\0']), ('\u{1e91c}', + ['\u{1e93e}', '\0', '\0']), ('\u{1e91d}', ['\u{1e93f}', '\0', '\0']), ('\u{1e91e}', + ['\u{1e940}', '\0', '\0']), ('\u{1e91f}', ['\u{1e941}', '\0', '\0']), ('\u{1e920}', + ['\u{1e942}', '\0', '\0']), ('\u{1e921}', ['\u{1e943}', '\0', '\0']) ]; const to_uppercase_table: &[(char, [char; 3])] = &[ @@ -1955,325 +2129,346 @@ pub mod conversions { ['\u{550}', '\0', '\0']), ('\u{581}', ['\u{551}', '\0', '\0']), ('\u{582}', ['\u{552}', '\0', '\0']), ('\u{583}', ['\u{553}', '\0', '\0']), ('\u{584}', ['\u{554}', '\0', '\0']), ('\u{585}', ['\u{555}', '\0', '\0']), ('\u{586}', ['\u{556}', '\0', '\0']), ('\u{587}', - ['\u{535}', '\u{552}', '\0']), ('\u{13f8}', ['\u{13f0}', '\0', '\0']), ('\u{13f9}', - ['\u{13f1}', '\0', '\0']), ('\u{13fa}', ['\u{13f2}', '\0', '\0']), ('\u{13fb}', ['\u{13f3}', - '\0', '\0']), ('\u{13fc}', ['\u{13f4}', '\0', '\0']), ('\u{13fd}', ['\u{13f5}', '\0', - '\0']), ('\u{1c80}', ['\u{412}', '\0', '\0']), ('\u{1c81}', ['\u{414}', '\0', '\0']), - ('\u{1c82}', ['\u{41e}', '\0', '\0']), ('\u{1c83}', ['\u{421}', '\0', '\0']), ('\u{1c84}', - ['\u{422}', '\0', '\0']), ('\u{1c85}', ['\u{422}', '\0', '\0']), ('\u{1c86}', ['\u{42a}', - '\0', '\0']), ('\u{1c87}', ['\u{462}', '\0', '\0']), ('\u{1c88}', ['\u{a64a}', '\0', '\0']), - ('\u{1d79}', ['\u{a77d}', '\0', '\0']), ('\u{1d7d}', ['\u{2c63}', '\0', '\0']), ('\u{1e01}', - ['\u{1e00}', '\0', '\0']), ('\u{1e03}', ['\u{1e02}', '\0', '\0']), ('\u{1e05}', ['\u{1e04}', - '\0', '\0']), ('\u{1e07}', ['\u{1e06}', '\0', '\0']), ('\u{1e09}', ['\u{1e08}', '\0', - '\0']), ('\u{1e0b}', ['\u{1e0a}', '\0', '\0']), ('\u{1e0d}', ['\u{1e0c}', '\0', '\0']), - ('\u{1e0f}', ['\u{1e0e}', '\0', '\0']), ('\u{1e11}', ['\u{1e10}', '\0', '\0']), ('\u{1e13}', - ['\u{1e12}', '\0', '\0']), ('\u{1e15}', ['\u{1e14}', '\0', '\0']), ('\u{1e17}', ['\u{1e16}', - '\0', '\0']), ('\u{1e19}', ['\u{1e18}', '\0', '\0']), ('\u{1e1b}', ['\u{1e1a}', '\0', - '\0']), ('\u{1e1d}', ['\u{1e1c}', '\0', '\0']), ('\u{1e1f}', ['\u{1e1e}', '\0', '\0']), - ('\u{1e21}', ['\u{1e20}', '\0', '\0']), ('\u{1e23}', ['\u{1e22}', '\0', '\0']), ('\u{1e25}', - ['\u{1e24}', '\0', '\0']), ('\u{1e27}', ['\u{1e26}', '\0', '\0']), ('\u{1e29}', ['\u{1e28}', - '\0', '\0']), ('\u{1e2b}', ['\u{1e2a}', '\0', '\0']), ('\u{1e2d}', ['\u{1e2c}', '\0', - '\0']), ('\u{1e2f}', ['\u{1e2e}', '\0', '\0']), ('\u{1e31}', ['\u{1e30}', '\0', '\0']), - ('\u{1e33}', ['\u{1e32}', '\0', '\0']), ('\u{1e35}', ['\u{1e34}', '\0', '\0']), ('\u{1e37}', - ['\u{1e36}', '\0', '\0']), ('\u{1e39}', ['\u{1e38}', '\0', '\0']), ('\u{1e3b}', ['\u{1e3a}', - '\0', '\0']), ('\u{1e3d}', ['\u{1e3c}', '\0', '\0']), ('\u{1e3f}', ['\u{1e3e}', '\0', - '\0']), ('\u{1e41}', ['\u{1e40}', '\0', '\0']), ('\u{1e43}', ['\u{1e42}', '\0', '\0']), - ('\u{1e45}', ['\u{1e44}', '\0', '\0']), ('\u{1e47}', ['\u{1e46}', '\0', '\0']), ('\u{1e49}', - ['\u{1e48}', '\0', '\0']), ('\u{1e4b}', ['\u{1e4a}', '\0', '\0']), ('\u{1e4d}', ['\u{1e4c}', - '\0', '\0']), ('\u{1e4f}', ['\u{1e4e}', '\0', '\0']), ('\u{1e51}', ['\u{1e50}', '\0', - '\0']), ('\u{1e53}', ['\u{1e52}', '\0', '\0']), ('\u{1e55}', ['\u{1e54}', '\0', '\0']), - ('\u{1e57}', ['\u{1e56}', '\0', '\0']), ('\u{1e59}', ['\u{1e58}', '\0', '\0']), ('\u{1e5b}', - ['\u{1e5a}', '\0', '\0']), ('\u{1e5d}', ['\u{1e5c}', '\0', '\0']), ('\u{1e5f}', ['\u{1e5e}', - '\0', '\0']), ('\u{1e61}', ['\u{1e60}', '\0', '\0']), ('\u{1e63}', ['\u{1e62}', '\0', - '\0']), ('\u{1e65}', ['\u{1e64}', '\0', '\0']), ('\u{1e67}', ['\u{1e66}', '\0', '\0']), - ('\u{1e69}', ['\u{1e68}', '\0', '\0']), ('\u{1e6b}', ['\u{1e6a}', '\0', '\0']), ('\u{1e6d}', - ['\u{1e6c}', '\0', '\0']), ('\u{1e6f}', ['\u{1e6e}', '\0', '\0']), ('\u{1e71}', ['\u{1e70}', - '\0', '\0']), ('\u{1e73}', ['\u{1e72}', '\0', '\0']), ('\u{1e75}', ['\u{1e74}', '\0', - '\0']), ('\u{1e77}', ['\u{1e76}', '\0', '\0']), ('\u{1e79}', ['\u{1e78}', '\0', '\0']), - ('\u{1e7b}', ['\u{1e7a}', '\0', '\0']), ('\u{1e7d}', ['\u{1e7c}', '\0', '\0']), ('\u{1e7f}', - ['\u{1e7e}', '\0', '\0']), ('\u{1e81}', ['\u{1e80}', '\0', '\0']), ('\u{1e83}', ['\u{1e82}', - '\0', '\0']), ('\u{1e85}', ['\u{1e84}', '\0', '\0']), ('\u{1e87}', ['\u{1e86}', '\0', - '\0']), ('\u{1e89}', ['\u{1e88}', '\0', '\0']), ('\u{1e8b}', ['\u{1e8a}', '\0', '\0']), - ('\u{1e8d}', ['\u{1e8c}', '\0', '\0']), ('\u{1e8f}', ['\u{1e8e}', '\0', '\0']), ('\u{1e91}', - ['\u{1e90}', '\0', '\0']), ('\u{1e93}', ['\u{1e92}', '\0', '\0']), ('\u{1e95}', ['\u{1e94}', - '\0', '\0']), ('\u{1e96}', ['\u{48}', '\u{331}', '\0']), ('\u{1e97}', ['\u{54}', '\u{308}', - '\0']), ('\u{1e98}', ['\u{57}', '\u{30a}', '\0']), ('\u{1e99}', ['\u{59}', '\u{30a}', - '\0']), ('\u{1e9a}', ['\u{41}', '\u{2be}', '\0']), ('\u{1e9b}', ['\u{1e60}', '\0', '\0']), - ('\u{1ea1}', ['\u{1ea0}', '\0', '\0']), ('\u{1ea3}', ['\u{1ea2}', '\0', '\0']), ('\u{1ea5}', - ['\u{1ea4}', '\0', '\0']), ('\u{1ea7}', ['\u{1ea6}', '\0', '\0']), ('\u{1ea9}', ['\u{1ea8}', - '\0', '\0']), ('\u{1eab}', ['\u{1eaa}', '\0', '\0']), ('\u{1ead}', ['\u{1eac}', '\0', - '\0']), ('\u{1eaf}', ['\u{1eae}', '\0', '\0']), ('\u{1eb1}', ['\u{1eb0}', '\0', '\0']), - ('\u{1eb3}', ['\u{1eb2}', '\0', '\0']), ('\u{1eb5}', ['\u{1eb4}', '\0', '\0']), ('\u{1eb7}', - ['\u{1eb6}', '\0', '\0']), ('\u{1eb9}', ['\u{1eb8}', '\0', '\0']), ('\u{1ebb}', ['\u{1eba}', - '\0', '\0']), ('\u{1ebd}', ['\u{1ebc}', '\0', '\0']), ('\u{1ebf}', ['\u{1ebe}', '\0', - '\0']), ('\u{1ec1}', ['\u{1ec0}', '\0', '\0']), ('\u{1ec3}', ['\u{1ec2}', '\0', '\0']), - ('\u{1ec5}', ['\u{1ec4}', '\0', '\0']), ('\u{1ec7}', ['\u{1ec6}', '\0', '\0']), ('\u{1ec9}', - ['\u{1ec8}', '\0', '\0']), ('\u{1ecb}', ['\u{1eca}', '\0', '\0']), ('\u{1ecd}', ['\u{1ecc}', - '\0', '\0']), ('\u{1ecf}', ['\u{1ece}', '\0', '\0']), ('\u{1ed1}', ['\u{1ed0}', '\0', - '\0']), ('\u{1ed3}', ['\u{1ed2}', '\0', '\0']), ('\u{1ed5}', ['\u{1ed4}', '\0', '\0']), - ('\u{1ed7}', ['\u{1ed6}', '\0', '\0']), ('\u{1ed9}', ['\u{1ed8}', '\0', '\0']), ('\u{1edb}', - ['\u{1eda}', '\0', '\0']), ('\u{1edd}', ['\u{1edc}', '\0', '\0']), ('\u{1edf}', ['\u{1ede}', - '\0', '\0']), ('\u{1ee1}', ['\u{1ee0}', '\0', '\0']), ('\u{1ee3}', ['\u{1ee2}', '\0', - '\0']), ('\u{1ee5}', ['\u{1ee4}', '\0', '\0']), ('\u{1ee7}', ['\u{1ee6}', '\0', '\0']), - ('\u{1ee9}', ['\u{1ee8}', '\0', '\0']), ('\u{1eeb}', ['\u{1eea}', '\0', '\0']), ('\u{1eed}', - ['\u{1eec}', '\0', '\0']), ('\u{1eef}', ['\u{1eee}', '\0', '\0']), ('\u{1ef1}', ['\u{1ef0}', - '\0', '\0']), ('\u{1ef3}', ['\u{1ef2}', '\0', '\0']), ('\u{1ef5}', ['\u{1ef4}', '\0', - '\0']), ('\u{1ef7}', ['\u{1ef6}', '\0', '\0']), ('\u{1ef9}', ['\u{1ef8}', '\0', '\0']), - ('\u{1efb}', ['\u{1efa}', '\0', '\0']), ('\u{1efd}', ['\u{1efc}', '\0', '\0']), ('\u{1eff}', - ['\u{1efe}', '\0', '\0']), ('\u{1f00}', ['\u{1f08}', '\0', '\0']), ('\u{1f01}', ['\u{1f09}', - '\0', '\0']), ('\u{1f02}', ['\u{1f0a}', '\0', '\0']), ('\u{1f03}', ['\u{1f0b}', '\0', - '\0']), ('\u{1f04}', ['\u{1f0c}', '\0', '\0']), ('\u{1f05}', ['\u{1f0d}', '\0', '\0']), - ('\u{1f06}', ['\u{1f0e}', '\0', '\0']), ('\u{1f07}', ['\u{1f0f}', '\0', '\0']), ('\u{1f10}', - ['\u{1f18}', '\0', '\0']), ('\u{1f11}', ['\u{1f19}', '\0', '\0']), ('\u{1f12}', ['\u{1f1a}', - '\0', '\0']), ('\u{1f13}', ['\u{1f1b}', '\0', '\0']), ('\u{1f14}', ['\u{1f1c}', '\0', - '\0']), ('\u{1f15}', ['\u{1f1d}', '\0', '\0']), ('\u{1f20}', ['\u{1f28}', '\0', '\0']), - ('\u{1f21}', ['\u{1f29}', '\0', '\0']), ('\u{1f22}', ['\u{1f2a}', '\0', '\0']), ('\u{1f23}', - ['\u{1f2b}', '\0', '\0']), ('\u{1f24}', ['\u{1f2c}', '\0', '\0']), ('\u{1f25}', ['\u{1f2d}', - '\0', '\0']), ('\u{1f26}', ['\u{1f2e}', '\0', '\0']), ('\u{1f27}', ['\u{1f2f}', '\0', - '\0']), ('\u{1f30}', ['\u{1f38}', '\0', '\0']), ('\u{1f31}', ['\u{1f39}', '\0', '\0']), - ('\u{1f32}', ['\u{1f3a}', '\0', '\0']), ('\u{1f33}', ['\u{1f3b}', '\0', '\0']), ('\u{1f34}', - ['\u{1f3c}', '\0', '\0']), ('\u{1f35}', ['\u{1f3d}', '\0', '\0']), ('\u{1f36}', ['\u{1f3e}', - '\0', '\0']), ('\u{1f37}', ['\u{1f3f}', '\0', '\0']), ('\u{1f40}', ['\u{1f48}', '\0', - '\0']), ('\u{1f41}', ['\u{1f49}', '\0', '\0']), ('\u{1f42}', ['\u{1f4a}', '\0', '\0']), - ('\u{1f43}', ['\u{1f4b}', '\0', '\0']), ('\u{1f44}', ['\u{1f4c}', '\0', '\0']), ('\u{1f45}', - ['\u{1f4d}', '\0', '\0']), ('\u{1f50}', ['\u{3a5}', '\u{313}', '\0']), ('\u{1f51}', - ['\u{1f59}', '\0', '\0']), ('\u{1f52}', ['\u{3a5}', '\u{313}', '\u{300}']), ('\u{1f53}', - ['\u{1f5b}', '\0', '\0']), ('\u{1f54}', ['\u{3a5}', '\u{313}', '\u{301}']), ('\u{1f55}', - ['\u{1f5d}', '\0', '\0']), ('\u{1f56}', ['\u{3a5}', '\u{313}', '\u{342}']), ('\u{1f57}', - ['\u{1f5f}', '\0', '\0']), ('\u{1f60}', ['\u{1f68}', '\0', '\0']), ('\u{1f61}', ['\u{1f69}', - '\0', '\0']), ('\u{1f62}', ['\u{1f6a}', '\0', '\0']), ('\u{1f63}', ['\u{1f6b}', '\0', - '\0']), ('\u{1f64}', ['\u{1f6c}', '\0', '\0']), ('\u{1f65}', ['\u{1f6d}', '\0', '\0']), - ('\u{1f66}', ['\u{1f6e}', '\0', '\0']), ('\u{1f67}', ['\u{1f6f}', '\0', '\0']), ('\u{1f70}', - ['\u{1fba}', '\0', '\0']), ('\u{1f71}', ['\u{1fbb}', '\0', '\0']), ('\u{1f72}', ['\u{1fc8}', - '\0', '\0']), ('\u{1f73}', ['\u{1fc9}', '\0', '\0']), ('\u{1f74}', ['\u{1fca}', '\0', - '\0']), ('\u{1f75}', ['\u{1fcb}', '\0', '\0']), ('\u{1f76}', ['\u{1fda}', '\0', '\0']), - ('\u{1f77}', ['\u{1fdb}', '\0', '\0']), ('\u{1f78}', ['\u{1ff8}', '\0', '\0']), ('\u{1f79}', - ['\u{1ff9}', '\0', '\0']), ('\u{1f7a}', ['\u{1fea}', '\0', '\0']), ('\u{1f7b}', ['\u{1feb}', - '\0', '\0']), ('\u{1f7c}', ['\u{1ffa}', '\0', '\0']), ('\u{1f7d}', ['\u{1ffb}', '\0', - '\0']), ('\u{1f80}', ['\u{1f08}', '\u{399}', '\0']), ('\u{1f81}', ['\u{1f09}', '\u{399}', - '\0']), ('\u{1f82}', ['\u{1f0a}', '\u{399}', '\0']), ('\u{1f83}', ['\u{1f0b}', '\u{399}', - '\0']), ('\u{1f84}', ['\u{1f0c}', '\u{399}', '\0']), ('\u{1f85}', ['\u{1f0d}', '\u{399}', - '\0']), ('\u{1f86}', ['\u{1f0e}', '\u{399}', '\0']), ('\u{1f87}', ['\u{1f0f}', '\u{399}', - '\0']), ('\u{1f88}', ['\u{1f08}', '\u{399}', '\0']), ('\u{1f89}', ['\u{1f09}', '\u{399}', - '\0']), ('\u{1f8a}', ['\u{1f0a}', '\u{399}', '\0']), ('\u{1f8b}', ['\u{1f0b}', '\u{399}', - '\0']), ('\u{1f8c}', ['\u{1f0c}', '\u{399}', '\0']), ('\u{1f8d}', ['\u{1f0d}', '\u{399}', - '\0']), ('\u{1f8e}', ['\u{1f0e}', '\u{399}', '\0']), ('\u{1f8f}', ['\u{1f0f}', '\u{399}', - '\0']), ('\u{1f90}', ['\u{1f28}', '\u{399}', '\0']), ('\u{1f91}', ['\u{1f29}', '\u{399}', - '\0']), ('\u{1f92}', ['\u{1f2a}', '\u{399}', '\0']), ('\u{1f93}', ['\u{1f2b}', '\u{399}', - '\0']), ('\u{1f94}', ['\u{1f2c}', '\u{399}', '\0']), ('\u{1f95}', ['\u{1f2d}', '\u{399}', - '\0']), ('\u{1f96}', ['\u{1f2e}', '\u{399}', '\0']), ('\u{1f97}', ['\u{1f2f}', '\u{399}', - '\0']), ('\u{1f98}', ['\u{1f28}', '\u{399}', '\0']), ('\u{1f99}', ['\u{1f29}', '\u{399}', - '\0']), ('\u{1f9a}', ['\u{1f2a}', '\u{399}', '\0']), ('\u{1f9b}', ['\u{1f2b}', '\u{399}', - '\0']), ('\u{1f9c}', ['\u{1f2c}', '\u{399}', '\0']), ('\u{1f9d}', ['\u{1f2d}', '\u{399}', - '\0']), ('\u{1f9e}', ['\u{1f2e}', '\u{399}', '\0']), ('\u{1f9f}', ['\u{1f2f}', '\u{399}', - '\0']), ('\u{1fa0}', ['\u{1f68}', '\u{399}', '\0']), ('\u{1fa1}', ['\u{1f69}', '\u{399}', - '\0']), ('\u{1fa2}', ['\u{1f6a}', '\u{399}', '\0']), ('\u{1fa3}', ['\u{1f6b}', '\u{399}', - '\0']), ('\u{1fa4}', ['\u{1f6c}', '\u{399}', '\0']), ('\u{1fa5}', ['\u{1f6d}', '\u{399}', - '\0']), ('\u{1fa6}', ['\u{1f6e}', '\u{399}', '\0']), ('\u{1fa7}', ['\u{1f6f}', '\u{399}', - '\0']), ('\u{1fa8}', ['\u{1f68}', '\u{399}', '\0']), ('\u{1fa9}', ['\u{1f69}', '\u{399}', - '\0']), ('\u{1faa}', ['\u{1f6a}', '\u{399}', '\0']), ('\u{1fab}', ['\u{1f6b}', '\u{399}', - '\0']), ('\u{1fac}', ['\u{1f6c}', '\u{399}', '\0']), ('\u{1fad}', ['\u{1f6d}', '\u{399}', - '\0']), ('\u{1fae}', ['\u{1f6e}', '\u{399}', '\0']), ('\u{1faf}', ['\u{1f6f}', '\u{399}', - '\0']), ('\u{1fb0}', ['\u{1fb8}', '\0', '\0']), ('\u{1fb1}', ['\u{1fb9}', '\0', '\0']), - ('\u{1fb2}', ['\u{1fba}', '\u{399}', '\0']), ('\u{1fb3}', ['\u{391}', '\u{399}', '\0']), - ('\u{1fb4}', ['\u{386}', '\u{399}', '\0']), ('\u{1fb6}', ['\u{391}', '\u{342}', '\0']), - ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{399}']), ('\u{1fbc}', ['\u{391}', '\u{399}', '\0']), - ('\u{1fbe}', ['\u{399}', '\0', '\0']), ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\0']), - ('\u{1fc3}', ['\u{397}', '\u{399}', '\0']), ('\u{1fc4}', ['\u{389}', '\u{399}', '\0']), - ('\u{1fc6}', ['\u{397}', '\u{342}', '\0']), ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), - ('\u{1fcc}', ['\u{397}', '\u{399}', '\0']), ('\u{1fd0}', ['\u{1fd8}', '\0', '\0']), - ('\u{1fd1}', ['\u{1fd9}', '\0', '\0']), ('\u{1fd2}', ['\u{399}', '\u{308}', '\u{300}']), - ('\u{1fd3}', ['\u{399}', '\u{308}', '\u{301}']), ('\u{1fd6}', ['\u{399}', '\u{342}', '\0']), - ('\u{1fd7}', ['\u{399}', '\u{308}', '\u{342}']), ('\u{1fe0}', ['\u{1fe8}', '\0', '\0']), - ('\u{1fe1}', ['\u{1fe9}', '\0', '\0']), ('\u{1fe2}', ['\u{3a5}', '\u{308}', '\u{300}']), - ('\u{1fe3}', ['\u{3a5}', '\u{308}', '\u{301}']), ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\0']), - ('\u{1fe5}', ['\u{1fec}', '\0', '\0']), ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\0']), - ('\u{1fe7}', ['\u{3a5}', '\u{308}', '\u{342}']), ('\u{1ff2}', ['\u{1ffa}', '\u{399}', - '\0']), ('\u{1ff3}', ['\u{3a9}', '\u{399}', '\0']), ('\u{1ff4}', ['\u{38f}', '\u{399}', - '\0']), ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\0']), ('\u{1ff7}', ['\u{3a9}', '\u{342}', - '\u{399}']), ('\u{1ffc}', ['\u{3a9}', '\u{399}', '\0']), ('\u{214e}', ['\u{2132}', '\0', - '\0']), ('\u{2170}', ['\u{2160}', '\0', '\0']), ('\u{2171}', ['\u{2161}', '\0', '\0']), - ('\u{2172}', ['\u{2162}', '\0', '\0']), ('\u{2173}', ['\u{2163}', '\0', '\0']), ('\u{2174}', - ['\u{2164}', '\0', '\0']), ('\u{2175}', ['\u{2165}', '\0', '\0']), ('\u{2176}', ['\u{2166}', - '\0', '\0']), ('\u{2177}', ['\u{2167}', '\0', '\0']), ('\u{2178}', ['\u{2168}', '\0', - '\0']), ('\u{2179}', ['\u{2169}', '\0', '\0']), ('\u{217a}', ['\u{216a}', '\0', '\0']), - ('\u{217b}', ['\u{216b}', '\0', '\0']), ('\u{217c}', ['\u{216c}', '\0', '\0']), ('\u{217d}', - ['\u{216d}', '\0', '\0']), ('\u{217e}', ['\u{216e}', '\0', '\0']), ('\u{217f}', ['\u{216f}', - '\0', '\0']), ('\u{2184}', ['\u{2183}', '\0', '\0']), ('\u{24d0}', ['\u{24b6}', '\0', - '\0']), ('\u{24d1}', ['\u{24b7}', '\0', '\0']), ('\u{24d2}', ['\u{24b8}', '\0', '\0']), - ('\u{24d3}', ['\u{24b9}', '\0', '\0']), ('\u{24d4}', ['\u{24ba}', '\0', '\0']), ('\u{24d5}', - ['\u{24bb}', '\0', '\0']), ('\u{24d6}', ['\u{24bc}', '\0', '\0']), ('\u{24d7}', ['\u{24bd}', - '\0', '\0']), ('\u{24d8}', ['\u{24be}', '\0', '\0']), ('\u{24d9}', ['\u{24bf}', '\0', - '\0']), ('\u{24da}', ['\u{24c0}', '\0', '\0']), ('\u{24db}', ['\u{24c1}', '\0', '\0']), - ('\u{24dc}', ['\u{24c2}', '\0', '\0']), ('\u{24dd}', ['\u{24c3}', '\0', '\0']), ('\u{24de}', - ['\u{24c4}', '\0', '\0']), ('\u{24df}', ['\u{24c5}', '\0', '\0']), ('\u{24e0}', ['\u{24c6}', - '\0', '\0']), ('\u{24e1}', ['\u{24c7}', '\0', '\0']), ('\u{24e2}', ['\u{24c8}', '\0', - '\0']), ('\u{24e3}', ['\u{24c9}', '\0', '\0']), ('\u{24e4}', ['\u{24ca}', '\0', '\0']), - ('\u{24e5}', ['\u{24cb}', '\0', '\0']), ('\u{24e6}', ['\u{24cc}', '\0', '\0']), ('\u{24e7}', - ['\u{24cd}', '\0', '\0']), ('\u{24e8}', ['\u{24ce}', '\0', '\0']), ('\u{24e9}', ['\u{24cf}', - '\0', '\0']), ('\u{2c30}', ['\u{2c00}', '\0', '\0']), ('\u{2c31}', ['\u{2c01}', '\0', - '\0']), ('\u{2c32}', ['\u{2c02}', '\0', '\0']), ('\u{2c33}', ['\u{2c03}', '\0', '\0']), - ('\u{2c34}', ['\u{2c04}', '\0', '\0']), ('\u{2c35}', ['\u{2c05}', '\0', '\0']), ('\u{2c36}', - ['\u{2c06}', '\0', '\0']), ('\u{2c37}', ['\u{2c07}', '\0', '\0']), ('\u{2c38}', ['\u{2c08}', - '\0', '\0']), ('\u{2c39}', ['\u{2c09}', '\0', '\0']), ('\u{2c3a}', ['\u{2c0a}', '\0', - '\0']), ('\u{2c3b}', ['\u{2c0b}', '\0', '\0']), ('\u{2c3c}', ['\u{2c0c}', '\0', '\0']), - ('\u{2c3d}', ['\u{2c0d}', '\0', '\0']), ('\u{2c3e}', ['\u{2c0e}', '\0', '\0']), ('\u{2c3f}', - ['\u{2c0f}', '\0', '\0']), ('\u{2c40}', ['\u{2c10}', '\0', '\0']), ('\u{2c41}', ['\u{2c11}', - '\0', '\0']), ('\u{2c42}', ['\u{2c12}', '\0', '\0']), ('\u{2c43}', ['\u{2c13}', '\0', - '\0']), ('\u{2c44}', ['\u{2c14}', '\0', '\0']), ('\u{2c45}', ['\u{2c15}', '\0', '\0']), - ('\u{2c46}', ['\u{2c16}', '\0', '\0']), ('\u{2c47}', ['\u{2c17}', '\0', '\0']), ('\u{2c48}', - ['\u{2c18}', '\0', '\0']), ('\u{2c49}', ['\u{2c19}', '\0', '\0']), ('\u{2c4a}', ['\u{2c1a}', - '\0', '\0']), ('\u{2c4b}', ['\u{2c1b}', '\0', '\0']), ('\u{2c4c}', ['\u{2c1c}', '\0', - '\0']), ('\u{2c4d}', ['\u{2c1d}', '\0', '\0']), ('\u{2c4e}', ['\u{2c1e}', '\0', '\0']), - ('\u{2c4f}', ['\u{2c1f}', '\0', '\0']), ('\u{2c50}', ['\u{2c20}', '\0', '\0']), ('\u{2c51}', - ['\u{2c21}', '\0', '\0']), ('\u{2c52}', ['\u{2c22}', '\0', '\0']), ('\u{2c53}', ['\u{2c23}', - '\0', '\0']), ('\u{2c54}', ['\u{2c24}', '\0', '\0']), ('\u{2c55}', ['\u{2c25}', '\0', - '\0']), ('\u{2c56}', ['\u{2c26}', '\0', '\0']), ('\u{2c57}', ['\u{2c27}', '\0', '\0']), - ('\u{2c58}', ['\u{2c28}', '\0', '\0']), ('\u{2c59}', ['\u{2c29}', '\0', '\0']), ('\u{2c5a}', - ['\u{2c2a}', '\0', '\0']), ('\u{2c5b}', ['\u{2c2b}', '\0', '\0']), ('\u{2c5c}', ['\u{2c2c}', - '\0', '\0']), ('\u{2c5d}', ['\u{2c2d}', '\0', '\0']), ('\u{2c5e}', ['\u{2c2e}', '\0', - '\0']), ('\u{2c61}', ['\u{2c60}', '\0', '\0']), ('\u{2c65}', ['\u{23a}', '\0', '\0']), - ('\u{2c66}', ['\u{23e}', '\0', '\0']), ('\u{2c68}', ['\u{2c67}', '\0', '\0']), ('\u{2c6a}', - ['\u{2c69}', '\0', '\0']), ('\u{2c6c}', ['\u{2c6b}', '\0', '\0']), ('\u{2c73}', ['\u{2c72}', - '\0', '\0']), ('\u{2c76}', ['\u{2c75}', '\0', '\0']), ('\u{2c81}', ['\u{2c80}', '\0', - '\0']), ('\u{2c83}', ['\u{2c82}', '\0', '\0']), ('\u{2c85}', ['\u{2c84}', '\0', '\0']), - ('\u{2c87}', ['\u{2c86}', '\0', '\0']), ('\u{2c89}', ['\u{2c88}', '\0', '\0']), ('\u{2c8b}', - ['\u{2c8a}', '\0', '\0']), ('\u{2c8d}', ['\u{2c8c}', '\0', '\0']), ('\u{2c8f}', ['\u{2c8e}', - '\0', '\0']), ('\u{2c91}', ['\u{2c90}', '\0', '\0']), ('\u{2c93}', ['\u{2c92}', '\0', - '\0']), ('\u{2c95}', ['\u{2c94}', '\0', '\0']), ('\u{2c97}', ['\u{2c96}', '\0', '\0']), - ('\u{2c99}', ['\u{2c98}', '\0', '\0']), ('\u{2c9b}', ['\u{2c9a}', '\0', '\0']), ('\u{2c9d}', - ['\u{2c9c}', '\0', '\0']), ('\u{2c9f}', ['\u{2c9e}', '\0', '\0']), ('\u{2ca1}', ['\u{2ca0}', - '\0', '\0']), ('\u{2ca3}', ['\u{2ca2}', '\0', '\0']), ('\u{2ca5}', ['\u{2ca4}', '\0', - '\0']), ('\u{2ca7}', ['\u{2ca6}', '\0', '\0']), ('\u{2ca9}', ['\u{2ca8}', '\0', '\0']), - ('\u{2cab}', ['\u{2caa}', '\0', '\0']), ('\u{2cad}', ['\u{2cac}', '\0', '\0']), ('\u{2caf}', - ['\u{2cae}', '\0', '\0']), ('\u{2cb1}', ['\u{2cb0}', '\0', '\0']), ('\u{2cb3}', ['\u{2cb2}', - '\0', '\0']), ('\u{2cb5}', ['\u{2cb4}', '\0', '\0']), ('\u{2cb7}', ['\u{2cb6}', '\0', - '\0']), ('\u{2cb9}', ['\u{2cb8}', '\0', '\0']), ('\u{2cbb}', ['\u{2cba}', '\0', '\0']), - ('\u{2cbd}', ['\u{2cbc}', '\0', '\0']), ('\u{2cbf}', ['\u{2cbe}', '\0', '\0']), ('\u{2cc1}', - ['\u{2cc0}', '\0', '\0']), ('\u{2cc3}', ['\u{2cc2}', '\0', '\0']), ('\u{2cc5}', ['\u{2cc4}', - '\0', '\0']), ('\u{2cc7}', ['\u{2cc6}', '\0', '\0']), ('\u{2cc9}', ['\u{2cc8}', '\0', - '\0']), ('\u{2ccb}', ['\u{2cca}', '\0', '\0']), ('\u{2ccd}', ['\u{2ccc}', '\0', '\0']), - ('\u{2ccf}', ['\u{2cce}', '\0', '\0']), ('\u{2cd1}', ['\u{2cd0}', '\0', '\0']), ('\u{2cd3}', - ['\u{2cd2}', '\0', '\0']), ('\u{2cd5}', ['\u{2cd4}', '\0', '\0']), ('\u{2cd7}', ['\u{2cd6}', - '\0', '\0']), ('\u{2cd9}', ['\u{2cd8}', '\0', '\0']), ('\u{2cdb}', ['\u{2cda}', '\0', - '\0']), ('\u{2cdd}', ['\u{2cdc}', '\0', '\0']), ('\u{2cdf}', ['\u{2cde}', '\0', '\0']), - ('\u{2ce1}', ['\u{2ce0}', '\0', '\0']), ('\u{2ce3}', ['\u{2ce2}', '\0', '\0']), ('\u{2cec}', - ['\u{2ceb}', '\0', '\0']), ('\u{2cee}', ['\u{2ced}', '\0', '\0']), ('\u{2cf3}', ['\u{2cf2}', - '\0', '\0']), ('\u{2d00}', ['\u{10a0}', '\0', '\0']), ('\u{2d01}', ['\u{10a1}', '\0', - '\0']), ('\u{2d02}', ['\u{10a2}', '\0', '\0']), ('\u{2d03}', ['\u{10a3}', '\0', '\0']), - ('\u{2d04}', ['\u{10a4}', '\0', '\0']), ('\u{2d05}', ['\u{10a5}', '\0', '\0']), ('\u{2d06}', - ['\u{10a6}', '\0', '\0']), ('\u{2d07}', ['\u{10a7}', '\0', '\0']), ('\u{2d08}', ['\u{10a8}', - '\0', '\0']), ('\u{2d09}', ['\u{10a9}', '\0', '\0']), ('\u{2d0a}', ['\u{10aa}', '\0', - '\0']), ('\u{2d0b}', ['\u{10ab}', '\0', '\0']), ('\u{2d0c}', ['\u{10ac}', '\0', '\0']), - ('\u{2d0d}', ['\u{10ad}', '\0', '\0']), ('\u{2d0e}', ['\u{10ae}', '\0', '\0']), ('\u{2d0f}', - ['\u{10af}', '\0', '\0']), ('\u{2d10}', ['\u{10b0}', '\0', '\0']), ('\u{2d11}', ['\u{10b1}', - '\0', '\0']), ('\u{2d12}', ['\u{10b2}', '\0', '\0']), ('\u{2d13}', ['\u{10b3}', '\0', - '\0']), ('\u{2d14}', ['\u{10b4}', '\0', '\0']), ('\u{2d15}', ['\u{10b5}', '\0', '\0']), - ('\u{2d16}', ['\u{10b6}', '\0', '\0']), ('\u{2d17}', ['\u{10b7}', '\0', '\0']), ('\u{2d18}', - ['\u{10b8}', '\0', '\0']), ('\u{2d19}', ['\u{10b9}', '\0', '\0']), ('\u{2d1a}', ['\u{10ba}', - '\0', '\0']), ('\u{2d1b}', ['\u{10bb}', '\0', '\0']), ('\u{2d1c}', ['\u{10bc}', '\0', - '\0']), ('\u{2d1d}', ['\u{10bd}', '\0', '\0']), ('\u{2d1e}', ['\u{10be}', '\0', '\0']), - ('\u{2d1f}', ['\u{10bf}', '\0', '\0']), ('\u{2d20}', ['\u{10c0}', '\0', '\0']), ('\u{2d21}', - ['\u{10c1}', '\0', '\0']), ('\u{2d22}', ['\u{10c2}', '\0', '\0']), ('\u{2d23}', ['\u{10c3}', - '\0', '\0']), ('\u{2d24}', ['\u{10c4}', '\0', '\0']), ('\u{2d25}', ['\u{10c5}', '\0', - '\0']), ('\u{2d27}', ['\u{10c7}', '\0', '\0']), ('\u{2d2d}', ['\u{10cd}', '\0', '\0']), - ('\u{a641}', ['\u{a640}', '\0', '\0']), ('\u{a643}', ['\u{a642}', '\0', '\0']), ('\u{a645}', - ['\u{a644}', '\0', '\0']), ('\u{a647}', ['\u{a646}', '\0', '\0']), ('\u{a649}', ['\u{a648}', - '\0', '\0']), ('\u{a64b}', ['\u{a64a}', '\0', '\0']), ('\u{a64d}', ['\u{a64c}', '\0', - '\0']), ('\u{a64f}', ['\u{a64e}', '\0', '\0']), ('\u{a651}', ['\u{a650}', '\0', '\0']), - ('\u{a653}', ['\u{a652}', '\0', '\0']), ('\u{a655}', ['\u{a654}', '\0', '\0']), ('\u{a657}', - ['\u{a656}', '\0', '\0']), ('\u{a659}', ['\u{a658}', '\0', '\0']), ('\u{a65b}', ['\u{a65a}', - '\0', '\0']), ('\u{a65d}', ['\u{a65c}', '\0', '\0']), ('\u{a65f}', ['\u{a65e}', '\0', - '\0']), ('\u{a661}', ['\u{a660}', '\0', '\0']), ('\u{a663}', ['\u{a662}', '\0', '\0']), - ('\u{a665}', ['\u{a664}', '\0', '\0']), ('\u{a667}', ['\u{a666}', '\0', '\0']), ('\u{a669}', - ['\u{a668}', '\0', '\0']), ('\u{a66b}', ['\u{a66a}', '\0', '\0']), ('\u{a66d}', ['\u{a66c}', - '\0', '\0']), ('\u{a681}', ['\u{a680}', '\0', '\0']), ('\u{a683}', ['\u{a682}', '\0', - '\0']), ('\u{a685}', ['\u{a684}', '\0', '\0']), ('\u{a687}', ['\u{a686}', '\0', '\0']), - ('\u{a689}', ['\u{a688}', '\0', '\0']), ('\u{a68b}', ['\u{a68a}', '\0', '\0']), ('\u{a68d}', - ['\u{a68c}', '\0', '\0']), ('\u{a68f}', ['\u{a68e}', '\0', '\0']), ('\u{a691}', ['\u{a690}', - '\0', '\0']), ('\u{a693}', ['\u{a692}', '\0', '\0']), ('\u{a695}', ['\u{a694}', '\0', - '\0']), ('\u{a697}', ['\u{a696}', '\0', '\0']), ('\u{a699}', ['\u{a698}', '\0', '\0']), - ('\u{a69b}', ['\u{a69a}', '\0', '\0']), ('\u{a723}', ['\u{a722}', '\0', '\0']), ('\u{a725}', - ['\u{a724}', '\0', '\0']), ('\u{a727}', ['\u{a726}', '\0', '\0']), ('\u{a729}', ['\u{a728}', - '\0', '\0']), ('\u{a72b}', ['\u{a72a}', '\0', '\0']), ('\u{a72d}', ['\u{a72c}', '\0', - '\0']), ('\u{a72f}', ['\u{a72e}', '\0', '\0']), ('\u{a733}', ['\u{a732}', '\0', '\0']), - ('\u{a735}', ['\u{a734}', '\0', '\0']), ('\u{a737}', ['\u{a736}', '\0', '\0']), ('\u{a739}', - ['\u{a738}', '\0', '\0']), ('\u{a73b}', ['\u{a73a}', '\0', '\0']), ('\u{a73d}', ['\u{a73c}', - '\0', '\0']), ('\u{a73f}', ['\u{a73e}', '\0', '\0']), ('\u{a741}', ['\u{a740}', '\0', - '\0']), ('\u{a743}', ['\u{a742}', '\0', '\0']), ('\u{a745}', ['\u{a744}', '\0', '\0']), - ('\u{a747}', ['\u{a746}', '\0', '\0']), ('\u{a749}', ['\u{a748}', '\0', '\0']), ('\u{a74b}', - ['\u{a74a}', '\0', '\0']), ('\u{a74d}', ['\u{a74c}', '\0', '\0']), ('\u{a74f}', ['\u{a74e}', - '\0', '\0']), ('\u{a751}', ['\u{a750}', '\0', '\0']), ('\u{a753}', ['\u{a752}', '\0', - '\0']), ('\u{a755}', ['\u{a754}', '\0', '\0']), ('\u{a757}', ['\u{a756}', '\0', '\0']), - ('\u{a759}', ['\u{a758}', '\0', '\0']), ('\u{a75b}', ['\u{a75a}', '\0', '\0']), ('\u{a75d}', - ['\u{a75c}', '\0', '\0']), ('\u{a75f}', ['\u{a75e}', '\0', '\0']), ('\u{a761}', ['\u{a760}', - '\0', '\0']), ('\u{a763}', ['\u{a762}', '\0', '\0']), ('\u{a765}', ['\u{a764}', '\0', - '\0']), ('\u{a767}', ['\u{a766}', '\0', '\0']), ('\u{a769}', ['\u{a768}', '\0', '\0']), - ('\u{a76b}', ['\u{a76a}', '\0', '\0']), ('\u{a76d}', ['\u{a76c}', '\0', '\0']), ('\u{a76f}', - ['\u{a76e}', '\0', '\0']), ('\u{a77a}', ['\u{a779}', '\0', '\0']), ('\u{a77c}', ['\u{a77b}', - '\0', '\0']), ('\u{a77f}', ['\u{a77e}', '\0', '\0']), ('\u{a781}', ['\u{a780}', '\0', - '\0']), ('\u{a783}', ['\u{a782}', '\0', '\0']), ('\u{a785}', ['\u{a784}', '\0', '\0']), - ('\u{a787}', ['\u{a786}', '\0', '\0']), ('\u{a78c}', ['\u{a78b}', '\0', '\0']), ('\u{a791}', - ['\u{a790}', '\0', '\0']), ('\u{a793}', ['\u{a792}', '\0', '\0']), ('\u{a797}', ['\u{a796}', - '\0', '\0']), ('\u{a799}', ['\u{a798}', '\0', '\0']), ('\u{a79b}', ['\u{a79a}', '\0', - '\0']), ('\u{a79d}', ['\u{a79c}', '\0', '\0']), ('\u{a79f}', ['\u{a79e}', '\0', '\0']), - ('\u{a7a1}', ['\u{a7a0}', '\0', '\0']), ('\u{a7a3}', ['\u{a7a2}', '\0', '\0']), ('\u{a7a5}', - ['\u{a7a4}', '\0', '\0']), ('\u{a7a7}', ['\u{a7a6}', '\0', '\0']), ('\u{a7a9}', ['\u{a7a8}', - '\0', '\0']), ('\u{a7b5}', ['\u{a7b4}', '\0', '\0']), ('\u{a7b7}', ['\u{a7b6}', '\0', - '\0']), ('\u{ab53}', ['\u{a7b3}', '\0', '\0']), ('\u{ab70}', ['\u{13a0}', '\0', '\0']), - ('\u{ab71}', ['\u{13a1}', '\0', '\0']), ('\u{ab72}', ['\u{13a2}', '\0', '\0']), ('\u{ab73}', - ['\u{13a3}', '\0', '\0']), ('\u{ab74}', ['\u{13a4}', '\0', '\0']), ('\u{ab75}', ['\u{13a5}', - '\0', '\0']), ('\u{ab76}', ['\u{13a6}', '\0', '\0']), ('\u{ab77}', ['\u{13a7}', '\0', - '\0']), ('\u{ab78}', ['\u{13a8}', '\0', '\0']), ('\u{ab79}', ['\u{13a9}', '\0', '\0']), - ('\u{ab7a}', ['\u{13aa}', '\0', '\0']), ('\u{ab7b}', ['\u{13ab}', '\0', '\0']), ('\u{ab7c}', - ['\u{13ac}', '\0', '\0']), ('\u{ab7d}', ['\u{13ad}', '\0', '\0']), ('\u{ab7e}', ['\u{13ae}', - '\0', '\0']), ('\u{ab7f}', ['\u{13af}', '\0', '\0']), ('\u{ab80}', ['\u{13b0}', '\0', - '\0']), ('\u{ab81}', ['\u{13b1}', '\0', '\0']), ('\u{ab82}', ['\u{13b2}', '\0', '\0']), - ('\u{ab83}', ['\u{13b3}', '\0', '\0']), ('\u{ab84}', ['\u{13b4}', '\0', '\0']), ('\u{ab85}', - ['\u{13b5}', '\0', '\0']), ('\u{ab86}', ['\u{13b6}', '\0', '\0']), ('\u{ab87}', ['\u{13b7}', - '\0', '\0']), ('\u{ab88}', ['\u{13b8}', '\0', '\0']), ('\u{ab89}', ['\u{13b9}', '\0', - '\0']), ('\u{ab8a}', ['\u{13ba}', '\0', '\0']), ('\u{ab8b}', ['\u{13bb}', '\0', '\0']), - ('\u{ab8c}', ['\u{13bc}', '\0', '\0']), ('\u{ab8d}', ['\u{13bd}', '\0', '\0']), ('\u{ab8e}', - ['\u{13be}', '\0', '\0']), ('\u{ab8f}', ['\u{13bf}', '\0', '\0']), ('\u{ab90}', ['\u{13c0}', - '\0', '\0']), ('\u{ab91}', ['\u{13c1}', '\0', '\0']), ('\u{ab92}', ['\u{13c2}', '\0', - '\0']), ('\u{ab93}', ['\u{13c3}', '\0', '\0']), ('\u{ab94}', ['\u{13c4}', '\0', '\0']), - ('\u{ab95}', ['\u{13c5}', '\0', '\0']), ('\u{ab96}', ['\u{13c6}', '\0', '\0']), ('\u{ab97}', - ['\u{13c7}', '\0', '\0']), ('\u{ab98}', ['\u{13c8}', '\0', '\0']), ('\u{ab99}', ['\u{13c9}', - '\0', '\0']), ('\u{ab9a}', ['\u{13ca}', '\0', '\0']), ('\u{ab9b}', ['\u{13cb}', '\0', - '\0']), ('\u{ab9c}', ['\u{13cc}', '\0', '\0']), ('\u{ab9d}', ['\u{13cd}', '\0', '\0']), - ('\u{ab9e}', ['\u{13ce}', '\0', '\0']), ('\u{ab9f}', ['\u{13cf}', '\0', '\0']), ('\u{aba0}', - ['\u{13d0}', '\0', '\0']), ('\u{aba1}', ['\u{13d1}', '\0', '\0']), ('\u{aba2}', ['\u{13d2}', - '\0', '\0']), ('\u{aba3}', ['\u{13d3}', '\0', '\0']), ('\u{aba4}', ['\u{13d4}', '\0', - '\0']), ('\u{aba5}', ['\u{13d5}', '\0', '\0']), ('\u{aba6}', ['\u{13d6}', '\0', '\0']), - ('\u{aba7}', ['\u{13d7}', '\0', '\0']), ('\u{aba8}', ['\u{13d8}', '\0', '\0']), ('\u{aba9}', - ['\u{13d9}', '\0', '\0']), ('\u{abaa}', ['\u{13da}', '\0', '\0']), ('\u{abab}', ['\u{13db}', - '\0', '\0']), ('\u{abac}', ['\u{13dc}', '\0', '\0']), ('\u{abad}', ['\u{13dd}', '\0', - '\0']), ('\u{abae}', ['\u{13de}', '\0', '\0']), ('\u{abaf}', ['\u{13df}', '\0', '\0']), - ('\u{abb0}', ['\u{13e0}', '\0', '\0']), ('\u{abb1}', ['\u{13e1}', '\0', '\0']), ('\u{abb2}', - ['\u{13e2}', '\0', '\0']), ('\u{abb3}', ['\u{13e3}', '\0', '\0']), ('\u{abb4}', ['\u{13e4}', - '\0', '\0']), ('\u{abb5}', ['\u{13e5}', '\0', '\0']), ('\u{abb6}', ['\u{13e6}', '\0', - '\0']), ('\u{abb7}', ['\u{13e7}', '\0', '\0']), ('\u{abb8}', ['\u{13e8}', '\0', '\0']), - ('\u{abb9}', ['\u{13e9}', '\0', '\0']), ('\u{abba}', ['\u{13ea}', '\0', '\0']), ('\u{abbb}', - ['\u{13eb}', '\0', '\0']), ('\u{abbc}', ['\u{13ec}', '\0', '\0']), ('\u{abbd}', ['\u{13ed}', - '\0', '\0']), ('\u{abbe}', ['\u{13ee}', '\0', '\0']), ('\u{abbf}', ['\u{13ef}', '\0', - '\0']), ('\u{fb00}', ['\u{46}', '\u{46}', '\0']), ('\u{fb01}', ['\u{46}', '\u{49}', '\0']), - ('\u{fb02}', ['\u{46}', '\u{4c}', '\0']), ('\u{fb03}', ['\u{46}', '\u{46}', '\u{49}']), - ('\u{fb04}', ['\u{46}', '\u{46}', '\u{4c}']), ('\u{fb05}', ['\u{53}', '\u{54}', '\0']), - ('\u{fb06}', ['\u{53}', '\u{54}', '\0']), ('\u{fb13}', ['\u{544}', '\u{546}', '\0']), - ('\u{fb14}', ['\u{544}', '\u{535}', '\0']), ('\u{fb15}', ['\u{544}', '\u{53b}', '\0']), - ('\u{fb16}', ['\u{54e}', '\u{546}', '\0']), ('\u{fb17}', ['\u{544}', '\u{53d}', '\0']), - ('\u{ff41}', ['\u{ff21}', '\0', '\0']), ('\u{ff42}', ['\u{ff22}', '\0', '\0']), ('\u{ff43}', - ['\u{ff23}', '\0', '\0']), ('\u{ff44}', ['\u{ff24}', '\0', '\0']), ('\u{ff45}', ['\u{ff25}', - '\0', '\0']), ('\u{ff46}', ['\u{ff26}', '\0', '\0']), ('\u{ff47}', ['\u{ff27}', '\0', - '\0']), ('\u{ff48}', ['\u{ff28}', '\0', '\0']), ('\u{ff49}', ['\u{ff29}', '\0', '\0']), - ('\u{ff4a}', ['\u{ff2a}', '\0', '\0']), ('\u{ff4b}', ['\u{ff2b}', '\0', '\0']), ('\u{ff4c}', - ['\u{ff2c}', '\0', '\0']), ('\u{ff4d}', ['\u{ff2d}', '\0', '\0']), ('\u{ff4e}', ['\u{ff2e}', - '\0', '\0']), ('\u{ff4f}', ['\u{ff2f}', '\0', '\0']), ('\u{ff50}', ['\u{ff30}', '\0', - '\0']), ('\u{ff51}', ['\u{ff31}', '\0', '\0']), ('\u{ff52}', ['\u{ff32}', '\0', '\0']), - ('\u{ff53}', ['\u{ff33}', '\0', '\0']), ('\u{ff54}', ['\u{ff34}', '\0', '\0']), ('\u{ff55}', - ['\u{ff35}', '\0', '\0']), ('\u{ff56}', ['\u{ff36}', '\0', '\0']), ('\u{ff57}', ['\u{ff37}', - '\0', '\0']), ('\u{ff58}', ['\u{ff38}', '\0', '\0']), ('\u{ff59}', ['\u{ff39}', '\0', - '\0']), ('\u{ff5a}', ['\u{ff3a}', '\0', '\0']), ('\u{10428}', ['\u{10400}', '\0', '\0']), + ['\u{535}', '\u{552}', '\0']), ('\u{10d0}', ['\u{1c90}', '\0', '\0']), ('\u{10d1}', + ['\u{1c91}', '\0', '\0']), ('\u{10d2}', ['\u{1c92}', '\0', '\0']), ('\u{10d3}', ['\u{1c93}', + '\0', '\0']), ('\u{10d4}', ['\u{1c94}', '\0', '\0']), ('\u{10d5}', ['\u{1c95}', '\0', + '\0']), ('\u{10d6}', ['\u{1c96}', '\0', '\0']), ('\u{10d7}', ['\u{1c97}', '\0', '\0']), + ('\u{10d8}', ['\u{1c98}', '\0', '\0']), ('\u{10d9}', ['\u{1c99}', '\0', '\0']), ('\u{10da}', + ['\u{1c9a}', '\0', '\0']), ('\u{10db}', ['\u{1c9b}', '\0', '\0']), ('\u{10dc}', ['\u{1c9c}', + '\0', '\0']), ('\u{10dd}', ['\u{1c9d}', '\0', '\0']), ('\u{10de}', ['\u{1c9e}', '\0', + '\0']), ('\u{10df}', ['\u{1c9f}', '\0', '\0']), ('\u{10e0}', ['\u{1ca0}', '\0', '\0']), + ('\u{10e1}', ['\u{1ca1}', '\0', '\0']), ('\u{10e2}', ['\u{1ca2}', '\0', '\0']), ('\u{10e3}', + ['\u{1ca3}', '\0', '\0']), ('\u{10e4}', ['\u{1ca4}', '\0', '\0']), ('\u{10e5}', ['\u{1ca5}', + '\0', '\0']), ('\u{10e6}', ['\u{1ca6}', '\0', '\0']), ('\u{10e7}', ['\u{1ca7}', '\0', + '\0']), ('\u{10e8}', ['\u{1ca8}', '\0', '\0']), ('\u{10e9}', ['\u{1ca9}', '\0', '\0']), + ('\u{10ea}', ['\u{1caa}', '\0', '\0']), ('\u{10eb}', ['\u{1cab}', '\0', '\0']), ('\u{10ec}', + ['\u{1cac}', '\0', '\0']), ('\u{10ed}', ['\u{1cad}', '\0', '\0']), ('\u{10ee}', ['\u{1cae}', + '\0', '\0']), ('\u{10ef}', ['\u{1caf}', '\0', '\0']), ('\u{10f0}', ['\u{1cb0}', '\0', + '\0']), ('\u{10f1}', ['\u{1cb1}', '\0', '\0']), ('\u{10f2}', ['\u{1cb2}', '\0', '\0']), + ('\u{10f3}', ['\u{1cb3}', '\0', '\0']), ('\u{10f4}', ['\u{1cb4}', '\0', '\0']), ('\u{10f5}', + ['\u{1cb5}', '\0', '\0']), ('\u{10f6}', ['\u{1cb6}', '\0', '\0']), ('\u{10f7}', ['\u{1cb7}', + '\0', '\0']), ('\u{10f8}', ['\u{1cb8}', '\0', '\0']), ('\u{10f9}', ['\u{1cb9}', '\0', + '\0']), ('\u{10fa}', ['\u{1cba}', '\0', '\0']), ('\u{10fd}', ['\u{1cbd}', '\0', '\0']), + ('\u{10fe}', ['\u{1cbe}', '\0', '\0']), ('\u{10ff}', ['\u{1cbf}', '\0', '\0']), ('\u{13f8}', + ['\u{13f0}', '\0', '\0']), ('\u{13f9}', ['\u{13f1}', '\0', '\0']), ('\u{13fa}', ['\u{13f2}', + '\0', '\0']), ('\u{13fb}', ['\u{13f3}', '\0', '\0']), ('\u{13fc}', ['\u{13f4}', '\0', + '\0']), ('\u{13fd}', ['\u{13f5}', '\0', '\0']), ('\u{1c80}', ['\u{412}', '\0', '\0']), + ('\u{1c81}', ['\u{414}', '\0', '\0']), ('\u{1c82}', ['\u{41e}', '\0', '\0']), ('\u{1c83}', + ['\u{421}', '\0', '\0']), ('\u{1c84}', ['\u{422}', '\0', '\0']), ('\u{1c85}', ['\u{422}', + '\0', '\0']), ('\u{1c86}', ['\u{42a}', '\0', '\0']), ('\u{1c87}', ['\u{462}', '\0', '\0']), + ('\u{1c88}', ['\u{a64a}', '\0', '\0']), ('\u{1d79}', ['\u{a77d}', '\0', '\0']), ('\u{1d7d}', + ['\u{2c63}', '\0', '\0']), ('\u{1e01}', ['\u{1e00}', '\0', '\0']), ('\u{1e03}', ['\u{1e02}', + '\0', '\0']), ('\u{1e05}', ['\u{1e04}', '\0', '\0']), ('\u{1e07}', ['\u{1e06}', '\0', + '\0']), ('\u{1e09}', ['\u{1e08}', '\0', '\0']), ('\u{1e0b}', ['\u{1e0a}', '\0', '\0']), + ('\u{1e0d}', ['\u{1e0c}', '\0', '\0']), ('\u{1e0f}', ['\u{1e0e}', '\0', '\0']), ('\u{1e11}', + ['\u{1e10}', '\0', '\0']), ('\u{1e13}', ['\u{1e12}', '\0', '\0']), ('\u{1e15}', ['\u{1e14}', + '\0', '\0']), ('\u{1e17}', ['\u{1e16}', '\0', '\0']), ('\u{1e19}', ['\u{1e18}', '\0', + '\0']), ('\u{1e1b}', ['\u{1e1a}', '\0', '\0']), ('\u{1e1d}', ['\u{1e1c}', '\0', '\0']), + ('\u{1e1f}', ['\u{1e1e}', '\0', '\0']), ('\u{1e21}', ['\u{1e20}', '\0', '\0']), ('\u{1e23}', + ['\u{1e22}', '\0', '\0']), ('\u{1e25}', ['\u{1e24}', '\0', '\0']), ('\u{1e27}', ['\u{1e26}', + '\0', '\0']), ('\u{1e29}', ['\u{1e28}', '\0', '\0']), ('\u{1e2b}', ['\u{1e2a}', '\0', + '\0']), ('\u{1e2d}', ['\u{1e2c}', '\0', '\0']), ('\u{1e2f}', ['\u{1e2e}', '\0', '\0']), + ('\u{1e31}', ['\u{1e30}', '\0', '\0']), ('\u{1e33}', ['\u{1e32}', '\0', '\0']), ('\u{1e35}', + ['\u{1e34}', '\0', '\0']), ('\u{1e37}', ['\u{1e36}', '\0', '\0']), ('\u{1e39}', ['\u{1e38}', + '\0', '\0']), ('\u{1e3b}', ['\u{1e3a}', '\0', '\0']), ('\u{1e3d}', ['\u{1e3c}', '\0', + '\0']), ('\u{1e3f}', ['\u{1e3e}', '\0', '\0']), ('\u{1e41}', ['\u{1e40}', '\0', '\0']), + ('\u{1e43}', ['\u{1e42}', '\0', '\0']), ('\u{1e45}', ['\u{1e44}', '\0', '\0']), ('\u{1e47}', + ['\u{1e46}', '\0', '\0']), ('\u{1e49}', ['\u{1e48}', '\0', '\0']), ('\u{1e4b}', ['\u{1e4a}', + '\0', '\0']), ('\u{1e4d}', ['\u{1e4c}', '\0', '\0']), ('\u{1e4f}', ['\u{1e4e}', '\0', + '\0']), ('\u{1e51}', ['\u{1e50}', '\0', '\0']), ('\u{1e53}', ['\u{1e52}', '\0', '\0']), + ('\u{1e55}', ['\u{1e54}', '\0', '\0']), ('\u{1e57}', ['\u{1e56}', '\0', '\0']), ('\u{1e59}', + ['\u{1e58}', '\0', '\0']), ('\u{1e5b}', ['\u{1e5a}', '\0', '\0']), ('\u{1e5d}', ['\u{1e5c}', + '\0', '\0']), ('\u{1e5f}', ['\u{1e5e}', '\0', '\0']), ('\u{1e61}', ['\u{1e60}', '\0', + '\0']), ('\u{1e63}', ['\u{1e62}', '\0', '\0']), ('\u{1e65}', ['\u{1e64}', '\0', '\0']), + ('\u{1e67}', ['\u{1e66}', '\0', '\0']), ('\u{1e69}', ['\u{1e68}', '\0', '\0']), ('\u{1e6b}', + ['\u{1e6a}', '\0', '\0']), ('\u{1e6d}', ['\u{1e6c}', '\0', '\0']), ('\u{1e6f}', ['\u{1e6e}', + '\0', '\0']), ('\u{1e71}', ['\u{1e70}', '\0', '\0']), ('\u{1e73}', ['\u{1e72}', '\0', + '\0']), ('\u{1e75}', ['\u{1e74}', '\0', '\0']), ('\u{1e77}', ['\u{1e76}', '\0', '\0']), + ('\u{1e79}', ['\u{1e78}', '\0', '\0']), ('\u{1e7b}', ['\u{1e7a}', '\0', '\0']), ('\u{1e7d}', + ['\u{1e7c}', '\0', '\0']), ('\u{1e7f}', ['\u{1e7e}', '\0', '\0']), ('\u{1e81}', ['\u{1e80}', + '\0', '\0']), ('\u{1e83}', ['\u{1e82}', '\0', '\0']), ('\u{1e85}', ['\u{1e84}', '\0', + '\0']), ('\u{1e87}', ['\u{1e86}', '\0', '\0']), ('\u{1e89}', ['\u{1e88}', '\0', '\0']), + ('\u{1e8b}', ['\u{1e8a}', '\0', '\0']), ('\u{1e8d}', ['\u{1e8c}', '\0', '\0']), ('\u{1e8f}', + ['\u{1e8e}', '\0', '\0']), ('\u{1e91}', ['\u{1e90}', '\0', '\0']), ('\u{1e93}', ['\u{1e92}', + '\0', '\0']), ('\u{1e95}', ['\u{1e94}', '\0', '\0']), ('\u{1e96}', ['\u{48}', '\u{331}', + '\0']), ('\u{1e97}', ['\u{54}', '\u{308}', '\0']), ('\u{1e98}', ['\u{57}', '\u{30a}', + '\0']), ('\u{1e99}', ['\u{59}', '\u{30a}', '\0']), ('\u{1e9a}', ['\u{41}', '\u{2be}', + '\0']), ('\u{1e9b}', ['\u{1e60}', '\0', '\0']), ('\u{1ea1}', ['\u{1ea0}', '\0', '\0']), + ('\u{1ea3}', ['\u{1ea2}', '\0', '\0']), ('\u{1ea5}', ['\u{1ea4}', '\0', '\0']), ('\u{1ea7}', + ['\u{1ea6}', '\0', '\0']), ('\u{1ea9}', ['\u{1ea8}', '\0', '\0']), ('\u{1eab}', ['\u{1eaa}', + '\0', '\0']), ('\u{1ead}', ['\u{1eac}', '\0', '\0']), ('\u{1eaf}', ['\u{1eae}', '\0', + '\0']), ('\u{1eb1}', ['\u{1eb0}', '\0', '\0']), ('\u{1eb3}', ['\u{1eb2}', '\0', '\0']), + ('\u{1eb5}', ['\u{1eb4}', '\0', '\0']), ('\u{1eb7}', ['\u{1eb6}', '\0', '\0']), ('\u{1eb9}', + ['\u{1eb8}', '\0', '\0']), ('\u{1ebb}', ['\u{1eba}', '\0', '\0']), ('\u{1ebd}', ['\u{1ebc}', + '\0', '\0']), ('\u{1ebf}', ['\u{1ebe}', '\0', '\0']), ('\u{1ec1}', ['\u{1ec0}', '\0', + '\0']), ('\u{1ec3}', ['\u{1ec2}', '\0', '\0']), ('\u{1ec5}', ['\u{1ec4}', '\0', '\0']), + ('\u{1ec7}', ['\u{1ec6}', '\0', '\0']), ('\u{1ec9}', ['\u{1ec8}', '\0', '\0']), ('\u{1ecb}', + ['\u{1eca}', '\0', '\0']), ('\u{1ecd}', ['\u{1ecc}', '\0', '\0']), ('\u{1ecf}', ['\u{1ece}', + '\0', '\0']), ('\u{1ed1}', ['\u{1ed0}', '\0', '\0']), ('\u{1ed3}', ['\u{1ed2}', '\0', + '\0']), ('\u{1ed5}', ['\u{1ed4}', '\0', '\0']), ('\u{1ed7}', ['\u{1ed6}', '\0', '\0']), + ('\u{1ed9}', ['\u{1ed8}', '\0', '\0']), ('\u{1edb}', ['\u{1eda}', '\0', '\0']), ('\u{1edd}', + ['\u{1edc}', '\0', '\0']), ('\u{1edf}', ['\u{1ede}', '\0', '\0']), ('\u{1ee1}', ['\u{1ee0}', + '\0', '\0']), ('\u{1ee3}', ['\u{1ee2}', '\0', '\0']), ('\u{1ee5}', ['\u{1ee4}', '\0', + '\0']), ('\u{1ee7}', ['\u{1ee6}', '\0', '\0']), ('\u{1ee9}', ['\u{1ee8}', '\0', '\0']), + ('\u{1eeb}', ['\u{1eea}', '\0', '\0']), ('\u{1eed}', ['\u{1eec}', '\0', '\0']), ('\u{1eef}', + ['\u{1eee}', '\0', '\0']), ('\u{1ef1}', ['\u{1ef0}', '\0', '\0']), ('\u{1ef3}', ['\u{1ef2}', + '\0', '\0']), ('\u{1ef5}', ['\u{1ef4}', '\0', '\0']), ('\u{1ef7}', ['\u{1ef6}', '\0', + '\0']), ('\u{1ef9}', ['\u{1ef8}', '\0', '\0']), ('\u{1efb}', ['\u{1efa}', '\0', '\0']), + ('\u{1efd}', ['\u{1efc}', '\0', '\0']), ('\u{1eff}', ['\u{1efe}', '\0', '\0']), ('\u{1f00}', + ['\u{1f08}', '\0', '\0']), ('\u{1f01}', ['\u{1f09}', '\0', '\0']), ('\u{1f02}', ['\u{1f0a}', + '\0', '\0']), ('\u{1f03}', ['\u{1f0b}', '\0', '\0']), ('\u{1f04}', ['\u{1f0c}', '\0', + '\0']), ('\u{1f05}', ['\u{1f0d}', '\0', '\0']), ('\u{1f06}', ['\u{1f0e}', '\0', '\0']), + ('\u{1f07}', ['\u{1f0f}', '\0', '\0']), ('\u{1f10}', ['\u{1f18}', '\0', '\0']), ('\u{1f11}', + ['\u{1f19}', '\0', '\0']), ('\u{1f12}', ['\u{1f1a}', '\0', '\0']), ('\u{1f13}', ['\u{1f1b}', + '\0', '\0']), ('\u{1f14}', ['\u{1f1c}', '\0', '\0']), ('\u{1f15}', ['\u{1f1d}', '\0', + '\0']), ('\u{1f20}', ['\u{1f28}', '\0', '\0']), ('\u{1f21}', ['\u{1f29}', '\0', '\0']), + ('\u{1f22}', ['\u{1f2a}', '\0', '\0']), ('\u{1f23}', ['\u{1f2b}', '\0', '\0']), ('\u{1f24}', + ['\u{1f2c}', '\0', '\0']), ('\u{1f25}', ['\u{1f2d}', '\0', '\0']), ('\u{1f26}', ['\u{1f2e}', + '\0', '\0']), ('\u{1f27}', ['\u{1f2f}', '\0', '\0']), ('\u{1f30}', ['\u{1f38}', '\0', + '\0']), ('\u{1f31}', ['\u{1f39}', '\0', '\0']), ('\u{1f32}', ['\u{1f3a}', '\0', '\0']), + ('\u{1f33}', ['\u{1f3b}', '\0', '\0']), ('\u{1f34}', ['\u{1f3c}', '\0', '\0']), ('\u{1f35}', + ['\u{1f3d}', '\0', '\0']), ('\u{1f36}', ['\u{1f3e}', '\0', '\0']), ('\u{1f37}', ['\u{1f3f}', + '\0', '\0']), ('\u{1f40}', ['\u{1f48}', '\0', '\0']), ('\u{1f41}', ['\u{1f49}', '\0', + '\0']), ('\u{1f42}', ['\u{1f4a}', '\0', '\0']), ('\u{1f43}', ['\u{1f4b}', '\0', '\0']), + ('\u{1f44}', ['\u{1f4c}', '\0', '\0']), ('\u{1f45}', ['\u{1f4d}', '\0', '\0']), ('\u{1f50}', + ['\u{3a5}', '\u{313}', '\0']), ('\u{1f51}', ['\u{1f59}', '\0', '\0']), ('\u{1f52}', + ['\u{3a5}', '\u{313}', '\u{300}']), ('\u{1f53}', ['\u{1f5b}', '\0', '\0']), ('\u{1f54}', + ['\u{3a5}', '\u{313}', '\u{301}']), ('\u{1f55}', ['\u{1f5d}', '\0', '\0']), ('\u{1f56}', + ['\u{3a5}', '\u{313}', '\u{342}']), ('\u{1f57}', ['\u{1f5f}', '\0', '\0']), ('\u{1f60}', + ['\u{1f68}', '\0', '\0']), ('\u{1f61}', ['\u{1f69}', '\0', '\0']), ('\u{1f62}', ['\u{1f6a}', + '\0', '\0']), ('\u{1f63}', ['\u{1f6b}', '\0', '\0']), ('\u{1f64}', ['\u{1f6c}', '\0', + '\0']), ('\u{1f65}', ['\u{1f6d}', '\0', '\0']), ('\u{1f66}', ['\u{1f6e}', '\0', '\0']), + ('\u{1f67}', ['\u{1f6f}', '\0', '\0']), ('\u{1f70}', ['\u{1fba}', '\0', '\0']), ('\u{1f71}', + ['\u{1fbb}', '\0', '\0']), ('\u{1f72}', ['\u{1fc8}', '\0', '\0']), ('\u{1f73}', ['\u{1fc9}', + '\0', '\0']), ('\u{1f74}', ['\u{1fca}', '\0', '\0']), ('\u{1f75}', ['\u{1fcb}', '\0', + '\0']), ('\u{1f76}', ['\u{1fda}', '\0', '\0']), ('\u{1f77}', ['\u{1fdb}', '\0', '\0']), + ('\u{1f78}', ['\u{1ff8}', '\0', '\0']), ('\u{1f79}', ['\u{1ff9}', '\0', '\0']), ('\u{1f7a}', + ['\u{1fea}', '\0', '\0']), ('\u{1f7b}', ['\u{1feb}', '\0', '\0']), ('\u{1f7c}', ['\u{1ffa}', + '\0', '\0']), ('\u{1f7d}', ['\u{1ffb}', '\0', '\0']), ('\u{1f80}', ['\u{1f08}', '\u{399}', + '\0']), ('\u{1f81}', ['\u{1f09}', '\u{399}', '\0']), ('\u{1f82}', ['\u{1f0a}', '\u{399}', + '\0']), ('\u{1f83}', ['\u{1f0b}', '\u{399}', '\0']), ('\u{1f84}', ['\u{1f0c}', '\u{399}', + '\0']), ('\u{1f85}', ['\u{1f0d}', '\u{399}', '\0']), ('\u{1f86}', ['\u{1f0e}', '\u{399}', + '\0']), ('\u{1f87}', ['\u{1f0f}', '\u{399}', '\0']), ('\u{1f88}', ['\u{1f08}', '\u{399}', + '\0']), ('\u{1f89}', ['\u{1f09}', '\u{399}', '\0']), ('\u{1f8a}', ['\u{1f0a}', '\u{399}', + '\0']), ('\u{1f8b}', ['\u{1f0b}', '\u{399}', '\0']), ('\u{1f8c}', ['\u{1f0c}', '\u{399}', + '\0']), ('\u{1f8d}', ['\u{1f0d}', '\u{399}', '\0']), ('\u{1f8e}', ['\u{1f0e}', '\u{399}', + '\0']), ('\u{1f8f}', ['\u{1f0f}', '\u{399}', '\0']), ('\u{1f90}', ['\u{1f28}', '\u{399}', + '\0']), ('\u{1f91}', ['\u{1f29}', '\u{399}', '\0']), ('\u{1f92}', ['\u{1f2a}', '\u{399}', + '\0']), ('\u{1f93}', ['\u{1f2b}', '\u{399}', '\0']), ('\u{1f94}', ['\u{1f2c}', '\u{399}', + '\0']), ('\u{1f95}', ['\u{1f2d}', '\u{399}', '\0']), ('\u{1f96}', ['\u{1f2e}', '\u{399}', + '\0']), ('\u{1f97}', ['\u{1f2f}', '\u{399}', '\0']), ('\u{1f98}', ['\u{1f28}', '\u{399}', + '\0']), ('\u{1f99}', ['\u{1f29}', '\u{399}', '\0']), ('\u{1f9a}', ['\u{1f2a}', '\u{399}', + '\0']), ('\u{1f9b}', ['\u{1f2b}', '\u{399}', '\0']), ('\u{1f9c}', ['\u{1f2c}', '\u{399}', + '\0']), ('\u{1f9d}', ['\u{1f2d}', '\u{399}', '\0']), ('\u{1f9e}', ['\u{1f2e}', '\u{399}', + '\0']), ('\u{1f9f}', ['\u{1f2f}', '\u{399}', '\0']), ('\u{1fa0}', ['\u{1f68}', '\u{399}', + '\0']), ('\u{1fa1}', ['\u{1f69}', '\u{399}', '\0']), ('\u{1fa2}', ['\u{1f6a}', '\u{399}', + '\0']), ('\u{1fa3}', ['\u{1f6b}', '\u{399}', '\0']), ('\u{1fa4}', ['\u{1f6c}', '\u{399}', + '\0']), ('\u{1fa5}', ['\u{1f6d}', '\u{399}', '\0']), ('\u{1fa6}', ['\u{1f6e}', '\u{399}', + '\0']), ('\u{1fa7}', ['\u{1f6f}', '\u{399}', '\0']), ('\u{1fa8}', ['\u{1f68}', '\u{399}', + '\0']), ('\u{1fa9}', ['\u{1f69}', '\u{399}', '\0']), ('\u{1faa}', ['\u{1f6a}', '\u{399}', + '\0']), ('\u{1fab}', ['\u{1f6b}', '\u{399}', '\0']), ('\u{1fac}', ['\u{1f6c}', '\u{399}', + '\0']), ('\u{1fad}', ['\u{1f6d}', '\u{399}', '\0']), ('\u{1fae}', ['\u{1f6e}', '\u{399}', + '\0']), ('\u{1faf}', ['\u{1f6f}', '\u{399}', '\0']), ('\u{1fb0}', ['\u{1fb8}', '\0', '\0']), + ('\u{1fb1}', ['\u{1fb9}', '\0', '\0']), ('\u{1fb2}', ['\u{1fba}', '\u{399}', '\0']), + ('\u{1fb3}', ['\u{391}', '\u{399}', '\0']), ('\u{1fb4}', ['\u{386}', '\u{399}', '\0']), + ('\u{1fb6}', ['\u{391}', '\u{342}', '\0']), ('\u{1fb7}', ['\u{391}', '\u{342}', '\u{399}']), + ('\u{1fbc}', ['\u{391}', '\u{399}', '\0']), ('\u{1fbe}', ['\u{399}', '\0', '\0']), + ('\u{1fc2}', ['\u{1fca}', '\u{399}', '\0']), ('\u{1fc3}', ['\u{397}', '\u{399}', '\0']), + ('\u{1fc4}', ['\u{389}', '\u{399}', '\0']), ('\u{1fc6}', ['\u{397}', '\u{342}', '\0']), + ('\u{1fc7}', ['\u{397}', '\u{342}', '\u{399}']), ('\u{1fcc}', ['\u{397}', '\u{399}', '\0']), + ('\u{1fd0}', ['\u{1fd8}', '\0', '\0']), ('\u{1fd1}', ['\u{1fd9}', '\0', '\0']), ('\u{1fd2}', + ['\u{399}', '\u{308}', '\u{300}']), ('\u{1fd3}', ['\u{399}', '\u{308}', '\u{301}']), + ('\u{1fd6}', ['\u{399}', '\u{342}', '\0']), ('\u{1fd7}', ['\u{399}', '\u{308}', '\u{342}']), + ('\u{1fe0}', ['\u{1fe8}', '\0', '\0']), ('\u{1fe1}', ['\u{1fe9}', '\0', '\0']), ('\u{1fe2}', + ['\u{3a5}', '\u{308}', '\u{300}']), ('\u{1fe3}', ['\u{3a5}', '\u{308}', '\u{301}']), + ('\u{1fe4}', ['\u{3a1}', '\u{313}', '\0']), ('\u{1fe5}', ['\u{1fec}', '\0', '\0']), + ('\u{1fe6}', ['\u{3a5}', '\u{342}', '\0']), ('\u{1fe7}', ['\u{3a5}', '\u{308}', '\u{342}']), + ('\u{1ff2}', ['\u{1ffa}', '\u{399}', '\0']), ('\u{1ff3}', ['\u{3a9}', '\u{399}', '\0']), + ('\u{1ff4}', ['\u{38f}', '\u{399}', '\0']), ('\u{1ff6}', ['\u{3a9}', '\u{342}', '\0']), + ('\u{1ff7}', ['\u{3a9}', '\u{342}', '\u{399}']), ('\u{1ffc}', ['\u{3a9}', '\u{399}', '\0']), + ('\u{214e}', ['\u{2132}', '\0', '\0']), ('\u{2170}', ['\u{2160}', '\0', '\0']), ('\u{2171}', + ['\u{2161}', '\0', '\0']), ('\u{2172}', ['\u{2162}', '\0', '\0']), ('\u{2173}', ['\u{2163}', + '\0', '\0']), ('\u{2174}', ['\u{2164}', '\0', '\0']), ('\u{2175}', ['\u{2165}', '\0', + '\0']), ('\u{2176}', ['\u{2166}', '\0', '\0']), ('\u{2177}', ['\u{2167}', '\0', '\0']), + ('\u{2178}', ['\u{2168}', '\0', '\0']), ('\u{2179}', ['\u{2169}', '\0', '\0']), ('\u{217a}', + ['\u{216a}', '\0', '\0']), ('\u{217b}', ['\u{216b}', '\0', '\0']), ('\u{217c}', ['\u{216c}', + '\0', '\0']), ('\u{217d}', ['\u{216d}', '\0', '\0']), ('\u{217e}', ['\u{216e}', '\0', + '\0']), ('\u{217f}', ['\u{216f}', '\0', '\0']), ('\u{2184}', ['\u{2183}', '\0', '\0']), + ('\u{24d0}', ['\u{24b6}', '\0', '\0']), ('\u{24d1}', ['\u{24b7}', '\0', '\0']), ('\u{24d2}', + ['\u{24b8}', '\0', '\0']), ('\u{24d3}', ['\u{24b9}', '\0', '\0']), ('\u{24d4}', ['\u{24ba}', + '\0', '\0']), ('\u{24d5}', ['\u{24bb}', '\0', '\0']), ('\u{24d6}', ['\u{24bc}', '\0', + '\0']), ('\u{24d7}', ['\u{24bd}', '\0', '\0']), ('\u{24d8}', ['\u{24be}', '\0', '\0']), + ('\u{24d9}', ['\u{24bf}', '\0', '\0']), ('\u{24da}', ['\u{24c0}', '\0', '\0']), ('\u{24db}', + ['\u{24c1}', '\0', '\0']), ('\u{24dc}', ['\u{24c2}', '\0', '\0']), ('\u{24dd}', ['\u{24c3}', + '\0', '\0']), ('\u{24de}', ['\u{24c4}', '\0', '\0']), ('\u{24df}', ['\u{24c5}', '\0', + '\0']), ('\u{24e0}', ['\u{24c6}', '\0', '\0']), ('\u{24e1}', ['\u{24c7}', '\0', '\0']), + ('\u{24e2}', ['\u{24c8}', '\0', '\0']), ('\u{24e3}', ['\u{24c9}', '\0', '\0']), ('\u{24e4}', + ['\u{24ca}', '\0', '\0']), ('\u{24e5}', ['\u{24cb}', '\0', '\0']), ('\u{24e6}', ['\u{24cc}', + '\0', '\0']), ('\u{24e7}', ['\u{24cd}', '\0', '\0']), ('\u{24e8}', ['\u{24ce}', '\0', + '\0']), ('\u{24e9}', ['\u{24cf}', '\0', '\0']), ('\u{2c30}', ['\u{2c00}', '\0', '\0']), + ('\u{2c31}', ['\u{2c01}', '\0', '\0']), ('\u{2c32}', ['\u{2c02}', '\0', '\0']), ('\u{2c33}', + ['\u{2c03}', '\0', '\0']), ('\u{2c34}', ['\u{2c04}', '\0', '\0']), ('\u{2c35}', ['\u{2c05}', + '\0', '\0']), ('\u{2c36}', ['\u{2c06}', '\0', '\0']), ('\u{2c37}', ['\u{2c07}', '\0', + '\0']), ('\u{2c38}', ['\u{2c08}', '\0', '\0']), ('\u{2c39}', ['\u{2c09}', '\0', '\0']), + ('\u{2c3a}', ['\u{2c0a}', '\0', '\0']), ('\u{2c3b}', ['\u{2c0b}', '\0', '\0']), ('\u{2c3c}', + ['\u{2c0c}', '\0', '\0']), ('\u{2c3d}', ['\u{2c0d}', '\0', '\0']), ('\u{2c3e}', ['\u{2c0e}', + '\0', '\0']), ('\u{2c3f}', ['\u{2c0f}', '\0', '\0']), ('\u{2c40}', ['\u{2c10}', '\0', + '\0']), ('\u{2c41}', ['\u{2c11}', '\0', '\0']), ('\u{2c42}', ['\u{2c12}', '\0', '\0']), + ('\u{2c43}', ['\u{2c13}', '\0', '\0']), ('\u{2c44}', ['\u{2c14}', '\0', '\0']), ('\u{2c45}', + ['\u{2c15}', '\0', '\0']), ('\u{2c46}', ['\u{2c16}', '\0', '\0']), ('\u{2c47}', ['\u{2c17}', + '\0', '\0']), ('\u{2c48}', ['\u{2c18}', '\0', '\0']), ('\u{2c49}', ['\u{2c19}', '\0', + '\0']), ('\u{2c4a}', ['\u{2c1a}', '\0', '\0']), ('\u{2c4b}', ['\u{2c1b}', '\0', '\0']), + ('\u{2c4c}', ['\u{2c1c}', '\0', '\0']), ('\u{2c4d}', ['\u{2c1d}', '\0', '\0']), ('\u{2c4e}', + ['\u{2c1e}', '\0', '\0']), ('\u{2c4f}', ['\u{2c1f}', '\0', '\0']), ('\u{2c50}', ['\u{2c20}', + '\0', '\0']), ('\u{2c51}', ['\u{2c21}', '\0', '\0']), ('\u{2c52}', ['\u{2c22}', '\0', + '\0']), ('\u{2c53}', ['\u{2c23}', '\0', '\0']), ('\u{2c54}', ['\u{2c24}', '\0', '\0']), + ('\u{2c55}', ['\u{2c25}', '\0', '\0']), ('\u{2c56}', ['\u{2c26}', '\0', '\0']), ('\u{2c57}', + ['\u{2c27}', '\0', '\0']), ('\u{2c58}', ['\u{2c28}', '\0', '\0']), ('\u{2c59}', ['\u{2c29}', + '\0', '\0']), ('\u{2c5a}', ['\u{2c2a}', '\0', '\0']), ('\u{2c5b}', ['\u{2c2b}', '\0', + '\0']), ('\u{2c5c}', ['\u{2c2c}', '\0', '\0']), ('\u{2c5d}', ['\u{2c2d}', '\0', '\0']), + ('\u{2c5e}', ['\u{2c2e}', '\0', '\0']), ('\u{2c61}', ['\u{2c60}', '\0', '\0']), ('\u{2c65}', + ['\u{23a}', '\0', '\0']), ('\u{2c66}', ['\u{23e}', '\0', '\0']), ('\u{2c68}', ['\u{2c67}', + '\0', '\0']), ('\u{2c6a}', ['\u{2c69}', '\0', '\0']), ('\u{2c6c}', ['\u{2c6b}', '\0', + '\0']), ('\u{2c73}', ['\u{2c72}', '\0', '\0']), ('\u{2c76}', ['\u{2c75}', '\0', '\0']), + ('\u{2c81}', ['\u{2c80}', '\0', '\0']), ('\u{2c83}', ['\u{2c82}', '\0', '\0']), ('\u{2c85}', + ['\u{2c84}', '\0', '\0']), ('\u{2c87}', ['\u{2c86}', '\0', '\0']), ('\u{2c89}', ['\u{2c88}', + '\0', '\0']), ('\u{2c8b}', ['\u{2c8a}', '\0', '\0']), ('\u{2c8d}', ['\u{2c8c}', '\0', + '\0']), ('\u{2c8f}', ['\u{2c8e}', '\0', '\0']), ('\u{2c91}', ['\u{2c90}', '\0', '\0']), + ('\u{2c93}', ['\u{2c92}', '\0', '\0']), ('\u{2c95}', ['\u{2c94}', '\0', '\0']), ('\u{2c97}', + ['\u{2c96}', '\0', '\0']), ('\u{2c99}', ['\u{2c98}', '\0', '\0']), ('\u{2c9b}', ['\u{2c9a}', + '\0', '\0']), ('\u{2c9d}', ['\u{2c9c}', '\0', '\0']), ('\u{2c9f}', ['\u{2c9e}', '\0', + '\0']), ('\u{2ca1}', ['\u{2ca0}', '\0', '\0']), ('\u{2ca3}', ['\u{2ca2}', '\0', '\0']), + ('\u{2ca5}', ['\u{2ca4}', '\0', '\0']), ('\u{2ca7}', ['\u{2ca6}', '\0', '\0']), ('\u{2ca9}', + ['\u{2ca8}', '\0', '\0']), ('\u{2cab}', ['\u{2caa}', '\0', '\0']), ('\u{2cad}', ['\u{2cac}', + '\0', '\0']), ('\u{2caf}', ['\u{2cae}', '\0', '\0']), ('\u{2cb1}', ['\u{2cb0}', '\0', + '\0']), ('\u{2cb3}', ['\u{2cb2}', '\0', '\0']), ('\u{2cb5}', ['\u{2cb4}', '\0', '\0']), + ('\u{2cb7}', ['\u{2cb6}', '\0', '\0']), ('\u{2cb9}', ['\u{2cb8}', '\0', '\0']), ('\u{2cbb}', + ['\u{2cba}', '\0', '\0']), ('\u{2cbd}', ['\u{2cbc}', '\0', '\0']), ('\u{2cbf}', ['\u{2cbe}', + '\0', '\0']), ('\u{2cc1}', ['\u{2cc0}', '\0', '\0']), ('\u{2cc3}', ['\u{2cc2}', '\0', + '\0']), ('\u{2cc5}', ['\u{2cc4}', '\0', '\0']), ('\u{2cc7}', ['\u{2cc6}', '\0', '\0']), + ('\u{2cc9}', ['\u{2cc8}', '\0', '\0']), ('\u{2ccb}', ['\u{2cca}', '\0', '\0']), ('\u{2ccd}', + ['\u{2ccc}', '\0', '\0']), ('\u{2ccf}', ['\u{2cce}', '\0', '\0']), ('\u{2cd1}', ['\u{2cd0}', + '\0', '\0']), ('\u{2cd3}', ['\u{2cd2}', '\0', '\0']), ('\u{2cd5}', ['\u{2cd4}', '\0', + '\0']), ('\u{2cd7}', ['\u{2cd6}', '\0', '\0']), ('\u{2cd9}', ['\u{2cd8}', '\0', '\0']), + ('\u{2cdb}', ['\u{2cda}', '\0', '\0']), ('\u{2cdd}', ['\u{2cdc}', '\0', '\0']), ('\u{2cdf}', + ['\u{2cde}', '\0', '\0']), ('\u{2ce1}', ['\u{2ce0}', '\0', '\0']), ('\u{2ce3}', ['\u{2ce2}', + '\0', '\0']), ('\u{2cec}', ['\u{2ceb}', '\0', '\0']), ('\u{2cee}', ['\u{2ced}', '\0', + '\0']), ('\u{2cf3}', ['\u{2cf2}', '\0', '\0']), ('\u{2d00}', ['\u{10a0}', '\0', '\0']), + ('\u{2d01}', ['\u{10a1}', '\0', '\0']), ('\u{2d02}', ['\u{10a2}', '\0', '\0']), ('\u{2d03}', + ['\u{10a3}', '\0', '\0']), ('\u{2d04}', ['\u{10a4}', '\0', '\0']), ('\u{2d05}', ['\u{10a5}', + '\0', '\0']), ('\u{2d06}', ['\u{10a6}', '\0', '\0']), ('\u{2d07}', ['\u{10a7}', '\0', + '\0']), ('\u{2d08}', ['\u{10a8}', '\0', '\0']), ('\u{2d09}', ['\u{10a9}', '\0', '\0']), + ('\u{2d0a}', ['\u{10aa}', '\0', '\0']), ('\u{2d0b}', ['\u{10ab}', '\0', '\0']), ('\u{2d0c}', + ['\u{10ac}', '\0', '\0']), ('\u{2d0d}', ['\u{10ad}', '\0', '\0']), ('\u{2d0e}', ['\u{10ae}', + '\0', '\0']), ('\u{2d0f}', ['\u{10af}', '\0', '\0']), ('\u{2d10}', ['\u{10b0}', '\0', + '\0']), ('\u{2d11}', ['\u{10b1}', '\0', '\0']), ('\u{2d12}', ['\u{10b2}', '\0', '\0']), + ('\u{2d13}', ['\u{10b3}', '\0', '\0']), ('\u{2d14}', ['\u{10b4}', '\0', '\0']), ('\u{2d15}', + ['\u{10b5}', '\0', '\0']), ('\u{2d16}', ['\u{10b6}', '\0', '\0']), ('\u{2d17}', ['\u{10b7}', + '\0', '\0']), ('\u{2d18}', ['\u{10b8}', '\0', '\0']), ('\u{2d19}', ['\u{10b9}', '\0', + '\0']), ('\u{2d1a}', ['\u{10ba}', '\0', '\0']), ('\u{2d1b}', ['\u{10bb}', '\0', '\0']), + ('\u{2d1c}', ['\u{10bc}', '\0', '\0']), ('\u{2d1d}', ['\u{10bd}', '\0', '\0']), ('\u{2d1e}', + ['\u{10be}', '\0', '\0']), ('\u{2d1f}', ['\u{10bf}', '\0', '\0']), ('\u{2d20}', ['\u{10c0}', + '\0', '\0']), ('\u{2d21}', ['\u{10c1}', '\0', '\0']), ('\u{2d22}', ['\u{10c2}', '\0', + '\0']), ('\u{2d23}', ['\u{10c3}', '\0', '\0']), ('\u{2d24}', ['\u{10c4}', '\0', '\0']), + ('\u{2d25}', ['\u{10c5}', '\0', '\0']), ('\u{2d27}', ['\u{10c7}', '\0', '\0']), ('\u{2d2d}', + ['\u{10cd}', '\0', '\0']), ('\u{a641}', ['\u{a640}', '\0', '\0']), ('\u{a643}', ['\u{a642}', + '\0', '\0']), ('\u{a645}', ['\u{a644}', '\0', '\0']), ('\u{a647}', ['\u{a646}', '\0', + '\0']), ('\u{a649}', ['\u{a648}', '\0', '\0']), ('\u{a64b}', ['\u{a64a}', '\0', '\0']), + ('\u{a64d}', ['\u{a64c}', '\0', '\0']), ('\u{a64f}', ['\u{a64e}', '\0', '\0']), ('\u{a651}', + ['\u{a650}', '\0', '\0']), ('\u{a653}', ['\u{a652}', '\0', '\0']), ('\u{a655}', ['\u{a654}', + '\0', '\0']), ('\u{a657}', ['\u{a656}', '\0', '\0']), ('\u{a659}', ['\u{a658}', '\0', + '\0']), ('\u{a65b}', ['\u{a65a}', '\0', '\0']), ('\u{a65d}', ['\u{a65c}', '\0', '\0']), + ('\u{a65f}', ['\u{a65e}', '\0', '\0']), ('\u{a661}', ['\u{a660}', '\0', '\0']), ('\u{a663}', + ['\u{a662}', '\0', '\0']), ('\u{a665}', ['\u{a664}', '\0', '\0']), ('\u{a667}', ['\u{a666}', + '\0', '\0']), ('\u{a669}', ['\u{a668}', '\0', '\0']), ('\u{a66b}', ['\u{a66a}', '\0', + '\0']), ('\u{a66d}', ['\u{a66c}', '\0', '\0']), ('\u{a681}', ['\u{a680}', '\0', '\0']), + ('\u{a683}', ['\u{a682}', '\0', '\0']), ('\u{a685}', ['\u{a684}', '\0', '\0']), ('\u{a687}', + ['\u{a686}', '\0', '\0']), ('\u{a689}', ['\u{a688}', '\0', '\0']), ('\u{a68b}', ['\u{a68a}', + '\0', '\0']), ('\u{a68d}', ['\u{a68c}', '\0', '\0']), ('\u{a68f}', ['\u{a68e}', '\0', + '\0']), ('\u{a691}', ['\u{a690}', '\0', '\0']), ('\u{a693}', ['\u{a692}', '\0', '\0']), + ('\u{a695}', ['\u{a694}', '\0', '\0']), ('\u{a697}', ['\u{a696}', '\0', '\0']), ('\u{a699}', + ['\u{a698}', '\0', '\0']), ('\u{a69b}', ['\u{a69a}', '\0', '\0']), ('\u{a723}', ['\u{a722}', + '\0', '\0']), ('\u{a725}', ['\u{a724}', '\0', '\0']), ('\u{a727}', ['\u{a726}', '\0', + '\0']), ('\u{a729}', ['\u{a728}', '\0', '\0']), ('\u{a72b}', ['\u{a72a}', '\0', '\0']), + ('\u{a72d}', ['\u{a72c}', '\0', '\0']), ('\u{a72f}', ['\u{a72e}', '\0', '\0']), ('\u{a733}', + ['\u{a732}', '\0', '\0']), ('\u{a735}', ['\u{a734}', '\0', '\0']), ('\u{a737}', ['\u{a736}', + '\0', '\0']), ('\u{a739}', ['\u{a738}', '\0', '\0']), ('\u{a73b}', ['\u{a73a}', '\0', + '\0']), ('\u{a73d}', ['\u{a73c}', '\0', '\0']), ('\u{a73f}', ['\u{a73e}', '\0', '\0']), + ('\u{a741}', ['\u{a740}', '\0', '\0']), ('\u{a743}', ['\u{a742}', '\0', '\0']), ('\u{a745}', + ['\u{a744}', '\0', '\0']), ('\u{a747}', ['\u{a746}', '\0', '\0']), ('\u{a749}', ['\u{a748}', + '\0', '\0']), ('\u{a74b}', ['\u{a74a}', '\0', '\0']), ('\u{a74d}', ['\u{a74c}', '\0', + '\0']), ('\u{a74f}', ['\u{a74e}', '\0', '\0']), ('\u{a751}', ['\u{a750}', '\0', '\0']), + ('\u{a753}', ['\u{a752}', '\0', '\0']), ('\u{a755}', ['\u{a754}', '\0', '\0']), ('\u{a757}', + ['\u{a756}', '\0', '\0']), ('\u{a759}', ['\u{a758}', '\0', '\0']), ('\u{a75b}', ['\u{a75a}', + '\0', '\0']), ('\u{a75d}', ['\u{a75c}', '\0', '\0']), ('\u{a75f}', ['\u{a75e}', '\0', + '\0']), ('\u{a761}', ['\u{a760}', '\0', '\0']), ('\u{a763}', ['\u{a762}', '\0', '\0']), + ('\u{a765}', ['\u{a764}', '\0', '\0']), ('\u{a767}', ['\u{a766}', '\0', '\0']), ('\u{a769}', + ['\u{a768}', '\0', '\0']), ('\u{a76b}', ['\u{a76a}', '\0', '\0']), ('\u{a76d}', ['\u{a76c}', + '\0', '\0']), ('\u{a76f}', ['\u{a76e}', '\0', '\0']), ('\u{a77a}', ['\u{a779}', '\0', + '\0']), ('\u{a77c}', ['\u{a77b}', '\0', '\0']), ('\u{a77f}', ['\u{a77e}', '\0', '\0']), + ('\u{a781}', ['\u{a780}', '\0', '\0']), ('\u{a783}', ['\u{a782}', '\0', '\0']), ('\u{a785}', + ['\u{a784}', '\0', '\0']), ('\u{a787}', ['\u{a786}', '\0', '\0']), ('\u{a78c}', ['\u{a78b}', + '\0', '\0']), ('\u{a791}', ['\u{a790}', '\0', '\0']), ('\u{a793}', ['\u{a792}', '\0', + '\0']), ('\u{a797}', ['\u{a796}', '\0', '\0']), ('\u{a799}', ['\u{a798}', '\0', '\0']), + ('\u{a79b}', ['\u{a79a}', '\0', '\0']), ('\u{a79d}', ['\u{a79c}', '\0', '\0']), ('\u{a79f}', + ['\u{a79e}', '\0', '\0']), ('\u{a7a1}', ['\u{a7a0}', '\0', '\0']), ('\u{a7a3}', ['\u{a7a2}', + '\0', '\0']), ('\u{a7a5}', ['\u{a7a4}', '\0', '\0']), ('\u{a7a7}', ['\u{a7a6}', '\0', + '\0']), ('\u{a7a9}', ['\u{a7a8}', '\0', '\0']), ('\u{a7b5}', ['\u{a7b4}', '\0', '\0']), + ('\u{a7b7}', ['\u{a7b6}', '\0', '\0']), ('\u{a7b9}', ['\u{a7b8}', '\0', '\0']), ('\u{ab53}', + ['\u{a7b3}', '\0', '\0']), ('\u{ab70}', ['\u{13a0}', '\0', '\0']), ('\u{ab71}', ['\u{13a1}', + '\0', '\0']), ('\u{ab72}', ['\u{13a2}', '\0', '\0']), ('\u{ab73}', ['\u{13a3}', '\0', + '\0']), ('\u{ab74}', ['\u{13a4}', '\0', '\0']), ('\u{ab75}', ['\u{13a5}', '\0', '\0']), + ('\u{ab76}', ['\u{13a6}', '\0', '\0']), ('\u{ab77}', ['\u{13a7}', '\0', '\0']), ('\u{ab78}', + ['\u{13a8}', '\0', '\0']), ('\u{ab79}', ['\u{13a9}', '\0', '\0']), ('\u{ab7a}', ['\u{13aa}', + '\0', '\0']), ('\u{ab7b}', ['\u{13ab}', '\0', '\0']), ('\u{ab7c}', ['\u{13ac}', '\0', + '\0']), ('\u{ab7d}', ['\u{13ad}', '\0', '\0']), ('\u{ab7e}', ['\u{13ae}', '\0', '\0']), + ('\u{ab7f}', ['\u{13af}', '\0', '\0']), ('\u{ab80}', ['\u{13b0}', '\0', '\0']), ('\u{ab81}', + ['\u{13b1}', '\0', '\0']), ('\u{ab82}', ['\u{13b2}', '\0', '\0']), ('\u{ab83}', ['\u{13b3}', + '\0', '\0']), ('\u{ab84}', ['\u{13b4}', '\0', '\0']), ('\u{ab85}', ['\u{13b5}', '\0', + '\0']), ('\u{ab86}', ['\u{13b6}', '\0', '\0']), ('\u{ab87}', ['\u{13b7}', '\0', '\0']), + ('\u{ab88}', ['\u{13b8}', '\0', '\0']), ('\u{ab89}', ['\u{13b9}', '\0', '\0']), ('\u{ab8a}', + ['\u{13ba}', '\0', '\0']), ('\u{ab8b}', ['\u{13bb}', '\0', '\0']), ('\u{ab8c}', ['\u{13bc}', + '\0', '\0']), ('\u{ab8d}', ['\u{13bd}', '\0', '\0']), ('\u{ab8e}', ['\u{13be}', '\0', + '\0']), ('\u{ab8f}', ['\u{13bf}', '\0', '\0']), ('\u{ab90}', ['\u{13c0}', '\0', '\0']), + ('\u{ab91}', ['\u{13c1}', '\0', '\0']), ('\u{ab92}', ['\u{13c2}', '\0', '\0']), ('\u{ab93}', + ['\u{13c3}', '\0', '\0']), ('\u{ab94}', ['\u{13c4}', '\0', '\0']), ('\u{ab95}', ['\u{13c5}', + '\0', '\0']), ('\u{ab96}', ['\u{13c6}', '\0', '\0']), ('\u{ab97}', ['\u{13c7}', '\0', + '\0']), ('\u{ab98}', ['\u{13c8}', '\0', '\0']), ('\u{ab99}', ['\u{13c9}', '\0', '\0']), + ('\u{ab9a}', ['\u{13ca}', '\0', '\0']), ('\u{ab9b}', ['\u{13cb}', '\0', '\0']), ('\u{ab9c}', + ['\u{13cc}', '\0', '\0']), ('\u{ab9d}', ['\u{13cd}', '\0', '\0']), ('\u{ab9e}', ['\u{13ce}', + '\0', '\0']), ('\u{ab9f}', ['\u{13cf}', '\0', '\0']), ('\u{aba0}', ['\u{13d0}', '\0', + '\0']), ('\u{aba1}', ['\u{13d1}', '\0', '\0']), ('\u{aba2}', ['\u{13d2}', '\0', '\0']), + ('\u{aba3}', ['\u{13d3}', '\0', '\0']), ('\u{aba4}', ['\u{13d4}', '\0', '\0']), ('\u{aba5}', + ['\u{13d5}', '\0', '\0']), ('\u{aba6}', ['\u{13d6}', '\0', '\0']), ('\u{aba7}', ['\u{13d7}', + '\0', '\0']), ('\u{aba8}', ['\u{13d8}', '\0', '\0']), ('\u{aba9}', ['\u{13d9}', '\0', + '\0']), ('\u{abaa}', ['\u{13da}', '\0', '\0']), ('\u{abab}', ['\u{13db}', '\0', '\0']), + ('\u{abac}', ['\u{13dc}', '\0', '\0']), ('\u{abad}', ['\u{13dd}', '\0', '\0']), ('\u{abae}', + ['\u{13de}', '\0', '\0']), ('\u{abaf}', ['\u{13df}', '\0', '\0']), ('\u{abb0}', ['\u{13e0}', + '\0', '\0']), ('\u{abb1}', ['\u{13e1}', '\0', '\0']), ('\u{abb2}', ['\u{13e2}', '\0', + '\0']), ('\u{abb3}', ['\u{13e3}', '\0', '\0']), ('\u{abb4}', ['\u{13e4}', '\0', '\0']), + ('\u{abb5}', ['\u{13e5}', '\0', '\0']), ('\u{abb6}', ['\u{13e6}', '\0', '\0']), ('\u{abb7}', + ['\u{13e7}', '\0', '\0']), ('\u{abb8}', ['\u{13e8}', '\0', '\0']), ('\u{abb9}', ['\u{13e9}', + '\0', '\0']), ('\u{abba}', ['\u{13ea}', '\0', '\0']), ('\u{abbb}', ['\u{13eb}', '\0', + '\0']), ('\u{abbc}', ['\u{13ec}', '\0', '\0']), ('\u{abbd}', ['\u{13ed}', '\0', '\0']), + ('\u{abbe}', ['\u{13ee}', '\0', '\0']), ('\u{abbf}', ['\u{13ef}', '\0', '\0']), ('\u{fb00}', + ['\u{46}', '\u{46}', '\0']), ('\u{fb01}', ['\u{46}', '\u{49}', '\0']), ('\u{fb02}', + ['\u{46}', '\u{4c}', '\0']), ('\u{fb03}', ['\u{46}', '\u{46}', '\u{49}']), ('\u{fb04}', + ['\u{46}', '\u{46}', '\u{4c}']), ('\u{fb05}', ['\u{53}', '\u{54}', '\0']), ('\u{fb06}', + ['\u{53}', '\u{54}', '\0']), ('\u{fb13}', ['\u{544}', '\u{546}', '\0']), ('\u{fb14}', + ['\u{544}', '\u{535}', '\0']), ('\u{fb15}', ['\u{544}', '\u{53b}', '\0']), ('\u{fb16}', + ['\u{54e}', '\u{546}', '\0']), ('\u{fb17}', ['\u{544}', '\u{53d}', '\0']), ('\u{ff41}', + ['\u{ff21}', '\0', '\0']), ('\u{ff42}', ['\u{ff22}', '\0', '\0']), ('\u{ff43}', ['\u{ff23}', + '\0', '\0']), ('\u{ff44}', ['\u{ff24}', '\0', '\0']), ('\u{ff45}', ['\u{ff25}', '\0', + '\0']), ('\u{ff46}', ['\u{ff26}', '\0', '\0']), ('\u{ff47}', ['\u{ff27}', '\0', '\0']), + ('\u{ff48}', ['\u{ff28}', '\0', '\0']), ('\u{ff49}', ['\u{ff29}', '\0', '\0']), ('\u{ff4a}', + ['\u{ff2a}', '\0', '\0']), ('\u{ff4b}', ['\u{ff2b}', '\0', '\0']), ('\u{ff4c}', ['\u{ff2c}', + '\0', '\0']), ('\u{ff4d}', ['\u{ff2d}', '\0', '\0']), ('\u{ff4e}', ['\u{ff2e}', '\0', + '\0']), ('\u{ff4f}', ['\u{ff2f}', '\0', '\0']), ('\u{ff50}', ['\u{ff30}', '\0', '\0']), + ('\u{ff51}', ['\u{ff31}', '\0', '\0']), ('\u{ff52}', ['\u{ff32}', '\0', '\0']), ('\u{ff53}', + ['\u{ff33}', '\0', '\0']), ('\u{ff54}', ['\u{ff34}', '\0', '\0']), ('\u{ff55}', ['\u{ff35}', + '\0', '\0']), ('\u{ff56}', ['\u{ff36}', '\0', '\0']), ('\u{ff57}', ['\u{ff37}', '\0', + '\0']), ('\u{ff58}', ['\u{ff38}', '\0', '\0']), ('\u{ff59}', ['\u{ff39}', '\0', '\0']), + ('\u{ff5a}', ['\u{ff3a}', '\0', '\0']), ('\u{10428}', ['\u{10400}', '\0', '\0']), ('\u{10429}', ['\u{10401}', '\0', '\0']), ('\u{1042a}', ['\u{10402}', '\0', '\0']), ('\u{1042b}', ['\u{10403}', '\0', '\0']), ('\u{1042c}', ['\u{10404}', '\0', '\0']), ('\u{1042d}', ['\u{10405}', '\0', '\0']), ('\u{1042e}', ['\u{10406}', '\0', '\0']), @@ -2353,6 +2548,22 @@ pub mod conversions { ('\u{118da}', ['\u{118ba}', '\0', '\0']), ('\u{118db}', ['\u{118bb}', '\0', '\0']), ('\u{118dc}', ['\u{118bc}', '\0', '\0']), ('\u{118dd}', ['\u{118bd}', '\0', '\0']), ('\u{118de}', ['\u{118be}', '\0', '\0']), ('\u{118df}', ['\u{118bf}', '\0', '\0']), + ('\u{16e60}', ['\u{16e40}', '\0', '\0']), ('\u{16e61}', ['\u{16e41}', '\0', '\0']), + ('\u{16e62}', ['\u{16e42}', '\0', '\0']), ('\u{16e63}', ['\u{16e43}', '\0', '\0']), + ('\u{16e64}', ['\u{16e44}', '\0', '\0']), ('\u{16e65}', ['\u{16e45}', '\0', '\0']), + ('\u{16e66}', ['\u{16e46}', '\0', '\0']), ('\u{16e67}', ['\u{16e47}', '\0', '\0']), + ('\u{16e68}', ['\u{16e48}', '\0', '\0']), ('\u{16e69}', ['\u{16e49}', '\0', '\0']), + ('\u{16e6a}', ['\u{16e4a}', '\0', '\0']), ('\u{16e6b}', ['\u{16e4b}', '\0', '\0']), + ('\u{16e6c}', ['\u{16e4c}', '\0', '\0']), ('\u{16e6d}', ['\u{16e4d}', '\0', '\0']), + ('\u{16e6e}', ['\u{16e4e}', '\0', '\0']), ('\u{16e6f}', ['\u{16e4f}', '\0', '\0']), + ('\u{16e70}', ['\u{16e50}', '\0', '\0']), ('\u{16e71}', ['\u{16e51}', '\0', '\0']), + ('\u{16e72}', ['\u{16e52}', '\0', '\0']), ('\u{16e73}', ['\u{16e53}', '\0', '\0']), + ('\u{16e74}', ['\u{16e54}', '\0', '\0']), ('\u{16e75}', ['\u{16e55}', '\0', '\0']), + ('\u{16e76}', ['\u{16e56}', '\0', '\0']), ('\u{16e77}', ['\u{16e57}', '\0', '\0']), + ('\u{16e78}', ['\u{16e58}', '\0', '\0']), ('\u{16e79}', ['\u{16e59}', '\0', '\0']), + ('\u{16e7a}', ['\u{16e5a}', '\0', '\0']), ('\u{16e7b}', ['\u{16e5b}', '\0', '\0']), + ('\u{16e7c}', ['\u{16e5c}', '\0', '\0']), ('\u{16e7d}', ['\u{16e5d}', '\0', '\0']), + ('\u{16e7e}', ['\u{16e5e}', '\0', '\0']), ('\u{16e7f}', ['\u{16e5f}', '\0', '\0']), ('\u{1e922}', ['\u{1e900}', '\0', '\0']), ('\u{1e923}', ['\u{1e901}', '\0', '\0']), ('\u{1e924}', ['\u{1e902}', '\0', '\0']), ('\u{1e925}', ['\u{1e903}', '\0', '\0']), ('\u{1e926}', ['\u{1e904}', '\0', '\0']), ('\u{1e927}', ['\u{1e905}', '\0', '\0']), diff --git a/src/libcore/unicode/unicode.py b/src/libcore/unicode/unicode.py index 75ec01944bfb9..be0970b544406 100755 --- a/src/libcore/unicode/unicode.py +++ b/src/libcore/unicode/unicode.py @@ -21,11 +21,14 @@ # - UnicodeData.txt # # Since this should not require frequent updates, we just store this -# out-of-line and check the unicode.rs file into git. +# out-of-line and check the tables.rs file into git. -import fileinput, re, os, sys, operator, math +import fileinput, re, os, sys, operator, math, datetime -preamble = '''// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT +# The directory in which this file resides. +fdir = os.path.dirname(os.path.realpath(__file__)) + "/" + +preamble = '''// Copyright 2012-{year} The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -40,8 +43,8 @@ #![allow(missing_docs, non_upper_case_globals, non_snake_case)] use unicode::version::UnicodeVersion; -use unicode::bool_trie::{BoolTrie, SmallBoolTrie}; -''' +use unicode::bool_trie::{{BoolTrie, SmallBoolTrie}}; +'''.format(year = datetime.datetime.now().year) # Mapping taken from Table 12 from: # http://www.unicode.org/reports/tr44/#General_Category_Values @@ -61,11 +64,11 @@ surrogate_codepoints = (0xd800, 0xdfff) def fetch(f): - if not os.path.exists(os.path.basename(f)): - os.system("curl -O http://www.unicode.org/Public/UNIDATA/%s" - % f) + path = fdir + os.path.basename(f) + if not os.path.exists(path): + os.system("curl -o {0}{1} ftp://ftp.unicode.org/Public/UNIDATA/{1}".format(fdir, f)) - if not os.path.exists(os.path.basename(f)): + if not os.path.exists(path): sys.stderr.write("cannot load %s" % f) exit(1) @@ -84,7 +87,7 @@ def load_unicode_data(f): udict = {} range_start = -1 - for line in fileinput.input(f): + for line in fileinput.input(fdir + f): data = line.split(';') if len(data) != 15: continue @@ -156,7 +159,7 @@ def load_unicode_data(f): def load_special_casing(f, to_upper, to_lower, to_title): fetch(f) - for line in fileinput.input(f): + for line in fileinput.input(fdir + f): data = line.split('#')[0].split(';') if len(data) == 5: code, lower, title, upper, _comment = data @@ -243,7 +246,7 @@ def load_properties(f, interestingprops): re1 = re.compile("^ *([0-9A-F]+) *; *(\w+)") re2 = re.compile("^ *([0-9A-F]+)\.\.([0-9A-F]+) *; *(\w+)") - for line in fileinput.input(os.path.basename(f)): + for line in fileinput.input(fdir + os.path.basename(f)): prop = None d_lo = 0 d_hi = 0 @@ -456,7 +459,7 @@ def emit_norm_module(f, canon, compat, combine, norm_props): canon_comp_keys = sorted(canon_comp.keys()) if __name__ == "__main__": - r = "tables.rs" + r = fdir + "tables.rs" if os.path.exists(r): os.remove(r) with open(r, "w") as rf: @@ -465,7 +468,7 @@ def emit_norm_module(f, canon, compat, combine, norm_props): # download and parse all the data fetch("ReadMe.txt") - with open("ReadMe.txt") as readme: + with open(fdir + "ReadMe.txt") as readme: pattern = "for Version (\d+)\.(\d+)\.(\d+) of the Unicode" unicode_version = re.search(pattern, readme.read()).groups() rf.write(""" @@ -483,7 +486,7 @@ def emit_norm_module(f, canon, compat, combine, norm_props): to_upper, to_lower, to_title) = load_unicode_data("UnicodeData.txt") load_special_casing("SpecialCasing.txt", to_upper, to_lower, to_title) want_derived = ["XID_Start", "XID_Continue", "Alphabetic", "Lowercase", "Uppercase", - "Cased", "Case_Ignorable"] + "Cased", "Case_Ignorable", "Grapheme_Extend"] derived = load_properties("DerivedCoreProperties.txt", want_derived) scripts = load_properties("Scripts.txt", []) props = load_properties("PropList.txt", @@ -500,3 +503,4 @@ def emit_norm_module(f, canon, compat, combine, norm_props): # normalizations and conversions module emit_norm_module(rf, canon_decomp, compat_decomp, combines, norm_props) emit_conversions_module(rf, to_upper, to_lower, to_title) + print("Regenerated tables.rs.") diff --git a/src/libfmt_macros/lib.rs b/src/libfmt_macros/lib.rs index a551b1b770a68..3aa09a91e0765 100644 --- a/src/libfmt_macros/lib.rs +++ b/src/libfmt_macros/lib.rs @@ -127,6 +127,14 @@ pub enum Count<'a> { CountImplied, } +pub struct ParseError { + pub description: string::String, + pub note: Option, + pub label: string::String, + pub start: usize, + pub end: usize, +} + /// The parser structure for interpreting the input format string. This is /// modeled as an iterator over `Piece` structures to form a stream of tokens /// being output. @@ -137,15 +145,22 @@ pub struct Parser<'a> { input: &'a str, cur: iter::Peekable>, /// Error messages accumulated during parsing - pub errors: Vec<(string::String, Option)>, + pub errors: Vec, /// Current position of implicit positional argument pointer curarg: usize, + /// `Some(raw count)` when the string is "raw", used to position spans correctly + style: Option, + /// How many newlines have been seen in the string so far, to adjust the error spans + seen_newlines: usize, + /// Start and end byte offset of every successfuly parsed argument + pub arg_places: Vec<(usize, usize)>, } impl<'a> Iterator for Parser<'a> { type Item = Piece<'a>; fn next(&mut self) -> Option> { + let raw = self.style.map(|raw| raw + self.seen_newlines).unwrap_or(0); if let Some(&(pos, c)) = self.cur.peek() { match c { '{' => { @@ -153,9 +168,13 @@ impl<'a> Iterator for Parser<'a> { if self.consume('{') { Some(String(self.string(pos + 1))) } else { - let ret = Some(NextArgument(self.argument())); - self.must_consume('}'); - ret + let mut arg = self.argument(); + if let Some(arg_pos) = self.must_consume('}').map(|end| { + (pos + raw + 1, end + raw + 2) + }) { + self.arg_places.push(arg_pos); + } + Some(NextArgument(arg)) } } '}' => { @@ -163,12 +182,21 @@ impl<'a> Iterator for Parser<'a> { if self.consume('}') { Some(String(self.string(pos + 1))) } else { - self.err_with_note("unmatched `}` found", - "if you intended to print `}`, \ - you can escape it using `}}`"); + let err_pos = pos + raw + 1; + self.err_with_note( + "unmatched `}` found", + "unmatched `}`", + "if you intended to print `}`, you can escape it using `}}`", + err_pos, + err_pos, + ); None } } + '\n' => { + self.seen_newlines += 1; + Some(String(self.string(pos))) + } _ => Some(String(self.string(pos))), } } else { @@ -179,27 +207,55 @@ impl<'a> Iterator for Parser<'a> { impl<'a> Parser<'a> { /// Creates a new parser for the given format string - pub fn new(s: &'a str) -> Parser<'a> { + pub fn new(s: &'a str, style: Option) -> Parser<'a> { Parser { input: s, cur: s.char_indices().peekable(), errors: vec![], curarg: 0, + style, + seen_newlines: 0, + arg_places: vec![], } } /// Notifies of an error. The message doesn't actually need to be of type /// String, but I think it does when this eventually uses conditions so it /// might as well start using it now. - fn err(&mut self, msg: &str) { - self.errors.push((msg.to_owned(), None)); + fn err, S2: Into>( + &mut self, + description: S1, + label: S2, + start: usize, + end: usize, + ) { + self.errors.push(ParseError { + description: description.into(), + note: None, + label: label.into(), + start, + end, + }); } /// Notifies of an error. The message doesn't actually need to be of type /// String, but I think it does when this eventually uses conditions so it /// might as well start using it now. - fn err_with_note(&mut self, msg: &str, note: &str) { - self.errors.push((msg.to_owned(), Some(note.to_owned()))); + fn err_with_note, S2: Into, S3: Into>( + &mut self, + description: S1, + label: S2, + note: S3, + start: usize, + end: usize, + ) { + self.errors.push(ParseError { + description: description.into(), + note: Some(note.into()), + label: label.into(), + start, + end, + }); } /// Optionally consumes the specified character. If the character is not at @@ -220,22 +276,40 @@ impl<'a> Parser<'a> { /// Forces consumption of the specified character. If the character is not /// found, an error is emitted. - fn must_consume(&mut self, c: char) { + fn must_consume(&mut self, c: char) -> Option { self.ws(); - if let Some(&(_, maybe)) = self.cur.peek() { + let raw = self.style.unwrap_or(0); + + let padding = raw + self.seen_newlines; + if let Some(&(pos, maybe)) = self.cur.peek() { if c == maybe { self.cur.next(); + Some(pos) } else { - self.err(&format!("expected `{:?}`, found `{:?}`", c, maybe)); + let pos = pos + padding + 1; + self.err(format!("expected `{:?}`, found `{:?}`", c, maybe), + format!("expected `{}`", c), + pos, + pos); + None } } else { - let msg = &format!("expected `{:?}` but string was terminated", c); + let msg = format!("expected `{:?}` but string was terminated", c); + // point at closing `"`, unless the last char is `\n` to account for `println` + let pos = match self.input.chars().last() { + Some('\n') => self.input.len(), + _ => self.input.len() + 1, + }; if c == '}' { self.err_with_note(msg, - "if you intended to print `{`, you can escape it using `{{`"); + format!("expected `{:?}`", c), + "if you intended to print `{`, you can escape it using `{{`", + pos + padding, + pos + padding); } else { - self.err(msg); + self.err(msg, format!("expected `{:?}`", c), pos, pos); } + None } } @@ -300,6 +374,15 @@ impl<'a> Parser<'a> { } else { match self.cur.peek() { Some(&(_, c)) if c.is_alphabetic() => Some(ArgumentNamed(self.word())), + Some(&(pos, c)) if c == '_' => { + let invalid_name = self.string(pos); + self.err_with_note(format!("invalid argument name `{}`", invalid_name), + "invalid argument name", + "argument names cannot start with an underscore", + pos + 1, // add 1 to account for leading `{` + pos + 1 + invalid_name.len()); + Some(ArgumentNamed(invalid_name)) + }, // This is an `ArgumentNext`. // Record the fact and do the resolution after parsing the @@ -480,7 +563,7 @@ mod tests { use super::*; fn same(fmt: &'static str, p: &[Piece<'static>]) { - let parser = Parser::new(fmt); + let parser = Parser::new(fmt, None); assert!(parser.collect::>>() == p); } @@ -496,7 +579,7 @@ mod tests { } fn musterr(s: &str) { - let mut p = Parser::new(s); + let mut p = Parser::new(s, None); p.next(); assert!(!p.errors.is_empty()); } diff --git a/src/liblibc b/src/liblibc index a7e78a78e17c8..b6d23ed45d729 160000 --- a/src/liblibc +++ b/src/liblibc @@ -1 +1 @@ -Subproject commit a7e78a78e17c8776d7780008ccb3ce541ec64ae9 +Subproject commit b6d23ed45d72918239c0bfac11dc547895e59b81 diff --git a/src/libpanic_unwind/dwarf/eh.rs b/src/libpanic_unwind/dwarf/eh.rs index 0c326ce371843..a24c659689139 100644 --- a/src/libpanic_unwind/dwarf/eh.rs +++ b/src/libpanic_unwind/dwarf/eh.rs @@ -48,8 +48,8 @@ pub const DW_EH_PE_indirect: u8 = 0x80; pub struct EHContext<'a> { pub ip: usize, // Current instruction pointer pub func_start: usize, // Address of the current function - pub get_text_start: &'a Fn() -> usize, // Get address of the code section - pub get_data_start: &'a Fn() -> usize, // Get address of the data section + pub get_text_start: &'a dyn Fn() -> usize, // Get address of the code section + pub get_data_start: &'a dyn Fn() -> usize, // Get address of the data section } pub enum EHAction { diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index 0e48e37c92358..87efc23abc81d 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -29,20 +29,20 @@ pub fn payload() -> *mut u8 { ptr::null_mut() } -pub unsafe fn cleanup(ptr: *mut u8) -> Box { +pub unsafe fn cleanup(ptr: *mut u8) -> Box { assert!(!ptr.is_null()); let ex = ptr::read(ptr as *mut _); __cxa_free_exception(ptr as *mut _); ex } -pub unsafe fn panic(data: Box) -> u32 { +pub unsafe fn panic(data: Box) -> u32 { let sz = mem::size_of_val(&data); let exception = __cxa_allocate_exception(sz); if exception == ptr::null_mut() { return uw::_URC_FATAL_PHASE1_ERROR as u32; } - let exception = exception as *mut Box; + let exception = exception as *mut Box; ptr::write(exception, data); __cxa_throw(exception as *mut _, ptr::null_mut(), ptr::null_mut()); diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index eb6dc5b548869..11ebcf5c01ea7 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -67,10 +67,10 @@ use dwarf::eh::{self, EHContext, EHAction}; #[repr(C)] struct Exception { _uwe: uw::_Unwind_Exception, - cause: Option>, + cause: Option>, } -pub unsafe fn panic(data: Box) -> u32 { +pub unsafe fn panic(data: Box) -> u32 { let exception = Box::new(Exception { _uwe: uw::_Unwind_Exception { exception_class: rust_exception_class(), @@ -94,7 +94,7 @@ pub fn payload() -> *mut u8 { ptr::null_mut() } -pub unsafe fn cleanup(ptr: *mut u8) -> Box { +pub unsafe fn cleanup(ptr: *mut u8) -> Box { let my_ep = ptr as *mut Exception; let cause = (*my_ep).cause.take(); uw::_Unwind_DeleteException(ptr as *mut _); @@ -143,7 +143,7 @@ const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1 // The personality routine for most of our targets, except ARM, which has a slightly different ABI // (however, iOS goes here as it uses SjLj unwinding). Also, the 64-bit Windows implementation // lives in seh64_gnu.rs -#[cfg(all(any(target_os = "ios", not(target_arch = "arm"))))] +#[cfg(all(any(target_os = "ios", target_os = "netbsd", not(target_arch = "arm"))))] #[lang = "eh_personality"] #[no_mangle] #[allow(unused)] @@ -184,7 +184,7 @@ unsafe extern "C" fn rust_eh_personality(version: c_int, // ARM EHABI personality routine. // http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf -#[cfg(all(target_arch = "arm", not(target_os = "ios")))] +#[cfg(all(target_arch = "arm", not(target_os = "ios"), not(target_os = "netbsd")))] #[lang = "eh_personality"] #[no_mangle] unsafe extern "C" fn rust_eh_personality(state: uw::_Unwind_State, diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 6c52c0fa10cc0..5c320bb369e70 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -117,6 +117,6 @@ pub unsafe extern "C" fn __rust_maybe_catch_panic(f: fn(*mut u8), #[no_mangle] #[unwind(allowed)] pub unsafe extern "C" fn __rust_start_panic(payload: usize) -> u32 { - let payload = payload as *mut &mut BoxMeUp; + let payload = payload as *mut &mut dyn BoxMeUp; imp::panic(Box::from_raw((*payload).box_me_up())) } diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index 5896421493008..8cbc4a623fa05 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -43,7 +43,7 @@ //! throwing. Note that throwing an exception into Rust is undefined behavior //! anyway, so this should be fine. //! * We've got some data to transmit across the unwinding boundary, -//! specifically a `Box`. Like with Dwarf exceptions +//! specifically a `Box`. Like with Dwarf exceptions //! these two pointers are stored as a payload in the exception itself. On //! MSVC, however, there's no need for an extra heap allocation because the //! call stack is preserved while filter functions are being executed. This @@ -243,7 +243,7 @@ static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor { name: imp::NAME2, }; -pub unsafe fn panic(data: Box) -> u32 { +pub unsafe fn panic(data: Box) -> u32 { use core::intrinsics::atomic_store; // _CxxThrowException executes entirely on this stack frame, so there's no @@ -297,7 +297,7 @@ pub fn payload() -> [u64; 2] { [0; 2] } -pub unsafe fn cleanup(payload: [u64; 2]) -> Box { +pub unsafe fn cleanup(payload: [u64; 2]) -> Box { mem::transmute(raw::TraitObject { data: payload[0] as *mut _, vtable: payload[1] as *mut _, diff --git a/src/libpanic_unwind/seh64_gnu.rs b/src/libpanic_unwind/seh64_gnu.rs index c3715f96c6482..0b08e54c6739a 100644 --- a/src/libpanic_unwind/seh64_gnu.rs +++ b/src/libpanic_unwind/seh64_gnu.rs @@ -37,10 +37,10 @@ const RUST_PANIC: c::DWORD = ETYPE | (1 << 24) | MAGIC; #[repr(C)] struct PanicData { - data: Box, + data: Box, } -pub unsafe fn panic(data: Box) -> u32 { +pub unsafe fn panic(data: Box) -> u32 { let panic_ctx = Box::new(PanicData { data: data }); let params = [Box::into_raw(panic_ctx) as c::ULONG_PTR]; c::RaiseException(RUST_PANIC, @@ -54,7 +54,7 @@ pub fn payload() -> *mut u8 { ptr::null_mut() } -pub unsafe fn cleanup(ptr: *mut u8) -> Box { +pub unsafe fn cleanup(ptr: *mut u8) -> Box { let panic_ctx = Box::from_raw(ptr as *mut PanicData); return panic_ctx.data; } diff --git a/src/libpanic_unwind/wasm32.rs b/src/libpanic_unwind/wasm32.rs index 8aed61b3c385a..7150560b4a13d 100644 --- a/src/libpanic_unwind/wasm32.rs +++ b/src/libpanic_unwind/wasm32.rs @@ -20,10 +20,10 @@ pub fn payload() -> *mut u8 { 0 as *mut u8 } -pub unsafe fn cleanup(_ptr: *mut u8) -> Box { +pub unsafe fn cleanup(_ptr: *mut u8) -> Box { intrinsics::abort() } -pub unsafe fn panic(_data: Box) -> u32 { +pub unsafe fn panic(_data: Box) -> u32 { intrinsics::abort() } diff --git a/src/libproc_macro/diagnostic.rs b/src/libproc_macro/diagnostic.rs index c39aec896e6b4..51e7647f36cc2 100644 --- a/src/libproc_macro/diagnostic.rs +++ b/src/libproc_macro/diagnostic.rs @@ -10,10 +10,11 @@ use Span; -use rustc_errors as rustc; +use rustc_errors as errors; +use syntax_pos::MultiSpan; /// An enum representing a diagnostic level. -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] #[derive(Copy, Clone, Debug)] pub enum Level { /// An error. @@ -30,7 +31,7 @@ pub enum Level { /// A structure representing a diagnostic message and associated children /// messages. -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] #[derive(Clone, Debug)] pub struct Diagnostic { level: Level, @@ -43,7 +44,7 @@ macro_rules! diagnostic_child_methods { ($spanned:ident, $regular:ident, $level:expr) => ( /// Add a new child diagnostic message to `self` with the level /// identified by this methods name with the given `span` and `message`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn $spanned>(mut self, span: Span, message: T) -> Diagnostic { self.children.push(Diagnostic::spanned(span, $level, message)); self @@ -51,7 +52,7 @@ macro_rules! diagnostic_child_methods { /// Add a new child diagnostic message to `self` with the level /// identified by this method's name with the given `message`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn $regular>(mut self, message: T) -> Diagnostic { self.children.push(Diagnostic::new($level, message)); self @@ -61,7 +62,7 @@ macro_rules! diagnostic_child_methods { impl Diagnostic { /// Create a new diagnostic with the given `level` and `message`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn new>(level: Level, message: T) -> Diagnostic { Diagnostic { level: level, @@ -73,7 +74,7 @@ impl Diagnostic { /// Create a new diagnostic with the given `level` and `message` pointing to /// the given `span`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn spanned>(span: Span, level: Level, message: T) -> Diagnostic { Diagnostic { level: level, @@ -89,46 +90,29 @@ impl Diagnostic { diagnostic_child_methods!(span_help, help, Level::Help); /// Returns the diagnostic `level` for `self`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn level(&self) -> Level { self.level } /// Emit the diagnostic. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn emit(self) { - ::__internal::with_sess(move |(sess, _)| { - let handler = &sess.span_diagnostic; - let level = __internal::level_to_internal_level(self.level); - let mut diag = rustc::DiagnosticBuilder::new(handler, level, &*self.message); + let level = self.level.to_internal(); + let mut diag = errors::Diagnostic::new(level, &*self.message); - if let Some(span) = self.span { - diag.set_span(span.0); - } + if let Some(span) = self.span { + diag.set_span(span.0); + } - for child in self.children { - let span = child.span.map(|s| s.0); - let level = __internal::level_to_internal_level(child.level); - diag.sub(level, &*child.message, span); - } + for child in self.children { + let span = child.span.map_or(MultiSpan::new(), |s| s.0.into()); + let level = child.level.to_internal(); + diag.sub(level, &*child.message, span, None); + } - diag.emit(); + ::__internal::with_sess(move |sess, _| { + errors::DiagnosticBuilder::new_diagnostic(&sess.span_diagnostic, diag).emit(); }); } } - -#[unstable(feature = "proc_macro_internals", issue = "27812")] -#[doc(hidden)] -pub mod __internal { - use super::{Level, rustc}; - - pub fn level_to_internal_level(level: Level) -> rustc::Level { - match level { - Level::Error => rustc::Level::Error, - Level::Warning => rustc::Level::Warning, - Level::Note => rustc::Level::Note, - Level::Help => rustc::Level::Help, - Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive") - } - } -} diff --git a/src/libproc_macro/lib.rs b/src/libproc_macro/lib.rs index 8451e5987e908..bf6e4a3aaa405 100644 --- a/src/libproc_macro/lib.rs +++ b/src/libproc_macro/lib.rs @@ -11,13 +11,11 @@ //! A support library for macro authors when defining new macros. //! //! This library, provided by the standard distribution, provides the types -//! consumed in the interfaces of procedurally defined macro definitions. -//! Currently the primary use of this crate is to provide the ability to define -//! new custom derive modes through `#[proc_macro_derive]`. +//! consumed in the interfaces of procedurally defined macro definitions such as +//! function-like macros `#[proc_macro]`, macro attribures `#[proc_macro_attribute]` and +//! custom derive attributes`#[proc_macro_derive]`. //! -//! Note that this crate is intentionally very bare-bones currently. The main -//! type, `TokenStream`, only supports `fmt::Display` and `FromStr` -//! implementations, indicating that it can only go to and come from a string. +//! Note that this crate is intentionally bare-bones currently. //! This functionality is intended to be expanded over time as more surface //! area for macro authors is stabilized. //! @@ -38,35 +36,40 @@ #![feature(lang_items)] #![feature(optin_builtin_traits)] +#![recursion_limit="256"] + extern crate syntax; extern crate syntax_pos; extern crate rustc_errors; extern crate rustc_data_structures; +#[unstable(feature = "proc_macro_internals", issue = "27812")] +#[doc(hidden)] +pub mod rustc; + mod diagnostic; -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub use diagnostic::{Diagnostic, Level}; use std::{ascii, fmt, iter}; +use std::path::PathBuf; use rustc_data_structures::sync::Lrc; use std::str::FromStr; -use syntax::ast; use syntax::errors::DiagnosticBuilder; use syntax::parse::{self, token}; use syntax::symbol::Symbol; use syntax::tokenstream; -use syntax::parse::lexer::comments; -use syntax_pos::{FileMap, Pos, SyntaxContext, FileName}; -use syntax_pos::hygiene::Mark; +use syntax_pos::{FileMap, Pos, FileName}; /// The main type provided by this crate, representing an abstract stream of -/// tokens. +/// tokens, or, more specifically, a sequence of token trees. +/// The type provide interfaces for iterating over those token trees and, conversely, +/// collecting a number of token trees into one stream. /// -/// This is both the input and output of `#[proc_macro_derive]` definitions. -/// Currently it's required to be a list of valid Rust items, but this -/// restriction may be lifted in the future. +/// This is both the input and output of `#[proc_macro]`, `#[proc_macro_attribute]` +/// and `#[proc_macro_derive]` definitions. /// /// The API of this type is intentionally bare-bones, but it'll be expanded over /// time! @@ -74,9 +77,9 @@ use syntax_pos::hygiene::Mark; #[derive(Clone)] pub struct TokenStream(tokenstream::TokenStream); -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib", since = "1.15.0")] impl !Send for TokenStream {} -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib", since = "1.15.0")] impl !Sync for TokenStream {} /// Error returned from `TokenStream::from_str`. @@ -86,45 +89,48 @@ pub struct LexError { _inner: (), } -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib", since = "1.15.0")] impl !Send for LexError {} -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib", since = "1.15.0")] impl !Sync for LexError {} impl TokenStream { - /// Returns an empty `TokenStream`. - #[unstable(feature = "proc_macro", issue = "38356")] - pub fn empty() -> TokenStream { + /// Returns an empty `TokenStream` containing no token trees. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + pub fn new() -> TokenStream { TokenStream(tokenstream::TokenStream::empty()) } /// Checks if this `TokenStream` is empty. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn is_empty(&self) -> bool { self.0.is_empty() } } +/// Attempts to break the string into tokens and parse those tokens into a token stream. +/// May fail for a number of reasons, for example, if the string contains unbalanced delimiters +/// or characters not existing in the language. +/// All tokens in the parsed stream get `Span::call_site()` spans. +/// +/// NOTE: Some errors may cause panics instead of returning `LexError`. We reserve the right to +/// change these errors into `LexError`s later. #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl FromStr for TokenStream { type Err = LexError; fn from_str(src: &str) -> Result { - __internal::with_sess(|(sess, mark)| { - let src = src.to_string(); - let name = FileName::ProcMacroSourceCode; - let expn_info = mark.expn_info().unwrap(); - let call_site = expn_info.call_site; - // notify the expansion info that it is unhygienic - let mark = Mark::fresh(mark); - mark.set_expn_info(expn_info); - let span = call_site.with_ctxt(SyntaxContext::empty().apply_mark(mark)); - let stream = parse::parse_stream_from_source_str(name, src, sess, Some(span)); - Ok(__internal::token_stream_wrap(stream)) + __internal::with_sess(|sess, data| { + Ok(__internal::token_stream_wrap(parse::parse_stream_from_source_str( + FileName::ProcMacroSourceCode, src.to_string(), sess, Some(data.call_site.0) + ))) }) } } +/// Prints the token stream as a string that is supposed to be losslessly convertible back +/// into the same token stream (modulo spans), except for possibly `TokenTree::Group`s +/// with `Delimiter::None` delimiters and negative numeric literals. #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl fmt::Display for TokenStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -132,6 +138,7 @@ impl fmt::Display for TokenStream { } } +/// Prints token in a form convenient for debugging. #[stable(feature = "proc_macro_lib", since = "1.15.0")] impl fmt::Debug for TokenStream { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -140,21 +147,28 @@ impl fmt::Debug for TokenStream { } } -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub use quote::{quote, quote_span}; + +/// Creates a token stream containing a single token tree. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl From for TokenStream { fn from(tree: TokenTree) -> TokenStream { TokenStream(tree.to_internal()) } } -#[unstable(feature = "proc_macro", issue = "38356")] +/// Collects a number of token trees into a single stream. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl iter::FromIterator for TokenStream { fn from_iter>(trees: I) -> Self { trees.into_iter().map(TokenStream::from).collect() } } -#[unstable(feature = "proc_macro", issue = "38356")] +/// A "flattening" operation on token streams, collects token trees +/// from multiple token streams into a single stream. +#[stable(feature = "proc_macro_lib", since = "1.15.0")] impl iter::FromIterator for TokenStream { fn from_iter>(streams: I) -> Self { let mut builder = tokenstream::TokenStreamBuilder::new(); @@ -165,23 +179,23 @@ impl iter::FromIterator for TokenStream { } } -/// Implementation details for the `TokenTree` type, such as iterators. -#[unstable(feature = "proc_macro", issue = "38356")] +/// Public implementation details for the `TokenStream` type, such as iterators. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub mod token_stream { use syntax::tokenstream; - use syntax_pos::DUMMY_SP; - use {TokenTree, TokenStream, Delimiter}; - /// An iterator over `TokenTree`s. + /// An iterator over `TokenStream`'s `TokenTree`s. + /// The iteration is "shallow", e.g. the iterator doesn't recurse into delimited groups, + /// and returns whole groups as token trees. #[derive(Clone)] - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct IntoIter { cursor: tokenstream::Cursor, stack: Vec, } - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl Iterator for IntoIter { type Item = TokenTree; @@ -191,7 +205,13 @@ pub mod token_stream { let next = self.cursor.next_as_stream()?; Some(TokenTree::from_internal(next, &mut self.stack)) })?; - if tree.span().0 == DUMMY_SP { + // HACK: The condition "dummy span + group with empty delimiter" represents an AST + // fragment approximately converted into a token stream. This may happen, for + // example, with inputs to proc macro attributes, including derives. Such "groups" + // need to flattened during iteration over stream's token trees. + // Eventually this needs to be removed in favor of keeping original token trees + // and not doing the roundtrip through AST. + if tree.span().0.is_dummy() { if let TokenTree::Group(ref group) = tree { if group.delimiter() == Delimiter::None { self.cursor.insert(group.stream.clone().0); @@ -204,7 +224,7 @@ pub mod token_stream { } } - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl IntoIterator for TokenStream { type Item = TokenTree; type IntoIter = IntoIter; @@ -217,11 +237,13 @@ pub mod token_stream { /// `quote!(..)` accepts arbitrary tokens and expands into a `TokenStream` describing the input. /// For example, `quote!(a + b)` will produce a expression, that, when evaluated, constructs -/// the `TokenStream` `[Word("a"), Op('+', Alone), Word("b")]`. +/// the `TokenStream` `[Ident("a"), Punct('+', Alone), Ident("b")]`. /// /// Unquoting is done with `$`, and works by taking the single next ident as the unquoted term. /// To quote `$` itself, use `$$`. -#[unstable(feature = "proc_macro", issue = "38356")] +/// +/// This is a dummy macro, the actual implementation is in `quote::quote`.` +#[unstable(feature = "proc_macro_quote", issue = "38356")] #[macro_export] macro_rules! quote { () => {} } @@ -229,28 +251,21 @@ macro_rules! quote { () => {} } #[doc(hidden)] mod quote; -/// Quote a `Span` into a `TokenStream`. -/// This is needed to implement a custom quoter. -#[unstable(feature = "proc_macro", issue = "38356")] -pub fn quote_span(span: Span) -> TokenStream { - quote::Quote::quote(span) -} - /// A region of source code, along with macro expansion information. -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Copy, Clone)] pub struct Span(syntax_pos::Span); -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Send for Span {} -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Sync for Span {} macro_rules! diagnostic_method { ($name:ident, $level:expr) => ( /// Create a new `Diagnostic` with the given `message` at the span /// `self`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_diagnostic", issue = "38356")] pub fn $name>(self, message: T) -> Diagnostic { Diagnostic::spanned(self, $level, message) } @@ -259,22 +274,22 @@ macro_rules! diagnostic_method { impl Span { /// A span that resolves at the macro definition site. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn def_site() -> Span { - ::__internal::with_sess(|(_, mark)| { - let call_site = mark.expn_info().unwrap().call_site; - Span(call_site.with_ctxt(SyntaxContext::empty().apply_mark(mark))) - }) + ::__internal::with_sess(|_, data| data.def_site) } /// The span of the invocation of the current procedural macro. - #[unstable(feature = "proc_macro", issue = "38356")] + /// Identifiers created with this span will be resolved as if they were written + /// directly at the macro call location (call-site hygiene) and other code + /// at the macro call site will be able to refer to them as well. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn call_site() -> Span { - ::__internal::with_sess(|(_, mark)| Span(mark.expn_info().unwrap().call_site)) + ::__internal::with_sess(|_, data| data.call_site) } /// The original source file into which this span points. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn source_file(&self) -> SourceFile { SourceFile { filemap: __internal::lookup_char_pos(self.0.lo()).file, @@ -283,7 +298,7 @@ impl Span { /// The `Span` for the tokens in the previous macro expansion from which /// `self` was generated from, if any. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn parent(&self) -> Option { self.0.parent().map(Span) } @@ -291,13 +306,13 @@ impl Span { /// The span for the origin source code that `self` was generated from. If /// this `Span` wasn't generated from other macro expansions then the return /// value is the same as `*self`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn source(&self) -> Span { Span(self.0.source_callsite()) } /// Get the starting line/column in the source file for this span. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn start(&self) -> LineColumn { let loc = __internal::lookup_char_pos(self.0.lo()); LineColumn { @@ -307,7 +322,7 @@ impl Span { } /// Get the ending line/column in the source file for this span. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn end(&self) -> LineColumn { let loc = __internal::lookup_char_pos(self.0.hi()); LineColumn { @@ -319,7 +334,7 @@ impl Span { /// Create a new span encompassing `self` and `other`. /// /// Returns `None` if `self` and `other` are from different files. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn join(&self, other: Span) -> Option { let self_loc = __internal::lookup_char_pos(self.0.lo()); let other_loc = __internal::lookup_char_pos(other.0.lo()); @@ -331,20 +346,20 @@ impl Span { /// Creates a new span with the same line/column information as `self` but /// that resolves symbols as though it were at `other`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn resolved_at(&self, other: Span) -> Span { Span(self.0.with_ctxt(other.0.ctxt())) } /// Creates a new span with the same name resolution behavior as `self` but /// with the line/column information of `other`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn located_at(&self, other: Span) -> Span { other.resolved_at(*self) } /// Compares to spans to see if they're equal. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn eq(&self, other: &Span) -> bool { self.0 == other.0 } @@ -355,7 +370,8 @@ impl Span { diagnostic_method!(help, Level::Help); } -#[unstable(feature = "proc_macro", issue = "38356")] +/// Prints a span in a form convenient for debugging. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for Span { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{:?} bytes({}..{})", @@ -366,33 +382,33 @@ impl fmt::Debug for Span { } /// A line-column pair representing the start or end of a `Span`. -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct LineColumn { /// The 1-indexed line in the source file on which the span starts or ends (inclusive). - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub line: usize, /// The 0-indexed column (in UTF-8 characters) in the source file on which /// the span starts or ends (inclusive). - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub column: usize } -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] impl !Send for LineColumn {} -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] impl !Sync for LineColumn {} /// The source file of a given `Span`. -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] #[derive(Clone)] pub struct SourceFile { filemap: Lrc, } -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] impl !Send for SourceFile {} -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] impl !Sync for SourceFile {} impl SourceFile { @@ -406,14 +422,17 @@ impl SourceFile { /// the command line, the path as given may not actually be valid. /// /// [`is_real`]: #method.is_real - # [unstable(feature = "proc_macro", issue = "38356")] - pub fn path(&self) -> &FileName { - &self.filemap.name + #[unstable(feature = "proc_macro_span", issue = "38356")] + pub fn path(&self) -> PathBuf { + match self.filemap.name { + FileName::Real(ref path) => path.clone(), + _ => PathBuf::from(self.filemap.name.to_string()) + } } /// Returns `true` if this source file is a real source file, and not generated by an external /// macro's expansion. - #[unstable(feature = "proc_macro", issue = "38356")] + #[unstable(feature = "proc_macro_span", issue = "38356")] pub fn is_real(&self) -> bool { // This is a hack until intercrate spans are implemented and we can have real source files // for spans generated in external macros. @@ -422,68 +441,71 @@ impl SourceFile { } } -#[unstable(feature = "proc_macro", issue = "38356")] -impl AsRef for SourceFile { - fn as_ref(&self) -> &FileName { - self.path() - } -} -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] impl fmt::Debug for SourceFile { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("SourceFile") - .field("path", self.path()) + .field("path", &self.path()) .field("is_real", &self.is_real()) .finish() } } -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] impl PartialEq for SourceFile { fn eq(&self, other: &Self) -> bool { Lrc::ptr_eq(&self.filemap, &other.filemap) } } -#[unstable(feature = "proc_macro", issue = "38356")] +#[unstable(feature = "proc_macro_span", issue = "38356")] impl Eq for SourceFile {} -#[unstable(feature = "proc_macro", issue = "38356")] -impl PartialEq for SourceFile { - fn eq(&self, other: &FileName) -> bool { - self.as_ref() == other - } -} - /// A single token or a delimited sequence of token trees (e.g. `[1, (), ..]`). -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] #[derive(Clone)] pub enum TokenTree { - /// A delimited tokenstream - Group(Group), - /// A unicode identifier - Term(Term), - /// A punctuation character (`+`, `,`, `$`, etc.). - Op(Op), + /// A token stream surrounded by bracket delimiters. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Group( + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Group + ), + /// An identifier. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Ident( + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Ident + ), + /// A single punctuation character (`+`, `,`, `$`, etc.). + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Punct( + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Punct + ), /// A literal character (`'a'`), string (`"hello"`), number (`2.3`), etc. - Literal(Literal), + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Literal( + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + Literal + ), } -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Send for TokenTree {} -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Sync for TokenTree {} impl TokenTree { - /// Returns the span of this token, accessing the `span` method of each of - /// the internal tokens. - #[unstable(feature = "proc_macro", issue = "38356")] + /// Returns the span of this tree, delegating to the `span` method of + /// the contained token or a delimited stream. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn span(&self) -> Span { match *self { TokenTree::Group(ref t) => t.span(), - TokenTree::Term(ref t) => t.span(), - TokenTree::Op(ref t) => t.span(), + TokenTree::Ident(ref t) => t.span(), + TokenTree::Punct(ref t) => t.span(), TokenTree::Literal(ref t) => t.span(), } } @@ -493,110 +515,120 @@ impl TokenTree { /// Note that if this token is a `Group` then this method will not configure /// the span of each of the internal tokens, this will simply delegate to /// the `set_span` method of each variant. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn set_span(&mut self, span: Span) { match *self { TokenTree::Group(ref mut t) => t.set_span(span), - TokenTree::Term(ref mut t) => t.set_span(span), - TokenTree::Op(ref mut t) => t.set_span(span), + TokenTree::Ident(ref mut t) => t.set_span(span), + TokenTree::Punct(ref mut t) => t.set_span(span), TokenTree::Literal(ref mut t) => t.set_span(span), } } } -#[unstable(feature = "proc_macro", issue = "38356")] +/// Prints token treee in a form convenient for debugging. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Debug for TokenTree { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { // Each of these has the name in the struct type in the derived debug, // so don't bother with an extra layer of indirection match *self { TokenTree::Group(ref tt) => tt.fmt(f), - TokenTree::Term(ref tt) => tt.fmt(f), - TokenTree::Op(ref tt) => tt.fmt(f), + TokenTree::Ident(ref tt) => tt.fmt(f), + TokenTree::Punct(ref tt) => tt.fmt(f), TokenTree::Literal(ref tt) => tt.fmt(f), } } } -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl From for TokenTree { fn from(g: Group) -> TokenTree { TokenTree::Group(g) } } -#[unstable(feature = "proc_macro", issue = "38356")] -impl From for TokenTree { - fn from(g: Term) -> TokenTree { - TokenTree::Term(g) +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl From for TokenTree { + fn from(g: Ident) -> TokenTree { + TokenTree::Ident(g) } } -#[unstable(feature = "proc_macro", issue = "38356")] -impl From for TokenTree { - fn from(g: Op) -> TokenTree { - TokenTree::Op(g) +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl From for TokenTree { + fn from(g: Punct) -> TokenTree { + TokenTree::Punct(g) } } -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl From for TokenTree { fn from(g: Literal) -> TokenTree { TokenTree::Literal(g) } } -#[unstable(feature = "proc_macro", issue = "38356")] +/// Prints the token tree as a string that is supposed to be losslessly convertible back +/// into the same token tree (modulo spans), except for possibly `TokenTree::Group`s +/// with `Delimiter::None` delimiters and negative numeric literals. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for TokenTree { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { TokenTree::Group(ref t) => t.fmt(f), - TokenTree::Term(ref t) => t.fmt(f), - TokenTree::Op(ref t) => t.fmt(f), + TokenTree::Ident(ref t) => t.fmt(f), + TokenTree::Punct(ref t) => t.fmt(f), TokenTree::Literal(ref t) => t.fmt(f), } } } -/// A delimited token stream +/// A delimited token stream. /// -/// A `Group` internally contains a `TokenStream` which is delimited by a -/// `Delimiter`. Groups represent multiple tokens internally and have a `Span` -/// for the entire stream. -#[derive(Clone, Debug)] -#[unstable(feature = "proc_macro", issue = "38356")] +/// A `Group` internally contains a `TokenStream` which is surrounded by `Delimiter`s. +#[derive(Clone)] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Group { delimiter: Delimiter, stream: TokenStream, span: Span, } -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Send for Group {} -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Sync for Group {} /// Describes how a sequence of token trees is delimited. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub enum Delimiter { /// `( ... )` + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Parenthesis, /// `{ ... }` + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Brace, /// `[ ... ]` + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Bracket, - /// An implicit delimiter, e.g. `$var`, where $var is `...`. + /// `Ø ... Ø` + /// An implicit delimiter, that may, for example, appear around tokens coming from a + /// "macro variable" `$var`. It is important to preserve operator priorities in cases like + /// `$var * 3` where `$var` is `1 + 2`. + /// Implicit delimiters may not survive roundtrip of a token stream through a string. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] None, } impl Group { - /// Creates a new `group` with the given delimiter and token stream. + /// Creates a new `Group` with the given delimiter and token stream. /// /// This constructor will set the span for this group to /// `Span::call_site()`. To change the span you can use the `set_span` /// method below. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn new(delimiter: Delimiter, stream: TokenStream) -> Group { Group { delimiter: delimiter, @@ -606,7 +638,7 @@ impl Group { } /// Returns the delimiter of this `Group` - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn delimiter(&self) -> Delimiter { self.delimiter } @@ -615,14 +647,14 @@ impl Group { /// /// Note that the returned token stream does not include the delimiter /// returned above. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn stream(&self) -> TokenStream { self.stream.clone() } /// Returns the span for the delimiters of this token stream, spanning the /// entire `Group`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn span(&self) -> Span { self.span } @@ -633,168 +665,243 @@ impl Group { /// This method will **not** set the span of all the internal tokens spanned /// by this group, but rather it will only set the span of the delimiter /// tokens at the level of the `Group`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn set_span(&mut self, span: Span) { self.span = span; } } -#[unstable(feature = "proc_macro", issue = "38356")] +/// Prints the group as a string that should be losslessly convertible back +/// into the same group (modulo spans), except for possibly `TokenTree::Group`s +/// with `Delimiter::None` delimiters. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Group { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { TokenStream::from(TokenTree::from(self.clone())).fmt(f) } } -/// An `Op` is an operator like `+` or `-`, and only represents one character. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Group { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Group") + .field("delimiter", &self.delimiter()) + .field("stream", &self.stream()) + .field("span", &self.span()) + .finish() + } +} + +/// An `Punct` is an single punctuation character like `+`, `-` or `#`. /// -/// Operators like `+=` are represented as two instance of `Op` with different +/// Multicharacter operators like `+=` are represented as two instances of `Punct` with different /// forms of `Spacing` returned. -#[unstable(feature = "proc_macro", issue = "38356")] -#[derive(Copy, Clone, Debug)] -pub struct Op { - op: char, +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +#[derive(Clone)] +pub struct Punct { + ch: char, spacing: Spacing, span: Span, } -#[unstable(feature = "proc_macro", issue = "38356")] -impl !Send for Op {} -#[unstable(feature = "proc_macro", issue = "38356")] -impl !Sync for Op {} +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl !Send for Punct {} +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl !Sync for Punct {} -/// Whether an `Op` is either followed immediately by another `Op` or followed by whitespace. +/// Whether an `Punct` is followed immediately by another `Punct` or +/// followed by another token or whitespace. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub enum Spacing { - /// e.g. `+` is `Alone` in `+ =`. + /// E.g. `+` is `Alone` in `+ =`, `+ident` or `+()`. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Alone, - /// e.g. `+` is `Joint` in `+=`. + /// E.g. `+` is `Joint` in `+=` or `'#`. + /// Additionally, single quote `'` can join with identifiers to form lifetimes `'ident`. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] Joint, } -impl Op { - /// Creates a new `Op` from the given character and spacing. +impl Punct { + /// Creates a new `Punct` from the given character and spacing. + /// The `ch` argument must be a valid punctuation character permitted by the language, + /// otherwise the function will panic. /// - /// The returned `Op` will have the default span of `Span::call_site()` + /// The returned `Punct` will have the default span of `Span::call_site()` /// which can be further configured with the `set_span` method below. - #[unstable(feature = "proc_macro", issue = "38356")] - pub fn new(op: char, spacing: Spacing) -> Op { - Op { - op: op, + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + pub fn new(ch: char, spacing: Spacing) -> Punct { + const LEGAL_CHARS: &[char] = &['=', '<', '>', '!', '~', '+', '-', '*', '/', '%', '^', + '&', '|', '@', '.', ',', ';', ':', '#', '$', '?', '\'']; + if !LEGAL_CHARS.contains(&ch) { + panic!("unsupported character `{:?}`", ch) + } + Punct { + ch: ch, spacing: spacing, span: Span::call_site(), } } - /// Returns the character this operation represents, for example `'+'` - #[unstable(feature = "proc_macro", issue = "38356")] - pub fn op(&self) -> char { - self.op + /// Returns the value of this punctuation character as `char`. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + pub fn as_char(&self) -> char { + self.ch } - /// Returns the spacing of this operator, indicating whether it's a joint - /// operator with more operators coming next in the token stream or an - /// `Alone` meaning that the operator has ended. - #[unstable(feature = "proc_macro", issue = "38356")] + /// Returns the spacing of this punctuation character, indicating whether it's immediately + /// followed by another `Punct` in the token stream, so they can potentially be combined into + /// a multicharacter operator (`Joint`), or it's followed by some other token or whitespace + /// (`Alone`) so the operator has certainly ended. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn spacing(&self) -> Spacing { self.spacing } - /// Returns the span for this operator character - #[unstable(feature = "proc_macro", issue = "38356")] + /// Returns the span for this punctuation character. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn span(&self) -> Span { self.span } - /// Configure the span for this operator's character - #[unstable(feature = "proc_macro", issue = "38356")] + /// Configure the span for this punctuation character. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn set_span(&mut self, span: Span) { self.span = span; } } -#[unstable(feature = "proc_macro", issue = "38356")] -impl fmt::Display for Op { +/// Prints the punctuation character as a string that should be losslessly convertible +/// back into the same character. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Display for Punct { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { TokenStream::from(TokenTree::from(self.clone())).fmt(f) } } -/// An interned string. -#[derive(Copy, Clone, Debug)] -#[unstable(feature = "proc_macro", issue = "38356")] -pub struct Term { +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Punct { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Punct") + .field("ch", &self.as_char()) + .field("spacing", &self.spacing()) + .field("span", &self.span()) + .finish() + } +} + +/// An identifier (`ident`). +#[derive(Clone)] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +pub struct Ident { sym: Symbol, span: Span, + is_raw: bool, } -#[unstable(feature = "proc_macro", issue = "38356")] -impl !Send for Term {} -#[unstable(feature = "proc_macro", issue = "38356")] -impl !Sync for Term {} +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl !Send for Ident {} +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl !Sync for Ident {} + +impl Ident { + fn is_valid(string: &str) -> bool { + let mut chars = string.chars(); + if let Some(start) = chars.next() { + (start == '_' || start.is_xid_start()) + && chars.all(|cont| cont == '_' || cont.is_xid_continue()) + } else { + false + } + } -impl Term { - /// Creates a new `Term` with the given `string` as well as the specified + /// Creates a new `Ident` with the given `string` as well as the specified /// `span`. + /// The `string` argument must be a valid identifier permitted by the + /// language, otherwise the function will panic. /// /// Note that `span`, currently in rustc, configures the hygiene information - /// for this identifier. As of this time `Span::call_site()` explicitly - /// opts-in to **non-hygienic** information (aka copy/pasted code) while - /// spans like `Span::def_site()` will opt-in to hygienic information, - /// meaning that code at the call site of the macro can't access this - /// identifier. + /// for this identifier. + /// + /// As of this time `Span::call_site()` explicitly opts-in to "call-site" hygiene + /// meaning that identifiers created with this span will be resolved as if they were written + /// directly at the location of the macro call, and other code at the macro call site will be + /// able to refer to them as well. + /// + /// Later spans like `Span::def_site()` will allow to opt-in to "definition-site" hygiene + /// meaning that identifiers created with this span will be resolved at the location of the + /// macro definition and other code at the macro call site will not be able to refer to them. /// /// Due to the current importance of hygiene this constructor, unlike other /// tokens, requires a `Span` to be specified at construction. - #[unstable(feature = "proc_macro", issue = "38356")] - pub fn new(string: &str, span: Span) -> Term { - Term { - sym: Symbol::intern(string), - span, + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] + pub fn new(string: &str, span: Span) -> Ident { + if !Ident::is_valid(string) { + panic!("`{:?}` is not a valid identifier", string) } + Ident::new_maybe_raw(string, span, false) } - /// Get a reference to the interned string. - #[unstable(feature = "proc_macro", issue = "38356")] - pub fn as_str(&self) -> &str { - unsafe { &*(&*self.sym.as_str() as *const str) } + /// Same as `Ident::new`, but creates a raw identifier (`r#ident`). + #[unstable(feature = "proc_macro_raw_ident", issue = "38356")] + pub fn new_raw(string: &str, span: Span) -> Ident { + if !Ident::is_valid(string) { + panic!("`{:?}` is not a valid identifier", string) + } + Ident::new_maybe_raw(string, span, true) } - /// Returns the span of this `Term`, encompassing the entire string returned + /// Returns the span of this `Ident`, encompassing the entire string returned /// by `as_str`. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn span(&self) -> Span { self.span } - /// Configures the span of this `Term`, possibly changing hygiene - /// information. - #[unstable(feature = "proc_macro", issue = "38356")] + /// Configures the span of this `Ident`, possibly changing its hygiene context. + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn set_span(&mut self, span: Span) { self.span = span; } } -#[unstable(feature = "proc_macro", issue = "38356")] -impl fmt::Display for Term { +/// Prints the identifier as a string that should be losslessly convertible +/// back into the same identifier. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Display for Ident { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.as_str().fmt(f) + TokenStream::from(TokenTree::from(self.clone())).fmt(f) } } -/// A literal character (`'a'`), string (`"hello"`), a number (`2.3`), etc. +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] +impl fmt::Debug for Ident { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Ident") + .field("ident", &self.to_string()) + .field("span", &self.span()) + .finish() + } +} + +/// A literal string (`"hello"`), byte string (`b"hello"`), +/// character (`'a'`), byte character (`b'a'`), an integer or floating point number +/// with or without a suffix (`1`, `1u8`, `2.3`, `2.3f32`). +/// Boolean literals like `true` and `false` do not belong here, they are `Ident`s. +// FIXME(eddyb) `Literal` should not expose internal `Debug` impls. #[derive(Clone, Debug)] -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub struct Literal { lit: token::Lit, - suffix: Option, + suffix: Option, span: Span, } -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Send for Literal {} -#[unstable(feature = "proc_macro", issue = "38356")] +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl !Sync for Literal {} macro_rules! suffixed_int_literals { @@ -804,11 +911,13 @@ macro_rules! suffixed_int_literals { /// This function will create an integer like `1u32` where the integer /// value specified is the first part of the token and the integral is /// also suffixed at the end. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// Literals created through this method have the `Span::call_site()` /// span by default, which can be configured with the `set_span` method /// below. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn $name(n: $kind) -> Literal { Literal { lit: token::Lit::Integer(Symbol::intern(&n.to_string())), @@ -828,11 +937,13 @@ macro_rules! unsuffixed_int_literals { /// specified on this token, meaning that invocations like /// `Literal::i8_unsuffixed(1)` are equivalent to /// `Literal::u32_unsuffixed(1)`. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// Literals created through this method have the `Span::call_site()` /// span by default, which can be configured with the `set_span` method /// below. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn $name(n: $kind) -> Literal { Literal { lit: token::Lit::Integer(Symbol::intern(&n.to_string())), @@ -879,12 +990,14 @@ impl Literal { /// This constructor is similar to those like `Literal::i8_unsuffixed` where /// the float's value is emitted directly into the token but no suffix is /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics /// /// This function requires that the specified float is finite, for /// example if it is infinity or NaN this function will panic. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn f32_unsuffixed(n: f32) -> Literal { if !n.is_finite() { panic!("Invalid float literal {}", n); @@ -902,12 +1015,14 @@ impl Literal { /// specified is the preceding part of the token and `f32` is the suffix of /// the token. This token will always be inferred to be an `f32` in the /// compiler. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics /// /// This function requires that the specified float is finite, for /// example if it is infinity or NaN this function will panic. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn f32_suffixed(n: f32) -> Literal { if !n.is_finite() { panic!("Invalid float literal {}", n); @@ -924,12 +1039,14 @@ impl Literal { /// This constructor is similar to those like `Literal::i8_unsuffixed` where /// the float's value is emitted directly into the token but no suffix is /// used, so it may be inferred to be a `f64` later in the compiler. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics /// /// This function requires that the specified float is finite, for /// example if it is infinity or NaN this function will panic. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn f64_unsuffixed(n: f64) -> Literal { if !n.is_finite() { panic!("Invalid float literal {}", n); @@ -947,12 +1064,14 @@ impl Literal { /// specified is the preceding part of the token and `f64` is the suffix of /// the token. This token will always be inferred to be an `f64` in the /// compiler. + /// Literals created from negative numbers may not survive rountrips through + /// `TokenStream` or strings and may be broken into two tokens (`-` and positive literal). /// /// # Panics /// /// This function requires that the specified float is finite, for /// example if it is infinity or NaN this function will panic. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn f64_suffixed(n: f64) -> Literal { if !n.is_finite() { panic!("Invalid float literal {}", n); @@ -965,7 +1084,7 @@ impl Literal { } /// String literal. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn string(string: &str) -> Literal { let mut escaped = String::new(); for ch in string.chars() { @@ -979,7 +1098,7 @@ impl Literal { } /// Character literal. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn character(ch: char) -> Literal { let mut escaped = String::new(); escaped.extend(ch.escape_unicode()); @@ -991,7 +1110,7 @@ impl Literal { } /// Byte string literal. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn byte_string(bytes: &[u8]) -> Literal { let string = bytes.iter().cloned().flat_map(ascii::escape_default) .map(Into::::into).collect::(); @@ -1003,258 +1122,27 @@ impl Literal { } /// Returns the span encompassing this literal. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn span(&self) -> Span { self.span } /// Configures the span associated for this literal. - #[unstable(feature = "proc_macro", issue = "38356")] + #[stable(feature = "proc_macro_lib2", since = "1.29.0")] pub fn set_span(&mut self, span: Span) { self.span = span; } } -#[unstable(feature = "proc_macro", issue = "38356")] +/// Prints the literal as a string that should be losslessly convertible +/// back into the same literal (except for possible rounding for floating point literals). +#[stable(feature = "proc_macro_lib2", since = "1.29.0")] impl fmt::Display for Literal { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { TokenStream::from(TokenTree::from(self.clone())).fmt(f) } } -impl Delimiter { - fn from_internal(delim: token::DelimToken) -> Delimiter { - match delim { - token::Paren => Delimiter::Parenthesis, - token::Brace => Delimiter::Brace, - token::Bracket => Delimiter::Bracket, - token::NoDelim => Delimiter::None, - } - } - - fn to_internal(self) -> token::DelimToken { - match self { - Delimiter::Parenthesis => token::Paren, - Delimiter::Brace => token::Brace, - Delimiter::Bracket => token::Bracket, - Delimiter::None => token::NoDelim, - } - } -} - -impl TokenTree { - fn from_internal(stream: tokenstream::TokenStream, stack: &mut Vec) - -> TokenTree { - use syntax::parse::token::*; - - let (tree, is_joint) = stream.as_tree(); - let (span, token) = match tree { - tokenstream::TokenTree::Token(span, token) => (span, token), - tokenstream::TokenTree::Delimited(span, delimed) => { - let delimiter = Delimiter::from_internal(delimed.delim); - let mut g = Group::new(delimiter, TokenStream(delimed.tts.into())); - g.set_span(Span(span)); - return g.into() - } - }; - - let op_kind = if is_joint { Spacing::Joint } else { Spacing::Alone }; - macro_rules! tt { - ($e:expr) => ({ - let mut x = TokenTree::from($e); - x.set_span(Span(span)); - x - }) - } - macro_rules! op { - ($a:expr) => (tt!(Op::new($a, op_kind))); - ($a:expr, $b:expr) => ({ - stack.push(tt!(Op::new($b, op_kind))); - tt!(Op::new($a, Spacing::Joint)) - }); - ($a:expr, $b:expr, $c:expr) => ({ - stack.push(tt!(Op::new($c, op_kind))); - stack.push(tt!(Op::new($b, Spacing::Joint))); - tt!(Op::new($a, Spacing::Joint)) - }) - } - - match token { - Eq => op!('='), - Lt => op!('<'), - Le => op!('<', '='), - EqEq => op!('=', '='), - Ne => op!('!', '='), - Ge => op!('>', '='), - Gt => op!('>'), - AndAnd => op!('&', '&'), - OrOr => op!('|', '|'), - Not => op!('!'), - Tilde => op!('~'), - BinOp(Plus) => op!('+'), - BinOp(Minus) => op!('-'), - BinOp(Star) => op!('*'), - BinOp(Slash) => op!('/'), - BinOp(Percent) => op!('%'), - BinOp(Caret) => op!('^'), - BinOp(And) => op!('&'), - BinOp(Or) => op!('|'), - BinOp(Shl) => op!('<', '<'), - BinOp(Shr) => op!('>', '>'), - BinOpEq(Plus) => op!('+', '='), - BinOpEq(Minus) => op!('-', '='), - BinOpEq(Star) => op!('*', '='), - BinOpEq(Slash) => op!('/', '='), - BinOpEq(Percent) => op!('%', '='), - BinOpEq(Caret) => op!('^', '='), - BinOpEq(And) => op!('&', '='), - BinOpEq(Or) => op!('|', '='), - BinOpEq(Shl) => op!('<', '<', '='), - BinOpEq(Shr) => op!('>', '>', '='), - At => op!('@'), - Dot => op!('.'), - DotDot => op!('.', '.'), - DotDotDot => op!('.', '.', '.'), - DotDotEq => op!('.', '.', '='), - Comma => op!(','), - Semi => op!(';'), - Colon => op!(':'), - ModSep => op!(':', ':'), - RArrow => op!('-', '>'), - LArrow => op!('<', '-'), - FatArrow => op!('=', '>'), - Pound => op!('#'), - Dollar => op!('$'), - Question => op!('?'), - - Ident(ident, false) | Lifetime(ident) => { - tt!(Term::new(&ident.name.as_str(), Span(span))) - } - Ident(ident, true) => { - tt!(Term::new(&format!("r#{}", ident), Span(span))) - } - Literal(lit, suffix) => tt!(self::Literal { lit, suffix, span: Span(span) }), - DocComment(c) => { - let style = comments::doc_comment_style(&c.as_str()); - let stripped = comments::strip_doc_comment_decoration(&c.as_str()); - let stream = vec![ - tt!(Term::new("doc", Span(span))), - tt!(Op::new('=', Spacing::Alone)), - tt!(self::Literal::string(&stripped)), - ].into_iter().collect(); - stack.push(tt!(Group::new(Delimiter::Bracket, stream))); - if style == ast::AttrStyle::Inner { - stack.push(tt!(Op::new('!', Spacing::Alone))); - } - tt!(Op::new('#', Spacing::Alone)) - } - - Interpolated(_) => { - __internal::with_sess(|(sess, _)| { - let tts = token.interpolated_to_tokenstream(sess, span); - tt!(Group::new(Delimiter::None, TokenStream(tts))) - }) - } - - DotEq => op!('.', '='), - OpenDelim(..) | CloseDelim(..) => unreachable!(), - Whitespace | Comment | Shebang(..) | Eof => unreachable!(), - } - } - - fn to_internal(self) -> tokenstream::TokenStream { - use syntax::parse::token::*; - use syntax::tokenstream::{TokenTree, Delimited}; - - let (op, kind, span) = match self { - self::TokenTree::Op(tt) => (tt.op(), tt.spacing(), tt.span()), - self::TokenTree::Group(tt) => { - return TokenTree::Delimited(tt.span.0, Delimited { - delim: tt.delimiter.to_internal(), - tts: tt.stream.0.into(), - }).into(); - }, - self::TokenTree::Term(tt) => { - let ident = ast::Ident::new(tt.sym, tt.span.0); - let sym_str = tt.sym.as_str(); - let token = if sym_str.starts_with("'") { - Lifetime(ident) - } else if sym_str.starts_with("r#") { - let name = Symbol::intern(&sym_str[2..]); - let ident = ast::Ident::new(name, ident.span); - Ident(ident, true) - } else { - Ident(ident, false) - }; - return TokenTree::Token(tt.span.0, token).into(); - } - self::TokenTree::Literal(self::Literal { - lit: Lit::Integer(ref a), - suffix, - span, - }) - if a.as_str().starts_with("-") => - { - let minus = BinOp(BinOpToken::Minus); - let integer = Symbol::intern(&a.as_str()[1..]); - let integer = Literal(Lit::Integer(integer), suffix); - let a = TokenTree::Token(span.0, minus); - let b = TokenTree::Token(span.0, integer); - return vec![a, b].into_iter().collect() - } - self::TokenTree::Literal(self::Literal { - lit: Lit::Float(ref a), - suffix, - span, - }) - if a.as_str().starts_with("-") => - { - let minus = BinOp(BinOpToken::Minus); - let float = Symbol::intern(&a.as_str()[1..]); - let float = Literal(Lit::Float(float), suffix); - let a = TokenTree::Token(span.0, minus); - let b = TokenTree::Token(span.0, float); - return vec![a, b].into_iter().collect() - } - self::TokenTree::Literal(tt) => { - let token = Literal(tt.lit, tt.suffix); - return TokenTree::Token(tt.span.0, token).into() - } - }; - - let token = match op { - '=' => Eq, - '<' => Lt, - '>' => Gt, - '!' => Not, - '~' => Tilde, - '+' => BinOp(Plus), - '-' => BinOp(Minus), - '*' => BinOp(Star), - '/' => BinOp(Slash), - '%' => BinOp(Percent), - '^' => BinOp(Caret), - '&' => BinOp(And), - '|' => BinOp(Or), - '@' => At, - '.' => Dot, - ',' => Comma, - ';' => Semi, - ':' => Colon, - '#' => Pound, - '$' => Dollar, - '?' => Question, - _ => panic!("unsupported character {}", op), - }; - - let tree = TokenTree::Token(span.0, token); - match kind { - Spacing::Alone => tree.into(), - Spacing::Joint => tree.joint(), - } - } -} - /// Permanently unstable internal implementation details of this crate. This /// should not be used. /// @@ -1267,23 +1155,22 @@ impl TokenTree { #[unstable(feature = "proc_macro_internals", issue = "27812")] #[doc(hidden)] pub mod __internal { - pub use quote::{LiteralKind, Quoter, unquote}; - use std::cell::Cell; + use std::ptr; use syntax::ast; use syntax::ext::base::ExtCtxt; - use syntax::ext::hygiene::Mark; use syntax::ptr::P; use syntax::parse::{self, ParseSess}; use syntax::parse::token::{self, Token}; use syntax::tokenstream; use syntax_pos::{BytePos, Loc, DUMMY_SP}; + use syntax_pos::hygiene::{SyntaxContext, Transparency}; - use super::{TokenStream, LexError}; + use super::{TokenStream, LexError, Span}; pub fn lookup_char_pos(pos: BytePos) -> Loc { - with_sess(|(sess, _)| sess.codemap().lookup_char_pos(pos)) + with_sess(|sess, _| sess.codemap().lookup_char_pos(pos)) } pub fn new_token_stream(item: P) -> TokenStream { @@ -1296,7 +1183,7 @@ pub mod __internal { } pub fn token_stream_parse_items(stream: TokenStream) -> Result>, LexError> { - with_sess(move |(sess, _)| { + with_sess(move |sess, _| { let mut parser = parse::stream_to_parser(sess, stream.0); let mut items = Vec::new(); @@ -1327,16 +1214,30 @@ pub mod __internal { expand: fn(TokenStream) -> TokenStream); } + #[derive(Clone, Copy)] + pub struct ProcMacroData { + pub def_site: Span, + pub call_site: Span, + } + + #[derive(Clone, Copy)] + struct ProcMacroSess { + parse_sess: *const ParseSess, + data: ProcMacroData, + } + // Emulate scoped_thread_local!() here essentially thread_local! { - static CURRENT_SESS: Cell<(*const ParseSess, Mark)> = - Cell::new((0 as *const _, Mark::root())); + static CURRENT_SESS: Cell = Cell::new(ProcMacroSess { + parse_sess: ptr::null(), + data: ProcMacroData { def_site: Span(DUMMY_SP), call_site: Span(DUMMY_SP) }, + }); } pub fn set_sess(cx: &ExtCtxt, f: F) -> R where F: FnOnce() -> R { - struct Reset { prev: (*const ParseSess, Mark) } + struct Reset { prev: ProcMacroSess } impl Drop for Reset { fn drop(&mut self) { @@ -1346,24 +1247,37 @@ pub mod __internal { CURRENT_SESS.with(|p| { let _reset = Reset { prev: p.get() }; - p.set((cx.parse_sess, cx.current_expansion.mark)); + + // No way to determine def location for a proc macro right now, so use call location. + let location = cx.current_expansion.mark.expn_info().unwrap().call_site; + let to_span = |transparency| Span(location.with_ctxt( + SyntaxContext::empty().apply_mark_with_transparency(cx.current_expansion.mark, + transparency)) + ); + p.set(ProcMacroSess { + parse_sess: cx.parse_sess, + data: ProcMacroData { + def_site: to_span(Transparency::Opaque), + call_site: to_span(Transparency::Transparent), + }, + }); f() }) } pub fn in_sess() -> bool { - let p = CURRENT_SESS.with(|p| p.get()); - !p.0.is_null() + !CURRENT_SESS.with(|sess| sess.get()).parse_sess.is_null() } pub fn with_sess(f: F) -> R - where F: FnOnce((&ParseSess, Mark)) -> R + where F: FnOnce(&ParseSess, &ProcMacroData) -> R { - let p = CURRENT_SESS.with(|p| p.get()); - assert!(!p.0.is_null(), "proc_macro::__internal::with_sess() called \ - before set_parse_sess()!"); - f(unsafe { (&*p.0, p.1) }) + let sess = CURRENT_SESS.with(|sess| sess.get()); + if sess.parse_sess.is_null() { + panic!("procedural macro API is used outside of a procedural macro"); + } + f(unsafe { &*sess.parse_sess }, &sess.data) } } diff --git a/src/libproc_macro/quote.rs b/src/libproc_macro/quote.rs index d1f8e75192ae1..7ae7b13a15217 100644 --- a/src/libproc_macro/quote.rs +++ b/src/libproc_macro/quote.rs @@ -14,35 +14,30 @@ //! This quasiquoter uses macros 2.0 hygiene to reliably access //! items from `proc_macro`, to build a `proc_macro::TokenStream`. -use {Delimiter, Literal, Spacing, Span, Term, Op, Group, TokenStream, TokenTree}; - -use syntax::ext::base::{ExtCtxt, ProcMacro}; -use syntax::parse::token; -use syntax::tokenstream; - -pub struct Quoter; - -pub fn unquote + Clone>(tokens: &T) -> TokenStream { - tokens.clone().into() -} - -pub trait Quote { - fn quote(self) -> TokenStream; -} - -macro_rules! tt2ts { - ($e:expr) => (TokenStream::from(TokenTree::from($e))) -} - -macro_rules! quote_tok { - (,) => { tt2ts!(Op::new(',', Spacing::Alone)) }; - (.) => { tt2ts!(Op::new('.', Spacing::Alone)) }; - (:) => { tt2ts!(Op::new(':', Spacing::Alone)) }; - (|) => { tt2ts!(Op::new('|', Spacing::Alone)) }; +use {Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; + +macro_rules! quote_tt { + (($($t:tt)*)) => { Group::new(Delimiter::Parenthesis, quote!($($t)*)) }; + ([$($t:tt)*]) => { Group::new(Delimiter::Bracket, quote!($($t)*)) }; + ({$($t:tt)*}) => { Group::new(Delimiter::Brace, quote!($($t)*)) }; + (,) => { Punct::new(',', Spacing::Alone) }; + (.) => { Punct::new('.', Spacing::Alone) }; + (:) => { Punct::new(':', Spacing::Alone) }; + (;) => { Punct::new(';', Spacing::Alone) }; + (!) => { Punct::new('!', Spacing::Alone) }; + (<) => { Punct::new('<', Spacing::Alone) }; + (>) => { Punct::new('>', Spacing::Alone) }; + (&) => { Punct::new('&', Spacing::Alone) }; + (=) => { Punct::new('=', Spacing::Alone) }; + ($i:ident) => { Ident::new(stringify!($i), Span::def_site()) }; +} + +macro_rules! quote_ts { + ((@ $($t:tt)*)) => { $($t)* }; (::) => { [ - TokenTree::from(Op::new(':', Spacing::Joint)), - TokenTree::from(Op::new(':', Spacing::Alone)), + TokenTree::from(Punct::new(':', Spacing::Joint)), + TokenTree::from(Punct::new(':', Spacing::Alone)), ].iter() .cloned() .map(|mut x| { @@ -51,240 +46,105 @@ macro_rules! quote_tok { }) .collect::() }; - (!) => { tt2ts!(Op::new('!', Spacing::Alone)) }; - (<) => { tt2ts!(Op::new('<', Spacing::Alone)) }; - (>) => { tt2ts!(Op::new('>', Spacing::Alone)) }; - (_) => { tt2ts!(Op::new('_', Spacing::Alone)) }; - (0) => { tt2ts!(Literal::i8_unsuffixed(0)) }; - (&) => { tt2ts!(Op::new('&', Spacing::Alone)) }; - ($i:ident) => { tt2ts!(Term::new(stringify!($i), Span::def_site())) }; -} - -macro_rules! quote_tree { - ((unquote $($t:tt)*)) => { $($t)* }; - ((quote $($t:tt)*)) => { ($($t)*).quote() }; - (($($t:tt)*)) => { tt2ts!(Group::new(Delimiter::Parenthesis, quote!($($t)*))) }; - ([$($t:tt)*]) => { tt2ts!(Group::new(Delimiter::Bracket, quote!($($t)*))) }; - ({$($t:tt)*}) => { tt2ts!(Group::new(Delimiter::Brace, quote!($($t)*))) }; - ($t:tt) => { quote_tok!($t) }; + ($t:tt) => { TokenTree::from(quote_tt!($t)) }; } +/// Simpler version of the real `quote!` macro, implemented solely +/// through `macro_rules`, for bootstrapping the real implementation +/// (see the `quote` function), which does not have access to the +/// real `quote!` macro due to the `proc_macro` crate not being +/// able to depend on itself. +/// +/// Note: supported tokens are a subset of the real `quote!`, but +/// unquoting is different: instead of `$x`, this uses `(@ expr)`. macro_rules! quote { - () => { TokenStream::empty() }; + () => { TokenStream::new() }; ($($t:tt)*) => { - [$(quote_tree!($t),)*].iter() - .cloned() - .flat_map(|x| x.into_iter()) - .collect::() + [ + $(TokenStream::from(quote_ts!($t)),)* + ].iter().cloned().collect::() }; } -impl ProcMacro for Quoter { - fn expand<'cx>(&self, cx: &'cx mut ExtCtxt, - _: ::syntax_pos::Span, - stream: tokenstream::TokenStream) - -> tokenstream::TokenStream { - let mut info = cx.current_expansion.mark.expn_info().unwrap(); - info.callee.allow_internal_unstable = true; - cx.current_expansion.mark.set_expn_info(info); - ::__internal::set_sess(cx, || TokenStream(stream).quote().0) +/// Quote a `TokenStream` into a `TokenStream`. +/// This is the actual `quote!()` proc macro. +/// +/// It is manually loaded in `CStore::load_macro_untracked`. +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub fn quote(stream: TokenStream) -> TokenStream { + if stream.is_empty() { + return quote!(::TokenStream::new()); } -} - -impl Quote for Option { - fn quote(self) -> TokenStream { - match self { - Some(t) => quote!(Some((quote t))), - None => quote!(None), - } - } -} - -impl Quote for TokenStream { - fn quote(self) -> TokenStream { - if self.is_empty() { - return quote!(::TokenStream::empty()); - } - let mut after_dollar = false; - let tokens = self.into_iter().filter_map(|tree| { + let mut after_dollar = false; + let tokens = stream + .into_iter() + .filter_map(|tree| { if after_dollar { after_dollar = false; match tree { - TokenTree::Term(_) => { - let tree = TokenStream::from(tree); - return Some(quote!(::__internal::unquote(&(unquote tree)),)); + TokenTree::Ident(_) => { + return Some(quote!(Into::<::TokenStream>::into( + Clone::clone(&(@ tree))),)); } - TokenTree::Op(ref tt) if tt.op() == '$' => {} + TokenTree::Punct(ref tt) if tt.as_char() == '$' => {} _ => panic!("`$` must be followed by an ident or `$` in `quote!`"), } - } else if let TokenTree::Op(tt) = tree { - if tt.op() == '$' { + } else if let TokenTree::Punct(ref tt) = tree { + if tt.as_char() == '$' { after_dollar = true; return None; } } - Some(quote!(::TokenStream::from((quote tree)),)) - }).flat_map(|t| t.into_iter()).collect::(); - - if after_dollar { - panic!("unexpected trailing `$` in `quote!`"); - } - - quote!( - [(unquote tokens)].iter() - .cloned() - .flat_map(|x| x.into_iter()) - .collect::<::TokenStream>() - ) - } -} - -impl Quote for TokenTree { - fn quote(self) -> TokenStream { - match self { - TokenTree::Op(tt) => quote!(::TokenTree::Op( (quote tt) )), - TokenTree::Group(tt) => quote!(::TokenTree::Group( (quote tt) )), - TokenTree::Term(tt) => quote!(::TokenTree::Term( (quote tt) )), - TokenTree::Literal(tt) => quote!(::TokenTree::Literal( (quote tt) )), - } - } -} - -impl Quote for char { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::character(self)).into() - } -} - -impl<'a> Quote for &'a str { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::string(self)).into() - } -} - -impl Quote for u16 { - fn quote(self) -> TokenStream { - TokenTree::from(Literal::u16_unsuffixed(self)).into() - } -} - -impl Quote for Group { - fn quote(self) -> TokenStream { - quote!(::Group::new((quote self.delimiter()), (quote self.stream()))) - } -} - -impl Quote for Op { - fn quote(self) -> TokenStream { - quote!(::Op::new((quote self.op()), (quote self.spacing()))) - } -} - -impl Quote for Term { - fn quote(self) -> TokenStream { - quote!(::Term::new((quote self.as_str()), (quote self.span()))) - } -} - -impl Quote for Span { - fn quote(self) -> TokenStream { - quote!(::Span::def_site()) - } -} - -macro_rules! literals { - ($($i:ident),*; $($raw:ident),*) => { - pub enum LiteralKind { - $($i,)* - $($raw(u16),)* - } - - impl LiteralKind { - pub fn with_contents_and_suffix(self, contents: Term, suffix: Option) - -> Literal { - let sym = contents.sym; - let suffix = suffix.map(|t| t.sym); - match self { - $(LiteralKind::$i => { - Literal { - lit: token::Lit::$i(sym), - suffix, - span: contents.span, - } - })* - $(LiteralKind::$raw(n) => { - Literal { - lit: token::Lit::$raw(sym, n), - suffix, - span: contents.span, - } - })* - } - } - } - - impl Literal { - fn kind_contents_and_suffix(self) -> (LiteralKind, Term, Option) { - let (kind, contents) = match self.lit { - $(token::Lit::$i(contents) => (LiteralKind::$i, contents),)* - $(token::Lit::$raw(contents, n) => (LiteralKind::$raw(n), contents),)* - }; - let suffix = self.suffix.map(|sym| Term::new(&sym.as_str(), self.span())); - (kind, Term::new(&contents.as_str(), self.span()), suffix) - } - } - - impl Quote for LiteralKind { - fn quote(self) -> TokenStream { - match self { - $(LiteralKind::$i => quote! { - ::__internal::LiteralKind::$i - },)* - $(LiteralKind::$raw(n) => quote! { - ::__internal::LiteralKind::$raw((quote n)) - },)* - } - } - } + Some(quote!(::TokenStream::from((@ match tree { + TokenTree::Punct(tt) => quote!(::TokenTree::Punct(::Punct::new( + (@ TokenTree::from(Literal::character(tt.as_char()))), + (@ match tt.spacing() { + Spacing::Alone => quote!(::Spacing::Alone), + Spacing::Joint => quote!(::Spacing::Joint), + }), + ))), + TokenTree::Group(tt) => quote!(::TokenTree::Group(::Group::new( + (@ match tt.delimiter() { + Delimiter::Parenthesis => quote!(::Delimiter::Parenthesis), + Delimiter::Brace => quote!(::Delimiter::Brace), + Delimiter::Bracket => quote!(::Delimiter::Bracket), + Delimiter::None => quote!(::Delimiter::None), + }), + (@ quote(tt.stream())), + ))), + TokenTree::Ident(tt) => quote!(::TokenTree::Ident(::Ident::new( + (@ TokenTree::from(Literal::string(&tt.to_string()))), + (@ quote_span(tt.span())), + ))), + TokenTree::Literal(tt) => quote!(::TokenTree::Literal({ + let mut iter = (@ TokenTree::from(Literal::string(&tt.to_string()))) + .parse::<::TokenStream>() + .unwrap() + .into_iter(); + if let (Some(::TokenTree::Literal(mut lit)), None) = + (iter.next(), iter.next()) + { + lit.set_span((@ quote_span(tt.span()))); + lit + } else { + unreachable!() + } + })) + })),)) + }) + .collect::(); - impl Quote for Literal { - fn quote(self) -> TokenStream { - let (kind, contents, suffix) = self.kind_contents_and_suffix(); - quote! { - (quote kind).with_contents_and_suffix((quote contents), (quote suffix)) - } - } - } + if after_dollar { + panic!("unexpected trailing `$` in `quote!`"); } -} - -literals!(Byte, Char, Float, Str_, Integer, ByteStr; StrRaw, ByteStrRaw); -impl Quote for Delimiter { - fn quote(self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*) => { - match self { - $(Delimiter::$i => { quote!(::Delimiter::$i) })* - } - } - } - - gen_match!(Parenthesis, Brace, Bracket, None) - } + quote!([(@ tokens)].iter().cloned().collect::<::TokenStream>()) } -impl Quote for Spacing { - fn quote(self) -> TokenStream { - macro_rules! gen_match { - ($($i:ident),*) => { - match self { - $(Spacing::$i => { quote!(::Spacing::$i) })* - } - } - } - - gen_match!(Alone, Joint) - } +/// Quote a `Span` into a `TokenStream`. +/// This is needed to implement a custom quoter. +#[unstable(feature = "proc_macro_quote", issue = "38356")] +pub fn quote_span(_: Span) -> TokenStream { + quote!(::Span::def_site()) } diff --git a/src/libproc_macro/rustc.rs b/src/libproc_macro/rustc.rs new file mode 100644 index 0000000000000..a54c695f6376f --- /dev/null +++ b/src/libproc_macro/rustc.rs @@ -0,0 +1,284 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use {Delimiter, Level, Spacing, Span, __internal}; +use {Group, Ident, Literal, Punct, TokenTree}; + +use rustc_errors as errors; +use syntax::ast; +use syntax::parse::lexer::comments; +use syntax::parse::token; +use syntax::tokenstream; +use syntax_pos::symbol::{keywords, Symbol}; + +impl Ident { + pub(crate) fn new_maybe_raw(string: &str, span: Span, is_raw: bool) -> Ident { + let sym = Symbol::intern(string); + if is_raw + && (sym == keywords::Underscore.name() + || ast::Ident::with_empty_ctxt(sym).is_path_segment_keyword()) + { + panic!("`{:?}` is not a valid raw identifier", string) + } + Ident { sym, span, is_raw } + } +} + +impl Delimiter { + pub(crate) fn from_internal(delim: token::DelimToken) -> Delimiter { + match delim { + token::Paren => Delimiter::Parenthesis, + token::Brace => Delimiter::Brace, + token::Bracket => Delimiter::Bracket, + token::NoDelim => Delimiter::None, + } + } + + pub(crate) fn to_internal(self) -> token::DelimToken { + match self { + Delimiter::Parenthesis => token::Paren, + Delimiter::Brace => token::Brace, + Delimiter::Bracket => token::Bracket, + Delimiter::None => token::NoDelim, + } + } +} + +impl TokenTree { + pub(crate) fn from_internal( + stream: tokenstream::TokenStream, + stack: &mut Vec, + ) -> TokenTree { + use syntax::parse::token::*; + + let (tree, is_joint) = stream.as_tree(); + let (span, token) = match tree { + tokenstream::TokenTree::Token(span, token) => (span, token), + tokenstream::TokenTree::Delimited(span, delimed) => { + let delimiter = Delimiter::from_internal(delimed.delim); + let mut g = Group::new(delimiter, ::TokenStream(delimed.tts.into())); + g.set_span(Span(span)); + return g.into(); + } + }; + + let op_kind = if is_joint { + Spacing::Joint + } else { + Spacing::Alone + }; + macro_rules! tt { + ($e:expr) => {{ + let mut x = TokenTree::from($e); + x.set_span(Span(span)); + x + }}; + } + macro_rules! op { + ($a:expr) => { + tt!(Punct::new($a, op_kind)) + }; + ($a:expr, $b:expr) => {{ + stack.push(tt!(Punct::new($b, op_kind))); + tt!(Punct::new($a, Spacing::Joint)) + }}; + ($a:expr, $b:expr, $c:expr) => {{ + stack.push(tt!(Punct::new($c, op_kind))); + stack.push(tt!(Punct::new($b, Spacing::Joint))); + tt!(Punct::new($a, Spacing::Joint)) + }}; + } + + match token { + Eq => op!('='), + Lt => op!('<'), + Le => op!('<', '='), + EqEq => op!('=', '='), + Ne => op!('!', '='), + Ge => op!('>', '='), + Gt => op!('>'), + AndAnd => op!('&', '&'), + OrOr => op!('|', '|'), + Not => op!('!'), + Tilde => op!('~'), + BinOp(Plus) => op!('+'), + BinOp(Minus) => op!('-'), + BinOp(Star) => op!('*'), + BinOp(Slash) => op!('/'), + BinOp(Percent) => op!('%'), + BinOp(Caret) => op!('^'), + BinOp(And) => op!('&'), + BinOp(Or) => op!('|'), + BinOp(Shl) => op!('<', '<'), + BinOp(Shr) => op!('>', '>'), + BinOpEq(Plus) => op!('+', '='), + BinOpEq(Minus) => op!('-', '='), + BinOpEq(Star) => op!('*', '='), + BinOpEq(Slash) => op!('/', '='), + BinOpEq(Percent) => op!('%', '='), + BinOpEq(Caret) => op!('^', '='), + BinOpEq(And) => op!('&', '='), + BinOpEq(Or) => op!('|', '='), + BinOpEq(Shl) => op!('<', '<', '='), + BinOpEq(Shr) => op!('>', '>', '='), + At => op!('@'), + Dot => op!('.'), + DotDot => op!('.', '.'), + DotDotDot => op!('.', '.', '.'), + DotDotEq => op!('.', '.', '='), + Comma => op!(','), + Semi => op!(';'), + Colon => op!(':'), + ModSep => op!(':', ':'), + RArrow => op!('-', '>'), + LArrow => op!('<', '-'), + FatArrow => op!('=', '>'), + Pound => op!('#'), + Dollar => op!('$'), + Question => op!('?'), + SingleQuote => op!('\''), + + Ident(ident, false) => tt!(self::Ident::new(&ident.as_str(), Span(span))), + Ident(ident, true) => tt!(self::Ident::new_raw(&ident.as_str(), Span(span))), + Lifetime(ident) => { + let ident = ident.without_first_quote(); + stack.push(tt!(self::Ident::new(&ident.as_str(), Span(span)))); + tt!(Punct::new('\'', Spacing::Joint)) + } + Literal(lit, suffix) => tt!(self::Literal { + lit, + suffix, + span: Span(span) + }), + DocComment(c) => { + let style = comments::doc_comment_style(&c.as_str()); + let stripped = comments::strip_doc_comment_decoration(&c.as_str()); + let stream = vec![ + tt!(self::Ident::new("doc", Span(span))), + tt!(Punct::new('=', Spacing::Alone)), + tt!(self::Literal::string(&stripped)), + ].into_iter() + .collect(); + stack.push(tt!(Group::new(Delimiter::Bracket, stream))); + if style == ast::AttrStyle::Inner { + stack.push(tt!(Punct::new('!', Spacing::Alone))); + } + tt!(Punct::new('#', Spacing::Alone)) + } + + Interpolated(_) => __internal::with_sess(|sess, _| { + let tts = token.interpolated_to_tokenstream(sess, span); + tt!(Group::new(Delimiter::None, ::TokenStream(tts))) + }), + + DotEq => op!('.', '='), + OpenDelim(..) | CloseDelim(..) => unreachable!(), + Whitespace | Comment | Shebang(..) | Eof => unreachable!(), + } + } + + pub(crate) fn to_internal(self) -> tokenstream::TokenStream { + use syntax::parse::token::*; + use syntax::tokenstream::{Delimited, TokenTree}; + + let (ch, kind, span) = match self { + self::TokenTree::Punct(tt) => (tt.as_char(), tt.spacing(), tt.span()), + self::TokenTree::Group(tt) => { + return TokenTree::Delimited( + tt.span.0, + Delimited { + delim: tt.delimiter.to_internal(), + tts: tt.stream.0.into(), + }, + ).into(); + } + self::TokenTree::Ident(tt) => { + let token = Ident(ast::Ident::new(tt.sym, tt.span.0), tt.is_raw); + return TokenTree::Token(tt.span.0, token).into(); + } + self::TokenTree::Literal(self::Literal { + lit: Lit::Integer(ref a), + suffix, + span, + }) + if a.as_str().starts_with("-") => + { + let minus = BinOp(BinOpToken::Minus); + let integer = Symbol::intern(&a.as_str()[1..]); + let integer = Literal(Lit::Integer(integer), suffix); + let a = TokenTree::Token(span.0, minus); + let b = TokenTree::Token(span.0, integer); + return vec![a, b].into_iter().collect(); + } + self::TokenTree::Literal(self::Literal { + lit: Lit::Float(ref a), + suffix, + span, + }) + if a.as_str().starts_with("-") => + { + let minus = BinOp(BinOpToken::Minus); + let float = Symbol::intern(&a.as_str()[1..]); + let float = Literal(Lit::Float(float), suffix); + let a = TokenTree::Token(span.0, minus); + let b = TokenTree::Token(span.0, float); + return vec![a, b].into_iter().collect(); + } + self::TokenTree::Literal(tt) => { + let token = Literal(tt.lit, tt.suffix); + return TokenTree::Token(tt.span.0, token).into(); + } + }; + + let token = match ch { + '=' => Eq, + '<' => Lt, + '>' => Gt, + '!' => Not, + '~' => Tilde, + '+' => BinOp(Plus), + '-' => BinOp(Minus), + '*' => BinOp(Star), + '/' => BinOp(Slash), + '%' => BinOp(Percent), + '^' => BinOp(Caret), + '&' => BinOp(And), + '|' => BinOp(Or), + '@' => At, + '.' => Dot, + ',' => Comma, + ';' => Semi, + ':' => Colon, + '#' => Pound, + '$' => Dollar, + '?' => Question, + '\'' => SingleQuote, + _ => unreachable!(), + }; + + let tree = TokenTree::Token(span.0, token); + match kind { + Spacing::Alone => tree.into(), + Spacing::Joint => tree.joint(), + } + } +} + +impl Level { + pub(crate) fn to_internal(self) -> errors::Level { + match self { + Level::Error => errors::Level::Error, + Level::Warning => errors::Level::Warning, + Level::Note => errors::Level::Note, + Level::Help => errors::Level::Help, + Level::__Nonexhaustive => unreachable!("Level::__Nonexhaustive"), + } + } +} diff --git a/src/librustc/Cargo.toml b/src/librustc/Cargo.toml index af108188ce0f4..457a9f2f625ec 100644 --- a/src/librustc/Cargo.toml +++ b/src/librustc/Cargo.toml @@ -15,8 +15,12 @@ fmt_macros = { path = "../libfmt_macros" } graphviz = { path = "../libgraphviz" } jobserver = "0.1" lazy_static = "1.0.0" +scoped-tls = { version = "0.1.1", features = ["nightly"] } log = { version = "0.4", features = ["release_max_level_info", "std"] } +polonius-engine = "0.5.0" proc_macro = { path = "../libproc_macro" } +rustc-rayon = "0.1.1" +rustc-rayon-core = "0.1.1" rustc_apfloat = { path = "../librustc_apfloat" } rustc_target = { path = "../librustc_target" } rustc_data_structures = { path = "../librustc_data_structures" } @@ -25,7 +29,9 @@ serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } backtrace = "0.3.3" +parking_lot = "0.5.5" byteorder = { version = "1.1", features = ["i128"]} +chalk-engine = { version = "0.6.0", default-features=false } # Note that these dependencies are a lie, they're just here to get linkage to # work. @@ -35,13 +41,13 @@ byteorder = { version = "1.1", features = ["i128"]} # rlib/dylib pair but all crates.io crates tend to just be rlibs. This means # we've got a problem for dependency graphs that look like: # -# foo - rustc_trans +# foo - rustc_codegen_llvm # / \ # rustc ---- rustc_driver # \ / # foo - rustc_metadata # -# Here the crate `foo` is linked into the `rustc_trans` and the +# Here the crate `foo` is linked into the `rustc_codegen_llvm` and the # `rustc_metadata` dylibs, meaning we've got duplicate copies! When we then # go to link `rustc_driver` the compiler notices this and gives us a compiler # error. @@ -49,10 +55,10 @@ byteorder = { version = "1.1", features = ["i128"]} # To work around this problem we just add these crates.io dependencies to the # `rustc` crate which is a shared dependency above. That way the crate `foo` # shows up in the dylib for the `rustc` crate, deduplicating it and allowing -# crates like `rustc_trans` to use `foo` *through* the `rustc` crate. +# crates like `rustc_codegen_llvm` to use `foo` *through* the `rustc` crate. # # tl;dr; this is not needed to get `rustc` to compile, but if you remove it then # later crate stop compiling. If you can remove this and everything # compiles, then please feel free to do so! flate2 = "1.0" -tempdir = "0.3" +tempfile = "3.0" diff --git a/src/librustc/cfg/construct.rs b/src/librustc/cfg/construct.rs index 118125a19ddef..98cfa094c169a 100644 --- a/src/librustc/cfg/construct.rs +++ b/src/librustc/cfg/construct.rs @@ -8,11 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc_data_structures::graph; use cfg::*; use middle::region; -use ty::{self, TyCtxt}; +use rustc_data_structures::graph::implementation as graph; use syntax::ptr::P; +use ty::{self, TyCtxt}; use hir::{self, PatKind}; use hir::def_id::DefId; @@ -111,13 +111,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn stmt(&mut self, stmt: &hir::Stmt, pred: CFGIndex) -> CFGIndex { let hir_id = self.tcx.hir.node_to_hir_id(stmt.node.id()); match stmt.node { - hir::StmtDecl(ref decl, _) => { + hir::StmtKind::Decl(ref decl, _) => { let exit = self.decl(&decl, pred); self.add_ast_node(hir_id.local_id, &[exit]) } - hir::StmtExpr(ref expr, _) | - hir::StmtSemi(ref expr, _) => { + hir::StmtKind::Expr(ref expr, _) | + hir::StmtKind::Semi(ref expr, _) => { let exit = self.expr(&expr, pred); self.add_ast_node(hir_id.local_id, &[exit]) } @@ -126,12 +126,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn decl(&mut self, decl: &hir::Decl, pred: CFGIndex) -> CFGIndex { match decl.node { - hir::DeclLocal(ref local) => { + hir::DeclKind::Local(ref local) => { let init_exit = self.opt_expr(&local.init, pred); self.pat(&local.pat, init_exit) } - hir::DeclItem(_) => pred, + hir::DeclKind::Item(_) => pred, } } @@ -179,12 +179,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn expr(&mut self, expr: &hir::Expr, pred: CFGIndex) -> CFGIndex { match expr.node { - hir::ExprBlock(ref blk) => { + hir::ExprKind::Block(ref blk, _) => { let blk_exit = self.block(&blk, pred); self.add_ast_node(expr.hir_id.local_id, &[blk_exit]) } - hir::ExprIf(ref cond, ref then, None) => { + hir::ExprKind::If(ref cond, ref then, None) => { // // [pred] // | @@ -204,7 +204,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(expr.hir_id.local_id, &[cond_exit, then_exit]) // 3,4 } - hir::ExprIf(ref cond, ref then, Some(ref otherwise)) => { + hir::ExprKind::If(ref cond, ref then, Some(ref otherwise)) => { // // [pred] // | @@ -225,7 +225,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(expr.hir_id.local_id, &[then_exit, else_exit]) // 4, 5 } - hir::ExprWhile(ref cond, ref body, _) => { + hir::ExprKind::While(ref cond, ref body, _) => { // // [pred] // | @@ -267,7 +267,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { expr_exit } - hir::ExprLoop(ref body, _, _) => { + hir::ExprKind::Loop(ref body, _, _) => { // // [pred] // | @@ -295,11 +295,11 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { expr_exit } - hir::ExprMatch(ref discr, ref arms, _) => { + hir::ExprKind::Match(ref discr, ref arms, _) => { self.match_(expr.hir_id.local_id, &discr, &arms, pred) } - hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => { + hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => { // // [pred] // | @@ -319,14 +319,14 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_ast_node(expr.hir_id.local_id, &[l_exit, r_exit]) // 3,4 } - hir::ExprRet(ref v) => { + hir::ExprKind::Ret(ref v) => { let v_exit = self.opt_expr(v, pred); let b = self.add_ast_node(expr.hir_id.local_id, &[v_exit]); self.add_returning_edge(expr, b); self.add_unreachable_node() } - hir::ExprBreak(destination, ref opt_expr) => { + hir::ExprKind::Break(destination, ref opt_expr) => { let v = self.opt_expr(opt_expr, pred); let (target_scope, break_dest) = self.find_scope_edge(expr, destination, ScopeCfKind::Break); @@ -335,7 +335,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_unreachable_node() } - hir::ExprAgain(destination) => { + hir::ExprKind::Continue(destination) => { let (target_scope, cont_dest) = self.find_scope_edge(expr, destination, ScopeCfKind::Continue); let a = self.add_ast_node(expr.hir_id.local_id, &[pred]); @@ -343,66 +343,66 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { self.add_unreachable_node() } - hir::ExprArray(ref elems) => { + hir::ExprKind::Array(ref elems) => { self.straightline(expr, pred, elems.iter().map(|e| &*e)) } - hir::ExprCall(ref func, ref args) => { + hir::ExprKind::Call(ref func, ref args) => { self.call(expr, pred, &func, args.iter().map(|e| &*e)) } - hir::ExprMethodCall(.., ref args) => { + hir::ExprKind::MethodCall(.., ref args) => { self.call(expr, pred, &args[0], args[1..].iter().map(|e| &*e)) } - hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) if self.tables.is_method_call(expr) => { + hir::ExprKind::Index(ref l, ref r) | + hir::ExprKind::Binary(_, ref l, ref r) if self.tables.is_method_call(expr) => { self.call(expr, pred, &l, Some(&**r).into_iter()) } - hir::ExprUnary(_, ref e) if self.tables.is_method_call(expr) => { + hir::ExprKind::Unary(_, ref e) if self.tables.is_method_call(expr) => { self.call(expr, pred, &e, None::.iter()) } - hir::ExprTup(ref exprs) => { + hir::ExprKind::Tup(ref exprs) => { self.straightline(expr, pred, exprs.iter().map(|e| &*e)) } - hir::ExprStruct(_, ref fields, ref base) => { + hir::ExprKind::Struct(_, ref fields, ref base) => { let field_cfg = self.straightline(expr, pred, fields.iter().map(|f| &*f.expr)); self.opt_expr(base, field_cfg) } - hir::ExprAssign(ref l, ref r) | - hir::ExprAssignOp(_, ref l, ref r) => { + hir::ExprKind::Assign(ref l, ref r) | + hir::ExprKind::AssignOp(_, ref l, ref r) => { self.straightline(expr, pred, [r, l].iter().map(|&e| &**e)) } - hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) => { // NB: && and || handled earlier + hir::ExprKind::Index(ref l, ref r) | + hir::ExprKind::Binary(_, ref l, ref r) => { // NB: && and || handled earlier self.straightline(expr, pred, [l, r].iter().map(|&e| &**e)) } - hir::ExprBox(ref e) | - hir::ExprAddrOf(_, ref e) | - hir::ExprCast(ref e, _) | - hir::ExprType(ref e, _) | - hir::ExprUnary(_, ref e) | - hir::ExprField(ref e, _) | - hir::ExprYield(ref e) | - hir::ExprRepeat(ref e, _) => { + hir::ExprKind::Box(ref e) | + hir::ExprKind::AddrOf(_, ref e) | + hir::ExprKind::Cast(ref e, _) | + hir::ExprKind::Type(ref e, _) | + hir::ExprKind::Unary(_, ref e) | + hir::ExprKind::Field(ref e, _) | + hir::ExprKind::Yield(ref e) | + hir::ExprKind::Repeat(ref e, _) => { self.straightline(expr, pred, Some(&**e).into_iter()) } - hir::ExprInlineAsm(_, ref outputs, ref inputs) => { + hir::ExprKind::InlineAsm(_, ref outputs, ref inputs) => { let post_outputs = self.exprs(outputs.iter().map(|e| &*e), pred); let post_inputs = self.exprs(inputs.iter().map(|e| &*e), post_outputs); self.add_ast_node(expr.hir_id.local_id, &[post_inputs]) } - hir::ExprClosure(..) | - hir::ExprLit(..) | - hir::ExprPath(_) => { + hir::ExprKind::Closure(..) | + hir::ExprKind::Lit(..) | + hir::ExprKind::Path(_) => { self.straightline(expr, pred, None::.iter()) } } @@ -452,13 +452,13 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { // The CFG for match expression is quite complex, so no ASCII // art for it (yet). // - // The CFG generated below matches roughly what trans puts - // out. Each pattern and guard is visited in parallel, with + // The CFG generated below matches roughly what MIR contains. + // Each pattern and guard is visited in parallel, with // arms containing multiple patterns generating multiple nodes // for the same guard expression. The guard expressions chain // into each other from top to bottom, with a specific // exception to allow some additional valid programs - // (explained below). Trans differs slightly in that the + // (explained below). MIR differs slightly in that the // pattern matching may continue after a guard but the visible // behaviour should be the same. // @@ -567,12 +567,12 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { fn add_returning_edge(&mut self, _from_expr: &hir::Expr, from_index: CFGIndex) { - let mut data = CFGEdgeData { - exiting_scopes: vec![], + let data = CFGEdgeData { + exiting_scopes: self.loop_scopes.iter() + .rev() + .map(|&LoopScope { loop_id: id, .. }| id) + .collect() }; - for &LoopScope { loop_id: id, .. } in self.loop_scopes.iter().rev() { - data.exiting_scopes.push(id); - } self.graph.add_edge(from_index, self.fn_exit, data); } @@ -582,19 +582,16 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { scope_cf_kind: ScopeCfKind) -> (region::Scope, CFGIndex) { match destination.target_id { - hir::ScopeTarget::Block(block_expr_id) => { + Ok(loop_id) => { for b in &self.breakable_block_scopes { - if b.block_expr_id == self.tcx.hir.node_to_hir_id(block_expr_id).local_id { - let scope_id = self.tcx.hir.node_to_hir_id(block_expr_id).local_id; + if b.block_expr_id == self.tcx.hir.node_to_hir_id(loop_id).local_id { + let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id; return (region::Scope::Node(scope_id), match scope_cf_kind { ScopeCfKind::Break => b.break_index, ScopeCfKind::Continue => bug!("can't continue to block"), }); } } - span_bug!(expr.span, "no block expr for id {}", block_expr_id); - } - hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(loop_id)) => { for l in &self.loop_scopes { if l.loop_id == self.tcx.hir.node_to_hir_id(loop_id).local_id { let scope_id = self.tcx.hir.node_to_hir_id(loop_id).local_id; @@ -604,10 +601,9 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { }); } } - span_bug!(expr.span, "no loop scope for id {}", loop_id); + span_bug!(expr.span, "no scope for id {}", loop_id); } - hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => - span_bug!(expr.span, "loop scope error: {}", err), + Err(err) => span_bug!(expr.span, "scope error: {}", err), } } } diff --git a/src/librustc/cfg/mod.rs b/src/librustc/cfg/mod.rs index b379d3956e944..cf9c24cc58a62 100644 --- a/src/librustc/cfg/mod.rs +++ b/src/librustc/cfg/mod.rs @@ -11,7 +11,7 @@ //! Module that constructs a control-flow graph representing an item. //! Uses `Graph` as the underlying representation. -use rustc_data_structures::graph; +use rustc_data_structures::graph::implementation as graph; use ty::TyCtxt; use hir; use hir::def_id::DefId; diff --git a/src/librustc/dep_graph/debug.rs b/src/librustc/dep_graph/debug.rs index e56333aba9be5..f0e43e78a50af 100644 --- a/src/librustc/dep_graph/debug.rs +++ b/src/librustc/dep_graph/debug.rs @@ -40,7 +40,7 @@ impl DepNodeFilter { /// Tests whether `node` meets the filter, returning true if so. pub fn test(&self, node: &DepNode) -> bool { let debug_str = format!("{:?}", node); - self.text.split("&") + self.text.split('&') .map(|s| s.trim()) .all(|f| debug_str.contains(f)) } diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index e4f432e7caf49..14a818ddafb71 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -60,7 +60,7 @@ //! user of the `DepNode` API of having to know how to compute the expected //! fingerprint for a given set of node parameters. -use mir::interpret::{GlobalId}; +use mir::interpret::GlobalId; use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use hir::map::DefPathHash; use hir::{HirId, ItemLocalId}; @@ -70,9 +70,12 @@ use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use std::fmt; use std::hash::Hash; use syntax_pos::symbol::InternedString; -use traits::query::{CanonicalProjectionGoal, - CanonicalTyGoal, CanonicalPredicateGoal}; -use ty::{TyCtxt, Instance, InstanceDef, ParamEnv, ParamEnvAnd, PolyTraitRef, Ty}; +use traits::query::{ + CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, + CanonicalPredicateGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, +}; +use ty::{TyCtxt, FnSig, Instance, InstanceDef, + ParamEnv, ParamEnvAnd, Predicate, PolyFnSig, PolyTraitRef, Ty, self}; use ty::subst::Substs; // erase!() just makes tokens go away. It's used to specify which macro argument @@ -331,11 +334,8 @@ macro_rules! define_dep_nodes { pub fn extract_def_id(&self, tcx: TyCtxt) -> Option { if self.kind.can_reconstruct_query_key() { let def_path_hash = DefPathHash(self.hash); - if let Some(ref def_path_map) = tcx.def_path_hash_to_def_id.as_ref() { - def_path_map.get(&def_path_hash).cloned() - } else { - None - } + tcx.def_path_hash_to_def_id.as_ref()? + .get(&def_path_hash).cloned() } else { None } @@ -500,6 +500,8 @@ define_dep_nodes!( <'tcx> [] TypeOfItem(DefId), [] GenericsOfItem(DefId), [] PredicatesOfItem(DefId), + [] ExplicitPredicatesOfItem(DefId), + [] PredicatesDefinedOnItem(DefId), [] InferredOutlivesOf(DefId), [] InferredOutlivesCrate(CrateNum), [] SuperPredicatesOfItem(DefId), @@ -565,7 +567,7 @@ define_dep_nodes!( <'tcx> [] IsUnreachableLocalDefinition(DefId), [] IsMirAvailable(DefId), [] ItemAttrs(DefId), - [] TransFnAttrs(DefId), + [] CodegenFnAttrs(DefId), [] FnArgNames(DefId), [] RenderedConst(DefId), [] DylibDepFormats(CrateNum), @@ -621,13 +623,14 @@ define_dep_nodes!( <'tcx> [input] UsedCrateSource(CrateNum), [input] PostorderCnums, - // This query is not expected to have inputs -- as a result, it's - // not a good candidate for "replay" because it's essentially a - // pure function of its input (and hence the expectation is that - // no caller would be green **apart** from just this - // query). Making it anonymous avoids hashing the result, which + // These queries are not expected to have inputs -- as a result, they + // are not good candidates for "replay" because they are essentially + // pure functions of their input (and hence the expectation is that + // no caller would be green **apart** from just these + // queries). Making them anonymous avoids hashing the result, which // may save a bit of time. [anon] EraseRegionsTy { ty: Ty<'tcx> }, + [anon] ConstValueToAllocation { val: &'tcx ty::Const<'tcx> }, [input] Freevars(DefId), [input] MaybeUnusedTraitImport(DefId), @@ -636,15 +639,23 @@ define_dep_nodes!( <'tcx> [eval_always] AllTraits, [input] AllCrateNums, [] ExportedSymbols(CrateNum), - [eval_always] CollectAndPartitionTranslationItems, - [] IsTranslatedItem(DefId), + [eval_always] CollectAndPartitionMonoItems, + [] IsCodegenedItem(DefId), [] CodegenUnit(InternedString), [] CompileCodegenUnit(InternedString), [input] OutputFilenames, [] NormalizeProjectionTy(CanonicalProjectionGoal<'tcx>), [] NormalizeTyAfterErasingRegions(ParamEnvAnd<'tcx, Ty<'tcx>>), + [] ImpliedOutlivesBounds(CanonicalTyGoal<'tcx>), [] DropckOutlives(CanonicalTyGoal<'tcx>), [] EvaluateObligation(CanonicalPredicateGoal<'tcx>), + [] TypeOpEq(CanonicalTypeOpEqGoal<'tcx>), + [] TypeOpSubtype(CanonicalTypeOpSubtypeGoal<'tcx>), + [] TypeOpProvePredicate(CanonicalTypeOpProvePredicateGoal<'tcx>), + [] TypeOpNormalizeTy(CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>), + [] TypeOpNormalizePredicate(CanonicalTypeOpNormalizeGoal<'tcx, Predicate<'tcx>>), + [] TypeOpNormalizePolyFnSig(CanonicalTypeOpNormalizeGoal<'tcx, PolyFnSig<'tcx>>), + [] TypeOpNormalizeFnSig(CanonicalTypeOpNormalizeGoal<'tcx, FnSig<'tcx>>), [] SubstituteNormalizeAndTestPredicates { key: (DefId, &'tcx Substs<'tcx>) }, @@ -652,8 +663,6 @@ define_dep_nodes!( <'tcx> [] InstanceDefSizeEstimate { instance_def: InstanceDef<'tcx> }, - [] WasmCustomSections(CrateNum), - [input] Features, [] ProgramClausesFor(DefId), diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index 22ab1b15c8b8e..e308f2924a05c 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -12,7 +12,8 @@ use errors::DiagnosticBuilder; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; -use rustc_data_structures::sync::{Lrc, RwLock, ReadGuard, Lock}; +use rustc_data_structures::small_vec::SmallVec; +use rustc_data_structures::sync::{Lrc, Lock}; use std::env; use std::hash::Hash; use ty::{self, TyCtxt}; @@ -38,7 +39,6 @@ pub struct DepGraph { fingerprints: Lrc>> } - newtype_index!(DepNodeIndex); impl DepNodeIndex { @@ -77,10 +77,7 @@ struct DepGraphData { /// things available to us. If we find that they are not dirty, we /// load the path to the file storing those work-products here into /// this map. We can later look for and extract that data. - previous_work_products: RwLock>, - - /// Work-products that we generate in this run. - work_products: RwLock>, + previous_work_products: FxHashMap, dep_node_debug: Lock>, @@ -90,7 +87,8 @@ struct DepGraphData { impl DepGraph { - pub fn new(prev_graph: PreviousDepGraph) -> DepGraph { + pub fn new(prev_graph: PreviousDepGraph, + prev_work_products: FxHashMap) -> DepGraph { // Pre-allocate the fingerprints array. We over-allocate a little so // that we hopefully don't have to re-allocate during this compilation // session. @@ -100,8 +98,7 @@ impl DepGraph { (prev_graph_node_count * 115) / 100); DepGraph { data: Some(Lrc::new(DepGraphData { - previous_work_products: RwLock::new(FxHashMap()), - work_products: RwLock::new(FxHashMap()), + previous_work_products: prev_work_products, dep_node_debug: Lock::new(FxHashMap()), current: Lock::new(CurrentDepGraph::new()), previous: prev_graph, @@ -131,7 +128,7 @@ impl DepGraph { let mut edges = Vec::new(); for (index, edge_targets) in current_dep_graph.edges.iter_enumerated() { let from = current_dep_graph.nodes[index]; - for &edge_target in edge_targets { + for &edge_target in edge_targets.iter() { let to = current_dep_graph.nodes[edge_target]; edges.push((from, to)); } @@ -209,7 +206,7 @@ impl DepGraph { self.with_task_impl(key, cx, arg, false, task, |key| OpenTask::Regular(Lock::new(RegularOpenTask { node: key, - reads: Vec::new(), + reads: SmallVec::new(), read_set: FxHashSet(), })), |data, key, task| data.borrow_mut().complete_task(key, task)) @@ -230,7 +227,7 @@ impl DepGraph { self.with_task_impl(key, cx, input, true, identity_fn, |_| OpenTask::Ignore, - |data, key, _| data.borrow_mut().alloc_node(key, Vec::new())) + |data, key, _| data.borrow_mut().alloc_node(key, SmallVec::new())) } fn with_task_impl<'gcx, C, A, R>( @@ -353,7 +350,7 @@ impl DepGraph { if let Some(ref data) = self.data { let (result, open_task) = ty::tls::with_context(|icx| { let task = OpenTask::Anon(Lock::new(AnonOpenTask { - reads: Vec::new(), + reads: SmallVec::new(), read_set: FxHashSet(), })); @@ -460,52 +457,20 @@ impl DepGraph { self.data.as_ref().unwrap().previous.node_to_index(dep_node) } - /// Indicates that a previous work product exists for `v`. This is - /// invoked during initial start-up based on what nodes are clean - /// (and what files exist in the incr. directory). - pub fn insert_previous_work_product(&self, v: &WorkProductId, data: WorkProduct) { - debug!("insert_previous_work_product({:?}, {:?})", v, data); - self.data - .as_ref() - .unwrap() - .previous_work_products - .borrow_mut() - .insert(v.clone(), data); - } - - /// Indicates that we created the given work-product in this run - /// for `v`. This record will be preserved and loaded in the next - /// run. - pub fn insert_work_product(&self, v: &WorkProductId, data: WorkProduct) { - debug!("insert_work_product({:?}, {:?})", v, data); - self.data - .as_ref() - .unwrap() - .work_products - .borrow_mut() - .insert(v.clone(), data); - } - /// Check whether a previous work product exists for `v` and, if /// so, return the path that leads to it. Used to skip doing work. pub fn previous_work_product(&self, v: &WorkProductId) -> Option { self.data .as_ref() .and_then(|data| { - data.previous_work_products.borrow().get(v).cloned() + data.previous_work_products.get(v).cloned() }) } - /// Access the map of work-products created during this run. Only - /// used during saving of the dep-graph. - pub fn work_products(&self) -> ReadGuard> { - self.data.as_ref().unwrap().work_products.borrow() - } - /// Access the map of work-products created during the cached run. Only /// used during saving of the dep-graph. - pub fn previous_work_products(&self) -> ReadGuard> { - self.data.as_ref().unwrap().previous_work_products.borrow() + pub fn previous_work_products(&self) -> &FxHashMap { + &self.data.as_ref().unwrap().previous_work_products } #[inline(always)] @@ -524,7 +489,12 @@ impl DepGraph { } pub(super) fn dep_node_debug_str(&self, dep_node: DepNode) -> Option { - self.data.as_ref().and_then(|t| t.dep_node_debug.borrow().get(&dep_node).cloned()) + self.data + .as_ref()? + .dep_node_debug + .borrow() + .get(&dep_node) + .cloned() } pub fn edge_deduplication_data(&self) -> (u64, u64) { @@ -534,15 +504,9 @@ impl DepGraph { } pub fn serialize(&self) -> SerializedDepGraph { - let mut fingerprints = self.fingerprints.borrow_mut(); let current_dep_graph = self.data.as_ref().unwrap().current.borrow(); - // Make sure we don't run out of bounds below. - if current_dep_graph.nodes.len() > fingerprints.len() { - fingerprints.resize(current_dep_graph.nodes.len(), Fingerprint::ZERO); - } - - let fingerprints = fingerprints.clone().convert_index_type(); + let fingerprints = self.fingerprints.borrow().clone().convert_index_type(); let nodes = current_dep_graph.nodes.clone().convert_index_type(); let total_edge_count: usize = current_dep_graph.edges.iter() @@ -626,7 +590,7 @@ impl DepGraph { debug_assert!(data.colors.borrow().get(prev_dep_node_index).is_none()); - let mut current_deps = Vec::new(); + let mut current_deps = SmallVec::new(); for &dep_dep_node_index in prev_deps { let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); @@ -696,7 +660,7 @@ impl DepGraph { // We failed to mark it green, so we try to force the query. debug!("try_mark_green({:?}) --- trying to force \ dependency {:?}", dep_node, dep_dep_node); - if ::ty::maps::force_from_dep_node(tcx, dep_dep_node) { + if ::ty::query::force_from_dep_node(tcx, dep_dep_node) { let dep_dep_node_color = data.colors.borrow().get(dep_dep_node_index); match dep_dep_node_color { @@ -782,14 +746,14 @@ impl DepGraph { // and emit other diagnostics before these diagnostics are emitted. // Such diagnostics should be emitted after these. // See https://github.com/rust-lang/rust/issues/48685 - let diagnostics = tcx.on_disk_query_result_cache + let diagnostics = tcx.queries.on_disk_cache .load_diagnostics(tcx, prev_dep_node_index); if diagnostics.len() > 0 { let handle = tcx.sess.diagnostic(); // Promote the previous diagnostics to the current session. - tcx.on_disk_query_result_cache + tcx.queries.on_disk_cache .store_diagnostics(dep_node_index, diagnostics.clone()); for diagnostic in diagnostics { @@ -896,10 +860,10 @@ impl DepGraph { /// each partition. In the first run, we create partitions based on /// the symbols that need to be compiled. For each partition P, we /// hash the symbols in P and create a `WorkProduct` record associated -/// with `DepNode::TransPartition(P)`; the hash is the set of symbols +/// with `DepNode::CodegenUnit(P)`; the hash is the set of symbols /// in P. /// -/// The next time we compile, if the `DepNode::TransPartition(P)` is +/// The next time we compile, if the `DepNode::CodegenUnit(P)` is /// judged to be clean (which means none of the things we read to /// generate the partition were found to be dirty), it will be loaded /// into previous work products. We will then regenerate the set of @@ -923,7 +887,7 @@ pub enum WorkProductFileKind { pub(super) struct CurrentDepGraph { nodes: IndexVec, - edges: IndexVec>, + edges: IndexVec>, node_to_node_index: FxHashMap, forbidden_edge: Option, @@ -1061,7 +1025,7 @@ impl CurrentDepGraph { } = task { debug_assert_eq!(node, key); let krate_idx = self.node_to_node_index[&DepNode::new_no_params(DepKind::Krate)]; - self.alloc_node(node, vec![krate_idx]) + self.alloc_node(node, SmallVec::one(krate_idx)) } else { bug!("complete_eval_always_task() - Expected eval always task to be popped"); } @@ -1107,7 +1071,7 @@ impl CurrentDepGraph { fn alloc_node(&mut self, dep_node: DepNode, - edges: Vec) + edges: SmallVec<[DepNodeIndex; 8]>) -> DepNodeIndex { debug_assert_eq!(self.edges.len(), self.nodes.len()); debug_assert_eq!(self.node_to_node_index.len(), self.nodes.len()); @@ -1122,12 +1086,12 @@ impl CurrentDepGraph { pub struct RegularOpenTask { node: DepNode, - reads: Vec, + reads: SmallVec<[DepNodeIndex; 8]>, read_set: FxHashSet, } pub struct AnonOpenTask { - reads: Vec, + reads: SmallVec<[DepNodeIndex; 8]>, read_set: FxHashSet, } diff --git a/src/librustc/dep_graph/query.rs b/src/librustc/dep_graph/query.rs index ea83a4f8b3104..ce0b5557a34bf 100644 --- a/src/librustc/dep_graph/query.rs +++ b/src/librustc/dep_graph/query.rs @@ -9,7 +9,9 @@ // except according to those terms. use rustc_data_structures::fx::FxHashMap; -use rustc_data_structures::graph::{Direction, INCOMING, Graph, NodeIndex, OUTGOING}; +use rustc_data_structures::graph::implementation::{ + Direction, INCOMING, Graph, NodeIndex, OUTGOING +}; use super::DepNode; diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 2662e70999196..5ace8397d9f82 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -637,8 +637,8 @@ Erroneous code example: ```compile_fail,E0152 #![feature(lang_items)] -#[lang = "panic_fmt"] -struct Foo; // error: duplicate lang item found: `panic_fmt` +#[lang = "panic_impl"] +struct Foo; // error: duplicate lang item found: `panic_impl` ``` Lang items are already implemented in the standard library. Unless you are @@ -824,7 +824,7 @@ A list of available external lang items is available in #![feature(lang_items)] extern "C" { - #[lang = "panic_fmt"] // ok! + #[lang = "panic_impl"] // ok! fn cake(); } ``` @@ -1958,8 +1958,6 @@ representation hints. Erroneous code example: ```compile_fail,E0692 -#![feature(repr_transparent)] - #[repr(transparent, C)] // error: incompatible representation hints struct Grams(f32); ``` @@ -1969,8 +1967,6 @@ another type, so adding more representation hints is contradictory. Remove either the `transparent` hint or the other hints, like this: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Grams(f32); ``` @@ -1978,8 +1974,6 @@ struct Grams(f32); Alternatively, move the other attributes to the contained type: ``` -#![feature(repr_transparent)] - #[repr(C)] struct Foo { x: i32, @@ -1994,8 +1988,6 @@ Note that introducing another `struct` just to have a place for the other attributes may have unintended side effects on the representation: ``` -#![feature(repr_transparent)] - #[repr(transparent)] struct Grams(f32); @@ -2011,13 +2003,13 @@ a (non-transparent) struct containing a single float, while `Grams` is a transparent wrapper around a float. This can make a difference for the ABI. "##, -E0909: r##" +E0700: r##" The `impl Trait` return type captures lifetime parameters that do not appear within the `impl Trait` itself. Erroneous code example: -```compile-fail,E0909 +```compile-fail,E0700 use std::cell::Cell; trait Trait<'a> { } @@ -2058,13 +2050,13 @@ where 'x: 'y ``` "##, -E0910: r##" +E0701: r##" This error indicates that a `#[non_exhaustive]` attribute was incorrectly placed on something other than a struct or enum. Examples of erroneous code: -```compile_fail,E0910 +```compile_fail,E0701 # #![feature(non_exhaustive)] #[non_exhaustive] @@ -2072,13 +2064,13 @@ trait Foo { } ``` "##, -E0911: r##" +E0702: r##" This error indicates that a `#[non_exhaustive]` attribute had a value. The `#[non_exhaustive]` should be empty. Examples of erroneous code: -```compile_fail,E0911 +```compile_fail,E0702 # #![feature(non_exhaustive)] #[non_exhaustive(anything)] @@ -2140,5 +2132,10 @@ register_diagnostics! { E0687, // in-band lifetimes cannot be used in `fn`/`Fn` syntax E0688, // in-band lifetimes cannot be mixed with explicit lifetime binders - E0906, // closures cannot be static + E0697, // closures cannot be static + + E0707, // multiple elided lifetimes used in arguments of `async fn` + E0708, // `async` non-`move` closures with arguments are not currently supported + E0709, // multiple different lifetimes used in arguments of `async fn` + E0710, // an unknown tool name found in scoped lint } diff --git a/src/librustc/hir/check_attr.rs b/src/librustc/hir/check_attr.rs index 24a1256c9d35b..05e0257cdafd2 100644 --- a/src/librustc/hir/check_attr.rs +++ b/src/librustc/hir/check_attr.rs @@ -38,13 +38,13 @@ enum Target { impl Target { fn from_item(item: &hir::Item) -> Target { match item.node { - hir::ItemFn(..) => Target::Fn, - hir::ItemStruct(..) => Target::Struct, - hir::ItemUnion(..) => Target::Union, - hir::ItemEnum(..) => Target::Enum, - hir::ItemConst(..) => Target::Const, - hir::ItemForeignMod(..) => Target::ForeignMod, - hir::ItemStatic(..) => Target::Static, + hir::ItemKind::Fn(..) => Target::Fn, + hir::ItemKind::Struct(..) => Target::Struct, + hir::ItemKind::Union(..) => Target::Union, + hir::ItemKind::Enum(..) => Target::Enum, + hir::ItemKind::Const(..) => Target::Const, + hir::ItemKind::ForeignMod(..) => Target::ForeignMod, + hir::ItemKind::Static(..) => Target::Static, _ => Target::Other, } } @@ -57,52 +57,22 @@ struct CheckAttrVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { /// Check any attribute. fn check_attributes(&self, item: &hir::Item, target: Target) { - if target == Target::Fn { - self.tcx.trans_fn_attrs(self.tcx.hir.local_def_id(item.id)); + if target == Target::Fn || target == Target::Const { + self.tcx.codegen_fn_attrs(self.tcx.hir.local_def_id(item.id)); } else if let Some(a) = item.attrs.iter().find(|a| a.check_name("target_feature")) { self.tcx.sess.struct_span_err(a.span, "attribute should be applied to a function") .span_label(item.span, "not a function") .emit(); } - let mut has_wasm_import_module = false; for attr in &item.attrs { if attr.check_name("inline") { self.check_inline(attr, &item.span, target) } else if attr.check_name("non_exhaustive") { self.check_non_exhaustive(attr, item, target) - } else if attr.check_name("wasm_import_module") { - has_wasm_import_module = true; - if attr.value_str().is_none() { - self.tcx.sess.span_err(attr.span, "\ - must be of the form #[wasm_import_module = \"...\"]"); - } - if target != Target::ForeignMod { - self.tcx.sess.span_err(attr.span, "\ - must only be attached to foreign modules"); - } - } else if attr.check_name("wasm_custom_section") { - if target != Target::Const { - self.tcx.sess.span_err(attr.span, "only allowed on consts"); - } - - if attr.value_str().is_none() { - self.tcx.sess.span_err(attr.span, "must be of the form \ - #[wasm_custom_section = \"foo\"]"); - } } } - if target == Target::ForeignMod && - !has_wasm_import_module && - self.tcx.sess.target.target.arch == "wasm32" && - false // FIXME: eventually enable this warning when stable - { - self.tcx.sess.span_warn(item.span, "\ - must have a #[wasm_import_module = \"...\"] attribute, this \ - will become a hard error before too long"); - } - self.check_repr(item, target); self.check_used(item, target); } @@ -126,7 +96,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { _ => { struct_span_err!(self.tcx.sess, attr.span, - E0910, + E0701, "attribute can only be applied to a struct or enum") .span_label(item.span, "not a struct or enum") .emit(); @@ -137,7 +107,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { if attr.meta_item_list().is_some() || attr.value_str().is_some() { struct_span_err!(self.tcx.sess, attr.span, - E0911, + E0702, "attribute should be empty") .span_label(item.span, "not empty") .emit(); @@ -269,7 +239,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { fn check_stmt_attributes(&self, stmt: &hir::Stmt) { // When checking statements ignore expressions, they will be checked later - if let hir::Stmt_::StmtDecl(_, _) = stmt.node { + if let hir::StmtKind::Decl(_, _) = stmt.node { for attr in stmt.node.attrs() { if attr.check_name("inline") { self.check_inline(attr, &stmt.span, Target::Statement); @@ -288,7 +258,7 @@ impl<'a, 'tcx> CheckAttrVisitor<'a, 'tcx> { fn check_expr_attributes(&self, expr: &hir::Expr) { let target = match expr.node { - hir::ExprClosure(..) => Target::Closure, + hir::ExprKind::Closure(..) => Target::Closure, _ => Target::Expression, }; for attr in expr.attrs.iter() { @@ -345,7 +315,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { } fn is_c_like_enum(item: &hir::Item) -> bool { - if let hir::ItemEnum(ref def, _) = item.node { + if let hir::ItemKind::Enum(ref def, _) = item.node { for variant in &def.variants { match variant.node.data { hir::VariantData::Unit(_) => { /* continue */ } diff --git a/src/librustc/hir/def.rs b/src/librustc/hir/def.rs index 8e4a4d32c0bad..1c355e35fd6ea 100644 --- a/src/librustc/hir/def.rs +++ b/src/librustc/hir/def.rs @@ -16,6 +16,8 @@ use syntax_pos::Span; use hir; use ty; +use self::Namespace::*; + #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum CtorKind { /// Constructor function automatically created by a tuple struct/variant. @@ -35,10 +37,15 @@ pub enum Def { Enum(DefId), Variant(DefId), Trait(DefId), + /// `existential type Foo: Bar;` + Existential(DefId), + /// `type Foo = Bar;` TyAlias(DefId), TyForeign(DefId), TraitAlias(DefId), AssociatedTy(DefId), + /// `existential type Foo: Bar;` + AssociatedExistential(DefId), PrimTy(hir::PrimTy), TyParam(DefId), SelfTy(Option /* trait */, Option /* impl */), @@ -116,6 +123,82 @@ impl PathResolution { } } +/// Different kinds of symbols don't influence each other. +/// +/// Therefore, they have a separate universe (namespace). +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub enum Namespace { + TypeNS, + ValueNS, + MacroNS, +} + +impl Namespace { + pub fn descr(self) -> &'static str { + match self { + TypeNS => "type", + ValueNS => "value", + MacroNS => "macro", + } + } +} + +/// Just a helper ‒ separate structure for each namespace. +#[derive(Copy, Clone, Default, Debug)] +pub struct PerNS { + pub value_ns: T, + pub type_ns: T, + pub macro_ns: T, +} + +impl PerNS { + pub fn map U>(self, mut f: F) -> PerNS { + PerNS { + value_ns: f(self.value_ns), + type_ns: f(self.type_ns), + macro_ns: f(self.macro_ns), + } + } +} + +impl ::std::ops::Index for PerNS { + type Output = T; + fn index(&self, ns: Namespace) -> &T { + match ns { + ValueNS => &self.value_ns, + TypeNS => &self.type_ns, + MacroNS => &self.macro_ns, + } + } +} + +impl ::std::ops::IndexMut for PerNS { + fn index_mut(&mut self, ns: Namespace) -> &mut T { + match ns { + ValueNS => &mut self.value_ns, + TypeNS => &mut self.type_ns, + MacroNS => &mut self.macro_ns, + } + } +} + +impl PerNS> { + /// Returns whether all the items in this collection are `None`. + pub fn is_empty(&self) -> bool { + self.type_ns.is_none() && self.value_ns.is_none() && self.macro_ns.is_none() + } + + /// Returns an iterator over the items which are `Some`. + pub fn present_items(self) -> impl Iterator { + use std::iter::once; + + once(self.type_ns) + .chain(once(self.value_ns)) + .chain(once(self.macro_ns)) + .filter_map(|it| it) + } +} + /// Definition mapping pub type DefMap = NodeMap; @@ -123,6 +206,10 @@ pub type DefMap = NodeMap; /// within. pub type ExportMap = DefIdMap>; +/// Map used to track the `use` statements within a scope, matching it with all the items in every +/// namespace. +pub type ImportMap = NodeMap>>; + #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Export { /// The name of the target. @@ -134,9 +221,6 @@ pub struct Export { /// The visibility of the export. /// We include non-`pub` exports for hygienic macros that get used from extern crates. pub vis: ty::Visibility, - /// True if from a `use` or and `extern crate`. - /// Used in rustdoc. - pub is_import: bool, } impl CtorKind { @@ -165,6 +249,7 @@ impl Def { Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) | Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) | Def::AssociatedConst(id) | Def::Macro(id, ..) | + Def::Existential(id) | Def::AssociatedExistential(id) | Def::GlobalAsm(id) | Def::TyForeign(id) => { id } @@ -191,9 +276,11 @@ impl Def { Def::VariantCtor(.., CtorKind::Const) => "unit variant", Def::VariantCtor(.., CtorKind::Fictive) => "struct variant", Def::Enum(..) => "enum", + Def::Existential(..) => "existential type", Def::TyAlias(..) => "type alias", Def::TraitAlias(..) => "trait alias", Def::AssociatedTy(..) => "associated type", + Def::AssociatedExistential(..) => "associated existential type", Def::Struct(..) => "struct", Def::StructCtor(.., CtorKind::Fn) => "tuple struct", Def::StructCtor(.., CtorKind::Const) => "unit struct", @@ -210,7 +297,7 @@ impl Def { Def::Upvar(..) => "closure capture", Def::Label(..) => "label", Def::SelfTy(..) => "self type", - Def::Macro(..) => "macro", + Def::Macro(.., macro_kind) => macro_kind.descr(), Def::GlobalAsm(..) => "global asm", Def::Err => "unresolved item", } diff --git a/src/librustc/hir/def_id.rs b/src/librustc/hir/def_id.rs index 34b3aa53d6bcf..7acfe6839540b 100644 --- a/src/librustc/hir/def_id.rs +++ b/src/librustc/hir/def_id.rs @@ -81,7 +81,7 @@ impl serialize::UseSpecializedDecodable for CrateNum {} /// Since the DefIndex is mostly treated as an opaque ID, you probably /// don't have to care about these address spaces. -#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, Hash, Copy)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] pub struct DefIndex(u32); /// The crate root is always assigned index 0 by the AST Map code, @@ -150,7 +150,7 @@ impl DefIndex { impl serialize::UseSpecializedEncodable for DefIndex {} impl serialize::UseSpecializedDecodable for DefIndex {} -#[derive(Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Copy, Clone, Hash)] pub enum DefIndexAddressSpace { Low = 0, High = 1, @@ -165,7 +165,7 @@ impl DefIndexAddressSpace { /// A DefId identifies a particular *definition*, by combining a crate /// index and a def index. -#[derive(Clone, Eq, Ord, PartialOrd, PartialEq, Hash, Copy)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy)] pub struct DefId { pub krate: CrateNum, pub index: DefIndex, @@ -216,7 +216,7 @@ impl serialize::UseSpecializedDecodable for DefId {} /// few cases where we know that only DefIds from the local crate are expected /// and a DefId from a different crate would signify a bug somewhere. This /// is when LocalDefId comes in handy. -#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct LocalDefId(DefIndex); impl LocalDefId { diff --git a/src/librustc/hir/intravisit.rs b/src/librustc/hir/intravisit.rs index 3e5dcee113a4e..4274cd3a0a655 100644 --- a/src/librustc/hir/intravisit.rs +++ b/src/librustc/hir/intravisit.rs @@ -41,8 +41,7 @@ //! This order consistency is required in a few places in rustc, for //! example generator inference, and possibly also HIR borrowck. -use rustc_target::spec::abi::Abi; -use syntax::ast::{NodeId, CRATE_NODE_ID, Name, Attribute}; +use syntax::ast::{NodeId, CRATE_NODE_ID, Ident, Name, Attribute}; use syntax_pos::Span; use hir::*; use hir::def::Def; @@ -51,14 +50,15 @@ use super::itemlikevisit::DeepVisitor; use std::cmp; use std::u32; +use std::result::Result::Err; -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone)] pub enum FnKind<'a> { - /// fn foo() or extern "Abi" fn foo() - ItemFn(Name, &'a Generics, Unsafety, Constness, Abi, &'a Visibility, &'a [Attribute]), + /// #[xxx] pub async/const/extern "Abi" fn foo() + ItemFn(Name, &'a Generics, FnHeader, &'a Visibility, &'a [Attribute]), /// fn foo(&self) - Method(Name, &'a MethodSig, Option<&'a Visibility>, &'a [Attribute]), + Method(Ident, &'a MethodSig, Option<&'a Visibility>, &'a [Attribute]), /// |x, y| {} Closure(&'a [Attribute]), @@ -248,6 +248,9 @@ pub trait Visitor<'v> : Sized { fn visit_name(&mut self, _span: Span, _name: Name) { // Nothing to do. } + fn visit_ident(&mut self, ident: Ident) { + walk_ident(self, ident) + } fn visit_mod(&mut self, m: &'v Mod, _s: Span, n: NodeId) { walk_mod(self, m, n) } @@ -272,6 +275,9 @@ pub trait Visitor<'v> : Sized { fn visit_decl(&mut self, d: &'v Decl) { walk_decl(self, d) } + fn visit_anon_const(&mut self, c: &'v AnonConst) { + walk_anon_const(self, c) + } fn visit_expr(&mut self, ex: &'v Expr) { walk_expr(self, ex) } @@ -308,8 +314,8 @@ pub trait Visitor<'v> : Sized { fn visit_trait_ref(&mut self, t: &'v TraitRef) { walk_trait_ref(self, t) } - fn visit_ty_param_bound(&mut self, bounds: &'v TyParamBound) { - walk_ty_param_bound(self, bounds) + fn visit_param_bound(&mut self, bounds: &'v GenericBound) { + walk_param_bound(self, bounds) } fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef, m: TraitBoundModifier) { walk_poly_trait_ref(self, t, m) @@ -338,6 +344,12 @@ pub trait Visitor<'v> : Sized { fn visit_label(&mut self, label: &'v Label) { walk_label(self, label) } + fn visit_generic_arg(&mut self, generic_arg: &'v GenericArg) { + match generic_arg { + GenericArg::Lifetime(lt) => self.visit_lifetime(lt), + GenericArg::Type(ty) => self.visit_ty(ty), + } + } fn visit_lifetime(&mut self, lifetime: &'v Lifetime) { walk_lifetime(self, lifetime) } @@ -350,8 +362,8 @@ pub trait Visitor<'v> : Sized { fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v PathSegment) { walk_path_segment(self, path_span, path_segment) } - fn visit_path_parameters(&mut self, path_span: Span, path_parameters: &'v PathParameters) { - walk_path_parameters(self, path_span, path_parameters) + fn visit_generic_args(&mut self, path_span: Span, generic_args: &'v GenericArgs) { + walk_generic_args(self, path_span, generic_args) } fn visit_assoc_type_binding(&mut self, type_binding: &'v TypeBinding) { walk_assoc_type_binding(self, type_binding) @@ -410,17 +422,21 @@ pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) { walk_list!(visitor, visit_ty, &local.ty); } +pub fn walk_ident<'v, V: Visitor<'v>>(visitor: &mut V, ident: Ident) { + visitor.visit_name(ident.span, ident.name); +} + pub fn walk_label<'v, V: Visitor<'v>>(visitor: &mut V, label: &'v Label) { - visitor.visit_name(label.span, label.name); + visitor.visit_ident(label.ident); } pub fn walk_lifetime<'v, V: Visitor<'v>>(visitor: &mut V, lifetime: &'v Lifetime) { visitor.visit_id(lifetime.id); match lifetime.name { - LifetimeName::Name(name) => { - visitor.visit_name(lifetime.span, name); + LifetimeName::Param(ParamName::Plain(ident)) => { + visitor.visit_ident(ident); } - LifetimeName::Fresh(_) | + LifetimeName::Param(ParamName::Fresh(_)) | LifetimeName::Static | LifetimeName::Implicit | LifetimeName::Underscore => {} @@ -447,28 +463,26 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { visitor.visit_vis(&item.vis); visitor.visit_name(item.span, item.name); match item.node { - ItemExternCrate(orig_name) => { + ItemKind::ExternCrate(orig_name) => { visitor.visit_id(item.id); if let Some(orig_name) = orig_name { visitor.visit_name(item.span, orig_name); } } - ItemUse(ref path, _) => { + ItemKind::Use(ref path, _) => { visitor.visit_id(item.id); visitor.visit_path(path, item.id); } - ItemStatic(ref typ, _, body) | - ItemConst(ref typ, body) => { + ItemKind::Static(ref typ, _, body) | + ItemKind::Const(ref typ, body) => { visitor.visit_id(item.id); visitor.visit_ty(typ); visitor.visit_nested_body(body); } - ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => { + ItemKind::Fn(ref declaration, header, ref generics, body_id) => { visitor.visit_fn(FnKind::ItemFn(item.name, generics, - unsafety, - constness, - abi, + header, &item.vis, &item.attrs), declaration, @@ -476,50 +490,64 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item) { item.span, item.id) } - ItemMod(ref module) => { + ItemKind::Mod(ref module) => { // visit_mod() takes care of visiting the Item's NodeId visitor.visit_mod(module, item.span, item.id) } - ItemForeignMod(ref foreign_module) => { + ItemKind::ForeignMod(ref foreign_module) => { visitor.visit_id(item.id); walk_list!(visitor, visit_foreign_item, &foreign_module.items); } - ItemGlobalAsm(_) => { + ItemKind::GlobalAsm(_) => { visitor.visit_id(item.id); } - ItemTy(ref typ, ref type_parameters) => { + ItemKind::Ty(ref typ, ref type_parameters) => { visitor.visit_id(item.id); visitor.visit_ty(typ); visitor.visit_generics(type_parameters) } - ItemEnum(ref enum_definition, ref type_parameters) => { + ItemKind::Existential(ExistTy {ref generics, ref bounds, impl_trait_fn}) => { + visitor.visit_id(item.id); + walk_generics(visitor, generics); + walk_list!(visitor, visit_param_bound, bounds); + if let Some(impl_trait_fn) = impl_trait_fn { + visitor.visit_def_mention(Def::Fn(impl_trait_fn)) + } + } + ItemKind::Enum(ref enum_definition, ref type_parameters) => { visitor.visit_generics(type_parameters); // visit_enum_def() takes care of visiting the Item's NodeId visitor.visit_enum_def(enum_definition, type_parameters, item.id, item.span) } - ItemImpl(.., ref type_parameters, ref opt_trait_reference, ref typ, ref impl_item_refs) => { + ItemKind::Impl( + .., + ref type_parameters, + ref opt_trait_reference, + ref typ, + ref impl_item_refs + ) => { visitor.visit_id(item.id); visitor.visit_generics(type_parameters); walk_list!(visitor, visit_trait_ref, opt_trait_reference); visitor.visit_ty(typ); walk_list!(visitor, visit_impl_item_ref, impl_item_refs); } - ItemStruct(ref struct_definition, ref generics) | - ItemUnion(ref struct_definition, ref generics) => { + ItemKind::Struct(ref struct_definition, ref generics) | + ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_id(item.id); visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span); } - ItemTrait(.., ref generics, ref bounds, ref trait_item_refs) => { + ItemKind::Trait(.., ref generics, ref bounds, ref trait_item_refs) => { visitor.visit_id(item.id); visitor.visit_generics(generics); - walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_trait_item_ref, trait_item_refs); } - ItemTraitAlias(ref generics, ref bounds) => { + ItemKind::TraitAlias(ref generics, ref bounds) => { visitor.visit_id(item.id); visitor.visit_generics(generics); - walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds); } } walk_list!(visitor, visit_attribute, &item.attrs); @@ -547,7 +575,7 @@ pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, generics, parent_item_id, variant.span); - walk_list!(visitor, visit_nested_body, variant.node.disr_expr); + walk_list!(visitor, visit_anon_const, &variant.node.disr_expr); walk_list!(visitor, visit_attribute, &variant.node.attrs); } @@ -555,47 +583,41 @@ pub fn walk_ty<'v, V: Visitor<'v>>(visitor: &mut V, typ: &'v Ty) { visitor.visit_id(typ.id); match typ.node { - TySlice(ref ty) => { + TyKind::Slice(ref ty) => { visitor.visit_ty(ty) } - TyPtr(ref mutable_type) => { + TyKind::Ptr(ref mutable_type) => { visitor.visit_ty(&mutable_type.ty) } - TyRptr(ref lifetime, ref mutable_type) => { + TyKind::Rptr(ref lifetime, ref mutable_type) => { visitor.visit_lifetime(lifetime); visitor.visit_ty(&mutable_type.ty) } - TyNever => {}, - TyTup(ref tuple_element_types) => { + TyKind::Never => {}, + TyKind::Tup(ref tuple_element_types) => { walk_list!(visitor, visit_ty, tuple_element_types); } - TyBareFn(ref function_declaration) => { - visitor.visit_fn_decl(&function_declaration.decl); + TyKind::BareFn(ref function_declaration) => { walk_list!(visitor, visit_generic_param, &function_declaration.generic_params); + visitor.visit_fn_decl(&function_declaration.decl); } - TyPath(ref qpath) => { + TyKind::Path(ref qpath) => { visitor.visit_qpath(qpath, typ.id, typ.span); } - TyArray(ref ty, length) => { + TyKind::Array(ref ty, ref length) => { visitor.visit_ty(ty); - visitor.visit_nested_body(length) + visitor.visit_anon_const(length) } - TyTraitObject(ref bounds, ref lifetime) => { + TyKind::TraitObject(ref bounds, ref lifetime) => { for bound in bounds { visitor.visit_poly_trait_ref(bound, TraitBoundModifier::None); } visitor.visit_lifetime(lifetime); } - TyImplTraitExistential(ref existty, ref lifetimes) => { - let ExistTy { ref generics, ref bounds } = *existty; - walk_generics(visitor, generics); - walk_list!(visitor, visit_ty_param_bound, bounds); - walk_list!(visitor, visit_lifetime, lifetimes); - } - TyTypeof(expression) => { - visitor.visit_nested_body(expression) + TyKind::Typeof(ref expression) => { + visitor.visit_anon_const(expression) } - TyInfer | TyErr => {} + TyKind::Infer | TyKind::Err => {} } } @@ -624,24 +646,23 @@ pub fn walk_path<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path) { pub fn walk_path_segment<'v, V: Visitor<'v>>(visitor: &mut V, path_span: Span, segment: &'v PathSegment) { - visitor.visit_name(path_span, segment.name); - if let Some(ref parameters) = segment.parameters { - visitor.visit_path_parameters(path_span, parameters); + visitor.visit_ident(segment.ident); + if let Some(ref args) = segment.args { + visitor.visit_generic_args(path_span, args); } } -pub fn walk_path_parameters<'v, V: Visitor<'v>>(visitor: &mut V, - _path_span: Span, - path_parameters: &'v PathParameters) { - walk_list!(visitor, visit_lifetime, &path_parameters.lifetimes); - walk_list!(visitor, visit_ty, &path_parameters.types); - walk_list!(visitor, visit_assoc_type_binding, &path_parameters.bindings); +pub fn walk_generic_args<'v, V: Visitor<'v>>(visitor: &mut V, + _path_span: Span, + generic_args: &'v GenericArgs) { + walk_list!(visitor, visit_generic_arg, &generic_args.args); + walk_list!(visitor, visit_assoc_type_binding, &generic_args.bindings); } pub fn walk_assoc_type_binding<'v, V: Visitor<'v>>(visitor: &mut V, type_binding: &'v TypeBinding) { visitor.visit_id(type_binding.id); - visitor.visit_name(type_binding.span, type_binding.name); + visitor.visit_ident(type_binding.ident); visitor.visit_ty(&type_binding.ty); } @@ -659,7 +680,7 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { visitor.visit_qpath(qpath, pattern.id, pattern.span); for field in fields { visitor.visit_id(field.node.id); - visitor.visit_name(field.span, field.node.name); + visitor.visit_ident(field.node.ident); visitor.visit_pat(&field.node.pat) } } @@ -670,9 +691,9 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat) { PatKind::Ref(ref subpattern, _) => { visitor.visit_pat(subpattern) } - PatKind::Binding(_, canonical_id, ref pth1, ref optional_subpattern) => { + PatKind::Binding(_, canonical_id, ident, ref optional_subpattern) => { visitor.visit_def_mention(Def::Local(canonical_id)); - visitor.visit_name(pth1.span, pth1.node); + visitor.visit_ident(ident); walk_list!(visitor, visit_pat, optional_subpattern); } PatKind::Lit(ref expression) => visitor.visit_expr(expression), @@ -695,45 +716,41 @@ pub fn walk_foreign_item<'v, V: Visitor<'v>>(visitor: &mut V, foreign_item: &'v visitor.visit_name(foreign_item.span, foreign_item.name); match foreign_item.node { - ForeignItemFn(ref function_declaration, ref names, ref generics) => { + ForeignItemKind::Fn(ref function_declaration, ref param_names, ref generics) => { visitor.visit_generics(generics); visitor.visit_fn_decl(function_declaration); - for name in names { - visitor.visit_name(name.span, name.node); + for ¶m_name in param_names { + visitor.visit_ident(param_name); } } - ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ), - ForeignItemType => (), + ForeignItemKind::Static(ref typ, _) => visitor.visit_ty(typ), + ForeignItemKind::Type => (), } walk_list!(visitor, visit_attribute, &foreign_item.attrs); } -pub fn walk_ty_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v TyParamBound) { +pub fn walk_param_bound<'v, V: Visitor<'v>>(visitor: &mut V, bound: &'v GenericBound) { match *bound { - TraitTyParamBound(ref typ, modifier) => { + GenericBound::Trait(ref typ, modifier) => { visitor.visit_poly_trait_ref(typ, modifier); } - RegionTyParamBound(ref lifetime) => { - visitor.visit_lifetime(lifetime); - } + GenericBound::Outlives(ref lifetime) => visitor.visit_lifetime(lifetime), } } pub fn walk_generic_param<'v, V: Visitor<'v>>(visitor: &mut V, param: &'v GenericParam) { - match *param { - GenericParam::Lifetime(ref ld) => { - visitor.visit_lifetime(&ld.lifetime); - walk_list!(visitor, visit_lifetime, &ld.bounds); - } - GenericParam::Type(ref ty_param) => { - visitor.visit_id(ty_param.id); - visitor.visit_name(ty_param.span, ty_param.name); - walk_list!(visitor, visit_ty_param_bound, &ty_param.bounds); - walk_list!(visitor, visit_ty, &ty_param.default); - walk_list!(visitor, visit_attribute, ty_param.attrs.iter()); - } + visitor.visit_id(param.id); + walk_list!(visitor, visit_attribute, ¶m.attrs); + match param.name { + ParamName::Plain(ident) => visitor.visit_ident(ident), + ParamName::Fresh(_) => {} + } + match param.kind { + GenericParamKind::Lifetime { .. } => {} + GenericParamKind::Type { ref default, .. } => walk_list!(visitor, visit_ty, default), } + walk_list!(visitor, visit_param_bound, ¶m.bounds); } pub fn walk_generics<'v, V: Visitor<'v>>(visitor: &mut V, generics: &'v Generics) { @@ -752,14 +769,14 @@ pub fn walk_where_predicate<'v, V: Visitor<'v>>( ref bound_generic_params, ..}) => { visitor.visit_ty(bounded_ty); - walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_generic_param, bound_generic_params); } &WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime, ref bounds, ..}) => { visitor.visit_lifetime(lifetime); - walk_list!(visitor, visit_lifetime, bounds); + walk_list!(visitor, visit_param_bound, bounds); } &WherePredicate::EqPredicate(WhereEqPredicate{id, ref lhs_ty, @@ -808,7 +825,7 @@ pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V, } pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) { - visitor.visit_name(trait_item.span, trait_item.name); + visitor.visit_ident(trait_item.ident); walk_list!(visitor, visit_attribute, &trait_item.attrs); visitor.visit_generics(&trait_item.generics); match trait_item.node { @@ -817,15 +834,15 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai visitor.visit_ty(ty); walk_list!(visitor, visit_nested_body, default); } - TraitItemKind::Method(ref sig, TraitMethod::Required(ref names)) => { + TraitItemKind::Method(ref sig, TraitMethod::Required(ref param_names)) => { visitor.visit_id(trait_item.id); visitor.visit_fn_decl(&sig.decl); - for name in names { - visitor.visit_name(name.span, name.node); + for ¶m_name in param_names { + visitor.visit_ident(param_name); } } TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => { - visitor.visit_fn(FnKind::Method(trait_item.name, + visitor.visit_fn(FnKind::Method(trait_item.ident, sig, None, &trait_item.attrs), @@ -836,7 +853,7 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai } TraitItemKind::Type(ref bounds, ref default) => { visitor.visit_id(trait_item.id); - walk_list!(visitor, visit_ty_param_bound, bounds); + walk_list!(visitor, visit_param_bound, bounds); walk_list!(visitor, visit_ty, default); } } @@ -844,9 +861,9 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v Trai pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) { // NB: Deliberately force a compilation error if/when new fields are added. - let TraitItemRef { id, name, ref kind, span, ref defaultness } = *trait_item_ref; + let TraitItemRef { id, ident, ref kind, span: _, ref defaultness } = *trait_item_ref; visitor.visit_nested_trait_item(id); - visitor.visit_name(span, name); + visitor.visit_ident(ident); visitor.visit_associated_item_kind(kind); visitor.visit_defaultness(defaultness); } @@ -856,16 +873,16 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt let ImplItem { id: _, hir_id: _, - name, + ident, ref vis, ref defaultness, ref attrs, ref generics, ref node, - span + span: _, } = *impl_item; - visitor.visit_name(span, name); + visitor.visit_ident(ident); visitor.visit_vis(vis); visitor.visit_defaultness(defaultness); walk_list!(visitor, visit_attribute, attrs); @@ -877,7 +894,7 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_nested_body(body); } ImplItemKind::Method(ref sig, body_id) => { - visitor.visit_fn(FnKind::Method(impl_item.name, + visitor.visit_fn(FnKind::Method(impl_item.ident, sig, Some(&impl_item.vis), &impl_item.attrs), @@ -890,14 +907,18 @@ pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplIt visitor.visit_id(impl_item.id); visitor.visit_ty(ty); } + ImplItemKind::Existential(ref bounds) => { + visitor.visit_id(impl_item.id); + walk_list!(visitor, visit_param_bound, bounds); + } } } pub fn walk_impl_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, impl_item_ref: &'v ImplItemRef) { // NB: Deliberately force a compilation error if/when new fields are added. - let ImplItemRef { id, name, ref kind, span, ref vis, ref defaultness } = *impl_item_ref; + let ImplItemRef { id, ident, ref kind, span: _, ref vis, ref defaultness } = *impl_item_ref; visitor.visit_nested_impl_item(id); - visitor.visit_name(span, name); + visitor.visit_ident(ident); visitor.visit_associated_item_kind(kind); visitor.visit_vis(vis); visitor.visit_defaultness(defaultness); @@ -912,7 +933,7 @@ pub fn walk_struct_def<'v, V: Visitor<'v>>(visitor: &mut V, struct_definition: & pub fn walk_struct_field<'v, V: Visitor<'v>>(visitor: &mut V, struct_field: &'v StructField) { visitor.visit_id(struct_field.id); visitor.visit_vis(&struct_field.vis); - visitor.visit_name(struct_field.span, struct_field.name); + visitor.visit_ident(struct_field.ident); visitor.visit_ty(&struct_field.ty); walk_list!(visitor, visit_attribute, &struct_field.attrs); } @@ -925,12 +946,12 @@ pub fn walk_block<'v, V: Visitor<'v>>(visitor: &mut V, block: &'v Block) { pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { match statement.node { - StmtDecl(ref declaration, id) => { + StmtKind::Decl(ref declaration, id) => { visitor.visit_id(id); visitor.visit_decl(declaration) } - StmtExpr(ref expression, id) | - StmtSemi(ref expression, id) => { + StmtKind::Expr(ref expression, id) | + StmtKind::Semi(ref expression, id) => { visitor.visit_id(id); visitor.visit_expr(expression) } @@ -939,129 +960,133 @@ pub fn walk_stmt<'v, V: Visitor<'v>>(visitor: &mut V, statement: &'v Stmt) { pub fn walk_decl<'v, V: Visitor<'v>>(visitor: &mut V, declaration: &'v Decl) { match declaration.node { - DeclLocal(ref local) => visitor.visit_local(local), - DeclItem(item) => visitor.visit_nested_item(item), + DeclKind::Local(ref local) => visitor.visit_local(local), + DeclKind::Item(item) => visitor.visit_nested_item(item), } } +pub fn walk_anon_const<'v, V: Visitor<'v>>(visitor: &mut V, constant: &'v AnonConst) { + visitor.visit_id(constant.id); + visitor.visit_nested_body(constant.body); +} + pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_id(expression.id); walk_list!(visitor, visit_attribute, expression.attrs.iter()); match expression.node { - ExprBox(ref subexpression) => { + ExprKind::Box(ref subexpression) => { visitor.visit_expr(subexpression) } - ExprArray(ref subexpressions) => { + ExprKind::Array(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } - ExprRepeat(ref element, count) => { + ExprKind::Repeat(ref element, ref count) => { visitor.visit_expr(element); - visitor.visit_nested_body(count) + visitor.visit_anon_const(count) } - ExprStruct(ref qpath, ref fields, ref optional_base) => { + ExprKind::Struct(ref qpath, ref fields, ref optional_base) => { visitor.visit_qpath(qpath, expression.id, expression.span); for field in fields { visitor.visit_id(field.id); - visitor.visit_name(field.name.span, field.name.node); + visitor.visit_ident(field.ident); visitor.visit_expr(&field.expr) } walk_list!(visitor, visit_expr, optional_base); } - ExprTup(ref subexpressions) => { + ExprKind::Tup(ref subexpressions) => { walk_list!(visitor, visit_expr, subexpressions); } - ExprCall(ref callee_expression, ref arguments) => { + ExprKind::Call(ref callee_expression, ref arguments) => { visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); } - ExprMethodCall(ref segment, _, ref arguments) => { + ExprKind::MethodCall(ref segment, _, ref arguments) => { visitor.visit_path_segment(expression.span, segment); walk_list!(visitor, visit_expr, arguments); } - ExprBinary(_, ref left_expression, ref right_expression) => { + ExprKind::Binary(_, ref left_expression, ref right_expression) => { visitor.visit_expr(left_expression); visitor.visit_expr(right_expression) } - ExprAddrOf(_, ref subexpression) | ExprUnary(_, ref subexpression) => { + ExprKind::AddrOf(_, ref subexpression) | ExprKind::Unary(_, ref subexpression) => { visitor.visit_expr(subexpression) } - ExprLit(_) => {} - ExprCast(ref subexpression, ref typ) | ExprType(ref subexpression, ref typ) => { + ExprKind::Lit(_) => {} + ExprKind::Cast(ref subexpression, ref typ) | ExprKind::Type(ref subexpression, ref typ) => { visitor.visit_expr(subexpression); visitor.visit_ty(typ) } - ExprIf(ref head_expression, ref if_block, ref optional_else) => { + ExprKind::If(ref head_expression, ref if_block, ref optional_else) => { visitor.visit_expr(head_expression); visitor.visit_expr(if_block); walk_list!(visitor, visit_expr, optional_else); } - ExprWhile(ref subexpression, ref block, ref opt_label) => { + ExprKind::While(ref subexpression, ref block, ref opt_label) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_expr(subexpression); visitor.visit_block(block); } - ExprLoop(ref block, ref opt_label, _) => { + ExprKind::Loop(ref block, ref opt_label, _) => { walk_list!(visitor, visit_label, opt_label); visitor.visit_block(block); } - ExprMatch(ref subexpression, ref arms, _) => { + ExprKind::Match(ref subexpression, ref arms, _) => { visitor.visit_expr(subexpression); walk_list!(visitor, visit_arm, arms); } - ExprClosure(_, ref function_declaration, body, _fn_decl_span, _gen) => { + ExprKind::Closure(_, ref function_declaration, body, _fn_decl_span, _gen) => { visitor.visit_fn(FnKind::Closure(&expression.attrs), function_declaration, body, expression.span, expression.id) } - ExprBlock(ref block) => visitor.visit_block(block), - ExprAssign(ref left_hand_expression, ref right_hand_expression) => { + ExprKind::Block(ref block, ref opt_label) => { + walk_list!(visitor, visit_label, opt_label); + visitor.visit_block(block); + } + ExprKind::Assign(ref left_hand_expression, ref right_hand_expression) => { visitor.visit_expr(right_hand_expression); visitor.visit_expr(left_hand_expression) } - ExprAssignOp(_, ref left_expression, ref right_expression) => { + ExprKind::AssignOp(_, ref left_expression, ref right_expression) => { visitor.visit_expr(right_expression); visitor.visit_expr(left_expression) } - ExprField(ref subexpression, ref name) => { + ExprKind::Field(ref subexpression, ident) => { visitor.visit_expr(subexpression); - visitor.visit_name(name.span, name.node); + visitor.visit_ident(ident); } - ExprIndex(ref main_expression, ref index_expression) => { + ExprKind::Index(ref main_expression, ref index_expression) => { visitor.visit_expr(main_expression); visitor.visit_expr(index_expression) } - ExprPath(ref qpath) => { + ExprKind::Path(ref qpath) => { visitor.visit_qpath(qpath, expression.id, expression.span); } - ExprBreak(ref destination, ref opt_expr) => { + ExprKind::Break(ref destination, ref opt_expr) => { if let Some(ref label) = destination.label { visitor.visit_label(label); match destination.target_id { - ScopeTarget::Block(node_id) | - ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => - visitor.visit_def_mention(Def::Label(node_id)), - ScopeTarget::Loop(LoopIdResult::Err(_)) => {}, + Ok(node_id) => visitor.visit_def_mention(Def::Label(node_id)), + Err(_) => {}, }; } walk_list!(visitor, visit_expr, opt_expr); } - ExprAgain(ref destination) => { + ExprKind::Continue(ref destination) => { if let Some(ref label) = destination.label { visitor.visit_label(label); match destination.target_id { - ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"), - ScopeTarget::Loop(LoopIdResult::Ok(node_id)) => - visitor.visit_def_mention(Def::Label(node_id)), - ScopeTarget::Loop(LoopIdResult::Err(_)) => {}, + Ok(node_id) => visitor.visit_def_mention(Def::Label(node_id)), + Err(_) => {}, }; } } - ExprRet(ref optional_expression) => { + ExprKind::Ret(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } - ExprInlineAsm(_, ref outputs, ref inputs) => { + ExprKind::InlineAsm(_, ref outputs, ref inputs) => { for output in outputs { visitor.visit_expr(output) } @@ -1069,7 +1094,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) { visitor.visit_expr(input) } } - ExprYield(ref subexpression) => { + ExprKind::Yield(ref subexpression) => { visitor.visit_expr(subexpression); } } @@ -1083,7 +1108,7 @@ pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) { } pub fn walk_vis<'v, V: Visitor<'v>>(visitor: &mut V, vis: &'v Visibility) { - if let Visibility::Restricted { ref path, id } = *vis { + if let VisibilityKind::Restricted { ref path, id } = vis.node { visitor.visit_id(id); visitor.visit_path(path, id) } @@ -1101,7 +1126,7 @@ pub fn walk_defaultness<'v, V: Visitor<'v>>(_: &mut V, _: &'v Defaultness) { // would be to walk it. } -#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug)] pub struct IdRange { pub min: NodeId, pub max: NodeId, diff --git a/src/librustc/hir/itemlikevisit.rs b/src/librustc/hir/itemlikevisit.rs index 2221ecf07b434..a62000e10c79f 100644 --- a/src/librustc/hir/itemlikevisit.rs +++ b/src/librustc/hir/itemlikevisit.rs @@ -88,3 +88,33 @@ impl<'v, 'hir, V> ItemLikeVisitor<'hir> for DeepVisitor<'v, V> self.visitor.visit_impl_item(impl_item); } } + +/// A parallel variant of ItemLikeVisitor +pub trait ParItemLikeVisitor<'hir> { + fn visit_item(&self, item: &'hir Item); + fn visit_trait_item(&self, trait_item: &'hir TraitItem); + fn visit_impl_item(&self, impl_item: &'hir ImplItem); +} + +pub trait IntoVisitor<'hir> { + type Visitor: Visitor<'hir>; + fn into_visitor(&self) -> Self::Visitor; +} + +pub struct ParDeepVisitor(pub V); + +impl<'hir, V> ParItemLikeVisitor<'hir> for ParDeepVisitor + where V: IntoVisitor<'hir> +{ + fn visit_item(&self, item: &'hir Item) { + self.0.into_visitor().visit_item(item); + } + + fn visit_trait_item(&self, trait_item: &'hir TraitItem) { + self.0.into_visitor().visit_trait_item(trait_item); + } + + fn visit_impl_item(&self, impl_item: &'hir ImplItem) { + self.0.into_visitor().visit_impl_item(impl_item); + } +} diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 51f0c1d7047c9..7e2c5d03d6b24 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -41,23 +41,26 @@ //! in the HIR, especially for multiple identifiers. use dep_graph::DepGraph; -use hir; +use hir::{self, ParamName}; use hir::HirVec; use hir::map::{DefKey, DefPathData, Definitions}; use hir::def_id::{DefId, DefIndex, DefIndexAddressSpace, CRATE_DEF_INDEX}; -use hir::def::{Def, PathResolution}; -use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES}; +use hir::def::{Def, PathResolution, PerNS}; +use hir::GenericArg; +use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, + ELIDED_LIFETIMES_IN_PATHS}; use middle::cstore::CrateStore; use rustc_data_structures::indexed_vec::IndexVec; use session::Session; use util::common::FN_OUTPUT_NAME; -use util::nodemap::{DefIdMap, FxHashMap, NodeMap}; +use util::nodemap::{DefIdMap, NodeMap}; use std::collections::{BTreeMap, HashSet}; use std::fmt::Debug; use std::iter; use std::mem; use syntax::attr; +use syntax::ast; use syntax::ast::*; use syntax::errors; use syntax::ext::hygiene::{Mark, SyntaxContext}; @@ -70,7 +73,7 @@ use syntax::tokenstream::{Delimited, TokenStream, TokenTree}; use syntax::parse::token::Token; use syntax::util::small_vector::SmallVector; use syntax::visit::{self, Visitor}; -use syntax_pos::Span; +use syntax_pos::{Span, MultiSpan}; const HIR_ID_COUNTER_LOCKED: u32 = 0xFFFFFFFF; @@ -80,14 +83,9 @@ pub struct LoweringContext<'a> { // Use to assign ids to hir nodes that do not directly correspond to an ast node sess: &'a Session, - cstore: &'a CrateStore, + cstore: &'a dyn CrateStore, - // As we walk the AST we must keep track of the current 'parent' def id (in - // the form of a DefIndex) so that if we create a new node which introduces - // a definition, then we can properly create the def id. - parent_def: Option, - resolver: &'a mut Resolver, - name_map: FxHashMap, + resolver: &'a mut dyn Resolver, /// The items being lowered are collected here. items: BTreeMap, @@ -113,13 +111,6 @@ pub struct LoweringContext<'a> { /// written at all (e.g., `&T` or `std::cell::Ref`). anonymous_lifetime_mode: AnonymousLifetimeMode, - // This is a list of in-band type definitions being generated by - // Argument-position `impl Trait`. - // When traversing a signature such as `fn foo(x: impl Trait)`, - // we record `impl Trait` as a new type parameter, then later - // add it on to `foo`s generics. - in_band_ty_params: Vec, - // Used to create lifetime definitions from in-band lifetime usages. // e.g. `fn foo(x: &'x u8) -> &'x u8` to `fn foo<'x>(x: &'x u8) -> &'x u8` // When a named lifetime is encountered in a function or impl header and @@ -127,7 +118,7 @@ pub struct LoweringContext<'a> { // (i.e. it doesn't appear in the in_scope_lifetimes list), it is added // to this list. The results of this list are then added to the list of // lifetime definitions in the corresponding impl or function generics. - lifetimes_to_define: Vec<(Span, hir::LifetimeName)>, + lifetimes_to_define: Vec<(Span, ParamName)>, // Whether or not in-band lifetimes are being collected. This is used to // indicate whether or not we're in a place where new lifetimes will result @@ -140,7 +131,7 @@ pub struct LoweringContext<'a> { // When `is_collectin_in_band_lifetimes` is true, each lifetime is checked // against this list to see if it is already in-scope, or if a definition // needs to be created for it. - in_scope_lifetimes: Vec, + in_scope_lifetimes: Vec, type_def_lifetime_params: DefIdMap, @@ -156,6 +147,9 @@ pub trait Resolver { /// Obtain the resolution for a node id fn get_resolution(&mut self, id: NodeId) -> Option; + /// Obtain the possible resolutions for the given `use` statement. + fn get_import(&mut self, id: NodeId) -> PerNS>; + /// We must keep the set of definitions up to date as we add nodes that weren't in the AST. /// This should only return `None` during testing. fn definitions(&mut self) -> &mut Definitions; @@ -167,34 +161,48 @@ pub trait Resolver { span: Span, crate_root: Option<&str>, components: &[&str], + params: Option>, is_value: bool, ) -> hir::Path; } -#[derive(Clone, Copy, Debug)] -enum ImplTraitContext { +#[derive(Debug)] +enum ImplTraitContext<'a> { /// Treat `impl Trait` as shorthand for a new universal generic parameter. /// Example: `fn foo(x: impl Debug)`, where `impl Debug` is conceptually /// equivalent to a fresh universal parameter like `fn foo(x: T)`. /// - /// We store a DefId here so we can look up necessary information later - Universal(DefId), + /// Newly generated parameters should be inserted into the given `Vec` + Universal(&'a mut Vec), /// Treat `impl Trait` as shorthand for a new universal existential parameter. /// Example: `fn foo() -> impl Debug`, where `impl Debug` is conceptually /// equivalent to a fresh existential parameter like `abstract type T; fn foo() -> T`. - Existential, + /// + /// We store a DefId here so we can look up necessary information later + Existential(DefId), /// `impl Trait` is not accepted in this position. Disallowed, } +impl<'a> ImplTraitContext<'a> { + fn reborrow(&'b mut self) -> ImplTraitContext<'b> { + use self::ImplTraitContext::*; + match self { + Universal(params) => Universal(params), + Existential(did) => Existential(*did), + Disallowed => Disallowed, + } + } +} + pub fn lower_crate( sess: &Session, - cstore: &CrateStore, + cstore: &dyn CrateStore, dep_graph: &DepGraph, krate: &Crate, - resolver: &mut Resolver, + resolver: &mut dyn Resolver, ) -> hir::Crate { // We're constructing the HIR here; we don't care what we will // read, since we haven't even constructed the *input* to @@ -205,9 +213,7 @@ pub fn lower_crate( crate_root: std_inject::injected_crate_name(), sess, cstore, - parent_def: None, resolver, - name_map: FxHashMap(), items: BTreeMap::new(), trait_items: BTreeMap::new(), impl_items: BTreeMap::new(), @@ -225,14 +231,13 @@ pub fn lower_crate( node_id_to_hir_id: IndexVec::new(), is_generator: false, is_in_trait_impl: false, - in_band_ty_params: Vec::new(), lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, in_scope_lifetimes: Vec::new(), }.lower_crate(krate) } -#[derive(Copy, Clone, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq)] enum ParamMode { /// Any path in a type context. Explicit, @@ -240,6 +245,7 @@ enum ParamMode { Optional, } +#[derive(Debug)] struct LoweredNodeId { node_id: NodeId, hir_id: hir::HirId, @@ -316,12 +322,16 @@ impl<'a> LoweringContext<'a> { | ItemKind::Union(_, ref generics) | ItemKind::Enum(_, ref generics) | ItemKind::Ty(_, ref generics) + | ItemKind::Existential(_, ref generics) | ItemKind::Trait(_, _, ref generics, ..) => { let def_id = self.lctx.resolver.definitions().local_def_id(item.id); let count = generics .params .iter() - .filter(|param| param.is_lifetime_param()) + .filter(|param| match param.kind { + ast::GenericParamKind::Lifetime { .. } => true, + _ => false, + }) .count(); self.lctx.type_def_lifetime_params.insert(def_id, count); } @@ -373,25 +383,24 @@ impl<'a> LoweringContext<'a> { }); if item_lowered { - let item_lifetimes = match self.lctx.items.get(&item.id).unwrap().node { - hir::Item_::ItemImpl(_, _, _, ref generics, ..) - | hir::Item_::ItemTrait(_, _, ref generics, ..) => { - generics.lifetimes().cloned().collect::>() + let item_generics = match self.lctx.items.get(&item.id).unwrap().node { + hir::ItemKind::Impl(_, _, _, ref generics, ..) + | hir::ItemKind::Trait(_, _, ref generics, ..) => { + generics.params.clone() } - _ => Vec::new(), + _ => HirVec::new(), }; - self.lctx - .with_parent_impl_lifetime_defs(&item_lifetimes, |this| { - let this = &mut ItemLowerer { lctx: this }; - if let ItemKind::Impl(_, _, _, _, ref opt_trait_ref, _, _) = item.node { - this.with_trait_impl_ref(opt_trait_ref, |this| { - visit::walk_item(this, item) - }); - } else { - visit::walk_item(this, item); - } - }); + self.lctx.with_parent_impl_lifetime_defs(&item_generics, |this| { + let this = &mut ItemLowerer { lctx: this }; + if let ItemKind::Impl(_, _, _, _, ref opt_trait_ref, _, _) = item.node { + this.with_trait_impl_ref(opt_trait_ref, |this| { + visit::walk_item(this, item) + }); + } else { + visit::walk_item(this, item); + } + }); } } @@ -444,7 +453,7 @@ impl<'a> LoweringContext<'a> { } } - fn allocate_hir_id_counter(&mut self, owner: NodeId, debug: &T) { + fn allocate_hir_id_counter(&mut self, owner: NodeId, debug: &T) -> LoweredNodeId { if self.item_local_id_counters.insert(owner, 0).is_some() { bug!( "Tried to allocate item_local_id_counter for {:?} twice", @@ -452,7 +461,7 @@ impl<'a> LoweringContext<'a> { ); } // Always allocate the first HirId for the owner itself - self.lower_node_id_with_owner(owner, owner); + self.lower_node_id_with_owner(owner, owner) } fn lower_node_id_generic(&mut self, ast_node_id: NodeId, alloc_hir_id: F) -> LoweredNodeId @@ -490,16 +499,16 @@ impl<'a> LoweringContext<'a> { } } - fn with_hir_id_owner(&mut self, owner: NodeId, f: F) + fn with_hir_id_owner(&mut self, owner: NodeId, f: F) -> T where - F: FnOnce(&mut Self), + F: FnOnce(&mut Self) -> T, { let counter = self.item_local_id_counters .insert(owner, HIR_ID_COUNTER_LOCKED) - .unwrap(); + .unwrap_or_else(|| panic!("No item_local_id_counters entry for {:?}", owner)); let def_index = self.resolver.definitions().opt_def_index(owner).unwrap(); self.current_hir_id_owner.push((def_index, counter)); - f(self); + let ret = f(self); let (new_def_index, new_counter) = self.current_hir_id_owner.pop().unwrap(); debug_assert!(def_index == new_def_index); @@ -509,6 +518,7 @@ impl<'a> LoweringContext<'a> { .insert(owner, new_counter) .unwrap(); debug_assert!(prev == HIR_ID_COUNTER_LOCKED); + ret } /// This method allocates a new HirId for the given NodeId and stores it in @@ -532,7 +542,10 @@ impl<'a> LoweringContext<'a> { fn lower_node_id_with_owner(&mut self, ast_node_id: NodeId, owner: NodeId) -> LoweredNodeId { self.lower_node_id_generic(ast_node_id, |this| { - let local_id_counter = this.item_local_id_counters.get_mut(&owner).unwrap(); + let local_id_counter = this + .item_local_id_counters + .get_mut(&owner) + .expect("called lower_node_id_with_owner before allocate_hir_id_counter"); let local_id = *local_id_counter; // We want to be sure not to modify the counter in the map while it @@ -541,7 +554,12 @@ impl<'a> LoweringContext<'a> { debug_assert!(local_id != HIR_ID_COUNTER_LOCKED); *local_id_counter += 1; - let def_index = this.resolver.definitions().opt_def_index(owner).unwrap(); + let def_index = this + .resolver + .definitions() + .opt_def_index(owner) + .expect("You forgot to call `create_def_with_parent` or are lowering node ids \ + that do not belong to the current owner"); hir::HirId { owner: def_index, @@ -576,28 +594,49 @@ impl<'a> LoweringContext<'a> { }) } + fn expect_full_def_from_use(&mut self, id: NodeId) -> impl Iterator { + self.resolver.get_import(id).present_items().map(|pr| { + if pr.unresolved_segments() != 0 { + bug!("path not fully resolved: {:?}", pr); + } + pr.base_def() + }) + } + fn diagnostic(&self) -> &errors::Handler { self.sess.diagnostic() } - fn str_to_ident(&self, s: &'static str) -> Name { - Symbol::gensym(s) + fn str_to_ident(&self, s: &'static str) -> Ident { + Ident::with_empty_ctxt(Symbol::gensym(s)) } fn allow_internal_unstable(&self, reason: CompilerDesugaringKind, span: Span) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(codemap::ExpnInfo { call_site: span, - callee: codemap::NameAndSpan { - format: codemap::CompilerDesugaring(reason), - span: Some(span), - allow_internal_unstable: true, - allow_internal_unsafe: false, - }, + def_site: Some(span), + format: codemap::CompilerDesugaring(reason), + allow_internal_unstable: true, + allow_internal_unsafe: false, + local_inner_macros: false, + edition: codemap::hygiene::default_edition(), }); span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } + fn with_anonymous_lifetime_mode( + &mut self, + anonymous_lifetime_mode: AnonymousLifetimeMode, + op: impl FnOnce(&mut Self) -> R, + ) -> R { + let old_anonymous_lifetime_mode = self.anonymous_lifetime_mode; + self.anonymous_lifetime_mode = anonymous_lifetime_mode; + let result = op(self); + self.anonymous_lifetime_mode = old_anonymous_lifetime_mode; + result + } + /// Creates a new hir::GenericParam for every new lifetime and /// type parameter encountered while evaluating `f`. Definitions /// are created with the parent provided. If no `parent_id` is @@ -613,7 +652,7 @@ impl<'a> LoweringContext<'a> { f: F, ) -> (Vec, T) where - F: FnOnce(&mut LoweringContext) -> T, + F: FnOnce(&mut LoweringContext) -> (Vec, T), { assert!(!self.is_collecting_in_band_lifetimes); assert!(self.lifetimes_to_define.is_empty()); @@ -624,13 +663,11 @@ impl<'a> LoweringContext<'a> { self.anonymous_lifetime_mode = anonymous_lifetime_mode; } - assert!(self.in_band_ty_params.is_empty()); - let res = f(self); + let (in_band_ty_params, res) = f(self); self.is_collecting_in_band_lifetimes = false; self.anonymous_lifetime_mode = old_anonymous_lifetime_mode; - let in_band_ty_params = self.in_band_ty_params.split_off(0); let lifetimes_to_define = self.lifetimes_to_define.split_off(0); let params = lifetimes_to_define @@ -642,41 +679,31 @@ impl<'a> LoweringContext<'a> { // that collisions are ok here and this shouldn't // really show up for end-user. let str_name = match hir_name { - hir::LifetimeName::Name(n) => n.as_str(), - hir::LifetimeName::Fresh(_) => keywords::UnderscoreLifetime.name().as_str(), - hir::LifetimeName::Implicit - | hir::LifetimeName::Underscore - | hir::LifetimeName::Static => { - span_bug!(span, "unexpected in-band lifetime name: {:?}", hir_name) - } + ParamName::Plain(ident) => ident.as_interned_str(), + ParamName::Fresh(_) => keywords::UnderscoreLifetime.name().as_interned_str(), }; // Add a definition for the in-band lifetime def self.resolver.definitions().create_def_with_parent( parent_id.index, def_node_id, - DefPathData::LifetimeDef(str_name.as_interned_str()), + DefPathData::LifetimeParam(str_name), DefIndexAddressSpace::High, Mark::root(), span, ); - hir::GenericParam::Lifetime(hir::LifetimeDef { - lifetime: hir::Lifetime { - id: def_node_id, - span, - name: hir_name, - }, - bounds: Vec::new().into(), + hir::GenericParam { + id: def_node_id, + name: hir_name, + attrs: hir_vec![], + bounds: hir_vec![], + span, pure_wrt_drop: false, - in_band: true, - }) + kind: hir::GenericParamKind::Lifetime { in_band: true } + } }) - .chain( - in_band_ty_params - .into_iter() - .map(|tp| hir::GenericParam::Type(tp)), - ) + .chain(in_band_ty_params.into_iter()) .collect(); (params, res) @@ -686,51 +713,48 @@ impl<'a> LoweringContext<'a> { /// lifetimes are enabled, then we want to push that lifetime into /// the vector of names to define later. In that case, it will get /// added to the appropriate generics. - fn maybe_collect_in_band_lifetime(&mut self, span: Span, name: Name) { + fn maybe_collect_in_band_lifetime(&mut self, ident: Ident) { if !self.is_collecting_in_band_lifetimes { return; } - if self.in_scope_lifetimes.contains(&name) { + if self.in_scope_lifetimes.contains(&ident.modern()) { return; } - let hir_name = hir::LifetimeName::Name(name); + let hir_name = ParamName::Plain(ident); - if self.lifetimes_to_define - .iter() - .any(|(_, lt_name)| *lt_name == hir_name) - { + if self.lifetimes_to_define.iter() + .any(|(_, lt_name)| lt_name.modern() == hir_name.modern()) { return; } - self.lifetimes_to_define.push((span, hir_name)); + self.lifetimes_to_define.push((ident.span, hir_name)); } /// When we have either an elided or `'_` lifetime in an impl /// header, we convert it to - fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> hir::LifetimeName { + fn collect_fresh_in_band_lifetime(&mut self, span: Span) -> ParamName { assert!(self.is_collecting_in_band_lifetimes); let index = self.lifetimes_to_define.len(); - let hir_name = hir::LifetimeName::Fresh(index); + let hir_name = ParamName::Fresh(index); self.lifetimes_to_define.push((span, hir_name)); hir_name } - // Evaluates `f` with the lifetimes in `lt_defs` in-scope. + // Evaluates `f` with the lifetimes in `params` in-scope. // This is used to track which lifetimes have already been defined, and // which are new in-band lifetimes that need to have a definition created // for them. - fn with_in_scope_lifetime_defs<'l, T, F>( - &mut self, - lt_defs: impl Iterator, - f: F, - ) -> T + fn with_in_scope_lifetime_defs(&mut self, params: &[GenericParam], f: F) -> T where F: FnOnce(&mut LoweringContext) -> T, { let old_len = self.in_scope_lifetimes.len(); - let lt_def_names = lt_defs.map(|lt_def| lt_def.lifetime.ident.name); + let lt_def_names = params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some(param.ident.modern()), + _ => None, + }); self.in_scope_lifetimes.extend(lt_def_names); let res = f(self); @@ -739,17 +763,22 @@ impl<'a> LoweringContext<'a> { res } - // Same as the method above, but accepts `hir::LifetimeDef`s - // instead of `ast::LifetimeDef`s. + // Same as the method above, but accepts `hir::GenericParam`s + // instead of `ast::GenericParam`s. // This should only be used with generics that have already had their // in-band lifetimes added. In practice, this means that this function is // only used when lowering a child item of a trait or impl. - fn with_parent_impl_lifetime_defs(&mut self, lt_defs: &[hir::LifetimeDef], f: F) -> T - where + fn with_parent_impl_lifetime_defs(&mut self, + params: &HirVec, + f: F + ) -> T where F: FnOnce(&mut LoweringContext) -> T, { let old_len = self.in_scope_lifetimes.len(); - let lt_def_names = lt_defs.iter().map(|lt_def| lt_def.lifetime.name.name()); + let lt_def_names = params.iter().filter_map(|param| match param.kind { + hir::GenericParamKind::Lifetime { .. } => Some(param.name.ident().modern()), + _ => None, + }); self.in_scope_lifetimes.extend(lt_def_names); let res = f(self); @@ -772,17 +801,19 @@ impl<'a> LoweringContext<'a> { f: F, ) -> (hir::Generics, T) where - F: FnOnce(&mut LoweringContext) -> T, + F: FnOnce(&mut LoweringContext, &mut Vec) -> T, { let (in_band_defs, (mut lowered_generics, res)) = self.with_in_scope_lifetime_defs( - generics.params.iter().filter_map(|p| match p { - GenericParam::Lifetime(ld) => Some(ld), - _ => None, - }), + &generics.params, |this| { - let itctx = ImplTraitContext::Universal(parent_id); this.collect_in_band_defs(parent_id, anonymous_lifetime_mode, |this| { - (this.lower_generics(generics, itctx), f(this)) + let mut params = Vec::new(); + let generics = this.lower_generics( + generics, + ImplTraitContext::Universal(&mut params), + ); + let res = f(this, &mut params); + (params, (generics, res)) }) }, ); @@ -816,6 +847,46 @@ impl<'a> LoweringContext<'a> { result } + fn make_async_expr( + &mut self, + capture_clause: CaptureBy, + closure_node_id: NodeId, + ret_ty: Option<&Ty>, + body: impl FnOnce(&mut LoweringContext) -> hir::Expr, + ) -> hir::ExprKind { + let prev_is_generator = mem::replace(&mut self.is_generator, true); + let body_expr = body(self); + let span = body_expr.span; + let output = match ret_ty { + Some(ty) => FunctionRetTy::Ty(P(ty.clone())), + None => FunctionRetTy::Default(span), + }; + let decl = FnDecl { + inputs: vec![], + output, + variadic: false + }; + let body_id = self.record_body(body_expr, Some(&decl)); + self.is_generator = prev_is_generator; + + let capture_clause = self.lower_capture_clause(capture_clause); + let closure_hir_id = self.lower_node_id(closure_node_id).hir_id; + let decl = self.lower_fn_decl(&decl, None, /* impl trait allowed */ false, None); + let generator = hir::Expr { + id: closure_node_id, + hir_id: closure_hir_id, + node: hir::ExprKind::Closure(capture_clause, decl, body_id, span, + Some(hir::GeneratorMovability::Static)), + span, + attrs: ThinVec::new(), + }; + + let unstable_span = self.allow_internal_unstable(CompilerDesugaringKind::Async, span); + let gen_future = self.expr_std_path( + unstable_span, &["future", "from_generator"], None, ThinVec::new()); + hir::ExprKind::Call(P(gen_future), hir_vec![generator]) + } + fn lower_body(&mut self, decl: Option<&FnDecl>, f: F) -> hir::BodyId where F: FnOnce(&mut LoweringContext) -> hir::Expr, @@ -884,22 +955,6 @@ impl<'a> LoweringContext<'a> { result } - fn with_parent_def(&mut self, parent_id: NodeId, f: F) -> T - where - F: FnOnce(&mut LoweringContext) -> T, - { - let old_def = self.parent_def; - self.parent_def = { - let defs = self.resolver.definitions(); - Some(defs.opt_def_index(parent_id).unwrap()) - }; - - let result = f(self); - - self.parent_def = old_def; - result - } - fn def_key(&mut self, id: DefId) -> DefKey { if id.is_local() { self.resolver.definitions().def_key(id.index) @@ -908,51 +963,33 @@ impl<'a> LoweringContext<'a> { } } - fn lower_ident(&mut self, ident: Ident) -> Name { - let ident = ident.modern(); - if ident.span.ctxt() == SyntaxContext::empty() { - return ident.name; - } - *self.name_map - .entry(ident) - .or_insert_with(|| Symbol::from_ident(ident)) - } - fn lower_label(&mut self, label: Option, D}` - ItemEnum(EnumDef, Generics), + Enum(EnumDef, Generics), /// A struct definition, e.g. `struct Foo {x: A}` - ItemStruct(VariantData, Generics), + Struct(VariantData, Generics), /// A union definition, e.g. `union Foo {x: A, y: B}` - ItemUnion(VariantData, Generics), + Union(VariantData, Generics), /// Represents a Trait Declaration - ItemTrait(IsAuto, Unsafety, Generics, TyParamBounds, HirVec), + Trait(IsAuto, Unsafety, Generics, GenericBounds, HirVec), /// Represents a Trait Alias Declaration - ItemTraitAlias(Generics, TyParamBounds), + TraitAlias(Generics, GenericBounds), /// An implementation, eg `impl Trait for Foo { .. }` - ItemImpl(Unsafety, - ImplPolarity, - Defaultness, - Generics, - Option, // (optional) trait this impl implements - P, // self - HirVec), + Impl(Unsafety, + ImplPolarity, + Defaultness, + Generics, + Option, // (optional) trait this impl implements + P, // self + HirVec), } -impl Item_ { +impl ItemKind { pub fn descriptive_variant(&self) -> &str { match *self { - ItemExternCrate(..) => "extern crate", - ItemUse(..) => "use", - ItemStatic(..) => "static item", - ItemConst(..) => "constant item", - ItemFn(..) => "function", - ItemMod(..) => "module", - ItemForeignMod(..) => "foreign module", - ItemGlobalAsm(..) => "global asm", - ItemTy(..) => "type alias", - ItemEnum(..) => "enum", - ItemStruct(..) => "struct", - ItemUnion(..) => "union", - ItemTrait(..) => "trait", - ItemTraitAlias(..) => "trait alias", - ItemImpl(..) => "item", + ItemKind::ExternCrate(..) => "extern crate", + ItemKind::Use(..) => "use", + ItemKind::Static(..) => "static item", + ItemKind::Const(..) => "constant item", + ItemKind::Fn(..) => "function", + ItemKind::Mod(..) => "module", + ItemKind::ForeignMod(..) => "foreign module", + ItemKind::GlobalAsm(..) => "global asm", + ItemKind::Ty(..) => "type alias", + ItemKind::Existential(..) => "existential type", + ItemKind::Enum(..) => "enum", + ItemKind::Struct(..) => "struct", + ItemKind::Union(..) => "union", + ItemKind::Trait(..) => "trait", + ItemKind::TraitAlias(..) => "trait alias", + ItemKind::Impl(..) => "item", } } pub fn adt_kind(&self) -> Option { match *self { - ItemStruct(..) => Some(AdtKind::Struct), - ItemUnion(..) => Some(AdtKind::Union), - ItemEnum(..) => Some(AdtKind::Enum), + ItemKind::Struct(..) => Some(AdtKind::Struct), + ItemKind::Union(..) => Some(AdtKind::Union), + ItemKind::Enum(..) => Some(AdtKind::Enum), _ => None, } } pub fn generics(&self) -> Option<&Generics> { Some(match *self { - ItemFn(_, _, _, _, ref generics, _) | - ItemTy(_, ref generics) | - ItemEnum(_, ref generics) | - ItemStruct(_, ref generics) | - ItemUnion(_, ref generics) | - ItemTrait(_, _, ref generics, _, _) | - ItemImpl(_, _, _, ref generics, _, _, _)=> generics, + ItemKind::Fn(_, _, ref generics, _) | + ItemKind::Ty(_, ref generics) | + ItemKind::Existential(ExistTy { ref generics, impl_trait_fn: None, .. }) | + ItemKind::Enum(_, ref generics) | + ItemKind::Struct(_, ref generics) | + ItemKind::Union(_, ref generics) | + ItemKind::Trait(_, _, ref generics, _, _) | + ItemKind::Impl(_, _, _, ref generics, _, _, _)=> generics, _ => return None }) } @@ -2153,10 +2157,10 @@ impl Item_ { /// type or method, and whether it is public). This allows other /// passes to find the impl they want without loading the id (which /// means fewer edges in the incremental compilation graph). -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct TraitItemRef { pub id: TraitItemId, - pub name: Name, + pub ident: Ident, pub kind: AssociatedItemKind, pub span: Span, pub defaultness: Defaultness, @@ -2168,51 +2172,52 @@ pub struct TraitItemRef { /// type or method, and whether it is public). This allows other /// passes to find the impl they want without loading the id (which /// means fewer edges in the incremental compilation graph). -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ImplItemRef { pub id: ImplItemId, - pub name: Name, + pub ident: Ident, pub kind: AssociatedItemKind, pub span: Span, pub vis: Visibility, pub defaultness: Defaultness, } -#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, RustcEncodable, RustcDecodable, Debug)] pub enum AssociatedItemKind { Const, Method { has_self: bool }, Type, + Existential, } -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] pub struct ForeignItem { pub name: Name, pub attrs: HirVec, - pub node: ForeignItem_, + pub node: ForeignItemKind, pub id: NodeId, pub span: Span, pub vis: Visibility, } /// An item within an `extern` block -#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum ForeignItem_ { +#[derive(Clone, RustcEncodable, RustcDecodable, Debug)] +pub enum ForeignItemKind { /// A foreign function - ForeignItemFn(P, HirVec>, Generics), + Fn(P, HirVec, Generics), /// A foreign static item (`static ext: u8`), with optional mutability /// (the boolean is true when mutable) - ForeignItemStatic(P, bool), + Static(P, bool), /// A foreign type - ForeignItemType, + Type, } -impl ForeignItem_ { +impl ForeignItemKind { pub fn descriptive_variant(&self) -> &str { match *self { - ForeignItemFn(..) => "foreign function", - ForeignItemStatic(..) => "foreign static item", - ForeignItemType => "foreign type", + ForeignItemKind::Fn(..) => "foreign function", + ForeignItemKind::Static(..) => "foreign static item", + ForeignItemKind::Type => "foreign type", } } } @@ -2258,37 +2263,41 @@ pub fn provide(providers: &mut Providers) { providers.describe_def = map::describe_def; } -#[derive(Clone, RustcEncodable, RustcDecodable, Hash)] -pub struct TransFnAttrs { - pub flags: TransFnAttrFlags, +#[derive(Clone, RustcEncodable, RustcDecodable)] +pub struct CodegenFnAttrs { + pub flags: CodegenFnAttrFlags, pub inline: InlineAttr, pub export_name: Option, pub target_features: Vec, pub linkage: Option, + pub link_section: Option, } bitflags! { #[derive(RustcEncodable, RustcDecodable)] - pub struct TransFnAttrFlags: u8 { - const COLD = 0b0000_0001; - const ALLOCATOR = 0b0000_0010; - const UNWIND = 0b0000_0100; - const RUSTC_ALLOCATOR_NOUNWIND = 0b0000_1000; - const NAKED = 0b0001_0000; - const NO_MANGLE = 0b0010_0000; - const RUSTC_STD_INTERNAL_SYMBOL = 0b0100_0000; - const NO_DEBUG = 0b1000_0000; - } -} - -impl TransFnAttrs { - pub fn new() -> TransFnAttrs { - TransFnAttrs { - flags: TransFnAttrFlags::empty(), + pub struct CodegenFnAttrFlags: u32 { + const COLD = 1 << 0; + const ALLOCATOR = 1 << 1; + const UNWIND = 1 << 2; + const RUSTC_ALLOCATOR_NOUNWIND = 1 << 3; + const NAKED = 1 << 4; + const NO_MANGLE = 1 << 5; + const RUSTC_STD_INTERNAL_SYMBOL = 1 << 6; + const NO_DEBUG = 1 << 7; + const THREAD_LOCAL = 1 << 8; + const USED = 1 << 9; + } +} + +impl CodegenFnAttrs { + pub fn new() -> CodegenFnAttrs { + CodegenFnAttrs { + flags: CodegenFnAttrFlags::empty(), inline: InlineAttr::None, export_name: None, target_features: vec![], linkage: None, + link_section: None, } } @@ -2302,7 +2311,6 @@ impl TransFnAttrs { /// True if `#[no_mangle]` or `#[export_name(...)]` is present. pub fn contains_extern_indicator(&self) -> bool { - self.flags.contains(TransFnAttrFlags::NO_MANGLE) || self.export_name.is_some() + self.flags.contains(CodegenFnAttrFlags::NO_MANGLE) || self.export_name.is_some() } } - diff --git a/src/librustc/hir/pat_util.rs b/src/librustc/hir/pat_util.rs index 1f00a3ab1f5de..8a714a5fbd847 100644 --- a/src/librustc/hir/pat_util.rs +++ b/src/librustc/hir/pat_util.rs @@ -10,9 +10,8 @@ use hir::def::Def; use hir::def_id::DefId; -use hir::{self, PatKind}; +use hir::{self, HirId, PatKind}; use syntax::ast; -use syntax::codemap::Spanned; use syntax_pos::Span; use std::iter::{Enumerate, ExactSizeIterator}; @@ -48,7 +47,7 @@ impl EnumerateAndAdjustIterator for T { let actual_len = self.len(); EnumerateAndAdjust { enumerate: self.enumerate(), - gap_pos: if let Some(gap_pos) = gap_pos { gap_pos } else { expected_len }, + gap_pos: gap_pos.unwrap_or(expected_len), gap_len: expected_len - actual_len, } } @@ -91,11 +90,11 @@ impl hir::Pat { /// Call `f` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` pub fn each_binding(&self, mut f: F) - where F: FnMut(hir::BindingAnnotation, ast::NodeId, Span, &Spanned), + where F: FnMut(hir::BindingAnnotation, HirId, Span, ast::Ident), { self.walk(|p| { - if let PatKind::Binding(binding_mode, _, ref pth, _) = p.node { - f(binding_mode, p.id, p.span, pth); + if let PatKind::Binding(binding_mode, _, ident, _) = p.node { + f(binding_mode, p.hir_id, p.span, ident); } true }); @@ -132,11 +131,10 @@ impl hir::Pat { contains_bindings } - pub fn simple_name(&self) -> Option { + pub fn simple_ident(&self) -> Option { match self.node { - PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ref path1, None) | - PatKind::Binding(hir::BindingAnnotation::Mutable, _, ref path1, None) => - Some(path1.node), + PatKind::Binding(hir::BindingAnnotation::Unannotated, _, ident, None) | + PatKind::Binding(hir::BindingAnnotation::Mutable, _, ident, None) => Some(ident), _ => None, } } diff --git a/src/librustc/hir/print.rs b/src/librustc/hir/print.rs index 3943c30127d6f..4499a378be21a 100644 --- a/src/librustc/hir/print.rs +++ b/src/librustc/hir/print.rs @@ -13,7 +13,7 @@ pub use self::AnnNode::*; use rustc_target::spec::abi::Abi; use syntax::ast; use syntax::codemap::{CodeMap, Spanned}; -use syntax::parse::{token, ParseSess}; +use syntax::parse::ParseSess; use syntax::parse::lexer::comments; use syntax::print::pp::{self, Breaks}; use syntax::print::pp::Breaks::{Consistent, Inconsistent}; @@ -24,7 +24,8 @@ use syntax::util::parser::{self, AssocOp, Fixity}; use syntax_pos::{self, BytePos, FileName}; use hir; -use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier, RangeEnd}; +use hir::{PatKind, GenericBound, TraitBoundModifier, RangeEnd}; +use hir::{GenericParam, GenericParamKind, GenericArg}; use std::cell::Cell; use std::io::{self, Write, Read}; @@ -58,6 +59,9 @@ pub trait PpAnn { fn post(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> { Ok(()) } + fn try_fetch_item(&self, _: ast::NodeId) -> Option<&hir::Item> { + None + } } pub struct NoAnn; @@ -65,6 +69,9 @@ impl PpAnn for NoAnn {} pub const NO_ANN: &'static dyn PpAnn = &NoAnn; impl PpAnn for hir::Crate { + fn try_fetch_item(&self, item: ast::NodeId) -> Option<&hir::Item> { + Some(self.item(item)) + } fn nested(&self, state: &mut State, nested: Nested) -> io::Result<()> { match nested { Nested::Item(id) => state.print_item(self.item(id.id)), @@ -360,12 +367,12 @@ impl<'a> State<'a> { self.maybe_print_comment(ty.span.lo())?; self.ibox(0)?; match ty.node { - hir::TySlice(ref ty) => { + hir::TyKind::Slice(ref ty) => { self.s.word("[")?; self.print_type(&ty)?; self.s.word("]")?; } - hir::TyPtr(ref mt) => { + hir::TyKind::Ptr(ref mt) => { self.s.word("*")?; match mt.mutbl { hir::MutMutable => self.word_nbsp("mut")?, @@ -373,15 +380,15 @@ impl<'a> State<'a> { } self.print_type(&mt.ty)?; } - hir::TyRptr(ref lifetime, ref mt) => { + hir::TyKind::Rptr(ref lifetime, ref mt) => { self.s.word("&")?; self.print_opt_lifetime(lifetime)?; self.print_mt(mt)?; } - hir::TyNever => { + hir::TyKind::Never => { self.s.word("!")?; }, - hir::TyTup(ref elts) => { + hir::TyKind::Tup(ref elts) => { self.popen()?; self.commasep(Inconsistent, &elts[..], |s, ty| s.print_type(&ty))?; if elts.len() == 1 { @@ -389,14 +396,14 @@ impl<'a> State<'a> { } self.pclose()?; } - hir::TyBareFn(ref f) => { + hir::TyKind::BareFn(ref f) => { self.print_ty_fn(f.abi, f.unsafety, &f.decl, None, &f.generic_params, &f.arg_names[..])?; } - hir::TyPath(ref qpath) => { + hir::TyKind::Path(ref qpath) => { self.print_qpath(qpath, false)? } - hir::TyTraitObject(ref bounds, ref lifetime) => { + hir::TyKind::TraitObject(ref bounds, ref lifetime) => { let mut first = true; for bound in bounds { if first { @@ -413,25 +420,22 @@ impl<'a> State<'a> { self.print_lifetime(lifetime)?; } } - hir::TyImplTraitExistential(ref existty, ref _lifetimes) => { - self.print_bounds("impl", &existty.bounds[..])?; - } - hir::TyArray(ref ty, v) => { + hir::TyKind::Array(ref ty, ref length) => { self.s.word("[")?; self.print_type(&ty)?; self.s.word("; ")?; - self.ann.nested(self, Nested::Body(v))?; + self.print_anon_const(length)?; self.s.word("]")?; } - hir::TyTypeof(e) => { + hir::TyKind::Typeof(ref e) => { self.s.word("typeof(")?; - self.ann.nested(self, Nested::Body(e))?; + self.print_anon_const(e)?; self.s.word(")")?; } - hir::TyInfer => { + hir::TyKind::Infer => { self.s.word("_")?; } - hir::TyErr => { + hir::TyKind::Err => { self.s.word("?")?; } } @@ -443,12 +447,15 @@ impl<'a> State<'a> { self.maybe_print_comment(item.span.lo())?; self.print_outer_attributes(&item.attrs)?; match item.node { - hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => { + hir::ForeignItemKind::Fn(ref decl, ref arg_names, ref generics) => { self.head("")?; self.print_fn(decl, - hir::Unsafety::Normal, - hir::Constness::NotConst, - Abi::Rust, + hir::FnHeader { + unsafety: hir::Unsafety::Normal, + constness: hir::Constness::NotConst, + abi: Abi::Rust, + asyncness: hir::IsAsync::NotAsync, + }, Some(item.name), generics, &item.vis, @@ -458,7 +465,7 @@ impl<'a> State<'a> { self.s.word(";")?; self.end() // end the outer fn box } - hir::ForeignItemStatic(ref t, m) => { + hir::ForeignItemKind::Static(ref t, m) => { self.head(&visibility_qualified(&item.vis, "static"))?; if m { self.word_space("mut")?; @@ -470,7 +477,7 @@ impl<'a> State<'a> { self.end()?; // end the head-ibox self.end() // end the outer cbox } - hir::ForeignItemType => { + hir::ForeignItemKind::Type => { self.head(&visibility_qualified(&item.vis, "type"))?; self.print_name(item.name)?; self.s.word(";")?; @@ -481,14 +488,14 @@ impl<'a> State<'a> { } fn print_associated_const(&mut self, - name: ast::Name, + ident: ast::Ident, ty: &hir::Ty, default: Option, vis: &hir::Visibility) -> io::Result<()> { self.s.word(&visibility_qualified(vis, ""))?; self.word_space("const")?; - self.print_name(name)?; + self.print_ident(ident)?; self.word_space(":")?; self.print_type(ty)?; if let Some(expr) = default { @@ -500,12 +507,12 @@ impl<'a> State<'a> { } fn print_associated_type(&mut self, - name: ast::Name, - bounds: Option<&hir::TyParamBounds>, + ident: ast::Ident, + bounds: Option<&hir::GenericBounds>, ty: Option<&hir::Ty>) -> io::Result<()> { self.word_space("type")?; - self.print_name(name)?; + self.print_ident(ident)?; if let Some(bounds) = bounds { self.print_bounds(":", bounds)?; } @@ -524,7 +531,7 @@ impl<'a> State<'a> { self.print_outer_attributes(&item.attrs)?; self.ann.pre(self, NodeItem(item))?; match item.node { - hir::ItemExternCrate(orig_name) => { + hir::ItemKind::ExternCrate(orig_name) => { self.head(&visibility_qualified(&item.vis, "extern crate"))?; if let Some(orig_name) = orig_name { self.print_name(orig_name)?; @@ -537,13 +544,13 @@ impl<'a> State<'a> { self.end()?; // end inner head-block self.end()?; // end outer head-block } - hir::ItemUse(ref path, kind) => { + hir::ItemKind::Use(ref path, kind) => { self.head(&visibility_qualified(&item.vis, "use"))?; self.print_path(path, false)?; match kind { hir::UseKind::Single => { - if path.segments.last().unwrap().name != item.name { + if path.segments.last().unwrap().ident.name != item.name { self.s.space()?; self.word_space("as")?; self.print_name(item.name)?; @@ -556,7 +563,7 @@ impl<'a> State<'a> { self.end()?; // end inner head-block self.end()?; // end outer head-block } - hir::ItemStatic(ref ty, m, expr) => { + hir::ItemKind::Static(ref ty, m, expr) => { self.head(&visibility_qualified(&item.vis, "static"))?; if m == hir::MutMutable { self.word_space("mut")?; @@ -572,7 +579,7 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - hir::ItemConst(ref ty, expr) => { + hir::ItemKind::Const(ref ty, expr) => { self.head(&visibility_qualified(&item.vis, "const"))?; self.print_name(item.name)?; self.word_space(":")?; @@ -585,12 +592,10 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer cbox } - hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => { + hir::ItemKind::Fn(ref decl, header, ref typarams, body) => { self.head("")?; self.print_fn(decl, - unsafety, - constness, - abi, + header, Some(item.name), typarams, &item.vis, @@ -601,7 +606,7 @@ impl<'a> State<'a> { self.end()?; // need to close a box self.ann.nested(self, Nested::Body(body))?; } - hir::ItemMod(ref _mod) => { + hir::ItemKind::Mod(ref _mod) => { self.head(&visibility_qualified(&item.vis, "mod"))?; self.print_name(item.name)?; self.nbsp()?; @@ -609,22 +614,20 @@ impl<'a> State<'a> { self.print_mod(_mod, &item.attrs)?; self.bclose(item.span)?; } - hir::ItemForeignMod(ref nmod) => { + hir::ItemKind::ForeignMod(ref nmod) => { self.head("extern")?; self.word_nbsp(&nmod.abi.to_string())?; self.bopen()?; self.print_foreign_mod(nmod, &item.attrs)?; self.bclose(item.span)?; } - hir::ItemGlobalAsm(ref ga) => { + hir::ItemKind::GlobalAsm(ref ga) => { self.head(&visibility_qualified(&item.vis, "global asm"))?; self.s.word(&ga.asm.as_str())?; self.end()? } - hir::ItemTy(ref ty, ref generics) => { - self.ibox(indent_unit)?; - self.ibox(0)?; - self.word_nbsp(&visibility_qualified(&item.vis, "type"))?; + hir::ItemKind::Ty(ref ty, ref generics) => { + self.head(&visibility_qualified(&item.vis, "type"))?; self.print_name(item.name)?; self.print_generic_params(&generics.params)?; self.end()?; // end the inner ibox @@ -636,18 +639,41 @@ impl<'a> State<'a> { self.s.word(";")?; self.end()?; // end the outer ibox } - hir::ItemEnum(ref enum_definition, ref params) => { + hir::ItemKind::Existential(ref exist) => { + self.head(&visibility_qualified(&item.vis, "existential type"))?; + self.print_name(item.name)?; + self.print_generic_params(&exist.generics.params)?; + self.end()?; // end the inner ibox + + self.print_where_clause(&exist.generics.where_clause)?; + self.s.space()?; + self.word_space(":")?; + let mut real_bounds = Vec::with_capacity(exist.bounds.len()); + for b in exist.bounds.iter() { + if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b { + self.s.space()?; + self.word_space("for ?")?; + self.print_trait_ref(&ptr.trait_ref)?; + } else { + real_bounds.push(b.clone()); + } + } + self.print_bounds(":", &real_bounds[..])?; + self.s.word(";")?; + self.end()?; // end the outer ibox + } + hir::ItemKind::Enum(ref enum_definition, ref params) => { self.print_enum_def(enum_definition, params, item.name, item.span, &item.vis)?; } - hir::ItemStruct(ref struct_def, ref generics) => { + hir::ItemKind::Struct(ref struct_def, ref generics) => { self.head(&visibility_qualified(&item.vis, "struct"))?; self.print_struct(struct_def, generics, item.name, item.span, true)?; } - hir::ItemUnion(ref struct_def, ref generics) => { + hir::ItemKind::Union(ref struct_def, ref generics) => { self.head(&visibility_qualified(&item.vis, "union"))?; self.print_struct(struct_def, generics, item.name, item.span, true)?; } - hir::ItemImpl(unsafety, + hir::ItemKind::Impl(unsafety, polarity, defaultness, ref generics, @@ -692,7 +718,7 @@ impl<'a> State<'a> { } self.bclose(item.span)?; } - hir::ItemTrait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => { + hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref trait_items) => { self.head("")?; self.print_visibility(&item.vis)?; self.print_is_auto(is_auto)?; @@ -702,7 +728,7 @@ impl<'a> State<'a> { self.print_generic_params(&generics.params)?; let mut real_bounds = Vec::with_capacity(bounds.len()); for b in bounds.iter() { - if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b { + if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b { self.s.space()?; self.word_space("for ?")?; self.print_trait_ref(&ptr.trait_ref)?; @@ -719,7 +745,7 @@ impl<'a> State<'a> { } self.bclose(item.span)?; } - hir::ItemTraitAlias(ref generics, ref bounds) => { + hir::ItemKind::TraitAlias(ref generics, ref bounds) => { self.head("")?; self.print_visibility(&item.vis)?; self.word_nbsp("trait")?; @@ -728,7 +754,7 @@ impl<'a> State<'a> { let mut real_bounds = Vec::with_capacity(bounds.len()); // FIXME(durka) this seems to be some quite outdated syntax for b in bounds.iter() { - if let TraitTyParamBound(ref ptr, hir::TraitBoundModifier::Maybe) = *b { + if let GenericBound::Trait(ref ptr, hir::TraitBoundModifier::Maybe) = *b { self.s.space()?; self.word_space("for ?")?; self.print_trait_ref(&ptr.trait_ref)?; @@ -800,16 +826,27 @@ impl<'a> State<'a> { } pub fn print_visibility(&mut self, vis: &hir::Visibility) -> io::Result<()> { - match *vis { - hir::Public => self.word_nbsp("pub"), - hir::Visibility::Crate => self.word_nbsp("pub(crate)"), - hir::Visibility::Restricted { ref path, .. } => { + match vis.node { + hir::VisibilityKind::Public => self.word_nbsp("pub")?, + hir::VisibilityKind::Crate(ast::CrateSugar::JustCrate) => self.word_nbsp("crate")?, + hir::VisibilityKind::Crate(ast::CrateSugar::PubCrate) => self.word_nbsp("pub(crate)")?, + hir::VisibilityKind::Restricted { ref path, .. } => { self.s.word("pub(")?; - self.print_path(path, false)?; - self.word_nbsp(")") + if path.segments.len() == 1 && + path.segments[0].ident.name == keywords::Super.name() { + // Special case: `super` can print like `pub(super)`. + self.s.word("super")?; + } else { + // Everything else requires `in` at present. + self.word_nbsp("in")?; + self.print_path(path, false)?; + } + self.word_nbsp(")")?; } - hir::Inherited => Ok(()), + hir::VisibilityKind::Inherited => () } + + Ok(()) } pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) -> io::Result<()> { @@ -857,7 +894,7 @@ impl<'a> State<'a> { self.maybe_print_comment(field.span.lo())?; self.print_outer_attributes(&field.attrs)?; self.print_visibility(&field.vis)?; - self.print_name(field.name)?; + self.print_ident(field.ident)?; self.word_nbsp(":")?; self.print_type(&field.ty)?; self.s.word(",")?; @@ -871,26 +908,24 @@ impl<'a> State<'a> { self.head("")?; let generics = hir::Generics::empty(); self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?; - if let Some(d) = v.node.disr_expr { + if let Some(ref d) = v.node.disr_expr { self.s.space()?; self.word_space("=")?; - self.ann.nested(self, Nested::Body(d))?; + self.print_anon_const(d)?; } Ok(()) } pub fn print_method_sig(&mut self, - name: ast::Name, + ident: ast::Ident, m: &hir::MethodSig, generics: &hir::Generics, vis: &hir::Visibility, - arg_names: &[Spanned], + arg_names: &[ast::Ident], body_id: Option) -> io::Result<()> { self.print_fn(&m.decl, - m.unsafety, - m.constness, - m.abi, - Some(name), + m.header, + Some(ident.name), generics, vis, arg_names, @@ -904,24 +939,28 @@ impl<'a> State<'a> { self.print_outer_attributes(&ti.attrs)?; match ti.node { hir::TraitItemKind::Const(ref ty, default) => { - self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?; + let vis = Spanned { span: syntax_pos::DUMMY_SP, + node: hir::VisibilityKind::Inherited }; + self.print_associated_const(ti.ident, &ty, default, &vis)?; } hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => { - self.print_method_sig(ti.name, sig, &ti.generics, &hir::Inherited, arg_names, - None)?; + let vis = Spanned { span: syntax_pos::DUMMY_SP, + node: hir::VisibilityKind::Inherited }; + self.print_method_sig(ti.ident, sig, &ti.generics, &vis, arg_names, None)?; self.s.word(";")?; } hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => { + let vis = Spanned { span: syntax_pos::DUMMY_SP, + node: hir::VisibilityKind::Inherited }; self.head("")?; - self.print_method_sig(ti.name, sig, &ti.generics, &hir::Inherited, &[], - Some(body))?; + self.print_method_sig(ti.ident, sig, &ti.generics, &vis, &[], Some(body))?; self.nbsp()?; self.end()?; // need to close a box self.end()?; // need to close a box self.ann.nested(self, Nested::Body(body))?; } hir::TraitItemKind::Type(ref bounds, ref default) => { - self.print_associated_type(ti.name, + self.print_associated_type(ti.ident, Some(bounds), default.as_ref().map(|ty| &**ty))?; } @@ -938,18 +977,22 @@ impl<'a> State<'a> { match ii.node { hir::ImplItemKind::Const(ref ty, expr) => { - self.print_associated_const(ii.name, &ty, Some(expr), &ii.vis)?; + self.print_associated_const(ii.ident, &ty, Some(expr), &ii.vis)?; } hir::ImplItemKind::Method(ref sig, body) => { self.head("")?; - self.print_method_sig(ii.name, sig, &ii.generics, &ii.vis, &[], Some(body))?; + self.print_method_sig(ii.ident, sig, &ii.generics, &ii.vis, &[], Some(body))?; self.nbsp()?; self.end()?; // need to close a box self.end()?; // need to close a box self.ann.nested(self, Nested::Body(body))?; } hir::ImplItemKind::Type(ref ty) => { - self.print_associated_type(ii.name, None, Some(ty))?; + self.print_associated_type(ii.ident, None, Some(ty))?; + } + hir::ImplItemKind::Existential(ref bounds) => { + self.word_space("existential")?; + self.print_associated_type(ii.ident, Some(bounds), None)?; } } self.ann.post(self, NodeSubItem(ii.id)) @@ -958,14 +1001,14 @@ impl<'a> State<'a> { pub fn print_stmt(&mut self, st: &hir::Stmt) -> io::Result<()> { self.maybe_print_comment(st.span.lo())?; match st.node { - hir::StmtDecl(ref decl, _) => { + hir::StmtKind::Decl(ref decl, _) => { self.print_decl(&decl)?; } - hir::StmtExpr(ref expr, _) => { + hir::StmtKind::Expr(ref expr, _) => { self.space_if_not_bol()?; self.print_expr(&expr)?; } - hir::StmtSemi(ref expr, _) => { + hir::StmtKind::Semi(ref expr, _) => { self.space_if_not_bol()?; self.print_expr(&expr)?; self.s.word(";")?; @@ -1037,7 +1080,7 @@ impl<'a> State<'a> { Some(_else) => { match _else.node { // "another else-if" - hir::ExprIf(ref i, ref then, ref e) => { + hir::ExprKind::If(ref i, ref then, ref e) => { self.cbox(indent_unit - 1)?; self.ibox(0)?; self.s.word(" else if ")?; @@ -1047,7 +1090,7 @@ impl<'a> State<'a> { self.print_else(e.as_ref().map(|e| &**e)) } // "final else" - hir::ExprBlock(ref b) => { + hir::ExprKind::Block(ref b, _) => { self.cbox(indent_unit - 1)?; self.ibox(0)?; self.s.word(" else ")?; @@ -1091,6 +1134,9 @@ impl<'a> State<'a> { self.print_else(elseopt) } + pub fn print_anon_const(&mut self, constant: &hir::AnonConst) -> io::Result<()> { + self.ann.nested(self, Nested::Body(constant.body)) + } fn print_call_post(&mut self, args: &[hir::Expr]) -> io::Result<()> { self.popen()?; @@ -1116,9 +1162,9 @@ impl<'a> State<'a> { let needs_par = match expr.node { // These cases need parens due to the parse error observed in #26461: `if return {}` // parses as the erroneous construct `if (return {})`, not `if (return) {}`. - hir::ExprClosure(..) | - hir::ExprRet(..) | - hir::ExprBreak(..) => true, + hir::ExprKind::Closure(..) | + hir::ExprKind::Ret(..) | + hir::ExprKind::Break(..) => true, _ => contains_exterior_struct_lit(expr), }; @@ -1141,12 +1187,12 @@ impl<'a> State<'a> { self.end() } - fn print_expr_repeat(&mut self, element: &hir::Expr, count: hir::BodyId) -> io::Result<()> { + fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::AnonConst) -> io::Result<()> { self.ibox(indent_unit)?; self.s.word("[")?; self.print_expr(element)?; self.word_space(";")?; - self.ann.nested(self, Nested::Body(count))?; + self.print_anon_const(count)?; self.s.word("]")?; self.end() } @@ -1163,7 +1209,7 @@ impl<'a> State<'a> { |s, field| { s.ibox(indent_unit)?; if !field.is_shorthand { - s.print_name(field.name.node)?; + s.print_ident(field.ident)?; s.word_space(":")?; } s.print_expr(&field.expr)?; @@ -1201,7 +1247,7 @@ impl<'a> State<'a> { fn print_expr_call(&mut self, func: &hir::Expr, args: &[hir::Expr]) -> io::Result<()> { let prec = match func.node { - hir::ExprField(..) => parser::PREC_FORCE_PAREN, + hir::ExprKind::Field(..) => parser::PREC_FORCE_PAREN, _ => parser::PREC_POSTFIX, }; @@ -1216,17 +1262,13 @@ impl<'a> State<'a> { let base_args = &args[1..]; self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX)?; self.s.word(".")?; - self.print_name(segment.name)?; - - segment.with_parameters(|parameters| { - if !parameters.lifetimes.is_empty() || - !parameters.types.is_empty() || - !parameters.bindings.is_empty() - { - self.print_path_parameters(¶meters, segment.infer_types, true) - } else { - Ok(()) + self.print_ident(segment.ident)?; + + segment.with_generic_args(|generic_args| { + if !generic_args.args.is_empty() || !generic_args.bindings.is_empty() { + return self.print_generic_args(&generic_args, segment.infer_types, true); } + Ok(()) })?; self.print_call_post(base_args) } @@ -1250,8 +1292,8 @@ impl<'a> State<'a> { // These cases need parens: `x as i32 < y` has the parser thinking that `i32 < y` is // the beginning of a path type. It starts trying to parse `x as (i32 < y ...` instead // of `(x as i32) < ...`. We need to convince it _not_ to do that. - (&hir::ExprCast { .. }, hir::BinOp_::BiLt) | - (&hir::ExprCast { .. }, hir::BinOp_::BiShl) => parser::PREC_FORCE_PAREN, + (&hir::ExprKind::Cast { .. }, hir::BinOpKind::Lt) | + (&hir::ExprKind::Cast { .. }, hir::BinOpKind::Shl) => parser::PREC_FORCE_PAREN, _ => left_prec, }; @@ -1281,59 +1323,59 @@ impl<'a> State<'a> { self.ibox(indent_unit)?; self.ann.pre(self, NodeExpr(expr))?; match expr.node { - hir::ExprBox(ref expr) => { + hir::ExprKind::Box(ref expr) => { self.word_space("box")?; self.print_expr_maybe_paren(expr, parser::PREC_PREFIX)?; } - hir::ExprArray(ref exprs) => { + hir::ExprKind::Array(ref exprs) => { self.print_expr_vec(exprs)?; } - hir::ExprRepeat(ref element, count) => { + hir::ExprKind::Repeat(ref element, ref count) => { self.print_expr_repeat(&element, count)?; } - hir::ExprStruct(ref qpath, ref fields, ref wth) => { + hir::ExprKind::Struct(ref qpath, ref fields, ref wth) => { self.print_expr_struct(qpath, &fields[..], wth)?; } - hir::ExprTup(ref exprs) => { + hir::ExprKind::Tup(ref exprs) => { self.print_expr_tup(exprs)?; } - hir::ExprCall(ref func, ref args) => { + hir::ExprKind::Call(ref func, ref args) => { self.print_expr_call(&func, args)?; } - hir::ExprMethodCall(ref segment, _, ref args) => { + hir::ExprKind::MethodCall(ref segment, _, ref args) => { self.print_expr_method_call(segment, args)?; } - hir::ExprBinary(op, ref lhs, ref rhs) => { + hir::ExprKind::Binary(op, ref lhs, ref rhs) => { self.print_expr_binary(op, &lhs, &rhs)?; } - hir::ExprUnary(op, ref expr) => { + hir::ExprKind::Unary(op, ref expr) => { self.print_expr_unary(op, &expr)?; } - hir::ExprAddrOf(m, ref expr) => { + hir::ExprKind::AddrOf(m, ref expr) => { self.print_expr_addr_of(m, &expr)?; } - hir::ExprLit(ref lit) => { + hir::ExprKind::Lit(ref lit) => { self.print_literal(&lit)?; } - hir::ExprCast(ref expr, ref ty) => { + hir::ExprKind::Cast(ref expr, ref ty) => { let prec = AssocOp::As.precedence() as i8; self.print_expr_maybe_paren(&expr, prec)?; self.s.space()?; self.word_space("as")?; self.print_type(&ty)?; } - hir::ExprType(ref expr, ref ty) => { + hir::ExprKind::Type(ref expr, ref ty) => { let prec = AssocOp::Colon.precedence() as i8; self.print_expr_maybe_paren(&expr, prec)?; self.word_space(":")?; self.print_type(&ty)?; } - hir::ExprIf(ref test, ref blk, ref elseopt) => { + hir::ExprKind::If(ref test, ref blk, ref elseopt) => { self.print_if(&test, &blk, elseopt.as_ref().map(|e| &**e))?; } - hir::ExprWhile(ref test, ref blk, opt_label) => { + hir::ExprKind::While(ref test, ref blk, opt_label) => { if let Some(label) = opt_label { - self.print_name(label.name)?; + self.print_ident(label.ident)?; self.word_space(":")?; } self.head("while")?; @@ -1341,16 +1383,16 @@ impl<'a> State<'a> { self.s.space()?; self.print_block(&blk)?; } - hir::ExprLoop(ref blk, opt_label, _) => { + hir::ExprKind::Loop(ref blk, opt_label, _) => { if let Some(label) = opt_label { - self.print_name(label.name)?; + self.print_ident(label.ident)?; self.word_space(":")?; } self.head("loop")?; self.s.space()?; self.print_block(&blk)?; } - hir::ExprMatch(ref expr, ref arms, _) => { + hir::ExprKind::Match(ref expr, ref arms, _) => { self.cbox(indent_unit)?; self.ibox(4)?; self.word_nbsp("match")?; @@ -1362,7 +1404,7 @@ impl<'a> State<'a> { } self.bclose_(expr.span, indent_unit)?; } - hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span, _gen) => { + hir::ExprKind::Closure(capture_clause, ref decl, body, _fn_decl_span, _gen) => { self.print_capture_clause(capture_clause)?; self.print_closure_args(&decl, body)?; @@ -1377,21 +1419,25 @@ impl<'a> State<'a> { // empty box to satisfy the close. self.ibox(0)?; } - hir::ExprBlock(ref blk) => { + hir::ExprKind::Block(ref blk, opt_label) => { + if let Some(label) = opt_label { + self.print_ident(label.ident)?; + self.word_space(":")?; + } // containing cbox, will be closed by print-block at } self.cbox(indent_unit)?; // head-box, will be closed by print-block after { self.ibox(0)?; self.print_block(&blk)?; } - hir::ExprAssign(ref lhs, ref rhs) => { + hir::ExprKind::Assign(ref lhs, ref rhs) => { let prec = AssocOp::Assign.precedence() as i8; self.print_expr_maybe_paren(&lhs, prec + 1)?; self.s.space()?; self.word_space("=")?; self.print_expr_maybe_paren(&rhs, prec)?; } - hir::ExprAssignOp(op, ref lhs, ref rhs) => { + hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => { let prec = AssocOp::Assign.precedence() as i8; self.print_expr_maybe_paren(&lhs, prec + 1)?; self.s.space()?; @@ -1399,25 +1445,25 @@ impl<'a> State<'a> { self.word_space("=")?; self.print_expr_maybe_paren(&rhs, prec)?; } - hir::ExprField(ref expr, name) => { + hir::ExprKind::Field(ref expr, ident) => { self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX)?; self.s.word(".")?; - self.print_name(name.node)?; + self.print_ident(ident)?; } - hir::ExprIndex(ref expr, ref index) => { + hir::ExprKind::Index(ref expr, ref index) => { self.print_expr_maybe_paren(&expr, parser::PREC_POSTFIX)?; self.s.word("[")?; self.print_expr(&index)?; self.s.word("]")?; } - hir::ExprPath(ref qpath) => { + hir::ExprKind::Path(ref qpath) => { self.print_qpath(qpath, true)? } - hir::ExprBreak(destination, ref opt_expr) => { + hir::ExprKind::Break(destination, ref opt_expr) => { self.s.word("break")?; self.s.space()?; if let Some(label) = destination.label { - self.print_name(label.name)?; + self.print_ident(label.ident)?; self.s.space()?; } if let Some(ref expr) = *opt_expr { @@ -1425,15 +1471,15 @@ impl<'a> State<'a> { self.s.space()?; } } - hir::ExprAgain(destination) => { + hir::ExprKind::Continue(destination) => { self.s.word("continue")?; self.s.space()?; if let Some(label) = destination.label { - self.print_name(label.name)?; + self.print_ident(label.ident)?; self.s.space()? } } - hir::ExprRet(ref result) => { + hir::ExprKind::Ret(ref result) => { self.s.word("return")?; match *result { Some(ref expr) => { @@ -1443,7 +1489,7 @@ impl<'a> State<'a> { _ => (), } } - hir::ExprInlineAsm(ref a, ref outputs, ref inputs) => { + hir::ExprKind::InlineAsm(ref a, ref outputs, ref inputs) => { self.s.word("asm!")?; self.popen()?; self.print_string(&a.asm.as_str(), a.asm_str_style)?; @@ -1508,7 +1554,7 @@ impl<'a> State<'a> { self.pclose()?; } - hir::ExprYield(ref expr) => { + hir::ExprKind::Yield(ref expr) => { self.word_space("yield")?; self.print_expr_maybe_paren(&expr, parser::PREC_JUMP)?; } @@ -1529,7 +1575,7 @@ impl<'a> State<'a> { pub fn print_decl(&mut self, decl: &hir::Decl) -> io::Result<()> { self.maybe_print_comment(decl.span.lo())?; match decl.node { - hir::DeclLocal(ref loc) => { + hir::DeclKind::Local(ref loc) => { self.space_if_not_bol()?; self.ibox(indent_unit)?; self.word_nbsp("let")?; @@ -1544,7 +1590,7 @@ impl<'a> State<'a> { } self.end() } - hir::DeclItem(item) => { + hir::DeclKind::Item(item) => { self.ann.nested(self, Nested::Item(item)) } } @@ -1554,13 +1600,17 @@ impl<'a> State<'a> { self.s.word(&i.to_string()) } - pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> { - if token::is_raw_guess(ast::Ident::with_empty_ctxt(name)) { - self.s.word(&format!("r#{}", name))?; + pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> { + if ident.is_raw_guess() { + self.s.word(&format!("r#{}", ident.name))?; } else { - self.s.word(&name.as_str())?; + self.s.word(&ident.as_str())?; } - self.ann.post(self, NodeName(&name)) + self.ann.post(self, NodeName(&ident.name)) + } + + pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> { + self.print_ident(ast::Ident::with_empty_ctxt(name)) } pub fn print_for_decl(&mut self, loc: &hir::Local, coll: &hir::Expr) -> io::Result<()> { @@ -1580,13 +1630,12 @@ impl<'a> State<'a> { if i > 0 { self.s.word("::")? } - if segment.name != keywords::CrateRoot.name() && - segment.name != keywords::DollarCrate.name() { - self.print_name(segment.name)?; - segment.with_parameters(|parameters| { - self.print_path_parameters(parameters, - segment.infer_types, - colons_before_params) + if segment.ident.name != keywords::CrateRoot.name() && + segment.ident.name != keywords::DollarCrate.name() { + self.print_ident(segment.ident)?; + segment.with_generic_args(|generic_args| { + self.print_generic_args(generic_args, segment.infer_types, + colons_before_params) })?; } } @@ -1612,13 +1661,13 @@ impl<'a> State<'a> { if i > 0 { self.s.word("::")? } - if segment.name != keywords::CrateRoot.name() && - segment.name != keywords::DollarCrate.name() { - self.print_name(segment.name)?; - segment.with_parameters(|parameters| { - self.print_path_parameters(parameters, - segment.infer_types, - colons_before_params) + if segment.ident.name != keywords::CrateRoot.name() && + segment.ident.name != keywords::DollarCrate.name() { + self.print_ident(segment.ident)?; + segment.with_generic_args(|generic_args| { + self.print_generic_args(generic_args, + segment.infer_types, + colons_before_params) })?; } } @@ -1626,11 +1675,11 @@ impl<'a> State<'a> { self.s.word(">")?; self.s.word("::")?; let item_segment = path.segments.last().unwrap(); - self.print_name(item_segment.name)?; - item_segment.with_parameters(|parameters| { - self.print_path_parameters(parameters, - item_segment.infer_types, - colons_before_params) + self.print_ident(item_segment.ident)?; + item_segment.with_generic_args(|generic_args| { + self.print_generic_args(generic_args, + item_segment.infer_types, + colons_before_params) }) } hir::QPath::TypeRelative(ref qself, ref item_segment) => { @@ -1638,29 +1687,29 @@ impl<'a> State<'a> { self.print_type(qself)?; self.s.word(">")?; self.s.word("::")?; - self.print_name(item_segment.name)?; - item_segment.with_parameters(|parameters| { - self.print_path_parameters(parameters, - item_segment.infer_types, - colons_before_params) + self.print_ident(item_segment.ident)?; + item_segment.with_generic_args(|generic_args| { + self.print_generic_args(generic_args, + item_segment.infer_types, + colons_before_params) }) } } } - fn print_path_parameters(&mut self, - parameters: &hir::PathParameters, + fn print_generic_args(&mut self, + generic_args: &hir::GenericArgs, infer_types: bool, colons_before_params: bool) -> io::Result<()> { - if parameters.parenthesized { + if generic_args.parenthesized { self.s.word("(")?; - self.commasep(Inconsistent, parameters.inputs(), |s, ty| s.print_type(&ty))?; + self.commasep(Inconsistent, generic_args.inputs(), |s, ty| s.print_type(&ty))?; self.s.word(")")?; self.space_if_not_bol()?; self.word_space("->")?; - self.print_type(¶meters.bindings[0].ty)?; + self.print_type(&generic_args.bindings[0].ty)?; } else { let start = if colons_before_params { "::<" } else { "<" }; let empty = Cell::new(true); @@ -1673,16 +1722,31 @@ impl<'a> State<'a> { } }; - if !parameters.lifetimes.iter().all(|lt| lt.is_elided()) { - for lifetime in ¶meters.lifetimes { - start_or_comma(self)?; - self.print_lifetime(lifetime)?; + let mut types = vec![]; + let mut elide_lifetimes = true; + for arg in &generic_args.args { + match arg { + GenericArg::Lifetime(lt) => { + if !lt.is_elided() { + elide_lifetimes = false; + } + } + GenericArg::Type(ty) => { + types.push(ty); + } } } - - if !parameters.types.is_empty() { + if !elide_lifetimes { start_or_comma(self)?; - self.commasep(Inconsistent, ¶meters.types, |s, ty| s.print_type(&ty))?; + self.commasep(Inconsistent, &generic_args.args, |s, generic_arg| { + match generic_arg { + GenericArg::Lifetime(lt) => s.print_lifetime(lt), + GenericArg::Type(ty) => s.print_type(ty), + } + })?; + } else if !types.is_empty() { + start_or_comma(self)?; + self.commasep(Inconsistent, &types, |s, ty| s.print_type(&ty))?; } // FIXME(eddyb) This would leak into error messages, e.g.: @@ -1692,9 +1756,9 @@ impl<'a> State<'a> { self.s.word("..")?; } - for binding in parameters.bindings.iter() { + for binding in generic_args.bindings.iter() { start_or_comma(self)?; - self.print_name(binding.name)?; + self.print_ident(binding.ident)?; self.s.space()?; self.word_space("=")?; self.print_type(&binding.ty)?; @@ -1715,7 +1779,7 @@ impl<'a> State<'a> { // is that it doesn't matter match pat.node { PatKind::Wild => self.s.word("_")?, - PatKind::Binding(binding_mode, _, ref path1, ref sub) => { + PatKind::Binding(binding_mode, _, ident, ref sub) => { match binding_mode { hir::BindingAnnotation::Ref => { self.word_nbsp("ref")?; @@ -1730,7 +1794,7 @@ impl<'a> State<'a> { self.word_nbsp("mut")?; } } - self.print_name(path1.node)?; + self.print_ident(ident)?; if let Some(ref p) = *sub { self.s.word("@")?; self.print_pat(&p)?; @@ -1766,7 +1830,7 @@ impl<'a> State<'a> { |s, f| { s.cbox(indent_unit)?; if !f.node.is_shorthand { - s.print_name(f.node.name)?; + s.print_ident(f.node.ident)?; s.word_nbsp(":")?; } s.print_pat(&f.node.pat)?; @@ -1850,7 +1914,9 @@ impl<'a> State<'a> { if !before.is_empty() { self.word_space(",")?; } - if p.node != PatKind::Wild { + if let PatKind::Wild = p.node { + // Print nothing + } else { self.print_pat(&p)?; } self.s.word("..")?; @@ -1893,7 +1959,11 @@ impl<'a> State<'a> { self.word_space("=>")?; match arm.body.node { - hir::ExprBlock(ref blk) => { + hir::ExprKind::Block(ref blk, opt_label) => { + if let Some(label) = opt_label { + self.print_ident(label.ident)?; + self.word_space(":")?; + } // the block will close the pattern's ibox self.print_block_unclosed_indent(&blk, indent_unit)?; @@ -1913,16 +1983,14 @@ impl<'a> State<'a> { pub fn print_fn(&mut self, decl: &hir::FnDecl, - unsafety: hir::Unsafety, - constness: hir::Constness, - abi: Abi, + header: hir::FnHeader, name: Option, generics: &hir::Generics, vis: &hir::Visibility, - arg_names: &[Spanned], + arg_names: &[ast::Ident], body_id: Option) -> io::Result<()> { - self.print_fn_header_info(unsafety, constness, abi, vis)?; + self.print_fn_header_info(header, vis)?; if let Some(name) = name { self.nbsp()?; @@ -1936,8 +2004,8 @@ impl<'a> State<'a> { assert!(arg_names.is_empty() || body_id.is_none()); self.commasep(Inconsistent, &decl.inputs, |s, ty| { s.ibox(indent_unit)?; - if let Some(name) = arg_names.get(i) { - s.s.word(&name.node.as_str())?; + if let Some(arg_name) = arg_names.get(i) { + s.s.word(&arg_name.as_str())?; s.s.word(":")?; s.s.space()?; } else if let Some(body_id) = body_id { @@ -1967,7 +2035,9 @@ impl<'a> State<'a> { s.ann.nested(s, Nested::BodyArgPat(body_id, i))?; i += 1; - if ty.node != hir::TyInfer { + if let hir::TyKind::Infer = ty.node { + // Print nothing + } else { s.s.word(":")?; s.s.space()?; s.print_type(ty)?; @@ -1998,7 +2068,7 @@ impl<'a> State<'a> { } } - pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::TyParamBound]) -> io::Result<()> { + pub fn print_bounds(&mut self, prefix: &str, bounds: &[hir::GenericBound]) -> io::Result<()> { if !bounds.is_empty() { self.s.word(prefix)?; let mut first = true; @@ -2013,13 +2083,13 @@ impl<'a> State<'a> { } match bound { - TraitTyParamBound(tref, modifier) => { + GenericBound::Trait(tref, modifier) => { if modifier == &TraitBoundModifier::Maybe { self.s.word("?")?; } self.print_poly_trait_ref(tref)?; } - RegionTyParamBound(lt) => { + GenericBound::Outlives(lt) => { self.print_lifetime(lt)?; } } @@ -2028,30 +2098,12 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> { - self.print_name(lifetime.name.name()) - } - - pub fn print_lifetime_def(&mut self, lifetime: &hir::LifetimeDef) -> io::Result<()> { - self.print_lifetime(&lifetime.lifetime)?; - let mut sep = ":"; - for v in &lifetime.bounds { - self.s.word(sep)?; - self.print_lifetime(v)?; - sep = "+"; - } - Ok(()) - } - - pub fn print_generic_params(&mut self, generic_params: &[hir::GenericParam]) -> io::Result<()> { + pub fn print_generic_params(&mut self, generic_params: &[GenericParam]) -> io::Result<()> { if !generic_params.is_empty() { self.s.word("<")?; self.commasep(Inconsistent, generic_params, |s, param| { - match *param { - hir::GenericParam::Lifetime(ref ld) => s.print_lifetime_def(ld), - hir::GenericParam::Type(ref tp) => s.print_ty_param(tp), - } + s.print_generic_param(param) })?; self.s.word(">")?; @@ -2059,19 +2111,41 @@ impl<'a> State<'a> { Ok(()) } - pub fn print_ty_param(&mut self, param: &hir::TyParam) -> io::Result<()> { - self.print_name(param.name)?; - self.print_bounds(":", ¶m.bounds)?; - match param.default { - Some(ref default) => { - self.s.space()?; - self.word_space("=")?; - self.print_type(&default) + pub fn print_generic_param(&mut self, param: &GenericParam) -> io::Result<()> { + self.print_ident(param.name.ident())?; + match param.kind { + GenericParamKind::Lifetime { .. } => { + let mut sep = ":"; + for bound in ¶m.bounds { + match bound { + GenericBound::Outlives(lt) => { + self.s.word(sep)?; + self.print_lifetime(lt)?; + sep = "+"; + } + _ => bug!(), + } + } + Ok(()) + } + GenericParamKind::Type { ref default, .. } => { + self.print_bounds(":", ¶m.bounds)?; + match default { + Some(default) => { + self.s.space()?; + self.word_space("=")?; + self.print_type(&default) + } + _ => Ok(()), + } } - _ => Ok(()), } } + pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) -> io::Result<()> { + self.print_ident(lifetime.name.ident()) + } + pub fn print_where_clause(&mut self, where_clause: &hir::WhereClause) -> io::Result<()> { if where_clause.predicates.is_empty() { return Ok(()); @@ -2103,7 +2177,12 @@ impl<'a> State<'a> { self.s.word(":")?; for (i, bound) in bounds.iter().enumerate() { - self.print_lifetime(bound)?; + match bound { + GenericBound::Outlives(lt) => { + self.print_lifetime(lt)?; + } + _ => bug!(), + } if i != 0 { self.s.word(":")?; @@ -2162,7 +2241,7 @@ impl<'a> State<'a> { decl: &hir::FnDecl, name: Option, generic_params: &[hir::GenericParam], - arg_names: &[Spanned]) + arg_names: &[ast::Ident]) -> io::Result<()> { self.ibox(indent_unit)?; if !generic_params.is_empty() { @@ -2178,12 +2257,16 @@ impl<'a> State<'a> { span: syntax_pos::DUMMY_SP, }; self.print_fn(decl, - unsafety, - hir::Constness::NotConst, - abi, + hir::FnHeader { + unsafety, + abi, + constness: hir::Constness::NotConst, + asyncness: hir::IsAsync::NotAsync, + }, name, &generics, - &hir::Inherited, + &Spanned { span: syntax_pos::DUMMY_SP, + node: hir::VisibilityKind::Inherited }, arg_names, None)?; self.end() @@ -2251,22 +2334,26 @@ impl<'a> State<'a> { } pub fn print_fn_header_info(&mut self, - unsafety: hir::Unsafety, - constness: hir::Constness, - abi: Abi, + header: hir::FnHeader, vis: &hir::Visibility) -> io::Result<()> { self.s.word(&visibility_qualified(vis, ""))?; - self.print_unsafety(unsafety)?; - match constness { + match header.constness { hir::Constness::NotConst => {} hir::Constness::Const => self.word_nbsp("const")?, } - if abi != Abi::Rust { + match header.asyncness { + hir::IsAsync::NotAsync => {} + hir::IsAsync::Async => self.word_nbsp("async")?, + } + + self.print_unsafety(header.unsafety)?; + + if header.abi != Abi::Rust { self.word_nbsp("extern")?; - self.word_nbsp(&abi.to_string())?; + self.word_nbsp(&header.abi.to_string())?; } self.s.word("fn") @@ -2297,11 +2384,11 @@ impl<'a> State<'a> { /// isn't parsed as (if true {...} else {...} | x) | 5 fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool { match e.node { - hir::ExprIf(..) | - hir::ExprMatch(..) | - hir::ExprBlock(_) | - hir::ExprWhile(..) | - hir::ExprLoop(..) => false, + hir::ExprKind::If(..) | + hir::ExprKind::Match(..) | + hir::ExprKind::Block(..) | + hir::ExprKind::While(..) | + hir::ExprKind::Loop(..) => false, _ => true, } } @@ -2309,47 +2396,47 @@ fn expr_requires_semi_to_be_stmt(e: &hir::Expr) -> bool { /// this statement requires a semicolon after it. /// note that in one case (stmt_semi), we've already /// seen the semicolon, and thus don't need another. -fn stmt_ends_with_semi(stmt: &hir::Stmt_) -> bool { +fn stmt_ends_with_semi(stmt: &hir::StmtKind) -> bool { match *stmt { - hir::StmtDecl(ref d, _) => { + hir::StmtKind::Decl(ref d, _) => { match d.node { - hir::DeclLocal(_) => true, - hir::DeclItem(_) => false, + hir::DeclKind::Local(_) => true, + hir::DeclKind::Item(_) => false, } } - hir::StmtExpr(ref e, _) => { + hir::StmtKind::Expr(ref e, _) => { expr_requires_semi_to_be_stmt(&e) } - hir::StmtSemi(..) => { + hir::StmtKind::Semi(..) => { false } } } -fn bin_op_to_assoc_op(op: hir::BinOp_) -> AssocOp { - use hir::BinOp_::*; +fn bin_op_to_assoc_op(op: hir::BinOpKind) -> AssocOp { + use hir::BinOpKind::*; match op { - BiAdd => AssocOp::Add, - BiSub => AssocOp::Subtract, - BiMul => AssocOp::Multiply, - BiDiv => AssocOp::Divide, - BiRem => AssocOp::Modulus, - - BiAnd => AssocOp::LAnd, - BiOr => AssocOp::LOr, - - BiBitXor => AssocOp::BitXor, - BiBitAnd => AssocOp::BitAnd, - BiBitOr => AssocOp::BitOr, - BiShl => AssocOp::ShiftLeft, - BiShr => AssocOp::ShiftRight, - - BiEq => AssocOp::Equal, - BiLt => AssocOp::Less, - BiLe => AssocOp::LessEqual, - BiNe => AssocOp::NotEqual, - BiGe => AssocOp::GreaterEqual, - BiGt => AssocOp::Greater, + Add => AssocOp::Add, + Sub => AssocOp::Subtract, + Mul => AssocOp::Multiply, + Div => AssocOp::Divide, + Rem => AssocOp::Modulus, + + And => AssocOp::LAnd, + Or => AssocOp::LOr, + + BitXor => AssocOp::BitXor, + BitAnd => AssocOp::BitAnd, + BitOr => AssocOp::BitOr, + Shl => AssocOp::ShiftLeft, + Shr => AssocOp::ShiftRight, + + Eq => AssocOp::Equal, + Lt => AssocOp::Less, + Le => AssocOp::LessEqual, + Ne => AssocOp::NotEqual, + Ge => AssocOp::GreaterEqual, + Gt => AssocOp::Greater, } } @@ -2358,24 +2445,24 @@ fn bin_op_to_assoc_op(op: hir::BinOp_) -> AssocOp { /// `X { y: 1 } == foo` all do, but `(X { y: 1 }) == foo` does not. fn contains_exterior_struct_lit(value: &hir::Expr) -> bool { match value.node { - hir::ExprStruct(..) => true, + hir::ExprKind::Struct(..) => true, - hir::ExprAssign(ref lhs, ref rhs) | - hir::ExprAssignOp(_, ref lhs, ref rhs) | - hir::ExprBinary(_, ref lhs, ref rhs) => { + hir::ExprKind::Assign(ref lhs, ref rhs) | + hir::ExprKind::AssignOp(_, ref lhs, ref rhs) | + hir::ExprKind::Binary(_, ref lhs, ref rhs) => { // X { y: 1 } + X { y: 2 } contains_exterior_struct_lit(&lhs) || contains_exterior_struct_lit(&rhs) } - hir::ExprUnary(_, ref x) | - hir::ExprCast(ref x, _) | - hir::ExprType(ref x, _) | - hir::ExprField(ref x, _) | - hir::ExprIndex(ref x, _) => { + hir::ExprKind::Unary(_, ref x) | + hir::ExprKind::Cast(ref x, _) | + hir::ExprKind::Type(ref x, _) | + hir::ExprKind::Field(ref x, _) | + hir::ExprKind::Index(ref x, _) => { // &X { y: 1 }, X { y: 1 }.y contains_exterior_struct_lit(&x) } - hir::ExprMethodCall(.., ref exprs) => { + hir::ExprKind::MethodCall(.., ref exprs) => { // X { y: 1 }.bar(...) contains_exterior_struct_lit(&exprs[0]) } diff --git a/src/librustc/ich/fingerprint.rs b/src/librustc/ich/fingerprint.rs index a7adf28c481b9..a6e35d78dcb5a 100644 --- a/src/librustc/ich/fingerprint.rs +++ b/src/librustc/ich/fingerprint.rs @@ -45,6 +45,18 @@ impl Fingerprint { ) } + // Combines two hashes in an order independent way. Make sure this is what + // you want. + #[inline] + pub fn combine_commutative(self, other: Fingerprint) -> Fingerprint { + let a = (self.1 as u128) << 64 | self.0 as u128; + let b = (other.1 as u128) << 64 | other.0 as u128; + + let c = a.wrapping_add(b); + + Fingerprint((c >> 64) as u64, c as u64) + } + pub fn to_hex(&self) -> String { format!("{:x}{:x}", self.0, self.1) } @@ -52,7 +64,8 @@ impl Fingerprint { pub fn encode_opaque(&self, encoder: &mut Encoder) -> EncodeResult { let bytes: [u8; 16] = unsafe { mem::transmute([self.0.to_le(), self.1.to_le()]) }; - encoder.emit_raw_bytes(&bytes) + encoder.emit_raw_bytes(&bytes); + Ok(()) } pub fn decode_opaque<'a>(decoder: &mut Decoder<'a>) -> Result { @@ -67,7 +80,7 @@ impl Fingerprint { } impl ::std::fmt::Display for Fingerprint { - fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(formatter, "{:x}-{:x}", self.0, self.1) } } @@ -92,7 +105,7 @@ impl serialize::UseSpecializedEncodable for Fingerprint { } impl serialize::UseSpecializedDecodable for Fingerprint { } -impl<'a> serialize::SpecializedEncoder for serialize::opaque::Encoder<'a> { +impl serialize::SpecializedEncoder for serialize::opaque::Encoder { fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { f.encode_opaque(self) } diff --git a/src/librustc/ich/hcx.rs b/src/librustc/ich/hcx.rs index 04b725957b627..05361b6564170 100644 --- a/src/librustc/ich/hcx.rs +++ b/src/librustc/ich/hcx.rs @@ -396,7 +396,7 @@ impl<'a> HashStable> for Span { pub fn hash_stable_trait_impls<'a, 'gcx, W, R>( hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher, - blanket_impls: &Vec, + blanket_impls: &[DefId], non_blanket_impls: &HashMap, R>) where W: StableHasherResult, R: std_hash::BuildHasher, diff --git a/src/librustc/ich/impls_cstore.rs b/src/librustc/ich/impls_cstore.rs index 96d7cb6b041a8..f8cd3b8a18a3b 100644 --- a/src/librustc/ich/impls_cstore.rs +++ b/src/librustc/ich/impls_cstore.rs @@ -31,7 +31,8 @@ impl_stable_hash_for!(struct middle::cstore::NativeLibrary { kind, name, cfg, - foreign_module + foreign_module, + wasm_import_module }); impl_stable_hash_for!(struct middle::cstore::ForeignModule { diff --git a/src/librustc/ich/impls_hir.rs b/src/librustc/ich/impls_hir.rs index 4a001802eacb4..410d578d4044c 100644 --- a/src/librustc/ich/impls_hir.rs +++ b/src/librustc/ich/impls_hir.rs @@ -14,7 +14,7 @@ use hir; use hir::map::DefPathHash; use hir::def_id::{DefId, LocalDefId, CrateNum, CRATE_DEF_INDEX}; -use ich::{StableHashingContext, NodeIdHashingMode}; +use ich::{StableHashingContext, NodeIdHashingMode, Fingerprint}; use rustc_data_structures::stable_hasher::{HashStable, ToStableHashKey, StableHasher, StableHasherResult}; use std::mem; @@ -142,17 +142,20 @@ impl<'a> HashStable> for hir::ImplItemId { } } +impl_stable_hash_for!(enum hir::ParamName { + Plain(name), + Fresh(index) +}); + impl_stable_hash_for!(enum hir::LifetimeName { + Param(param_name), Implicit, Underscore, - Fresh(index), Static, - Name(name) }); impl_stable_hash_for!(struct hir::Label { - span, - name + ident }); impl_stable_hash_for!(struct hir::Lifetime { @@ -161,13 +164,6 @@ impl_stable_hash_for!(struct hir::Lifetime { name }); -impl_stable_hash_for!(struct hir::LifetimeDef { - lifetime, - bounds, - pure_wrt_drop, - in_band -}); - impl_stable_hash_for!(struct hir::Path { span, def, @@ -175,21 +171,25 @@ impl_stable_hash_for!(struct hir::Path { }); impl_stable_hash_for!(struct hir::PathSegment { - name, + ident -> (ident.name), infer_types, - parameters + args }); -impl_stable_hash_for!(struct hir::PathParameters { - lifetimes, - types, +impl_stable_hash_for!(enum hir::GenericArg { + Lifetime(lt), + Type(ty) +}); + +impl_stable_hash_for!(struct hir::GenericArgs { + args, bindings, parenthesized }); -impl_stable_hash_for!(enum hir::TyParamBound { - TraitTyParamBound(poly_trait_ref, trait_bound_modifier), - RegionTyParamBound(lifetime) +impl_stable_hash_for!(enum hir::GenericBound { + Trait(poly_trait_ref, trait_bound_modifier), + Outlives(lifetime) }); impl_stable_hash_for!(enum hir::TraitBoundModifier { @@ -197,21 +197,32 @@ impl_stable_hash_for!(enum hir::TraitBoundModifier { Maybe }); -impl_stable_hash_for!(struct hir::TyParam { - name, +impl_stable_hash_for!(struct hir::GenericParam { id, + name, + pure_wrt_drop, + attrs, bounds, - default, span, - pure_wrt_drop, - synthetic, - attrs + kind }); -impl_stable_hash_for!(enum hir::GenericParam { - Lifetime(lifetime_def), - Type(ty_param) -}); +impl<'a> HashStable> for hir::GenericParamKind { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match self { + hir::GenericParamKind::Lifetime { in_band } => { + in_band.hash_stable(hcx, hasher); + } + hir::GenericParamKind::Type { ref default, synthetic } => { + default.hash_stable(hcx, hasher); + synthetic.hash_stable(hcx, hasher); + } + } + } +} impl_stable_hash_for!(struct hir::Generics { params, @@ -260,19 +271,24 @@ impl_stable_hash_for!(struct hir::MutTy { }); impl_stable_hash_for!(struct hir::MethodSig { - unsafety, - constness, - abi, + header, decl }); impl_stable_hash_for!(struct hir::TypeBinding { id, - name, + ident -> (ident.name), ty, span }); +impl_stable_hash_for!(struct hir::FnHeader { + unsafety, + constness, + asyncness, + abi +}); + impl<'a> HashStable> for hir::Ty { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -310,23 +326,23 @@ impl_stable_hash_for!(struct hir::BareFnTy { impl_stable_hash_for!(struct hir::ExistTy { generics, + impl_trait_fn, bounds }); -impl_stable_hash_for!(enum hir::Ty_ { - TySlice(t), - TyArray(t, body_id), - TyPtr(t), - TyRptr(lifetime, t), - TyBareFn(t), - TyNever, - TyTup(ts), - TyPath(qpath), - TyTraitObject(trait_refs, lifetime), - TyImplTraitExistential(existty, lifetimes), - TyTypeof(body_id), - TyErr, - TyInfer +impl_stable_hash_for!(enum hir::TyKind { + Slice(t), + Array(t, body_id), + Ptr(t), + Rptr(lifetime, t), + BareFn(t), + Never, + Tup(ts), + Path(qpath), + TraitObject(trait_refs, lifetime), + Typeof(body_id), + Err, + Infer }); impl_stable_hash_for!(struct hir::FnDecl { @@ -341,20 +357,11 @@ impl_stable_hash_for!(enum hir::FunctionRetTy { Return(t) }); -impl<'a> HashStable> for hir::TraitRef { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let hir::TraitRef { - ref path, - // Don't hash the ref_id. It is tracked via the thing it is used to access - ref_id: _, - } = *self; - - path.hash_stable(hcx, hasher); - } -} - +impl_stable_hash_for!(struct hir::TraitRef { + // Don't hash the ref_id. It is tracked via the thing it is used to access + ref_id -> _, + path, +}); impl_stable_hash_for!(struct hir::PolyTraitRef { bound_generic_params, @@ -377,66 +384,32 @@ impl_stable_hash_for!(struct hir::MacroDef { body }); +impl_stable_hash_for!(struct hir::Block { + stmts, + expr, + id -> _, + hir_id -> _, + rules, + span, + targeted_by_break, + recovered, +}); -impl<'a> HashStable> for hir::Block { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let hir::Block { - ref stmts, - ref expr, - id: _, - hir_id: _, - rules, - span, - targeted_by_break, - recovered, - } = *self; - - stmts.hash_stable(hcx, hasher); - expr.hash_stable(hcx, hasher); - rules.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); - recovered.hash_stable(hcx, hasher); - targeted_by_break.hash_stable(hcx, hasher); - } -} - -impl<'a> HashStable> for hir::Pat { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let hir::Pat { - id: _, - hir_id: _, - ref node, - ref span - } = *self; - - - node.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(struct hir::Pat { + id -> _, + hir_id -> _, + node, + span, +}); impl_stable_hash_for_spanned!(hir::FieldPat); -impl<'a> HashStable> for hir::FieldPat { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let hir::FieldPat { - id: _, - name, - ref pat, - is_shorthand, - } = *self; - - name.hash_stable(hcx, hasher); - pat.hash_stable(hcx, hasher); - is_shorthand.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(struct hir::FieldPat { + id -> _, + ident -> (ident.name), + pat, + is_shorthand, +}); impl_stable_hash_for!(enum hir::BindingAnnotation { Unannotated, @@ -464,28 +437,28 @@ impl_stable_hash_for!(enum hir::PatKind { Slice(one, two, three) }); -impl_stable_hash_for!(enum hir::BinOp_ { - BiAdd, - BiSub, - BiMul, - BiDiv, - BiRem, - BiAnd, - BiOr, - BiBitXor, - BiBitAnd, - BiBitOr, - BiShl, - BiShr, - BiEq, - BiLt, - BiLe, - BiNe, - BiGe, - BiGt -}); - -impl_stable_hash_for_spanned!(hir::BinOp_); +impl_stable_hash_for!(enum hir::BinOpKind { + Add, + Sub, + Mul, + Div, + Rem, + And, + Or, + BitXor, + BitAnd, + BitOr, + Shl, + Shr, + Eq, + Lt, + Le, + Ne, + Ge, + Gt +}); + +impl_stable_hash_for_spanned!(hir::BinOpKind); impl_stable_hash_for!(enum hir::UnOp { UnDeref, @@ -493,7 +466,7 @@ impl_stable_hash_for!(enum hir::UnOp { UnNeg }); -impl_stable_hash_for_spanned!(hir::Stmt_); +impl_stable_hash_for_spanned!(hir::StmtKind); impl_stable_hash_for!(struct hir::Local { pat, @@ -506,10 +479,10 @@ impl_stable_hash_for!(struct hir::Local { source }); -impl_stable_hash_for_spanned!(hir::Decl_); -impl_stable_hash_for!(enum hir::Decl_ { - DeclLocal(local), - DeclItem(item_id) +impl_stable_hash_for_spanned!(hir::DeclKind); +impl_stable_hash_for!(enum hir::DeclKind { + Local(local), + Item(item_id) }); impl_stable_hash_for!(struct hir::Arm { @@ -519,24 +492,13 @@ impl_stable_hash_for!(struct hir::Arm { body }); -impl<'a> HashStable> for hir::Field { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let hir::Field { - id: _, - name, - ref expr, - span, - is_shorthand, - } = *self; - - name.hash_stable(hcx, hasher); - expr.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); - is_shorthand.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(struct hir::Field { + id -> _, + ident, + expr, + span, + is_shorthand, +}); impl_stable_hash_for_spanned!(ast::Name); @@ -553,6 +515,12 @@ impl_stable_hash_for!(enum hir::UnsafeSource { UserProvided }); +impl_stable_hash_for!(struct hir::AnonConst { + id, + hir_id, + body +}); + impl<'a> HashStable> for hir::Expr { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -573,36 +541,36 @@ impl<'a> HashStable> for hir::Expr { } } -impl_stable_hash_for!(enum hir::Expr_ { - ExprBox(sub), - ExprArray(subs), - ExprCall(callee, args), - ExprMethodCall(segment, span, args), - ExprTup(fields), - ExprBinary(op, lhs, rhs), - ExprUnary(op, operand), - ExprLit(value), - ExprCast(expr, t), - ExprType(expr, t), - ExprIf(cond, then, els), - ExprWhile(cond, body, label), - ExprLoop(body, label, loop_src), - ExprMatch(matchee, arms, match_src), - ExprClosure(capture_clause, decl, body_id, span, gen), - ExprBlock(blk), - ExprAssign(lhs, rhs), - ExprAssignOp(op, lhs, rhs), - ExprField(owner, field_name), - ExprIndex(lhs, rhs), - ExprPath(path), - ExprAddrOf(mutability, sub), - ExprBreak(destination, sub), - ExprAgain(destination), - ExprRet(val), - ExprInlineAsm(asm, inputs, outputs), - ExprStruct(path, fields, base), - ExprRepeat(val, times), - ExprYield(val) +impl_stable_hash_for!(enum hir::ExprKind { + Box(sub), + Array(subs), + Call(callee, args), + MethodCall(segment, span, args), + Tup(fields), + Binary(op, lhs, rhs), + Unary(op, operand), + Lit(value), + Cast(expr, t), + Type(expr, t), + If(cond, then, els), + While(cond, body, label), + Loop(body, label, loop_src), + Match(matchee, arms, match_src), + Closure(capture_clause, decl, body_id, span, gen), + Block(blk, label), + Assign(lhs, rhs), + AssignOp(op, lhs, rhs), + Field(owner, ident), + Index(lhs, rhs), + Path(path), + AddrOf(mutability, sub), + Break(destination, sub), + Continue(destination), + Ret(val), + InlineAsm(asm, inputs, outputs), + Struct(path, fields, base), + Repeat(val, times), + Yield(val) }); impl_stable_hash_for!(enum hir::LocalSource { @@ -656,36 +624,17 @@ impl_stable_hash_for!(struct hir::Destination { impl_stable_hash_for_spanned!(ast::Ident); -impl_stable_hash_for!(enum hir::LoopIdResult { - Ok(node_id), - Err(loop_id_error) -}); - impl_stable_hash_for!(enum hir::LoopIdError { OutsideLoopScope, UnlabeledCfInWhileCondition, UnresolvedLabel }); -impl_stable_hash_for!(enum hir::ScopeTarget { - Block(node_id), - Loop(loop_id_result) +impl_stable_hash_for!(struct ast::Ident { + name, + span, }); -impl<'a> HashStable> for ast::Ident { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let ast::Ident { - name, - span, - } = *self; - - name.hash_stable(hcx, hasher); - span.hash_stable(hcx, hasher); - } -} - impl<'a> HashStable> for hir::TraitItem { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -693,7 +642,7 @@ impl<'a> HashStable> for hir::TraitItem { let hir::TraitItem { id: _, hir_id: _, - name, + ident, ref attrs, ref generics, ref node, @@ -701,7 +650,7 @@ impl<'a> HashStable> for hir::TraitItem { } = *self; hcx.hash_hir_item_like(|hcx| { - name.hash_stable(hcx, hasher); + ident.name.hash_stable(hcx, hasher); attrs.hash_stable(hcx, hasher); generics.hash_stable(hcx, hasher); node.hash_stable(hcx, hasher); @@ -728,7 +677,7 @@ impl<'a> HashStable> for hir::ImplItem { let hir::ImplItem { id: _, hir_id: _, - name, + ident, ref vis, defaultness, ref attrs, @@ -738,7 +687,7 @@ impl<'a> HashStable> for hir::ImplItem { } = *self; hcx.hash_hir_item_like(|hcx| { - name.hash_stable(hcx, hasher); + ident.name.hash_stable(hcx, hasher); vis.hash_stable(hcx, hasher); defaultness.hash_stable(hcx, hasher); attrs.hash_stable(hcx, hasher); @@ -752,21 +701,29 @@ impl<'a> HashStable> for hir::ImplItem { impl_stable_hash_for!(enum hir::ImplItemKind { Const(t, body), Method(sig, body), + Existential(bounds), Type(t) }); -impl<'a> HashStable> for hir::Visibility { +impl_stable_hash_for!(enum ::syntax::ast::CrateSugar { + JustCrate, + PubCrate, +}); + +impl<'a> HashStable> for hir::VisibilityKind { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { - hir::Visibility::Public | - hir::Visibility::Crate | - hir::Visibility::Inherited => { + hir::VisibilityKind::Public | + hir::VisibilityKind::Inherited => { // No fields to hash. } - hir::Visibility::Restricted { ref path, id } => { + hir::VisibilityKind::Crate(sugar) => { + sugar.hash_stable(hcx, hasher); + } + hir::VisibilityKind::Restricted { ref path, id } => { hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { id.hash_stable(hcx, hasher); }); @@ -776,6 +733,8 @@ impl<'a> HashStable> for hir::Visibility { } } +impl_stable_hash_for_spanned!(hir::VisibilityKind); + impl<'a> HashStable> for hir::Defaultness { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -802,14 +761,27 @@ impl<'a> HashStable> for hir::Mod { hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { let hir::Mod { - inner, - // We are not hashing the IDs of the items contained in the module. - // This is harmless and matches the current behavior but it's not - // actually correct. See issue #40876. - item_ids: _, + inner: ref inner_span, + ref item_ids, } = *self; - inner.hash_stable(hcx, hasher); + inner_span.hash_stable(hcx, hasher); + + // Combining the DefPathHashes directly is faster than feeding them + // into the hasher. Because we use a commutative combine, we also don't + // have to sort the array. + let item_ids_hash = item_ids + .iter() + .map(|id| { + let (def_path_hash, local_id) = id.id.to_stable_hash_key(hcx); + debug_assert_eq!(local_id, hir::ItemLocalId(0)); + def_path_hash.0 + }).fold(Fingerprint::ZERO, |a, b| { + a.combine_commutative(b) + }); + + item_ids.len().hash_stable(hcx, hasher); + item_ids_hash.hash_stable(hcx, hasher); } } @@ -822,14 +794,14 @@ impl_stable_hash_for!(struct hir::EnumDef { variants }); -impl_stable_hash_for!(struct hir::Variant_ { +impl_stable_hash_for!(struct hir::VariantKind { name, attrs, data, disr_expr }); -impl_stable_hash_for_spanned!(hir::Variant_); +impl_stable_hash_for_spanned!(hir::VariantKind); impl_stable_hash_for!(enum hir::UseKind { Single, @@ -839,7 +811,7 @@ impl_stable_hash_for!(enum hir::UseKind { impl_stable_hash_for!(struct hir::StructField { span, - name, + ident -> (ident.name), vis, id, ty, @@ -876,27 +848,28 @@ impl<'a> HashStable> for hir::Item { } } -impl_stable_hash_for!(enum hir::Item_ { - ItemExternCrate(orig_name), - ItemUse(path, use_kind), - ItemStatic(ty, mutability, body_id), - ItemConst(ty, body_id), - ItemFn(fn_decl, unsafety, constness, abi, generics, body_id), - ItemMod(module), - ItemForeignMod(foreign_mod), - ItemGlobalAsm(global_asm), - ItemTy(ty, generics), - ItemEnum(enum_def, generics), - ItemStruct(variant_data, generics), - ItemUnion(variant_data, generics), - ItemTrait(is_auto, unsafety, generics, bounds, item_refs), - ItemTraitAlias(generics, bounds), - ItemImpl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) +impl_stable_hash_for!(enum hir::ItemKind { + ExternCrate(orig_name), + Use(path, use_kind), + Static(ty, mutability, body_id), + Const(ty, body_id), + Fn(fn_decl, header, generics, body_id), + Mod(module), + ForeignMod(foreign_mod), + GlobalAsm(global_asm), + Ty(ty, generics), + Existential(exist), + Enum(enum_def, generics), + Struct(variant_data, generics), + Union(variant_data, generics), + Trait(is_auto, unsafety, generics, bounds, item_refs), + TraitAlias(generics, bounds), + Impl(unsafety, impl_polarity, impl_defaultness, generics, trait_ref, ty, impl_item_refs) }); impl_stable_hash_for!(struct hir::TraitItemRef { id, - name, + ident -> (ident.name), kind, span, defaultness @@ -904,21 +877,21 @@ impl_stable_hash_for!(struct hir::TraitItemRef { impl_stable_hash_for!(struct hir::ImplItemRef { id, - name, + ident -> (ident.name), kind, span, vis, defaultness }); -impl<'a> HashStable> -for hir::AssociatedItemKind { +impl<'a> HashStable> for hir::AssociatedItemKind { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { mem::discriminant(self).hash_stable(hcx, hasher); match *self { hir::AssociatedItemKind::Const | + hir::AssociatedItemKind::Existential | hir::AssociatedItemKind::Type => { // No fields to hash. } @@ -938,16 +911,16 @@ impl_stable_hash_for!(struct hir::ForeignItem { vis }); -impl_stable_hash_for!(enum hir::ForeignItem_ { - ForeignItemFn(fn_decl, arg_names, generics), - ForeignItemStatic(ty, is_mutbl), - ForeignItemType +impl_stable_hash_for!(enum hir::ForeignItemKind { + Fn(fn_decl, arg_names, generics), + Static(ty, is_mutbl), + Type }); -impl_stable_hash_for!(enum hir::Stmt_ { - StmtDecl(decl, id), - StmtExpr(expr, id), - StmtSemi(expr, id) +impl_stable_hash_for!(enum hir::StmtKind { + Decl(decl, id), + Expr(expr, id), + Semi(expr, id) }); impl_stable_hash_for!(struct hir::Arg { @@ -992,45 +965,22 @@ impl_stable_hash_for!(struct hir::InlineAsmOutput { is_indirect }); -impl<'a> HashStable> for hir::GlobalAsm { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let hir::GlobalAsm { - asm, - ctxt: _ - } = *self; - - asm.hash_stable(hcx, hasher); - } -} - -impl<'a> HashStable> for hir::InlineAsm { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let hir::InlineAsm { - asm, - asm_str_style, - ref outputs, - ref inputs, - ref clobbers, - volatile, - alignstack, - dialect, - ctxt: _, // This is used for error reporting - } = *self; +impl_stable_hash_for!(struct hir::GlobalAsm { + asm, + ctxt -> _, // This is used for error reporting +}); - asm.hash_stable(hcx, hasher); - asm_str_style.hash_stable(hcx, hasher); - outputs.hash_stable(hcx, hasher); - inputs.hash_stable(hcx, hasher); - clobbers.hash_stable(hcx, hasher); - volatile.hash_stable(hcx, hasher); - alignstack.hash_stable(hcx, hasher); - dialect.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(struct hir::InlineAsm { + asm, + asm_str_style, + outputs, + inputs, + clobbers, + volatile, + alignstack, + dialect, + ctxt -> _, // This is used for error reporting +}); impl_stable_hash_for!(enum hir::def::CtorKind { Fn, @@ -1043,11 +993,13 @@ impl_stable_hash_for!(enum hir::def::Def { Struct(def_id), Union(def_id), Enum(def_id), + Existential(def_id), Variant(def_id), Trait(def_id), TyAlias(def_id), TraitAlias(def_id), AssociatedTy(def_id), + AssociatedExistential(def_id), PrimTy(prim_ty), TyParam(def_id), SelfTy(trait_def_id, impl_def_id), @@ -1082,14 +1034,17 @@ impl_stable_hash_for!(enum hir::Unsafety { Normal }); +impl_stable_hash_for!(enum hir::IsAsync { + Async, + NotAsync +}); impl_stable_hash_for!(enum hir::Constness { Const, NotConst }); -impl<'a> HashStable> -for hir::def_id::DefIndex { +impl<'a> HashStable> for hir::def_id::DefIndex { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -1112,12 +1067,10 @@ impl_stable_hash_for!(struct hir::def::Export { ident, def, vis, - span, - is_import + span }); -impl<'a> HashStable> -for ::middle::lang_items::LangItem { +impl<'a> HashStable> for ::middle::lang_items::LangItem { fn hash_stable(&self, _: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { @@ -1130,8 +1083,7 @@ impl_stable_hash_for!(struct ::middle::lang_items::LanguageItems { missing }); -impl<'a> HashStable> -for hir::TraitCandidate { +impl<'a> HashStable> for hir::TraitCandidate { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { @@ -1165,28 +1117,16 @@ impl<'a> ToStableHashKey> for hir::TraitCandidate { } } -impl<'hir> HashStable> for hir::TransFnAttrs -{ - fn hash_stable(&self, - hcx: &mut StableHashingContext<'hir>, - hasher: &mut StableHasher) { - let hir::TransFnAttrs { - flags, - inline, - export_name, - ref target_features, - linkage, - } = *self; - - flags.hash_stable(hcx, hasher); - inline.hash_stable(hcx, hasher); - export_name.hash_stable(hcx, hasher); - target_features.hash_stable(hcx, hasher); - linkage.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(struct hir::CodegenFnAttrs { + flags, + inline, + export_name, + target_features, + linkage, + link_section, +}); -impl<'hir> HashStable> for hir::TransFnAttrFlags +impl<'hir> HashStable> for hir::CodegenFnAttrFlags { fn hash_stable(&self, hcx: &mut StableHashingContext<'hir>, diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index 33f43e53394f5..38ea536b4ee72 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -26,13 +26,13 @@ impl_stable_hash_for!(struct mir::LocalDecl<'tcx> { ty, name, source_info, + visibility_scope, internal, - syntactic_scope, is_user_variable }); -impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, by_ref, mutability }); +impl_stable_hash_for!(struct mir::UpvarDecl { debug_name, var_hir_id, by_ref, mutability }); impl_stable_hash_for!(struct mir::BasicBlockData<'tcx> { statements, terminator, is_cleanup }); -impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, kind }); +impl_stable_hash_for!(struct mir::UnsafetyViolation { source_info, description, details, kind }); impl_stable_hash_for!(struct mir::UnsafetyCheckResult { violations, unsafe_blocks }); impl<'a> HashStable> @@ -127,7 +127,7 @@ impl<'a> HashStable> for mir::Field { } impl<'a> HashStable> -for mir::VisibilityScope { +for mir::SourceScope { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, @@ -241,6 +241,9 @@ for mir::StatementKind<'gcx> { place.hash_stable(hcx, hasher); rvalue.hash_stable(hcx, hasher); } + mir::StatementKind::ReadForMatch(ref place) => { + place.hash_stable(hcx, hasher); + } mir::StatementKind::SetDiscriminant { ref place, variant_index } => { place.hash_stable(hcx, hasher); variant_index.hash_stable(hcx, hasher); @@ -299,6 +302,9 @@ impl<'a, 'gcx> HashStable> for mir::Place<'gcx> { mir::Place::Static(ref statik) => { statik.hash_stable(hcx, hasher); } + mir::Place::Promoted(ref promoted) => { + promoted.hash_stable(hcx, hasher); + } mir::Place::Projection(ref place_projection) => { place_projection.hash_stable(hcx, hasher); } @@ -360,8 +366,8 @@ for mir::ProjectionElem<'gcx, V, T> } } -impl_stable_hash_for!(struct mir::VisibilityScopeData { span, parent_scope }); -impl_stable_hash_for!(struct mir::VisibilityScopeInfo { +impl_stable_hash_for!(struct mir::SourceScopeData { span, parent_scope }); +impl_stable_hash_for!(struct mir::SourceScopeLocalData { lint_root, safety }); @@ -483,10 +489,10 @@ for mir::AggregateKind<'gcx> { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } - mir::AggregateKind::Generator(def_id, ref substs, ref interior) => { + mir::AggregateKind::Generator(def_id, ref substs, movability) => { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); - interior.hash_stable(hcx, hasher); + movability.hash_stable(hcx, hasher); } } } @@ -524,22 +530,6 @@ impl_stable_hash_for!(enum mir::NullOp { impl_stable_hash_for!(struct mir::Constant<'tcx> { span, ty, literal }); -impl<'a, 'gcx> HashStable> for mir::Literal<'gcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - mem::discriminant(self).hash_stable(hcx, hasher); - match *self { - mir::Literal::Value { ref value } => { - value.hash_stable(hcx, hasher); - } - mir::Literal::Promoted { index } => { - index.hash_stable(hcx, hasher); - } - } - } -} - impl_stable_hash_for!(struct mir::Location { block, statement_index }); impl_stable_hash_for!(struct mir::BorrowCheckResult<'tcx> { diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 1cf9b7bf4780e..c106966fb70be 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -98,7 +98,8 @@ impl_stable_hash_for!(enum ::syntax::ast::AsmDialect { impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { Bang, Attr, - Derive + Derive, + ProcMacroStub, }); @@ -114,6 +115,7 @@ impl_stable_hash_for!(enum ::rustc_target::spec::abi::Abi { PtxKernel, Msp430Interrupt, X86Interrupt, + AmdGpuKernel, Rust, C, System, @@ -131,6 +133,15 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability { rustc_const_unstable }); +impl<'a> HashStable> +for ::syntax::edition::Edition { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + } +} + impl<'a> HashStable> for ::syntax::attr::StabilityLevel { fn hash_stable(&self, @@ -314,6 +325,7 @@ fn hash_token<'a, 'gcx, W: StableHasherResult>( token::Token::Pound | token::Token::Dollar | token::Token::Question | + token::Token::SingleQuote | token::Token::Whitespace | token::Token::Comment | token::Token::Eof => {} @@ -381,14 +393,12 @@ impl_stable_hash_for!(enum ::syntax::ast::MetaItemKind { impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { call_site, - callee -}); - -impl_stable_hash_for!(struct ::syntax_pos::hygiene::NameAndSpan { + def_site, format, allow_internal_unstable, allow_internal_unsafe, - span + local_inner_macros, + edition }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { @@ -398,8 +408,11 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { + Async, DotFill, QuestionMark, + ExistentialReturnType, + ForLoop, Catch }); @@ -410,6 +423,7 @@ impl_stable_hash_for!(enum ::syntax_pos::FileName { Anon, MacroExpansion, ProcMacroSourceCode, + CliCrateAttr, CfgSpec, Custom(s) }); @@ -446,27 +460,21 @@ impl<'a> HashStable> for FileMap { src_hash.hash_stable(hcx, hasher); // We only hash the relative position within this filemap - lines.with_lock(|lines| { - lines.len().hash_stable(hcx, hasher); - for &line in lines.iter() { - stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); - } - }); + lines.len().hash_stable(hcx, hasher); + for &line in lines.iter() { + stable_byte_pos(line, start_pos).hash_stable(hcx, hasher); + } // We only hash the relative position within this filemap - multibyte_chars.with_lock(|multibyte_chars| { - multibyte_chars.len().hash_stable(hcx, hasher); - for &char_pos in multibyte_chars.iter() { - stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); - } - }); + multibyte_chars.len().hash_stable(hcx, hasher); + for &char_pos in multibyte_chars.iter() { + stable_multibyte_char(char_pos, start_pos).hash_stable(hcx, hasher); + } - non_narrow_chars.with_lock(|non_narrow_chars| { - non_narrow_chars.len().hash_stable(hcx, hasher); - for &char_pos in non_narrow_chars.iter() { - stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); - } - }); + non_narrow_chars.len().hash_stable(hcx, hasher); + for &char_pos in non_narrow_chars.iter() { + stable_non_narrow_char(char_pos, start_pos).hash_stable(hcx, hasher); + } } } diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index a40d8e0927740..cb685f83aba1e 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -104,16 +104,16 @@ for ty::RegionKind { c.hash_stable(hcx, hasher); } ty::ReLateBound(db, ty::BrAnon(i)) => { - db.depth.hash_stable(hcx, hasher); + db.hash_stable(hcx, hasher); i.hash_stable(hcx, hasher); } ty::ReLateBound(db, ty::BrNamed(def_id, name)) => { - db.depth.hash_stable(hcx, hasher); + db.hash_stable(hcx, hasher); def_id.hash_stable(hcx, hasher); name.hash_stable(hcx, hasher); } ty::ReLateBound(db, ty::BrEnv) => { - db.depth.hash_stable(hcx, hasher); + db.hash_stable(hcx, hasher); } ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, index, name }) => { def_id.hash_stable(hcx, hasher); @@ -132,7 +132,7 @@ for ty::RegionKind { ty::ReLateBound(..) | ty::ReVar(..) | ty::ReSkolemized(..) => { - bug!("TypeIdHasher: unexpected region {:?}", *self) + bug!("StableHasher: unexpected region {:?}", *self) } } } @@ -359,16 +359,16 @@ impl_stable_hash_for!(enum ty::VariantDiscr { impl_stable_hash_for!(struct ty::FieldDef { did, - name, - vis + ident -> (ident.name), + vis, }); impl<'a, 'gcx> HashStable> -for ::middle::const_val::ConstVal<'gcx> { +for ::mir::interpret::ConstValue<'gcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use middle::const_val::ConstVal::*; + use mir::interpret::ConstValue::*; mem::discriminant(self).hash_stable(hcx, hasher); @@ -377,35 +377,32 @@ for ::middle::const_val::ConstVal<'gcx> { def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); } - Value(ref value) => { - value.hash_stable(hcx, hasher); + Scalar(val) => { + val.hash_stable(hcx, hasher); + } + ScalarPair(a, b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + ByRef(alloc, offset) => { + alloc.hash_stable(hcx, hasher); + offset.hash_stable(hcx, hasher); } } } } impl_stable_hash_for!(enum mir::interpret::Value { - ByVal(v), - ByValPair(a, b), + Scalar(v), + ScalarPair(a, b), ByRef(ptr, align) }); -impl_stable_hash_for!(struct mir::interpret::MemoryPointer { +impl_stable_hash_for!(struct mir::interpret::Pointer { alloc_id, offset }); -enum AllocDiscriminant { - Alloc, - Static, - Function, -} -impl_stable_hash_for!(enum self::AllocDiscriminant { - Alloc, - Static, - Function -}); - impl<'a> HashStable> for mir::interpret::AllocId { fn hash_stable( &self, @@ -415,30 +412,29 @@ impl<'a> HashStable> for mir::interpret::AllocId { ty::tls::with_opt(|tcx| { trace!("hashing {:?}", *self); let tcx = tcx.expect("can't hash AllocIds during hir lowering"); - if let Some(def_id) = tcx.interpret_interner.get_static(*self) { - AllocDiscriminant::Static.hash_stable(hcx, hasher); - trace!("hashing {:?} as static {:?}", *self, def_id); - def_id.hash_stable(hcx, hasher); - } else if let Some(alloc) = tcx.interpret_interner.get_alloc(*self) { - AllocDiscriminant::Alloc.hash_stable(hcx, hasher); - if hcx.alloc_id_recursion_tracker.insert(*self) { - trace!("hashing {:?} as alloc {:#?}", *self, alloc); - alloc.hash_stable(hcx, hasher); - assert!(hcx.alloc_id_recursion_tracker.remove(self)); - } else { - trace!("skipping hashing of {:?} due to recursion", *self); - } - } else if let Some(inst) = tcx.interpret_interner.get_fn(*self) { - trace!("hashing {:?} as fn {:#?}", *self, inst); - AllocDiscriminant::Function.hash_stable(hcx, hasher); - inst.hash_stable(hcx, hasher); - } else { - bug!("no allocation for {}", self); - } + let alloc_kind = tcx.alloc_map.lock().get(*self).expect("no value for AllocId"); + alloc_kind.hash_stable(hcx, hasher); }); } } +impl<'a, 'gcx, M: HashStable>> HashStable> +for mir::interpret::AllocType<'gcx, M> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use mir::interpret::AllocType::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + + match *self { + Function(instance) => instance.hash_stable(hcx, hasher), + Static(def_id) => def_id.hash_stable(hcx, hasher), + Memory(ref mem) => mem.hash_stable(hcx, hasher), + } + } +} + impl<'a> HashStable> for mir::interpret::Allocation { fn hash_stable( &self, @@ -460,80 +456,51 @@ impl_stable_hash_for!(enum ::syntax::ast::Mutability { Mutable }); -impl_stable_hash_for!(struct mir::interpret::Pointer{primval}); -impl_stable_hash_for!(enum mir::interpret::PrimVal { - Bytes(b), - Ptr(p), - Undef -}); +impl<'a> HashStable> +for ::mir::interpret::Scalar { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use mir::interpret::Scalar::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + Bits { bits, defined } => { + bits.hash_stable(hcx, hasher); + defined.hash_stable(hcx, hasher); + }, + Ptr(ptr) => ptr.hash_stable(hcx, hasher), + } + } +} impl_stable_hash_for!(struct ty::Const<'tcx> { ty, val }); -impl_stable_hash_for!(struct ::middle::const_val::ConstEvalErr<'tcx> { +impl_stable_hash_for!(struct ::mir::interpret::ConstEvalErr<'tcx> { span, - kind + stacktrace, + error }); -impl_stable_hash_for!(struct ::middle::const_val::FrameInfo { +impl_stable_hash_for!(struct ::mir::interpret::FrameInfo { span, + lint_root, location }); -impl<'a, 'gcx> HashStable> -for ::middle::const_val::ErrKind<'gcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - use middle::const_val::ErrKind::*; - - mem::discriminant(self).hash_stable(hcx, hasher); - - match *self { - NonConstPath | - TypeckError | - CheckMatchError => { - // nothing to do - } - UnimplementedConstVal(s) => { - s.hash_stable(hcx, hasher); - } - IndexOutOfBounds { len, index } => { - len.hash_stable(hcx, hasher); - index.hash_stable(hcx, hasher); - } - LayoutError(ref layout_error) => { - layout_error.hash_stable(hcx, hasher); - } - Miri(ref err, ref trace) => { - err.hash_stable(hcx, hasher); - trace.hash_stable(hcx, hasher); - }, - } - } -} - impl_stable_hash_for!(struct ty::ClosureSubsts<'tcx> { substs }); - -impl_stable_hash_for!(struct ty::GeneratorInterior<'tcx> { witness, movable }); +impl_stable_hash_for!(struct ty::GeneratorSubsts<'tcx> { substs }); impl_stable_hash_for!(struct ty::GenericPredicates<'tcx> { parent, predicates }); - -impl<'a, 'gcx> HashStable> -for ::mir::interpret::EvalError<'gcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - self.kind.hash_stable(hcx, hasher) - } -} +impl_stable_hash_for!(struct ::mir::interpret::EvalError<'tcx> { kind }); impl<'a, 'gcx, O: HashStable>> HashStable> for ::mir::interpret::EvalErrorKind<'gcx, O> { @@ -554,6 +521,7 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> { InvalidNullPointerUsage | ReadPointerAsBytes | ReadBytesAsPointer | + ReadForeignStatic | InvalidPointerMath | ReadUndefBytes | DeadLocal | @@ -573,6 +541,8 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> { ReadFromReturnPointer | UnimplementedTraitSelection | TypeckError | + TooGeneric | + CheckMatchError | DerefFunctionPointer | ExecuteMemory | OverflowNeg | @@ -580,7 +550,8 @@ for ::mir::interpret::EvalErrorKind<'gcx, O> { DivisionByZero | GeneratorResumedAfterReturn | GeneratorResumedAfterPanic | - ReferencedConstant => {} + InfiniteLoop => {} + ReferencedConstant(ref err) => err.hash_stable(hcx, hasher), MachineError(ref err) => err.hash_stable(hcx, hasher), FunctionPointerTyMismatch(a, b) => { a.hash_stable(hcx, hasher); @@ -706,63 +677,44 @@ impl_stable_hash_for!(enum ty::adjustment::CustomCoerceUnsized { Struct(index) }); -impl<'a> HashStable> for ty::Generics { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let ty::Generics { - parent, - parent_regions, - parent_types, - ref regions, - ref types, - - // Reverse map to each `TypeParameterDef`'s `index` field, from - // `def_id.index` (`def_id.krate` is the same as the item's). - type_param_to_index: _, // Don't hash this - has_self, - has_late_bound_regions, - } = *self; +impl_stable_hash_for!(struct ty::Generics { + parent, + parent_count, + params, + // Reverse map to each param's `index` field, from its `def_id`. + param_def_id_to_index -> _, // Don't hash this + has_self, + has_late_bound_regions, +}); - parent.hash_stable(hcx, hasher); - parent_regions.hash_stable(hcx, hasher); - parent_types.hash_stable(hcx, hasher); - regions.hash_stable(hcx, hasher); - types.hash_stable(hcx, hasher); - has_self.hash_stable(hcx, hasher); - has_late_bound_regions.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(struct ty::GenericParamDef { + name, + def_id, + index, + pure_wrt_drop, + kind +}); -impl<'a> HashStable> -for ty::RegionParameterDef { +impl<'a> HashStable> for ty::GenericParamDefKind { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let ty::RegionParameterDef { - name, - def_id, - index, - pure_wrt_drop - } = *self; - - name.hash_stable(hcx, hasher); - def_id.hash_stable(hcx, hasher); - index.hash_stable(hcx, hasher); - pure_wrt_drop.hash_stable(hcx, hasher); + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + ty::GenericParamDefKind::Lifetime => {} + ty::GenericParamDefKind::Type { + has_default, + ref object_lifetime_default, + ref synthetic, + } => { + has_default.hash_stable(hcx, hasher); + object_lifetime_default.hash_stable(hcx, hasher); + synthetic.hash_stable(hcx, hasher); + } + } } } -impl_stable_hash_for!(struct ty::TypeParameterDef { - name, - def_id, - index, - has_default, - object_lifetime_default, - pure_wrt_drop, - synthetic -}); - impl<'a, 'gcx, T> HashStable> for ::middle::resolve_lifetime::Set1 where T: HashStable> @@ -798,10 +750,6 @@ impl_stable_hash_for!(enum ::middle::resolve_lifetime::Region { Free(call_site_scope_data, decl) }); -impl_stable_hash_for!(struct ty::DebruijnIndex { - depth -}); - impl_stable_hash_for!(enum ty::cast::CastKind { CoercionCast, PtrPtrCast, @@ -889,9 +837,10 @@ for ty::TypeVariants<'gcx> TyRawPtr(pointee_ty) => { pointee_ty.hash_stable(hcx, hasher); } - TyRef(region, pointee_ty) => { + TyRef(region, pointee_ty, mutbl) => { region.hash_stable(hcx, hasher); pointee_ty.hash_stable(hcx, hasher); + mutbl.hash_stable(hcx, hasher); } TyFnDef(def_id, substs) => { def_id.hash_stable(hcx, hasher); @@ -908,10 +857,10 @@ for ty::TypeVariants<'gcx> def_id.hash_stable(hcx, hasher); closure_substs.hash_stable(hcx, hasher); } - TyGenerator(def_id, closure_substs, interior) => { + TyGenerator(def_id, generator_substs, movability) => { def_id.hash_stable(hcx, hasher); - closure_substs.hash_stable(hcx, hasher); - interior.hash_stable(hcx, hasher); + generator_substs.hash_stable(hcx, hasher); + movability.hash_stable(hcx, hasher); } TyGeneratorWitness(types) => { types.hash_stable(hcx, hasher) @@ -1068,61 +1017,34 @@ impl<'a, 'gcx> HashStable> for ty::InstanceDef<'gcx> { } } -impl<'a> HashStable> for ty::TraitDef { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let ty::TraitDef { - // We already have the def_path_hash below, no need to hash it twice - def_id: _, - unsafety, - paren_sugar, - has_auto_impl, - def_path_hash, - } = *self; - - unsafety.hash_stable(hcx, hasher); - paren_sugar.hash_stable(hcx, hasher); - has_auto_impl.hash_stable(hcx, hasher); - def_path_hash.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(struct ty::TraitDef { + // We already have the def_path_hash below, no need to hash it twice + def_id -> _, + unsafety, + paren_sugar, + has_auto_impl, + def_path_hash, +}); impl_stable_hash_for!(struct ty::Destructor { did }); -impl<'a> HashStable> for ty::CrateVariancesMap { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let ty::CrateVariancesMap { - ref variances, - // This is just an irrelevant helper value. - empty_variance: _, - } = *self; - - variances.hash_stable(hcx, hasher); - } -} - -impl<'a, 'gcx> HashStable> for ty::CratePredicatesMap<'gcx> { - fn hash_stable(&self, - hcx: &mut StableHashingContext<'a>, - hasher: &mut StableHasher) { - let ty::CratePredicatesMap { - ref predicates, - // This is just an irrelevant helper value. - empty_predicate: _, - } = *self; +impl_stable_hash_for!(struct ty::CrateVariancesMap { + variances, + // This is just an irrelevant helper value. + empty_variance -> _, +}); - predicates.hash_stable(hcx, hasher); - } -} +impl_stable_hash_for!(struct ty::CratePredicatesMap<'tcx> { + predicates, + // This is just an irrelevant helper value. + empty_predicate -> _, +}); impl_stable_hash_for!(struct ty::AssociatedItem { def_id, - name, + ident -> (ident.name), kind, vis, defaultness, @@ -1133,6 +1055,7 @@ impl_stable_hash_for!(struct ty::AssociatedItem { impl_stable_hash_for!(enum ty::AssociatedKind { Const, Method, + Existential, Type }); @@ -1315,11 +1238,11 @@ for traits::VtableGeneratorData<'gcx, N> where N: HashStable, hasher: &mut StableHasher) { let traits::VtableGeneratorData { - closure_def_id, + generator_def_id, substs, ref nested, } = *self; - closure_def_id.hash_stable(hcx, hasher); + generator_def_id.hash_stable(hcx, hasher); substs.hash_stable(hcx, hasher); nested.hash_stable(hcx, hasher); } @@ -1362,16 +1285,46 @@ impl_stable_hash_for!(enum infer::canonical::Certainty { Proven, Ambiguous }); -impl<'a, 'tcx> HashStable> for traits::WhereClauseAtom<'tcx> { +impl<'a, 'tcx> HashStable> for traits::WhereClause<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - use traits::WhereClauseAtom::*; + use traits::WhereClause::*; mem::discriminant(self).hash_stable(hcx, hasher); match self { Implemented(trait_ref) => trait_ref.hash_stable(hcx, hasher), ProjectionEq(projection) => projection.hash_stable(hcx, hasher), + TypeOutlives(ty_outlives) => ty_outlives.hash_stable(hcx, hasher), + RegionOutlives(region_outlives) => region_outlives.hash_stable(hcx, hasher), + } + } +} + +impl<'a, 'tcx> HashStable> for traits::WellFormed<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use traits::WellFormed::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match self { + Trait(trait_ref) => trait_ref.hash_stable(hcx, hasher), + Ty(ty) => ty.hash_stable(hcx, hasher), + } + } +} + +impl<'a, 'tcx> HashStable> for traits::FromEnv<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use traits::FromEnv::*; + + mem::discriminant(self).hash_stable(hcx, hasher); + match self { + Trait(trait_ref) => trait_ref.hash_stable(hcx, hasher), + Ty(ty) => ty.hash_stable(hcx, hasher), } } } @@ -1384,15 +1337,10 @@ impl<'a, 'tcx> HashStable> for traits::DomainGoal<'tcx> mem::discriminant(self).hash_stable(hcx, hasher); match self { - Holds(where_clause) | - WellFormed(where_clause) | - FromEnv(where_clause) => where_clause.hash_stable(hcx, hasher), - - WellFormedTy(ty) => ty.hash_stable(hcx, hasher), + Holds(wc) => wc.hash_stable(hcx, hasher), + WellFormed(wf) => wf.hash_stable(hcx, hasher), + FromEnv(from_env) => from_env.hash_stable(hcx, hasher), Normalize(projection) => projection.hash_stable(hcx, hasher), - FromEnvTy(ty) => ty.hash_stable(hcx, hasher), - RegionOutlives(predicate) => predicate.hash_stable(hcx, hasher), - TypeOutlives(predicate) => predicate.hash_stable(hcx, hasher), } } } diff --git a/src/librustc/ich/mod.rs b/src/librustc/ich/mod.rs index a0c6bbbb2393f..d58eb64c366e7 100644 --- a/src/librustc/ich/mod.rs +++ b/src/librustc/ich/mod.rs @@ -30,7 +30,7 @@ pub const ATTR_CLEAN: &'static str = "rustc_clean"; pub const ATTR_IF_THIS_CHANGED: &'static str = "rustc_if_this_changed"; pub const ATTR_THEN_THIS_WOULD_NEED: &'static str = "rustc_then_this_would_need"; pub const ATTR_PARTITION_REUSED: &'static str = "rustc_partition_reused"; -pub const ATTR_PARTITION_TRANSLATED: &'static str = "rustc_partition_translated"; +pub const ATTR_PARTITION_CODEGENED: &'static str = "rustc_partition_codegened"; pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ @@ -39,7 +39,7 @@ pub const DEP_GRAPH_ASSERT_ATTRS: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_PARTITION_REUSED, - ATTR_PARTITION_TRANSLATED, + ATTR_PARTITION_CODEGENED, ]; pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ @@ -49,5 +49,5 @@ pub const IGNORED_ATTRIBUTES: &'static [&'static str] = &[ ATTR_DIRTY, ATTR_CLEAN, ATTR_PARTITION_REUSED, - ATTR_PARTITION_TRANSLATED, + ATTR_PARTITION_CODEGENED, ]; diff --git a/src/librustc/infer/anon_types/mod.rs b/src/librustc/infer/anon_types/mod.rs index 725ea9734abf4..205f8c5ad068c 100644 --- a/src/librustc/infer/anon_types/mod.rs +++ b/src/librustc/infer/anon_types/mod.rs @@ -9,12 +9,13 @@ // except according to those terms. use hir::def_id::DefId; +use hir; use infer::{self, InferCtxt, InferOk, TypeVariableOrigin}; use infer::outlives::free_region_map::FreeRegionRelations; use rustc_data_structures::fx::FxHashMap; use syntax::ast; use traits::{self, PredicateObligation}; -use ty::{self, Ty, TyCtxt}; +use ty::{self, Ty, TyCtxt, GenericParamDefKind}; use ty::fold::{BottomUpFolder, TypeFoldable, TypeFolder}; use ty::outlives::Component; use ty::subst::{Kind, Substs, UnpackedKind}; @@ -313,12 +314,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // `['a]` for the first impl trait and `'b` for the // second. let mut least_region = None; - for region_def in &abstract_type_generics.regions { - // Find the index of this region in the list of substitutions. - let index = region_def.index as usize; - + for param in &abstract_type_generics.params { + match param.kind { + GenericParamDefKind::Lifetime => {} + _ => continue + } // Get the value supplied for this region from the substs. - let subst_arg = anon_defn.substs.region_at(index); + let subst_arg = anon_defn.substs.region_at(param.index as usize); // Compute the least upper bound of it with the other regions. debug!("constrain_anon_types: least_region={:?}", least_region); @@ -432,8 +434,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { instantiated_ty: Ty<'gcx>, ) -> Ty<'gcx> { debug!( - "infer_anon_definition_from_instantiation(instantiated_ty={:?})", - instantiated_ty + "infer_anon_definition_from_instantiation(def_id={:?}, instantiated_ty={:?})", + def_id, instantiated_ty ); let gcx = self.tcx.global_tcx(); @@ -555,7 +557,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> let mut err = struct_span_err!( self.tcx.sess, span, - E0909, + E0700, "hidden type for `impl Trait` captures lifetime that \ does not appear in bounds", ); @@ -613,13 +615,12 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for ReverseMapper<'cx, 'gcx, 'tcx> // compiler; those regions are ignored for the // outlives relation, and hence don't affect trait // selection or auto traits, and they are erased - // during trans. + // during codegen. let generics = self.tcx.generics_of(def_id); - let parent_len = generics.parent_count(); let substs = self.tcx.mk_substs(substs.substs.iter().enumerate().map( |(index, &kind)| { - if index < parent_len { + if index < generics.parent_count { // Accommodate missing regions in the parent kinds... self.fold_kind_mapping_missing_regions_to_empty(kind) } else { @@ -652,6 +653,7 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { let tcx = self.infcx.tcx; value.fold_with(&mut BottomUpFolder { tcx, + reg_op: |reg| reg, fldop: |ty| { if let ty::TyAnon(def_id, substs) = ty.sty { // Check that this is `impl Trait` type is @@ -689,18 +691,51 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { // } // ``` if let Some(anon_node_id) = tcx.hir.as_local_node_id(def_id) { - let anon_parent_node_id = tcx.hir.get_parent(anon_node_id); - let anon_parent_def_id = tcx.hir.local_def_id(anon_parent_node_id); - if self.parent_def_id == anon_parent_def_id { + let parent_def_id = self.parent_def_id; + let def_scope_default = || { + let anon_parent_node_id = tcx.hir.get_parent(anon_node_id); + parent_def_id == tcx.hir.local_def_id(anon_parent_node_id) + }; + let in_definition_scope = match tcx.hir.find(anon_node_id) { + Some(hir::map::NodeItem(item)) => match item.node { + // impl trait + hir::ItemKind::Existential(hir::ExistTy { + impl_trait_fn: Some(parent), + .. + }) => parent == self.parent_def_id, + // named existential types + hir::ItemKind::Existential(hir::ExistTy { + impl_trait_fn: None, + .. + }) => may_define_existential_type( + tcx, + self.parent_def_id, + anon_node_id, + ), + _ => def_scope_default(), + }, + Some(hir::map::NodeImplItem(item)) => match item.node { + hir::ImplItemKind::Existential(_) => may_define_existential_type( + tcx, + self.parent_def_id, + anon_node_id, + ), + _ => def_scope_default(), + }, + _ => bug!( + "expected (impl) item, found {}", + tcx.hir.node_to_string(anon_node_id), + ), + }; + if in_definition_scope { return self.fold_anon_ty(ty, def_id, substs); } debug!( "instantiate_anon_types_in_map: \ - encountered anon with wrong parent \ - def_id={:?} \ - anon_parent_def_id={:?}", - def_id, anon_parent_def_id + encountered anon outside it's definition scope \ + def_id={:?}", + def_id, ); } } @@ -733,6 +768,10 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { let ty_var = infcx.next_ty_var(TypeVariableOrigin::TypeInference(span)); let predicates_of = tcx.predicates_of(def_id); + debug!( + "instantiate_anon_types: predicates: {:#?}", + predicates_of, + ); let bounds = predicates_of.instantiate(tcx, substs); debug!("instantiate_anon_types: bounds={:?}", bounds); @@ -742,6 +781,18 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { required_region_bounds ); + // make sure that we are in fact defining the *entire* type + // e.g. `existential type Foo: Bar;` needs to be + // defined by a function like `fn foo() -> Foo`. + debug!( + "instantiate_anon_types: param_env: {:#?}", + self.param_env, + ); + debug!( + "instantiate_anon_types: generics: {:#?}", + tcx.generics_of(def_id), + ); + self.anon_types.insert( def_id, AnonTypeDecl { @@ -769,3 +820,42 @@ impl<'a, 'gcx, 'tcx> Instantiator<'a, 'gcx, 'tcx> { ty_var } } + +/// Whether `anon_node_id` is a sibling or a child of a sibling of `def_id` +/// +/// ```rust +/// pub mod foo { +/// pub mod bar { +/// pub existential type Baz; +/// +/// fn f1() -> Baz { .. } +/// } +/// +/// fn f2() -> bar::Baz { .. } +/// } +/// ``` +/// +/// Here, `def_id` will be the `DefId` of the existential type `Baz`. +/// `anon_node_id` is the `NodeId` of the reference to Baz -- so either the return type of f1 or f2. +/// We will return true if the reference is within the same module as the existential type +/// So true for f1, false for f2. +pub fn may_define_existential_type( + tcx: TyCtxt, + def_id: DefId, + anon_node_id: ast::NodeId, +) -> bool { + let mut node_id = tcx + .hir + .as_local_node_id(def_id) + .unwrap(); + // named existential types can be defined by any siblings or + // children of siblings + let mod_id = tcx.hir.get_parent(anon_node_id); + // so we walk up the node tree until we hit the root or the parent + // of the anon type + while node_id != mod_id && node_id != ast::CRATE_NODE_ID { + node_id = tcx.hir.get_parent(node_id); + } + // syntactically we are allowed to define the concrete type + node_id == mod_id +} diff --git a/src/librustc/infer/canonical.rs b/src/librustc/infer/canonical.rs deleted file mode 100644 index 4bb191a878fdb..0000000000000 --- a/src/librustc/infer/canonical.rs +++ /dev/null @@ -1,925 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! **Canonicalization** is the key to constructing a query in the -//! middle of type inference. Ordinarily, it is not possible to store -//! types from type inference in query keys, because they contain -//! references to inference variables whose lifetimes are too short -//! and so forth. Canonicalizing a value T1 using `canonicalize_query` -//! produces two things: -//! -//! - a value T2 where each unbound inference variable has been -//! replaced with a **canonical variable**; -//! - a map M (of type `CanonicalVarValues`) from those canonical -//! variables back to the original. -//! -//! We can then do queries using T2. These will give back constriants -//! on the canonical variables which can be translated, using the map -//! M, into constraints in our source context. This process of -//! translating the results back is done by the -//! `instantiate_query_result` method. -//! -//! For a more detailed look at what is happening here, check -//! out the [chapter in the rustc guide][c]. -//! -//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html - -use infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TypeVariableOrigin}; -use rustc_data_structures::indexed_vec::Idx; -use serialize::UseSpecializedDecodable; -use std::fmt::Debug; -use std::ops::Index; -use std::sync::atomic::Ordering; -use syntax::codemap::Span; -use traits::{Obligation, ObligationCause, PredicateObligation}; -use ty::{self, CanonicalVar, Lift, Region, Slice, Ty, TyCtxt, TypeFlags}; -use ty::subst::{Kind, UnpackedKind}; -use ty::fold::{TypeFoldable, TypeFolder}; - -use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::fx::FxHashMap; - -/// A "canonicalized" type `V` is one where all free inference -/// variables have been rewriten to "canonical vars". These are -/// numbered starting from 0 in order of first appearance. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -pub struct Canonical<'gcx, V> { - pub variables: CanonicalVarInfos<'gcx>, - pub value: V, -} - -pub type CanonicalVarInfos<'gcx> = &'gcx Slice; - -impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> { } - -/// A set of values corresponding to the canonical variables from some -/// `Canonical`. You can give these values to -/// `canonical_value.substitute` to substitute them into the canonical -/// value at the right places. -/// -/// When you canonicalize a value `V`, you get back one of these -/// vectors with the original values that were replaced by canonical -/// variables. -/// -/// You can also use `infcx.fresh_inference_vars_for_canonical_vars` -/// to get back a `CanonicalVarValues` containing fresh inference -/// variables. -#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -pub struct CanonicalVarValues<'tcx> { - pub var_values: IndexVec>, -} - -/// Information about a canonical variable that is included with the -/// canonical value. This is sufficient information for code to create -/// a copy of the canonical value in some other inference context, -/// with fresh inference variables replacing the canonical values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -pub struct CanonicalVarInfo { - pub kind: CanonicalVarKind, -} - -/// Describes the "kind" of the canonical variable. This is a "kind" -/// in the type-theory sense of the term -- i.e., a "meta" type system -/// that analyzes type-like values. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -pub enum CanonicalVarKind { - /// Some kind of type inference variable. - Ty(CanonicalTyVarKind), - - /// Region variable `'?R`. - Region, -} - -/// Rust actually has more than one category of type variables; -/// notably, the type variables we create for literals (e.g., 22 or -/// 22.) can only be instantiated with integral/float types (e.g., -/// usize or f32). In order to faithfully reproduce a type, we need to -/// know what set of types a given type variable can be unified with. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] -pub enum CanonicalTyVarKind { - /// General type variable `?T` that can be unified with arbitrary types. - General, - - /// Integral type variable `?I` (that can only be unified with integral types). - Int, - - /// Floating-point type variable `?F` (that can only be unified with float types). - Float, -} - -/// After we execute a query with a canonicalized key, we get back a -/// `Canonical>`. You can use -/// `instantiate_query_result` to access the data in this result. -#[derive(Clone, Debug)] -pub struct QueryResult<'tcx, R> { - pub var_values: CanonicalVarValues<'tcx>, - pub region_constraints: Vec>, - pub certainty: Certainty, - pub value: R, -} - -/// Indicates whether or not we were able to prove the query to be -/// true. -#[derive(Copy, Clone, Debug)] -pub enum Certainty { - /// The query is known to be true, presuming that you apply the - /// given `var_values` and the region-constraints are satisfied. - Proven, - - /// The query is not known to be true, but also not known to be - /// false. The `var_values` represent *either* values that must - /// hold in order for the query to be true, or helpful tips that - /// *might* make it true. Currently rustc's trait solver cannot - /// distinguish the two (e.g., due to our preference for where - /// clauses over impls). - /// - /// After some unifiations and things have been done, it makes - /// sense to try and prove again -- of course, at that point, the - /// canonical form will be different, making this a distinct - /// query. - Ambiguous, -} - -impl Certainty { - pub fn is_proven(&self) -> bool { - match self { - Certainty::Proven => true, - Certainty::Ambiguous => false, - } - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, R> QueryResult<'tcx, R> { - pub fn is_proven(&self) -> bool { - self.certainty.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> { - pub fn is_proven(&self) -> bool { - self.value.is_proven() - } - - pub fn is_ambiguous(&self) -> bool { - !self.is_proven() - } -} - -pub type QueryRegionConstraint<'tcx> = ty::Binder, Region<'tcx>>>; - -/// Trait implemented by values that can be canonicalized. It mainly -/// serves to identify the interning table we will use. -pub trait Canonicalize<'gcx: 'tcx, 'tcx>: TypeFoldable<'tcx> + Lift<'gcx> { - type Canonicalized: 'gcx + Debug; - - /// After a value has been fully canonicalized and lifted, this - /// method will allocate it in a global arena. - fn intern( - gcx: TyCtxt<'_, 'gcx, 'gcx>, - value: Canonical<'gcx, Self::Lifted>, - ) -> Self::Canonicalized; -} - -impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { - /// Creates a substitution S for the canonical value with fresh - /// inference variables and applies it to the canonical value. - /// Returns both the instantiated result *and* the substitution S. - /// - /// This is useful at the start of a query: it basically brings - /// the canonical value "into scope" within your new infcx. At the - /// end of processing, the substitution S (once canonicalized) - /// then represents the values that you computed for each of the - /// canonical inputs to your query. - pub fn instantiate_canonical_with_fresh_inference_vars( - &self, - span: Span, - canonical: &Canonical<'tcx, T>, - ) -> (T, CanonicalVarValues<'tcx>) - where - T: TypeFoldable<'tcx>, - { - let canonical_inference_vars = - self.fresh_inference_vars_for_canonical_vars(span, canonical.variables); - let result = canonical.substitute(self.tcx, &canonical_inference_vars); - (result, canonical_inference_vars) - } - - /// Given the "infos" about the canonical variables from some - /// canonical, creates fresh inference variables with the same - /// characteristics. You can then use `substitute` to instantiate - /// the canonical variable with these inference variables. - pub fn fresh_inference_vars_for_canonical_vars( - &self, - span: Span, - variables: &Slice, - ) -> CanonicalVarValues<'tcx> { - let var_values: IndexVec> = variables - .iter() - .map(|info| self.fresh_inference_var_for_canonical_var(span, *info)) - .collect(); - - CanonicalVarValues { var_values } - } - - /// Given the "info" about a canonical variable, creates a fresh - /// inference variable with the same characteristics. - pub fn fresh_inference_var_for_canonical_var( - &self, - span: Span, - cv_info: CanonicalVarInfo, - ) -> Kind<'tcx> { - match cv_info.kind { - CanonicalVarKind::Ty(ty_kind) => { - let ty = match ty_kind { - CanonicalTyVarKind::General => { - self.next_ty_var( - TypeVariableOrigin::MiscVariable(span), - ) - } - - CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()), - - CanonicalTyVarKind::Float => self.tcx.mk_float_var(self.next_float_var_id()), - }; - Kind::from(ty) - } - - CanonicalVarKind::Region => { - Kind::from(self.next_region_var(RegionVariableOrigin::MiscVariable(span))) - } - } - } - - /// Given the (canonicalized) result to a canonical query, - /// instantiates the result so it can be used, plugging in the - /// values from the canonical query. (Note that the result may - /// have been ambiguous; you should check the certainty level of - /// the query before applying this function.) - /// - /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. - /// - /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#processing-the-canonicalized-query-result - pub fn instantiate_query_result( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - original_values: &CanonicalVarValues<'tcx>, - query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, - ) -> InferResult<'tcx, R> - where - R: Debug + TypeFoldable<'tcx>, - { - debug!( - "instantiate_query_result(original_values={:#?}, query_result={:#?})", - original_values, query_result, - ); - - // Every canonical query result includes values for each of - // the inputs to the query. Therefore, we begin by unifying - // these values with the original inputs that were - // canonicalized. - let result_values = &query_result.value.var_values; - assert_eq!(original_values.len(), result_values.len()); - - // Quickly try to find initial values for the canonical - // variables in the result in terms of the query. We do this - // by iterating down the values that the query gave to each of - // the canonical inputs. If we find that one of those values - // is directly equal to one of the canonical variables in the - // result, then we can type the corresponding value from the - // input. See the example above. - let mut opt_values: IndexVec>> = - IndexVec::from_elem_n(None, query_result.variables.len()); - - // In terms of our example above, we are iterating over pairs like: - // [(?A, Vec), ('static, '?1), (?B, ?0)] - for (original_value, result_value) in original_values.iter().zip(result_values) { - match result_value.unpack() { - UnpackedKind::Type(result_value) => { - // e.g., here `result_value` might be `?0` in the example above... - if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty { - // in which case we would set `canonical_vars[0]` to `Some(?U)`. - opt_values[index] = Some(original_value); - } - } - UnpackedKind::Lifetime(result_value) => { - // e.g., here `result_value` might be `'?1` in the example above... - if let &ty::RegionKind::ReCanonical(index) = result_value { - // in which case we would set `canonical_vars[0]` to `Some('static)`. - opt_values[index] = Some(original_value); - } - } - } - } - - // Create a result substitution: if we found a value for a - // given variable in the loop above, use that. Otherwise, use - // a fresh inference variable. - let result_subst = &CanonicalVarValues { - var_values: query_result - .variables - .iter() - .enumerate() - .map(|(index, info)| match opt_values[CanonicalVar::new(index)] { - Some(k) => k, - None => self.fresh_inference_var_for_canonical_var(cause.span, *info), - }) - .collect(), - }; - - // Unify the original values for the canonical variables in - // the input with the value found in the query - // post-substitution. Often, but not always, this is a no-op, - // because we already found the mapping in the first step. - let substituted_values = |index: CanonicalVar| -> Kind<'tcx> { - query_result.substitute_projected(self.tcx, result_subst, |v| &v.var_values[index]) - }; - let mut obligations = - self.unify_canonical_vars(cause, param_env, original_values, substituted_values)? - .into_obligations(); - - obligations.extend(self.query_region_constraints_into_obligations( - cause, - param_env, - &query_result.value.region_constraints, - result_subst, - )); - - let user_result: R = - query_result.substitute_projected(self.tcx, result_subst, |q_r| &q_r.value); - - Ok(InferOk { - value: user_result, - obligations, - }) - } - - /// Converts the region constraints resulting from a query into an - /// iterator of obligations. - fn query_region_constraints_into_obligations<'a>( - &'a self, - cause: &'a ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>], - result_subst: &'a CanonicalVarValues<'tcx>, - ) -> impl Iterator> + 'a { - Box::new(unsubstituted_region_constraints.iter().map(move |constraint| { - let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below - let k1 = substitute_value(self.tcx, result_subst, k1); - let r2 = substitute_value(self.tcx, result_subst, r2); - match k1.unpack() { - UnpackedKind::Lifetime(r1) => - Obligation::new( - cause.clone(), - param_env, - ty::Predicate::RegionOutlives( - ty::Binder::dummy(ty::OutlivesPredicate(r1, r2))), - ), - - UnpackedKind::Type(t1) => - Obligation::new( - cause.clone(), - param_env, - ty::Predicate::TypeOutlives( - ty::Binder::dummy(ty::OutlivesPredicate(t1, r2))), - ), - } - })) as Box> - } - - /// Given two sets of values for the same set of canonical variables, unify them. - /// The second set is produced lazilly by supplying indices from the first set. - fn unify_canonical_vars( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - variables1: &CanonicalVarValues<'tcx>, - variables2: impl Fn(CanonicalVar) -> Kind<'tcx>, - ) -> InferResult<'tcx, ()> { - self.commit_if_ok(|_| { - let mut obligations = vec![]; - for (index, value1) in variables1.var_values.iter_enumerated() { - let value2 = variables2(index); - - match (value1.unpack(), value2.unpack()) { - (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { - obligations - .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); - } - ( - UnpackedKind::Lifetime(ty::ReErased), - UnpackedKind::Lifetime(ty::ReErased), - ) => { - // no action needed - } - (UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => { - obligations - .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); - } - _ => { - bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); - } - } - } - Ok(InferOk { - value: (), - obligations, - }) - }) - } - - /// Canonicalizes a query value `V`. When we canonicalize a query, - /// we not only canonicalize unbound inference variables, but we - /// *also* replace all free regions whatsoever. So for example a - /// query like `T: Trait<'static>` would be canonicalized to - /// - /// ```text - /// T: Trait<'?0> - /// ``` - /// - /// with a mapping M that maps `'?0` to `'static`. - /// - /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. - /// - /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query - pub fn canonicalize_query(&self, value: &V) -> (V::Canonicalized, CanonicalVarValues<'tcx>) - where - V: Canonicalize<'gcx, 'tcx>, - { - self.tcx.sess.perf_stats.queries_canonicalized.fetch_add(1, Ordering::Relaxed); - - Canonicalizer::canonicalize( - value, - Some(self), - self.tcx, - CanonicalizeAllFreeRegions(true), - ) - } - - /// Canonicalizes a query *response* `V`. When we canonicalize a - /// query response, we only canonicalize unbound inference - /// variables, and we leave other free regions alone. So, - /// continuing with the example from `canonicalize_query`, if - /// there was an input query `T: Trait<'static>`, it would have - /// been canonicalized to - /// - /// ```text - /// T: Trait<'?0> - /// ``` - /// - /// with a mapping M that maps `'?0` to `'static`. But if we found that there - /// exists only one possible impl of `Trait`, and it looks like - /// - /// impl Trait<'static> for T { .. } - /// - /// then we would prepare a query result R that (among other - /// things) includes a mapping to `'?0 := 'static`. When - /// canonicalizing this query result R, we would leave this - /// reference to `'static` alone. - /// - /// To get a good understanding of what is happening here, check - /// out the [chapter in the rustc guide][c]. - /// - /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits-canonicalization.html#canonicalizing-the-query-result - pub fn canonicalize_response( - &self, - value: &V, - ) -> (V::Canonicalized, CanonicalVarValues<'tcx>) - where - V: Canonicalize<'gcx, 'tcx>, - { - Canonicalizer::canonicalize( - value, - Some(self), - self.tcx, - CanonicalizeAllFreeRegions(false), - ) - } -} - -/// If this flag is true, then all free regions will be replaced with -/// a canonical var. This is used to make queries as generic as -/// possible. For example, the query `F: Foo<'static>` would be -/// canonicalized to `F: Foo<'0>`. -struct CanonicalizeAllFreeRegions(bool); - -struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - variables: IndexVec, - indices: FxHashMap, CanonicalVar>, - var_values: IndexVec>, - canonicalize_all_free_regions: CanonicalizeAllFreeRegions, - needs_canonical_flags: TypeFlags, -} - -impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { - self.tcx - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match *r { - ty::ReLateBound(..) => { - // leave bound regions alone - r - } - - ty::ReVar(vid) => { - let r = self.infcx - .unwrap() - .borrow_region_constraints() - .opportunistic_resolve_var(self.tcx, vid); - let info = CanonicalVarInfo { - kind: CanonicalVarKind::Region, - }; - debug!( - "canonical: region var found with vid {:?}, \ - opportunistically resolved to {:?}", - vid, r - ); - let cvar = self.canonical_var(info, Kind::from(r)); - self.tcx().mk_region(ty::ReCanonical(cvar)) - } - - ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(_) - | ty::ReScope(_) - | ty::ReSkolemized(..) - | ty::ReEmpty - | ty::ReErased => { - if self.canonicalize_all_free_regions.0 { - let info = CanonicalVarInfo { - kind: CanonicalVarKind::Region, - }; - let cvar = self.canonical_var(info, Kind::from(r)); - self.tcx().mk_region(ty::ReCanonical(cvar)) - } else { - r - } - } - - ty::ReClosureBound(..) | ty::ReCanonical(_) => { - bug!("canonical region encountered during canonicalization") - } - } - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.sty { - ty::TyInfer(ty::TyVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::General, t), - - ty::TyInfer(ty::IntVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Int, t), - - ty::TyInfer(ty::FloatVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Float, t), - - ty::TyInfer(ty::FreshTy(_)) - | ty::TyInfer(ty::FreshIntTy(_)) - | ty::TyInfer(ty::FreshFloatTy(_)) => { - bug!("encountered a fresh type during canonicalization") - } - - ty::TyInfer(ty::CanonicalTy(_)) => { - bug!("encountered a canonical type during canonicalization") - } - - ty::TyClosure(..) - | ty::TyGenerator(..) - | ty::TyGeneratorWitness(..) - | ty::TyBool - | ty::TyChar - | ty::TyInt(..) - | ty::TyUint(..) - | ty::TyFloat(..) - | ty::TyAdt(..) - | ty::TyStr - | ty::TyError - | ty::TyArray(..) - | ty::TySlice(..) - | ty::TyRawPtr(..) - | ty::TyRef(..) - | ty::TyFnDef(..) - | ty::TyFnPtr(_) - | ty::TyDynamic(..) - | ty::TyNever - | ty::TyTuple(..) - | ty::TyProjection(..) - | ty::TyForeign(..) - | ty::TyParam(..) - | ty::TyAnon(..) => { - if t.flags.intersects(self.needs_canonical_flags) { - t.super_fold_with(self) - } else { - t - } - } - } - } -} - -impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { - /// The main `canonicalize` method, shared impl of - /// `canonicalize_query` and `canonicalize_response`. - fn canonicalize( - value: &V, - infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - canonicalize_all_free_regions: CanonicalizeAllFreeRegions, - ) -> (V::Canonicalized, CanonicalVarValues<'tcx>) - where - V: Canonicalize<'gcx, 'tcx>, - { - debug_assert!( - !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS), - "canonicalizing a canonical value: {:?}", - value, - ); - - let needs_canonical_flags = if canonicalize_all_free_regions.0 { - TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX - } else { - TypeFlags::KEEP_IN_LOCAL_TCX - }; - - let gcx = tcx.global_tcx(); - - // Fast path: nothing that needs to be canonicalized. - if !value.has_type_flags(needs_canonical_flags) { - let out_value = gcx.lift(value).unwrap(); - let canon_value = V::intern( - gcx, - Canonical { - variables: Slice::empty(), - value: out_value, - }, - ); - let values = CanonicalVarValues { - var_values: IndexVec::default(), - }; - return (canon_value, values); - } - - let mut canonicalizer = Canonicalizer { - infcx, - tcx, - canonicalize_all_free_regions, - needs_canonical_flags, - variables: IndexVec::default(), - indices: FxHashMap::default(), - var_values: IndexVec::default(), - }; - let out_value = value.fold_with(&mut canonicalizer); - - // Once we have canonicalized `out_value`, it should not - // contain anything that ties it to this inference context - // anymore, so it should live in the global arena. - let out_value = gcx.lift(&out_value).unwrap_or_else(|| { - bug!( - "failed to lift `{:?}`, canonicalized from `{:?}`", - out_value, - value - ) - }); - - let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables.raw); - - let canonical_value = V::intern( - gcx, - Canonical { - variables: canonical_variables, - value: out_value, - }, - ); - let canonical_var_values = CanonicalVarValues { - var_values: canonicalizer.var_values, - }; - (canonical_value, canonical_var_values) - } - - /// Creates a canonical variable replacing `kind` from the input, - /// or returns an existing variable if `kind` has already been - /// seen. `kind` is expected to be an unbound variable (or - /// potentially a free region). - fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> CanonicalVar { - let Canonicalizer { - indices, - variables, - var_values, - .. - } = self; - - indices - .entry(kind) - .or_insert_with(|| { - let cvar1 = variables.push(info); - let cvar2 = var_values.push(kind); - assert_eq!(cvar1, cvar2); - cvar1 - }) - .clone() - } - - /// Given a type variable `ty_var` of the given kind, first check - /// if `ty_var` is bound to anything; if so, canonicalize - /// *that*. Otherwise, create a new canonical variable for - /// `ty_var`. - fn canonicalize_ty_var(&mut self, ty_kind: CanonicalTyVarKind, ty_var: Ty<'tcx>) -> Ty<'tcx> { - let infcx = self.infcx.expect("encountered ty-var without infcx"); - let bound_to = infcx.shallow_resolve(ty_var); - if bound_to != ty_var { - self.fold_ty(bound_to) - } else { - let info = CanonicalVarInfo { - kind: CanonicalVarKind::Ty(ty_kind), - }; - let cvar = self.canonical_var(info, Kind::from(ty_var)); - self.tcx().mk_infer(ty::InferTy::CanonicalTy(cvar)) - } - } -} - -impl<'tcx, V> Canonical<'tcx, V> { - /// Instantiate the wrapped value, replacing each canonical value - /// with the value given in `var_values`. - fn substitute(&self, tcx: TyCtxt<'_, '_, 'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V - where - V: TypeFoldable<'tcx>, - { - self.substitute_projected(tcx, var_values, |value| value) - } - - /// Invoke `projection_fn` with `self.value` to get a value V that - /// is expressed in terms of the same canonical variables bound in - /// `self`. Apply the substitution `var_values` to this value V, - /// replacing each of the canonical variables. - fn substitute_projected( - &self, - tcx: TyCtxt<'_, '_, 'tcx>, - var_values: &CanonicalVarValues<'tcx>, - projection_fn: impl FnOnce(&V) -> &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - assert_eq!(self.variables.len(), var_values.var_values.len()); - let value = projection_fn(&self.value); - substitute_value(tcx, var_values, value) - } -} - -/// Substitute the values from `var_values` into `value`. `var_values` -/// must be values for the set of cnaonical variables that appear in -/// `value`. -fn substitute_value<'a, 'tcx, T>( - tcx: TyCtxt<'_, '_, 'tcx>, - var_values: &CanonicalVarValues<'tcx>, - value: &'a T, -) -> T -where - T: TypeFoldable<'tcx>, -{ - if var_values.var_values.is_empty() { - debug_assert!(!value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS)); - value.clone() - } else if !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) { - value.clone() - } else { - value.fold_with(&mut CanonicalVarValuesSubst { tcx, var_values }) - } -} - -struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> { - tcx: TyCtxt<'cx, 'gcx, 'tcx>, - var_values: &'cx CanonicalVarValues<'tcx>, -} - -impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> { - fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { - self.tcx - } - - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.sty { - ty::TyInfer(ty::InferTy::CanonicalTy(c)) => { - match self.var_values.var_values[c].unpack() { - UnpackedKind::Type(ty) => ty, - r => bug!("{:?} is a type but value is {:?}", c, r), - } - } - _ => { - if !t.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) { - t - } else { - t.super_fold_with(self) - } - } - } - } - - fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { - match r { - ty::RegionKind::ReCanonical(c) => match self.var_values.var_values[*c].unpack() { - UnpackedKind::Lifetime(l) => l, - r => bug!("{:?} is a region but value is {:?}", c, r), - }, - _ => r.super_fold_with(self), - } - } -} - -CloneTypeFoldableAndLiftImpls! { - ::infer::canonical::Certainty, - ::infer::canonical::CanonicalVarInfo, - ::infer::canonical::CanonicalVarKind, -} - -CloneTypeFoldableImpls! { - for <'tcx> { - ::infer::canonical::CanonicalVarInfos<'tcx>, - } -} - -BraceStructTypeFoldableImpl! { - impl<'tcx, C> TypeFoldable<'tcx> for Canonical<'tcx, C> { - variables, - value, - } where C: TypeFoldable<'tcx> -} - -BraceStructLiftImpl! { - impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> { - type Lifted = Canonical<'tcx, T::Lifted>; - variables, value - } where T: Lift<'tcx> -} - -impl<'tcx> CanonicalVarValues<'tcx> { - fn iter<'a>(&'a self) -> impl Iterator> + 'a { - self.var_values.iter().cloned() - } - - fn len(&self) -> usize { - self.var_values.len() - } -} - -impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { - type Item = Kind<'tcx>; - type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, Kind<'tcx>>>; - - fn into_iter(self) -> Self::IntoIter { - self.var_values.iter().cloned() - } -} - -BraceStructLiftImpl! { - impl<'a, 'tcx> Lift<'tcx> for CanonicalVarValues<'a> { - type Lifted = CanonicalVarValues<'tcx>; - var_values, - } -} - -BraceStructTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for CanonicalVarValues<'tcx> { - var_values, - } -} - -BraceStructTypeFoldableImpl! { - impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> { - var_values, region_constraints, certainty, value - } where R: TypeFoldable<'tcx>, -} - -BraceStructLiftImpl! { - impl<'a, 'tcx, R> Lift<'tcx> for QueryResult<'a, R> { - type Lifted = QueryResult<'tcx, R::Lifted>; - var_values, region_constraints, certainty, value - } where R: Lift<'tcx> -} - -impl<'tcx> Index for CanonicalVarValues<'tcx> { - type Output = Kind<'tcx>; - - fn index(&self, value: CanonicalVar) -> &Kind<'tcx> { - &self.var_values[value] - } -} diff --git a/src/librustc/infer/canonical/canonicalizer.rs b/src/librustc/infer/canonical/canonicalizer.rs new file mode 100644 index 0000000000000..c4de95c60bff5 --- /dev/null +++ b/src/librustc/infer/canonical/canonicalizer.rs @@ -0,0 +1,439 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains the "canonicalizer" itself. +//! +//! For an overview of what canonicaliation is and how it fits into +//! rustc, check out the [chapter in the rustc guide][c]. +//! +//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html + +use infer::canonical::{ + Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized, + SmallCanonicalVarValues, +}; +use infer::InferCtxt; +use std::sync::atomic::Ordering; +use ty::fold::{TypeFoldable, TypeFolder}; +use ty::subst::Kind; +use ty::{self, CanonicalVar, Lift, Slice, Ty, TyCtxt, TypeFlags}; + +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::small_vec::SmallVec; + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// Canonicalizes a query value `V`. When we canonicalize a query, + /// we not only canonicalize unbound inference variables, but we + /// *also* replace all free regions whatsoever. So for example a + /// query like `T: Trait<'static>` would be canonicalized to + /// + /// ```text + /// T: Trait<'?0> + /// ``` + /// + /// with a mapping M that maps `'?0` to `'static`. + /// + /// To get a good understanding of what is happening here, check + /// out the [chapter in the rustc guide][c]. + /// + /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query + pub fn canonicalize_query( + &self, + value: &V, + var_values: &mut SmallCanonicalVarValues<'tcx> + ) -> Canonicalized<'gcx, V> + where + V: TypeFoldable<'tcx> + Lift<'gcx>, + { + self.tcx + .sess + .perf_stats + .queries_canonicalized + .fetch_add(1, Ordering::Relaxed); + + Canonicalizer::canonicalize( + value, + Some(self), + self.tcx, + CanonicalizeRegionMode { + static_region: true, + other_free_regions: true, + }, + var_values, + ) + } + + /// Canonicalizes a query *response* `V`. When we canonicalize a + /// query response, we only canonicalize unbound inference + /// variables, and we leave other free regions alone. So, + /// continuing with the example from `canonicalize_query`, if + /// there was an input query `T: Trait<'static>`, it would have + /// been canonicalized to + /// + /// ```text + /// T: Trait<'?0> + /// ``` + /// + /// with a mapping M that maps `'?0` to `'static`. But if we found that there + /// exists only one possible impl of `Trait`, and it looks like + /// + /// impl Trait<'static> for T { .. } + /// + /// then we would prepare a query result R that (among other + /// things) includes a mapping to `'?0 := 'static`. When + /// canonicalizing this query result R, we would leave this + /// reference to `'static` alone. + /// + /// To get a good understanding of what is happening here, check + /// out the [chapter in the rustc guide][c]. + /// + /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#canonicalizing-the-query-result + pub fn canonicalize_response( + &self, + value: &V, + ) -> Canonicalized<'gcx, V> + where + V: TypeFoldable<'tcx> + Lift<'gcx>, + { + let mut var_values = SmallVec::new(); + Canonicalizer::canonicalize( + value, + Some(self), + self.tcx, + CanonicalizeRegionMode { + static_region: false, + other_free_regions: false, + }, + &mut var_values + ) + } + + /// A hacky variant of `canonicalize_query` that does not + /// canonicalize `'static`. Unfortunately, the existing leak + /// check treaks `'static` differently in some cases (see also + /// #33684), so if we are performing an operation that may need to + /// prove "leak-check" related things, we leave `'static` + /// alone. + /// + /// FIXME(#48536) -- once we have universes, we can remove this and just use + /// `canonicalize_query`. + pub fn canonicalize_hr_query_hack( + &self, + value: &V, + var_values: &mut SmallCanonicalVarValues<'tcx> + ) -> Canonicalized<'gcx, V> + where + V: TypeFoldable<'tcx> + Lift<'gcx>, + { + self.tcx + .sess + .perf_stats + .queries_canonicalized + .fetch_add(1, Ordering::Relaxed); + + Canonicalizer::canonicalize( + value, + Some(self), + self.tcx, + CanonicalizeRegionMode { + static_region: false, + other_free_regions: true, + }, + var_values + ) + } +} + +/// If this flag is true, then all free regions will be replaced with +/// a canonical var. This is used to make queries as generic as +/// possible. For example, the query `F: Foo<'static>` would be +/// canonicalized to `F: Foo<'0>`. +struct CanonicalizeRegionMode { + static_region: bool, + other_free_regions: bool, +} + +impl CanonicalizeRegionMode { + fn any(&self) -> bool { + self.static_region || self.other_free_regions + } +} + +struct Canonicalizer<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + variables: SmallVec<[CanonicalVarInfo; 8]>, + var_values: &'cx mut SmallCanonicalVarValues<'tcx>, + // Note that indices is only used once `var_values` is big enough to be + // heap-allocated. + indices: FxHashMap, CanonicalVar>, + canonicalize_region_mode: CanonicalizeRegionMode, + needs_canonical_flags: TypeFlags, +} + +impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for Canonicalizer<'cx, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match *r { + ty::ReLateBound(..) => { + // leave bound regions alone + r + } + + ty::ReVar(vid) => { + let r = self + .infcx + .unwrap() + .borrow_region_constraints() + .opportunistic_resolve_var(self.tcx, vid); + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + }; + debug!( + "canonical: region var found with vid {:?}, \ + opportunistically resolved to {:?}", + vid, r + ); + let cvar = self.canonical_var(info, r.into()); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } + + ty::ReStatic => { + if self.canonicalize_region_mode.static_region { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + }; + let cvar = self.canonical_var(info, r.into()); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } else { + r + } + } + + ty::ReEarlyBound(..) + | ty::ReFree(_) + | ty::ReScope(_) + | ty::ReSkolemized(..) + | ty::ReEmpty + | ty::ReErased => { + if self.canonicalize_region_mode.other_free_regions { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Region, + }; + let cvar = self.canonical_var(info, r.into()); + self.tcx().mk_region(ty::ReCanonical(cvar)) + } else { + r + } + } + + ty::ReClosureBound(..) | ty::ReCanonical(_) => { + bug!("canonical region encountered during canonicalization") + } + } + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.sty { + ty::TyInfer(ty::TyVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::General, t), + + ty::TyInfer(ty::IntVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Int, t), + + ty::TyInfer(ty::FloatVar(_)) => self.canonicalize_ty_var(CanonicalTyVarKind::Float, t), + + ty::TyInfer(ty::FreshTy(_)) + | ty::TyInfer(ty::FreshIntTy(_)) + | ty::TyInfer(ty::FreshFloatTy(_)) => { + bug!("encountered a fresh type during canonicalization") + } + + ty::TyInfer(ty::CanonicalTy(_)) => { + bug!("encountered a canonical type during canonicalization") + } + + ty::TyClosure(..) + | ty::TyGenerator(..) + | ty::TyGeneratorWitness(..) + | ty::TyBool + | ty::TyChar + | ty::TyInt(..) + | ty::TyUint(..) + | ty::TyFloat(..) + | ty::TyAdt(..) + | ty::TyStr + | ty::TyError + | ty::TyArray(..) + | ty::TySlice(..) + | ty::TyRawPtr(..) + | ty::TyRef(..) + | ty::TyFnDef(..) + | ty::TyFnPtr(_) + | ty::TyDynamic(..) + | ty::TyNever + | ty::TyTuple(..) + | ty::TyProjection(..) + | ty::TyForeign(..) + | ty::TyParam(..) + | ty::TyAnon(..) => { + if t.flags.intersects(self.needs_canonical_flags) { + t.super_fold_with(self) + } else { + t + } + } + } + } +} + +impl<'cx, 'gcx, 'tcx> Canonicalizer<'cx, 'gcx, 'tcx> { + /// The main `canonicalize` method, shared impl of + /// `canonicalize_query` and `canonicalize_response`. + fn canonicalize( + value: &V, + infcx: Option<&'cx InferCtxt<'cx, 'gcx, 'tcx>>, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + canonicalize_region_mode: CanonicalizeRegionMode, + var_values: &'cx mut SmallCanonicalVarValues<'tcx> + ) -> Canonicalized<'gcx, V> + where + V: TypeFoldable<'tcx> + Lift<'gcx>, + { + debug_assert!( + !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS), + "canonicalizing a canonical value: {:?}", + value, + ); + + let needs_canonical_flags = if canonicalize_region_mode.any() { + TypeFlags::HAS_FREE_REGIONS | TypeFlags::KEEP_IN_LOCAL_TCX + } else { + TypeFlags::KEEP_IN_LOCAL_TCX + }; + + let gcx = tcx.global_tcx(); + + // Fast path: nothing that needs to be canonicalized. + if !value.has_type_flags(needs_canonical_flags) { + let out_value = gcx.lift(value).unwrap(); + let canon_value = Canonical { + variables: Slice::empty(), + value: out_value, + }; + return canon_value; + } + + let mut canonicalizer = Canonicalizer { + infcx, + tcx, + canonicalize_region_mode, + needs_canonical_flags, + variables: SmallVec::new(), + var_values, + indices: FxHashMap::default(), + }; + let out_value = value.fold_with(&mut canonicalizer); + + // Once we have canonicalized `out_value`, it should not + // contain anything that ties it to this inference context + // anymore, so it should live in the global arena. + let out_value = gcx.lift(&out_value).unwrap_or_else(|| { + bug!( + "failed to lift `{:?}`, canonicalized from `{:?}`", + out_value, + value + ) + }); + + let canonical_variables = tcx.intern_canonical_var_infos(&canonicalizer.variables); + + Canonical { + variables: canonical_variables, + value: out_value, + } + } + + /// Creates a canonical variable replacing `kind` from the input, + /// or returns an existing variable if `kind` has already been + /// seen. `kind` is expected to be an unbound variable (or + /// potentially a free region). + fn canonical_var(&mut self, info: CanonicalVarInfo, kind: Kind<'tcx>) -> CanonicalVar { + let Canonicalizer { + variables, + var_values, + indices, + .. + } = self; + + // This code is hot. `variables` and `var_values` are usually small + // (fewer than 8 elements ~95% of the time). They are SmallVec's to + // avoid allocations in those cases. We also don't use `indices` to + // determine if a kind has been seen before until the limit of 8 has + // been exceeded, to also avoid allocations for `indices`. + if var_values.is_array() { + // `var_values` is stack-allocated. `indices` isn't used yet. Do a + // direct linear search of `var_values`. + if let Some(idx) = var_values.iter().position(|&k| k == kind) { + // `kind` is already present in `var_values`. + CanonicalVar::new(idx) + } else { + // `kind` isn't present in `var_values`. Append it. Likewise + // for `info` and `variables`. + variables.push(info); + var_values.push(kind); + assert_eq!(variables.len(), var_values.len()); + + // If `var_values` has become big enough to be heap-allocated, + // fill up `indices` to facilitate subsequent lookups. + if !var_values.is_array() { + assert!(indices.is_empty()); + *indices = + var_values.iter() + .enumerate() + .map(|(i, &kind)| (kind, CanonicalVar::new(i))) + .collect(); + } + // The cv is the index of the appended element. + CanonicalVar::new(var_values.len() - 1) + } + } else { + // `var_values` is large. Do a hashmap search via `indices`. + *indices + .entry(kind) + .or_insert_with(|| { + variables.push(info); + var_values.push(kind); + assert_eq!(variables.len(), var_values.len()); + CanonicalVar::new(variables.len() - 1) + }) + } + } + + /// Given a type variable `ty_var` of the given kind, first check + /// if `ty_var` is bound to anything; if so, canonicalize + /// *that*. Otherwise, create a new canonical variable for + /// `ty_var`. + fn canonicalize_ty_var(&mut self, ty_kind: CanonicalTyVarKind, ty_var: Ty<'tcx>) -> Ty<'tcx> { + let infcx = self.infcx.expect("encountered ty-var without infcx"); + let bound_to = infcx.shallow_resolve(ty_var); + if bound_to != ty_var { + self.fold_ty(bound_to) + } else { + let info = CanonicalVarInfo { + kind: CanonicalVarKind::Ty(ty_kind), + }; + let cvar = self.canonical_var(info, ty_var.into()); + self.tcx().mk_infer(ty::InferTy::CanonicalTy(cvar)) + } + } +} diff --git a/src/librustc/infer/canonical/mod.rs b/src/librustc/infer/canonical/mod.rs new file mode 100644 index 0000000000000..958b339106050 --- /dev/null +++ b/src/librustc/infer/canonical/mod.rs @@ -0,0 +1,335 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! **Canonicalization** is the key to constructing a query in the +//! middle of type inference. Ordinarily, it is not possible to store +//! types from type inference in query keys, because they contain +//! references to inference variables whose lifetimes are too short +//! and so forth. Canonicalizing a value T1 using `canonicalize_query` +//! produces two things: +//! +//! - a value T2 where each unbound inference variable has been +//! replaced with a **canonical variable**; +//! - a map M (of type `CanonicalVarValues`) from those canonical +//! variables back to the original. +//! +//! We can then do queries using T2. These will give back constriants +//! on the canonical variables which can be translated, using the map +//! M, into constraints in our source context. This process of +//! translating the results back is done by the +//! `instantiate_query_result` method. +//! +//! For a more detailed look at what is happening here, check +//! out the [chapter in the rustc guide][c]. +//! +//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html + +use infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin}; +use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::small_vec::SmallVec; +use rustc_data_structures::sync::Lrc; +use serialize::UseSpecializedDecodable; +use std::ops::Index; +use syntax::codemap::Span; +use ty::fold::TypeFoldable; +use ty::subst::Kind; +use ty::{self, CanonicalVar, Lift, Region, Slice, TyCtxt}; + +mod canonicalizer; + +pub mod query_result; + +mod substitute; + +/// A "canonicalized" type `V` is one where all free inference +/// variables have been rewriten to "canonical vars". These are +/// numbered starting from 0 in order of first appearance. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +pub struct Canonical<'gcx, V> { + pub variables: CanonicalVarInfos<'gcx>, + pub value: V, +} + +pub type CanonicalVarInfos<'gcx> = &'gcx Slice; + +impl<'gcx> UseSpecializedDecodable for CanonicalVarInfos<'gcx> {} + +/// A set of values corresponding to the canonical variables from some +/// `Canonical`. You can give these values to +/// `canonical_value.substitute` to substitute them into the canonical +/// value at the right places. +/// +/// When you canonicalize a value `V`, you get back one of these +/// vectors with the original values that were replaced by canonical +/// variables. You will need to supply it later to instantiate the +/// canonicalized query response. +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +pub struct CanonicalVarValues<'tcx> { + pub var_values: IndexVec>, +} + +/// Like CanonicalVarValues, but for use in places where a SmallVec is +/// appropriate. +pub type SmallCanonicalVarValues<'tcx> = SmallVec<[Kind<'tcx>; 8]>; + +/// Information about a canonical variable that is included with the +/// canonical value. This is sufficient information for code to create +/// a copy of the canonical value in some other inference context, +/// with fresh inference variables replacing the canonical values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +pub struct CanonicalVarInfo { + pub kind: CanonicalVarKind, +} + +/// Describes the "kind" of the canonical variable. This is a "kind" +/// in the type-theory sense of the term -- i.e., a "meta" type system +/// that analyzes type-like values. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +pub enum CanonicalVarKind { + /// Some kind of type inference variable. + Ty(CanonicalTyVarKind), + + /// Region variable `'?R`. + Region, +} + +/// Rust actually has more than one category of type variables; +/// notably, the type variables we create for literals (e.g., 22 or +/// 22.) can only be instantiated with integral/float types (e.g., +/// usize or f32). In order to faithfully reproduce a type, we need to +/// know what set of types a given type variable can be unified with. +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, RustcDecodable, RustcEncodable)] +pub enum CanonicalTyVarKind { + /// General type variable `?T` that can be unified with arbitrary types. + General, + + /// Integral type variable `?I` (that can only be unified with integral types). + Int, + + /// Floating-point type variable `?F` (that can only be unified with float types). + Float, +} + +/// After we execute a query with a canonicalized key, we get back a +/// `Canonical>`. You can use +/// `instantiate_query_result` to access the data in this result. +#[derive(Clone, Debug)] +pub struct QueryResult<'tcx, R> { + pub var_values: CanonicalVarValues<'tcx>, + pub region_constraints: Vec>, + pub certainty: Certainty, + pub value: R, +} + +pub type Canonicalized<'gcx, V> = Canonical<'gcx, >::Lifted>; + +pub type CanonicalizedQueryResult<'gcx, T> = + Lrc>::Lifted>>>; + +/// Indicates whether or not we were able to prove the query to be +/// true. +#[derive(Copy, Clone, Debug)] +pub enum Certainty { + /// The query is known to be true, presuming that you apply the + /// given `var_values` and the region-constraints are satisfied. + Proven, + + /// The query is not known to be true, but also not known to be + /// false. The `var_values` represent *either* values that must + /// hold in order for the query to be true, or helpful tips that + /// *might* make it true. Currently rustc's trait solver cannot + /// distinguish the two (e.g., due to our preference for where + /// clauses over impls). + /// + /// After some unifiations and things have been done, it makes + /// sense to try and prove again -- of course, at that point, the + /// canonical form will be different, making this a distinct + /// query. + Ambiguous, +} + +impl Certainty { + pub fn is_proven(&self) -> bool { + match self { + Certainty::Proven => true, + Certainty::Ambiguous => false, + } + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, R> QueryResult<'tcx, R> { + pub fn is_proven(&self) -> bool { + self.certainty.is_proven() + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +impl<'tcx, R> Canonical<'tcx, QueryResult<'tcx, R>> { + pub fn is_proven(&self) -> bool { + self.value.is_proven() + } + + pub fn is_ambiguous(&self) -> bool { + !self.is_proven() + } +} + +pub type QueryRegionConstraint<'tcx> = ty::Binder, Region<'tcx>>>; + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// Creates a substitution S for the canonical value with fresh + /// inference variables and applies it to the canonical value. + /// Returns both the instantiated result *and* the substitution S. + /// + /// This is useful at the start of a query: it basically brings + /// the canonical value "into scope" within your new infcx. At the + /// end of processing, the substitution S (once canonicalized) + /// then represents the values that you computed for each of the + /// canonical inputs to your query. + pub fn instantiate_canonical_with_fresh_inference_vars( + &self, + span: Span, + canonical: &Canonical<'tcx, T>, + ) -> (T, CanonicalVarValues<'tcx>) + where + T: TypeFoldable<'tcx>, + { + let canonical_inference_vars = + self.fresh_inference_vars_for_canonical_vars(span, canonical.variables); + let result = canonical.substitute(self.tcx, &canonical_inference_vars); + (result, canonical_inference_vars) + } + + /// Given the "infos" about the canonical variables from some + /// canonical, creates fresh inference variables with the same + /// characteristics. You can then use `substitute` to instantiate + /// the canonical variable with these inference variables. + fn fresh_inference_vars_for_canonical_vars( + &self, + span: Span, + variables: &Slice, + ) -> CanonicalVarValues<'tcx> { + let var_values: IndexVec> = variables + .iter() + .map(|info| self.fresh_inference_var_for_canonical_var(span, *info)) + .collect(); + + CanonicalVarValues { var_values } + } + + /// Given the "info" about a canonical variable, creates a fresh + /// inference variable with the same characteristics. + fn fresh_inference_var_for_canonical_var( + &self, + span: Span, + cv_info: CanonicalVarInfo, + ) -> Kind<'tcx> { + match cv_info.kind { + CanonicalVarKind::Ty(ty_kind) => { + let ty = match ty_kind { + CanonicalTyVarKind::General => { + self.next_ty_var(TypeVariableOrigin::MiscVariable(span)) + } + + CanonicalTyVarKind::Int => self.tcx.mk_int_var(self.next_int_var_id()), + + CanonicalTyVarKind::Float => self.tcx.mk_float_var(self.next_float_var_id()), + }; + ty.into() + } + + CanonicalVarKind::Region => self + .next_region_var(RegionVariableOrigin::MiscVariable(span)) + .into(), + } + } +} + +CloneTypeFoldableAndLiftImpls! { + ::infer::canonical::Certainty, + ::infer::canonical::CanonicalVarInfo, + ::infer::canonical::CanonicalVarKind, +} + +CloneTypeFoldableImpls! { + for <'tcx> { + ::infer::canonical::CanonicalVarInfos<'tcx>, + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx, C> TypeFoldable<'tcx> for Canonical<'tcx, C> { + variables, + value, + } where C: TypeFoldable<'tcx> +} + +BraceStructLiftImpl! { + impl<'a, 'tcx, T> Lift<'tcx> for Canonical<'a, T> { + type Lifted = Canonical<'tcx, T::Lifted>; + variables, value + } where T: Lift<'tcx> +} + +impl<'tcx> CanonicalVarValues<'tcx> { + fn len(&self) -> usize { + self.var_values.len() + } +} + +impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> { + type Item = Kind<'tcx>; + type IntoIter = ::std::iter::Cloned<::std::slice::Iter<'a, Kind<'tcx>>>; + + fn into_iter(self) -> Self::IntoIter { + self.var_values.iter().cloned() + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for CanonicalVarValues<'a> { + type Lifted = CanonicalVarValues<'tcx>; + var_values, + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for CanonicalVarValues<'tcx> { + var_values, + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx, R> TypeFoldable<'tcx> for QueryResult<'tcx, R> { + var_values, region_constraints, certainty, value + } where R: TypeFoldable<'tcx>, +} + +BraceStructLiftImpl! { + impl<'a, 'tcx, R> Lift<'tcx> for QueryResult<'a, R> { + type Lifted = QueryResult<'tcx, R::Lifted>; + var_values, region_constraints, certainty, value + } where R: Lift<'tcx> +} + +impl<'tcx> Index for CanonicalVarValues<'tcx> { + type Output = Kind<'tcx>; + + fn index(&self, value: CanonicalVar) -> &Kind<'tcx> { + &self.var_values[value] + } +} diff --git a/src/librustc/infer/canonical/query_result.rs b/src/librustc/infer/canonical/query_result.rs new file mode 100644 index 0000000000000..f0b6d25e9dae8 --- /dev/null +++ b/src/librustc/infer/canonical/query_result.rs @@ -0,0 +1,610 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains the code to instantiate a "query result", and +//! in particular to extract out the resulting region obligations and +//! encode them therein. +//! +//! For an overview of what canonicaliation is and how it fits into +//! rustc, check out the [chapter in the rustc guide][c]. +//! +//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html + +use infer::canonical::substitute::substitute_value; +use infer::canonical::{ + Canonical, CanonicalVarKind, CanonicalVarValues, CanonicalizedQueryResult, Certainty, + QueryRegionConstraint, QueryResult, SmallCanonicalVarValues, +}; +use infer::region_constraints::{Constraint, RegionConstraintData}; +use infer::InferCtxtBuilder; +use infer::{InferCtxt, InferOk, InferResult, RegionObligation}; +use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::sync::Lrc; +use std::fmt::Debug; +use syntax::ast; +use syntax_pos::DUMMY_SP; +use traits::query::{Fallible, NoSolution}; +use traits::{FulfillmentContext, TraitEngine}; +use traits::{Obligation, ObligationCause, PredicateObligation}; +use ty::fold::TypeFoldable; +use ty::subst::{Kind, UnpackedKind}; +use ty::{self, CanonicalVar, Lift, TyCtxt}; + +impl<'cx, 'gcx, 'tcx> InferCtxtBuilder<'cx, 'gcx, 'tcx> { + /// The "main method" for a canonicalized trait query. Given the + /// canonical key `canonical_key`, this method will create a new + /// inference context, instantiate the key, and run your operation + /// `op`. The operation should yield up a result (of type `R`) as + /// well as a set of trait obligations that must be fully + /// satisfied. These obligations will be processed and the + /// canonical result created. + /// + /// Returns `NoSolution` in the event of any error. + /// + /// (It might be mildly nicer to implement this on `TyCtxt`, and + /// not `InferCtxtBuilder`, but that is a bit tricky right now. + /// In part because we would need a `for<'gcx: 'tcx>` sort of + /// bound for the closure and in part because it is convenient to + /// have `'tcx` be free on this function so that we can talk about + /// `K: TypeFoldable<'tcx>`.) + pub fn enter_canonical_trait_query( + &'tcx mut self, + canonical_key: &Canonical<'tcx, K>, + operation: impl FnOnce(&InferCtxt<'_, 'gcx, 'tcx>, &mut FulfillmentContext<'tcx>, K) + -> Fallible, + ) -> Fallible> + where + K: TypeFoldable<'tcx>, + R: Debug + Lift<'gcx> + TypeFoldable<'tcx>, + { + self.enter(|ref infcx| { + let (key, canonical_inference_vars) = + infcx.instantiate_canonical_with_fresh_inference_vars(DUMMY_SP, &canonical_key); + let fulfill_cx = &mut FulfillmentContext::new(); + let value = operation(infcx, fulfill_cx, key)?; + infcx.make_canonicalized_query_result(canonical_inference_vars, value, fulfill_cx) + }) + } +} + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// This method is meant to be invoked as the final step of a canonical query + /// implementation. It is given: + /// + /// - the instantiated variables `inference_vars` created from the query key + /// - the result `answer` of the query + /// - a fulfillment context `fulfill_cx` that may contain various obligations which + /// have yet to be proven. + /// + /// Given this, the function will process the obligations pending + /// in `fulfill_cx`: + /// + /// - If all the obligations can be proven successfully, it will + /// package up any resulting region obligations (extracted from + /// `infcx`) along with the fully resolved value `answer` into a + /// query result (which is then itself canonicalized). + /// - If some obligations can be neither proven nor disproven, then + /// the same thing happens, but the resulting query is marked as ambiguous. + /// - Finally, if any of the obligations result in a hard error, + /// then `Err(NoSolution)` is returned. + pub fn make_canonicalized_query_result( + &self, + inference_vars: CanonicalVarValues<'tcx>, + answer: T, + fulfill_cx: &mut FulfillmentContext<'tcx>, + ) -> Fallible> + where + T: Debug + Lift<'gcx> + TypeFoldable<'tcx>, + { + let query_result = self.make_query_result(inference_vars, answer, fulfill_cx)?; + let canonical_result = self.canonicalize_response(&query_result); + + debug!( + "make_canonicalized_query_result: canonical_result = {:#?}", + canonical_result + ); + + Ok(Lrc::new(canonical_result)) + } + + /// Helper for `make_canonicalized_query_result` that does + /// everything up until the final canonicalization. + fn make_query_result( + &self, + inference_vars: CanonicalVarValues<'tcx>, + answer: T, + fulfill_cx: &mut FulfillmentContext<'tcx>, + ) -> Result, NoSolution> + where + T: Debug + TypeFoldable<'tcx> + Lift<'gcx>, + { + let tcx = self.tcx; + + debug!( + "make_query_result(\ + inference_vars={:?}, \ + answer={:?})", + inference_vars, answer, + ); + + // Select everything, returning errors. + let true_errors = match fulfill_cx.select_where_possible(self) { + Ok(()) => vec![], + Err(errors) => errors, + }; + debug!("true_errors = {:#?}", true_errors); + + if !true_errors.is_empty() { + // FIXME -- we don't indicate *why* we failed to solve + debug!("make_query_result: true_errors={:#?}", true_errors); + return Err(NoSolution); + } + + // Anything left unselected *now* must be an ambiguity. + let ambig_errors = match fulfill_cx.select_all_or_error(self) { + Ok(()) => vec![], + Err(errors) => errors, + }; + debug!("ambig_errors = {:#?}", ambig_errors); + + let region_obligations = self.take_registered_region_obligations(); + let region_constraints = self.with_region_constraints(|region_constraints| { + make_query_outlives(tcx, region_obligations, region_constraints) + }); + + let certainty = if ambig_errors.is_empty() { + Certainty::Proven + } else { + Certainty::Ambiguous + }; + + Ok(QueryResult { + var_values: inference_vars, + region_constraints, + certainty, + value: answer, + }) + } + + /// Given the (canonicalized) result to a canonical query, + /// instantiates the result so it can be used, plugging in the + /// values from the canonical query. (Note that the result may + /// have been ambiguous; you should check the certainty level of + /// the query before applying this function.) + /// + /// To get a good understanding of what is happening here, check + /// out the [chapter in the rustc guide][c]. + /// + /// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html#processing-the-canonicalized-query-result + pub fn instantiate_query_result_and_region_obligations( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, + query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + ) -> InferResult<'tcx, R> + where + R: Debug + TypeFoldable<'tcx>, + { + let InferOk { + value: result_subst, + mut obligations, + } = self.query_result_substitution(cause, param_env, original_values, query_result)?; + + obligations.extend(self.query_region_constraints_into_obligations( + cause, + param_env, + &query_result.value.region_constraints, + &result_subst, + )); + + let user_result: R = + query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + + Ok(InferOk { + value: user_result, + obligations, + }) + } + + /// An alternative to + /// `instantiate_query_result_and_region_obligations` that is more + /// efficient for NLL. NLL is a bit more advanced in the + /// "transition to chalk" than the rest of the compiler. During + /// the NLL type check, all of the "processing" of types and + /// things happens in queries -- the NLL checker itself is only + /// interested in the region obligations (`'a: 'b` or `T: 'b`) + /// that come out of these queries, which it wants to convert into + /// MIR-based constraints and solve. Therefore, it is most + /// convenient for the NLL Type Checker to **directly consume** + /// the `QueryRegionConstraint` values that arise from doing a + /// query. This is contrast to other parts of the compiler, which + /// would prefer for those `QueryRegionConstraint` to be converted + /// into the older infcx-style constraints (e.g., calls to + /// `sub_regions` or `register_region_obligation`). + /// + /// Therefore, `instantiate_nll_query_result_and_region_obligations` performs the same + /// basic operations as `instantiate_query_result_and_region_obligations` but + /// it returns its result differently: + /// + /// - It creates a substitution `S` that maps from the original + /// query variables to the values computed in the query + /// result. If any errors arise, they are propagated back as an + /// `Err` result. + /// - In the case of a successful substitution, we will append + /// `QueryRegionConstraint` values onto the + /// `output_query_region_constraints` vector for the solver to + /// use (if an error arises, some values may also be pushed, but + /// they should be ignored). + /// - It **can happen** (though it rarely does currently) that + /// equating types and things will give rise to subobligations + /// that must be processed. In this case, those subobligations + /// are propagated back in the return value. + /// - Finally, the query result (of type `R`) is propagated back, + /// after applying the substitution `S`. + pub fn instantiate_nll_query_result_and_region_obligations( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, + query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + output_query_region_constraints: &mut Vec>, + ) -> InferResult<'tcx, R> + where + R: Debug + TypeFoldable<'tcx>, + { + // In an NLL query, there should be no type variables in the + // query, only region variables. + debug_assert!(query_result.variables.iter().all(|v| match v.kind { + CanonicalVarKind::Ty(_) => false, + CanonicalVarKind::Region => true, + })); + + let result_subst = + self.query_result_substitution_guess(cause, original_values, query_result); + + // Compute `QueryRegionConstraint` values that unify each of + // the original values `v_o` that was canonicalized into a + // variable... + let mut obligations = vec![]; + + for (index, original_value) in original_values.iter().enumerate() { + // ...with the value `v_r` of that variable from the query. + let result_value = query_result.substitute_projected(self.tcx, &result_subst, |v| { + &v.var_values[CanonicalVar::new(index)] + }); + match (original_value.unpack(), result_value.unpack()) { + (UnpackedKind::Lifetime(ty::ReErased), UnpackedKind::Lifetime(ty::ReErased)) => { + // no action needed + } + + (UnpackedKind::Lifetime(v_o), UnpackedKind::Lifetime(v_r)) => { + // To make `v_o = v_r`, we emit `v_o: v_r` and `v_r: v_o`. + if v_o != v_r { + output_query_region_constraints + .push(ty::Binder::dummy(ty::OutlivesPredicate(v_o.into(), v_r))); + output_query_region_constraints + .push(ty::Binder::dummy(ty::OutlivesPredicate(v_r.into(), v_o))); + } + } + + (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { + let ok = self.at(cause, param_env).eq(v1, v2)?; + obligations.extend(ok.into_obligations()); + } + + _ => { + bug!( + "kind mismatch, cannot unify {:?} and {:?}", + original_value, + result_value + ); + } + } + } + + // ...also include the other query region constraints from the query. + output_query_region_constraints.reserve(query_result.value.region_constraints.len()); + for r_c in query_result.value.region_constraints.iter() { + let &ty::OutlivesPredicate(k1, r2) = r_c.skip_binder(); // reconstructed below + let k1 = substitute_value(self.tcx, &result_subst, &k1); + let r2 = substitute_value(self.tcx, &result_subst, &r2); + if k1 != r2.into() { + output_query_region_constraints + .push(ty::Binder::bind(ty::OutlivesPredicate(k1, r2))); + } + } + + let user_result: R = + query_result.substitute_projected(self.tcx, &result_subst, |q_r| &q_r.value); + + Ok(InferOk { + value: user_result, + obligations, + }) + } + + /// Given the original values and the (canonicalized) result from + /// computing a query, returns a substitution that can be applied + /// to the query result to convert the result back into the + /// original namespace. + /// + /// The substitution also comes accompanied with subobligations + /// that arose from unification; these might occur if (for + /// example) we are doing lazy normalization and the value + /// assigned to a type variable is unified with an unnormalized + /// projection. + fn query_result_substitution( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, + query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + ) -> InferResult<'tcx, CanonicalVarValues<'tcx>> + where + R: Debug + TypeFoldable<'tcx>, + { + debug!( + "query_result_substitution(original_values={:#?}, query_result={:#?})", + original_values, query_result, + ); + + let result_subst = + self.query_result_substitution_guess(cause, original_values, query_result); + + let obligations = self.unify_query_result_substitution_guess( + cause, + param_env, + original_values, + &result_subst, + query_result, + )? + .into_obligations(); + + Ok(InferOk { + value: result_subst, + obligations, + }) + } + + /// Given the original values and the (canonicalized) result from + /// computing a query, returns a **guess** at a substitution that + /// can be applied to the query result to convert the result back + /// into the original namespace. This is called a **guess** + /// because it uses a quick heuristic to find the values for each + /// canonical variable; if that quick heuristic fails, then we + /// will instantiate fresh inference variables for each canonical + /// variable instead. Therefore, the result of this method must be + /// properly unified + fn query_result_substitution_guess( + &self, + cause: &ObligationCause<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, + query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + ) -> CanonicalVarValues<'tcx> + where + R: Debug + TypeFoldable<'tcx>, + { + debug!( + "query_result_substitution_guess(original_values={:#?}, query_result={:#?})", + original_values, query_result, + ); + + // Every canonical query result includes values for each of + // the inputs to the query. Therefore, we begin by unifying + // these values with the original inputs that were + // canonicalized. + let result_values = &query_result.value.var_values; + assert_eq!(original_values.len(), result_values.len()); + + // Quickly try to find initial values for the canonical + // variables in the result in terms of the query. We do this + // by iterating down the values that the query gave to each of + // the canonical inputs. If we find that one of those values + // is directly equal to one of the canonical variables in the + // result, then we can type the corresponding value from the + // input. See the example above. + let mut opt_values: IndexVec>> = + IndexVec::from_elem_n(None, query_result.variables.len()); + + // In terms of our example above, we are iterating over pairs like: + // [(?A, Vec), ('static, '?1), (?B, ?0)] + for (original_value, result_value) in original_values.iter().zip(result_values) { + match result_value.unpack() { + UnpackedKind::Type(result_value) => { + // e.g., here `result_value` might be `?0` in the example above... + if let ty::TyInfer(ty::InferTy::CanonicalTy(index)) = result_value.sty { + // in which case we would set `canonical_vars[0]` to `Some(?U)`. + opt_values[index] = Some(*original_value); + } + } + UnpackedKind::Lifetime(result_value) => { + // e.g., here `result_value` might be `'?1` in the example above... + if let &ty::RegionKind::ReCanonical(index) = result_value { + // in which case we would set `canonical_vars[0]` to `Some('static)`. + opt_values[index] = Some(*original_value); + } + } + } + } + + // Create a result substitution: if we found a value for a + // given variable in the loop above, use that. Otherwise, use + // a fresh inference variable. + let result_subst = CanonicalVarValues { + var_values: query_result + .variables + .iter() + .enumerate() + .map(|(index, info)| match opt_values[CanonicalVar::new(index)] { + Some(k) => k, + None => self.fresh_inference_var_for_canonical_var(cause.span, *info), + }) + .collect(), + }; + + result_subst + } + + /// Given a "guess" at the values for the canonical variables in + /// the input, try to unify with the *actual* values found in the + /// query result. Often, but not always, this is a no-op, because + /// we already found the mapping in the "guessing" step. + /// + /// See also: `query_result_substitution_guess` + fn unify_query_result_substitution_guess( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + original_values: &SmallCanonicalVarValues<'tcx>, + result_subst: &CanonicalVarValues<'tcx>, + query_result: &Canonical<'tcx, QueryResult<'tcx, R>>, + ) -> InferResult<'tcx, ()> + where + R: Debug + TypeFoldable<'tcx>, + { + // A closure that yields the result value for the given + // canonical variable; this is taken from + // `query_result.var_values` after applying the substitution + // `result_subst`. + let substituted_query_result = |index: CanonicalVar| -> Kind<'tcx> { + query_result.substitute_projected(self.tcx, &result_subst, |v| &v.var_values[index]) + }; + + // Unify the original value for each variable with the value + // taken from `query_result` (after applying `result_subst`). + Ok(self.unify_canonical_vars(cause, param_env, original_values, substituted_query_result)?) + } + + /// Converts the region constraints resulting from a query into an + /// iterator of obligations. + fn query_region_constraints_into_obligations<'a>( + &'a self, + cause: &'a ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + unsubstituted_region_constraints: &'a [QueryRegionConstraint<'tcx>], + result_subst: &'a CanonicalVarValues<'tcx>, + ) -> impl Iterator> + 'a { + Box::new( + unsubstituted_region_constraints + .iter() + .map(move |constraint| { + let ty::OutlivesPredicate(k1, r2) = constraint.skip_binder(); // restored below + let k1 = substitute_value(self.tcx, result_subst, k1); + let r2 = substitute_value(self.tcx, result_subst, r2); + match k1.unpack() { + UnpackedKind::Lifetime(r1) => Obligation::new( + cause.clone(), + param_env, + ty::Predicate::RegionOutlives(ty::Binder::dummy( + ty::OutlivesPredicate(r1, r2), + )), + ), + + UnpackedKind::Type(t1) => Obligation::new( + cause.clone(), + param_env, + ty::Predicate::TypeOutlives(ty::Binder::dummy(ty::OutlivesPredicate( + t1, r2, + ))), + ), + } + }), + ) as Box> + } + + /// Given two sets of values for the same set of canonical variables, unify them. + /// The second set is produced lazilly by supplying indices from the first set. + fn unify_canonical_vars( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + variables1: &SmallCanonicalVarValues<'tcx>, + variables2: impl Fn(CanonicalVar) -> Kind<'tcx>, + ) -> InferResult<'tcx, ()> { + self.commit_if_ok(|_| { + let mut obligations = vec![]; + for (index, value1) in variables1.iter().enumerate() { + let value2 = variables2(CanonicalVar::new(index)); + + match (value1.unpack(), value2.unpack()) { + (UnpackedKind::Type(v1), UnpackedKind::Type(v2)) => { + obligations + .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); + } + ( + UnpackedKind::Lifetime(ty::ReErased), + UnpackedKind::Lifetime(ty::ReErased), + ) => { + // no action needed + } + (UnpackedKind::Lifetime(v1), UnpackedKind::Lifetime(v2)) => { + obligations + .extend(self.at(cause, param_env).eq(v1, v2)?.into_obligations()); + } + _ => { + bug!("kind mismatch, cannot unify {:?} and {:?}", value1, value2,); + } + } + } + Ok(InferOk { + value: (), + obligations, + }) + }) + } +} + +/// Given the region obligations and constraints scraped from the infcx, +/// creates query region constraints. +pub fn make_query_outlives<'tcx>( + tcx: TyCtxt<'_, '_, 'tcx>, + region_obligations: Vec<(ast::NodeId, RegionObligation<'tcx>)>, + region_constraints: &RegionConstraintData<'tcx>, +) -> Vec> { + let RegionConstraintData { + constraints, + verifys, + givens, + } = region_constraints; + + assert!(verifys.is_empty()); + assert!(givens.is_empty()); + + let mut outlives: Vec<_> = constraints + .into_iter() + .map(|(k, _)| match *k { + // Swap regions because we are going from sub (<=) to outlives + // (>=). + Constraint::VarSubVar(v1, v2) => ty::OutlivesPredicate( + tcx.mk_region(ty::ReVar(v2)).into(), + tcx.mk_region(ty::ReVar(v1)), + ), + Constraint::VarSubReg(v1, r2) => { + ty::OutlivesPredicate(r2.into(), tcx.mk_region(ty::ReVar(v1))) + } + Constraint::RegSubVar(r1, v2) => { + ty::OutlivesPredicate(tcx.mk_region(ty::ReVar(v2)).into(), r1) + } + Constraint::RegSubReg(r1, r2) => ty::OutlivesPredicate(r2.into(), r1), + }) + .map(ty::Binder::dummy) // no bound regions in the code above + .collect(); + + outlives.extend( + region_obligations + .into_iter() + .map(|(_, r_o)| ty::OutlivesPredicate(r_o.sup_type.into(), r_o.sub_region)) + .map(ty::Binder::dummy), // no bound regions in the code above + ); + + outlives +} diff --git a/src/librustc/infer/canonical/substitute.rs b/src/librustc/infer/canonical/substitute.rs new file mode 100644 index 0000000000000..679829f43c529 --- /dev/null +++ b/src/librustc/infer/canonical/substitute.rs @@ -0,0 +1,113 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module contains code to substitute new values into a +//! `Canonical<'tcx, T>`. +//! +//! For an overview of what canonicaliation is and how it fits into +//! rustc, check out the [chapter in the rustc guide][c]. +//! +//! [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html + +use infer::canonical::{Canonical, CanonicalVarValues}; +use ty::fold::{TypeFoldable, TypeFolder}; +use ty::subst::UnpackedKind; +use ty::{self, Ty, TyCtxt, TypeFlags}; + +impl<'tcx, V> Canonical<'tcx, V> { + /// Instantiate the wrapped value, replacing each canonical value + /// with the value given in `var_values`. + pub fn substitute(&self, tcx: TyCtxt<'_, '_, 'tcx>, var_values: &CanonicalVarValues<'tcx>) -> V + where + V: TypeFoldable<'tcx>, + { + self.substitute_projected(tcx, var_values, |value| value) + } + + /// Allows one to apply a substitute to some subset of + /// `self.value`. Invoke `projection_fn` with `self.value` to get + /// a value V that is expressed in terms of the same canonical + /// variables bound in `self` (usually this extracts from subset + /// of `self`). Apply the substitution `var_values` to this value + /// V, replacing each of the canonical variables. + pub fn substitute_projected( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + var_values: &CanonicalVarValues<'tcx>, + projection_fn: impl FnOnce(&V) -> &T, + ) -> T + where + T: TypeFoldable<'tcx>, + { + assert_eq!(self.variables.len(), var_values.len()); + let value = projection_fn(&self.value); + substitute_value(tcx, var_values, value) + } +} + +/// Substitute the values from `var_values` into `value`. `var_values` +/// must be values for the set of canonical variables that appear in +/// `value`. +pub(super) fn substitute_value<'a, 'tcx, T>( + tcx: TyCtxt<'_, '_, 'tcx>, + var_values: &CanonicalVarValues<'tcx>, + value: &'a T, +) -> T +where + T: TypeFoldable<'tcx>, +{ + if var_values.var_values.is_empty() { + debug_assert!(!value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS)); + value.clone() + } else if !value.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) { + value.clone() + } else { + value.fold_with(&mut CanonicalVarValuesSubst { tcx, var_values }) + } +} + +struct CanonicalVarValuesSubst<'cx, 'gcx: 'tcx, 'tcx: 'cx> { + tcx: TyCtxt<'cx, 'gcx, 'tcx>, + var_values: &'cx CanonicalVarValues<'tcx>, +} + +impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for CanonicalVarValuesSubst<'cx, 'gcx, 'tcx> { + fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { + self.tcx + } + + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + match t.sty { + ty::TyInfer(ty::InferTy::CanonicalTy(c)) => { + match self.var_values.var_values[c].unpack() { + UnpackedKind::Type(ty) => ty, + r => bug!("{:?} is a type but value is {:?}", c, r), + } + } + _ => { + if !t.has_type_flags(TypeFlags::HAS_CANONICAL_VARS) { + t + } else { + t.super_fold_with(self) + } + } + } + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + match r { + ty::RegionKind::ReCanonical(c) => match self.var_values.var_values[*c].unpack() { + UnpackedKind::Lifetime(l) => l, + r => bug!("{:?} is a region but value is {:?}", c, r), + }, + _ => r.super_fold_with(self), + } + } +} diff --git a/src/librustc/infer/error_reporting/mod.rs b/src/librustc/infer/error_reporting/mod.rs index 588f75f809c15..90248e89fa73a 100644 --- a/src/librustc/infer/error_reporting/mod.rs +++ b/src/librustc/infer/error_reporting/mod.rs @@ -60,17 +60,17 @@ use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePa use super::region_constraints::GenericKind; use super::lexical_region_resolve::RegionResolutionError; -use std::fmt; +use std::{cmp, fmt}; use hir; use hir::map as hir_map; use hir::def_id::DefId; use middle::region; use traits::{ObligationCause, ObligationCauseCode}; -use ty::{self, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; +use ty::{self, subst::Subst, Region, Ty, TyCtxt, TypeFoldable, TypeVariants}; use ty::error::TypeError; use syntax::ast::DUMMY_NODE_ID; use syntax_pos::{Pos, Span}; -use errors::{DiagnosticBuilder, DiagnosticStyledString}; +use errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use rustc_data_structures::indexed_vec::Idx; @@ -102,12 +102,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let tag = match self.hir.find(scope.node_id(self, region_scope_tree)) { Some(hir_map::NodeBlock(_)) => "block", Some(hir_map::NodeExpr(expr)) => match expr.node { - hir::ExprCall(..) => "call", - hir::ExprMethodCall(..) => "method call", - hir::ExprMatch(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", - hir::ExprMatch(.., hir::MatchSource::WhileLetDesugar) => "while let", - hir::ExprMatch(.., hir::MatchSource::ForLoopDesugar) => "for", - hir::ExprMatch(..) => "match", + hir::ExprKind::Call(..) => "call", + hir::ExprKind::MethodCall(..) => "method call", + hir::ExprKind::Match(.., hir::MatchSource::IfLetDesugar { .. }) => "if let", + hir::ExprKind::Match(.., hir::MatchSource::WhileLetDesugar) => "while let", + hir::ExprKind::Match(.., hir::MatchSource::ForLoopDesugar) => "for", + hir::ExprKind::Match(..) => "match", _ => "expression", }, Some(hir_map::NodeStmt(_)) => "statement", @@ -189,40 +189,38 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self, region: ty::Region<'tcx>, ) -> (String, Option) { + let cm = self.sess.codemap(); + let scope = region.free_region_binding_scope(self); let node = self.hir.as_local_node_id(scope).unwrap_or(DUMMY_NODE_ID); - let unknown; let tag = match self.hir.find(node) { Some(hir_map::NodeBlock(_)) | Some(hir_map::NodeExpr(_)) => "body", Some(hir_map::NodeItem(it)) => Self::item_scope_tag(&it), Some(hir_map::NodeTraitItem(it)) => Self::trait_item_scope_tag(&it), Some(hir_map::NodeImplItem(it)) => Self::impl_item_scope_tag(&it), - - // this really should not happen, but it does: - // FIXME(#27942) - Some(_) => { - unknown = format!( - "unexpected node ({}) for scope {:?}. \ - Please report a bug.", - self.hir.node_to_string(node), - scope - ); - &unknown - } - None => { - unknown = format!( - "unknown node for scope {:?}. \ - Please report a bug.", - scope - ); - &unknown - } + _ => unreachable!() }; let (prefix, span) = match *region { - ty::ReEarlyBound(ref br) => ( - format!("the lifetime {} as defined on", br.name), - self.sess.codemap().def_span(self.hir.span(node)), - ), + ty::ReEarlyBound(ref br) => { + let mut sp = cm.def_span(self.hir.span(node)); + if let Some(param) = self.hir.get_generics(scope).and_then(|generics| { + generics.get_named(&br.name) + }) { + sp = param.span; + } + (format!("the lifetime {} as defined on", br.name), sp) + } + ty::ReFree(ty::FreeRegion { + bound_region: ty::BoundRegion::BrNamed(_, ref name), .. + }) => { + let mut sp = cm.def_span(self.hir.span(node)); + if let Some(param) = self.hir.get_generics(scope).and_then(|generics| { + generics.get_named(&name) + }) { + sp = param.span; + } + (format!("the lifetime {} as defined on", name), sp) + } ty::ReFree(ref fr) => match fr.bound_region { ty::BrAnon(idx) => ( format!("the anonymous lifetime #{} defined on", idx + 1), @@ -234,7 +232,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ), _ => ( format!("the lifetime {} as defined on", fr.bound_region), - self.sess.codemap().def_span(self.hir.span(node)), + cm.def_span(self.hir.span(node)), ), }, _ => bug!(), @@ -261,12 +259,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { fn item_scope_tag(item: &hir::Item) -> &'static str { match item.node { - hir::ItemImpl(..) => "impl", - hir::ItemStruct(..) => "struct", - hir::ItemUnion(..) => "union", - hir::ItemEnum(..) => "enum", - hir::ItemTrait(..) => "trait", - hir::ItemFn(..) => "function body", + hir::ItemKind::Impl(..) => "impl", + hir::ItemKind::Struct(..) => "struct", + hir::ItemKind::Union(..) => "union", + hir::ItemKind::Enum(..) => "enum", + hir::ItemKind::Trait(..) => "trait", + hir::ItemKind::Fn(..) => "function body", _ => "item", } } @@ -281,7 +279,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { fn impl_item_scope_tag(item: &hir::ImplItem) -> &'static str { match item.node { hir::ImplItemKind::Method(..) => "method body", - hir::ImplItemKind::Const(..) | hir::ImplItemKind::Type(_) => "associated item", + hir::ImplItemKind::Const(..) | + hir::ImplItemKind::Existential(..) | + hir::ImplItemKind::Type(..) => "associated item", } } @@ -500,7 +500,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } else { err.span_label(arm_span, msg); } - } + }, + hir::MatchSource::TryDesugar => { // Issue #51632 + if let Ok(try_snippet) = self.tcx.sess.codemap().span_to_snippet(arm_span) { + err.span_suggestion_with_applicability( + arm_span, + "try wrapping with a success variant", + format!("Ok({})", try_snippet), + Applicability::MachineApplicable + ); + } + }, _ => { let msg = "match arm with an incompatible type"; if self.tcx.sess.codemap().is_multiline(arm_span) { @@ -547,7 +557,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Output the lifetimes fot the first type let lifetimes = sub.regions() .map(|lifetime| { - let s = format!("{}", lifetime); + let s = lifetime.to_string(); if s.is_empty() { "'_".to_string() } else { @@ -572,7 +582,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { value.0.extend((values.0).0); other_value.0.extend((values.1).0); } else { - value.push_highlighted(format!("{}", type_arg)); + value.push_highlighted(type_arg.to_string()); } if len > 0 && i != len - 1 { @@ -644,6 +654,43 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } + /// For generic types with parameters with defaults, remove the parameters corresponding to + /// the defaults. This repeats a lot of the logic found in `PrintContext::parameterized`. + fn strip_generic_default_params( + &self, + def_id: DefId, + substs: &ty::subst::Substs<'tcx> + ) -> &'tcx ty::subst::Substs<'tcx> { + let generics = self.tcx.generics_of(def_id); + let mut num_supplied_defaults = 0; + let mut type_params = generics.params.iter().rev().filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => None, + ty::GenericParamDefKind::Type { has_default, .. } => { + Some((param.def_id, has_default)) + } + }).peekable(); + let has_default = { + let has_default = type_params.peek().map(|(_, has_default)| has_default); + *has_default.unwrap_or(&false) + }; + if has_default { + let types = substs.types().rev(); + for ((def_id, has_default), actual) in type_params.zip(types) { + if !has_default { + break; + } + if self.tcx.type_of(def_id).subst(self.tcx, substs) != actual { + break; + } + num_supplied_defaults += 1; + } + } + let len = generics.params.len(); + let mut generics = generics.clone(); + generics.params.truncate(len - num_supplied_defaults); + substs.truncate_to(self.tcx, &generics) + } + /// Compare two given types, eliding parts that are the same between them and highlighting /// relevant differences, and return two representation of those types for highlighted printing. fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { @@ -665,25 +712,28 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn push_ty_ref<'tcx>( r: &ty::Region<'tcx>, - tnm: &ty::TypeAndMut<'tcx>, + ty: Ty<'tcx>, + mutbl: hir::Mutability, s: &mut DiagnosticStyledString, ) { - let r = &format!("{}", r); + let r = &r.to_string(); s.push_highlighted(format!( "&{}{}{}", r, if r == "" { "" } else { " " }, - if tnm.mutbl == hir::MutMutable { + if mutbl == hir::MutMutable { "mut " } else { "" } )); - s.push_normal(format!("{}", tnm.ty)); + s.push_normal(ty.to_string()); } match (&t1.sty, &t2.sty) { (&ty::TyAdt(def1, sub1), &ty::TyAdt(def2, sub2)) => { + let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1); + let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2); let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); let path1 = self.tcx.item_path_str(def1.did.clone()); let path2 = self.tcx.item_path_str(def2.did.clone()); @@ -699,15 +749,26 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { values.0.push_normal(path1); values.1.push_normal(path2); + // Avoid printing out default generic parameters that are common to both + // types. + let len1 = sub_no_defaults_1.len(); + let len2 = sub_no_defaults_2.len(); + let common_len = cmp::min(len1, len2); + let remainder1: Vec<_> = sub1.types().skip(common_len).collect(); + let remainder2: Vec<_> = sub2.types().skip(common_len).collect(); + let common_default_params = + remainder1.iter().rev().zip(remainder2.iter().rev()) + .filter(|(a, b)| a == b).count(); + let len = sub1.len() - common_default_params; + // Only draw `<...>` if there're lifetime/type arguments. - let len = sub1.len(); if len > 0 { values.0.push_normal("<"); values.1.push_normal("<"); } fn lifetime_display(lifetime: Region) -> String { - let s = format!("{}", lifetime); + let s = lifetime.to_string(); if s.is_empty() { "'_".to_string() } else { @@ -744,8 +805,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Foo<_, Qux> // ^ elided type as this type argument was the same in both sides let type_arguments = sub1.types().zip(sub2.types()); - let regions_len = sub1.regions().collect::>().len(); - for (i, (ta1, ta2)) in type_arguments.enumerate() { + let regions_len = sub1.regions().count(); + for (i, (ta1, ta2)) in type_arguments.take(len).enumerate() { let i = i + regions_len; if ta1 == ta2 { values.0.push_normal("_"); @@ -775,7 +836,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &mut values.0, &mut values.1, path1.clone(), - sub1, + sub_no_defaults_1, path2.clone(), &t2, ).is_some() @@ -787,8 +848,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Bar // Foo> // ------- this type argument is exactly the same as the other type - if self.cmp_type_arg(&mut values.1, &mut values.0, path2, sub2, path1, &t1) - .is_some() + if self.cmp_type_arg( + &mut values.1, + &mut values.0, + path2, + sub_no_defaults_2, + path1, + &t1, + ).is_some() { return values; } @@ -796,31 +863,32 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // We couldn't find anything in common, highlight everything. // let x: Bar = y::>(); ( - DiagnosticStyledString::highlighted(format!("{}", t1)), - DiagnosticStyledString::highlighted(format!("{}", t2)), + DiagnosticStyledString::highlighted(t1.to_string()), + DiagnosticStyledString::highlighted(t2.to_string()), ) } } // When finding T != &T, highlight only the borrow - (&ty::TyRef(r1, ref tnm1), _) if equals(&tnm1.ty, &t2) => { + (&ty::TyRef(r1, ref_ty1, mutbl1), _) if equals(&ref_ty1, &t2) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - push_ty_ref(&r1, tnm1, &mut values.0); - values.1.push_normal(format!("{}", t2)); + push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); + values.1.push_normal(t2.to_string()); values } - (_, &ty::TyRef(r2, ref tnm2)) if equals(&t1, &tnm2.ty) => { + (_, &ty::TyRef(r2, ref_ty2, mutbl2)) if equals(&t1, &ref_ty2) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - values.0.push_normal(format!("{}", t1)); - push_ty_ref(&r2, tnm2, &mut values.1); + values.0.push_normal(t1.to_string()); + push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); values } // When encountering &T != &mut T, highlight only the borrow - (&ty::TyRef(r1, ref tnm1), &ty::TyRef(r2, ref tnm2)) if equals(&tnm1.ty, &tnm2.ty) => { + (&ty::TyRef(r1, ref_ty1, mutbl1), + &ty::TyRef(r2, ref_ty2, mutbl2)) if equals(&ref_ty1, &ref_ty2) => { let mut values = (DiagnosticStyledString::new(), DiagnosticStyledString::new()); - push_ty_ref(&r1, tnm1, &mut values.0); - push_ty_ref(&r2, tnm2, &mut values.1); + push_ty_ref(&r1, ref_ty1, mutbl1, &mut values.0); + push_ty_ref(&r2, ref_ty2, mutbl2, &mut values.1); values } @@ -834,8 +902,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } else { // We couldn't find anything in common, highlight everything. ( - DiagnosticStyledString::highlighted(format!("{}", t1)), - DiagnosticStyledString::highlighted(format!("{}", t2)), + DiagnosticStyledString::highlighted(t1.to_string()), + DiagnosticStyledString::highlighted(t2.to_string()), ) } } @@ -1005,8 +1073,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } Some(( - DiagnosticStyledString::highlighted(format!("{}", exp_found.expected)), - DiagnosticStyledString::highlighted(format!("{}", exp_found.found)), + DiagnosticStyledString::highlighted(exp_found.expected.to_string()), + DiagnosticStyledString::highlighted(exp_found.found.to_string()), )) } @@ -1018,6 +1086,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { bound_kind: GenericKind<'tcx>, sub: Region<'tcx>, ) { + self.construct_generic_bound_failure(region_scope_tree, + span, + origin, + bound_kind, + sub) + .emit() + } + + pub fn construct_generic_bound_failure( + &self, + region_scope_tree: ®ion::ScopeTree, + span: Span, + origin: Option>, + bound_kind: GenericKind<'tcx>, + sub: Region<'tcx>, + ) -> DiagnosticBuilder<'a> + { // Attempt to obtain the span of the parameter so we can // suggest adding an explicit lifetime bound to it. let type_param_span = match (self.in_progress_tables, bound_kind) { @@ -1034,15 +1119,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Get the `hir::TyParam` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: 'a'b`, // instead we suggest `T: 'a + 'b` in that case. - let has_lifetimes = if let hir_map::NodeTyParam(ref p) = hir.get(id) { - p.bounds.len() > 0 - } else { - false - }; + let mut has_bounds = false; + if let hir_map::NodeGenericParam(ref param) = hir.get(id) { + has_bounds = !param.bounds.is_empty(); + } let sp = hir.span(id); // `sp` only covers `T`, change it so that it covers // `T:` when appropriate - let sp = if has_lifetimes { + let sp = if has_bounds { sp.to(self.tcx .sess .codemap() @@ -1050,7 +1134,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } else { sp }; - (sp, has_lifetimes) + (sp, has_bounds) }) } else { None @@ -1072,14 +1156,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { trait_item_def_id, }) = origin { - self.report_extra_impl_obligation( + return self.report_extra_impl_obligation( span, item_name, impl_item_def_id, trait_item_def_id, &format!("`{}: {}`", bound_kind, sub), - ).emit(); - return; + ); } fn binding_suggestion<'tcx, S: fmt::Display>( @@ -1095,7 +1178,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some((sp, has_lifetimes)) = type_param_span { let tail = if has_lifetimes { " + " } else { "" }; let suggestion = format!("{}: {}{}", bound_kind, sub, tail); - err.span_suggestion_short(sp, consider, suggestion); + err.span_suggestion_short_with_applicability( + sp, consider, suggestion, + Applicability::MaybeIncorrect // Issue #41966 + ); } else { err.help(consider); } @@ -1159,7 +1245,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some(origin) = origin { self.note_region_origin(&mut err, &origin); } - err.emit(); + err } fn report_sub_sup_conflict( @@ -1251,7 +1337,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { infer::LateBoundRegion(_, br, infer::AssocTypeProjection(def_id)) => format!( " for lifetime parameter {}in trait containing associated type `{}`", br_string(br), - self.tcx.associated_item(def_id).name + self.tcx.associated_item(def_id).ident ), infer::EarlyBoundRegion(_, name) => format!(" for lifetime parameter `{}`", name), infer::BoundRegionInCoherence(name) => { @@ -1290,7 +1376,12 @@ impl<'tcx> ObligationCause<'tcx> { match self.code { CompareImplMethodObligation { .. } => Error0308("method not compatible with trait"), MatchExpressionArm { source, .. } => Error0308(match source { - hir::MatchSource::IfLetDesugar { .. } => "`if let` arms have incompatible types", + hir::MatchSource::IfLetDesugar { .. } => { + "`if let` arms have incompatible types" + }, + hir::MatchSource::TryDesugar => { + "try expression alternatives have incompatible types" + }, _ => "match arms have incompatible types", }), IfExpression => Error0308("if and else have incompatible types"), diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index ea3c0a8ddb450..693219ec4b03f 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -13,7 +13,9 @@ use hir::intravisit::{self, Visitor, NestedVisitorMap}; use infer::InferCtxt; use infer::type_variable::TypeVariableOrigin; use ty::{self, Ty, TyInfer, TyVar}; +use syntax::codemap::CompilerDesugaringKind; use syntax_pos::Span; +use errors::DiagnosticBuilder; struct FindLocalByTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, @@ -72,7 +74,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindLocalByTypeVisitor<'a, 'gcx, 'tcx> { impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String { + pub fn extract_type_name(&self, ty: &'a Ty<'tcx>) -> String { if let ty::TyInfer(ty::TyVar(ty_vid)) = (*ty).sty { let ty_vars = self.type_variables.borrow(); if let TypeVariableOrigin::TypeParameterDefinition(_, name) = @@ -86,12 +88,23 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } - pub fn need_type_info(&self, body_id: Option, span: Span, ty: Ty<'tcx>) { + pub fn need_type_info_err(&self, + body_id: Option, + span: Span, + ty: Ty<'tcx>) + -> DiagnosticBuilder<'gcx> { let ty = self.resolve_type_vars_if_possible(&ty); let name = self.extract_type_name(&ty); let mut err_span = span; - let mut labels = vec![(span, format!("cannot infer type for `{}`", name))]; + let mut labels = vec![( + span, + if &name == "_" { + "cannot infer type".to_string() + } else { + format!("cannot infer type for `{}`", name) + }, + )]; let mut local_visitor = FindLocalByTypeVisitor { infcx: &self, @@ -126,8 +139,16 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { labels.clear(); labels.push((pattern.span, format!("consider giving this closure parameter a type"))); } else if let Some(pattern) = local_visitor.found_local_pattern { - if let Some(simple_name) = pattern.simple_name() { - labels.push((pattern.span, format!("consider giving `{}` a type", simple_name))); + if let Some(simple_ident) = pattern.simple_ident() { + match pattern.span.compiler_desugaring_kind() { + None => labels.push((pattern.span, + format!("consider giving `{}` a type", simple_ident))), + Some(CompilerDesugaringKind::ForLoop) => labels.push(( + pattern.span, + "the element type for this iterator is not specified".to_string(), + )), + _ => {} + } } else { labels.push((pattern.span, format!("consider giving the pattern a type"))); } @@ -142,6 +163,6 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { err.span_label(target_span, label_message); } - err.emit(); + err } } diff --git a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs index 7b0f2933580b3..f3f3dcfeea002 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/different_lifetimes.rs @@ -96,14 +96,14 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { let sub_is_ret_type = self.is_return_type_anon(scope_def_id_sub, bregion_sub, ty_fndecl_sub); - let span_label_var1 = if let Some(simple_name) = anon_arg_sup.pat.simple_name() { - format!(" from `{}`", simple_name) + let span_label_var1 = if let Some(simple_ident) = anon_arg_sup.pat.simple_ident() { + format!(" from `{}`", simple_ident) } else { format!("") }; - let span_label_var2 = if let Some(simple_name) = anon_arg_sub.pat.simple_name() { - format!(" into `{}`", simple_name) + let span_label_var2 = if let Some(simple_ident) = anon_arg_sub.pat.simple_ident() { + format!(" into `{}`", simple_ident) } else { format!("") }; @@ -111,7 +111,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { let (span_1, span_2, main_label, span_label) = match (sup_is_ret_type, sub_is_ret_type) { (None, None) => { - let (main_label_1, span_label_1) = if ty_sup == ty_sub { + let (main_label_1, span_label_1) = if ty_sup.id == ty_sub.id { ( format!("this type is declared with multiple lifetimes..."), format!( diff --git a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs index dc53c1db06f14..21be09b0ba193 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -41,7 +41,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { let fndecl = match self.tcx.hir.get(node_id) { hir_map::NodeItem(&hir::Item { - node: hir::ItemFn(ref fndecl, ..), + node: hir::ItemKind::Fn(ref fndecl, ..), .. }) => &fndecl, hir_map::NodeTraitItem(&hir::TraitItem { @@ -77,7 +77,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { tcx: self.tcx, bound_region: *br, found_type: None, - depth: 1, + current_index: ty::INNERMOST, }; nested_visitor.visit_ty(arg); nested_visitor.found_type @@ -99,7 +99,7 @@ struct FindNestedTypeVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { // The type where the anonymous lifetime appears // for e.g. Vec<`&u8`> and <`&u8`> found_type: Option<&'gcx hir::Ty>, - depth: u32, + current_index: ty::DebruijnIndex, } impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { @@ -109,20 +109,20 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { fn visit_ty(&mut self, arg: &'gcx hir::Ty) { match arg.node { - hir::TyBareFn(_) => { - self.depth += 1; + hir::TyKind::BareFn(_) => { + self.current_index.shift_in(1); intravisit::walk_ty(self, arg); - self.depth -= 1; + self.current_index.shift_out(1); return; } - hir::TyTraitObject(ref bounds, _) => for bound in bounds { - self.depth += 1; + hir::TyKind::TraitObject(ref bounds, _) => for bound in bounds { + self.current_index.shift_in(1); self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); - self.depth -= 1; + self.current_index.shift_out(1); }, - hir::TyRptr(ref lifetime, _) => { + hir::TyKind::Rptr(ref lifetime, _) => { // the lifetime of the TyRptr let hir_id = self.tcx.hir.node_to_hir_id(lifetime.id); match (self.tcx.named_region(hir_id), self.bound_region) { @@ -135,11 +135,11 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { ) => { debug!( "LateBoundAnon depth = {:?} anon_index = {:?} br_index={:?}", - debruijn_index.depth, + debruijn_index, anon_index, br_index ); - if debruijn_index.depth == self.depth && anon_index == br_index { + if debruijn_index == self.current_index && anon_index == br_index { self.found_type = Some(arg); return; // we can stop visiting now } @@ -170,11 +170,11 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { ) => { debug!( "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", - debruijn_index.depth + debruijn_index ); debug!("self.infcx.tcx.hir.local_def_id(id)={:?}", id); debug!("def_id={:?}", def_id); - if debruijn_index.depth == self.depth && id == def_id { + if debruijn_index == self.current_index && id == def_id { self.found_type = Some(arg); return; // we can stop visiting now } @@ -190,13 +190,13 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { } } } - // Checks if it is of type `hir::TyPath` which corresponds to a struct. - hir::TyPath(_) => { + // Checks if it is of type `hir::TyKind::Path` which corresponds to a struct. + hir::TyKind::Path(_) => { let subvisitor = &mut TyPathVisitor { tcx: self.tcx, found_it: false, bound_region: self.bound_region, - depth: self.depth, + current_index: self.current_index, }; intravisit::walk_ty(subvisitor, arg); // call walk_ty; as visit_ty is empty, // this will visit only outermost type @@ -213,7 +213,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for FindNestedTypeVisitor<'a, 'gcx, 'tcx> { } // The visitor captures the corresponding `hir::Ty` of the anonymous region -// in the case of structs ie. `hir::TyPath`. +// in the case of structs ie. `hir::TyKind::Path`. // This visitor would be invoked for each lifetime corresponding to a struct, // and would walk the types like Vec in the above example and Ref looking for the HIR // where that lifetime appears. This allows us to highlight the @@ -222,7 +222,7 @@ struct TyPathVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, found_it: bool, bound_region: ty::BoundRegion, - depth: u32, + current_index: ty::DebruijnIndex, } impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> { @@ -235,7 +235,7 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> { match (self.tcx.named_region(hir_id), self.bound_region) { // the lifetime of the TyPath! (Some(rl::Region::LateBoundAnon(debruijn_index, anon_index)), ty::BrAnon(br_index)) => { - if debruijn_index.depth == self.depth && anon_index == br_index { + if debruijn_index == self.current_index && anon_index == br_index { self.found_it = true; return; } @@ -257,11 +257,11 @@ impl<'a, 'gcx, 'tcx> Visitor<'gcx> for TyPathVisitor<'a, 'gcx, 'tcx> { (Some(rl::Region::LateBound(debruijn_index, id, _)), ty::BrNamed(def_id, _)) => { debug!( "FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", - debruijn_index.depth + debruijn_index, ); debug!("id={:?}", id); debug!("def_id={:?}", def_id); - if debruijn_index.depth == self.depth && id == def_id { + if debruijn_index == self.current_index && id == def_id { self.found_it = true; return; // we can stop visiting now } diff --git a/src/librustc/infer/error_reporting/nice_region_error/mod.rs b/src/librustc/infer/error_reporting/nice_region_error/mod.rs index 59b36a50a2b09..f50c23b0aa752 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/mod.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/mod.rs @@ -19,6 +19,7 @@ mod different_lifetimes; mod find_anon_type; mod named_anon_conflict; mod outlives_closure; +mod static_impl_trait; mod util; impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { @@ -67,6 +68,7 @@ impl<'cx, 'gcx, 'tcx> NiceRegionError<'cx, 'gcx, 'tcx> { self.try_report_named_anon_conflict() .or_else(|| self.try_report_anon_anon_conflict()) .or_else(|| self.try_report_outlives_closure()) + .or_else(|| self.try_report_static_impl_trait()) } pub fn get_regions(&self) -> (Span, ty::Region<'tcx>, ty::Region<'tcx>) { diff --git a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs index c106fd0c3d2c0..51abfa2505ab5 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -95,10 +95,10 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { } } - let (error_var, span_label_var) = if let Some(simple_name) = arg.pat.simple_name() { + let (error_var, span_label_var) = if let Some(simple_ident) = arg.pat.simple_ident() { ( - format!("the type of `{}`", simple_name), - format!("the type of `{}`", simple_name), + format!("the type of `{}`", simple_ident), + format!("the type of `{}`", simple_ident), ) } else { ("parameter type".to_owned(), "type".to_owned()) diff --git a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs index 18b8c70c3ef79..f4ef197e5b422 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/outlives_closure.rs @@ -14,7 +14,7 @@ use infer::error_reporting::nice_region_error::NiceRegionError; use infer::SubregionOrigin; use ty::RegionKind; -use hir::{Expr, ExprClosure}; +use hir::{Expr, ExprKind::Closure}; use hir::map::NodeExpr; use util::common::ErrorReported; use infer::lexical_region_resolve::RegionResolutionError::SubSupConflict; @@ -60,7 +60,7 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { if let Some(node_id) = hir.as_local_node_id(free_region.scope) { match hir.get(node_id) { NodeExpr(Expr { - node: ExprClosure(_, _, _, closure_span, None), + node: Closure(_, _, _, closure_span, None), .. }) => { let sup_sp = sup_origin.span(); diff --git a/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs new file mode 100644 index 0000000000000..193f86a382795 --- /dev/null +++ b/src/librustc/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -0,0 +1,83 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Error Reporting for static impl Traits. + +use infer::error_reporting::nice_region_error::NiceRegionError; +use infer::lexical_region_resolve::RegionResolutionError; +use ty::{BoundRegion, FreeRegion, RegionKind}; +use util::common::ErrorReported; + +impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { + /// Print the error message for lifetime errors when the return type is a static impl Trait. + pub(super) fn try_report_static_impl_trait(&self) -> Option { + if let Some(ref error) = self.error { + match error.clone() { + RegionResolutionError::SubSupConflict( + var_origin, + sub_origin, + sub_r, + sup_origin, + sup_r, + ) => { + let anon_reg_sup = self.is_suitable_region(sup_r)?; + if sub_r == &RegionKind::ReStatic && + self.is_return_type_impl_trait(anon_reg_sup.def_id) + { + let sp = var_origin.span(); + let return_sp = sub_origin.span(); + let mut err = self.tcx.sess.struct_span_err( + sp, + "cannot infer an appropriate lifetime", + ); + err.span_label( + return_sp, + "this return type evaluates to the `'static` lifetime...", + ); + err.span_label( + sup_origin.span(), + "...but this borrow...", + ); + + let (lifetime, lt_sp_opt) = self.tcx.msg_span_from_free_region(sup_r); + if let Some(lifetime_sp) = lt_sp_opt { + err.span_note( + lifetime_sp, + &format!("...can't outlive {}", lifetime), + ); + } + + let lifetime_name = match sup_r { + RegionKind::ReFree(FreeRegion { + bound_region: BoundRegion::BrNamed(_, ref name), .. + }) => name.to_string(), + _ => "'_".to_owned(), + }; + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(return_sp) { + err.span_suggestion( + return_sp, + &format!( + "you can add a constraint to the return type to make it last \ + less than `'static` and match {}", + lifetime, + ), + format!("{} + {}", snippet, lifetime_name), + ); + } + err.emit(); + return Some(ErrorReported); + } + } + _ => {} + } + } + None + } +} diff --git a/src/librustc/infer/error_reporting/nice_region_error/util.rs b/src/librustc/infer/error_reporting/nice_region_error/util.rs index 8aadec6455414..1cc2b9d50b99b 100644 --- a/src/librustc/infer/error_reporting/nice_region_error/util.rs +++ b/src/librustc/infer/error_reporting/nice_region_error/util.rs @@ -167,6 +167,23 @@ impl<'a, 'gcx, 'tcx> NiceRegionError<'a, 'gcx, 'tcx> { } None } + + pub(super) fn is_return_type_impl_trait( + &self, + scope_def_id: DefId, + ) -> bool { + let ret_ty = self.tcx.type_of(scope_def_id); + match ret_ty.sty { + ty::TyFnDef(_, _) => { + let sig = ret_ty.fn_sig(self.tcx); + let output = self.tcx.erase_late_bound_regions(&sig.output()); + return output.is_impl_trait(); + } + _ => {} + } + false + } + // Here we check for the case where anonymous region // corresponds to self and if yes, we display E0312. // FIXME(#42700) - Need to format self properly to diff --git a/src/librustc/infer/higher_ranked/mod.rs b/src/librustc/infer/higher_ranked/mod.rs index b8437e39ddca4..cb4e1ab65e759 100644 --- a/src/librustc/infer/higher_ranked/mod.rs +++ b/src/librustc/infer/higher_ranked/mod.rs @@ -19,10 +19,10 @@ use super::{CombinedSnapshot, use super::combine::CombineFields; use super::region_constraints::{TaintDirections}; -use rustc_data_structures::lazy_btree_map::LazyBTreeMap; use ty::{self, TyCtxt, Binder, TypeFoldable}; use ty::error::TypeError; use ty::relate::{Relate, RelateResult, TypeRelation}; +use std::collections::BTreeMap; use syntax_pos::Span; use util::nodemap::{FxHashMap, FxHashSet}; @@ -247,8 +247,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &LazyBTreeMap>, + a_map: &BTreeMap>, r0: ty::Region<'tcx>) -> ty::Region<'tcx> { // Regions that pre-dated the LUB computation stay as they are. @@ -344,8 +343,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { snapshot: &CombinedSnapshot<'a, 'tcx>, debruijn: ty::DebruijnIndex, new_vars: &[ty::RegionVid], - a_map: &LazyBTreeMap>, + a_map: &BTreeMap>, a_vars: &[ty::RegionVid], b_vars: &[ty::RegionVid], r0: ty::Region<'tcx>) @@ -414,12 +412,12 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { fn rev_lookup<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, span: Span, - a_map: &LazyBTreeMap>, + a_map: &BTreeMap>, r: ty::Region<'tcx>) -> ty::Region<'tcx> { for (a_br, a_r) in a_map { if *a_r == r { - return infcx.tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), *a_br)); + return infcx.tcx.mk_region(ty::ReLateBound(ty::INNERMOST, *a_br)); } } span_bug!( @@ -437,7 +435,7 @@ impl<'a, 'gcx, 'tcx> CombineFields<'a, 'gcx, 'tcx> { } fn var_ids<'a, 'gcx, 'tcx>(fields: &CombineFields<'a, 'gcx, 'tcx>, - map: &LazyBTreeMap>) + map: &BTreeMap>) -> Vec { map.iter() .map(|(_, &r)| match *r { @@ -475,7 +473,7 @@ fn fold_regions_in<'a, 'gcx, 'tcx, T, F>(tcx: TyCtxt<'a, 'gcx, 'tcx>, _ => true }); - fldr(region, ty::DebruijnIndex::new(current_depth)) + fldr(region, current_depth) }) } @@ -585,7 +583,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { /// For more information about how skolemization for HRTBs works, see /// the [rustc guide]. /// - /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-hrtb.html + /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html pub fn skolemize_late_bound_regions(&self, binder: &ty::Binder) -> (T, SkolemizationMap<'tcx>) @@ -619,6 +617,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { debug!("leak_check: skol_map={:?}", skol_map); + // If the user gave `-Zno-leak-check`, then skip the leak + // check completely. This is wildly unsound and also not + // unlikely to cause an ICE or two. It is intended for use + // only during a transition period, in which the MIR typeck + // uses the "universe-style" check, and the rest of typeck + // uses the more conservative leak check. Since the leak + // check is more conservative, we can't test the + // universe-style check without disabling it. + if self.tcx.sess.opts.debugging_opts.no_leak_check { + return Ok(()); + } + let new_vars = self.region_vars_confined_to_snapshot(snapshot); for (&skol_br, &skol) in skol_map { // The inputs to a skolemized variable can only @@ -736,7 +746,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // trait checking, and all of the skolemized regions // appear inside predicates, which always have // binders, so this assert is satisfied. - assert!(current_depth > 1); + assert!(current_depth > ty::INNERMOST); // since leak-check passed, this skolemized region // should only have incoming edges from variables @@ -752,7 +762,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { r, br); self.tcx.mk_region(ty::ReLateBound( - ty::DebruijnIndex::new(current_depth - 1), br.clone())) + current_depth.shifted_out(1), + br.clone(), + )) } } }); diff --git a/src/librustc/infer/lexical_region_resolve/README.md b/src/librustc/infer/lexical_region_resolve/README.md index 0086aed3e7c97..6e1c4191173bc 100644 --- a/src/librustc/infer/lexical_region_resolve/README.md +++ b/src/librustc/infer/lexical_region_resolve/README.md @@ -3,7 +3,7 @@ > WARNING: This README is obsolete and will be removed soon! For > more info on how the current borrowck works, see the [rustc guide]. -[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir-borrowck.html +[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir/borrowck.html ## Terminology diff --git a/src/librustc/infer/lexical_region_resolve/graphviz.rs b/src/librustc/infer/lexical_region_resolve/graphviz.rs index d9d08294334db..d76d33b990222 100644 --- a/src/librustc/infer/lexical_region_resolve/graphviz.rs +++ b/src/librustc/infer/lexical_region_resolve/graphviz.rs @@ -39,14 +39,14 @@ use std::sync::atomic::{AtomicBool, Ordering}; fn print_help_message() { println!("\ -Z print-region-graph by default prints a region constraint graph for every \n\ -function body, to the path `/tmp/constraints.nodeXXX.dot`, where the XXX is \n\ +function body, to the path `constraints.nodeXXX.dot`, where the XXX is \n\ replaced with the node id of the function under analysis. \n\ \n\ To select one particular function body, set `RUST_REGION_GRAPH_NODE=XXX`, \n\ where XXX is the node id desired. \n\ \n\ To generate output to some path other than the default \n\ -`/tmp/constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`; \n\ +`constraints.nodeXXX.dot`, set `RUST_REGION_GRAPH=/path/desired.dot`; \n\ occurrences of the character `%` in the requested path will be replaced with\n\ the node id of the function under analysis. \n\ \n\ @@ -90,7 +90,7 @@ pub fn maybe_print_constraints_for<'a, 'gcx, 'tcx>( } Ok(other_path) => other_path, - Err(_) => "/tmp/constraints.node%.dot".to_string(), + Err(_) => "constraints.node%.dot".to_string(), }; if output_template.is_empty() { diff --git a/src/librustc/infer/lexical_region_resolve/mod.rs b/src/librustc/infer/lexical_region_resolve/mod.rs index 5984a831e6fa0..120b45ec01e5e 100644 --- a/src/librustc/infer/lexical_region_resolve/mod.rs +++ b/src/librustc/infer/lexical_region_resolve/mod.rs @@ -20,7 +20,7 @@ use infer::region_constraints::VerifyBound; use middle::free_region::RegionRelations; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc_data_structures::fx::FxHashSet; -use rustc_data_structures::graph::{self, Direction, NodeIndex, OUTGOING}; +use rustc_data_structures::graph::implementation::{Graph, Direction, NodeIndex, INCOMING, OUTGOING}; use std::fmt; use std::u32; use ty::{self, TyCtxt}; @@ -99,7 +99,7 @@ struct RegionAndOrigin<'tcx> { origin: SubregionOrigin<'tcx>, } -type RegionGraph<'tcx> = graph::Graph<(), Constraint<'tcx>>; +type RegionGraph<'tcx> = Graph<(), Constraint<'tcx>>; struct LexicalResolver<'cx, 'gcx: 'tcx, 'tcx: 'cx> { region_rels: &'cx RegionRelations<'cx, 'gcx, 'tcx>, @@ -501,7 +501,7 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { fn construct_graph(&self) -> RegionGraph<'tcx> { let num_vars = self.num_vars(); - let mut graph = graph::Graph::new(); + let mut graph = Graph::new(); for _ in 0..num_vars { graph.add_node(()); @@ -550,9 +550,9 @@ impl<'cx, 'gcx, 'tcx> LexicalResolver<'cx, 'gcx, 'tcx> { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. let (mut lower_bounds, lower_dup) = - self.collect_concrete_regions(graph, node_idx, graph::INCOMING, dup_vec); + self.collect_concrete_regions(graph, node_idx, INCOMING, dup_vec); let (mut upper_bounds, upper_dup) = - self.collect_concrete_regions(graph, node_idx, graph::OUTGOING, dup_vec); + self.collect_concrete_regions(graph, node_idx, OUTGOING, dup_vec); if lower_dup || upper_dup { return; diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs index c62e7f8d9b635..0b84c6a0aa77a 100644 --- a/src/librustc/infer/mod.rs +++ b/src/librustc/infer/mod.rs @@ -21,16 +21,16 @@ use hir::def_id::DefId; use middle::free_region::RegionRelations; use middle::region; use middle::lang_items; -use ty::subst::Substs; +use ty::subst::{Kind, Substs}; use ty::{TyVid, IntVid, FloatVid}; -use ty::{self, Ty, TyCtxt}; +use ty::{self, Ty, TyCtxt, GenericParamDefKind}; use ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use ty::fold::TypeFoldable; use ty::relate::RelateResult; -use traits::{self, ObligationCause, PredicateObligations}; -use rustc_data_structures::lazy_btree_map::LazyBTreeMap; +use traits::{self, ObligationCause, PredicateObligations, TraitEngine}; use rustc_data_structures::unify as ut; use std::cell::{Cell, RefCell, Ref, RefMut}; +use std::collections::BTreeMap; use std::fmt; use syntax::ast; use errors::DiagnosticBuilder; @@ -198,7 +198,7 @@ pub struct InferCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { /// A map returned by `skolemize_late_bound_regions()` indicating the skolemized /// region that each late-bound region was replaced with. -pub type SkolemizationMap<'tcx> = LazyBTreeMap>; +pub type SkolemizationMap<'tcx> = BTreeMap>; /// See `error_reporting` module for more details #[derive(Clone, Debug)] @@ -377,7 +377,23 @@ pub enum NLLRegionVariableOrigin { // elsewhere. This origin indices we've got one of those. FreeRegion, - Inferred(::mir::visit::TyContext), + BoundRegion(ty::UniverseIndex), + + Existential, +} + +impl NLLRegionVariableOrigin { + pub fn is_universal(self) -> bool { + match self { + NLLRegionVariableOrigin::FreeRegion => true, + NLLRegionVariableOrigin::BoundRegion(..) => true, + NLLRegionVariableOrigin::Existential => false, + } + } + + pub fn is_existential(self) -> bool { + !self.is_universal() + } } #[derive(Copy, Clone, Debug)] @@ -485,6 +501,19 @@ impl<'tcx, T> InferOk<'tcx, T> { pub fn unit(self) -> InferOk<'tcx, ()> { InferOk { value: (), obligations: self.obligations } } + + /// Extract `value`, registering any obligations into `fulfill_cx` + pub fn into_value_registering_obligations( + self, + infcx: &InferCtxt<'_, '_, 'tcx>, + fulfill_cx: &mut impl TraitEngine<'tcx>, + ) -> T { + let InferOk { value, obligations } = self; + for obligation in obligations { + fulfill_cx.register_predicate_obligation(infcx, obligation); + } + value + } } impl<'tcx> InferOk<'tcx, ()> { @@ -549,36 +578,25 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } pub fn unsolved_variables(&self) -> Vec> { - let mut variables = Vec::new(); - - { - let mut type_variables = self.type_variables.borrow_mut(); - variables.extend( - type_variables - .unsolved_variables() - .into_iter() - .map(|t| self.tcx.mk_var(t))); - } - - { - let mut int_unification_table = self.int_unification_table.borrow_mut(); - variables.extend( + let mut type_variables = self.type_variables.borrow_mut(); + let mut int_unification_table = self.int_unification_table.borrow_mut(); + let mut float_unification_table = self.float_unification_table.borrow_mut(); + + type_variables + .unsolved_variables() + .into_iter() + .map(|t| self.tcx.mk_var(t)) + .chain( (0..int_unification_table.len()) .map(|i| ty::IntVid { index: i as u32 }) .filter(|&vid| int_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_int_var(v))); - } - - { - let mut float_unification_table = self.float_unification_table.borrow_mut(); - variables.extend( + .map(|v| self.tcx.mk_int_var(v)) + ).chain( (0..float_unification_table.len()) .map(|i| ty::FloatVid { index: i as u32 }) .filter(|&vid| float_unification_table.probe_value(vid).is_none()) - .map(|v| self.tcx.mk_float_var(v))); - } - - return variables; + .map(|v| self.tcx.mk_float_var(v)) + ).collect() } fn combine_fields(&'a self, trace: TypeTrace<'tcx>, param_env: ty::ParamEnv<'tcx>) @@ -905,34 +923,35 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.next_region_var(RegionVariableOrigin::NLL(origin)) } - /// Create a region inference variable for the given - /// region parameter definition. - pub fn region_var_for_def(&self, - span: Span, - def: &ty::RegionParameterDef) - -> ty::Region<'tcx> { - self.next_region_var(EarlyBoundRegion(span, def.name)) - } - - /// Create a type inference variable for the given - /// type parameter definition. The substitutions are - /// for actual parameters that may be referred to by - /// the default of this type parameter, if it exists. - /// E.g. `struct Foo(...);` when - /// used in a path such as `Foo::::new()` will - /// use an inference variable for `C` with `[T, U]` - /// as the substitutions for the default, `(T, U)`. - pub fn type_var_for_def(&self, - span: Span, - def: &ty::TypeParameterDef) - -> Ty<'tcx> { - let ty_var_id = self.type_variables - .borrow_mut() - .new_var(self.universe(), - false, - TypeVariableOrigin::TypeParameterDefinition(span, def.name)); - - self.tcx.mk_var(ty_var_id) + pub fn var_for_def(&self, + span: Span, + param: &ty::GenericParamDef) + -> Kind<'tcx> { + match param.kind { + GenericParamDefKind::Lifetime => { + // Create a region inference variable for the given + // region parameter definition. + self.next_region_var(EarlyBoundRegion(span, param.name)).into() + } + GenericParamDefKind::Type {..} => { + // Create a type inference variable for the given + // type parameter definition. The substitutions are + // for actual parameters that may be referred to by + // the default of this type parameter, if it exists. + // E.g. `struct Foo(...);` when + // used in a path such as `Foo::::new()` will + // use an inference variable for `C` with `[T, U]` + // as the substitutions for the default, `(T, U)`. + let ty_var_id = + self.type_variables + .borrow_mut() + .new_var(self.universe(), + false, + TypeVariableOrigin::TypeParameterDefinition(span, param.name)); + + self.tcx.mk_var(ty_var_id).into() + } + } } /// Given a set of generics defined on a type or impl, returns a substitution mapping each @@ -941,10 +960,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, def_id: DefId) -> &'tcx Substs<'tcx> { - Substs::for_item(self.tcx, def_id, |def, _| { - self.region_var_for_def(span, def) - }, |def, _| { - self.type_var_for_def(span, def) + Substs::for_item(self.tcx, def_id, |param, _| { + self.var_for_def(span, param) }) } @@ -1236,7 +1253,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { span: Span, lbrct: LateBoundRegionConversionTime, value: &ty::Binder) - -> (T, LazyBTreeMap>) + -> (T, BTreeMap>) where T : TypeFoldable<'tcx> { self.tcx.replace_late_bound_regions( @@ -1380,6 +1397,17 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { fn universe(&self) -> ty::UniverseIndex { self.universe.get() } + + /// Create and return a new subunivese of the current universe; + /// update `self.universe` to that new subuniverse. At present, + /// used only in the NLL subtyping code, which uses the new + /// universe-based scheme instead of the more limited leak-check + /// scheme. + pub fn create_subuniverse(&self) -> ty::UniverseIndex { + let u = self.universe.get().subuniverse(); + self.universe.set(u); + u + } } impl<'a, 'gcx, 'tcx> TypeTrace<'tcx> { diff --git a/src/librustc/infer/outlives/bounds.rs b/src/librustc/infer/outlives/bounds.rs deleted file mode 100644 index 4bc64acc76306..0000000000000 --- a/src/librustc/infer/outlives/bounds.rs +++ /dev/null @@ -1,216 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use infer::InferCtxt; -use syntax::ast; -use syntax::codemap::Span; -use traits::{FulfillmentContext, TraitEngine}; -use ty::{self, Ty, TypeFoldable}; -use ty::outlives::Component; -use ty::wf; - -/// Outlives bounds are relationships between generic parameters, -/// whether they both be regions (`'a: 'b`) or whether types are -/// involved (`T: 'a`). These relationships can be extracted from the -/// full set of predicates we understand or also from types (in which -/// case they are called implied bounds). They are fed to the -/// `OutlivesEnv` which in turn is supplied to the region checker and -/// other parts of the inference system. -#[derive(Debug)] -pub enum OutlivesBound<'tcx> { - RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), - RegionSubParam(ty::Region<'tcx>, ty::ParamTy), - RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), -} - -impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { - /// Implied bounds are region relationships that we deduce - /// automatically. The idea is that (e.g.) a caller must check that a - /// function's argument types are well-formed immediately before - /// calling that fn, and hence the *callee* can assume that its - /// argument types are well-formed. This may imply certain relationships - /// between generic parameters. For example: - /// - /// fn foo<'a,T>(x: &'a T) - /// - /// can only be called with a `'a` and `T` such that `&'a T` is WF. - /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. - /// - /// # Parameters - /// - /// - `param_env`, the where-clauses in scope - /// - `body_id`, the body-id to use when normalizing assoc types. - /// Note that this may cause outlives obligations to be injected - /// into the inference context with this body-id. - /// - `ty`, the type that we are supposed to assume is WF. - /// - `span`, a span to use when normalizing, hopefully not important, - /// might be useful if a `bug!` occurs. - pub fn implied_outlives_bounds( - &self, - param_env: ty::ParamEnv<'tcx>, - body_id: ast::NodeId, - ty: Ty<'tcx>, - span: Span, - ) -> Vec> { - let tcx = self.tcx; - - // Sometimes when we ask what it takes for T: WF, we get back that - // U: WF is required; in that case, we push U onto this stack and - // process it next. Currently (at least) these resulting - // predicates are always guaranteed to be a subset of the original - // type, so we need not fear non-termination. - let mut wf_types = vec![ty]; - - let mut implied_bounds = vec![]; - - let mut fulfill_cx = FulfillmentContext::new(); - - while let Some(ty) = wf_types.pop() { - // Compute the obligations for `ty` to be well-formed. If `ty` is - // an unresolved inference variable, just substituted an empty set - // -- because the return type here is going to be things we *add* - // to the environment, it's always ok for this set to be smaller - // than the ultimate set. (Note: normally there won't be - // unresolved inference variables here anyway, but there might be - // during typeck under some circumstances.) - let obligations = wf::obligations(self, param_env, body_id, ty, span).unwrap_or(vec![]); - - // NB: All of these predicates *ought* to be easily proven - // true. In fact, their correctness is (mostly) implied by - // other parts of the program. However, in #42552, we had - // an annoying scenario where: - // - // - Some `T::Foo` gets normalized, resulting in a - // variable `_1` and a `T: Trait` constraint - // (not sure why it couldn't immediately get - // solved). This result of `_1` got cached. - // - These obligations were dropped on the floor here, - // rather than being registered. - // - Then later we would get a request to normalize - // `T::Foo` which would result in `_1` being used from - // the cache, but hence without the `T: Trait` - // constraint. As a result, `_1` never gets resolved, - // and we get an ICE (in dropck). - // - // Therefore, we register any predicates involving - // inference variables. We restrict ourselves to those - // involving inference variables both for efficiency and - // to avoids duplicate errors that otherwise show up. - fulfill_cx.register_predicate_obligations( - self, - obligations - .iter() - .filter(|o| o.predicate.has_infer_types()) - .cloned(), - ); - - // From the full set of obligations, just filter down to the - // region relationships. - implied_bounds.extend(obligations.into_iter().flat_map(|obligation| { - assert!(!obligation.has_escaping_regions()); - match obligation.predicate { - ty::Predicate::Trait(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::Projection(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ConstEvaluatable(..) => vec![], - - ty::Predicate::WellFormed(subty) => { - wf_types.push(subty); - vec![] - } - - ty::Predicate::RegionOutlives(ref data) => match data.no_late_bound_regions() { - None => vec![], - Some(ty::OutlivesPredicate(r_a, r_b)) => { - vec![OutlivesBound::RegionSubRegion(r_b, r_a)] - } - }, - - ty::Predicate::TypeOutlives(ref data) => match data.no_late_bound_regions() { - None => vec![], - Some(ty::OutlivesPredicate(ty_a, r_b)) => { - let ty_a = self.resolve_type_vars_if_possible(&ty_a); - let components = tcx.outlives_components(ty_a); - Self::implied_bounds_from_components(r_b, components) - } - }, - } - })); - } - - // Ensure that those obligations that we had to solve - // get solved *here*. - match fulfill_cx.select_all_or_error(self) { - Ok(()) => (), - Err(errors) => self.report_fulfillment_errors(&errors, None, false), - } - - implied_bounds - } - - /// When we have an implied bound that `T: 'a`, we can further break - /// this down to determine what relationships would have to hold for - /// `T: 'a` to hold. We get to assume that the caller has validated - /// those relationships. - fn implied_bounds_from_components( - sub_region: ty::Region<'tcx>, - sup_components: Vec>, - ) -> Vec> { - sup_components - .into_iter() - .flat_map(|component| { - match component { - Component::Region(r) => - vec![OutlivesBound::RegionSubRegion(sub_region, r)], - Component::Param(p) => - vec![OutlivesBound::RegionSubParam(sub_region, p)], - Component::Projection(p) => - vec![OutlivesBound::RegionSubProjection(sub_region, p)], - Component::EscapingProjection(_) => - // If the projection has escaping regions, don't - // try to infer any implied bounds even for its - // free components. This is conservative, because - // the caller will still have to prove that those - // free components outlive `sub_region`. But the - // idea is that the WAY that the caller proves - // that may change in the future and we want to - // give ourselves room to get smarter here. - vec![], - Component::UnresolvedInferenceVariable(..) => - vec![], - } - }) - .collect() - } -} - -pub fn explicit_outlives_bounds<'tcx>( - param_env: ty::ParamEnv<'tcx>, -) -> impl Iterator> + 'tcx { - debug!("explicit_outlives_bounds()"); - param_env - .caller_bounds - .into_iter() - .filter_map(move |predicate| match predicate { - ty::Predicate::Projection(..) | - ty::Predicate::Trait(..) | - ty::Predicate::Subtype(..) | - ty::Predicate::WellFormed(..) | - ty::Predicate::ObjectSafe(..) | - ty::Predicate::ClosureKind(..) | - ty::Predicate::TypeOutlives(..) | - ty::Predicate::ConstEvaluatable(..) => None, - ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map( - |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a), - ), - }) -} diff --git a/src/librustc/infer/outlives/env.rs b/src/librustc/infer/outlives/env.rs index d47507592f80d..7f59a6794efbd 100644 --- a/src/librustc/infer/outlives/env.rs +++ b/src/librustc/infer/outlives/env.rs @@ -10,7 +10,7 @@ use infer::{GenericKind, InferCtxt}; use infer::outlives::free_region_map::FreeRegionMap; -use infer::outlives::bounds::{self, OutlivesBound}; +use traits::query::outlives_bounds::{self, OutlivesBound}; use ty::{self, Ty}; use syntax::ast; @@ -50,7 +50,7 @@ impl<'a, 'gcx: 'tcx, 'tcx: 'a> OutlivesEnvironment<'tcx> { region_bound_pairs: vec![], }; - env.add_outlives_bounds(None, bounds::explicit_outlives_bounds(param_env)); + env.add_outlives_bounds(None, outlives_bounds::explicit_outlives_bounds(param_env)); env } diff --git a/src/librustc/infer/outlives/mod.rs b/src/librustc/infer/outlives/mod.rs index 6aafebe79c671..bb3703b215732 100644 --- a/src/librustc/infer/outlives/mod.rs +++ b/src/librustc/infer/outlives/mod.rs @@ -12,5 +12,4 @@ pub mod env; pub mod free_region_map; -pub mod bounds; -mod obligations; +pub mod obligations; diff --git a/src/librustc/infer/outlives/obligations.rs b/src/librustc/infer/outlives/obligations.rs index e5461685bd470..c74783f5e4db5 100644 --- a/src/librustc/infer/outlives/obligations.rs +++ b/src/librustc/infer/outlives/obligations.rs @@ -71,11 +71,11 @@ use hir::def_id::DefId; use infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound}; +use syntax::ast; use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable}; -use ty::subst::{Subst, Substs}; use ty::outlives::Component; -use syntax::ast; +use ty::subst::{Subst, Substs}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// Registers that the given region obligation must be resolved @@ -90,8 +90,7 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ) { debug!( "register_region_obligation(body_id={:?}, obligation={:?})", - body_id, - obligation + body_id, obligation ); self.region_obligations @@ -100,13 +99,8 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { } /// Trait queries just want to pass back type obligations "as is" - pub fn take_registered_region_obligations( - &self, - ) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> { - ::std::mem::replace( - &mut *self.region_obligations.borrow_mut(), - vec![], - ) + pub fn take_registered_region_obligations(&self) -> Vec<(ast::NodeId, RegionObligation<'tcx>)> { + ::std::mem::replace(&mut *self.region_obligations.borrow_mut(), vec![]) } /// Process the region obligations that must be proven (during @@ -157,16 +151,20 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { debug!("process_registered_region_obligations()"); // pull out the region obligations with the given `body_id` (leaving the rest) - let mut my_region_obligations = Vec::with_capacity(self.region_obligations.borrow().len()); - { + let my_region_obligations = { let mut r_o = self.region_obligations.borrow_mut(); - for (_, obligation) in r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id) { - my_region_obligations.push(obligation); - } - } - - let outlives = - TypeOutlives::new(self, region_bound_pairs, implicit_region_bound, param_env); + let my_r_o = r_o.drain_filter(|(ro_body_id, _)| *ro_body_id == body_id) + .map(|(_, obligation)| obligation).collect::>(); + my_r_o + }; + + let outlives = &mut TypeOutlives::new( + self, + self.tcx, + region_bound_pairs, + implicit_region_bound, + param_env, + ); for RegionObligation { sup_type, @@ -176,16 +174,14 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { { debug!( "process_registered_region_obligations: sup_type={:?} sub_region={:?} cause={:?}", - sup_type, - sub_region, - cause + sup_type, sub_region, cause ); - let origin = SubregionOrigin::from_obligation_cause( - &cause, - || infer::RelateParamBound(cause.span, sup_type), - ); + let origin = SubregionOrigin::from_obligation_cause(&cause, || { + infer::RelateParamBound(cause.span, sup_type) + }); + let sup_type = self.resolve_type_vars_if_possible(&sup_type); outlives.type_must_outlive(origin, sup_type, sub_region); } } @@ -201,31 +197,68 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { ty: Ty<'tcx>, region: ty::Region<'tcx>, ) { - let outlives = - TypeOutlives::new(self, region_bound_pairs, implicit_region_bound, param_env); + let outlives = &mut TypeOutlives::new( + self, + self.tcx, + region_bound_pairs, + implicit_region_bound, + param_env, + ); + let ty = self.resolve_type_vars_if_possible(&ty); outlives.type_must_outlive(origin, ty, region); } } -#[must_use] // you ought to invoke `into_accrued_obligations` when you are done =) -struct TypeOutlives<'cx, 'gcx: 'tcx, 'tcx: 'cx> { +/// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` +/// obligation into a series of `'a: 'b` constraints and "verifys", as +/// described on the module comment. The final constraints are emitted +/// via a "delegate" of type `D` -- this is usually the `infcx`, which +/// accrues them into the `region_obligations` code, but for NLL we +/// use something else. +pub struct TypeOutlives<'cx, 'gcx: 'tcx, 'tcx: 'cx, D> +where + D: TypeOutlivesDelegate<'tcx>, +{ // See the comments on `process_registered_region_obligations` for the meaning // of these fields. - infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, + delegate: D, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, param_env: ty::ParamEnv<'tcx>, } -impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { - fn new( - infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>, +pub trait TypeOutlivesDelegate<'tcx> { + fn push_sub_region_constraint( + &mut self, + origin: SubregionOrigin<'tcx>, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ); + + fn push_verify( + &mut self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region<'tcx>, + bound: VerifyBound<'tcx>, + ); +} + +impl<'cx, 'gcx, 'tcx, D> TypeOutlives<'cx, 'gcx, 'tcx, D> +where + D: TypeOutlivesDelegate<'tcx>, +{ + pub fn new( + delegate: D, + tcx: TyCtxt<'cx, 'gcx, 'tcx>, region_bound_pairs: &'cx [(ty::Region<'tcx>, GenericKind<'tcx>)], implicit_region_bound: Option>, param_env: ty::ParamEnv<'tcx>, ) -> Self { Self { - infcx, + delegate, + tcx, region_bound_pairs, implicit_region_bound, param_env, @@ -240,33 +273,25 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { /// - `origin`, the reason we need this constraint /// - `ty`, the type `T` /// - `region`, the region `'a` - fn type_must_outlive( - &self, + pub fn type_must_outlive( + &mut self, origin: infer::SubregionOrigin<'tcx>, ty: Ty<'tcx>, region: ty::Region<'tcx>, ) { - let ty = self.infcx.resolve_type_vars_if_possible(&ty); - debug!( "type_must_outlive(ty={:?}, region={:?}, origin={:?})", - ty, - region, - origin + ty, region, origin ); assert!(!ty.has_escaping_regions()); - let components = self.tcx().outlives_components(ty); + let components = self.tcx.outlives_components(ty); self.components_must_outlive(origin, components, region); } - fn tcx(&self) -> TyCtxt<'cx, 'gcx, 'tcx> { - self.infcx.tcx - } - fn components_must_outlive( - &self, + &mut self, origin: infer::SubregionOrigin<'tcx>, components: Vec>, region: ty::Region<'tcx>, @@ -275,7 +300,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { let origin = origin.clone(); match component { Component::Region(region1) => { - self.infcx.sub_regions(origin, region, region1); + self.delegate.push_sub_region_constraint(origin, region, region1); } Component::Param(param_ty) => { self.param_ty_must_outlive(origin, region, param_ty); @@ -290,7 +315,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { // ignore this, we presume it will yield an error // later, since if a type variable is not resolved by // this point it never will be - self.infcx.tcx.sess.delay_span_bug( + self.tcx.sess.delay_span_bug( origin.span(), &format!("unresolved inference variable in outlives: {:?}", v), ); @@ -300,35 +325,31 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { } fn param_ty_must_outlive( - &self, + &mut self, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, param_ty: ty::ParamTy, ) { debug!( "param_ty_must_outlive(region={:?}, param_ty={:?}, origin={:?})", - region, - param_ty, - origin + region, param_ty, origin ); let verify_bound = self.param_bound(param_ty); let generic = GenericKind::Param(param_ty); - self.infcx - .verify_generic_bound(origin, generic, region, verify_bound); + self.delegate + .push_verify(origin, generic, region, verify_bound); } fn projection_must_outlive( - &self, + &mut self, origin: infer::SubregionOrigin<'tcx>, region: ty::Region<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, ) { debug!( "projection_must_outlive(region={:?}, projection_ty={:?}, origin={:?})", - region, - projection_ty, - origin + region, projection_ty, origin ); // This case is thorny for inference. The fundamental problem is @@ -382,7 +403,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { } for r in projection_ty.substs.regions() { - self.infcx.sub_regions(origin.clone(), region, r); + self.delegate.push_sub_region_constraint(origin.clone(), region, r); } return; @@ -408,7 +429,8 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { .any(|r| env_bounds.contains(&r)) { debug!("projection_must_outlive: unique declared bound appears in trait ref"); - self.infcx.sub_regions(origin.clone(), region, unique_bound); + self.delegate + .push_sub_region_constraint(origin.clone(), region, unique_bound); return; } } @@ -420,8 +442,8 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { // even though a satisfactory solution exists. let verify_bound = self.projection_bound(env_bounds, projection_ty); let generic = GenericKind::Projection(projection_ty); - self.infcx - .verify_generic_bound(origin, generic.clone(), region, verify_bound); + self.delegate + .push_verify(origin, generic.clone(), region, verify_bound); } fn type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { @@ -469,12 +491,11 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { ) -> VerifyBound<'tcx> { debug!( "projection_bound(declared_bounds={:?}, projection_ty={:?})", - declared_bounds, - projection_ty + declared_bounds, projection_ty ); // see the extensive comment in projection_must_outlive - let ty = self.infcx + let ty = self .tcx .mk_projection(projection_ty.item_def_id, projection_ty.substs); let recursive_bound = self.recursive_type_bound(ty); @@ -483,11 +504,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { } fn recursive_type_bound(&self, ty: Ty<'tcx>) -> VerifyBound<'tcx> { - let mut bounds = vec![]; - - for subty in ty.walk_shallow() { - bounds.push(self.type_bound(subty)); - } + let mut bounds = ty.walk_shallow().map(|subty| self.type_bound(subty)).collect::>(); let mut regions = ty.regions(); regions.retain(|r| !r.is_late_bound()); // ignore late-bound regions @@ -507,7 +524,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { &self, generic: GenericKind<'tcx>, ) -> Vec> { - let tcx = self.tcx(); + let tcx = self.tcx; // To start, collect bounds from user environment. Note that // parameter environments are already elaborated, so we don't @@ -559,7 +576,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { debug!("projection_bounds(projection_ty={:?})", projection_ty); let mut bounds = self.region_bounds_declared_on_associated_item(projection_ty.item_def_id); for r in &mut bounds { - *r = r.subst(self.tcx(), projection_ty.substs); + *r = r.subst(self.tcx, projection_ty.substs); } bounds } @@ -598,7 +615,7 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { &self, assoc_item_def_id: DefId, ) -> Vec> { - let tcx = self.tcx(); + let tcx = self.tcx; let assoc_item = tcx.associated_item(assoc_item_def_id); let trait_def_id = assoc_item.container.assert_trait(); let trait_predicates = tcx.predicates_of(trait_def_id); @@ -634,3 +651,25 @@ impl<'cx, 'gcx, 'tcx> TypeOutlives<'cx, 'gcx, 'tcx> { .collect() } } + +impl<'cx, 'gcx, 'tcx> TypeOutlivesDelegate<'tcx> for &'cx InferCtxt<'cx, 'gcx, 'tcx> { + fn push_sub_region_constraint( + &mut self, + origin: SubregionOrigin<'tcx>, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + ) { + self.sub_regions(origin, a, b) + } + + fn push_verify( + &mut self, + origin: SubregionOrigin<'tcx>, + kind: GenericKind<'tcx>, + a: ty::Region<'tcx>, + bound: VerifyBound<'tcx>, + ) { + self.verify_generic_bound(origin, kind, a, bound) + } +} + diff --git a/src/librustc/infer/region_constraints/README.md b/src/librustc/infer/region_constraints/README.md index 07b87e2012dde..61603e6dee686 100644 --- a/src/librustc/infer/region_constraints/README.md +++ b/src/librustc/infer/region_constraints/README.md @@ -3,7 +3,7 @@ > WARNING: This README is obsolete and will be removed soon! For > more info on how the current borrowck works, see the [rustc guide]. -[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir-borrowck.html +[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir/borrowck.html ## Terminology diff --git a/src/librustc/infer/region_constraints/mod.rs b/src/librustc/infer/region_constraints/mod.rs index c388fa2137192..296808cea2bd7 100644 --- a/src/librustc/infer/region_constraints/mod.rs +++ b/src/librustc/infer/region_constraints/mod.rs @@ -69,6 +69,10 @@ pub struct RegionConstraintCollector<'tcx> { /// would wind up with a fresh stream of region variables that /// have been equated but appear distinct. unification_table: ut::UnificationTable>, + + /// a flag set to true when we perform any unifications; this is used + /// to micro-optimize `take_and_reset_data` + any_unifications: bool, } pub type VarInfos = IndexVec; @@ -234,6 +238,7 @@ pub struct RegionVariableInfo { pub struct RegionSnapshot { length: usize, region_snapshot: ut::Snapshot>, + any_unifications: bool, } /// When working with skolemized regions, we often wish to find all of @@ -280,6 +285,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { bound_count: 0, undo_log: Vec::new(), unification_table: ut::UnificationTable::new(), + any_unifications: false, } } @@ -318,13 +324,14 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // should think carefully about whether it needs to be cleared // or updated in some way. let RegionConstraintCollector { - var_infos, + var_infos: _, data, lubs, glbs, bound_count: _, undo_log: _, unification_table, + any_unifications, } = self; // Clear the tables of (lubs, glbs), so that we will create @@ -338,9 +345,9 @@ impl<'tcx> RegionConstraintCollector<'tcx> { // un-unified" state. Note that when we unify `a` and `b`, we // also insert `a <= b` and a `b <= a` edges, so the // `RegionConstraintData` contains the relationship here. - *unification_table = ut::UnificationTable::new(); - for vid in var_infos.indices() { - unification_table.new_key(unify_key::RegionVidKey { min_vid: vid }); + if *any_unifications { + unification_table.reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid }); + *any_unifications = false; } mem::replace(data, RegionConstraintData::default()) @@ -361,6 +368,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { RegionSnapshot { length, region_snapshot: self.unification_table.snapshot(), + any_unifications: self.any_unifications, } } @@ -388,6 +396,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { let c = self.undo_log.pop().unwrap(); assert!(c == OpenSnapshot); self.unification_table.rollback_to(snapshot.region_snapshot); + self.any_unifications = snapshot.any_unifications; } fn rollback_undo_entry(&mut self, undo_entry: UndoLogEntry<'tcx>) { @@ -626,6 +635,7 @@ impl<'tcx> RegionConstraintCollector<'tcx> { if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) { self.unification_table.union(sub, sup); + self.any_unifications = true; } } } diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index 879d38c489443..8e71df3c34b0b 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -45,17 +45,15 @@ #![feature(const_fn)] #![feature(core_intrinsics)] #![feature(drain_filter)] -#![feature(entry_or_default)] -#![cfg_attr(stage0, feature(dyn_trait))] #![feature(from_ref)] #![feature(fs_read_write)] +#![feature(iterator_find_map)] #![cfg_attr(windows, feature(libc))] -#![feature(macro_lifetime_matcher)] #![feature(macro_vis_matcher)] #![feature(never_type)] #![feature(exhaustive_patterns)] +#![feature(extern_types)] #![feature(non_exhaustive)] -#![feature(nonzero)] #![feature(proc_macro_internals)] #![feature(quote)] #![feature(optin_builtin_traits)] @@ -67,9 +65,15 @@ #![feature(unboxed_closures)] #![feature(trace_macros)] #![feature(trusted_len)] +#![feature(vec_remove_item)] #![feature(catch_expr)] +#![feature(step_trait)] +#![feature(integer_atomics)] #![feature(test)] +#![feature(in_band_lifetimes)] +#![feature(macro_at_most_once_rep)] #![feature(inclusive_range_methods)] +#![feature(crate_in_paths)] #![recursion_limit="512"] @@ -80,17 +84,23 @@ extern crate fmt_macros; extern crate getopts; extern crate graphviz; #[macro_use] extern crate lazy_static; +#[macro_use] extern crate scoped_tls; #[cfg(windows)] extern crate libc; +extern crate polonius_engine; extern crate rustc_target; #[macro_use] extern crate rustc_data_structures; extern crate serialize; +extern crate parking_lot; extern crate rustc_errors as errors; +extern crate rustc_rayon as rayon; +extern crate rustc_rayon_core as rayon_core; #[macro_use] extern crate log; #[macro_use] extern crate syntax; extern crate syntax_pos; extern crate jobserver; extern crate proc_macro; +extern crate chalk_engine; extern crate serialize as rustc_serialize; // used by deriving @@ -123,7 +133,6 @@ pub mod middle { pub mod allocator; pub mod borrowck; pub mod expr_use_visitor; - pub mod const_val; pub mod cstore; pub mod dataflow; pub mod dead; @@ -155,6 +164,7 @@ pub mod util { pub mod ppaux; pub mod nodemap; pub mod fs; + pub mod time_graph; } // A private module so that macro-expanded idents like diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index 109edffcde38a..4184cba7db3ef 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -14,9 +14,10 @@ //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. -use errors::DiagnosticBuilder; +use errors::{Applicability, DiagnosticBuilder}; use lint::{LintPass, LateLintPass, LintArray}; use session::Session; +use syntax::ast; use syntax::codemap::Span; declare_lint! { @@ -27,7 +28,7 @@ declare_lint! { declare_lint! { pub CONST_ERR, - Warn, + Deny, "constant evaluation detected erroneous expression" } @@ -76,7 +77,8 @@ declare_lint! { declare_lint! { pub UNREACHABLE_CODE, Warn, - "detects unreachable code paths" + "detects unreachable code paths", + report_in_external_macro: true } declare_lint! { @@ -176,12 +178,6 @@ declare_lint! { not named `mod.rs`" } -declare_lint! { - pub LEGACY_IMPORTS, - Deny, - "detects names that resolve to ambiguous glob imports with RFC 1560" -} - declare_lint! { pub LEGACY_CONSTRUCTOR_VISIBILITY, Deny, @@ -208,14 +204,21 @@ declare_lint! { declare_lint! { pub INCOHERENT_FUNDAMENTAL_IMPLS, - Warn, + Deny, "potentially-conflicting impls were erroneously allowed" } +declare_lint! { + pub BAD_REPR, + Warn, + "detects incorrect use of `repr` attribute" +} + declare_lint! { pub DEPRECATED, Warn, - "detects use of deprecated items" + "detects use of deprecated items", + report_in_external_macro: true } declare_lint! { @@ -231,9 +234,15 @@ declare_lint! { } declare_lint! { - pub SINGLE_USE_LIFETIME, + pub SINGLE_USE_LIFETIMES, + Allow, + "detects lifetime parameters that are only used once" +} + +declare_lint! { + pub UNUSED_LIFETIMES, Allow, - "detects single use lifetimes" + "detects lifetime parameters that are never used" } declare_lint! { @@ -243,19 +252,19 @@ declare_lint! { } declare_lint! { - pub ELIDED_LIFETIME_IN_PATH, + pub ELIDED_LIFETIMES_IN_PATHS, Allow, - "hidden lifetime parameters are deprecated, try `Foo<'_>`" + "hidden lifetime parameters in types are deprecated" } declare_lint! { - pub BARE_TRAIT_OBJECT, + pub BARE_TRAIT_OBJECTS, Allow, "suggest using `dyn Trait` for trait objects" } declare_lint! { - pub ABSOLUTE_PATH_STARTING_WITH_MODULE, + pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, Allow, "fully qualified paths that start with a module name \ instead of `crate`, `self`, or an extern crate name" @@ -268,11 +277,69 @@ declare_lint! { } declare_lint! { - pub UNSTABLE_NAME_COLLISION, + pub UNSTABLE_NAME_COLLISIONS, Warn, "detects name collision with an existing but unstable method" } +declare_lint! { + pub IRREFUTABLE_LET_PATTERNS, + Deny, + "detects irrefutable patterns in if-let and while-let statements" +} + +declare_lint! { + pub UNUSED_LABELS, + Allow, + "detects labels that are never used" +} + +declare_lint! { + pub DUPLICATE_ASSOCIATED_TYPE_BINDINGS, + Warn, + "warns about duplicate associated type bindings in generics" +} + +declare_lint! { + pub DUPLICATE_MACRO_EXPORTS, + Deny, + "detects duplicate macro exports" +} + +declare_lint! { + pub INTRA_DOC_LINK_RESOLUTION_FAILURE, + Warn, + "warn about documentation intra links resolution failure" +} + +declare_lint! { + pub WHERE_CLAUSES_OBJECT_SAFETY, + Warn, + "checks the object safety of where clauses" +} + +declare_lint! { + pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + Warn, + "detects proc macro derives using inaccessible names from parent modules" +} + +declare_lint! { + pub MACRO_USE_EXTERN_CRATE, + Allow, + "the `#[macro_use]` attribute is now deprecated in favor of using macros \ + via the module system" +} + +/// Some lints that are buffered from `libsyntax`. See `syntax::early_buffered_lints`. +pub mod parser { + declare_lint! { + pub QUESTION_MARK_MACRO_SEP, + Allow, + "detects the use of `?` as a macro separator" + } +} + /// Does nothing as a lint pass, but registers some `Lint`s /// which are used by other parts of the compiler. #[derive(Copy, Clone)] @@ -308,7 +375,6 @@ impl LintPass for HardwiredLints { SAFE_PACKED_BORROWS, PATTERNS_IN_FNS_WITHOUT_BODY, LEGACY_DIRECTORY_OWNERSHIP, - LEGACY_IMPORTS, LEGACY_CONSTRUCTOR_VISIBILITY, MISSING_FRAGMENT_SPECIFIER, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES, @@ -317,12 +383,22 @@ impl LintPass for HardwiredLints { DEPRECATED, UNUSED_UNSAFE, UNUSED_MUT, - SINGLE_USE_LIFETIME, + SINGLE_USE_LIFETIMES, + UNUSED_LIFETIMES, + UNUSED_LABELS, TYVAR_BEHIND_RAW_POINTER, - ELIDED_LIFETIME_IN_PATH, - BARE_TRAIT_OBJECT, - ABSOLUTE_PATH_STARTING_WITH_MODULE, - UNSTABLE_NAME_COLLISION, + ELIDED_LIFETIMES_IN_PATHS, + BARE_TRAIT_OBJECTS, + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + UNSTABLE_NAME_COLLISIONS, + IRREFUTABLE_LET_PATTERNS, + DUPLICATE_ASSOCIATED_TYPE_BINDINGS, + DUPLICATE_MACRO_EXPORTS, + INTRA_DOC_LINK_RESOLUTION_FAILURE, + WHERE_CLAUSES_OBJECT_SAFETY, + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + MACRO_USE_EXTERN_CRATE, + parser::QUESTION_MARK_MACRO_SEP, ) } } @@ -334,6 +410,9 @@ pub enum BuiltinLintDiagnostics { Normal, BareTraitObject(Span, /* is_global */ bool), AbsPathWithModule(Span), + DuplicatedMacroExports(ast::Ident, Span, Span), + ProcMacroDeriveResolutionFallback(Span), + ElidedLifetimesInPaths(usize, Span, bool, Span, String), } impl BuiltinLintDiagnostics { @@ -341,15 +420,16 @@ impl BuiltinLintDiagnostics { match self { BuiltinLintDiagnostics::Normal => (), BuiltinLintDiagnostics::BareTraitObject(span, is_global) => { - let sugg = match sess.codemap().span_to_snippet(span) { - Ok(ref s) if is_global => format!("dyn ({})", s), - Ok(s) => format!("dyn {}", s), - Err(_) => format!("dyn ") + let (sugg, app) = match sess.codemap().span_to_snippet(span) { + Ok(ref s) if is_global => (format!("dyn ({})", s), + Applicability::MachineApplicable), + Ok(s) => (format!("dyn {}", s), Applicability::MachineApplicable), + Err(_) => (format!("dyn "), Applicability::HasPlaceholders) }; - db.span_suggestion(span, "use `dyn`", sugg); + db.span_suggestion_with_applicability(span, "use `dyn`", sugg, app); } BuiltinLintDiagnostics::AbsPathWithModule(span) => { - let sugg = match sess.codemap().span_to_snippet(span) { + let (sugg, app) = match sess.codemap().span_to_snippet(span) { Ok(ref s) => { // FIXME(Manishearth) ideally the emitting code // can tell us whether or not this is global @@ -359,11 +439,54 @@ impl BuiltinLintDiagnostics { "::" }; - format!("crate{}{}", opt_colon, s) + (format!("crate{}{}", opt_colon, s), Applicability::MachineApplicable) + } + Err(_) => (format!("crate::"), Applicability::HasPlaceholders) + }; + db.span_suggestion_with_applicability(span, "use `crate`", sugg, app); + } + BuiltinLintDiagnostics::DuplicatedMacroExports(ident, earlier_span, later_span) => { + db.span_label(later_span, format!("`{}` already exported", ident)); + db.span_note(earlier_span, "previous macro export is now shadowed"); + } + BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(span) => { + db.span_label(span, "names from parent modules are not \ + accessible without an explicit import"); + } + BuiltinLintDiagnostics::ElidedLifetimesInPaths( + n, path_span, incl_angl_brckt, insertion_span, anon_lts + ) => { + let (replace_span, suggestion) = if incl_angl_brckt { + (insertion_span, anon_lts) + } else { + // When possible, prefer a suggestion that replaces the whole + // `Path` expression with `Path<'_, T>`, rather than inserting `'_, ` + // at a point (which makes for an ugly/confusing label) + if let Ok(snippet) = sess.codemap().span_to_snippet(path_span) { + // But our spans can get out of whack due to macros; if the place we think + // we want to insert `'_` isn't even within the path expression's span, we + // should bail out of making any suggestion rather than panicking on a + // subtract-with-overflow or string-slice-out-out-bounds (!) + // FIXME: can we do better? + if insertion_span.lo().0 < path_span.lo().0 { + return; + } + let insertion_index = (insertion_span.lo().0 - path_span.lo().0) as usize; + if insertion_index > snippet.len() { + return; + } + let (before, after) = snippet.split_at(insertion_index); + (path_span, format!("{}{}{}", before, anon_lts, after)) + } else { + (insertion_span, anon_lts) } - Err(_) => format!("crate::") }; - db.span_suggestion(span, "use `crate`", sugg); + db.span_suggestion_with_applicability( + replace_span, + &format!("indicate the anonymous lifetime{}", if n >= 2 { "s" } else { "" }), + suggestion, + Applicability::MachineApplicable + ); } } } diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index f90baa2ccd95d..14cfaa8153377 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -10,15 +10,15 @@ //! Implementation of lint checking. //! -//! The lint checking is mostly consolidated into one pass which runs just -//! before translation to LLVM bytecode. Throughout compilation, lint warnings +//! The lint checking is mostly consolidated into one pass which runs +//! after all other analyses. Throughout compilation, lint warnings //! can be added via the `add_lint` method on the Session structure. This //! requires a span and an id of the node that the lint is being added to. The //! lint isn't actually emitted at that time because it is unknown what the //! actual lint level at that location is. //! -//! To actually emit lint warnings/errors, a separate pass is used just before -//! translation. A context keeps track of the current state of all lint levels. +//! To actually emit lint warnings/errors, a separate pass is used. +//! A context keeps track of the current state of all lint levels. //! Upon entering a node of the ast which can modify the lint settings, the //! previous lint state is pushed onto a stack and the ast is then recursed //! upon. As the ast is traversed, this keeps track of the current lint level @@ -27,7 +27,7 @@ use self::TargetLint::*; use std::slice; -use rustc_data_structures::sync::{RwLock, ReadGuard}; +use rustc_data_structures::sync::ReadGuard; use lint::{EarlyLintPassObject, LateLintPassObject}; use lint::{Level, Lint, LintId, LintPass, LintBuffer}; use lint::builtin::BuiltinLintDiagnostics; @@ -59,8 +59,8 @@ pub struct LintStore { lints: Vec<(&'static Lint, bool)>, /// Trait objects for each lint pass. - /// This is only `None` while performing a lint pass. See the definition - /// of `LintSession::new`. + /// This is only `None` while performing a lint pass. + pre_expansion_passes: Option>, early_passes: Option>, late_passes: Option>, @@ -131,14 +131,15 @@ pub enum CheckLintNameResult<'a> { /// Lint doesn't exist NoLint, /// The lint is either renamed or removed. This is the warning - /// message. - Warning(String), + /// message, and an optional new name (`None` if removed). + Warning(String, Option), } impl LintStore { pub fn new() -> LintStore { LintStore { lints: vec![], + pre_expansion_passes: Some(vec![]), early_passes: Some(vec![]), late_passes: Some(vec![]), by_name: FxHashMap(), @@ -165,6 +166,15 @@ impl LintStore { self.early_passes.as_mut().unwrap().push(pass); } + pub fn register_pre_expansion_pass( + &mut self, + sess: Option<&Session>, + pass: EarlyLintPassObject, + ) { + self.push_pass(sess, false, &pass); + self.pre_expansion_passes.as_mut().unwrap().push(pass); + } + pub fn register_late_pass(&mut self, sess: Option<&Session>, from_plugin: bool, @@ -178,10 +188,10 @@ impl LintStore { sess: Option<&Session>, from_plugin: bool, pass: &Box

) { - for &lint in pass.get_lints() { - self.lints.push((*lint, from_plugin)); + for lint in pass.get_lints() { + self.lints.push((lint, from_plugin)); - let id = LintId::of(*lint); + let id = LintId::of(lint); if self.by_name.insert(lint.name_lower(), Id(id)).is_some() { let msg = format!("duplicate specification of lint {}", lint.name_lower()); match (sess, from_plugin) { @@ -209,7 +219,7 @@ impl LintStore { } } - let mut future_incompatible = vec![]; + let mut future_incompatible = Vec::with_capacity(lints.len()); for lint in lints { future_incompatible.push(lint.id); self.future_incompatible.insert(lint.id, lint); @@ -280,7 +290,7 @@ impl LintStore { level: Level) { let db = match self.check_lint_name(lint_name) { CheckLintNameResult::Ok(_) => None, - CheckLintNameResult::Warning(ref msg) => { + CheckLintNameResult::Warning(ref msg, _) => { Some(sess.struct_warn(msg)) }, CheckLintNameResult::NoLint => { @@ -313,12 +323,14 @@ impl LintStore { match self.by_name.get(lint_name) { Some(&Renamed(ref new_name, _)) => { CheckLintNameResult::Warning( - format!("lint {} has been renamed to {}", lint_name, new_name) + format!("lint `{}` has been renamed to `{}`", lint_name, new_name), + Some(new_name.to_owned()) ) }, Some(&Removed(ref reason)) => { CheckLintNameResult::Warning( - format!("lint {} has been removed: {}", lint_name, reason) + format!("lint `{}` has been removed: `{}`", lint_name, reason), + None ) }, None => { @@ -332,28 +344,6 @@ impl LintStore { } } -impl<'a, PassObject: LintPassObject> LintSession<'a, PassObject> { - /// Creates a new `LintSession`, by moving out the `LintStore`'s initial - /// lint levels and pass objects. These can be restored using the `restore` - /// method. - fn new(store: &'a RwLock) -> LintSession<'a, PassObject> { - let mut s = store.borrow_mut(); - let passes = PassObject::take_passes(&mut *s); - drop(s); - LintSession { - lints: store.borrow(), - passes, - } - } - - /// Restores the levels back to the original lint store. - fn restore(self, store: &RwLock) { - drop(self.lints); - let mut s = store.borrow_mut(); - PassObject::restore_passes(&mut *s, self.passes); - } -} - /// Context for lint checking after type checking. pub struct LateContext<'a, 'tcx: 'a> { /// Type context we're checking in. @@ -395,7 +385,7 @@ pub struct EarlyContext<'a> { } /// Convenience macro for calling a `LintPass` method on every pass in the context. -macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({ +macro_rules! run_lints { ($cx:expr, $f:ident, $($args:expr),*) => ({ // Move the vector of passes out of `$cx` so that we can // iterate over it mutably while passing `$cx` to the methods. let mut passes = $cx.lint_sess_mut().passes.take().unwrap(); @@ -405,30 +395,11 @@ macro_rules! run_lints { ($cx:expr, $f:ident, $ps:ident, $($args:expr),*) => ({ $cx.lint_sess_mut().passes = Some(passes); }) } -pub trait LintPassObject: Sized { - fn take_passes(store: &mut LintStore) -> Option>; - fn restore_passes(store: &mut LintStore, passes: Option>); -} - -impl LintPassObject for EarlyLintPassObject { - fn take_passes(store: &mut LintStore) -> Option> { - store.early_passes.take() - } +pub trait LintPassObject: Sized {} - fn restore_passes(store: &mut LintStore, passes: Option>) { - store.early_passes = passes; - } -} +impl LintPassObject for EarlyLintPassObject {} -impl LintPassObject for LateLintPassObject { - fn take_passes(store: &mut LintStore) -> Option> { - store.late_passes.take() - } - - fn restore_passes(store: &mut LintStore, passes: Option>) { - store.late_passes = passes; - } -} +impl LintPassObject for LateLintPassObject {} pub trait LintContext<'tcx>: Sized { @@ -515,14 +486,21 @@ pub trait LintContext<'tcx>: Sized { impl<'a> EarlyContext<'a> { - fn new(sess: &'a Session, - krate: &'a ast::Crate) -> EarlyContext<'a> { + fn new( + sess: &'a Session, + krate: &'a ast::Crate, + passes: Option>, + buffered: LintBuffer, + ) -> EarlyContext<'a> { EarlyContext { sess, krate, - lint_sess: LintSession::new(&sess.lint_store), + lint_sess: LintSession { + lints: sess.lint_store.borrow(), + passes, + }, builder: LintLevelSets::builder(sess), - buffered: sess.buffered_lints.borrow_mut().take().unwrap(), + buffered, } } @@ -558,12 +536,12 @@ impl<'a, 'tcx> LintContext<'tcx> for LateContext<'a, 'tcx> { fn enter_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { debug!("late context: enter_attrs({:?})", attrs); - run_lints!(self, enter_lint_attrs, late_passes, attrs); + run_lints!(self, enter_lint_attrs, attrs); } fn exit_attrs(&mut self, attrs: &'tcx [ast::Attribute]) { debug!("late context: exit_attrs({:?})", attrs); - run_lints!(self, exit_lint_attrs, late_passes, attrs); + run_lints!(self, exit_lint_attrs, attrs); } fn lookup>(&self, @@ -615,12 +593,12 @@ impl<'a> LintContext<'a> for EarlyContext<'a> { fn enter_attrs(&mut self, attrs: &'a [ast::Attribute]) { debug!("early context: enter_attrs({:?})", attrs); - run_lints!(self, enter_lint_attrs, early_passes, attrs); + run_lints!(self, enter_lint_attrs, attrs); } fn exit_attrs(&mut self, attrs: &'a [ast::Attribute]) { debug!("early context: exit_attrs({:?})", attrs); - run_lints!(self, exit_lint_attrs, early_passes, attrs); + run_lints!(self, exit_lint_attrs, attrs); } fn lookup>(&self, @@ -655,6 +633,9 @@ impl<'a, 'tcx> LateContext<'a, 'tcx> { f(self); self.param_env = old_param_env; } + pub fn current_lint_root(&self) -> ast::NodeId { + self.last_ast_node_with_lint_attrs + } } impl<'a, 'tcx> LayoutOf for &'a LateContext<'a, 'tcx> { @@ -683,9 +664,9 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { } fn visit_body(&mut self, body: &'tcx hir::Body) { - run_lints!(self, check_body, late_passes, body); + run_lints!(self, check_body, body); hir_visit::walk_body(self, body); - run_lints!(self, check_body_post, late_passes, body); + run_lints!(self, check_body_post, body); } fn visit_item(&mut self, it: &'tcx hir::Item) { @@ -693,9 +674,9 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { self.generics = it.node.generics(); self.with_lint_attrs(it.id, &it.attrs, |cx| { cx.with_param_env(it.id, |cx| { - run_lints!(cx, check_item, late_passes, it); + run_lints!(cx, check_item, it); hir_visit::walk_item(cx, it); - run_lints!(cx, check_item_post, late_passes, it); + run_lints!(cx, check_item_post, it); }); }); self.generics = generics; @@ -704,23 +685,23 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem) { self.with_lint_attrs(it.id, &it.attrs, |cx| { cx.with_param_env(it.id, |cx| { - run_lints!(cx, check_foreign_item, late_passes, it); + run_lints!(cx, check_foreign_item, it); hir_visit::walk_foreign_item(cx, it); - run_lints!(cx, check_foreign_item_post, late_passes, it); + run_lints!(cx, check_foreign_item_post, it); }); }) } fn visit_pat(&mut self, p: &'tcx hir::Pat) { - run_lints!(self, check_pat, late_passes, p); + run_lints!(self, check_pat, p); hir_visit::walk_pat(self, p); } fn visit_expr(&mut self, e: &'tcx hir::Expr) { self.with_lint_attrs(e.id, &e.attrs, |cx| { - run_lints!(cx, check_expr, late_passes, e); + run_lints!(cx, check_expr, e); hir_visit::walk_expr(cx, e); - run_lints!(cx, check_expr_post, late_passes, e); + run_lints!(cx, check_expr_post, e); }) } @@ -730,7 +711,7 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { // - local // - expression // so we keep track of lint levels there - run_lints!(self, check_stmt, late_passes, s); + run_lints!(self, check_stmt, s); hir_visit::walk_stmt(self, s); } @@ -741,9 +722,9 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { let old_tables = self.tables; self.tables = self.tcx.body_tables(body_id); let body = self.tcx.hir.body(body_id); - run_lints!(self, check_fn, late_passes, fk, decl, body, span, id); + run_lints!(self, check_fn, fk, decl, body, span, id); hir_visit::walk_fn(self, fk, decl, body_id, span, id); - run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id); + run_lints!(self, check_fn_post, fk, decl, body, span, id); self.tables = old_tables; } @@ -753,14 +734,14 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { g: &'tcx hir::Generics, item_id: ast::NodeId, _: Span) { - run_lints!(self, check_struct_def, late_passes, s, name, g, item_id); + run_lints!(self, check_struct_def, s, name, g, item_id); hir_visit::walk_struct_def(self, s); - run_lints!(self, check_struct_def_post, late_passes, s, name, g, item_id); + run_lints!(self, check_struct_def_post, s, name, g, item_id); } fn visit_struct_field(&mut self, s: &'tcx hir::StructField) { self.with_lint_attrs(s.id, &s.attrs, |cx| { - run_lints!(cx, check_struct_field, late_passes, s); + run_lints!(cx, check_struct_field, s); hir_visit::walk_struct_field(cx, s); }) } @@ -770,68 +751,68 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { g: &'tcx hir::Generics, item_id: ast::NodeId) { self.with_lint_attrs(v.node.data.id(), &v.node.attrs, |cx| { - run_lints!(cx, check_variant, late_passes, v, g); + run_lints!(cx, check_variant, v, g); hir_visit::walk_variant(cx, v, g, item_id); - run_lints!(cx, check_variant_post, late_passes, v, g); + run_lints!(cx, check_variant_post, v, g); }) } fn visit_ty(&mut self, t: &'tcx hir::Ty) { - run_lints!(self, check_ty, late_passes, t); + run_lints!(self, check_ty, t); hir_visit::walk_ty(self, t); } fn visit_name(&mut self, sp: Span, name: ast::Name) { - run_lints!(self, check_name, late_passes, sp, name); + run_lints!(self, check_name, sp, name); } fn visit_mod(&mut self, m: &'tcx hir::Mod, s: Span, n: ast::NodeId) { - run_lints!(self, check_mod, late_passes, m, s, n); + run_lints!(self, check_mod, m, s, n); hir_visit::walk_mod(self, m, n); - run_lints!(self, check_mod_post, late_passes, m, s, n); + run_lints!(self, check_mod_post, m, s, n); } fn visit_local(&mut self, l: &'tcx hir::Local) { self.with_lint_attrs(l.id, &l.attrs, |cx| { - run_lints!(cx, check_local, late_passes, l); + run_lints!(cx, check_local, l); hir_visit::walk_local(cx, l); }) } fn visit_block(&mut self, b: &'tcx hir::Block) { - run_lints!(self, check_block, late_passes, b); + run_lints!(self, check_block, b); hir_visit::walk_block(self, b); - run_lints!(self, check_block_post, late_passes, b); + run_lints!(self, check_block_post, b); } fn visit_arm(&mut self, a: &'tcx hir::Arm) { - run_lints!(self, check_arm, late_passes, a); + run_lints!(self, check_arm, a); hir_visit::walk_arm(self, a); } fn visit_decl(&mut self, d: &'tcx hir::Decl) { - run_lints!(self, check_decl, late_passes, d); + run_lints!(self, check_decl, d); hir_visit::walk_decl(self, d); } fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam) { - run_lints!(self, check_generic_param, late_passes, p); + run_lints!(self, check_generic_param, p); hir_visit::walk_generic_param(self, p); } fn visit_generics(&mut self, g: &'tcx hir::Generics) { - run_lints!(self, check_generics, late_passes, g); + run_lints!(self, check_generics, g); hir_visit::walk_generics(self, g); } fn visit_where_predicate(&mut self, p: &'tcx hir::WherePredicate) { - run_lints!(self, check_where_predicate, late_passes, p); + run_lints!(self, check_where_predicate, p); hir_visit::walk_where_predicate(self, p); } fn visit_poly_trait_ref(&mut self, t: &'tcx hir::PolyTraitRef, m: hir::TraitBoundModifier) { - run_lints!(self, check_poly_trait_ref, late_passes, t, m); + run_lints!(self, check_poly_trait_ref, t, m); hir_visit::walk_poly_trait_ref(self, t, m); } @@ -840,9 +821,9 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { self.generics = Some(&trait_item.generics); self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { cx.with_param_env(trait_item.id, |cx| { - run_lints!(cx, check_trait_item, late_passes, trait_item); + run_lints!(cx, check_trait_item, trait_item); hir_visit::walk_trait_item(cx, trait_item); - run_lints!(cx, check_trait_item_post, late_passes, trait_item); + run_lints!(cx, check_trait_item_post, trait_item); }); }); self.generics = generics; @@ -853,71 +834,71 @@ impl<'a, 'tcx> hir_visit::Visitor<'tcx> for LateContext<'a, 'tcx> { self.generics = Some(&impl_item.generics); self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { cx.with_param_env(impl_item.id, |cx| { - run_lints!(cx, check_impl_item, late_passes, impl_item); + run_lints!(cx, check_impl_item, impl_item); hir_visit::walk_impl_item(cx, impl_item); - run_lints!(cx, check_impl_item_post, late_passes, impl_item); + run_lints!(cx, check_impl_item_post, impl_item); }); }); self.generics = generics; } fn visit_lifetime(&mut self, lt: &'tcx hir::Lifetime) { - run_lints!(self, check_lifetime, late_passes, lt); + run_lints!(self, check_lifetime, lt); hir_visit::walk_lifetime(self, lt); } fn visit_path(&mut self, p: &'tcx hir::Path, id: ast::NodeId) { - run_lints!(self, check_path, late_passes, p, id); + run_lints!(self, check_path, p, id); hir_visit::walk_path(self, p); } fn visit_attribute(&mut self, attr: &'tcx ast::Attribute) { - run_lints!(self, check_attribute, late_passes, attr); + run_lints!(self, check_attribute, attr); } } impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { fn visit_item(&mut self, it: &'a ast::Item) { self.with_lint_attrs(it.id, &it.attrs, |cx| { - run_lints!(cx, check_item, early_passes, it); + run_lints!(cx, check_item, it); ast_visit::walk_item(cx, it); - run_lints!(cx, check_item_post, early_passes, it); + run_lints!(cx, check_item_post, it); }) } fn visit_foreign_item(&mut self, it: &'a ast::ForeignItem) { self.with_lint_attrs(it.id, &it.attrs, |cx| { - run_lints!(cx, check_foreign_item, early_passes, it); + run_lints!(cx, check_foreign_item, it); ast_visit::walk_foreign_item(cx, it); - run_lints!(cx, check_foreign_item_post, early_passes, it); + run_lints!(cx, check_foreign_item_post, it); }) } fn visit_pat(&mut self, p: &'a ast::Pat) { - run_lints!(self, check_pat, early_passes, p); + run_lints!(self, check_pat, p); self.check_id(p.id); ast_visit::walk_pat(self, p); } fn visit_expr(&mut self, e: &'a ast::Expr) { self.with_lint_attrs(e.id, &e.attrs, |cx| { - run_lints!(cx, check_expr, early_passes, e); + run_lints!(cx, check_expr, e); ast_visit::walk_expr(cx, e); }) } fn visit_stmt(&mut self, s: &'a ast::Stmt) { - run_lints!(self, check_stmt, early_passes, s); + run_lints!(self, check_stmt, s); self.check_id(s.id); ast_visit::walk_stmt(self, s); } fn visit_fn(&mut self, fk: ast_visit::FnKind<'a>, decl: &'a ast::FnDecl, span: Span, id: ast::NodeId) { - run_lints!(self, check_fn, early_passes, fk, decl, span, id); + run_lints!(self, check_fn, fk, decl, span, id); self.check_id(id); ast_visit::walk_fn(self, fk, decl, span); - run_lints!(self, check_fn_post, early_passes, fk, decl, span, id); + run_lints!(self, check_fn_post, fk, decl, span, id); } fn visit_variant_data(&mut self, @@ -926,121 +907,126 @@ impl<'a> ast_visit::Visitor<'a> for EarlyContext<'a> { g: &'a ast::Generics, item_id: ast::NodeId, _: Span) { - run_lints!(self, check_struct_def, early_passes, s, ident, g, item_id); + run_lints!(self, check_struct_def, s, ident, g, item_id); self.check_id(s.id()); ast_visit::walk_struct_def(self, s); - run_lints!(self, check_struct_def_post, early_passes, s, ident, g, item_id); + run_lints!(self, check_struct_def_post, s, ident, g, item_id); } fn visit_struct_field(&mut self, s: &'a ast::StructField) { self.with_lint_attrs(s.id, &s.attrs, |cx| { - run_lints!(cx, check_struct_field, early_passes, s); + run_lints!(cx, check_struct_field, s); ast_visit::walk_struct_field(cx, s); }) } fn visit_variant(&mut self, v: &'a ast::Variant, g: &'a ast::Generics, item_id: ast::NodeId) { self.with_lint_attrs(item_id, &v.node.attrs, |cx| { - run_lints!(cx, check_variant, early_passes, v, g); + run_lints!(cx, check_variant, v, g); ast_visit::walk_variant(cx, v, g, item_id); - run_lints!(cx, check_variant_post, early_passes, v, g); + run_lints!(cx, check_variant_post, v, g); }) } fn visit_ty(&mut self, t: &'a ast::Ty) { - run_lints!(self, check_ty, early_passes, t); + run_lints!(self, check_ty, t); self.check_id(t.id); ast_visit::walk_ty(self, t); } fn visit_ident(&mut self, ident: ast::Ident) { - run_lints!(self, check_ident, early_passes, ident); + run_lints!(self, check_ident, ident); } fn visit_mod(&mut self, m: &'a ast::Mod, s: Span, _a: &[ast::Attribute], n: ast::NodeId) { - run_lints!(self, check_mod, early_passes, m, s, n); + run_lints!(self, check_mod, m, s, n); self.check_id(n); ast_visit::walk_mod(self, m); - run_lints!(self, check_mod_post, early_passes, m, s, n); + run_lints!(self, check_mod_post, m, s, n); } fn visit_local(&mut self, l: &'a ast::Local) { self.with_lint_attrs(l.id, &l.attrs, |cx| { - run_lints!(cx, check_local, early_passes, l); + run_lints!(cx, check_local, l); ast_visit::walk_local(cx, l); }) } fn visit_block(&mut self, b: &'a ast::Block) { - run_lints!(self, check_block, early_passes, b); + run_lints!(self, check_block, b); self.check_id(b.id); ast_visit::walk_block(self, b); - run_lints!(self, check_block_post, early_passes, b); + run_lints!(self, check_block_post, b); } fn visit_arm(&mut self, a: &'a ast::Arm) { - run_lints!(self, check_arm, early_passes, a); + run_lints!(self, check_arm, a); ast_visit::walk_arm(self, a); } fn visit_expr_post(&mut self, e: &'a ast::Expr) { - run_lints!(self, check_expr_post, early_passes, e); + run_lints!(self, check_expr_post, e); } fn visit_generic_param(&mut self, param: &'a ast::GenericParam) { - run_lints!(self, check_generic_param, early_passes, param); + run_lints!(self, check_generic_param, param); ast_visit::walk_generic_param(self, param); } fn visit_generics(&mut self, g: &'a ast::Generics) { - run_lints!(self, check_generics, early_passes, g); + run_lints!(self, check_generics, g); ast_visit::walk_generics(self, g); } fn visit_where_predicate(&mut self, p: &'a ast::WherePredicate) { - run_lints!(self, check_where_predicate, early_passes, p); + run_lints!(self, check_where_predicate, p); ast_visit::walk_where_predicate(self, p); } fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) { - run_lints!(self, check_poly_trait_ref, early_passes, t, m); + run_lints!(self, check_poly_trait_ref, t, m); ast_visit::walk_poly_trait_ref(self, t, m); } fn visit_trait_item(&mut self, trait_item: &'a ast::TraitItem) { self.with_lint_attrs(trait_item.id, &trait_item.attrs, |cx| { - run_lints!(cx, check_trait_item, early_passes, trait_item); + run_lints!(cx, check_trait_item, trait_item); ast_visit::walk_trait_item(cx, trait_item); - run_lints!(cx, check_trait_item_post, early_passes, trait_item); + run_lints!(cx, check_trait_item_post, trait_item); }); } fn visit_impl_item(&mut self, impl_item: &'a ast::ImplItem) { self.with_lint_attrs(impl_item.id, &impl_item.attrs, |cx| { - run_lints!(cx, check_impl_item, early_passes, impl_item); + run_lints!(cx, check_impl_item, impl_item); ast_visit::walk_impl_item(cx, impl_item); - run_lints!(cx, check_impl_item_post, early_passes, impl_item); + run_lints!(cx, check_impl_item_post, impl_item); }); } fn visit_lifetime(&mut self, lt: &'a ast::Lifetime) { - run_lints!(self, check_lifetime, early_passes, lt); + run_lints!(self, check_lifetime, lt); self.check_id(lt.id); } fn visit_path(&mut self, p: &'a ast::Path, id: ast::NodeId) { - run_lints!(self, check_path, early_passes, p, id); + run_lints!(self, check_path, p, id); self.check_id(id); ast_visit::walk_path(self, p); } fn visit_attribute(&mut self, attr: &'a ast::Attribute) { - run_lints!(self, check_attribute, early_passes, attr); + run_lints!(self, check_attribute, attr); } - fn visit_mac_def(&mut self, _mac: &'a ast::MacroDef, id: ast::NodeId) { + fn visit_mac_def(&mut self, mac: &'a ast::MacroDef, id: ast::NodeId) { + run_lints!(self, check_mac_def, mac, id); self.check_id(id); } + + fn visit_mac(&mut self, mac: &'ast ast::Mac) { + run_lints!(self, check_mac, mac); + } } @@ -1051,48 +1037,77 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { let access_levels = &tcx.privacy_access_levels(LOCAL_CRATE); let krate = tcx.hir.krate(); + let passes = tcx.sess.lint_store.borrow_mut().late_passes.take(); + + let passes = { + let mut cx = LateContext { + tcx, + tables: &ty::TypeckTables::empty(None), + param_env: ty::ParamEnv::empty(), + access_levels, + lint_sess: LintSession { + passes, + lints: tcx.sess.lint_store.borrow(), + }, + last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID, + generics: None, + }; - let mut cx = LateContext { - tcx, - tables: &ty::TypeckTables::empty(None), - param_env: ty::ParamEnv::empty(), - access_levels, - lint_sess: LintSession::new(&tcx.sess.lint_store), - last_ast_node_with_lint_attrs: ast::CRATE_NODE_ID, - generics: None, - }; - - // Visit the whole crate. - cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { - // since the root module isn't visited as an item (because it isn't an - // item), warn for it here. - run_lints!(cx, check_crate, late_passes, krate); + // Visit the whole crate. + cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { + // since the root module isn't visited as an item (because it isn't an + // item), warn for it here. + run_lints!(cx, check_crate, krate); - hir_visit::walk_crate(cx, krate); + hir_visit::walk_crate(cx, krate); - run_lints!(cx, check_crate_post, late_passes, krate); - }); + run_lints!(cx, check_crate_post, krate); + }); + cx.lint_sess.passes + }; // Put the lint store levels and passes back in the session. - cx.lint_sess.restore(&tcx.sess.lint_store); + tcx.sess.lint_store.borrow_mut().late_passes = passes; } -pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { - let mut cx = EarlyContext::new(sess, krate); +pub fn check_ast_crate( + sess: &Session, + krate: &ast::Crate, + pre_expansion: bool, +) { + let (passes, buffered) = if pre_expansion { + ( + sess.lint_store.borrow_mut().pre_expansion_passes.take(), + LintBuffer::new(), + ) + } else { + ( + sess.lint_store.borrow_mut().early_passes.take(), + sess.buffered_lints.borrow_mut().take().unwrap(), + ) + }; + let (passes, buffered) = { + let mut cx = EarlyContext::new(sess, krate, passes, buffered); - // Visit the whole crate. - cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { - // since the root module isn't visited as an item (because it isn't an - // item), warn for it here. - run_lints!(cx, check_crate, early_passes, krate); + // Visit the whole crate. + cx.with_lint_attrs(ast::CRATE_NODE_ID, &krate.attrs, |cx| { + // since the root module isn't visited as an item (because it isn't an + // item), warn for it here. + run_lints!(cx, check_crate, krate); - ast_visit::walk_crate(cx, krate); + ast_visit::walk_crate(cx, krate); - run_lints!(cx, check_crate_post, early_passes, krate); - }); + run_lints!(cx, check_crate_post, krate); + }); + (cx.lint_sess.passes, cx.buffered) + }; // Put the lint store levels and passes back in the session. - cx.lint_sess.restore(&sess.lint_store); + if pre_expansion { + sess.lint_store.borrow_mut().pre_expansion_passes = passes; + } else { + sess.lint_store.borrow_mut().early_passes = passes; + } // All of the buffered lints should have been emitted at this point. // If not, that means that we somehow buffered a lint for a node id @@ -1104,7 +1119,7 @@ pub fn check_ast_crate(sess: &Session, krate: &ast::Crate) { // unused_macro lint) anymore. So we only run this check // when we're not in rustdoc mode. (see issue #47639) if !sess.opts.actually_rustdoc { - for (_id, lints) in cx.buffered.map { + for (_id, lints) in buffered.map { for early_lint in lints { sess.delay_span_bug(early_lint.span, "failed to process buffered lint here"); } diff --git a/src/librustc/lint/levels.rs b/src/librustc/lint/levels.rs index d158f52c643ce..b7b6aba970bff 100644 --- a/src/librustc/lint/levels.rs +++ b/src/librustc/lint/levels.rs @@ -10,7 +10,7 @@ use std::cmp; -use errors::DiagnosticBuilder; +use errors::{Applicability, DiagnosticBuilder}; use hir::HirId; use ich::StableHashingContext; use lint::builtin; @@ -22,6 +22,7 @@ use session::Session; use syntax::ast; use syntax::attr; use syntax::codemap::MultiSpan; +use syntax::feature_gate; use syntax::symbol::Symbol; use util::nodemap::FxHashMap; @@ -118,6 +119,11 @@ impl LintLevelSets { // Ensure that we never exceed the `--cap-lints` argument. level = cmp::min(level, self.lint_cap); + if let Some(driver_level) = sess.driver_lint_caps.get(&LintId::of(lint)) { + // Ensure that we never exceed driver level. + level = cmp::min(*driver_level, level); + } + return (level, src) } @@ -221,6 +227,28 @@ impl<'a> LintLevelsBuilder<'a> { continue } }; + if let Some(lint_tool) = word.is_scoped() { + if !self.sess.features_untracked().tool_lints { + feature_gate::emit_feature_err(&sess.parse_sess, + "tool_lints", + word.span, + feature_gate::GateIssue::Language, + &format!("scoped lint `{}` is experimental", + word.ident)); + } + + if !attr::is_known_lint_tool(lint_tool) { + span_err!( + sess, + lint_tool.span, + E0710, + "an unknown tool name found in scoped lint: `{}`", + word.ident + ); + } + + continue + } let name = word.name(); match store.check_lint_name(&name.as_str()) { CheckLintNameResult::Ok(ids) => { @@ -232,19 +260,27 @@ impl<'a> LintLevelsBuilder<'a> { _ if !self.warn_about_weird_lints => {} - CheckLintNameResult::Warning(ref msg) => { + CheckLintNameResult::Warning(msg, renamed) => { let lint = builtin::RENAMED_AND_REMOVED_LINTS; let (level, src) = self.sets.get_lint_level(lint, self.cur, Some(&specs), &sess); - lint::struct_lint_level(self.sess, - lint, - level, - src, - Some(li.span.into()), - msg) - .emit(); + let mut err = lint::struct_lint_level(self.sess, + lint, + level, + src, + Some(li.span.into()), + &msg); + if let Some(new_name) = renamed { + err.span_suggestion_with_applicability( + li.span, + "use the new name", + new_name, + Applicability::MachineApplicable + ); + } + err.emit(); } CheckLintNameResult::NoLint => { let lint = builtin::UNKNOWN_LINTS; @@ -265,10 +301,11 @@ impl<'a> LintLevelsBuilder<'a> { store.check_lint_name(&name_lower) { db.emit(); } else { - db.span_suggestion( + db.span_suggestion_with_applicability( li.span, "lowercase the lint name", - name_lower + name_lower, + Applicability::MachineApplicable ).emit(); } } else { diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index d6c6f9dc0f61a..3c1b205620892 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -16,15 +16,15 @@ //! other phases of the compiler, which are generally required to hold in order //! to compile the program at all. //! -//! Most lints can be written as `LintPass` instances. These run just before -//! translation to LLVM bytecode. The `LintPass`es built into rustc are defined +//! Most lints can be written as `LintPass` instances. These run after +//! all other analyses. The `LintPass`es built into rustc are defined //! within `builtin.rs`, which has further comments on how to add such a lint. //! rustc can also load user-defined lint plugins via the plugin mechanism. //! //! Some of rustc's lints are defined elsewhere in the compiler and work by //! calling `add_lint()` on the overall `Session` object. This works when //! it happens before the main lint pass, which emits the lints stored by -//! `add_lint()`. To emit lints after the main lint pass (from trans, for +//! `add_lint()`. To emit lints after the main lint pass (from codegen, for //! example) requires more effort. See `emit_lint` and `GatherNodeLevels` //! in `context.rs`. @@ -35,19 +35,21 @@ use rustc_data_structures::sync::{self, Lrc}; use errors::{DiagnosticBuilder, DiagnosticId}; use hir::def_id::{CrateNum, LOCAL_CRATE}; -use hir::intravisit::{self, FnKind}; +use hir::intravisit; use hir; use lint::builtin::BuiltinLintDiagnostics; +use lint::builtin::parser::QUESTION_MARK_MACRO_SEP; use session::{Session, DiagnosticMessageId}; -use std::hash; +use std::{hash, ptr}; use syntax::ast; -use syntax::codemap::MultiSpan; +use syntax::codemap::{MultiSpan, ExpnFormat}; +use syntax::early_buffered_lints::BufferedEarlyLintId; use syntax::edition::Edition; use syntax::symbol::Symbol; use syntax::visit as ast_visit; use syntax_pos::Span; use ty::TyCtxt; -use ty::maps::Providers; +use ty::query::Providers; use util::nodemap::NodeMap; pub use lint::context::{LateContext, EarlyContext, LintContext, LintStore, @@ -77,43 +79,62 @@ pub struct Lint { /// e.g. "imports that are never used" pub desc: &'static str, - /// Deny lint after this edition - pub edition_deny: Option, + /// Starting at the given edition, default to the given lint level. If this is `None`, then use + /// `default_level`. + pub edition_lint_opts: Option<(Edition, Level)>, + + /// Whether this lint is reported even inside expansions of external macros + pub report_in_external_macro: bool, } impl Lint { + /// Returns the `rust::lint::Lint` for a `syntax::early_buffered_lints::BufferedEarlyLintId`. + pub fn from_parser_lint_id(lint_id: BufferedEarlyLintId) -> &'static Self { + match lint_id { + BufferedEarlyLintId::QuestionMarkMacroSep => QUESTION_MARK_MACRO_SEP, + } + } + /// Get the lint's name, with ASCII letters converted to lowercase. pub fn name_lower(&self) -> String { self.name.to_ascii_lowercase() } pub fn default_level(&self, session: &Session) -> Level { - if let Some(edition_deny) = self.edition_deny { - if session.edition() >= edition_deny { - return Level::Deny - } - } - self.default_level + self.edition_lint_opts + .filter(|(e, _)| *e <= session.edition()) + .map(|(_, l)| l) + .unwrap_or(self.default_level) } } /// Declare a static item of type `&'static Lint`. #[macro_export] macro_rules! declare_lint { - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, $edition: expr) => ( + ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( + declare_lint!{$vis $NAME, $Level, $desc, false} + ); + ($vis: vis $NAME: ident, $Level: ident, $desc: expr, report_in_external_macro: $rep: expr) => ( + declare_lint!{$vis $NAME, $Level, $desc, $rep} + ); + ($vis: vis $NAME: ident, $Level: ident, $desc: expr, $external: expr) => ( $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, desc: $desc, - edition_deny: Some($edition) + edition_lint_opts: None, + report_in_external_macro: $external, }; ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( + ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + $lint_edition: expr => $edition_level: ident + ) => ( $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, desc: $desc, - edition_deny: None, + edition_lint_opts: Some(($lint_edition, $crate::lint::Level::$edition_level)), + report_in_external_macro: false, }; ); } @@ -121,14 +142,13 @@ macro_rules! declare_lint { /// Declare a static `LintArray` and return it as an expression. #[macro_export] macro_rules! lint_array { - ($( $lint:expr ),*,) => { lint_array!( $( $lint ),* ) }; + ($( $lint:expr ),* ,) => { lint_array!( $($lint),* ) }; ($( $lint:expr ),*) => {{ - static ARRAY: LintArray = &[ $( &$lint ),* ]; - ARRAY + vec![$($lint),*] }} } -pub type LintArray = &'static [&'static &'static Lint]; +pub type LintArray = Vec<&'static Lint>; pub trait LintPass { /// Get descriptions of the lints this `LintPass` object can emit. @@ -140,6 +160,80 @@ pub trait LintPass { fn get_lints(&self) -> LintArray; } +#[macro_export] +macro_rules! late_lint_methods { + ($macro:path, $args:tt, [$hir:tt]) => ( + $macro!($args, [$hir], [ + fn check_body(a: &$hir hir::Body); + fn check_body_post(a: &$hir hir::Body); + fn check_name(a: Span, b: ast::Name); + fn check_crate(a: &$hir hir::Crate); + fn check_crate_post(a: &$hir hir::Crate); + fn check_mod(a: &$hir hir::Mod, b: Span, c: ast::NodeId); + fn check_mod_post(a: &$hir hir::Mod, b: Span, c: ast::NodeId); + fn check_foreign_item(a: &$hir hir::ForeignItem); + fn check_foreign_item_post(a: &$hir hir::ForeignItem); + fn check_item(a: &$hir hir::Item); + fn check_item_post(a: &$hir hir::Item); + fn check_local(a: &$hir hir::Local); + fn check_block(a: &$hir hir::Block); + fn check_block_post(a: &$hir hir::Block); + fn check_stmt(a: &$hir hir::Stmt); + fn check_arm(a: &$hir hir::Arm); + fn check_pat(a: &$hir hir::Pat); + fn check_decl(a: &$hir hir::Decl); + fn check_expr(a: &$hir hir::Expr); + fn check_expr_post(a: &$hir hir::Expr); + fn check_ty(a: &$hir hir::Ty); + fn check_generic_param(a: &$hir hir::GenericParam); + fn check_generics(a: &$hir hir::Generics); + fn check_where_predicate(a: &$hir hir::WherePredicate); + fn check_poly_trait_ref(a: &$hir hir::PolyTraitRef, b: hir::TraitBoundModifier); + fn check_fn( + a: hir::intravisit::FnKind<$hir>, + b: &$hir hir::FnDecl, + c: &$hir hir::Body, + d: Span, + e: ast::NodeId); + fn check_fn_post( + a: hir::intravisit::FnKind<$hir>, + b: &$hir hir::FnDecl, + c: &$hir hir::Body, + d: Span, + e: ast::NodeId + ); + fn check_trait_item(a: &$hir hir::TraitItem); + fn check_trait_item_post(a: &$hir hir::TraitItem); + fn check_impl_item(a: &$hir hir::ImplItem); + fn check_impl_item_post(a: &$hir hir::ImplItem); + fn check_struct_def( + a: &$hir hir::VariantData, + b: ast::Name, + c: &$hir hir::Generics, + d: ast::NodeId + ); + fn check_struct_def_post( + a: &$hir hir::VariantData, + b: ast::Name, + c: &$hir hir::Generics, + d: ast::NodeId + ); + fn check_struct_field(a: &$hir hir::StructField); + fn check_variant(a: &$hir hir::Variant, b: &$hir hir::Generics); + fn check_variant_post(a: &$hir hir::Variant, b: &$hir hir::Generics); + fn check_lifetime(a: &$hir hir::Lifetime); + fn check_path(a: &$hir hir::Path, b: ast::NodeId); + fn check_attribute(a: &$hir ast::Attribute); + + /// Called when entering a syntax node that can have lint attributes such + /// as `#[allow(...)]`. Called with *all* the attributes of that node. + fn enter_lint_attrs(a: &$hir [ast::Attribute]); + + /// Counterpart to `enter_lint_attrs`. + fn exit_lint_attrs(a: &$hir [ast::Attribute]); + ]); + ) +} /// Trait for types providing lint checks. /// @@ -149,90 +243,67 @@ pub trait LintPass { // // FIXME: eliminate the duplication with `Visitor`. But this also // contains a few lint-specific methods with no equivalent in `Visitor`. -pub trait LateLintPass<'a, 'tcx>: LintPass { - fn check_body(&mut self, _: &LateContext, _: &'tcx hir::Body) { } - fn check_body_post(&mut self, _: &LateContext, _: &'tcx hir::Body) { } - fn check_name(&mut self, _: &LateContext, _: Span, _: ast::Name) { } - fn check_crate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } - fn check_crate_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Crate) { } - fn check_mod(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Mod, - _: Span, - _: ast::NodeId) { } - fn check_mod_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Mod, - _: Span, - _: ast::NodeId) { } - fn check_foreign_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ForeignItem) { } - fn check_foreign_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ForeignItem) { } - fn check_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Item) { } - fn check_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Item) { } - fn check_local(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Local) { } - fn check_block(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Block) { } - fn check_block_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Block) { } - fn check_stmt(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Stmt) { } - fn check_arm(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Arm) { } - fn check_pat(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Pat) { } - fn check_decl(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Decl) { } - fn check_expr(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } - fn check_expr_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Expr) { } - fn check_ty(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Ty) { } - fn check_generic_param(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::GenericParam) { } - fn check_generics(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Generics) { } - fn check_where_predicate(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::WherePredicate) { } - fn check_poly_trait_ref(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::PolyTraitRef, - _: hir::TraitBoundModifier) { } - fn check_fn(&mut self, - _: &LateContext<'a, 'tcx>, - _: FnKind<'tcx>, - _: &'tcx hir::FnDecl, - _: &'tcx hir::Body, - _: Span, - _: ast::NodeId) { } - fn check_fn_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: FnKind<'tcx>, - _: &'tcx hir::FnDecl, - _: &'tcx hir::Body, - _: Span, - _: ast::NodeId) { } - fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { } - fn check_trait_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { } - fn check_impl_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ImplItem) { } - fn check_impl_item_post(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::ImplItem) { } - fn check_struct_def(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::VariantData, - _: ast::Name, - _: &'tcx hir::Generics, - _: ast::NodeId) { } - fn check_struct_def_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::VariantData, - _: ast::Name, - _: &'tcx hir::Generics, - _: ast::NodeId) { } - fn check_struct_field(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::StructField) { } - fn check_variant(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Variant, - _: &'tcx hir::Generics) { } - fn check_variant_post(&mut self, - _: &LateContext<'a, 'tcx>, - _: &'tcx hir::Variant, - _: &'tcx hir::Generics) { } - fn check_lifetime(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Lifetime) { } - fn check_path(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::Path, _: ast::NodeId) { } - fn check_attribute(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx ast::Attribute) { } - /// Called when entering a syntax node that can have lint attributes such - /// as `#[allow(...)]`. Called with *all* the attributes of that node. - fn enter_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { } +macro_rules! expand_lint_pass_methods { + ($context:ty, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(#[inline(always)] fn $name(&mut self, $context, $(_: $arg),*) {})* + ) +} - /// Counterpart to `enter_lint_attrs`. - fn exit_lint_attrs(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx [ast::Attribute]) { } +macro_rules! declare_late_lint_pass { + ([], [$hir:tt], [$($methods:tt)*]) => ( + pub trait LateLintPass<'a, $hir>: LintPass { + expand_lint_pass_methods!(&LateContext<'a, $hir>, [$($methods)*]); + } + ) +} + +late_lint_methods!(declare_late_lint_pass, [], ['tcx]); + +#[macro_export] +macro_rules! expand_combined_late_lint_pass_method { + ([$($passes:ident),*], $self: ident, $name: ident, $params:tt) => ({ + $($self.$passes.$name $params;)* + }) +} + +#[macro_export] +macro_rules! expand_combined_late_lint_pass_methods { + ($passes:tt, [$($(#[$attr:meta])* fn $name:ident($($param:ident: $arg:ty),*);)*]) => ( + $(fn $name(&mut self, context: &LateContext<'a, 'tcx>, $($param: $arg),*) { + expand_combined_late_lint_pass_method!($passes, self, $name, (context, $($param),*)); + })* + ) +} + +#[macro_export] +macro_rules! declare_combined_late_lint_pass { + ([$name:ident, [$($passes:ident: $constructor:expr,)*]], [$hir:tt], $methods:tt) => ( + #[allow(non_snake_case)] + struct $name { + $($passes: $passes,)* + } + + impl $name { + fn new() -> Self { + Self { + $($passes: $constructor,)* + } + } + } + + impl<'a, 'tcx> LateLintPass<'a, 'tcx> for $name { + expand_combined_late_lint_pass_methods!([$($passes),*], $methods); + } + + impl LintPass for $name { + fn get_lints(&self) -> LintArray { + let mut lints = Vec::new(); + $(lints.extend_from_slice(&self.$passes.get_lints());)* + lints + } + } + ) } pub trait EarlyLintPass: LintPass { @@ -277,6 +348,8 @@ pub trait EarlyLintPass: LintPass { fn check_lifetime(&mut self, _: &EarlyContext, _: &ast::Lifetime) { } fn check_path(&mut self, _: &EarlyContext, _: &ast::Path, _: ast::NodeId) { } fn check_attribute(&mut self, _: &EarlyContext, _: &ast::Attribute) { } + fn check_mac_def(&mut self, _: &EarlyContext, _: &ast::MacroDef, _id: ast::NodeId) { } + fn check_mac(&mut self, _: &EarlyContext, _: &ast::Mac) { } /// Called when entering a syntax node that can have lint attributes such /// as `#[allow(...)]`. Called with *all* the attributes of that node. @@ -291,6 +364,8 @@ pub type EarlyLintPassObject = Box LateLintPass<'a, 'tcx> + sync::Send + sync::Sync + 'static>; + + /// Identifies a lint known to the compiler. #[derive(Clone, Copy, Debug)] pub struct LintId { @@ -300,7 +375,7 @@ pub struct LintId { impl PartialEq for LintId { fn eq(&self, other: &LintId) -> bool { - (self.lint as *const Lint) == (other.lint as *const Lint) + ptr::eq(self.lint, other.lint) } } @@ -505,7 +580,7 @@ pub fn struct_lint_level<'a>(sess: &'a Session, "this was previously accepted by the compiler but is being phased out; \ it will become a hard error"; - let explanation = if lint_id == LintId::of(::lint::builtin::UNSTABLE_NAME_COLLISION) { + let explanation = if lint_id == LintId::of(::lint::builtin::UNSTABLE_NAME_COLLISIONS) { "once this method is added to the standard library, \ the ambiguity may cause an error or change in behavior!" .to_owned() @@ -518,6 +593,21 @@ pub fn struct_lint_level<'a>(sess: &'a Session, future_incompatible.reference); err.warn(&explanation); err.note(&citation); + + // If this lint is *not* a future incompatibility warning then we want to be + // sure to not be too noisy in some situations. If this code originates in a + // foreign macro, aka something that this crate did not itself author, then + // it's likely that there's nothing this crate can do about it. We probably + // want to skip the lint entirely. + // + // For some lints though (like unreachable code) there's clear actionable + // items to take care of (delete the macro invocation). As a result we have + // a few lints we whitelist here for allowing a lint even though it's in a + // foreign macro invocation. + } else if !lint.report_in_external_macro { + if err.span.primary_spans().iter().any(|s| in_external_macro(sess, *s)) { + err.cancel(); + } } return err @@ -619,3 +709,32 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'a, 'tcx> { pub fn provide(providers: &mut Providers) { providers.lint_levels = lint_levels; } + +/// Returns whether `span` originates in a foreign crate's external macro. +/// +/// This is used to test whether a lint should be entirely aborted above. +pub fn in_external_macro(sess: &Session, span: Span) -> bool { + let info = match span.ctxt().outer().expn_info() { + Some(info) => info, + // no ExpnInfo means this span doesn't come from a macro + None => return false, + }; + + match info.format { + ExpnFormat::MacroAttribute(..) => return true, // definitely a plugin + ExpnFormat::CompilerDesugaring(_) => return true, // well, it's "external" + ExpnFormat::MacroBang(..) => {} // check below + } + + let def_site = match info.def_site { + Some(span) => span, + // no span for the def_site means it's an external macro + None => return true, + }; + + match sess.codemap().span_to_snippet(def_site) { + Ok(code) => !code.starts_with("macro_rules"), + // no snippet = external macro or compiler-builtin expansion + Err(_) => true, + } +} diff --git a/src/librustc/macros.rs b/src/librustc/macros.rs index 7dc84b9ca2956..0bf1f4decc430 100644 --- a/src/librustc/macros.rs +++ b/src/librustc/macros.rs @@ -64,15 +64,16 @@ macro_rules! span_bug { #[macro_export] macro_rules! __impl_stable_hash_field { - (DECL IGNORED) => (_); - (DECL $name:ident) => (ref $name); - (USE IGNORED $ctx:expr, $hasher:expr) => ({}); - (USE $name:ident, $ctx:expr, $hasher:expr) => ($name.hash_stable($ctx, $hasher)); + ($field:ident, $ctx:expr, $hasher:expr) => ($field.hash_stable($ctx, $hasher)); + ($field:ident, $ctx:expr, $hasher:expr, _) => ({ let _ = $field; }); + ($field:ident, $ctx:expr, $hasher:expr, $delegate:expr) => ($delegate.hash_stable($ctx, $hasher)); } #[macro_export] macro_rules! impl_stable_hash_for { - (enum $enum_name:path { $( $variant:ident $( ( $($arg:ident),* ) )* ),* $(,)* }) => { + // FIXME(mark-i-m): Some of these should be `?` rather than `*`. See the git blame and change + // them back when `?` is supported again. + (enum $enum_name:path { $( $variant:ident $( ( $($field:ident $(-> $delegate:tt)*),* ) )* ),* $(,)* }) => { impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $enum_name { #[inline] fn hash_stable(&self, @@ -83,15 +84,16 @@ macro_rules! impl_stable_hash_for { match *self { $( - $variant $( ( $( __impl_stable_hash_field!(DECL $arg) ),* ) )* => { - $($( __impl_stable_hash_field!(USE $arg, __ctx, __hasher) );*)* + $variant $( ( $(ref $field),* ) )* => { + $($( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );*)* } )* } } } }; - (struct $struct_name:path { $($field:ident),* }) => { + // FIXME(mark-i-m): same here. + (struct $struct_name:path { $($field:ident $(-> $delegate:tt)*),* $(,)* }) => { impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name { #[inline] fn hash_stable(&self, @@ -101,11 +103,12 @@ macro_rules! impl_stable_hash_for { $(ref $field),* } = *self; - $( $field.hash_stable(__ctx, __hasher));* + $( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );* } } }; - (tuple_struct $struct_name:path { $($field:ident),* }) => { + // FIXME(mark-i-m): same here. + (tuple_struct $struct_name:path { $($field:ident $(-> $delegate:tt)*),* $(,)* }) => { impl<'a, 'tcx> ::rustc_data_structures::stable_hasher::HashStable<$crate::ich::StableHashingContext<'a>> for $struct_name { #[inline] fn hash_stable(&self, @@ -115,7 +118,7 @@ macro_rules! impl_stable_hash_for { $(ref $field),* ) = *self; - $( $field.hash_stable(__ctx, __hasher));* + $( __impl_stable_hash_field!($field, __ctx, __hasher $(, $delegate)*) );* } } }; @@ -250,10 +253,7 @@ macro_rules! BraceStructLiftImpl { macro_rules! EnumLiftImpl { (impl<$($p:tt),*> Lift<$tcx:tt> for $s:path { type Lifted = $lifted:ty; - $( - ($variant:path) ( $( $variant_arg:ident),* ) - ),* - $(,)* + $($variants:tt)* } $(where $($wc:tt)*)*) => { impl<$($p),*> $crate::ty::Lift<$tcx> for $s $(where $($wc)*)* @@ -261,14 +261,44 @@ macro_rules! EnumLiftImpl { type Lifted = $lifted; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<$lifted> { - match self { - $($variant ( $($variant_arg),* ) => { - Some($variant ( $(tcx.lift($variant_arg)?),* )) - })* - } + EnumLiftImpl!(@Variants(self, tcx) input($($variants)*) output()) } } }; + + (@Variants($this:expr, $tcx:expr) input() output($($output:tt)*)) => { + match $this { + $($output)* + } + }; + + (@Variants($this:expr, $tcx:expr) + input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*) + output( $($output:tt)*) ) => { + EnumLiftImpl!( + @Variants($this, $tcx) + input($($input)*) + output( + $variant ( $($variant_arg),* ) => { + Some($variant ( $($tcx.lift($variant_arg)?),* )) + } + $($output)* + ) + ) + }; + + (@Variants($this:expr, $tcx:expr) + input( ($variant:path), $($input:tt)*) + output( $($output:tt)*) ) => { + EnumLiftImpl!( + @Variants($this, $tcx) + input($($input)*) + output( + $variant => { Some($variant) } + $($output)* + ) + ) + }; } #[macro_export] diff --git a/src/librustc/middle/borrowck.rs b/src/librustc/middle/borrowck.rs index 6f5791ed5d71b..c8d513a59f00d 100644 --- a/src/librustc/middle/borrowck.rs +++ b/src/librustc/middle/borrowck.rs @@ -15,9 +15,15 @@ use util::nodemap::FxHashSet; use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; +#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] +pub enum SignalledError { SawSomeError, NoErrorsSeen } + +impl_stable_hash_for!(enum self::SignalledError { SawSomeError, NoErrorsSeen }); + #[derive(Debug, RustcEncodable, RustcDecodable)] pub struct BorrowCheckResult { pub used_mut_nodes: FxHashSet, + pub signalled_any_error: SignalledError, } impl<'a> HashStable> for BorrowCheckResult { @@ -26,7 +32,9 @@ impl<'a> HashStable> for BorrowCheckResult { hasher: &mut StableHasher) { let BorrowCheckResult { ref used_mut_nodes, + ref signalled_any_error, } = *self; used_mut_nodes.hash_stable(hcx, hasher); + signalled_any_error.hash_stable(hcx, hasher); } } diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs deleted file mode 100644 index 0ecab50dda229..0000000000000 --- a/src/librustc/middle/const_val.rs +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2012-2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use hir::def_id::DefId; -use ty::{self, TyCtxt, layout}; -use ty::subst::Substs; -use mir::interpret::{Value, PrimVal}; -use errors::DiagnosticBuilder; - -use graphviz::IntoCow; -use syntax_pos::Span; - -use std::borrow::Cow; -use rustc_data_structures::sync::Lrc; - -pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>; - -#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] -pub enum ConstVal<'tcx> { - Unevaluated(DefId, &'tcx Substs<'tcx>), - Value(Value), -} - -impl<'tcx> ConstVal<'tcx> { - pub fn to_raw_bits(&self) -> Option { - match *self { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => { - Some(b) - }, - _ => None, - } - } - pub fn unwrap_u64(&self) -> u64 { - match self.to_raw_bits() { - Some(val) => { - assert_eq!(val as u64 as u128, val); - val as u64 - }, - None => bug!("expected constant u64, got {:#?}", self), - } - } -} - -#[derive(Clone, Debug)] -pub struct ConstEvalErr<'tcx> { - pub span: Span, - pub kind: Lrc>, -} - -#[derive(Clone, Debug)] -pub enum ErrKind<'tcx> { - - NonConstPath, - UnimplementedConstVal(&'static str), - IndexOutOfBounds { len: u64, index: u64 }, - - LayoutError(layout::LayoutError<'tcx>), - - TypeckError, - CheckMatchError, - Miri(::mir::interpret::EvalError<'tcx>, Vec), -} - -#[derive(Clone, Debug)] -pub struct FrameInfo { - pub span: Span, - pub location: String, -} - -#[derive(Clone, Debug)] -pub enum ConstEvalErrDescription<'a, 'tcx: 'a> { - Simple(Cow<'a, str>), - Backtrace(&'a ::mir::interpret::EvalError<'tcx>, &'a [FrameInfo]), -} - -impl<'a, 'tcx> ConstEvalErrDescription<'a, 'tcx> { - /// Return a one-line description of the error, for lints and such - pub fn into_oneline(self) -> Cow<'a, str> { - match self { - ConstEvalErrDescription::Simple(simple) => simple, - ConstEvalErrDescription::Backtrace(miri, _) => format!("{}", miri).into_cow(), - } - } -} - -impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { - pub fn description(&'a self) -> ConstEvalErrDescription<'a, 'tcx> { - use self::ErrKind::*; - use self::ConstEvalErrDescription::*; - - macro_rules! simple { - ($msg:expr) => ({ Simple($msg.into_cow()) }); - ($fmt:expr, $($arg:tt)+) => ({ - Simple(format!($fmt, $($arg)+).into_cow()) - }) - } - - match *self.kind { - NonConstPath => simple!("non-constant path in constant expression"), - UnimplementedConstVal(what) => - simple!("unimplemented constant expression: {}", what), - IndexOutOfBounds { len, index } => { - simple!("index out of bounds: the len is {} but the index is {}", - len, index) - } - - LayoutError(ref err) => Simple(err.to_string().into_cow()), - - TypeckError => simple!("type-checking failed"), - CheckMatchError => simple!("match-checking failed"), - Miri(ref err, ref trace) => Backtrace(err, trace), - } - } - - pub fn struct_error(&self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - primary_span: Span, - primary_kind: &str) - -> DiagnosticBuilder<'gcx> - { - let mut diag = struct_error(tcx, self.span, "constant evaluation error"); - self.note(tcx, primary_span, primary_kind, &mut diag); - diag - } - - pub fn note(&self, - _tcx: TyCtxt<'a, 'gcx, 'tcx>, - primary_span: Span, - primary_kind: &str, - diag: &mut DiagnosticBuilder) - { - match self.description() { - ConstEvalErrDescription::Simple(message) => { - diag.span_label(self.span, message); - } - ConstEvalErrDescription::Backtrace(miri, frames) => { - diag.span_label(self.span, format!("{}", miri)); - for frame in frames { - diag.span_label(frame.span, format!("inside call to `{}`", frame.location)); - } - } - } - - if !primary_span.contains(self.span) { - diag.span_note(primary_span, - &format!("for {} here", primary_kind)); - } - } - - pub fn report(&self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - primary_span: Span, - primary_kind: &str) - { - match *self.kind { - ErrKind::TypeckError | ErrKind::CheckMatchError => return, - ErrKind::Miri(ref miri, _) => { - match miri.kind { - ::mir::interpret::EvalErrorKind::TypeckError | - ::mir::interpret::EvalErrorKind::Layout(_) => return, - _ => {}, - } - } - _ => {} - } - self.struct_error(tcx, primary_span, primary_kind).emit(); - } -} - -pub fn struct_error<'a, 'gcx, 'tcx>( - tcx: TyCtxt<'a, 'gcx, 'tcx>, - span: Span, - msg: &str, -) -> DiagnosticBuilder<'gcx> { - struct_span_err!(tcx.sess, span, E0080, "{}", msg) -} diff --git a/src/librustc/middle/cstore.rs b/src/librustc/middle/cstore.rs index 4400ebc294fd8..54169acac46ac 100644 --- a/src/librustc/middle/cstore.rs +++ b/src/librustc/middle/cstore.rs @@ -34,11 +34,12 @@ use session::search_paths::PathKind; use std::any::Any; use std::path::{Path, PathBuf}; use syntax::ast; +use syntax::edition::Edition; use syntax::ext::base::SyntaxExtension; use syntax::symbol::Symbol; use syntax_pos::Span; use rustc_target::spec::Target; -use rustc_data_structures::sync::{MetadataRef, Lrc}; +use rustc_data_structures::sync::{self, MetadataRef, Lrc}; pub use self::NativeLibraryKind::*; @@ -124,12 +125,13 @@ pub enum NativeLibraryKind { NativeUnknown, } -#[derive(Clone, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, RustcEncodable, RustcDecodable)] pub struct NativeLibrary { pub kind: NativeLibraryKind, - pub name: Symbol, + pub name: Option, pub cfg: Option, pub foreign_module: Option, + pub wasm_import_module: Option, } #[derive(Clone, Hash, RustcEncodable, RustcDecodable)] @@ -235,6 +237,7 @@ pub trait CrateStore { fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol; fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator; fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh; + fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition; fn struct_field_names_untracked(&self, def: DefId) -> Vec; fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec; fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro; @@ -255,6 +258,8 @@ pub trait CrateStore { fn metadata_encoding_version(&self) -> &[u8]; } +pub type CrateStoreDyn = dyn CrateStore + sync::Sync; + // FIXME: find a better place for this? pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { let mut err_count = 0; @@ -307,6 +312,7 @@ impl CrateStore for DummyCrateStore { bug!("crate_disambiguator") } fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") } + fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition { bug!("crate_edition_untracked") } // resolve fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") } diff --git a/src/librustc/middle/dataflow.rs b/src/librustc/middle/dataflow.rs index 5c86554f90790..b949fd02126ba 100644 --- a/src/librustc/middle/dataflow.rs +++ b/src/librustc/middle/dataflow.rs @@ -22,7 +22,7 @@ use std::mem; use std::usize; use syntax::print::pprust::PrintState; -use rustc_data_structures::graph::OUTGOING; +use rustc_data_structures::graph::implementation::OUTGOING; use util::nodemap::FxHashMap; use hir; diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 9ec3d2e2460e9..e4fc1b09fcebc 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -96,7 +96,11 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { } fn lookup_and_handle_method(&mut self, id: hir::HirId) { - self.check_def_id(self.tables.type_dependent_defs()[id].def_id()); + if let Some(def) = self.tables.type_dependent_defs().get(id) { + self.check_def_id(def.def_id()); + } else { + bug!("no type-dependent def for method"); + } } fn handle_field_access(&mut self, lhs: &hir::Expr, node_id: ast::NodeId) { @@ -149,21 +153,21 @@ impl<'a, 'tcx> MarkSymbolVisitor<'a, 'tcx> { match *node { hir_map::NodeItem(item) => { match item.node { - hir::ItemStruct(..) | hir::ItemUnion(..) => { + hir::ItemKind::Struct(..) | hir::ItemKind::Union(..) => { let def_id = self.tcx.hir.local_def_id(item.id); let def = self.tcx.adt_def(def_id); self.repr_has_repr_c = def.repr.c(); intravisit::walk_item(self, &item); } - hir::ItemEnum(..) => { - self.inherited_pub_visibility = item.vis == hir::Public; + hir::ItemKind::Enum(..) => { + self.inherited_pub_visibility = item.vis.node.is_pub(); intravisit::walk_item(self, &item); } - hir::ItemFn(..) - | hir::ItemTy(..) - | hir::ItemStatic(..) - | hir::ItemConst(..) => { + hir::ItemKind::Fn(..) + | hir::ItemKind::Ty(..) + | hir::ItemKind::Static(..) + | hir::ItemKind::Const(..) => { intravisit::walk_item(self, &item); } _ => () @@ -212,7 +216,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { let has_repr_c = self.repr_has_repr_c; let inherited_pub_visibility = self.inherited_pub_visibility; let live_fields = def.fields().iter().filter(|f| { - has_repr_c || inherited_pub_visibility || f.vis == hir::Public + has_repr_c || inherited_pub_visibility || f.vis.node.is_pub() }); self.live_symbols.extend(live_fields.map(|f| f.id)); @@ -221,17 +225,17 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkSymbolVisitor<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { match expr.node { - hir::ExprPath(ref qpath @ hir::QPath::TypeRelative(..)) => { + hir::ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(..)) => { let def = self.tables.qpath_def(qpath, expr.hir_id); self.handle_definition(def); } - hir::ExprMethodCall(..) => { + hir::ExprKind::MethodCall(..) => { self.lookup_and_handle_method(expr.hir_id); } - hir::ExprField(ref lhs, ..) => { + hir::ExprKind::Field(ref lhs, ..) => { self.handle_field_access(&lhs, expr.id); } - hir::ExprStruct(_, ref fields, _) => { + hir::ExprKind::Struct(_, ref fields, _) => { if let ty::TypeVariants::TyAdt(ref adt, _) = self.tables.expr_ty(expr).sty { self.mark_as_used_if_union(adt, fields); } @@ -288,6 +292,16 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt, return true; } + // (To be) stable attribute for #[lang = "panic_impl"] + if attr::contains_name(attrs, "panic_implementation") { + return true; + } + + // (To be) stable attribute for #[lang = "oom"] + if attr::contains_name(attrs, "alloc_error_handler") { + return true; + } + // #[used] also keeps the item alive forcefully, // e.g. for placing it in a specific section. if attr::contains_name(attrs, "used") { @@ -299,11 +313,6 @@ fn has_allow_dead_code_or_lang_attr(tcx: TyCtxt, return true; } - // These constants are special for wasm - if attr::contains_name(attrs, "wasm_custom_section") { - return true; - } - tcx.lint_level_at_node(lint::builtin::DEAD_CODE, id).0 == lint::Allow } @@ -335,11 +344,11 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { self.worklist.push(item.id); } match item.node { - hir::ItemEnum(ref enum_def, _) if allow_dead_code => { + hir::ItemKind::Enum(ref enum_def, _) if allow_dead_code => { self.worklist.extend(enum_def.variants.iter() .map(|variant| variant.node.data.id())); } - hir::ItemTrait(.., ref trait_item_refs) => { + hir::ItemKind::Trait(.., ref trait_item_refs) => { for trait_item_ref in trait_item_refs { let trait_item = self.krate.trait_item(trait_item_ref.id); match trait_item.node { @@ -355,7 +364,7 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } } - hir::ItemImpl(.., ref opt_trait, _, ref impl_item_refs) => { + hir::ItemKind::Impl(.., ref opt_trait, _, ref impl_item_refs) => { for impl_item_ref in impl_item_refs { let impl_item = self.krate.impl_item(impl_item_ref.id); if opt_trait.is_some() || @@ -382,16 +391,12 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { fn create_and_seed_worklist<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, access_levels: &privacy::AccessLevels, krate: &hir::Crate) - -> Vec { - let mut worklist = Vec::new(); - for (id, _) in &access_levels.map { - worklist.push(*id); - } - - // Seed entry point - if let Some((id, _, _)) = *tcx.sess.entry_fn.borrow() { - worklist.push(id); - } + -> Vec +{ + let worklist = access_levels.map.iter().map(|(&id, _)| id).chain( + // Seed entry point + tcx.sess.entry_fn.borrow().map(|(id, _, _)| id) + ).collect::>(); // Seed implemented trait items let mut life_seeder = LifeSeeder { @@ -425,7 +430,7 @@ fn find_live<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn get_struct_ctor_id(item: &hir::Item) -> Option { match item.node { - hir::ItemStruct(ref struct_def, _) if !struct_def.is_struct() => { + hir::ItemKind::Struct(ref struct_def, _) if !struct_def.is_struct() => { Some(struct_def.id()) } _ => None @@ -440,13 +445,13 @@ struct DeadVisitor<'a, 'tcx: 'a> { impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { fn should_warn_about_item(&mut self, item: &hir::Item) -> bool { let should_warn = match item.node { - hir::ItemStatic(..) - | hir::ItemConst(..) - | hir::ItemFn(..) - | hir::ItemTy(..) - | hir::ItemEnum(..) - | hir::ItemStruct(..) - | hir::ItemUnion(..) => true, + hir::ItemKind::Static(..) + | hir::ItemKind::Const(..) + | hir::ItemKind::Fn(..) + | hir::ItemKind::Ty(..) + | hir::ItemKind::Enum(..) + | hir::ItemKind::Struct(..) + | hir::ItemKind::Union(..) => true, _ => false }; let ctor_id = get_struct_ctor_id(item); @@ -455,17 +460,13 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { fn should_warn_about_field(&mut self, field: &hir::StructField) -> bool { let field_type = self.tcx.type_of(self.tcx.hir.local_def_id(field.id)); - let is_marker_field = match field_type.ty_to_def_id() { - Some(def_id) => self.tcx.lang_items().items().iter().any(|item| *item == Some(def_id)), - _ => false - }; !field.is_positional() && !self.symbol_is_live(field.id, None) - && !is_marker_field + && !field_type.is_phantom_data() && !has_allow_dead_code_or_lang_attr(self.tcx, field.id, &field.attrs) } - fn should_warn_about_variant(&mut self, variant: &hir::Variant_) -> bool { + fn should_warn_about_variant(&mut self, variant: &hir::VariantKind) -> bool { !self.symbol_is_live(variant.data.id(), None) && !has_allow_dead_code_or_lang_attr(self.tcx, variant.data.id(), @@ -482,7 +483,7 @@ impl<'a, 'tcx> DeadVisitor<'a, 'tcx> { // `None` otherwise. // If the item is a struct_ctor, then either its `id` or // `ctor_id` (unwrapped) is in the live_symbols set. More specifically, - // DefMap maps the ExprPath of a struct_ctor to the node referred by + // DefMap maps the ExprKind::Path of a struct_ctor to the node referred by // `ctor_id`. On the other hand, in a statement like // `type = ;` where refers to a struct_ctor, // DefMap maps to `id` instead. @@ -544,13 +545,13 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { // For items that have a definition with a signature followed by a // block, point only at the signature. let span = match item.node { - hir::ItemFn(..) | - hir::ItemMod(..) | - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemUnion(..) | - hir::ItemTrait(..) | - hir::ItemImpl(..) => self.tcx.sess.codemap().def_span(item.span), + hir::ItemKind::Fn(..) | + hir::ItemKind::Mod(..) | + hir::ItemKind::Enum(..) | + hir::ItemKind::Struct(..) | + hir::ItemKind::Union(..) | + hir::ItemKind::Trait(..) | + hir::ItemKind::Impl(..) => self.tcx.sess.codemap().def_span(item.span), _ => item.span, }; self.warn_dead_code( @@ -588,7 +589,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { fn visit_struct_field(&mut self, field: &'tcx hir::StructField) { if self.should_warn_about_field(&field) { - self.warn_dead_code(field.id, field.span, field.name, "field", "used"); + self.warn_dead_code(field.id, field.span, field.ident.name, "field", "used"); } intravisit::walk_struct_field(self, field); } @@ -599,7 +600,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { if !self.symbol_is_live(impl_item.id, None) { self.warn_dead_code(impl_item.id, impl_item.span, - impl_item.name, + impl_item.ident.name, "associated const", "used"); } @@ -608,10 +609,11 @@ impl<'a, 'tcx> Visitor<'tcx> for DeadVisitor<'a, 'tcx> { hir::ImplItemKind::Method(_, body_id) => { if !self.symbol_is_live(impl_item.id, None) { let span = self.tcx.sess.codemap().def_span(impl_item.span); - self.warn_dead_code(impl_item.id, span, impl_item.name, "method", "used"); + self.warn_dead_code(impl_item.id, span, impl_item.ident.name, "method", "used"); } self.visit_nested_body(body_id) } + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(..) => {} } } diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 4996a6acff85c..4c99b46ddff6e 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -109,7 +109,7 @@ fn calculate_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let sess = &tcx.sess; - if !sess.opts.output_types.should_trans() { + if !sess.opts.output_types.should_codegen() { return Vec::new(); } diff --git a/src/librustc/middle/entry.rs b/src/librustc/middle/entry.rs index ebc796466629c..feeb508d676c9 100644 --- a/src/librustc/middle/entry.rs +++ b/src/librustc/middle/entry.rs @@ -16,7 +16,7 @@ use syntax::ast::NodeId; use syntax::attr; use syntax::entry::EntryPointType; use syntax_pos::Span; -use hir::{Item, ItemFn, ImplItem, TraitItem}; +use hir::{Item, ItemKind, ImplItem, TraitItem}; use hir::itemlikevisit::ItemLikeVisitor; struct EntryContext<'a, 'tcx: 'a> { @@ -91,7 +91,7 @@ pub fn find_entry_point(session: &Session, // them in sync. fn entry_point_type(item: &Item, at_root: bool) -> EntryPointType { match item.node { - ItemFn(..) => { + ItemKind::Fn(..) => { if attr::contains_name(&item.attrs, "start") { EntryPointType::Start } else if attr::contains_name(&item.attrs, "main") { diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 725fcf1e6463b..5beafe2b601bf 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -313,12 +313,13 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { debug!("consume_body(body={:?})", body); for arg in &body.arguments { - let arg_ty = return_if_err!(self.mc.node_ty(arg.pat.hir_id)); + let arg_ty = return_if_err!(self.mc.pat_ty_adjusted(&arg.pat)); + debug!("consume_body: arg_ty = {:?}", arg_ty); let fn_body_scope_r = self.tcx().mk_region(ty::ReScope(region::Scope::Node(body.value.hir_id.local_id))); let arg_cmt = Rc::new(self.mc.cat_rvalue( - arg.id, + arg.hir_id, arg.pat.span, fn_body_scope_r, // Args live only as long as the fn body. arg_ty)); @@ -391,43 +392,43 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.walk_adjustment(expr); match expr.node { - hir::ExprPath(_) => { } + hir::ExprKind::Path(_) => { } - hir::ExprType(ref subexpr, _) => { + hir::ExprKind::Type(ref subexpr, _) => { self.walk_expr(&subexpr) } - hir::ExprUnary(hir::UnDeref, ref base) => { // *base + hir::ExprKind::Unary(hir::UnDeref, ref base) => { // *base self.select_from_expr(&base); } - hir::ExprField(ref base, _) => { // base.f + hir::ExprKind::Field(ref base, _) => { // base.f self.select_from_expr(&base); } - hir::ExprIndex(ref lhs, ref rhs) => { // lhs[rhs] + hir::ExprKind::Index(ref lhs, ref rhs) => { // lhs[rhs] self.select_from_expr(&lhs); self.consume_expr(&rhs); } - hir::ExprCall(ref callee, ref args) => { // callee(args) + hir::ExprKind::Call(ref callee, ref args) => { // callee(args) self.walk_callee(expr, &callee); self.consume_exprs(args); } - hir::ExprMethodCall(.., ref args) => { // callee.m(args) + hir::ExprKind::MethodCall(.., ref args) => { // callee.m(args) self.consume_exprs(args); } - hir::ExprStruct(_, ref fields, ref opt_with) => { + hir::ExprKind::Struct(_, ref fields, ref opt_with) => { self.walk_struct_expr(fields, opt_with); } - hir::ExprTup(ref exprs) => { + hir::ExprKind::Tup(ref exprs) => { self.consume_exprs(exprs); } - hir::ExprIf(ref cond_expr, ref then_expr, ref opt_else_expr) => { + hir::ExprKind::If(ref cond_expr, ref then_expr, ref opt_else_expr) => { self.consume_expr(&cond_expr); self.walk_expr(&then_expr); if let Some(ref else_expr) = *opt_else_expr { @@ -435,7 +436,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } - hir::ExprMatch(ref discr, ref arms, _) => { + hir::ExprKind::Match(ref discr, ref arms, _) => { let discr_cmt = Rc::new(return_if_err!(self.mc.cat_expr(&discr))); let r = self.tcx().types.re_empty; self.borrow_expr(&discr, r, ty::ImmBorrow, MatchDiscriminant); @@ -448,21 +449,21 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } } - hir::ExprArray(ref exprs) => { + hir::ExprKind::Array(ref exprs) => { self.consume_exprs(exprs); } - hir::ExprAddrOf(m, ref base) => { // &base + hir::ExprKind::AddrOf(m, ref base) => { // &base // make sure that the thing we are pointing out stays valid // for the lifetime `scope_r` of the resulting ptr: let expr_ty = return_if_err!(self.mc.expr_ty(expr)); - if let ty::TyRef(r, _) = expr_ty.sty { + if let ty::TyRef(r, _, _) = expr_ty.sty { let bk = ty::BorrowKind::from_mutbl(m); self.borrow_expr(&base, r, bk, AddrOf); } } - hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => { + hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => { for (o, output) in ia.outputs.iter().zip(outputs) { if o.is_indirect { self.consume_expr(output); @@ -478,47 +479,47 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_exprs(inputs); } - hir::ExprAgain(..) | - hir::ExprLit(..) => {} + hir::ExprKind::Continue(..) | + hir::ExprKind::Lit(..) => {} - hir::ExprLoop(ref blk, _, _) => { + hir::ExprKind::Loop(ref blk, _, _) => { self.walk_block(&blk); } - hir::ExprWhile(ref cond_expr, ref blk, _) => { + hir::ExprKind::While(ref cond_expr, ref blk, _) => { self.consume_expr(&cond_expr); self.walk_block(&blk); } - hir::ExprUnary(_, ref lhs) => { + hir::ExprKind::Unary(_, ref lhs) => { self.consume_expr(&lhs); } - hir::ExprBinary(_, ref lhs, ref rhs) => { + hir::ExprKind::Binary(_, ref lhs, ref rhs) => { self.consume_expr(&lhs); self.consume_expr(&rhs); } - hir::ExprBlock(ref blk) => { + hir::ExprKind::Block(ref blk, _) => { self.walk_block(&blk); } - hir::ExprBreak(_, ref opt_expr) | hir::ExprRet(ref opt_expr) => { + hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => { if let Some(ref expr) = *opt_expr { self.consume_expr(&expr); } } - hir::ExprAssign(ref lhs, ref rhs) => { + hir::ExprKind::Assign(ref lhs, ref rhs) => { self.mutate_expr(expr, &lhs, MutateMode::JustWrite); self.consume_expr(&rhs); } - hir::ExprCast(ref base, _) => { + hir::ExprKind::Cast(ref base, _) => { self.consume_expr(&base); } - hir::ExprAssignOp(_, ref lhs, ref rhs) => { + hir::ExprKind::AssignOp(_, ref lhs, ref rhs) => { if self.mc.tables.is_method_call(expr) { self.consume_expr(lhs); } else { @@ -527,19 +528,19 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { self.consume_expr(&rhs); } - hir::ExprRepeat(ref base, _) => { + hir::ExprKind::Repeat(ref base, _) => { self.consume_expr(&base); } - hir::ExprClosure(.., fn_decl_span, _) => { + hir::ExprKind::Closure(.., fn_decl_span, _) => { self.walk_captures(expr, fn_decl_span) } - hir::ExprBox(ref base) => { + hir::ExprKind::Box(ref base) => { self.consume_expr(&base); } - hir::ExprYield(ref value) => { + hir::ExprKind::Yield(ref value) => { self.consume_expr(&value); } } @@ -585,21 +586,21 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_stmt(&mut self, stmt: &hir::Stmt) { match stmt.node { - hir::StmtDecl(ref decl, _) => { + hir::StmtKind::Decl(ref decl, _) => { match decl.node { - hir::DeclLocal(ref local) => { + hir::DeclKind::Local(ref local) => { self.walk_local(&local); } - hir::DeclItem(_) => { + hir::DeclKind::Item(_) => { // we don't visit nested items in this visitor, // only the fn body we were given. } } } - hir::StmtExpr(ref expr, _) | - hir::StmtSemi(ref expr, _) => { + hir::StmtKind::Expr(ref expr, _) | + hir::StmtKind::Semi(ref expr, _) => { self.consume_expr(&expr); } } @@ -608,9 +609,9 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { fn walk_local(&mut self, local: &hir::Local) { match local.init { None => { - let delegate = &mut self.delegate; - local.pat.each_binding(|_, id, span, _| { - delegate.decl_without_init(id, span); + local.pat.each_binding(|_, hir_id, span, _| { + let node_id = self.mc.tcx.hir.hir_to_node_id(hir_id); + self.delegate.decl_without_init(node_id, span); }) } @@ -669,7 +670,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { &*with_expr, with_cmt.clone(), f_index, - with_field.name, + with_field.ident, with_field.ty(self.tcx(), substs) ); self.delegate_consume(with_expr.id, with_expr.span, &cmt_field); @@ -837,38 +838,48 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { /// established up front, e.g. via `determine_pat_move_mode` (see /// also `walk_irrefutable_pat` for patterns that stand alone). fn walk_pat(&mut self, cmt_discr: mc::cmt<'tcx>, pat: &hir::Pat, match_mode: MatchMode) { - debug!("walk_pat cmt_discr={:?} pat={:?}", cmt_discr, pat); + debug!("walk_pat(cmt_discr={:?}, pat={:?})", cmt_discr, pat); + let tcx = self.tcx(); let ExprUseVisitor { ref mc, ref mut delegate, param_env } = *self; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |cmt_pat, pat| { if let PatKind::Binding(_, canonical_id, ..) = pat.node { - debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", cmt_pat, pat, match_mode); - let bm = *mc.tables.pat_binding_modes().get(pat.hir_id) - .expect("missing binding mode"); - - // pat_ty: the type of the binding being produced. - let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); - - // Each match binding is effectively an assignment to the - // binding being produced. - let def = Def::Local(canonical_id); - if let Ok(ref binding_cmt) = mc.cat_def(pat.id, pat.span, pat_ty, def) { - delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); - } + debug!( + "walk_pat: binding cmt_pat={:?} pat={:?} match_mode={:?}", + cmt_pat, + pat, + match_mode, + ); + if let Some(&bm) = mc.tables.pat_binding_modes().get(pat.hir_id) { + debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm); + + // pat_ty: the type of the binding being produced. + let pat_ty = return_if_err!(mc.node_ty(pat.hir_id)); + debug!("walk_pat: pat_ty={:?}", pat_ty); + + // Each match binding is effectively an assignment to the + // binding being produced. + let def = Def::Local(canonical_id); + if let Ok(ref binding_cmt) = mc.cat_def(pat.hir_id, pat.span, pat_ty, def) { + delegate.mutate(pat.id, pat.span, binding_cmt, MutateMode::Init); + } - // It is also a borrow or copy/move of the value being matched. - match bm { - ty::BindByReference(m) => { - if let ty::TyRef(r, _) = pat_ty.sty { - let bk = ty::BorrowKind::from_mutbl(m); - delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding); + // It is also a borrow or copy/move of the value being matched. + match bm { + ty::BindByReference(m) => { + if let ty::TyRef(r, _, _) = pat_ty.sty { + let bk = ty::BorrowKind::from_mutbl(m); + delegate.borrow(pat.id, pat.span, &cmt_pat, r, bk, RefBinding); + } + } + ty::BindByValue(..) => { + let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); + debug!("walk_pat binding consuming pat"); + delegate.consume_pat(pat, &cmt_pat, mode); } } - ty::BindByValue(..) => { - let mode = copy_or_move(mc, param_env, &cmt_pat, PatBindingMove); - debug!("walk_pat binding consuming pat"); - delegate.consume_pat(pat, &cmt_pat, mode); - } + } else { + tcx.sess.delay_span_bug(pat.span, "missing binding mode"); } } })); @@ -915,7 +926,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { closure_expr_id: closure_def_id.to_local(), }; let upvar_capture = self.mc.tables.upvar_capture(upvar_id); - let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.id, + let cmt_var = return_if_err!(self.cat_captured_var(closure_expr.hir_id, fn_decl_span, freevar)); match upvar_capture { @@ -940,7 +951,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { } fn cat_captured_var(&mut self, - closure_id: ast::NodeId, + closure_hir_id: hir::HirId, closure_span: Span, upvar: &hir::Freevar) -> mc::McResult> { @@ -948,7 +959,7 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> { // caller's perspective let var_hir_id = self.tcx().hir.node_to_hir_id(upvar.var_id()); let var_ty = self.mc.node_ty(var_hir_id)?; - self.mc.cat_def(closure_id, closure_span, var_ty, upvar.def) + self.mc.cat_def(closure_hir_id, closure_span, var_ty, upvar.def) } } diff --git a/src/librustc/middle/intrinsicck.rs b/src/librustc/middle/intrinsicck.rs index 27f7dbf508db0..668bac1e4795b 100644 --- a/src/librustc/middle/intrinsicck.rs +++ b/src/librustc/middle/intrinsicck.rs @@ -145,7 +145,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ExprVisitor<'a, 'tcx> { } fn visit_expr(&mut self, expr: &'tcx hir::Expr) { - let def = if let hir::ExprPath(ref qpath) = expr.node { + let def = if let hir::ExprKind::Path(ref qpath) = expr.node { self.tables.qpath_def(qpath, expr.hir_id) } else { Def::Err diff --git a/src/librustc/middle/lang_items.rs b/src/librustc/middle/lang_items.rs index 95e92e21b09dc..cf94a0fb4b4ba 100644 --- a/src/librustc/middle/lang_items.rs +++ b/src/librustc/middle/lang_items.rs @@ -185,6 +185,10 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { if let Some(value) = attribute.value_str() { return Some((value, attribute.span)); } + } else if attribute.check_name("panic_implementation") { + return Some((Symbol::intern("panic_impl"), attribute.span)) + } else if attribute.check_name("alloc_error_handler") { + return Some((Symbol::intern("oom"), attribute.span)) } } @@ -299,12 +303,14 @@ language_item_table! { // lang item, but do not have it defined. PanicFnLangItem, "panic", panic_fn; PanicBoundsCheckFnLangItem, "panic_bounds_check", panic_bounds_check_fn; - PanicFmtLangItem, "panic_fmt", panic_fmt; + PanicInfoLangItem, "panic_info", panic_info; + PanicImplLangItem, "panic_impl", panic_impl; ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn; BoxFreeFnLangItem, "box_free", box_free_fn; DropInPlaceFnLangItem, "drop_in_place", drop_in_place_fn; OomLangItem, "oom", oom; + AllocLayoutLangItem, "alloc_layout", alloc_layout; StartFnLangItem, "start", start_fn; @@ -318,6 +324,8 @@ language_item_table! { NonZeroItem, "non_zero", non_zero; + ManuallyDropItem, "manually_drop", manually_drop; + DebugTraitLangItem, "debug_trait", debug_trait; // A lang item for each of the 128-bit operators we can optionally lower. @@ -348,6 +356,9 @@ language_item_table! { I128ShroFnLangItem, "i128_shro", i128_shro_fn; U128ShroFnLangItem, "u128_shro", u128_shro_fn; + // Align offset for stride != 1, must not panic. + AlignOffsetLangItem, "align_offset", align_offset_fn; + TerminationTraitLangItem, "termination", termination; } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index d1a46f5f15563..b828b1bd30a94 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -51,8 +51,8 @@ //! enclosing function. On the way down the tree, it identifies those AST //! nodes and variable IDs that will be needed for the liveness analysis //! and assigns them contiguous IDs. The liveness id for an AST node is -//! called a `live_node` (it's a newtype'd usize) and the id for a variable -//! is called a `variable` (another newtype'd usize). +//! called a `live_node` (it's a newtype'd u32) and the id for a variable +//! is called a `variable` (another newtype'd u32). //! //! On the way back up the tree, as we are about to exit from a function //! declaration we allocate a `liveness` instance. Now that we know @@ -109,18 +109,20 @@ use self::VarKind::*; use hir::def::*; use ty::{self, TyCtxt}; use lint; -use util::nodemap::{NodeMap, NodeSet}; +use errors::Applicability; +use util::nodemap::{NodeMap, HirIdMap, HirIdSet}; use std::collections::VecDeque; -use std::{fmt, usize}; +use std::{fmt, u32}; use std::io::prelude::*; use std::io; use std::rc::Rc; use syntax::ast::{self, NodeId}; +use syntax::ptr::P; use syntax::symbol::keywords; use syntax_pos::Span; -use hir::Expr; +use hir::{Expr, HirId}; use hir; use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap}; @@ -133,23 +135,17 @@ enum LoopKind<'a> { } #[derive(Copy, Clone, PartialEq)] -struct Variable(usize); +struct Variable(u32); -#[derive(Copy, PartialEq)] -struct LiveNode(usize); +#[derive(Copy, Clone, PartialEq)] +struct LiveNode(u32); impl Variable { - fn get(&self) -> usize { let Variable(v) = *self; v } + fn get(&self) -> usize { self.0 as usize } } impl LiveNode { - fn get(&self) -> usize { let LiveNode(v) = *self; v } -} - -impl Clone for LiveNode { - fn clone(&self) -> LiveNode { - LiveNode(self.get()) - } + fn get(&self) -> usize { self.0 as usize } } #[derive(Copy, Clone, PartialEq, Debug)] @@ -232,27 +228,27 @@ impl fmt::Debug for Variable { impl LiveNode { fn is_valid(&self) -> bool { - self.get() != usize::MAX + self.0 != u32::MAX } } -fn invalid_node() -> LiveNode { LiveNode(usize::MAX) } +fn invalid_node() -> LiveNode { LiveNode(u32::MAX) } struct CaptureInfo { ln: LiveNode, - var_nid: NodeId + var_hid: HirId } #[derive(Copy, Clone, Debug)] struct LocalInfo { - id: NodeId, + id: HirId, name: ast::Name, is_shorthand: bool, } #[derive(Copy, Clone, Debug)] enum VarKind { - Arg(NodeId, ast::Name), + Arg(HirId, ast::Name), Local(LocalInfo), CleanExit } @@ -262,8 +258,8 @@ struct IrMaps<'a, 'tcx: 'a> { num_live_nodes: usize, num_vars: usize, - live_node_map: NodeMap, - variable_map: NodeMap, + live_node_map: HirIdMap, + variable_map: HirIdMap, capture_info_map: NodeMap>>, var_kinds: Vec, lnks: Vec, @@ -275,8 +271,8 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { tcx, num_live_nodes: 0, num_vars: 0, - live_node_map: NodeMap(), - variable_map: NodeMap(), + live_node_map: HirIdMap(), + variable_map: HirIdMap(), capture_info_map: NodeMap(), var_kinds: Vec::new(), lnks: Vec::new(), @@ -284,7 +280,7 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { } fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode { - let ln = LiveNode(self.num_live_nodes); + let ln = LiveNode(self.num_live_nodes as u32); self.lnks.push(lnk); self.num_live_nodes += 1; @@ -294,15 +290,15 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { ln } - fn add_live_node_for_node(&mut self, node_id: NodeId, lnk: LiveNodeKind) { + fn add_live_node_for_node(&mut self, hir_id: HirId, lnk: LiveNodeKind) { let ln = self.add_live_node(lnk); - self.live_node_map.insert(node_id, ln); + self.live_node_map.insert(hir_id, ln); - debug!("{:?} is node {}", ln, node_id); + debug!("{:?} is node {:?}", ln, hir_id); } fn add_variable(&mut self, vk: VarKind) -> Variable { - let v = Variable(self.num_vars); + let v = Variable(self.num_vars as u32); self.var_kinds.push(vk); self.num_vars += 1; @@ -318,11 +314,11 @@ impl<'a, 'tcx> IrMaps<'a, 'tcx> { v } - fn variable(&self, node_id: NodeId, span: Span) -> Variable { - match self.variable_map.get(&node_id) { + fn variable(&self, hir_id: HirId, span: Span) -> Variable { + match self.variable_map.get(&hir_id) { Some(&var) => var, None => { - span_bug!(span, "no variable registered for id {}", node_id); + span_bug!(span, "no variable registered for id {:?}", hir_id); } } } @@ -378,10 +374,9 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>, let body = ir.tcx.hir.body(body_id); for arg in &body.arguments { - arg.pat.each_binding(|_bm, arg_id, _x, path1| { - debug!("adding argument {}", arg_id); - let name = path1.node; - fn_maps.add_variable(Arg(arg_id, name)); + arg.pat.each_binding(|_bm, hir_id, _x, ident| { + debug!("adding argument {:?}", hir_id); + fn_maps.add_variable(Arg(hir_id, ident.name)); }) }; @@ -398,72 +393,60 @@ fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>, lsets.warn_about_unused_args(body, entry_ln); } -fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) { - local.pat.each_binding(|_, p_id, sp, path1| { - debug!("adding local variable {}", p_id); - let name = path1.node; - ir.add_live_node_for_node(p_id, VarDefNode(sp)); +fn add_from_pat<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, pat: &P) { + // For struct patterns, take note of which fields used shorthand + // (`x` rather than `x: x`). + let mut shorthand_field_ids = HirIdSet(); + let mut pats = VecDeque::new(); + pats.push_back(pat); + while let Some(pat) = pats.pop_front() { + use hir::PatKind::*; + match pat.node { + Binding(_, _, _, ref inner_pat) => { + pats.extend(inner_pat.iter()); + } + Struct(_, ref fields, _) => { + for field in fields { + if field.node.is_shorthand { + shorthand_field_ids.insert(field.node.pat.hir_id); + } + } + } + Ref(ref inner_pat, _) | + Box(ref inner_pat) => { + pats.push_back(inner_pat); + } + TupleStruct(_, ref inner_pats, _) | + Tuple(ref inner_pats, _) => { + pats.extend(inner_pats.iter()); + } + Slice(ref pre_pats, ref inner_pat, ref post_pats) => { + pats.extend(pre_pats.iter()); + pats.extend(inner_pat.iter()); + pats.extend(post_pats.iter()); + } + _ => {} + } + } + + pat.each_binding(|_bm, hir_id, _sp, ident| { + ir.add_live_node_for_node(hir_id, VarDefNode(ident.span)); ir.add_variable(Local(LocalInfo { - id: p_id, - name, - is_shorthand: false, + id: hir_id, + name: ident.name, + is_shorthand: shorthand_field_ids.contains(&hir_id) })); }); +} + +fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) { + add_from_pat(ir, &local.pat); intravisit::walk_local(ir, local); } fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) { - for mut pat in &arm.pats { - // For struct patterns, take note of which fields used shorthand - // (`x` rather than `x: x`). - // - // FIXME: according to the rust-lang-nursery/rustc-guide book, `NodeId`s are to be - // phased out in favor of `HirId`s; however, we need to match the signature of - // `each_binding`, which uses `NodeIds`. - let mut shorthand_field_ids = NodeSet(); - let mut pats = VecDeque::new(); - pats.push_back(pat); - while let Some(pat) = pats.pop_front() { - use hir::PatKind::*; - match pat.node { - Binding(_, _, _, ref inner_pat) => { - pats.extend(inner_pat.iter()); - } - Struct(_, ref fields, _) => { - for field in fields { - if field.node.is_shorthand { - shorthand_field_ids.insert(field.node.pat.id); - } - } - } - Ref(ref inner_pat, _) | - Box(ref inner_pat) => { - pats.push_back(inner_pat); - } - TupleStruct(_, ref inner_pats, _) | - Tuple(ref inner_pats, _) => { - pats.extend(inner_pats.iter()); - } - Slice(ref pre_pats, ref inner_pat, ref post_pats) => { - pats.extend(pre_pats.iter()); - pats.extend(inner_pat.iter()); - pats.extend(post_pats.iter()); - } - _ => {} - } - } - - pat.each_binding(|bm, p_id, sp, path1| { - debug!("adding local variable {} from match with bm {:?}", - p_id, bm); - let name = path1.node; - ir.add_live_node_for_node(p_id, VarDefNode(sp)); - ir.add_variable(Local(LocalInfo { - id: p_id, - name: name, - is_shorthand: shorthand_field_ids.contains(&p_id) - })); - }) + for pat in &arm.pats { + add_from_pat(ir, pat); } intravisit::walk_arm(ir, arm); } @@ -471,17 +454,17 @@ fn visit_arm<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, arm: &'tcx hir::Arm) { fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { match expr.node { // live nodes required for uses or definitions of variables: - hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { + hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { debug!("expr {}: path that leads to {:?}", expr.id, path.def); if let Def::Local(..) = path.def { - ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); + ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); } intravisit::walk_expr(ir, expr); } - hir::ExprClosure(..) => { + hir::ExprKind::Closure(..) => { // Interesting control flow (for loops can contain labeled // breaks or continues) - ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); + ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); // Make a live_node for each captured variable, with the span // being the location that the variable is used. This results @@ -492,8 +475,8 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { for fv in freevars { if let Def::Local(rv) = fv.def { let fv_ln = ir.add_live_node(FreeVarNode(fv.span)); - call_caps.push(CaptureInfo {ln: fv_ln, - var_nid: rv}); + let var_hid = ir.tcx.hir.node_to_hir_id(rv); + call_caps.push(CaptureInfo { ln: fv_ln, var_hid }); } } }); @@ -503,25 +486,43 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) { } // live nodes required for interesting control flow: - hir::ExprIf(..) | hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) => { - ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); + hir::ExprKind::If(..) | + hir::ExprKind::Match(..) | + hir::ExprKind::While(..) | + hir::ExprKind::Loop(..) => { + ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); intravisit::walk_expr(ir, expr); } - hir::ExprBinary(op, ..) if op.node.is_lazy() => { - ir.add_live_node_for_node(expr.id, ExprNode(expr.span)); + hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => { + ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); intravisit::walk_expr(ir, expr); } // otherwise, live nodes are not required: - hir::ExprIndex(..) | hir::ExprField(..) | - hir::ExprArray(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) | - hir::ExprTup(..) | hir::ExprBinary(..) | hir::ExprAddrOf(..) | - hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprBreak(..) | - hir::ExprAgain(_) | hir::ExprLit(_) | hir::ExprRet(..) | - hir::ExprBlock(..) | hir::ExprAssign(..) | hir::ExprAssignOp(..) | - hir::ExprStruct(..) | hir::ExprRepeat(..) | - hir::ExprInlineAsm(..) | hir::ExprBox(..) | hir::ExprYield(..) | - hir::ExprType(..) | hir::ExprPath(hir::QPath::TypeRelative(..)) => { + hir::ExprKind::Index(..) | + hir::ExprKind::Field(..) | + hir::ExprKind::Array(..) | + hir::ExprKind::Call(..) | + hir::ExprKind::MethodCall(..) | + hir::ExprKind::Tup(..) | + hir::ExprKind::Binary(..) | + hir::ExprKind::AddrOf(..) | + hir::ExprKind::Cast(..) | + hir::ExprKind::Unary(..) | + hir::ExprKind::Break(..) | + hir::ExprKind::Continue(_) | + hir::ExprKind::Lit(_) | + hir::ExprKind::Ret(..) | + hir::ExprKind::Block(..) | + hir::ExprKind::Assign(..) | + hir::ExprKind::AssignOp(..) | + hir::ExprKind::Struct(..) | + hir::ExprKind::Repeat(..) | + hir::ExprKind::InlineAsm(..) | + hir::ExprKind::Box(..) | + hir::ExprKind::Yield(..) | + hir::ExprKind::Type(..) | + hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => { intravisit::walk_expr(ir, expr); } } @@ -571,9 +572,6 @@ struct Liveness<'a, 'tcx: 'a> { // it probably doesn't now) break_ln: NodeMap, cont_ln: NodeMap, - - // mappings from node ID to LiveNode for "breakable" blocks-- currently only `catch {...}` - breakable_block_ln: NodeMap, } impl<'a, 'tcx> Liveness<'a, 'tcx> { @@ -601,12 +599,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { users: vec![invalid_users(); num_live_nodes * num_vars], break_ln: NodeMap(), cont_ln: NodeMap(), - breakable_block_ln: NodeMap(), } } - fn live_node(&self, node_id: NodeId, span: Span) -> LiveNode { - match self.ir.live_node_map.get(&node_id) { + fn live_node(&self, hir_id: HirId, span: Span) -> LiveNode { + match self.ir.live_node_map.get(&hir_id) { Some(&ln) => ln, None => { // This must be a mismatch between the ir_map construction @@ -615,28 +612,28 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // creating liveness nodes for. span_bug!( span, - "no live node registered for node {}", - node_id); + "no live node registered for node {:?}", + hir_id); } } } - fn variable(&self, node_id: NodeId, span: Span) -> Variable { - self.ir.variable(node_id, span) + fn variable(&self, hir_id: HirId, span: Span) -> Variable { + self.ir.variable(hir_id, span) } fn pat_bindings(&mut self, pat: &hir::Pat, mut f: F) where - F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId), + F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId), { - pat.each_binding(|_bm, p_id, sp, _n| { - let ln = self.live_node(p_id, sp); - let var = self.variable(p_id, sp); - f(self, ln, var, sp, p_id); + pat.each_binding(|_bm, hir_id, sp, n| { + let ln = self.live_node(hir_id, sp); + let var = self.variable(hir_id, n.span); + f(self, ln, var, n.span, hir_id); }) } fn arm_pats_bindings(&mut self, pat: Option<&hir::Pat>, f: F) where - F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, NodeId), + F: FnMut(&mut Liveness<'a, 'tcx>, LiveNode, Variable, Span, HirId), { if let Some(pat) = pat { self.pat_bindings(pat, f); @@ -718,7 +715,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { for var_idx in 0..self.ir.num_vars { let idx = node_base_idx + var_idx; if test(idx).is_valid() { - write!(wr, " {:?}", Variable(var_idx))?; + write!(wr, " {:?}", Variable(var_idx as u32))?; } } Ok(()) @@ -858,7 +855,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!("^^ liveness computation results for body {} (entry={:?})", { for ln_idx in 0..self.ir.num_live_nodes { - debug!("{:?}", self.ln_str(LiveNode(ln_idx))); + debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32))); } body.id }, @@ -870,7 +867,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_block(&mut self, blk: &hir::Block, succ: LiveNode) -> LiveNode { if blk.targeted_by_break { - self.breakable_block_ln.insert(blk.id, succ); + self.break_ln.insert(blk.id, succ); } let succ = self.propagate_through_opt_expr(blk.expr.as_ref().map(|e| &**e), succ); blk.stmts.iter().rev().fold(succ, |succ, stmt| { @@ -881,11 +878,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_stmt(&mut self, stmt: &hir::Stmt, succ: LiveNode) -> LiveNode { match stmt.node { - hir::StmtDecl(ref decl, _) => { + hir::StmtKind::Decl(ref decl, _) => { self.propagate_through_decl(&decl, succ) } - hir::StmtExpr(ref expr, _) | hir::StmtSemi(ref expr, _) => { + hir::StmtKind::Expr(ref expr, _) | hir::StmtKind::Semi(ref expr, _) => { self.propagate_through_expr(&expr, succ) } } @@ -894,10 +891,10 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn propagate_through_decl(&mut self, decl: &hir::Decl, succ: LiveNode) -> LiveNode { match decl.node { - hir::DeclLocal(ref local) => { + hir::DeclKind::Local(ref local) => { self.propagate_through_local(&local, succ) } - hir::DeclItem(_) => succ, + hir::DeclKind::Item(_) => succ, } } @@ -941,22 +938,20 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { match expr.node { // Interesting cases with control flow or which gen/kill - hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { - self.access_path(expr.id, path, succ, ACC_READ | ACC_USE) + hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { + self.access_path(expr.hir_id, path, succ, ACC_READ | ACC_USE) } - hir::ExprField(ref e, _) => { + hir::ExprKind::Field(ref e, _) => { self.propagate_through_expr(&e, succ) } - hir::ExprClosure(.., blk_id, _, _) => { - debug!("{} is an ExprClosure", self.ir.tcx.hir.node_to_pretty_string(expr.id)); + hir::ExprKind::Closure(.., blk_id, _, _) => { + debug!("{} is an ExprKind::Closure", self.ir.tcx.hir.node_to_pretty_string(expr.id)); - /* - The next-node for a break is the successor of the entire - loop. The next-node for a continue is the top of this loop. - */ - let node = self.live_node(expr.id, expr.span); + // The next-node for a break is the successor of the entire + // loop. The next-node for a continue is the top of this loop. + let node = self.live_node(expr.hir_id, expr.span); let break_ln = succ; let cont_ln = node; @@ -973,13 +968,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }; caps.iter().rev().fold(succ, |succ, cap| { self.init_from_succ(cap.ln, succ); - let var = self.variable(cap.var_nid, expr.span); + let var = self.variable(cap.var_hid, expr.span); self.acc(cap.ln, var, ACC_READ | ACC_USE); cap.ln }) } - hir::ExprIf(ref cond, ref then, ref els) => { + hir::ExprKind::If(ref cond, ref then, ref els) => { // // (cond) // | @@ -995,23 +990,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // let else_ln = self.propagate_through_opt_expr(els.as_ref().map(|e| &**e), succ); let then_ln = self.propagate_through_expr(&then, succ); - let ln = self.live_node(expr.id, expr.span); + let ln = self.live_node(expr.hir_id, expr.span); self.init_from_succ(ln, else_ln); self.merge_from_succ(ln, then_ln, false); self.propagate_through_expr(&cond, ln) } - hir::ExprWhile(ref cond, ref blk, _) => { + hir::ExprKind::While(ref cond, ref blk, _) => { self.propagate_through_loop(expr, WhileLoop(&cond), &blk, succ) } // Note that labels have been resolved, so we don't need to look // at the label ident - hir::ExprLoop(ref blk, _, _) => { + hir::ExprKind::Loop(ref blk, _, _) => { self.propagate_through_loop(expr, LoopLoop, &blk, succ) } - hir::ExprMatch(ref e, ref arms, _) => { + hir::ExprKind::Match(ref e, ref arms, _) => { // // (e) // | @@ -1026,7 +1021,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // ( succ ) // // - let ln = self.live_node(expr.id, expr.span); + let ln = self.live_node(expr.hir_id, expr.span); self.init_empty(ln, succ); let mut first_merge = true; for arm in arms { @@ -1046,21 +1041,17 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&e, ln) } - hir::ExprRet(ref o_e) => { + hir::ExprKind::Ret(ref o_e) => { // ignore succ and subst exit_ln: let exit_ln = self.s.exit_ln; self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln) } - hir::ExprBreak(label, ref opt_expr) => { + hir::ExprKind::Break(label, ref opt_expr) => { // Find which label this break jumps to let target = match label.target_id { - hir::ScopeTarget::Block(node_id) => - self.breakable_block_ln.get(&node_id), - hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(node_id)) => - self.break_ln.get(&node_id), - hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => - span_bug!(expr.span, "loop scope error: {}", err), + Ok(node_id) => self.break_ln.get(&node_id), + Err(err) => span_bug!(expr.span, "loop scope error: {}", err), }.map(|x| *x); // Now that we know the label we're going to, @@ -1072,13 +1063,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } } - hir::ExprAgain(label) => { + hir::ExprKind::Continue(label) => { // Find which label this expr continues to let sc = match label.target_id { - hir::ScopeTarget::Block(_) => bug!("can't `continue` to a non-loop block"), - hir::ScopeTarget::Loop(hir::LoopIdResult::Ok(node_id)) => node_id, - hir::ScopeTarget::Loop(hir::LoopIdResult::Err(err)) => - span_bug!(expr.span, "loop scope error: {}", err), + Ok(node_id) => node_id, + Err(err) => span_bug!(expr.span, "loop scope error: {}", err), }; // Now that we know the label we're going to, @@ -1090,7 +1079,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } } - hir::ExprAssign(ref l, ref r) => { + hir::ExprKind::Assign(ref l, ref r) => { // see comment on places in // propagate_through_place_components() let succ = self.write_place(&l, succ, ACC_WRITE); @@ -1098,7 +1087,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&r, succ) } - hir::ExprAssignOp(_, ref l, ref r) => { + hir::ExprKind::AssignOp(_, ref l, ref r) => { // an overloaded assign op is like a method call if self.tables.is_method_call(expr) { let succ = self.propagate_through_expr(&l, succ); @@ -1114,18 +1103,18 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Uninteresting cases: just propagate in rev exec order - hir::ExprArray(ref exprs) => { + hir::ExprKind::Array(ref exprs) => { self.propagate_through_exprs(exprs, succ) } - hir::ExprStruct(_, ref fields, ref with_expr) => { + hir::ExprKind::Struct(_, ref fields, ref with_expr) => { let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ); fields.iter().rev().fold(succ, |succ, field| { self.propagate_through_expr(&field.expr, succ) }) } - hir::ExprCall(ref f, ref args) => { + hir::ExprKind::Call(ref f, ref args) => { // FIXME(canndrew): This is_never should really be an is_uninhabited let succ = if self.tables.expr_ty(expr).is_never() { self.s.exit_ln @@ -1136,7 +1125,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_expr(&f, succ) } - hir::ExprMethodCall(.., ref args) => { + hir::ExprKind::MethodCall(.., ref args) => { // FIXME(canndrew): This is_never should really be an is_uninhabited let succ = if self.tables.expr_ty(expr).is_never() { self.s.exit_ln @@ -1146,37 +1135,37 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_exprs(args, succ) } - hir::ExprTup(ref exprs) => { + hir::ExprKind::Tup(ref exprs) => { self.propagate_through_exprs(exprs, succ) } - hir::ExprBinary(op, ref l, ref r) if op.node.is_lazy() => { + hir::ExprKind::Binary(op, ref l, ref r) if op.node.is_lazy() => { let r_succ = self.propagate_through_expr(&r, succ); - let ln = self.live_node(expr.id, expr.span); + let ln = self.live_node(expr.hir_id, expr.span); self.init_from_succ(ln, succ); self.merge_from_succ(ln, r_succ, false); self.propagate_through_expr(&l, ln) } - hir::ExprIndex(ref l, ref r) | - hir::ExprBinary(_, ref l, ref r) => { + hir::ExprKind::Index(ref l, ref r) | + hir::ExprKind::Binary(_, ref l, ref r) => { let r_succ = self.propagate_through_expr(&r, succ); self.propagate_through_expr(&l, r_succ) } - hir::ExprBox(ref e) | - hir::ExprAddrOf(_, ref e) | - hir::ExprCast(ref e, _) | - hir::ExprType(ref e, _) | - hir::ExprUnary(_, ref e) | - hir::ExprYield(ref e) | - hir::ExprRepeat(ref e, _) => { + hir::ExprKind::Box(ref e) | + hir::ExprKind::AddrOf(_, ref e) | + hir::ExprKind::Cast(ref e, _) | + hir::ExprKind::Type(ref e, _) | + hir::ExprKind::Unary(_, ref e) | + hir::ExprKind::Yield(ref e) | + hir::ExprKind::Repeat(ref e, _) => { self.propagate_through_expr(&e, succ) } - hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => { + hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => { let succ = ia.outputs.iter().zip(outputs).rev().fold(succ, |succ, (o, output)| { // see comment on places // in propagate_through_place_components() @@ -1193,11 +1182,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.propagate_through_exprs(inputs, succ) } - hir::ExprLit(..) | hir::ExprPath(hir::QPath::TypeRelative(..)) => { + hir::ExprKind::Lit(..) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => { succ } - hir::ExprBlock(ref blk) => { + // Note that labels have been resolved, so we don't need to look + // at the label ident + hir::ExprKind::Block(ref blk, _) => { self.propagate_through_block(&blk, succ) } } @@ -1257,8 +1248,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // just ignore such cases and treat them as reads. match expr.node { - hir::ExprPath(_) => succ, - hir::ExprField(ref e, _) => self.propagate_through_expr(&e, succ), + hir::ExprKind::Path(_) => succ, + hir::ExprKind::Field(ref e, _) => self.propagate_through_expr(&e, succ), _ => self.propagate_through_expr(expr, succ) } } @@ -1267,8 +1258,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn write_place(&mut self, expr: &Expr, succ: LiveNode, acc: u32) -> LiveNode { match expr.node { - hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { - self.access_path(expr.id, path, succ, acc) + hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { + self.access_path(expr.hir_id, path, succ, acc) } // We do not track other places, so just propagate through @@ -1279,22 +1270,23 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } } - fn access_var(&mut self, id: NodeId, nid: NodeId, succ: LiveNode, acc: u32, span: Span) + fn access_var(&mut self, hir_id: HirId, nid: NodeId, succ: LiveNode, acc: u32, span: Span) -> LiveNode { - let ln = self.live_node(id, span); + let ln = self.live_node(hir_id, span); if acc != 0 { self.init_from_succ(ln, succ); - let var = self.variable(nid, span); + let var_hid = self.ir.tcx.hir.node_to_hir_id(nid); + let var = self.variable(var_hid, span); self.acc(ln, var, acc); } ln } - fn access_path(&mut self, id: NodeId, path: &hir::Path, succ: LiveNode, acc: u32) + fn access_path(&mut self, hir_id: HirId, path: &hir::Path, succ: LiveNode, acc: u32) -> LiveNode { match path.def { Def::Local(nid) => { - self.access_var(id, nid, succ, acc, path.span) + self.access_var(hir_id, nid, succ, acc, path.span) } _ => succ } @@ -1328,7 +1320,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // first iteration: let mut first_merge = true; - let ln = self.live_node(expr.id, expr.span); + let ln = self.live_node(expr.hir_id, expr.span); self.init_empty(ln, succ); match kind { LoopLoop => {} @@ -1398,7 +1390,8 @@ fn check_local<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, local: &'tcx hir::Local) }, None => { this.pat_bindings(&local.pat, |this, ln, var, sp, id| { - this.warn_about_unused(sp, id, ln, var); + let span = local.pat.simple_ident().map_or(sp, |ident| ident.span); + this.warn_about_unused(span, id, ln, var); }) } } @@ -1418,13 +1411,13 @@ fn check_arm<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, arm: &'tcx hir::Arm) { fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { match expr.node { - hir::ExprAssign(ref l, _) => { + hir::ExprKind::Assign(ref l, _) => { this.check_place(&l); intravisit::walk_expr(this, expr); } - hir::ExprAssignOp(_, ref l, _) => { + hir::ExprKind::AssignOp(_, ref l, _) => { if !this.tables.is_method_call(expr) { this.check_place(&l); } @@ -1432,7 +1425,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { intravisit::walk_expr(this, expr); } - hir::ExprInlineAsm(ref ia, ref outputs, ref inputs) => { + hir::ExprKind::InlineAsm(ref ia, ref outputs, ref inputs) => { for input in inputs { this.visit_expr(input); } @@ -1449,16 +1442,16 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { } // no correctness conditions related to liveness - hir::ExprCall(..) | hir::ExprMethodCall(..) | hir::ExprIf(..) | - hir::ExprMatch(..) | hir::ExprWhile(..) | hir::ExprLoop(..) | - hir::ExprIndex(..) | hir::ExprField(..) | - hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprBinary(..) | - hir::ExprCast(..) | hir::ExprUnary(..) | hir::ExprRet(..) | - hir::ExprBreak(..) | hir::ExprAgain(..) | hir::ExprLit(_) | - hir::ExprBlock(..) | hir::ExprAddrOf(..) | - hir::ExprStruct(..) | hir::ExprRepeat(..) | - hir::ExprClosure(..) | hir::ExprPath(_) | hir::ExprYield(..) | - hir::ExprBox(..) | hir::ExprType(..) => { + hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) | hir::ExprKind::If(..) | + hir::ExprKind::Match(..) | hir::ExprKind::While(..) | hir::ExprKind::Loop(..) | + hir::ExprKind::Index(..) | hir::ExprKind::Field(..) | + hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::Binary(..) | + hir::ExprKind::Cast(..) | hir::ExprKind::Unary(..) | hir::ExprKind::Ret(..) | + hir::ExprKind::Break(..) | hir::ExprKind::Continue(..) | hir::ExprKind::Lit(_) | + hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) | + hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | + hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) | + hir::ExprKind::Box(..) | hir::ExprKind::Type(..) => { intravisit::walk_expr(this, expr); } } @@ -1467,15 +1460,16 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) { impl<'a, 'tcx> Liveness<'a, 'tcx> { fn check_place(&mut self, expr: &'tcx Expr) { match expr.node { - hir::ExprPath(hir::QPath::Resolved(_, ref path)) => { + hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { if let Def::Local(nid) = path.def { // Assignment to an immutable variable or argument: only legal // if there is no later assignment. If this local is actually // mutable, then check for a reassignment to flag the mutability // as being used. - let ln = self.live_node(expr.id, expr.span); - let var = self.variable(nid, expr.span); - self.warn_about_dead_assign(expr.span, expr.id, ln, var); + let ln = self.live_node(expr.hir_id, expr.span); + let var_hid = self.ir.tcx.hir.node_to_hir_id(nid); + let var = self.variable(var_hid, expr.span); + self.warn_about_dead_assign(expr.span, expr.hir_id, ln, var); } } _ => { @@ -1497,14 +1491,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) { for arg in &body.arguments { - arg.pat.each_binding(|_bm, p_id, sp, path1| { - let var = self.variable(p_id, sp); + arg.pat.each_binding(|_bm, hir_id, _, ident| { + let sp = ident.span; + let var = self.variable(hir_id, sp); // Ignore unused self. - let name = path1.node; - if name != keywords::SelfValue.name() { - if !self.warn_about_unused(sp, p_id, entry_ln, var) { + if ident.name != keywords::SelfValue.name() { + if !self.warn_about_unused(sp, hir_id, entry_ln, var) { if self.live_on_entry(entry_ln, var).is_none() { - self.report_dead_assign(p_id, sp, var, true); + self.report_dead_assign(hir_id, sp, var, true); } } } @@ -1522,7 +1516,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn warn_about_unused(&self, sp: Span, - id: NodeId, + hir_id: HirId, ln: LiveNode, var: Variable) -> bool { @@ -1541,22 +1535,27 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let suggest_underscore_msg = format!("consider using `_{}` instead", name); + if is_assigned { self.ir.tcx - .lint_node_note(lint::builtin::UNUSED_VARIABLES, id, sp, - &format!("variable `{}` is assigned to, but never used", - name), - &suggest_underscore_msg); + .lint_hir_note(lint::builtin::UNUSED_VARIABLES, hir_id, sp, + &format!("variable `{}` is assigned to, but never used", + name), + &suggest_underscore_msg); } else if name != "self" { let msg = format!("unused variable: `{}`", name); let mut err = self.ir.tcx - .struct_span_lint_node(lint::builtin::UNUSED_VARIABLES, id, sp, &msg); + .struct_span_lint_hir(lint::builtin::UNUSED_VARIABLES, hir_id, sp, &msg); if self.ir.variable_is_shorthand(var) { - err.span_suggestion(sp, "try ignoring the field", - format!("{}: _", name)); + err.span_suggestion_with_applicability(sp, "try ignoring the field", + format!("{}: _", name), + Applicability::MachineApplicable); } else { - err.span_suggestion_short(sp, &suggest_underscore_msg, - format!("_{}", name)); + err.span_suggestion_short_with_applicability( + sp, &suggest_underscore_msg, + format!("_{}", name), + Applicability::MachineApplicable, + ); } err.emit() } @@ -1569,21 +1568,21 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn warn_about_dead_assign(&self, sp: Span, - id: NodeId, + hir_id: HirId, ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { - self.report_dead_assign(id, sp, var, false); + self.report_dead_assign(hir_id, sp, var, false); } } - fn report_dead_assign(&self, id: NodeId, sp: Span, var: Variable, is_argument: bool) { + fn report_dead_assign(&self, hir_id: HirId, sp: Span, var: Variable, is_argument: bool) { if let Some(name) = self.should_warn(var) { if is_argument { - self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, + self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, &format!("value passed to `{}` is never read", name)); } else { - self.ir.tcx.lint_node(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, + self.ir.tcx.lint_hir(lint::builtin::UNUSED_ASSIGNMENTS, hir_id, sp, &format!("value assigned to `{}` is never read", name)); } } diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index f40a41cd29924..0602dc55c43d6 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -46,9 +46,9 @@ //! //! ## By-reference upvars //! -//! One part of the translation which may be non-obvious is that we translate +//! One part of the codegen which may be non-obvious is that we translate //! closure upvars into the dereference of a borrowed pointer; this more closely -//! resembles the runtime translation. So, for example, if we had: +//! resembles the runtime codegen. So, for example, if we had: //! //! let mut x = 3; //! let y = 5; @@ -95,7 +95,7 @@ pub enum Categorization<'tcx> { StaticItem, Upvar(Upvar), // upvar referenced by closure env Local(ast::NodeId), // local variable - Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr + Deref(cmt<'tcx>, PointerKind<'tcx>), // deref of a ptr Interior(cmt<'tcx>, InteriorKind), // something interior: field, tuple, etc Downcast(cmt<'tcx>, DefId), // selects a particular enum variant (*1) @@ -120,9 +120,6 @@ pub enum PointerKind<'tcx> { /// `*T` UnsafePtr(hir::Mutability), - - /// Implicit deref of the `&T` that results from an overloaded index `[]`. - Implicit(ty::BorrowKind, ty::Region<'tcx>), } // We use the term "interior" to mean "something reachable from the @@ -172,6 +169,7 @@ pub enum MutabilityCategory { pub enum Note { NoteClosureEnv(ty::UpvarId), // Deref through closure env NoteUpvarRef(ty::UpvarId), // Deref through by-ref upvar + NoteIndex, // Deref as part of desugaring `x[]` into its two components NoteNone // Nothing special } @@ -182,16 +180,20 @@ pub enum Note { // which the value is stored. // // *WARNING* The field `cmt.type` is NOT necessarily the same as the -// result of `node_id_to_type(cmt.id)`. This is because the `id` is -// always the `id` of the node producing the type; in an expression -// like `*x`, the type of this deref node is the deref'd type (`T`), -// but in a pattern like `@x`, the `@x` pattern is again a -// dereference, but its type is the type *before* the dereference -// (`@T`). So use `cmt.ty` to find the type of the value in a consistent -// fashion. For more details, see the method `cat_pattern` +// result of `node_id_to_type(cmt.id)`. +// +// (FIXME: rewrite the following comment given that `@x` managed +// pointers have been obsolete for quite some time.) +// +// This is because the `id` is always the `id` of the node producing the +// type; in an expression like `*x`, the type of this deref node is the +// deref'd type (`T`), but in a pattern like `@x`, the `@x` pattern is +// again a dereference, but its type is the type *before* the +// dereference (`@T`). So use `cmt.ty` to find the type of the value in +// a consistent fashion. For more details, see the method `cat_pattern` #[derive(Clone, Debug, PartialEq)] pub struct cmt_<'tcx> { - pub id: ast::NodeId, // id of expr/pat producing this value + pub hir_id: hir::HirId, // HIR id of expr/pat producing this value pub span: Span, // span of same expr/pat pub cat: Categorization<'tcx>, // categorization of expr pub mutbl: MutabilityCategory, // mutability of expr as place @@ -231,8 +233,7 @@ impl<'tcx> cmt_<'tcx> { pub fn immutability_blame(&self) -> Option> { match self.cat { - Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(ref base_cmt, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(ref base_cmt, BorrowedPtr(ty::ImmBorrow, _)) => { // try to figure out where the immutable reference came from match base_cmt.cat { Categorization::Local(node_id) => @@ -274,18 +275,18 @@ impl<'tcx> cmt_<'tcx> { } } -pub trait ast_node { - fn id(&self) -> ast::NodeId; +pub trait HirNode { + fn hir_id(&self) -> hir::HirId; fn span(&self) -> Span; } -impl ast_node for hir::Expr { - fn id(&self) -> ast::NodeId { self.id } +impl HirNode for hir::Expr { + fn hir_id(&self) -> hir::HirId { self.hir_id } fn span(&self) -> Span { self.span } } -impl ast_node for hir::Pat { - fn id(&self) -> ast::NodeId { self.id } +impl HirNode for hir::Pat { + fn hir_id(&self) -> hir::HirId { self.hir_id } fn span(&self) -> Span { self.span } } @@ -328,7 +329,7 @@ impl MutabilityCategory { Unique => { base_mutbl.inherit() } - BorrowedPtr(borrow_kind, _) | Implicit(borrow_kind, _) => { + BorrowedPtr(borrow_kind, _) => { MutabilityCategory::from_borrow_kind(borrow_kind) } UnsafePtr(m) => { @@ -488,7 +489,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // FIXME None if self.is_tainted_by_errors() => Err(()), None => { - let id = self.tcx.hir.definitions().find_node_for_hir_id(id); + let id = self.tcx.hir.hir_to_node_id(id); bug!("no type for node {}: {} in mem_categorization", id, self.tcx.hir.node_to_string(id)); } @@ -520,7 +521,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { /// implicit deref patterns attached (e.g., it is really /// `&Some(x)`). In that case, we return the "outermost" type /// (e.g., `&Option). - fn pat_ty(&self, pat: &hir::Pat) -> McResult> { + pub fn pat_ty_adjusted(&self, pat: &hir::Pat) -> McResult> { // Check for implicit `&` types wrapping the pattern; note // that these are never attached to binding patterns, so // actually this is somewhat "disjoint" from the code below @@ -613,11 +614,11 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ty: target, mutbl: deref.mutbl, }); - self.cat_rvalue_node(expr.id, expr.span, ref_ty) + self.cat_rvalue_node(expr.hir_id, expr.span, ref_ty) } else { previous()? }); - self.cat_deref(expr, base, false) + self.cat_deref(expr, base, NoteNone) } adjustment::Adjust::NeverToAny | @@ -628,7 +629,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { adjustment::Adjust::Borrow(_) | adjustment::Adjust::Unsize => { // Result is an rvalue. - Ok(self.cat_rvalue_node(expr.id, expr.span, target)) + Ok(self.cat_rvalue_node(expr.hir_id, expr.span, target)) } } } @@ -638,88 +639,88 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let expr_ty = self.expr_ty(expr)?; match expr.node { - hir::ExprUnary(hir::UnDeref, ref e_base) => { + hir::ExprKind::Unary(hir::UnDeref, ref e_base) => { if self.tables.is_method_call(expr) { - self.cat_overloaded_place(expr, e_base, false) + self.cat_overloaded_place(expr, e_base, NoteNone) } else { let base_cmt = Rc::new(self.cat_expr(&e_base)?); - self.cat_deref(expr, base_cmt, false) + self.cat_deref(expr, base_cmt, NoteNone) } } - hir::ExprField(ref base, f_name) => { + hir::ExprKind::Field(ref base, f_ident) => { let base_cmt = Rc::new(self.cat_expr(&base)?); debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.id, expr, base_cmt); let f_index = self.tcx.field_index(expr.id, self.tables); - Ok(self.cat_field(expr, base_cmt, f_index, f_name.node, expr_ty)) + Ok(self.cat_field(expr, base_cmt, f_index, f_ident, expr_ty)) } - hir::ExprIndex(ref base, _) => { + hir::ExprKind::Index(ref base, _) => { if self.tables.is_method_call(expr) { // If this is an index implemented by a method call, then it // will include an implicit deref of the result. // The call to index() returns a `&T` value, which // is an rvalue. That is what we will be // dereferencing. - self.cat_overloaded_place(expr, base, true) + self.cat_overloaded_place(expr, base, NoteIndex) } else { let base_cmt = Rc::new(self.cat_expr(&base)?); self.cat_index(expr, base_cmt, expr_ty, InteriorOffsetKind::Index) } } - hir::ExprPath(ref qpath) => { - let def = self.tables.qpath_def(qpath, expr.hir_id); - self.cat_def(expr.id, expr.span, expr_ty, def) + hir::ExprKind::Path(ref qpath) => { + let def = self.tables.qpath_def(qpath, expr.hir_id); + self.cat_def(expr.hir_id, expr.span, expr_ty, def) } - hir::ExprType(ref e, _) => { + hir::ExprKind::Type(ref e, _) => { self.cat_expr(&e) } - hir::ExprAddrOf(..) | hir::ExprCall(..) | - hir::ExprAssign(..) | hir::ExprAssignOp(..) | - hir::ExprClosure(..) | hir::ExprRet(..) | - hir::ExprUnary(..) | hir::ExprYield(..) | - hir::ExprMethodCall(..) | hir::ExprCast(..) | - hir::ExprArray(..) | hir::ExprTup(..) | hir::ExprIf(..) | - hir::ExprBinary(..) | hir::ExprWhile(..) | - hir::ExprBlock(..) | hir::ExprLoop(..) | hir::ExprMatch(..) | - hir::ExprLit(..) | hir::ExprBreak(..) | - hir::ExprAgain(..) | hir::ExprStruct(..) | hir::ExprRepeat(..) | - hir::ExprInlineAsm(..) | hir::ExprBox(..) => { - Ok(self.cat_rvalue_node(expr.id(), expr.span(), expr_ty)) + hir::ExprKind::AddrOf(..) | hir::ExprKind::Call(..) | + hir::ExprKind::Assign(..) | hir::ExprKind::AssignOp(..) | + hir::ExprKind::Closure(..) | hir::ExprKind::Ret(..) | + hir::ExprKind::Unary(..) | hir::ExprKind::Yield(..) | + hir::ExprKind::MethodCall(..) | hir::ExprKind::Cast(..) | + hir::ExprKind::Array(..) | hir::ExprKind::Tup(..) | hir::ExprKind::If(..) | + hir::ExprKind::Binary(..) | hir::ExprKind::While(..) | + hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) | + hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) | + hir::ExprKind::Continue(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) | + hir::ExprKind::InlineAsm(..) | hir::ExprKind::Box(..) => { + Ok(self.cat_rvalue_node(expr.hir_id, expr.span, expr_ty)) } } } pub fn cat_def(&self, - id: ast::NodeId, + hir_id: hir::HirId, span: Span, expr_ty: Ty<'tcx>, def: Def) -> McResult> { - debug!("cat_def: id={} expr={:?} def={:?}", - id, expr_ty, def); + debug!("cat_def: id={:?} expr={:?} def={:?}", + hir_id, expr_ty, def); match def { Def::StructCtor(..) | Def::VariantCtor(..) | Def::Const(..) | Def::AssociatedConst(..) | Def::Fn(..) | Def::Method(..) => { - Ok(self.cat_rvalue_node(id, span, expr_ty)) + Ok(self.cat_rvalue_node(hir_id, span, expr_ty)) } Def::Static(def_id, mutbl) => { // `#[thread_local]` statics may not outlive the current function. for attr in &self.tcx.get_attrs(def_id)[..] { if attr.check_name("thread_local") { - return Ok(self.cat_rvalue_node(id, span, expr_ty)); + return Ok(self.cat_rvalue_node(hir_id, span, expr_ty)); } } Ok(cmt_ { - id:id, + hir_id, span:span, cat:Categorization::StaticItem, mutbl: if mutbl { McDeclared } else { McImmutable}, @@ -729,12 +730,12 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } Def::Upvar(var_id, _, fn_node_id) => { - self.cat_upvar(id, span, var_id, fn_node_id) + self.cat_upvar(hir_id, span, var_id, fn_node_id) } Def::Local(vid) => { Ok(cmt_ { - id, + hir_id, span, cat: Categorization::Local(vid), mutbl: MutabilityCategory::from_local(self.tcx, self.tables, vid), @@ -750,7 +751,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // Categorize an upvar, complete with invisible derefs of closure // environment and upvar reference as appropriate. fn cat_upvar(&self, - id: ast::NodeId, + hir_id: hir::HirId, span: Span, var_id: ast::NodeId, fn_node_id: ast::NodeId) @@ -817,7 +818,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // from the environment (perhaps we should eventually desugar // this field further, but it will do for now). let cmt_result = cmt_ { - id, + hir_id, span, cat: Categorization::Upvar(Upvar {id: upvar_id, kind: kind}), mutbl: var_mutbl, @@ -833,10 +834,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { cmt_result } ty::ClosureKind::FnMut => { - self.env_deref(id, span, upvar_id, var_mutbl, ty::MutBorrow, cmt_result) + self.env_deref(hir_id, span, upvar_id, var_mutbl, ty::MutBorrow, cmt_result) } ty::ClosureKind::Fn => { - self.env_deref(id, span, upvar_id, var_mutbl, ty::ImmBorrow, cmt_result) + self.env_deref(hir_id, span, upvar_id, var_mutbl, ty::ImmBorrow, cmt_result) } }; @@ -851,7 +852,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ty::UpvarCapture::ByRef(upvar_borrow) => { let ptr = BorrowedPtr(upvar_borrow.kind, upvar_borrow.region); cmt_ { - id, + hir_id, span, cat: Categorization::Deref(Rc::new(cmt_result), ptr), mutbl: MutabilityCategory::from_borrow_kind(upvar_borrow.kind), @@ -867,7 +868,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } fn env_deref(&self, - id: ast::NodeId, + hir_id: hir::HirId, span: Span, upvar_id: ty::UpvarId, upvar_mutbl: MutabilityCategory, @@ -911,7 +912,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } let ret = cmt_ { - id, + hir_id, span, cat: Categorization::Deref(Rc::new(cmt_result), env_ptr), mutbl: deref_mutbl, @@ -935,20 +936,35 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } pub fn cat_rvalue_node(&self, - id: ast::NodeId, + hir_id: hir::HirId, span: Span, expr_ty: Ty<'tcx>) -> cmt_<'tcx> { - let hir_id = self.tcx.hir.node_to_hir_id(id); + debug!( + "cat_rvalue_node(id={:?}, span={:?}, expr_ty={:?})", + hir_id, + span, + expr_ty, + ); let promotable = self.rvalue_promotable_map.as_ref().map(|m| m.contains(&hir_id.local_id)) .unwrap_or(false); + debug!( + "cat_rvalue_node: promotable = {:?}", + promotable, + ); + // Always promote `[T; 0]` (even when e.g. borrowed mutably). let promotable = match expr_ty.sty { - ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true, + ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true, _ => promotable, }; + debug!( + "cat_rvalue_node: promotable = {:?} (2)", + promotable, + ); + // Compute maximum lifetime of this rvalue. This is 'static if // we can promote to a constant, otherwise equal to enclosing temp // lifetime. @@ -957,18 +973,18 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { } else { self.temporary_scope(hir_id.local_id) }; - let ret = self.cat_rvalue(id, span, re, expr_ty); + let ret = self.cat_rvalue(hir_id, span, re, expr_ty); debug!("cat_rvalue_node ret {:?}", ret); ret } pub fn cat_rvalue(&self, - cmt_id: ast::NodeId, + cmt_hir_id: hir::HirId, span: Span, temp_scope: ty::Region<'tcx>, expr_ty: Ty<'tcx>) -> cmt_<'tcx> { let ret = cmt_ { - id:cmt_id, + hir_id: cmt_hir_id, span:span, cat:Categorization::Rvalue(temp_scope), mutbl:McDeclared, @@ -979,18 +995,19 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - pub fn cat_field(&self, + pub fn cat_field(&self, node: &N, base_cmt: cmt<'tcx>, f_index: usize, - f_name: Name, + f_ident: ast::Ident, f_ty: Ty<'tcx>) -> cmt_<'tcx> { let ret = cmt_ { - id: node.id(), + hir_id: node.hir_id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), - cat: Categorization::Interior(base_cmt, InteriorField(FieldIndex(f_index, f_name))), + cat: Categorization::Interior(base_cmt, + InteriorField(FieldIndex(f_index, f_ident.name))), ty: f_ty, note: NoteNone }; @@ -998,12 +1015,18 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - fn cat_overloaded_place(&self, - expr: &hir::Expr, - base: &hir::Expr, - implicit: bool) - -> McResult> { - debug!("cat_overloaded_place: implicit={}", implicit); + fn cat_overloaded_place( + &self, + expr: &hir::Expr, + base: &hir::Expr, + note: Note, + ) -> McResult> { + debug!( + "cat_overloaded_place(expr={:?}, base={:?}, note={:?})", + expr, + base, + note, + ); // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for @@ -1012,7 +1035,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let base_ty = self.expr_ty_adjusted(base)?; let (region, mutbl) = match base_ty.sty { - ty::TyRef(region, mt) => (region, mt.mutbl), + ty::TyRef(region, _, mutbl) => (region, mutbl), _ => { span_bug!(expr.span, "cat_overloaded_place: base is not a reference") } @@ -1022,15 +1045,16 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { mutbl, }); - let base_cmt = Rc::new(self.cat_rvalue_node(expr.id, expr.span, ref_ty)); - self.cat_deref(expr, base_cmt, implicit) + let base_cmt = Rc::new(self.cat_rvalue_node(expr.hir_id, expr.span, ref_ty)); + self.cat_deref(expr, base_cmt, note) } - pub fn cat_deref(&self, - node: &N, - base_cmt: cmt<'tcx>, - implicit: bool) - -> McResult> { + pub fn cat_deref( + &self, + node: &impl HirNode, + base_cmt: cmt<'tcx>, + note: Note, + ) -> McResult> { debug!("cat_deref: base_cmt={:?}", base_cmt); let base_cmt_ty = base_cmt.ty; @@ -1046,26 +1070,26 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { let ptr = match base_cmt.ty.sty { ty::TyAdt(def, ..) if def.is_box() => Unique, ty::TyRawPtr(ref mt) => UnsafePtr(mt.mutbl), - ty::TyRef(r, mt) => { - let bk = ty::BorrowKind::from_mutbl(mt.mutbl); - if implicit { Implicit(bk, r) } else { BorrowedPtr(bk, r) } + ty::TyRef(r, _, mutbl) => { + let bk = ty::BorrowKind::from_mutbl(mutbl); + BorrowedPtr(bk, r) } ref ty => bug!("unexpected type in cat_deref: {:?}", ty) }; let ret = cmt_ { - id: node.id(), + hir_id: node.hir_id(), span: node.span(), // For unique ptrs, we inherit mutability from the owning reference. mutbl: MutabilityCategory::from_pointer_kind(base_cmt.mutbl, ptr), cat: Categorization::Deref(base_cmt, ptr), ty: deref_ty, - note: NoteNone + note: note, }; debug!("cat_deref ret {:?}", ret); Ok(ret) } - fn cat_index(&self, + fn cat_index(&self, elt: &N, base_cmt: cmt<'tcx>, element_ty: Ty<'tcx>, @@ -1085,7 +1109,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { //! presuming that `base_cmt` is not of fixed-length type. //! //! # Parameters - //! - `elt`: the AST node being indexed + //! - `elt`: the HIR node being indexed //! - `base_cmt`: the cmt of `elt` let interior_elem = InteriorElement(context); @@ -1094,14 +1118,14 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { return Ok(ret); } - pub fn cat_imm_interior(&self, + pub fn cat_imm_interior(&self, node: &N, base_cmt: cmt<'tcx>, interior_ty: Ty<'tcx>, interior: InteriorKind) -> cmt_<'tcx> { let ret = cmt_ { - id: node.id(), + hir_id: node.hir_id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), cat: Categorization::Interior(base_cmt, interior), @@ -1112,7 +1136,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ret } - pub fn cat_downcast_if_needed(&self, + pub fn cat_downcast_if_needed(&self, node: &N, base_cmt: cmt<'tcx>, variant_did: DefId) @@ -1122,7 +1146,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { if self.tcx.adt_def(base_did).variants.len() != 1 { let base_ty = base_cmt.ty; let ret = Rc::new(cmt_ { - id: node.id(), + hir_id: node.hir_id(), span: node.span(), mutbl: base_cmt.mutbl.inherit(), cat: Categorization::Downcast(base_cmt, variant_did), @@ -1172,6 +1196,8 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // value, and I consider them to produce the value that was // matched. So if you have something like: // + // (FIXME: `@@3` is not legal code anymore!) + // // let x = @@3; // match x { // @@y { ... } @@ -1192,7 +1218,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // step out of sync again. So you'll see below that we always // get the type of the *subpattern* and use that. - debug!("cat_pattern: {:?} cmt={:?}", pat, cmt); + debug!("cat_pattern(pat={:?}, cmt={:?})", pat, cmt); // If (pattern) adjustments are active for this pattern, adjust the `cmt` correspondingly. // `cmt`s are constructed differently from patterns. For example, in @@ -1230,10 +1256,13 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { .pat_adjustments() .get(pat.hir_id) .map(|v| v.len()) - .unwrap_or(0) { - cmt = Rc::new(self.cat_deref(pat, cmt, true /* implicit */)?); + .unwrap_or(0) + { + debug!("cat_pattern: applying adjustment to cmt={:?}", cmt); + cmt = Rc::new(self.cat_deref(pat, cmt, NoteNone)?); } let cmt = cmt; // lose mutability + debug!("cat_pattern: applied adjustment derefs to get cmt={:?}", cmt); // Invoke the callback, but only now, after the `cmt` has adjusted. // @@ -1276,7 +1305,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { - let subpat_ty = self.pat_ty(&subpat)?; // see (*2) + let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2) let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); let subcmt = Rc::new(self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior)); self.cat_pattern_(subcmt, &subpat, op)?; @@ -1299,10 +1328,10 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { }; for fp in field_pats { - let field_ty = self.pat_ty(&fp.node.pat)?; // see (*2) + let field_ty = self.pat_ty_adjusted(&fp.node.pat)?; // see (*2) let f_index = self.tcx.field_index(fp.node.id, self.tables); - let cmt_field = - Rc::new(self.cat_field(pat, cmt.clone(), f_index, fp.node.name, field_ty)); + let cmt_field = Rc::new(self.cat_field(pat, cmt.clone(), f_index, + fp.node.ident, field_ty)); self.cat_pattern_(cmt_field, &fp.node.pat, op)?; } } @@ -1318,7 +1347,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { ref ty => span_bug!(pat.span, "tuple pattern unexpected type {:?}", ty), }; for (i, subpat) in subpats.iter().enumerate_and_adjust(expected_len, ddpos) { - let subpat_ty = self.pat_ty(&subpat)?; // see (*2) + let subpat_ty = self.pat_ty_adjusted(&subpat)?; // see (*2) let interior = InteriorField(FieldIndex(i, Name::intern(&i.to_string()))); let subcmt = Rc::new(self.cat_imm_interior(pat, cmt.clone(), subpat_ty, interior)); self.cat_pattern_(subcmt, &subpat, op)?; @@ -1329,7 +1358,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> { // box p1, &p1, &mut p1. we can ignore the mutability of // PatKind::Ref since that information is already contained // in the type. - let subcmt = Rc::new(self.cat_deref(pat, cmt, false)?); + let subcmt = Rc::new(self.cat_deref(pat, cmt, NoteNone)?); self.cat_pattern_(subcmt, &subpat, op)?; } @@ -1390,7 +1419,6 @@ impl<'tcx> cmt_<'tcx> { Categorization::Local(..) | Categorization::Deref(_, UnsafePtr(..)) | Categorization::Deref(_, BorrowedPtr(..)) | - Categorization::Deref(_, Implicit(..)) | Categorization::Upvar(..) => { (*self).clone() } @@ -1410,9 +1438,7 @@ impl<'tcx> cmt_<'tcx> { match self.cat { Categorization::Deref(ref b, BorrowedPtr(ty::MutBorrow, _)) | - Categorization::Deref(ref b, Implicit(ty::MutBorrow, _)) | Categorization::Deref(ref b, BorrowedPtr(ty::UniqueImmBorrow, _)) | - Categorization::Deref(ref b, Implicit(ty::UniqueImmBorrow, _)) | Categorization::Deref(ref b, Unique) | Categorization::Downcast(ref b, _) | Categorization::Interior(ref b, _) => { @@ -1435,8 +1461,7 @@ impl<'tcx> cmt_<'tcx> { } } - Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) | - Categorization::Deref(_, Implicit(ty::ImmBorrow, _)) => { + Categorization::Deref(_, BorrowedPtr(ty::ImmBorrow, _)) => { FreelyAliasable(AliasableBorrowed) } } @@ -1459,7 +1484,7 @@ impl<'tcx> cmt_<'tcx> { _ => bug!() }) } - NoteNone => None + NoteIndex | NoteNone => None } } @@ -1486,9 +1511,6 @@ impl<'tcx> cmt_<'tcx> { Some(_) => bug!(), None => { match pk { - Implicit(..) => { - format!("indexed content") - } Unique => { format!("`Box` content") } @@ -1496,7 +1518,10 @@ impl<'tcx> cmt_<'tcx> { format!("dereference of raw pointer") } BorrowedPtr(..) => { - format!("borrowed content") + match self.note { + NoteIndex => format!("indexed content"), + _ => format!("borrowed content"), + } } } } @@ -1524,12 +1549,9 @@ impl<'tcx> cmt_<'tcx> { pub fn ptr_sigil(ptr: PointerKind) -> &'static str { match ptr { Unique => "Box", - BorrowedPtr(ty::ImmBorrow, _) | - Implicit(ty::ImmBorrow, _) => "&", - BorrowedPtr(ty::MutBorrow, _) | - Implicit(ty::MutBorrow, _) => "&mut", - BorrowedPtr(ty::UniqueImmBorrow, _) | - Implicit(ty::UniqueImmBorrow, _) => "&unique", + BorrowedPtr(ty::ImmBorrow, _) => "&", + BorrowedPtr(ty::MutBorrow, _) => "&mut", + BorrowedPtr(ty::UniqueImmBorrow, _) => "&unique", UnsafePtr(_) => "*", } } diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs index 0aeb15b49fbbd..19c82d7d27c79 100644 --- a/src/librustc/middle/reachable.rs +++ b/src/librustc/middle/reachable.rs @@ -15,13 +15,13 @@ // makes all other generics or inline functions that it references // reachable as well. -use hir::TransFnAttrs; +use hir::CodegenFnAttrs; use hir::map as hir_map; use hir::def::Def; use hir::def_id::{DefId, CrateNum}; use rustc_data_structures::sync::Lrc; -use ty::{self, TyCtxt}; -use ty::maps::Providers; +use ty::{self, TyCtxt, GenericParamDefKind}; +use ty::query::Providers; use middle::privacy; use session::config; use util::nodemap::{NodeSet, FxHashSet}; @@ -37,21 +37,30 @@ use hir::intravisit; // Returns true if the given set of generics implies that the item it's // associated with must be inlined. -fn generics_require_inlining(generics: &hir::Generics) -> bool { - generics.params.iter().any(|param| param.is_type_param()) +fn generics_require_inlining(generics: &ty::Generics) -> bool { + for param in &generics.params { + match param.kind { + GenericParamDefKind::Lifetime { .. } => {} + GenericParamDefKind::Type { .. } => return true, + } + } + false } // Returns true if the given item must be inlined because it may be // monomorphized or it was marked with `#[inline]`. This will only return // true for functions. -fn item_might_be_inlined(item: &hir::Item, attrs: TransFnAttrs) -> bool { +fn item_might_be_inlined(tcx: TyCtxt<'a, 'tcx, 'tcx>, + item: &hir::Item, + attrs: CodegenFnAttrs) -> bool { if attrs.requests_inline() { return true } match item.node { - hir::ItemImpl(_, _, _, ref generics, ..) | - hir::ItemFn(.., ref generics, _) => { + hir::ItemKind::Impl(..) | + hir::ItemKind::Fn(..) => { + let generics = tcx.generics_of(tcx.hir.local_def_id(item.id)); generics_require_inlining(generics) } _ => false, @@ -61,15 +70,15 @@ fn item_might_be_inlined(item: &hir::Item, attrs: TransFnAttrs) -> bool { fn method_might_be_inlined<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem, impl_src: DefId) -> bool { - let trans_fn_attrs = tcx.trans_fn_attrs(impl_item.hir_id.owner_def_id()); - if trans_fn_attrs.requests_inline() || - generics_require_inlining(&impl_item.generics) { + let codegen_fn_attrs = tcx.codegen_fn_attrs(impl_item.hir_id.owner_def_id()); + let generics = tcx.generics_of(tcx.hir.local_def_id(impl_item.id)); + if codegen_fn_attrs.requests_inline() || generics_require_inlining(generics) { return true } if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_src) { match tcx.hir.find(impl_node_id) { Some(hir_map::NodeItem(item)) => - item_might_be_inlined(&item, trans_fn_attrs), + item_might_be_inlined(tcx, &item, codegen_fn_attrs), Some(..) | None => span_bug!(impl_item.span, "impl did is not an item") } @@ -107,11 +116,11 @@ impl<'a, 'tcx> Visitor<'tcx> for ReachableContext<'a, 'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr) { let def = match expr.node { - hir::ExprPath(ref qpath) => { + hir::ExprKind::Path(ref qpath) => { Some(self.tables.qpath_def(qpath, expr.hir_id)) } - hir::ExprMethodCall(..) => { - Some(self.tables.type_dependent_defs()[expr.hir_id]) + hir::ExprKind::MethodCall(..) => { + self.tables.type_dependent_defs().get(expr.hir_id).cloned() } _ => None }; @@ -162,8 +171,8 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match self.tcx.hir.find(node_id) { Some(hir_map::NodeItem(item)) => { match item.node { - hir::ItemFn(..) => - item_might_be_inlined(&item, self.tcx.trans_fn_attrs(def_id)), + hir::ItemKind::Fn(..) => + item_might_be_inlined(self.tcx, &item, self.tcx.codegen_fn_attrs(def_id)), _ => false, } } @@ -179,8 +188,9 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match impl_item.node { hir::ImplItemKind::Const(..) => true, hir::ImplItemKind::Method(..) => { - let attrs = self.tcx.trans_fn_attrs(def_id); - if generics_require_inlining(&impl_item.generics) || + let attrs = self.tcx.codegen_fn_attrs(def_id); + let generics = self.tcx.generics_of(def_id); + if generics_require_inlining(&generics) || attrs.requests_inline() { true } else { @@ -192,13 +202,15 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // does too. let impl_node_id = self.tcx.hir.as_local_node_id(impl_did).unwrap(); match self.tcx.hir.expect_item(impl_node_id).node { - hir::ItemImpl(_, _, _, ref generics, ..) => { - generics_require_inlining(generics) + hir::ItemKind::Impl(..) => { + let generics = self.tcx.generics_of(impl_did); + generics_require_inlining(&generics) } _ => false } } } + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(_) => false, } } @@ -227,13 +239,13 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // If we are building an executable, only explicitly extern // types need to be exported. if let hir_map::NodeItem(item) = *node { - let reachable = if let hir::ItemFn(.., abi, _, _) = item.node { - abi != Abi::Rust + let reachable = if let hir::ItemKind::Fn(_, header, ..) = item.node { + header.abi != Abi::Rust } else { false }; let def_id = self.tcx.hir.local_def_id(item.id); - let is_extern = self.tcx.trans_fn_attrs(def_id).contains_extern_indicator(); + let is_extern = self.tcx.codegen_fn_attrs(def_id).contains_extern_indicator(); if reachable || is_extern { self.reachable_symbols.insert(search_item); } @@ -249,9 +261,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { match *node { hir_map::NodeItem(item) => { match item.node { - hir::ItemFn(.., body) => { + hir::ItemKind::Fn(.., body) => { let def_id = self.tcx.hir.local_def_id(item.id); - if item_might_be_inlined(&item, self.tcx.trans_fn_attrs(def_id)) { + if item_might_be_inlined(self.tcx, + &item, + self.tcx.codegen_fn_attrs(def_id)) { self.visit_nested_body(body); } } @@ -259,19 +273,27 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { // Reachable constants will be inlined into other crates // unconditionally, so we need to make sure that their // contents are also reachable. - hir::ItemConst(_, init) => { + hir::ItemKind::Const(_, init) => { self.visit_nested_body(init); } // These are normal, nothing reachable about these // inherently and their children are already in the // worklist, as determined by the privacy pass - hir::ItemExternCrate(_) | hir::ItemUse(..) | - hir::ItemTy(..) | hir::ItemStatic(..) | - hir::ItemMod(..) | hir::ItemForeignMod(..) | - hir::ItemImpl(..) | hir::ItemTrait(..) | hir::ItemTraitAlias(..) | - hir::ItemStruct(..) | hir::ItemEnum(..) | - hir::ItemUnion(..) | hir::ItemGlobalAsm(..) => {} + hir::ItemKind::ExternCrate(_) | + hir::ItemKind::Use(..) | + hir::ItemKind::Existential(..) | + hir::ItemKind::Ty(..) | + hir::ItemKind::Static(..) | + hir::ItemKind::Mod(..) | + hir::ItemKind::ForeignMod(..) | + hir::ItemKind::Impl(..) | + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) | + hir::ItemKind::Struct(..) | + hir::ItemKind::Enum(..) | + hir::ItemKind::Union(..) | + hir::ItemKind::GlobalAsm(..) => {} } } hir_map::NodeTraitItem(trait_method) => { @@ -298,10 +320,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> { self.visit_nested_body(body) } } + hir::ImplItemKind::Existential(..) | hir::ImplItemKind::Type(_) => {} } } - hir_map::NodeExpr(&hir::Expr { node: hir::ExprClosure(.., body, _, _), .. }) => { + hir_map::NodeExpr(&hir::Expr { node: hir::ExprKind::Closure(.., body, _, _), .. }) => { self.visit_nested_body(body); } // Nothing to recurse on for these @@ -342,11 +365,9 @@ impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for CollectPrivateImplItemsVisitor<'a, } // We need only trait impls here, not inherent impls, and only non-exported ones - if let hir::ItemImpl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node { + if let hir::ItemKind::Impl(.., Some(ref trait_ref), _, ref impl_item_refs) = item.node { if !self.access_levels.is_reachable(item.id) { - for impl_item_ref in impl_item_refs { - self.worklist.push(impl_item_ref.id.node_id); - } + self.worklist.extend(impl_item_refs.iter().map(|r| r.id.node_id)); let trait_def_id = match trait_ref.path.def { Def::Trait(def_id) => def_id, @@ -403,9 +424,7 @@ fn reachable_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, crate_num: CrateNum) -> // If other crates link to us, they're going to expect to be able to // use the lang items, so we need to be sure to mark them as // exported. - for (id, _) in &access_levels.map { - reachable_context.worklist.push(*id); - } + reachable_context.worklist.extend(access_levels.map.iter().map(|(id, _)| *id)); for item in tcx.lang_items().items().iter() { if let Some(did) = *item { if let Some(node_id) = tcx.hir.as_local_node_id(did) { diff --git a/src/librustc/middle/region.rs b/src/librustc/middle/region.rs index bfc9ff6660de9..ebdc9c922b1df 100644 --- a/src/librustc/middle/region.rs +++ b/src/librustc/middle/region.rs @@ -14,7 +14,7 @@ //! For more information about how MIR-based region-checking works, //! see the [rustc guide]. //! -//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir-borrowck.html +//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir/borrowck.html use ich::{StableHashingContext, NodeIdHashingMode}; use util::nodemap::{FxHashMap, FxHashSet}; @@ -22,13 +22,12 @@ use ty; use std::fmt; use std::mem; -use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::sync::Lrc; use syntax::codemap; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; use ty::TyCtxt; -use ty::maps::Providers; +use ty::query::Providers; use hir; use hir::def_id::DefId; @@ -280,6 +279,8 @@ impl Scope { } } +pub type ScopeDepth = u32; + /// The region scope tree encodes information about region relationships. #[derive(Default, Debug)] pub struct ScopeTree { @@ -297,7 +298,7 @@ pub struct ScopeTree { /// conditional expression or repeating block. (Note that the /// enclosing scope id for the block associated with a closure is /// the closure itself.) - parent_map: FxHashMap, + parent_map: FxHashMap, /// `var_map` maps from a variable or binding id to the block in /// which that variable is declared. @@ -415,11 +416,12 @@ pub struct Context { /// details. root_id: Option, - /// the scope that contains any new variables declared - var_parent: Option, + /// The scope that contains any new variables declared, plus its depth in + /// the scope tree. + var_parent: Option<(Scope, ScopeDepth)>, - /// region parent of expressions etc - parent: Option, + /// Region parent of expressions, etc., plus its depth in the scope tree. + parent: Option<(Scope, ScopeDepth)>, } struct RegionResolutionVisitor<'a, 'tcx: 'a> { @@ -457,7 +459,7 @@ struct RegionResolutionVisitor<'a, 'tcx: 'a> { } struct ExprLocatorVisitor { - id: ast::NodeId, + hir_id: hir::HirId, result: Option, expr_and_pat_count: usize, } @@ -474,7 +476,7 @@ impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor { self.expr_and_pat_count += 1; - if pat.id == self.id { + if pat.hir_id == self.hir_id { self.result = Some(self.expr_and_pat_count); } } @@ -492,14 +494,14 @@ impl<'tcx> Visitor<'tcx> for ExprLocatorVisitor { self.expr_and_pat_count, expr); - if expr.id == self.id { + if expr.hir_id == self.hir_id { self.result = Some(self.expr_and_pat_count); } } } impl<'tcx> ScopeTree { - pub fn record_scope_parent(&mut self, child: Scope, parent: Option) { + pub fn record_scope_parent(&mut self, child: Scope, parent: Option<(Scope, ScopeDepth)>) { debug!("{:?}.parent = {:?}", child, parent); if let Some(p) = parent { @@ -515,7 +517,7 @@ impl<'tcx> ScopeTree { pub fn each_encl_scope(&self, mut e:E) where E: FnMut(Scope, Scope) { for (&child, &parent) in &self.parent_map { - e(child, parent) + e(child, parent.0) } } @@ -542,18 +544,6 @@ impl<'tcx> ScopeTree { assert!(previous.is_none()); } - fn closure_is_enclosed_by(&self, - mut sub_closure: hir::ItemLocalId, - sup_closure: hir::ItemLocalId) -> bool { - loop { - if sub_closure == sup_closure { return true; } - match self.closure_tree.get(&sub_closure) { - Some(&s) => { sub_closure = s; } - None => { return false; } - } - } - } - fn record_var_scope(&mut self, var: hir::ItemLocalId, lifetime: Scope) { debug!("record_var_scope(sub={:?}, sup={:?})", var, lifetime); assert!(var != lifetime.item_local_id()); @@ -570,7 +560,7 @@ impl<'tcx> ScopeTree { pub fn opt_encl_scope(&self, id: Scope) -> Option { //! Returns the narrowest scope that encloses `id`, if any. - self.parent_map.get(&id).cloned() + self.parent_map.get(&id).cloned().map(|(p, _)| p) } #[allow(dead_code)] // used in cfg @@ -602,7 +592,7 @@ impl<'tcx> ScopeTree { // returned. let mut id = Scope::Node(expr_id); - while let Some(&p) = self.parent_map.get(&id) { + while let Some(&(p, _)) = self.parent_map.get(&id) { match p.data() { ScopeData::Destruction(..) => { debug!("temporary_scope({:?}) = {:?} [enclosing]", @@ -670,85 +660,61 @@ impl<'tcx> ScopeTree { } } - /// Finds the nearest common ancestor (if any) of two scopes. That is, finds the smallest - /// scope which is greater than or equal to both `scope_a` and `scope_b`. - pub fn nearest_common_ancestor(&self, - scope_a: Scope, - scope_b: Scope) - -> Scope { + /// Finds the nearest common ancestor of two scopes. That is, finds the + /// smallest scope which is greater than or equal to both `scope_a` and + /// `scope_b`. + pub fn nearest_common_ancestor(&self, scope_a: Scope, scope_b: Scope) -> Scope { if scope_a == scope_b { return scope_a; } - // Process the lists in tandem from the innermost scope, recording the - // scopes seen so far. The first scope that comes up for a second time - // is the nearest common ancestor. - // - // Note: another way to compute the nearest common ancestor is to get - // the full scope chain for both scopes and then compare the chains to - // find the first scope in a common tail. But getting a parent scope - // requires a hash table lookup, and we often have very long scope - // chains (10s or 100s of scopes) that only differ by a few elements at - // the start. So this algorithm is faster. - let mut ma = Some(scope_a); - let mut mb = Some(scope_b); - let mut seen_a: SmallVec<[Scope; 32]> = SmallVec::new(); - let mut seen_b: SmallVec<[Scope; 32]> = SmallVec::new(); - loop { - if let Some(a) = ma { - if seen_b.iter().position(|s| *s == a).is_some() { - return a; - } - seen_a.push(a); - ma = self.parent_map.get(&a).map(|s| *s); - } - - if let Some(b) = mb { - if seen_a.iter().position(|s| *s == b).is_some() { - return b; - } - seen_b.push(b); - mb = self.parent_map.get(&b).map(|s| *s); - } + let mut a = scope_a; + let mut b = scope_b; - if ma.is_none() && mb.is_none() { - break; - } + // Get the depth of each scope's parent. If either scope has no parent, + // it must be the root, which means we can stop immediately because the + // root must be the nearest common ancestor. (In practice, this is + // moderately common.) + let (parent_a, parent_a_depth) = match self.parent_map.get(&a) { + Some(pd) => *pd, + None => return a, + }; + let (parent_b, parent_b_depth) = match self.parent_map.get(&b) { + Some(pd) => *pd, + None => return b, }; - fn outermost_scope(parent_map: &FxHashMap, scope: Scope) -> Scope { - let mut scope = scope; - loop { - match parent_map.get(&scope) { - Some(&superscope) => scope = superscope, - None => break scope, - } - } - } - - // In this (rare) case, the two regions belong to completely different - // functions. Compare those fn for lexical nesting. The reasoning - // behind this is subtle. See the "Modeling closures" section of the - // README in infer::region_constraints for more details. - let a_root_scope = outermost_scope(&self.parent_map, scope_a); - let b_root_scope = outermost_scope(&self.parent_map, scope_b); - match (a_root_scope.data(), b_root_scope.data()) { - (ScopeData::Destruction(a_root_id), - ScopeData::Destruction(b_root_id)) => { - if self.closure_is_enclosed_by(a_root_id, b_root_id) { - // `a` is enclosed by `b`, hence `b` is the ancestor of everything in `a` - scope_b - } else if self.closure_is_enclosed_by(b_root_id, a_root_id) { - // `b` is enclosed by `a`, hence `a` is the ancestor of everything in `b` - scope_a - } else { - // neither fn encloses the other - bug!() - } + if parent_a_depth > parent_b_depth { + // `a` is lower than `b`. Move `a` up until it's at the same depth + // as `b`. The first move up is trivial because we already found + // `parent_a` above; the loop does the remaining N-1 moves. + a = parent_a; + for _ in 0..(parent_a_depth - parent_b_depth - 1) { + a = self.parent_map.get(&a).unwrap().0; } - _ => { - // root ids are always Node right now - bug!() + } else if parent_b_depth > parent_a_depth { + // `b` is lower than `a`. + b = parent_b; + for _ in 0..(parent_b_depth - parent_a_depth - 1) { + b = self.parent_map.get(&b).unwrap().0; } + } else { + // Both scopes are at the same depth, and we know they're not equal + // because that case was tested for at the top of this function. So + // we can trivially move them both up one level now. + assert!(parent_a_depth != 0); + a = parent_a; + b = parent_b; } + + // Now both scopes are at the same level. We move upwards in lockstep + // until they match. In practice, this loop is almost always executed + // zero times because `a` is almost always a direct ancestor of `b` or + // vice versa. + while a != b { + a = self.parent_map.get(&a).unwrap().0; + b = self.parent_map.get(&b).unwrap().0; + }; + + a } /// Assuming that the provided region was defined within this `ScopeTree`, @@ -812,11 +778,11 @@ impl<'tcx> ScopeTree { /// `scope` must be inside the body. pub fn yield_in_scope_for_expr(&self, scope: Scope, - expr: ast::NodeId, + expr_hir_id: hir::HirId, body: &'tcx hir::Body) -> Option { self.yield_in_scope(scope).and_then(|(span, count)| { let mut visitor = ExprLocatorVisitor { - id: expr, + hir_id: expr_hir_id, result: None, expr_and_pat_count: 0, }; @@ -847,7 +813,7 @@ fn record_var_lifetime(visitor: &mut RegionResolutionVisitor, // // extern fn isalnum(c: c_int) -> c_int } - Some(parent_scope) => + Some((parent_scope, _)) => visitor.scope_tree.record_var_scope(var_id, parent_scope), } } @@ -892,8 +858,8 @@ fn resolve_block<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk: // index information.) for (i, statement) in blk.stmts.iter().enumerate() { - if let hir::StmtDecl(..) = statement.node { - // Each StmtDecl introduces a subscope for bindings + if let hir::StmtKind::Decl(..) = statement.node { + // Each StmtKind::Decl introduces a subscope for bindings // introduced by the declaration; this subscope covers // a suffix of the block . Each subscope in a block // has the previous subscope in the block as a parent, @@ -977,39 +943,39 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: // scopes, meaning that temporaries cannot outlive them. // This ensures fixed size stacks. - hir::ExprBinary(codemap::Spanned { node: hir::BiAnd, .. }, _, ref r) | - hir::ExprBinary(codemap::Spanned { node: hir::BiOr, .. }, _, ref r) => { + hir::ExprKind::Binary(codemap::Spanned { node: hir::BinOpKind::And, .. }, _, ref r) | + hir::ExprKind::Binary(codemap::Spanned { node: hir::BinOpKind::Or, .. }, _, ref r) => { // For shortcircuiting operators, mark the RHS as a terminating // scope since it only executes conditionally. terminating(r.hir_id.local_id); } - hir::ExprIf(ref expr, ref then, Some(ref otherwise)) => { + hir::ExprKind::If(ref expr, ref then, Some(ref otherwise)) => { terminating(expr.hir_id.local_id); terminating(then.hir_id.local_id); terminating(otherwise.hir_id.local_id); } - hir::ExprIf(ref expr, ref then, None) => { + hir::ExprKind::If(ref expr, ref then, None) => { terminating(expr.hir_id.local_id); terminating(then.hir_id.local_id); } - hir::ExprLoop(ref body, _, _) => { + hir::ExprKind::Loop(ref body, _, _) => { terminating(body.hir_id.local_id); } - hir::ExprWhile(ref expr, ref body, _) => { + hir::ExprKind::While(ref expr, ref body, _) => { terminating(expr.hir_id.local_id); terminating(body.hir_id.local_id); } - hir::ExprMatch(..) => { + hir::ExprKind::Match(..) => { visitor.cx.var_parent = visitor.cx.parent; } - hir::ExprAssignOp(..) | hir::ExprIndex(..) | - hir::ExprUnary(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) => { + hir::ExprKind::AssignOp(..) | hir::ExprKind::Index(..) | + hir::ExprKind::Unary(..) | hir::ExprKind::Call(..) | hir::ExprKind::MethodCall(..) => { // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls // // The lifetimes for a call or method call look as follows: @@ -1037,7 +1003,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: match expr.node { // Manually recurse over closures, because they are the only // case of nested bodies that share the parent environment. - hir::ExprClosure(.., body, _, _) => { + hir::ExprKind::Closure(.., body, _, _) => { let body = visitor.tcx.hir.body(body); visitor.visit_body(body); } @@ -1049,7 +1015,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: debug!("resolve_expr post-increment {}, expr = {:?}", visitor.expr_and_pat_count, expr); - if let hir::ExprYield(..) = expr.node { + if let hir::ExprKind::Yield(..) = expr.node { // Mark this expr's scope and all parent scopes as containing `yield`. let mut scope = Scope::Node(expr.hir_id.local_id); loop { @@ -1059,7 +1025,7 @@ fn resolve_expr<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, expr: // Keep traversing up while we can. match visitor.scope_tree.parent_map.get(&scope) { // Don't cross from closure bodies to their parent. - Some(&superscope) => match superscope.data() { + Some(&(superscope, _)) => match superscope.data() { ScopeData::CallSite(_) => break, _ => scope = superscope }, @@ -1076,7 +1042,7 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, init: Option<&'tcx hir::Expr>) { debug!("resolve_local(pat={:?}, init={:?})", pat, init); - let blk_scope = visitor.cx.var_parent; + let blk_scope = visitor.cx.var_parent.map(|(p, _)| p); // As an exception to the normal rules governing temporary // lifetimes, initializers in a let have a temporary lifetime @@ -1227,27 +1193,27 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, blk_id: Option) { match expr.node { - hir::ExprAddrOf(_, ref subexpr) => { + hir::ExprKind::AddrOf(_, ref subexpr) => { record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id); record_rvalue_scope(visitor, &subexpr, blk_id); } - hir::ExprStruct(_, ref fields, _) => { + hir::ExprKind::Struct(_, ref fields, _) => { for field in fields { record_rvalue_scope_if_borrow_expr( visitor, &field.expr, blk_id); } } - hir::ExprArray(ref subexprs) | - hir::ExprTup(ref subexprs) => { + hir::ExprKind::Array(ref subexprs) | + hir::ExprKind::Tup(ref subexprs) => { for subexpr in subexprs { record_rvalue_scope_if_borrow_expr( visitor, &subexpr, blk_id); } } - hir::ExprCast(ref subexpr, _) => { + hir::ExprKind::Cast(ref subexpr, _) => { record_rvalue_scope_if_borrow_expr(visitor, &subexpr, blk_id) } - hir::ExprBlock(ref block) => { + hir::ExprKind::Block(ref block, _) => { if let Some(ref subexpr) = block.expr { record_rvalue_scope_if_borrow_expr( visitor, &subexpr, blk_id); @@ -1279,16 +1245,16 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, loop { // Note: give all the expressions matching `ET` with the // extended temporary lifetime, not just the innermost rvalue, - // because in trans if we must compile e.g. `*rvalue()` + // because in codegen if we must compile e.g. `*rvalue()` // into a temporary, we request the temporary scope of the // outer expression. visitor.scope_tree.record_rvalue_scope(expr.hir_id.local_id, blk_scope); match expr.node { - hir::ExprAddrOf(_, ref subexpr) | - hir::ExprUnary(hir::UnDeref, ref subexpr) | - hir::ExprField(ref subexpr, _) | - hir::ExprIndex(ref subexpr, _) => { + hir::ExprKind::AddrOf(_, ref subexpr) | + hir::ExprKind::Unary(hir::UnDeref, ref subexpr) | + hir::ExprKind::Field(ref subexpr, _) | + hir::ExprKind::Index(ref subexpr, _) => { expr = &subexpr; } _ => { @@ -1301,16 +1267,20 @@ fn resolve_local<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'a, 'tcx>, impl<'a, 'tcx> RegionResolutionVisitor<'a, 'tcx> { /// Records the current parent (if any) as the parent of `child_scope`. - fn record_child_scope(&mut self, child_scope: Scope) { + /// Returns the depth of `child_scope`. + fn record_child_scope(&mut self, child_scope: Scope) -> ScopeDepth { let parent = self.cx.parent; self.scope_tree.record_scope_parent(child_scope, parent); + // If `child_scope` has no parent, it must be the root node, and so has + // a depth of 1. Otherwise, its depth is one more than its parent's. + parent.map_or(1, |(_p, d)| d + 1) } /// Records the current parent (if any) as the parent of `child_scope`, /// and sets `child_scope` as the new current parent. fn enter_scope(&mut self, child_scope: Scope) { - self.record_child_scope(child_scope); - self.cx.parent = Some(child_scope); + let child_depth = self.record_child_scope(child_scope); + self.cx.parent = Some((child_scope, child_depth)); } fn enter_node_scope_with_dtor(&mut self, id: hir::ItemLocalId) { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index ceda72dcd7ae0..1309540717c2b 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -15,28 +15,27 @@ //! used between functions, and they operate in a purely top-down //! way. Therefore we break lifetime name resolution into a separate pass. -use hir::map::Map; use hir::def::Def; use hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; -use hir::ItemLocalId; -use hir::LifetimeName; -use ty::{self, TyCtxt}; +use hir::map::Map; +use hir::{GenericArg, GenericParam, ItemLocalId, LifetimeName, ParamName}; +use ty::{self, TyCtxt, GenericParamDefKind}; +use errors::DiagnosticBuilder; +use rustc::lint; +use rustc_data_structures::sync::Lrc; +use session::Session; use std::cell::Cell; use std::mem::replace; -use rustc_data_structures::sync::Lrc; use syntax::ast; use syntax::attr; use syntax::ptr::P; +use syntax::symbol::keywords; use syntax_pos::Span; -use errors::DiagnosticBuilder; use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap, NodeSet}; -use session::Session; -use std::slice; -use rustc::lint; -use hir::{self, GenericParamsExt}; use hir::intravisit::{self, NestedVisitorMap, Visitor}; +use hir::{self, GenericParamKind}; /// The origin of a named lifetime definition. /// @@ -50,11 +49,16 @@ pub enum LifetimeDefOrigin { } impl LifetimeDefOrigin { - fn from_is_in_band(is_in_band: bool) -> Self { - if is_in_band { - LifetimeDefOrigin::InBand - } else { - LifetimeDefOrigin::Explicit + fn from_param(param: &GenericParam) -> Self { + match param.kind { + GenericParamKind::Lifetime { in_band } => { + if in_band { + LifetimeDefOrigin::InBand + } else { + LifetimeDefOrigin::Explicit + } + } + _ => bug!("expected a lifetime param"), } } } @@ -84,30 +88,33 @@ pub enum Region { } impl Region { - fn early( - hir_map: &Map, - index: &mut u32, - def: &hir::LifetimeDef, - ) -> (hir::LifetimeName, Region) { + fn early(hir_map: &Map, index: &mut u32, param: &GenericParam) -> (ParamName, Region) { let i = *index; *index += 1; - let def_id = hir_map.local_def_id(def.lifetime.id); - let origin = LifetimeDefOrigin::from_is_in_band(def.in_band); + let def_id = hir_map.local_def_id(param.id); + let origin = LifetimeDefOrigin::from_param(param); debug!("Region::early: index={} def_id={:?}", i, def_id); - (def.lifetime.name, Region::EarlyBound(i, def_id, origin)) + (param.name.modern(), Region::EarlyBound(i, def_id, origin)) } - fn late(hir_map: &Map, def: &hir::LifetimeDef) -> (hir::LifetimeName, Region) { - let depth = ty::DebruijnIndex::new(1); - let def_id = hir_map.local_def_id(def.lifetime.id); - let origin = LifetimeDefOrigin::from_is_in_band(def.in_band); - (def.lifetime.name, Region::LateBound(depth, def_id, origin)) + fn late(hir_map: &Map, param: &GenericParam) -> (ParamName, Region) { + let depth = ty::INNERMOST; + let def_id = hir_map.local_def_id(param.id); + let origin = LifetimeDefOrigin::from_param(param); + debug!( + "Region::late: param={:?} depth={:?} def_id={:?} origin={:?}", + param, + depth, + def_id, + origin, + ); + (param.name.modern(), Region::LateBound(depth, def_id, origin)) } fn late_anon(index: &Cell) -> Region { let i = index.get(); index.set(i + 1); - let depth = ty::DebruijnIndex::new(1); + let depth = ty::INNERMOST; Region::LateBoundAnon(depth, i) } @@ -123,40 +130,35 @@ impl Region { fn shifted(self, amount: u32) -> Region { match self { - Region::LateBound(depth, id, origin) => { - Region::LateBound(depth.shifted(amount), id, origin) + Region::LateBound(debruijn, id, origin) => { + Region::LateBound(debruijn.shifted_in(amount), id, origin) } - Region::LateBoundAnon(depth, index) => { - Region::LateBoundAnon(depth.shifted(amount), index) + Region::LateBoundAnon(debruijn, index) => { + Region::LateBoundAnon(debruijn.shifted_in(amount), index) } _ => self, } } - fn from_depth(self, depth: u32) -> Region { + fn shifted_out_to_binder(self, binder: ty::DebruijnIndex) -> Region { match self { Region::LateBound(debruijn, id, origin) => Region::LateBound( - ty::DebruijnIndex { - depth: debruijn.depth - (depth - 1), - }, + debruijn.shifted_out_to_binder(binder), id, origin, ), Region::LateBoundAnon(debruijn, index) => Region::LateBoundAnon( - ty::DebruijnIndex { - depth: debruijn.depth - (depth - 1), - }, + debruijn.shifted_out_to_binder(binder), index, ), _ => self, } } - fn subst(self, params: &[hir::Lifetime], map: &NamedRegionMap) -> Option { + fn subst<'a, L>(self, mut params: L, map: &NamedRegionMap) -> Option + where L: Iterator { if let Region::EarlyBound(index, _, _) = self { - params - .get(index as usize) - .and_then(|lifetime| map.defs.get(&lifetime.id).cloned()) + params.nth(index as usize).and_then(|lifetime| map.defs.get(&lifetime.id).cloned()) } else { Some(self) } @@ -230,33 +232,34 @@ struct LifetimeContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, map: &'a mut NamedRegionMap, scope: ScopeRef<'a>, - // Deep breath. Our representation for poly trait refs contains a single - // binder and thus we only allow a single level of quantification. However, - // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` - // and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices - // correct when representing these constraints, we should only introduce one - // scope. However, we want to support both locations for the quantifier and - // during lifetime resolution we want precise information (so we can't - // desugar in an earlier phase). - - // SO, if we encounter a quantifier at the outer scope, we set - // trait_ref_hack to true (and introduce a scope), and then if we encounter - // a quantifier at the inner scope, we error. If trait_ref_hack is false, - // then we introduce the scope at the inner quantifier. - - // I'm sorry. + + /// Deep breath. Our representation for poly trait refs contains a single + /// binder and thus we only allow a single level of quantification. However, + /// the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` + /// and `for <'a, 'b> &'b T: Foo<'a>`. In order to get the de Bruijn indices + /// correct when representing these constraints, we should only introduce one + /// scope. However, we want to support both locations for the quantifier and + /// during lifetime resolution we want precise information (so we can't + /// desugar in an earlier phase). + /// + /// SO, if we encounter a quantifier at the outer scope, we set + /// trait_ref_hack to true (and introduce a scope), and then if we encounter + /// a quantifier at the inner scope, we error. If trait_ref_hack is false, + /// then we introduce the scope at the inner quantifier. + /// + /// I'm sorry. trait_ref_hack: bool, - // Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. + /// Used to disallow the use of in-band lifetimes in `fn` or `Fn` syntax. is_in_fn_syntax: bool, - // List of labels in the function/method currently under analysis. - labels_in_fn: Vec<(ast::Name, Span)>, + /// List of labels in the function/method currently under analysis. + labels_in_fn: Vec, - // Cache for cross-crate per-definition object lifetime defaults. + /// Cache for cross-crate per-definition object lifetime defaults. xcrate_object_lifetime_defaults: DefIdMap>, - lifetime_uses: DefIdMap>, + lifetime_uses: &'a mut DefIdMap>, } #[derive(Debug)] @@ -266,12 +269,17 @@ enum Scope<'a> { /// it should be shifted by the number of `Binder`s in between the /// declaration `Binder` and the location it's referenced from. Binder { - lifetimes: FxHashMap, + lifetimes: FxHashMap, /// if we extend this scope with another scope, what is the next index /// we should use for an early-bound region? next_early_index: u32, + /// Flag is set to true if, in this binder, `'_` would be + /// equivalent to a "single-use region". This is true on + /// impls, but not other kinds of items. + track_lifetime_uses: bool, + /// Whether or not this binder would serve as the parent /// binder for abstract types introduced within. For example: /// @@ -340,8 +348,8 @@ type ScopeRef<'a> = &'a Scope<'a>; const ROOT_SCOPE: ScopeRef<'static> = &Scope::Root; -pub fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { resolve_lifetimes, named_region_map: |tcx, id| { @@ -432,7 +440,7 @@ fn krate<'tcx>(tcx: TyCtxt<'_, 'tcx, 'tcx>) -> NamedRegionMap { is_in_fn_syntax: false, labels_in_fn: vec![], xcrate_object_lifetime_defaults: DefIdMap(), - lifetime_uses: DefIdMap(), + lifetime_uses: &mut DefIdMap(), }; for (_, item) in &krate.items { visitor.visit_item(item); @@ -468,21 +476,21 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { match item.node { - hir::ItemFn(ref decl, _, _, _, ref generics, _) => { + hir::ItemKind::Fn(ref decl, _, ref generics, _) => { self.visit_early_late(None, decl, generics, |this| { intravisit::walk_item(this, item); }); } - hir::ItemExternCrate(_) - | hir::ItemUse(..) - | hir::ItemMod(..) - | hir::ItemForeignMod(..) - | hir::ItemGlobalAsm(..) => { + hir::ItemKind::ExternCrate(_) + | hir::ItemKind::Use(..) + | hir::ItemKind::Mod(..) + | hir::ItemKind::ForeignMod(..) + | hir::ItemKind::GlobalAsm(..) => { // These sorts of items have no lifetime parameters at all. intravisit::walk_item(self, item); } - hir::ItemStatic(..) | hir::ItemConst(..) => { + hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => { // No lifetime parameters, but implied 'static. let scope = Scope::Elision { elide: Elide::Exact(Region::Static), @@ -490,28 +498,46 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |_, this| intravisit::walk_item(this, item)); } - hir::ItemTy(_, ref generics) - | hir::ItemEnum(_, ref generics) - | hir::ItemStruct(_, ref generics) - | hir::ItemUnion(_, ref generics) - | hir::ItemTrait(_, _, ref generics, ..) - | hir::ItemTraitAlias(ref generics, ..) - | hir::ItemImpl(_, _, _, ref generics, ..) => { + hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: Some(_), .. }) => { + // currently existential type declarations are just generated from impl Trait + // items. doing anything on this node is irrelevant, as we currently don't need + // it. + } + hir::ItemKind::Ty(_, ref generics) + | hir::ItemKind::Existential(hir::ExistTy { impl_trait_fn: None, ref generics, .. }) + | hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) + | hir::ItemKind::Trait(_, _, ref generics, ..) + | hir::ItemKind::TraitAlias(ref generics, ..) + | hir::ItemKind::Impl(_, _, _, ref generics, ..) => { + // Impls permit `'_` to be used and it is equivalent to "some fresh lifetime name". + // This is not true for other kinds of items.x + let track_lifetime_uses = match item.node { + hir::ItemKind::Impl(..) => true, + _ => false, + }; // These kinds of items have only early bound lifetime parameters. - let mut index = if let hir::ItemTrait(..) = item.node { + let mut index = if let hir::ItemKind::Trait(..) = item.node { 1 // Self comes before lifetimes } else { 0 }; - let lifetimes = generics - .lifetimes() - .map(|def| Region::early(&self.tcx.hir, &mut index, def)) - .collect(); - let next_early_index = index + generics.ty_params().count() as u32; + let mut type_count = 0; + let lifetimes = generics.params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + type_count += 1; + None + } + }).collect(); let scope = Scope::Binder { lifetimes, - next_early_index, + next_early_index: index + type_count, abstract_type_parent: true, + track_lifetime_uses, s: ROOT_SCOPE, }; self.with(scope, |old_scope, this| { @@ -524,34 +550,37 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) { match item.node { - hir::ForeignItemFn(ref decl, _, ref generics) => { + hir::ForeignItemKind::Fn(ref decl, _, ref generics) => { self.visit_early_late(None, decl, generics, |this| { intravisit::walk_foreign_item(this, item); }) } - hir::ForeignItemStatic(..) => { + hir::ForeignItemKind::Static(..) => { intravisit::walk_foreign_item(self, item); } - hir::ForeignItemType => { + hir::ForeignItemKind::Type => { intravisit::walk_foreign_item(self, item); } } } fn visit_ty(&mut self, ty: &'tcx hir::Ty) { - debug!("visit_ty: ty={:?}", ty); + debug!("visit_ty: id={:?} ty={:?}", ty.id, ty); match ty.node { - hir::TyBareFn(ref c) => { + hir::TyKind::BareFn(ref c) => { let next_early_index = self.next_early_index(); let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; let scope = Scope::Binder { - lifetimes: c.generic_params - .lifetimes() - .map(|def| Region::late(&self.tcx.hir, def)) - .collect(), + lifetimes: c.generic_params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir, param)) + } + _ => None, + }).collect(), s: self.scope, next_early_index, + track_lifetime_uses: true, abstract_type_parent: false, }; self.with(scope, |old_scope, this| { @@ -562,7 +591,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }); self.is_in_fn_syntax = was_in_fn_syntax; } - hir::TyTraitObject(ref bounds, ref lifetime) => { + hir::TyKind::TraitObject(ref bounds, ref lifetime) => { for bound in bounds { self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); } @@ -580,15 +609,15 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { // resolved the same as the `'_` in `&'_ Foo`. // // cc #48468 - self.resolve_elided_lifetimes(slice::from_ref(lifetime), false) + self.resolve_elided_lifetimes(vec![lifetime]) } - LifetimeName::Fresh(_) | LifetimeName::Static | LifetimeName::Name(_) => { + LifetimeName::Param(_) | LifetimeName::Static => { // If the user wrote an explicit name, use that. self.visit_lifetime(lifetime); } } } - hir::TyRptr(ref lifetime_ref, ref mt) => { + hir::TyKind::Rptr(ref lifetime_ref, ref mt) => { self.visit_lifetime(lifetime_ref); let scope = Scope::ObjectLifetimeDefault { lifetime: self.map.defs.get(&lifetime_ref.id).cloned(), @@ -596,105 +625,140 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { }; self.with(scope, |_, this| this.visit_ty(&mt.ty)); } - hir::TyImplTraitExistential(ref exist_ty, ref lifetimes) => { - // Resolve the lifetimes that are applied to the existential type. - // These are resolved in the current scope. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `fn foo<'a>() -> MyAnonTy<'a> { ... }` - // ^ ^this gets resolved in the current scope - for lifetime in lifetimes { - self.visit_lifetime(lifetime); + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { + if let Def::Existential(exist_ty_did) = path.def { + let id = self.tcx.hir.as_local_node_id(exist_ty_did).unwrap(); + + // Resolve the lifetimes in the bounds to the lifetime defs in the generics. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `abstract type MyAnonTy<'b>: MyTrait<'b>;` + // ^ ^ this gets resolved in the scope of + // the exist_ty generics + let (generics, bounds) = match self.tcx.hir.expect_item(id).node { + // named existential types don't need these hacks + hir::ItemKind::Existential(hir::ExistTy{ impl_trait_fn: None, .. }) => { + intravisit::walk_ty(self, ty); + return; + }, + hir::ItemKind::Existential(hir::ExistTy{ + ref generics, + ref bounds, + .. + }) => ( + generics, + bounds, + ), + ref i => bug!("impl Trait pointed to non-existential type?? {:#?}", i), + }; - // Check for predicates like `impl for<'a> SomeTrait>` - // and ban them. Type variables instantiated inside binders aren't - // well-supported at the moment, so this doesn't work. - // In the future, this should be fixed and this error should be removed. - let def = self.map.defs.get(&lifetime.id); - if let Some(&Region::LateBound(_, def_id, _)) = def { - if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { - // Ensure that the parent of the def is an item, not HRTB - let parent_id = self.tcx.hir.get_parent_node(node_id); - let parent_impl_id = hir::ImplItemId { node_id: parent_id }; - let parent_trait_id = hir::TraitItemId { node_id: parent_id }; - let krate = self.tcx.hir.forest.krate(); - if !(krate.items.contains_key(&parent_id) - || krate.impl_items.contains_key(&parent_impl_id) - || krate.trait_items.contains_key(&parent_trait_id)) - { - span_err!( - self.tcx.sess, - lifetime.span, - E0657, - "`impl Trait` can only capture lifetimes \ - bound at the fn or impl level" - ); + assert!(exist_ty_did.is_local()); + // Resolve the lifetimes that are applied to the existential type. + // These are resolved in the current scope. + // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to + // `fn foo<'a>() -> MyAnonTy<'a> { ... }` + // ^ ^this gets resolved in the current scope + for lifetime in &path.segments[0].args.as_ref().unwrap().args { + if let hir::GenericArg::Lifetime(lifetime) = lifetime { + self.visit_lifetime(lifetime); + + // Check for predicates like `impl for<'a> Trait>` + // and ban them. Type variables instantiated inside binders aren't + // well-supported at the moment, so this doesn't work. + // In the future, this should be fixed and this error should be removed. + let def = self.map.defs.get(&lifetime.id).cloned(); + if let Some(Region::LateBound(_, def_id, _)) = def { + if let Some(node_id) = self.tcx.hir.as_local_node_id(def_id) { + // Ensure that the parent of the def is an item, not HRTB + let parent_id = self.tcx.hir.get_parent_node(node_id); + let parent_impl_id = hir::ImplItemId { node_id: parent_id }; + let parent_trait_id = hir::TraitItemId { node_id: parent_id }; + let krate = self.tcx.hir.forest.krate(); + if !(krate.items.contains_key(&parent_id) + || krate.impl_items.contains_key(&parent_impl_id) + || krate.trait_items.contains_key(&parent_trait_id)) + { + span_err!( + self.tcx.sess, + lifetime.span, + E0657, + "`impl Trait` can only capture lifetimes \ + bound at the fn or impl level" + ); + self.uninsert_lifetime_on_error(lifetime, def.unwrap()); + } + } } } } - } - // Resolve the lifetimes in the bounds to the lifetime defs in the generics. - // `fn foo<'a>() -> impl MyTrait<'a> { ... }` desugars to - // `abstract type MyAnonTy<'b>: MyTrait<'b>;` - // ^ ^ this gets resolved in the scope of - // the exist_ty generics - let hir::ExistTy { - ref generics, - ref bounds, - } = *exist_ty; - - // We want to start our early-bound indices at the end of the parent scope, - // not including any parent `impl Trait`s. - let mut index = self.next_early_index_for_abstract_type(); - debug!("visit_ty: index = {}", index); - - let mut elision = None; - let mut lifetimes = FxHashMap(); - for lt_def in generics.lifetimes() { - let (lt_name, region) = Region::early(&self.tcx.hir, &mut index, <_def); - if let hir::LifetimeName::Underscore = lt_name { - // Pick the elided lifetime "definition" if one exists and use it to make an - // elision scope. - elision = Some(region); - } else { - lifetimes.insert(lt_name, region); + // We want to start our early-bound indices at the end of the parent scope, + // not including any parent `impl Trait`s. + let mut index = self.next_early_index_for_abstract_type(); + debug!("visit_ty: index = {}", index); + + let mut elision = None; + let mut lifetimes = FxHashMap(); + let mut type_count = 0; + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => { + let (name, reg) = Region::early(&self.tcx.hir, &mut index, ¶m); + if let hir::ParamName::Plain(param_name) = name { + if param_name.name == keywords::UnderscoreLifetime.name() { + // Pick the elided lifetime "definition" if one exists + // and use it to make an elision scope. + elision = Some(reg); + } else { + lifetimes.insert(name, reg); + } + } else { + lifetimes.insert(name, reg); + } + } + GenericParamKind::Type { .. } => { + type_count += 1; + } + } } - } + let next_early_index = index + type_count; - let next_early_index = index + generics.ty_params().count() as u32; - - if let Some(elision_region) = elision { - let scope = Scope::Elision { - elide: Elide::Exact(elision_region), - s: self.scope, - }; - self.with(scope, |_old_scope, this| { + if let Some(elision_region) = elision { + let scope = Scope::Elision { + elide: Elide::Exact(elision_region), + s: self.scope, + }; + self.with(scope, |_old_scope, this| { + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: this.scope, + track_lifetime_uses: true, + abstract_type_parent: false, + }; + this.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + }); + } else { let scope = Scope::Binder { lifetimes, next_early_index, - s: this.scope, + s: self.scope, + track_lifetime_uses: true, abstract_type_parent: false, }; - this.with(scope, |_old_scope, this| { + self.with(scope, |_old_scope, this| { this.visit_generics(generics); for bound in bounds { - this.visit_ty_param_bound(bound); + this.visit_param_bound(bound); } }); - }); + } } else { - let scope = Scope::Binder { - lifetimes, - next_early_index, - s: self.scope, - abstract_type_parent: false, - }; - self.with(scope, |_old_scope, this| { - this.visit_generics(generics); - for bound in bounds { - this.visit_ty_param_bound(bound); - } - }); + intravisit::walk_ty(self, ty) } } _ => intravisit::walk_ty(self, ty), @@ -717,22 +781,27 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { let generics = &trait_item.generics; let mut index = self.next_early_index(); debug!("visit_ty: index = {}", index); - let lifetimes = generics - .lifetimes() - .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def)) - .collect(); - - let next_early_index = index + generics.ty_params().count() as u32; + let mut type_count = 0; + let lifetimes = generics.params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + type_count += 1; + None + } + }).collect(); let scope = Scope::Binder { lifetimes, - next_early_index, + next_early_index: index + type_count, s: self.scope, + track_lifetime_uses: true, abstract_type_parent: true, }; self.with(scope, |_old_scope, this| { this.visit_generics(generics); for bound in bounds { - this.visit_ty_param_bound(bound); + this.visit_param_bound(bound); } if let Some(ty) = ty { this.visit_ty(ty); @@ -762,17 +831,22 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { Type(ref ty) => { let generics = &impl_item.generics; let mut index = self.next_early_index(); + let mut next_early_index = index; debug!("visit_ty: index = {}", index); - let lifetimes = generics - .lifetimes() - .map(|lt_def| Region::early(&self.tcx.hir, &mut index, lt_def)) - .collect(); - - let next_early_index = index + generics.ty_params().count() as u32; + let lifetimes = generics.params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + next_early_index += 1; + None + } + }).collect(); let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope, + track_lifetime_uses: true, abstract_type_parent: true, }; self.with(scope, |_old_scope, this| { @@ -780,6 +854,35 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { this.visit_ty(ty); }); } + Existential(ref bounds) => { + let generics = &impl_item.generics; + let mut index = self.next_early_index(); + let mut next_early_index = index; + debug!("visit_ty: index = {}", index); + let lifetimes = generics.params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::early(&self.tcx.hir, &mut index, param)) + } + GenericParamKind::Type { .. } => { + next_early_index += 1; + None + } + }).collect(); + + let scope = Scope::Binder { + lifetimes, + next_early_index, + s: self.scope, + track_lifetime_uses: true, + abstract_type_parent: true, + }; + self.with(scope, |_old_scope, this| { + this.visit_generics(generics); + for bound in bounds { + this.visit_param_bound(bound); + } + }); + } Const(_, _) => { // Only methods and types support generics. assert!(impl_item.generics.params.is_empty()); @@ -790,7 +893,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime) { if lifetime_ref.is_elided() { - self.resolve_elided_lifetimes(slice::from_ref(lifetime_ref), false); + self.resolve_elided_lifetimes(vec![lifetime_ref]); return; } if lifetime_ref.is_static() { @@ -803,8 +906,8 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path, _: ast::NodeId) { for (i, segment) in path.segments.iter().enumerate() { let depth = path.segments.len() - i - 1; - if let Some(ref parameters) = segment.parameters { - self.visit_segment_parameters(path.def, depth, parameters); + if let Some(ref args) = segment.args { + self.visit_segment_args(path.def, depth, args); } } } @@ -818,14 +921,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } fn visit_generics(&mut self, generics: &'tcx hir::Generics) { - check_mixed_explicit_and_in_band_defs( - self.tcx, - &generics.lifetimes().cloned().collect::>(), - ); - for ty_param in generics.ty_params() { - walk_list!(self, visit_ty_param_bound, &ty_param.bounds); - if let Some(ref ty) = ty_param.default { - self.visit_ty(&ty); + check_mixed_explicit_and_in_band_defs(self.tcx, &generics.params); + for param in &generics.params { + match param.kind { + GenericParamKind::Lifetime { .. } => {} + GenericParamKind::Type { ref default, .. } => { + walk_list!(self, visit_param_bound, ¶m.bounds); + if let Some(ref ty) = default { + self.visit_ty(&ty); + } + } } } for predicate in &generics.where_clause.predicates { @@ -836,28 +941,33 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { ref bound_generic_params, .. }) => { - if bound_generic_params.iter().any(|p| p.is_lifetime_param()) { + let lifetimes: FxHashMap<_, _> = bound_generic_params.iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir, param)) + } + _ => None, + }).collect(); + if !lifetimes.is_empty() { self.trait_ref_hack = true; let next_early_index = self.next_early_index(); let scope = Scope::Binder { - lifetimes: bound_generic_params - .lifetimes() - .map(|def| Region::late(&self.tcx.hir, def)) - .collect(), + lifetimes, s: self.scope, next_early_index, + track_lifetime_uses: true, abstract_type_parent: false, }; let result = self.with(scope, |old_scope, this| { this.check_lifetime_params(old_scope, &bound_generic_params); this.visit_ty(&bounded_ty); - walk_list!(this, visit_ty_param_bound, bounds); + walk_list!(this, visit_param_bound, bounds); }); self.trait_ref_hack = false; result } else { self.visit_ty(&bounded_ty); - walk_list!(self, visit_ty_param_bound, bounds); + walk_list!(self, visit_param_bound, bounds); } } &hir::WherePredicate::RegionPredicate(hir::WhereRegionPredicate { @@ -866,9 +976,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { .. }) => { self.visit_lifetime(lifetime); - for bound in bounds { - self.visit_lifetime(bound); - } + walk_list!(self, visit_param_bound, bounds); } &hir::WherePredicate::EqPredicate(hir::WhereEqPredicate { ref lhs_ty, @@ -893,7 +1001,10 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { || trait_ref .bound_generic_params .iter() - .any(|p| p.is_lifetime_param()) + .any(|param| match param.kind { + GenericParamKind::Lifetime { .. } => true, + _ => false, + }) { if self.trait_ref_hack { span_err!( @@ -905,13 +1016,16 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> { } let next_early_index = self.next_early_index(); let scope = Scope::Binder { - lifetimes: trait_ref - .bound_generic_params - .lifetimes() - .map(|def| Region::late(&self.tcx.hir, def)) - .collect(), + lifetimes: trait_ref.bound_generic_params.iter() + .filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(Region::late(&self.tcx.hir, param)) + } + _ => None, + }).collect(), s: self.scope, next_early_index, + track_lifetime_uses: true, abstract_type_parent: false, }; self.with(scope, |old_scope, this| { @@ -957,10 +1071,10 @@ fn original_lifetime(span: Span) -> Original { span: span, } } -fn shadower_lifetime(l: &hir::Lifetime) -> Shadower { +fn shadower_lifetime(param: &hir::GenericParam) -> Shadower { Shadower { kind: ShadowKind::Lifetime, - span: l.span, + span: param.span, } } @@ -975,23 +1089,27 @@ impl ShadowKind { fn check_mixed_explicit_and_in_band_defs( tcx: TyCtxt<'_, '_, '_>, - lifetime_defs: &[hir::LifetimeDef], + params: &P<[hir::GenericParam]>, ) { - let oob_def = lifetime_defs.iter().find(|lt| !lt.in_band); - let in_band_def = lifetime_defs.iter().find(|lt| lt.in_band); - - if let (Some(oob_def), Some(in_band_def)) = (oob_def, in_band_def) { + let in_bands: Vec<_> = params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { in_band, .. } => Some((in_band, param.span)), + _ => None, + }).collect(); + let out_of_band = in_bands.iter().find(|(in_band, _)| !in_band); + let in_band = in_bands.iter().find(|(in_band, _)| *in_band); + + if let (Some((_, out_of_band_span)), Some((_, in_band_span))) + = (out_of_band, in_band) { struct_span_err!( tcx.sess, - in_band_def.lifetime.span, + *in_band_span, E0688, "cannot mix in-band and explicit lifetime definitions" ).span_label( - in_band_def.lifetime.span, + *in_band_span, "in-band lifetime definition here", - ) - .span_label(oob_def.lifetime.span, "explicit lifetime definition here") - .emit(); + ).span_label(*out_of_band_span, "explicit lifetime definition here") + .emit(); } } @@ -1038,7 +1156,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) { struct GatherLabels<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, scope: ScopeRef<'a>, - labels_in_fn: &'a mut Vec<(ast::Name, Span)>, + labels_in_fn: &'a mut Vec, } let mut gather = GatherLabels { @@ -1054,32 +1172,31 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) { } fn visit_expr(&mut self, ex: &hir::Expr) { - if let Some((label, label_span)) = expression_label(ex) { - for &(prior, prior_span) in &self.labels_in_fn[..] { + if let Some(label) = expression_label(ex) { + for prior_label in &self.labels_in_fn[..] { // FIXME (#24278): non-hygienic comparison - if label == prior { + if label.name == prior_label.name { signal_shadowing_problem( self.tcx, - label, - original_label(prior_span), - shadower_label(label_span), + label.name, + original_label(prior_label.span), + shadower_label(label.span), ); } } - check_if_label_shadows_lifetime(self.tcx, self.scope, label, label_span); + check_if_label_shadows_lifetime(self.tcx, self.scope, label); - self.labels_in_fn.push((label, label_span)); + self.labels_in_fn.push(label); } intravisit::walk_expr(self, ex) } } - fn expression_label(ex: &hir::Expr) -> Option<(ast::Name, Span)> { + fn expression_label(ex: &hir::Expr) -> Option { match ex.node { - hir::ExprWhile(.., Some(label)) | hir::ExprLoop(_, Some(label), _) => { - Some((label.name, label.span)) - } + hir::ExprKind::While(.., Some(label)) | + hir::ExprKind::Loop(_, Some(label), _) => Some(label.ident), _ => None, } } @@ -1087,8 +1204,7 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) { fn check_if_label_shadows_lifetime( tcx: TyCtxt<'_, '_, '_>, mut scope: ScopeRef<'_>, - label: ast::Name, - label_span: Span, + label: ast::Ident, ) { loop { match *scope { @@ -1103,20 +1219,17 @@ fn extract_labels(ctxt: &mut LifetimeContext<'_, '_>, body: &hir::Body) { } Scope::Binder { - ref lifetimes, - s, - next_early_index: _, - abstract_type_parent: _, + ref lifetimes, s, .. } => { // FIXME (#24278): non-hygienic comparison - if let Some(def) = lifetimes.get(&hir::LifetimeName::Name(label)) { + if let Some(def) = lifetimes.get(&hir::ParamName::Plain(label.modern())) { let node_id = tcx.hir.as_local_node_id(def.id().unwrap()).unwrap(); signal_shadowing_problem( tcx, - label, + label.name, original_lifetime(tcx.hir.span(node_id)), - shadower_label(label_span), + shadower_label(label.span), ); return; } @@ -1133,11 +1246,12 @@ fn compute_object_lifetime_defaults( let mut map = NodeMap(); for item in tcx.hir.krate().items.values() { match item.node { - hir::ItemStruct(_, ref generics) - | hir::ItemUnion(_, ref generics) - | hir::ItemEnum(_, ref generics) - | hir::ItemTy(_, ref generics) - | hir::ItemTrait(_, _, ref generics, ..) => { + hir::ItemKind::Struct(_, ref generics) + | hir::ItemKind::Union(_, ref generics) + | hir::ItemKind::Enum(_, ref generics) + | hir::ItemKind::Existential(hir::ExistTy { ref generics, impl_trait_fn: None, .. }) + | hir::ItemKind::Ty(_, ref generics) + | hir::ItemKind::Trait(_, _, ref generics, ..) => { let result = object_lifetime_defaults_for_item(tcx, generics); // Debugging aid. @@ -1147,14 +1261,18 @@ fn compute_object_lifetime_defaults( .map(|set| match *set { Set1::Empty => "BaseDefault".to_string(), Set1::One(Region::Static) => "'static".to_string(), - Set1::One(Region::EarlyBound(i, _, _)) => generics - .lifetimes() - .nth(i as usize) - .unwrap() - .lifetime - .name - .name() - .to_string(), + Set1::One(Region::EarlyBound(mut i, _, _)) => { + generics.params.iter().find_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + if i == 0 { + return Some(param.name.ident().to_string()); + } + i -= 1; + None + } + _ => None, + }).unwrap() + } Set1::One(_) => bug!(), Set1::Many => "Ambiguous".to_string(), }) @@ -1178,17 +1296,17 @@ fn object_lifetime_defaults_for_item( tcx: TyCtxt<'_, '_, '_>, generics: &hir::Generics, ) -> Vec { - fn add_bounds(set: &mut Set1, bounds: &[hir::TyParamBound]) { + fn add_bounds(set: &mut Set1, bounds: &[hir::GenericBound]) { for bound in bounds { - if let hir::RegionTyParamBound(ref lifetime) = *bound { - set.insert(lifetime.name); + if let hir::GenericBound::Outlives(ref lifetime) = *bound { + set.insert(lifetime.name.modern()); } } } - generics - .ty_params() - .map(|param| { + generics.params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => None, + GenericParamKind::Type { .. } => { let mut set = Set1::Empty; add_bounds(&mut set, ¶m.bounds); @@ -1208,7 +1326,7 @@ fn object_lifetime_defaults_for_item( } let def = match data.bounded_ty.node { - hir::TyPath(hir::QPath::Resolved(None, ref path)) => path.def, + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => path.def, _ => continue, }; @@ -1217,27 +1335,35 @@ fn object_lifetime_defaults_for_item( } } - match set { + Some(match set { Set1::Empty => Set1::Empty, Set1::One(name) => { if name == hir::LifetimeName::Static { Set1::One(Region::Static) } else { - generics - .lifetimes() - .enumerate() - .find(|&(_, def)| def.lifetime.name == name) - .map_or(Set1::Many, |(i, def)| { - let def_id = tcx.hir.local_def_id(def.lifetime.id); - let origin = LifetimeDefOrigin::from_is_in_band(def.in_band); - Set1::One(Region::EarlyBound(i as u32, def_id, origin)) - }) + generics.params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + Some(( + param.id, + hir::LifetimeName::Param(param.name), + LifetimeDefOrigin::from_param(param), + )) + } + _ => None, + }) + .enumerate() + .find(|&(_, (_, lt_name, _))| lt_name == name) + .map_or(Set1::Many, |(i, (id, _, origin))| { + let def_id = tcx.hir.local_def_id(id); + Set1::One(Region::EarlyBound(i as u32, def_id, origin)) + }) } } Set1::Many => Set1::Many, - } - }) - .collect() + }) + } + }) + .collect() } impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { @@ -1254,56 +1380,113 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { F: for<'b> FnOnce(ScopeRef, &mut LifetimeContext<'b, 'tcx>), { let LifetimeContext { - tcx, ref mut map, .. - } = *self; + tcx, + map, + lifetime_uses, + .. + } = self; let labels_in_fn = replace(&mut self.labels_in_fn, vec![]); let xcrate_object_lifetime_defaults = replace(&mut self.xcrate_object_lifetime_defaults, DefIdMap()); let mut this = LifetimeContext { - tcx, - map: *map, + tcx: *tcx, + map: map, scope: &wrap_scope, trait_ref_hack: self.trait_ref_hack, is_in_fn_syntax: self.is_in_fn_syntax, labels_in_fn, xcrate_object_lifetime_defaults, - lifetime_uses: DefIdMap(), + lifetime_uses: lifetime_uses, }; debug!("entering scope {:?}", this.scope); f(self.scope, &mut this); + this.check_uses_for_lifetimes_defined_by_scope(); debug!("exiting scope {:?}", this.scope); self.labels_in_fn = this.labels_in_fn; self.xcrate_object_lifetime_defaults = this.xcrate_object_lifetime_defaults; + } - for (def_id, lifetimeuseset) in &this.lifetime_uses { + fn check_uses_for_lifetimes_defined_by_scope(&mut self) { + let defined_by = match self.scope { + Scope::Binder { lifetimes, .. } => lifetimes, + _ => { + debug!("check_uses_for_lifetimes_defined_by_scope: not in a binder scope"); + return; + } + }; + + let mut def_ids: Vec<_> = defined_by.values() + .flat_map(|region| match region { + Region::EarlyBound(_, def_id, _) + | Region::LateBound(_, def_id, _) + | Region::Free(_, def_id) => Some(*def_id), + + Region::LateBoundAnon(..) | Region::Static => None, + }) + .collect(); + + // ensure that we issue lints in a repeatable order + def_ids.sort_by_key(|&def_id| self.tcx.def_path_hash(def_id)); + + for def_id in def_ids { + debug!( + "check_uses_for_lifetimes_defined_by_scope: def_id = {:?}", + def_id, + ); + + let lifetimeuseset = self.lifetime_uses.remove(&def_id); + debug!( + "check_uses_for_lifetimes_defined_by_scope: lifetimeuseset = {:?}", + lifetimeuseset + ); match lifetimeuseset { - &LifetimeUseSet::One(_) => { - let node_id = this.tcx.hir.as_local_node_id(*def_id).unwrap(); + Some(LifetimeUseSet::One(lifetime)) => { + let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); debug!("node id first={:?}", node_id); - if let hir::map::NodeLifetime(hir_lifetime) = this.tcx.hir.get(node_id) { - let span = hir_lifetime.span; - let id = hir_lifetime.id; - debug!( - "id ={:?} span = {:?} hir_lifetime = {:?}", - node_id, span, hir_lifetime + if let Some((id, span, name)) = match self.tcx.hir.get(node_id) { + hir::map::NodeLifetime(hir_lifetime) => { + Some((hir_lifetime.id, hir_lifetime.span, hir_lifetime.name.ident())) + } + hir::map::NodeGenericParam(param) => { + Some((param.id, param.span, param.name.ident())) + } + _ => None, + } { + debug!("id = {:?} span = {:?} name = {:?}", node_id, span, name); + let mut err = self.tcx.struct_span_lint_node( + lint::builtin::SINGLE_USE_LIFETIMES, + id, + span, + &format!("lifetime parameter `{}` only used once", name), ); - - this.tcx - .struct_span_lint_node( - lint::builtin::SINGLE_USE_LIFETIME, - id, - span, - &format!( - "lifetime name `{}` only used once", - hir_lifetime.name.name() - ), - ) - .emit(); + err.span_label(span, "this lifetime..."); + err.span_label(lifetime.span, "...is used only here"); + err.emit(); } } - _ => { + Some(LifetimeUseSet::Many) => { debug!("Not one use lifetime"); } + None => { + let node_id = self.tcx.hir.as_local_node_id(def_id).unwrap(); + if let Some((id, span, name)) = match self.tcx.hir.get(node_id) { + hir::map::NodeLifetime(hir_lifetime) => { + Some((hir_lifetime.id, hir_lifetime.span, hir_lifetime.name.ident())) + } + hir::map::NodeGenericParam(param) => { + Some((param.id, param.span, param.name.ident())) + } + _ => None, + } { + debug!("id ={:?} span = {:?} name = {:?}", node_id, span, name); + self.tcx.struct_span_lint_node( + lint::builtin::UNUSED_LIFETIMES, + id, + span, + &format!("lifetime parameter `{}` never used", name) + ).emit(); + } + } } } } @@ -1341,36 +1524,40 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let mut index = 0; if let Some(parent_id) = parent_id { let parent = self.tcx.hir.expect_item(parent_id); - if let hir::ItemTrait(..) = parent.node { + if let hir::ItemKind::Trait(..) = parent.node { index += 1; // Self comes first. } match parent.node { - hir::ItemTrait(_, _, ref generics, ..) - | hir::ItemImpl(_, _, _, ref generics, ..) => { + hir::ItemKind::Trait(_, _, ref generics, ..) + | hir::ItemKind::Impl(_, _, _, ref generics, ..) => { index += generics.params.len() as u32; } _ => {} } } - let lifetimes = generics - .lifetimes() - .map(|def| { - if self.map.late_bound.contains(&def.lifetime.id) { - Region::late(&self.tcx.hir, def) + let mut type_count = 0; + let lifetimes = generics.params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => { + if self.map.late_bound.contains(¶m.id) { + Some(Region::late(&self.tcx.hir, param)) } else { - Region::early(&self.tcx.hir, &mut index, def) + Some(Region::early(&self.tcx.hir, &mut index, param)) } - }) - .collect(); - - let next_early_index = index + generics.ty_params().count() as u32; + } + GenericParamKind::Type { .. } => { + type_count += 1; + None + } + }).collect(); + let next_early_index = index + type_count; let scope = Scope::Binder { lifetimes, next_early_index, s: self.scope, abstract_type_parent: true, + track_lifetime_uses: false, }; self.with(scope, move |old_scope, this| { this.check_lifetime_params(old_scope, &generics.params); @@ -1435,13 +1622,12 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { break None; } - Scope::Binder { - ref lifetimes, - s, - next_early_index: _, - abstract_type_parent: _, - } => { - if let Some(&def) = lifetimes.get(&lifetime_ref.name) { + Scope::Binder { ref lifetimes, s, .. } => { + let name = match lifetime_ref.name { + LifetimeName::Param(param_name) => param_name, + _ => bug!("expected LifetimeName::Param"), + }; + if let Some(&def) = lifetimes.get(&name.modern()) { break Some(def.shifted(late_depth)); } else { late_depth += 1; @@ -1462,7 +1648,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let fn_id = self.tcx.hir.body_owner(body_id); match self.tcx.hir.get(fn_id) { hir::map::NodeItem(&hir::Item { - node: hir::ItemFn(..), + node: hir::ItemKind::Fn(..), .. }) | hir::map::NodeTraitItem(&hir::TraitItem { @@ -1510,32 +1696,41 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { lifetime_ref.span, E0261, "use of undeclared lifetime name `{}`", - lifetime_ref.name.name() + lifetime_ref ).span_label(lifetime_ref.span, "undeclared lifetime") .emit(); } } - fn visit_segment_parameters( + fn visit_segment_args( &mut self, def: Def, depth: usize, - params: &'tcx hir::PathParameters, + generic_args: &'tcx hir::GenericArgs, ) { - if params.parenthesized { + if generic_args.parenthesized { let was_in_fn_syntax = self.is_in_fn_syntax; self.is_in_fn_syntax = true; - self.visit_fn_like_elision(params.inputs(), Some(¶ms.bindings[0].ty)); + self.visit_fn_like_elision(generic_args.inputs(), + Some(&generic_args.bindings[0].ty)); self.is_in_fn_syntax = was_in_fn_syntax; return; } - if params.lifetimes.iter().all(|l| l.is_elided()) { - self.resolve_elided_lifetimes(¶ms.lifetimes, true); - } else { - for l in ¶ms.lifetimes { - self.visit_lifetime(l); + let mut elide_lifetimes = true; + let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { + hir::GenericArg::Lifetime(lt) => { + if !lt.is_elided() { + elide_lifetimes = false; + } + Some(lt) } + _ => None, + }).collect(); + if elide_lifetimes { + self.resolve_elided_lifetimes(lifetimes); + } else { + lifetimes.iter().for_each(|lt| self.visit_lifetime(lt)); } // Figure out if this is a type/trait segment, @@ -1587,49 +1782,65 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { self.xcrate_object_lifetime_defaults .entry(def_id) .or_insert_with(|| { - tcx.generics_of(def_id) - .types - .iter() - .map(|def| def.object_lifetime_default) - .collect() + tcx.generics_of(def_id).params.iter().filter_map(|param| { + match param.kind { + GenericParamDefKind::Type { object_lifetime_default, .. } => { + Some(object_lifetime_default) + } + GenericParamDefKind::Lifetime => None, + } + }).collect() }) }; - unsubst - .iter() - .map(|set| match *set { - Set1::Empty => if in_body { - None - } else { - Some(Region::Static) - }, - Set1::One(r) => r.subst(¶ms.lifetimes, map), - Set1::Many => None, - }) - .collect() + unsubst.iter() + .map(|set| match *set { + Set1::Empty => if in_body { + None + } else { + Some(Region::Static) + }, + Set1::One(r) => { + let lifetimes = generic_args.args.iter().filter_map(|arg| match arg { + GenericArg::Lifetime(lt) => Some(lt), + _ => None, + }); + r.subst(lifetimes, map) + } + Set1::Many => None, + }) + .collect() }); - for (i, ty) in params.types.iter().enumerate() { - if let Some(<) = object_lifetime_defaults.get(i) { - let scope = Scope::ObjectLifetimeDefault { - lifetime: lt, - s: self.scope, - }; - self.with(scope, |_, this| this.visit_ty(ty)); - } else { - self.visit_ty(ty); + let mut i = 0; + for arg in &generic_args.args { + match arg { + GenericArg::Lifetime(_) => {} + GenericArg::Type(ty) => { + if let Some(<) = object_lifetime_defaults.get(i) { + let scope = Scope::ObjectLifetimeDefault { + lifetime: lt, + s: self.scope, + }; + self.with(scope, |_, this| this.visit_ty(ty)); + } else { + self.visit_ty(ty); + } + i += 1; + } } } - for b in ¶ms.bindings { + for b in &generic_args.bindings { self.visit_assoc_type_binding(b); } } fn visit_fn_like_elision( &mut self, - inputs: &'tcx [P], + inputs: &'tcx [hir::Ty], output: Option<&'tcx P>, ) { + debug!("visit_fn_like_elision: enter"); let mut arg_elide = Elide::FreshLateAnon(Cell::new(0)); let arg_scope = Scope::Elision { elide: arg_elide.clone(), @@ -1652,6 +1863,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { None => return, }; + debug!("visit_fn_like_elision: determine output"); + // Figure out if there's a body we can get argument names from, // and whether there's a `self` argument (treated specially). let mut assoc_item_kind = None; @@ -1660,7 +1873,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let body = match self.tcx.hir.get(parent) { // `fn` definitions and methods. hir::map::NodeItem(&hir::Item { - node: hir::ItemFn(.., body), + node: hir::ItemKind::Fn(.., body), .. }) => Some(body), @@ -1673,7 +1886,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .expect_item(self.tcx.hir.get_parent(parent)) .node { - hir::ItemTrait(.., ref trait_items) => { + hir::ItemKind::Trait(.., ref trait_items) => { assoc_item_kind = trait_items .iter() .find(|ti| ti.id.node_id == parent) @@ -1696,7 +1909,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .expect_item(self.tcx.hir.get_parent(parent)) .node { - hir::ItemImpl(.., ref self_ty, ref impl_items) => { + hir::ItemKind::Impl(.., ref self_ty, ref impl_items) => { impl_self = Some(self_ty); assoc_item_kind = impl_items .iter() @@ -1738,7 +1951,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { // Can't always rely on literal (or implied) `Self` due // to the way elision rules were originally specified. let impl_self = impl_self.map(|ty| &ty.node); - if let Some(&hir::TyPath(hir::QPath::Resolved(None, ref path))) = impl_self { + if let Some(&hir::TyKind::Path(hir::QPath::Resolved(None, ref path))) = impl_self { match path.def { // Whitelist the types that unambiguously always // result in the same type constructor being used @@ -1753,8 +1966,8 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { false }; - if let hir::TyRptr(lifetime_ref, ref mt) = inputs[0].node { - if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = mt.ty.node { + if let hir::TyKind::Rptr(lifetime_ref, ref mt) = inputs[0].node { + if let hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) = mt.ty.node { if is_self_ty(path.def) { if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) { let scope = Scope::Elision { @@ -1781,7 +1994,7 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { .map(|(i, input)| { let mut gather = GatherLifetimes { map: self.map, - binder_depth: 1, + outer_index: ty::INNERMOST, have_bound_regions: false, lifetimes: FxHashSet(), }; @@ -1811,15 +2024,18 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { Elide::Error(arg_lifetimes) }; + debug!("visit_fn_like_elision: elide={:?}", elide); + let scope = Scope::Elision { elide, s: self.scope, }; self.with(scope, |_, this| this.visit_ty(output)); + debug!("visit_fn_like_elision: exit"); struct GatherLifetimes<'a> { map: &'a NamedRegionMap, - binder_depth: u32, + outer_index: ty::DebruijnIndex, have_bound_regions: bool, lifetimes: FxHashSet, } @@ -1830,10 +2046,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn visit_ty(&mut self, ty: &hir::Ty) { - if let hir::TyBareFn(_) = ty.node { - self.binder_depth += 1; + if let hir::TyKind::BareFn(_) = ty.node { + self.outer_index.shift_in(1); } - if let hir::TyTraitObject(ref bounds, ref lifetime) = ty.node { + if let hir::TyKind::TraitObject(ref bounds, ref lifetime) = ty.node { for bound in bounds { self.visit_poly_trait_ref(bound, hir::TraitBoundModifier::None); } @@ -1846,16 +2062,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } else { intravisit::walk_ty(self, ty); } - if let hir::TyBareFn(_) = ty.node { - self.binder_depth -= 1; + if let hir::TyKind::BareFn(_) = ty.node { + self.outer_index.shift_out(1); } } fn visit_generic_param(&mut self, param: &hir::GenericParam) { - if let hir::GenericParam::Lifetime(ref lifetime_def) = *param { - for l in &lifetime_def.bounds { - self.visit_lifetime(l); - } + if let hir::GenericParamKind::Lifetime { .. } = param.kind { + // FIXME(eddyb) Do we want this? It only makes a difference + // if this `for<'a>` lifetime parameter is never used. + self.have_bound_regions = true; } intravisit::walk_generic_param(self, param); @@ -1866,22 +2082,22 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { trait_ref: &hir::PolyTraitRef, modifier: hir::TraitBoundModifier, ) { - self.binder_depth += 1; + self.outer_index.shift_in(1); intravisit::walk_poly_trait_ref(self, trait_ref, modifier); - self.binder_depth -= 1; + self.outer_index.shift_out(1); } fn visit_lifetime(&mut self, lifetime_ref: &hir::Lifetime) { if let Some(&lifetime) = self.map.defs.get(&lifetime_ref.id) { match lifetime { Region::LateBound(debruijn, _, _) | Region::LateBoundAnon(debruijn, _) - if debruijn.depth < self.binder_depth => + if debruijn < self.outer_index => { self.have_bound_regions = true; } _ => { self.lifetimes - .insert(lifetime.from_depth(self.binder_depth)); + .insert(lifetime.shifted_out_to_binder(self.outer_index)); } } } @@ -1889,25 +2105,15 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } - fn resolve_elided_lifetimes(&mut self, lifetime_refs: &'tcx [hir::Lifetime], deprecated: bool) { + fn resolve_elided_lifetimes(&mut self, + lifetime_refs: Vec<&'tcx hir::Lifetime>) { if lifetime_refs.is_empty() { return; } let span = lifetime_refs[0].span; - let id = lifetime_refs[0].id; let mut late_depth = 0; let mut scope = self.scope; - if deprecated { - self.tcx - .struct_span_lint_node( - lint::builtin::ELIDED_LIFETIME_IN_PATH, - id, - span, - &format!("hidden lifetime parameters are deprecated, try `Foo<'_>`"), - ) - .emit(); - } let error = loop { match *scope { // Do not assign any resolution, it will be inferred. @@ -2067,100 +2273,99 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } fn check_lifetime_params(&mut self, old_scope: ScopeRef, params: &'tcx [hir::GenericParam]) { - for (i, lifetime_i) in params.lifetimes().enumerate() { - for lifetime in params.lifetimes() { - match lifetime.lifetime.name { - hir::LifetimeName::Static | hir::LifetimeName::Underscore => { - let lifetime = lifetime.lifetime; - let name = lifetime.name.name(); - let mut err = struct_span_err!( - self.tcx.sess, - lifetime.span, - E0262, - "invalid lifetime parameter name: `{}`", - name - ); - err.span_label( - lifetime.span, - format!("{} is a reserved lifetime name", name), - ); - err.emit(); - } - hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit | - hir::LifetimeName::Name(_) => {} + let lifetimes: Vec<_> = params.iter().filter_map(|param| match param.kind { + GenericParamKind::Lifetime { .. } => Some((param, param.name)), + _ => None, + }).collect(); + for (i, (lifetime_i, lifetime_i_name)) in lifetimes.iter().enumerate() { + if let hir::ParamName::Plain(_) = lifetime_i_name { + let name = lifetime_i_name.ident().name; + if name == keywords::UnderscoreLifetime.name() || + name == keywords::StaticLifetime.name() { + let mut err = struct_span_err!( + self.tcx.sess, + lifetime_i.span, + E0262, + "invalid lifetime parameter name: `{}`", + lifetime_i.name.ident(), + ); + err.span_label( + lifetime_i.span, + format!("{} is a reserved lifetime name", name), + ); + err.emit(); } } // It is a hard error to shadow a lifetime within the same scope. - for lifetime_j in params.lifetimes().skip(i + 1) { - if lifetime_i.lifetime.name == lifetime_j.lifetime.name { + for (lifetime_j, lifetime_j_name) in lifetimes.iter().skip(i + 1) { + if lifetime_i_name == lifetime_j_name { struct_span_err!( self.tcx.sess, - lifetime_j.lifetime.span, + lifetime_j.span, E0263, "lifetime name `{}` declared twice in the same scope", - lifetime_j.lifetime.name.name() - ).span_label(lifetime_j.lifetime.span, "declared twice") - .span_label(lifetime_i.lifetime.span, "previous declaration here") - .emit(); + lifetime_j.name.ident() + ).span_label(lifetime_j.span, "declared twice") + .span_label(lifetime_i.span, "previous declaration here") + .emit(); } } // It is a soft error to shadow a lifetime within a parent scope. - self.check_lifetime_def_for_shadowing(old_scope, &lifetime_i.lifetime); + self.check_lifetime_param_for_shadowing(old_scope, &lifetime_i); for bound in &lifetime_i.bounds { - match bound.name { - hir::LifetimeName::Underscore => { - let mut err = struct_span_err!( - self.tcx.sess, - bound.span, - E0637, - "invalid lifetime bound name: `'_`" - ); - err.span_label(bound.span, "`'_` is a reserved lifetime name"); - err.emit(); - } - hir::LifetimeName::Static => { - self.insert_lifetime(bound, Region::Static); - self.tcx - .sess - .struct_span_warn( - lifetime_i.lifetime.span.to(bound.span), + match bound { + hir::GenericBound::Outlives(lt) => match lt.name { + hir::LifetimeName::Underscore => { + let mut err = struct_span_err!( + self.tcx.sess, + lt.span, + E0637, + "invalid lifetime bound name: `'_`" + ); + err.span_label(lt.span, "`'_` is a reserved lifetime name"); + err.emit(); + } + hir::LifetimeName::Static => { + self.insert_lifetime(lt, Region::Static); + self.tcx.sess.struct_span_warn( + lifetime_i.span.to(lt.span), &format!( "unnecessary lifetime parameter `{}`", - lifetime_i.lifetime.name.name() + lifetime_i.name.ident(), ), - ) - .help(&format!( + ).help(&format!( "you can use the `'static` lifetime directly, in place \ - of `{}`", - lifetime_i.lifetime.name.name() - )) - .emit(); - } - hir::LifetimeName::Fresh(_) | hir::LifetimeName::Implicit | - hir::LifetimeName::Name(_) => { - self.resolve_lifetime_ref(bound); + of `{}`", + lifetime_i.name.ident(), + )).emit(); + } + hir::LifetimeName::Param(_) + | hir::LifetimeName::Implicit => { + self.resolve_lifetime_ref(lt); + } } + _ => bug!(), } } } } - fn check_lifetime_def_for_shadowing( + fn check_lifetime_param_for_shadowing( &self, mut old_scope: ScopeRef, - lifetime: &'tcx hir::Lifetime, + param: &'tcx hir::GenericParam, ) { - for &(label, label_span) in &self.labels_in_fn { + for label in &self.labels_in_fn { // FIXME (#24278): non-hygienic comparison - if lifetime.name.name() == label { + if param.name.ident().name == label.name { signal_shadowing_problem( self.tcx, - label, - original_label(label_span), - shadower_lifetime(&lifetime), + label.name, + original_label(label.span), + shadower_lifetime(¶m), ); return; } @@ -2179,19 +2384,16 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } Scope::Binder { - ref lifetimes, - s, - next_early_index: _, - abstract_type_parent: _, + ref lifetimes, s, .. } => { - if let Some(&def) = lifetimes.get(&lifetime.name) { + if let Some(&def) = lifetimes.get(¶m.name.modern()) { let node_id = self.tcx.hir.as_local_node_id(def.id().unwrap()).unwrap(); signal_shadowing_problem( self.tcx, - lifetime.name.name(), + param.name.ident().name, original_lifetime(self.tcx.hir.span(node_id)), - shadower_lifetime(&lifetime), + shadower_lifetime(¶m), ); return; } @@ -2202,6 +2404,50 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { } } + /// Returns true if, in the current scope, replacing `'_` would be + /// equivalent to a single-use lifetime. + fn track_lifetime_uses(&self) -> bool { + let mut scope = self.scope; + loop { + match *scope { + Scope::Root => break false, + + // Inside of items, it depends on the kind of item. + Scope::Binder { + track_lifetime_uses, + .. + } => break track_lifetime_uses, + + // Inside a body, `'_` will use an inference variable, + // should be fine. + Scope::Body { .. } => break true, + + // A lifetime only used in a fn argument could as well + // be replaced with `'_`, as that would generate a + // fresh name, too. + Scope::Elision { + elide: Elide::FreshLateAnon(_), + .. + } => break true, + + // In the return type or other such place, `'_` is not + // going to make a fresh name, so we cannot + // necessarily replace a single-use lifetime with + // `'_`. + Scope::Elision { + elide: Elide::Exact(_), + .. + } => break false, + Scope::Elision { + elide: Elide::Error(_), + .. + } => break false, + + Scope::ObjectLifetimeDefault { s, .. } => scope = s, + } + } + } + fn insert_lifetime(&mut self, lifetime_ref: &'tcx hir::Lifetime, def: Region) { if lifetime_ref.id == ast::DUMMY_NODE_ID { span_bug!( @@ -2228,15 +2474,30 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { | Region::LateBound(_, def_id, _) | Region::EarlyBound(_, def_id, _) => { // A lifetime declared by the user. - if !self.lifetime_uses.contains_key(&def_id) { + let track_lifetime_uses = self.track_lifetime_uses(); + debug!( + "insert_lifetime: track_lifetime_uses={}", + track_lifetime_uses + ); + if track_lifetime_uses && !self.lifetime_uses.contains_key(&def_id) { + debug!("insert_lifetime: first use of {:?}", def_id); self.lifetime_uses .insert(def_id, LifetimeUseSet::One(lifetime_ref)); } else { + debug!("insert_lifetime: many uses of {:?}", def_id); self.lifetime_uses.insert(def_id, LifetimeUseSet::Many); } } } } + + /// Sometimes we resolve a lifetime, but later find that it is an + /// error (esp. around impl trait). In that case, we remove the + /// entry into `map.defs` so as not to confuse later code. + fn uninsert_lifetime_on_error(&mut self, lifetime_ref: &'tcx hir::Lifetime, bad_def: Region) { + let old_value = self.map.defs.remove(&lifetime_ref.id); + assert_eq!(old_value, Some(bad_def)); + } } /////////////////////////////////////////////////////////////////////////// @@ -2285,31 +2546,21 @@ fn insert_late_bound_lifetimes( let mut appears_in_where_clause = AllCollector { regions: FxHashSet(), }; + appears_in_where_clause.visit_generics(generics); for param in &generics.params { - match *param { - hir::GenericParam::Lifetime(ref lifetime_def) => { - if !lifetime_def.bounds.is_empty() { + match param.kind { + hir::GenericParamKind::Lifetime { .. } => { + if !param.bounds.is_empty() { // `'a: 'b` means both `'a` and `'b` are referenced - appears_in_where_clause.visit_generic_param(param); + appears_in_where_clause + .regions.insert(hir::LifetimeName::Param(param.name.modern())); } } - hir::GenericParam::Type(ref ty_param) => { - walk_list!( - &mut appears_in_where_clause, - visit_ty_param_bound, - &ty_param.bounds - ); - } + hir::GenericParamKind::Type { .. } => {} } } - walk_list!( - &mut appears_in_where_clause, - visit_where_predicate, - &generics.where_clause.predicates - ); - debug!( "insert_late_bound_lifetimes: appears_in_where_clause={:?}", appears_in_where_clause.regions @@ -2319,33 +2570,26 @@ fn insert_late_bound_lifetimes( // - appear in the inputs // - do not appear in the where-clauses // - are not implicitly captured by `impl Trait` - for lifetime in generics.lifetimes() { - let name = lifetime.lifetime.name; - + for param in &generics.params { + let lt_name = hir::LifetimeName::Param(param.name.modern()); // appears in the where clauses? early-bound. - if appears_in_where_clause.regions.contains(&name) { + if appears_in_where_clause.regions.contains(<_name) { continue; } // does not appear in the inputs, but appears in the return type? early-bound. - if !constrained_by_input.regions.contains(&name) - && appears_in_output.regions.contains(&name) + if !constrained_by_input.regions.contains(<_name) + && appears_in_output.regions.contains(<_name) { continue; } - debug!( - "insert_late_bound_lifetimes: \ - lifetime {:?} with id {:?} is late-bound", - lifetime.lifetime.name, lifetime.lifetime.id - ); + debug!("insert_late_bound_lifetimes: lifetime {:?} with id {:?} is late-bound", + param.name.ident(), + param.id); - let inserted = map.late_bound.insert(lifetime.lifetime.id); - assert!( - inserted, - "visited lifetime {:?} twice", - lifetime.lifetime.id - ); + let inserted = map.late_bound.insert(param.id); + assert!(inserted, "visited lifetime {:?} twice", param.id); } return; @@ -2361,14 +2605,14 @@ fn insert_late_bound_lifetimes( fn visit_ty(&mut self, ty: &'v hir::Ty) { match ty.node { - hir::TyPath(hir::QPath::Resolved(Some(_), _)) - | hir::TyPath(hir::QPath::TypeRelative(..)) => { + hir::TyKind::Path(hir::QPath::Resolved(Some(_), _)) + | hir::TyKind::Path(hir::QPath::TypeRelative(..)) => { // ignore lifetimes appearing in associated type // projections, as they are not *constrained* // (defined above) } - hir::TyPath(hir::QPath::Resolved(None, ref path)) => { + hir::TyKind::Path(hir::QPath::Resolved(None, ref path)) => { // consider only the lifetimes on the final // segment; I am not sure it's even currently // valid to have them elsewhere, but even if it @@ -2386,7 +2630,7 @@ fn insert_late_bound_lifetimes( } fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - self.regions.insert(lifetime_ref.name); + self.regions.insert(lifetime_ref.name.modern()); } } @@ -2400,7 +2644,7 @@ fn insert_late_bound_lifetimes( } fn visit_lifetime(&mut self, lifetime_ref: &'v hir::Lifetime) { - self.regions.insert(lifetime_ref.name); + self.regions.insert(lifetime_ref.name.modern()); } } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 279908d2b675f..262a617cb6924 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -20,7 +20,7 @@ use ty::{self, TyCtxt}; use middle::privacy::AccessLevels; use session::DiagnosticMessageId; use syntax::symbol::Symbol; -use syntax_pos::{Span, MultiSpan, DUMMY_SP}; +use syntax_pos::{Span, MultiSpan}; use syntax::ast; use syntax::ast::{NodeId, Attribute}; use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version}; @@ -165,7 +165,7 @@ impl<'a, 'tcx: 'a> Annotator<'a, 'tcx> { &attr::Stable {since: stab_since}) = (&stab.rustc_depr, &stab.level) { // Explicit version of iter::order::lt to handle parse errors properly for (dep_v, stab_v) in - dep_since.as_str().split(".").zip(stab_since.as_str().split(".")) { + dep_since.as_str().split('.').zip(stab_since.as_str().split('.')) { if let (Ok(dep_v), Ok(stab_v)) = (dep_v.parse::(), stab_v.parse()) { match dep_v.cmp(&stab_v) { Ordering::Less => { @@ -263,14 +263,14 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { // they don't have their own stability. They still can be annotated as unstable // and propagate this unstability to children, but this annotation is completely // optional. They inherit stability from their parents when unannotated. - hir::ItemImpl(.., None, _, _) | hir::ItemForeignMod(..) => { + hir::ItemKind::Impl(.., None, _, _) | hir::ItemKind::ForeignMod(..) => { self.in_trait_impl = false; kind = AnnotationKind::Container; } - hir::ItemImpl(.., Some(_), _, _) => { + hir::ItemKind::Impl(.., Some(_), _, _) => { self.in_trait_impl = true; } - hir::ItemStruct(ref sd, _) => { + hir::ItemKind::Struct(ref sd, _) => { if !sd.is_struct() { self.annotate(sd.id(), &i.attrs, i.span, AnnotationKind::Required, |_| {}) } @@ -353,7 +353,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'a, 'tcx> { // they don't have their own stability. They still can be annotated as unstable // and propagate this unstability to children, but this annotation is completely // optional. They inherit stability from their parents when unannotated. - hir::ItemImpl(.., None, _, _) | hir::ItemForeignMod(..) => {} + hir::ItemKind::Impl(.., None, _, _) | hir::ItemKind::ForeignMod(..) => {} _ => self.check_missing_stability(i.id, i.span) } @@ -614,10 +614,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { debug!("stability: \ inspecting def_id={:?} span={:?} of stability={:?}", def_id, span, stability); - if let Some(&Stability{rustc_depr: Some(attr::RustcDeprecation { reason, .. }), ..}) + if let Some(&Stability{rustc_depr: Some(attr::RustcDeprecation { reason, since }), ..}) = stability { if let Some(id) = id { - lint_deprecated(def_id, id, Some(reason)); + if deprecation_in_effect(&since.as_str()) { + lint_deprecated(def_id, id, Some(reason)); + } } } @@ -685,7 +687,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let msp: MultiSpan = span.into(); let cm = &self.sess.parse_sess.codemap(); let span_key = msp.primary_span().and_then(|sp: Span| - if sp != DUMMY_SP { + if !sp.is_dummy() { let file = cm.lookup_char_pos(sp.lo()).file; if file.name.is_macros() { None @@ -721,9 +723,9 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { fn visit_item(&mut self, item: &'tcx hir::Item) { match item.node { - hir::ItemExternCrate(_) => { + hir::ItemKind::ExternCrate(_) => { // compiler-generated `extern crate` items have a dummy span. - if item.span == DUMMY_SP { return } + if item.span.is_dummy() { return } let def_id = self.tcx.hir.local_def_id(item.id); let cnum = match self.tcx.extern_mod_stmt_cnum(def_id) { @@ -737,12 +739,13 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemImpl(.., Some(ref t), _, ref impl_item_refs) => { + hir::ItemKind::Impl(.., Some(ref t), _, ref impl_item_refs) => { if let Def::Trait(trait_did) = t.path.def { for impl_item_ref in impl_item_refs { let impl_item = self.tcx.hir.impl_item(impl_item_ref.id); let trait_item_def_id = self.tcx.associated_items(trait_did) - .find(|item| item.name == impl_item.name).map(|item| item.def_id); + .find(|item| item.ident.name == impl_item.ident.name) + .map(|item| item.def_id); if let Some(def_id) = trait_item_def_id { // Pass `None` to skip deprecation warnings. self.tcx.check_stability(def_id, None, impl_item.span); @@ -753,7 +756,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { // There's no good place to insert stability check for non-Copy unions, // so semi-randomly perform it here in stability.rs - hir::ItemUnion(..) if !self.tcx.features().untagged_unions => { + hir::ItemKind::Union(..) if !self.tcx.features().untagged_unions => { let def_id = self.tcx.hir.local_def_id(item.id); let adt_def = self.tcx.adt_def(def_id); let ty = self.tcx.type_of(def_id); @@ -764,7 +767,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> { "unions with `Drop` implementations are unstable"); } else { let param_env = self.tcx.param_env(def_id); - if !param_env.can_type_implement_copy(self.tcx, ty, item.span).is_ok() { + if !param_env.can_type_implement_copy(self.tcx, ty).is_ok() { emit_feature_err(&self.tcx.sess.parse_sess, "untagged_unions", item.span, GateIssue::Language, "unions with non-`Copy` fields are unstable"); diff --git a/src/librustc/middle/weak_lang_items.rs b/src/librustc/middle/weak_lang_items.rs index 42e4d3861bae3..d8570b43fbe27 100644 --- a/src/librustc/middle/weak_lang_items.rs +++ b/src/librustc/middle/weak_lang_items.rs @@ -17,6 +17,7 @@ use rustc_target::spec::PanicStrategy; use syntax::ast; use syntax::symbol::Symbol; use syntax_pos::Span; +use hir::def_id::DefId; use hir::intravisit::{Visitor, NestedVisitorMap}; use hir::intravisit; use hir; @@ -111,9 +112,16 @@ fn verify<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if missing.contains(&lang_items::$item) && !whitelisted(tcx, lang_items::$item) && items.$name().is_none() { - tcx.sess.err(&format!("language item required, but not found: `{}`", - stringify!($name))); - + if lang_items::$item == lang_items::PanicImplLangItem { + tcx.sess.err(&format!("`#[panic_implementation]` function required, \ + but not found")); + } else if lang_items::$item == lang_items::OomLangItem { + tcx.sess.err(&format!("`#[alloc_error_handler]` function required, \ + but not found")); + } else { + tcx.sess.err(&format!("language item required, but not found: `{}`", + stringify!($name))); + } } )* } @@ -145,10 +153,19 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { } } +impl<'a, 'tcx, 'gcx> TyCtxt<'a, 'tcx, 'gcx> { + pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { + let lang_items = self.lang_items(); + let did = Some(item_def_id); + + $(lang_items.$name() == did)||+ + } +} + ) } weak_lang_items! { - panic_fmt, PanicFmtLangItem, rust_begin_unwind; + panic_impl, PanicImplLangItem, rust_begin_unwind; eh_personality, EhPersonalityLangItem, rust_eh_personality; eh_unwind_resume, EhUnwindResumeLangItem, rust_eh_unwind_resume; oom, OomLangItem, rust_oom; diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 1e1d50c3fc036..1e9584bc55bdf 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -2,28 +2,164 @@ use std::{fmt, env}; use mir; use ty::{FnSig, Ty, layout}; +use ty::layout::{Size, Align}; +use rustc_data_structures::sync::Lrc; use super::{ - MemoryPointer, Lock, AccessKind + Pointer, Lock, AccessKind }; use backtrace::Backtrace; -#[derive(Debug, Clone)] +use ty; +use ty::query::TyCtxtAt; +use errors::DiagnosticBuilder; + +use syntax_pos::Span; +use syntax::ast; + +pub type ConstEvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, Lrc>>; + +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct ConstEvalErr<'tcx> { + pub span: Span, + pub error: ::mir::interpret::EvalError<'tcx>, + pub stacktrace: Vec, +} + +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct FrameInfo { + pub span: Span, + pub location: String, + pub lint_root: Option, +} + +impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> { + pub fn struct_error(&self, + tcx: TyCtxtAt<'a, 'gcx, 'tcx>, + message: &str) + -> Option> + { + self.struct_generic(tcx, message, None) + } + + pub fn report_as_error(&self, + tcx: TyCtxtAt<'a, 'gcx, 'tcx>, + message: &str + ) { + let err = self.struct_error(tcx, message); + if let Some(mut err) = err { + err.emit(); + } + } + + pub fn report_as_lint(&self, + tcx: TyCtxtAt<'a, 'gcx, 'tcx>, + message: &str, + lint_root: ast::NodeId, + ) { + let lint = self.struct_generic( + tcx, + message, + Some(lint_root), + ); + if let Some(mut lint) = lint { + lint.emit(); + } + } + + fn struct_generic( + &self, + tcx: TyCtxtAt<'a, 'gcx, 'tcx>, + message: &str, + lint_root: Option, + ) -> Option> { + match self.error.kind { + ::mir::interpret::EvalErrorKind::TypeckError | + ::mir::interpret::EvalErrorKind::TooGeneric | + ::mir::interpret::EvalErrorKind::CheckMatchError | + ::mir::interpret::EvalErrorKind::Layout(_) => return None, + ::mir::interpret::EvalErrorKind::ReferencedConstant(ref inner) => { + inner.struct_generic(tcx, "referenced constant has errors", lint_root)?.emit(); + }, + _ => {}, + } + trace!("reporting const eval failure at {:?}", self.span); + let mut err = if let Some(lint_root) = lint_root { + let node_id = self.stacktrace + .iter() + .rev() + .filter_map(|frame| frame.lint_root) + .next() + .unwrap_or(lint_root); + tcx.struct_span_lint_node( + ::rustc::lint::builtin::CONST_ERR, + node_id, + tcx.span, + message, + ) + } else { + struct_error(tcx, message) + }; + err.span_label(self.span, self.error.to_string()); + for FrameInfo { span, location, .. } in &self.stacktrace { + err.span_label(*span, format!("inside call to `{}`", location)); + } + Some(err) + } +} + +pub fn struct_error<'a, 'gcx, 'tcx>( + tcx: TyCtxtAt<'a, 'gcx, 'tcx>, + msg: &str, +) -> DiagnosticBuilder<'tcx> { + struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) +} + +#[derive(Debug, Clone, RustcEncodable, RustcDecodable)] pub struct EvalError<'tcx> { pub kind: EvalErrorKind<'tcx, u64>, - pub backtrace: Option, } impl<'tcx> From> for EvalError<'tcx> { fn from(kind: EvalErrorKind<'tcx, u64>) -> Self { - let backtrace = match env::var("MIRI_BACKTRACE") { - Ok(ref val) if !val.is_empty() => Some(Backtrace::new_unresolved()), - _ => None - }; + match env::var("MIRI_BACKTRACE") { + Ok(ref val) if !val.is_empty() => { + let backtrace = Backtrace::new(); + + use std::fmt::Write; + let mut trace_text = "\n\nAn error occurred in miri:\n".to_string(); + write!(trace_text, "backtrace frames: {}\n", backtrace.frames().len()).unwrap(); + 'frames: for (i, frame) in backtrace.frames().iter().enumerate() { + if frame.symbols().is_empty() { + write!(trace_text, "{}: no symbols\n", i).unwrap(); + } + for symbol in frame.symbols() { + write!(trace_text, "{}: ", i).unwrap(); + if let Some(name) = symbol.name() { + write!(trace_text, "{}\n", name).unwrap(); + } else { + write!(trace_text, "\n").unwrap(); + } + write!(trace_text, "\tat ").unwrap(); + if let Some(file_path) = symbol.filename() { + write!(trace_text, "{}", file_path.display()).unwrap(); + } else { + write!(trace_text, "").unwrap(); + } + if let Some(line) = symbol.lineno() { + write!(trace_text, ":{}\n", line).unwrap(); + } else { + write!(trace_text, "\n").unwrap(); + } + } + } + error!("{}", trace_text); + }, + _ => {}, + } EvalError { kind, - backtrace, } } } @@ -37,7 +173,7 @@ pub enum EvalErrorKind<'tcx, O> { MachineError(String), FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>), NoMirFor(String), - UnterminatedCString(MemoryPointer), + UnterminatedCString(Pointer), DanglingPointerDeref, DoubleFree, InvalidMemoryAccess, @@ -45,13 +181,14 @@ pub enum EvalErrorKind<'tcx, O> { InvalidBool, InvalidDiscriminant, PointerOutOfBounds { - ptr: MemoryPointer, + ptr: Pointer, access: bool, - allocation_size: u64, + allocation_size: Size, }, InvalidNullPointerUsage, ReadPointerAsBytes, ReadBytesAsPointer, + ReadForeignStatic, InvalidPointerMath, ReadUndefBytes, DeadLocal, @@ -71,30 +208,30 @@ pub enum EvalErrorKind<'tcx, O> { TlsOutOfBounds, AbiViolation(String), AlignmentCheckFailed { - required: u64, - has: u64, + required: Align, + has: Align, }, MemoryLockViolation { - ptr: MemoryPointer, + ptr: Pointer, len: u64, frame: usize, access: AccessKind, lock: Lock, }, MemoryAcquireConflict { - ptr: MemoryPointer, + ptr: Pointer, len: u64, kind: AccessKind, lock: Lock, }, InvalidMemoryLockRelease { - ptr: MemoryPointer, + ptr: Pointer, len: u64, frame: usize, lock: Lock, }, DeallocatedLockedMemory { - ptr: MemoryPointer, + ptr: Pointer, lock: Lock, }, ValidationFailure(String), @@ -108,7 +245,7 @@ pub enum EvalErrorKind<'tcx, O> { DeallocatedWrongMemoryKind(String, String), ReallocateNonBasePtr, DeallocateNonBasePtr, - IncorrectAllocationInformation(u64, usize, u64, u64), + IncorrectAllocationInformation(Size, Size, Align, Align), Layout(layout::LayoutError<'tcx>), HeapAllocZeroBytes, HeapAllocNonPowerOfTwoAlignment(u64), @@ -119,11 +256,15 @@ pub enum EvalErrorKind<'tcx, O> { UnimplementedTraitSelection, /// Abort in case type errors are reached TypeckError, + /// Resolution can fail if we are in a too generic context + TooGeneric, + CheckMatchError, /// Cannot compute this constant because it depends on another one /// which already produced an error - ReferencedConstant, + ReferencedConstant(Lrc>), GeneratorResumedAfterReturn, GeneratorResumedAfterPanic, + InfiniteLoop, } pub type EvalResult<'tcx, T = ()> = Result>; @@ -165,6 +306,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> { "a raw memory access tried to access part of a pointer value as raw bytes", ReadBytesAsPointer => "a memory access tried to interpret some bytes as a pointer", + ReadForeignStatic => + "tried to read from foreign (extern) static", InvalidPointerMath => "attempted to do invalid arithmetic on pointers that would leak base addresses, e.g. comparing pointers into different allocations", ReadUndefBytes => @@ -237,7 +380,11 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> { "there were unresolved type arguments during trait selection", TypeckError => "encountered constants with type errors, stopping evaluation", - ReferencedConstant => + TooGeneric => + "encountered overly generic constant", + CheckMatchError => + "match checking failed", + ReferencedConstant(_) => "referenced constant has errors", Overflow(mir::BinOp::Add) => "attempt to add with overflow", Overflow(mir::BinOp::Sub) => "attempt to subtract with overflow", @@ -252,6 +399,8 @@ impl<'tcx, O> EvalErrorKind<'tcx, O> { RemainderByZero => "attempt to calculate the remainder with a divisor of zero", GeneratorResumedAfterReturn => "generator resumed after completion", GeneratorResumedAfterPanic => "generator resumed after panicking", + InfiniteLoop => + "duplicate interpreter state observed here, const evaluation will never terminate", } } } @@ -269,7 +418,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { PointerOutOfBounds { ptr, access, allocation_size } => { write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", if access { "memory access" } else { "pointer computed" }, - ptr.offset, ptr.alloc_id, allocation_size) + ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes()) }, MemoryLockViolation { ptr, len, frame, access, ref lock } => { write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}", @@ -305,7 +454,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c), AlignmentCheckFailed { required, has } => write!(f, "tried to access memory with alignment {}, but alignment {} is required", - has, required), + has.abi(), required.abi()), TypeNotPrimitive(ty) => write!(f, "expected primitive type, got {}", ty), Layout(ref err) => @@ -315,7 +464,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { MachineError(ref inner) => write!(f, "{}", inner), IncorrectAllocationInformation(size, size2, align, align2) => - write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2), + write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()), _ => write!(f, "{}", self.description()), } } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 546c7a920d538..4164fe3fd933b 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -8,22 +8,35 @@ macro_rules! err { mod error; mod value; -pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage}; +pub use self::error::{ + EvalError, EvalResult, EvalErrorKind, AssertMessage, ConstEvalErr, struct_error, + FrameInfo, ConstEvalResult, +}; -pub use self::value::{PrimVal, PrimValKind, Value, Pointer}; +pub use self::value::{Scalar, Value, ConstValue}; -use std::collections::BTreeMap; use std::fmt; use mir; use hir::def_id::DefId; -use ty::{self, TyCtxt}; -use ty::layout::{self, Align, HasDataLayout}; +use ty::{self, TyCtxt, Instance}; +use ty::layout::{self, Align, HasDataLayout, Size}; use middle::region; use std::iter; +use std::io; +use std::ops::{Deref, DerefMut}; +use std::hash::Hash; use syntax::ast::Mutability; -use rustc_serialize::{Encoder, Decoder, Decodable, Encodable}; - -#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)] +use rustc_serialize::{Encoder, Decodable, Encodable}; +use rustc_data_structures::sorted_map::SortedMap; +use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{Lock as Mutex, HashMapExt}; +use rustc_data_structures::tiny_list::TinyList; +use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian}; +use ty::codec::TyDecoder; +use std::sync::atomic::{AtomicU32, Ordering}; +use std::num::NonZeroU32; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum Lock { NoLock, WriteLock(DynamicLifetime), @@ -104,51 +117,58 @@ pub trait PointerArithmetic: layout::HasDataLayout { impl PointerArithmetic for T {} -#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] -pub struct MemoryPointer { +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)] +pub struct Pointer { pub alloc_id: AllocId, - pub offset: u64, + pub offset: Size, +} + +/// Produces a `Pointer` which points to the beginning of the Allocation +impl From for Pointer { + fn from(alloc_id: AllocId) -> Self { + Pointer::new(alloc_id, Size::ZERO) + } } -impl<'tcx> MemoryPointer { - pub fn new(alloc_id: AllocId, offset: u64) -> Self { - MemoryPointer { alloc_id, offset } +impl<'tcx> Pointer { + pub fn new(alloc_id: AllocId, offset: Size) -> Self { + Pointer { alloc_id, offset } } pub(crate) fn wrapping_signed_offset(self, i: i64, cx: C) -> Self { - MemoryPointer::new( + Pointer::new( self.alloc_id, - cx.data_layout().wrapping_signed_offset(self.offset, i), + Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)), ) } pub fn overflowing_signed_offset(self, i: i128, cx: C) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset, i); - (MemoryPointer::new(self.alloc_id, res), over) + let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i); + (Pointer::new(self.alloc_id, Size::from_bytes(res)), over) } pub(crate) fn signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { - Ok(MemoryPointer::new( + Ok(Pointer::new( self.alloc_id, - cx.data_layout().signed_offset(self.offset, i)?, + Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?), )) } - pub fn overflowing_offset(self, i: u64, cx: C) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_offset(self.offset, i); - (MemoryPointer::new(self.alloc_id, res), over) + pub fn overflowing_offset(self, i: Size, cx: C) -> (Self, bool) { + let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes()); + (Pointer::new(self.alloc_id, Size::from_bytes(res)), over) } - pub fn offset(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { - Ok(MemoryPointer::new( + pub fn offset(self, i: Size, cx: C) -> EvalResult<'tcx, Self> { + Ok(Pointer::new( self.alloc_id, - cx.data_layout().offset(self.offset, i)?, + Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?), )) } } -#[derive(Copy, Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)] +#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd, Debug)] pub struct AllocId(pub u64); impl ::rustc_serialize::UseSpecializedEncodable for AllocId {} @@ -169,63 +189,186 @@ pub fn specialized_encode_alloc_id< tcx: TyCtxt<'a, 'tcx, 'tcx>, alloc_id: AllocId, ) -> Result<(), E::Error> { - if let Some(alloc) = tcx.interpret_interner.get_alloc(alloc_id) { - trace!("encoding {:?} with {:#?}", alloc_id, alloc); - AllocKind::Alloc.encode(encoder)?; - alloc.encode(encoder)?; - } else if let Some(fn_instance) = tcx.interpret_interner.get_fn(alloc_id) { - trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); - AllocKind::Fn.encode(encoder)?; - fn_instance.encode(encoder)?; - } else if let Some(did) = tcx.interpret_interner.get_static(alloc_id) { - // referring to statics doesn't need to know about their allocations, just about its DefId - AllocKind::Static.encode(encoder)?; - did.encode(encoder)?; - } else { - bug!("alloc id without corresponding allocation: {}", alloc_id); + let alloc_type: AllocType<'tcx, &'tcx Allocation> = + tcx.alloc_map.lock().get(alloc_id).expect("no value for AllocId"); + match alloc_type { + AllocType::Memory(alloc) => { + trace!("encoding {:?} with {:#?}", alloc_id, alloc); + AllocKind::Alloc.encode(encoder)?; + alloc.encode(encoder)?; + } + AllocType::Function(fn_instance) => { + trace!("encoding {:?} with {:#?}", alloc_id, fn_instance); + AllocKind::Fn.encode(encoder)?; + fn_instance.encode(encoder)?; + } + AllocType::Static(did) => { + // referring to statics doesn't need to know about their allocations, + // just about its DefId + AllocKind::Static.encode(encoder)?; + did.encode(encoder)?; + } } Ok(()) } -pub fn specialized_decode_alloc_id< - 'a, 'tcx, - D: Decoder, - CACHE: FnOnce(&mut D, AllocId), ->( - decoder: &mut D, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - cache: CACHE, -) -> Result { - match AllocKind::decode(decoder)? { - AllocKind::Alloc => { - let alloc_id = tcx.interpret_interner.reserve(); - trace!("creating alloc id {:?}", alloc_id); - // insert early to allow recursive allocs - cache(decoder, alloc_id); - - let allocation = Allocation::decode(decoder)?; - trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); - let allocation = tcx.intern_const_alloc(allocation); - tcx.interpret_interner.intern_at_reserved(alloc_id, allocation); - - Ok(alloc_id) - }, - AllocKind::Fn => { - trace!("creating fn alloc id"); - let instance = ty::Instance::decode(decoder)?; - trace!("decoded fn alloc instance: {:?}", instance); - let id = tcx.interpret_interner.create_fn_alloc(instance); - trace!("created fn alloc id: {:?}", id); - cache(decoder, id); - Ok(id) - }, - AllocKind::Static => { - trace!("creating extern static alloc id at"); - let did = DefId::decode(decoder)?; - let alloc_id = tcx.interpret_interner.cache_static(did); - cache(decoder, alloc_id); - Ok(alloc_id) - }, +// Used to avoid infinite recursion when decoding cyclic allocations. +type DecodingSessionId = NonZeroU32; + +#[derive(Clone)] +enum State { + Empty, + InProgressNonAlloc(TinyList), + InProgress(TinyList, AllocId), + Done(AllocId), +} + +pub struct AllocDecodingState { + // For each AllocId we keep track of which decoding state it's currently in. + decoding_state: Vec>, + // The offsets of each allocation in the data stream. + data_offsets: Vec, +} + +impl AllocDecodingState { + + pub fn new_decoding_session(&self) -> AllocDecodingSession { + static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0); + let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst); + + // Make sure this is never zero + let session_id = DecodingSessionId::new((counter & 0x7FFFFFFF) + 1).unwrap(); + + AllocDecodingSession { + state: self, + session_id, + } + } + + pub fn new(data_offsets: Vec) -> AllocDecodingState { + let decoding_state: Vec<_> = ::std::iter::repeat(Mutex::new(State::Empty)) + .take(data_offsets.len()) + .collect(); + + AllocDecodingState { + decoding_state: decoding_state, + data_offsets, + } + } +} + +#[derive(Copy, Clone)] +pub struct AllocDecodingSession<'s> { + state: &'s AllocDecodingState, + session_id: DecodingSessionId, +} + +impl<'s> AllocDecodingSession<'s> { + + // Decodes an AllocId in a thread-safe way. + pub fn decode_alloc_id<'a, 'tcx, D>(&self, + decoder: &mut D) + -> Result + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, + { + // Read the index of the allocation + let idx = decoder.read_u32()? as usize; + let pos = self.state.data_offsets[idx] as usize; + + // Decode the AllocKind now so that we know if we have to reserve an + // AllocId. + let (alloc_kind, pos) = decoder.with_position(pos, |decoder| { + let alloc_kind = AllocKind::decode(decoder)?; + Ok((alloc_kind, decoder.position())) + })?; + + // Check the decoding state, see if it's already decoded or if we should + // decode it here. + let alloc_id = { + let mut entry = self.state.decoding_state[idx].lock(); + + match *entry { + State::Done(alloc_id) => { + return Ok(alloc_id); + } + ref mut entry @ State::Empty => { + // We are allowed to decode + match alloc_kind { + AllocKind::Alloc => { + // If this is an allocation, we need to reserve an + // AllocId so we can decode cyclic graphs. + let alloc_id = decoder.tcx().alloc_map.lock().reserve(); + *entry = State::InProgress( + TinyList::new_single(self.session_id), + alloc_id); + Some(alloc_id) + }, + AllocKind::Fn | AllocKind::Static => { + // Fns and statics cannot be cyclic and their AllocId + // is determined later by interning + *entry = State::InProgressNonAlloc( + TinyList::new_single(self.session_id)); + None + } + } + } + State::InProgressNonAlloc(ref mut sessions) => { + if sessions.contains(&self.session_id) { + bug!("This should be unreachable") + } else { + // Start decoding concurrently + sessions.insert(self.session_id); + None + } + } + State::InProgress(ref mut sessions, alloc_id) => { + if sessions.contains(&self.session_id) { + // Don't recurse. + return Ok(alloc_id) + } else { + // Start decoding concurrently + sessions.insert(self.session_id); + Some(alloc_id) + } + } + } + }; + + // Now decode the actual data + let alloc_id = decoder.with_position(pos, |decoder| { + match alloc_kind { + AllocKind::Alloc => { + let allocation = <&'tcx Allocation as Decodable>::decode(decoder)?; + // We already have a reserved AllocId. + let alloc_id = alloc_id.unwrap(); + trace!("decoded alloc {:?} {:#?}", alloc_id, allocation); + decoder.tcx().alloc_map.lock().set_id_same_memory(alloc_id, allocation); + Ok(alloc_id) + }, + AllocKind::Fn => { + assert!(alloc_id.is_none()); + trace!("creating fn alloc id"); + let instance = ty::Instance::decode(decoder)?; + trace!("decoded fn alloc instance: {:?}", instance); + let alloc_id = decoder.tcx().alloc_map.lock().create_fn_alloc(instance); + Ok(alloc_id) + }, + AllocKind::Static => { + assert!(alloc_id.is_none()); + trace!("creating extern static alloc id at"); + let did = DefId::decode(decoder)?; + let alloc_id = decoder.tcx().alloc_map.lock().intern_static(did); + Ok(alloc_id) + } + } + })?; + + self.state.decoding_state[idx].with_lock(|entry| { + *entry = State::Done(alloc_id); + }); + + Ok(alloc_id) } } @@ -235,38 +378,214 @@ impl fmt::Display for AllocId { } } -#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Debug, Clone, Eq, PartialEq, Hash, RustcDecodable, RustcEncodable)] +pub enum AllocType<'tcx, M> { + /// The alloc id is used as a function pointer + Function(Instance<'tcx>), + /// The alloc id points to a static variable + Static(DefId), + /// The alloc id points to memory + Memory(M) +} + +pub struct AllocMap<'tcx, M> { + /// Lets you know what an AllocId refers to + id_to_type: FxHashMap>, + + /// Used to ensure that functions and statics only get one associated AllocId + type_interner: FxHashMap, AllocId>, + + /// The AllocId to assign to the next requested id. + /// Always incremented, never gets smaller. + next_id: AllocId, +} + +impl<'tcx, M: fmt::Debug + Eq + Hash + Clone> AllocMap<'tcx, M> { + pub fn new() -> Self { + AllocMap { + id_to_type: FxHashMap(), + type_interner: FxHashMap(), + next_id: AllocId(0), + } + } + + /// obtains a new allocation ID that can be referenced but does not + /// yet have an allocation backing it. + pub fn reserve( + &mut self, + ) -> AllocId { + let next = self.next_id; + self.next_id.0 = self.next_id.0 + .checked_add(1) + .expect("You overflowed a u64 by incrementing by 1... \ + You've just earned yourself a free drink if we ever meet. \ + Seriously, how did you do that?!"); + next + } + + fn intern(&mut self, alloc_type: AllocType<'tcx, M>) -> AllocId { + if let Some(&alloc_id) = self.type_interner.get(&alloc_type) { + return alloc_id; + } + let id = self.reserve(); + debug!("creating alloc_type {:?} with id {}", alloc_type, id); + self.id_to_type.insert(id, alloc_type.clone()); + self.type_interner.insert(alloc_type, id); + id + } + + // FIXME: Check if functions have identity. If not, we should not intern these, + // but instead create a new id per use. + // Alternatively we could just make comparing function pointers an error. + pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> AllocId { + self.intern(AllocType::Function(instance)) + } + + pub fn get(&self, id: AllocId) -> Option> { + self.id_to_type.get(&id).cloned() + } + + pub fn unwrap_memory(&self, id: AllocId) -> M { + match self.get(id) { + Some(AllocType::Memory(mem)) => mem, + _ => bug!("expected allocation id {} to point to memory", id), + } + } + + pub fn intern_static(&mut self, static_id: DefId) -> AllocId { + self.intern(AllocType::Static(static_id)) + } + + pub fn allocate(&mut self, mem: M) -> AllocId { + let id = self.reserve(); + self.set_id_memory(id, mem); + id + } + + pub fn set_id_memory(&mut self, id: AllocId, mem: M) { + if let Some(old) = self.id_to_type.insert(id, AllocType::Memory(mem)) { + bug!("tried to set allocation id {}, but it was already existing as {:#?}", id, old); + } + } + + pub fn set_id_same_memory(&mut self, id: AllocId, mem: M) { + self.id_to_type.insert_same(id, AllocType::Memory(mem)); + } +} + +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct Allocation { /// The actual bytes of the allocation. /// Note that the bytes of a pointer represent the offset of the pointer pub bytes: Vec, /// Maps from byte addresses to allocations. /// Only the first byte of a pointer is inserted into the map. - pub relocations: BTreeMap, + pub relocations: Relocations, /// Denotes undefined memory. Reading from undefined memory is forbidden in miri pub undef_mask: UndefMask, /// The alignment of the allocation to detect unaligned reads. pub align: Align, - /// Whether the allocation (of a static) should be put into mutable memory when translating + /// Whether the allocation (of a static) should be put into mutable memory when codegenning /// /// Only happens for `static mut` or `static` with interior mutability pub runtime_mutability: Mutability, } impl Allocation { - pub fn from_bytes(slice: &[u8]) -> Self { - let mut undef_mask = UndefMask::new(0); - undef_mask.grow(slice.len() as u64, true); + pub fn from_bytes(slice: &[u8], align: Align) -> Self { + let mut undef_mask = UndefMask::new(Size::ZERO); + undef_mask.grow(Size::from_bytes(slice.len() as u64), true); Self { bytes: slice.to_owned(), - relocations: BTreeMap::new(), + relocations: Relocations::new(), undef_mask, - align: Align::from_bytes(1, 1).unwrap(), + align, + runtime_mutability: Mutability::Immutable, + } + } + + pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self { + Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap()) + } + + pub fn undef(size: Size, align: Align) -> Self { + assert_eq!(size.bytes() as usize as u64, size.bytes()); + Allocation { + bytes: vec![0; size.bytes() as usize], + relocations: Relocations::new(), + undef_mask: UndefMask::new(size), + align, runtime_mutability: Mutability::Immutable, } } } +impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {} + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct Relocations(SortedMap); + +impl Relocations { + pub fn new() -> Relocations { + Relocations(SortedMap::new()) + } + + // The caller must guarantee that the given relocations are already sorted + // by address and contain no duplicates. + pub fn from_presorted(r: Vec<(Size, AllocId)>) -> Relocations { + Relocations(SortedMap::from_presorted_elements(r)) + } +} + +impl Deref for Relocations { + type Target = SortedMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Relocations { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Methods to access integers in the target endianness +//////////////////////////////////////////////////////////////////////////////// + +pub fn write_target_uint( + endianness: layout::Endian, + mut target: &mut [u8], + data: u128, +) -> Result<(), io::Error> { + let len = target.len(); + match endianness { + layout::Endian::Little => target.write_uint128::(data, len), + layout::Endian::Big => target.write_uint128::(data, len), + } +} + +pub fn write_target_int( + endianness: layout::Endian, + mut target: &mut [u8], + data: i128, +) -> Result<(), io::Error> { + let len = target.len(); + match endianness { + layout::Endian::Little => target.write_int128::(data, len), + layout::Endian::Big => target.write_int128::(data, len), + } +} + +pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result { + match endianness { + layout::Endian::Little => source.read_uint128::(source.len()), + layout::Endian::Big => source.read_uint128::(source.len()), + } +} + //////////////////////////////////////////////////////////////////////////////// // Undefined byte tracking //////////////////////////////////////////////////////////////////////////////// @@ -274,38 +593,38 @@ impl Allocation { type Block = u64; const BLOCK_SIZE: u64 = 64; -#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct UndefMask { blocks: Vec, - len: u64, + len: Size, } impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len}); impl UndefMask { - pub fn new(size: u64) -> Self { + pub fn new(size: Size) -> Self { let mut m = UndefMask { blocks: vec![], - len: 0, + len: Size::ZERO, }; m.grow(size, false); m } /// Check whether the range `start..end` (end-exclusive) is entirely defined. - pub fn is_range_defined(&self, start: u64, end: u64) -> bool { + pub fn is_range_defined(&self, start: Size, end: Size) -> bool { if end > self.len { return false; } - for i in start..end { - if !self.get(i) { + for i in start.bytes()..end.bytes() { + if !self.get(Size::from_bytes(i)) { return false; } } true } - pub fn set_range(&mut self, start: u64, end: u64, new_state: bool) { + pub fn set_range(&mut self, start: Size, end: Size, new_state: bool) { let len = self.len; if end > len { self.grow(end - len, new_state); @@ -313,18 +632,20 @@ impl UndefMask { self.set_range_inbounds(start, end, new_state); } - pub fn set_range_inbounds(&mut self, start: u64, end: u64, new_state: bool) { - for i in start..end { - self.set(i, new_state); + pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) { + for i in start.bytes()..end.bytes() { + self.set(Size::from_bytes(i), new_state); } } - pub fn get(&self, i: u64) -> bool { + #[inline] + pub fn get(&self, i: Size) -> bool { let (block, bit) = bit_index(i); (self.blocks[block] & 1 << bit) != 0 } - pub fn set(&mut self, i: u64, new_state: bool) { + #[inline] + pub fn set(&mut self, i: Size, new_state: bool) { let (block, bit) = bit_index(i); if new_state { self.blocks[block] |= 1 << bit; @@ -333,10 +654,10 @@ impl UndefMask { } } - pub fn grow(&mut self, amount: u64, new_state: bool) { - let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len; - if amount > unused_trailing_bits { - let additional_blocks = amount / BLOCK_SIZE + 1; + pub fn grow(&mut self, amount: Size, new_state: bool) { + let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len.bytes(); + if amount.bytes() > unused_trailing_bits { + let additional_blocks = amount.bytes() / BLOCK_SIZE + 1; assert_eq!(additional_blocks as usize as u64, additional_blocks); self.blocks.extend( iter::repeat(0).take(additional_blocks as usize), @@ -348,7 +669,9 @@ impl UndefMask { } } -fn bit_index(bits: u64) -> (usize, usize) { +#[inline] +fn bit_index(bits: Size) -> (usize, usize) { + let bits = bits.bytes(); let a = bits / BLOCK_SIZE; let b = bits % BLOCK_SIZE; assert_eq!(a as usize as u64, a); diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 7289d74bfbb1b..ffd138c9c4815 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,24 +1,88 @@ #![allow(unknown_lints)] -use ty::layout::{Align, HasDataLayout}; +use ty::layout::{Align, HasDataLayout, Size}; use ty; +use ty::subst::Substs; +use hir::def_id::DefId; + +use super::{EvalResult, Pointer, PointerArithmetic, Allocation}; + +/// Represents a constant value in Rust. Scalar and ScalarPair are optimizations which +/// matches Value's optimizations for easy conversions between these two types +#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)] +pub enum ConstValue<'tcx> { + /// Never returned from the `const_eval` query, but the HIR contains these frequently in order + /// to allow HIR creation to happen for everything before needing to be able to run constant + /// evaluation + Unevaluated(DefId, &'tcx Substs<'tcx>), + /// Used only for types with layout::abi::Scalar ABI and ZSTs which use Scalar::undef() + Scalar(Scalar), + /// Used only for types with layout::abi::ScalarPair + ScalarPair(Scalar, Scalar), + /// Used only for the remaining cases. An allocation + offset into the allocation + ByRef(&'tcx Allocation, Size), +} + +impl<'tcx> ConstValue<'tcx> { + #[inline] + pub fn from_byval_value(val: Value) -> Self { + match val { + Value::ByRef(..) => bug!(), + Value::ScalarPair(a, b) => ConstValue::ScalarPair(a, b), + Value::Scalar(val) => ConstValue::Scalar(val), + } + } + + #[inline] + pub fn to_byval_value(&self) -> Option { + match *self { + ConstValue::Unevaluated(..) | + ConstValue::ByRef(..) => None, + ConstValue::ScalarPair(a, b) => Some(Value::ScalarPair(a, b)), + ConstValue::Scalar(val) => Some(Value::Scalar(val)), + } + } + + #[inline] + pub fn from_scalar(val: Scalar) -> Self { + ConstValue::Scalar(val) + } + + #[inline] + pub fn to_scalar(&self) -> Option { + match *self { + ConstValue::Unevaluated(..) | + ConstValue::ByRef(..) | + ConstValue::ScalarPair(..) => None, + ConstValue::Scalar(val) => Some(val), + } + } + + #[inline] + pub fn to_bits(&self, size: Size) -> Option { + self.to_scalar()?.to_bits(size).ok() + } -use super::{EvalResult, MemoryPointer, PointerArithmetic}; + #[inline] + pub fn to_ptr(&self) -> Option { + self.to_scalar()?.to_ptr().ok() + } +} /// A `Value` represents a single self-contained Rust value. /// /// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve -/// value held directly, outside of any allocation (`ByVal`). For `ByRef`-values, we remember +/// value held directly, outside of any allocation (`Scalar`). For `ByRef`-values, we remember /// whether the pointer is supposed to be aligned or not (also see Place). /// /// For optimization of a few very common cases, there is also a representation for a pair of -/// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary -/// operations and fat pointers. This idea was taken from rustc's trans. -#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] +/// primitive values (`ScalarPair`). It allows Miri to avoid making allocations for checked binary +/// operations and fat pointers. This idea was taken from rustc's codegen. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)] pub enum Value { - ByRef(Pointer, Align), - ByVal(PrimVal), - ByValPair(PrimVal, PrimVal), + ByRef(Scalar, Align), + Scalar(Scalar), + ScalarPair(Scalar, Scalar), } impl<'tcx> ty::TypeFoldable<'tcx> for Value { @@ -30,277 +94,171 @@ impl<'tcx> ty::TypeFoldable<'tcx> for Value { } } -/// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally. -/// This type clears up a few APIs where having a `PrimVal` argument for something that is -/// potentially an integer pointer or a pointer to an allocation was unclear. -/// -/// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just -/// the representation of pointers. Also all the sites that convert between primvals and pointers -/// are explicit now (and rare!) -#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] -pub struct Pointer { - pub primval: PrimVal, -} - -impl<'tcx> Pointer { - pub fn null() -> Self { - PrimVal::Bytes(0).into() - } - pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { - self.primval.to_ptr() - } - pub fn into_inner_primval(self) -> PrimVal { - self.primval +impl<'tcx> Scalar { + pub fn ptr_null(cx: C) -> Self { + Scalar::Bits { + bits: 0, + defined: cx.data_layout().pointer_size.bits() as u8, + } } - pub fn signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { + pub fn ptr_signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from( - PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128), - )) + match self { + Scalar::Bits { bits, defined } => { + let pointer_size = layout.pointer_size.bits() as u8; + if defined < pointer_size { + err!(ReadUndefBytes) + } else { + Ok(Scalar::Bits { + bits: layout.signed_offset(bits as u64, i)? as u128, + defined: pointer_size, + }) + } } - PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from), - PrimVal::Undef => err!(ReadUndefBytes), + Scalar::Ptr(ptr) => ptr.signed_offset(i, layout).map(Scalar::Ptr), } } - pub fn offset(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { + pub fn ptr_offset(self, i: Size, cx: C) -> EvalResult<'tcx, Self> { let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from( - PrimVal::Bytes(layout.offset(b as u64, i)? as u128), - )) + match self { + Scalar::Bits { bits, defined } => { + let pointer_size = layout.pointer_size.bits() as u8; + if defined < pointer_size { + err!(ReadUndefBytes) + } else { + Ok(Scalar::Bits { + bits: layout.offset(bits as u64, i.bytes())? as u128, + defined: pointer_size, + }) } - PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from), - PrimVal::Undef => err!(ReadUndefBytes), + } + Scalar::Ptr(ptr) => ptr.offset(i, layout).map(Scalar::Ptr), } } - pub fn wrapping_signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { + pub fn ptr_wrapping_signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from(PrimVal::Bytes( - layout.wrapping_signed_offset(b as u64, i) as u128, - ))) + match self { + Scalar::Bits { bits, defined } => { + let pointer_size = layout.pointer_size.bits() as u8; + if defined < pointer_size { + err!(ReadUndefBytes) + } else { + Ok(Scalar::Bits { + bits: layout.wrapping_signed_offset(bits as u64, i) as u128, + defined: pointer_size, + }) + } } - PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))), - PrimVal::Undef => err!(ReadUndefBytes), + Scalar::Ptr(ptr) => Ok(Scalar::Ptr(ptr.wrapping_signed_offset(i, layout))), } } - pub fn is_null(self) -> EvalResult<'tcx, bool> { - match self.primval { - PrimVal::Bytes(b) => Ok(b == 0), - PrimVal::Ptr(_) => Ok(false), - PrimVal::Undef => err!(ReadUndefBytes), + pub fn is_null_ptr(self, cx: C) -> EvalResult<'tcx, bool> { + match self { + Scalar::Bits { + bits, defined, + } => if defined < cx.data_layout().pointer_size.bits() as u8 { + err!(ReadUndefBytes) + } else { + Ok(bits == 0) + }, + Scalar::Ptr(_) => Ok(false), } } - pub fn to_value_with_len(self, len: u64) -> Value { - Value::ByValPair(self.primval, PrimVal::from_u128(len as u128)) + pub fn to_value_with_len(self, len: u64, cx: C) -> Value { + Value::ScalarPair(self, Scalar::Bits { + bits: len as u128, + defined: cx.data_layout().pointer_size.bits() as u8, + }) } - pub fn to_value_with_vtable(self, vtable: MemoryPointer) -> Value { - Value::ByValPair(self.primval, PrimVal::Ptr(vtable)) + pub fn to_value_with_vtable(self, vtable: Pointer) -> Value { + Value::ScalarPair(self, Scalar::Ptr(vtable)) } pub fn to_value(self) -> Value { - Value::ByVal(self.primval) - } -} - -impl ::std::convert::From for Pointer { - fn from(primval: PrimVal) -> Self { - Pointer { primval } + Value::Scalar(self) } } -impl ::std::convert::From for Pointer { - fn from(ptr: MemoryPointer) -> Self { - PrimVal::Ptr(ptr).into() +impl From for Scalar { + fn from(ptr: Pointer) -> Self { + Scalar::Ptr(ptr) } } -/// A `PrimVal` represents an immediate, primitive value existing outside of a +/// A `Scalar` represents an immediate, primitive value existing outside of a /// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in -/// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes -/// of a simple value, a pointer into another `Allocation`, or be undefined. -#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] -pub enum PrimVal { +/// size. Like a range of bytes in an `Allocation`, a `Scalar` can either represent the raw bytes +/// of a simple value or a pointer into another `Allocation` +#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, RustcEncodable, RustcDecodable, Hash)] +pub enum Scalar { /// The raw bytes of a simple value. - Bytes(u128), + Bits { + /// The first `defined` number of bits are valid + defined: u8, + bits: u128, + }, /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of - /// relocations, but a `PrimVal` is only large enough to contain one, so we just represent the - /// relocation and its associated offset together as a `MemoryPointer` here. - Ptr(MemoryPointer), - - /// An undefined `PrimVal`, for representing values that aren't safe to examine, but are safe - /// to copy around, just like undefined bytes in an `Allocation`. - Undef, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum PrimValKind { - I8, I16, I32, I64, I128, - U8, U16, U32, U64, U128, - F32, F64, - Ptr, FnPtr, - Bool, - Char, + /// relocations, but a `Scalar` is only large enough to contain one, so we just represent the + /// relocation and its associated offset together as a `Pointer` here. + Ptr(Pointer), } -impl<'tcx> PrimVal { - pub fn from_u128(n: u128) -> Self { - PrimVal::Bytes(n) - } - - pub fn from_i128(n: i128) -> Self { - PrimVal::Bytes(n as u128) +impl<'tcx> Scalar { + pub fn undef() -> Self { + Scalar::Bits { bits: 0, defined: 0 } } pub fn from_bool(b: bool) -> Self { - PrimVal::Bytes(b as u128) + // FIXME: can we make defined `1`? + Scalar::Bits { bits: b as u128, defined: 8 } } pub fn from_char(c: char) -> Self { - PrimVal::Bytes(c as u128) + Scalar::Bits { bits: c as u128, defined: 32 } } - pub fn to_bytes(self) -> EvalResult<'tcx, u128> { + pub fn to_bits(self, size: Size) -> EvalResult<'tcx, u128> { match self { - PrimVal::Bytes(b) => Ok(b), - PrimVal::Ptr(_) => err!(ReadPointerAsBytes), - PrimVal::Undef => err!(ReadUndefBytes), + Scalar::Bits { .. } if size.bits() == 0 => bug!("to_bits cannot be used with zsts"), + Scalar::Bits { bits, defined } if size.bits() <= defined as u64 => Ok(bits), + Scalar::Bits { .. } => err!(ReadUndefBytes), + Scalar::Ptr(_) => err!(ReadPointerAsBytes), } } - pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { + pub fn to_ptr(self) -> EvalResult<'tcx, Pointer> { match self { - PrimVal::Bytes(_) => err!(ReadBytesAsPointer), - PrimVal::Ptr(p) => Ok(p), - PrimVal::Undef => err!(ReadUndefBytes), + Scalar::Bits {..} => err!(ReadBytesAsPointer), + Scalar::Ptr(p) => Ok(p), } } - pub fn is_bytes(self) -> bool { + pub fn is_bits(self) -> bool { match self { - PrimVal::Bytes(_) => true, + Scalar::Bits { .. } => true, _ => false, } } pub fn is_ptr(self) -> bool { match self { - PrimVal::Ptr(_) => true, - _ => false, - } - } - - pub fn is_undef(self) -> bool { - match self { - PrimVal::Undef => true, + Scalar::Ptr(_) => true, _ => false, } } - pub fn to_u128(self) -> EvalResult<'tcx, u128> { - self.to_bytes() - } - - pub fn to_u64(self) -> EvalResult<'tcx, u64> { - self.to_bytes().map(|b| { - assert_eq!(b as u64 as u128, b); - b as u64 - }) - } - - pub fn to_i32(self) -> EvalResult<'tcx, i32> { - self.to_bytes().map(|b| { - assert_eq!(b as i32 as u128, b); - b as i32 - }) - } - - pub fn to_i128(self) -> EvalResult<'tcx, i128> { - self.to_bytes().map(|b| b as i128) - } - - pub fn to_i64(self) -> EvalResult<'tcx, i64> { - self.to_bytes().map(|b| { - assert_eq!(b as i64 as u128, b); - b as i64 - }) - } - pub fn to_bool(self) -> EvalResult<'tcx, bool> { - match self.to_bytes()? { - 0 => Ok(false), - 1 => Ok(true), - _ => err!(InvalidBool), - } - } -} - -impl PrimValKind { - pub fn is_int(self) -> bool { - use self::PrimValKind::*; - match self { - I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true, - _ => false, - } - } - - pub fn is_signed_int(self) -> bool { - use self::PrimValKind::*; match self { - I8 | I16 | I32 | I64 | I128 => true, - _ => false, - } - } - - pub fn is_float(self) -> bool { - use self::PrimValKind::*; - match self { - F32 | F64 => true, - _ => false, - } - } - - pub fn from_uint_size(size: u64) -> Self { - match size { - 1 => PrimValKind::U8, - 2 => PrimValKind::U16, - 4 => PrimValKind::U32, - 8 => PrimValKind::U64, - 16 => PrimValKind::U128, - _ => bug!("can't make uint with size {}", size), - } - } - - pub fn from_int_size(size: u64) -> Self { - match size { - 1 => PrimValKind::I8, - 2 => PrimValKind::I16, - 4 => PrimValKind::I32, - 8 => PrimValKind::I64, - 16 => PrimValKind::I128, - _ => bug!("can't make int with size {}", size), - } - } - - pub fn is_ptr(self) -> bool { - use self::PrimValKind::*; - match self { - Ptr | FnPtr => true, - _ => false, + Scalar::Bits { bits: 0, defined: 8 } => Ok(false), + Scalar::Bits { bits: 1, defined: 8 } => Ok(true), + _ => err!(InvalidBool), } } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 37f6d47ff849d..4bfb4c96497ff 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -10,49 +10,46 @@ //! MIR datatypes and passes. See the [rustc guide] for more info. //! -//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html +//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir/index.html use graphviz::IntoCow; -use middle::const_val::ConstVal; -use middle::region; -use rustc_data_structures::sync::{Lrc}; -use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators}; -use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors}; -use rustc_data_structures::control_flow_graph::ControlFlowGraph; -use rustc_data_structures::small_vec::SmallVec; -use rustc_serialize as serialize; use hir::def::CtorKind; use hir::def_id::DefId; +use hir::{self, HirId, InlineAsm}; +use middle::region; +use mir::interpret::{EvalErrorKind, Scalar, Value}; use mir::visit::MirVisitable; -use mir::interpret::{Value, PrimVal, EvalErrorKind}; -use ty::subst::{Subst, Substs}; -use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, Region, Ty, TyCtxt, GeneratorInterior}; -use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use ty::TypeAndMut; -use util::ppaux; -use std::slice; -use hir::{self, InlineAsm}; -use std::borrow::{Cow}; +use rustc_apfloat::ieee::{Double, Single}; +use rustc_apfloat::Float; +use rustc_data_structures::graph::dominators::{dominators, Dominators}; +use rustc_data_structures::graph::{self, GraphPredecessors, GraphSuccessors}; +use rustc_data_structures::indexed_vec::{Idx, IndexVec}; +use rustc_data_structures::small_vec::SmallVec; +use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::ReadGuard; +use rustc_serialize as serialize; +use std::borrow::Cow; use std::fmt::{self, Debug, Formatter, Write}; -use std::{iter, mem, option, u32}; use std::ops::{Index, IndexMut}; +use std::slice; use std::vec::IntoIter; +use std::{iter, mem, option, u32}; use syntax::ast::{self, Name}; use syntax::symbol::InternedString; use syntax_pos::{Span, DUMMY_SP}; -use rustc_apfloat::ieee::{Single, Double}; -use rustc_apfloat::Float; +use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::subst::{Subst, Substs}; +use ty::{self, AdtDef, CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty, TyCtxt}; +use util::ppaux; pub use mir::interpret::AssertMessage; mod cache; -pub mod tcx; -pub mod visit; -pub mod traversal; pub mod interpret; pub mod mono; +pub mod tcx; +pub mod traversal; +pub mod visit; /// Types for locals type LocalDecls<'tcx> = IndexVec>; @@ -80,13 +77,13 @@ pub struct Mir<'tcx> { /// that indexes into this vector. basic_blocks: IndexVec>, - /// List of visibility (lexical) scopes; these are referenced by statements - /// and used (eventually) for debuginfo. Indexed by a `VisibilityScope`. - pub visibility_scopes: IndexVec, + /// List of source scopes; these are referenced by statements + /// and used for debuginfo. Indexed by a `SourceScope`. + pub source_scopes: IndexVec, - /// Crate-local information for each visibility scope, that can't (and + /// Crate-local information for each source scope, that can't (and /// needn't) be tracked across crates. - pub visibility_scope_info: ClearCrossCrate>, + pub source_scope_local_data: ClearCrossCrate>, /// Rvalues promoted from this function, such as borrows of constants. /// Each of them is the Mir of a constant with the fn's type parameters @@ -131,32 +128,36 @@ pub struct Mir<'tcx> { pub span: Span, /// A cache for various calculations - cache: cache::Cache + cache: cache::Cache, } /// where execution begins pub const START_BLOCK: BasicBlock = BasicBlock(0); impl<'tcx> Mir<'tcx> { - pub fn new(basic_blocks: IndexVec>, - visibility_scopes: IndexVec, - visibility_scope_info: ClearCrossCrate>, - promoted: IndexVec>, - yield_ty: Option>, - local_decls: IndexVec>, - arg_count: usize, - upvar_decls: Vec, - span: Span) -> Self - { + pub fn new( + basic_blocks: IndexVec>, + source_scopes: IndexVec, + source_scope_local_data: ClearCrossCrate>, + promoted: IndexVec>, + yield_ty: Option>, + local_decls: IndexVec>, + arg_count: usize, + upvar_decls: Vec, + span: Span, + ) -> Self { // We need `arg_count` locals, and one for the return place - assert!(local_decls.len() >= arg_count + 1, - "expected at least {} locals, got {}", arg_count + 1, local_decls.len()); + assert!( + local_decls.len() >= arg_count + 1, + "expected at least {} locals, got {}", + arg_count + 1, + local_decls.len() + ); Mir { basic_blocks, - visibility_scopes, - visibility_scope_info, + source_scopes, + source_scope_local_data, promoted, yield_ty, generator_drop: None, @@ -166,7 +167,7 @@ impl<'tcx> Mir<'tcx> { upvar_decls, spread_arg: None, span, - cache: cache::Cache::new() + cache: cache::Cache::new(), } } @@ -182,7 +183,9 @@ impl<'tcx> Mir<'tcx> { } #[inline] - pub fn basic_blocks_and_local_decls_mut(&mut self) -> ( + pub fn basic_blocks_and_local_decls_mut( + &mut self, + ) -> ( &mut IndexVec>, &mut LocalDecls<'tcx>, ) { @@ -209,8 +212,10 @@ impl<'tcx> Mir<'tcx> { pub fn local_kind(&self, local: Local) -> LocalKind { let index = local.0 as usize; if index == 0 { - debug_assert!(self.local_decls[local].mutability == Mutability::Mut, - "return place should be mutable"); + debug_assert!( + self.local_decls[local].mutability == Mutability::Mut, + "return place should be mutable" + ); LocalKind::ReturnPointer } else if index < self.arg_count + 1 { @@ -218,8 +223,10 @@ impl<'tcx> Mir<'tcx> { } else if self.local_decls[local].name.is_some() { LocalKind::Var } else { - debug_assert!(self.local_decls[local].mutability == Mutability::Mut, - "temp should be mutable"); + debug_assert!( + self.local_decls[local].mutability == Mutability::Mut, + "temp should be mutable" + ); LocalKind::Temp } @@ -227,10 +234,10 @@ impl<'tcx> Mir<'tcx> { /// Returns an iterator over all temporaries. #[inline] - pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { - (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { + pub fn temps_iter<'a>(&'a self) -> impl Iterator + 'a { + (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable { + if self.local_decls[local].is_user_variable.is_some() { None } else { Some(local) @@ -240,10 +247,10 @@ impl<'tcx> Mir<'tcx> { /// Returns an iterator over all user-declared locals. #[inline] - pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { - (self.arg_count+1..self.local_decls.len()).filter_map(move |index| { + pub fn vars_iter<'a>(&'a self) -> impl Iterator + 'a { + (self.arg_count + 1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); - if self.local_decls[local].is_user_variable { + if self.local_decls[local].is_user_variable.is_some() { Some(local) } else { None @@ -253,12 +260,12 @@ impl<'tcx> Mir<'tcx> { /// Returns an iterator over all user-declared mutable arguments and locals. #[inline] - pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator + 'a { + pub fn mut_vars_and_args_iter<'a>(&'a self) -> impl Iterator + 'a { (1..self.local_decls.len()).filter_map(move |index| { let local = Local::new(index); let decl = &self.local_decls[local]; - if (decl.is_user_variable || index < self.arg_count + 1) - && decl.mutability == Mutability::Mut + if (decl.is_user_variable.is_some() || index < self.arg_count + 1) + && decl.mutability == Mutability::Mut { Some(local) } else { @@ -269,18 +276,18 @@ impl<'tcx> Mir<'tcx> { /// Returns an iterator over all function arguments. #[inline] - pub fn args_iter(&self) -> impl Iterator { + pub fn args_iter(&self) -> impl Iterator { let arg_count = self.arg_count; - (1..arg_count+1).map(Local::new) + (1..arg_count + 1).map(Local::new) } /// Returns an iterator over all user-defined variables and compiler-generated temporaries (all /// locals that are neither arguments nor the return place). #[inline] - pub fn vars_and_temps_iter(&self) -> impl Iterator { + pub fn vars_and_temps_iter(&self) -> impl Iterator { let arg_count = self.arg_count; let local_count = self.local_decls.len(); - (arg_count+1..local_count).map(Local::new) + (arg_count + 1..local_count).map(Local::new) } /// Changes a statement to a nop. This is both faster than deleting instructions and avoids @@ -304,20 +311,25 @@ impl<'tcx> Mir<'tcx> { } } + /// Check if `sub` is a sub scope of `sup` + pub fn is_sub_scope(&self, mut sub: SourceScope, sup: SourceScope) -> bool { + loop { + if sub == sup { + return true; + } + match self.source_scopes[sub].parent_scope { + None => return false, + Some(p) => sub = p, + } + } + } + /// Return the return type, it always return first element from `local_decls` array pub fn return_ty(&self) -> Ty<'tcx> { self.local_decls[RETURN_PLACE].ty } } -#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct VisibilityScopeInfo { - /// A NodeId with lint levels equivalent to this scope's lint levels. - pub lint_root: ast::NodeId, - /// The unsafe block that contains this node. - pub safety: Safety, -} - #[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)] pub enum Safety { Safe, @@ -326,13 +338,13 @@ pub enum Safety { /// Unsafe because of an unsafe fn FnUnsafe, /// Unsafe because of an `unsafe` block - ExplicitUnsafe(ast::NodeId) + ExplicitUnsafe(ast::NodeId), } impl_stable_hash_for!(struct Mir<'tcx> { basic_blocks, - visibility_scopes, - visibility_scope_info, + source_scopes, + source_scope_local_data, promoted, yield_ty, generator_drop, @@ -361,10 +373,19 @@ impl<'tcx> IndexMut for Mir<'tcx> { } } -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum ClearCrossCrate { Clear, - Set(T) + Set(T), +} + +impl ClearCrossCrate { + pub fn assert_crate_local(self) -> T { + match self { + ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), + ClearCrossCrate::Set(v) => v, + } + } } impl serialize::UseSpecializedEncodable for ClearCrossCrate {} @@ -378,8 +399,9 @@ pub struct SourceInfo { /// Source span for the AST pertaining to this MIR entity. pub span: Span, - /// The lexical visibility scope, i.e. which bindings can be seen. - pub scope: VisibilityScope + /// The source scope, keeping track of which bindings can be + /// seen by debuginfo, active lint levels, `unsafe {...}`, etc. + pub scope: SourceScope, } /////////////////////////////////////////////////////////////////////////// @@ -391,6 +413,15 @@ pub enum Mutability { Not, } +impl From for hir::Mutability { + fn from(m: Mutability) -> Self { + match m { + Mutability::Mut => hir::MutMutable, + Mutability::Not => hir::MutImmutable, + } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum BorrowKind { /// Data must be immutable and is aliasable. @@ -437,15 +468,17 @@ pub enum BorrowKind { Mut { /// True if this borrow arose from method-call auto-ref /// (i.e. `adjustment::Adjust::Borrow`) - allow_two_phase_borrow: bool - } + allow_two_phase_borrow: bool, + }, } impl BorrowKind { pub fn allows_two_phase_borrow(&self) -> bool { match *self { BorrowKind::Shared | BorrowKind::Unique => false, - BorrowKind::Mut { allow_two_phase_borrow } => allow_two_phase_borrow, + BorrowKind::Mut { + allow_two_phase_borrow, + } => allow_two_phase_borrow, } } } @@ -472,6 +505,64 @@ pub enum LocalKind { ReturnPointer, } +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct VarBindingForm<'tcx> { + /// Is variable bound via `x`, `mut x`, `ref x`, or `ref mut x`? + pub binding_mode: ty::BindingMode, + /// If an explicit type was provided for this variable binding, + /// this holds the source Span of that type. + /// + /// NOTE: If you want to change this to a `HirId`, be wary that + /// doing so breaks incremental compilation (as of this writing), + /// while a `Span` does not cause our tests to fail. + pub opt_ty_info: Option, + /// Place of the RHS of the =, or the subject of the `match` where this + /// variable is initialized. None in the case of `let PATTERN;`. + /// Some((None, ..)) in the case of and `let [mut] x = ...` because + /// (a) the right-hand side isn't evaluated as a place expression. + /// (b) it gives a way to separate this case from the remaining cases + /// for diagnostics. + pub opt_match_place: Option<(Option>, Span)>, +} + +#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +pub enum BindingForm<'tcx> { + /// This is a binding for a non-`self` binding, or a `self` that has an explicit type. + Var(VarBindingForm<'tcx>), + /// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit. + ImplicitSelf, + /// Reference used in a guard expression to ensure immutability. + RefForGuard, +} + +CloneTypeFoldableAndLiftImpls! { BindingForm<'tcx>, } + +impl_stable_hash_for!(struct self::VarBindingForm<'tcx> { + binding_mode, + opt_ty_info, + opt_match_place +}); + +mod binding_form_impl { + use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableHasherResult}; + use ich::StableHashingContext; + + impl<'a, 'tcx> HashStable> for super::BindingForm<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + use super::BindingForm::*; + ::std::mem::discriminant(self).hash_stable(hcx, hasher); + + match self { + Var(binding) => binding.hash_stable(hcx, hasher), + ImplicitSelf => (), + RefForGuard => (), + } + } + } +} + /// A MIR local. /// /// This can be a binding declared by the user, a temporary inserted by the compiler, a function @@ -483,8 +574,14 @@ pub struct LocalDecl<'tcx> { /// Temporaries and the return place are always mutable. pub mutability: Mutability, - /// True if this corresponds to a user-declared local variable. - pub is_user_variable: bool, + /// Some(binding_mode) if this corresponds to a user-declared local variable. + /// + /// This is solely used for local diagnostics when generating + /// warnings/errors when compiling the current crate, and + /// therefore it need not be visible across crates. pnkfelix + /// currently hypothesized we *need* to wrap this in a + /// `ClearCrossCrate` as long as it carries as `HirId`. + pub is_user_variable: Option>>, /// True if this is an internal local /// @@ -514,16 +611,13 @@ pub struct LocalDecl<'tcx> { /// to generate better debuginfo. pub name: Option, - /// Source info of the local. - pub source_info: SourceInfo, - - /// The *syntactic* visibility scope the local is defined + /// The *syntactic* (i.e. not visibility) source scope the local is defined /// in. If the local was defined in a let-statement, this /// is *within* the let-statement, rather than outside /// of it. /// - /// This is needed because visibility scope of locals within a let-statement - /// is weird. + /// This is needed because the visibility source scope of locals within + /// a let-statement is weird. /// /// The reason is that we want the local to be *within* the let-statement /// for lint purposes, but we want the local to be *after* the let-statement @@ -568,9 +662,9 @@ pub struct LocalDecl<'tcx> { /// `drop(x)`, we want it to refer to `x: u32`. /// /// To allow both uses to work, we need to have more than a single scope - /// for a local. We have the `syntactic_scope` represent the + /// for a local. We have the `source_info.scope` represent the /// "syntactic" lint scope (with a variable being under its let - /// block) while the source-info scope represents the "local variable" + /// block) while the `visibility_scope` represents the "local variable" /// scope (where the "rest" of a block is under all prior let-statements). /// /// The end result looks like this: @@ -582,24 +676,67 @@ pub struct LocalDecl<'tcx> { /// │ │{ #[allow(unused_mut] } // this is actually split into 2 scopes /// │ │ // in practice because I'm lazy. /// │ │ - /// │ │← x.syntactic_scope + /// │ │← x.source_info.scope /// │ │← `x.parse().unwrap()` /// │ │ - /// │ │ │← y.syntactic_scope + /// │ │ │← y.source_info.scope /// │ │ /// │ │ │{ let y: u32 } /// │ │ │ - /// │ │ │← y.source_info.scope + /// │ │ │← y.visibility_scope /// │ │ │← `y + 2` /// │ /// │ │{ let x: u32 } - /// │ │← x.source_info.scope + /// │ │← x.visibility_scope /// │ │← `drop(x)` // this accesses `x: u32` /// ``` - pub syntactic_scope: VisibilityScope, + pub source_info: SourceInfo, + + /// Source scope within which the local is visible (for debuginfo) + /// (see `source_info` for more details). + pub visibility_scope: SourceScope, } impl<'tcx> LocalDecl<'tcx> { + /// Returns true only if local is a binding that can itself be + /// made mutable via the addition of the `mut` keyword, namely + /// something like the occurrences of `x` in: + /// - `fn foo(x: Type) { ... }`, + /// - `let x = ...`, + /// - or `match ... { C(x) => ... }` + pub fn can_be_made_mutable(&self) -> bool { + match self.is_user_variable { + Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info: _, + opt_match_place: _, + }))) => true, + + // FIXME: might be able to thread the distinction between + // `self`/`mut self`/`&self`/`&mut self` into the + // `BindingForm::ImplicitSelf` variant, (and then return + // true here for solely the first case). + _ => false, + } + } + + /// Returns true if local is definitely not a `ref ident` or + /// `ref mut ident` binding. (Such bindings cannot be made into + /// mutable bindings, but the inverse does not necessarily hold). + pub fn is_nonref_binding(&self) -> bool { + match self.is_user_variable { + Some(ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info: _, + opt_match_place: _, + }))) => true, + + Some(ClearCrossCrate::Set(BindingForm::ImplicitSelf)) => true, + + _ => false, + } + } + /// Create a new `LocalDecl` for a temporary. #[inline] pub fn new_temp(ty: Ty<'tcx>, span: Span) -> Self { @@ -609,11 +746,11 @@ impl<'tcx> LocalDecl<'tcx> { name: None, source_info: SourceInfo { span, - scope: ARGUMENT_VISIBILITY_SCOPE + scope: OUTERMOST_SOURCE_SCOPE, }, - syntactic_scope: ARGUMENT_VISIBILITY_SCOPE, + visibility_scope: OUTERMOST_SOURCE_SCOPE, internal: false, - is_user_variable: false + is_user_variable: None, } } @@ -626,11 +763,11 @@ impl<'tcx> LocalDecl<'tcx> { name: None, source_info: SourceInfo { span, - scope: ARGUMENT_VISIBILITY_SCOPE + scope: OUTERMOST_SOURCE_SCOPE, }, - syntactic_scope: ARGUMENT_VISIBILITY_SCOPE, + visibility_scope: OUTERMOST_SOURCE_SCOPE, internal: true, - is_user_variable: false + is_user_variable: None, } } @@ -644,12 +781,12 @@ impl<'tcx> LocalDecl<'tcx> { ty: return_ty, source_info: SourceInfo { span, - scope: ARGUMENT_VISIBILITY_SCOPE + scope: OUTERMOST_SOURCE_SCOPE, }, - syntactic_scope: ARGUMENT_VISIBILITY_SCOPE, + visibility_scope: OUTERMOST_SOURCE_SCOPE, internal: false, - name: None, // FIXME maybe we do want some name here? - is_user_variable: false + name: None, // FIXME maybe we do want some name here? + is_user_variable: None, } } } @@ -659,6 +796,9 @@ impl<'tcx> LocalDecl<'tcx> { pub struct UpvarDecl { pub debug_name: Name, + /// `HirId` of the captured variable + pub var_hir_id: ClearCrossCrate, + /// If true, the capture is behind a reference. pub by_ref: bool, @@ -698,7 +838,7 @@ pub struct BasicBlockData<'tcx> { pub terminator: Option>, /// If true, this block lies on an unwind path. This is used - /// during trans where distinct kinds of basic blocks may be + /// during codegen where distinct kinds of basic blocks may be /// generated (particularly for MSVC cleanup). Unwind blocks must /// only branch to other unwind blocks. pub is_cleanup: bool, @@ -707,15 +847,13 @@ pub struct BasicBlockData<'tcx> { #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Terminator<'tcx> { pub source_info: SourceInfo, - pub kind: TerminatorKind<'tcx> + pub kind: TerminatorKind<'tcx>, } #[derive(Clone, RustcEncodable, RustcDecodable)] pub enum TerminatorKind<'tcx> { /// block should have one successor in the graph; we jump there - Goto { - target: BasicBlock, - }, + Goto { target: BasicBlock }, /// operand evaluates to an integer; jump depending on its value /// to one of the targets, and otherwise fallback to `otherwise` @@ -763,7 +901,7 @@ pub enum TerminatorKind<'tcx> { Drop { location: Place<'tcx>, target: BasicBlock, - unwind: Option + unwind: Option, }, /// Drop the Place and assign the new value over it. This ensures @@ -811,7 +949,7 @@ pub enum TerminatorKind<'tcx> { /// Destination for the return value. If some, the call is converging. destination: Option<(Place<'tcx>, BasicBlock)>, /// Cleanups to be done if the call unwinds. - cleanup: Option + cleanup: Option, }, /// Jump to the target if the condition has the expected value, @@ -821,7 +959,7 @@ pub enum TerminatorKind<'tcx> { expected: bool, msg: AssertMessage<'tcx>, target: BasicBlock, - cleanup: Option + cleanup: Option, }, /// A suspend point @@ -876,14 +1014,22 @@ impl<'tcx> Terminator<'tcx> { self.kind.successors_mut() } + pub fn unwind(&self) -> Option<&Option> { + self.kind.unwind() + } + pub fn unwind_mut(&mut self) -> Option<&mut Option> { self.kind.unwind_mut() } } impl<'tcx> TerminatorKind<'tcx> { - pub fn if_<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>, - t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> { + pub fn if_<'a, 'gcx>( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + cond: Operand<'tcx>, + t: BasicBlock, + f: BasicBlock, + ) -> TerminatorKind<'tcx> { static BOOL_SWITCH_FALSE: &'static [u128] = &[0]; TerminatorKind::SwitchInt { discr: cond, @@ -896,91 +1042,224 @@ impl<'tcx> TerminatorKind<'tcx> { pub fn successors(&self) -> Successors { use self::TerminatorKind::*; match *self { - Resume | Abort | GeneratorDrop | Return | Unreachable | - Call { destination: None, cleanup: None, .. } => { - None.into_iter().chain(&[]) + Resume + | Abort + | GeneratorDrop + | Return + | Unreachable + | Call { + destination: None, + cleanup: None, + .. + } => None.into_iter().chain(&[]), + Goto { target: ref t } + | Call { + destination: None, + cleanup: Some(ref t), + .. + } + | Call { + destination: Some((_, ref t)), + cleanup: None, + .. + } + | Yield { + resume: ref t, + drop: None, + .. + } + | DropAndReplace { + target: ref t, + unwind: None, + .. + } + | Drop { + target: ref t, + unwind: None, + .. + } + | Assert { + target: ref t, + cleanup: None, + .. } - Goto { target: ref t } | - Call { destination: None, cleanup: Some(ref t), .. } | - Call { destination: Some((_, ref t)), cleanup: None, .. } | - Yield { resume: ref t, drop: None, .. } | - DropAndReplace { target: ref t, unwind: None, .. } | - Drop { target: ref t, unwind: None, .. } | - Assert { target: ref t, cleanup: None, .. } | - FalseUnwind { real_target: ref t, unwind: None } => { - Some(t).into_iter().chain(&[]) + | FalseUnwind { + real_target: ref t, + unwind: None, + } => Some(t).into_iter().chain(&[]), + Call { + destination: Some((_, ref t)), + cleanup: Some(ref u), + .. } - Call { destination: Some((_, ref t)), cleanup: Some(ref u), .. } | - Yield { resume: ref t, drop: Some(ref u), .. } | - DropAndReplace { target: ref t, unwind: Some(ref u), .. } | - Drop { target: ref t, unwind: Some(ref u), .. } | - Assert { target: ref t, cleanup: Some(ref u), .. } | - FalseUnwind { real_target: ref t, unwind: Some(ref u) } => { - Some(t).into_iter().chain(slice::from_ref(u)) + | Yield { + resume: ref t, + drop: Some(ref u), + .. } - SwitchInt { ref targets, .. } => { - None.into_iter().chain(&targets[..]) + | DropAndReplace { + target: ref t, + unwind: Some(ref u), + .. } - FalseEdges { ref real_target, ref imaginary_targets } => { - Some(real_target).into_iter().chain(&imaginary_targets[..]) + | Drop { + target: ref t, + unwind: Some(ref u), + .. } + | Assert { + target: ref t, + cleanup: Some(ref u), + .. + } + | FalseUnwind { + real_target: ref t, + unwind: Some(ref u), + } => Some(t).into_iter().chain(slice::from_ref(u)), + SwitchInt { ref targets, .. } => None.into_iter().chain(&targets[..]), + FalseEdges { + ref real_target, + ref imaginary_targets, + } => Some(real_target).into_iter().chain(&imaginary_targets[..]), } } pub fn successors_mut(&mut self) -> SuccessorsMut { use self::TerminatorKind::*; match *self { - Resume | Abort | GeneratorDrop | Return | Unreachable | - Call { destination: None, cleanup: None, .. } => { - None.into_iter().chain(&mut []) + Resume + | Abort + | GeneratorDrop + | Return + | Unreachable + | Call { + destination: None, + cleanup: None, + .. + } => None.into_iter().chain(&mut []), + Goto { target: ref mut t } + | Call { + destination: None, + cleanup: Some(ref mut t), + .. + } + | Call { + destination: Some((_, ref mut t)), + cleanup: None, + .. + } + | Yield { + resume: ref mut t, + drop: None, + .. + } + | DropAndReplace { + target: ref mut t, + unwind: None, + .. + } + | Drop { + target: ref mut t, + unwind: None, + .. + } + | Assert { + target: ref mut t, + cleanup: None, + .. } - Goto { target: ref mut t } | - Call { destination: None, cleanup: Some(ref mut t), .. } | - Call { destination: Some((_, ref mut t)), cleanup: None, .. } | - Yield { resume: ref mut t, drop: None, .. } | - DropAndReplace { target: ref mut t, unwind: None, .. } | - Drop { target: ref mut t, unwind: None, .. } | - Assert { target: ref mut t, cleanup: None, .. } | - FalseUnwind { real_target: ref mut t, unwind: None } => { - Some(t).into_iter().chain(&mut []) + | FalseUnwind { + real_target: ref mut t, + unwind: None, + } => Some(t).into_iter().chain(&mut []), + Call { + destination: Some((_, ref mut t)), + cleanup: Some(ref mut u), + .. } - Call { destination: Some((_, ref mut t)), cleanup: Some(ref mut u), .. } | - Yield { resume: ref mut t, drop: Some(ref mut u), .. } | - DropAndReplace { target: ref mut t, unwind: Some(ref mut u), .. } | - Drop { target: ref mut t, unwind: Some(ref mut u), .. } | - Assert { target: ref mut t, cleanup: Some(ref mut u), .. } | - FalseUnwind { real_target: ref mut t, unwind: Some(ref mut u) } => { - Some(t).into_iter().chain(slice::from_ref_mut(u)) + | Yield { + resume: ref mut t, + drop: Some(ref mut u), + .. } - SwitchInt { ref mut targets, .. } => { - None.into_iter().chain(&mut targets[..]) + | DropAndReplace { + target: ref mut t, + unwind: Some(ref mut u), + .. } - FalseEdges { ref mut real_target, ref mut imaginary_targets } => { - Some(real_target).into_iter().chain(&mut imaginary_targets[..]) + | Drop { + target: ref mut t, + unwind: Some(ref mut u), + .. } + | Assert { + target: ref mut t, + cleanup: Some(ref mut u), + .. + } + | FalseUnwind { + real_target: ref mut t, + unwind: Some(ref mut u), + } => Some(t).into_iter().chain(slice::from_mut(u)), + SwitchInt { + ref mut targets, .. + } => None.into_iter().chain(&mut targets[..]), + FalseEdges { + ref mut real_target, + ref mut imaginary_targets, + } => Some(real_target) + .into_iter() + .chain(&mut imaginary_targets[..]), + } + } + + pub fn unwind(&self) -> Option<&Option> { + match *self { + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop + | TerminatorKind::Yield { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::FalseEdges { .. } => None, + TerminatorKind::Call { + cleanup: ref unwind, + .. + } + | TerminatorKind::Assert { + cleanup: ref unwind, + .. + } + | TerminatorKind::DropAndReplace { ref unwind, .. } + | TerminatorKind::Drop { ref unwind, .. } + | TerminatorKind::FalseUnwind { ref unwind, .. } => Some(unwind), } } pub fn unwind_mut(&mut self) -> Option<&mut Option> { match *self { - TerminatorKind::Goto { .. } | - TerminatorKind::Resume | - TerminatorKind::Abort | - TerminatorKind::Return | - TerminatorKind::Unreachable | - TerminatorKind::GeneratorDrop | - TerminatorKind::Yield { .. } | - TerminatorKind::SwitchInt { .. } | - TerminatorKind::FalseEdges { .. } => { - None - }, - TerminatorKind::Call { cleanup: ref mut unwind, .. } | - TerminatorKind::Assert { cleanup: ref mut unwind, .. } | - TerminatorKind::DropAndReplace { ref mut unwind, .. } | - TerminatorKind::Drop { ref mut unwind, .. } | - TerminatorKind::FalseUnwind { ref mut unwind, .. } => { - Some(unwind) + TerminatorKind::Goto { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::GeneratorDrop + | TerminatorKind::Yield { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::FalseEdges { .. } => None, + TerminatorKind::Call { + cleanup: ref mut unwind, + .. + } + | TerminatorKind::Assert { + cleanup: ref mut unwind, + .. } + | TerminatorKind::DropAndReplace { ref mut unwind, .. } + | TerminatorKind::Drop { ref mut unwind, .. } + | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind), } } } @@ -1006,7 +1285,10 @@ impl<'tcx> BasicBlockData<'tcx> { self.terminator.as_mut().expect("invalid terminator state") } - pub fn retain_statements(&mut self, mut f: F) where F: FnMut(&mut Statement) -> bool { + pub fn retain_statements(&mut self, mut f: F) + where + F: FnMut(&mut Statement) -> bool, + { for s in &mut self.statements { if !f(s) { s.make_nop(); @@ -1015,8 +1297,9 @@ impl<'tcx> BasicBlockData<'tcx> { } pub fn expand_statements(&mut self, mut f: F) - where F: FnMut(&mut Statement<'tcx>) -> Option, - I: iter::TrustedLen> + where + F: FnMut(&mut Statement<'tcx>) -> Option, + I: iter::TrustedLen>, { // Gather all the iterators we'll need to splice in, and their positions. let mut splices: Vec<(usize, I)> = vec![]; @@ -1045,14 +1328,17 @@ impl<'tcx> BasicBlockData<'tcx> { // splicing adding new elements to the end of that gap and moving // existing elements from before the gap to the end of the gap. // For now, this is safe code, emulating a gap but initializing it. - let mut gap = self.statements.len()..self.statements.len()+extra_stmts; - self.statements.resize(gap.end, Statement { - source_info: SourceInfo { - span: DUMMY_SP, - scope: ARGUMENT_VISIBILITY_SCOPE + let mut gap = self.statements.len()..self.statements.len() + extra_stmts; + self.statements.resize( + gap.end, + Statement { + source_info: SourceInfo { + span: DUMMY_SP, + scope: OUTERMOST_SOURCE_SCOPE, + }, + kind: StatementKind::Nop, }, - kind: StatementKind::Nop - }); + ); for (splice_start, new_stmts) in splices.into_iter().rev() { let splice_end = splice_start + new_stmts.size_hint().0; while gap.end > splice_end { @@ -1096,7 +1382,6 @@ impl<'tcx> Debug for TerminatorKind<'tcx> { } write!(fmt, "]") } - } } } @@ -1109,7 +1394,9 @@ impl<'tcx> TerminatorKind<'tcx> { use self::TerminatorKind::*; match *self { Goto { .. } => write!(fmt, "goto"), - SwitchInt { discr: ref place, .. } => write!(fmt, "switchInt({:?})", place), + SwitchInt { + discr: ref place, .. + } => write!(fmt, "switchInt({:?})", place), Return => write!(fmt, "return"), GeneratorDrop => write!(fmt, "generator_drop"), Resume => write!(fmt, "resume"), @@ -1117,9 +1404,17 @@ impl<'tcx> TerminatorKind<'tcx> { Yield { ref value, .. } => write!(fmt, "_1 = suspend({:?})", value), Unreachable => write!(fmt, "unreachable"), Drop { ref location, .. } => write!(fmt, "drop({:?})", location), - DropAndReplace { ref location, ref value, .. } => - write!(fmt, "replace({:?} <- {:?})", location, value), - Call { ref func, ref args, ref destination, .. } => { + DropAndReplace { + ref location, + ref value, + .. + } => write!(fmt, "replace({:?} <- {:?})", location, value), + Call { + ref func, + ref args, + ref destination, + .. + } => { if let Some((ref destination, _)) = *destination { write!(fmt, "{:?} = ", destination)?; } @@ -1132,13 +1427,18 @@ impl<'tcx> TerminatorKind<'tcx> { } write!(fmt, ")") } - Assert { ref cond, expected, ref msg, .. } => { + Assert { + ref cond, + expected, + ref msg, + .. + } => { write!(fmt, "assert(")?; if !expected { write!(fmt, "!")?; } write!(fmt, "{:?}, \"{:?}\")", cond, msg) - }, + } FalseEdges { .. } => write!(fmt, "falseEdges"), FalseUnwind { .. } => write!(fmt, "falseUnwind"), } @@ -1150,43 +1450,77 @@ impl<'tcx> TerminatorKind<'tcx> { match *self { Return | Resume | Abort | Unreachable | GeneratorDrop => vec![], Goto { .. } => vec!["".into()], - SwitchInt { ref values, switch_ty, .. } => { - values.iter() - .map(|&u| { - let mut s = String::new(); - print_miri_value( - Value::ByVal(PrimVal::Bytes(u)), - switch_ty, - &mut s, - ).unwrap(); - s.into() - }) - .chain(iter::once(String::from("otherwise").into())) - .collect() + SwitchInt { + ref values, + switch_ty, + .. + } => { + let size = ty::tls::with(|tcx| { + let param_env = ty::ParamEnv::empty(); + let switch_ty = tcx.lift_to_global(&switch_ty).unwrap(); + tcx.layout_of(param_env.and(switch_ty)).unwrap().size + }); + values + .iter() + .map(|&u| { + let mut s = String::new(); + print_miri_value( + Value::Scalar(Scalar::Bits { + bits: u, + defined: size.bits() as u8, + }), + switch_ty, + &mut s, + ).unwrap(); + s.into() + }) + .chain(iter::once(String::from("otherwise").into())) + .collect() } - Call { destination: Some(_), cleanup: Some(_), .. } => - vec!["return".into_cow(), "unwind".into_cow()], - Call { destination: Some(_), cleanup: None, .. } => vec!["return".into_cow()], - Call { destination: None, cleanup: Some(_), .. } => vec!["unwind".into_cow()], - Call { destination: None, cleanup: None, .. } => vec![], - Yield { drop: Some(_), .. } => - vec!["resume".into_cow(), "drop".into_cow()], + Call { + destination: Some(_), + cleanup: Some(_), + .. + } => vec!["return".into_cow(), "unwind".into_cow()], + Call { + destination: Some(_), + cleanup: None, + .. + } => vec!["return".into_cow()], + Call { + destination: None, + cleanup: Some(_), + .. + } => vec!["unwind".into_cow()], + Call { + destination: None, + cleanup: None, + .. + } => vec![], + Yield { drop: Some(_), .. } => vec!["resume".into_cow(), "drop".into_cow()], Yield { drop: None, .. } => vec!["resume".into_cow()], - DropAndReplace { unwind: None, .. } | - Drop { unwind: None, .. } => vec!["return".into_cow()], - DropAndReplace { unwind: Some(_), .. } | - Drop { unwind: Some(_), .. } => { - vec!["return".into_cow(), "unwind".into_cow()] + DropAndReplace { unwind: None, .. } | Drop { unwind: None, .. } => { + vec!["return".into_cow()] } + DropAndReplace { + unwind: Some(_), .. + } + | Drop { + unwind: Some(_), .. + } => vec!["return".into_cow(), "unwind".into_cow()], Assert { cleanup: None, .. } => vec!["".into()], - Assert { .. } => - vec!["success".into_cow(), "unwind".into_cow()], - FalseEdges { ref imaginary_targets, .. } => { + Assert { .. } => vec!["success".into_cow(), "unwind".into_cow()], + FalseEdges { + ref imaginary_targets, + .. + } => { let mut l = vec!["real".into()]; l.resize(imaginary_targets.len() + 1, "imaginary".into()); l } - FalseUnwind { unwind: Some(_), .. } => vec!["real".into(), "cleanup".into()], + FalseUnwind { + unwind: Some(_), .. + } => vec!["real".into(), "cleanup".into()], FalseUnwind { unwind: None, .. } => vec!["real".into()], } } @@ -1212,7 +1546,7 @@ impl<'tcx> Statement<'tcx> { pub fn replace_nop(&mut self) -> Self { Statement { source_info: self.source_info, - kind: mem::replace(&mut self.kind, StatementKind::Nop) + kind: mem::replace(&mut self.kind, StatementKind::Nop), } } } @@ -1222,8 +1556,15 @@ pub enum StatementKind<'tcx> { /// Write the RHS Rvalue to the LHS Place. Assign(Place<'tcx>, Rvalue<'tcx>), + /// This represents all the reading that a pattern match may do + /// (e.g. inspecting constants and discriminant values). + ReadForMatch(Place<'tcx>), + /// Write the discriminant for a variant to the enum Place. - SetDiscriminant { place: Place<'tcx>, variant_index: usize }, + SetDiscriminant { + place: Place<'tcx>, + variant_index: usize, + }, /// Start a live range for the storage of the local. StorageLive(Local), @@ -1235,7 +1576,7 @@ pub enum StatementKind<'tcx> { InlineAsm { asm: Box, outputs: Vec>, - inputs: Vec> + inputs: Vec>, }, /// Assert the given places to be valid inhabitants of their type. These statements are @@ -1297,7 +1638,7 @@ impl Debug for ValidationOp { } // This is generic so that it can be reused by miri -#[derive(Clone, RustcEncodable, RustcDecodable)] +#[derive(Clone, Hash, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct ValidationOperand<'tcx, T> { pub place: T, pub ty: Ty<'tcx>, @@ -1324,19 +1665,24 @@ impl<'tcx> Debug for Statement<'tcx> { use self::StatementKind::*; match self.kind { Assign(ref place, ref rv) => write!(fmt, "{:?} = {:?}", place, rv), + ReadForMatch(ref place) => write!(fmt, "ReadForMatch({:?})", place), // (reuse lifetime rendering policy from ppaux.) EndRegion(ref ce) => write!(fmt, "EndRegion({})", ty::ReScope(*ce)), Validate(ref op, ref places) => write!(fmt, "Validate({:?}, {:?})", op, places), StorageLive(ref place) => write!(fmt, "StorageLive({:?})", place), StorageDead(ref place) => write!(fmt, "StorageDead({:?})", place), - SetDiscriminant { ref place, variant_index } => { - write!(fmt, "discriminant({:?}) = {:?}", place, variant_index) - }, - InlineAsm { ref asm, ref outputs, ref inputs } => { - write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs) - }, - UserAssertTy(ref c_ty, ref local) => write!(fmt, "UserAssertTy({:?}, {:?})", - c_ty, local), + SetDiscriminant { + ref place, + variant_index, + } => write!(fmt, "discriminant({:?}) = {:?}", place, variant_index), + InlineAsm { + ref asm, + ref outputs, + ref inputs, + } => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs), + UserAssertTy(ref c_ty, ref local) => { + write!(fmt, "UserAssertTy({:?}, {:?})", c_ty, local) + } Nop => write!(fmt, "nop"), } } @@ -1355,6 +1701,9 @@ pub enum Place<'tcx> { /// static or static mut variable Static(Box>), + /// Constant code promoted to an injected static + Promoted(Box<(Promoted, Ty<'tcx>)>), + /// projection out of a place (access a field, deref a pointer, etc) Projection(Box>), } @@ -1448,10 +1797,7 @@ impl<'tcx> Place<'tcx> { } pub fn elem(self, elem: PlaceElem<'tcx>) -> Place<'tcx> { - Place::Projection(Box::new(PlaceProjection { - base: self, - elem, - })) + Place::Projection(Box::new(PlaceProjection { base: self, elem })) } } @@ -1461,31 +1807,42 @@ impl<'tcx> Debug for Place<'tcx> { match *self { Local(id) => write!(fmt, "{:?}", id), - Static(box self::Static { def_id, ty }) => - write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.item_path_str(def_id)), ty), - Projection(ref data) => - match data.elem { - ProjectionElem::Downcast(ref adt_def, index) => - write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name), - ProjectionElem::Deref => - write!(fmt, "(*{:?})", data.base), - ProjectionElem::Field(field, ty) => - write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty), - ProjectionElem::Index(ref index) => - write!(fmt, "{:?}[{:?}]", data.base, index), - ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => - write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length), - ProjectionElem::ConstantIndex { offset, min_length, from_end: true } => - write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), - ProjectionElem::Subslice { from, to } if to == 0 => - write!(fmt, "{:?}[{:?}:]", data.base, from), - ProjectionElem::Subslice { from, to } if from == 0 => - write!(fmt, "{:?}[:-{:?}]", data.base, to), - ProjectionElem::Subslice { from, to } => - write!(fmt, "{:?}[{:?}:-{:?}]", data.base, - from, to), - - }, + Static(box self::Static { def_id, ty }) => write!( + fmt, + "({}: {:?})", + ty::tls::with(|tcx| tcx.item_path_str(def_id)), + ty + ), + Promoted(ref promoted) => write!(fmt, "({:?}: {:?})", promoted.0, promoted.1), + Projection(ref data) => match data.elem { + ProjectionElem::Downcast(ref adt_def, index) => { + write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].name) + } + ProjectionElem::Deref => write!(fmt, "(*{:?})", data.base), + ProjectionElem::Field(field, ty) => { + write!(fmt, "({:?}.{:?}: {:?})", data.base, field.index(), ty) + } + ProjectionElem::Index(ref index) => write!(fmt, "{:?}[{:?}]", data.base, index), + ProjectionElem::ConstantIndex { + offset, + min_length, + from_end: false, + } => write!(fmt, "{:?}[{:?} of {:?}]", data.base, offset, min_length), + ProjectionElem::ConstantIndex { + offset, + min_length, + from_end: true, + } => write!(fmt, "{:?}[-{:?} of {:?}]", data.base, offset, min_length), + ProjectionElem::Subslice { from, to } if to == 0 => { + write!(fmt, "{:?}[{:?}:]", data.base, from) + } + ProjectionElem::Subslice { from, to } if from == 0 => { + write!(fmt, "{:?}[:-{:?}]", data.base, to) + } + ProjectionElem::Subslice { from, to } => { + write!(fmt, "{:?}[{:?}:-{:?}]", data.base, from, to) + } + }, } } } @@ -1493,16 +1850,24 @@ impl<'tcx> Debug for Place<'tcx> { /////////////////////////////////////////////////////////////////////////// // Scopes -newtype_index!(VisibilityScope +newtype_index!(SourceScope { DEBUG_FORMAT = "scope[{}]", - const ARGUMENT_VISIBILITY_SCOPE = 0, + const OUTERMOST_SOURCE_SCOPE = 0, }); #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] -pub struct VisibilityScopeData { +pub struct SourceScopeData { pub span: Span, - pub parent_scope: Option, + pub parent_scope: Option, +} + +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub struct SourceScopeLocalData { + /// A NodeId with lint levels equivalent to this scope's lint levels. + pub lint_root: ast::NodeId, + /// The unsafe block that contains this node. + pub safety: Safety, } /////////////////////////////////////////////////////////////////////////// @@ -1549,20 +1914,14 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(box Constant { span, ty, - literal: Literal::Value { - value: tcx.mk_const(ty::Const { - // ZST function type - val: ConstVal::Value(Value::ByVal(PrimVal::Undef)), - ty - }) - }, + literal: ty::Const::zero_sized(tcx, ty), }) } pub fn to_copy(&self) -> Self { match *self { Operand::Copy(_) | Operand::Constant(_) => self.clone(), - Operand::Move(ref place) => Operand::Copy(place.clone()) + Operand::Move(ref place) => Operand::Copy(place.clone()), } } } @@ -1620,7 +1979,7 @@ pub enum CastKind { UnsafeFnPointer, /// "Unsize" -- convert a thin-or-fat pointer to a fat pointer. - /// trans must figure out the details once full monomorphization + /// codegen must figure out the details once full monomorphization /// is known. For example, this could be used to cast from a /// `&[i32;N]` to a `&[i32]`, or a `Box` to a `Box` /// (presuming `T: Trait`). @@ -1641,7 +2000,7 @@ pub enum AggregateKind<'tcx> { Adt(&'tcx AdtDef, usize, &'tcx Substs<'tcx>, Option), Closure(DefId, ClosureSubsts<'tcx>), - Generator(DefId, ClosureSubsts<'tcx>, GeneratorInterior<'tcx>), + Generator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), } #[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] @@ -1687,7 +2046,7 @@ impl BinOp { use self::BinOp::*; match self { Add | Sub | Mul | Shl | Shr => true, - _ => false + _ => false, } } } @@ -1734,8 +2093,10 @@ impl<'tcx> Debug for Rvalue<'tcx> { // When printing regions, add trailing space if necessary. let region = if ppaux::verbose() || ppaux::identify_regions() { - let mut region = format!("{}", region); - if region.len() > 0 { region.push(' '); } + let mut region = region.to_string(); + if region.len() > 0 { + region.push(' '); + } region } else { // Do not even print 'static @@ -1756,13 +2117,11 @@ impl<'tcx> Debug for Rvalue<'tcx> { match **kind { AggregateKind::Array(_) => write!(fmt, "{:?}", places), - AggregateKind::Tuple => { - match places.len() { - 0 => write!(fmt, "()"), - 1 => write!(fmt, "({:?},)", places[0]), - _ => fmt_tuple(fmt, places), - } - } + AggregateKind::Tuple => match places.len() { + 0 => write!(fmt, "()"), + 1 => write!(fmt, "({:?},)", places[0]), + _ => fmt_tuple(fmt, places), + }, AggregateKind::Adt(adt_def, variant, substs, _) => { let variant_def = &adt_def.variants[variant]; @@ -1775,7 +2134,7 @@ impl<'tcx> Debug for Rvalue<'tcx> { CtorKind::Fictive => { let mut struct_fmt = fmt.debug_struct(""); for (field, place) in variant_def.fields.iter().zip(places) { - struct_fmt.field(&field.name.as_str(), place); + struct_fmt.field(&field.ident.as_str(), place); } struct_fmt.finish() } @@ -1816,8 +2175,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { } struct_fmt.field("$state", &places[freevars.len()]); for i in (freevars.len() + 1)..places.len() { - struct_fmt.field(&format!("${}", i - freevars.len() - 1), - &places[i]); + struct_fmt + .field(&format!("${}", i - freevars.len() - 1), &places[i]); } }); @@ -1843,86 +2202,66 @@ impl<'tcx> Debug for Rvalue<'tcx> { pub struct Constant<'tcx> { pub span: Span, pub ty: Ty<'tcx>, - pub literal: Literal<'tcx>, + pub literal: &'tcx ty::Const<'tcx>, } newtype_index!(Promoted { DEBUG_FORMAT = "promoted[{}]" }); - -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] -pub enum Literal<'tcx> { - Value { - value: &'tcx ty::Const<'tcx>, - }, - Promoted { - // Index into the `promoted` vector of `Mir`. - index: Promoted - }, -} - impl<'tcx> Debug for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - write!(fmt, "{:?}", self.literal) - } -} - -impl<'tcx> Debug for Literal<'tcx> { - fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - use self::Literal::*; - match *self { - Value { value } => { - write!(fmt, "const ")?; - fmt_const_val(fmt, value) - } - Promoted { index } => { - write!(fmt, "{:?}", index) - } - } + write!(fmt, "const ")?; + fmt_const_val(fmt, self.literal) } } -/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output. -fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { - use middle::const_val::ConstVal::*; - match const_val.val { - Unevaluated(..) => write!(fmt, "{:?}", const_val), - Value(val) => print_miri_value(val, const_val.ty, fmt), +/// Write a `ConstValue` in a way closer to the original source code than the `Debug` output. +pub fn fmt_const_val(fmt: &mut W, const_val: &ty::Const) -> fmt::Result { + if let Some(value) = const_val.to_byval_value() { + print_miri_value(value, const_val.ty, fmt) + } else { + write!(fmt, "{:?}:{}", const_val.val, const_val.ty) } } pub fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Result { use ty::TypeVariants::*; match (value, &ty.sty) { - (Value::ByVal(PrimVal::Bytes(0)), &TyBool) => write!(f, "false"), - (Value::ByVal(PrimVal::Bytes(1)), &TyBool) => write!(f, "true"), - (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(ast::FloatTy::F32)) => - write!(f, "{}f32", Single::from_bits(bits)), - (Value::ByVal(PrimVal::Bytes(bits)), &TyFloat(ast::FloatTy::F64)) => - write!(f, "{}f64", Double::from_bits(bits)), - (Value::ByVal(PrimVal::Bytes(n)), &TyUint(ui)) => write!(f, "{:?}{}", n, ui), - (Value::ByVal(PrimVal::Bytes(n)), &TyInt(i)) => write!(f, "{:?}{}", n as i128, i), - (Value::ByVal(PrimVal::Bytes(n)), &TyChar) => - write!(f, "{:?}", ::std::char::from_u32(n as u32).unwrap()), - (Value::ByVal(PrimVal::Undef), &TyFnDef(did, _)) => - write!(f, "{}", item_path_str(did)), - (Value::ByValPair(PrimVal::Ptr(ptr), PrimVal::Bytes(len)), &TyRef(_, TypeAndMut { - ty: &ty::TyS { sty: TyStr, .. }, .. - })) => { - ty::tls::with(|tcx| { - let alloc = tcx - .interpret_interner - .get_alloc(ptr.alloc_id); - if let Some(alloc) = alloc { - assert_eq!(len as usize as u128, len); - let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice) - .expect("non utf8 str from miri"); - write!(f, "{:?}", s) - } else { - write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len) - } - }) - }, + (Value::Scalar(Scalar::Bits { bits: 0, .. }), &TyBool) => write!(f, "false"), + (Value::Scalar(Scalar::Bits { bits: 1, .. }), &TyBool) => write!(f, "true"), + (Value::Scalar(Scalar::Bits { bits, .. }), &TyFloat(ast::FloatTy::F32)) => { + write!(f, "{}f32", Single::from_bits(bits)) + } + (Value::Scalar(Scalar::Bits { bits, .. }), &TyFloat(ast::FloatTy::F64)) => { + write!(f, "{}f64", Double::from_bits(bits)) + } + (Value::Scalar(Scalar::Bits { bits, .. }), &TyUint(ui)) => write!(f, "{:?}{}", bits, ui), + (Value::Scalar(Scalar::Bits { bits, .. }), &TyInt(i)) => { + let bit_width = ty::tls::with(|tcx| { + let ty = tcx.lift_to_global(&ty).unwrap(); + tcx.layout_of(ty::ParamEnv::empty().and(ty)) + .unwrap() + .size + .bits() + }); + let shift = 128 - bit_width; + write!(f, "{:?}{}", ((bits as i128) << shift) >> shift, i) + } + (Value::Scalar(Scalar::Bits { bits, .. }), &TyChar) => { + write!(f, "{:?}", ::std::char::from_u32(bits as u32).unwrap()) + } + (_, &TyFnDef(did, _)) => write!(f, "{}", item_path_str(did)), + ( + Value::ScalarPair(Scalar::Ptr(ptr), Scalar::Bits { bits: len, .. }), + &TyRef(_, &ty::TyS { sty: TyStr, .. }, _), + ) => ty::tls::with(|tcx| match tcx.alloc_map.lock().get(ptr.alloc_id) { + Some(interpret::AllocType::Memory(alloc)) => { + assert_eq!(len as usize as u128, len); + let slice = &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; + let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); + write!(f, "{:?}", s) + } + _ => write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len), + }), _ => write!(f, "{:?}:{}", value, ty), } } @@ -1931,32 +2270,46 @@ fn item_path_str(def_id: DefId) -> String { ty::tls::with(|tcx| tcx.item_path_str(def_id)) } -impl<'tcx> ControlFlowGraph for Mir<'tcx> { - +impl<'tcx> graph::DirectedGraph for Mir<'tcx> { type Node = BasicBlock; +} - fn num_nodes(&self) -> usize { self.basic_blocks.len() } +impl<'tcx> graph::WithNumNodes for Mir<'tcx> { + fn num_nodes(&self) -> usize { + self.basic_blocks.len() + } +} - fn start_node(&self) -> Self::Node { START_BLOCK } +impl<'tcx> graph::WithStartNode for Mir<'tcx> { + fn start_node(&self) -> Self::Node { + START_BLOCK + } +} - fn predecessors<'graph>(&'graph self, node: Self::Node) - -> >::Iter - { +impl<'tcx> graph::WithPredecessors for Mir<'tcx> { + fn predecessors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter { self.predecessors_for(node).clone().into_iter() } - fn successors<'graph>(&'graph self, node: Self::Node) - -> >::Iter - { +} + +impl<'tcx> graph::WithSuccessors for Mir<'tcx> { + fn successors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter { self.basic_blocks[node].terminator().successors().cloned() } } -impl<'a, 'b> GraphPredecessors<'b> for Mir<'a> { +impl<'a, 'b> graph::GraphPredecessors<'b> for Mir<'a> { type Item = BasicBlock; type Iter = IntoIter; } -impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { +impl<'a, 'b> graph::GraphSuccessors<'b> for Mir<'a> { type Item = BasicBlock; type Iter = iter::Cloned>; } @@ -1988,7 +2341,10 @@ impl Location { /// Note that if this location represents a terminator, then the /// resulting location would be out of bounds and invalid. pub fn successor_within_block(&self) -> Location { - Location { block: self.block, statement_index: self.statement_index + 1 } + Location { + block: self.block, + statement_index: self.statement_index + 1, + } } pub fn dominates(&self, other: Location, dominators: &Dominators) -> bool { @@ -2011,6 +2367,7 @@ pub enum UnsafetyViolationKind { pub struct UnsafetyViolation { pub source_info: SourceInfo, pub description: InternedString, + pub details: InternedString, pub kind: UnsafetyViolationKind, } @@ -2139,16 +2496,16 @@ CloneTypeFoldableAndLiftImpls! { SourceInfo, UpvarDecl, ValidationOp, - VisibilityScopeData, - VisibilityScope, - VisibilityScopeInfo, + SourceScope, + SourceScopeData, + SourceScopeLocalData, } BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for Mir<'tcx> { basic_blocks, - visibility_scopes, - visibility_scope_info, + source_scopes, + source_scope_local_data, promoted, yield_ty, generator_drop, @@ -2176,7 +2533,7 @@ BraceStructTypeFoldableImpl! { ty, name, source_info, - syntactic_scope, + visibility_scope, } } @@ -2203,6 +2560,7 @@ BraceStructTypeFoldableImpl! { EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for StatementKind<'tcx> { (StatementKind::Assign)(a, b), + (StatementKind::ReadForMatch)(place), (StatementKind::SetDiscriminant) { place, variant_index }, (StatementKind::StorageLive)(a), (StatementKind::StorageDead)(a), @@ -2227,32 +2585,55 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { let kind = match self.kind { Goto { target } => Goto { target: target }, - SwitchInt { ref discr, switch_ty, ref values, ref targets } => SwitchInt { + SwitchInt { + ref discr, + switch_ty, + ref values, + ref targets, + } => SwitchInt { discr: discr.fold_with(folder), switch_ty: switch_ty.fold_with(folder), values: values.clone(), - targets: targets.clone() + targets: targets.clone(), }, - Drop { ref location, target, unwind } => Drop { + Drop { + ref location, + target, + unwind, + } => Drop { location: location.fold_with(folder), target, unwind, }, - DropAndReplace { ref location, ref value, target, unwind } => DropAndReplace { + DropAndReplace { + ref location, + ref value, + target, + unwind, + } => DropAndReplace { location: location.fold_with(folder), value: value.fold_with(folder), target, unwind, }, - Yield { ref value, resume, drop } => Yield { + Yield { + ref value, + resume, + drop, + } => Yield { value: value.fold_with(folder), resume: resume, drop: drop, }, - Call { ref func, ref args, ref destination, cleanup } => { - let dest = destination.as_ref().map(|&(ref loc, dest)| { - (loc.fold_with(folder), dest) - }); + Call { + ref func, + ref args, + ref destination, + cleanup, + } => { + let dest = destination + .as_ref() + .map(|&(ref loc, dest)| (loc.fold_with(folder), dest)); Call { func: func.fold_with(folder), @@ -2260,8 +2641,14 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { destination: dest, cleanup, } - }, - Assert { ref cond, expected, ref msg, target, cleanup } => { + } + Assert { + ref cond, + expected, + ref msg, + target, + cleanup, + } => { let msg = if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg { EvalErrorKind::BoundsCheck { len: len.fold_with(folder), @@ -2277,15 +2664,26 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { target, cleanup, } - }, + } GeneratorDrop => GeneratorDrop, Resume => Resume, Abort => Abort, Return => Return, Unreachable => Unreachable, - FalseEdges { real_target, ref imaginary_targets } => - FalseEdges { real_target, imaginary_targets: imaginary_targets.clone() }, - FalseUnwind { real_target, unwind } => FalseUnwind { real_target, unwind }, + FalseEdges { + real_target, + ref imaginary_targets, + } => FalseEdges { + real_target, + imaginary_targets: imaginary_targets.clone(), + }, + FalseUnwind { + real_target, + unwind, + } => FalseUnwind { + real_target, + unwind, + }, }; Terminator { source_info: self.source_info, @@ -2297,20 +2695,34 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { use mir::TerminatorKind::*; match self.kind { - SwitchInt { ref discr, switch_ty, .. } => - discr.visit_with(visitor) || switch_ty.visit_with(visitor), - Drop { ref location, ..} => location.visit_with(visitor), - DropAndReplace { ref location, ref value, ..} => - location.visit_with(visitor) || value.visit_with(visitor), - Yield { ref value, ..} => - value.visit_with(visitor), - Call { ref func, ref args, ref destination, .. } => { + SwitchInt { + ref discr, + switch_ty, + .. + } => discr.visit_with(visitor) || switch_ty.visit_with(visitor), + Drop { ref location, .. } => location.visit_with(visitor), + DropAndReplace { + ref location, + ref value, + .. + } => location.visit_with(visitor) || value.visit_with(visitor), + Yield { ref value, .. } => value.visit_with(visitor), + Call { + ref func, + ref args, + ref destination, + .. + } => { let dest = if let Some((ref loc, _)) = *destination { loc.visit_with(visitor) - } else { false }; + } else { + false + }; dest || func.visit_with(visitor) || args.visit_with(visitor) - }, - Assert { ref cond, ref msg, .. } => { + } + Assert { + ref cond, ref msg, .. + } => { if cond.visit_with(visitor) { if let EvalErrorKind::BoundsCheck { ref len, ref index } = *msg { len.visit_with(visitor) || index.visit_with(visitor) @@ -2320,15 +2732,15 @@ impl<'tcx> TypeFoldable<'tcx> for Terminator<'tcx> { } else { false } - }, - Goto { .. } | - Resume | - Abort | - Return | - GeneratorDrop | - Unreachable | - FalseEdges { .. } | - FalseUnwind { .. } => false + } + Goto { .. } + | Resume + | Abort + | Return + | GeneratorDrop + | Unreachable + | FalseEdges { .. } + | FalseUnwind { .. } => false, } } } @@ -2337,7 +2749,7 @@ impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match self { &Place::Projection(ref p) => Place::Projection(p.fold_with(folder)), - _ => self.clone() + _ => self.clone(), } } @@ -2356,14 +2768,17 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { match *self { Use(ref op) => Use(op.fold_with(folder)), Repeat(ref op, len) => Repeat(op.fold_with(folder), len), - Ref(region, bk, ref place) => - Ref(region.fold_with(folder), bk, place.fold_with(folder)), + Ref(region, bk, ref place) => { + Ref(region.fold_with(folder), bk, place.fold_with(folder)) + } Len(ref place) => Len(place.fold_with(folder)), Cast(kind, ref op, ty) => Cast(kind, op.fold_with(folder), ty.fold_with(folder)), - BinaryOp(op, ref rhs, ref lhs) => - BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), - CheckedBinaryOp(op, ref rhs, ref lhs) => - CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)), + BinaryOp(op, ref rhs, ref lhs) => { + BinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) + } + CheckedBinaryOp(op, ref rhs, ref lhs) => { + CheckedBinaryOp(op, rhs.fold_with(folder), lhs.fold_with(folder)) + } UnaryOp(op, ref val) => UnaryOp(op, val.fold_with(folder)), Discriminant(ref place) => Discriminant(place.fold_with(folder)), NullaryOp(op, ty) => NullaryOp(op, ty.fold_with(folder)), @@ -2371,14 +2786,15 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { let kind = box match **kind { AggregateKind::Array(ty) => AggregateKind::Array(ty.fold_with(folder)), AggregateKind::Tuple => AggregateKind::Tuple, - AggregateKind::Adt(def, v, substs, n) => - AggregateKind::Adt(def, v, substs.fold_with(folder), n), - AggregateKind::Closure(id, substs) => - AggregateKind::Closure(id, substs.fold_with(folder)), - AggregateKind::Generator(id, substs, interior) => - AggregateKind::Generator(id, - substs.fold_with(folder), - interior.fold_with(folder)), + AggregateKind::Adt(def, v, substs, n) => { + AggregateKind::Adt(def, v, substs.fold_with(folder), n) + } + AggregateKind::Closure(id, substs) => { + AggregateKind::Closure(id, substs.fold_with(folder)) + } + AggregateKind::Generator(id, substs, movablity) => { + AggregateKind::Generator(id, substs.fold_with(folder), movablity) + } }; Aggregate(kind, fields.fold_with(folder)) } @@ -2393,9 +2809,9 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { Ref(region, _, ref place) => region.visit_with(visitor) || place.visit_with(visitor), Len(ref place) => place.visit_with(visitor), Cast(_, ref op, ty) => op.visit_with(visitor) || ty.visit_with(visitor), - BinaryOp(_, ref rhs, ref lhs) | - CheckedBinaryOp(_, ref rhs, ref lhs) => - rhs.visit_with(visitor) || lhs.visit_with(visitor), + BinaryOp(_, ref rhs, ref lhs) | CheckedBinaryOp(_, ref rhs, ref lhs) => { + rhs.visit_with(visitor) || lhs.visit_with(visitor) + } UnaryOp(_, ref val) => val.visit_with(visitor), Discriminant(ref place) => place.visit_with(visitor), NullaryOp(_, ty) => ty.visit_with(visitor), @@ -2405,8 +2821,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { AggregateKind::Tuple => false, AggregateKind::Adt(_, _, substs, _) => substs.visit_with(visitor), AggregateKind::Closure(_, substs) => substs.visit_with(visitor), - AggregateKind::Generator(_, substs, interior) => substs.visit_with(visitor) || - interior.visit_with(visitor), + AggregateKind::Generator(_, substs, _) => substs.visit_with(visitor), }) || fields.visit_with(visitor) } } @@ -2424,15 +2839,17 @@ impl<'tcx> TypeFoldable<'tcx> for Operand<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { - Operand::Copy(ref place) | - Operand::Move(ref place) => place.visit_with(visitor), - Operand::Constant(ref c) => c.visit_with(visitor) + Operand::Copy(ref place) | Operand::Move(ref place) => place.visit_with(visitor), + Operand::Constant(ref c) => c.visit_with(visitor), } } } impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> - where B: TypeFoldable<'tcx>, V: TypeFoldable<'tcx>, T: TypeFoldable<'tcx> +where + B: TypeFoldable<'tcx>, + V: TypeFoldable<'tcx>, + T: TypeFoldable<'tcx>, { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { use mir::ProjectionElem::*; @@ -2442,24 +2859,20 @@ impl<'tcx, B, V, T> TypeFoldable<'tcx> for Projection<'tcx, B, V, T> Deref => Deref, Field(f, ref ty) => Field(f, ty.fold_with(folder)), Index(ref v) => Index(v.fold_with(folder)), - ref elem => elem.clone() + ref elem => elem.clone(), }; - Projection { - base, - elem, - } + Projection { base, elem } } fn super_visit_with>(&self, visitor: &mut Vs) -> bool { use mir::ProjectionElem::*; - self.base.visit_with(visitor) || - match self.elem { - Field(_, ref ty) => ty.visit_with(visitor), - Index(ref v) => v.visit_with(visitor), - _ => false - } + self.base.visit_with(visitor) || match self.elem { + Field(_, ref ty) => ty.visit_with(visitor), + Index(ref v) => v.visit_with(visitor), + _ => false, + } } } @@ -2477,27 +2890,10 @@ impl<'tcx> TypeFoldable<'tcx> for Constant<'tcx> { Constant { span: self.span.clone(), ty: self.ty.fold_with(folder), - literal: self.literal.fold_with(folder) + literal: self.literal.fold_with(folder), } } fn super_visit_with>(&self, visitor: &mut V) -> bool { self.ty.visit_with(visitor) || self.literal.visit_with(visitor) } } - -impl<'tcx> TypeFoldable<'tcx> for Literal<'tcx> { - fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - match *self { - Literal::Value { value } => Literal::Value { - value: value.fold_with(folder) - }, - Literal::Promoted { index } => Literal::Promoted { index } - } - } - fn super_visit_with>(&self, visitor: &mut V) -> bool { - match *self { - Literal::Value { value } => value.visit_with(visitor), - Literal::Promoted { .. } => false - } - } -} diff --git a/src/librustc/mir/mono.rs b/src/librustc/mir/mono.rs index d01059a3e0171..f0d6b8170eb64 100644 --- a/src/librustc/mir/mono.rs +++ b/src/librustc/mir/mono.rs @@ -36,7 +36,8 @@ impl<'tcx> MonoItem<'tcx> { }, // Conservatively estimate the size of a static declaration // or assembly to be 1. - MonoItem::Static(_) | MonoItem::GlobalAsm(_) => 1, + MonoItem::Static(_) | + MonoItem::GlobalAsm(_) => 1, } } } @@ -184,11 +185,11 @@ impl<'a, 'tcx> HashStable> for CodegenUnit<'tcx> { name.hash_stable(hcx, hasher); - let mut items: Vec<(Fingerprint, _)> = items.iter().map(|(trans_item, &attrs)| { + let mut items: Vec<(Fingerprint, _)> = items.iter().map(|(mono_item, &attrs)| { let mut hasher = StableHasher::new(); - trans_item.hash_stable(hcx, &mut hasher); - let trans_item_fingerprint = hasher.finish(); - (trans_item_fingerprint, attrs) + mono_item.hash_stable(hcx, &mut hasher); + let mono_item_fingerprint = hasher.finish(); + (mono_item_fingerprint, attrs) }).collect(); items.sort_unstable_by_key(|i| i.0); @@ -238,4 +239,3 @@ impl Stats { self.fn_stats.extend(stats.fn_stats); } } - diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs index 20902d9111019..b55843ac527df 100644 --- a/src/librustc/mir/tcx.rs +++ b/src/librustc/mir/tcx.rs @@ -69,7 +69,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> { PlaceTy::Ty { ty: match ty.sty { ty::TyArray(inner, size) => { - let size = size.val.unwrap_u64(); + let size = size.unwrap_usize(tcx); let len = size - (from as u64) - (to as u64); tcx.mk_array(inner, len) } @@ -113,12 +113,46 @@ impl<'tcx> Place<'tcx> { match *self { Place::Local(index) => PlaceTy::Ty { ty: local_decls.local_decls()[index].ty }, + Place::Promoted(ref data) => PlaceTy::Ty { ty: data.1 }, Place::Static(ref data) => PlaceTy::Ty { ty: data.ty }, Place::Projection(ref proj) => proj.base.ty(local_decls, tcx).projection_ty(tcx, &proj.elem), } } + + /// If this is a field projection, and the field is being projected from a closure type, + /// then returns the index of the field being projected. Note that this closure will always + /// be `self` in the current MIR, because that is the only time we directly access the fields + /// of a closure type. + pub fn is_upvar_field_projection<'cx, 'gcx>(&self, mir: &'cx Mir<'tcx>, + tcx: &TyCtxt<'cx, 'gcx, 'tcx>) -> Option { + let place = if let Place::Projection(ref proj) = self { + if let ProjectionElem::Deref = proj.elem { + &proj.base + } else { + self + } + } else { + self + }; + + match place { + Place::Projection(ref proj) => match proj.elem { + ProjectionElem::Field(field, _ty) => { + let base_ty = proj.base.ty(mir, *tcx).to_ty(*tcx); + + if base_ty.is_closure() || base_ty.is_generator() { + Some(field) + } else { + None + } + }, + _ => None, + }, + _ => None, + } + } } pub enum RvalueInitializationState { @@ -184,10 +218,10 @@ impl<'tcx> Rvalue<'tcx> { tcx.type_of(def.did).subst(tcx, substs) } AggregateKind::Closure(did, substs) => { - tcx.mk_closure_from_closure_substs(did, substs) + tcx.mk_closure(did, substs) } - AggregateKind::Generator(did, substs, interior) => { - tcx.mk_generator(did, substs, interior) + AggregateKind::Generator(did, substs, movability) => { + tcx.mk_generator(did, substs, movability) } } } @@ -256,24 +290,24 @@ impl BorrowKind { } impl BinOp { - pub fn to_hir_binop(self) -> hir::BinOp_ { + pub fn to_hir_binop(self) -> hir::BinOpKind { match self { - BinOp::Add => hir::BinOp_::BiAdd, - BinOp::Sub => hir::BinOp_::BiSub, - BinOp::Mul => hir::BinOp_::BiMul, - BinOp::Div => hir::BinOp_::BiDiv, - BinOp::Rem => hir::BinOp_::BiRem, - BinOp::BitXor => hir::BinOp_::BiBitXor, - BinOp::BitAnd => hir::BinOp_::BiBitAnd, - BinOp::BitOr => hir::BinOp_::BiBitOr, - BinOp::Shl => hir::BinOp_::BiShl, - BinOp::Shr => hir::BinOp_::BiShr, - BinOp::Eq => hir::BinOp_::BiEq, - BinOp::Ne => hir::BinOp_::BiNe, - BinOp::Lt => hir::BinOp_::BiLt, - BinOp::Gt => hir::BinOp_::BiGt, - BinOp::Le => hir::BinOp_::BiLe, - BinOp::Ge => hir::BinOp_::BiGe, + BinOp::Add => hir::BinOpKind::Add, + BinOp::Sub => hir::BinOpKind::Sub, + BinOp::Mul => hir::BinOpKind::Mul, + BinOp::Div => hir::BinOpKind::Div, + BinOp::Rem => hir::BinOpKind::Rem, + BinOp::BitXor => hir::BinOpKind::BitXor, + BinOp::BitAnd => hir::BinOpKind::BitAnd, + BinOp::BitOr => hir::BinOpKind::BitOr, + BinOp::Shl => hir::BinOpKind::Shl, + BinOp::Shr => hir::BinOpKind::Shr, + BinOp::Eq => hir::BinOpKind::Eq, + BinOp::Ne => hir::BinOpKind::Ne, + BinOp::Lt => hir::BinOpKind::Lt, + BinOp::Gt => hir::BinOpKind::Gt, + BinOp::Le => hir::BinOpKind::Le, + BinOp::Ge => hir::BinOpKind::Ge, BinOp::Offset => unreachable!() } } diff --git a/src/librustc/mir/traversal.rs b/src/librustc/mir/traversal.rs index 92888ed99e472..86fd825850fc5 100644 --- a/src/librustc/mir/traversal.rs +++ b/src/librustc/mir/traversal.rs @@ -9,7 +9,6 @@ // except according to those terms. use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::indexed_vec::Idx; use super::*; @@ -33,7 +32,7 @@ use super::*; #[derive(Clone)] pub struct Preorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, - visited: BitVector, + visited: BitVector, worklist: Vec, } @@ -58,16 +57,14 @@ impl<'a, 'tcx> Iterator for Preorder<'a, 'tcx> { fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> { while let Some(idx) = self.worklist.pop() { - if !self.visited.insert(idx.index()) { + if !self.visited.insert(idx) { continue; } let data = &self.mir[idx]; if let Some(ref term) = data.terminator { - for &succ in term.successors() { - self.worklist.push(succ); - } + self.worklist.extend(term.successors()); } return Some((idx, data)); @@ -107,7 +104,7 @@ impl<'a, 'tcx> ExactSizeIterator for Preorder<'a, 'tcx> {} /// A Postorder traversal of this graph is `D B C A` or `D C B A` pub struct Postorder<'a, 'tcx: 'a> { mir: &'a Mir<'tcx>, - visited: BitVector, + visited: BitVector, visit_stack: Vec<(BasicBlock, Successors<'a>)> } @@ -123,7 +120,7 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { let data = &po.mir[root]; if let Some(ref term) = data.terminator { - po.visited.insert(root.index()); + po.visited.insert(root); po.visit_stack.push((root, term.successors())); po.traverse_successor(); } @@ -190,8 +187,8 @@ impl<'a, 'tcx> Postorder<'a, 'tcx> { break; }; - if self.visited.insert(bb.index()) { - if let Some(ref term) = self.mir[bb].terminator { + if self.visited.insert(bb) { + if let Some(term) = &self.mir[bb].terminator { self.visit_stack.push((bb, term.successors())); } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index 59b6f3697541a..cab6ed0c122cd 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use ty::subst::Substs; -use ty::{CanonicalTy, ClosureSubsts, Region, Ty, GeneratorInterior}; +use ty::{CanonicalTy, ClosureSubsts, GeneratorSubsts, Region, Ty}; use mir::*; use syntax_pos::Span; @@ -92,9 +92,9 @@ macro_rules! make_mir_visitor { self.super_basic_block_data(block, data); } - fn visit_visibility_scope_data(&mut self, - scope_data: & $($mutability)* VisibilityScopeData) { - self.super_visibility_scope_data(scope_data); + fn visit_source_scope_data(&mut self, + scope_data: & $($mutability)* SourceScopeData) { + self.super_source_scope_data(scope_data); } fn visit_statement(&mut self, @@ -191,12 +191,6 @@ macro_rules! make_mir_visitor { self.super_constant(constant, location); } - fn visit_literal(&mut self, - literal: & $($mutability)* Literal<'tcx>, - location: Location) { - self.super_literal(literal, location); - } - fn visit_def_id(&mut self, def_id: & $($mutability)* DefId, _: Location) { @@ -243,10 +237,10 @@ macro_rules! make_mir_visitor { self.super_closure_substs(substs); } - fn visit_generator_interior(&mut self, - interior: & $($mutability)* GeneratorInterior<'tcx>, + fn visit_generator_substs(&mut self, + substs: & $($mutability)* GeneratorSubsts<'tcx>, _: Location) { - self.super_generator_interior(interior); + self.super_generator_substs(substs); } fn visit_local_decl(&mut self, @@ -261,9 +255,9 @@ macro_rules! make_mir_visitor { _location: Location) { } - fn visit_visibility_scope(&mut self, - scope: & $($mutability)* VisibilityScope) { - self.super_visibility_scope(scope); + fn visit_source_scope(&mut self, + scope: & $($mutability)* SourceScope) { + self.super_source_scope(scope); } // The `super_xxx` methods comprise the default behavior and are @@ -274,7 +268,7 @@ macro_rules! make_mir_visitor { if let Some(yield_ty) = &$($mutability)* mir.yield_ty { self.visit_ty(yield_ty, TyContext::YieldTy(SourceInfo { span: mir.span, - scope: ARGUMENT_VISIBILITY_SCOPE, + scope: OUTERMOST_SOURCE_SCOPE, })); } @@ -289,13 +283,13 @@ macro_rules! make_mir_visitor { self.visit_basic_block_data(bb, data); } - for scope in &$($mutability)* mir.visibility_scopes { - self.visit_visibility_scope_data(scope); + for scope in &$($mutability)* mir.source_scopes { + self.visit_source_scope_data(scope); } self.visit_ty(&$($mutability)* mir.return_ty(), TyContext::ReturnTy(SourceInfo { span: mir.span, - scope: ARGUMENT_VISIBILITY_SCOPE, + scope: OUTERMOST_SOURCE_SCOPE, })); for local in mir.local_decls.indices() { @@ -327,16 +321,16 @@ macro_rules! make_mir_visitor { } } - fn super_visibility_scope_data(&mut self, - scope_data: & $($mutability)* VisibilityScopeData) { - let VisibilityScopeData { + fn super_source_scope_data(&mut self, + scope_data: & $($mutability)* SourceScopeData) { + let SourceScopeData { ref $($mutability)* span, ref $($mutability)* parent_scope, } = *scope_data; self.visit_span(span); if let Some(ref $($mutability)* parent_scope) = *parent_scope { - self.visit_visibility_scope(parent_scope); + self.visit_source_scope(parent_scope); } } @@ -355,6 +349,11 @@ macro_rules! make_mir_visitor { ref $($mutability)* rvalue) => { self.visit_assign(block, place, rvalue, location); } + StatementKind::ReadForMatch(ref $($mutability)* place) => { + self.visit_place(place, + PlaceContext::Inspect, + location); + } StatementKind::EndRegion(_) => {} StatementKind::Validate(_, ref $($mutability)* places) => { for operand in places { @@ -595,11 +594,10 @@ macro_rules! make_mir_visitor { self.visit_closure_substs(closure_substs, location); } AggregateKind::Generator(ref $($mutability)* def_id, - ref $($mutability)* closure_substs, - ref $($mutability)* interior) => { + ref $($mutability)* generator_substs, + _movability) => { self.visit_def_id(def_id, location); - self.visit_closure_substs(closure_substs, location); - self.visit_generator_interior(interior, location); + self.visit_generator_substs(generator_substs, location); } } @@ -644,6 +642,9 @@ macro_rules! make_mir_visitor { Place::Static(ref $($mutability)* static_) => { self.visit_static(static_, context, location); } + Place::Promoted(ref $($mutability)* promoted) => { + self.visit_ty(& $($mutability)* promoted.1, TyContext::Location(location)); + }, Place::Projection(ref $($mutability)* proj) => { self.visit_projection(proj, context, location); } @@ -711,8 +712,8 @@ macro_rules! make_mir_visitor { ref $($mutability)* ty, name: _, ref $($mutability)* source_info, + ref $($mutability)* visibility_scope, internal: _, - ref $($mutability)* syntactic_scope, is_user_variable: _, } = *local_decl; @@ -721,11 +722,11 @@ macro_rules! make_mir_visitor { source_info: *source_info, }); self.visit_source_info(source_info); - self.visit_visibility_scope(syntactic_scope); + self.visit_source_scope(visibility_scope); } - fn super_visibility_scope(&mut self, - _scope: & $($mutability)* VisibilityScope) { + fn super_source_scope(&mut self, + _scope: & $($mutability)* SourceScope) { } fn super_branch(&mut self, @@ -744,18 +745,7 @@ macro_rules! make_mir_visitor { self.visit_span(span); self.visit_ty(ty, TyContext::Location(location)); - self.visit_literal(literal, location); - } - - fn super_literal(&mut self, - literal: & $($mutability)* Literal<'tcx>, - location: Location) { - match *literal { - Literal::Value { ref $($mutability)* value } => { - self.visit_const(value, location); - } - Literal::Promoted { index: _ } => {} - } + self.visit_const(literal, location); } fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) { @@ -771,7 +761,7 @@ macro_rules! make_mir_visitor { } = *source_info; self.visit_span(span); - self.visit_visibility_scope(scope); + self.visit_source_scope(scope); } fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) { @@ -786,8 +776,8 @@ macro_rules! make_mir_visitor { fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) { } - fn super_generator_interior(&mut self, - _interior: & $($mutability)* GeneratorInterior<'tcx>) { + fn super_generator_substs(&mut self, + _substs: & $($mutability)* GeneratorSubsts<'tcx>) { } fn super_closure_substs(&mut self, diff --git a/src/librustc/session/code_stats.rs b/src/librustc/session/code_stats.rs index df4060e71e53e..1eee6508c59cc 100644 --- a/src/librustc/session/code_stats.rs +++ b/src/librustc/session/code_stats.rs @@ -135,8 +135,8 @@ impl CodeStats { let VariantInfo { ref name, kind: _, align: _, size, ref fields } = *variant_info; let indent = if !struct_like { let name = match name.as_ref() { - Some(name) => format!("{}", name), - None => format!("{}", i), + Some(name) => name.to_owned(), + None => i.to_string(), }; println!("print-type-size {}variant `{}`: {} bytes", indent, name, size - discr_size); diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index 0beda679e6959..e0532a3320bc4 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -95,6 +95,23 @@ pub enum Lto { Fat, } +#[derive(Clone, PartialEq, Hash)] +pub enum CrossLangLto { + LinkerPlugin(PathBuf), + LinkerPluginAuto, + Disabled +} + +impl CrossLangLto { + pub fn enabled(&self) -> bool { + match *self { + CrossLangLto::LinkerPlugin(_) | + CrossLangLto::LinkerPluginAuto => true, + CrossLangLto::Disabled => false, + } + } +} + #[derive(Clone, Copy, PartialEq, Hash)] pub enum DebugInfoLevel { NoDebugInfo, @@ -253,7 +270,7 @@ impl OutputTypes { } // True if any of the output types require codegen or linking. - pub fn should_trans(&self) -> bool { + pub fn should_codegen(&self) -> bool { self.0.keys().any(|k| match *k { OutputType::Bitcode | OutputType::Assembly @@ -412,6 +429,7 @@ top_level_options!( // Remap source path prefixes in all output (messages, object files, debug, etc) remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED], + edition: Edition [TRACKED], } ); @@ -437,15 +455,28 @@ pub enum BorrowckMode { Ast, Mir, Compare, + Migrate, } impl BorrowckMode { + /// Should we run the MIR-based borrow check, but also fall back + /// on the AST borrow check if the MIR-based one errors. + pub fn migrate(self) -> bool { + match self { + BorrowckMode::Ast => false, + BorrowckMode::Compare => false, + BorrowckMode::Mir => false, + BorrowckMode::Migrate => true, + } + } + /// Should we emit the AST-based borrow checker errors? pub fn use_ast(self) -> bool { match self { BorrowckMode::Ast => true, BorrowckMode::Compare => true, BorrowckMode::Mir => false, + BorrowckMode::Migrate => false, } } /// Should we emit the MIR-based borrow checker errors? @@ -454,6 +485,7 @@ impl BorrowckMode { BorrowckMode::Ast => false, BorrowckMode::Compare => true, BorrowckMode::Mir => true, + BorrowckMode::Migrate => true, } } } @@ -476,6 +508,13 @@ impl Input { Input::Str { .. } => "rust_out".to_string(), } } + + pub fn get_input(&mut self) -> Option<&mut String> { + match *self { + Input::File(_) => None, + Input::Str { ref mut input, .. } => Some(input), + } + } } #[derive(Clone)] @@ -777,11 +816,15 @@ macro_rules! options { Some("`string` or `string=string`"); pub const parse_lto: Option<&'static str> = Some("one of `thin`, `fat`, or omitted"); + pub const parse_cross_lang_lto: Option<&'static str> = + Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `no-link`, \ + or the path to the linker plugin"); } #[allow(dead_code)] mod $mod_set { - use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto}; + use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto, + CrossLangLto}; use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel}; use std::path::PathBuf; @@ -856,9 +899,7 @@ macro_rules! options { -> bool { match v { Some(s) => { - for s in s.split_whitespace() { - slot.push(s.to_string()); - } + slot.extend(s.split_whitespace().map(|s| s.to_string())); true }, None => false, @@ -986,6 +1027,25 @@ macro_rules! options { true } + fn parse_cross_lang_lto(slot: &mut CrossLangLto, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + CrossLangLto::LinkerPluginAuto + } else { + CrossLangLto::Disabled + }; + return true + } + } + + *slot = match v { + None => CrossLangLto::LinkerPluginAuto, + Some(path) => CrossLangLto::LinkerPlugin(PathBuf::from(path)), + }; + true + } } ) } @@ -1079,7 +1139,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, emit_end_regions: bool = (false, parse_bool, [UNTRACKED], "emit EndRegion as part of MIR; enable transforms that solely process EndRegion"), borrowck: Option = (None, parse_opt_string, [UNTRACKED], - "select which borrowck is used (`ast`, `mir`, or `compare`)"), + "select which borrowck is used (`ast`, `mir`, `migrate`, or `compare`)"), two_phase_borrows: bool = (false, parse_bool, [UNTRACKED], "use two-phase reserved/active distinction for `&mut` borrows in MIR borrowck"), two_phase_beyond_autoref: bool = (false, parse_bool, [UNTRACKED], @@ -1093,18 +1153,18 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "count where LLVM instrs originate"), time_llvm_passes: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true, "The output of `-Z time-llvm-passes` will only reflect timings of \ - re-translated modules when used with incremental compilation" )], + re-codegened modules when used with incremental compilation" )], "measure time of each LLVM pass"), input_stats: bool = (false, parse_bool, [UNTRACKED], "gather statistics about the input"), - trans_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true, - "The output of `-Z trans-stats` might not be accurate when incremental \ + codegen_stats: bool = (false, parse_bool, [UNTRACKED_WITH_WARNING(true, + "The output of `-Z codegen-stats` might not be accurate when incremental \ compilation is enabled")], - "gather trans statistics"), + "gather codegen statistics"), asm_comments: bool = (false, parse_bool, [TRACKED], "generate comments into the assembly (may change behavior)"), - no_verify: bool = (false, parse_bool, [TRACKED], - "skip LLVM verification"), + verify_llvm_ir: bool = (false, parse_bool, [TRACKED], + "verify LLVM IR"), borrowck_stats: bool = (false, parse_bool, [UNTRACKED], "gather borrowck statistics"), no_landing_pads: bool = (false, parse_bool, [TRACKED], @@ -1141,10 +1201,12 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, Use with RUST_REGION_GRAPH=help for more info"), parse_only: bool = (false, parse_bool, [UNTRACKED], "parse only; do not compile, assemble, or link"), - no_trans: bool = (false, parse_bool, [TRACKED], - "run all passes except translation; no output"), + no_codegen: bool = (false, parse_bool, [TRACKED], + "run all passes except codegen; no output"), treat_err_as_bug: bool = (false, parse_bool, [TRACKED], "treat all errors that occur as bugs"), + report_delayed_bugs: bool = (false, parse_bool, [TRACKED], + "immediately print bugs registered with `delay_span_bug`"), external_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], "show macro backtraces even for non-local macros"), teach: bool = (false, parse_bool, [TRACKED], @@ -1183,8 +1245,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "for every macro invocation, print its name and arguments"), debug_macros: bool = (false, parse_bool, [TRACKED], "emit line numbers debug info inside macros"), - enable_nonzeroing_move_hints: bool = (false, parse_bool, [TRACKED], - "force nonzeroing move optimization on"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], "don't clear the hygiene data after analysis"), keep_ast: bool = (false, parse_bool, [UNTRACKED], @@ -1193,16 +1253,16 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "show spans for compiler debugging (expr|pat|ty)"), print_type_sizes: bool = (false, parse_bool, [UNTRACKED], "print layout information for each type encountered"), - print_trans_items: Option = (None, parse_opt_string, [UNTRACKED], - "print the result of the translation item collection pass"), + print_mono_items: Option = (None, parse_opt_string, [UNTRACKED], + "print the result of the monomorphization collection pass"), mir_opt_level: usize = (1, parse_uint, [TRACKED], "set the MIR optimization level (0-3, default: 1)"), - mutable_noalias: bool = (false, parse_bool, [UNTRACKED], - "emit noalias metadata for mutable references"), - arg_align_attributes: bool = (false, parse_bool, [UNTRACKED], + mutable_noalias: Option = (None, parse_opt_bool, [TRACKED], + "emit noalias metadata for mutable references (default: yes on LLVM >= 6)"), + arg_align_attributes: bool = (false, parse_bool, [TRACKED], "emit align metadata for reference arguments"), dump_mir: Option = (None, parse_opt_string, [UNTRACKED], - "dump MIR state at various points in translation"), + "dump MIR state at various points in transforms"), dump_mir_dir: String = (String::from("mir_dump"), parse_string, [UNTRACKED], "the directory the MIR is dumped into"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], @@ -1248,14 +1308,20 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, useful for profiling / PGO."), relro_level: Option = (None, parse_relro_level, [TRACKED], "choose which RELRO level to use"), + disable_ast_check_for_mutation_in_guard: bool = (false, parse_bool, [UNTRACKED], + "skip AST-based mutation-in-guard check (mir-borrowck provides more precise check)"), nll_subminimal_causes: bool = (false, parse_bool, [UNTRACKED], "when tracking region error causes, accept subminimal results for faster execution."), nll_facts: bool = (false, parse_bool, [UNTRACKED], "dump facts from NLL analysis into side files"), disable_nll_user_type_assert: bool = (false, parse_bool, [UNTRACKED], "disable user provided type assertion in NLL"), - trans_time_graph: bool = (false, parse_bool, [UNTRACKED], - "generate a graphical HTML report of time spent in trans and LLVM"), + nll_dont_emit_read_for_match: bool = (false, parse_bool, [UNTRACKED], + "in match codegen, do not include ReadForMatch statements (used by mir-borrowck)"), + polonius: bool = (false, parse_bool, [UNTRACKED], + "enable polonius-based borrow-checker"), + codegen_time_graph: bool = (false, parse_bool, [UNTRACKED], + "generate a graphical HTML report of time spent in codegen and LLVM"), thinlto: Option = (None, parse_opt_bool, [TRACKED], "enable ThinLTO when possible"), inline_in_all_cgus: Option = (None, parse_opt_bool, [TRACKED], @@ -1267,15 +1333,13 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, the max/min integer respectively, and NaN is mapped to 0"), lower_128bit_ops: Option = (None, parse_opt_bool, [TRACKED], "rewrite operators on i128 and u128 into lang item calls (typically provided \ - by compiler-builtins) so translation doesn't need to support them, + by compiler-builtins) so codegen doesn't need to support them, overriding the default for the current target"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], "generate human-readable, predictable names for codegen units"), dep_info_omit_d_target: bool = (false, parse_bool, [TRACKED], "in dep-info output, omit targets for tracking dependencies of the dep-info files \ themselves"), - suggestion_applicability: bool = (false, parse_bool, [UNTRACKED], - "include machine-applicability of suggestions in JSON output"), unpretty: Option = (None, parse_unpretty, [UNTRACKED], "Present the input source, unstable (and less-pretty) variants; valid types are any of the types for `--pretty`, as well as: @@ -1295,6 +1359,14 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "make the current crate share its generic instantiations"), chalk: bool = (false, parse_bool, [TRACKED], "enable the experimental Chalk-based trait solving engine"), + cross_lang_lto: CrossLangLto = (CrossLangLto::Disabled, parse_cross_lang_lto, [TRACKED], + "generate build artifacts that are compatible with linker-based LTO."), + no_parallel_llvm: bool = (false, parse_bool, [UNTRACKED], + "don't run LLVM in parallel (while keeping codegen-units and ThinLTO)"), + no_leak_check: bool = (false, parse_bool, [UNTRACKED], + "disables the 'leak check' for subtyping; unsound, but useful for tests"), + crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], + "inject the given attribute in the crate"), } pub fn default_lib_output() -> CrateType { @@ -1310,6 +1382,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { let vendor = &sess.target.target.target_vendor; let min_atomic_width = sess.target.target.min_atomic_width(); let max_atomic_width = sess.target.target.max_atomic_width(); + let atomic_cas = sess.target.target.options.atomic_cas; let mut ret = HashSet::new(); // Target bindings. @@ -1349,6 +1422,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig { } } } + if atomic_cas { + ret.insert((Symbol::intern("target_has_atomic"), Some(Symbol::intern("cas")))); + } if sess.opts.debug_assertions { ret.insert((Symbol::intern("debug_assertions"), None)); } @@ -1690,6 +1766,29 @@ pub fn parse_cfgspecs(cfgspecs: Vec) -> ast::CrateConfig { .collect::() } +pub fn get_cmd_lint_options(matches: &getopts::Matches, + error_format: ErrorOutputType) + -> (Vec<(String, lint::Level)>, bool, Option) { + let mut lint_opts = vec![]; + let mut describe_lints = false; + + for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] { + for lint_name in matches.opt_strs(level.as_str()) { + if lint_name == "help" { + describe_lints = true; + } else { + lint_opts.push((lint_name.replace("-", "_"), level)); + } + } + } + + let lint_cap = matches.opt_str("cap-lints").map(|cap| { + lint::Level::from_str(&cap) + .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap))) + }); + (lint_opts, describe_lints, lint_cap) +} + pub fn build_session_options_and_crate_config( matches: &getopts::Matches, ) -> (Options, ast::CrateConfig) { @@ -1730,7 +1829,7 @@ pub fn build_session_options_and_crate_config( early_error( ErrorOutputType::default(), &format!( - "Edition {} is unstable an only\ + "Edition {} is unstable and only \ available for nightly builds of rustc.", edition, ) @@ -1747,19 +1846,7 @@ pub fn build_session_options_and_crate_config( Some("human") => ErrorOutputType::HumanReadable(color), Some("json") => ErrorOutputType::Json(false), Some("pretty-json") => ErrorOutputType::Json(true), - Some("short") => { - if nightly_options::is_unstable_enabled(matches) { - ErrorOutputType::Short(color) - } else { - early_error( - ErrorOutputType::default(), - &format!( - "the `-Z unstable-options` flag must also be passed to \ - enable the short error message option" - ), - ); - } - } + Some("short") => ErrorOutputType::Short(color), None => ErrorOutputType::HumanReadable(color), Some(arg) => early_error( @@ -1779,23 +1866,7 @@ pub fn build_session_options_and_crate_config( let crate_types = parse_crate_types_from_list(unparsed_crate_types) .unwrap_or_else(|e| early_error(error_format, &e[..])); - let mut lint_opts = vec![]; - let mut describe_lints = false; - - for &level in &[lint::Allow, lint::Warn, lint::Deny, lint::Forbid] { - for lint_name in matches.opt_strs(level.as_str()) { - if lint_name == "help" { - describe_lints = true; - } else { - lint_opts.push((lint_name.replace("-", "_"), level)); - } - } - } - - let lint_cap = matches.opt_str("cap-lints").map(|cap| { - lint::Level::from_str(&cap) - .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap))) - }); + let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); let mut debugging_opts = build_debugging_options(matches, error_format); @@ -1925,6 +1996,13 @@ pub fn build_session_options_and_crate_config( ); } + if debugging_opts.profile && incremental.is_some() { + early_error( + error_format, + "can't instrument with gcov profiling when compiling incrementally", + ); + } + let mut prints = Vec::::new(); if cg.target_cpu.as_ref().map_or(false, |s| s == "help") { prints.push(PrintRequest::TargetCPUs); @@ -1976,27 +2054,15 @@ pub fn build_session_options_and_crate_config( } OptLevel::Default } else { - match ( - cg.opt_level.as_ref().map(String::as_ref), - nightly_options::is_nightly_build(), - ) { - (None, _) => OptLevel::No, - (Some("0"), _) => OptLevel::No, - (Some("1"), _) => OptLevel::Less, - (Some("2"), _) => OptLevel::Default, - (Some("3"), _) => OptLevel::Aggressive, - (Some("s"), true) => OptLevel::Size, - (Some("z"), true) => OptLevel::SizeMin, - (Some("s"), false) | (Some("z"), false) => { - early_error( - error_format, - &format!( - "the optimizations s or z are only \ - accepted on the nightly compiler" - ), - ); - } - (Some(arg), _) => { + match cg.opt_level.as_ref().map(String::as_ref) { + None => OptLevel::No, + Some("0") => OptLevel::No, + Some("1") => OptLevel::Less, + Some("2") => OptLevel::Default, + Some("3") => OptLevel::Aggressive, + Some("s") => OptLevel::Size, + Some("z") => OptLevel::SizeMin, + Some(arg) => { early_error( error_format, &format!( @@ -2114,6 +2180,7 @@ pub fn build_session_options_and_crate_config( None | Some("ast") => BorrowckMode::Ast, Some("mir") => BorrowckMode::Mir, Some("compare") => BorrowckMode::Compare, + Some("migrate") => BorrowckMode::Migrate, Some(m) => early_error(error_format, &format!("unknown borrowck mode `{}`", m)), }; @@ -2325,7 +2392,7 @@ mod dep_tracking { use std::path::PathBuf; use std::collections::hash_map::DefaultHasher; use super::{CrateType, DebugInfoLevel, ErrorOutputType, Lto, OptLevel, OutputTypes, - Passes, Sanitizer}; + Passes, Sanitizer, CrossLangLto}; use syntax::feature_gate::UnstableFeatures; use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple}; use syntax::edition::Edition; @@ -2389,6 +2456,7 @@ mod dep_tracking { impl_dep_tracking_hash_via_hash!(Option); impl_dep_tracking_hash_via_hash!(TargetTriple); impl_dep_tracking_hash_via_hash!(Edition); + impl_dep_tracking_hash_via_hash!(CrossLangLto); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); @@ -2453,7 +2521,7 @@ mod tests { use lint; use middle::cstore; use session::config::{build_configuration, build_session_options_and_crate_config}; - use session::config::Lto; + use session::config::{Lto, CrossLangLto}; use session::build_session; use std::collections::{BTreeMap, BTreeSet}; use std::iter::FromIterator; @@ -3002,7 +3070,7 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.input_stats = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.trans_stats = true; + opts.debugging_opts.codegen_stats = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.borrowck_stats = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); @@ -3048,7 +3116,7 @@ mod tests { assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.keep_ast = true; assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); - opts.debugging_opts.print_trans_items = Some(String::from("abc")); + opts.debugging_opts.print_mono_items = Some(String::from("abc")); assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); opts.debugging_opts.dump_mir = Some(String::from("abc")); assert_eq!(reference.dep_tracking_hash(), opts.dep_tracking_hash()); @@ -3063,7 +3131,7 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.no_verify = true; + opts.debugging_opts.verify_llvm_ir = true; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); @@ -3075,7 +3143,7 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.no_trans = true; + opts.debugging_opts.no_codegen = true; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); @@ -3083,19 +3151,19 @@ mod tests { assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.continue_parse_after_error = true; + opts.debugging_opts.report_delayed_bugs = true; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")]; + opts.debugging_opts.continue_parse_after_error = true; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.force_overflow_checks = Some(true); + opts.debugging_opts.extra_plugins = vec![String::from("plugin1"), String::from("plugin2")]; assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); - opts.debugging_opts.enable_nonzeroing_move_hints = true; + opts.debugging_opts.force_overflow_checks = Some(true); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); opts = reference.clone(); @@ -3109,6 +3177,10 @@ mod tests { opts = reference.clone(); opts.debugging_opts.relro_level = Some(RelroLevel::Full); assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); + + opts = reference.clone(); + opts.debugging_opts.cross_lang_lto = CrossLangLto::LinkerPluginAuto; + assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash()); } #[test] diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 2ab72ba20bf4f..7b8bbbf4a10e0 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -22,7 +22,7 @@ use middle::dependency_format; use session::search_paths::PathKind; use session::config::{OutputType}; use ty::tls; -use util::nodemap::{FxHashSet}; +use util::nodemap::{FxHashMap, FxHashSet}; use util::common::{duration_to_secs_str, ErrorReported}; use util::common::ProfileQueriesMsg; @@ -98,7 +98,7 @@ pub struct Session { /// arguments passed to the compiler. Its value together with the crate-name /// forms a unique global identifier for the crate. It is used to allow /// multiple crates with the same name to coexist. See the - /// trans::back::symbol_names module for more information. + /// rustc_codegen_llvm::back::symbol_names module for more information. pub crate_disambiguator: Once, features: Once, @@ -160,6 +160,9 @@ pub struct Session { /// Metadata about the allocators for the current crate being compiled pub has_global_allocator: Once, + + /// Cap lint level specified by a driver specifically. + pub driver_lint_caps: FxHashMap, } pub struct PerfStats { @@ -504,8 +507,8 @@ impl Session { pub fn time_llvm_passes(&self) -> bool { self.opts.debugging_opts.time_llvm_passes } - pub fn trans_stats(&self) -> bool { - self.opts.debugging_opts.trans_stats + pub fn codegen_stats(&self) -> bool { + self.opts.debugging_opts.codegen_stats } pub fn meta_stats(&self) -> bool { self.opts.debugging_opts.meta_stats @@ -513,8 +516,8 @@ impl Session { pub fn asm_comments(&self) -> bool { self.opts.debugging_opts.asm_comments } - pub fn no_verify(&self) -> bool { - self.opts.debugging_opts.no_verify + pub fn verify_llvm_ir(&self) -> bool { + self.opts.debugging_opts.verify_llvm_ir } pub fn borrowck_stats(&self) -> bool { self.opts.debugging_opts.borrowck_stats @@ -621,9 +624,6 @@ impl Session { pub fn unstable_options(&self) -> bool { self.opts.debugging_opts.unstable_options } - pub fn nonzeroing_move_hints(&self) -> bool { - self.opts.debugging_opts.enable_nonzeroing_move_hints - } pub fn overflow_checks(&self) -> bool { self.opts .cg @@ -657,6 +657,13 @@ impl Session { } } + pub fn target_cpu(&self) -> &str { + match self.opts.cg.target_cpu { + Some(ref s) => &**s, + None => &*self.target.target.options.cpu + } + } + pub fn must_not_eliminate_frame_pointers(&self) -> bool { if let Some(x) = self.opts.cg.force_frame_pointers { x @@ -838,10 +845,10 @@ impl Session { /// We want to know if we're allowed to do an optimization for crate foo from -z fuel=foo=n. /// This expends fuel if applicable, and records fuel if applicable. pub fn consider_optimizing String>(&self, crate_name: &str, msg: T) -> bool { - assert!(self.query_threads() == 1); let mut ret = true; match self.optimization_fuel_crate { Some(ref c) if c == crate_name => { + assert!(self.query_threads() == 1); let fuel = self.optimization_fuel_limit.get(); ret = fuel != 0; if fuel == 0 && !self.out_of_fuel.get() { @@ -855,6 +862,7 @@ impl Session { } match self.print_fuel_crate { Some(ref c) if c == crate_name => { + assert!(self.query_threads() == 1); self.print_fuel.set(self.print_fuel.get() + 1); } _ => {} @@ -862,10 +870,16 @@ impl Session { ret } + /// Returns the number of query threads that should be used for this + /// compilation + pub fn query_threads_from_opts(opts: &config::Options) -> usize { + opts.debugging_opts.query_threads.unwrap_or(1) + } + /// Returns the number of query threads that should be used for this /// compilation pub fn query_threads(&self) -> usize { - self.opts.debugging_opts.query_threads.unwrap_or(1) + Self::query_threads_from_opts(&self.opts) } /// Returns the number of codegen units that should be used for this @@ -881,11 +895,11 @@ impl Session { // Why is 16 codegen units the default all the time? // // The main reason for enabling multiple codegen units by default is to - // leverage the ability for the trans backend to do translation and - // codegen in parallel. This allows us, especially for large crates, to + // leverage the ability for the codegen backend to do codegen and + // optimization in parallel. This allows us, especially for large crates, to // make good use of all available resources on the machine once we've // hit that stage of compilation. Large crates especially then often - // take a long time in trans/codegen and this helps us amortize that + // take a long time in codegen/optimization and this helps us amortize that // cost. // // Note that a high number here doesn't mean that we'll be spawning a @@ -983,6 +997,7 @@ pub fn build_session_with_codemap( let can_emit_warnings = !(warnings_allow || cap_lints_allow); let treat_err_as_bug = sopts.debugging_opts.treat_err_as_bug; + let report_delayed_bugs = sopts.debugging_opts.report_delayed_bugs; let external_macro_backtrace = sopts.debugging_opts.external_macro_backtrace; @@ -1005,7 +1020,6 @@ pub fn build_session_with_codemap( Some(registry), codemap.clone(), pretty, - sopts.debugging_opts.suggestion_applicability, ).ui_testing(sopts.debugging_opts.ui_testing), ), (config::ErrorOutputType::Json(pretty), Some(dst)) => Box::new( @@ -1014,7 +1028,6 @@ pub fn build_session_with_codemap( Some(registry), codemap.clone(), pretty, - sopts.debugging_opts.suggestion_applicability, ).ui_testing(sopts.debugging_opts.ui_testing), ), (config::ErrorOutputType::Short(color_config), None) => Box::new( @@ -1030,6 +1043,7 @@ pub fn build_session_with_codemap( errors::HandlerFlags { can_emit_warnings, treat_err_as_bug, + report_delayed_bugs, external_macro_backtrace, ..Default::default() }, @@ -1152,6 +1166,7 @@ pub fn build_session_( (*GLOBAL_JOBSERVER).clone() }, has_global_allocator: Once::new(), + driver_lint_caps: FxHashMap(), }; sess diff --git a/src/librustc/traits/auto_trait.rs b/src/librustc/traits/auto_trait.rs new file mode 100644 index 0000000000000..f48739799203f --- /dev/null +++ b/src/librustc/traits/auto_trait.rs @@ -0,0 +1,664 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support code for rustdoc and external tools . You really don't +//! want to be using this unless you need to. + +use super::*; + +use std::collections::hash_map::Entry; +use std::collections::VecDeque; + +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; + +use infer::region_constraints::{Constraint, RegionConstraintData}; +use infer::{InferCtxt, RegionObligation}; + +use ty::fold::TypeFolder; +use ty::{Region, RegionVid}; + +// FIXME(twk): this is obviously not nice to duplicate like that +#[derive(Eq, PartialEq, Hash, Copy, Clone, Debug)] +pub enum RegionTarget<'tcx> { + Region(Region<'tcx>), + RegionVid(RegionVid), +} + +#[derive(Default, Debug, Clone)] +pub struct RegionDeps<'tcx> { + larger: FxHashSet>, + smaller: FxHashSet>, +} + +pub enum AutoTraitResult { + ExplicitImpl, + PositiveImpl(A), + NegativeImpl, +} + +impl AutoTraitResult { + fn is_auto(&self) -> bool { + match *self { + AutoTraitResult::PositiveImpl(_) | AutoTraitResult::NegativeImpl => true, + _ => false, + } + } +} + +pub struct AutoTraitInfo<'cx> { + pub full_user_env: ty::ParamEnv<'cx>, + pub region_data: RegionConstraintData<'cx>, + pub names_map: FxHashSet, + pub vid_to_region: FxHashMap>, +} + +pub struct AutoTraitFinder<'a, 'tcx: 'a> { + tcx: &'a TyCtxt<'a, 'tcx, 'tcx>, +} + +impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { + pub fn new(tcx: &'a TyCtxt<'a, 'tcx, 'tcx>) -> Self { + AutoTraitFinder { tcx } + } + + /// Make a best effort to determine whether and under which conditions an auto trait is + /// implemented for a type. For example, if you have + /// + /// ``` + /// struct Foo { data: Box } + /// ``` + + /// then this might return that Foo: Send if T: Send (encoded in the AutoTraitResult type). + /// The analysis attempts to account for custom impls as well as other complex cases. This + /// result is intended for use by rustdoc and other such consumers. + + /// (Note that due to the coinductive nature of Send, the full and correct result is actually + /// quite simple to generate. That is, when a type has no custom impl, it is Send iff its field + /// types are all Send. So, in our example, we might have that Foo: Send if Box: Send. + /// But this is often not the best way to present to the user.) + + /// Warning: The API should be considered highly unstable, and it may be refactored or removed + /// in the future. + pub fn find_auto_trait_generics( + &self, + did: DefId, + trait_did: DefId, + generics: &ty::Generics, + auto_trait_callback: impl for<'i> Fn(&InferCtxt<'_, 'tcx, 'i>, AutoTraitInfo<'i>) -> A, + ) -> AutoTraitResult { + let tcx = self.tcx; + let ty = self.tcx.type_of(did); + + let orig_params = tcx.param_env(did); + + let trait_ref = ty::TraitRef { + def_id: trait_did, + substs: tcx.mk_substs_trait(ty, &[]), + }; + + let trait_pred = ty::Binder::bind(trait_ref); + + let bail_out = tcx.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::with_negative(&infcx, true); + let result = selcx.select(&Obligation::new( + ObligationCause::dummy(), + orig_params, + trait_pred.to_poly_trait_predicate(), + )); + match result { + Ok(Some(Vtable::VtableImpl(_))) => { + debug!( + "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): \ + manual impl found, bailing out", + did, trait_did, generics + ); + return true; + } + _ => return false, + }; + }); + + // If an explicit impl exists, it always takes priority over an auto impl + if bail_out { + return AutoTraitResult::ExplicitImpl; + } + + return tcx.infer_ctxt().enter(|mut infcx| { + let mut fresh_preds = FxHashSet(); + + // Due to the way projections are handled by SelectionContext, we need to run + // evaluate_predicates twice: once on the original param env, and once on the result of + // the first evaluate_predicates call. + // + // The problem is this: most of rustc, including SelectionContext and traits::project, + // are designed to work with a concrete usage of a type (e.g. Vec + // fn() { Vec }. This information will generally never change - given + // the 'T' in fn() { ... }, we'll never know anything else about 'T'. + // If we're unable to prove that 'T' implements a particular trait, we're done - + // there's nothing left to do but error out. + // + // However, synthesizing an auto trait impl works differently. Here, we start out with + // a set of initial conditions - the ParamEnv of the struct/enum/union we're dealing + // with - and progressively discover the conditions we need to fulfill for it to + // implement a certain auto trait. This ends up breaking two assumptions made by trait + // selection and projection: + // + // * We can always cache the result of a particular trait selection for the lifetime of + // an InfCtxt + // * Given a projection bound such as '::SomeItem = K', if 'T: + // SomeTrait' doesn't hold, then we don't need to care about the 'SomeItem = K' + // + // We fix the first assumption by manually clearing out all of the InferCtxt's caches + // in between calls to SelectionContext.select. This allows us to keep all of the + // intermediate types we create bound to the 'tcx lifetime, rather than needing to lift + // them between calls. + // + // We fix the second assumption by reprocessing the result of our first call to + // evaluate_predicates. Using the example of '::SomeItem = K', our first + // pass will pick up 'T: SomeTrait', but not 'SomeItem = K'. On our second pass, + // traits::project will see that 'T: SomeTrait' is in our ParamEnv, allowing + // SelectionContext to return it back to us. + + let (new_env, user_env) = match self.evaluate_predicates( + &mut infcx, + did, + trait_did, + ty, + orig_params.clone(), + orig_params, + &mut fresh_preds, + false, + ) { + Some(e) => e, + None => return AutoTraitResult::NegativeImpl, + }; + + let (full_env, full_user_env) = self.evaluate_predicates( + &mut infcx, + did, + trait_did, + ty, + new_env.clone(), + user_env, + &mut fresh_preds, + true, + ).unwrap_or_else(|| { + panic!( + "Failed to fully process: {:?} {:?} {:?}", + ty, trait_did, orig_params + ) + }); + + debug!( + "find_auto_trait_generics(did={:?}, trait_did={:?}, generics={:?}): fulfilling \ + with {:?}", + did, trait_did, generics, full_env + ); + infcx.clear_caches(); + + // At this point, we already have all of the bounds we need. FulfillmentContext is used + // to store all of the necessary region/lifetime bounds in the InferContext, as well as + // an additional sanity check. + let mut fulfill = FulfillmentContext::new(); + fulfill.register_bound( + &infcx, + full_env, + ty, + trait_did, + ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID), + ); + fulfill.select_all_or_error(&infcx).unwrap_or_else(|e| { + panic!( + "Unable to fulfill trait {:?} for '{:?}': {:?}", + trait_did, ty, e + ) + }); + + let names_map: FxHashSet = generics + .params + .iter() + .filter_map(|param| match param.kind { + ty::GenericParamDefKind::Lifetime => Some(param.name.to_string()), + _ => None + }) + .collect(); + + let body_ids: FxHashSet<_> = infcx + .region_obligations + .borrow() + .iter() + .map(|&(id, _)| id) + .collect(); + + for id in body_ids { + infcx.process_registered_region_obligations(&[], None, full_env.clone(), id); + } + + let region_data = infcx + .borrow_region_constraints() + .region_constraint_data() + .clone(); + + let vid_to_region = self.map_vid_to_region(®ion_data); + + let info = AutoTraitInfo { + full_user_env, + region_data, + names_map, + vid_to_region, + }; + + return AutoTraitResult::PositiveImpl(auto_trait_callback(&infcx, info)); + }); + } +} + +impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { + // The core logic responsible for computing the bounds for our synthesized impl. + // + // To calculate the bounds, we call SelectionContext.select in a loop. Like FulfillmentContext, + // we recursively select the nested obligations of predicates we encounter. However, whenver we + // encounter an UnimplementedError involving a type parameter, we add it to our ParamEnv. Since + // our goal is to determine when a particular type implements an auto trait, Unimplemented + // errors tell us what conditions need to be met. + // + // This method ends up working somewhat similary to FulfillmentContext, but with a few key + // differences. FulfillmentContext works under the assumption that it's dealing with concrete + // user code. According, it considers all possible ways that a Predicate could be met - which + // isn't always what we want for a synthesized impl. For example, given the predicate 'T: + // Iterator', FulfillmentContext can end up reporting an Unimplemented error for T: + // IntoIterator - since there's an implementation of Iteratpr where T: IntoIterator, + // FulfillmentContext will drive SelectionContext to consider that impl before giving up. If we + // were to rely on FulfillmentContext's decision, we might end up synthesizing an impl like + // this: + // 'impl Send for Foo where T: IntoIterator' + // + // While it might be technically true that Foo implements Send where T: IntoIterator, + // the bound is overly restrictive - it's really only necessary that T: Iterator. + // + // For this reason, evaluate_predicates handles predicates with type variables specially. When + // we encounter an Unimplemented error for a bound such as 'T: Iterator', we immediately add it + // to our ParamEnv, and add it to our stack for recursive evaluation. When we later select it, + // we'll pick up any nested bounds, without ever inferring that 'T: IntoIterator' needs to + // hold. + // + // One additonal consideration is supertrait bounds. Normally, a ParamEnv is only ever + // consutrcted once for a given type. As part of the construction process, the ParamEnv will + // have any supertrait bounds normalized - e.g. if we have a type 'struct Foo', the + // ParamEnv will contain 'T: Copy' and 'T: Clone', since 'Copy: Clone'. When we construct our + // own ParamEnv, we need to do this outselves, through traits::elaborate_predicates, or else + // SelectionContext will choke on the missing predicates. However, this should never show up in + // the final synthesized generics: we don't want our generated docs page to contain something + // like 'T: Copy + Clone', as that's redundant. Therefore, we keep track of a separate + // 'user_env', which only holds the predicates that will actually be displayed to the user. + pub fn evaluate_predicates<'b, 'gcx, 'c>( + &self, + infcx: &InferCtxt<'b, 'tcx, 'c>, + ty_did: DefId, + trait_did: DefId, + ty: ty::Ty<'c>, + param_env: ty::ParamEnv<'c>, + user_env: ty::ParamEnv<'c>, + fresh_preds: &mut FxHashSet>, + only_projections: bool, + ) -> Option<(ty::ParamEnv<'c>, ty::ParamEnv<'c>)> { + let tcx = infcx.tcx; + + let mut select = SelectionContext::new(&infcx); + + let mut already_visited = FxHashSet(); + let mut predicates = VecDeque::new(); + predicates.push_back(ty::Binder::bind(ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: trait_did, + substs: infcx.tcx.mk_substs_trait(ty, &[]), + }, + })); + + let mut computed_preds: FxHashSet<_> = param_env.caller_bounds.iter().cloned().collect(); + let mut user_computed_preds: FxHashSet<_> = + user_env.caller_bounds.iter().cloned().collect(); + + let mut new_env = param_env.clone(); + let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID); + + while let Some(pred) = predicates.pop_front() { + infcx.clear_caches(); + + if !already_visited.insert(pred.clone()) { + continue; + } + + let result = select.select(&Obligation::new(dummy_cause.clone(), new_env, pred)); + + match &result { + &Ok(Some(ref vtable)) => { + let obligations = vtable.clone().nested_obligations().into_iter(); + + if !self.evaluate_nested_obligations( + ty, + obligations, + &mut user_computed_preds, + fresh_preds, + &mut predicates, + &mut select, + only_projections, + ) { + return None; + } + } + &Ok(None) => {} + &Err(SelectionError::Unimplemented) => { + if self.is_of_param(pred.skip_binder().trait_ref.substs) { + already_visited.remove(&pred); + user_computed_preds.insert(ty::Predicate::Trait(pred.clone())); + predicates.push_back(pred); + } else { + debug!( + "evaluate_nested_obligations: Unimplemented found, bailing: \ + {:?} {:?} {:?}", + ty, + pred, + pred.skip_binder().trait_ref.substs + ); + return None; + } + } + _ => panic!("Unexpected error for '{:?}': {:?}", ty, result), + }; + + computed_preds.extend(user_computed_preds.iter().cloned()); + let normalized_preds = + elaborate_predicates(tcx, computed_preds.clone().into_iter().collect()); + new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal); + } + + let final_user_env = ty::ParamEnv::new( + tcx.mk_predicates(user_computed_preds.into_iter()), + user_env.reveal, + ); + debug!( + "evaluate_nested_obligations(ty_did={:?}, trait_did={:?}): succeeded with '{:?}' \ + '{:?}'", + ty_did, trait_did, new_env, final_user_env + ); + + return Some((new_env, final_user_env)); + } + + pub fn region_name(&self, region: Region) -> Option { + match region { + &ty::ReEarlyBound(r) => Some(r.name.to_string()), + _ => None, + } + } + + pub fn get_lifetime(&self, region: Region, names_map: &FxHashMap) -> String { + self.region_name(region) + .map(|name| { + names_map.get(&name).unwrap_or_else(|| { + panic!("Missing lifetime with name {:?} for {:?}", name, region) + }) + }) + .unwrap_or(&"'static".to_string()) + .clone() + } + + // This is very similar to handle_lifetimes. However, instead of matching ty::Region's + // to each other, we match ty::RegionVid's to ty::Region's + pub fn map_vid_to_region<'cx>( + &self, + regions: &RegionConstraintData<'cx>, + ) -> FxHashMap> { + let mut vid_map: FxHashMap, RegionDeps<'cx>> = FxHashMap(); + let mut finished_map = FxHashMap(); + + for constraint in regions.constraints.keys() { + match constraint { + &Constraint::VarSubVar(r1, r2) => { + { + let deps1 = vid_map + .entry(RegionTarget::RegionVid(r1)) + .or_insert_with(|| Default::default()); + deps1.larger.insert(RegionTarget::RegionVid(r2)); + } + + let deps2 = vid_map + .entry(RegionTarget::RegionVid(r2)) + .or_insert_with(|| Default::default()); + deps2.smaller.insert(RegionTarget::RegionVid(r1)); + } + &Constraint::RegSubVar(region, vid) => { + { + let deps1 = vid_map + .entry(RegionTarget::Region(region)) + .or_insert_with(|| Default::default()); + deps1.larger.insert(RegionTarget::RegionVid(vid)); + } + + let deps2 = vid_map + .entry(RegionTarget::RegionVid(vid)) + .or_insert_with(|| Default::default()); + deps2.smaller.insert(RegionTarget::Region(region)); + } + &Constraint::VarSubReg(vid, region) => { + finished_map.insert(vid, region); + } + &Constraint::RegSubReg(r1, r2) => { + { + let deps1 = vid_map + .entry(RegionTarget::Region(r1)) + .or_insert_with(|| Default::default()); + deps1.larger.insert(RegionTarget::Region(r2)); + } + + let deps2 = vid_map + .entry(RegionTarget::Region(r2)) + .or_insert_with(|| Default::default()); + deps2.smaller.insert(RegionTarget::Region(r1)); + } + } + } + + while !vid_map.is_empty() { + let target = vid_map.keys().next().expect("Keys somehow empty").clone(); + let deps = vid_map.remove(&target).expect("Entry somehow missing"); + + for smaller in deps.smaller.iter() { + for larger in deps.larger.iter() { + match (smaller, larger) { + (&RegionTarget::Region(_), &RegionTarget::Region(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*smaller) { + let smaller_deps = v.into_mut(); + smaller_deps.larger.insert(*larger); + smaller_deps.larger.remove(&target); + } + + if let Entry::Occupied(v) = vid_map.entry(*larger) { + let larger_deps = v.into_mut(); + larger_deps.smaller.insert(*smaller); + larger_deps.smaller.remove(&target); + } + } + (&RegionTarget::RegionVid(v1), &RegionTarget::Region(r1)) => { + finished_map.insert(v1, r1); + } + (&RegionTarget::Region(_), &RegionTarget::RegionVid(_)) => { + // Do nothing - we don't care about regions that are smaller than vids + } + (&RegionTarget::RegionVid(_), &RegionTarget::RegionVid(_)) => { + if let Entry::Occupied(v) = vid_map.entry(*smaller) { + let smaller_deps = v.into_mut(); + smaller_deps.larger.insert(*larger); + smaller_deps.larger.remove(&target); + } + + if let Entry::Occupied(v) = vid_map.entry(*larger) { + let larger_deps = v.into_mut(); + larger_deps.smaller.insert(*smaller); + larger_deps.smaller.remove(&target); + } + } + } + } + } + } + finished_map + } + + pub fn is_of_param(&self, substs: &Substs) -> bool { + if substs.is_noop() { + return false; + } + + return match substs.type_at(0).sty { + ty::TyParam(_) => true, + ty::TyProjection(p) => self.is_of_param(p.substs), + _ => false, + }; + } + + pub fn evaluate_nested_obligations< + 'b, + 'c, + 'd, + 'cx, + T: Iterator>>, + >( + &self, + ty: ty::Ty, + nested: T, + computed_preds: &'b mut FxHashSet>, + fresh_preds: &'b mut FxHashSet>, + predicates: &'b mut VecDeque>, + select: &mut SelectionContext<'c, 'd, 'cx>, + only_projections: bool, + ) -> bool { + let dummy_cause = ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID); + + for (obligation, predicate) in nested + .filter(|o| o.recursion_depth == 1) + .map(|o| (o.clone(), o.predicate.clone())) + { + let is_new_pred = + fresh_preds.insert(self.clean_pred(select.infcx(), predicate.clone())); + + match &predicate { + &ty::Predicate::Trait(ref p) => { + let substs = &p.skip_binder().trait_ref.substs; + + if self.is_of_param(substs) && !only_projections && is_new_pred { + computed_preds.insert(predicate); + } + predicates.push_back(p.clone()); + } + &ty::Predicate::Projection(p) => { + // If the projection isn't all type vars, then + // we don't want to add it as a bound + if self.is_of_param(p.skip_binder().projection_ty.substs) && is_new_pred { + computed_preds.insert(predicate); + } else { + match poly_project_and_unify_type(select, &obligation.with(p.clone())) { + Err(e) => { + debug!( + "evaluate_nested_obligations: Unable to unify predicate \ + '{:?}' '{:?}', bailing out", + ty, e + ); + return false; + } + Ok(Some(v)) => { + if !self.evaluate_nested_obligations( + ty, + v.clone().iter().cloned(), + computed_preds, + fresh_preds, + predicates, + select, + only_projections, + ) { + return false; + } + } + Ok(None) => { + panic!("Unexpected result when selecting {:?} {:?}", ty, obligation) + } + } + } + } + &ty::Predicate::RegionOutlives(ref binder) => { + if let Err(_) = select + .infcx() + .region_outlives_predicate(&dummy_cause, binder) + { + return false; + } + } + &ty::Predicate::TypeOutlives(ref binder) => { + match ( + binder.no_late_bound_regions(), + binder.map_bound_ref(|pred| pred.0).no_late_bound_regions(), + ) { + (None, Some(t_a)) => { + select.infcx().register_region_obligation( + ast::DUMMY_NODE_ID, + RegionObligation { + sup_type: t_a, + sub_region: select.infcx().tcx.types.re_static, + cause: dummy_cause.clone(), + }, + ); + } + (Some(ty::OutlivesPredicate(t_a, r_b)), _) => { + select.infcx().register_region_obligation( + ast::DUMMY_NODE_ID, + RegionObligation { + sup_type: t_a, + sub_region: r_b, + cause: dummy_cause.clone(), + }, + ); + } + _ => {} + }; + } + _ => panic!("Unexpected predicate {:?} {:?}", ty, predicate), + }; + } + return true; + } + + pub fn clean_pred<'c, 'd, 'cx>( + &self, + infcx: &InferCtxt<'c, 'd, 'cx>, + p: ty::Predicate<'cx>, + ) -> ty::Predicate<'cx> { + infcx.freshen(p) + } +} + +// Replaces all ReVars in a type with ty::Region's, using the provided map +pub struct RegionReplacer<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> { + vid_to_region: &'a FxHashMap>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, +} + +impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + (match r { + &ty::ReVar(vid) => self.vid_to_region.get(&vid).cloned(), + _ => None, + }).unwrap_or_else(|| r.super_fold_with(self)) + } +} diff --git a/src/librustc/traits/codegen/mod.rs b/src/librustc/traits/codegen/mod.rs new file mode 100644 index 0000000000000..cf404202ac120 --- /dev/null +++ b/src/librustc/traits/codegen/mod.rs @@ -0,0 +1,184 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// This file contains various trait resolution methods used by codegen. +// They all assume regions can be erased and monomorphic types. It +// seems likely that they should eventually be merged into more +// general routines. + +use dep_graph::{DepKind, DepTrackingMapConfig}; +use std::marker::PhantomData; +use syntax_pos::DUMMY_SP; +use infer::InferCtxt; +use syntax_pos::Span; +use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, + TraitEngine, Vtable}; +use ty::{self, Ty, TyCtxt}; +use ty::subst::{Subst, Substs}; +use ty::fold::TypeFoldable; + +/// Attempts to resolve an obligation to a vtable.. The result is +/// a shallow vtable resolution -- meaning that we do not +/// (necessarily) resolve all nested obligations on the impl. Note +/// that type check should guarantee to us that all nested +/// obligations *could be* resolved if we wanted to. +/// Assumes that this is run after the entire crate has been successfully type-checked. +pub fn codegen_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, + (param_env, trait_ref): + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) + -> Vtable<'tcx, ()> +{ + // Remove any references to regions; this helps improve caching. + let trait_ref = ty.erase_regions(&trait_ref); + + debug!("codegen_fulfill_obligation(trait_ref={:?}, def_id={:?})", + (param_env, trait_ref), trait_ref.def_id()); + + // Do the initial selection for the obligation. This yields the + // shallow result we are looking for -- that is, what specific impl. + ty.infer_ctxt().enter(|infcx| { + let mut selcx = SelectionContext::new(&infcx); + + let obligation_cause = ObligationCause::dummy(); + let obligation = Obligation::new(obligation_cause, + param_env, + trait_ref.to_poly_trait_predicate()); + + let selection = match selcx.select(&obligation) { + Ok(Some(selection)) => selection, + Ok(None) => { + // Ambiguity can happen when monomorphizing during trans + // expands to some humongo type that never occurred + // statically -- this humongo type can then overflow, + // leading to an ambiguous result. So report this as an + // overflow bug, since I believe this is the only case + // where ambiguity can result. + bug!("Encountered ambiguity selecting `{:?}` during codegen, \ + presuming due to overflow", + trait_ref) + } + Err(e) => { + bug!("Encountered error `{:?}` selecting `{:?}` during codegen", + e, trait_ref) + } + }; + + debug!("fulfill_obligation: selection={:?}", selection); + + // Currently, we use a fulfillment context to completely resolve + // all nested obligations. This is because they can inform the + // inference of the impl's type parameters. + let mut fulfill_cx = FulfillmentContext::new(); + let vtable = selection.map(|predicate| { + debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); + fulfill_cx.register_predicate_obligation(&infcx, predicate); + }); + let vtable = infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable); + + info!("Cache miss: {:?} => {:?}", trait_ref, vtable); + vtable + }) +} + +impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { + /// Monomorphizes a type from the AST by first applying the + /// in-scope substitutions and then normalizing any associated + /// types. + pub fn subst_and_normalize_erasing_regions( + self, + param_substs: &Substs<'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &T + ) -> T + where + T: TypeFoldable<'tcx>, + { + debug!( + "subst_and_normalize_erasing_regions(\ + param_substs={:?}, \ + value={:?}, \ + param_env={:?})", + param_substs, + value, + param_env, + ); + let substituted = value.subst(self, param_substs); + self.normalize_erasing_regions(param_env, substituted) + } +} + +// Implement DepTrackingMapConfig for `trait_cache` +pub struct TraitSelectionCache<'tcx> { + data: PhantomData<&'tcx ()> +} + +impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { + type Key = (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>); + type Value = Vtable<'tcx, ()>; + fn to_dep_kind() -> DepKind { + DepKind::TraitSelect + } +} + +// # Global Cache + +pub struct ProjectionCache<'gcx> { + data: PhantomData<&'gcx ()> +} + +impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { + type Key = Ty<'gcx>; + type Value = Ty<'gcx>; + fn to_dep_kind() -> DepKind { + DepKind::TraitSelect + } +} + +impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { + /// Finishes processes any obligations that remain in the + /// fulfillment context, and then returns the result with all type + /// variables removed and regions erased. Because this is intended + /// for use after type-check has completed, if any errors occur, + /// it will panic. It is used during normalization and other cases + /// where processing the obligations in `fulfill_cx` may cause + /// type inference variables that appear in `result` to be + /// unified, and hence we need to process those obligations to get + /// the complete picture of the type. + fn drain_fulfillment_cx_or_panic(&self, + span: Span, + fulfill_cx: &mut FulfillmentContext<'tcx>, + result: &T) + -> T::Lifted + where T: TypeFoldable<'tcx> + ty::Lift<'gcx> + { + debug!("drain_fulfillment_cx_or_panic()"); + + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + match fulfill_cx.select_all_or_error(self) { + Ok(()) => { } + Err(errors) => { + span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", + errors); + } + } + + let result = self.resolve_type_vars_if_possible(result); + let result = self.tcx.erase_regions(&result); + + match self.tcx.lift_to_global(&result) { + Some(result) => result, + None => { + span_bug!(span, "Uninferred types/regions in `{:?}`", result); + } + } + } +} diff --git a/src/librustc/traits/coherence.rs b/src/librustc/traits/coherence.rs index 5a626e7b82cc4..02bfab033efc8 100644 --- a/src/librustc/traits/coherence.rs +++ b/src/librustc/traits/coherence.rs @@ -11,8 +11,8 @@ //! See rustc guide chapters on [trait-resolution] and [trait-specialization] for more info on how //! this works. //! -//! [trait-resolution]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html -//! [trait-specialization]: https://rust-lang-nursery.github.io/rustc-guide/trait-specialization.html +//! [trait-resolution]: https://rust-lang-nursery.github.io/rustc-guide/traits/resolution.html +//! [trait-specialization]: https://rust-lang-nursery.github.io/rustc-guide/traits/specialization.html use hir::def_id::{DefId, LOCAL_CRATE}; use syntax_pos::DUMMY_SP; @@ -59,7 +59,7 @@ where F1: FnOnce(OverlapResult<'_>) -> R, F2: FnOnce() -> R, { - debug!("impl_can_satisfy(\ + debug!("overlapping_impls(\ impl1_def_id={:?}, \ impl2_def_id={:?}, intercrate_mode={:?})", diff --git a/src/librustc/traits/engine.rs b/src/librustc/traits/engine.rs index 8eee6f35ab956..acbf5392cf54c 100644 --- a/src/librustc/traits/engine.rs +++ b/src/librustc/traits/engine.rs @@ -13,59 +13,67 @@ use ty::{self, Ty, TyCtxt}; use hir::def_id::DefId; use super::{FulfillmentContext, FulfillmentError}; -use super::{ObligationCause, PendingPredicateObligation, PredicateObligation}; +use super::{ObligationCause, PredicateObligation}; pub trait TraitEngine<'tcx>: 'tcx { - fn normalize_projection_type<'a, 'gcx>( + fn normalize_projection_type( &mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, ) -> Ty<'tcx>; - fn register_bound<'a, 'gcx>( + fn register_bound( &mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, def_id: DefId, cause: ObligationCause<'tcx>, ); - fn register_predicate_obligation<'a, 'gcx>( + fn register_predicate_obligation( &mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, obligation: PredicateObligation<'tcx>, ); - fn select_all_or_error<'a, 'gcx>( + fn select_all_or_error( &mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, ) -> Result<(), Vec>>; - fn select_where_possible<'a, 'gcx>( + fn select_where_possible( &mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, ) -> Result<(), Vec>>; - fn pending_obligations(&self) -> Vec>; + fn pending_obligations(&self) -> Vec>; } -impl<'a, 'gcx, 'tcx> dyn TraitEngine<'tcx> { - pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box { - Box::new(FulfillmentContext::new()) - } +pub trait TraitEngineExt<'tcx> { + fn register_predicate_obligations( + &mut self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + obligations: impl IntoIterator>, + ); +} - pub fn register_predicate_obligations( +impl> TraitEngineExt<'tcx> for T { + fn register_predicate_obligations( &mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - obligations: I, - ) where - I: IntoIterator>, - { + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + obligations: impl IntoIterator>, + ) { for obligation in obligations { self.register_predicate_obligation(infcx, obligation); } } } + +impl dyn TraitEngine<'tcx> { + pub fn new(_tcx: TyCtxt<'_, '_, 'tcx>) -> Box { + Box::new(FulfillmentContext::new()) + } +} diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 047d4bb893096..b99c630edfcbd 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -27,7 +27,7 @@ use super::{ Overflow, }; -use errors::DiagnosticBuilder; +use errors::{Applicability, DiagnosticBuilder}; use hir; use hir::def_id::DefId; use infer::{self, InferCtxt}; @@ -36,6 +36,7 @@ use std::fmt; use syntax::ast; use session::DiagnosticMessageId; use ty::{self, AdtKind, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; +use ty::GenericParamDefKind; use ty::error::ExpectedFound; use ty::fast_reject; use ty::fold::TypeFolder; @@ -47,7 +48,7 @@ use syntax_pos::{DUMMY_SP, Span}; impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn report_fulfillment_errors(&self, - errors: &Vec>, + errors: &[FulfillmentError<'tcx>], body_id: Option, fallback_has_occurred: bool) { #[derive(Debug)] @@ -202,17 +203,19 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { obligation.cause.span, infer::LateBoundRegionConversionTime::HigherRankedType, data); - let normalized = super::normalize_projection_type( + let mut obligations = vec![]; + let normalized_ty = super::normalize_projection_type( &mut selcx, obligation.param_env, data.projection_ty, obligation.cause.clone(), - 0 + 0, + &mut obligations ); if let Err(error) = self.at(&obligation.cause, obligation.param_env) - .eq(normalized.value, data.ty) { + .eq(normalized_ty, data.ty) { values = Some(infer::ValuePairs::Types(ExpectedFound { - expected: normalized.value, + expected: normalized_ty, found: data.ty, })); err_buf = error; @@ -363,9 +366,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { - let desugaring = k.as_symbol().as_str(); flags.push(("from_desugaring".to_string(), None)); - flags.push(("from_desugaring".to_string(), Some(desugaring.to_string()))); + flags.push(("from_desugaring".to_string(), Some(k.name().to_string()))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); @@ -378,15 +380,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { flags.push(("_Self".to_string(), Some(self.tcx.type_of(def.did).to_string()))); } - for param in generics.types.iter() { + for param in generics.params.iter() { + let value = match param.kind { + GenericParamDefKind::Type {..} => { + trait_ref.substs[param.index as usize].to_string() + }, + GenericParamDefKind::Lifetime => continue, + }; let name = param.name.to_string(); - let ty = trait_ref.substs.type_for_def(param); - let ty_str = ty.to_string(); - flags.push((name.clone(), - Some(ty_str.clone()))); + flags.push((name, Some(value))); } - if let Some(true) = self_ty.ty_to_def_id().map(|def_id| def_id.is_local()) { + if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { flags.push(("crate_local".to_string(), None)); } @@ -538,7 +543,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { &data.parent_trait_ref); match self.get_parent_trait_ref(&data.parent_code) { Some(t) => Some(t), - None => Some(format!("{}", parent_trait_ref.skip_binder().self_ty())), + None => Some(parent_trait_ref.skip_binder().self_ty().to_string()), } } _ => None, @@ -646,14 +651,10 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { && fallback_has_occurred { let predicate = trait_predicate.map_bound(|mut trait_pred| { - { - let trait_ref = &mut trait_pred.trait_ref; - let never_substs = trait_ref.substs; - let mut unit_substs = Vec::with_capacity(never_substs.len()); - unit_substs.push(self.tcx.mk_nil().into()); - unit_substs.extend(&never_substs[1..]); - trait_ref.substs = self.tcx.intern_substs(&unit_substs); - } + trait_pred.trait_ref.substs = self.tcx.mk_substs_trait( + self.tcx.mk_nil(), + &trait_pred.trait_ref.substs[1..], + ); trait_pred }); let unit_obligation = Obligation { @@ -774,7 +775,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } let found_trait_ty = found_trait_ref.self_ty(); - let found_did = found_trait_ty.ty_to_def_id(); + let found_did = match found_trait_ty.sty { + ty::TyClosure(did, _) | + ty::TyForeign(did) | + ty::TyFnDef(did, _) => Some(did), + ty::TyAdt(def, _) => Some(def.did), + _ => None, + }; let found_span = found_did.and_then(|did| { self.tcx.hir.span_if_local(did) }).map(|sp| self.tcx.sess.codemap().def_span(sp)); // the sp could be an fn def @@ -790,12 +797,12 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ty::TypeVariants::TyTuple(ref tys) => ArgKind::Tuple( Some(span), tys.iter() - .map(|ty| ("_".to_owned(), format!("{}", ty.sty))) + .map(|ty| ("_".to_owned(), ty.sty.to_string())) .collect::>() ), - _ => ArgKind::Arg("_".to_owned(), format!("{}", t.sty)), + _ => ArgKind::Arg("_".to_owned(), t.sty.to_string()), }).collect(), - ref sty => vec![ArgKind::Arg("_".to_owned(), format!("{}", sty))], + ref sty => vec![ArgKind::Arg("_".to_owned(), sty.to_string())], }; if found.len() == expected.len() { self.report_closure_arg_mismatch(span, @@ -825,10 +832,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ConstEvalFailure(ref err) => { - if let ::middle::const_val::ErrKind::TypeckError = *err.kind { - return; + match err.struct_error( + self.tcx.at(span), + "could not evaluate constant expression", + ) { + Some(err) => err, + None => return, } - err.struct_error(self.tcx, span, "constant expression") } Overflow => { @@ -848,11 +858,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let parent_node = self.tcx.hir.get_parent_node(node_id); if let Some(hir::map::NodeLocal(ref local)) = self.tcx.hir.find(parent_node) { if let Some(ref expr) = local.init { - if let hir::ExprIndex(_, _) = expr.node { + if let hir::ExprKind::Index(_, _) = expr.node { if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(expr.span) { - err.span_suggestion(expr.span, - "consider borrowing here", - format!("&{}", snippet)); + err.span_suggestion_with_applicability( + expr.span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::MachineApplicable + ); } } } @@ -878,9 +891,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let mut trait_type = trait_ref.self_ty(); for refs_remaining in 0..refs_number { - if let ty::TypeVariants::TyRef(_, ty::TypeAndMut{ ty: t_type, mutbl: _ }) = - trait_type.sty { - + if let ty::TypeVariants::TyRef(_, t_type, _) = trait_type.sty { trait_type = t_type; let substs = self.tcx.mk_substs_trait(trait_type, &[]); @@ -897,7 +908,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let format_str = format!("consider removing {} leading `&`-references", remove_refs); - err.span_suggestion_short(sp, &format_str, String::from("")); + err.span_suggestion_short_with_applicability( + sp, &format_str, String::from(""), Applicability::MachineApplicable + ); break; } } else { @@ -914,7 +927,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { pub fn get_fn_like_arguments(&self, node: hir::map::Node) -> (Span, Vec) { match node { hir::map::NodeExpr(&hir::Expr { - node: hir::ExprClosure(_, ref _decl, id, span, _), + node: hir::ExprKind::Closure(_, ref _decl, id, span, _), .. }) => { (self.tcx.sess.codemap().def_span(span), self.tcx.hir.body(id).arguments.iter() @@ -942,7 +955,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } hir::map::NodeItem(&hir::Item { span, - node: hir::ItemFn(ref decl, ..), + node: hir::ItemKind::Fn(ref decl, ..), .. }) | hir::map::NodeImplItem(&hir::ImplItem { @@ -956,8 +969,8 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { .. }) => { (self.tcx.sess.codemap().def_span(span), decl.inputs.iter() - .map(|arg| match arg.clone().into_inner().node { - hir::TyTup(ref tys) => ArgKind::Tuple( + .map(|arg| match arg.clone().node { + hir::TyKind::Tup(ref tys) => ArgKind::Tuple( Some(arg.span), tys.iter() .map(|_| ("_".to_owned(), "_".to_owned())) @@ -968,7 +981,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } hir::map::NodeVariant(&hir::Variant { span, - node: hir::Variant_ { + node: hir::VariantKind { data: hir::VariantData::Tuple(ref fields, _), .. }, @@ -976,7 +989,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { }) => { (self.tcx.sess.codemap().def_span(span), fields.iter().map(|field| { - ArgKind::Arg(format!("{}", field.name), "_".to_string()) + ArgKind::Arg(field.ident.to_string(), "_".to_string()) }).collect::>()) } hir::map::NodeStructCtor(ref variant_data) => { @@ -1002,7 +1015,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ) -> DiagnosticBuilder<'tcx> { let kind = if is_closure { "closure" } else { "function" }; - let args_str = |arguments: &Vec, other: &Vec| { + let args_str = |arguments: &[ArgKind], other: &[ArgKind]| { let arg_length = arguments.len(); let distinct = match &other[..] { &[ArgKind::Tuple(..)] => true, @@ -1037,15 +1050,40 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { if let Some(found_span) = found_span { err.span_label(found_span, format!("takes {}", found_str)); + // Suggest to take and ignore the arguments with expected_args_length `_`s if + // found arguments is empty (assume the user just wants to ignore args in this case). + // For example, if `expected_args_length` is 2, suggest `|_, _|`. + if found_args.is_empty() && is_closure { + let mut underscores = "_".repeat(expected_args.len()) + .split("") + .filter(|s| !s.is_empty()) + .collect::>() + .join(", "); + err.span_suggestion_with_applicability( + found_span, + &format!( + "consider changing the closure to take and ignore the expected argument{}", + if expected_args.len() < 2 { + "" + } else { + "s" + } + ), + format!("|{}|", underscores), + Applicability::MachineApplicable, + ); + } + if let &[ArgKind::Tuple(_, ref fields)] = &found_args[..] { if fields.len() == expected_args.len() { let sugg = fields.iter() .map(|(name, _)| name.to_owned()) .collect::>().join(", "); - err.span_suggestion(found_span, - "change the closure to take multiple arguments instead of \ - a single tuple", - format!("|{}|", sugg)); + err.span_suggestion_with_applicability(found_span, + "change the closure to take multiple \ + arguments instead of a single tuple", + format!("|{}|", sugg), + Applicability::MachineApplicable); } } if let &[ArgKind::Tuple(_, ref fields)] = &expected_args[..] { @@ -1073,10 +1111,13 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { "".to_owned() }, ); - err.span_suggestion(found_span, - "change the closure to accept a tuple instead of \ - individual arguments", - sugg); + err.span_suggestion_with_applicability( + found_span, + "change the closure to accept a tuple instead of \ + individual arguments", + sugg, + Applicability::MachineApplicable + ); } } } @@ -1111,7 +1152,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { ::rustc_target::spec::abi::Abi::Rust ) }; - format!("{}", ty::Binder::bind(sig)) + ty::Binder::bind(sig).to_string() } let argument_is_closure = expected_ref.skip_binder().substs.type_at(0).is_closure(); @@ -1236,7 +1277,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { self.tcx.lang_items().sized_trait() .map_or(false, |sized_id| sized_id == trait_ref.def_id()) { - self.need_type_info(body_id, span, self_ty); + self.need_type_info_err(body_id, span, self_ty).emit(); } else { let mut err = struct_span_err!(self.tcx.sess, span, E0283, @@ -1253,7 +1294,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { // Same hacky approach as above to avoid deluging user // with error messages. if !ty.references_error() && !self.tcx.sess.has_errors() { - self.need_type_info(body_id, span, ty); + self.need_type_info_err(body_id, span, ty).emit(); } } @@ -1264,9 +1305,9 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { let &SubtypePredicate { a_is_expected: _, a, b } = data.skip_binder(); // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info(body_id, - obligation.cause.span, - a); + self.need_type_info_err(body_id, + obligation.cause.span, + a).emit(); } } @@ -1477,6 +1518,14 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } ObligationCauseCode::ReturnType(_) | ObligationCauseCode::BlockTailExpression(_) => (), + ObligationCauseCode::TrivialBound => { + err.help("see issue #48214"); + if tcx.sess.opts.unstable_features.is_nightly_build() { + err.help("add #![feature(trivial_bounds)] to the \ + crate attributes to enable", + ); + } + } } } @@ -1526,10 +1575,10 @@ impl ArgKind { ty::TyTuple(ref tys) => ArgKind::Tuple( None, tys.iter() - .map(|ty| ("_".to_owned(), format!("{}", ty.sty))) + .map(|ty| ("_".to_owned(), ty.sty.to_string())) .collect::>() ), - _ => ArgKind::Arg("_".to_owned(), format!("{}", t.sty)), + _ => ArgKind::Arg("_".to_owned(), t.sty.to_string()), } } } diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs index 6e20150718110..b7d3ad76588f7 100644 --- a/src/librustc/traits/fulfill.rs +++ b/src/librustc/traits/fulfill.rs @@ -12,16 +12,17 @@ use infer::{RegionObligation, InferCtxt}; use mir::interpret::GlobalId; use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, ToPredicate}; use ty::error::ExpectedFound; -use rustc_data_structures::obligation_forest::{ObligationForest, Error}; -use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor}; +use rustc_data_structures::obligation_forest::{Error, ForestObligation, ObligationForest}; +use rustc_data_structures::obligation_forest::{ObligationProcessor, ProcessResult}; use std::marker::PhantomData; use hir::def_id::DefId; -use middle::const_val::{ConstEvalErr, ErrKind}; +use mir::interpret::ConstEvalErr; +use mir::interpret::EvalErrorKind; use super::CodeAmbiguity; use super::CodeProjectionError; use super::CodeSelectionError; -use super::engine::TraitEngine; +use super::engine::{TraitEngine, TraitEngineExt}; use super::{FulfillmentError, FulfillmentErrorCode}; use super::{ObligationCause, PredicateObligation, Obligation}; use super::project; @@ -86,18 +87,7 @@ impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> { } } - pub fn register_predicate_obligations(&mut self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - obligations: I) - where I: IntoIterator> - { - for obligation in obligations { - self.register_predicate_obligation(infcx, obligation); - } - } - - /// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it - /// only attempts to select obligations that haven't been seen before. + /// Attempts to select obligations using `selcx`. fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>) -> Result<(),Vec>> { debug!("select(obligation-forest-size={})", self.predicates.len()); @@ -161,19 +151,18 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { // FIXME(#20304) -- cache let mut selcx = SelectionContext::new(infcx); - let normalized = project::normalize_projection_type(&mut selcx, - param_env, - projection_ty, - cause, - 0); - - for obligation in normalized.obligations { - self.register_predicate_obligation(infcx, obligation); - } - - debug!("normalize_projection_type: result={:?}", normalized.value); - - normalized.value + let mut obligations = vec![]; + let normalized_ty = project::normalize_projection_type(&mut selcx, + param_env, + projection_ty, + cause, + 0, + &mut obligations); + self.register_predicate_obligations(infcx, obligations); + + debug!("normalize_projection_type: result={:?}", normalized_ty); + + normalized_ty } /// Requires that `ty` must implement the trait with `def_id` in @@ -242,8 +231,8 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> { self.select(&mut selcx) } - fn pending_obligations(&self) -> Vec> { - self.predicates.pending_obligations() + fn pending_obligations(&self) -> Vec> { + self.predicates.map_pending_obligations(|o| o.obligation.clone()) } } @@ -252,303 +241,307 @@ struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> { register_region_obligations: bool } +fn mk_pending(os: Vec>) -> Vec> { + os.into_iter().map(|o| PendingPredicateObligation { + obligation: o, + stalled_on: vec![] + }).collect() +} + impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> { type Obligation = PendingPredicateObligation<'tcx>; type Error = FulfillmentErrorCode<'tcx>; + /// Processes a predicate obligation and returns either: + /// - `Changed(v)` if the predicate is true, presuming that `v` are also true + /// - `Unchanged` if we don't have enough info to be sure + /// - `Error(e)` if the predicate does not hold + /// + /// This is always inlined, despite its size, because it has a single + /// callsite and it is called *very* frequently. + #[inline(always)] fn process_obligation(&mut self, - obligation: &mut Self::Obligation) - -> Result>, Self::Error> + pending_obligation: &mut Self::Obligation) + -> ProcessResult { - process_predicate(self.selcx, obligation, self.register_region_obligations) - .map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation { - obligation: o, - stalled_on: vec![] - }).collect())) - } - - fn process_backedge<'c, I>(&mut self, cycle: I, - _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>) - where I: Clone + Iterator>, - { - if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { - debug!("process_child_obligations: coinductive match"); - } else { - let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); - self.selcx.infcx().report_overflow_error_cycle(&cycle); + // if we were stalled on some unresolved variables, first check + // whether any of them have been resolved; if not, don't bother + // doing more work yet + if !pending_obligation.stalled_on.is_empty() { + if pending_obligation.stalled_on.iter().all(|&ty| { + let resolved_ty = self.selcx.infcx().shallow_resolve(&ty); + resolved_ty == ty // nothing changed here + }) { + debug!("process_predicate: pending obligation {:?} still stalled on {:?}", + self.selcx.infcx() + .resolve_type_vars_if_possible(&pending_obligation.obligation), + pending_obligation.stalled_on); + return ProcessResult::Unchanged; + } + pending_obligation.stalled_on = vec![]; } - } -} -/// Return the set of type variables contained in a trait ref -fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, - t: ty::PolyTraitRef<'tcx>) -> Vec> -{ - t.skip_binder() // ok b/c this check doesn't care about regions - .input_types() - .map(|t| selcx.infcx().resolve_type_vars_if_possible(&t)) - .filter(|t| t.has_infer_types()) - .flat_map(|t| t.walk()) - .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false }) - .collect() -} + let obligation = &mut pending_obligation.obligation; -/// Processes a predicate obligation and returns either: -/// - `Ok(Some(v))` if the predicate is true, presuming that `v` are also true -/// - `Ok(None)` if we don't have enough info to be sure -/// - `Err` if the predicate does not hold -fn process_predicate<'a, 'gcx, 'tcx>( - selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, - pending_obligation: &mut PendingPredicateObligation<'tcx>, - register_region_obligations: bool) - -> Result>>, - FulfillmentErrorCode<'tcx>> -{ - // if we were stalled on some unresolved variables, first check - // whether any of them have been resolved; if not, don't bother - // doing more work yet - if !pending_obligation.stalled_on.is_empty() { - if pending_obligation.stalled_on.iter().all(|&ty| { - let resolved_ty = selcx.infcx().shallow_resolve(&ty); - resolved_ty == ty // nothing changed here - }) { - debug!("process_predicate: pending obligation {:?} still stalled on {:?}", - selcx.infcx().resolve_type_vars_if_possible(&pending_obligation.obligation), - pending_obligation.stalled_on); - return Ok(None); + if obligation.predicate.has_infer_types() { + obligation.predicate = + self.selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate); } - pending_obligation.stalled_on = vec![]; - } - - let obligation = &mut pending_obligation.obligation; - if obligation.predicate.has_infer_types() { - obligation.predicate = selcx.infcx().resolve_type_vars_if_possible(&obligation.predicate); - } - - match obligation.predicate { - ty::Predicate::Trait(ref data) => { - let trait_obligation = obligation.with(data.clone()); - - if data.is_global() { - // no type variables present, can use evaluation for better caching. - // FIXME: consider caching errors too. - if selcx.infcx().predicate_must_hold(&obligation) { - debug!("selecting trait `{:?}` at depth {} evaluated to holds", - data, obligation.recursion_depth); - return Ok(Some(vec![])) + match obligation.predicate { + ty::Predicate::Trait(ref data) => { + let trait_obligation = obligation.with(data.clone()); + + if data.is_global() && !data.has_late_bound_regions() { + // no type variables present, can use evaluation for better caching. + // FIXME: consider caching errors too. + if self.selcx.infcx().predicate_must_hold(&obligation) { + debug!("selecting trait `{:?}` at depth {} evaluated to holds", + data, obligation.recursion_depth); + return ProcessResult::Changed(vec![]) + } } - } - match selcx.select(&trait_obligation) { - Ok(Some(vtable)) => { - debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)", - data, obligation.recursion_depth); - Ok(Some(vtable.nested_obligations())) - } - Ok(None) => { - debug!("selecting trait `{:?}` at depth {} yielded Ok(None)", - data, obligation.recursion_depth); - - // This is a bit subtle: for the most part, the - // only reason we can fail to make progress on - // trait selection is because we don't have enough - // information about the types in the trait. One - // exception is that we sometimes haven't decided - // what kind of closure a closure is. *But*, in - // that case, it turns out, the type of the - // closure will also change, because the closure - // also includes references to its upvars as part - // of its type, and those types are resolved at - // the same time. - // - // FIXME(#32286) logic seems false if no upvars - pending_obligation.stalled_on = - trait_ref_type_vars(selcx, data.to_poly_trait_ref()); - - debug!("process_predicate: pending obligation {:?} now stalled on {:?}", - selcx.infcx().resolve_type_vars_if_possible(obligation), - pending_obligation.stalled_on); - - Ok(None) - } - Err(selection_err) => { - info!("selecting trait `{:?}` at depth {} yielded Err", - data, obligation.recursion_depth); + match self.selcx.select(&trait_obligation) { + Ok(Some(vtable)) => { + debug!("selecting trait `{:?}` at depth {} yielded Ok(Some)", + data, obligation.recursion_depth); + ProcessResult::Changed(mk_pending(vtable.nested_obligations())) + } + Ok(None) => { + debug!("selecting trait `{:?}` at depth {} yielded Ok(None)", + data, obligation.recursion_depth); + + // This is a bit subtle: for the most part, the + // only reason we can fail to make progress on + // trait selection is because we don't have enough + // information about the types in the trait. One + // exception is that we sometimes haven't decided + // what kind of closure a closure is. *But*, in + // that case, it turns out, the type of the + // closure will also change, because the closure + // also includes references to its upvars as part + // of its type, and those types are resolved at + // the same time. + // + // FIXME(#32286) logic seems false if no upvars + pending_obligation.stalled_on = + trait_ref_type_vars(self.selcx, data.to_poly_trait_ref()); + + debug!("process_predicate: pending obligation {:?} now stalled on {:?}", + self.selcx.infcx().resolve_type_vars_if_possible(obligation), + pending_obligation.stalled_on); + + ProcessResult::Unchanged + } + Err(selection_err) => { + info!("selecting trait `{:?}` at depth {} yielded Err", + data, obligation.recursion_depth); - Err(CodeSelectionError(selection_err)) + ProcessResult::Error(CodeSelectionError(selection_err)) + } } } - } - ty::Predicate::RegionOutlives(ref binder) => { - match selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { - Ok(()) => Ok(Some(Vec::new())), - Err(_) => Err(CodeSelectionError(Unimplemented)), + ty::Predicate::RegionOutlives(ref binder) => { + match self.selcx.infcx().region_outlives_predicate(&obligation.cause, binder) { + Ok(()) => ProcessResult::Changed(vec![]), + Err(_) => ProcessResult::Error(CodeSelectionError(Unimplemented)), + } } - } - ty::Predicate::TypeOutlives(ref binder) => { - // Check if there are higher-ranked regions. - match binder.no_late_bound_regions() { - // If there are, inspect the underlying type further. - None => { - // Convert from `Binder>` to `Binder`. - let binder = binder.map_bound_ref(|pred| pred.0); - - // Check if the type has any bound regions. - match binder.no_late_bound_regions() { - // If so, this obligation is an error (for now). Eventually we should be - // able to support additional cases here, like `for<'a> &'a str: 'a`. - None => { - Err(CodeSelectionError(Unimplemented)) - } - // Otherwise, we have something of the form - // `for<'a> T: 'a where 'a not in T`, which we can treat as `T: 'static`. - Some(t_a) => { - let r_static = selcx.tcx().types.re_static; - if register_region_obligations { - selcx.infcx().register_region_obligation( - obligation.cause.body_id, - RegionObligation { - sup_type: t_a, - sub_region: r_static, - cause: obligation.cause.clone(), - }); + ty::Predicate::TypeOutlives(ref binder) => { + // Check if there are higher-ranked regions. + match binder.no_late_bound_regions() { + // If there are, inspect the underlying type further. + None => { + // Convert from `Binder>` to `Binder`. + let binder = binder.map_bound_ref(|pred| pred.0); + + // Check if the type has any bound regions. + match binder.no_late_bound_regions() { + // If so, this obligation is an error (for now). Eventually we should be + // able to support additional cases here, like `for<'a> &'a str: 'a`. + None => { + ProcessResult::Error(CodeSelectionError(Unimplemented)) + } + // Otherwise, we have something of the form + // `for<'a> T: 'a where 'a not in T`, which we can treat as + // `T: 'static`. + Some(t_a) => { + let r_static = self.selcx.tcx().types.re_static; + if self.register_region_obligations { + self.selcx.infcx().register_region_obligation( + obligation.cause.body_id, + RegionObligation { + sup_type: t_a, + sub_region: r_static, + cause: obligation.cause.clone(), + }); + } + ProcessResult::Changed(vec![]) } - Ok(Some(vec![])) } } - } - // If there aren't, register the obligation. - Some(ty::OutlivesPredicate(t_a, r_b)) => { - if register_region_obligations { - selcx.infcx().register_region_obligation( - obligation.cause.body_id, - RegionObligation { - sup_type: t_a, - sub_region: r_b, - cause: obligation.cause.clone() - }); + // If there aren't, register the obligation. + Some(ty::OutlivesPredicate(t_a, r_b)) => { + if self.register_region_obligations { + self.selcx.infcx().register_region_obligation( + obligation.cause.body_id, + RegionObligation { + sup_type: t_a, + sub_region: r_b, + cause: obligation.cause.clone() + }); + } + ProcessResult::Changed(vec![]) } - Ok(Some(vec![])) } } - } - ty::Predicate::Projection(ref data) => { - let project_obligation = obligation.with(data.clone()); - match project::poly_project_and_unify_type(selcx, &project_obligation) { - Ok(None) => { - let tcx = selcx.tcx(); - pending_obligation.stalled_on = - trait_ref_type_vars(selcx, data.to_poly_trait_ref(tcx)); - Ok(None) + ty::Predicate::Projection(ref data) => { + let project_obligation = obligation.with(data.clone()); + match project::poly_project_and_unify_type(self.selcx, &project_obligation) { + Ok(None) => { + let tcx = self.selcx.tcx(); + pending_obligation.stalled_on = + trait_ref_type_vars(self.selcx, data.to_poly_trait_ref(tcx)); + ProcessResult::Unchanged + } + Ok(Some(os)) => ProcessResult::Changed(mk_pending(os)), + Err(e) => ProcessResult::Error(CodeProjectionError(e)) } - Ok(v) => Ok(v), - Err(e) => Err(CodeProjectionError(e)) } - } - ty::Predicate::ObjectSafe(trait_def_id) => { - if !selcx.tcx().is_object_safe(trait_def_id) { - Err(CodeSelectionError(Unimplemented)) - } else { - Ok(Some(Vec::new())) + ty::Predicate::ObjectSafe(trait_def_id) => { + if !self.selcx.tcx().is_object_safe(trait_def_id) { + ProcessResult::Error(CodeSelectionError(Unimplemented)) + } else { + ProcessResult::Changed(vec![]) + } } - } - ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { - match selcx.infcx().closure_kind(closure_def_id, closure_substs) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - Ok(Some(vec![])) - } else { - Err(CodeSelectionError(Unimplemented)) + ty::Predicate::ClosureKind(closure_def_id, closure_substs, kind) => { + match self.selcx.infcx().closure_kind(closure_def_id, closure_substs) { + Some(closure_kind) => { + if closure_kind.extends(kind) { + ProcessResult::Changed(vec![]) + } else { + ProcessResult::Error(CodeSelectionError(Unimplemented)) + } + } + None => { + ProcessResult::Unchanged } - } - None => { - Ok(None) } } - } - ty::Predicate::WellFormed(ty) => { - match ty::wf::obligations(selcx.infcx(), - obligation.param_env, - obligation.cause.body_id, - ty, obligation.cause.span) { - None => { - pending_obligation.stalled_on = vec![ty]; - Ok(None) + ty::Predicate::WellFormed(ty) => { + match ty::wf::obligations(self.selcx.infcx(), + obligation.param_env, + obligation.cause.body_id, + ty, obligation.cause.span) { + None => { + pending_obligation.stalled_on = vec![ty]; + ProcessResult::Unchanged + } + Some(os) => ProcessResult::Changed(mk_pending(os)) } - s => Ok(s) } - } - ty::Predicate::Subtype(ref subtype) => { - match selcx.infcx().subtype_predicate(&obligation.cause, - obligation.param_env, - subtype) { - None => { - // none means that both are unresolved - pending_obligation.stalled_on = vec![subtype.skip_binder().a, - subtype.skip_binder().b]; - Ok(None) - } - Some(Ok(ok)) => { - Ok(Some(ok.obligations)) - } - Some(Err(err)) => { - let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected, - subtype.skip_binder().a, - subtype.skip_binder().b); - Err(FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) + ty::Predicate::Subtype(ref subtype) => { + match self.selcx.infcx().subtype_predicate(&obligation.cause, + obligation.param_env, + subtype) { + None => { + // None means that both are unresolved. + pending_obligation.stalled_on = vec![subtype.skip_binder().a, + subtype.skip_binder().b]; + ProcessResult::Unchanged + } + Some(Ok(ok)) => { + ProcessResult::Changed(mk_pending(ok.obligations)) + } + Some(Err(err)) => { + let expected_found = ExpectedFound::new(subtype.skip_binder().a_is_expected, + subtype.skip_binder().a, + subtype.skip_binder().b); + ProcessResult::Error( + FulfillmentErrorCode::CodeSubtypeError(expected_found, err)) + } } } - } - ty::Predicate::ConstEvaluatable(def_id, substs) => { - match selcx.tcx().lift_to_global(&obligation.param_env) { - None => { - Ok(None) - } - Some(param_env) => { - match selcx.tcx().lift_to_global(&substs) { - Some(substs) => { - let instance = ty::Instance::resolve( - selcx.tcx().global_tcx(), - param_env, - def_id, - substs, - ); - if let Some(instance) = instance { - let cid = GlobalId { - instance, - promoted: None, - }; - match selcx.tcx().at(obligation.cause.span) - .const_eval(param_env.and(cid)) { - Ok(_) => Ok(Some(vec![])), - Err(err) => Err(CodeSelectionError(ConstEvalFailure(err))) + ty::Predicate::ConstEvaluatable(def_id, substs) => { + match self.selcx.tcx().lift_to_global(&obligation.param_env) { + None => { + ProcessResult::Unchanged + } + Some(param_env) => { + match self.selcx.tcx().lift_to_global(&substs) { + Some(substs) => { + let instance = ty::Instance::resolve( + self.selcx.tcx().global_tcx(), + param_env, + def_id, + substs, + ); + if let Some(instance) = instance { + let cid = GlobalId { + instance, + promoted: None, + }; + match self.selcx.tcx().at(obligation.cause.span) + .const_eval(param_env.and(cid)) { + Ok(_) => ProcessResult::Changed(vec![]), + Err(err) => ProcessResult::Error( + CodeSelectionError(ConstEvalFailure(err))) + } + } else { + ProcessResult::Error( + CodeSelectionError(ConstEvalFailure(ConstEvalErr { + span: obligation.cause.span, + error: EvalErrorKind::TooGeneric.into(), + stacktrace: vec![], + }.into())) + ) } - } else { - Err(CodeSelectionError(ConstEvalFailure(ConstEvalErr { - span: obligation.cause.span, - kind: ErrKind::UnimplementedConstVal("could not resolve") - .into(), - }))) + }, + None => { + pending_obligation.stalled_on = substs.types().collect(); + ProcessResult::Unchanged } - }, - None => { - pending_obligation.stalled_on = substs.types().collect(); - Ok(None) } } } } } } + + fn process_backedge<'c, I>(&mut self, cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>) + where I: Clone + Iterator>, + { + if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { + debug!("process_child_obligations: coinductive match"); + } else { + let cycle : Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); + self.selcx.infcx().report_overflow_error_cycle(&cycle); + } + } +} + +/// Return the set of type variables contained in a trait ref +fn trait_ref_type_vars<'a, 'gcx, 'tcx>(selcx: &mut SelectionContext<'a, 'gcx, 'tcx>, + t: ty::PolyTraitRef<'tcx>) -> Vec> +{ + t.skip_binder() // ok b/c this check doesn't care about regions + .input_types() + .map(|t| selcx.infcx().resolve_type_vars_if_possible(&t)) + .filter(|t| t.has_infer_types()) + .flat_map(|t| t.walk()) + .filter(|t| match t.sty { ty::TyInfer(_) => true, _ => false }) + .collect() } fn to_fulfillment_error<'tcx>( diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index dd5208e908e19..0290f2e3b13f0 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -10,24 +10,27 @@ //! Trait Resolution. See [rustc guide] for more info on how this works. //! -//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html +//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/resolution.html pub use self::SelectionError::*; pub use self::FulfillmentErrorCode::*; pub use self::Vtable::*; pub use self::ObligationCauseCode::*; +use chalk_engine; use hir; use hir::def_id::DefId; use infer::outlives::env::OutlivesEnvironment; use middle::region; -use middle::const_val::ConstEvalErr; +use mir::interpret::ConstEvalErr; use ty::subst::Substs; -use ty::{self, AdtKind, Slice, Ty, TyCtxt, TypeFoldable, ToPredicate}; +use ty::{self, AdtKind, Slice, Ty, TyCtxt, GenericParamDefKind, ToPredicate}; use ty::error::{ExpectedFound, TypeError}; +use ty::fold::{TypeFolder, TypeFoldable, TypeVisitor}; use infer::{InferCtxt}; use rustc_data_structures::sync::Lrc; +use std::fmt::Debug; use std::rc::Rc; use syntax::ast; use syntax_pos::{Span, DUMMY_SP}; @@ -44,7 +47,7 @@ pub use self::select::{EvaluationCache, SelectionContext, SelectionCache}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::{OverlapError, specialization_graph, translate_substs}; pub use self::specialize::{SpecializesCache, find_associated_item}; -pub use self::engine::TraitEngine; +pub use self::engine::{TraitEngine, TraitEngineExt}; pub use self::util::elaborate_predicates; pub use self::util::supertraits; pub use self::util::Supertraits; @@ -52,6 +55,8 @@ pub use self::util::supertrait_def_ids; pub use self::util::SupertraitDefIds; pub use self::util::transitive_bounds; +#[allow(dead_code)] +pub mod auto_trait; mod coherence; pub mod error_reporting; mod engine; @@ -62,7 +67,7 @@ mod on_unimplemented; mod select; mod specialize; mod structural_impls; -pub mod trans; +pub mod codegen; mod util; pub mod query; @@ -241,6 +246,9 @@ pub enum ObligationCauseCode<'tcx> { /// Block implicit return BlockTailExpression(ast::NodeId), + + /// #[feature(trivial_bounds)] is not enabled + TrivialBound, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] @@ -260,7 +268,9 @@ pub type PredicateObligations<'tcx> = Vec>; pub type TraitObligations<'tcx> = Vec>; /// The following types: -/// * `WhereClauseAtom` +/// * `WhereClause` +/// * `WellFormed` +/// * `FromEnv` /// * `DomainGoal` /// * `Goal` /// * `Clause` @@ -268,21 +278,31 @@ pub type TraitObligations<'tcx> = Vec>; /// logic programming clauses. They are part of the interface /// for the chalk SLG solver. #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] -pub enum WhereClauseAtom<'tcx> { +pub enum WhereClause<'tcx> { Implemented(ty::TraitPredicate<'tcx>), ProjectionEq(ty::ProjectionPredicate<'tcx>), + RegionOutlives(ty::RegionOutlivesPredicate<'tcx>), + TypeOutlives(ty::TypeOutlivesPredicate<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum WellFormed<'tcx> { + Trait(ty::TraitPredicate<'tcx>), + Ty(Ty<'tcx>), +} + +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] +pub enum FromEnv<'tcx> { + Trait(ty::TraitPredicate<'tcx>), + Ty(Ty<'tcx>), } #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub enum DomainGoal<'tcx> { - Holds(WhereClauseAtom<'tcx>), - WellFormed(WhereClauseAtom<'tcx>), - FromEnv(WhereClauseAtom<'tcx>), - WellFormedTy(Ty<'tcx>), + Holds(WhereClause<'tcx>), + WellFormed(WellFormed<'tcx>), + FromEnv(FromEnv<'tcx>), Normalize(ty::ProjectionPredicate<'tcx>), - FromEnvTy(Ty<'tcx>), - RegionOutlives(ty::RegionOutlivesPredicate<'tcx>), - TypeOutlives(ty::TypeOutlivesPredicate<'tcx>), } pub type PolyDomainGoal<'tcx> = ty::Binder>; @@ -305,27 +325,27 @@ pub enum Goal<'tcx> { pub type Goals<'tcx> = &'tcx Slice>; +impl<'tcx> DomainGoal<'tcx> { + pub fn into_goal(self) -> Goal<'tcx> { + Goal::DomainGoal(self) + } +} + impl<'tcx> Goal<'tcx> { pub fn from_poly_domain_goal<'a>( domain_goal: PolyDomainGoal<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>, ) -> Goal<'tcx> { match domain_goal.no_late_bound_regions() { - Some(p) => p.into(), + Some(p) => p.into_goal(), None => Goal::Quantified( QuantifierKind::Universal, - domain_goal.map_bound(|p| tcx.mk_goal(Goal::from(p))) + domain_goal.map_bound(|p| tcx.mk_goal(p.into_goal())) ), } } } -impl<'tcx> From> for Goal<'tcx> { - fn from(domain_goal: DomainGoal<'tcx>) -> Self { - Goal::DomainGoal(domain_goal) - } -} - /// This matches the definition from Page 7 of "A Proof Procedure for the Logic of Hereditary /// Harrop Formulas". #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] @@ -361,7 +381,7 @@ pub enum SelectionError<'tcx> { ty::PolyTraitRef<'tcx>, ty::error::TypeError<'tcx>), TraitNotObjectSafe(DefId), - ConstEvalFailure(ConstEvalErr<'tcx>), + ConstEvalFailure(Lrc>), Overflow, } @@ -468,8 +488,8 @@ pub enum Vtable<'tcx, N> { /// /// The type parameter `N` indicates the type used for "nested /// obligations" that are required by the impl. During type check, this -/// is `Obligation`, as one might expect. During trans, however, this -/// is `()`, because trans only requires a shallow resolution of an +/// is `Obligation`, as one might expect. During codegen, however, this +/// is `()`, because codegen only requires a shallow resolution of an /// impl, and nested obligations are satisfied later. #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableImplData<'tcx, N> { @@ -480,8 +500,8 @@ pub struct VtableImplData<'tcx, N> { #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub struct VtableGeneratorData<'tcx, N> { - pub closure_def_id: DefId, - pub substs: ty::ClosureSubsts<'tcx>, + pub generator_def_id: DefId, + pub substs: ty::GeneratorSubsts<'tcx>, /// Nested obligations. This can be non-empty if the generator /// signature contains associated types. pub nested: Vec @@ -639,17 +659,8 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let predicates: Vec<_> = util::elaborate_predicates(tcx, unnormalized_env.caller_bounds.to_vec()) - .filter(|p| !p.is_global()) // (*) .collect(); - // (*) Any predicate like `i32: Trait` or whatever doesn't - // need to be in the *environment* to be proven, so screen those - // out. This is important for the soundness of inter-fn - // caching. Note though that we should probably check that these - // predicates hold at the point where the environment is - // constructed, but I am not currently doing so out of laziness. - // -nmatsakis - debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); @@ -672,7 +683,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // we move over to lazy normalization *anyway*. let fulfill_cx = FulfillmentContext::new_ignoring_regions(); - let predicates = match fully_normalize_with_fulfillcx( + let predicates = match fully_normalize( &infcx, fulfill_cx, cause, @@ -732,31 +743,7 @@ pub fn normalize_param_env_or_error<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -pub fn fully_normalize<'a, 'gcx, 'tcx, T>(infcx: &InferCtxt<'a, 'gcx, 'tcx>, - cause: ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T) - -> Result>> - where T : TypeFoldable<'tcx> -{ - // FIXME (@jroesch) ISSUE 26721 - // I'm not sure if this is a bug or not, needs further investigation. - // It appears that by reusing the fulfillment_cx here we incur more - // obligations and later trip an assertion on regionck.rs line 337. - // - // The two possibilities I see is: - // - normalization is not actually fully happening and we - // have a bug else where - // - we are adding a duplicate bound into the list causing - // its size to change. - // - // I think we should probably land this refactor and then come - // back to this is a follow-up patch. - let fulfillcx = FulfillmentContext::new(); - fully_normalize_with_fulfillcx(infcx, fulfillcx, cause, param_env, value) -} - -pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>( +pub fn fully_normalize<'a, 'gcx, 'tcx, T>( infcx: &InferCtxt<'a, 'gcx, 'tcx>, mut fulfill_cx: FulfillmentContext<'tcx>, cause: ObligationCause<'tcx>, @@ -777,13 +764,7 @@ pub fn fully_normalize_with_fulfillcx<'a, 'gcx, 'tcx, T>( } debug!("fully_normalize: select_all_or_error start"); - match fulfill_cx.select_all_or_error(infcx) { - Ok(()) => { } - Err(e) => { - debug!("fully_normalize: error={:?}", e); - return Err(e); - } - } + fulfill_cx.select_all_or_error(infcx)?; debug!("fully_normalize: select_all_or_error complete"); let resolved_value = infcx.resolve_type_vars_if_possible(&normalized_value); debug!("fully_normalize: resolved_value={:?}", resolved_value); @@ -869,10 +850,14 @@ fn vtable_methods<'a, 'tcx>( // the method may have some early-bound lifetimes, add // regions for those let substs = trait_ref.map_bound(|trait_ref| { - Substs::for_item( - tcx, def_id, - |_, _| tcx.types.re_erased, - |def, _| trait_ref.substs.type_for_def(def)) + Substs::for_item(tcx, def_id, |param, _| { + match param.kind { + GenericParamDefKind::Lifetime => tcx.types.re_erased.into(), + GenericParamDefKind::Type {..} => { + trait_ref.substs[param.index as usize] + } + } + }) }); // the trait type may have higher-ranked lifetimes in it; @@ -886,7 +871,7 @@ fn vtable_methods<'a, 'tcx>( // It's possible that the method relies on where clauses that // do not hold for this particular set of type parameters. // Note that this method could then never be called, so we - // do not want to try and trans it, in that case (see #23435). + // do not want to try and codegen it, in that case (see #23435). let predicates = tcx.predicates_of(def_id).instantiate_own(tcx, substs); if !normalize_and_test_predicates(tcx, predicates.predicates) { debug!("vtable_methods: predicates do not hold"); @@ -989,7 +974,7 @@ impl<'tcx, N> Vtable<'tcx, N> { nested: p.nested.into_iter().map(f).collect(), }), VtableGenerator(c) => VtableGenerator(VtableGeneratorData { - closure_def_id: c.closure_def_id, + generator_def_id: c.generator_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), @@ -1017,14 +1002,41 @@ impl<'tcx> TraitObligation<'tcx> { } } -pub fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { is_object_safe: object_safety::is_object_safe_provider, specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, - trans_fulfill_obligation: trans::trans_fulfill_obligation, + codegen_fulfill_obligation: codegen::codegen_fulfill_obligation, vtable_methods, substitute_normalize_and_test_predicates, ..*providers }; } + +pub trait ExClauseFold<'tcx> +where + Self: chalk_engine::context::Context + Clone, +{ + fn fold_ex_clause_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>( + ex_clause: &chalk_engine::ExClause, + folder: &mut F, + ) -> chalk_engine::ExClause; + + fn visit_ex_clause_with<'gcx: 'tcx, V: TypeVisitor<'tcx>>( + ex_clause: &chalk_engine::ExClause, + visitor: &mut V, + ) -> bool; +} + +pub trait ExClauseLift<'tcx> +where + Self: chalk_engine::context::Context + Clone, +{ + type LiftedExClause: Debug + 'tcx; + + fn lift_ex_clause_to_tcx<'a, 'gcx>( + ex_clause: &chalk_engine::ExClause, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + ) -> Option; +} diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs index c0d5a337cee3a..aa4f63675d734 100644 --- a/src/librustc/traits/object_safety.rs +++ b/src/librustc/traits/object_safety.rs @@ -20,14 +20,15 @@ use super::elaborate_predicates; use hir::def_id::DefId; +use lint; use traits; use ty::{self, Ty, TyCtxt, TypeFoldable}; -use ty::subst::Substs; use ty::util::ExplicitSelf; use std::borrow::Cow; use syntax::ast; +use syntax_pos::Span; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum ObjectSafetyViolation { /// Self : Sized declared on the trait SizedSelf, @@ -56,6 +57,9 @@ impl ObjectSafetyViolation { ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) => format!("method `{}` references the `Self` type \ in its arguments or return type", name).into(), + ObjectSafetyViolation::Method(name, + MethodViolationCode::WhereClauseReferencesSelf(_)) => + format!("method `{}` references the `Self` type in where clauses", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) => format!("method `{}` has generic type parameters", name).into(), ObjectSafetyViolation::Method(name, MethodViolationCode::NonStandardSelfType) => @@ -75,6 +79,9 @@ pub enum MethodViolationCode { /// e.g., `fn foo(&self, x: Self)` or `fn foo(&self) -> Self` ReferencesSelf, + /// e.g. `fn foo(&self) where Self: Clone` + WhereClauseReferencesSelf(Span), + /// e.g., `fn foo()` Generic, @@ -91,13 +98,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn astconv_object_safety_violations(self, trait_def_id: DefId) -> Vec { - let mut violations = vec![]; - - for def_id in traits::supertrait_def_ids(self, trait_def_id) { - if self.predicates_reference_self(def_id, true) { - violations.push(ObjectSafetyViolation::SupertraitSelf); - } - } + let violations = traits::supertrait_def_ids(self, trait_def_id) + .filter(|&def_id| self.predicates_reference_self(def_id, true)) + .map(|_| ObjectSafetyViolation::SupertraitSelf) + .collect(); debug!("astconv_object_safety_violations(trait_def_id={:?}) = {:?}", trait_def_id, @@ -122,7 +126,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .filter(|item| item.kind == ty::AssociatedKind::Method) .filter_map(|item| { self.object_safety_violation_for_method(trait_def_id, &item) - .map(|code| ObjectSafetyViolation::Method(item.name, code)) + .map(|code| ObjectSafetyViolation::Method(item.ident.name, code)) + }).filter(|violation| { + if let ObjectSafetyViolation::Method(_, + MethodViolationCode::WhereClauseReferencesSelf(span)) = violation { + // Using`CRATE_NODE_ID` is wrong, but it's hard to get a more precise id. + // It's also hard to get a use site span, so we use the method definition span. + self.lint_node_note( + lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY, + ast::CRATE_NODE_ID, + *span, + &format!("the trait `{}` cannot be made into an object", + self.item_path_str(trait_def_id)), + &violation.error_msg()); + false + } else { + true + } }).collect(); // Check the trait itself. @@ -135,7 +155,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { violations.extend(self.associated_items(trait_def_id) .filter(|item| item.kind == ty::AssociatedKind::Const) - .map(|item| ObjectSafetyViolation::AssociatedConst(item.name))); + .map(|item| ObjectSafetyViolation::AssociatedConst(item.ident.name))); debug!("object_safety_violations_for_trait(trait_def_id={:?}) = {:?}", trait_def_id, @@ -149,10 +169,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { trait_def_id: DefId, supertraits_only: bool) -> bool { - let trait_ref = ty::Binder::dummy(ty::TraitRef { - def_id: trait_def_id, - substs: Substs::identity_for_item(self, trait_def_id) - }); + let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(self, trait_def_id)); let predicates = if supertraits_only { self.super_predicates_of(trait_def_id) } else { @@ -245,7 +262,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return false; } - self.virtual_call_violation_for_method(trait_def_id, method).is_none() + match self.virtual_call_violation_for_method(trait_def_id, method) { + None | Some(MethodViolationCode::WhereClauseReferencesSelf(_)) => true, + Some(_) => false, + } } /// Returns `Some(_)` if this method cannot be called on a trait @@ -284,10 +304,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } // We can't monomorphize things like `fn foo(...)`. - if !self.generics_of(method.def_id).types.is_empty() { + if self.generics_of(method.def_id).own_counts().types != 0 { return Some(MethodViolationCode::Generic); } + if self.predicates_of(method.def_id).predicates.into_iter() + // A trait object can't claim to live more than the concrete type, + // so outlives predicates will always hold. + .filter(|p| p.to_opt_type_outlives().is_none()) + .collect::>() + // Do a shallow visit so that `contains_illegal_self_type_reference` + // may apply it's custom visiting. + .visit_tys_shallow(|t| self.contains_illegal_self_type_reference(trait_def_id, t)) { + let span = self.def_span(method.def_id); + return Some(MethodViolationCode::WhereClauseReferencesSelf(span)); + } + None } @@ -352,10 +384,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Compute supertraits of current trait lazily. if supertraits.is_none() { - let trait_ref = ty::Binder::bind(ty::TraitRef { - def_id: trait_def_id, - substs: Substs::identity_for_item(self, trait_def_id) - }); + let trait_ref = ty::Binder::bind( + ty::TraitRef::identity(self, trait_def_id), + ); supertraits = Some(traits::supertraits(self, trait_ref).collect()); } @@ -387,7 +418,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub(super) fn is_object_safe_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_def_id: DefId) - -> bool { + trait_def_id: DefId) -> bool { tcx.object_safety_violations(trait_def_id).is_empty() } diff --git a/src/librustc/traits/on_unimplemented.rs b/src/librustc/traits/on_unimplemented.rs index 3cf7af30b3d55..e1395c3fa4427 100644 --- a/src/librustc/traits/on_unimplemented.rs +++ b/src/librustc/traits/on_unimplemented.rs @@ -11,7 +11,7 @@ use fmt_macros::{Parser, Piece, Position}; use hir::def_id::DefId; -use ty::{self, TyCtxt}; +use ty::{self, TyCtxt, GenericParamDefKind}; use util::common::ErrorReported; use util::nodemap::FxHashMap; @@ -190,11 +190,10 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedDirective { for command in self.subcommands.iter().chain(Some(self)).rev() { if let Some(ref condition) = command.condition { if !attr::eval_condition(condition, &tcx.sess.parse_sess, &mut |c| { - options.contains(&(c.name().as_str().to_string(), - match c.value_str().map(|s| s.as_str().to_string()) { - Some(s) => Some(s), - None => None - })) + options.contains(&( + c.name().as_str().to_string(), + c.value_str().map(|s| s.as_str().to_string()) + )) }) { debug!("evaluate: skipping {:?} due to condition", command); continue @@ -242,8 +241,7 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { { let name = tcx.item_name(trait_def_id); let generics = tcx.generics_of(trait_def_id); - let parser = Parser::new(&self.0); - let types = &generics.types; + let parser = Parser::new(&self.0, None); let mut result = Ok(()); for token in parser { match token { @@ -254,13 +252,13 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { // `{ThisTraitsName}` is allowed Position::ArgumentNamed(s) if s == name => (), // So is `{A}` if A is a type parameter - Position::ArgumentNamed(s) => match types.iter().find(|t| { - t.name == s + Position::ArgumentNamed(s) => match generics.params.iter().find(|param| { + param.name == s }) { Some(_) => (), None => { span_err!(tcx.sess, span, E0230, - "there is no type parameter \ + "there is no parameter \ {} on trait {}", s, name); result = Err(ErrorReported); @@ -288,12 +286,18 @@ impl<'a, 'gcx, 'tcx> OnUnimplementedFormatString { let name = tcx.item_name(trait_ref.def_id); let trait_str = tcx.item_path_str(trait_ref.def_id); let generics = tcx.generics_of(trait_ref.def_id); - let generic_map = generics.types.iter().map(|param| { - (param.name.to_string(), - trait_ref.substs.type_for_def(param).to_string()) + let generic_map = generics.params.iter().filter_map(|param| { + let value = match param.kind { + GenericParamDefKind::Type {..} => { + trait_ref.substs[param.index as usize].to_string() + }, + GenericParamDefKind::Lifetime => return None + }; + let name = param.name.to_string(); + Some((name, value)) }).collect::>(); - let parser = Parser::new(&self.0); + let parser = Parser::new(&self.0, None); parser.map(|p| { match p { Piece::String(s) => s, diff --git a/src/librustc/traits/project.rs b/src/librustc/traits/project.rs index 45fa588bbf533..1ce60d8f05599 100644 --- a/src/librustc/traits/project.rs +++ b/src/librustc/traits/project.rs @@ -28,10 +28,10 @@ use super::util; use hir::def_id::DefId; use infer::{InferCtxt, InferOk}; use infer::type_variable::TypeVariableOrigin; -use middle::const_val::ConstVal; +use mir::interpret::ConstValue; use mir::interpret::{GlobalId}; use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap}; -use syntax::symbol::Symbol; +use syntax::ast::Ident; use ty::subst::{Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; @@ -65,7 +65,7 @@ pub enum Reveal { /// } UserFacing, - /// At trans time, all monomorphic projections will succeed. + /// At codegen time, all monomorphic projections will succeed. /// Also, `impl Trait` is normalized to the concrete type, /// which has to be already collected by type-checking. /// @@ -137,17 +137,30 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { fn push_candidate(&mut self, candidate: ProjectionTyCandidate<'tcx>) -> bool { use self::ProjectionTyCandidateSet::*; use self::ProjectionTyCandidate::*; + + // This wacky variable is just used to try and + // make code readable and avoid confusing paths. + // It is assigned a "value" of `()` only on those + // paths in which we wish to convert `*self` to + // ambiguous (and return false, because the candidate + // was not used). On other paths, it is not assigned, + // and hence if those paths *could* reach the code that + // comes after the match, this fn would not compile. + let convert_to_ambiguous; + match self { None => { *self = Single(candidate); - true + return true; } + Single(current) => { // Duplicates can happen inside ParamEnv. In the case, we // perform a lazy deduplication. if current == &candidate { return false; } + // Prefer where-clauses. As in select, if there are multiple // candidates, we prefer where-clause candidates over impls. This // may seem a bit surprising, since impls are the source of @@ -156,17 +169,23 @@ impl<'tcx> ProjectionTyCandidateSet<'tcx> { // clauses are the safer choice. See the comment on // `select::SelectionCandidate` and #21974 for more details. match (current, candidate) { - (ParamEnv(..), ParamEnv(..)) => { *self = Ambiguous; } - (ParamEnv(..), _) => {} + (ParamEnv(..), ParamEnv(..)) => convert_to_ambiguous = (), + (ParamEnv(..), _) => return false, (_, ParamEnv(..)) => { unreachable!(); } - (_, _) => { *self = Ambiguous; } + (_, _) => convert_to_ambiguous = (), } - false } + Ambiguous | Error(..) => { - false + return false; } } + + // We only ever get here when we moved from a single candidate + // to ambiguous. + let () = convert_to_ambiguous; + *self = Ambiguous; + false } } @@ -225,12 +244,14 @@ fn project_and_unify_type<'cx, 'gcx, 'tcx>( debug!("project_and_unify_type(obligation={:?})", obligation); - let Normalized { value: normalized_ty, mut obligations } = + let mut obligations = vec![]; + let normalized_ty = match opt_normalize_projection_type(selcx, obligation.param_env, obligation.predicate.projection_ty, obligation.cause.clone(), - obligation.recursion_depth) { + obligation.recursion_depth, + &mut obligations) { Some(n) => n, None => return Ok(None), }; @@ -346,7 +367,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, let ty = ty.super_fold_with(self); match ty.sty { ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) - // Only normalize `impl Trait` after type-checking, usually in trans. + // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal { Reveal::UserFacing => ty, @@ -386,16 +407,15 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, // binder). It would be better to normalize in a // binding-aware fashion. - let Normalized { value: normalized_ty, obligations } = - normalize_projection_type(self.selcx, - self.param_env, - data.clone(), - self.cause.clone(), - self.depth); - debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?} \ - with {} add'l obligations", - self.depth, ty, normalized_ty, obligations.len()); - self.obligations.extend(obligations); + let normalized_ty = normalize_projection_type(self.selcx, + self.param_env, + data.clone(), + self.cause.clone(), + self.depth, + &mut self.obligations); + debug!("AssociatedTypeNormalizer: depth={} normalized {:?} to {:?}, \ + now with {} obligations", + self.depth, ty, normalized_ty, self.obligations.len()); normalized_ty } @@ -406,7 +426,7 @@ impl<'a, 'b, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for AssociatedTypeNormalizer<'a, } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ConstVal::Unevaluated(def_id, substs) = constant.val { + if let ConstValue::Unevaluated(def_id, substs) = constant.val { let tcx = self.selcx.tcx().global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { if substs.needs_infer() || substs.has_skol() { @@ -471,10 +491,12 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, - depth: usize) - -> NormalizedTy<'tcx> + depth: usize, + obligations: &mut Vec>) + -> Ty<'tcx> { - opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth) + opt_normalize_projection_type(selcx, param_env, projection_ty.clone(), cause.clone(), depth, + obligations) .unwrap_or_else(move || { // if we bottom out in ambiguity, create a type variable // and a deferred predicate to resolve this when more type @@ -490,10 +512,8 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( }); let obligation = Obligation::with_depth( cause, depth + 1, param_env, projection.to_predicate()); - Normalized { - value: ty_var, - obligations: vec![obligation] - } + obligations.push(obligation); + ty_var }) } @@ -501,13 +521,20 @@ pub fn normalize_projection_type<'a, 'b, 'gcx, 'tcx>( /// as Trait>::Item`. The result is always a type (and possibly /// additional obligations). Returns `None` in the case of ambiguity, /// which indicates that there are unbound type variables. +/// +/// This function used to return `Option>`, which contains a +/// `Ty<'tcx>` and an obligations vector. But that obligation vector was very +/// often immediately appended to another obligations vector. So now this +/// function takes an obligations vector and appends to it directly, which is +/// slightly uglier but avoids the need for an extra short-lived allocation. fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, projection_ty: ty::ProjectionTy<'tcx>, cause: ObligationCause<'tcx>, - depth: usize) - -> Option> + depth: usize, + obligations: &mut Vec>) + -> Option> { let infcx = selcx.infcx(); @@ -579,7 +606,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( projection_ty); selcx.infcx().report_overflow_error(&obligation, false); } - Err(ProjectionCacheEntry::NormalizedTy(mut ty)) => { + Err(ProjectionCacheEntry::NormalizedTy(ty)) => { + // This is the hottest path in this function. + // // If we find the value in the cache, then return it along // with the obligations that went along with it. Note // that, when using a fulfillment context, these @@ -596,29 +625,32 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( // Once we have inferred everything we need to know, we // can ignore the `obligations` from that point on. if !infcx.any_unresolved_type_vars(&ty.value) { - infcx.projection_cache.borrow_mut().complete(cache_key); - ty.obligations = vec![]; + infcx.projection_cache.borrow_mut().complete_normalized(cache_key, &ty); + // No need to extend `obligations`. + } else { + obligations.extend(ty.obligations); } - push_paranoid_cache_value_obligation(infcx, - param_env, - projection_ty, - cause, - depth, - &mut ty); - - return Some(ty); + obligations.push(get_paranoid_cache_value_obligation(infcx, + param_env, + projection_ty, + cause, + depth)); + return Some(ty.value); } Err(ProjectionCacheEntry::Error) => { debug!("opt_normalize_projection_type: \ found error"); - return Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth)); + let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); + obligations.extend(result.obligations); + return Some(result.value) } } let obligation = Obligation::with_depth(cause.clone(), depth, param_env, projection_ty); match project_type(selcx, &obligation) { - Ok(ProjectedTy::Progress(Progress { ty: projected_ty, mut obligations })) => { + Ok(ProjectedTy::Progress(Progress { ty: projected_ty, + obligations: mut projected_obligations })) => { // if projection succeeded, then what we get out of this // is also non-normalized (consider: it was derived from // an impl, where-clause etc) and hence we must @@ -627,10 +659,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( debug!("opt_normalize_projection_type: \ projected_ty={:?} \ depth={} \ - obligations={:?}", + projected_obligations={:?}", projected_ty, depth, - obligations); + projected_obligations); let result = if projected_ty.has_projections() { let mut normalizer = AssociatedTypeNormalizer::new(selcx, @@ -644,22 +676,22 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( normalized_ty, depth); - obligations.extend(normalizer.obligations); + projected_obligations.extend(normalizer.obligations); Normalized { value: normalized_ty, - obligations, + obligations: projected_obligations, } } else { Normalized { value: projected_ty, - obligations, + obligations: projected_obligations, } }; let cache_value = prune_cache_value_obligations(infcx, &result); infcx.projection_cache.borrow_mut().insert_ty(cache_key, cache_value); - - Some(result) + obligations.extend(result.obligations); + Some(result.value) } Ok(ProjectedTy::NoProgress(projected_ty)) => { debug!("opt_normalize_projection_type: \ @@ -670,7 +702,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( obligations: vec![] }; infcx.projection_cache.borrow_mut().insert_ty(cache_key, result.clone()); - Some(result) + // No need to extend `obligations`. + Some(result.value) } Err(ProjectionTyError::TooManyCandidates) => { debug!("opt_normalize_projection_type: \ @@ -688,7 +721,9 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>( infcx.projection_cache.borrow_mut() .error(cache_key); - Some(normalize_to_error(selcx, param_env, projection_ty, cause, depth)) + let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth); + obligations.extend(result.obligations); + Some(result.value) } } } @@ -737,7 +772,7 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, /// may or may not be necessary -- in principle, all the obligations /// that must be proven to show that `T: Trait` were also returned /// when the cache was first populated. But there are some vague concerns, -/// and so we take the precatuionary measure of including `T: Trait` in +/// and so we take the precautionary measure of including `T: Trait` in /// the result: /// /// Concern #1. The current setup is fragile. Perhaps someone could @@ -754,19 +789,21 @@ fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, /// that may yet turn out to be wrong. This *may* lead to some sort /// of trouble, though we don't have a concrete example of how that /// can occur yet. But it seems risky at best. -fn push_paranoid_cache_value_obligation<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - cause: ObligationCause<'tcx>, - depth: usize, - result: &mut NormalizedTy<'tcx>) +fn get_paranoid_cache_value_obligation<'a, 'gcx, 'tcx>( + infcx: &'a InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + cause: ObligationCause<'tcx>, + depth: usize) + -> PredicateObligation<'tcx> { let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref(); - let trait_obligation = Obligation { cause, - recursion_depth: depth, - param_env, - predicate: trait_ref.to_predicate() }; - result.obligations.push(trait_obligation); + Obligation { + cause, + recursion_depth: depth, + param_env, + predicate: trait_ref.to_predicate(), + } } /// If we are projecting `::Item`, but `T: Trait` does not @@ -1054,7 +1091,7 @@ fn assemble_candidates_from_impls<'cx, 'gcx, 'tcx>( super::VtableImpl(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in - // trans (i.e., projection mode is not "any"), and the + // codegen (i.e., projection mode is not "any"), and the // impl's type is declared as default, then we disable // projection (even if the trait ref is fully // monomorphic). In the case where trait ref is not @@ -1288,7 +1325,7 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( vtable: VtableGeneratorData<'tcx, PredicateObligation<'tcx>>) -> Progress<'tcx> { - let gen_sig = vtable.substs.generator_poly_sig(vtable.closure_def_id, selcx.tcx()); + let gen_sig = vtable.substs.poly_sig(vtable.generator_def_id, selcx.tcx()); let Normalized { value: gen_sig, obligations @@ -1312,10 +1349,10 @@ fn confirm_generator_candidate<'cx, 'gcx, 'tcx>( obligation.predicate.self_ty(), gen_sig) .map_bound(|(trait_ref, yield_ty, return_ty)| { - let name = tcx.associated_item(obligation.predicate.item_def_id).name; - let ty = if name == Symbol::intern("Return") { + let name = tcx.associated_item(obligation.predicate.item_def_id).ident.name; + let ty = if name == "Return" { return_ty - } else if name == Symbol::intern("Yield") { + } else if name == "Yield" { yield_ty } else { bug!() @@ -1415,7 +1452,7 @@ fn confirm_callable_candidate<'cx, 'gcx, 'tcx>( projection_ty: ty::ProjectionTy::from_ref_and_name( tcx, trait_ref, - Symbol::intern(FN_OUTPUT_NAME), + Ident::from_str(FN_OUTPUT_NAME), ), ty: ret_type } @@ -1465,19 +1502,26 @@ fn confirm_impl_candidate<'cx, 'gcx, 'tcx>( let param_env = obligation.param_env; let assoc_ty = assoc_ty_def(selcx, impl_def_id, obligation.predicate.item_def_id); - let ty = if !assoc_ty.item.defaultness.has_value() { + if !assoc_ty.item.defaultness.has_value() { // This means that the impl is missing a definition for the // associated type. This error will be reported by the type // checker method `check_impl_items_against_trait`, so here we // just return TyError. debug!("confirm_impl_candidate: no associated type {:?} for {:?}", - assoc_ty.item.name, + assoc_ty.item.ident, obligation.predicate); - tcx.types.err + return Progress { + ty: tcx.types.err, + obligations: nested, + }; + } + let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node); + let ty = if let ty::AssociatedKind::Existential = assoc_ty.item.kind { + let item_substs = Substs::identity_for_item(tcx, assoc_ty.item.def_id); + tcx.mk_anon(assoc_ty.item.def_id, item_substs) } else { tcx.type_of(assoc_ty.item.def_id) }; - let substs = translate_substs(selcx.infcx(), param_env, impl_def_id, substs, assoc_ty.node); Progress { ty: ty.subst(tcx, substs), obligations: nested, @@ -1496,7 +1540,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( -> specialization_graph::NodeItem { let tcx = selcx.tcx(); - let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).name; + let assoc_ty_name = tcx.associated_item(assoc_ty_def_id).ident; let trait_def_id = tcx.impl_trait_ref(impl_def_id).unwrap().def_id; let trait_def = tcx.trait_def(trait_def_id); @@ -1509,7 +1553,7 @@ fn assoc_ty_def<'cx, 'gcx, 'tcx>( let impl_node = specialization_graph::Node::Impl(impl_def_id); for item in impl_node.items(tcx) { if item.kind == ty::AssociatedKind::Type && - tcx.hygienic_eq(item.name, assoc_ty_name, trait_def_id) { + tcx.hygienic_eq(item.ident, assoc_ty_name, trait_def_id) { return specialization_graph::NodeItem { node: specialization_graph::Node::Impl(impl_def_id), item, @@ -1682,6 +1726,23 @@ impl<'tcx> ProjectionCache<'tcx> { })); } + /// A specialized version of `complete` for when the key's value is known + /// to be a NormalizedTy. + pub fn complete_normalized(&mut self, key: ProjectionCacheKey<'tcx>, ty: &NormalizedTy<'tcx>) { + // We want to insert `ty` with no obligations. If the existing value + // already has no obligations (as is common) we can use `insert_noop` + // to do a minimal amount of work -- the HashMap insertion is skipped, + // and minimal changes are made to the undo log. + if ty.obligations.is_empty() { + self.map.insert_noop(); + } else { + self.map.insert(key, ProjectionCacheEntry::NormalizedTy(Normalized { + value: ty.value, + obligations: vec![] + })); + } + } + /// Indicates that trying to normalize `key` resulted in /// ambiguity. No point in trying it again then until we gain more /// type information (in which case, the "fully resolved" key will diff --git a/src/librustc/traits/query/dropck_outlives.rs b/src/librustc/traits/query/dropck_outlives.rs index af1d2c77c28a8..a48d24bb97a9c 100644 --- a/src/librustc/traits/query/dropck_outlives.rs +++ b/src/librustc/traits/query/dropck_outlives.rs @@ -9,13 +9,12 @@ // except according to those terms. use infer::at::At; -use infer::canonical::{Canonical, Canonicalize, QueryResult}; use infer::InferOk; +use rustc_data_structures::small_vec::SmallVec; use std::iter::FromIterator; -use traits::query::CanonicalTyGoal; -use ty::{self, Ty, TyCtxt}; +use syntax::codemap::Span; use ty::subst::Kind; -use rustc_data_structures::sync::Lrc; +use ty::{self, Ty, TyCtxt}; impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { /// Given a type `ty` of some value being dropped, computes a set @@ -45,37 +44,28 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { // any destructor. let tcx = self.infcx.tcx; if trivial_dropck_outlives(tcx, ty) { - return InferOk { value: vec![], obligations: vec![] }; + return InferOk { + value: vec![], + obligations: vec![], + }; } let gcx = tcx.global_tcx(); - let (c_ty, orig_values) = self.infcx.canonicalize_query(&self.param_env.and(ty)); + let mut orig_values = SmallVec::new(); + let c_ty = self.infcx.canonicalize_query(&self.param_env.and(ty), &mut orig_values); let span = self.cause.span; debug!("c_ty = {:?}", c_ty); match &gcx.dropck_outlives(c_ty) { Ok(result) if result.is_proven() => { - match self.infcx.instantiate_query_result( + match self.infcx.instantiate_query_result_and_region_obligations( self.cause, self.param_env, &orig_values, result, ) { - Ok(InferOk { - value: DropckOutlivesResult { kinds, overflows }, - obligations, - }) => { - for overflow_ty in overflows.into_iter().take(1) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0320, - "overflow while adding drop-check rules for {}", - self.infcx.resolve_type_vars_if_possible(&ty), - ); - err.note(&format!("overflowed on {}", overflow_ty)); - err.emit(); - } - + Ok(InferOk { value, obligations }) => { + let ty = self.infcx.resolve_type_vars_if_possible(&ty); + let kinds = value.into_kinds_reporting_overflows(tcx, span, ty); return InferOk { value: kinds, obligations, @@ -102,12 +92,44 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct DropckOutlivesResult<'tcx> { pub kinds: Vec>, pub overflows: Vec>, } +impl<'tcx> DropckOutlivesResult<'tcx> { + pub fn report_overflows( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + span: Span, + ty: Ty<'tcx>, + ) { + for overflow_ty in self.overflows.iter().take(1) { + let mut err = struct_span_err!( + tcx.sess, + span, + E0320, + "overflow while adding drop-check rules for {}", + ty, + ); + err.note(&format!("overflowed on {}", overflow_ty)); + err.emit(); + } + } + + pub fn into_kinds_reporting_overflows( + self, + tcx: TyCtxt<'_, '_, 'tcx>, + span: Span, + ty: Ty<'tcx>, + ) -> Vec> { + self.report_overflows(tcx, span, ty); + let DropckOutlivesResult { kinds, overflows: _ } = self; + kinds + } +} + /// A set of constraints that need to be satisfied in order for /// a type to be valid for destruction. #[derive(Clone, Debug)] @@ -153,17 +175,6 @@ impl<'tcx> FromIterator> for DtorckConstraint<'tcx> { result } } -impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, Ty<'tcx>> { - type Canonicalized = CanonicalTyGoal<'gcx>; - - fn intern( - _gcx: TyCtxt<'_, 'gcx, 'gcx>, - value: Canonical<'gcx, Self::Lifted>, - ) -> Self::Canonicalized { - value - } -} - BraceStructTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for DropckOutlivesResult<'tcx> { kinds, overflows @@ -181,18 +192,6 @@ impl_stable_hash_for!(struct DropckOutlivesResult<'tcx> { kinds, overflows }); -impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, DropckOutlivesResult<'tcx>> { - // we ought to intern this, but I'm too lazy just now - type Canonicalized = Lrc>>>; - - fn intern( - _gcx: TyCtxt<'_, 'gcx, 'gcx>, - value: Canonical<'gcx, Self::Lifted>, - ) -> Self::Canonicalized { - Lrc::new(value) - } -} - impl_stable_hash_for!(struct DtorckConstraint<'tcx> { outlives, dtorck_types, @@ -210,7 +209,7 @@ impl_stable_hash_for!(struct DtorckConstraint<'tcx> { /// /// Note also that `needs_drop` requires a "global" type (i.e., one /// with erased regions), but this funtcion does not. -fn trivial_dropck_outlives<'cx, 'tcx>(tcx: TyCtxt<'cx, '_, 'tcx>, ty: Ty<'tcx>) -> bool { +pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { match ty.sty { // None of these types have a destructor and hence they do not // require anything in particular to outlive the dtor's @@ -244,7 +243,10 @@ fn trivial_dropck_outlives<'cx, 'tcx>(tcx: TyCtxt<'cx, '_, 'tcx>, ty: Ty<'tcx>) ty::TyAdt(def, _) => { if def.is_union() { - // Unions never run have a dtor. + // Unions never have a dtor. + true + } else if Some(def.did) == tcx.lang_items().manually_drop() { + // `ManuallyDrop` never has a dtor. true } else { // Other types might. Moreover, PhantomData doesn't diff --git a/src/librustc/traits/query/evaluate_obligation.rs b/src/librustc/traits/query/evaluate_obligation.rs index 4e028cac49abe..93fcadceb1655 100644 --- a/src/librustc/traits/query/evaluate_obligation.rs +++ b/src/librustc/traits/query/evaluate_obligation.rs @@ -9,11 +9,9 @@ // except according to those terms. use infer::InferCtxt; -use infer::canonical::{Canonical, Canonicalize}; +use rustc_data_structures::small_vec::SmallVec; use traits::{EvaluationResult, PredicateObligation, SelectionContext, TraitQueryMode, OverflowError}; -use traits::query::CanonicalPredicateGoal; -use ty::{ParamEnvAnd, Predicate, TyCtxt}; impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { /// Evaluates whether the predicate can be satisfied (by any means) @@ -41,8 +39,9 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { &self, obligation: &PredicateObligation<'tcx>, ) -> EvaluationResult { - let (c_pred, _) = - self.canonicalize_query(&obligation.param_env.and(obligation.predicate)); + let mut _orig_values = SmallVec::new(); + let c_pred = self.canonicalize_query(&obligation.param_env.and(obligation.predicate), + &mut _orig_values); // Run canonical query. If overflow occurs, rerun from scratch but this time // in standard trait query mode so that overflow is handled appropriately // within `SelectionContext`. @@ -57,14 +56,3 @@ impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { } } } - -impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ParamEnvAnd<'tcx, Predicate<'tcx>> { - type Canonicalized = CanonicalPredicateGoal<'gcx>; - - fn intern( - _gcx: TyCtxt<'_, 'gcx, 'gcx>, - value: Canonical<'gcx, Self::Lifted>, - ) -> Self::Canonicalized { - value - } -} diff --git a/src/librustc/traits/query/mod.rs b/src/librustc/traits/query/mod.rs index 096633ddab2f7..35f17aebc0443 100644 --- a/src/librustc/traits/query/mod.rs +++ b/src/librustc/traits/query/mod.rs @@ -16,12 +16,15 @@ //! `librustc_traits`. use infer::canonical::Canonical; +use ty::error::TypeError; use ty::{self, Ty}; pub mod dropck_outlives; pub mod evaluate_obligation; pub mod normalize; pub mod normalize_erasing_regions; +pub mod outlives_bounds; +pub mod type_op; pub type CanonicalProjectionGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>>>; @@ -31,9 +34,27 @@ pub type CanonicalTyGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, Ty<'tcx>> pub type CanonicalPredicateGoal<'tcx> = Canonical<'tcx, ty::ParamEnvAnd<'tcx, ty::Predicate<'tcx>>>; +pub type CanonicalTypeOpEqGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::eq::Eq<'tcx>>>; + +pub type CanonicalTypeOpSubtypeGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::subtype::Subtype<'tcx>>>; + +pub type CanonicalTypeOpProvePredicateGoal<'tcx> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::prove_predicate::ProvePredicate<'tcx>>>; + +pub type CanonicalTypeOpNormalizeGoal<'tcx, T> = + Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::normalize::Normalize>>; + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct NoSolution; pub type Fallible = Result; +impl<'tcx> From> for NoSolution { + fn from(_: TypeError<'tcx>) -> NoSolution { + NoSolution + } +} + impl_stable_hash_for!(struct NoSolution { }); diff --git a/src/librustc/traits/query/normalize.rs b/src/librustc/traits/query/normalize.rs index f074e06165311..2203aefa31468 100644 --- a/src/librustc/traits/query/normalize.rs +++ b/src/librustc/traits/query/normalize.rs @@ -14,12 +14,9 @@ use infer::{InferCtxt, InferOk}; use infer::at::At; -use infer::canonical::{Canonical, Canonicalize, QueryResult}; -use middle::const_val::ConstVal; -use mir::interpret::GlobalId; -use rustc_data_structures::sync::Lrc; +use mir::interpret::{GlobalId, ConstValue}; +use rustc_data_structures::small_vec::SmallVec; use traits::{Obligation, ObligationCause, PredicateObligation, Reveal}; -use traits::query::CanonicalProjectionGoal; use traits::project::Normalized; use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder}; @@ -33,7 +30,7 @@ impl<'cx, 'gcx, 'tcx> At<'cx, 'gcx, 'tcx> { /// normalized. If you don't care about regions, you should prefer /// `normalize_erasing_regions`, which is more efficient. /// - /// If the normalization succeeds and is unambigious, returns back + /// If the normalization succeeds and is unambiguous, returns back /// the normalized value along with various outlives relations (in /// the form of obligations that must be discharged). /// @@ -104,7 +101,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx match ty.sty { ty::TyAnon(def_id, substs) if !substs.has_escaping_regions() => { // (*) - // Only normalize `impl Trait` after type-checking, usually in trans. + // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal { Reveal::UserFacing => ty, @@ -123,6 +120,11 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx let generic_ty = self.tcx().type_of(def_id); let concrete_ty = generic_ty.subst(self.tcx(), substs); self.anon_depth += 1; + if concrete_ty == ty { + bug!("infinite recursion generic_ty: {:#?}, substs: {:#?}, \ + concrete_ty: {:#?}, ty: {:#?}", generic_ty, substs, concrete_ty, + ty); + } let folded_ty = self.fold_ty(concrete_ty); self.anon_depth -= 1; folded_ty @@ -146,8 +148,9 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx let gcx = self.infcx.tcx.global_tcx(); - let (c_data, orig_values) = - self.infcx.canonicalize_query(&self.param_env.and(*data)); + let mut orig_values = SmallVec::new(); + let c_data = + self.infcx.canonicalize_query(&self.param_env.and(*data), &mut orig_values); debug!("QueryNormalizer: c_data = {:#?}", c_data); debug!("QueryNormalizer: orig_values = {:#?}", orig_values); match gcx.normalize_projection_ty(c_data) { @@ -158,7 +161,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx return ty; } - match self.infcx.instantiate_query_result( + match self.infcx.instantiate_query_result_and_region_obligations( self.cause, self.param_env, &orig_values, @@ -193,7 +196,7 @@ impl<'cx, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for QueryNormalizer<'cx, 'gcx, 'tcx } fn fold_const(&mut self, constant: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { - if let ConstVal::Unevaluated(def_id, substs) = constant.val { + if let ConstValue::Unevaluated(def_id, substs) = constant.val { let tcx = self.infcx.tcx.global_tcx(); if let Some(param_env) = self.tcx().lift_to_global(&self.param_env) { if substs.needs_infer() || substs.has_skol() { @@ -246,29 +249,6 @@ BraceStructLiftImpl! { } } -impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for ty::ParamEnvAnd<'tcx, ty::ProjectionTy<'tcx>> { - type Canonicalized = CanonicalProjectionGoal<'gcx>; - - fn intern( - _gcx: TyCtxt<'_, 'gcx, 'gcx>, - value: Canonical<'gcx, Self::Lifted>, - ) -> Self::Canonicalized { - value - } -} - -impl<'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for QueryResult<'tcx, NormalizationResult<'tcx>> { - // we ought to intern this, but I'm too lazy just now - type Canonicalized = Lrc>>>; - - fn intern( - _gcx: TyCtxt<'_, 'gcx, 'gcx>, - value: Canonical<'gcx, Self::Lifted>, - ) -> Self::Canonicalized { - Lrc::new(value) - } -} - impl_stable_hash_for!(struct NormalizationResult<'tcx> { normalized_ty }); diff --git a/src/librustc/traits/query/normalize_erasing_regions.rs b/src/librustc/traits/query/normalize_erasing_regions.rs index a9734e9c2986e..1cb96a3e33f43 100644 --- a/src/librustc/traits/query/normalize_erasing_regions.rs +++ b/src/librustc/traits/query/normalize_erasing_regions.rs @@ -57,7 +57,7 @@ impl<'cx, 'tcx> TyCtxt<'cx, 'tcx, 'tcx> { /// /// NB. Currently, higher-ranked type bounds inhibit /// normalization. Therefore, each time we erase them in - /// translation, we need to normalize the contents. + /// codegen, we need to normalize the contents. pub fn normalize_erasing_late_bound_regions( self, param_env: ty::ParamEnv<'tcx>, diff --git a/src/librustc/traits/query/outlives_bounds.rs b/src/librustc/traits/query/outlives_bounds.rs new file mode 100644 index 0000000000000..f79ce73ad928a --- /dev/null +++ b/src/librustc/traits/query/outlives_bounds.rs @@ -0,0 +1,171 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::InferCtxt; +use syntax::ast; +use syntax::codemap::Span; +use rustc_data_structures::small_vec::SmallVec; +use traits::{FulfillmentContext, ObligationCause, TraitEngine, TraitEngineExt}; +use traits::query::NoSolution; +use ty::{self, Ty, TyCtxt}; + +use ich::StableHashingContext; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher, + StableHasherResult}; +use std::mem; + +/// Outlives bounds are relationships between generic parameters, +/// whether they both be regions (`'a: 'b`) or whether types are +/// involved (`T: 'a`). These relationships can be extracted from the +/// full set of predicates we understand or also from types (in which +/// case they are called implied bounds). They are fed to the +/// `OutlivesEnv` which in turn is supplied to the region checker and +/// other parts of the inference system. +#[derive(Clone, Debug)] +pub enum OutlivesBound<'tcx> { + RegionSubRegion(ty::Region<'tcx>, ty::Region<'tcx>), + RegionSubParam(ty::Region<'tcx>, ty::ParamTy), + RegionSubProjection(ty::Region<'tcx>, ty::ProjectionTy<'tcx>), +} + +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for self::OutlivesBound<'a> { + type Lifted = self::OutlivesBound<'tcx>; + (self::OutlivesBound::RegionSubRegion)(a, b), + (self::OutlivesBound::RegionSubParam)(a, b), + (self::OutlivesBound::RegionSubProjection)(a, b), + } +} + +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for self::OutlivesBound<'tcx> { + (self::OutlivesBound::RegionSubRegion)(a, b), + (self::OutlivesBound::RegionSubParam)(a, b), + (self::OutlivesBound::RegionSubProjection)(a, b), + } +} + +impl<'a, 'tcx> HashStable> for OutlivesBound<'tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + OutlivesBound::RegionSubRegion(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + OutlivesBound::RegionSubParam(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + OutlivesBound::RegionSubProjection(ref a, ref b) => { + a.hash_stable(hcx, hasher); + b.hash_stable(hcx, hasher); + } + } + } +} + +impl<'cx, 'gcx, 'tcx> InferCtxt<'cx, 'gcx, 'tcx> { + /// Implied bounds are region relationships that we deduce + /// automatically. The idea is that (e.g.) a caller must check that a + /// function's argument types are well-formed immediately before + /// calling that fn, and hence the *callee* can assume that its + /// argument types are well-formed. This may imply certain relationships + /// between generic parameters. For example: + /// + /// fn foo<'a,T>(x: &'a T) + /// + /// can only be called with a `'a` and `T` such that `&'a T` is WF. + /// For `&'a T` to be WF, `T: 'a` must hold. So we can assume `T: 'a`. + /// + /// # Parameters + /// + /// - `param_env`, the where-clauses in scope + /// - `body_id`, the body-id to use when normalizing assoc types. + /// Note that this may cause outlives obligations to be injected + /// into the inference context with this body-id. + /// - `ty`, the type that we are supposed to assume is WF. + /// - `span`, a span to use when normalizing, hopefully not important, + /// might be useful if a `bug!` occurs. + pub fn implied_outlives_bounds( + &self, + param_env: ty::ParamEnv<'tcx>, + body_id: ast::NodeId, + ty: Ty<'tcx>, + span: Span, + ) -> Vec> { + debug!("implied_outlives_bounds(ty = {:?})", ty); + + let mut orig_values = SmallVec::new(); + let key = self.canonicalize_query(¶m_env.and(ty), &mut orig_values); + let result = match self.tcx.global_tcx().implied_outlives_bounds(key) { + Ok(r) => r, + Err(NoSolution) => { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve all obligations" + ); + return vec![]; + } + }; + assert!(result.value.is_proven()); + + let result = self.instantiate_query_result_and_region_obligations( + &ObligationCause::misc(span, body_id), param_env, &orig_values, &result); + debug!("implied_outlives_bounds for {:?}: {:#?}", ty, result); + let result = match result { + Ok(v) => v, + Err(_) => { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to instantiate" + ); + return vec![]; + } + }; + + // Instantiation may have produced new inference variables and constraints on those + // variables. Process these constraints. + let mut fulfill_cx = FulfillmentContext::new(); + fulfill_cx.register_predicate_obligations(self, result.obligations); + if let Err(_) = fulfill_cx.select_all_or_error(self) { + self.tcx.sess.delay_span_bug( + span, + "implied_outlives_bounds failed to solve obligations from instantiation" + ); + } + + result.value + } +} + +pub fn explicit_outlives_bounds<'tcx>( + param_env: ty::ParamEnv<'tcx>, +) -> impl Iterator> + 'tcx { + debug!("explicit_outlives_bounds()"); + param_env + .caller_bounds + .into_iter() + .filter_map(move |predicate| match predicate { + ty::Predicate::Projection(..) | + ty::Predicate::Trait(..) | + ty::Predicate::Subtype(..) | + ty::Predicate::WellFormed(..) | + ty::Predicate::ObjectSafe(..) | + ty::Predicate::ClosureKind(..) | + ty::Predicate::TypeOutlives(..) | + ty::Predicate::ConstEvaluatable(..) => None, + ty::Predicate::RegionOutlives(ref data) => data.no_late_bound_regions().map( + |ty::OutlivesPredicate(r_a, r_b)| OutlivesBound::RegionSubRegion(r_b, r_a), + ), + }) +} diff --git a/src/librustc/traits/query/type_op/custom.rs b/src/librustc/traits/query/type_op/custom.rs new file mode 100644 index 0000000000000..3d10ce805853d --- /dev/null +++ b/src/librustc/traits/query/type_op/custom.rs @@ -0,0 +1,100 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::{InferCtxt, InferOk}; +use std::fmt; +use traits::query::Fallible; + +use infer::canonical::query_result; +use infer::canonical::QueryRegionConstraint; +use std::rc::Rc; +use syntax::codemap::DUMMY_SP; +use traits::{ObligationCause, TraitEngine, TraitEngineExt}; + +pub struct CustomTypeOp { + closure: F, + description: G, +} + +impl CustomTypeOp { + pub fn new<'gcx, 'tcx, R>(closure: F, description: G) -> Self + where + F: FnOnce(&InferCtxt<'_, 'gcx, 'tcx>) -> Fallible>, + G: Fn() -> String, + { + CustomTypeOp { + closure, + description, + } + } +} + +impl<'gcx, 'tcx, F, R, G> super::TypeOp<'gcx, 'tcx> for CustomTypeOp +where + F: for<'a, 'cx> FnOnce(&'a InferCtxt<'cx, 'gcx, 'tcx>) -> Fallible>, + G: Fn() -> String, +{ + type Output = R; + + /// Processes the operation and all resulting obligations, + /// returning the final result along with any region constraints + /// (they will be given over to the NLL region solver). + fn fully_perform( + self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + ) -> Fallible<(Self::Output, Option>>>)> { + if cfg!(debug_assertions) { + info!("fully_perform({:?})", self); + } + + scrape_region_constraints(infcx, || Ok((self.closure)(infcx)?)) + } +} + +impl fmt::Debug for CustomTypeOp +where + G: Fn() -> String, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", (self.description)()) + } +} + +/// Executes `op` and then scrapes out all the "old style" region +/// constraints that result, creating query-region-constraints. +fn scrape_region_constraints<'gcx, 'tcx, R>( + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + op: impl FnOnce() -> Fallible>, +) -> Fallible<(R, Option>>>)> { + let mut fulfill_cx = TraitEngine::new(infcx.tcx); + let dummy_body_id = ObligationCause::dummy().body_id; + let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?; + debug_assert!(obligations.iter().all(|o| o.cause.body_id == dummy_body_id)); + fulfill_cx.register_predicate_obligations(infcx, obligations); + if let Err(e) = fulfill_cx.select_all_or_error(infcx) { + infcx.tcx.sess.diagnostic().delay_span_bug( + DUMMY_SP, + &format!("errors selecting obligation during MIR typeck: {:?}", e), + ); + } + + let region_obligations = infcx.take_registered_region_obligations(); + + let region_constraint_data = infcx.take_and_reset_region_constraints(); + + let outlives = + query_result::make_query_outlives(infcx.tcx, region_obligations, ®ion_constraint_data); + + if outlives.is_empty() { + Ok((value, None)) + } else { + Ok((value, Some(Rc::new(outlives)))) + } +} diff --git a/src/librustc/traits/query/type_op/eq.rs b/src/librustc/traits/query/type_op/eq.rs new file mode 100644 index 0000000000000..52a087cbc8069 --- /dev/null +++ b/src/librustc/traits/query/type_op/eq.rs @@ -0,0 +1,72 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use traits::query::Fallible; +use ty::{ParamEnvAnd, Ty, TyCtxt}; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Eq<'tcx> { + pub a: Ty<'tcx>, + pub b: Ty<'tcx>, +} + +impl<'tcx> Eq<'tcx> { + pub fn new(a: Ty<'tcx>, b: Ty<'tcx>) -> Self { + Self { a, b } + } +} + +impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Eq<'tcx> { + type QueryResult = (); + + fn try_fast_path( + _tcx: TyCtxt<'_, 'gcx, 'tcx>, + key: &ParamEnvAnd<'tcx, Eq<'tcx>>, + ) -> Option { + if key.value.a == key.value.b { + Some(()) + } else { + None + } + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + tcx.type_op_eq(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for Eq<'tcx> { + a, + b, + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for Eq<'a> { + type Lifted = Eq<'tcx>; + a, + b, + } +} + +impl_stable_hash_for! { + struct Eq<'tcx> { a, b } +} diff --git a/src/librustc/traits/query/type_op/mod.rs b/src/librustc/traits/query/type_op/mod.rs new file mode 100644 index 0000000000000..be5e2838963ee --- /dev/null +++ b/src/librustc/traits/query/type_op/mod.rs @@ -0,0 +1,166 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryRegionConstraint, + QueryResult}; +use infer::{InferCtxt, InferOk}; +use rustc_data_structures::small_vec::SmallVec; +use std::fmt; +use std::rc::Rc; +use traits::query::Fallible; +use traits::ObligationCause; +use ty::fold::TypeFoldable; +use ty::{Lift, ParamEnvAnd, TyCtxt}; + +pub mod custom; +pub mod eq; +pub mod normalize; +pub mod outlives; +pub mod prove_predicate; +use self::prove_predicate::ProvePredicate; +pub mod subtype; + +/// "Type ops" are used in NLL to perform some particular action and +/// extract out the resulting region constraints (or an error if it +/// cannot be completed). +pub trait TypeOp<'gcx, 'tcx>: Sized + fmt::Debug { + type Output; + + /// Processes the operation and all resulting obligations, + /// returning the final result along with any region constraints + /// (they will be given over to the NLL region solver). + fn fully_perform( + self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + ) -> Fallible<(Self::Output, Option>>>)>; +} + +/// "Query type ops" are type ops that are implemented using a +/// [canonical query][c]. The `Self` type here contains the kernel of +/// information needed to do the operation -- `TypeOp` is actually +/// implemented for `ParamEnvAnd`, since we always need to bring +/// along a parameter environment as well. For query type-ops, we will +/// first canonicalize the key and then invoke the query on the tcx, +/// which produces the resulting query region constraints. +/// +/// [c]: https://rust-lang-nursery.github.io/rustc-guide/traits/canonicalization.html +pub trait QueryTypeOp<'gcx: 'tcx, 'tcx>: + fmt::Debug + Sized + TypeFoldable<'tcx> + Lift<'gcx> +{ + type QueryResult: TypeFoldable<'tcx> + Lift<'gcx>; + + /// Give query the option for a simple fast path that never + /// actually hits the tcx cache lookup etc. Return `Some(r)` with + /// a final result or `None` to do the full path. + fn try_fast_path( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + key: &ParamEnvAnd<'tcx, Self>, + ) -> Option; + + /// Performs the actual query with the canonicalized key -- the + /// real work happens here. This method is not given an `infcx` + /// because it shouldn't need one -- and if it had access to one, + /// it might do things like invoke `sub_regions`, which would be + /// bad, because it would create subregion relationships that are + /// not captured in the return value. + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible>; + + /// Casts a lifted query result (which is in the gcx lifetime) + /// into the tcx lifetime. This is always just an identity cast, + /// but the generic code doesn't realize it -- put another way, in + /// the generic code, we have a `Lifted<'gcx, Self::QueryResult>` + /// and we want to convert that to a `Self::QueryResult`. This is + /// not a priori valid, so we can't do it -- but in practice, it + /// is always a no-op (e.g., the lifted form of a type, + /// `Ty<'gcx>`, is a subtype of `Ty<'tcx>`). So we have to push + /// the operation into the impls that know more specifically what + /// `QueryResult` is. This operation would (maybe) be nicer with + /// something like HKTs or GATs, since then we could make + /// `QueryResult` parametric and `'gcx` and `'tcx` etc. + fn shrink_to_tcx_lifetime( + lifted_query_result: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>>; + + fn fully_perform_into( + query_key: ParamEnvAnd<'tcx, Self>, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + output_query_region_constraints: &mut Vec>, + ) -> Fallible { + if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) { + return Ok(result); + } + + // FIXME(#33684) -- We need to use + // `canonicalize_hr_query_hack` here because of things + // like the subtype query, which go awry around + // `'static` otherwise. + let mut canonical_var_values = SmallVec::new(); + let canonical_self = + infcx.canonicalize_hr_query_hack(&query_key, &mut canonical_var_values); + let canonical_result = Self::perform_query(infcx.tcx, canonical_self)?; + let canonical_result = Self::shrink_to_tcx_lifetime(&canonical_result); + + let param_env = query_key.param_env; + + let InferOk { value, obligations } = infcx + .instantiate_nll_query_result_and_region_obligations( + &ObligationCause::dummy(), + param_env, + &canonical_var_values, + canonical_result, + output_query_region_constraints, + )?; + + // Typically, instantiating NLL query results does not + // create obligations. However, in some cases there + // are unresolved type variables, and unify them *can* + // create obligations. In that case, we have to go + // fulfill them. We do this via a (recursive) query. + for obligation in obligations { + let () = ProvePredicate::fully_perform_into( + obligation + .param_env + .and(ProvePredicate::new(obligation.predicate)), + infcx, + output_query_region_constraints, + )?; + } + + Ok(value) + } +} + +impl<'gcx: 'tcx, 'tcx, Q> TypeOp<'gcx, 'tcx> for ParamEnvAnd<'tcx, Q> +where + Q: QueryTypeOp<'gcx, 'tcx>, +{ + type Output = Q::QueryResult; + + fn fully_perform( + self, + infcx: &InferCtxt<'_, 'gcx, 'tcx>, + ) -> Fallible<(Self::Output, Option>>>)> { + let mut qrc = vec![]; + let r = Q::fully_perform_into(self, infcx, &mut qrc)?; + + // Promote the final query-region-constraints into a + // (optional) ref-counted vector: + let opt_qrc = if qrc.is_empty() { + None + } else { + Some(Rc::new(qrc)) + }; + + Ok((r, opt_qrc)) + } +} diff --git a/src/librustc/traits/query/type_op/normalize.rs b/src/librustc/traits/query/type_op/normalize.rs new file mode 100644 index 0000000000000..0c393fa4ca80f --- /dev/null +++ b/src/librustc/traits/query/type_op/normalize.rs @@ -0,0 +1,161 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use std::fmt; +use traits::query::Fallible; +use ty::fold::TypeFoldable; +use ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt}; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Normalize { + pub value: T, +} + +impl<'tcx, T> Normalize +where + T: fmt::Debug + TypeFoldable<'tcx>, +{ + pub fn new(value: T) -> Self { + Self { value } + } +} + +impl<'gcx: 'tcx, 'tcx, T> super::QueryTypeOp<'gcx, 'tcx> for Normalize +where + T: Normalizable<'gcx, 'tcx>, +{ + type QueryResult = T; + + fn try_fast_path(_tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option { + if !key.value.value.has_projections() { + Some(key.value.value) + } else { + None + } + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + T::type_op_method(tcx, canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, T>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, T>> { + T::shrink_to_tcx_lifetime(v) + } +} + +pub trait Normalizable<'gcx, 'tcx>: fmt::Debug + TypeFoldable<'tcx> + Lift<'gcx> + Copy { + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible>; + + /// Convert from the `'gcx` (lifted) form of `Self` into the `tcx` + /// form of `Self`. + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>>; +} + +impl Normalizable<'gcx, 'tcx> for Ty<'tcx> +where + 'gcx: 'tcx, +{ + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible> { + tcx.type_op_normalize_ty(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v + } +} + +impl Normalizable<'gcx, 'tcx> for ty::Predicate<'tcx> +where + 'gcx: 'tcx, +{ + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible> { + tcx.type_op_normalize_predicate(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v + } +} + +impl Normalizable<'gcx, 'tcx> for ty::PolyFnSig<'tcx> +where + 'gcx: 'tcx, +{ + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible> { + tcx.type_op_normalize_poly_fn_sig(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v + } +} + +impl Normalizable<'gcx, 'tcx> for ty::FnSig<'tcx> +where + 'gcx: 'tcx, +{ + fn type_op_method( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Normalize>>, + ) -> Fallible> { + tcx.type_op_normalize_fn_sig(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, Self>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self>> { + v + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx, T> TypeFoldable<'tcx> for Normalize { + value, + } where T: TypeFoldable<'tcx>, +} + +BraceStructLiftImpl! { + impl<'tcx, T> Lift<'tcx> for Normalize { + type Lifted = Normalize; + value, + } where T: Lift<'tcx>, +} + +impl_stable_hash_for! { + impl<'tcx, T> for struct Normalize { + value + } +} diff --git a/src/librustc/traits/query/type_op/outlives.rs b/src/librustc/traits/query/type_op/outlives.rs new file mode 100644 index 0000000000000..e41ae7a72f9c2 --- /dev/null +++ b/src/librustc/traits/query/type_op/outlives.rs @@ -0,0 +1,100 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use traits::query::dropck_outlives::trivial_dropck_outlives; +use traits::query::dropck_outlives::DropckOutlivesResult; +use traits::query::Fallible; +use ty::{ParamEnvAnd, Ty, TyCtxt}; + +#[derive(Copy, Clone, Debug)] +pub struct DropckOutlives<'tcx> { + dropped_ty: Ty<'tcx>, +} + +impl<'tcx> DropckOutlives<'tcx> { + pub fn new(dropped_ty: Ty<'tcx>) -> Self { + DropckOutlives { dropped_ty } + } +} + +impl super::QueryTypeOp<'gcx, 'tcx> for DropckOutlives<'tcx> +where + 'gcx: 'tcx, +{ + type QueryResult = DropckOutlivesResult<'tcx>; + + fn try_fast_path( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + key: &ParamEnvAnd<'tcx, Self>, + ) -> Option { + if trivial_dropck_outlives(tcx, key.value.dropped_ty) { + Some(DropckOutlivesResult::default()) + } else { + None + } + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + // Subtle: note that we are not invoking + // `infcx.at(...).dropck_outlives(...)` here, but rather the + // underlying `dropck_outlives` query. This same underlying + // query is also used by the + // `infcx.at(...).dropck_outlives(...)` fn. Avoiding the + // wrapper means we don't need an infcx in this code, which is + // good because the interface doesn't give us one (so that we + // know we are not registering any subregion relations or + // other things). + + // FIXME convert to the type expected by the `dropck_outlives` + // query. This should eventually be fixed by changing the + // *underlying query*. + let Canonical { + variables, + value: + ParamEnvAnd { + param_env, + value: DropckOutlives { dropped_ty }, + }, + } = canonicalized; + let canonicalized = Canonical { + variables, + value: param_env.and(dropped_ty), + }; + + tcx.dropck_outlives(canonicalized) + } + + fn shrink_to_tcx_lifetime( + lifted_query_result: &'a CanonicalizedQueryResult<'gcx, Self::QueryResult>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, Self::QueryResult>> { + lifted_query_result + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for DropckOutlives<'tcx> { + dropped_ty + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for DropckOutlives<'a> { + type Lifted = DropckOutlives<'tcx>; + dropped_ty + } +} + +impl_stable_hash_for! { + struct DropckOutlives<'tcx> { dropped_ty } +} diff --git a/src/librustc/traits/query/type_op/prove_predicate.rs b/src/librustc/traits/query/type_op/prove_predicate.rs new file mode 100644 index 0000000000000..33dc3210f0881 --- /dev/null +++ b/src/librustc/traits/query/type_op/prove_predicate.rs @@ -0,0 +1,65 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use traits::query::Fallible; +use ty::{ParamEnvAnd, Predicate, TyCtxt}; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct ProvePredicate<'tcx> { + pub predicate: Predicate<'tcx>, +} + +impl<'tcx> ProvePredicate<'tcx> { + pub fn new(predicate: Predicate<'tcx>) -> Self { + ProvePredicate { predicate } + } +} + +impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for ProvePredicate<'tcx> { + type QueryResult = (); + + fn try_fast_path( + _tcx: TyCtxt<'_, 'gcx, 'tcx>, + _key: &ParamEnvAnd<'tcx, Self>, + ) -> Option { + None + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + tcx.type_op_prove_predicate(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for ProvePredicate<'tcx> { + predicate, + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for ProvePredicate<'a> { + type Lifted = ProvePredicate<'tcx>; + predicate, + } +} + +impl_stable_hash_for! { + struct ProvePredicate<'tcx> { predicate } +} diff --git a/src/librustc/traits/query/type_op/subtype.rs b/src/librustc/traits/query/type_op/subtype.rs new file mode 100644 index 0000000000000..dc41bb1d6ab69 --- /dev/null +++ b/src/librustc/traits/query/type_op/subtype.rs @@ -0,0 +1,72 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use infer::canonical::{Canonical, Canonicalized, CanonicalizedQueryResult, QueryResult}; +use traits::query::Fallible; +use ty::{ParamEnvAnd, Ty, TyCtxt}; + +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub struct Subtype<'tcx> { + pub sub: Ty<'tcx>, + pub sup: Ty<'tcx>, +} + +impl<'tcx> Subtype<'tcx> { + pub fn new(sub: Ty<'tcx>, sup: Ty<'tcx>) -> Self { + Self { + sub, + sup, + } + } +} + +impl<'gcx: 'tcx, 'tcx> super::QueryTypeOp<'gcx, 'tcx> for Subtype<'tcx> { + type QueryResult = (); + + fn try_fast_path(_tcx: TyCtxt<'_, 'gcx, 'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<()> { + if key.value.sub == key.value.sup { + Some(()) + } else { + None + } + } + + fn perform_query( + tcx: TyCtxt<'_, 'gcx, 'tcx>, + canonicalized: Canonicalized<'gcx, ParamEnvAnd<'tcx, Self>>, + ) -> Fallible> { + tcx.type_op_subtype(canonicalized) + } + + fn shrink_to_tcx_lifetime( + v: &'a CanonicalizedQueryResult<'gcx, ()>, + ) -> &'a Canonical<'tcx, QueryResult<'tcx, ()>> { + v + } +} + +BraceStructTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for Subtype<'tcx> { + sub, + sup, + } +} + +BraceStructLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for Subtype<'a> { + type Lifted = Subtype<'tcx>; + sub, + sup, + } +} + +impl_stable_hash_for! { + struct Subtype<'tcx> { sub, sup } +} diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs index 54b2cf2808282..40171345f558b 100644 --- a/src/librustc/traits/select.rs +++ b/src/librustc/traits/select.rs @@ -10,7 +10,7 @@ //! See [rustc guide] for more info on how this works. //! -//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#selection +//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/resolution.html#selection use self::SelectionCandidate::*; use self::EvaluationResult::*; @@ -37,16 +37,16 @@ use dep_graph::{DepNodeIndex, DepKind}; use hir::def_id::DefId; use infer; use infer::{InferCtxt, InferOk, TypeFreshener}; -use ty::subst::{Kind, Subst, Substs}; +use ty::subst::{Subst, Substs}; use ty::{self, ToPredicate, ToPolyTraitRef, Ty, TyCtxt, TypeFoldable}; use ty::fast_reject; use ty::relate::TypeRelation; use middle::lang_items; use mir::interpret::{GlobalId}; +use rustc_data_structures::sync::Lock; use rustc_data_structures::bitvec::BitVector; use std::iter; -use std::cell::RefCell; use std::cmp; use std::fmt; use std::mem; @@ -148,7 +148,7 @@ struct TraitObligationStack<'prev, 'tcx: 'prev> { #[derive(Clone)] pub struct SelectionCache<'tcx> { - hashmap: RefCell, + hashmap: Lock, WithDepNode>>>>, } @@ -305,9 +305,6 @@ enum BuiltinImplConditions<'tcx> { /// There is no built-in impl. There may be some other /// candidate (a where-clause or user-defined impl). None, - /// There is *no* impl for this, builtin or not. Ignore - /// all where-clauses. - Never, /// It is unknown whether there is an impl. Ambiguous } @@ -435,7 +432,7 @@ impl<'tcx> From for SelectionError<'tcx> { #[derive(Clone)] pub struct EvaluationCache<'tcx> { - hashmap: RefCell, WithDepNode>> + hashmap: Lock, WithDepNode>> } impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { @@ -781,13 +778,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { mut obligation: TraitObligation<'tcx>) -> Result { - debug!("evaluate_trait_predicate_recursively({:?})", - obligation); + debug!("evaluate_trait_predicate_recursively({:?})", obligation); - if !self.intercrate.is_some() && obligation.is_global() { - // If a param env is consistent, global obligations do not depend on its particular - // value in order to work, so we can clear out the param env and get better - // caching. (If the current param env is inconsistent, we don't care what happens). + if self.intercrate.is_none() && obligation.is_global() + && obligation.param_env.caller_bounds.iter().all(|bound| bound.needs_subst()) { + // If a param env has no global bounds, global obligations do not + // depend on its particular value in order to work, so we can clear + // out the param env and get better caching. debug!("evaluate_trait_predicate_recursively({:?}) - in global", obligation); obligation.param_env = obligation.param_env.without_caller_bounds(); } @@ -1015,14 +1012,19 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } if self.can_use_global_caches(param_env) { - let mut cache = self.tcx().evaluation_cache.hashmap.borrow_mut(); if let Some(trait_ref) = self.tcx().lift_to_global(&trait_ref) { debug!( "insert_evaluation_cache(trait_ref={:?}, candidate={:?}) global", trait_ref, result, ); - cache.insert(trait_ref, WithDepNode::new(dep_node, result)); + // This may overwrite the cache with the same value + // FIXME: Due to #50507 this overwrites the different values + // This should be changed to use HashMapExt::insert_same + // when that is fixed + self.tcx().evaluation_cache + .hashmap.borrow_mut() + .insert(trait_ref, WithDepNode::new(dep_node, result)); return; } } @@ -1045,7 +1047,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // candidates. See [rustc guide] for more details. // // [rustc guide]: - // https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#candidate-assembly + // https://rust-lang-nursery.github.io/rustc-guide/traits/resolution.html#candidate-assembly fn candidate_from_obligation<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) @@ -1235,6 +1237,11 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let mut candidates: Vec = candidates?.into_iter().filter_map(|c| c).collect(); + debug!("winnowed to {} candidates for {:?}: {:?}", + candidates.len(), + stack, + candidates); + // If there are STILL multiple candidate, we can further // reduce the list by dropping duplicates -- including // resolving specializations. @@ -1368,7 +1375,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let tcx = self.tcx(); let trait_ref = cache_fresh_trait_pred.skip_binder().trait_ref; if self.can_use_global_caches(param_env) { - let mut cache = tcx.selection_cache.hashmap.borrow_mut(); if let Some(trait_ref) = tcx.lift_to_global(&trait_ref) { if let Some(candidate) = tcx.lift_to_global(&candidate) { debug!( @@ -1376,7 +1382,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_ref, candidate, ); - cache.insert(trait_ref, WithDepNode::new(dep_node, candidate)); + // This may overwrite the cache with the same value + tcx.selection_cache + .hashmap.borrow_mut() + .insert(trait_ref, WithDepNode::new(dep_node, candidate)); return; } } @@ -1444,22 +1453,22 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let sized_conditions = self.sized_conditions(obligation); self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates)?; - } else if lang_items.unsize_trait() == Some(def_id) { - self.assemble_candidates_for_unsizing(obligation, &mut candidates); - } else { - if lang_items.clone_trait() == Some(def_id) { - // Same builtin conditions as `Copy`, i.e. every type which has builtin support - // for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone` - // types have builtin support for `Clone`. - let clone_conditions = self.copy_clone_conditions(obligation); - self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?; - } - - self.assemble_generator_candidates(obligation, &mut candidates)?; - self.assemble_closure_candidates(obligation, &mut candidates)?; - self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; - self.assemble_candidates_from_impls(obligation, &mut candidates)?; - self.assemble_candidates_from_object_ty(obligation, &mut candidates); + } else if lang_items.unsize_trait() == Some(def_id) { + self.assemble_candidates_for_unsizing(obligation, &mut candidates); + } else { + if lang_items.clone_trait() == Some(def_id) { + // Same builtin conditions as `Copy`, i.e. every type which has builtin support + // for `Copy` also has builtin support for `Clone`, + tuples and arrays of `Clone` + // types have builtin support for `Clone`. + let clone_conditions = self.copy_clone_conditions(obligation); + self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates)?; + } + + self.assemble_generator_candidates(obligation, &mut candidates)?; + self.assemble_closure_candidates(obligation, &mut candidates)?; + self.assemble_fn_pointer_candidates(obligation, &mut candidates)?; + self.assemble_candidates_from_impls(obligation, &mut candidates)?; + self.assemble_candidates_from_object_ty(obligation, &mut candidates); } self.assemble_candidates_from_projected_tys(obligation, &mut candidates); @@ -2007,9 +2016,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // attempt to evaluate recursive bounds to see if they are // satisfied. - /// Returns true if `candidate_i` should be dropped in favor of - /// `candidate_j`. Generally speaking we will drop duplicate - /// candidates and prefer where-clause candidates. /// Returns true if `victim` should be dropped in favor of /// `other`. Generally speaking we will drop duplicate /// candidates and prefer where-clause candidates. @@ -2021,13 +2027,46 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { other: &EvaluatedCandidate<'tcx>) -> bool { + // Check if a bound would previously have been removed when normalizing + // the param_env so that it can be given the lowest priority. See + // #50825 for the motivation for this. + let is_global = |cand: &ty::PolyTraitRef<'_>| { + cand.is_global() && !cand.has_late_bound_regions() + }; + if victim.candidate == other.candidate { return true; } match other.candidate { + ParamCandidate(ref cand) => match victim.candidate { + AutoImplCandidate(..) => { + bug!( + "default implementations shouldn't be recorded \ + when there are other valid candidates"); + } + ImplCandidate(..) | + ClosureCandidate | + GeneratorCandidate | + FnPointerCandidate | + BuiltinObjectCandidate | + BuiltinUnsizeCandidate | + BuiltinCandidate { .. } => { + // Global bounds from the where clause should be ignored + // here (see issue #50825). Otherwise, we have a where + // clause so don't go around looking for impls. + !is_global(cand) + } + ObjectCandidate | + ProjectionCandidate => { + // Arbitrarily give param candidates priority + // over projection and object candidates. + !is_global(cand) + }, + ParamCandidate(..) => false, + }, ObjectCandidate | - ParamCandidate(_) | ProjectionCandidate => match victim.candidate { + ProjectionCandidate => match victim.candidate { AutoImplCandidate(..) => { bug!( "default implementations shouldn't be recorded \ @@ -2040,8 +2079,6 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { BuiltinObjectCandidate | BuiltinUnsizeCandidate | BuiltinCandidate { .. } => { - // We have a where-clause so don't go around looking - // for impls. true } ObjectCandidate | @@ -2050,22 +2087,44 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // over projection and object candidates. true }, - ParamCandidate(..) => false, + ParamCandidate(ref cand) => is_global(cand), }, ImplCandidate(other_def) => { // See if we can toss out `victim` based on specialization. // This requires us to know *for sure* that the `other` impl applies // i.e. EvaluatedToOk: if other.evaluation == EvaluatedToOk { - if let ImplCandidate(victim_def) = victim.candidate { - let tcx = self.tcx().global_tcx(); - return tcx.specializes((other_def, victim_def)) || - tcx.impls_are_allowed_to_overlap(other_def, victim_def); + match victim.candidate { + ImplCandidate(victim_def) => { + let tcx = self.tcx().global_tcx(); + return tcx.specializes((other_def, victim_def)) || + tcx.impls_are_allowed_to_overlap(other_def, victim_def); + } + ParamCandidate(ref cand) => { + // Prefer the impl to a global where clause candidate. + return is_global(cand); + } + _ => () } } false }, + ClosureCandidate | + GeneratorCandidate | + FnPointerCandidate | + BuiltinObjectCandidate | + BuiltinUnsizeCandidate | + BuiltinCandidate { .. } => { + match victim.candidate { + ParamCandidate(ref cand) => { + // Prefer these to a global where-clause bound + // (see issue #50825) + is_global(cand) && other.evaluation == EvaluatedToOk + } + _ => false, + } + } _ => false } } @@ -2074,13 +2133,8 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // BUILTIN BOUNDS // // These cover the traits that are built-in to the language - // itself. This includes `Copy` and `Sized` for sure. For the - // moment, it also includes `Send` / `Sync` and a few others, but - // those will hopefully change to library-defined traits in the - // future. + // itself: `Copy`, `Clone` and `Sized`. - // HACK: if this returns an error, selection exits without considering - // other impls. fn assemble_builtin_bound_candidates<'o>(&mut self, conditions: BuiltinImplConditions<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>) @@ -2099,14 +2153,13 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { debug!("assemble_builtin_bound_candidates: ambiguous builtin"); Ok(candidates.ambiguous = true) } - BuiltinImplConditions::Never => { Err(Unimplemented) } } } fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>) -> BuiltinImplConditions<'tcx> { - use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; + use self::BuiltinImplConditions::{Ambiguous, None, Where}; // NOTE: binder moved to (*) let self_ty = self.infcx.shallow_resolve( @@ -2123,7 +2176,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { Where(ty::Binder::dummy(Vec::new())) } - ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => Never, + ty::TyStr | ty::TySlice(_) | ty::TyDynamic(..) | ty::TyForeign(..) => None, ty::TyTuple(tys) => { Where(ty::Binder::bind(tys.last().into_iter().cloned().collect())) @@ -2157,7 +2210,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { let self_ty = self.infcx.shallow_resolve( obligation.predicate.skip_binder().self_ty()); - use self::BuiltinImplConditions::{Ambiguous, None, Never, Where}; + use self::BuiltinImplConditions::{Ambiguous, None, Where}; match self_ty.sty { ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) | @@ -2167,15 +2220,15 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | ty::TyChar | ty::TyRawPtr(..) | ty::TyNever | - ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => { + ty::TyRef(_, _, hir::MutImmutable) => { // Implementations provided in libcore None } ty::TyDynamic(..) | ty::TyStr | ty::TySlice(..) | ty::TyGenerator(..) | ty::TyGeneratorWitness(..) | ty::TyForeign(..) | - ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => { - Never + ty::TyRef(_, _, hir::MutMutable) => { + None } ty::TyArray(element_ty, _) => { @@ -2195,7 +2248,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { if is_copy_trait || is_clone_trait { Where(ty::Binder::bind(substs.upvar_tys(def_id, self.tcx()).collect())) } else { - Never + None } } @@ -2263,7 +2316,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { } ty::TyRawPtr(ty::TypeAndMut { ty: element_ty, ..}) | - ty::TyRef(_, ty::TypeAndMut { ty: element_ty, ..}) => { + ty::TyRef(_, element_ty, _) => { vec![element_ty] }, @@ -2280,8 +2333,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { substs.upvar_tys(def_id, self.tcx()).collect() } - ty::TyGenerator(def_id, ref substs, interior) => { - substs.upvar_tys(def_id, self.tcx()).chain(iter::once(interior.witness)).collect() + ty::TyGenerator(def_id, ref substs, _) => { + let witness = substs.witness(def_id, self.tcx()); + substs.upvar_tys(def_id, self.tcx()).chain(iter::once(witness)).collect() } ty::TyGeneratorWitness(types) => { @@ -2366,7 +2420,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // type error. See [rustc guide] for more details. // // [rustc guide]: - // https://rust-lang-nursery.github.io/rustc-guide/trait-resolution.html#confirmation + // https://rust-lang-nursery.github.io/rustc-guide/traits/resolution.html#confirmation fn confirm_candidate(&mut self, obligation: &TraitObligation<'tcx>, @@ -2755,18 +2809,18 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.sty { + let (generator_def_id, substs) = match self_ty.sty { ty::TyGenerator(id, substs, _) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation) }; debug!("confirm_generator_candidate({:?},{:?},{:?})", obligation, - closure_def_id, + generator_def_id, substs); let trait_ref = - self.generator_trait_ref_unnormalized(obligation, closure_def_id, substs); + self.generator_trait_ref_unnormalized(obligation, generator_def_id, substs); let Normalized { value: trait_ref, mut obligations @@ -2776,8 +2830,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.recursion_depth+1, &trait_ref); - debug!("confirm_generator_candidate(closure_def_id={:?}, trait_ref={:?}, obligations={:?})", - closure_def_id, + debug!("confirm_generator_candidate(generator_def_id={:?}, \ + trait_ref={:?}, obligations={:?})", + generator_def_id, trait_ref, obligations); @@ -2788,7 +2843,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { trait_ref)?); Ok(VtableGeneratorData { - closure_def_id: closure_def_id, + generator_def_id: generator_def_id, substs: substs.clone(), nested: obligations }) @@ -3019,7 +3074,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { // with a potentially unsized trailing field. let params = substs_a.iter().enumerate().map(|(i, &k)| { if ty_params.contains(i) { - Kind::from(tcx.types.err) + tcx.types.err.into() } else { k } @@ -3058,7 +3113,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.recursion_depth + 1, inner_source, - &[inner_target])); + &[inner_target.into()])); } // (.., T) -> (.., U). @@ -3066,16 +3121,16 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { assert_eq!(tys_a.len(), tys_b.len()); // The last field of the tuple has to exist. - let (a_last, a_mid) = if let Some(x) = tys_a.split_last() { + let (&a_last, a_mid) = if let Some(x) = tys_a.split_last() { x } else { return Err(Unimplemented); }; - let b_last = tys_b.last().unwrap(); + let &b_last = tys_b.last().unwrap(); // Check that the source tuple with the target's // last element is equal to the target. - let new_tuple = tcx.mk_tup(a_mid.iter().chain(Some(b_last))); + let new_tuple = tcx.mk_tup(a_mid.iter().cloned().chain(iter::once(b_last))); let InferOk { obligations, .. } = self.infcx.at(&obligation.cause, obligation.param_env) .eq(target, new_tuple) @@ -3089,7 +3144,7 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { obligation.predicate.def_id(), obligation.recursion_depth + 1, a_last, - &[b_last])); + &[b_last.into()])); } _ => bug!() @@ -3294,10 +3349,10 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { fn generator_trait_ref_unnormalized(&mut self, obligation: &TraitObligation<'tcx>, closure_def_id: DefId, - substs: ty::ClosureSubsts<'tcx>) + substs: ty::GeneratorSubsts<'tcx>) -> ty::PolyTraitRef<'tcx> { - let gen_sig = substs.generator_poly_sig(closure_def_id, self.tcx()); + let gen_sig = substs.poly_sig(closure_def_id, self.tcx()); // (1) Feels icky to skip the binder here, but OTOH we know // that the self-type is an generator type and hence is @@ -3356,13 +3411,28 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> { predicate: predicate.value })) }).collect(); + // We are performing deduplication here to avoid exponential blowups // (#38528) from happening, but the real cause of the duplication is // unknown. What we know is that the deduplication avoids exponential - // amount of predicates being propogated when processing deeply nested + // amount of predicates being propagated when processing deeply nested // types. - let mut seen = FxHashSet(); - predicates.retain(|i| seen.insert(i.clone())); + // + // This code is hot enough that it's worth avoiding the allocation + // required for the FxHashSet when possible. Special-casing lengths 0, + // 1 and 2 covers roughly 75--80% of the cases. + if predicates.len() <= 1 { + // No possibility of duplicates. + } else if predicates.len() == 2 { + // Only two elements. Drop the second if they are equal. + if predicates[0] == predicates[1] { + predicates.truncate(1); + } + } else { + // Three or more elements. Use a general deduplication process. + let mut seen = FxHashSet(); + predicates.retain(|i| seen.insert(i.clone())); + } self.infcx().plug_leaks(skol_map, snapshot, predicates) } } @@ -3404,7 +3474,7 @@ impl<'tcx> TraitObligation<'tcx> { impl<'tcx> SelectionCache<'tcx> { pub fn new() -> SelectionCache<'tcx> { SelectionCache { - hashmap: RefCell::new(FxHashMap()) + hashmap: Lock::new(FxHashMap()) } } @@ -3416,7 +3486,7 @@ impl<'tcx> SelectionCache<'tcx> { impl<'tcx> EvaluationCache<'tcx> { pub fn new() -> EvaluationCache<'tcx> { EvaluationCache { - hashmap: RefCell::new(FxHashMap()) + hashmap: Lock::new(FxHashMap()) } } @@ -3470,7 +3540,7 @@ impl<'o,'tcx> fmt::Debug for TraitObligationStack<'o,'tcx> { } } -#[derive(Clone)] +#[derive(Clone, Eq, PartialEq)] pub struct WithDepNode { dep_node: DepNodeIndex, cached_value: T diff --git a/src/librustc/traits/specialize/mod.rs b/src/librustc/traits/specialize/mod.rs index 30b2c55afa194..1ed9ae4392fa7 100644 --- a/src/librustc/traits/specialize/mod.rs +++ b/src/librustc/traits/specialize/mod.rs @@ -17,7 +17,7 @@ //! See the [rustc guide] for a bit more detail on how specialization //! fits together with the rest of the trait machinery. //! -//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-specialization.html +//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/specialization.html use super::{SelectionContext, FulfillmentContext}; use super::util::impl_trait_ref_and_oblig; @@ -129,7 +129,7 @@ pub fn find_associated_item<'a, 'tcx>( let trait_def = tcx.trait_def(trait_def_id); let ancestors = trait_def.ancestors(tcx, impl_data.impl_def_id); - match ancestors.defs(tcx, item.name, item.kind, trait_def_id).next() { + match ancestors.defs(tcx, item.ident, item.kind, trait_def_id).next() { Some(node_item) => { let substs = tcx.infer_ctxt().enter(|infcx| { let param_env = ty::ParamEnv::reveal_all(); @@ -196,6 +196,7 @@ pub(super) fn specializes<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // that this always succeeds. let impl1_trait_ref = match traits::fully_normalize(&infcx, + FulfillmentContext::new(), ObligationCause::dummy(), penv, &impl1_trait_ref) { @@ -437,9 +438,9 @@ fn to_pretty_impl_header(tcx: TyCtxt, impl_def_id: DefId) -> Option { } pretty_predicates.push(p.to_string()); } - for ty in types_without_default_bounds { - pretty_predicates.push(format!("{}: ?Sized", ty)); - } + pretty_predicates.extend( + types_without_default_bounds.iter().map(|ty| format!("{}: ?Sized", ty)) + ); if !pretty_predicates.is_empty() { write!(w, "\n where {}", pretty_predicates.join(", ")).unwrap(); } diff --git a/src/librustc/traits/specialize/specialization_graph.rs b/src/librustc/traits/specialize/specialization_graph.rs index e56a8662f3eb4..f9c0581d3ca37 100644 --- a/src/librustc/traits/specialize/specialization_graph.rs +++ b/src/librustc/traits/specialize/specialization_graph.rs @@ -18,7 +18,7 @@ use traits; use ty::{self, TyCtxt, TypeFoldable}; use ty::fast_reject::{self, SimplifiedType}; use rustc_data_structures::sync::Lrc; -use syntax::ast::Name; +use syntax::ast::Ident; use util::captures::Captures; use util::nodemap::{DefIdMap, FxHashMap}; @@ -73,8 +73,8 @@ enum Inserted { /// The impl was inserted as a new child in this group of children. BecameNewSibling(Option), - /// The impl replaced an existing impl that specializes it. - Replaced(DefId), + /// The impl should replace an existing impl X, because the impl specializes X. + ReplaceChild(DefId), /// The impl is a specialization of an existing child. ShouldRecurseOn(DefId), @@ -94,12 +94,34 @@ impl<'a, 'gcx, 'tcx> Children { impl_def_id: DefId) { let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { + debug!("insert_blindly: impl_def_id={:?} sty={:?}", impl_def_id, sty); self.nonblanket_impls.entry(sty).or_insert(vec![]).push(impl_def_id) } else { + debug!("insert_blindly: impl_def_id={:?} sty=None", impl_def_id); self.blanket_impls.push(impl_def_id) } } + /// Remove an impl from this set of children. Used when replacing + /// an impl with a parent. The impl must be present in the list of + /// children already. + fn remove_existing(&mut self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + impl_def_id: DefId) { + let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap(); + let vec: &mut Vec; + if let Some(sty) = fast_reject::simplify_type(tcx, trait_ref.self_ty(), false) { + debug!("remove_existing: impl_def_id={:?} sty={:?}", impl_def_id, sty); + vec = self.nonblanket_impls.get_mut(&sty).unwrap(); + } else { + debug!("remove_existing: impl_def_id={:?} sty=None", impl_def_id); + vec = &mut self.blanket_impls; + } + + let index = vec.iter().position(|d| *d == impl_def_id).unwrap(); + vec.remove(index); + } + /// Attempt to insert an impl into this set of children, while comparing for /// specialization relationships. fn insert(&mut self, @@ -110,11 +132,22 @@ impl<'a, 'gcx, 'tcx> Children { { let mut last_lint = None; - for slot in match simplified_self { - Some(sty) => self.filtered_mut(sty), - None => self.iter_mut(), + debug!( + "insert(impl_def_id={:?}, simplified_self={:?})", + impl_def_id, + simplified_self, + ); + + for possible_sibling in match simplified_self { + Some(sty) => self.filtered(sty), + None => self.iter(), } { - let possible_sibling = *slot; + debug!( + "insert: impl_def_id={:?}, simplified_self={:?}, possible_sibling={:?}", + impl_def_id, + simplified_self, + possible_sibling, + ); let overlap_error = |overlap: traits::coherence::OverlapResult| { // overlap, but no specialization; error out @@ -168,9 +201,7 @@ impl<'a, 'gcx, 'tcx> Children { debug!("placing as parent of TraitRef {:?}", tcx.impl_trait_ref(possible_sibling).unwrap()); - // possible_sibling specializes the impl - *slot = impl_def_id; - return Ok(Inserted::Replaced(possible_sibling)); + return Ok(Inserted::ReplaceChild(possible_sibling)); } else { if !tcx.impls_are_allowed_to_overlap(impl_def_id, possible_sibling) { traits::overlapping_impls( @@ -193,15 +224,14 @@ impl<'a, 'gcx, 'tcx> Children { Ok(Inserted::BecameNewSibling(last_lint)) } - fn iter_mut(&'a mut self) -> Box + 'a> { - let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter_mut()); - Box::new(self.blanket_impls.iter_mut().chain(nonblanket)) + fn iter(&mut self) -> Box + '_> { + let nonblanket = self.nonblanket_impls.iter_mut().flat_map(|(_, v)| v.iter()); + Box::new(self.blanket_impls.iter().chain(nonblanket).cloned()) } - fn filtered_mut(&'a mut self, sty: SimplifiedType) - -> Box + 'a> { - let nonblanket = self.nonblanket_impls.entry(sty).or_insert(vec![]).iter_mut(); - Box::new(self.blanket_impls.iter_mut().chain(nonblanket)) + fn filtered(&mut self, sty: SimplifiedType) -> Box + '_> { + let nonblanket = self.nonblanket_impls.entry(sty).or_insert(vec![]).iter(); + Box::new(self.blanket_impls.iter().chain(nonblanket).cloned()) } } @@ -259,11 +289,38 @@ impl<'a, 'gcx, 'tcx> Graph { last_lint = opt_lint; break; } - Replaced(new_child) => { - self.parent.insert(new_child, impl_def_id); - let mut new_children = Children::new(); - new_children.insert_blindly(tcx, new_child); - self.children.insert(impl_def_id, new_children); + ReplaceChild(grand_child_to_be) => { + // We currently have + // + // P + // | + // G + // + // and we are inserting the impl N. We want to make it: + // + // P + // | + // N + // | + // G + + // Adjust P's list of children: remove G and then add N. + { + let siblings = self.children + .get_mut(&parent) + .unwrap(); + siblings.remove_existing(tcx, grand_child_to_be); + siblings.insert_blindly(tcx, impl_def_id); + } + + // Set G's parent to N and N's parent to P + self.parent.insert(grand_child_to_be, impl_def_id); + self.parent.insert(impl_def_id, parent); + + // Add G as N's child. + let mut grand_children = Children::new(); + grand_children.insert_blindly(tcx, grand_child_to_be); + self.children.insert(impl_def_id, grand_children); break; } ShouldRecurseOn(new_parent) => { @@ -372,14 +429,24 @@ impl<'a, 'gcx, 'tcx> Ancestors { pub fn defs( self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_item_name: Name, + trait_item_name: Ident, trait_item_kind: ty::AssociatedKind, trait_def_id: DefId, ) -> impl Iterator> + Captures<'gcx> + Captures<'tcx> + 'a { self.flat_map(move |node| { - node.items(tcx).filter(move |impl_item| { - impl_item.kind == trait_item_kind && - tcx.hygienic_eq(impl_item.name, trait_item_name, trait_def_id) + use ty::AssociatedKind::*; + node.items(tcx).filter(move |impl_item| match (trait_item_kind, impl_item.kind) { + | (Const, Const) + | (Method, Method) + | (Type, Type) + | (Type, Existential) + => tcx.hygienic_eq(impl_item.ident, trait_item_name, trait_def_id), + + | (Const, _) + | (Method, _) + | (Type, _) + | (Existential, _) + => false, }).map(move |item| NodeItem { node: node, item: item }) }) } diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index d7e42655bbb5b..39e358803cbe8 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -8,11 +8,12 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use chalk_engine; use rustc_data_structures::accumulate_vec::AccumulateVec; use traits; use traits::project::Normalized; -use ty::{self, Lift, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; +use ty::{self, Lift, TyCtxt}; use std::fmt; use std::rc::Rc; @@ -21,23 +22,24 @@ use std::rc::Rc; impl<'tcx, T: fmt::Debug> fmt::Debug for Normalized<'tcx, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Normalized({:?},{:?})", - self.value, - self.obligations) + write!(f, "Normalized({:?},{:?})", self.value, self.obligations) } } impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { if ty::tls::with(|tcx| tcx.sess.verbose()) { - write!(f, "Obligation(predicate={:?},cause={:?},depth={})", - self.predicate, - self.cause, - self.recursion_depth) + write!( + f, + "Obligation(predicate={:?},cause={:?},depth={})", + self.predicate, self.cause, self.recursion_depth + ) } else { - write!(f, "Obligation(predicate={:?},depth={})", - self.predicate, - self.recursion_depth) + write!( + f, + "Obligation(predicate={:?},depth={})", + self.predicate, self.recursion_depth + ) } } } @@ -45,57 +47,52 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for traits::Obligation<'tcx, O> { impl<'tcx, N: fmt::Debug> fmt::Debug for traits::Vtable<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - super::VtableImpl(ref v) => - write!(f, "{:?}", v), + super::VtableImpl(ref v) => write!(f, "{:?}", v), - super::VtableAutoImpl(ref t) => - write!(f, "{:?}", t), + super::VtableAutoImpl(ref t) => write!(f, "{:?}", t), - super::VtableClosure(ref d) => - write!(f, "{:?}", d), + super::VtableClosure(ref d) => write!(f, "{:?}", d), - super::VtableGenerator(ref d) => - write!(f, "{:?}", d), + super::VtableGenerator(ref d) => write!(f, "{:?}", d), - super::VtableFnPointer(ref d) => - write!(f, "VtableFnPointer({:?})", d), + super::VtableFnPointer(ref d) => write!(f, "VtableFnPointer({:?})", d), - super::VtableObject(ref d) => - write!(f, "{:?}", d), + super::VtableObject(ref d) => write!(f, "{:?}", d), - super::VtableParam(ref n) => - write!(f, "VtableParam({:?})", n), + super::VtableParam(ref n) => write!(f, "VtableParam({:?})", n), - super::VtableBuiltin(ref d) => - write!(f, "{:?}", d) + super::VtableBuiltin(ref d) => write!(f, "{:?}", d), } } } impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableImplData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})", - self.impl_def_id, - self.substs, - self.nested) + write!( + f, + "VtableImpl(impl_def_id={:?}, substs={:?}, nested={:?})", + self.impl_def_id, self.substs, self.nested + ) } } impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableGeneratorData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableGenerator(closure_def_id={:?}, substs={:?}, nested={:?})", - self.closure_def_id, - self.substs, - self.nested) + write!( + f, + "VtableGenerator(generator_def_id={:?}, substs={:?}, nested={:?})", + self.generator_def_id, self.substs, self.nested + ) } } impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableClosureData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})", - self.closure_def_id, - self.substs, - self.nested) + write!( + f, + "VtableClosure(closure_def_id={:?}, substs={:?}, nested={:?})", + self.closure_def_id, self.substs, self.nested + ) } } @@ -107,34 +104,37 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableBuiltinData { impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableAutoImplData { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableAutoImplData(trait_def_id={:?}, nested={:?})", - self.trait_def_id, - self.nested) + write!( + f, + "VtableAutoImplData(trait_def_id={:?}, nested={:?})", + self.trait_def_id, self.nested + ) } } impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableObjectData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableObject(upcast={:?}, vtable_base={}, nested={:?})", - self.upcast_trait_ref, - self.vtable_base, - self.nested) + write!( + f, + "VtableObject(upcast={:?}, vtable_base={}, nested={:?})", + self.upcast_trait_ref, self.vtable_base, self.nested + ) } } impl<'tcx, N: fmt::Debug> fmt::Debug for traits::VtableFnPointerData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "VtableFnPointer(fn_ty={:?}, nested={:?})", - self.fn_ty, - self.nested) + write!( + f, + "VtableFnPointer(fn_ty={:?}, nested={:?})", + self.fn_ty, self.nested + ) } } impl<'tcx> fmt::Debug for traits::FulfillmentError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "FulfillmentError({:?},{:?})", - self.obligation, - self.code) + write!(f, "FulfillmentError({:?},{:?})", self.obligation, self.code) } } @@ -143,9 +143,10 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> { match *self { super::CodeSelectionError(ref e) => write!(f, "{:?}", e), super::CodeProjectionError(ref e) => write!(f, "{:?}", e), - super::CodeSubtypeError(ref a, ref b) => - write!(f, "CodeSubtypeError({:?}, {:?})", a, b), - super::CodeAmbiguity => write!(f, "Ambiguity") + super::CodeSubtypeError(ref a, ref b) => { + write!(f, "CodeSubtypeError({:?}, {:?})", a, b) + } + super::CodeAmbiguity => write!(f, "Ambiguity"), } } } @@ -166,18 +167,15 @@ impl<'a, 'tcx> Lift<'tcx> for traits::SelectionError<'a> { super::Unimplemented => Some(super::Unimplemented), super::OutputTypeParameterMismatch(a, b, ref err) => { tcx.lift(&(a, b)).and_then(|(a, b)| { - tcx.lift(err).map(|err| { - super::OutputTypeParameterMismatch(a, b, err) - }) + tcx.lift(err) + .map(|err| super::OutputTypeParameterMismatch(a, b, err)) }) } - super::TraitNotObjectSafe(def_id) => { - Some(super::TraitNotObjectSafe(def_id)) - } - super::ConstEvalFailure(ref err) => { - tcx.lift(err).map(super::ConstEvalFailure) - } - super::Overflow => bug!() // FIXME: ape ConstEvalFailure? + super::TraitNotObjectSafe(def_id) => Some(super::TraitNotObjectSafe(def_id)), + super::ConstEvalFailure(ref err) => tcx.lift(&**err).map(|err| super::ConstEvalFailure( + err.into(), + )), + super::Overflow => bug!(), // FIXME: ape ConstEvalFailure? } } } @@ -195,16 +193,11 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::ReferenceOutlivesReferent(ty) => { tcx.lift(&ty).map(super::ReferenceOutlivesReferent) } - super::ObjectTypeBound(ty, r) => { - tcx.lift(&ty).and_then(|ty| { - tcx.lift(&r).and_then(|r| { - Some(super::ObjectTypeBound(ty, r)) - }) - }) - } - super::ObjectCastObligation(ty) => { - tcx.lift(&ty).map(super::ObjectCastObligation) - } + super::ObjectTypeBound(ty, r) => tcx.lift(&ty).and_then(|ty| { + tcx.lift(&r) + .and_then(|r| Some(super::ObjectTypeBound(ty, r))) + }), + super::ObjectCastObligation(ty) => tcx.lift(&ty).map(super::ObjectCastObligation), super::AssignmentLhsSized => Some(super::AssignmentLhsSized), super::TupleInitializerSized => Some(super::TupleInitializerSized), super::StructInitializerSized => Some(super::StructInitializerSized), @@ -222,20 +215,20 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::ImplDerivedObligation(ref cause) => { tcx.lift(cause).map(super::ImplDerivedObligation) } - super::CompareImplMethodObligation { item_name, - impl_item_def_id, - trait_item_def_id } => { - Some(super::CompareImplMethodObligation { - item_name, - impl_item_def_id, - trait_item_def_id, - }) - } + super::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + } => Some(super::CompareImplMethodObligation { + item_name, + impl_item_def_id, + trait_item_def_id, + }), super::ExprAssignable => Some(super::ExprAssignable), - super::MatchExpressionArm { arm_span, source } => { - Some(super::MatchExpressionArm { arm_span, - source: source }) - } + super::MatchExpressionArm { arm_span, source } => Some(super::MatchExpressionArm { + arm_span, + source: source, + }), super::IfExpression => Some(super::IfExpression), super::IfExpressionWithNoElse => Some(super::IfExpressionWithNoElse), super::MainFunctionType => Some(super::MainFunctionType), @@ -243,6 +236,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::IntrinsicType => Some(super::IntrinsicType), super::MethodReceiver => Some(super::MethodReceiver), super::BlockTailExpression(id) => Some(super::BlockTailExpression(id)), + super::TrivialBound => Some(super::TrivialBound), } } } @@ -251,12 +245,11 @@ impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { type Lifted = traits::DerivedObligationCause<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { tcx.lift(&self.parent_trait_ref).and_then(|trait_ref| { - tcx.lift(&*self.parent_code).map(|code| { - traits::DerivedObligationCause { + tcx.lift(&*self.parent_code) + .map(|code| traits::DerivedObligationCause { parent_trait_ref: trait_ref, - parent_code: Rc::new(code) - } - }) + parent_code: Rc::new(code), + }) }) } } @@ -264,17 +257,15 @@ impl<'a, 'tcx> Lift<'tcx> for traits::DerivedObligationCause<'a> { impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCause<'a> { type Lifted = traits::ObligationCause<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.code).map(|code| { - traits::ObligationCause { - span: self.span, - body_id: self.body_id, - code, - } + tcx.lift(&self.code).map(|code| traits::ObligationCause { + span: self.span, + body_id: self.body_id, + code, }) } } -// For trans only. +// For codegen only. impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { type Lifted = traits::Vtable<'tcx, ()>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { @@ -282,49 +273,40 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { traits::VtableImpl(traits::VtableImplData { impl_def_id, substs, - nested - }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableImpl(traits::VtableImplData { - impl_def_id, - substs, - nested, - }) + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::VtableImpl(traits::VtableImplData { + impl_def_id, + substs, + nested, }) - } + }), traits::VtableAutoImpl(t) => Some(traits::VtableAutoImpl(t)), traits::VtableGenerator(traits::VtableGeneratorData { - closure_def_id, + generator_def_id, substs, - nested - }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableGenerator(traits::VtableGeneratorData { - closure_def_id: closure_def_id, - substs: substs, - nested: nested - }) + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::VtableGenerator(traits::VtableGeneratorData { + generator_def_id: generator_def_id, + substs: substs, + nested: nested, }) - } + }), traits::VtableClosure(traits::VtableClosureData { closure_def_id, substs, - nested - }) => { - tcx.lift(&substs).map(|substs| { - traits::VtableClosure(traits::VtableClosureData { - closure_def_id, - substs, - nested, - }) + nested, + }) => tcx.lift(&substs).map(|substs| { + traits::VtableClosure(traits::VtableClosureData { + closure_def_id, + substs, + nested, }) - } + }), traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) => { tcx.lift(&fn_ty).map(|fn_ty| { - traits::VtableFnPointer(traits::VtableFnPointerData { - fn_ty, - nested, - }) + traits::VtableFnPointer(traits::VtableFnPointerData { fn_ty, nested }) }) } traits::VtableParam(n) => Some(traits::VtableParam(n)), @@ -332,16 +314,14 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { traits::VtableObject(traits::VtableObjectData { upcast_trait_ref, vtable_base, - nested - }) => { - tcx.lift(&upcast_trait_ref).map(|trait_ref| { - traits::VtableObject(traits::VtableObjectData { - upcast_trait_ref: trait_ref, - vtable_base, - nested, - }) + nested, + }) => tcx.lift(&upcast_trait_ref).map(|trait_ref| { + traits::VtableObject(traits::VtableObjectData { + upcast_trait_ref: trait_ref, + vtable_base, + nested, }) - } + }), } } } @@ -349,8 +329,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> { /////////////////////////////////////////////////////////////////////////// // TypeFoldable implementations. -impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> -{ +impl<'tcx, O: TypeFoldable<'tcx>> TypeFoldable<'tcx> for traits::Obligation<'tcx, O> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { traits::Obligation { cause: self.cause.clone(), @@ -373,7 +352,7 @@ BraceStructTypeFoldableImpl! { BraceStructTypeFoldableImpl! { impl<'tcx, N> TypeFoldable<'tcx> for traits::VtableGeneratorData<'tcx, N> { - closure_def_id, substs, nested + generator_def_id, substs, nested } where N: TypeFoldable<'tcx> } @@ -428,13 +407,37 @@ BraceStructTypeFoldableImpl! { } where T: TypeFoldable<'tcx> } -impl<'tcx> fmt::Display for traits::WhereClauseAtom<'tcx> { +impl<'tcx> fmt::Display for traits::WhereClause<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - use traits::WhereClauseAtom::*; + use traits::WhereClause::*; match self { Implemented(trait_ref) => write!(fmt, "Implemented({})", trait_ref), ProjectionEq(projection) => write!(fmt, "ProjectionEq({})", projection), + RegionOutlives(predicate) => write!(fmt, "RegionOutlives({})", predicate), + TypeOutlives(predicate) => write!(fmt, "TypeOutlives({})", predicate), + } + } +} + +impl<'tcx> fmt::Display for traits::WellFormed<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use traits::WellFormed::*; + + match self { + Trait(trait_ref) => write!(fmt, "WellFormed({})", trait_ref), + Ty(ty) => write!(fmt, "WellFormed({})", ty), + } + } +} + +impl<'tcx> fmt::Display for traits::FromEnv<'tcx> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + use traits::FromEnv::*; + + match self { + Trait(trait_ref) => write!(fmt, "FromEnv({})", trait_ref), + Ty(ty) => write!(fmt, "FromEnv({})", ty), } } } @@ -442,19 +445,12 @@ impl<'tcx> fmt::Display for traits::WhereClauseAtom<'tcx> { impl<'tcx> fmt::Display for traits::DomainGoal<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { use traits::DomainGoal::*; - use traits::WhereClauseAtom::*; match self { Holds(wc) => write!(fmt, "{}", wc), - WellFormed(Implemented(trait_ref)) => write!(fmt, "WellFormed({})", trait_ref), - WellFormed(ProjectionEq(projection)) => write!(fmt, "WellFormed({})", projection), - FromEnv(Implemented(trait_ref)) => write!(fmt, "FromEnv({})", trait_ref), - FromEnv(ProjectionEq(projection)) => write!(fmt, "FromEnv({})", projection), - WellFormedTy(ty) => write!(fmt, "WellFormed({})", ty), + WellFormed(wf) => write!(fmt, "{}", wf), + FromEnv(from_env) => write!(fmt, "{}", from_env), Normalize(projection) => write!(fmt, "Normalize({})", projection), - FromEnvTy(ty) => write!(fmt, "FromEnv({})", ty), - RegionOutlives(predicate) => write!(fmt, "RegionOutlives({})", predicate), - TypeOutlives(predicate) => write!(fmt, "TypeOutlives({})", predicate), } } } @@ -529,26 +525,74 @@ impl<'tcx> fmt::Display for traits::Clause<'tcx> { } EnumTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for traits::WhereClauseAtom<'tcx> { - (traits::WhereClauseAtom::Implemented)(trait_ref), - (traits::WhereClauseAtom::ProjectionEq)(projection), + impl<'tcx> TypeFoldable<'tcx> for traits::WhereClause<'tcx> { + (traits::WhereClause::Implemented)(trait_ref), + (traits::WhereClause::ProjectionEq)(projection), + (traits::WhereClause::TypeOutlives)(ty_outlives), + (traits::WhereClause::RegionOutlives)(region_outlives), + } +} + +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for traits::WhereClause<'a> { + type Lifted = traits::WhereClause<'tcx>; + (traits::WhereClause::Implemented)(trait_ref), + (traits::WhereClause::ProjectionEq)(projection), + (traits::WhereClause::TypeOutlives)(ty_outlives), + (traits::WhereClause::RegionOutlives)(region_outlives), + } +} + +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::WellFormed<'tcx> { + (traits::WellFormed::Trait)(trait_ref), + (traits::WellFormed::Ty)(ty), + } +} + +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for traits::WellFormed<'a> { + type Lifted = traits::WellFormed<'tcx>; + (traits::WellFormed::Trait)(trait_ref), + (traits::WellFormed::Ty)(ty), + } +} + +EnumTypeFoldableImpl! { + impl<'tcx> TypeFoldable<'tcx> for traits::FromEnv<'tcx> { + (traits::FromEnv::Trait)(trait_ref), + (traits::FromEnv::Ty)(ty), + } +} + +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for traits::FromEnv<'a> { + type Lifted = traits::FromEnv<'tcx>; + (traits::FromEnv::Trait)(trait_ref), + (traits::FromEnv::Ty)(ty), } } EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for traits::DomainGoal<'tcx> { (traits::DomainGoal::Holds)(wc), - (traits::DomainGoal::WellFormed)(wc), - (traits::DomainGoal::FromEnv)(wc), - (traits::DomainGoal::WellFormedTy)(ty), + (traits::DomainGoal::WellFormed)(wf), + (traits::DomainGoal::FromEnv)(from_env), (traits::DomainGoal::Normalize)(projection), - (traits::DomainGoal::FromEnvTy)(ty), - (traits::DomainGoal::RegionOutlives)(predicate), - (traits::DomainGoal::TypeOutlives)(predicate), } } -CloneTypeFoldableImpls! { +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for traits::DomainGoal<'a> { + type Lifted = traits::DomainGoal<'tcx>; + (traits::DomainGoal::Holds)(wc), + (traits::DomainGoal::WellFormed)(wf), + (traits::DomainGoal::FromEnv)(from_env), + (traits::DomainGoal::Normalize)(projection), + } +} + +CloneTypeFoldableAndLiftImpls! { traits::QuantifierKind, } @@ -563,9 +607,23 @@ EnumTypeFoldableImpl! { } } +EnumLiftImpl! { + impl<'a, 'tcx> Lift<'tcx> for traits::Goal<'a> { + type Lifted = traits::Goal<'tcx>; + (traits::Goal::Implies)(hypotheses, goal), + (traits::Goal::And)(goal1, goal2), + (traits::Goal::Not)(goal), + (traits::Goal::DomainGoal)(domain_goal), + (traits::Goal::Quantified)(kind, goal), + (traits::Goal::CannotProve), + } +} + impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + let v = self.iter() + .map(|t| t.fold_with(folder)) + .collect::>(); folder.tcx().intern_goals(&v) } @@ -601,7 +659,9 @@ EnumTypeFoldableImpl! { impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); + let v = self.iter() + .map(|t| t.fold_with(folder)) + .collect::>(); folder.tcx().intern_clauses(&v) } @@ -609,3 +669,59 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::Slice> { self.iter().any(|t| t.visit_with(visitor)) } } + +impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::ExClause +where + C: traits::ExClauseFold<'tcx>, + C::Substitution: Clone, + C::RegionConstraint: Clone, +{ + fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { + ::fold_ex_clause_with( + self, + folder, + ) + } + + fn super_visit_with>(&self, visitor: &mut V) -> bool { + ::visit_ex_clause_with( + self, + visitor, + ) + } +} + +impl<'tcx, C> Lift<'tcx> for chalk_engine::ExClause +where + C: chalk_engine::context::Context + Clone, + C: traits::ExClauseLift<'tcx>, +{ + type Lifted = C::LiftedExClause; + + fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option { + ::lift_ex_clause_to_tcx(self, tcx) + } +} + +EnumTypeFoldableImpl! { + impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::DelayedLiteral { + (chalk_engine::DelayedLiteral::CannotProve)(a), + (chalk_engine::DelayedLiteral::Negative)(a), + (chalk_engine::DelayedLiteral::Positive)(a, b), + } where + C: chalk_engine::context::Context + Clone, + C::CanonicalConstrainedSubst: TypeFoldable<'tcx>, +} + +EnumTypeFoldableImpl! { + impl<'tcx, C> TypeFoldable<'tcx> for chalk_engine::Literal { + (chalk_engine::Literal::Negative)(a), + (chalk_engine::Literal::Positive)(a), + } where + C: chalk_engine::context::Context + Clone, + C::GoalInEnvironment: Clone + TypeFoldable<'tcx>, +} + +CloneTypeFoldableAndLiftImpls! { + chalk_engine::TableIndex, +} diff --git a/src/librustc/traits/trans/mod.rs b/src/librustc/traits/trans/mod.rs deleted file mode 100644 index 31e851126d76a..0000000000000 --- a/src/librustc/traits/trans/mod.rs +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// This file contains various trait resolution methods used by trans. -// They all assume regions can be erased and monomorphic types. It -// seems likely that they should eventually be merged into more -// general routines. - -use dep_graph::{DepKind, DepTrackingMapConfig}; -use std::marker::PhantomData; -use syntax_pos::DUMMY_SP; -use infer::InferCtxt; -use syntax_pos::Span; -use traits::{FulfillmentContext, Obligation, ObligationCause, SelectionContext, - TraitEngine, Vtable}; -use ty::{self, Ty, TyCtxt}; -use ty::subst::{Subst, Substs}; -use ty::fold::TypeFoldable; - -/// Attempts to resolve an obligation to a vtable.. The result is -/// a shallow vtable resolution -- meaning that we do not -/// (necessarily) resolve all nested obligations on the impl. Note -/// that type check should guarantee to us that all nested -/// obligations *could be* resolved if we wanted to. -/// Assumes that this is run after the entire crate has been successfully type-checked. -pub fn trans_fulfill_obligation<'a, 'tcx>(ty: TyCtxt<'a, 'tcx, 'tcx>, - (param_env, trait_ref): - (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) - -> Vtable<'tcx, ()> -{ - // Remove any references to regions; this helps improve caching. - let trait_ref = ty.erase_regions(&trait_ref); - - debug!("trans::fulfill_obligation(trait_ref={:?}, def_id={:?})", - (param_env, trait_ref), trait_ref.def_id()); - - // Do the initial selection for the obligation. This yields the - // shallow result we are looking for -- that is, what specific impl. - ty.infer_ctxt().enter(|infcx| { - let mut selcx = SelectionContext::new(&infcx); - - let obligation_cause = ObligationCause::dummy(); - let obligation = Obligation::new(obligation_cause, - param_env, - trait_ref.to_poly_trait_predicate()); - - let selection = match selcx.select(&obligation) { - Ok(Some(selection)) => selection, - Ok(None) => { - // Ambiguity can happen when monomorphizing during trans - // expands to some humongo type that never occurred - // statically -- this humongo type can then overflow, - // leading to an ambiguous result. So report this as an - // overflow bug, since I believe this is the only case - // where ambiguity can result. - bug!("Encountered ambiguity selecting `{:?}` during trans, \ - presuming due to overflow", - trait_ref) - } - Err(e) => { - bug!("Encountered error `{:?}` selecting `{:?}` during trans", - e, trait_ref) - } - }; - - debug!("fulfill_obligation: selection={:?}", selection); - - // Currently, we use a fulfillment context to completely resolve - // all nested obligations. This is because they can inform the - // inference of the impl's type parameters. - let mut fulfill_cx = FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - debug!("fulfill_obligation: register_predicate_obligation {:?}", predicate); - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - let vtable = infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable); - - info!("Cache miss: {:?} => {:?}", trait_ref, vtable); - vtable - }) -} - -impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { - /// Monomorphizes a type from the AST by first applying the - /// in-scope substitutions and then normalizing any associated - /// types. - pub fn subst_and_normalize_erasing_regions( - self, - param_substs: &Substs<'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T - ) -> T - where - T: TypeFoldable<'tcx>, - { - debug!( - "subst_and_normalize_erasing_regions(\ - param_substs={:?}, \ - value={:?}, \ - param_env={:?})", - param_substs, - value, - param_env, - ); - let substituted = value.subst(self, param_substs); - self.normalize_erasing_regions(param_env, substituted) - } -} - -// Implement DepTrackingMapConfig for `trait_cache` -pub struct TraitSelectionCache<'tcx> { - data: PhantomData<&'tcx ()> -} - -impl<'tcx> DepTrackingMapConfig for TraitSelectionCache<'tcx> { - type Key = (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>); - type Value = Vtable<'tcx, ()>; - fn to_dep_kind() -> DepKind { - DepKind::TraitSelect - } -} - -// # Global Cache - -pub struct ProjectionCache<'gcx> { - data: PhantomData<&'gcx ()> -} - -impl<'gcx> DepTrackingMapConfig for ProjectionCache<'gcx> { - type Key = Ty<'gcx>; - type Value = Ty<'gcx>; - fn to_dep_kind() -> DepKind { - DepKind::TraitSelect - } -} - -impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { - /// Finishes processes any obligations that remain in the - /// fulfillment context, and then returns the result with all type - /// variables removed and regions erased. Because this is intended - /// for use after type-check has completed, if any errors occur, - /// it will panic. It is used during normalization and other cases - /// where processing the obligations in `fulfill_cx` may cause - /// type inference variables that appear in `result` to be - /// unified, and hence we need to process those obligations to get - /// the complete picture of the type. - fn drain_fulfillment_cx_or_panic(&self, - span: Span, - fulfill_cx: &mut FulfillmentContext<'tcx>, - result: &T) - -> T::Lifted - where T: TypeFoldable<'tcx> + ty::Lift<'gcx> - { - debug!("drain_fulfillment_cx_or_panic()"); - - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(self) { - Ok(()) => { } - Err(errors) => { - span_bug!(span, "Encountered errors `{:?}` resolving bounds after type-checking", - errors); - } - } - - let result = self.resolve_type_vars_if_possible(result); - let result = self.tcx.erase_regions(&result); - - match self.tcx.lift_to_global(&result) { - Some(result) => result, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}`", result); - } - } - } -} diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs index 3c62f04afc56e..875c7199f6d11 100644 --- a/src/librustc/traits/util.rs +++ b/src/librustc/traits/util.rs @@ -9,7 +9,7 @@ // except according to those terms. use hir::def_id::DefId; -use ty::subst::{Subst, Substs}; +use ty::subst::{Kind, Subst, Substs}; use ty::{self, Ty, TyCtxt, ToPredicate, ToPolyTraitRef}; use ty::outlives::Component; use util::nodemap::FxHashSet; @@ -213,7 +213,7 @@ impl<'cx, 'gcx, 'tcx> Elaborator<'cx, 'gcx, 'tcx> { }, Component::Param(p) => { - let ty = tcx.mk_param(p.idx, p.name); + let ty = tcx.mk_ty_param(p.idx, p.name); Some(ty::Predicate::TypeOutlives( ty::Binder::dummy(ty::OutlivesPredicate(ty, r_min)))) }, @@ -430,13 +430,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { cause: ObligationCause<'tcx>, trait_def_id: DefId, recursion_depth: usize, - param_ty: Ty<'tcx>, - ty_params: &[Ty<'tcx>]) + self_ty: Ty<'tcx>, + params: &[Kind<'tcx>]) -> PredicateObligation<'tcx> { let trait_ref = ty::TraitRef { def_id: trait_def_id, - substs: self.mk_substs_trait(param_ty, ty_params) + substs: self.mk_substs_trait(self_ty, params) }; predicate_for_trait_ref(cause, param_env, trait_ref, recursion_depth) } @@ -512,7 +512,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }; let trait_ref = ty::TraitRef { def_id: fn_trait_def_id, - substs: self.mk_substs_trait(self_ty, &[arguments_tuple]), + substs: self.mk_substs_trait(self_ty, &[arguments_tuple.into()]), }; ty::Binder::bind((trait_ref, sig.skip_binder().output())) } @@ -534,7 +534,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { match self.hir.as_local_node_id(node_item_def_id) { Some(node_id) => { let item = self.hir.expect_item(node_id); - if let hir::ItemImpl(_, _, defaultness, ..) = item.node { + if let hir::ItemKind::Impl(_, _, defaultness, ..) = item.node { defaultness.is_default() } else { false diff --git a/src/librustc/ty/adjustment.rs b/src/librustc/ty/adjustment.rs index a0c31e8b50923..3263da8fda365 100644 --- a/src/librustc/ty/adjustment.rs +++ b/src/librustc/ty/adjustment.rs @@ -91,8 +91,8 @@ pub enum Adjust<'tcx> { /// pointers. We don't store the details of how the transform is /// done (in fact, we don't know that, because it might depend on /// the precise type parameters). We just store the target - /// type. Trans figures out what has to be done at monomorphization - /// time based on the precise source/target type at hand. + /// type. Codegen backends and miri figure out what has to be done + /// based on the precise source/target type at hand. Unsize, } diff --git a/src/librustc/ty/binding.rs b/src/librustc/ty/binding.rs index 3db61b76cc55c..971b3c3d14aeb 100644 --- a/src/librustc/ty/binding.rs +++ b/src/librustc/ty/binding.rs @@ -18,6 +18,8 @@ pub enum BindingMode { BindByValue(Mutability), } +CloneTypeFoldableAndLiftImpls! { BindingMode, } + impl BindingMode { pub fn convert(ba: BindingAnnotation) -> BindingMode { match ba { diff --git a/src/librustc/ty/cast.rs b/src/librustc/ty/cast.rs index 3ba79d91964ab..7593d4ed24e76 100644 --- a/src/librustc/ty/cast.rs +++ b/src/librustc/ty/cast.rs @@ -9,7 +9,7 @@ // except according to those terms. // Helpers for handling cast expressions, used in both -// typeck and trans. +// typeck and codegen. use ty::{self, Ty}; @@ -36,9 +36,9 @@ pub enum CastTy<'tcx> { /// Function Pointers FnPtr, /// Raw pointers - Ptr(&'tcx ty::TypeAndMut<'tcx>), + Ptr(ty::TypeAndMut<'tcx>), /// References - RPtr(&'tcx ty::TypeAndMut<'tcx>), + RPtr(ty::TypeAndMut<'tcx>), } /// Cast Kind. See RFC 401 (or librustc_typeck/check/cast.rs) @@ -69,8 +69,8 @@ impl<'tcx> CastTy<'tcx> { ty::TyFloat(_) => Some(CastTy::Float), ty::TyAdt(d,_) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), - ty::TyRawPtr(ref mt) => Some(CastTy::Ptr(mt)), - ty::TyRef(_, ref mt) => Some(CastTy::RPtr(mt)), + ty::TyRawPtr(mt) => Some(CastTy::Ptr(mt)), + ty::TyRef(_, ty, mutbl) => Some(CastTy::RPtr(ty::TypeAndMut { ty, mutbl })), ty::TyFnPtr(..) => Some(CastTy::FnPtr), _ => None, } diff --git a/src/librustc/ty/codec.rs b/src/librustc/ty/codec.rs index 4e15f0711a5aa..967a3324cfb2a 100644 --- a/src/librustc/ty/codec.rs +++ b/src/librustc/ty/codec.rs @@ -24,6 +24,7 @@ use std::hash::Hash; use std::intrinsics; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; +use mir::interpret::Allocation; /// The shorthand encoding uses an enum's variant index `usize` /// and is offset by this value so it never matches a real variant. @@ -53,7 +54,7 @@ pub trait TyEncoder: Encoder { fn position(&self) -> usize; } -impl<'buf> TyEncoder for opaque::Encoder<'buf> { +impl TyEncoder for opaque::Encoder { #[inline] fn position(&self) -> usize { self.position() @@ -262,6 +263,15 @@ pub fn decode_const<'a, 'tcx, D>(decoder: &mut D) Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?)) } +#[inline] +pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D) + -> Result<&'tcx Allocation, D::Error> + where D: TyDecoder<'a, 'tcx>, + 'tcx: 'a, +{ + Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?)) +} + #[macro_export] macro_rules! __impl_decoder_methods { ($($name:ident -> $ty:ty;)*) => { @@ -393,6 +403,15 @@ macro_rules! implement_ty_decoder { decode_const(self) } } + + impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation> + for $DecoderName<$($typaram),*> { + fn specialized_decode( + &mut self + ) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> { + decode_allocation(self) + } + } } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 3d154e43a9ae1..98568f860a4fd 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -26,28 +26,27 @@ use lint::{self, Lint}; use ich::{StableHashingContext, NodeIdHashingMode}; use infer::canonical::{CanonicalVarInfo, CanonicalVarInfos}; use infer::outlives::free_region_map::FreeRegionMap; -use middle::const_val::ConstVal; -use middle::cstore::{CrateStore, LinkMeta}; +use middle::cstore::{CrateStoreDyn, LinkMeta}; use middle::cstore::EncodedMetadata; use middle::lang_items; use middle::resolve_lifetime::{self, ObjectLifetimeDefault}; use middle::stability; use mir::{self, Mir, interpret}; -use mir::interpret::{Value, PrimVal}; +use mir::interpret::Allocation; use ty::subst::{Kind, Substs, Subst}; use ty::ReprOptions; -use ty::Instance; use traits; use traits::{Clause, Clauses, Goal, Goals}; use ty::{self, Ty, TypeAndMut}; use ty::{TyS, TypeVariants, Slice}; -use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorInterior, Region, Const}; +use ty::{AdtKind, AdtDef, ClosureSubsts, GeneratorSubsts, Region, Const}; use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate, Predicate}; use ty::RegionKind; use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid}; use ty::TypeVariants::*; +use ty::GenericParamDefKind; use ty::layout::{LayoutDetails, TargetDataLayout}; -use ty::maps; +use ty::query; use ty::steal::Steal; use ty::BindingMode; use ty::CanonicalTy; @@ -59,12 +58,13 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap, StableVec}; use arena::{TypedArena, SyncDroplessArena}; use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::sync::{Lrc, Lock}; +use rustc_data_structures::sync::{self, Lrc, Lock, WorkerLocal}; use std::any::Any; use std::borrow::Borrow; use std::cmp::Ordering; use std::collections::hash_map::{self, Entry}; use std::hash::{Hash, Hasher}; +use std::fmt; use std::mem; use std::ops::Deref; use std::iter; @@ -74,6 +74,7 @@ use rustc_target::spec::abi; use syntax::ast::{self, NodeId}; use syntax::attr; use syntax::codemap::MultiSpan; +use syntax::edition::Edition; use syntax::feature_gate; use syntax::symbol::{Symbol, keywords, InternedString}; use syntax_pos::Span; @@ -81,14 +82,14 @@ use syntax_pos::Span; use hir; pub struct AllArenas<'tcx> { - pub global: GlobalArenas<'tcx>, + pub global: WorkerLocal>, pub interner: SyncDroplessArena, } impl<'tcx> AllArenas<'tcx> { pub fn new() -> Self { AllArenas { - global: GlobalArenas::new(), + global: WorkerLocal::new(|_| GlobalArenas::new()), interner: SyncDroplessArena::new(), } } @@ -162,66 +163,65 @@ impl<'gcx: 'tcx, 'tcx> CtxtInterners<'tcx> { } } - /// Intern a type. global_interners is Some only if this is - /// a local interner and global_interners is its counterpart. - fn intern_ty(&self, st: TypeVariants<'tcx>, - global_interners: Option<&CtxtInterners<'gcx>>) - -> Ty<'tcx> { - let ty = { - let mut interner = self.type_.borrow_mut(); + /// Intern a type + fn intern_ty( + local: &CtxtInterners<'tcx>, + global: &CtxtInterners<'gcx>, + st: TypeVariants<'tcx> + ) -> Ty<'tcx> { + let flags = super::flags::FlagComputation::for_sty(&st); + + // HACK(eddyb) Depend on flags being accurate to + // determine that all contents are in the global tcx. + // See comments on Lift for why we can't use that. + if flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) { + let mut interner = local.type_.borrow_mut(); if let Some(&Interned(ty)) = interner.get(&st) { return ty; } - let global_interner = global_interners.map(|interners| { - (interners.type_.borrow_mut(), &interners.arena) - }); - if let Some((ref type_, _)) = global_interner { - if let Some(&Interned(ty)) = type_.get(&st) { - return ty; - } - } - let flags = super::flags::FlagComputation::for_sty(&st); let ty_struct = TyS { sty: st, flags: flags.flags, - region_depth: flags.depth, + outer_exclusive_binder: flags.outer_exclusive_binder, }; - // HACK(eddyb) Depend on flags being accurate to - // determine that all contents are in the global tcx. - // See comments on Lift for why we can't use that. - if !flags.flags.intersects(ty::TypeFlags::KEEP_IN_LOCAL_TCX) { - if let Some((mut type_, arena)) = global_interner { - let ty_struct: TyS<'gcx> = unsafe { - mem::transmute(ty_struct) - }; - let ty: Ty<'gcx> = arena.alloc(ty_struct); - type_.insert(Interned(ty)); - return ty; - } - } else { - // Make sure we don't end up with inference - // types/regions in the global tcx. - if global_interner.is_none() { - drop(interner); - bug!("Attempted to intern `{:?}` which contains \ - inference types/regions in the global type context", - &ty_struct); - } + // Make sure we don't end up with inference + // types/regions in the global interner + if local as *const _ as usize == global as *const _ as usize { + bug!("Attempted to intern `{:?}` which contains \ + inference types/regions in the global type context", + &ty_struct); } // Don't be &mut TyS. - let ty: Ty<'tcx> = self.arena.alloc(ty_struct); + let ty: Ty<'tcx> = local.arena.alloc(ty_struct); interner.insert(Interned(ty)); ty - }; + } else { + let mut interner = global.type_.borrow_mut(); + if let Some(&Interned(ty)) = interner.get(&st) { + return ty; + } - debug!("Interned type: {:?} Pointer: {:?}", - ty, ty as *const TyS); - ty - } + let ty_struct = TyS { + sty: st, + flags: flags.flags, + outer_exclusive_binder: flags.outer_exclusive_binder, + }; + // This is safe because all the types the ty_struct can point to + // already is in the global arena + let ty_struct: TyS<'gcx> = unsafe { + mem::transmute(ty_struct) + }; + + // Don't be &mut TyS. + let ty: Ty<'gcx> = global.arena.alloc(ty_struct); + interner.insert(Interned(ty)); + ty + } + } } pub struct CommonTypes<'tcx> { @@ -268,9 +268,7 @@ fn validate_hir_id_for_typeck_tables(local_id_root: Option, if let Some(local_id_root) = local_id_root { if hir_id.owner != local_id_root.index { ty::tls::with(|tcx| { - let node_id = tcx.hir - .definitions() - .find_node_for_hir_id(hir_id); + let node_id = tcx.hir.hir_to_node_id(hir_id); bug!("node {} with HirId::owner {:?} cannot be placed in \ TypeckTables with local_id_root {:?}", @@ -403,7 +401,7 @@ pub struct TypeckTables<'tcx> { /// For each fn, records the "liberated" types of its arguments /// and return type. Liberated means that all bound regions /// (including late-bound regions) are replaced with free - /// equivalents. This table is not used in trans (since regions + /// equivalents. This table is not used in codegen (since regions /// are erased there) and hence is not serialized to metadata. liberated_fn_sigs: ItemLocalMap>, @@ -431,6 +429,10 @@ pub struct TypeckTables<'tcx> { /// its where clauses and parameter types. These are then /// read-again by borrowck. pub free_region_map: FreeRegionMap<'tcx>, + + /// All the existential types that are restricted to concrete types + /// by this function + pub concrete_existential_types: FxHashMap>, } impl<'tcx> TypeckTables<'tcx> { @@ -453,6 +455,7 @@ impl<'tcx> TypeckTables<'tcx> { used_trait_imports: Lrc::new(DefIdSet()), tainted_by_errors: false, free_region_map: FreeRegionMap::new(), + concrete_existential_types: FxHashMap(), } } @@ -529,7 +532,7 @@ impl<'tcx> TypeckTables<'tcx> { None => { bug!("node_id_to_type: no type for node `{}`", tls::with(|tcx| { - let id = tcx.hir.definitions().find_node_for_hir_id(id); + let id = tcx.hir.hir_to_node_id(id); tcx.hir.node_to_string(id) })) } @@ -625,7 +628,7 @@ impl<'tcx> TypeckTables<'tcx> { pub fn is_method_call(&self, expr: &hir::Expr) -> bool { // Only paths and method calls/overloaded operators have // entries in type_dependent_defs, ignore the former here. - if let hir::ExprPath(_) = expr.node { + if let hir::ExprKind::Path(_) = expr.node { return false; } @@ -750,6 +753,7 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { ref used_trait_imports, tainted_by_errors, ref free_region_map, + ref concrete_existential_types, } = *self; hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { @@ -790,13 +794,20 @@ impl<'a, 'gcx> HashStable> for TypeckTables<'gcx> { used_trait_imports.hash_stable(hcx, hasher); tainted_by_errors.hash_stable(hcx, hasher); free_region_map.hash_stable(hcx, hasher); + concrete_existential_types.hash_stable(hcx, hasher); }) } } impl<'tcx> CommonTypes<'tcx> { fn new(interners: &CtxtInterners<'tcx>) -> CommonTypes<'tcx> { - let mk = |sty| interners.intern_ty(sty, None); + // Ensure our type representation does not grow + #[cfg(target_pointer_width = "64")] + assert!(mem::size_of::() <= 24); + #[cfg(target_pointer_width = "64")] + assert!(mem::size_of::() <= 32); + + let mk = |sty| CtxtInterners::intern_ty(interners, interners, sty); let mk_region = |r| { if let Some(r) = interners.region.borrow().get(&r) { return r.0; @@ -839,7 +850,7 @@ impl<'tcx> CommonTypes<'tcx> { /// /// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/ty.html #[derive(Copy, Clone)] -pub struct TyCtxt<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { +pub struct TyCtxt<'a, 'gcx: 'tcx, 'tcx: 'a> { gcx: &'a GlobalCtxt<'gcx>, interners: &'a CtxtInterners<'tcx> } @@ -852,20 +863,15 @@ impl<'a, 'gcx, 'tcx> Deref for TyCtxt<'a, 'gcx, 'tcx> { } pub struct GlobalCtxt<'tcx> { - global_arenas: &'tcx GlobalArenas<'tcx>, + global_arenas: &'tcx WorkerLocal>, global_interners: CtxtInterners<'tcx>, - cstore: &'tcx dyn CrateStore, + cstore: &'tcx CrateStoreDyn, pub sess: &'tcx Session, pub dep_graph: DepGraph, - /// This provides access to the incr. comp. on-disk cache for query results. - /// Do not access this directly. It is only meant to be used by - /// `DepGraph::try_mark_green()` and the query infrastructure in `ty::maps`. - pub(crate) on_disk_query_result_cache: maps::OnDiskCache<'tcx>, - /// Common types, pre-interned for your convenience. pub types: CommonTypes<'tcx>, @@ -884,7 +890,7 @@ pub struct GlobalCtxt<'tcx> { /// as well as all upstream crates. Only populated in incremental mode. pub def_path_hash_to_def_id: Option>, - pub maps: maps::Maps<'tcx>, + pub(crate) queries: query::Queries<'tcx>, // Records the free variables refrenced by every closure // expression. Do not track deps for this, just recompute it from @@ -916,14 +922,17 @@ pub struct GlobalCtxt<'tcx> { stability_interner: Lock>, - pub interpret_interner: InterpretInterner<'tcx>, + /// Stores the value of constants (and deduplicates the actual memory) + allocation_interner: Lock>, + + pub alloc_map: Lock>, layout_interner: Lock>, /// A general purpose channel to throw data out the back towards LLVM worker /// threads. /// - /// This is intended to only get used during the trans phase of the compiler + /// This is intended to only get used during the codegen phase of the compiler /// when satisfying the query for a particular codegen unit. Internally in /// the query it'll send data along this channel to get processed later. pub tx_to_llvm_workers: Lock>>, @@ -931,117 +940,6 @@ pub struct GlobalCtxt<'tcx> { output_filenames: Arc, } -/// Everything needed to efficiently work with interned allocations -#[derive(Debug, Default)] -pub struct InterpretInterner<'tcx> { - inner: Lock>, -} - -#[derive(Debug, Default)] -struct InterpretInternerInner<'tcx> { - /// Stores the value of constants (and deduplicates the actual memory) - allocs: FxHashSet<&'tcx interpret::Allocation>, - - /// Allows obtaining function instance handles via a unique identifier - functions: FxHashMap>, - - /// Inverse map of `interpret_functions`. - /// Used so we don't allocate a new pointer every time we need one - function_cache: FxHashMap, interpret::AllocId>, - - /// Allows obtaining const allocs via a unique identifier - alloc_by_id: FxHashMap, - - /// Allows obtaining static def ids via a unique id - statics: FxHashMap, - - /// The AllocId to assign to the next new regular allocation. - /// Always incremented, never gets smaller. - next_id: interpret::AllocId, - - /// Inverse map of `statics` - /// Used so we don't allocate a new pointer every time we need one - static_cache: FxHashMap, - - /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate - /// allocations for string and bytestring literals. - literal_alloc_cache: FxHashMap, interpret::AllocId>, -} - -impl<'tcx> InterpretInterner<'tcx> { - pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> interpret::AllocId { - if let Some(&alloc_id) = self.inner.borrow().function_cache.get(&instance) { - return alloc_id; - } - let id = self.reserve(); - debug!("creating fn ptr: {}", id); - let mut inner = self.inner.borrow_mut(); - inner.functions.insert(id, instance); - inner.function_cache.insert(instance, id); - id - } - - pub fn get_fn( - &self, - id: interpret::AllocId, - ) -> Option> { - self.inner.borrow().functions.get(&id).cloned() - } - - pub fn get_alloc( - &self, - id: interpret::AllocId, - ) -> Option<&'tcx interpret::Allocation> { - self.inner.borrow().alloc_by_id.get(&id).cloned() - } - - pub fn cache_static( - &self, - static_id: DefId, - ) -> interpret::AllocId { - if let Some(alloc_id) = self.inner.borrow().static_cache.get(&static_id).cloned() { - return alloc_id; - } - let alloc_id = self.reserve(); - let mut inner = self.inner.borrow_mut(); - inner.static_cache.insert(static_id, alloc_id); - inner.statics.insert(alloc_id, static_id); - alloc_id - } - - pub fn get_static( - &self, - ptr: interpret::AllocId, - ) -> Option { - self.inner.borrow().statics.get(&ptr).cloned() - } - - pub fn intern_at_reserved( - &self, - id: interpret::AllocId, - alloc: &'tcx interpret::Allocation, - ) { - if let Some(old) = self.inner.borrow_mut().alloc_by_id.insert(id, alloc) { - bug!("tried to intern allocation at {}, but was already existing as {:#?}", id, old); - } - } - - /// obtains a new allocation ID that can be referenced but does not - /// yet have an allocation backing it. - pub fn reserve( - &self, - ) -> interpret::AllocId { - let mut inner = self.inner.borrow_mut(); - let next = inner.next_id; - inner.next_id.0 = inner.next_id.0 - .checked_add(1) - .expect("You overflowed a u64 by incrementing by 1... \ - You've just earned yourself a free drink if we ever meet. \ - Seriously, how did you do that?!"); - next - } -} - impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Get the global TyCtxt. #[inline] @@ -1110,9 +1008,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn intern_const_alloc( self, - alloc: interpret::Allocation, - ) -> &'gcx interpret::Allocation { - let allocs = &mut self.interpret_interner.inner.borrow_mut().allocs; + alloc: Allocation, + ) -> &'gcx Allocation { + let allocs = &mut self.allocation_interner.borrow_mut(); if let Some(alloc) = allocs.get(&alloc) { return alloc; } @@ -1125,23 +1023,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Allocates a byte or string literal for `mir::interpret` - pub fn allocate_cached(self, bytes: &[u8]) -> interpret::AllocId { - // check whether we already allocated this literal or a constant with the same memory - if let Some(&alloc_id) = self.interpret_interner.inner.borrow() - .literal_alloc_cache.get(bytes) { - return alloc_id; - } + pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { // create an allocation that just contains these bytes - let alloc = interpret::Allocation::from_bytes(bytes); + let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes); let alloc = self.intern_const_alloc(alloc); - - // the next unique id - let id = self.interpret_interner.reserve(); - // make the allocation identifiable - self.interpret_interner.inner.borrow_mut().alloc_by_id.insert(id, alloc); - // cache it for the future - self.interpret_interner.inner.borrow_mut().literal_alloc_cache.insert(bytes.to_owned(), id); - id + self.alloc_map.lock().allocate(alloc) } pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability { @@ -1191,13 +1077,13 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// value (types, substs, etc.) can only be used while `ty::tls` has a valid /// reference to the context, to allow formatting values that need it. pub fn create_and_enter(s: &'tcx Session, - cstore: &'tcx dyn CrateStore, - local_providers: ty::maps::Providers<'tcx>, - extern_providers: ty::maps::Providers<'tcx>, + cstore: &'tcx CrateStoreDyn, + local_providers: ty::query::Providers<'tcx>, + extern_providers: ty::query::Providers<'tcx>, arenas: &'tcx AllArenas<'tcx>, resolutions: ty::Resolutions, hir: hir_map::Map<'tcx>, - on_disk_query_result_cache: maps::OnDiskCache<'tcx>, + on_disk_query_result_cache: query::OnDiskCache<'tcx>, crate_name: &str, tx: mpsc::Sender>, output_filenames: &OutputFilenames, @@ -1262,7 +1148,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { global_arenas: &arenas.global, global_interners: interners, dep_graph: dep_graph.clone(), - on_disk_query_result_cache, types: common_types, trait_map, export_map: resolutions.export_map.into_iter().map(|(k, v)| { @@ -1283,7 +1168,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .collect(), hir, def_path_hash_to_def_id, - maps: maps::Maps::new(providers), + queries: query::Queries::new(providers, on_disk_query_result_cache), rcache: Lock::new(FxHashMap()), selection_cache: traits::SelectionCache::new(), evaluation_cache: traits::EvaluationCache::new(), @@ -1291,11 +1176,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data_layout, layout_interner: Lock::new(FxHashSet()), stability_interner: Lock::new(FxHashSet()), - interpret_interner: Default::default(), + allocation_interner: Lock::new(FxHashSet()), + alloc_map: Lock::new(interpret::AllocMap::new()), tx_to_llvm_workers: Lock::new(tx), output_filenames: Arc::new(output_filenames.clone()), }; + sync::assert_send_val(&gcx); + tls::enter_global(gcx, f) } @@ -1458,7 +1346,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> Result<(), E::Error> where E: ty::codec::TyEncoder { - self.on_disk_query_result_cache.serialize(self.global_tcx(), encoder) + self.queries.on_disk_cache.serialize(self.global_tcx(), encoder) + } + + /// If true, we should use a naive AST walk to determine if match + /// guard could perform bad mutations (or mutable-borrows). + pub fn check_for_mutation_in_guard_via_ast_walk(self) -> bool { + !self.sess.opts.debugging_opts.disable_ast_check_for_mutation_in_guard + } + + /// If true, we should use the AST-based borrowck (we may *also* use + /// the MIR-based borrowck). + pub fn use_ast_borrowck(self) -> bool { + self.borrowck_mode().use_ast() } /// If true, we should use the MIR-based borrowck (we may *also* use @@ -1467,6 +1367,25 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.borrowck_mode().use_mir() } + /// If true, we should use the MIR-based borrow check, but also + /// fall back on the AST borrow check if the MIR-based one errors. + pub fn migrate_borrowck(self) -> bool { + self.borrowck_mode().migrate() + } + + /// If true, make MIR codegen for `match` emit a temp that holds a + /// borrow of the input to the match expression. + pub fn generate_borrow_of_any_match_input(&self) -> bool { + self.emit_read_for_match() + } + + /// If true, make MIR codegen for `match` emit ReadForMatch + /// statements (which simulate the maximal effect of executing the + /// patterns in a match arm). + pub fn emit_read_for_match(&self) -> bool { + self.use_mir_borrowck() && !self.sess.opts.debugging_opts.nll_dont_emit_read_for_match + } + /// If true, pattern variables for use in guards on match arms /// will be bound as references to the data, and occurrences of /// those variables in the guard expression will implicitly @@ -1485,18 +1404,51 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// What mode(s) of borrowck should we run? AST? MIR? both? /// (Also considers the `#![feature(nll)]` setting.) pub fn borrowck_mode(&self) -> BorrowckMode { + // Here are the main constraints we need to deal with: + // + // 1. An opts.borrowck_mode of `BorrowckMode::Ast` is + // synonymous with no `-Z borrowck=...` flag at all. + // (This is arguably a historical accident.) + // + // 2. `BorrowckMode::Migrate` is the limited migration to + // NLL that we are deploying with the 2018 edition. + // + // 3. We want to allow developers on the Nightly channel + // to opt back into the "hard error" mode for NLL, + // (which they can do via specifying `#![feature(nll)]` + // explicitly in their crate). + // + // So, this precedence list is how pnkfelix chose to work with + // the above constraints: + // + // * `#![feature(nll)]` *always* means use NLL with hard + // errors. (To simplify the code here, it now even overrides + // a user's attempt to specify `-Z borrowck=compare`, which + // we arguably do not need anymore and should remove.) + // + // * Otherwise, if no `-Z borrowck=...` flag was given (or + // if `borrowck=ast` was specified), then use the default + // as required by the edition. + // + // * Otherwise, use the behavior requested via `-Z borrowck=...` + + if self.features().nll { return BorrowckMode::Mir; } + match self.sess.opts.borrowck_mode { mode @ BorrowckMode::Mir | - mode @ BorrowckMode::Compare => mode, + mode @ BorrowckMode::Compare | + mode @ BorrowckMode::Migrate => mode, - mode @ BorrowckMode::Ast => { - if self.features().nll { - BorrowckMode::Mir - } else { - mode - } - } + BorrowckMode::Ast => match self.sess.edition() { + Edition::Edition2015 => BorrowckMode::Ast, + Edition::Edition2018 => BorrowckMode::Migrate, + // For now, future editions mean Migrate. (But it + // would make a lot of sense for it to be changed to + // `BorrowckMode::Mir`, depending on how we plan to + // time the forcing of full migration to NLL.) + _ => BorrowckMode::Migrate, + }, } } @@ -1598,8 +1550,8 @@ impl<'gcx: 'tcx, 'tcx> GlobalCtxt<'gcx> { /// contain the TypeVariants key or if the address of the interned /// pointer differs. The latter case is possible if a primitive type, /// e.g. `()` or `u8`, was interned in a different context. -pub trait Lift<'tcx> { - type Lifted: 'tcx; +pub trait Lift<'tcx>: fmt::Debug { + type Lifted: fmt::Debug + 'tcx; fn lift_to_tcx<'a, 'gcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option; } @@ -1633,6 +1585,57 @@ impl<'a, 'tcx> Lift<'tcx> for Region<'a> { } } +impl<'a, 'tcx> Lift<'tcx> for &'a Goal<'a> { + type Lifted = &'tcx Goal<'tcx>; + fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Goal<'tcx>> { + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { + type Lifted = &'tcx Slice>; + fn lift_to_tcx<'b, 'gcx>( + &self, + tcx: TyCtxt<'b, 'gcx, 'tcx>, + ) -> Option<&'tcx Slice>> { + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } +} + +impl<'a, 'tcx> Lift<'tcx> for &'a Slice> { + type Lifted = &'tcx Slice>; + fn lift_to_tcx<'b, 'gcx>( + &self, + tcx: TyCtxt<'b, 'gcx, 'tcx>, + ) -> Option<&'tcx Slice>> { + if tcx.interners.arena.in_arena(*self as *const _) { + return Some(unsafe { mem::transmute(*self) }); + } + // Also try in the global tcx if we're not that. + if !tcx.is_global() { + self.lift_to_tcx(tcx.global_tcx()) + } else { + None + } + } +} + impl<'a, 'tcx> Lift<'tcx> for &'a Const<'a> { type Lifted = &'tcx Const<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<&'tcx Const<'tcx>> { @@ -1744,16 +1747,21 @@ impl<'a, 'tcx> Lift<'tcx> for &'a Slice { pub mod tls { use super::{GlobalCtxt, TyCtxt}; - use std::cell::Cell; use std::fmt; use std::mem; use syntax_pos; - use ty::maps; + use ty::query; use errors::{Diagnostic, TRACK_DIAGNOSTICS}; use rustc_data_structures::OnDrop; - use rustc_data_structures::sync::Lrc; + use rustc_data_structures::sync::{self, Lrc, Lock}; use dep_graph::OpenTask; + #[cfg(not(parallel_queries))] + use std::cell::Cell; + + #[cfg(parallel_queries)] + use rayon_core; + /// This is the implicit state of rustc. It contains the current /// TyCtxt and query. It is updated when creating a local interner or /// executing a new query. Whenever there's a TyCtxt value available @@ -1766,8 +1774,8 @@ pub mod tls { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, /// The current query job, if any. This is updated by start_job in - /// ty::maps::plumbing when executing a query - pub query: Option>>, + /// ty::query::plumbing when executing a query + pub query: Option>>, /// Used to prevent layout from recursing too deeply. pub layout_depth: usize, @@ -1777,9 +1785,29 @@ pub mod tls { pub task: &'a OpenTask, } - // A thread local value which stores a pointer to the current ImplicitCtxt + /// Sets Rayon's thread local variable which is preserved for Rayon jobs + /// to `value` during the call to `f`. It is restored to its previous value after. + /// This is used to set the pointer to the new ImplicitCtxt. + #[cfg(parallel_queries)] + fn set_tlv R, R>(value: usize, f: F) -> R { + rayon_core::tlv::with(value, f) + } + + /// Gets Rayon's thread local variable which is preserved for Rayon jobs. + /// This is used to get the pointer to the current ImplicitCtxt. + #[cfg(parallel_queries)] + fn get_tlv() -> usize { + rayon_core::tlv::get() + } + + /// A thread local variable which stores a pointer to the current ImplicitCtxt + #[cfg(not(parallel_queries))] thread_local!(static TLV: Cell = Cell::new(0)); + /// Sets TLV to `value` during the call to `f`. + /// It is restored to its previous value after. + /// This is used to set the pointer to the new ImplicitCtxt. + #[cfg(not(parallel_queries))] fn set_tlv R, R>(value: usize, f: F) -> R { let old = get_tlv(); let _reset = OnDrop(move || TLV.with(|tlv| tlv.set(old))); @@ -1787,6 +1815,8 @@ pub mod tls { f() } + /// This is used to get the pointer to the current ImplicitCtxt. + #[cfg(not(parallel_queries))] fn get_tlv() -> usize { TLV.with(|tlv| tlv.get()) } @@ -1803,9 +1833,11 @@ pub mod tls { /// in librustc otherwise. It is used to when diagnostic messages are /// emitted and stores them in the current query, if there is one. fn track_diagnostic(diagnostic: &Diagnostic) { - with_context(|context| { - if let Some(ref query) = context.query { - query.diagnostics.lock().push(diagnostic.clone()); + with_context_opt(|icx| { + if let Some(icx) = icx { + if let Some(ref query) = icx.query { + query.diagnostics.lock().push(diagnostic.clone()); + } } }) } @@ -1853,6 +1885,15 @@ pub mod tls { where F: for<'a> FnOnce(TyCtxt<'a, 'gcx, 'gcx>) -> R { with_thread_locals(|| { + // Update GCX_PTR to indicate there's a GlobalCtxt available + GCX_PTR.with(|lock| { + *lock.lock() = gcx as *const _ as usize; + }); + // Set GCX_PTR back to 0 when we exit + let _on_drop = OnDrop(move || { + GCX_PTR.with(|lock| *lock.lock() = 0); + }); + let tcx = TyCtxt { gcx, interners: &gcx.global_interners, @@ -1869,6 +1910,32 @@ pub mod tls { }) } + /// Stores a pointer to the GlobalCtxt if one is available. + /// This is used to access the GlobalCtxt in the deadlock handler + /// given to Rayon. + scoped_thread_local!(pub static GCX_PTR: Lock); + + /// Creates a TyCtxt and ImplicitCtxt based on the GCX_PTR thread local. + /// This is used in the deadlock handler. + pub unsafe fn with_global(f: F) -> R + where F: for<'a, 'gcx, 'tcx> FnOnce(TyCtxt<'a, 'gcx, 'tcx>) -> R + { + let gcx = GCX_PTR.with(|lock| *lock.lock()); + assert!(gcx != 0); + let gcx = &*(gcx as *const GlobalCtxt<'_>); + let tcx = TyCtxt { + gcx, + interners: &gcx.global_interners, + }; + let icx = ImplicitCtxt { + query: None, + tcx, + layout_depth: 0, + task: &OpenTask::Ignore, + }; + enter_context(&icx, |_| f(tcx)) + } + /// Allows access to the current ImplicitCtxt in a closure if one is available pub fn with_context_opt(f: F) -> R where F: for<'a, 'gcx, 'tcx> FnOnce(Option<&ImplicitCtxt<'a, 'gcx, 'tcx>>) -> R @@ -1877,6 +1944,10 @@ pub mod tls { if context == 0 { f(None) } else { + // We could get a ImplicitCtxt pointer from another thread. + // Ensure that ImplicitCtxt is Sync + sync::assert_sync::(); + unsafe { f(Some(&*(context as *const ImplicitCtxt))) } } } @@ -2019,7 +2090,7 @@ impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { println!("Substs interner: #{}", self.interners.substs.borrow().len()); println!("Region interner: #{}", self.interners.region.borrow().len()); println!("Stability interner: #{}", self.stability_interner.borrow().len()); - println!("Interpret interner: #{}", self.interpret_interner.inner.borrow().allocs.len()); + println!("Allocation interner: #{}", self.allocation_interner.borrow().len()); println!("Layout interner: #{}", self.layout_interner.borrow().len()); } } @@ -2124,37 +2195,22 @@ for Interned<'tcx, Slice>> { macro_rules! intern_method { ($lt_tcx:tt, $name:ident: $method:ident($alloc:ty, - $alloc_method:ident, + $alloc_method:expr, $alloc_to_key:expr, - $alloc_to_ret:expr, $keep_in_local_tcx:expr) -> $ty:ty) => { impl<'a, 'gcx, $lt_tcx> TyCtxt<'a, 'gcx, $lt_tcx> { pub fn $method(self, v: $alloc) -> &$lt_tcx $ty { - { - let key = ($alloc_to_key)(&v); - if let Some(i) = self.interners.$name.borrow().get(key) { - return i.0; - } - if !self.is_global() { - if let Some(i) = self.global_interners.$name.borrow().get(key) { - return i.0; - } - } - } + let key = ($alloc_to_key)(&v); // HACK(eddyb) Depend on flags being accurate to // determine that all contents are in the global tcx. // See comments on Lift for why we can't use that. - if !($keep_in_local_tcx)(&v) { - if !self.is_global() { - let v = unsafe { - mem::transmute(v) - }; - let i = ($alloc_to_ret)(self.global_interners.arena.$alloc_method(v)); - self.global_interners.$name.borrow_mut().insert(Interned(i)); - return i; + if ($keep_in_local_tcx)(&v) { + let mut interner = self.interners.$name.borrow_mut(); + if let Some(&Interned(v)) = interner.get(key) { + return v; } - } else { + // Make sure we don't end up with inference // types/regions in the global tcx. if self.is_global() { @@ -2162,11 +2218,26 @@ macro_rules! intern_method { inference types/regions in the global type context", v); } - } - let i = ($alloc_to_ret)(self.interners.arena.$alloc_method(v)); - self.interners.$name.borrow_mut().insert(Interned(i)); - i + let i = $alloc_method(&self.interners.arena, v); + interner.insert(Interned(i)); + i + } else { + let mut interner = self.global_interners.$name.borrow_mut(); + if let Some(&Interned(v)) = interner.get(key) { + return v; + } + + // This transmutes $alloc<'tcx> to $alloc<'gcx> + let v = unsafe { + mem::transmute(v) + }; + let i: &$lt_tcx $ty = $alloc_method(&self.global_interners.arena, v); + // Cast to 'gcx + let i = unsafe { mem::transmute(i) }; + interner.insert(Interned(i)); + i + } } } } @@ -2190,8 +2261,10 @@ macro_rules! direct_interners { intern_method!( $lt_tcx, - $name: $method($ty, alloc, |x| x, |x| x, $keep_in_local_tcx) -> $ty - );)+ + $name: $method($ty, + |a: &$lt_tcx SyncDroplessArena, v| -> &$lt_tcx $ty { a.alloc(v) }, + |x| x, + $keep_in_local_tcx) -> $ty);)+ } } @@ -2206,10 +2279,11 @@ direct_interners!('tcx, macro_rules! slice_interners { ($($field:ident: $method:ident($ty:ident)),+) => ( - $(intern_method!('tcx, $field: $method(&[$ty<'tcx>], alloc_slice, Deref::deref, - |xs: &[$ty]| -> &Slice<$ty> { - unsafe { mem::transmute(xs) } - }, |xs: &[$ty]| xs.iter().any(keep_local)) -> Slice<$ty<'tcx>>);)+ + $(intern_method!( 'tcx, $field: $method( + &[$ty<'tcx>], + |a, v| Slice::from_arena(a, v), + Deref::deref, + |xs: &[$ty]| xs.iter().any(keep_local)) -> Slice<$ty<'tcx>>);)+ ) } @@ -2231,9 +2305,8 @@ intern_method! { 'tcx, canonical_var_infos: _intern_canonical_var_infos( &[CanonicalVarInfo], - alloc_slice, + |a, v| Slice::from_arena(a, v), Deref::deref, - |xs: &[CanonicalVarInfo]| -> &Slice { unsafe { mem::transmute(xs) } }, |_xs: &[CanonicalVarInfo]| -> bool { false } ) -> Slice } @@ -2274,15 +2347,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_fn_ptr(converted_sig) } - // Interns a type/name combination, stores the resulting box in cx.interners, - // and returns the box as cast to an unsafe ptr (see comments for Ty above). - pub fn mk_ty(self, st: TypeVariants<'tcx>) -> Ty<'tcx> { - let global_interners = if !self.is_global() { - Some(&self.global_interners) - } else { - None - }; - self.interners.intern_ty(st, global_interners) + pub fn mk_ty(&self, st: TypeVariants<'tcx>) -> Ty<'tcx> { + CtxtInterners::intern_ty(&self.interners, &self.global_interners, st) } pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> { @@ -2334,15 +2400,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn mk_box(self, ty: Ty<'tcx>) -> Ty<'tcx> { let def_id = self.require_lang_item(lang_items::OwnedBoxLangItem); let adt_def = self.adt_def(def_id); - let generics = self.generics_of(def_id); - let mut substs = vec![Kind::from(ty)]; - // Add defaults for other generic params if there are some. - for def in generics.types.iter().skip(1) { - assert!(def.has_default); - let ty = self.type_of(def.def_id).subst(self, &substs); - substs.push(ty.into()); - } - let substs = self.mk_substs(substs.into_iter()); + let substs = Substs::for_item(self, def_id, |param, substs| { + match param.kind { + GenericParamDefKind::Lifetime => bug!(), + GenericParamDefKind::Type { has_default, .. } => { + if param.index == 0 { + ty.into() + } else { + assert!(has_default); + self.type_of(param.def_id).subst(self, substs).into() + } + } + } + }); self.mk_ty(TyAdt(adt_def, substs)) } @@ -2351,7 +2421,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_ref(self, r: Region<'tcx>, tm: TypeAndMut<'tcx>) -> Ty<'tcx> { - self.mk_ty(TyRef(r, tm)) + self.mk_ty(TyRef(r, tm.ty, tm.mutbl)) } pub fn mk_mut_ref(self, r: Region<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -2375,10 +2445,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_array(self, ty: Ty<'tcx>, n: u64) -> Ty<'tcx> { - self.mk_ty(TyArray(ty, self.mk_const(ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(n.into()))), - ty: self.types.usize - }))) + self.mk_ty(TyArray(ty, ty::Const::from_usize(self, n))) } pub fn mk_slice(self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -2436,26 +2503,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { })) } - pub fn mk_closure(self, - closure_id: DefId, - substs: ClosureSubsts<'tcx>) - -> Ty<'tcx> { - self.mk_closure_from_closure_substs(closure_id, substs) - } - - pub fn mk_closure_from_closure_substs(self, - closure_id: DefId, - closure_substs: ClosureSubsts<'tcx>) + pub fn mk_closure(self, closure_id: DefId, closure_substs: ClosureSubsts<'tcx>) -> Ty<'tcx> { self.mk_ty(TyClosure(closure_id, closure_substs)) } pub fn mk_generator(self, id: DefId, - closure_substs: ClosureSubsts<'tcx>, - interior: GeneratorInterior<'tcx>) + generator_substs: GeneratorSubsts<'tcx>, + movability: hir::GeneratorMovability) -> Ty<'tcx> { - self.mk_ty(TyGenerator(id, closure_substs, interior)) + self.mk_ty(TyGenerator(id, generator_substs, movability)) } pub fn mk_generator_witness(self, types: ty::Binder<&'tcx Slice>>) -> Ty<'tcx> { @@ -2478,18 +2536,23 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.mk_ty(TyInfer(it)) } - pub fn mk_param(self, + pub fn mk_ty_param(self, index: u32, name: InternedString) -> Ty<'tcx> { self.mk_ty(TyParam(ParamTy { idx: index, name: name })) } pub fn mk_self_type(self) -> Ty<'tcx> { - self.mk_param(0, keywords::SelfType.name().as_interned_str()) + self.mk_ty_param(0, keywords::SelfType.name().as_interned_str()) } - pub fn mk_param_from_def(self, def: &ty::TypeParameterDef) -> Ty<'tcx> { - self.mk_param(def.index, def.name) + pub fn mk_param_from_def(self, param: &ty::GenericParamDef) -> Kind<'tcx> { + match param.kind { + GenericParamDefKind::Lifetime => { + self.mk_region(ty::ReEarlyBound(param.to_early_bound_region_data())).into() + } + GenericParamDefKind::Type {..} => self.mk_ty_param(param.index, param.name).into(), + } } pub fn mk_anon(self, def_id: DefId, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { @@ -2499,7 +2562,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn intern_existential_predicates(self, eps: &[ExistentialPredicate<'tcx>]) -> &'tcx Slice> { assert!(!eps.is_empty()); - assert!(eps.windows(2).all(|w| w[0].cmp(self, &w[1]) != Ordering::Greater)); + assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater)); self._intern_existential_predicates(eps) } @@ -2595,11 +2658,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_substs_trait(self, - s: Ty<'tcx>, - t: &[Ty<'tcx>]) + self_ty: Ty<'tcx>, + rest: &[Kind<'tcx>]) -> &'tcx Substs<'tcx> { - self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from)) + self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned())) } pub fn mk_clauses], Clauses<'tcx>>>(self, iter: I) -> I::Output { @@ -2611,7 +2674,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } pub fn mk_goal(self, goal: Goal<'tcx>) -> &'tcx Goal { - &self.mk_goals(iter::once(goal))[0] + &self.intern_goals(&[goal])[0] + } + + pub fn lint_hir>(self, + lint: &'static Lint, + hir_id: HirId, + span: S, + msg: &str) { + self.struct_span_lint_hir(lint, hir_id, span.into(), msg).emit() } pub fn lint_node>(self, @@ -2622,6 +2693,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.struct_span_lint_node(lint, id, span.into(), msg).emit() } + pub fn lint_hir_note>(self, + lint: &'static Lint, + hir_id: HirId, + span: S, + msg: &str, + note: &str) { + let mut err = self.struct_span_lint_hir(lint, hir_id, span.into(), msg); + err.note(note); + err.emit() + } + pub fn lint_node_note>(self, lint: &'static Lint, id: NodeId, @@ -2660,6 +2742,18 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }) } + pub fn struct_span_lint_hir>(self, + lint: &'static Lint, + hir_id: HirId, + span: S, + msg: &str) + -> DiagnosticBuilder<'tcx> + { + let node_id = self.hir.hir_to_node_id(hir_id); + let (level, src) = self.lint_level_at_node(lint, node_id); + lint::struct_lint_level(self.sess, lint, level, src, Some(span.into()), msg) + } + pub fn struct_span_lint_node>(self, lint: &'static Lint, id: NodeId, @@ -2746,7 +2840,7 @@ impl InternIteratorElement for Result { } } -pub fn provide(providers: &mut ty::maps::Providers) { +pub fn provide(providers: &mut ty::query::Providers) { // FIXME(#44234) - almost all of these queries have no sub-queries and // therefore no actual inputs, they're just reading tables calculated in // resolve! Does this work? Unsure! That's what the issue is about diff --git a/src/librustc/ty/erase_regions.rs b/src/librustc/ty/erase_regions.rs index 4f8fca67949b5..2fb2154ce6ba0 100644 --- a/src/librustc/ty/erase_regions.rs +++ b/src/librustc/ty/erase_regions.rs @@ -11,8 +11,8 @@ use ty::{self, Ty, TyCtxt}; use ty::fold::{TypeFolder, TypeFoldable}; -pub(super) fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub(super) fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { erase_regions_ty, ..*providers }; @@ -68,7 +68,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 't // // Note that we *CAN* replace early-bound regions -- the // type system never "sees" those, they get substituted - // away. In trans, they will always be erased to 'erased + // away. In codegen, they will always be erased to 'erased // whenever a substitution occurs. match *r { ty::ReLateBound(..) => r, @@ -76,4 +76,3 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 't } } } - diff --git a/src/librustc/ty/error.rs b/src/librustc/ty/error.rs index cf2004a681e62..7dfdc592647db 100644 --- a/src/librustc/ty/error.rs +++ b/src/librustc/ty/error.rs @@ -182,27 +182,24 @@ impl<'a, 'gcx, 'lcx, 'tcx> ty::TyS<'tcx> { ty::TyAdt(def, _) => format!("{} `{}`", def.descr(), tcx.item_path_str(def.did)), ty::TyForeign(def_id) => format!("extern type `{}`", tcx.item_path_str(def_id)), ty::TyArray(_, n) => { - match n.val.to_raw_bits() { + match n.assert_usize(tcx) { Some(n) => format!("array of {} elements", n), None => "array".to_string(), } } ty::TySlice(_) => "slice".to_string(), ty::TyRawPtr(_) => "*-ptr".to_string(), - ty::TyRef(region, tymut) => { + ty::TyRef(region, ty, mutbl) => { + let tymut = ty::TypeAndMut { ty, mutbl }; let tymut_string = tymut.to_string(); if tymut_string == "_" || //unknown type name, tymut_string.len() > 10 || //name longer than saying "reference", region.to_string() != "" //... or a complex type { - match tymut { - ty::TypeAndMut{mutbl, ..} => { - format!("{}reference", match mutbl { - hir::Mutability::MutMutable => "mutable ", - _ => "" - }) - } - } + format!("{}reference", match mutbl { + hir::Mutability::MutMutable => "mutable ", + _ => "" + }) } else { format!("&{}", tymut_string) } diff --git a/src/librustc/ty/fast_reject.rs b/src/librustc/ty/fast_reject.rs index 31b3ca44700e9..cf5e55a59f713 100644 --- a/src/librustc/ty/fast_reject.rs +++ b/src/librustc/ty/fast_reject.rs @@ -80,11 +80,11 @@ pub fn simplify_type<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, ty::TyDynamic(ref trait_info, ..) => { trait_info.principal().map(|p| TraitSimplifiedType(p.def_id())) } - ty::TyRef(_, mt) => { + ty::TyRef(_, ty, _) => { // since we introduce auto-refs during method lookup, we // just treat &T and T as equivalent from the point of // view of possibly unifying - simplify_type(tcx, mt.ty, can_simplify_params) + simplify_type(tcx, ty, can_simplify_params) } ty::TyFnDef(def_id, _) | ty::TyClosure(def_id, _) => { diff --git a/src/librustc/ty/flags.rs b/src/librustc/ty/flags.rs index 086fc66c70f9d..3718c436b3a00 100644 --- a/src/librustc/ty/flags.rs +++ b/src/librustc/ty/flags.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::const_val::ConstVal; +use mir::interpret::ConstValue; use ty::subst::Substs; use ty::{self, Ty, TypeFlags, TypeFoldable}; @@ -16,13 +16,16 @@ use ty::{self, Ty, TypeFlags, TypeFoldable}; pub struct FlagComputation { pub flags: TypeFlags, - // maximum depth of any bound region that we have seen thus far - pub depth: u32, + // see `TyS::outer_exclusive_binder` for details + pub outer_exclusive_binder: ty::DebruijnIndex, } impl FlagComputation { fn new() -> FlagComputation { - FlagComputation { flags: TypeFlags::empty(), depth: 0 } + FlagComputation { + flags: TypeFlags::empty(), + outer_exclusive_binder: ty::INNERMOST, + } } pub fn for_sty(st: &ty::TypeVariants) -> FlagComputation { @@ -35,10 +38,17 @@ impl FlagComputation { self.flags = self.flags | (flags & TypeFlags::NOMINAL_FLAGS); } - fn add_depth(&mut self, depth: u32) { - if depth > self.depth { - self.depth = depth; - } + /// indicates that `self` refers to something at binding level `binder` + fn add_binder(&mut self, binder: ty::DebruijnIndex) { + let exclusive_binder = binder.shifted_in(1); + self.add_exclusive_binder(exclusive_binder); + } + + /// indicates that `self` refers to something *inside* binding + /// level `binder` -- not bound by `binder`, but bound by the next + /// binder internal to it + fn add_exclusive_binder(&mut self, exclusive_binder: ty::DebruijnIndex) { + self.outer_exclusive_binder = self.outer_exclusive_binder.max(exclusive_binder); } /// Adds the flags/depth from a set of types that appear within the current type, but within a @@ -49,9 +59,11 @@ impl FlagComputation { // The types that contributed to `computation` occurred within // a region binder, so subtract one from the region depth // within when adding the depth to `self`. - let depth = computation.depth; - if depth > 0 { - self.add_depth(depth - 1); + let outer_exclusive_binder = computation.outer_exclusive_binder; + if outer_exclusive_binder > ty::INNERMOST { + self.add_exclusive_binder(outer_exclusive_binder.shifted_out(1)); + } else { + // otherwise, this binder captures nothing } } @@ -79,7 +91,7 @@ impl FlagComputation { } &ty::TyParam(ref p) => { - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); + self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); if p.is_self() { self.add_flags(TypeFlags::HAS_SELF); } else { @@ -87,11 +99,10 @@ impl FlagComputation { } } - &ty::TyGenerator(_, ref substs, ref interior) => { + &ty::TyGenerator(_, ref substs, _) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); + self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); self.add_substs(&substs.substs); - self.add_ty(interior.witness); } &ty::TyGeneratorWitness(ref ts) => { @@ -102,12 +113,12 @@ impl FlagComputation { &ty::TyClosure(_, ref substs) => { self.add_flags(TypeFlags::HAS_TY_CLOSURE); - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); + self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); self.add_substs(&substs.substs); } &ty::TyInfer(infer) => { - self.add_flags(TypeFlags::HAS_LOCAL_NAMES); // it might, right? + self.add_flags(TypeFlags::HAS_FREE_LOCAL_NAMES); // it might, right? self.add_flags(TypeFlags::HAS_TY_INFER); match infer { ty::FreshTy(_) | @@ -174,9 +185,9 @@ impl FlagComputation { self.add_ty(m.ty); } - &ty::TyRef(r, ref m) => { + &ty::TyRef(r, ty, _) => { self.add_region(r); - self.add_ty(m.ty); + self.add_ty(ty); } &ty::TyTuple(ref ts) => { @@ -195,7 +206,7 @@ impl FlagComputation { fn add_ty(&mut self, ty: Ty) { self.add_flags(ty.flags); - self.add_depth(ty.region_depth); + self.add_exclusive_binder(ty.outer_exclusive_binder); } fn add_tys(&mut self, tys: &[Ty]) { @@ -216,18 +227,15 @@ impl FlagComputation { fn add_region(&mut self, r: ty::Region) { self.add_flags(r.type_flags()); if let ty::ReLateBound(debruijn, _) = *r { - self.add_depth(debruijn.depth); + self.add_binder(debruijn); } } fn add_const(&mut self, constant: &ty::Const) { self.add_ty(constant.ty); - match constant.val { - ConstVal::Value(_) => {} - ConstVal::Unevaluated(_, substs) => { - self.add_flags(TypeFlags::HAS_PROJECTION); - self.add_substs(substs); - } + if let ConstValue::Unevaluated(_, substs) = constant.val { + self.add_flags(TypeFlags::HAS_PROJECTION); + self.add_substs(substs); } } diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs index 1793b5e1edba8..e4484041b065c 100644 --- a/src/librustc/ty/fold.rs +++ b/src/librustc/ty/fold.rs @@ -39,11 +39,11 @@ //! These methods return true to indicate that the visitor has found what it is looking for //! and does not need to visit anything else. -use middle::const_val::ConstVal; +use mir::interpret::ConstValue; use hir::def_id::DefId; use ty::{self, Binder, Ty, TyCtxt, TypeFlags}; -use rustc_data_structures::lazy_btree_map::LazyBTreeMap; +use std::collections::BTreeMap; use std::fmt; use util::nodemap::FxHashSet; @@ -63,11 +63,22 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { self.super_visit_with(visitor) } - fn has_regions_escaping_depth(&self, depth: u32) -> bool { - self.visit_with(&mut HasEscapingRegionsVisitor { depth: depth }) + /// True if `self` has any late-bound regions that are either + /// bound by `binder` or bound by some binder outside of `binder`. + /// If `binder` is `ty::INNERMOST`, this indicates whether + /// there are any late-bound regions that appear free. + fn has_regions_bound_at_or_above(&self, binder: ty::DebruijnIndex) -> bool { + self.visit_with(&mut HasEscapingRegionsVisitor { outer_index: binder }) } + + /// True if this `self` has any regions that escape `binder` (and + /// hence are not bound by it). + fn has_regions_bound_above(&self, binder: ty::DebruijnIndex) -> bool { + self.has_regions_bound_at_or_above(binder.shifted_in(1)) + } + fn has_escaping_regions(&self) -> bool { - self.has_regions_escaping_depth(0) + self.has_regions_bound_at_or_above(ty::INNERMOST) } fn has_type_flags(&self, flags: TypeFlags) -> bool { @@ -116,10 +127,28 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { /// Indicates whether this value references only 'global' /// types/lifetimes that are the same regardless of what fn we are - /// in. This is used for caching. Errs on the side of returning - /// false. + /// in. This is used for caching. fn is_global(&self) -> bool { - !self.has_type_flags(TypeFlags::HAS_LOCAL_NAMES) + !self.has_type_flags(TypeFlags::HAS_FREE_LOCAL_NAMES) + } + + /// True if there are any late-bound regions + fn has_late_bound_regions(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_RE_LATE_BOUND) + } + + /// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`. + fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool { + + pub struct Visitor(F); + + impl<'tcx, F: FnMut(Ty<'tcx>) -> bool> TypeVisitor<'tcx> for Visitor { + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + self.0(ty) + } + } + + self.visit_with(&mut Visitor(visit)) } } @@ -171,15 +200,18 @@ pub trait TypeVisitor<'tcx> : Sized { /////////////////////////////////////////////////////////////////////////// // Some sample folders -pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F> - where F: FnMut(Ty<'tcx>) -> Ty<'tcx> +pub struct BottomUpFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a, F, G> + where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, + G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, { pub tcx: TyCtxt<'a, 'gcx, 'tcx>, pub fldop: F, + pub reg_op: G, } -impl<'a, 'gcx, 'tcx, F> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F> +impl<'a, 'gcx, 'tcx, F, G> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx, F, G> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>, + G: FnMut(ty::Region<'tcx>) -> ty::Region<'tcx>, { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } @@ -187,6 +219,11 @@ impl<'a, 'gcx, 'tcx, F> TypeFolder<'gcx, 'tcx> for BottomUpFolder<'a, 'gcx, 'tcx let t1 = ty.super_fold_with(self); (self.fldop)(t1) } + + fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { + let r = r.super_fold_with(self); + (self.reg_op)(r) + } } /////////////////////////////////////////////////////////////////////////// @@ -203,7 +240,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { { let mut have_bound_regions = false; self.fold_regions(value, &mut have_bound_regions, |r, d| { - region_set.insert(self.mk_region(r.from_depth(d))); + region_set.insert(self.mk_region(r.shifted_out_to_binder(d))); r }); have_bound_regions @@ -212,50 +249,98 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Folds the escaping and free regions in `value` using `f`, and /// sets `skipped_regions` to true if any late-bound region was found /// and skipped. - pub fn fold_regions(self, + pub fn fold_regions( + self, value: &T, skipped_regions: &mut bool, - mut f: F) - -> T - where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx>, - T : TypeFoldable<'tcx>, + mut f: impl FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, + ) -> T + where + T : TypeFoldable<'tcx>, { value.fold_with(&mut RegionFolder::new(self, skipped_regions, &mut f)) } - pub fn for_each_free_region(self, - value: &T, - callback: F) - where F: FnMut(ty::Region<'tcx>), - T: TypeFoldable<'tcx>, - { - value.visit_with(&mut RegionVisitor { current_depth: 0, callback }); + /// Invoke `callback` on every region appearing free in `value`. + pub fn for_each_free_region( + self, + value: &impl TypeFoldable<'tcx>, + mut callback: impl FnMut(ty::Region<'tcx>), + ) { + self.any_free_region_meets(value, |r| { + callback(r); + false + }); + } + + /// True if `callback` returns true for every region appearing free in `value`. + pub fn all_free_regions_meet( + self, + value: &impl TypeFoldable<'tcx>, + mut callback: impl FnMut(ty::Region<'tcx>) -> bool, + ) -> bool { + !self.any_free_region_meets(value, |r| !callback(r)) + } + + /// True if `callback` returns true for some region appearing free in `value`. + pub fn any_free_region_meets( + self, + value: &impl TypeFoldable<'tcx>, + callback: impl FnMut(ty::Region<'tcx>) -> bool, + ) -> bool { + return value.visit_with(&mut RegionVisitor { + outer_index: ty::INNERMOST, + callback + }); struct RegionVisitor { - current_depth: u32, + /// The index of a binder *just outside* the things we have + /// traversed. If we encounter a bound region bound by this + /// binder or one outer to it, it appears free. Example: + /// + /// ``` + /// for<'a> fn(for<'b> fn(), T) + /// ^ ^ ^ ^ + /// | | | | here, would be shifted in 1 + /// | | | here, would be shifted in 2 + /// | | here, would be INNERMOST shifted in by 1 + /// | here, initially, binder would be INNERMOST + /// ``` + /// + /// You see that, initially, *any* bound value is free, + /// because we've not traversed any binders. As we pass + /// through a binder, we shift the `outer_index` by 1 to + /// account for the new binder that encloses us. + outer_index: ty::DebruijnIndex, callback: F, } impl<'tcx, F> TypeVisitor<'tcx> for RegionVisitor - where F : FnMut(ty::Region<'tcx>) + where F: FnMut(ty::Region<'tcx>) -> bool { fn visit_binder>(&mut self, t: &Binder) -> bool { - self.current_depth += 1; - t.skip_binder().visit_with(self); - self.current_depth -= 1; - - false // keep visiting + self.outer_index.shift_in(1); + let result = t.skip_binder().visit_with(self); + self.outer_index.shift_out(1); + result } fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { match *r { - ty::ReLateBound(debruijn, _) if debruijn.depth <= self.current_depth => { - /* ignore bound regions */ + ty::ReLateBound(debruijn, _) if debruijn < self.outer_index => { + false // ignore bound regions, keep visiting } _ => (self.callback)(r), } + } - false // keep visiting + fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { + // We're only interested in types involving regions + if ty.flags.intersects(TypeFlags::HAS_FREE_REGIONS) { + ty.super_visit_with(self) + } else { + false // keep visiting + } } } } @@ -273,21 +358,32 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub struct RegionFolder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, skipped_regions: &'a mut bool, - current_depth: u32, - fld_r: &'a mut (dyn FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx> + 'a), + + /// Stores the index of a binder *just outside* the stuff we have + /// visited. So this begins as INNERMOST; when we pass through a + /// binder, it is incremented (via `shift_in`). + current_index: ty::DebruijnIndex, + + /// Callback invokes for each free region. The `DebruijnIndex` + /// points to the binder *just outside* the ones we have passed + /// through. + fold_region_fn: &'a mut (dyn FnMut( + ty::Region<'tcx>, + ty::DebruijnIndex, + ) -> ty::Region<'tcx> + 'a), } impl<'a, 'gcx, 'tcx> RegionFolder<'a, 'gcx, 'tcx> { - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, - skipped_regions: &'a mut bool, - fld_r: &'a mut F) -> RegionFolder<'a, 'gcx, 'tcx> - where F : FnMut(ty::Region<'tcx>, u32) -> ty::Region<'tcx> - { + pub fn new( + tcx: TyCtxt<'a, 'gcx, 'tcx>, + skipped_regions: &'a mut bool, + fold_region_fn: &'a mut dyn FnMut(ty::Region<'tcx>, ty::DebruijnIndex) -> ty::Region<'tcx>, + ) -> RegionFolder<'a, 'gcx, 'tcx> { RegionFolder { tcx, skipped_regions, - current_depth: 1, - fld_r, + current_index: ty::INNERMOST, + fold_region_fn, } } } @@ -296,24 +392,24 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { - self.current_depth += 1; + self.current_index.shift_in(1); let t = t.super_fold_with(self); - self.current_depth -= 1; + self.current_index.shift_out(1); t } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReLateBound(debruijn, _) if debruijn.depth < self.current_depth => { - debug!("RegionFolder.fold_region({:?}) skipped bound region (current depth={})", - r, self.current_depth); + ty::ReLateBound(debruijn, _) if debruijn < self.current_index => { + debug!("RegionFolder.fold_region({:?}) skipped bound region (current index={:?})", + r, self.current_index); *self.skipped_regions = true; r } _ => { - debug!("RegionFolder.fold_region({:?}) folding free region (current_depth={})", - r, self.current_depth); - (self.fld_r)(r, self.current_depth) + debug!("RegionFolder.fold_region({:?}) folding free region (current_index={:?})", + r, self.current_index); + (self.fold_region_fn)(r, self.current_index) } } } @@ -326,9 +422,13 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionFolder<'a, 'gcx, 'tcx> { struct RegionReplacer<'a, 'gcx: 'a+'tcx, 'tcx: 'a> { tcx: TyCtxt<'a, 'gcx, 'tcx>, - current_depth: u32, + + /// As with `RegionFolder`, represents the index of a binder *just outside* + /// the ones we have visited. + current_index: ty::DebruijnIndex, + fld_r: &'a mut (dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx> + 'a), - map: LazyBTreeMap> + map: BTreeMap> } impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { @@ -343,7 +443,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn replace_late_bound_regions(self, value: &Binder, mut f: F) - -> (T, LazyBTreeMap>) + -> (T, BTreeMap>) where F : FnMut(ty::BoundRegion) -> ty::Region<'tcx>, T : TypeFoldable<'tcx>, { @@ -368,20 +468,22 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { }).0 } - /// Flattens two binding levels into one. So `for<'a> for<'b> Foo` + /// Flattens multiple binding levels into one. So `for<'a> for<'b> Foo` /// becomes `for<'a,'b> Foo`. pub fn flatten_late_bound_regions(self, bound2_value: &Binder>) -> Binder where T: TypeFoldable<'tcx> { let bound0_value = bound2_value.skip_binder().skip_binder(); - let value = self.fold_regions(bound0_value, &mut false, - |region, current_depth| { + let value = self.fold_regions(bound0_value, &mut false, |region, current_depth| { match *region { - ty::ReLateBound(debruijn, br) if debruijn.depth >= current_depth => { - // should be true if no escaping regions from bound2_value - assert!(debruijn.depth - current_depth <= 1); - self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(current_depth), br)) + ty::ReLateBound(debruijn, br) => { + // We assume no regions bound *outside* of the + // binders in `bound2_value` (nmatsakis added in + // the course of this PR; seems like a reasonable + // sanity check though). + assert!(debruijn == current_depth); + self.mk_region(ty::ReLateBound(current_depth, br)) } _ => { region @@ -420,7 +522,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { collector.regions } - /// Replace any late-bound regions bound in `value` with `'erased`. Useful in trans but also + /// Replace any late-bound regions bound in `value` with `'erased`. Useful in codegen but also /// method lookup and a few other places where precise region relationships are not required. pub fn erase_late_bound_regions(self, value: &Binder) -> T where T : TypeFoldable<'tcx> @@ -442,7 +544,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let mut counter = 0; Binder::bind(self.replace_late_bound_regions(sig, |_| { counter += 1; - self.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrAnon(counter))) + self.mk_region(ty::ReLateBound(ty::INNERMOST, ty::BrAnon(counter))) }).0) } } @@ -454,9 +556,9 @@ impl<'a, 'gcx, 'tcx> RegionReplacer<'a, 'gcx, 'tcx> { { RegionReplacer { tcx, - current_depth: 1, + current_index: ty::INNERMOST, fld_r, - map: LazyBTreeMap::default() + map: BTreeMap::default() } } } @@ -465,14 +567,14 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.tcx } fn fold_binder>(&mut self, t: &ty::Binder) -> ty::Binder { - self.current_depth += 1; + self.current_index.shift_in(1); let t = t.super_fold_with(self); - self.current_depth -= 1; + self.current_index.shift_out(1); t } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - if !t.has_regions_escaping_depth(self.current_depth-1) { + if !t.has_regions_bound_at_or_above(self.current_index) { return t; } @@ -481,14 +583,15 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { match *r { - ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { + ty::ReLateBound(debruijn, br) if debruijn == self.current_index => { let fld_r = &mut self.fld_r; let region = *self.map.entry(br).or_insert_with(|| fld_r(br)); if let ty::ReLateBound(debruijn1, br) = *region { // If the callback returns a late-bound region, - // that region should always use depth 1. Then we - // adjust it to the correct depth. - assert_eq!(debruijn1.depth, 1); + // that region should always use the INNERMOST + // debruijn index. Then we adjust it to the + // correct depth. + assert_eq!(debruijn1, ty::INNERMOST); self.tcx.mk_region(ty::ReLateBound(debruijn, br)) } else { region @@ -511,7 +614,7 @@ impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionReplacer<'a, 'gcx, 'tcx> { pub fn shift_region(region: ty::RegionKind, amount: u32) -> ty::RegionKind { match region { ty::ReLateBound(debruijn, br) => { - ty::ReLateBound(debruijn.shifted(amount), br) + ty::ReLateBound(debruijn.shifted_in(amount), br) } _ => { region @@ -527,7 +630,7 @@ pub fn shift_region_ref<'a, 'gcx, 'tcx>( { match region { &ty::ReLateBound(debruijn, br) if amount > 0 => { - tcx.mk_region(ty::ReLateBound(debruijn.shifted(amount), br)) + tcx.mk_region(ty::ReLateBound(debruijn.shifted_in(amount), br)) } _ => { region @@ -571,23 +674,32 @@ pub fn shift_regions<'a, 'gcx, 'tcx, T>(tcx: TyCtxt<'a, 'gcx, 'tcx>, /// represent the scope to which it is attached, etc. An escaping region represents a bound region /// for which this processing has not yet been done. struct HasEscapingRegionsVisitor { - depth: u32, + /// Anything bound by `outer_index` or "above" is escaping + outer_index: ty::DebruijnIndex, } impl<'tcx> TypeVisitor<'tcx> for HasEscapingRegionsVisitor { fn visit_binder>(&mut self, t: &Binder) -> bool { - self.depth += 1; + self.outer_index.shift_in(1); let result = t.super_visit_with(self); - self.depth -= 1; + self.outer_index.shift_out(1); result } fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - t.region_depth > self.depth + // If the outer-exclusive-binder is *strictly greater* than + // `outer_index`, that means that `t` contains some content + // bound at `outer_index` or above (because + // `outer_exclusive_binder` is always 1 higher than the + // content in `t`). Therefore, `t` has some escaping regions. + t.outer_exclusive_binder > self.outer_index } fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - r.escapes_depth(self.depth) + // If the region is bound by `outer_index` or anything outside + // of outer index, then it escapes the binders we have + // visited. + r.bound_at_or_above_binder(self.outer_index) } } @@ -608,7 +720,7 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { - if let ConstVal::Unevaluated(..) = c.val { + if let ConstValue::Unevaluated(..) = c.val { let projection_flags = TypeFlags::HAS_NORMALIZABLE_PROJECTION | TypeFlags::HAS_PROJECTION; if projection_flags.intersects(self.flags) { @@ -619,17 +731,26 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { } } -/// Collects all the late-bound regions it finds into a hash set. +/// Collects all the late-bound regions at the innermost binding level +/// into a hash set. struct LateBoundRegionsCollector { - current_depth: u32, + current_index: ty::DebruijnIndex, regions: FxHashSet, + + /// If true, we only want regions that are known to be + /// "constrained" when you equate this type with another type. In + /// partcular, if you have e.g. `&'a u32` and `&'b u32`, equating + /// them constraints `'a == 'b`. But if you have `<&'a u32 as + /// Trait>::Foo` and `<&'b u32 as Trait>::Foo`, normalizing those + /// types may mean that `'a` and `'b` don't appear in the results, + /// so they are not considered *constrained*. just_constrained: bool, } impl LateBoundRegionsCollector { fn new(just_constrained: bool) -> Self { LateBoundRegionsCollector { - current_depth: 1, + current_index: ty::INNERMOST, regions: FxHashSet(), just_constrained, } @@ -638,9 +759,9 @@ impl LateBoundRegionsCollector { impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { fn visit_binder>(&mut self, t: &Binder) -> bool { - self.current_depth += 1; + self.current_index.shift_in(1); let result = t.super_visit_with(self); - self.current_depth -= 1; + self.current_index.shift_out(1); result } @@ -660,7 +781,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { match *r { - ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => { + ty::ReLateBound(debruijn, br) if debruijn == self.current_index => { self.regions.insert(br); } _ => { } diff --git a/src/librustc/ty/inhabitedness/mod.rs b/src/librustc/ty/inhabitedness/mod.rs index 325f8575fd0a7..19e5406cd0d0a 100644 --- a/src/librustc/ty/inhabitedness/mod.rs +++ b/src/librustc/ty/inhabitedness/mod.rs @@ -262,15 +262,15 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { })) }, TyArray(ty, len) => { - match len.val.to_raw_bits() { + match len.assert_usize(tcx) { // If the array is definitely non-empty, it's uninhabited if // the type of its elements is uninhabited. Some(n) if n != 0 => ty.uninhabited_from(visited, tcx), _ => DefIdForest::empty() } } - TyRef(_, ref tm) => { - tm.ty.uninhabited_from(visited, tcx) + TyRef(_, ty, _) => { + ty.uninhabited_from(visited, tcx) } _ => DefIdForest::empty(), diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index ecd415c4bc420..66edbeff749f7 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -10,7 +10,6 @@ use hir::def_id::DefId; use ty::{self, Ty, TypeFoldable, Substs, TyCtxt}; -use ty::subst::Kind; use traits; use rustc_target::spec::abi::Abi; use util::ppaux; @@ -104,13 +103,13 @@ impl<'tcx> InstanceDef<'tcx> { return true } if let ty::InstanceDef::DropGlue(..) = *self { - // Drop glue wants to be instantiated at every translation + // Drop glue wants to be instantiated at every codegen // unit, but without an #[inline] hint. We should make this // available to normal end-users. return true } - let trans_fn_attrs = tcx.trans_fn_attrs(self.def_id()); - trans_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id()) + let codegen_fn_attrs = tcx.codegen_fn_attrs(self.def_id()); + codegen_fn_attrs.requests_inline() || tcx.is_const_fn(self.def_id()) } } @@ -145,7 +144,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> Instance<'tcx> { assert!(!substs.has_escaping_regions(), - "substs of instance {:?} not normalized for trans: {:?}", + "substs of instance {:?} not normalized for codegen: {:?}", def_id, substs); Instance { def: InstanceDef::Item(def_id), substs: substs } } @@ -175,7 +174,7 @@ impl<'a, 'b, 'tcx> Instance<'tcx> { /// `RevealMode` in the parameter environment.) /// /// Presuming that coherence and type-check have succeeded, if this method is invoked - /// in a monomorphic context (i.e., like during trans), then it is guaranteed to return + /// in a monomorphic context (i.e., like during codegen), then it is guaranteed to return /// `Some`. pub fn resolve(tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParamEnv<'tcx>, @@ -259,7 +258,7 @@ fn resolve_associated_item<'a, 'tcx>( def_id, trait_id, rcvr_substs); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation((param_env, ty::Binder::bind(trait_ref))); + let vtbl = tcx.codegen_fulfill_obligation((param_env, ty::Binder::bind(trait_ref))); // Now that we know which impl is being used, we can dispatch to // the actual function: @@ -270,10 +269,10 @@ fn resolve_associated_item<'a, 'tcx>( let substs = tcx.erase_regions(&substs); Some(ty::Instance::new(def_id, substs)) } - traits::VtableGenerator(closure_data) => { + traits::VtableGenerator(generator_data) => { Some(Instance { - def: ty::InstanceDef::Item(closure_data.closure_def_id), - substs: closure_data.substs.substs + def: ty::InstanceDef::Item(generator_data.generator_def_id), + substs: generator_data.substs.substs }) } traits::VtableClosure(closure_data) => { @@ -321,7 +320,7 @@ fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind, } (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are + // `fn(&mut self, ...)`. In fact, at codegen time, these are // basically the same thing, so we can just return llfn. Ok(false) } @@ -334,7 +333,7 @@ fn needs_fn_once_adapter_shim<'a, 'tcx>(actual_closure_kind: ty::ClosureKind, // fn call_once(self, ...) { call_mut(&self, ...) } // fn call_once(mut self, ...) { call_mut(&mut self, ...) } // - // These are both the same at trans time. + // These are both the same at codegen time. Ok(true) } (ty::ClosureKind::FnMut, _) | @@ -356,13 +355,12 @@ fn fn_once_adapter_instance<'a, 'tcx>( .unwrap().def_id; let def = ty::InstanceDef::ClosureOnceShim { call_once }; - let self_ty = tcx.mk_closure_from_closure_substs( - closure_did, substs); + let self_ty = tcx.mk_closure(closure_did, substs); let sig = substs.closure_sig(closure_did, tcx); let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); assert_eq!(sig.inputs().len(), 1); - let substs = tcx.mk_substs([Kind::from(self_ty), sig.inputs()[0].into()].iter().cloned()); + let substs = tcx.mk_substs_trait(self_ty, &[sig.inputs()[0].into()]); debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); Instance { def, substs } diff --git a/src/librustc/ty/item_path.rs b/src/librustc/ty/item_path.rs index 752b7f69a6a7f..c44b7327a0830 100644 --- a/src/librustc/ty/item_path.rs +++ b/src/librustc/ty/item_path.rs @@ -169,7 +169,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { let data = cur_def_key.disambiguated_data.data; let symbol = data.get_opt_name().map(|n| n.as_str()).unwrap_or_else(|| { - Symbol::intern("").as_str() + if let DefPathData::CrateRoot = data { // reexported `extern crate` (#43189) + self.original_crate_name(cur_def.krate).as_str() + } else { + Symbol::intern("").as_str() + } }); cur_path.push(symbol); @@ -208,17 +212,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { data @ DefPathData::Trait(..) | data @ DefPathData::AssocTypeInTrait(..) | data @ DefPathData::AssocTypeInImpl(..) | + data @ DefPathData::AssocExistentialInImpl(..) | data @ DefPathData::ValueNs(..) | data @ DefPathData::Module(..) | data @ DefPathData::TypeParam(..) | - data @ DefPathData::LifetimeDef(..) | + data @ DefPathData::LifetimeParam(..) | data @ DefPathData::EnumVariant(..) | data @ DefPathData::Field(..) | - data @ DefPathData::Initializer | + data @ DefPathData::AnonConst | data @ DefPathData::MacroDef(..) | data @ DefPathData::ClosureExpr | data @ DefPathData::ImplTrait | - data @ DefPathData::Typeof | data @ DefPathData::GlobalMetaData(..) => { let parent_def_id = self.parent_def_id(def_id).unwrap(); self.push_item_path(buffer, parent_def_id); @@ -311,7 +315,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { ty::TyUint(_) | ty::TyFloat(_) | ty::TyStr => { - buffer.push(&format!("{}", self_ty)); + buffer.push(&self_ty.to_string()); } _ => { @@ -360,8 +364,9 @@ pub fn characteristic_def_id_of_type(ty: Ty) -> Option { ty::TyArray(subty, _) | ty::TySlice(subty) => characteristic_def_id_of_type(subty), - ty::TyRawPtr(mt) | - ty::TyRef(_, mt) => characteristic_def_id_of_type(mt.ty), + ty::TyRawPtr(mt) => characteristic_def_id_of_type(mt.ty), + + ty::TyRef(_, ty, _) => characteristic_def_id_of_type(ty), ty::TyTuple(ref tys) => tys.iter() .filter_map(|ty| characteristic_def_id_of_type(ty)) diff --git a/src/librustc/ty/layout.rs b/src/librustc/ty/layout.rs index a319b341ebbf0..81cc897232ab0 100644 --- a/src/librustc/ty/layout.rs +++ b/src/librustc/ty/layout.rs @@ -11,13 +11,14 @@ use session::{self, DataTypeKind}; use ty::{self, Ty, TyCtxt, TypeFoldable, ReprOptions}; -use syntax::ast::{self, FloatTy, IntTy, UintTy}; +use syntax::ast::{self, IntTy, UintTy}; use syntax::attr; use syntax_pos::DUMMY_SP; use std::cmp; use std::fmt; use std::i128; +use std::iter; use std::mem; use ich::StableHashingContext; @@ -129,8 +130,8 @@ impl PrimitiveExt for Primitive { fn to_ty<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> { match *self { Int(i, signed) => i.to_ty(tcx, signed), - F32 => tcx.types.f32, - F64 => tcx.types.f64, + Float(FloatTy::F32) => tcx.types.f32, + Float(FloatTy::F64) => tcx.types.f64, Pointer => tcx.mk_mut_ptr(tcx.mk_nil()), } } @@ -193,8 +194,8 @@ fn layout_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) } -pub fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { layout_raw, ..*providers }; @@ -230,7 +231,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { LayoutDetails { variants: Variants::Single { index: 0 }, fields: FieldPlacement::Arbitrary { - offsets: vec![Size::from_bytes(0), b_offset], + offsets: vec![Size::ZERO, b_offset], memory_index: vec![0, 1] }, abi: Abi::ScalarPair(a, b), @@ -266,7 +267,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { }; let mut sized = true; - let mut offsets = vec![Size::from_bytes(0); fields.len()]; + let mut offsets = vec![Size::ZERO; fields.len()]; let mut inverse_memory_index: Vec = (0..fields.len() as u32).collect(); let mut optimize = !repr.inhibit_struct_field_reordering_opt(); @@ -306,7 +307,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // field 5 with offset 0 puts 0 in offsets[5]. // At the bottom of this function, we use inverse_memory_index to produce memory_index. - let mut offset = Size::from_bytes(0); + let mut offset = Size::ZERO; if let StructKind::Prefixed(prefix_size, prefix_align) = kind { if packed { @@ -325,10 +326,6 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { offsets.len(), ty); } - if field.abi == Abi::Uninhabited { - return Ok(LayoutDetails::uninhabited(fields.len())); - } - if field.is_unsized() { sized = false; } @@ -451,6 +448,10 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } + if sized && fields.iter().any(|f| f.abi == Abi::Uninhabited) { + abi = Abi::Uninhabited; + } + Ok(LayoutDetails { variants: Variants::Single { index: 0 }, fields: FieldPlacement::Arbitrary { @@ -487,8 +488,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { ty::TyUint(ity) => { scalar(Int(Integer::from_attr(dl, attr::UnsignedInt(ity)), false)) } - ty::TyFloat(FloatTy::F32) => scalar(F32), - ty::TyFloat(FloatTy::F64) => scalar(F64), + ty::TyFloat(fty) => scalar(Float(fty)), ty::TyFnPtr(_) => { let mut ptr = scalar_unit(Pointer); ptr.valid_range = 1..=*ptr.valid_range.end(); @@ -497,11 +497,17 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // The never type. ty::TyNever => { - tcx.intern_layout(LayoutDetails::uninhabited(0)) + tcx.intern_layout(LayoutDetails { + variants: Variants::Single { index: 0 }, + fields: FieldPlacement::Union(0), + abi: Abi::Uninhabited, + align: dl.i8_align, + size: Size::ZERO + }) } // Potentially-fat pointers. - ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRef(_, pointee, _) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { let mut data_ptr = scalar_unit(Pointer); if !ty.is_unsafe_ptr() { @@ -543,7 +549,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } let element = self.layout_of(element)?; - let count = count.val.unwrap_u64(); + let count = count.unwrap_usize(tcx); let size = element.size.checked_mul(count, dl) .ok_or(LayoutError::SizeOverflow(ty))?; @@ -568,7 +574,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { }, abi: Abi::Aggregate { sized: false }, align: element.align, - size: Size::from_bytes(0) + size: Size::ZERO }) } ty::TyStr => { @@ -580,7 +586,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { }, abi: Abi::Aggregate { sized: false }, align: dl.i8_align, - size: Size::from_bytes(0) + size: Size::ZERO }) } @@ -689,7 +695,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { Align::from_bytes(repr_align, repr_align).unwrap()); } - let mut size = Size::from_bytes(0); + let mut size = Size::ZERO; for field in &variants[0] { assert!(!field.is_unsized()); @@ -711,27 +717,37 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { })); } - let (inh_first, inh_second) = { - let mut inh_variants = (0..variants.len()).filter(|&v| { - variants[v].iter().all(|f| f.abi != Abi::Uninhabited) + // A variant is absent if it's uninhabited and only has ZST fields. + // Present uninhabited variants only require space for their fields, + // but *not* an encoding of the discriminant (e.g. a tag value). + // See issue #49298 for more details on the need to leave space + // for non-ZST uninhabited data (mostly partial initialization). + let absent = |fields: &[TyLayout]| { + let uninhabited = fields.iter().any(|f| f.abi == Abi::Uninhabited); + let is_zst = fields.iter().all(|f| f.is_zst()); + uninhabited && is_zst + }; + let (present_first, present_second) = { + let mut present_variants = (0..variants.len()).filter(|&v| { + !absent(&variants[v]) }); - (inh_variants.next(), inh_variants.next()) + (present_variants.next(), present_variants.next()) }; - if inh_first.is_none() { - // Uninhabited because it has no variants, or only uninhabited ones. - return Ok(tcx.intern_layout(LayoutDetails::uninhabited(0))); + if present_first.is_none() { + // Uninhabited because it has no variants, or only absent ones. + return tcx.layout_raw(param_env.and(tcx.types.never)); } let is_struct = !def.is_enum() || - // Only one variant is inhabited. - (inh_second.is_none() && + // Only one variant is present. + (present_second.is_none() && // Representation optimizations are allowed. !def.repr.inhibit_enum_layout_opt()); if is_struct { // Struct, or univariant enum equivalent to a struct. // (Typechecking will reject discriminant-sizing attrs.) - let v = inh_first.unwrap(); + let v = present_first.unwrap(); let kind = if def.is_enum() || variants[v].len() == 0 { StructKind::AlwaysSized } else { @@ -773,7 +789,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // Find one non-ZST variant. 'variants: for (v, fields) in variants.iter().enumerate() { - if fields.iter().any(|f| f.abi == Abi::Uninhabited) { + if absent(fields) { continue 'variants; } for f in fields { @@ -797,11 +813,15 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { if let Some(i) = dataful_variant { let count = (niche_variants.end() - niche_variants.start() + 1) as u128; for (field_index, &field) in variants[i].iter().enumerate() { - let (offset, niche, niche_start) = - match self.find_niche(field, count)? { - Some(niche) => niche, - None => continue - }; + let niche = match self.find_niche(field)? { + Some(niche) => niche, + _ => continue, + }; + let (niche_start, niche_scalar) = match niche.reserve(self, count) { + Some(pair) => pair, + None => continue, + }; + let mut align = dl.aggregate_align; let st = variants.iter().enumerate().map(|(j, v)| { let mut st = univariant_uninterned(v, @@ -813,11 +833,11 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { Ok(st) }).collect::, _>>()?; - let offset = st[i].fields.offset(field_index) + offset; + let offset = st[i].fields.offset(field_index) + niche.offset; let size = st[i].size; - let abi = match st[i].abi { - Abi::Scalar(_) => Abi::Scalar(niche.clone()), + let mut abi = match st[i].abi { + Abi::Scalar(_) => Abi::Scalar(niche_scalar.clone()), Abi::ScalarPair(ref first, ref second) => { // We need to use scalar_unit to reset the // valid range to the maximal one for that @@ -825,19 +845,29 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // guaranteed to be initialised, not the // other primitive. if offset.bytes() == 0 { - Abi::ScalarPair(niche.clone(), scalar_unit(second.value)) + Abi::ScalarPair( + niche_scalar.clone(), + scalar_unit(second.value), + ) } else { - Abi::ScalarPair(scalar_unit(first.value), niche.clone()) + Abi::ScalarPair( + scalar_unit(first.value), + niche_scalar.clone(), + ) } } _ => Abi::Aggregate { sized: true }, }; + if st.iter().all(|v| v.abi == Abi::Uninhabited) { + abi = Abi::Uninhabited; + } + return Ok(tcx.intern_layout(LayoutDetails { variants: Variants::NicheFilling { dataful_variant: i, niche_variants, - niche, + niche: niche_scalar, niche_start, variants: st, }, @@ -868,11 +898,16 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { if x < min { min = x; } if x > max { max = x; } } + // We might have no inhabited variants, so pretend there's at least one. + if (min, max) == (i128::max_value(), i128::min_value()) { + min = 0; + max = 0; + } assert!(min <= max, "discriminant range is {}...{}", min, max); let (min_ity, signed) = Integer::repr_discr(tcx, ty, &def.repr, min, max); let mut align = dl.aggregate_align; - let mut size = Size::from_bytes(0); + let mut size = Size::ZERO; // We're interested in the smallest alignment, so start large. let mut start_align = Align::from_bytes(256, 256).unwrap(); @@ -924,14 +959,14 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // because this discriminant will be loaded, and then stored into variable of // type calculated by typeck. Consider such case (a bug): typeck decided on // byte-sized discriminant, but layout thinks we need a 16-bit to store all - // discriminant values. That would be a bug, because then, in trans, in order + // discriminant values. That would be a bug, because then, in codegen, in order // to store this 16-bit discriminant into 8-bit sized temporary some of the // space necessary to represent would have to be discarded (or layout is wrong // on thinking it needs 16 bits) bug!("layout decided on a larger discriminant type ({:?}) than typeck ({:?})", min_ity, typeck_ity); // However, it is fine to make discr type however large (as an optimisation) - // after this point – we’ll just truncate the value we load in trans. + // after this point – we’ll just truncate the value we load in codegen. } // Check to see if we should use a different type for the @@ -959,9 +994,6 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let old_ity_size = min_ity.size(); let new_ity_size = ity.size(); for variant in &mut layout_variants { - if variant.abi == Abi::Uninhabited { - continue; - } match variant.fields { FieldPlacement::Arbitrary { ref mut offsets, .. } => { for i in offsets { @@ -988,13 +1020,8 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let mut abi = Abi::Aggregate { sized: true }; if tag.value.size(dl) == size { abi = Abi::Scalar(tag.clone()); - } else if !tag.is_bool() { - // HACK(nox): Blindly using ScalarPair for all tagged enums - // where applicable leads to Option being handled as {i1, i8}, - // which later confuses SROA and some loop optimisations, - // ultimately leading to the repeat-trusted-len test - // failing. We make the trade-off of using ScalarPair only - // for types where the tag isn't a boolean. + } else { + // Try to use a ScalarPair for all tagged enums. let mut common_prim = None; for (field_layouts, layout_variant) in variants.iter().zip(&layout_variants) { let offsets = match layout_variant.fields { @@ -1045,7 +1072,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } _ => bug!() }; - if pair_offsets[0] == Size::from_bytes(0) && + if pair_offsets[0] == Size::ZERO && pair_offsets[1] == *offset && align == pair.align && size == pair.size { @@ -1055,13 +1082,18 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } } + + if layout_variants.iter().all(|v| v.abi == Abi::Uninhabited) { + abi = Abi::Uninhabited; + } + tcx.intern_layout(LayoutDetails { variants: Variants::Tagged { - discr: tag, + tag, variants: layout_variants, }, fields: FieldPlacement::Arbitrary { - offsets: vec![Size::from_bytes(0)], + offsets: vec![Size::ZERO], memory_index: vec![0] }, abi, @@ -1078,12 +1110,12 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } tcx.layout_raw(param_env.and(normalized))? } - ty::TyParam(_) => { - return Err(LayoutError::Unknown(ty)); - } - ty::TyGeneratorWitness(..) | ty::TyInfer(_) | ty::TyError => { + ty::TyGeneratorWitness(..) | ty::TyInfer(_) => { bug!("LayoutDetails::compute: unexpected type `{}`", ty) } + ty::TyParam(_) | ty::TyError => { + return Err(LayoutError::Unknown(ty)); + } }) } @@ -1094,7 +1126,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { // If we are running with `-Zprint-type-sizes`, record layouts for // dumping later. Ignore layouts that are done with non-empty // environments or non-monomorphic layouts, as the user only wants - // to see the stuff resulting from the final trans session. + // to see the stuff resulting from the final codegen session. if !self.tcx.sess.opts.debugging_opts.print_type_sizes || layout.ty.has_param_types() || @@ -1144,7 +1176,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let build_variant_info = |n: Option, flds: &[ast::Name], layout: TyLayout<'tcx>| { - let mut min_size = Size::from_bytes(0); + let mut min_size = Size::ZERO; let field_info: Vec<_> = flds.iter().enumerate().map(|(i, &name)| { match layout.field(self, i) { Err(err) => { @@ -1190,7 +1222,7 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { if !adt_def.variants.is_empty() { let variant_def = &adt_def.variants[index]; let fields: Vec<_> = - variant_def.fields.iter().map(|f| f.name).collect(); + variant_def.fields.iter().map(|f| f.ident.name).collect(); record(adt_kind.into(), adt_packed, None, @@ -1211,14 +1243,14 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let variant_infos: Vec<_> = adt_def.variants.iter().enumerate().map(|(i, variant_def)| { let fields: Vec<_> = - variant_def.fields.iter().map(|f| f.name).collect(); + variant_def.fields.iter().map(|f| f.ident.name).collect(); build_variant_info(Some(variant_def.name), &fields, layout.for_variant(self, i)) }) .collect(); record(adt_kind.into(), adt_packed, match layout.variants { - Variants::Tagged { ref discr, .. } => Some(discr.value.size(self)), + Variants::Tagged { ref tag, .. } => Some(tag.value.size(self)), _ => None }, variant_infos); } @@ -1262,7 +1294,7 @@ impl<'a, 'tcx> SizeSkeleton<'tcx> { }; match ty.sty { - ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRef(_, pointee, _) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { let non_zero = !ty.is_unsafe_ptr(); let tail = tcx.struct_tail(pointee); @@ -1444,7 +1476,7 @@ impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } } -impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> { +impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, ty::query::TyCtxtAt<'a, 'tcx, 'tcx>> { type Ty = Ty<'tcx>; type TyLayout = Result, LayoutError<'tcx>>; @@ -1476,28 +1508,28 @@ impl<'a, 'tcx> LayoutOf for LayoutCx<'tcx, ty::maps::TyCtxtAt<'a, 'tcx, 'tcx>> { } // Helper (inherent) `layout_of` methods to avoid pushing `LayoutCx` to users. -impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { +impl TyCtxt<'a, 'tcx, '_> { /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. #[inline] pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result, LayoutError<'tcx>> { let cx = LayoutCx { - tcx: self, + tcx: self.global_tcx(), param_env: param_env_and_ty.param_env }; cx.layout_of(param_env_and_ty.value) } } -impl<'a, 'tcx> ty::maps::TyCtxtAt<'a, 'tcx, 'tcx> { +impl ty::query::TyCtxtAt<'a, 'tcx, '_> { /// Computes the layout of a type. Note that this implicitly /// executes in "reveal all" mode. #[inline] pub fn layout_of(self, param_env_and_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> Result, LayoutError<'tcx>> { let cx = LayoutCx { - tcx: self, + tcx: self.global_tcx().at(self.span), param_env: param_env_and_ty.param_env }; cx.layout_of(param_env_and_ty.value) @@ -1523,9 +1555,14 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> ty::TyAdt(def, _) => def.variants[variant_index].fields.len(), _ => bug!() }; - let mut details = LayoutDetails::uninhabited(fields); - details.variants = Variants::Single { index: variant_index }; - cx.tcx().intern_layout(details) + let tcx = cx.tcx(); + tcx.intern_layout(LayoutDetails { + variants: Variants::Single { index: variant_index }, + fields: FieldPlacement::Union(fields), + abi: Abi::Uninhabited, + align: tcx.data_layout.i8_align, + size: Size::ZERO + }) } Variants::NicheFilling { ref variants, .. } | @@ -1560,9 +1597,9 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } // Potentially-fat pointers. - ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRef(_, pointee, _) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - assert!(i < 2); + assert!(i < this.fields.count()); // Reuse the fat *T type as its own thin pointer data field. // This provides information about e.g. DST struct pointees @@ -1584,10 +1621,25 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> match tcx.struct_tail(pointee).sty { ty::TySlice(_) | ty::TyStr => tcx.types.usize, - ty::TyDynamic(..) => { - // FIXME(eddyb) use an usize/fn() array with - // the correct number of vtables slots. - tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil()) + ty::TyDynamic(data, _) => { + let trait_def_id = data.principal().unwrap().def_id(); + let num_fns: u64 = crate::traits::supertrait_def_ids(tcx, trait_def_id) + .map(|trait_def_id| { + tcx.associated_items(trait_def_id) + .filter(|item| item.kind == ty::AssociatedKind::Method) + .count() as u64 + }) + .sum(); + tcx.mk_imm_ref( + tcx.types.re_static, + tcx.mk_array(tcx.types.usize, 3 + num_fns), + ) + /* FIXME use actual fn pointers + tcx.mk_tup(&[ + tcx.mk_array(tcx.types.usize, 3), + tcx.mk_array(Option), + ]) + */ } _ => bug!("TyLayout::field_type({:?}): not applicable", this) } @@ -1622,7 +1674,7 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } // Discriminant field for enums (where applicable). - Variants::Tagged { ref discr, .. } | + Variants::Tagged { tag: ref discr, .. } | Variants::NicheFilling { niche: ref discr, .. } => { assert_eq!(i, 0); let layout = LayoutDetails::scalar(tcx, discr.clone()); @@ -1642,16 +1694,37 @@ impl<'a, 'tcx, C> TyLayoutMethods<'tcx, C> for Ty<'tcx> } } +struct Niche { + offset: Size, + scalar: Scalar, + available: u128, +} + +impl Niche { + fn reserve<'a, 'tcx>( + &self, + cx: LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>>, + count: u128, + ) -> Option<(u128, Scalar)> { + if count > self.available { + return None; + } + let Scalar { value, valid_range: ref v } = self.scalar; + let bits = value.size(cx).bits(); + assert!(bits <= 128); + let max_value = !0u128 >> (128 - bits); + let start = v.end().wrapping_add(1) & max_value; + let end = v.end().wrapping_add(count) & max_value; + Some((start, Scalar { value, valid_range: *v.start()..=end })) + } +} + impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { /// Find the offset of a niche leaf field, starting from - /// the given type and recursing through aggregates, which - /// has at least `count` consecutive invalid values. - /// The tuple is `(offset, scalar, niche_value)`. + /// the given type and recursing through aggregates. // FIXME(eddyb) traverse already optimized enums. - fn find_niche(self, layout: TyLayout<'tcx>, count: u128) - -> Result, LayoutError<'tcx>> - { - let scalar_component = |scalar: &Scalar, offset| { + fn find_niche(self, layout: TyLayout<'tcx>) -> Result, LayoutError<'tcx>> { + let scalar_niche = |scalar: &Scalar, offset| { let Scalar { value, valid_range: ref v } = *scalar; let bits = value.size(self).bits(); @@ -1659,23 +1732,18 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { let max_value = !0u128 >> (128 - bits); // Find out how many values are outside the valid range. - let niches = if v.start() <= v.end() { + let available = if v.start() <= v.end() { v.start() + (max_value - v.end()) } else { v.start() - v.end() - 1 }; - // Give up if we can't fit `count` consecutive niches. - if count > niches { + // Give up if there is no niche value available. + if available == 0 { return None; } - let niche_start = v.end().wrapping_add(1) & max_value; - let niche_end = v.end().wrapping_add(count) & max_value; - Some((offset, Scalar { - value, - valid_range: *v.start()..=niche_end - }, niche_start)) + Some(Niche { offset, scalar: scalar.clone(), available }) }; // Locals variables which live across yields are stored @@ -1687,15 +1755,19 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { match layout.abi { Abi::Scalar(ref scalar) => { - return Ok(scalar_component(scalar, Size::from_bytes(0))); + return Ok(scalar_niche(scalar, Size::ZERO)); } Abi::ScalarPair(ref a, ref b) => { - return Ok(scalar_component(a, Size::from_bytes(0)).or_else(|| { - scalar_component(b, a.value.size(self).abi_align(b.value.align(self))) - })); + // HACK(nox): We iter on `b` and then `a` because `max_by_key` + // returns the last maximum. + let niche = iter::once((b, a.value.size(self).abi_align(b.value.align(self)))) + .chain(iter::once((a, Size::ZERO))) + .filter_map(|(scalar, offset)| scalar_niche(scalar, offset)) + .max_by_key(|niche| niche.available); + return Ok(niche); } Abi::Vector { ref element, .. } => { - return Ok(scalar_component(element, Size::from_bytes(0))); + return Ok(scalar_niche(element, Size::ZERO)); } _ => {} } @@ -1710,17 +1782,23 @@ impl<'a, 'tcx> LayoutCx<'tcx, TyCtxt<'a, 'tcx, 'tcx>> { } if let FieldPlacement::Array { .. } = layout.fields { if layout.fields.count() > 0 { - return self.find_niche(layout.field(self, 0)?, count); + return self.find_niche(layout.field(self, 0)?); + } else { + return Ok(None); } } + let mut niche = None; + let mut available = 0; for i in 0..layout.fields.count() { - let r = self.find_niche(layout.field(self, i)?, count)?; - if let Some((offset, scalar, niche_value)) = r { - let offset = layout.fields.offset(i) + offset; - return Ok(Some((offset, scalar, niche_value))); + if let Some(mut c) = self.find_niche(layout.field(self, i)?)? { + if c.available > available { + available = c.available; + c.offset += layout.fields.offset(i); + niche = Some(c); + } } } - Ok(None) + Ok(niche) } } @@ -1736,10 +1814,10 @@ impl<'a> HashStable> for Variants { index.hash_stable(hcx, hasher); } Tagged { - ref discr, + ref tag, ref variants, } => { - discr.hash_stable(hcx, hasher); + tag.hash_stable(hcx, hasher); variants.hash_stable(hcx, hasher); } NicheFilling { @@ -1839,8 +1917,7 @@ impl_stable_hash_for!(enum ::ty::layout::Integer { impl_stable_hash_for!(enum ::ty::layout::Primitive { Int(integer, signed), - F32, - F64, + Float(fty), Pointer }); diff --git a/src/librustc/ty/maps/README.md b/src/librustc/ty/maps/README.md deleted file mode 100644 index 8207c18e67791..0000000000000 --- a/src/librustc/ty/maps/README.md +++ /dev/null @@ -1,302 +0,0 @@ -# The Rust Compiler Query System - -The Compiler Query System is the key to our new demand-driven -organization. The idea is pretty simple. You have various queries -that compute things about the input -- for example, there is a query -called `type_of(def_id)` that, given the def-id of some item, will -compute the type of that item and return it to you. - -Query execution is **memoized** -- so the first time you invoke a -query, it will go do the computation, but the next time, the result is -returned from a hashtable. Moreover, query execution fits nicely into -**incremental computation**; the idea is roughly that, when you do a -query, the result **may** be returned to you by loading stored data -from disk (but that's a separate topic we won't discuss further here). - -The overall vision is that, eventually, the entire compiler -control-flow will be query driven. There will effectively be one -top-level query ("compile") that will run compilation on a crate; this -will in turn demand information about that crate, starting from the -*end*. For example: - -- This "compile" query might demand to get a list of codegen-units - (i.e., modules that need to be compiled by LLVM). -- But computing the list of codegen-units would invoke some subquery - that returns the list of all modules defined in the Rust source. -- That query in turn would invoke something asking for the HIR. -- This keeps going further and further back until we wind up doing the - actual parsing. - -However, that vision is not fully realized. Still, big chunks of the -compiler (for example, generating MIR) work exactly like this. - -### Invoking queries - -To invoke a query is simple. The tcx ("type context") offers a method -for each defined query. So, for example, to invoke the `type_of` -query, you would just do this: - -```rust -let ty = tcx.type_of(some_def_id); -``` - -### Cycles between queries - -Currently, cycles during query execution should always result in a -compilation error. Typically, they arise because of illegal programs -that contain cyclic references they shouldn't (though sometimes they -arise because of compiler bugs, in which case we need to factor our -queries in a more fine-grained fashion to avoid them). - -However, it is nonetheless often useful to *recover* from a cycle -(after reporting an error, say) and try to soldier on, so as to give a -better user experience. In order to recover from a cycle, you don't -get to use the nice method-call-style syntax. Instead, you invoke -using the `try_get` method, which looks roughly like this: - -```rust -use ty::maps::queries; -... -match queries::type_of::try_get(tcx, DUMMY_SP, self.did) { - Ok(result) => { - // no cycle occurred! You can use `result` - } - Err(err) => { - // A cycle occurred! The error value `err` is a `DiagnosticBuilder`, - // meaning essentially an "in-progress", not-yet-reported error message. - // See below for more details on what to do here. - } -} -``` - -So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This means that -you must ensure that a compiler error message is reported. You can do that in two ways: - -The simplest is to invoke `err.emit()`. This will emit the cycle error to the user. - -However, often cycles happen because of an illegal program, and you -know at that point that an error either already has been reported or -will be reported due to this cycle by some other bit of code. In that -case, you can invoke `err.cancel()` to not emit any error. It is -traditional to then invoke: - -``` -tcx.sess.delay_span_bug(some_span, "some message") -``` - -`delay_span_bug()` is a helper that says: we expect a compilation -error to have happened or to happen in the future; so, if compilation -ultimately succeeds, make an ICE with the message `"some -message"`. This is basically just a precaution in case you are wrong. - -### How the compiler executes a query - -So you may be wondering what happens when you invoke a query -method. The answer is that, for each query, the compiler maintains a -cache -- if your query has already been executed, then, the answer is -simple: we clone the return value out of the cache and return it -(therefore, you should try to ensure that the return types of queries -are cheaply cloneable; insert a `Rc` if necessary). - -#### Providers - -If, however, the query is *not* in the cache, then the compiler will -try to find a suitable **provider**. A provider is a function that has -been defined and linked into the compiler somewhere that contains the -code to compute the result of the query. - -**Providers are defined per-crate.** The compiler maintains, -internally, a table of providers for every crate, at least -conceptually. Right now, there are really two sets: the providers for -queries about the **local crate** (that is, the one being compiled) -and providers for queries about **external crates** (that is, -dependencies of the local crate). Note that what determines the crate -that a query is targeting is not the *kind* of query, but the *key*. -For example, when you invoke `tcx.type_of(def_id)`, that could be a -local query or an external query, depending on what crate the `def_id` -is referring to (see the `self::keys::Key` trait for more information -on how that works). - -Providers always have the same signature: - -```rust -fn provider<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx, 'tcx>, - key: QUERY_KEY) - -> QUERY_RESULT -{ - ... -} -``` - -Providers take two arguments: the `tcx` and the query key. Note also -that they take the *global* tcx (i.e., they use the `'tcx` lifetime -twice), rather than taking a tcx with some active inference context. -They return the result of the query. - -#### How providers are setup - -When the tcx is created, it is given the providers by its creator using -the `Providers` struct. This struct is generate by the macros here, but it -is basically a big list of function pointers: - -```rust -struct Providers { - type_of: for<'cx, 'tcx> fn(TyCtxt<'cx, 'tcx, 'tcx>, DefId) -> Ty<'tcx>, - ... -} -``` - -At present, we have one copy of the struct for local crates, and one -for external crates, though the plan is that we may eventually have -one per crate. - -These `Provider` structs are ultimately created and populated by -`librustc_driver`, but it does this by distributing the work -throughout the other `rustc_*` crates. This is done by invoking -various `provide` functions. These functions tend to look something -like this: - -```rust -pub fn provide(providers: &mut Providers) { - *providers = Providers { - type_of, - ..*providers - }; -} -``` - -That is, they take an `&mut Providers` and mutate it in place. Usually -we use the formulation above just because it looks nice, but you could -as well do `providers.type_of = type_of`, which would be equivalent. -(Here, `type_of` would be a top-level function, defined as we saw -before.) So, if we want to add a provider for some other query, -let's call it `fubar`, into the crate above, we might modify the `provide()` -function like so: - -```rust -pub fn provide(providers: &mut Providers) { - *providers = Providers { - type_of, - fubar, - ..*providers - }; -} - -fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. } -``` - -NB. Most of the `rustc_*` crates only provide **local -providers**. Almost all **extern providers** wind up going through the -`rustc_metadata` crate, which loads the information from the crate -metadata. But in some cases there are crates that provide queries for -*both* local and external crates, in which case they define both a -`provide` and a `provide_extern` function that `rustc_driver` can -invoke. - -### Adding a new kind of query - -So suppose you want to add a new kind of query, how do you do so? -Well, defining a query takes place in two steps: - -1. first, you have to specify the query name and arguments; and then, -2. you have to supply query providers where needed. - -To specify the query name and arguments, you simply add an entry -to the big macro invocation in `mod.rs`. This will probably have changed -by the time you read this README, but at present it looks something -like: - -``` -define_maps! { <'tcx> - /// Records the type of every item. - [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, - - ... -} -``` - -Each line of the macro defines one query. The name is broken up like this: - -``` -[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, -^^ ^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^ -| | | | | -| | | | result type of query -| | | query key type -| | dep-node constructor -| name of query -query flags -``` - -Let's go over them one by one: - -- **Query flags:** these are largely unused right now, but the intention - is that we'll be able to customize various aspects of how the query is - processed. -- **Name of query:** the name of the query method - (`tcx.type_of(..)`). Also used as the name of a struct - (`ty::maps::queries::type_of`) that will be generated to represent - this query. -- **Dep-node constructor:** indicates the constructor function that - connects this query to incremental compilation. Typically, this is a - `DepNode` variant, which can be added by modifying the - `define_dep_nodes!` macro invocation in - `librustc/dep_graph/dep_node.rs`. - - However, sometimes we use a custom function, in which case the - name will be in snake case and the function will be defined at the - bottom of the file. This is typically used when the query key is - not a def-id, or just not the type that the dep-node expects. -- **Query key type:** the type of the argument to this query. - This type must implement the `ty::maps::keys::Key` trait, which - defines (for example) how to map it to a crate, and so forth. -- **Result type of query:** the type produced by this query. This type - should (a) not use `RefCell` or other interior mutability and (b) be - cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for - non-trivial data types. - - The one exception to those rules is the `ty::steal::Steal` type, - which is used to cheaply modify MIR in place. See the definition - of `Steal` for more details. New uses of `Steal` should **not** be - added without alerting `@rust-lang/compiler`. - -So, to add a query: - -- Add an entry to `define_maps!` using the format above. -- Possibly add a corresponding entry to the dep-node macro. -- Link the provider by modifying the appropriate `provide` method; - or add a new one if needed and ensure that `rustc_driver` is invoking it. - -#### Query structs and descriptions - -For each kind, the `define_maps` macro will generate a "query struct" -named after the query. This struct is a kind of a place-holder -describing the query. Each such struct implements the -`self::config::QueryConfig` trait, which has associated types for the -key/value of that particular query. Basically the code generated looks something -like this: - -```rust -// Dummy struct representing a particular kind of query: -pub struct type_of<'tcx> { phantom: PhantomData<&'tcx ()> } - -impl<'tcx> QueryConfig for type_of<'tcx> { - type Key = DefId; - type Value = Ty<'tcx>; -} -``` - -There is an additional trait that you may wish to implement called -`self::config::QueryDescription`. This trait is used during cycle -errors to give a "human readable" name for the query, so that we can -summarize what was happening when the cycle occurred. Implementing -this trait is optional if the query key is `DefId`, but if you *don't* -implement it, you get a pretty generic error ("processing `foo`..."). -You can put new impls into the `config` module. They look something like this: - -```rust -impl<'tcx> QueryDescription for queries::type_of<'tcx> { - fn describe(tcx: TyCtxt, key: DefId) -> String { - format!("computing the type of `{}`", tcx.item_path_str(key)) - } -} -``` - diff --git a/src/librustc/ty/maps/job.rs b/src/librustc/ty/maps/job.rs deleted file mode 100644 index 3b6af018d6b78..0000000000000 --- a/src/librustc/ty/maps/job.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use rustc_data_structures::sync::{Lock, Lrc}; -use syntax_pos::Span; -use ty::tls; -use ty::maps::Query; -use ty::maps::plumbing::CycleError; -use ty::context::TyCtxt; -use errors::Diagnostic; - -/// Indicates the state of a query for a given key in a query map -pub(super) enum QueryResult<'tcx> { - /// An already executing query. The query job can be used to await for its completion - Started(Lrc>), - - /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic - Poisoned, -} - -/// A span and a query key -#[derive(Clone, Debug)] -pub struct QueryInfo<'tcx> { - /// The span for a reason this query was required - pub span: Span, - pub query: Query<'tcx>, -} - -/// A object representing an active query job. -pub struct QueryJob<'tcx> { - pub info: QueryInfo<'tcx>, - - /// The parent query job which created this job and is implicitly waiting on it. - pub parent: Option>>, - - /// Diagnostic messages which are emitted while the query executes - pub diagnostics: Lock>, -} - -impl<'tcx> QueryJob<'tcx> { - /// Creates a new query job - pub fn new(info: QueryInfo<'tcx>, parent: Option>>) -> Self { - QueryJob { - diagnostics: Lock::new(Vec::new()), - info, - parent, - } - } - - /// Awaits for the query job to complete. - /// - /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any - /// query that means that there is a query cycle, thus this always running a cycle error. - pub(super) fn await<'lcx>( - &self, - tcx: TyCtxt<'_, 'tcx, 'lcx>, - span: Span, - ) -> Result<(), CycleError<'tcx>> { - // Get the current executing query (waiter) and find the waitee amongst its parents - let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone()); - let mut cycle = Vec::new(); - - while let Some(job) = current_job { - cycle.insert(0, job.info.clone()); - - if &*job as *const _ == self as *const _ { - // This is the end of the cycle - // The span entry we included was for the usage - // of the cycle itself, and not part of the cycle - // Replace it with the span which caused the cycle to form - cycle[0].span = span; - // Find out why the cycle itself was used - let usage = job.parent.as_ref().map(|parent| { - (job.info.span, parent.info.query.clone()) - }); - return Err(CycleError { usage, cycle }); - } - - current_job = job.parent.clone(); - } - - panic!("did not find a cycle") - } - - /// Signals to waiters that the query is complete. - /// - /// This does nothing for single threaded rustc, - /// as there are no concurrent jobs which could be waiting on us - pub fn signal_complete(&self) {} -} diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs deleted file mode 100644 index d89846a75ef51..0000000000000 --- a/src/librustc/ty/maps/mod.rs +++ /dev/null @@ -1,627 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use dep_graph::{DepConstructor, DepNode}; -use hir::def_id::{CrateNum, DefId, DefIndex}; -use hir::def::{Def, Export}; -use hir::{self, TraitCandidate, ItemLocalId, TransFnAttrs}; -use hir::svh::Svh; -use infer::canonical::{self, Canonical}; -use lint; -use middle::borrowck::BorrowCheckResult; -use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; -use middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; -use middle::privacy::AccessLevels; -use middle::reachable::ReachableSet; -use middle::region; -use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault}; -use middle::stability::{self, DeprecationEntry}; -use middle::lang_items::{LanguageItems, LangItem}; -use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; -use middle::const_val::EvalResult; -use mir::mono::{CodegenUnit, Stats}; -use mir; -use mir::interpret::{GlobalId}; -use session::{CompileResult, CrateDisambiguator}; -use session::config::OutputFilenames; -use traits::{self, Vtable}; -use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, - CanonicalTyGoal, NoSolution}; -use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; -use traits::query::normalize::NormalizationResult; -use traits::specialization_graph; -use traits::Clauses; -use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; -use ty::steal::Steal; -use ty::subst::Substs; -use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; -use util::common::{ErrorReported}; - -use rustc_data_structures::indexed_set::IdxSetBuf; -use rustc_target::spec::PanicStrategy; -use rustc_data_structures::indexed_vec::IndexVec; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_data_structures::stable_hasher::StableVec; - -use std::ops::Deref; -use rustc_data_structures::sync::Lrc; -use std::sync::Arc; -use syntax_pos::{Span, DUMMY_SP}; -use syntax_pos::symbol::InternedString; -use syntax::attr; -use syntax::ast; -use syntax::feature_gate; -use syntax::symbol::Symbol; - -#[macro_use] -mod plumbing; -use self::plumbing::*; -pub use self::plumbing::force_from_dep_node; - -mod job; -pub use self::job::{QueryJob, QueryInfo}; - -mod keys; -pub use self::keys::Key; - -mod values; -use self::values::Value; - -mod config; -pub use self::config::QueryConfig; -use self::config::QueryDescription; - -mod on_disk_cache; -pub use self::on_disk_cache::OnDiskCache; - -// Each of these maps also corresponds to a method on a -// `Provider` trait for requesting a value of that type, -// and a method on `Maps` itself for doing that in a -// a way that memoizes and does dep-graph tracking, -// wrapping around the actual chain of providers that -// the driver creates (using several `rustc_*` crates). -// -// The result of query must implement Clone. They must also implement ty::maps::values::Value -// which produces an appropriate error value if the query resulted in a query cycle. -// Queries marked with `fatal_cycle` do not need that implementation -// as they will raise an fatal error on query cycles instead. -define_maps! { <'tcx> - /// Records the type of every item. - [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, - - /// Maps from the def-id of an item (trait/struct/enum/fn) to its - /// associated generics and predicates. - [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics, - [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, - [] fn explicit_predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, - - /// Maps from the def-id of a trait to the list of - /// super-predicates. This is a subset of the full list of - /// predicates. We store these in a separate map because we must - /// evaluate them even during type conversion, often before the - /// full predicates are available (note that supertraits have - /// additional acyclicity requirements). - [] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, - - /// To avoid cycles within the predicates of a single item we compute - /// per-type-parameter predicates for resolving `T::AssocTy`. - [] fn type_param_predicates: type_param_predicates((DefId, DefId)) - -> ty::GenericPredicates<'tcx>, - - [] fn trait_def: TraitDefOfItem(DefId) -> &'tcx ty::TraitDef, - [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, - [] fn adt_destructor: AdtDestructor(DefId) -> Option, - [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], - [] fn adt_dtorck_constraint: DtorckConstraint( - DefId - ) -> Result, NoSolution>, - - /// True if this is a const fn - [] fn is_const_fn: IsConstFn(DefId) -> bool, - - /// True if this is a foreign item (i.e., linked via `extern { ... }`). - [] fn is_foreign_item: IsForeignItem(DefId) -> bool, - - /// Get a map with the variance of every item; use `item_variance` - /// instead. - [] fn crate_variances: crate_variances(CrateNum) -> Lrc, - - /// Maps from def-id of a type or region parameter to its - /// (inferred) variance. - [] fn variances_of: ItemVariances(DefId) -> Lrc>, - - /// Maps from def-id of a type to its (inferred) outlives. - [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc>>, - - /// Maps from def-id of a type to its (inferred) outlives. - [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum) - -> Lrc>, - - /// Maps from an impl/trait def-id to a list of the def-ids of its items - [] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc>, - - /// Maps from a trait item to the trait item "descriptor" - [] fn associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, - - [] fn impl_trait_ref: ImplTraitRef(DefId) -> Option>, - [] fn impl_polarity: ImplPolarity(DefId) -> hir::ImplPolarity, - - /// Maps a DefId of a type to a list of its inherent impls. - /// Contains implementations of methods that are inherent to a type. - /// Methods in these implementations don't need to be exported. - [] fn inherent_impls: InherentImpls(DefId) -> Lrc>, - - /// Set of all the def-ids in this crate that have MIR associated with - /// them. This includes all the body owners, but also things like struct - /// constructors. - [] fn mir_keys: mir_keys(CrateNum) -> Lrc, - - /// Maps DefId's that have an associated Mir to the result - /// of the MIR qualify_consts pass. The actual meaning of - /// the value isn't known except to the pass itself. - [] fn mir_const_qualif: MirConstQualif(DefId) -> (u8, Lrc>), - - /// Fetch the MIR for a given def-id right after it's built - this includes - /// unreachable code. - [] fn mir_built: MirBuilt(DefId) -> &'tcx Steal>, - - /// Fetch the MIR for a given def-id up till the point where it is - /// ready for const evaluation. - /// - /// See the README for the `mir` module for details. - [] fn mir_const: MirConst(DefId) -> &'tcx Steal>, - - [] fn mir_validated: MirValidated(DefId) -> &'tcx Steal>, - - /// MIR after our optimization passes have run. This is MIR that is ready - /// for trans. This is also the only query that can fetch non-local MIR, at present. - [] fn optimized_mir: MirOptimized(DefId) -> &'tcx mir::Mir<'tcx>, - - /// The result of unsafety-checking this def-id. - [] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult, - - /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error - [] fn unsafe_derive_on_repr_packed: UnsafeDeriveOnReprPacked(DefId) -> (), - - /// The signature of functions and closures. - [] fn fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>, - - /// Caches CoerceUnsized kinds for impls on custom types. - [] fn coerce_unsized_info: CoerceUnsizedInfo(DefId) - -> ty::adjustment::CoerceUnsizedInfo, - - [] fn typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult, - - [] fn typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, - - [] fn used_trait_imports: UsedTraitImports(DefId) -> Lrc, - - [] fn has_typeck_tables: HasTypeckTables(DefId) -> bool, - - [] fn coherent_trait: CoherenceCheckTrait(DefId) -> (), - - [] fn borrowck: BorrowCheck(DefId) -> Lrc, - - /// Borrow checks the function body. If this is a closure, returns - /// additional requirements that the closure's creator must verify. - [] fn mir_borrowck: MirBorrowCheck(DefId) -> mir::BorrowCheckResult<'tcx>, - - /// Gets a complete map from all types to their inherent impls. - /// Not meant to be used directly outside of coherence. - /// (Defined only for LOCAL_CRATE) - [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, - - /// Checks all types in the krate for overlap in their inherent impls. Reports errors. - /// Not meant to be used directly outside of coherence. - /// (Defined only for LOCAL_CRATE) - [] fn crate_inherent_impls_overlap_check: inherent_impls_overlap_check_dep_node(CrateNum) -> (), - - /// Results of evaluating const items or constants embedded in - /// other items (such as enum variant explicit discriminants). - [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> EvalResult<'tcx>, - - [] fn check_match: CheckMatch(DefId) - -> Result<(), ErrorReported>, - - /// Performs the privacy check and computes "access levels". - [] fn privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Lrc, - - [] fn reachable_set: reachability_dep_node(CrateNum) -> ReachableSet, - - /// Per-body `region::ScopeTree`. The `DefId` should be the owner-def-id for the body; - /// in the case of closures, this will be redirected to the enclosing function. - [] fn region_scope_tree: RegionScopeTree(DefId) -> Lrc, - - [] fn mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>, - - [] fn def_symbol_name: SymbolName(DefId) -> ty::SymbolName, - [] fn symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName, - - [] fn describe_def: DescribeDef(DefId) -> Option, - [] fn def_span: DefSpan(DefId) -> Span, - [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>, - [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option, - [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>, - [] fn trans_fn_attrs: trans_fn_attrs(DefId) -> TransFnAttrs, - [] fn fn_arg_names: FnArgNames(DefId) -> Vec, - /// Gets the rendered value of the specified constant or associated constant. - /// Used by rustdoc. - [] fn rendered_const: RenderedConst(DefId) -> String, - [] fn impl_parent: ImplParent(DefId) -> Option, - [] fn trait_of_item: TraitOfItem(DefId) -> Option, - [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, - [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc, - [] fn is_mir_available: IsMirAvailable(DefId) -> bool, - [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) - -> Lrc)>>>, - - [] fn trans_fulfill_obligation: fulfill_obligation_dep_node( - (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, - [] fn trait_impls_of: TraitImpls(DefId) -> Lrc, - [] fn specialization_graph_of: SpecializationGraph(DefId) -> Lrc, - [] fn is_object_safe: ObjectSafety(DefId) -> bool, - - // Get the ParameterEnvironment for a given item; this environment - // will be in "user-facing" mode, meaning that it is suitabe for - // type-checking etc, and it does not normalize specializable - // associated types. This is almost always what you want, - // unless you are doing MIR optimizations, in which case you - // might want to use `reveal_all()` method to change modes. - [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, - - // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, - // `ty.is_copy()`, etc, since that will prune the environment where possible. - [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, - [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) - -> Result<&'tcx ty::layout::LayoutDetails, - ty::layout::LayoutError<'tcx>>, - - [] fn dylib_dependency_formats: DylibDepFormats(CrateNum) - -> Lrc>, - - [fatal_cycle] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool, - [fatal_cycle] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, - [fatal_cycle] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, - [fatal_cycle] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, - [fatal_cycle] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, - [fatal_cycle] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, - [fatal_cycle] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, - - [] fn extern_crate: ExternCrate(DefId) -> Lrc>, - - [] fn specializes: specializes_node((DefId, DefId)) -> bool, - [] fn in_scope_traits_map: InScopeTraits(DefIndex) - -> Option>>>>, - [] fn module_exports: ModuleExports(DefId) -> Option>>, - [] fn lint_levels: lint_levels_node(CrateNum) -> Lrc, - - [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, - - [] fn check_item_well_formed: CheckItemWellFormed(DefId) -> (), - [] fn check_trait_item_well_formed: CheckTraitItemWellFormed(DefId) -> (), - [] fn check_impl_item_well_formed: CheckImplItemWellFormed(DefId) -> (), - - // The DefIds of all non-generic functions and statics in the given crate - // that can be reached from outside the crate. - // - // We expect this items to be available for being linked to. - // - // This query can also be called for LOCAL_CRATE. In this case it will - // compute which items will be reachable to other crates, taking into account - // the kind of crate that is currently compiled. Crates with only a - // C interface have fewer reachable things. - // - // Does not include external symbols that don't have a corresponding DefId, - // like the compiler-generated `main` function and so on. - [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) - -> Lrc>, - [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, - [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool, - - [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum) - -> Lrc, CrateNum>>>>, - [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId) - -> Option, CrateNum>>>, - - [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc>, - - [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc>, - - [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, - [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option, - [] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator, - [] fn crate_hash: CrateHash(CrateNum) -> Svh, - [] fn original_crate_name: OriginalCrateName(CrateNum) -> Symbol, - [] fn extra_filename: ExtraFileName(CrateNum) -> String, - - [] fn implementations_of_trait: implementations_of_trait_node((CrateNum, DefId)) - -> Lrc>, - [] fn all_trait_implementations: AllTraitImplementations(CrateNum) - -> Lrc>, - - [] fn dllimport_foreign_items: DllimportForeignItems(CrateNum) - -> Lrc>, - [] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool, - [] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool, - [] fn native_library_kind: NativeLibraryKind(DefId) - -> Option, - [] fn link_args: link_args_node(CrateNum) -> Lrc>, - - // Lifetime resolution. See `middle::resolve_lifetimes`. - [] fn resolve_lifetimes: ResolveLifetimes(CrateNum) -> Lrc, - [] fn named_region_map: NamedRegion(DefIndex) -> - Option>>, - [] fn is_late_bound_map: IsLateBound(DefIndex) -> - Option>>, - [] fn object_lifetime_defaults_map: ObjectLifetimeDefaults(DefIndex) - -> Option>>>>, - - [] fn visibility: Visibility(DefId) -> ty::Visibility, - [] fn dep_kind: DepKind(CrateNum) -> DepKind, - [] fn crate_name: CrateName(CrateNum) -> Symbol, - [] fn item_children: ItemChildren(DefId) -> Lrc>, - [] fn extern_mod_stmt_cnum: ExternModStmtCnum(DefId) -> Option, - - [] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc, - [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc>, - [] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc>, - [] fn visible_parent_map: visible_parent_map_node(CrateNum) - -> Lrc>, - [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool, - [] fn used_crate_source: UsedCrateSource(CrateNum) -> Lrc, - [] fn postorder_cnums: postorder_cnums_node(CrateNum) -> Lrc>, - - [] fn freevars: Freevars(DefId) -> Option>>, - [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool, - [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum) - -> Lrc>, - - [] fn stability_index: stability_index_node(CrateNum) -> Lrc>, - [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc>, - - /// A vector of every trait accessible in the whole crate - /// (i.e. including those from subcrates). This is used only for - /// error reporting. - [] fn all_traits: all_traits_node(CrateNum) -> Lrc>, - - [] fn exported_symbols: ExportedSymbols(CrateNum) - -> Arc, SymbolExportLevel)>>, - [] fn collect_and_partition_translation_items: - collect_and_partition_translation_items_node(CrateNum) - -> (Arc, Arc>>>), - [] fn is_translated_item: IsTranslatedItem(DefId) -> bool, - [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, - [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, - [] fn output_filenames: output_filenames_node(CrateNum) - -> Arc, - - // Erases regions from `ty` to yield a new type. - // Normally you would just use `tcx.erase_regions(&value)`, - // however, which uses this query as a kind of cache. - [] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>, - - /// Do not call this query directly: invoke `normalize` instead. - [] fn normalize_projection_ty: NormalizeProjectionTy( - CanonicalProjectionGoal<'tcx> - ) -> Result< - Lrc>>>, - NoSolution, - >, - - /// Do not call this query directly: invoke `normalize_erasing_regions` instead. - [] fn normalize_ty_after_erasing_regions: NormalizeTyAfterErasingRegions( - ParamEnvAnd<'tcx, Ty<'tcx>> - ) -> Ty<'tcx>, - - /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. - [] fn dropck_outlives: DropckOutlives( - CanonicalTyGoal<'tcx> - ) -> Result< - Lrc>>>, - NoSolution, - >, - - /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or - /// `infcx.predicate_must_hold()` instead. - [] fn evaluate_obligation: EvaluateObligation( - CanonicalPredicateGoal<'tcx> - ) -> Result, - - [] fn substitute_normalize_and_test_predicates: - substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, - - [] fn target_features_whitelist: - target_features_whitelist_node(CrateNum) -> Lrc>>, - - // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. - [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) - -> usize, - - [] fn features_query: features_node(CrateNum) -> Lrc, - - [] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>, - - [] fn program_clauses_for_env: ProgramClausesForEnv( - ty::ParamEnv<'tcx> - ) -> Clauses<'tcx>, - - [] fn wasm_custom_sections: WasmCustomSections(CrateNum) -> Lrc>, - [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum) - -> Lrc>, -} - -////////////////////////////////////////////////////////////////////// -// These functions are little shims used to find the dep-node for a -// given query when there is not a *direct* mapping: - - -fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Features -} - -fn trans_fn_attrs<'tcx>(id: DefId) -> DepConstructor<'tcx> { - DepConstructor::TransFnAttrs { 0: id } -} - -fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::EraseRegionsTy { ty } -} - -fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { - DepConstructor::TypeParamPredicates { - item_id, - param_id - } -} - -fn fulfill_obligation_dep_node<'tcx>((param_env, trait_ref): - (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> DepConstructor<'tcx> { - DepConstructor::FulfillObligation { - param_env, - trait_ref - } -} - -fn crate_inherent_impls_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Coherence -} - -fn inherent_impls_overlap_check_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CoherenceInherentImplOverlapCheck -} - -fn reachability_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::Reachability -} - -fn mir_shim_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::MirShim { - instance_def - } -} - -fn symbol_name_dep_node<'tcx>(instance: ty::Instance<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::InstanceSymbolName { instance } -} - -fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::TypeckBodiesKrate -} - -fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> DepConstructor<'tcx> { - DepConstructor::ConstEval { param_env } -} - -fn mir_keys<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::MirKeys -} - -fn crate_variances<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CrateVariances -} - -fn is_copy_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsCopy { param_env } -} - -fn is_sized_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsSized { param_env } -} - -fn is_freeze_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::IsFreeze { param_env } -} - -fn needs_drop_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::NeedsDrop { param_env } -} - -fn layout_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { - DepConstructor::Layout { param_env } -} - -fn lint_levels_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::LintLevels -} - -fn specializes_node<'tcx>((a, b): (DefId, DefId)) -> DepConstructor<'tcx> { - DepConstructor::Specializes { impl1: a, impl2: b } -} - -fn implementations_of_trait_node<'tcx>((krate, trait_id): (CrateNum, DefId)) - -> DepConstructor<'tcx> -{ - DepConstructor::ImplementationsOfTrait { krate, trait_id } -} - -fn link_args_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::LinkArgs -} - -fn get_lang_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::GetLangItems -} - -fn visible_parent_map_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::VisibleParentMap -} - -fn postorder_cnums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::PostorderCnums -} - -fn maybe_unused_extern_crates_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::MaybeUnusedExternCrates -} - -fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::StabilityIndex -} - -fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::AllCrateNums -} - -fn all_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::AllTraits -} - -fn collect_and_partition_translation_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::CollectAndPartitionTranslationItems -} - -fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::OutputFilenames -} - -fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> { - DepConstructor::VtableMethods{ trait_ref } -} - -fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, &'tcx Substs<'tcx>)) - -> DepConstructor<'tcx> { - DepConstructor::SubstituteNormalizeAndTestPredicates { key } -} - -fn target_features_whitelist_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { - DepConstructor::TargetFeaturesWhitelist -} - -fn instance_def_size_estimate_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) - -> DepConstructor<'tcx> { - DepConstructor::InstanceDefSizeEstimate { - instance_def - } -} diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index c4fe112a9e913..4fda3bdca3dfc 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -21,13 +21,12 @@ use hir::map::DefPathData; use hir::svh::Svh; use ich::Fingerprint; use ich::StableHashingContext; -use infer::canonical::{Canonical, Canonicalize}; -use middle::const_val::ConstVal; +use infer::canonical::Canonical; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem}; use middle::privacy::AccessLevels; use middle::resolve_lifetime::ObjectLifetimeDefault; use mir::Mir; -use mir::interpret::{GlobalId, Value, PrimVal}; +use mir::interpret::GlobalId; use mir::GeneratorLayout; use session::CrateDisambiguator; use traits::{self, Reveal}; @@ -37,17 +36,18 @@ use ty::util::{IntTypeExt, Discr}; use ty::walk::TypeWalker; use util::captures::Captures; use util::nodemap::{NodeSet, DefIdMap, FxHashMap}; +use arena::SyncDroplessArena; use serialize::{self, Encodable, Encoder}; use std::cell::RefCell; -use std::cmp; +use std::cmp::{self, Ordering}; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::Deref; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{self, Lrc, ParallelIterator, par_iter}; use std::slice; use std::vec::IntoIter; -use std::mem; +use std::{mem, ptr}; use syntax::ast::{self, DUMMY_NODE_ID, Name, Ident, NodeId}; use syntax::attr; use syntax::ext::hygiene::Mark; @@ -60,10 +60,10 @@ use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, use hir; -pub use self::sty::{Binder, CanonicalVar, DebruijnIndex}; +pub use self::sty::{Binder, CanonicalVar, DebruijnIndex, INNERMOST}; pub use self::sty::{FnSig, GenSig, PolyFnSig, PolyGenSig}; pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate}; -pub use self::sty::{ClosureSubsts, GeneratorInterior, TypeAndMut}; +pub use self::sty::{ClosureSubsts, GeneratorSubsts, UpvarSubsts, TypeAndMut}; pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef}; pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef}; pub use self::sty::{ExistentialProjection, PolyExistentialProjection, Const}; @@ -79,13 +79,13 @@ pub use self::binding::BindingMode; pub use self::binding::BindingMode::*; pub use self::context::{TyCtxt, GlobalArenas, AllArenas, tls, keep_local}; -pub use self::context::{Lift, TypeckTables, InterpretInterner}; +pub use self::context::{Lift, TypeckTables}; pub use self::instance::{Instance, InstanceDef}; pub use self::trait_def::TraitDef; -pub use self::maps::queries; +pub use self::query::queries; pub mod adjustment; pub mod binding; @@ -100,8 +100,8 @@ pub mod inhabitedness; pub mod item_path; pub mod layout; pub mod _match; -pub mod maps; pub mod outlives; +pub mod query; pub mod relate; pub mod steal; pub mod subst; @@ -119,7 +119,7 @@ mod sty; // Data types /// The complete set of all analyses described in this module. This is -/// produced by the driver and fed to trans and later passes. +/// produced by the driver and fed to codegen and later passes. /// /// NB: These contents are being migrated into queries using the /// *on-demand* infrastructure. @@ -174,10 +174,10 @@ pub struct ImplHeader<'tcx> { pub predicates: Vec>, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug, PartialEq)] pub struct AssociatedItem { pub def_id: DefId, - pub name: Name, + pub ident: Ident, pub kind: AssociatedKind, pub vis: Visibility, pub defaultness: hir::Defaultness, @@ -192,6 +192,7 @@ pub struct AssociatedItem { pub enum AssociatedKind { Const, Method, + Existential, Type } @@ -201,6 +202,7 @@ impl AssociatedItem { AssociatedKind::Const => Def::AssociatedConst(self.def_id), AssociatedKind::Method => Def::Method(self.def_id), AssociatedKind::Type => Def::AssociatedTy(self.def_id), + AssociatedKind::Existential => Def::AssociatedExistential(self.def_id), } } @@ -208,7 +210,8 @@ impl AssociatedItem { /// for ! pub fn relevant_for_never<'tcx>(&self) -> bool { match self.kind { - AssociatedKind::Const => true, + AssociatedKind::Existential | + AssociatedKind::Const | AssociatedKind::Type => true, // FIXME(canndrew): Be more thorough here, check if any argument is uninhabited. AssociatedKind::Method => !self.method_has_self_argument, @@ -222,11 +225,12 @@ impl AssociatedItem { // late-bound regions, and we don't want method signatures to show up // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound // regions just fine, showing `fn(&MyType)`. - format!("{}", tcx.fn_sig(self.def_id).skip_binder()) + tcx.fn_sig(self.def_id).skip_binder().to_string() } - ty::AssociatedKind::Type => format!("type {};", self.name.to_string()), + ty::AssociatedKind::Type => format!("type {};", self.ident), + ty::AssociatedKind::Existential => format!("existential type {};", self.ident), ty::AssociatedKind::Const => { - format!("const {}: {:?};", self.name.to_string(), tcx.type_of(self.def_id)) + format!("const {}: {:?};", self.ident, tcx.type_of(self.def_id)) } } } @@ -268,16 +272,16 @@ impl<'a, 'gcx, 'tcx> DefIdTree for TyCtxt<'a, 'gcx, 'tcx> { impl Visibility { pub fn from_hir(visibility: &hir::Visibility, id: NodeId, tcx: TyCtxt) -> Self { - match *visibility { - hir::Public => Visibility::Public, - hir::Visibility::Crate => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)), - hir::Visibility::Restricted { ref path, .. } => match path.def { + match visibility.node { + hir::VisibilityKind::Public => Visibility::Public, + hir::VisibilityKind::Crate(_) => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)), + hir::VisibilityKind::Restricted { ref path, .. } => match path.def { // If there is no resolution, `resolve` will have already reported an error, so // assume that the visibility is public to avoid reporting more privacy errors. Def::Err => Visibility::Public, def => Visibility::Restricted(def.def_id()), }, - hir::Inherited => { + hir::VisibilityKind::Inherited => { Visibility::Restricted(tcx.hir.get_module_parent(id)) } } @@ -442,7 +446,7 @@ bitflags! { // true if there are "names" of types and regions and so forth // that are local to a particular fn - const HAS_LOCAL_NAMES = 1 << 10; + const HAS_FREE_LOCAL_NAMES = 1 << 10; // Present if the type belongs in a local type context. // Only set for TyInfer other than Fresh. @@ -456,6 +460,10 @@ bitflags! { // ought to be true only for the results of canonicalization. const HAS_CANONICAL_VARS = 1 << 13; + /// Does this have any `ReLateBound` regions? Used to check + /// if a global bound is safe to evaluate. + const HAS_RE_LATE_BOUND = 1 << 14; + const NEEDS_SUBST = TypeFlags::HAS_PARAMS.bits | TypeFlags::HAS_SELF.bits | TypeFlags::HAS_RE_EARLY_BOUND.bits; @@ -473,9 +481,10 @@ bitflags! { TypeFlags::HAS_TY_ERR.bits | TypeFlags::HAS_PROJECTION.bits | TypeFlags::HAS_TY_CLOSURE.bits | - TypeFlags::HAS_LOCAL_NAMES.bits | + TypeFlags::HAS_FREE_LOCAL_NAMES.bits | TypeFlags::KEEP_IN_LOCAL_TCX.bits | - TypeFlags::HAS_CANONICAL_VARS.bits; + TypeFlags::HAS_CANONICAL_VARS.bits | + TypeFlags::HAS_RE_LATE_BOUND.bits; } } @@ -483,15 +492,42 @@ pub struct TyS<'tcx> { pub sty: TypeVariants<'tcx>, pub flags: TypeFlags, - // the maximal depth of any bound regions appearing in this type. - region_depth: u32, + /// This is a kind of confusing thing: it stores the smallest + /// binder such that + /// + /// (a) the binder itself captures nothing but + /// (b) all the late-bound things within the type are captured + /// by some sub-binder. + /// + /// So, for a type without any late-bound things, like `u32`, this + /// will be INNERMOST, because that is the innermost binder that + /// captures nothing. But for a type `&'D u32`, where `'D` is a + /// late-bound region with debruijn index D, this would be D+1 -- + /// the binder itself does not capture D, but D is captured by an + /// inner binder. + /// + /// We call this concept an "exclusive" binder D (because all + /// debruijn indices within the type are contained within `0..D` + /// (exclusive)). + outer_exclusive_binder: ty::DebruijnIndex, +} + +impl<'tcx> Ord for TyS<'tcx> { + fn cmp(&self, other: &TyS<'tcx>) -> Ordering { + self.sty.cmp(&other.sty) + } +} + +impl<'tcx> PartialOrd for TyS<'tcx> { + fn partial_cmp(&self, other: &TyS<'tcx>) -> Option { + Some(self.sty.cmp(&other.sty)) + } } impl<'tcx> PartialEq for TyS<'tcx> { #[inline] fn eq(&self, other: &TyS<'tcx>) -> bool { - // (self as *const _) == (other as *const _) - (self as *const TyS<'tcx>) == (other as *const TyS<'tcx>) + ptr::eq(self, other) } } impl<'tcx> Eq for TyS<'tcx> {} @@ -514,7 +550,7 @@ impl<'tcx> TyS<'tcx> { TypeVariants::TyInfer(InferTy::FloatVar(_)) | TypeVariants::TyInfer(InferTy::FreshIntTy(_)) | TypeVariants::TyInfer(InferTy::FreshFloatTy(_)) => true, - TypeVariants::TyRef(_, x) => x.ty.is_primitive_ty(), + TypeVariants::TyRef(_, x, _) => x.is_primitive_ty(), _ => false, } } @@ -543,7 +579,8 @@ impl<'a, 'gcx> HashStable> for ty::TyS<'gcx> { // The other fields just provide fast access to information that is // also contained in `sty`, so no need to hash them. flags: _, - region_depth: _, + + outer_exclusive_binder: _, } = *self; sty.hash_stable(hcx, hasher); @@ -557,47 +594,115 @@ impl<'tcx> serialize::UseSpecializedDecodable for Ty<'tcx> {} pub type CanonicalTy<'gcx> = Canonical<'gcx, Ty<'gcx>>; -impl <'gcx: 'tcx, 'tcx> Canonicalize<'gcx, 'tcx> for Ty<'tcx> { - type Canonicalized = CanonicalTy<'gcx>; - - fn intern(_gcx: TyCtxt<'_, 'gcx, 'gcx>, - value: Canonical<'gcx, Self::Lifted>) -> Self::Canonicalized { - value - } +extern { + /// A dummy type used to force Slice to by unsized without requiring fat pointers + type OpaqueSliceContents; } /// A wrapper for slices with the additional invariant /// that the slice is interned and no other slice with /// the same contents can exist in the same context. -/// This means we can use pointer + length for both +/// This means we can use pointer for both /// equality comparisons and hashing. -#[derive(Debug, RustcEncodable)] -pub struct Slice([T]); +#[repr(C)] +pub struct Slice { + len: usize, + data: [T; 0], + opaque: OpaqueSliceContents, +} + +unsafe impl Sync for Slice {} -impl PartialEq for Slice { +impl Slice { + #[inline] + fn from_arena<'tcx>(arena: &'tcx SyncDroplessArena, slice: &[T]) -> &'tcx Slice { + assert!(!mem::needs_drop::()); + assert!(mem::size_of::() != 0); + assert!(slice.len() != 0); + + // Align up the size of the len (usize) field + let align = mem::align_of::(); + let align_mask = align - 1; + let offset = mem::size_of::(); + let offset = (offset + align_mask) & !align_mask; + + let size = offset + slice.len() * mem::size_of::(); + + let mem = arena.alloc_raw( + size, + cmp::max(mem::align_of::(), mem::align_of::())); + unsafe { + let result = &mut *(mem.as_mut_ptr() as *mut Slice); + // Write the length + result.len = slice.len(); + + // Write the elements + let arena_slice = slice::from_raw_parts_mut(result.data.as_mut_ptr(), result.len); + arena_slice.copy_from_slice(slice); + + result + } + } +} + +impl fmt::Debug for Slice { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + (**self).fmt(f) + } +} + +impl Encodable for Slice { + #[inline] + fn encode(&self, s: &mut S) -> Result<(), S::Error> { + (**self).encode(s) + } +} + +impl Ord for Slice where T: Ord { + fn cmp(&self, other: &Slice) -> Ordering { + if self == other { Ordering::Equal } else { + <[T] as Ord>::cmp(&**self, &**other) + } + } +} + +impl PartialOrd for Slice where T: PartialOrd { + fn partial_cmp(&self, other: &Slice) -> Option { + if self == other { Some(Ordering::Equal) } else { + <[T] as PartialOrd>::partial_cmp(&**self, &**other) + } + } +} + +impl PartialEq for Slice { #[inline] fn eq(&self, other: &Slice) -> bool { - (&self.0 as *const [T]) == (&other.0 as *const [T]) + ptr::eq(self, other) } } -impl Eq for Slice {} +impl Eq for Slice {} impl Hash for Slice { + #[inline] fn hash(&self, s: &mut H) { - (self.as_ptr(), self.len()).hash(s) + (self as *const Slice).hash(s) } } impl Deref for Slice { type Target = [T]; + #[inline(always)] fn deref(&self) -> &[T] { - &self.0 + unsafe { + slice::from_raw_parts(self.data.as_ptr(), self.len) + } } } impl<'a, T> IntoIterator for &'a Slice { type Item = &'a T; type IntoIter = <&'a [T] as IntoIterator>::IntoIter; + #[inline(always)] fn into_iter(self) -> Self::IntoIter { self[..].iter() } @@ -606,9 +711,14 @@ impl<'a, T> IntoIterator for &'a Slice { impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Slice> {} impl Slice { + #[inline(always)] pub fn empty<'a>() -> &'a Slice { + #[repr(align(64), C)] + struct EmptySlice([u8; 64]); + static EMPTY_SLICE: EmptySlice = EmptySlice([0; 64]); + assert!(mem::align_of::() <= 64); unsafe { - mem::transmute(slice::from_raw_parts(0x1 as *const T, 0)) + &*(&EMPTY_SLICE as *const _ as *const Slice) } } } @@ -710,148 +820,149 @@ pub enum IntVarValue { #[derive(Clone, Copy, PartialEq, Eq)] pub struct FloatVarValue(pub ast::FloatTy); -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub struct TypeParameterDef { - pub name: InternedString, - pub def_id: DefId, - pub index: u32, - pub has_default: bool, - pub object_lifetime_default: ObjectLifetimeDefault, - - /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute - /// on generic parameter `T`, asserts data behind the parameter - /// `T` won't be accessed during the parent type's `Drop` impl. - pub pure_wrt_drop: bool, +impl ty::EarlyBoundRegion { + pub fn to_bound_region(&self) -> ty::BoundRegion { + ty::BoundRegion::BrNamed(self.def_id, self.name) + } +} - pub synthetic: Option, +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] +pub enum GenericParamDefKind { + Lifetime, + Type { + has_default: bool, + object_lifetime_default: ObjectLifetimeDefault, + synthetic: Option, + } } -#[derive(Copy, Clone, RustcEncodable, RustcDecodable)] -pub struct RegionParameterDef { +#[derive(Clone, RustcEncodable, RustcDecodable)] +pub struct GenericParamDef { pub name: InternedString, pub def_id: DefId, pub index: u32, /// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute - /// on generic parameter `'a`, asserts data of lifetime `'a` - /// won't be accessed during the parent type's `Drop` impl. + /// on generic parameter `'a`/`T`, asserts data behind the parameter + /// `'a`/`T` won't be accessed during the parent type's `Drop` impl. pub pure_wrt_drop: bool, + + pub kind: GenericParamDefKind, } -impl RegionParameterDef { +impl GenericParamDef { pub fn to_early_bound_region_data(&self) -> ty::EarlyBoundRegion { - ty::EarlyBoundRegion { - def_id: self.def_id, - index: self.index, - name: self.name, + match self.kind { + GenericParamDefKind::Lifetime => { + ty::EarlyBoundRegion { + def_id: self.def_id, + index: self.index, + name: self.name, + } + } + _ => bug!("cannot convert a non-lifetime parameter def to an early bound region") } } pub fn to_bound_region(&self) -> ty::BoundRegion { - self.to_early_bound_region_data().to_bound_region() + match self.kind { + GenericParamDefKind::Lifetime => { + self.to_early_bound_region_data().to_bound_region() + } + _ => bug!("cannot convert a non-lifetime parameter def to an early bound region") + } } } -impl ty::EarlyBoundRegion { - pub fn to_bound_region(&self) -> ty::BoundRegion { - ty::BoundRegion::BrNamed(self.def_id, self.name) - } +pub struct GenericParamCount { + pub lifetimes: usize, + pub types: usize, } /// Information about the formal type/lifetime parameters associated /// with an item or method. Analogous to hir::Generics. /// -/// Note that in the presence of a `Self` parameter, the ordering here -/// is different from the ordering in a Substs. Substs are ordered as -/// Self, *Regions, *Other Type Params, (...child generics) -/// while this struct is ordered as -/// regions = Regions -/// types = [Self, *Other Type Params] +/// The ordering of parameters is the same as in Subst (excluding child generics): +/// Self (optionally), Lifetime params..., Type params... #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct Generics { pub parent: Option, - pub parent_regions: u32, - pub parent_types: u32, - pub regions: Vec, - pub types: Vec, + pub parent_count: usize, + pub params: Vec, - /// Reverse map to each `TypeParameterDef`'s `index` field - pub type_param_to_index: FxHashMap, + /// Reverse map to the `index` field of each `GenericParamDef` + pub param_def_id_to_index: FxHashMap, pub has_self: bool, pub has_late_bound_regions: Option, } impl<'a, 'gcx, 'tcx> Generics { - pub fn parent_count(&self) -> usize { - self.parent_regions as usize + self.parent_types as usize + pub fn count(&self) -> usize { + self.parent_count + self.params.len() } - pub fn own_count(&self) -> usize { - self.regions.len() + self.types.len() + pub fn own_counts(&self) -> GenericParamCount { + // We could cache this as a property of `GenericParamCount`, but + // the aim is to refactor this away entirely eventually and the + // presence of this method will be a constant reminder. + let mut own_counts = GenericParamCount { + lifetimes: 0, + types: 0, + }; + + for param in &self.params { + match param.kind { + GenericParamDefKind::Lifetime => own_counts.lifetimes += 1, + GenericParamDefKind::Type {..} => own_counts.types += 1, + }; + } + + own_counts } - pub fn count(&self) -> usize { - self.parent_count() + self.own_count() + pub fn requires_monomorphization(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool { + for param in &self.params { + match param.kind { + GenericParamDefKind::Type {..} => return true, + GenericParamDefKind::Lifetime => {} + } + } + if let Some(parent_def_id) = self.parent { + let parent = tcx.generics_of(parent_def_id); + parent.requires_monomorphization(tcx) + } else { + false + } } pub fn region_param(&'tcx self, param: &EarlyBoundRegion, tcx: TyCtxt<'a, 'gcx, 'tcx>) - -> &'tcx RegionParameterDef + -> &'tcx GenericParamDef { - if let Some(index) = param.index.checked_sub(self.parent_count() as u32) { - &self.regions[index as usize - self.has_self as usize] + if let Some(index) = param.index.checked_sub(self.parent_count as u32) { + let param = &self.params[index as usize]; + match param.kind { + ty::GenericParamDefKind::Lifetime => param, + _ => bug!("expected lifetime parameter, but found another generic parameter") + } } else { tcx.generics_of(self.parent.expect("parent_count>0 but no parent?")) .region_param(param, tcx) } } - /// Returns the `TypeParameterDef` associated with this `ParamTy`. + /// Returns the `GenericParamDef` associated with this `ParamTy`. pub fn type_param(&'tcx self, param: &ParamTy, tcx: TyCtxt<'a, 'gcx, 'tcx>) - -> &TypeParameterDef { - if let Some(idx) = param.idx.checked_sub(self.parent_count() as u32) { - // non-Self type parameters are always offset by exactly - // `self.regions.len()`. In the absence of a Self, this is obvious, - // but even in the presence of a `Self` we just have to "compensate" - // for the regions: - // - // Without a `Self` (or in a nested generics that doesn't have - // a `Self` in itself, even through it parent does), for example - // for `fn foo<'a, T1, T2>()`, the situation is: - // Substs: - // 0 1 2 - // 'a T1 T2 - // generics.types: - // 0 1 - // T1 T2 - // - // And with a `Self`, for example for `trait Foo<'a, 'b, T1, T2>`, the - // situation is: - // Substs: - // 0 1 2 3 4 - // Self 'a 'b T1 T2 - // generics.types: - // 0 1 2 - // Self T1 T2 - // - // And it can be seen that in both cases, to move from a substs - // offset to a generics offset you just have to offset by the - // number of regions. - let type_param_offset = self.regions.len(); - - let has_self = self.has_self && self.parent.is_none(); - let is_separated_self = type_param_offset != 0 && idx == 0 && has_self; - - if let Some(idx) = (idx as usize).checked_sub(type_param_offset) { - assert!(!is_separated_self, "found a Self after type_param_offset"); - &self.types[idx] - } else { - assert!(is_separated_self, "non-Self param before type_param_offset"); - &self.types[0] + -> &'tcx GenericParamDef { + if let Some(index) = param.idx.checked_sub(self.parent_count as u32) { + let param = &self.params[index as usize]; + match param.kind { + ty::GenericParamDefKind::Type {..} => param, + _ => bug!("expected type parameter, but found another generic parameter") } } else { tcx.generics_of(self.parent.expect("parent_count>0 but no parent?")) @@ -1099,7 +1210,7 @@ impl<'tcx> PolyTraitPredicate<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct OutlivesPredicate(pub A, pub B); // `A : B` pub type PolyOutlivesPredicate = ty::Binder>; pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate, @@ -1370,7 +1481,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { /// type name in a non-zero universe is a skolemized type -- an /// idealized representative of "types in general" that we use for /// checking generic functions. -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct UniverseIndex(u32); impl UniverseIndex { @@ -1378,6 +1489,19 @@ impl UniverseIndex { /// visible. pub const ROOT: Self = UniverseIndex(0); + /// The "max universe" -- this isn't really a valid universe, but + /// it's useful sometimes as a "starting value" when you are + /// taking the minimum of a (non-empty!) set of universes. + pub const MAX: Self = UniverseIndex(::std::u32::MAX); + + /// Creates a universe index from the given integer. Not to be + /// used lightly lest you pick a bad value. But sometimes we + /// convert universe indicies into integers and back for various + /// reasons. + pub fn from_u32(index: u32) -> Self { + UniverseIndex(index) + } + /// A "subuniverse" corresponds to being inside a `forall` quantifier. /// So, for example, suppose we have this type in universe `U`: /// @@ -1393,6 +1517,11 @@ impl UniverseIndex { UniverseIndex(self.0.checked_add(1).unwrap()) } + /// True if the names in this universe are a subset of the names in `other`. + pub fn is_subset_of(self, other: UniverseIndex) -> bool { + self.0 <= other.0 + } + pub fn as_u32(&self) -> u32 { self.0 } @@ -1402,6 +1531,12 @@ impl UniverseIndex { } } +impl fmt::Debug for UniverseIndex { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + write!(fmt, "U{}", self.as_u32()) + } +} + impl From for UniverseIndex { fn from(index: u32) -> Self { UniverseIndex(index) @@ -1418,7 +1553,7 @@ pub struct ParamEnv<'tcx> { /// into Obligations, and elaborated and normalized. pub caller_bounds: &'tcx Slice>, - /// Typically, this is `Reveal::UserFacing`, but during trans we + /// Typically, this is `Reveal::UserFacing`, but during codegen we /// want `Reveal::All` -- note that this is always paired with an /// empty environment. To get that, use `ParamEnv::reveal()`. pub reveal: traits::Reveal, @@ -1436,7 +1571,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Construct a trait environment with no where clauses in scope /// where the values of all `impl Trait` and other hidden types /// are revealed. This is suitable for monomorphized, post-typeck - /// environments like trans or doing optimizations. + /// environments like codegen or doing optimizations. /// /// NB. If you want to have predicates in scope, use `ParamEnv::new`, /// or invoke `param_env.with_reveal_all()`. @@ -1454,7 +1589,7 @@ impl<'tcx> ParamEnv<'tcx> { /// Returns a new parameter environment with the same clauses, but /// which "reveals" the true results of projections in all cases /// (even for associated types that are specializable). This is - /// the desired behavior during trans and certain other special + /// the desired behavior during codegen and certain other special /// contexts; normally though we want to use `Reveal::UserFacing`, /// which is the default. pub fn with_reveal_all(self) -> Self { @@ -1586,7 +1721,7 @@ pub enum VariantDiscr { #[derive(Debug)] pub struct FieldDef { pub did: DefId, - pub name: Name, + pub ident: Ident, pub vis: Visibility, } @@ -1601,10 +1736,24 @@ pub struct AdtDef { pub repr: ReprOptions, } +impl PartialOrd for AdtDef { + fn partial_cmp(&self, other: &AdtDef) -> Option { + Some(self.cmp(&other)) + } +} + +/// There should be only one AdtDef for each `did`, therefore +/// it is fine to implement `Ord` only based on `did`. +impl Ord for AdtDef { + fn cmp(&self, other: &AdtDef) -> Ordering { + self.did.cmp(&other.did) + } +} + impl PartialEq for AdtDef { // AdtDef are always interned and this is part of TyS equality #[inline] - fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } + fn eq(&self, other: &Self) -> bool { ptr::eq(self, other) } } impl Eq for AdtDef {} @@ -1933,30 +2082,28 @@ impl<'a, 'gcx, 'tcx> AdtDef { promoted: None }; match tcx.const_eval(param_env.and(cid)) { - Ok(&ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), - ty, - }) => { - trace!("discriminants: {} ({:?})", b, repr_type); - Some(Discr { - val: b, - ty, - }) - }, - Ok(&ty::Const { - val: ConstVal::Value(other), - .. - }) => { - info!("invalid enum discriminant: {:#?}", other); - ::middle::const_val::struct_error( - tcx, - tcx.def_span(expr_did), - "constant evaluation of enum discriminant resulted in non-integer", - ).emit(); - None + Ok(val) => { + // FIXME: Find the right type and use it instead of `val.ty` here + if let Some(b) = val.assert_bits(tcx.global_tcx(), param_env.and(val.ty)) { + trace!("discriminants: {} ({:?})", b, repr_type); + Some(Discr { + val: b, + ty: val.ty, + }) + } else { + info!("invalid enum discriminant: {:#?}", val); + ::mir::interpret::struct_error( + tcx.at(tcx.def_span(expr_did)), + "constant evaluation of enum discriminant resulted in non-integer", + ).emit(); + None + } } Err(err) => { - err.report(tcx, tcx.def_span(expr_did), "enum discriminant"); + err.report_as_error( + tcx.at(tcx.def_span(expr_did)), + "could not evaluate enum discriminant", + ); if !expr_did.is_local() { span_bug!(tcx.def_span(expr_did), "variant discriminant evaluation succeeded \ @@ -1964,7 +2111,6 @@ impl<'a, 'gcx, 'tcx> AdtDef { } None } - _ => span_bug!(tcx.def_span(expr_did), "const eval "), } } @@ -2047,7 +2193,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { /// Due to normalization being eager, this applies even if /// the associated type is behind a pointer, e.g. issue #31299. pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] { - match tcx.try_get_query::(DUMMY_SP, self.did) { + match tcx.try_adt_sized_constraint(DUMMY_SP, self.did) { Ok(tys) => tys, Err(mut bug) => { debug!("adt_sized_constraint: {:?} is recursive", self); @@ -2308,6 +2454,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { .map(move |&body_id| self.hir.body_owner_def_id(body_id)) } + pub fn par_body_owners(self, f: F) { + par_iter(&self.hir.krate().body_ids).for_each(|&body_id| { + f(self.hir.body_owner_def_id(body_id)) + }); + } + pub fn expr_span(self, id: NodeId) -> Span { match self.hir.find(id) { Some(hir_map::NodeExpr(e)) => { @@ -2366,10 +2518,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { (ty::AssociatedKind::Method, has_self) } hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false), + hir::AssociatedItemKind::Existential => bug!("only impls can have existentials"), }; AssociatedItem { - name: trait_item_ref.name, + ident: trait_item_ref.ident, kind, // Visibility of trait items is inherited from their traits. vis: Visibility::from_hir(parent_vis, trait_item_ref.id.node_id, self), @@ -2391,10 +2544,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { (ty::AssociatedKind::Method, has_self) } hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false), + hir::AssociatedItemKind::Existential => (ty::AssociatedKind::Existential, false), }; - ty::AssociatedItem { - name: impl_item_ref.name, + AssociatedItem { + ident: impl_item_ref.ident, kind, // Visibility of trait impl items doesn't matter. vis: ty::Visibility::from_hir(&impl_item_ref.vis, impl_item_ref.id.node_id, self), @@ -2412,17 +2566,17 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { pub fn find_field_index(self, ident: Ident, variant: &VariantDef) -> Option { variant.fields.iter().position(|field| { - self.adjust_ident(ident.modern(), variant.did, DUMMY_NODE_ID).0 == field.name.to_ident() + self.adjust_ident(ident, variant.did, DUMMY_NODE_ID).0 == field.ident.modern() }) } pub fn associated_items( self, def_id: DefId, - ) -> impl Iterator + 'a { + ) -> impl Iterator + 'a { let def_ids = self.associated_item_def_ids(def_id); Box::new((0..def_ids.len()).map(move |i| self.associated_item(def_ids[i]))) - as Box + 'a> + as Box + 'a> } /// Returns true if the impls are the same polarity and are implementing @@ -2567,15 +2721,12 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.opt_associated_item(def_id) }; - match item { - Some(trait_item) => { - match trait_item.container { - TraitContainer(_) => None, - ImplContainer(def_id) => Some(def_id), - } + item.and_then(|trait_item| + match trait_item.container { + TraitContainer(_) => None, + ImplContainer(def_id) => Some(def_id), } - None => None - } + ) } /// Looks up the span of `impl_did` if the impl is local; otherwise returns `Err` @@ -2592,21 +2743,19 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { // Hygienically compare a use-site name (`use_name`) for a field or an associated item with its // supposed definition name (`def_name`). The method also needs `DefId` of the supposed // definition's parent/scope to perform comparison. - pub fn hygienic_eq(self, use_name: Name, def_name: Name, def_parent_def_id: DefId) -> bool { - self.adjust(use_name, def_parent_def_id, DUMMY_NODE_ID).0 == def_name.to_ident() - } - - pub fn adjust(self, name: Name, scope: DefId, block: NodeId) -> (Ident, DefId) { - self.adjust_ident(name.to_ident(), scope, block) + pub fn hygienic_eq(self, use_name: Ident, def_name: Ident, def_parent_def_id: DefId) -> bool { + self.adjust_ident(use_name, def_parent_def_id, DUMMY_NODE_ID).0 == def_name.modern() } pub fn adjust_ident(self, mut ident: Ident, scope: DefId, block: NodeId) -> (Ident, DefId) { - let expansion = match scope.krate { - LOCAL_CRATE => self.hir.definitions().expansion(scope.index), + ident = ident.modern(); + let target_expansion = match scope.krate { + LOCAL_CRATE => self.hir.definitions().expansion_that_defined(scope.index), _ => Mark::root(), }; - let scope = match ident.span.adjust(expansion) { - Some(macro_def) => self.hir.definitions().macro_def_scope(macro_def), + let scope = match ident.span.adjust(target_expansion) { + Some(actual_expansion) => + self.hir.definitions().parent_module_of_macro_def(actual_expansion), None if block == DUMMY_NODE_ID => DefId::local(CRATE_DEF_INDEX), // Dummy DefId None => self.hir.get_module_parent(block), }; @@ -2634,7 +2783,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) let parent_def_id = tcx.hir.local_def_id(parent_id); let parent_item = tcx.hir.expect_item(parent_id); match parent_item.node { - hir::ItemImpl(.., ref impl_item_refs) => { + hir::ItemKind::Impl(.., ref impl_item_refs) => { if let Some(impl_item_ref) = impl_item_refs.iter().find(|i| i.id.node_id == id) { let assoc_item = tcx.associated_item_from_impl_item_ref(parent_def_id, impl_item_ref); @@ -2643,7 +2792,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) } } - hir::ItemTrait(.., ref trait_item_refs) => { + hir::ItemKind::Trait(.., ref trait_item_refs) => { if let Some(trait_item_ref) = trait_item_refs.iter().find(|i| i.id.node_id == id) { let assoc_item = tcx.associated_item_from_trait_item_ref(parent_def_id, &parent_item.vis, @@ -2675,11 +2824,11 @@ fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, -> &'tcx [Ty<'tcx>] { let def = tcx.adt_def(def_id); - let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| { + let result = tcx.mk_type_list(def.variants.iter().flat_map(|v| { v.fields.last() }).flat_map(|f| { def.sized_constraint_for_ty(tcx, tcx.type_of(f.did)) - }).collect::>()); + })); debug!("adt_sized_constraint: {:?} => {:?}", def, result); @@ -2692,19 +2841,19 @@ fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let id = tcx.hir.as_local_node_id(def_id).unwrap(); let item = tcx.hir.expect_item(id); let vec: Vec<_> = match item.node { - hir::ItemTrait(.., ref trait_item_refs) => { + hir::ItemKind::Trait(.., ref trait_item_refs) => { trait_item_refs.iter() .map(|trait_item_ref| trait_item_ref.id) .map(|id| tcx.hir.local_def_id(id.node_id)) .collect() } - hir::ItemImpl(.., ref impl_item_refs) => { + hir::ItemKind::Impl(.., ref impl_item_refs) => { impl_item_refs.iter() .map(|impl_item_ref| impl_item_ref.id) .map(|id| tcx.hir.local_def_id(id.node_id)) .collect() } - hir::ItemTraitAlias(..) => vec![], + hir::ItemKind::TraitAlias(..) => vec![], _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait") }; Lrc::new(vec) @@ -2727,14 +2876,31 @@ fn trait_of_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> Option }) } +/// Yields the parent function's `DefId` if `def_id` is an `impl Trait` definition +pub fn is_impl_trait_defn(tcx: TyCtxt, def_id: DefId) -> Option { + if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { + if let hir::map::NodeItem(item) = tcx.hir.get(node_id) { + if let hir::ItemKind::Existential(ref exist_ty) = item.node { + return exist_ty.impl_trait_fn; + } + } + } + None +} + /// See `ParamEnv` struct def'n for details. fn param_env<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ParamEnv<'tcx> { + + // The param_env of an impl Trait type is its defining function's param_env + if let Some(parent) = is_impl_trait_defn(tcx, def_id) { + return param_env(tcx, parent); + } // Compute the bounds on Self and the type parameters. - let bounds = tcx.predicates_of(def_id).instantiate_identity(tcx); - let predicates = bounds.predicates; + let InstantiatedPredicates { predicates } = + tcx.predicates_of(def_id).instantiate_identity(tcx); // Finally, we have to normalize the bounds in the environment, in // case they contain any associated type projections. This process @@ -2791,12 +2957,12 @@ fn instance_def_size_estimate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } -pub fn provide(providers: &mut ty::maps::Providers) { +pub fn provide(providers: &mut ty::query::Providers) { context::provide(providers); erase_regions::provide(providers); layout::provide(providers); util::provide(providers); - *providers = ty::maps::Providers { + *providers = ty::query::Providers { associated_item, associated_item_def_ids, adt_sized_constraint, diff --git a/src/librustc/ty/query/README.md b/src/librustc/ty/query/README.md new file mode 100644 index 0000000000000..ca6f0b77b6640 --- /dev/null +++ b/src/librustc/ty/query/README.md @@ -0,0 +1,302 @@ +# The Rust Compiler Query System + +The Compiler Query System is the key to our new demand-driven +organization. The idea is pretty simple. You have various queries +that compute things about the input -- for example, there is a query +called `type_of(def_id)` that, given the def-id of some item, will +compute the type of that item and return it to you. + +Query execution is **memoized** -- so the first time you invoke a +query, it will go do the computation, but the next time, the result is +returned from a hashtable. Moreover, query execution fits nicely into +**incremental computation**; the idea is roughly that, when you do a +query, the result **may** be returned to you by loading stored data +from disk (but that's a separate topic we won't discuss further here). + +The overall vision is that, eventually, the entire compiler +control-flow will be query driven. There will effectively be one +top-level query ("compile") that will run compilation on a crate; this +will in turn demand information about that crate, starting from the +*end*. For example: + +- This "compile" query might demand to get a list of codegen-units + (i.e., modules that need to be compiled by LLVM). +- But computing the list of codegen-units would invoke some subquery + that returns the list of all modules defined in the Rust source. +- That query in turn would invoke something asking for the HIR. +- This keeps going further and further back until we wind up doing the + actual parsing. + +However, that vision is not fully realized. Still, big chunks of the +compiler (for example, generating MIR) work exactly like this. + +### Invoking queries + +To invoke a query is simple. The tcx ("type context") offers a method +for each defined query. So, for example, to invoke the `type_of` +query, you would just do this: + +```rust +let ty = tcx.type_of(some_def_id); +``` + +### Cycles between queries + +Currently, cycles during query execution should always result in a +compilation error. Typically, they arise because of illegal programs +that contain cyclic references they shouldn't (though sometimes they +arise because of compiler bugs, in which case we need to factor our +queries in a more fine-grained fashion to avoid them). + +However, it is nonetheless often useful to *recover* from a cycle +(after reporting an error, say) and try to soldier on, so as to give a +better user experience. In order to recover from a cycle, you don't +get to use the nice method-call-style syntax. Instead, you invoke +using the `try_get` method, which looks roughly like this: + +```rust +use ty::query::queries; +... +match queries::type_of::try_get(tcx, DUMMY_SP, self.did) { + Ok(result) => { + // no cycle occurred! You can use `result` + } + Err(err) => { + // A cycle occurred! The error value `err` is a `DiagnosticBuilder`, + // meaning essentially an "in-progress", not-yet-reported error message. + // See below for more details on what to do here. + } +} +``` + +So, if you get back an `Err` from `try_get`, then a cycle *did* occur. This means that +you must ensure that a compiler error message is reported. You can do that in two ways: + +The simplest is to invoke `err.emit()`. This will emit the cycle error to the user. + +However, often cycles happen because of an illegal program, and you +know at that point that an error either already has been reported or +will be reported due to this cycle by some other bit of code. In that +case, you can invoke `err.cancel()` to not emit any error. It is +traditional to then invoke: + +``` +tcx.sess.delay_span_bug(some_span, "some message") +``` + +`delay_span_bug()` is a helper that says: we expect a compilation +error to have happened or to happen in the future; so, if compilation +ultimately succeeds, make an ICE with the message `"some +message"`. This is basically just a precaution in case you are wrong. + +### How the compiler executes a query + +So you may be wondering what happens when you invoke a query +method. The answer is that, for each query, the compiler maintains a +cache -- if your query has already been executed, then, the answer is +simple: we clone the return value out of the cache and return it +(therefore, you should try to ensure that the return types of queries +are cheaply cloneable; insert a `Rc` if necessary). + +#### Providers + +If, however, the query is *not* in the cache, then the compiler will +try to find a suitable **provider**. A provider is a function that has +been defined and linked into the compiler somewhere that contains the +code to compute the result of the query. + +**Providers are defined per-crate.** The compiler maintains, +internally, a table of providers for every crate, at least +conceptually. Right now, there are really two sets: the providers for +queries about the **local crate** (that is, the one being compiled) +and providers for queries about **external crates** (that is, +dependencies of the local crate). Note that what determines the crate +that a query is targeting is not the *kind* of query, but the *key*. +For example, when you invoke `tcx.type_of(def_id)`, that could be a +local query or an external query, depending on what crate the `def_id` +is referring to (see the `self::keys::Key` trait for more information +on how that works). + +Providers always have the same signature: + +```rust +fn provider<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx, 'tcx>, + key: QUERY_KEY) + -> QUERY_RESULT +{ + ... +} +``` + +Providers take two arguments: the `tcx` and the query key. Note also +that they take the *global* tcx (i.e., they use the `'tcx` lifetime +twice), rather than taking a tcx with some active inference context. +They return the result of the query. + +#### How providers are setup + +When the tcx is created, it is given the providers by its creator using +the `Providers` struct. This struct is generate by the macros here, but it +is basically a big list of function pointers: + +```rust +struct Providers { + type_of: for<'cx, 'tcx> fn(TyCtxt<'cx, 'tcx, 'tcx>, DefId) -> Ty<'tcx>, + ... +} +``` + +At present, we have one copy of the struct for local crates, and one +for external crates, though the plan is that we may eventually have +one per crate. + +These `Provider` structs are ultimately created and populated by +`librustc_driver`, but it does this by distributing the work +throughout the other `rustc_*` crates. This is done by invoking +various `provide` functions. These functions tend to look something +like this: + +```rust +pub fn provide(providers: &mut Providers) { + *providers = Providers { + type_of, + ..*providers + }; +} +``` + +That is, they take an `&mut Providers` and mutate it in place. Usually +we use the formulation above just because it looks nice, but you could +as well do `providers.type_of = type_of`, which would be equivalent. +(Here, `type_of` would be a top-level function, defined as we saw +before.) So, if we want to add a provider for some other query, +let's call it `fubar`, into the crate above, we might modify the `provide()` +function like so: + +```rust +pub fn provide(providers: &mut Providers) { + *providers = Providers { + type_of, + fubar, + ..*providers + }; +} + +fn fubar<'cx, 'tcx>(tcx: TyCtxt<'cx, 'tcx>, key: DefId) -> Fubar<'tcx> { .. } +``` + +NB. Most of the `rustc_*` crates only provide **local +providers**. Almost all **extern providers** wind up going through the +`rustc_metadata` crate, which loads the information from the crate +metadata. But in some cases there are crates that provide queries for +*both* local and external crates, in which case they define both a +`provide` and a `provide_extern` function that `rustc_driver` can +invoke. + +### Adding a new kind of query + +So suppose you want to add a new kind of query, how do you do so? +Well, defining a query takes place in two steps: + +1. first, you have to specify the query name and arguments; and then, +2. you have to supply query providers where needed. + +To specify the query name and arguments, you simply add an entry +to the big macro invocation in `mod.rs`. This will probably have changed +by the time you read this README, but at present it looks something +like: + +``` +define_queries! { <'tcx> + /// Records the type of every item. + [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, + + ... +} +``` + +Each line of the macro defines one query. The name is broken up like this: + +``` +[] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, +^^ ^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^^^^^^^ +| | | | | +| | | | result type of query +| | | query key type +| | dep-node constructor +| name of query +query flags +``` + +Let's go over them one by one: + +- **Query flags:** these are largely unused right now, but the intention + is that we'll be able to customize various aspects of how the query is + processed. +- **Name of query:** the name of the query method + (`tcx.type_of(..)`). Also used as the name of a struct + (`ty::query::queries::type_of`) that will be generated to represent + this query. +- **Dep-node constructor:** indicates the constructor function that + connects this query to incremental compilation. Typically, this is a + `DepNode` variant, which can be added by modifying the + `define_dep_nodes!` macro invocation in + `librustc/dep_graph/dep_node.rs`. + - However, sometimes we use a custom function, in which case the + name will be in snake case and the function will be defined at the + bottom of the file. This is typically used when the query key is + not a def-id, or just not the type that the dep-node expects. +- **Query key type:** the type of the argument to this query. + This type must implement the `ty::query::keys::Key` trait, which + defines (for example) how to map it to a crate, and so forth. +- **Result type of query:** the type produced by this query. This type + should (a) not use `RefCell` or other interior mutability and (b) be + cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for + non-trivial data types. + - The one exception to those rules is the `ty::steal::Steal` type, + which is used to cheaply modify MIR in place. See the definition + of `Steal` for more details. New uses of `Steal` should **not** be + added without alerting `@rust-lang/compiler`. + +So, to add a query: + +- Add an entry to `define_queries!` using the format above. +- Possibly add a corresponding entry to the dep-node macro. +- Link the provider by modifying the appropriate `provide` method; + or add a new one if needed and ensure that `rustc_driver` is invoking it. + +#### Query structs and descriptions + +For each kind, the `define_queries` macro will generate a "query struct" +named after the query. This struct is a kind of a place-holder +describing the query. Each such struct implements the +`self::config::QueryConfig` trait, which has associated types for the +key/value of that particular query. Basically the code generated looks something +like this: + +```rust +// Dummy struct representing a particular kind of query: +pub struct type_of<'tcx> { phantom: PhantomData<&'tcx ()> } + +impl<'tcx> QueryConfig for type_of<'tcx> { + type Key = DefId; + type Value = Ty<'tcx>; +} +``` + +There is an additional trait that you may wish to implement called +`self::config::QueryDescription`. This trait is used during cycle +errors to give a "human readable" name for the query, so that we can +summarize what was happening when the cycle occurred. Implementing +this trait is optional if the query key is `DefId`, but if you *don't* +implement it, you get a pretty generic error ("processing `foo`..."). +You can put new impls into the `config` module. They look something like this: + +```rust +impl<'tcx> QueryDescription for queries::type_of<'tcx> { + fn describe(tcx: TyCtxt, key: DefId) -> String { + format!("computing the type of `{}`", tcx.item_path_str(key)) + } +} +``` + diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/query/config.rs similarity index 87% rename from src/librustc/ty/maps/config.rs rename to src/librustc/ty/query/config.rs index 57c8c4f34e70e..8db33032625b2 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/query/config.rs @@ -11,13 +11,16 @@ use dep_graph::SerializedDepNodeIndex; use dep_graph::DepNode; use hir::def_id::{CrateNum, DefId, DefIndex}; -use mir::interpret::{GlobalId}; -use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; +use mir::interpret::GlobalId; +use traits::query::{ + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpEqGoal, + CanonicalTypeOpNormalizeGoal, CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, +}; use ty::{self, ParamEnvAnd, Ty, TyCtxt}; use ty::subst::Substs; -use ty::maps::queries; -use ty::maps::Query; -use ty::maps::QueryMap; +use ty::query::queries; +use ty::query::Query; +use ty::query::QueryCache; use std::hash::Hash; use std::fmt::Debug; @@ -26,18 +29,20 @@ use rustc_data_structures::sync::Lock; use rustc_data_structures::stable_hasher::HashStable; use ich::StableHashingContext; -/// Query configuration and description traits. +// Query configuration and description traits. pub trait QueryConfig<'tcx> { const NAME: &'static str; type Key: Eq + Hash + Clone + Debug; type Value: Clone + for<'a> HashStable>; +} +pub(super) trait QueryAccessors<'tcx>: QueryConfig<'tcx> { fn query(key: Self::Key) -> Query<'tcx>; // Don't use this method to access query results, instead use the methods on TyCtxt - fn query_map<'a>(tcx: TyCtxt<'a, 'tcx, '_>) -> &'a Lock>; + fn query_cache<'a>(tcx: TyCtxt<'a, 'tcx, '_>) -> &'a Lock>; fn to_dep_node(tcx: TyCtxt<'_, 'tcx, '_>, key: &Self::Key) -> DepNode; @@ -47,7 +52,7 @@ pub trait QueryConfig<'tcx> { fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value; } -pub trait QueryDescription<'tcx>: QueryConfig<'tcx> { +pub(super) trait QueryDescription<'tcx>: QueryAccessors<'tcx> { fn describe(tcx: TyCtxt, key: Self::Key) -> String; #[inline] @@ -62,7 +67,7 @@ pub trait QueryDescription<'tcx>: QueryConfig<'tcx> { } } -impl<'tcx, M: QueryConfig<'tcx, Key=DefId>> QueryDescription<'tcx> for M { +impl<'tcx, M: QueryAccessors<'tcx, Key=DefId>> QueryDescription<'tcx> for M { default fn describe(tcx: TyCtxt, def_id: DefId) -> String { if !tcx.sess.verbose() { format!("processing `{}`", tcx.item_path_str(def_id)) @@ -82,6 +87,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::normalize_projection_ty<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::implied_outlives_bounds<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTyGoal<'tcx>) -> String { + format!("computing implied outlives bounds for `{:?}`", goal) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::dropck_outlives<'tcx> { fn describe(_tcx: TyCtxt, goal: CanonicalTyGoal<'tcx>) -> String { format!("computing dropck types for `{:?}`", goal) @@ -100,6 +111,54 @@ impl<'tcx> QueryDescription<'tcx> for queries::evaluate_obligation<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::type_op_eq<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpEqGoal<'tcx>) -> String { + format!("evaluating `type_op_eq` `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_subtype<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpSubtypeGoal<'tcx>) -> String { + format!("evaluating `type_op_subtype` `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_prove_predicate<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpProvePredicateGoal<'tcx>) -> String { + format!("evaluating `type_op_prove_predicate` `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_ty<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>>) -> String { + format!("normalizing `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_predicate<'tcx> { + fn describe( + _tcx: TyCtxt, + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>>, + ) -> String { + format!("normalizing `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_poly_fn_sig<'tcx> { + fn describe( + _tcx: TyCtxt, + goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>>, + ) -> String { + format!("normalizing `{:?}`", goal) + } +} + +impl<'tcx> QueryDescription<'tcx> for queries::type_op_normalize_fn_sig<'tcx> { + fn describe(_tcx: TyCtxt, goal: CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>>) -> String { + format!("normalizing `{:?}`", goal) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::is_copy_raw<'tcx> { fn describe(_tcx: TyCtxt, env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> String { format!("computing whether `{}` is `Copy`", env.value) @@ -137,6 +196,12 @@ impl<'tcx> QueryDescription<'tcx> for queries::super_predicates_of<'tcx> { } } +impl<'tcx> QueryDescription<'tcx> for queries::const_value_to_allocation<'tcx> { + fn describe(_tcx: TyCtxt, val: &'tcx ty::Const<'tcx>) -> String { + format!("converting value `{:?}` to an allocation", val) + } +} + impl<'tcx> QueryDescription<'tcx> for queries::erase_regions_ty<'tcx> { fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String { format!("erasing regions from `{:?}`", ty) @@ -227,7 +292,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id).map(Ok) + tcx.queries.on_disk_cache.try_load_query_result(tcx, id).map(Ok) } } @@ -251,7 +316,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::symbol_name<'tcx> { fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id) + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) } } @@ -325,7 +390,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_is_rvalue_promotable_to_sta fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id) + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) } } @@ -343,7 +408,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::is_mir_available<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::trans_fulfill_obligation<'tcx> { +impl<'tcx> QueryDescription<'tcx> for queries::codegen_fulfill_obligation<'tcx> { fn describe(tcx: TyCtxt, key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> String { format!("checking if `{}` fulfills its obligations", tcx.item_path_str(key.1.def_id())) } @@ -357,7 +422,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::trans_fulfill_obligation<'tcx> { fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id) + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) } } @@ -537,7 +602,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::named_region_map<'tcx> { impl<'tcx> QueryDescription<'tcx> for queries::is_late_bound_map<'tcx> { fn describe(_tcx: TyCtxt, _: DefIndex) -> String { - format!("testing if a region is late boudn") + format!("testing if a region is late bound") } } @@ -631,9 +696,9 @@ impl<'tcx> QueryDescription<'tcx> for queries::exported_symbols<'tcx> { } } -impl<'tcx> QueryDescription<'tcx> for queries::collect_and_partition_translation_items<'tcx> { +impl<'tcx> QueryDescription<'tcx> for queries::collect_and_partition_mono_items<'tcx> { fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("collect_and_partition_translation_items") + format!("collect_and_partition_mono_items") } } @@ -677,7 +742,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::typeck_tables_of<'tcx> { id: SerializedDepNodeIndex) -> Option { let typeck_tables: Option> = tcx - .on_disk_query_result_cache + .queries.on_disk_cache .try_load_query_result(tcx, id); typeck_tables.map(|tables| tcx.alloc_tables(tables)) @@ -693,7 +758,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::optimized_mir<'tcx> { fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - let mir: Option<::mir::Mir<'tcx>> = tcx.on_disk_query_result_cache + let mir: Option<::mir::Mir<'tcx>> = tcx.queries.on_disk_cache .try_load_query_result(tcx, id); mir.map(|x| tcx.alloc_mir(x)) } @@ -717,12 +782,6 @@ impl<'tcx> QueryDescription<'tcx> for queries::instance_def_size_estimate<'tcx> } } -impl<'tcx> QueryDescription<'tcx> for queries::wasm_custom_sections<'tcx> { - fn describe(_tcx: TyCtxt, _: CrateNum) -> String { - format!("custom wasm sections for a crate") - } -} - impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> { #[inline] fn cache_on_disk(def_id: Self::Key) -> bool { @@ -732,7 +791,7 @@ impl<'tcx> QueryDescription<'tcx> for queries::generics_of<'tcx> { fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - let generics: Option = tcx.on_disk_query_result_cache + let generics: Option = tcx.queries.on_disk_cache .try_load_query_result(tcx, id); generics.map(|x| tcx.alloc_generics(x)) } @@ -774,7 +833,7 @@ macro_rules! impl_disk_cacheable_query( fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - tcx.on_disk_query_result_cache.try_load_query_result(tcx, id) + tcx.queries.on_disk_cache.try_load_query_result(tcx, id) } } } @@ -789,5 +848,5 @@ impl_disk_cacheable_query!(def_symbol_name, |_| true); impl_disk_cacheable_query!(type_of, |def_id| def_id.is_local()); impl_disk_cacheable_query!(predicates_of, |def_id| def_id.is_local()); impl_disk_cacheable_query!(used_trait_imports, |def_id| def_id.is_local()); -impl_disk_cacheable_query!(trans_fn_attrs, |_| true); +impl_disk_cacheable_query!(codegen_fn_attrs, |_| true); impl_disk_cacheable_query!(specialization_graph_of, |_| true); diff --git a/src/librustc/ty/query/job.rs b/src/librustc/ty/query/job.rs new file mode 100644 index 0000000000000..56a8c13a8d3b8 --- /dev/null +++ b/src/librustc/ty/query/job.rs @@ -0,0 +1,525 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(warnings)] + +use std::mem; +use rustc_data_structures::sync::{Lock, LockGuard, Lrc, Weak}; +use rustc_data_structures::OnDrop; +use syntax_pos::Span; +use ty::tls; +use ty::query::Query; +use ty::query::plumbing::CycleError; +use ty::context::TyCtxt; +use errors::Diagnostic; +use std::process; +use std::{fmt, ptr}; +use std::collections::HashSet; +#[cfg(parallel_queries)] +use { + rayon_core, + parking_lot::{Mutex, Condvar}, + std::sync::atomic::Ordering, + std::thread, + std::iter, + std::iter::FromIterator, + syntax_pos::DUMMY_SP, + rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable}, +}; + +/// Indicates the state of a query for a given key in a query map +pub(super) enum QueryResult<'tcx> { + /// An already executing query. The query job can be used to await for its completion + Started(Lrc>), + + /// The query panicked. Queries trying to wait on this will raise a fatal error / silently panic + Poisoned, +} + +/// A span and a query key +#[derive(Clone, Debug)] +pub struct QueryInfo<'tcx> { + /// The span for a reason this query was required + pub span: Span, + pub query: Query<'tcx>, +} + +/// A object representing an active query job. +pub struct QueryJob<'tcx> { + pub info: QueryInfo<'tcx>, + + /// The parent query job which created this job and is implicitly waiting on it. + pub parent: Option>>, + + /// Diagnostic messages which are emitted while the query executes + pub diagnostics: Lock>, + + /// The latch which is used to wait on this job + #[cfg(parallel_queries)] + latch: QueryLatch<'tcx>, +} + +impl<'tcx> QueryJob<'tcx> { + /// Creates a new query job + pub fn new(info: QueryInfo<'tcx>, parent: Option>>) -> Self { + QueryJob { + diagnostics: Lock::new(Vec::new()), + info, + parent, + #[cfg(parallel_queries)] + latch: QueryLatch::new(), + } + } + + /// Awaits for the query job to complete. + /// + /// For single threaded rustc there's no concurrent jobs running, so if we are waiting for any + /// query that means that there is a query cycle, thus this always running a cycle error. + pub(super) fn await<'lcx>( + &self, + tcx: TyCtxt<'_, 'tcx, 'lcx>, + span: Span, + ) -> Result<(), CycleError<'tcx>> { + #[cfg(not(parallel_queries))] + { + self.find_cycle_in_stack(tcx, span) + } + + #[cfg(parallel_queries)] + { + tls::with_related_context(tcx, move |icx| { + let mut waiter = Lrc::new(QueryWaiter { + query: icx.query.clone(), + span, + cycle: Lock::new(None), + condvar: Condvar::new(), + }); + self.latch.await(&waiter); + + match Lrc::get_mut(&mut waiter).unwrap().cycle.get_mut().take() { + None => Ok(()), + Some(cycle) => Err(cycle) + } + }) + } + } + + #[cfg(not(parallel_queries))] + fn find_cycle_in_stack<'lcx>( + &self, + tcx: TyCtxt<'_, 'tcx, 'lcx>, + span: Span, + ) -> Result<(), CycleError<'tcx>> { + // Get the current executing query (waiter) and find the waitee amongst its parents + let mut current_job = tls::with_related_context(tcx, |icx| icx.query.clone()); + let mut cycle = Vec::new(); + + while let Some(job) = current_job { + cycle.insert(0, job.info.clone()); + + if ptr::eq(&*job, self) { + // This is the end of the cycle + // The span entry we included was for the usage + // of the cycle itself, and not part of the cycle + // Replace it with the span which caused the cycle to form + cycle[0].span = span; + // Find out why the cycle itself was used + let usage = job.parent.as_ref().map(|parent| { + (job.info.span, parent.info.query.clone()) + }); + return Err(CycleError { usage, cycle }); + } + + current_job = job.parent.clone(); + } + + panic!("did not find a cycle") + } + + /// Signals to waiters that the query is complete. + /// + /// This does nothing for single threaded rustc, + /// as there are no concurrent jobs which could be waiting on us + pub fn signal_complete(&self) { + #[cfg(parallel_queries)] + self.latch.set(); + } + + fn as_ptr(&self) -> *const QueryJob<'tcx> { + self as *const _ + } +} + +#[cfg(parallel_queries)] +struct QueryWaiter<'tcx> { + query: Option>>, + condvar: Condvar, + span: Span, + cycle: Lock>>, +} + +#[cfg(parallel_queries)] +impl<'tcx> QueryWaiter<'tcx> { + fn notify(&self, registry: &rayon_core::Registry) { + rayon_core::mark_unblocked(registry); + self.condvar.notify_one(); + } +} + +#[cfg(parallel_queries)] +struct QueryLatchInfo<'tcx> { + complete: bool, + waiters: Vec>>, +} + +#[cfg(parallel_queries)] +struct QueryLatch<'tcx> { + info: Mutex>, +} + +#[cfg(parallel_queries)] +impl<'tcx> QueryLatch<'tcx> { + fn new() -> Self { + QueryLatch { + info: Mutex::new(QueryLatchInfo { + complete: false, + waiters: Vec::new(), + }), + } + } + + /// Awaits the caller on this latch by blocking the current thread. + fn await(&self, waiter: &Lrc>) { + let mut info = self.info.lock(); + if !info.complete { + // We push the waiter on to the `waiters` list. It can be accessed inside + // the `wait` call below, by 1) the `set` method or 2) by deadlock detection. + // Both of these will remove it from the `waiters` list before resuming + // this thread. + info.waiters.push(waiter.clone()); + + // If this detects a deadlock and the deadlock handler wants to resume this thread + // we have to be in the `wait` call. This is ensured by the deadlock handler + // getting the self.info lock. + rayon_core::mark_blocked(); + waiter.condvar.wait(&mut info); + } + } + + /// Sets the latch and resumes all waiters on it + fn set(&self) { + let mut info = self.info.lock(); + debug_assert!(!info.complete); + info.complete = true; + let registry = rayon_core::Registry::current(); + for waiter in info.waiters.drain(..) { + waiter.notify(®istry); + } + } + + /// Remove a single waiter from the list of waiters. + /// This is used to break query cycles. + fn extract_waiter( + &self, + waiter: usize, + ) -> Lrc> { + let mut info = self.info.lock(); + debug_assert!(!info.complete); + // Remove the waiter from the list of waiters + info.waiters.remove(waiter) + } +} + +/// A resumable waiter of a query. The usize is the index into waiters in the query's latch +#[cfg(parallel_queries)] +type Waiter<'tcx> = (Lrc>, usize); + +/// Visits all the non-resumable and resumable waiters of a query. +/// Only waiters in a query are visited. +/// `visit` is called for every waiter and is passed a query waiting on `query_ref` +/// and a span indicating the reason the query waited on `query_ref`. +/// If `visit` returns Some, this function returns. +/// For visits of non-resumable waiters it returns the return value of `visit`. +/// For visits of resumable waiters it returns Some(Some(Waiter)) which has the +/// required information to resume the waiter. +/// If all `visit` calls returns None, this function also returns None. +#[cfg(parallel_queries)] +fn visit_waiters<'tcx, F>(query: Lrc>, mut visit: F) -> Option>> +where + F: FnMut(Span, Lrc>) -> Option>> +{ + // Visit the parent query which is a non-resumable waiter since it's on the same stack + if let Some(ref parent) = query.parent { + if let Some(cycle) = visit(query.info.span, parent.clone()) { + return Some(cycle); + } + } + + // Visit the explict waiters which use condvars and are resumable + for (i, waiter) in query.latch.info.lock().waiters.iter().enumerate() { + if let Some(ref waiter_query) = waiter.query { + if visit(waiter.span, waiter_query.clone()).is_some() { + // Return a value which indicates that this waiter can be resumed + return Some(Some((query.clone(), i))); + } + } + } + None +} + +/// Look for query cycles by doing a depth first search starting at `query`. +/// `span` is the reason for the `query` to execute. This is initially DUMMY_SP. +/// If a cycle is detected, this initial value is replaced with the span causing +/// the cycle. +#[cfg(parallel_queries)] +fn cycle_check<'tcx>(query: Lrc>, + span: Span, + stack: &mut Vec<(Span, Lrc>)>, + visited: &mut HashSet<*const QueryJob<'tcx>> +) -> Option>> { + if visited.contains(&query.as_ptr()) { + return if let Some(p) = stack.iter().position(|q| q.1.as_ptr() == query.as_ptr()) { + // We detected a query cycle, fix up the initial span and return Some + + // Remove previous stack entries + stack.splice(0..p, iter::empty()); + // Replace the span for the first query with the cycle cause + stack[0].0 = span; + Some(None) + } else { + None + } + } + + // Mark this query is visited and add it to the stack + visited.insert(query.as_ptr()); + stack.push((span, query.clone())); + + // Visit all the waiters + let r = visit_waiters(query, |span, successor| { + cycle_check(successor, span, stack, visited) + }); + + // Remove the entry in our stack if we didn't find a cycle + if r.is_none() { + stack.pop(); + } + + r +} + +/// Finds out if there's a path to the compiler root (aka. code which isn't in a query) +/// from `query` without going through any of the queries in `visited`. +/// This is achieved with a depth first search. +#[cfg(parallel_queries)] +fn connected_to_root<'tcx>( + query: Lrc>, + visited: &mut HashSet<*const QueryJob<'tcx>> +) -> bool { + // We already visited this or we're deliberately ignoring it + if visited.contains(&query.as_ptr()) { + return false; + } + + // This query is connected to the root (it has no query parent), return true + if query.parent.is_none() { + return true; + } + + visited.insert(query.as_ptr()); + + let mut connected = false; + + visit_waiters(query, |_, successor| { + if connected_to_root(successor, visited) { + Some(None) + } else { + None + } + }).is_some() +} + +/// Looks for query cycles starting from the last query in `jobs`. +/// If a cycle is found, all queries in the cycle is removed from `jobs` and +/// the function return true. +/// If a cycle was not found, the starting query is removed from `jobs` and +/// the function returns false. +#[cfg(parallel_queries)] +fn remove_cycle<'tcx>( + jobs: &mut Vec>>, + wakelist: &mut Vec>>, + tcx: TyCtxt<'_, 'tcx, '_> +) -> bool { + let mut visited = HashSet::new(); + let mut stack = Vec::new(); + // Look for a cycle starting with the last query in `jobs` + if let Some(waiter) = cycle_check(jobs.pop().unwrap(), + DUMMY_SP, + &mut stack, + &mut visited) { + // Reverse the stack so earlier entries require later entries + stack.reverse(); + + // Extract the spans and queries into separate arrays + let mut spans: Vec<_> = stack.iter().map(|e| e.0).collect(); + let queries = stack.into_iter().map(|e| e.1); + + // Shift the spans so that queries are matched with the span for their waitee + let last = spans.pop().unwrap(); + spans.insert(0, last); + + // Zip them back together + let mut stack: Vec<_> = spans.into_iter().zip(queries).collect(); + + // Remove the queries in our cycle from the list of jobs to look at + for r in &stack { + if let Some(pos) = jobs.iter().position(|j| j.as_ptr() == r.1.as_ptr()) { + jobs.remove(pos); + } + } + + // Find the queries in the cycle which are + // connected to queries outside the cycle + let entry_points: Vec>> = stack.iter().filter_map(|query| { + // Mark all the other queries in the cycle as already visited + let mut visited = HashSet::from_iter(stack.iter().filter_map(|q| { + if q.1.as_ptr() != query.1.as_ptr() { + Some(q.1.as_ptr()) + } else { + None + } + })); + + if connected_to_root(query.1.clone(), &mut visited) { + Some(query.1.clone()) + } else { + None + } + }).collect(); + + // Deterministically pick an entry point + // FIXME: Sort this instead + let mut hcx = tcx.create_stable_hashing_context(); + let entry_point = entry_points.iter().min_by_key(|q| { + let mut stable_hasher = StableHasher::::new(); + q.info.query.hash_stable(&mut hcx, &mut stable_hasher); + stable_hasher.finish() + }).unwrap().as_ptr(); + + // Shift the stack until our entry point is first + while stack[0].1.as_ptr() != entry_point { + let last = stack.pop().unwrap(); + stack.insert(0, last); + } + + // Create the cycle error + let mut error = CycleError { + usage: None, + cycle: stack.iter().map(|&(s, ref q)| QueryInfo { + span: s, + query: q.info.query.clone(), + } ).collect(), + }; + + // We unwrap `waiter` here since there must always be one + // edge which is resumeable / waited using a query latch + let (waitee_query, waiter_idx) = waiter.unwrap(); + + // Extract the waiter we want to resume + let waiter = waitee_query.latch.extract_waiter(waiter_idx); + + // Set the cycle error so it will be picked up when resumed + *waiter.cycle.lock() = Some(error); + + // Put the waiter on the list of things to resume + wakelist.push(waiter); + + true + } else { + false + } +} + +/// Creates a new thread and forwards information in thread locals to it. +/// The new thread runs the deadlock handler. +/// Must only be called when a deadlock is about to happen. +#[cfg(parallel_queries)] +pub unsafe fn handle_deadlock() { + use syntax; + use syntax_pos; + + let registry = rayon_core::Registry::current(); + + let gcx_ptr = tls::GCX_PTR.with(|gcx_ptr| { + gcx_ptr as *const _ + }); + let gcx_ptr = &*gcx_ptr; + + let syntax_globals = syntax::GLOBALS.with(|syntax_globals| { + syntax_globals as *const _ + }); + let syntax_globals = &*syntax_globals; + + let syntax_pos_globals = syntax_pos::GLOBALS.with(|syntax_pos_globals| { + syntax_pos_globals as *const _ + }); + let syntax_pos_globals = &*syntax_pos_globals; + thread::spawn(move || { + tls::GCX_PTR.set(gcx_ptr, || { + syntax_pos::GLOBALS.set(syntax_pos_globals, || { + syntax_pos::GLOBALS.set(syntax_pos_globals, || { + tls::with_thread_locals(|| { + tls::with_global(|tcx| deadlock(tcx, ®istry)) + }) + }) + }) + }) + }); +} + +/// Detects query cycles by using depth first search over all active query jobs. +/// If a query cycle is found it will break the cycle by finding an edge which +/// uses a query latch and then resuming that waiter. +/// There may be multiple cycles involved in a deadlock, so this searches +/// all active queries for cycles before finally resuming all the waiters at once. +#[cfg(parallel_queries)] +fn deadlock(tcx: TyCtxt<'_, '_, '_>, registry: &rayon_core::Registry) { + let on_panic = OnDrop(|| { + eprintln!("deadlock handler panicked, aborting process"); + process::abort(); + }); + + let mut wakelist = Vec::new(); + let mut jobs: Vec<_> = tcx.queries.collect_active_jobs(); + + let mut found_cycle = false; + + while jobs.len() > 0 { + if remove_cycle(&mut jobs, &mut wakelist, tcx) { + found_cycle = true; + } + } + + // Check that a cycle was found. It is possible for a deadlock to occur without + // a query cycle if a query which can be waited on uses Rayon to do multithreading + // internally. Such a query (X) may be executing on 2 threads (A and B) and A may + // wait using Rayon on B. Rayon may then switch to executing another query (Y) + // which in turn will wait on X causing a deadlock. We have a false dependency from + // X to Y due to Rayon waiting and a true dependency from Y to X. The algorithm here + // only considers the true dependency and won't detect a cycle. + assert!(found_cycle); + + // FIXME: Ensure this won't cause a deadlock before we return + for waiter in wakelist.into_iter() { + waiter.notify(registry); + } + + on_panic.disable(); +} diff --git a/src/librustc/ty/maps/keys.rs b/src/librustc/ty/query/keys.rs similarity index 75% rename from src/librustc/ty/maps/keys.rs rename to src/librustc/ty/query/keys.rs index da29f23589e85..8423b02ee7582 100644 --- a/src/librustc/ty/maps/keys.rs +++ b/src/librustc/ty/query/keys.rs @@ -10,8 +10,8 @@ //! Defines the set of legal keys that can be used in queries. +use infer::canonical::Canonical; use hir::def_id::{CrateNum, DefId, LOCAL_CRATE, DefIndex}; -use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal}; use ty::{self, Ty, TyCtxt}; use ty::subst::Substs; use ty::fast_reject::SimplifiedType; @@ -24,10 +24,10 @@ use syntax_pos::symbol::InternedString; /// The `Key` trait controls what types can legally be used as the key /// for a query. -pub trait Key: Clone + Hash + Eq + Debug { +pub(super) trait Key: Clone + Hash + Eq + Debug { /// Given an instance of this key, what crate is it referring to? /// This is used to find the provider. - fn map_crate(&self) -> CrateNum; + fn query_crate(&self) -> CrateNum; /// In the event that a cycle occurs, if no explicit span has been /// given for a query with key `self`, what span should we use? @@ -35,7 +35,7 @@ pub trait Key: Clone + Hash + Eq + Debug { } impl<'tcx> Key for ty::InstanceDef<'tcx> { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -45,7 +45,7 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> { } impl<'tcx> Key for ty::Instance<'tcx> { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } @@ -55,8 +55,8 @@ impl<'tcx> Key for ty::Instance<'tcx> { } impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { - fn map_crate(&self) -> CrateNum { - self.instance.map_crate() + fn query_crate(&self) -> CrateNum { + self.instance.query_crate() } fn default_span(&self, tcx: TyCtxt) -> Span { @@ -65,7 +65,7 @@ impl<'tcx> Key for mir::interpret::GlobalId<'tcx> { } impl Key for CrateNum { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { *self } fn default_span(&self, _: TyCtxt) -> Span { @@ -74,7 +74,7 @@ impl Key for CrateNum { } impl Key for DefIndex { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } fn default_span(&self, _tcx: TyCtxt) -> Span { @@ -83,7 +83,7 @@ impl Key for DefIndex { } impl Key for DefId { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { self.krate } fn default_span(&self, tcx: TyCtxt) -> Span { @@ -92,7 +92,7 @@ impl Key for DefId { } impl Key for (DefId, DefId) { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { self.0.krate } fn default_span(&self, tcx: TyCtxt) -> Span { @@ -101,7 +101,7 @@ impl Key for (DefId, DefId) { } impl Key for (CrateNum, DefId) { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { self.0 } fn default_span(&self, tcx: TyCtxt) -> Span { @@ -110,7 +110,7 @@ impl Key for (CrateNum, DefId) { } impl Key for (DefId, SimplifiedType) { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { self.0.krate } fn default_span(&self, tcx: TyCtxt) -> Span { @@ -119,7 +119,7 @@ impl Key for (DefId, SimplifiedType) { } impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { self.0.krate } fn default_span(&self, tcx: TyCtxt) -> Span { @@ -128,7 +128,7 @@ impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) { } impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { self.1.def_id().krate } fn default_span(&self, tcx: TyCtxt) -> Span { @@ -137,7 +137,7 @@ impl<'tcx> Key for (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>) { } impl<'tcx> Key for ty::PolyTraitRef<'tcx>{ - fn map_crate(&self) -> CrateNum { + fn query_crate(&self) -> CrateNum { self.def_id().krate } fn default_span(&self, tcx: TyCtxt) -> Span { @@ -145,8 +145,8 @@ impl<'tcx> Key for ty::PolyTraitRef<'tcx>{ } } -impl<'tcx> Key for Ty<'tcx> { - fn map_crate(&self) -> CrateNum { +impl<'tcx> Key for &'tcx ty::Const<'tcx> { + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } fn default_span(&self, _: TyCtxt) -> Span { @@ -154,8 +154,8 @@ impl<'tcx> Key for Ty<'tcx> { } } -impl<'tcx> Key for ty::ParamEnv<'tcx> { - fn map_crate(&self) -> CrateNum { +impl<'tcx> Key for Ty<'tcx> { + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } fn default_span(&self, _: TyCtxt) -> Span { @@ -163,46 +163,40 @@ impl<'tcx> Key for ty::ParamEnv<'tcx> { } } -impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { - fn map_crate(&self) -> CrateNum { - self.value.map_crate() - } - fn default_span(&self, tcx: TyCtxt) -> Span { - self.value.default_span(tcx) - } -} - -impl Key for InternedString { - fn map_crate(&self) -> CrateNum { +impl<'tcx> Key for ty::ParamEnv<'tcx> { + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } - fn default_span(&self, _tcx: TyCtxt) -> Span { + fn default_span(&self, _: TyCtxt) -> Span { DUMMY_SP } } -impl<'tcx> Key for CanonicalProjectionGoal<'tcx> { - fn map_crate(&self) -> CrateNum { - LOCAL_CRATE +impl<'tcx, T: Key> Key for ty::ParamEnvAnd<'tcx, T> { + fn query_crate(&self) -> CrateNum { + self.value.query_crate() } - - fn default_span(&self, _tcx: TyCtxt) -> Span { - DUMMY_SP + fn default_span(&self, tcx: TyCtxt) -> Span { + self.value.default_span(tcx) } } -impl<'tcx> Key for CanonicalTyGoal<'tcx> { - fn map_crate(&self) -> CrateNum { +impl Key for InternedString { + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } - fn default_span(&self, _tcx: TyCtxt) -> Span { DUMMY_SP } } -impl<'tcx> Key for CanonicalPredicateGoal<'tcx> { - fn map_crate(&self) -> CrateNum { +/// Canonical query goals correspond to abstract trait operations that +/// are not tied to any crate in particular. +impl<'tcx, T> Key for Canonical<'tcx, T> +where + T: Debug + Hash + Clone + Eq, +{ + fn query_crate(&self) -> CrateNum { LOCAL_CRATE } diff --git a/src/librustc/ty/query/mod.rs b/src/librustc/ty/query/mod.rs new file mode 100644 index 0000000000000..1b1020c9bd86d --- /dev/null +++ b/src/librustc/ty/query/mod.rs @@ -0,0 +1,856 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use dep_graph::{DepConstructor, DepNode}; +use errors::DiagnosticBuilder; +use hir::def_id::{CrateNum, DefId, DefIndex}; +use hir::def::{Def, Export}; +use hir::{self, TraitCandidate, ItemLocalId, CodegenFnAttrs}; +use hir::svh::Svh; +use infer::canonical::{self, Canonical}; +use lint; +use middle::borrowck::BorrowCheckResult; +use middle::cstore::{ExternCrate, LinkagePreference, NativeLibrary, ForeignModule}; +use middle::cstore::{NativeLibraryKind, DepKind, CrateSource}; +use middle::privacy::AccessLevels; +use middle::reachable::ReachableSet; +use middle::region; +use middle::resolve_lifetime::{ResolveLifetimes, Region, ObjectLifetimeDefault}; +use middle::stability::{self, DeprecationEntry}; +use middle::lang_items::{LanguageItems, LangItem}; +use middle::exported_symbols::{SymbolExportLevel, ExportedSymbol}; +use mir::interpret::ConstEvalResult; +use mir::mono::{CodegenUnit, Stats}; +use mir; +use mir::interpret::{GlobalId, Allocation}; +use session::{CompileResult, CrateDisambiguator}; +use session::config::OutputFilenames; +use traits::{self, Vtable}; +use traits::query::{CanonicalPredicateGoal, CanonicalProjectionGoal, + CanonicalTyGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpSubtypeGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpNormalizeGoal, NoSolution}; +use traits::query::dropck_outlives::{DtorckConstraint, DropckOutlivesResult}; +use traits::query::normalize::NormalizationResult; +use traits::query::outlives_bounds::OutlivesBound; +use traits::specialization_graph; +use traits::Clauses; +use ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; +use ty::steal::Steal; +use ty::subst::Substs; +use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet}; +use util::common::{ErrorReported}; + +use rustc_data_structures::indexed_set::IdxSetBuf; +use rustc_target::spec::PanicStrategy; +use rustc_data_structures::indexed_vec::IndexVec; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::stable_hasher::StableVec; + +use std::ops::Deref; +use rustc_data_structures::sync::Lrc; +use std::sync::Arc; +use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::symbol::InternedString; +use syntax::attr; +use syntax::ast; +use syntax::feature_gate; +use syntax::symbol::Symbol; + +#[macro_use] +mod plumbing; +use self::plumbing::*; +pub use self::plumbing::{force_from_dep_node, CycleError}; + +mod job; +pub use self::job::{QueryJob, QueryInfo}; +#[cfg(parallel_queries)] +pub use self::job::handle_deadlock; + +mod keys; +use self::keys::Key; + +mod values; +use self::values::Value; + +mod config; +pub use self::config::QueryConfig; +use self::config::{QueryAccessors, QueryDescription}; + +mod on_disk_cache; +pub use self::on_disk_cache::OnDiskCache; + +// Each of these quries corresponds to a function pointer field in the +// `Providers` struct for requesting a value of that type, and a method +// on `tcx: TyCtxt` (and `tcx.at(span)`) for doing that request in a way +// which memoizes and does dep-graph tracking, wrapping around the actual +// `Providers` that the driver creates (using several `rustc_*` crates). +// +// The result type of each query must implement `Clone`, and additionally +// `ty::query::values::Value`, which produces an appropriate placeholder +// (error) value if the query resulted in a query cycle. +// Queries marked with `fatal_cycle` do not need the latter implementation, +// as they will raise an fatal error on query cycles instead. +define_queries! { <'tcx> + Other { + /// Records the type of every item. + [] fn type_of: TypeOfItem(DefId) -> Ty<'tcx>, + + /// Maps from the def-id of an item (trait/struct/enum/fn) to its + /// associated generics. + [] fn generics_of: GenericsOfItem(DefId) -> &'tcx ty::Generics, + + /// Maps from the def-id of an item (trait/struct/enum/fn) to the + /// predicates (where clauses) that must be proven true in order + /// to reference it. This is almost always the "predicates query" + /// that you want. + /// + /// `predicates_of` builds on `predicates_defined_on` -- in fact, + /// it is almost always the same as that query, except for the + /// case of traits. For traits, `predicates_of` contains + /// an additional `Self: Trait<...>` predicate that users don't + /// actually write. This reflects the fact that to invoke the + /// trait (e.g., via `Default::default`) you must supply types + /// that actually implement the trait. (However, this extra + /// predicate gets in the way of some checks, which are intended + /// to operate over only the actual where-clauses written by the + /// user.) + [] fn predicates_of: PredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + + /// Maps from the def-id of an item (trait/struct/enum/fn) to the + /// predicates (where clauses) directly defined on it. This is + /// equal to the `explicit_predicates_of` predicates plus the + /// `inferred_outlives_of` predicates. + [] fn predicates_defined_on: PredicatesDefinedOnItem(DefId) -> ty::GenericPredicates<'tcx>, + + /// Returns the predicates written explicit by the user. + [] fn explicit_predicates_of: ExplicitPredicatesOfItem(DefId) + -> ty::GenericPredicates<'tcx>, + + /// Returns the inferred outlives predicates (e.g., for `struct + /// Foo<'a, T> { x: &'a T }`, this would return `T: 'a`). + [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Lrc>>, + + /// Maps from the def-id of a trait to the list of + /// super-predicates. This is a subset of the full list of + /// predicates. We store these in a separate map because we must + /// evaluate them even during type conversion, often before the + /// full predicates are available (note that supertraits have + /// additional acyclicity requirements). + [] fn super_predicates_of: SuperPredicatesOfItem(DefId) -> ty::GenericPredicates<'tcx>, + + /// To avoid cycles within the predicates of a single item we compute + /// per-type-parameter predicates for resolving `T::AssocTy`. + [] fn type_param_predicates: type_param_predicates((DefId, DefId)) + -> ty::GenericPredicates<'tcx>, + + [] fn trait_def: TraitDefOfItem(DefId) -> &'tcx ty::TraitDef, + [] fn adt_def: AdtDefOfItem(DefId) -> &'tcx ty::AdtDef, + [] fn adt_destructor: AdtDestructor(DefId) -> Option, + [] fn adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>], + [] fn adt_dtorck_constraint: DtorckConstraint( + DefId + ) -> Result, NoSolution>, + + /// True if this is a const fn + [] fn is_const_fn: IsConstFn(DefId) -> bool, + + /// True if this is a foreign item (i.e., linked via `extern { ... }`). + [] fn is_foreign_item: IsForeignItem(DefId) -> bool, + + /// Get a map with the variance of every item; use `item_variance` + /// instead. + [] fn crate_variances: crate_variances(CrateNum) -> Lrc, + + /// Maps from def-id of a type or region parameter to its + /// (inferred) variance. + [] fn variances_of: ItemVariances(DefId) -> Lrc>, + }, + + TypeChecking { + /// Maps from def-id of a type to its (inferred) outlives. + [] fn inferred_outlives_crate: InferredOutlivesCrate(CrateNum) + -> Lrc>, + }, + + Other { + /// Maps from an impl/trait def-id to a list of the def-ids of its items + [] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Lrc>, + + /// Maps from a trait item to the trait item "descriptor" + [] fn associated_item: AssociatedItems(DefId) -> ty::AssociatedItem, + + [] fn impl_trait_ref: ImplTraitRef(DefId) -> Option>, + [] fn impl_polarity: ImplPolarity(DefId) -> hir::ImplPolarity, + }, + + TypeChecking { + /// Maps a DefId of a type to a list of its inherent impls. + /// Contains implementations of methods that are inherent to a type. + /// Methods in these implementations don't need to be exported. + [] fn inherent_impls: InherentImpls(DefId) -> Lrc>, + }, + + Codegen { + /// Set of all the def-ids in this crate that have MIR associated with + /// them. This includes all the body owners, but also things like struct + /// constructors. + [] fn mir_keys: mir_keys(CrateNum) -> Lrc, + + /// Maps DefId's that have an associated Mir to the result + /// of the MIR qualify_consts pass. The actual meaning of + /// the value isn't known except to the pass itself. + [] fn mir_const_qualif: MirConstQualif(DefId) -> (u8, Lrc>), + + /// Fetch the MIR for a given def-id right after it's built - this includes + /// unreachable code. + [] fn mir_built: MirBuilt(DefId) -> &'tcx Steal>, + + /// Fetch the MIR for a given def-id up till the point where it is + /// ready for const evaluation. + /// + /// See the README for the `mir` module for details. + [] fn mir_const: MirConst(DefId) -> &'tcx Steal>, + + [] fn mir_validated: MirValidated(DefId) -> &'tcx Steal>, + + /// MIR after our optimization passes have run. This is MIR that is ready + /// for codegen. This is also the only query that can fetch non-local MIR, at present. + [] fn optimized_mir: MirOptimized(DefId) -> &'tcx mir::Mir<'tcx>, + }, + + TypeChecking { + /// The result of unsafety-checking this def-id. + [] fn unsafety_check_result: UnsafetyCheckResult(DefId) -> mir::UnsafetyCheckResult, + + /// HACK: when evaluated, this reports a "unsafe derive on repr(packed)" error + [] fn unsafe_derive_on_repr_packed: UnsafeDeriveOnReprPacked(DefId) -> (), + + /// The signature of functions and closures. + [] fn fn_sig: FnSignature(DefId) -> ty::PolyFnSig<'tcx>, + }, + + Other { + /// Caches CoerceUnsized kinds for impls on custom types. + [] fn coerce_unsized_info: CoerceUnsizedInfo(DefId) + -> ty::adjustment::CoerceUnsizedInfo, + }, + + TypeChecking { + [] fn typeck_item_bodies: typeck_item_bodies_dep_node(CrateNum) -> CompileResult, + + [] fn typeck_tables_of: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>, + }, + + Other { + [] fn used_trait_imports: UsedTraitImports(DefId) -> Lrc, + }, + + TypeChecking { + [] fn has_typeck_tables: HasTypeckTables(DefId) -> bool, + + [] fn coherent_trait: CoherenceCheckTrait(DefId) -> (), + }, + + BorrowChecking { + [] fn borrowck: BorrowCheck(DefId) -> Lrc, + + /// Borrow checks the function body. If this is a closure, returns + /// additional requirements that the closure's creator must verify. + [] fn mir_borrowck: MirBorrowCheck(DefId) -> mir::BorrowCheckResult<'tcx>, + }, + + TypeChecking { + /// Gets a complete map from all types to their inherent impls. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + [] fn crate_inherent_impls: crate_inherent_impls_dep_node(CrateNum) -> CrateInherentImpls, + + /// Checks all types in the krate for overlap in their inherent impls. Reports errors. + /// Not meant to be used directly outside of coherence. + /// (Defined only for LOCAL_CRATE) + [] fn crate_inherent_impls_overlap_check: inherent_impls_overlap_check_dep_node(CrateNum) + -> (), + }, + + Other { + /// Results of evaluating const items or constants embedded in + /// other items (such as enum variant explicit discriminants). + [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> ConstEvalResult<'tcx>, + + /// Converts a constant value to an constant allocation + [] fn const_value_to_allocation: const_value_to_allocation( + &'tcx ty::Const<'tcx> + ) -> &'tcx Allocation, + }, + + TypeChecking { + [] fn check_match: CheckMatch(DefId) + -> Result<(), ErrorReported>, + + /// Performs the privacy check and computes "access levels". + [] fn privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Lrc, + }, + + Other { + [] fn reachable_set: reachability_dep_node(CrateNum) -> ReachableSet, + + /// Per-body `region::ScopeTree`. The `DefId` should be the owner-def-id for the body; + /// in the case of closures, this will be redirected to the enclosing function. + [] fn region_scope_tree: RegionScopeTree(DefId) -> Lrc, + + [] fn mir_shims: mir_shim_dep_node(ty::InstanceDef<'tcx>) -> &'tcx mir::Mir<'tcx>, + + [] fn def_symbol_name: SymbolName(DefId) -> ty::SymbolName, + [] fn symbol_name: symbol_name_dep_node(ty::Instance<'tcx>) -> ty::SymbolName, + + [] fn describe_def: DescribeDef(DefId) -> Option, + [] fn def_span: DefSpan(DefId) -> Span, + [] fn lookup_stability: LookupStability(DefId) -> Option<&'tcx attr::Stability>, + [] fn lookup_deprecation_entry: LookupDeprecationEntry(DefId) -> Option, + [] fn item_attrs: ItemAttrs(DefId) -> Lrc<[ast::Attribute]>, + }, + + Codegen { + [] fn codegen_fn_attrs: codegen_fn_attrs(DefId) -> CodegenFnAttrs, + }, + + Other { + [] fn fn_arg_names: FnArgNames(DefId) -> Vec, + /// Gets the rendered value of the specified constant or associated constant. + /// Used by rustdoc. + [] fn rendered_const: RenderedConst(DefId) -> String, + [] fn impl_parent: ImplParent(DefId) -> Option, + }, + + TypeChecking { + [] fn trait_of_item: TraitOfItem(DefId) -> Option, + [] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool, + [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Lrc, + }, + + Codegen { + [] fn is_mir_available: IsMirAvailable(DefId) -> bool, + }, + + Other { + [] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>) + -> Lrc)>>>, + }, + + Codegen { + [] fn codegen_fulfill_obligation: fulfill_obligation_dep_node( + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> Vtable<'tcx, ()>, + }, + + TypeChecking { + [] fn trait_impls_of: TraitImpls(DefId) -> Lrc, + [] fn specialization_graph_of: SpecializationGraph(DefId) + -> Lrc, + [] fn is_object_safe: ObjectSafety(DefId) -> bool, + + // Get the ParameterEnvironment for a given item; this environment + // will be in "user-facing" mode, meaning that it is suitabe for + // type-checking etc, and it does not normalize specializable + // associated types. This is almost always what you want, + // unless you are doing MIR optimizations, in which case you + // might want to use `reveal_all()` method to change modes. + [] fn param_env: ParamEnv(DefId) -> ty::ParamEnv<'tcx>, + + // Trait selection queries. These are best used by invoking `ty.moves_by_default()`, + // `ty.is_copy()`, etc, since that will prune the environment where possible. + [] fn is_copy_raw: is_copy_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn is_sized_raw: is_sized_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn is_freeze_raw: is_freeze_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn needs_drop_raw: needs_drop_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool, + [] fn layout_raw: layout_dep_node(ty::ParamEnvAnd<'tcx, Ty<'tcx>>) + -> Result<&'tcx ty::layout::LayoutDetails, + ty::layout::LayoutError<'tcx>>, + }, + + Other { + [] fn dylib_dependency_formats: DylibDepFormats(CrateNum) + -> Lrc>, + }, + + Codegen { + [fatal_cycle] fn is_panic_runtime: IsPanicRuntime(CrateNum) -> bool, + [fatal_cycle] fn is_compiler_builtins: IsCompilerBuiltins(CrateNum) -> bool, + [fatal_cycle] fn has_global_allocator: HasGlobalAllocator(CrateNum) -> bool, + [fatal_cycle] fn is_sanitizer_runtime: IsSanitizerRuntime(CrateNum) -> bool, + [fatal_cycle] fn is_profiler_runtime: IsProfilerRuntime(CrateNum) -> bool, + [fatal_cycle] fn panic_strategy: GetPanicStrategy(CrateNum) -> PanicStrategy, + [fatal_cycle] fn is_no_builtins: IsNoBuiltins(CrateNum) -> bool, + + [] fn extern_crate: ExternCrate(DefId) -> Lrc>, + }, + + TypeChecking { + [] fn specializes: specializes_node((DefId, DefId)) -> bool, + [] fn in_scope_traits_map: InScopeTraits(DefIndex) + -> Option>>>>, + }, + + Other { + [] fn module_exports: ModuleExports(DefId) -> Option>>, + [] fn lint_levels: lint_levels_node(CrateNum) -> Lrc, + }, + + TypeChecking { + [] fn impl_defaultness: ImplDefaultness(DefId) -> hir::Defaultness, + + [] fn check_item_well_formed: CheckItemWellFormed(DefId) -> (), + [] fn check_trait_item_well_formed: CheckTraitItemWellFormed(DefId) -> (), + [] fn check_impl_item_well_formed: CheckImplItemWellFormed(DefId) -> (), + }, + + Linking { + // The DefIds of all non-generic functions and statics in the given crate + // that can be reached from outside the crate. + // + // We expect this items to be available for being linked to. + // + // This query can also be called for LOCAL_CRATE. In this case it will + // compute which items will be reachable to other crates, taking into account + // the kind of crate that is currently compiled. Crates with only a + // C interface have fewer reachable things. + // + // Does not include external symbols that don't have a corresponding DefId, + // like the compiler-generated `main` function and so on. + [] fn reachable_non_generics: ReachableNonGenerics(CrateNum) + -> Lrc>, + [] fn is_reachable_non_generic: IsReachableNonGeneric(DefId) -> bool, + [] fn is_unreachable_local_definition: IsUnreachableLocalDefinition(DefId) -> bool, + }, + + Codegen { + [] fn upstream_monomorphizations: UpstreamMonomorphizations(CrateNum) + -> Lrc, CrateNum>>>>, + [] fn upstream_monomorphizations_for: UpstreamMonomorphizationsFor(DefId) + -> Option, CrateNum>>>, + }, + + Other { + [] fn native_libraries: NativeLibraries(CrateNum) -> Lrc>, + + [] fn foreign_modules: ForeignModules(CrateNum) -> Lrc>, + + [] fn plugin_registrar_fn: PluginRegistrarFn(CrateNum) -> Option, + [] fn derive_registrar_fn: DeriveRegistrarFn(CrateNum) -> Option, + [] fn crate_disambiguator: CrateDisambiguator(CrateNum) -> CrateDisambiguator, + [] fn crate_hash: CrateHash(CrateNum) -> Svh, + [] fn original_crate_name: OriginalCrateName(CrateNum) -> Symbol, + [] fn extra_filename: ExtraFileName(CrateNum) -> String, + }, + + TypeChecking { + [] fn implementations_of_trait: implementations_of_trait_node((CrateNum, DefId)) + -> Lrc>, + [] fn all_trait_implementations: AllTraitImplementations(CrateNum) + -> Lrc>, + }, + + Other { + [] fn dllimport_foreign_items: DllimportForeignItems(CrateNum) + -> Lrc>, + [] fn is_dllimport_foreign_item: IsDllimportForeignItem(DefId) -> bool, + [] fn is_statically_included_foreign_item: IsStaticallyIncludedForeignItem(DefId) -> bool, + [] fn native_library_kind: NativeLibraryKind(DefId) + -> Option, + }, + + Linking { + [] fn link_args: link_args_node(CrateNum) -> Lrc>, + }, + + BorrowChecking { + // Lifetime resolution. See `middle::resolve_lifetimes`. + [] fn resolve_lifetimes: ResolveLifetimes(CrateNum) -> Lrc, + [] fn named_region_map: NamedRegion(DefIndex) -> + Option>>, + [] fn is_late_bound_map: IsLateBound(DefIndex) -> + Option>>, + [] fn object_lifetime_defaults_map: ObjectLifetimeDefaults(DefIndex) + -> Option>>>>, + }, + + TypeChecking { + [] fn visibility: Visibility(DefId) -> ty::Visibility, + }, + + Other { + [] fn dep_kind: DepKind(CrateNum) -> DepKind, + [] fn crate_name: CrateName(CrateNum) -> Symbol, + [] fn item_children: ItemChildren(DefId) -> Lrc>, + [] fn extern_mod_stmt_cnum: ExternModStmtCnum(DefId) -> Option, + + [] fn get_lang_items: get_lang_items_node(CrateNum) -> Lrc, + [] fn defined_lang_items: DefinedLangItems(CrateNum) -> Lrc>, + [] fn missing_lang_items: MissingLangItems(CrateNum) -> Lrc>, + [] fn visible_parent_map: visible_parent_map_node(CrateNum) + -> Lrc>, + [] fn missing_extern_crate_item: MissingExternCrateItem(CrateNum) -> bool, + [] fn used_crate_source: UsedCrateSource(CrateNum) -> Lrc, + [] fn postorder_cnums: postorder_cnums_node(CrateNum) -> Lrc>, + + [] fn freevars: Freevars(DefId) -> Option>>, + [] fn maybe_unused_trait_import: MaybeUnusedTraitImport(DefId) -> bool, + [] fn maybe_unused_extern_crates: maybe_unused_extern_crates_node(CrateNum) + -> Lrc>, + + [] fn stability_index: stability_index_node(CrateNum) -> Lrc>, + [] fn all_crate_nums: all_crate_nums_node(CrateNum) -> Lrc>, + + /// A vector of every trait accessible in the whole crate + /// (i.e. including those from subcrates). This is used only for + /// error reporting. + [] fn all_traits: all_traits_node(CrateNum) -> Lrc>, + }, + + Linking { + [] fn exported_symbols: ExportedSymbols(CrateNum) + -> Arc, SymbolExportLevel)>>, + }, + + Codegen { + [] fn collect_and_partition_mono_items: + collect_and_partition_mono_items_node(CrateNum) + -> (Arc, Arc>>>), + [] fn is_codegened_item: IsCodegenedItem(DefId) -> bool, + [] fn codegen_unit: CodegenUnit(InternedString) -> Arc>, + [] fn compile_codegen_unit: CompileCodegenUnit(InternedString) -> Stats, + }, + + Other { + [] fn output_filenames: output_filenames_node(CrateNum) + -> Arc, + }, + + TypeChecking { + // Erases regions from `ty` to yield a new type. + // Normally you would just use `tcx.erase_regions(&value)`, + // however, which uses this query as a kind of cache. + [] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>, + + /// Do not call this query directly: invoke `normalize` instead. + [] fn normalize_projection_ty: NormalizeProjectionTy( + CanonicalProjectionGoal<'tcx> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: invoke `normalize_erasing_regions` instead. + [] fn normalize_ty_after_erasing_regions: NormalizeTyAfterErasingRegions( + ParamEnvAnd<'tcx, Ty<'tcx>> + ) -> Ty<'tcx>, + + [] fn implied_outlives_bounds: ImpliedOutlivesBounds( + CanonicalTyGoal<'tcx> + ) -> Result< + Lrc>>>>, + NoSolution, + >, + + /// Do not call this query directly: invoke `infcx.at().dropck_outlives()` instead. + [] fn dropck_outlives: DropckOutlives( + CanonicalTyGoal<'tcx> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: invoke `infcx.predicate_may_hold()` or + /// `infcx.predicate_must_hold()` instead. + [] fn evaluate_obligation: EvaluateObligation( + CanonicalPredicateGoal<'tcx> + ) -> Result, + + /// Do not call this query directly: part of the `Eq` type-op + [] fn type_op_eq: TypeOpEq( + CanonicalTypeOpEqGoal<'tcx> + ) -> Result< + Lrc>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `Subtype` type-op + [] fn type_op_subtype: TypeOpSubtype( + CanonicalTypeOpSubtypeGoal<'tcx> + ) -> Result< + Lrc>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `ProvePredicate` type-op + [] fn type_op_prove_predicate: TypeOpProvePredicate( + CanonicalTypeOpProvePredicateGoal<'tcx> + ) -> Result< + Lrc>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `Normalize` type-op + [] fn type_op_normalize_ty: TypeOpNormalizeTy( + CanonicalTypeOpNormalizeGoal<'tcx, Ty<'tcx>> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `Normalize` type-op + [] fn type_op_normalize_predicate: TypeOpNormalizePredicate( + CanonicalTypeOpNormalizeGoal<'tcx, ty::Predicate<'tcx>> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `Normalize` type-op + [] fn type_op_normalize_poly_fn_sig: TypeOpNormalizePolyFnSig( + CanonicalTypeOpNormalizeGoal<'tcx, ty::PolyFnSig<'tcx>> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + /// Do not call this query directly: part of the `Normalize` type-op + [] fn type_op_normalize_fn_sig: TypeOpNormalizeFnSig( + CanonicalTypeOpNormalizeGoal<'tcx, ty::FnSig<'tcx>> + ) -> Result< + Lrc>>>, + NoSolution, + >, + + [] fn substitute_normalize_and_test_predicates: + substitute_normalize_and_test_predicates_node((DefId, &'tcx Substs<'tcx>)) -> bool, + }, + + Other { + [] fn target_features_whitelist: + target_features_whitelist_node(CrateNum) -> Lrc>>, + + // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. + [] fn instance_def_size_estimate: instance_def_size_estimate_dep_node(ty::InstanceDef<'tcx>) + -> usize, + + [] fn features_query: features_node(CrateNum) -> Lrc, + }, + + TypeChecking { + [] fn program_clauses_for: ProgramClausesFor(DefId) -> Clauses<'tcx>, + + [] fn program_clauses_for_env: ProgramClausesForEnv( + ty::ParamEnv<'tcx> + ) -> Clauses<'tcx>, + }, + + Linking { + [] fn wasm_import_module_map: WasmImportModuleMap(CrateNum) + -> Lrc>, + }, +} + +// `try_get_query` can't be public because it uses the private query +// implementation traits, so we provide access to it selectively. +impl<'a, 'tcx, 'lcx> TyCtxt<'a, 'tcx, 'lcx> { + pub fn try_adt_sized_constraint( + self, + span: Span, + key: DefId, + ) -> Result<&'tcx [Ty<'tcx>], DiagnosticBuilder<'a>> { + self.try_get_query::(span, key) + } + pub fn try_needs_drop_raw( + self, + span: Span, + key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>, + ) -> Result> { + self.try_get_query::(span, key) + } + pub fn try_optimized_mir( + self, + span: Span, + key: DefId, + ) -> Result<&'tcx mir::Mir<'tcx>, DiagnosticBuilder<'a>> { + self.try_get_query::(span, key) + } +} + +////////////////////////////////////////////////////////////////////// +// These functions are little shims used to find the dep-node for a +// given query when there is not a *direct* mapping: + + +fn features_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Features +} + +fn codegen_fn_attrs<'tcx>(id: DefId) -> DepConstructor<'tcx> { + DepConstructor::CodegenFnAttrs { 0: id } +} + +fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::EraseRegionsTy { ty } +} + +fn const_value_to_allocation<'tcx>( + val: &'tcx ty::Const<'tcx>, +) -> DepConstructor<'tcx> { + DepConstructor::ConstValueToAllocation { val } +} + +fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> { + DepConstructor::TypeParamPredicates { + item_id, + param_id + } +} + +fn fulfill_obligation_dep_node<'tcx>((param_env, trait_ref): + (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)) -> DepConstructor<'tcx> { + DepConstructor::FulfillObligation { + param_env, + trait_ref + } +} + +fn crate_inherent_impls_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Coherence +} + +fn inherent_impls_overlap_check_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CoherenceInherentImplOverlapCheck +} + +fn reachability_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::Reachability +} + +fn mir_shim_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::MirShim { + instance_def + } +} + +fn symbol_name_dep_node<'tcx>(instance: ty::Instance<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::InstanceSymbolName { instance } +} + +fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::TypeckBodiesKrate +} + +fn const_eval_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> DepConstructor<'tcx> { + DepConstructor::ConstEval { param_env } +} + +fn mir_keys<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::MirKeys +} + +fn crate_variances<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CrateVariances +} + +fn is_copy_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsCopy { param_env } +} + +fn is_sized_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsSized { param_env } +} + +fn is_freeze_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::IsFreeze { param_env } +} + +fn needs_drop_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::NeedsDrop { param_env } +} + +fn layout_dep_node<'tcx>(param_env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> DepConstructor<'tcx> { + DepConstructor::Layout { param_env } +} + +fn lint_levels_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::LintLevels +} + +fn specializes_node<'tcx>((a, b): (DefId, DefId)) -> DepConstructor<'tcx> { + DepConstructor::Specializes { impl1: a, impl2: b } +} + +fn implementations_of_trait_node<'tcx>((krate, trait_id): (CrateNum, DefId)) + -> DepConstructor<'tcx> +{ + DepConstructor::ImplementationsOfTrait { krate, trait_id } +} + +fn link_args_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::LinkArgs +} + +fn get_lang_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::GetLangItems +} + +fn visible_parent_map_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::VisibleParentMap +} + +fn postorder_cnums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::PostorderCnums +} + +fn maybe_unused_extern_crates_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::MaybeUnusedExternCrates +} + +fn stability_index_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::StabilityIndex +} + +fn all_crate_nums_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::AllCrateNums +} + +fn all_traits_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::AllTraits +} + +fn collect_and_partition_mono_items_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::CollectAndPartitionMonoItems +} + +fn output_filenames_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::OutputFilenames +} + +fn vtable_methods_node<'tcx>(trait_ref: ty::PolyTraitRef<'tcx>) -> DepConstructor<'tcx> { + DepConstructor::VtableMethods{ trait_ref } +} + +fn substitute_normalize_and_test_predicates_node<'tcx>(key: (DefId, &'tcx Substs<'tcx>)) + -> DepConstructor<'tcx> { + DepConstructor::SubstituteNormalizeAndTestPredicates { key } +} + +fn target_features_whitelist_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { + DepConstructor::TargetFeaturesWhitelist +} + +fn instance_def_size_estimate_dep_node<'tcx>(instance_def: ty::InstanceDef<'tcx>) + -> DepConstructor<'tcx> { + DepConstructor::InstanceDefSizeEstimate { + instance_def + } +} diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs similarity index 93% rename from src/librustc/ty/maps/on_disk_cache.rs rename to src/librustc/ty/query/on_disk_cache.rs index cea2a03fd532c..aa42b4072bd8a 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -16,6 +16,7 @@ use hir::def_id::{CrateNum, DefIndex, DefId, LocalDefId, use hir::map::definitions::DefPathHash; use ich::{CachingCodemapView, Fingerprint}; use mir::{self, interpret}; +use mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{Lrc, Lock, HashMapExt, Once}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; @@ -23,7 +24,6 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder, opaque, SpecializedDecoder, SpecializedEncoder, UseSpecializedDecodable, UseSpecializedEncodable}; use session::{CrateDisambiguator, Session}; -use std::cell::RefCell; use std::mem; use syntax::ast::NodeId; use syntax::codemap::{CodeMap, StableFilemapId}; @@ -77,11 +77,7 @@ pub struct OnDiskCache<'sess> { // `serialized_data`. prev_diagnostics_index: FxHashMap, - // Alloc indices to memory location map - prev_interpret_alloc_index: Vec, - - /// Deserialization: A cache to ensure we don't read allocations twice - interpret_alloc_cache: RefCell>, + alloc_decoding_state: AllocDecodingState, } // This type is used only for (de-)serialization. @@ -92,7 +88,7 @@ struct Footer { query_result_index: EncodedQueryResultIndex, diagnostics_index: EncodedQueryResultIndex, // the location of all allocations - interpret_alloc_index: Vec, + interpret_alloc_index: Vec, } type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; @@ -149,8 +145,7 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: footer.query_result_index.into_iter().collect(), prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), synthetic_expansion_infos: Lock::new(FxHashMap()), - prev_interpret_alloc_index: footer.interpret_alloc_index, - interpret_alloc_cache: RefCell::new(FxHashMap::default()), + alloc_decoding_state: AllocDecodingState::new(footer.interpret_alloc_index), } } @@ -166,8 +161,7 @@ impl<'sess> OnDiskCache<'sess> { query_result_index: FxHashMap(), prev_diagnostics_index: FxHashMap(), synthetic_expansion_infos: Lock::new(FxHashMap()), - prev_interpret_alloc_index: Vec::new(), - interpret_alloc_cache: RefCell::new(FxHashMap::default()), + alloc_decoding_state: AllocDecodingState::new(Vec::new()), } } @@ -215,7 +209,7 @@ impl<'sess> OnDiskCache<'sess> { let mut query_result_index = EncodedQueryResultIndex::new(); time(tcx.sess, "encode query results", || { - use ty::maps::queries::*; + use ty::query::queries::*; let enc = &mut encoder; let qri = &mut query_result_index; @@ -224,7 +218,7 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; @@ -234,15 +228,15 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; - encode_query_results::(tcx, enc, qri)?; + encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; // const eval is special, it only encodes successfully evaluated constants - use ty::maps::QueryConfig; - let map = const_eval::query_map(tcx).borrow(); - assert!(map.active.is_empty()); - for (key, entry) in map.results.iter() { - use ty::maps::config::QueryDescription; + use ty::query::QueryAccessors; + let cache = const_eval::query_cache(tcx).borrow(); + assert!(cache.active.is_empty()); + for (key, entry) in cache.results.iter() { + use ty::query::config::QueryDescription; if const_eval::cache_on_disk(key.clone()) { if let Ok(ref value) = entry.value { let dep_node = SerializedDepNodeIndex::new(entry.index.index()); @@ -291,7 +285,7 @@ impl<'sess> OnDiskCache<'sess> { } for idx in n..new_n { let id = encoder.interpret_allocs_inverse[idx]; - let pos = AbsoluteBytePos::new(encoder.position()); + let pos = encoder.position() as u32; interpret_alloc_index.push(pos); interpret::specialized_encode_alloc_id( &mut encoder, @@ -424,8 +418,7 @@ impl<'sess> OnDiskCache<'sess> { file_index_to_file: &self.file_index_to_file, file_index_to_stable_id: &self.file_index_to_stable_id, synthetic_expansion_infos: &self.synthetic_expansion_infos, - prev_interpret_alloc_index: &self.prev_interpret_alloc_index, - interpret_alloc_cache: &self.interpret_alloc_cache, + alloc_decoding_session: self.alloc_decoding_state.new_decoding_session(), }; match decode_tagged(&mut decoder, dep_node_index) { @@ -487,9 +480,7 @@ struct CacheDecoder<'a, 'tcx: 'a, 'x> { synthetic_expansion_infos: &'x Lock>, file_index_to_file: &'x Lock>>, file_index_to_stable_id: &'x FxHashMap, - interpret_alloc_cache: &'x RefCell>, - /// maps from index in the cache file to location in the cache file - prev_interpret_alloc_index: &'x [AbsoluteBytePos], + alloc_decoding_session: AllocDecodingSession<'x>, } impl<'a, 'tcx, 'x> CacheDecoder<'a, 'tcx, 'x> { @@ -612,30 +603,8 @@ implement_ty_decoder!( CacheDecoder<'a, 'tcx, 'x> ); impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { fn specialized_decode(&mut self) -> Result { - let tcx = self.tcx; - let idx = usize::decode(self)?; - trace!("loading index {}", idx); - - if let Some(cached) = self.interpret_alloc_cache.borrow().get(&idx).cloned() { - trace!("loading alloc id {:?} from alloc_cache", cached); - return Ok(cached); - } - let pos = self.prev_interpret_alloc_index[idx].to_usize(); - trace!("loading position {}", pos); - self.with_position(pos, |this| { - interpret::specialized_decode_alloc_id( - this, - tcx, - |this, alloc_id| { - trace!("caching idx {} for alloc id {} at position {}", idx, alloc_id, pos); - assert!(this - .interpret_alloc_cache - .borrow_mut() - .insert(idx, alloc_id) - .is_none()); - }, - ) - }) + let alloc_decoding_session = self.alloc_decoding_session; + alloc_decoding_session.decode_alloc_id(self) } } impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { @@ -654,7 +623,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, 'tcx, 'x> { let len = BytePos::decode(self)?; let file_lo = self.file_index_to_file(file_lo_index); - let lo = file_lo.lines.borrow()[line_lo - 1] + col_lo; + let lo = file_lo.lines[line_lo - 1] + col_lo; let hi = lo + len; let expn_info_tag = u8::decode(self)?; @@ -1010,7 +979,7 @@ impl<'enc, 'a, 'tcx, E> SpecializedEncoder for CacheEncoder<'enc, 'a, 't } impl<'enc, 'a, 'tcx> SpecializedEncoder -for CacheEncoder<'enc, 'a, 'tcx, opaque::Encoder<'enc>> +for CacheEncoder<'enc, 'a, 'tcx, opaque::Encoder> { fn specialized_encode(&mut self, f: &Fingerprint) -> Result<(), Self::Error> { f.encode_opaque(&mut self.encoder) @@ -1088,7 +1057,7 @@ impl IntEncodedWithFixedSize { impl UseSpecializedEncodable for IntEncodedWithFixedSize {} impl UseSpecializedDecodable for IntEncodedWithFixedSize {} -impl<'enc> SpecializedEncoder for opaque::Encoder<'enc> { +impl SpecializedEncoder for opaque::Encoder { fn specialized_encode(&mut self, x: &IntEncodedWithFixedSize) -> Result<(), Self::Error> { let start_pos = self.position(); for i in 0 .. IntEncodedWithFixedSize::ENCODED_SIZE { @@ -1130,7 +1099,7 @@ fn encode_query_results<'enc, 'a, 'tcx, Q, E>(tcx: TyCtxt<'a, 'tcx, 'tcx>, time(tcx.sess, desc, || { - let map = Q::query_map(tcx).borrow(); + let map = Q::query_cache(tcx).borrow(); assert!(map.active.is_empty()); for (key, entry) in map.results.iter() { if Q::cache_on_disk(key.clone()) { diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/query/plumbing.rs similarity index 87% rename from src/librustc/ty/maps/plumbing.rs rename to src/librustc/ty/query/plumbing.rs index 37950463f7444..7a9827b50a176 100644 --- a/src/librustc/ty/maps/plumbing.rs +++ b/src/librustc/ty/query/plumbing.rs @@ -19,10 +19,9 @@ use errors::Diagnostic; use errors::FatalError; use ty::tls; use ty::{TyCtxt}; -use ty::maps::Query; -use ty::maps::config::QueryConfig; -use ty::maps::config::QueryDescription; -use ty::maps::job::{QueryJob, QueryResult, QueryInfo}; +use ty::query::Query; +use ty::query::config::{QueryConfig, QueryDescription}; +use ty::query::job::{QueryJob, QueryResult, QueryInfo}; use ty::item_path; use util::common::{profq_msg, ProfileQueriesMsg, QueryMsg}; @@ -35,7 +34,7 @@ use std::collections::hash_map::Entry; use syntax_pos::Span; use syntax::codemap::DUMMY_SP; -pub struct QueryMap<'tcx, D: QueryConfig<'tcx> + ?Sized> { +pub struct QueryCache<'tcx, D: QueryConfig<'tcx> + ?Sized> { pub(super) results: FxHashMap>, pub(super) active: FxHashMap>, } @@ -56,9 +55,9 @@ impl QueryValue { } } -impl<'tcx, M: QueryConfig<'tcx>> QueryMap<'tcx, M> { - pub(super) fn new() -> QueryMap<'tcx, M> { - QueryMap { +impl<'tcx, M: QueryConfig<'tcx>> QueryCache<'tcx, M> { + pub(super) fn new() -> QueryCache<'tcx, M> { + QueryCache { results: FxHashMap(), active: FxHashMap(), } @@ -95,7 +94,7 @@ macro_rules! profq_query_msg { /// A type representing the responsibility to execute the job in the `job` field. /// This will poison the relevant query if dropped. pub(super) struct JobOwner<'a, 'tcx: 'a, Q: QueryDescription<'tcx> + 'a> { - map: &'a Lock>, + cache: &'a Lock>, key: Q::Key, job: Lrc>, } @@ -105,14 +104,18 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { /// start executing the query, or it returns with the result of the query. /// If the query is executing elsewhere, this will wait for it. /// If the query panicked, this will silently panic. + /// + /// This function is inlined because that results in a noticeable speedup + /// for some compile-time benchmarks. + #[inline(always)] pub(super) fn try_get( tcx: TyCtxt<'a, 'tcx, '_>, span: Span, key: &Q::Key, ) -> TryGetJob<'a, 'tcx, Q> { - let map = Q::query_map(tcx); + let cache = Q::query_cache(tcx); loop { - let mut lock = map.borrow_mut(); + let mut lock = cache.borrow_mut(); if let Some(value) = lock.results.get(key) { profq_msg!(tcx, ProfileQueriesMsg::CacheHit); let result = Ok((value.value.clone(), value.index)); @@ -134,7 +137,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { }; let job = Lrc::new(QueryJob::new(info, icx.query.clone())); let owner = JobOwner { - map, + cache, job: job.clone(), key: (*key).clone(), }; @@ -151,20 +154,20 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { } } - /// Completes the query by updating the query map with the `result`, + /// Completes the query by updating the query cache with the `result`, /// signals the waiter and forgets the JobOwner, so it won't poison the query pub(super) fn complete(self, result: &Q::Value, dep_node_index: DepNodeIndex) { // We can move out of `self` here because we `mem::forget` it below let key = unsafe { ptr::read(&self.key) }; let job = unsafe { ptr::read(&self.job) }; - let map = self.map; + let cache = self.cache; // Forget ourself so our destructor won't poison the query mem::forget(self); let value = QueryValue::new(result.clone(), dep_node_index); { - let mut lock = map.borrow_mut(); + let mut lock = cache.borrow_mut(); lock.active.remove(&key); lock.results.insert(key, value); } @@ -211,7 +214,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> JobOwner<'a, 'tcx, Q> { impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { fn drop(&mut self) { // Poison the query so jobs waiting on it panic - self.map.borrow_mut().active.insert(self.key.clone(), QueryResult::Poisoned); + self.cache.borrow_mut().active.insert(self.key.clone(), QueryResult::Poisoned); // Also signal the completion of the job, so waiters // will continue execution self.job.signal_complete(); @@ -219,7 +222,7 @@ impl<'a, 'tcx, Q: QueryDescription<'tcx>> Drop for JobOwner<'a, 'tcx, Q> { } #[derive(Clone)] -pub(super) struct CycleError<'tcx> { +pub struct CycleError<'tcx> { /// The query and related span which uses the cycle pub(super) usage: Option<(Span, Query<'tcx>)>, pub(super) cycle: Vec>, @@ -227,7 +230,7 @@ pub(super) struct CycleError<'tcx> { /// The result of `try_get_lock` pub(super) enum TryGetJob<'a, 'tcx: 'a, D: QueryDescription<'tcx> + 'a> { - /// The query is not yet started. Contains a guard to the map eventually used to start it. + /// The query is not yet started. Contains a guard to the cache eventually used to start it. NotYetStarted(JobOwner<'a, 'tcx, D>), /// The query was already completed. @@ -388,7 +391,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.dep_graph.read_index(dep_node_index); - self.on_disk_query_result_cache + self.queries.on_disk_cache .store_diagnostics_for_anon_node(dep_node_index, diagnostics); job.complete(&result, dep_node_index); @@ -542,7 +545,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } if dep_node.kind != ::dep_graph::DepKind::Null { - self.on_disk_query_result_cache + self.queries.on_disk_cache .store_diagnostics(dep_node_index, diagnostics); } @@ -558,7 +561,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// side-effects -- e.g., in order to report errors for erroneous programs. /// /// Note: The optimization is only available during incr. comp. - pub fn ensure_query>(self, key: Q::Key) -> () { + pub(super) fn ensure_query>(self, key: Q::Key) -> () { let dep_node = Q::to_dep_node(self, &key); // Ensuring an "input" or anonymous query makes no sense @@ -591,10 +594,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { self.force_query_with_job::(key, job, dep_node) } - pub fn try_get_query>( + pub(super) fn try_get_query>( self, span: Span, - key: Q::Key + key: Q::Key, ) -> Result> { match self.try_get_with::(span, key) { Ok(e) => Ok(e), @@ -602,7 +605,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } - pub fn get_query>(self, span: Span, key: Q::Key) -> Q::Value { + pub(super) fn get_query>( + self, + span: Span, + key: Q::Key, + ) -> Q::Value { self.try_get_query::(span, key).unwrap_or_else(|mut e| { e.emit(); Q::handle_cycle_error(self) @@ -623,30 +630,68 @@ macro_rules! handle_cycle_error { }; } -macro_rules! define_maps { +macro_rules! define_queries { + (<$tcx:tt> $($category:tt { + $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)* + },)*) => { + define_queries_inner! { <$tcx> + $($( $(#[$attr])* category<$category> [$($modifiers)*] fn $name: $node($K) -> $V,)*)* + } + } +} + +macro_rules! define_queries_inner { (<$tcx:tt> - $($(#[$attr:meta])* - [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { + $($(#[$attr:meta])* category<$category:tt> + [$($modifiers:tt)*] fn $name:ident: $node:ident($K:ty) -> $V:ty,)*) => { + use std::mem; + #[cfg(parallel_queries)] + use ty::query::job::QueryResult; use rustc_data_structures::sync::Lock; + use { + rustc_data_structures::stable_hasher::HashStable, + rustc_data_structures::stable_hasher::StableHasherResult, + rustc_data_structures::stable_hasher::StableHasher, + ich::StableHashingContext + }; - define_map_struct! { + define_queries_struct! { tcx: $tcx, input: ($(([$($modifiers)*] [$($attr)*] [$name]))*) } - impl<$tcx> Maps<$tcx> { - pub fn new(providers: IndexVec>) - -> Self { - Maps { + impl<$tcx> Queries<$tcx> { + pub fn new( + providers: IndexVec>, + on_disk_cache: OnDiskCache<'tcx>, + ) -> Self { + Queries { providers, - $($name: Lock::new(QueryMap::new())),* + on_disk_cache, + $($name: Lock::new(QueryCache::new())),* } } + + #[cfg(parallel_queries)] + pub fn collect_active_jobs(&self) -> Vec>> { + let mut jobs = Vec::new(); + + // We use try_lock here since we are only called from the + // deadlock handler, and this shouldn't be locked + $(for v in self.$name.try_lock().unwrap().active.values() { + match *v { + QueryResult::Started(ref job) => jobs.push(job.clone()), + _ => (), + } + })* + + return jobs; + } } #[allow(bad_style)] - #[derive(Copy, Clone, Debug, PartialEq, Eq)] + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum Query<$tcx> { $($(#[$attr])* $name($K)),* } @@ -673,7 +718,7 @@ macro_rules! define_maps { // FIXME(eddyb) Get more valid Span's on queries. pub fn default_span(&self, tcx: TyCtxt<'_, $tcx, '_>, span: Span) -> Span { - if span != DUMMY_SP { + if !span.is_dummy() { return span; } // The def_span query is used to calculate default_span, @@ -688,6 +733,17 @@ macro_rules! define_maps { } } + impl<'a, $tcx> HashStable> for Query<$tcx> { + fn hash_stable(&self, + hcx: &mut StableHashingContext<'a>, + hasher: &mut StableHasher) { + mem::discriminant(self).hash_stable(hcx, hasher); + match *self { + $(Query::$name(key) => key.hash_stable(hcx, hasher),)* + } + } + } + pub mod queries { use std::marker::PhantomData; @@ -697,18 +753,30 @@ macro_rules! define_maps { })* } + // This module and the functions in it exist only to provide a + // predictable symbol name prefix for query providers. This is helpful + // for analyzing queries in profilers. + pub(super) mod __query_compute { + $(#[inline(never)] + pub fn $name R, R>(f: F) -> R { + f() + })* + } + $(impl<$tcx> QueryConfig<$tcx> for queries::$name<$tcx> { type Key = $K; type Value = $V; const NAME: &'static str = stringify!($name); + } + impl<$tcx> QueryAccessors<$tcx> for queries::$name<$tcx> { fn query(key: Self::Key) -> Query<'tcx> { Query::$name(key) } - fn query_map<'a>(tcx: TyCtxt<'a, $tcx, '_>) -> &'a Lock> { - &tcx.maps.$name + fn query_cache<'a>(tcx: TyCtxt<'a, $tcx, '_>) -> &'a Lock> { + &tcx.queries.$name } #[allow(unused)] @@ -718,9 +786,12 @@ macro_rules! define_maps { DepNode::new(tcx, $node(*key)) } + #[inline] fn compute(tcx: TyCtxt<'_, 'tcx, '_>, key: Self::Key) -> Self::Value { - let provider = tcx.maps.providers[key.map_crate()].$name; - provider(tcx.global_tcx(), key) + __query_compute::$name(move || { + let provider = tcx.queries.providers[key.query_crate()].$name; + provider(tcx.global_tcx(), key) + }) } fn handle_cycle_error(tcx: TyCtxt<'_, 'tcx, '_>) -> Self::Value { @@ -789,12 +860,18 @@ macro_rules! define_maps { } } -macro_rules! define_map_struct { +macro_rules! define_queries_struct { (tcx: $tcx:tt, input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => { - pub struct Maps<$tcx> { + pub(crate) struct Queries<$tcx> { + /// This provides access to the incr. comp. on-disk cache for query results. + /// Do not access this directly. It is only meant to be used by + /// `DepGraph::try_mark_green()` and the query infrastructure. + pub(crate) on_disk_cache: OnDiskCache<'tcx>, + providers: IndexVec>, - $($(#[$attr])* $name: Lock>>,)* + + $($(#[$attr])* $name: Lock>>,)* } }; } @@ -809,7 +886,7 @@ macro_rules! define_provider_struct { impl<$tcx> Default for Providers<$tcx> { fn default() -> Self { $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $R { - bug!("tcx.maps.{}({:?}) unsupported by its crate", + bug!("tcx.{}({:?}) unsupported by its crate", stringify!($name), key); })* Providers { $($name),* } @@ -871,7 +948,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, // Since we cannot reconstruct the query key of a DepNode::CodegenUnit, we // would always end up having to evaluate the first caller of the // `codegen_unit` query that *is* reconstructible. This might very well be - // the `compile_codegen_unit` query, thus re-translating the whole CGU just + // the `compile_codegen_unit` query, thus re-codegenning the whole CGU just // to re-trigger calling the `codegen_unit` query with the right key. At // that point we would already have re-done all the work we are trying to // avoid doing in the first place. @@ -909,11 +986,11 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, profq_msg!(tcx, ProfileQueriesMsg::QueryBegin( DUMMY_SP.data(), - profq_query_msg!(::ty::maps::queries::$query::NAME, tcx, $key), + profq_query_msg!(::ty::query::queries::$query::NAME, tcx, $key), ) ); - match tcx.force_query::<::ty::maps::queries::$query>($key, DUMMY_SP, *dep_node) { + match tcx.force_query::<::ty::query::queries::$query>($key, DUMMY_SP, *dep_node) { Ok(_) => {}, Err(e) => { tcx.report_cycle(e).emit(); @@ -956,10 +1033,19 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::FulfillObligation | DepKind::VtableMethods | DepKind::EraseRegionsTy | + DepKind::ConstValueToAllocation | DepKind::NormalizeProjectionTy | DepKind::NormalizeTyAfterErasingRegions | + DepKind::ImpliedOutlivesBounds | DepKind::DropckOutlives | DepKind::EvaluateObligation | + DepKind::TypeOpEq | + DepKind::TypeOpSubtype | + DepKind::TypeOpProvePredicate | + DepKind::TypeOpNormalizeTy | + DepKind::TypeOpNormalizePredicate | + DepKind::TypeOpNormalizePolyFnSig | + DepKind::TypeOpNormalizeFnSig | DepKind::SubstituteNormalizeAndTestPredicates | DepKind::InstanceDefSizeEstimate | DepKind::ProgramClausesForEnv | @@ -999,6 +1085,8 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::TypeOfItem => { force!(type_of, def_id!()); } DepKind::GenericsOfItem => { force!(generics_of, def_id!()); } DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); } + DepKind::PredicatesDefinedOnItem => { force!(predicates_defined_on, def_id!()); } + DepKind::ExplicitPredicatesOfItem => { force!(explicit_predicates_of, def_id!()); } DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); } DepKind::InferredOutlivesCrate => { force!(inferred_outlives_crate, LOCAL_CRATE); } DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); } @@ -1045,7 +1133,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, } DepKind::IsMirAvailable => { force!(is_mir_available, def_id!()); } DepKind::ItemAttrs => { force!(item_attrs, def_id!()); } - DepKind::TransFnAttrs => { force!(trans_fn_attrs, def_id!()); } + DepKind::CodegenFnAttrs => { force!(codegen_fn_attrs, def_id!()); } DepKind::FnArgNames => { force!(fn_arg_names, def_id!()); } DepKind::RenderedConst => { force!(rendered_const, def_id!()); } DepKind::DylibDepFormats => { force!(dylib_dependency_formats, krate!()); } @@ -1120,10 +1208,10 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::AllTraits => { force!(all_traits, LOCAL_CRATE); } DepKind::AllCrateNums => { force!(all_crate_nums, LOCAL_CRATE); } DepKind::ExportedSymbols => { force!(exported_symbols, krate!()); } - DepKind::CollectAndPartitionTranslationItems => { - force!(collect_and_partition_translation_items, LOCAL_CRATE); + DepKind::CollectAndPartitionMonoItems => { + force!(collect_and_partition_mono_items, LOCAL_CRATE); } - DepKind::IsTranslatedItem => { force!(is_translated_item, def_id!()); } + DepKind::IsCodegenedItem => { force!(is_codegened_item, def_id!()); } DepKind::OutputFilenames => { force!(output_filenames, LOCAL_CRATE); } DepKind::TargetFeaturesWhitelist => { force!(target_features_whitelist, LOCAL_CRATE); } @@ -1131,7 +1219,6 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, DepKind::Features => { force!(features_query, LOCAL_CRATE); } DepKind::ProgramClausesFor => { force!(program_clauses_for, def_id!()); } - DepKind::WasmCustomSections => { force!(wasm_custom_sections, krate!()); } DepKind::WasmImportModuleMap => { force!(wasm_import_module_map, krate!()); } DepKind::ForeignModules => { force!(foreign_modules, krate!()); } @@ -1148,15 +1235,15 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>, // FIXME(#45015): Another piece of boilerplate code that could be generated in -// a combined define_dep_nodes!()/define_maps!() macro. +// a combined define_dep_nodes!()/define_queries!() macro. macro_rules! impl_load_from_cache { ($($dep_kind:ident => $query_name:ident,)*) => { impl DepNode { // Check whether the query invocation corresponding to the given // DepNode is eligible for on-disk-caching. pub fn cache_on_disk(&self, tcx: TyCtxt) -> bool { - use ty::maps::queries; - use ty::maps::QueryDescription; + use ty::query::queries; + use ty::query::QueryDescription; match self.kind { $(DepKind::$dep_kind => { @@ -1206,6 +1293,6 @@ impl_load_from_cache!( GenericsOfItem => generics_of, PredicatesOfItem => predicates_of, UsedTraitImports => used_trait_imports, - TransFnAttrs => trans_fn_attrs, + CodegenFnAttrs => codegen_fn_attrs, SpecializationGraph => specialization_graph_of, ); diff --git a/src/librustc/ty/maps/values.rs b/src/librustc/ty/query/values.rs similarity index 100% rename from src/librustc/ty/maps/values.rs rename to src/librustc/ty/query/values.rs diff --git a/src/librustc/ty/relate.rs b/src/librustc/ty/relate.rs index 03ed6e7ac90d1..4e8f33d6a4a03 100644 --- a/src/librustc/ty/relate.rs +++ b/src/librustc/ty/relate.rs @@ -14,17 +14,17 @@ //! type equality, etc. use hir::def_id::DefId; -use middle::const_val::ConstVal; +use mir::interpret::ConstValue; use ty::subst::{Kind, UnpackedKind, Substs}; use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::error::{ExpectedFound, TypeError}; -use mir::interpret::{GlobalId, Value, PrimVal}; +use mir::interpret::GlobalId; use util::common::ErrorReported; +use syntax_pos::DUMMY_SP; use std::rc::Rc; use std::iter; use rustc_target::spec::abi; use hir as ast; -use rustc_data_structures::accumulate_vec::AccumulateVec; pub type RelateResult<'tcx, T> = Result>; @@ -154,6 +154,8 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { -> RelateResult<'tcx, ty::FnSig<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { + let tcx = relation.tcx(); + if a.variadic != b.variadic { return Err(TypeError::VariadicMismatch( expected_found(relation, &a.variadic, &b.variadic))); @@ -175,9 +177,9 @@ impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> { } else { relation.relate_with_variance(ty::Contravariant, &a, &b) } - }).collect::, _>>()?; + }); Ok(ty::FnSig { - inputs_and_output: relation.tcx().intern_type_list(&inputs_and_output), + inputs_and_output: tcx.mk_type_list(inputs_and_output)?, variadic: a.variadic, unsafety, abi, @@ -415,16 +417,15 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound)) } - (&ty::TyGenerator(a_id, a_substs, a_interior), - &ty::TyGenerator(b_id, b_substs, b_interior)) + (&ty::TyGenerator(a_id, a_substs, movability), + &ty::TyGenerator(b_id, b_substs, _)) if a_id == b_id => { // All TyGenerator types with the same id represent // the (anonymous) type of the same generator expression. So // all of their regions should be equated. let substs = relation.relate(&a_substs, &b_substs)?; - let interior = relation.relate(&a_interior, &b_interior)?; - Ok(tcx.mk_generator(a_id, substs, interior)) + Ok(tcx.mk_generator(a_id, substs, movability)) } (&ty::TyGeneratorWitness(a_types), &ty::TyGeneratorWitness(b_types)) => @@ -446,7 +447,7 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, // the (anonymous) type of the same closure expression. So // all of their regions should be equated. let substs = relation.relate(&a_substs, &b_substs)?; - Ok(tcx.mk_closure_from_closure_substs(a_id, substs)) + Ok(tcx.mk_closure(a_id, substs)) } (&ty::TyRawPtr(ref a_mt), &ty::TyRawPtr(ref b_mt)) => @@ -455,10 +456,12 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, Ok(tcx.mk_ptr(mt)) } - (&ty::TyRef(a_r, ref a_mt), &ty::TyRef(b_r, ref b_mt)) => + (&ty::TyRef(a_r, a_ty, a_mutbl), &ty::TyRef(b_r, b_ty, b_mutbl)) => { let r = relation.relate_with_variance(ty::Contravariant, &a_r, &b_r)?; - let mt = relation.relate(a_mt, b_mt)?; + let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl }; + let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl }; + let mt = relation.relate(&a_mt, &b_mt)?; Ok(tcx.mk_ref(r, mt)) } @@ -468,9 +471,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, assert_eq!(sz_a.ty, tcx.types.usize); assert_eq!(sz_b.ty, tcx.types.usize); let to_u64 = |x: &'tcx ty::Const<'tcx>| -> Result { + if let Some(s) = x.assert_usize(tcx) { + return Ok(s); + } match x.val { - ConstVal::Value(Value::ByVal(prim)) => Ok(prim.to_u64().unwrap()), - ConstVal::Unevaluated(def_id, substs) => { + ConstValue::Unevaluated(def_id, substs) => { // FIXME(eddyb) get the right param_env. let param_env = ty::ParamEnv::empty(); match tcx.lift_to_global(&substs) { @@ -486,15 +491,10 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, instance, promoted: None }; - match tcx.const_eval(param_env.and(cid)) { - Ok(&ty::Const { - val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))), - .. - }) => { - assert_eq!(b as u64 as u128, b); - return Ok(b as u64); - } - _ => {} + if let Some(s) = tcx.const_eval(param_env.and(cid)) + .ok() + .map(|c| c.unwrap_usize(tcx)) { + return Ok(s) } } }, @@ -504,7 +504,11 @@ pub fn super_relate_tys<'a, 'gcx, 'tcx, R>(relation: &mut R, "array length could not be evaluated"); Err(ErrorReported) } - _ => bug!("arrays should not have {:?} as length", x) + _ => { + tcx.sess.delay_span_bug(DUMMY_SP, + &format!("arrays should not have {:?} as length", x)); + Err(ErrorReported) + } } }; match (to_u64(sz_a), to_u64(sz_b)) { @@ -607,20 +611,19 @@ impl<'tcx> Relate<'tcx> for ty::ClosureSubsts<'tcx> { where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { let substs = relate_substs(relation, None, a.substs, b.substs)?; - Ok(ty::ClosureSubsts { substs: substs }) + Ok(ty::ClosureSubsts { substs }) } } -impl<'tcx> Relate<'tcx> for ty::GeneratorInterior<'tcx> { +impl<'tcx> Relate<'tcx> for ty::GeneratorSubsts<'tcx> { fn relate<'a, 'gcx, R>(relation: &mut R, - a: &ty::GeneratorInterior<'tcx>, - b: &ty::GeneratorInterior<'tcx>) - -> RelateResult<'tcx, ty::GeneratorInterior<'tcx>> + a: &ty::GeneratorSubsts<'tcx>, + b: &ty::GeneratorSubsts<'tcx>) + -> RelateResult<'tcx, ty::GeneratorSubsts<'tcx>> where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a { - assert_eq!(a.movable, b.movable); - let witness = relation.relate(&a.witness, &b.witness)?; - Ok(ty::GeneratorInterior { witness, movable: a.movable }) + let substs = relate_substs(relation, None, a.substs, b.substs)?; + Ok(ty::GeneratorSubsts { substs }) } } diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index d4ed6c60e0efa..ad29f808285b1 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -13,12 +13,11 @@ //! hand, though we've recently added some macros (e.g., //! `BraceStructLiftImpl!`) to help with the tedium. -use middle::const_val::{self, ConstVal, ConstEvalErr}; +use mir::interpret::{ConstValue, ConstEvalErr}; use ty::{self, Lift, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use rustc_data_structures::accumulate_vec::AccumulateVec; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; -use rustc_data_structures::sync::Lrc; use mir::interpret; use std::rc::Rc; @@ -57,6 +56,7 @@ CloneTypeFoldableAndLiftImpls! { ::ty::BoundRegion, ::ty::ClosureKind, ::ty::IntVarValue, + ::ty::ParamTy, ::syntax_pos::Span, } @@ -304,16 +304,16 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ClosureSubsts<'a> { type Lifted = ty::ClosureSubsts<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { tcx.lift(&self.substs).map(|substs| { - ty::ClosureSubsts { substs: substs } + ty::ClosureSubsts { substs } }) } } -impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorInterior<'a> { - type Lifted = ty::GeneratorInterior<'tcx>; +impl<'a, 'tcx> Lift<'tcx> for ty::GeneratorSubsts<'a> { + type Lifted = ty::GeneratorSubsts<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&self.witness).map(|witness| { - ty::GeneratorInterior { witness, movable: self.movable } + tcx.lift(&self.substs).map(|substs| { + ty::GeneratorSubsts { substs } }) } } @@ -462,10 +462,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { impl<'a, 'tcx> Lift<'tcx> for ConstEvalErr<'a> { type Lifted = ConstEvalErr<'tcx>; fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - tcx.lift(&*self.kind).map(|kind| { + tcx.lift(&self.error).map(|error| { ConstEvalErr { span: self.span, - kind: Lrc::new(kind), + stacktrace: self.stacktrace.clone(), + error, } }) } @@ -476,7 +477,6 @@ impl<'a, 'tcx> Lift<'tcx> for interpret::EvalError<'a> { fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { Some(interpret::EvalError { kind: tcx.lift(&self.kind)?, - backtrace: self.backtrace.clone(), }) } } @@ -507,6 +507,7 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> { InvalidNullPointerUsage => InvalidNullPointerUsage, ReadPointerAsBytes => ReadPointerAsBytes, ReadBytesAsPointer => ReadBytesAsPointer, + ReadForeignStatic => ReadForeignStatic, InvalidPointerMath => InvalidPointerMath, ReadUndefBytes => ReadUndefBytes, DeadLocal => DeadLocal, @@ -578,34 +579,16 @@ impl<'a, 'tcx, O: Lift<'tcx>> Lift<'tcx> for interpret::EvalErrorKind<'a, O> { PathNotFound(ref v) => PathNotFound(v.clone()), UnimplementedTraitSelection => UnimplementedTraitSelection, TypeckError => TypeckError, - ReferencedConstant => ReferencedConstant, + TooGeneric => TooGeneric, + CheckMatchError => CheckMatchError, + ReferencedConstant(ref err) => ReferencedConstant(tcx.lift(&**err)?.into()), OverflowNeg => OverflowNeg, Overflow(op) => Overflow(op), DivisionByZero => DivisionByZero, RemainderByZero => RemainderByZero, GeneratorResumedAfterReturn => GeneratorResumedAfterReturn, GeneratorResumedAfterPanic => GeneratorResumedAfterPanic, - }) - } -} - -impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> { - type Lifted = const_val::ErrKind<'tcx>; - fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option { - use middle::const_val::ErrKind::*; - - Some(match *self { - NonConstPath => NonConstPath, - UnimplementedConstVal(s) => UnimplementedConstVal(s), - IndexOutOfBounds { len, index } => IndexOutOfBounds { len, index }, - - LayoutError(ref e) => { - return tcx.lift(e).map(LayoutError) - } - - TypeckError => TypeckError, - CheckMatchError => CheckMatchError, - Miri(ref e, ref frames) => return tcx.lift(e).map(|e| Miri(e, frames.clone())), + InfiniteLoop => InfiniteLoop, }) } } @@ -864,11 +847,14 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyFnDef(def_id, substs.fold_with(folder)) } ty::TyFnPtr(f) => ty::TyFnPtr(f.fold_with(folder)), - ty::TyRef(ref r, tm) => { - ty::TyRef(r.fold_with(folder), tm.fold_with(folder)) + ty::TyRef(ref r, ty, mutbl) => { + ty::TyRef(r.fold_with(folder), ty.fold_with(folder), mutbl) } - ty::TyGenerator(did, substs, interior) => { - ty::TyGenerator(did, substs.fold_with(folder), interior.fold_with(folder)) + ty::TyGenerator(did, substs, movability) => { + ty::TyGenerator( + did, + substs.fold_with(folder), + movability) } ty::TyGeneratorWitness(types) => ty::TyGeneratorWitness(types.fold_with(folder)), ty::TyClosure(did, substs) => ty::TyClosure(did, substs.fold_with(folder)), @@ -901,9 +887,9 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { ty::TyTuple(ts) => ts.visit_with(visitor), ty::TyFnDef(_, substs) => substs.visit_with(visitor), ty::TyFnPtr(ref f) => f.visit_with(visitor), - ty::TyRef(r, ref tm) => r.visit_with(visitor) || tm.visit_with(visitor), - ty::TyGenerator(_did, ref substs, ref interior) => { - substs.visit_with(visitor) || interior.visit_with(visitor) + ty::TyRef(r, ty, _) => r.visit_with(visitor) || ty.visit_with(visitor), + ty::TyGenerator(_did, ref substs, _) => { + substs.visit_with(visitor) } ty::TyGeneratorWitness(ref types) => types.visit_with(visitor), ty::TyClosure(_did, ref substs) => substs.visit_with(visitor), @@ -980,8 +966,8 @@ BraceStructTypeFoldableImpl! { } BraceStructTypeFoldableImpl! { - impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorInterior<'tcx> { - witness, movable, + impl<'tcx> TypeFoldable<'tcx> for ty::GeneratorSubsts<'tcx> { + substs, } } @@ -1144,20 +1130,24 @@ EnumTypeFoldableImpl! { } } -impl<'tcx> TypeFoldable<'tcx> for ConstVal<'tcx> { +impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { - ConstVal::Value(v) => ConstVal::Value(v), - ConstVal::Unevaluated(def_id, substs) => { - ConstVal::Unevaluated(def_id, substs.fold_with(folder)) + ConstValue::Scalar(v) => ConstValue::Scalar(v), + ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b), + ConstValue::ByRef(alloc, offset) => ConstValue::ByRef(alloc, offset), + ConstValue::Unevaluated(def_id, substs) => { + ConstValue::Unevaluated(def_id, substs.fold_with(folder)) } } } fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { - ConstVal::Value(_) => false, - ConstVal::Unevaluated(_, substs) => substs.visit_with(visitor), + ConstValue::Scalar(_) | + ConstValue::ScalarPair(_, _) | + ConstValue::ByRef(_, _) => false, + ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor), } } } diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 382db571b524e..dd38188824338 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -12,18 +12,20 @@ use hir::def_id::DefId; -use middle::const_val::ConstVal; +use mir::interpret::ConstValue; use middle::region; +use polonius_engine::Atom; use rustc_data_structures::indexed_vec::Idx; use ty::subst::{Substs, Subst, Kind, UnpackedKind}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; -use ty::{Slice, TyS}; +use ty::{Slice, TyS, ParamEnvAnd, ParamEnv}; use util::captures::Captures; +use mir::interpret::{Scalar, Pointer, Value}; use std::iter; use std::cmp::Ordering; use rustc_target::spec::abi; -use syntax::ast::{self, Name}; +use syntax::ast::{self, Ident}; use syntax::symbol::{keywords, InternedString}; use serialize; @@ -33,7 +35,7 @@ use hir; use self::InferTy::*; use self::TypeVariants::*; -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct TypeAndMut<'tcx> { pub ty: Ty<'tcx>, pub mutbl: hir::Mutability, @@ -79,7 +81,7 @@ impl BoundRegion { /// NB: If you change this, you'll probably want to change the corresponding /// AST structure in libsyntax/ast.rs as well. -#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub enum TypeVariants<'tcx> { /// The primitive boolean type. Written as `bool`. TyBool, @@ -121,7 +123,7 @@ pub enum TypeVariants<'tcx> { /// A reference; a pointer with an associated lifetime. Written as /// `&'a mut T` or `&'a T`. - TyRef(Region<'tcx>, TypeAndMut<'tcx>), + TyRef(Region<'tcx>, Ty<'tcx>, hir::Mutability), /// The anonymous type of a function declaration/definition. Each /// function has a unique type. @@ -139,7 +141,7 @@ pub enum TypeVariants<'tcx> { /// The anonymous type of a generator. Used to represent the type of /// `|a| yield a`. - TyGenerator(DefId, ClosureSubsts<'tcx>, GeneratorInterior<'tcx>), + TyGenerator(DefId, GeneratorSubsts<'tcx>, hir::GeneratorMovability), /// A type representin the types stored inside a generator. /// This should only appear in GeneratorInteriors. @@ -156,8 +158,10 @@ pub enum TypeVariants<'tcx> { TyProjection(ProjectionTy<'tcx>), /// Anonymized (`impl Trait`) type found in a return type. - /// The DefId comes from the `impl Trait` ast::Ty node, and the - /// substitutions are for the generics of the function in question. + /// The DefId comes either from + /// * the `impl Trait` ast::Ty node, + /// * or the `existential type` declaration + /// The substitutions are for the generics of the function in question. /// After typeck, the concrete type can be found in the `types` map. TyAnon(DefId, &'tcx Substs<'tcx>), @@ -242,7 +246,7 @@ pub enum TypeVariants<'tcx> { /// out later. /// /// All right, you say, but why include the type parameters from the -/// original function then? The answer is that trans may need them +/// original function then? The answer is that codegen may need them /// when monomorphizing, and they may not appear in the upvars. A /// closure could capture no variables but still make use of some /// in-scope type parameter with a bound (e.g., if our example above @@ -267,12 +271,12 @@ pub enum TypeVariants<'tcx> { /// /// It'd be nice to split this struct into ClosureSubsts and /// GeneratorSubsts, I believe. -nmatsakis -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ClosureSubsts<'tcx> { /// Lifetime and type parameters from the enclosing function, /// concatenated with the types of the upvars. /// - /// These are separated out because trans wants to pass them around + /// These are separated out because codegen wants to pass them around /// when monomorphizing. pub substs: &'tcx Substs<'tcx>, } @@ -291,7 +295,7 @@ impl<'tcx> ClosureSubsts<'tcx> { /// ordering. fn split(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> SplitClosureSubsts<'tcx> { let generics = tcx.generics_of(def_id); - let parent_len = generics.parent_count(); + let parent_len = generics.parent_count; SplitClosureSubsts { closure_kind_ty: self.substs.type_at(parent_len), closure_sig_ty: self.substs.type_at(parent_len + 1), @@ -328,37 +332,6 @@ impl<'tcx> ClosureSubsts<'tcx> { self.split(def_id, tcx).closure_sig_ty } - /// Returns the type representing the yield type of the generator. - pub fn generator_yield_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> { - self.closure_kind_ty(def_id, tcx) - } - - /// Returns the type representing the return type of the generator. - pub fn generator_return_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> { - self.closure_sig_ty(def_id, tcx) - } - - /// Return the "generator signature", which consists of its yield - /// and return types. - /// - /// NB. Some bits of the code prefers to see this wrapped in a - /// binder, but it never contains bound regions. Probably this - /// function should be removed. - pub fn generator_poly_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> PolyGenSig<'tcx> { - ty::Binder::dummy(self.generator_sig(def_id, tcx)) - } - - /// Return the "generator signature", which consists of its yield - /// and return types. - pub fn generator_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> GenSig<'tcx> { - ty::GenSig { - yield_ty: self.generator_yield_ty(def_id, tcx), - return_ty: self.generator_return_ty(def_id, tcx), - } - } -} - -impl<'tcx> ClosureSubsts<'tcx> { /// Returns the closure kind for this closure; only usable outside /// of an inference context, because in that context we know that /// there are no type variables. @@ -381,7 +354,84 @@ impl<'tcx> ClosureSubsts<'tcx> { } } -impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] +pub struct GeneratorSubsts<'tcx> { + pub substs: &'tcx Substs<'tcx>, +} + +struct SplitGeneratorSubsts<'tcx> { + yield_ty: Ty<'tcx>, + return_ty: Ty<'tcx>, + witness: Ty<'tcx>, + upvar_kinds: &'tcx [Kind<'tcx>], +} + +impl<'tcx> GeneratorSubsts<'tcx> { + fn split(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> SplitGeneratorSubsts<'tcx> { + let generics = tcx.generics_of(def_id); + let parent_len = generics.parent_count; + SplitGeneratorSubsts { + yield_ty: self.substs.type_at(parent_len), + return_ty: self.substs.type_at(parent_len + 1), + witness: self.substs.type_at(parent_len + 2), + upvar_kinds: &self.substs[parent_len + 3..], + } + } + + /// This describes the types that can be contained in a generator. + /// It will be a type variable initially and unified in the last stages of typeck of a body. + /// It contains a tuple of all the types that could end up on a generator frame. + /// The state transformation MIR pass may only produce layouts which mention types + /// in this tuple. Upvars are not counted here. + pub fn witness(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> { + self.split(def_id, tcx).witness + } + + #[inline] + pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> + impl Iterator> + 'tcx + { + let SplitGeneratorSubsts { upvar_kinds, .. } = self.split(def_id, tcx); + upvar_kinds.iter().map(|t| { + if let UnpackedKind::Type(ty) = t.unpack() { + ty + } else { + bug!("upvar should be type") + } + }) + } + + /// Returns the type representing the yield type of the generator. + pub fn yield_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> { + self.split(def_id, tcx).yield_ty + } + + /// Returns the type representing the return type of the generator. + pub fn return_ty(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> Ty<'tcx> { + self.split(def_id, tcx).return_ty + } + + /// Return the "generator signature", which consists of its yield + /// and return types. + /// + /// NB. Some bits of the code prefers to see this wrapped in a + /// binder, but it never contains bound regions. Probably this + /// function should be removed. + pub fn poly_sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> PolyGenSig<'tcx> { + ty::Binder::dummy(self.sig(def_id, tcx)) + } + + /// Return the "generator signature", which consists of its yield + /// and return types. + pub fn sig(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> GenSig<'tcx> { + ty::GenSig { + yield_ty: self.yield_ty(def_id, tcx), + return_ty: self.return_ty(def_id, tcx), + } + } +} + +impl<'a, 'gcx, 'tcx> GeneratorSubsts<'tcx> { /// This returns the types of the MIR locals which had to be stored across suspension points. /// It is calculated in rustc_mir::transform::generator::StateTransform. /// All the types here must be in the tuple in GeneratorInterior. @@ -412,18 +462,32 @@ impl<'a, 'gcx, 'tcx> ClosureSubsts<'tcx> { } } -/// This describes the types that can be contained in a generator. -/// It will be a type variable initially and unified in the last stages of typeck of a body. -/// It contains a tuple of all the types that could end up on a generator frame. -/// The state transformation MIR pass may only produce layouts which mention types in this tuple. -/// Upvars are not counted here. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] -pub struct GeneratorInterior<'tcx> { - pub witness: Ty<'tcx>, - pub movable: bool, +#[derive(Debug, Copy, Clone)] +pub enum UpvarSubsts<'tcx> { + Closure(ClosureSubsts<'tcx>), + Generator(GeneratorSubsts<'tcx>), +} + +impl<'tcx> UpvarSubsts<'tcx> { + #[inline] + pub fn upvar_tys(self, def_id: DefId, tcx: TyCtxt<'_, '_, '_>) -> + impl Iterator> + 'tcx + { + let upvar_kinds = match self { + UpvarSubsts::Closure(substs) => substs.split(def_id, tcx).upvar_kinds, + UpvarSubsts::Generator(substs) => substs.split(def_id, tcx).upvar_kinds, + }; + upvar_kinds.iter().map(|t| { + if let UnpackedKind::Type(ty) = t.unpack() { + ty + } else { + bug!("upvar should be type") + } + }) + } } -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, RustcEncodable, RustcDecodable)] pub enum ExistentialPredicate<'tcx> { /// e.g. Iterator Trait(ExistentialTraitRef<'tcx>), @@ -434,7 +498,9 @@ pub enum ExistentialPredicate<'tcx> { } impl<'a, 'gcx, 'tcx> ExistentialPredicate<'tcx> { - pub fn cmp(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, other: &Self) -> Ordering { + /// Compares via an ordering that will not change if modules are reordered or other changes are + /// made to the tree. In particular, this ordering is preserved across incremental compilations. + pub fn stable_cmp(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, other: &Self) -> Ordering { use self::ExistentialPredicate::*; match (*self, *other) { (Trait(_), Trait(_)) => Ordering::Equal, @@ -550,6 +616,15 @@ impl<'tcx> TraitRef<'tcx> { TraitRef { def_id: def_id, substs: substs } } + /// Returns a TraitRef of the form `P0: Foo` where `Pi` + /// are the parameters defined on trait. + pub fn identity<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> TraitRef<'tcx> { + TraitRef { + def_id, + substs: Substs::identity_for_item(tcx, def_id), + } + } + pub fn self_ty(&self) -> Ty<'tcx> { self.substs.type_at(0) } @@ -561,6 +636,18 @@ impl<'tcx> TraitRef<'tcx> { // associated types. self.substs.types() } + + pub fn from_method(tcx: TyCtxt<'_, '_, 'tcx>, + trait_id: DefId, + substs: &Substs<'tcx>) + -> ty::TraitRef<'tcx> { + let defs = tcx.generics_of(trait_id); + + ty::TraitRef { + def_id: trait_id, + substs: tcx.intern_substs(&substs[..defs.params.len()]) + } + } } pub type PolyTraitRef<'tcx> = Binder>; @@ -587,7 +674,7 @@ impl<'tcx> PolyTraitRef<'tcx> { /// /// The substitutions don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct ExistentialTraitRef<'tcx> { pub def_id: DefId, pub substs: &'tcx Substs<'tcx>, @@ -602,6 +689,18 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { self.substs.types() } + pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>, + trait_ref: ty::TraitRef<'tcx>) + -> ty::ExistentialTraitRef<'tcx> { + // Assert there is a Self. + trait_ref.substs.type_at(0); + + ty::ExistentialTraitRef { + def_id: trait_ref.def_id, + substs: tcx.intern_substs(&trait_ref.substs[1..]) + } + } + /// Object types don't have a self-type specified. Therefore, when /// we convert the principal trait-ref into a normal trait-ref, /// you must give *some* self-type. A common choice is `mk_err()` @@ -613,8 +712,7 @@ impl<'a, 'gcx, 'tcx> ExistentialTraitRef<'tcx> { ty::TraitRef { def_id: self.def_id, - substs: tcx.mk_substs( - iter::once(self_ty.into()).chain(self.substs.iter().cloned())) + substs: tcx.mk_substs_trait(self_ty, self.substs) } } } @@ -625,6 +723,16 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { pub fn def_id(&self) -> DefId { self.skip_binder().def_id } + + /// Object types don't have a self-type specified. Therefore, when + /// we convert the principal trait-ref into a normal trait-ref, + /// you must give *some* self-type. A common choice is `mk_err()` + /// or some skolemized type. + pub fn with_self_ty(&self, tcx: TyCtxt<'_, '_, 'tcx>, + self_ty: Ty<'tcx>) + -> ty::PolyTraitRef<'tcx> { + self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty)) + } } /// Binder is a binder for higher-ranked lifetimes. It is part of the @@ -634,7 +742,7 @@ impl<'tcx> PolyExistentialTraitRef<'tcx> { /// erase, or otherwise "discharge" these bound regions, we change the /// type from `Binder` to just `T` (see /// e.g. `liberate_late_bound_regions`). -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Binder(T); impl Binder { @@ -740,7 +848,7 @@ impl Binder { /// Represents the projection of an associated type. In explicit UFCS /// form this would be written `>::N`. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ProjectionTy<'tcx> { /// The parameters of the associated item. pub substs: &'tcx Substs<'tcx>, @@ -756,11 +864,11 @@ impl<'a, 'tcx> ProjectionTy<'tcx> { /// Construct a ProjectionTy by searching the trait from trait_ref for the /// associated item named item_name. pub fn from_ref_and_name( - tcx: TyCtxt, trait_ref: ty::TraitRef<'tcx>, item_name: Name + tcx: TyCtxt, trait_ref: ty::TraitRef<'tcx>, item_name: Ident ) -> ProjectionTy<'tcx> { let item_def_id = tcx.associated_items(trait_ref.def_id).find(|item| { item.kind == ty::AssociatedKind::Type && - tcx.hygienic_eq(item_name, item.name, trait_ref.def_id) + tcx.hygienic_eq(item_name, item.ident, trait_ref.def_id) }).unwrap().def_id; ProjectionTy { @@ -808,7 +916,7 @@ impl<'tcx> PolyGenSig<'tcx> { /// - `inputs` is the list of arguments and their modes. /// - `output` is the return type. /// - `variadic` indicates whether this is a variadic function. (only true for foreign fns) -#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct FnSig<'tcx> { pub inputs_and_output: &'tcx Slice>, pub variadic: bool, @@ -852,7 +960,7 @@ impl<'tcx> PolyFnSig<'tcx> { } } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct ParamTy { pub idx: u32, pub name: InternedString, @@ -867,12 +975,12 @@ impl<'a, 'gcx, 'tcx> ParamTy { ParamTy::new(0, keywords::SelfType.name().as_interned_str()) } - pub fn for_def(def: &ty::TypeParameterDef) -> ParamTy { + pub fn for_def(def: &ty::GenericParamDef) -> ParamTy { ParamTy::new(def.index, def.name) } pub fn to_ty(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { - tcx.mk_param(self.idx, self.name) + tcx.mk_ty_param(self.idx, self.name) } pub fn is_self(&self) -> bool { @@ -894,11 +1002,11 @@ impl<'a, 'gcx, 'tcx> ParamTy { /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) /// ^ ^ | | | /// | | | | | -/// | +------------+ 1 | | +/// | +------------+ 0 | | /// | | | -/// +--------------------------------+ 2 | +/// +--------------------------------+ 1 | /// | | -/// +------------------------------------------+ 1 +/// +------------------------------------------+ 0 /// /// In this type, there are two binders (the outer fn and the inner /// fn). We need to be able to determine, for any given region, which @@ -910,9 +1018,9 @@ impl<'a, 'gcx, 'tcx> ParamTy { /// /// Let's start with the reference type `&'b isize` that is the first /// argument to the inner function. This region `'b` is assigned a De -/// Bruijn index of 1, meaning "the innermost binder" (in this case, a +/// Bruijn index of 0, meaning "the innermost binder" (in this case, a /// fn). The region `'a` that appears in the second argument type (`&'a -/// isize`) would then be assigned a De Bruijn index of 2, meaning "the +/// isize`) would then be assigned a De Bruijn index of 1, meaning "the /// second-innermost binder". (These indices are written on the arrays /// in the diagram). /// @@ -922,16 +1030,15 @@ impl<'a, 'gcx, 'tcx> ParamTy { /// the outermost fn. But this time, this reference is not nested within /// any other binders (i.e., it is not an argument to the inner fn, but /// rather the outer one). Therefore, in this case, it is assigned a -/// De Bruijn index of 1, because the innermost binder in that location +/// De Bruijn index of 0, because the innermost binder in that location /// is the outer fn. /// /// [dbi]: http://en.wikipedia.org/wiki/De_Bruijn_index -#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug, Copy, PartialOrd, Ord)] -pub struct DebruijnIndex { - /// We maintain the invariant that this is never 0. So 1 indicates - /// the innermost binder. To ensure this, create with `DebruijnIndex::new`. - pub depth: u32, -} +newtype_index!(DebruijnIndex + { + DEBUG_FORMAT = "DebruijnIndex({})", + const INNERMOST = 0, + }); pub type Region<'tcx> = &'tcx RegionKind; @@ -991,7 +1098,7 @@ pub type Region<'tcx> = &'tcx RegionKind; /// /// [1]: http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [2]: http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ -/// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/trait-hrtb.html +/// [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/traits/hrtb.html #[derive(Clone, PartialEq, Eq, Hash, Copy, RustcEncodable, RustcDecodable, PartialOrd, Ord)] pub enum RegionKind { // Region bound in a type or fn declaration which will be @@ -1032,7 +1139,7 @@ pub enum RegionKind { /// variable with no constraints. ReEmpty, - /// Erased region, used by trait selection, in MIR and during trans. + /// Erased region, used by trait selection, in MIR and during codegen. ReErased, /// These are regions bound in the "defining type" for a @@ -1054,17 +1161,17 @@ pub struct EarlyBoundRegion { pub name: InternedString, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct TyVid { pub index: u32, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct IntVid { pub index: u32, } -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub struct FloatVid { pub index: u32, } @@ -1075,7 +1182,25 @@ newtype_index!(RegionVid DEBUG_FORMAT = custom, }); -#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)] +impl Atom for RegionVid { + fn index(self) -> usize { + Idx::index(self) + } +} + +impl From for RegionVid { + fn from(i: usize) -> RegionVid { + RegionVid::new(i) + } +} + +impl From for usize { + fn from(vid: RegionVid) -> usize { + Idx::index(vid) + } +} + +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)] pub enum InferTy { TyVar(TyVid), IntVar(IntVid), @@ -1095,7 +1220,7 @@ pub enum InferTy { newtype_index!(CanonicalVar); /// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct ExistentialProjection<'tcx> { pub item_def_id: DefId, pub substs: &'tcx Substs<'tcx>, @@ -1127,8 +1252,7 @@ impl<'a, 'tcx, 'gcx> ExistentialProjection<'tcx> { ty::ProjectionPredicate { projection_ty: ty::ProjectionTy { item_def_id: self.item_def_id, - substs: tcx.mk_substs( - iter::once(self_ty.into()).chain(self.substs.iter().cloned())), + substs: tcx.mk_substs_trait(self_ty, self.substs), }, ty: self.ty, } @@ -1147,16 +1271,66 @@ impl<'a, 'tcx, 'gcx> PolyExistentialProjection<'tcx> { } impl DebruijnIndex { - pub fn new(depth: u32) -> DebruijnIndex { - assert!(depth > 0); - DebruijnIndex { depth: depth } + /// Returns the resulting index when this value is moved into + /// `amount` number of new binders. So e.g. if you had + /// + /// for<'a> fn(&'a x) + /// + /// and you wanted to change to + /// + /// for<'a> fn(for<'b> fn(&'a x)) + /// + /// you would need to shift the index for `'a` into 1 new binder. + #[must_use] + pub const fn shifted_in(self, amount: u32) -> DebruijnIndex { + DebruijnIndex(self.0 + amount) } - pub fn shifted(&self, amount: u32) -> DebruijnIndex { - DebruijnIndex { depth: self.depth + amount } + /// Update this index in place by shifting it "in" through + /// `amount` number of binders. + pub fn shift_in(&mut self, amount: u32) { + *self = self.shifted_in(amount); + } + + /// Returns the resulting index when this value is moved out from + /// `amount` number of new binders. + #[must_use] + pub const fn shifted_out(self, amount: u32) -> DebruijnIndex { + DebruijnIndex(self.0 - amount) + } + + /// Update in place by shifting out from `amount` binders. + pub fn shift_out(&mut self, amount: u32) { + *self = self.shifted_out(amount); + } + + /// Adjusts any Debruijn Indices so as to make `to_binder` the + /// innermost binder. That is, if we have something bound at `to_binder`, + /// it will now be bound at INNERMOST. This is an appropriate thing to do + /// when moving a region out from inside binders: + /// + /// ``` + /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) + /// // Binder: D3 D2 D1 ^^ + /// ``` + /// + /// Here, the region `'a` would have the debruijn index D3, + /// because it is the bound 3 binders out. However, if we wanted + /// to refer to that region `'a` in the second argument (the `_`), + /// those two binders would not be in scope. In that case, we + /// might invoke `shift_out_to_binder(D3)`. This would adjust the + /// debruijn index of `'a` to D1 (the innermost binder). + /// + /// If we invoke `shift_out_to_binder` and the region is in fact + /// bound by one of the binders we are shifting out of, that is an + /// error (and should fail an assertion failure). + pub fn shifted_out_to_binder(self, to_binder: DebruijnIndex) -> Self { + self.shifted_out((to_binder.0 - INNERMOST.0) as u32) } } +impl_stable_hash_for!(tuple_struct DebruijnIndex { index }); + /// Region utilities impl RegionKind { pub fn is_late_bound(&self) -> bool { @@ -1166,19 +1340,39 @@ impl RegionKind { } } - pub fn escapes_depth(&self, depth: u32) -> bool { + pub fn bound_at_or_above_binder(&self, index: DebruijnIndex) -> bool { match *self { - ty::ReLateBound(debruijn, _) => debruijn.depth > depth, + ty::ReLateBound(debruijn, _) => debruijn >= index, _ => false, } } - /// Returns the depth of `self` from the (1-based) binding level `depth` - pub fn from_depth(&self, depth: u32) -> RegionKind { + /// Adjusts any Debruijn Indices so as to make `to_binder` the + /// innermost binder. That is, if we have something bound at `to_binder`, + /// it will now be bound at INNERMOST. This is an appropriate thing to do + /// when moving a region out from inside binders: + /// + /// ``` + /// for<'a> fn(for<'b> for<'c> fn(&'a u32), _) + /// // Binder: D3 D2 D1 ^^ + /// ``` + /// + /// Here, the region `'a` would have the debruijn index D3, + /// because it is the bound 3 binders out. However, if we wanted + /// to refer to that region `'a` in the second argument (the `_`), + /// those two binders would not be in scope. In that case, we + /// might invoke `shift_out_to_binder(D3)`. This would adjust the + /// debruijn index of `'a` to D1 (the innermost binder). + /// + /// If we invoke `shift_out_to_binder` and the region is in fact + /// bound by one of the binders we are shifting out of, that is an + /// error (and should fail an assertion failure). + pub fn shifted_out_to_binder(&self, to_binder: ty::DebruijnIndex) -> RegionKind { match *self { - ty::ReLateBound(debruijn, r) => ty::ReLateBound(DebruijnIndex { - depth: debruijn.depth - (depth - 1) - }, r), + ty::ReLateBound(debruijn, r) => ty::ReLateBound( + debruijn.shifted_out_to_binder(to_binder), + r, + ), r => r } } @@ -1207,7 +1401,9 @@ impl RegionKind { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_RE_SKOL; } - ty::ReLateBound(..) => { } + ty::ReLateBound(..) => { + flags = flags | TypeFlags::HAS_RE_LATE_BOUND; + } ty::ReEarlyBound(..) => { flags = flags | TypeFlags::HAS_FREE_REGIONS; flags = flags | TypeFlags::HAS_RE_EARLY_BOUND; @@ -1230,8 +1426,8 @@ impl RegionKind { } match *self { - ty::ReStatic | ty::ReEmpty | ty::ReErased => (), - _ => flags = flags | TypeFlags::HAS_LOCAL_NAMES, + ty::ReStatic | ty::ReEmpty | ty::ReErased | ty::ReLateBound(..) => (), + _ => flags = flags | TypeFlags::HAS_FREE_LOCAL_NAMES, } debug!("type_flags({:?}) = {:?}", self, flags); @@ -1332,7 +1528,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_slice(&self) -> bool { match self.sty { - TyRawPtr(mt) | TyRef(_, mt) => match mt.ty.sty { + TyRawPtr(TypeAndMut { ty, .. }) | TyRef(_, ty, _) => match ty.sty { TySlice(_) | TyStr => true, _ => false, }, @@ -1381,11 +1577,8 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { pub fn is_mutable_pointer(&self) -> bool { match self.sty { - TyRawPtr(tnm) | TyRef(_, tnm) => if let hir::Mutability::MutMutable = tnm.mutbl { - true - } else { - false - }, + TyRawPtr(TypeAndMut { mutbl: hir::Mutability::MutMutable, .. }) | + TyRef(_, _, hir::Mutability::MutMutable) => true, _ => false } } @@ -1538,7 +1731,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { mutbl: hir::MutImmutable, }) }, - TyRef(_, mt) => Some(mt), + TyRef(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl }), TyRawPtr(mt) if explicit => Some(mt), _ => None, } @@ -1569,14 +1762,10 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } } - pub fn ty_to_def_id(&self) -> Option { + pub fn is_impl_trait(&self) -> bool { match self.sty { - TyDynamic(ref tt, ..) => tt.principal().map(|p| p.def_id()), - TyAdt(def, _) => Some(def.did), - TyForeign(did) => Some(did), - TyClosure(id, _) => Some(id), - TyFnDef(id, _) => Some(id), - _ => None, + TyAnon(..) => true, + _ => false, } } @@ -1592,7 +1781,7 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { /// ignores late-bound regions binders. pub fn regions(&self) -> Vec> { match self.sty { - TyRef(region, _) => { + TyRef(region, _, _) => { vec![region] } TyDynamic(ref obj, region) => { @@ -1605,8 +1794,9 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { TyAdt(_, substs) | TyAnon(_, substs) => { substs.regions().collect() } - TyClosure(_, ref substs) | TyGenerator(_, ref substs, _) => { - substs.substs.regions().collect() + TyClosure(_, ClosureSubsts { ref substs }) | + TyGenerator(_, GeneratorSubsts { ref substs }, _) => { + substs.regions().collect() } TyProjection(ref data) => { data.substs.regions().collect() @@ -1665,11 +1855,161 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> { } /// Typed constant value. -#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)] pub struct Const<'tcx> { pub ty: Ty<'tcx>, - pub val: ConstVal<'tcx>, + pub val: ConstValue<'tcx>, +} + +impl<'tcx> Const<'tcx> { + pub fn unevaluated( + tcx: TyCtxt<'_, '_, 'tcx>, + def_id: DefId, + substs: &'tcx Substs<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx Self { + tcx.mk_const(Const { + val: ConstValue::Unevaluated(def_id, substs), + ty, + }) + } + + #[inline] + pub fn from_const_value( + tcx: TyCtxt<'_, '_, 'tcx>, + val: ConstValue<'tcx>, + ty: Ty<'tcx>, + ) -> &'tcx Self { + tcx.mk_const(Const { + val, + ty, + }) + } + + #[inline] + pub fn from_byval_value( + tcx: TyCtxt<'_, '_, 'tcx>, + val: Value, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_value(tcx, ConstValue::from_byval_value(val), ty) + } + + #[inline] + pub fn from_scalar( + tcx: TyCtxt<'_, '_, 'tcx>, + val: Scalar, + ty: Ty<'tcx>, + ) -> &'tcx Self { + Self::from_const_value(tcx, ConstValue::from_scalar(val), ty) + } + + #[inline] + pub fn from_bits( + tcx: TyCtxt<'_, '_, 'tcx>, + bits: u128, + ty: ParamEnvAnd<'tcx, Ty<'tcx>>, + ) -> &'tcx Self { + let ty = tcx.lift_to_global(&ty).unwrap(); + let size = tcx.layout_of(ty).unwrap_or_else(|e| { + panic!("could not compute layout for {:?}: {:?}", ty, e) + }).size; + let shift = 128 - size.bits(); + let truncated = (bits << shift) >> shift; + assert_eq!(truncated, bits, "from_bits called with untruncated value"); + Self::from_scalar(tcx, Scalar::Bits { bits, defined: size.bits() as u8 }, ty.value) + } + + #[inline] + pub fn zero_sized(tcx: TyCtxt<'_, '_, 'tcx>, ty: Ty<'tcx>) -> &'tcx Self { + Self::from_scalar(tcx, Scalar::undef(), ty) + } + + #[inline] + pub fn from_bool(tcx: TyCtxt<'_, '_, 'tcx>, v: bool) -> &'tcx Self { + Self::from_bits(tcx, v as u128, ParamEnv::empty().and(tcx.types.bool)) + } + + #[inline] + pub fn from_usize(tcx: TyCtxt<'_, '_, 'tcx>, n: u64) -> &'tcx Self { + Self::from_bits(tcx, n as u128, ParamEnv::empty().and(tcx.types.usize)) + } + + #[inline] + pub fn to_bits( + &self, + tcx: TyCtxt<'_, '_, 'tcx>, + ty: ParamEnvAnd<'tcx, Ty<'tcx>>, + ) -> Option { + if self.ty != ty.value { + return None; + } + let ty = tcx.lift_to_global(&ty).unwrap(); + let size = tcx.layout_of(ty).ok()?.size; + self.val.to_bits(size) + } + + #[inline] + pub fn to_ptr(&self) -> Option { + self.val.to_ptr() + } + + #[inline] + pub fn to_byval_value(&self) -> Option { + self.val.to_byval_value() + } + + #[inline] + pub fn to_scalar(&self) -> Option { + self.val.to_scalar() + } + + #[inline] + pub fn assert_bits( + &self, + tcx: TyCtxt<'_, '_, '_>, + ty: ParamEnvAnd<'tcx, Ty<'tcx>>, + ) -> Option { + assert_eq!(self.ty, ty.value); + let ty = tcx.lift_to_global(&ty).unwrap(); + let size = tcx.layout_of(ty).ok()?.size; + self.val.to_bits(size) + } + + #[inline] + pub fn assert_bool(&self, tcx: TyCtxt<'_, '_, '_>) -> Option { + self.assert_bits(tcx, ParamEnv::empty().and(tcx.types.bool)).and_then(|v| match v { + 0 => Some(false), + 1 => Some(true), + _ => None, + }) + } + + #[inline] + pub fn assert_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> Option { + self.assert_bits(tcx, ParamEnv::empty().and(tcx.types.usize)).map(|v| v as u64) + } + + #[inline] + pub fn unwrap_bits( + &self, + tcx: TyCtxt<'_, '_, '_>, + ty: ParamEnvAnd<'tcx, Ty<'tcx>>, + ) -> u128 { + match self.assert_bits(tcx, ty) { + Some(val) => val, + None => bug!("expected bits of {}, got {:#?}", ty.value, self), + } + } + + #[inline] + pub fn unwrap_usize(&self, tcx: TyCtxt<'_, '_, '_>) -> u64 { + match self.assert_usize(tcx) { + Some(val) => val, + None => bug!("expected constant usize, got {:#?}", self), + } + } } impl<'tcx> serialize::UseSpecializedDecodable for &'tcx Const<'tcx> {} diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index e7b58ae1564aa..2e3c6df9754df 100644 --- a/src/librustc/ty/subst.rs +++ b/src/librustc/ty/subst.rs @@ -11,16 +11,17 @@ // Type substitutions. use hir::def_id::DefId; -use ty::{self, Lift, Slice, Region, Ty, TyCtxt}; +use ty::{self, Lift, Slice, Ty, TyCtxt}; use ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; use serialize::{self, Encodable, Encoder, Decodable, Decoder}; use syntax_pos::{Span, DUMMY_SP}; use rustc_data_structures::accumulate_vec::AccumulateVec; +use rustc_data_structures::array_vec::ArrayVec; use core::intrinsics; +use std::cmp::Ordering; use std::fmt; -use std::iter; use std::marker::PhantomData; use std::mem; use std::num::NonZeroUsize; @@ -40,7 +41,7 @@ const TAG_MASK: usize = 0b11; const TYPE_TAG: usize = 0b00; const REGION_TAG: usize = 0b01; -#[derive(Debug)] +#[derive(Debug, RustcEncodable, RustcDecodable)] pub enum UnpackedKind<'tcx> { Lifetime(ty::Region<'tcx>), Type(Ty<'tcx>), @@ -70,6 +71,28 @@ impl<'tcx> UnpackedKind<'tcx> { } } +impl<'tcx> Ord for Kind<'tcx> { + fn cmp(&self, other: &Kind) -> Ordering { + match (self.unpack(), other.unpack()) { + (UnpackedKind::Type(_), UnpackedKind::Lifetime(_)) => Ordering::Greater, + + (UnpackedKind::Type(ty1), UnpackedKind::Type(ty2)) => { + ty1.sty.cmp(&ty2.sty) + } + + (UnpackedKind::Lifetime(reg1), UnpackedKind::Lifetime(reg2)) => reg1.cmp(reg2), + + (UnpackedKind::Lifetime(_), UnpackedKind::Type(_)) => Ordering::Less, + } + } +} + +impl<'tcx> PartialOrd for Kind<'tcx> { + fn partial_cmp(&self, other: &Kind) -> Option { + Some(self.cmp(&other)) + } +} + impl<'tcx> From> for Kind<'tcx> { fn from(r: ty::Region<'tcx>) -> Kind<'tcx> { UnpackedKind::Lifetime(r).pack() @@ -143,123 +166,91 @@ impl<'tcx> TypeFoldable<'tcx> for Kind<'tcx> { impl<'tcx> Encodable for Kind<'tcx> { fn encode(&self, e: &mut E) -> Result<(), E::Error> { - e.emit_enum("Kind", |e| { - match self.unpack() { - UnpackedKind::Lifetime(lt) => { - e.emit_enum_variant("Region", REGION_TAG, 1, |e| { - e.emit_enum_variant_arg(0, |e| lt.encode(e)) - }) - } - UnpackedKind::Type(ty) => { - e.emit_enum_variant("Ty", TYPE_TAG, 1, |e| { - e.emit_enum_variant_arg(0, |e| ty.encode(e)) - }) - } - } - }) + self.unpack().encode(e) } } impl<'tcx> Decodable for Kind<'tcx> { fn decode(d: &mut D) -> Result, D::Error> { - d.read_enum("Kind", |d| { - d.read_enum_variant(&["Ty", "Region"], |d, tag| { - match tag { - TYPE_TAG => Ty::decode(d).map(Kind::from), - REGION_TAG => Region::decode(d).map(Kind::from), - _ => Err(d.error("invalid Kind tag")) - } - }) - }) + Ok(UnpackedKind::decode(d)?.pack()) } } -/// A substitution mapping type/region parameters to new values. +/// A substitution mapping generic parameters to new values. pub type Substs<'tcx> = Slice>; impl<'a, 'gcx, 'tcx> Substs<'tcx> { /// Creates a Substs that maps each generic parameter to itself. pub fn identity_for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, def_id: DefId) -> &'tcx Substs<'tcx> { - Substs::for_item(tcx, def_id, |def, _| { - tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data())) - }, |def, _| tcx.mk_param_from_def(def)) + Substs::for_item(tcx, def_id, |param, _| { + tcx.mk_param_from_def(param) + }) } /// Creates a Substs for generic parameter definitions, - /// by calling closures to obtain each region and type. + /// by calling closures to obtain each kind. /// The closures get to observe the Substs as they're /// being built, which can be used to correctly - /// substitute defaults of type parameters. - pub fn for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, - def_id: DefId, - mut mk_region: FR, - mut mk_type: FT) - -> &'tcx Substs<'tcx> - where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>, - FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { + /// substitute defaults of generic parameters. + pub fn for_item(tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + mut mk_kind: F) + -> &'tcx Substs<'tcx> + where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> + { let defs = tcx.generics_of(def_id); - let mut substs = Vec::with_capacity(defs.count()); - Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type); + let count = defs.count(); + let mut substs = if count <= 8 { + AccumulateVec::Array(ArrayVec::new()) + } else { + AccumulateVec::Heap(Vec::with_capacity(count)) + }; + Substs::fill_item(&mut substs, tcx, defs, &mut mk_kind); tcx.intern_substs(&substs) } - pub fn extend_to(&self, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - def_id: DefId, - mut mk_region: FR, - mut mk_type: FT) - -> &'tcx Substs<'tcx> - where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>, - FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> + pub fn extend_to(&self, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + def_id: DefId, + mut mk_kind: F) + -> &'tcx Substs<'tcx> + where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> { - let defs = tcx.generics_of(def_id); - let mut result = Vec::with_capacity(defs.count()); - result.extend(self[..].iter().cloned()); - Substs::fill_single(&mut result, defs, &mut mk_region, &mut mk_type); - tcx.intern_substs(&result) + Substs::for_item(tcx, def_id, |param, substs| { + match self.get(param.index as usize) { + Some(&kind) => kind, + None => mk_kind(param, substs), + } + }) } - pub fn fill_item(substs: &mut Vec>, - tcx: TyCtxt<'a, 'gcx, 'tcx>, - defs: &ty::Generics, - mk_region: &mut FR, - mk_type: &mut FT) - where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>, - FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { + fn fill_item(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, + tcx: TyCtxt<'a, 'gcx, 'tcx>, + defs: &ty::Generics, + mk_kind: &mut F) + where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> + { if let Some(def_id) = defs.parent { let parent_defs = tcx.generics_of(def_id); - Substs::fill_item(substs, tcx, parent_defs, mk_region, mk_type); - } - Substs::fill_single(substs, defs, mk_region, mk_type) - } - - fn fill_single(substs: &mut Vec>, - defs: &ty::Generics, - mk_region: &mut FR, - mk_type: &mut FT) - where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> ty::Region<'tcx>, - FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> { - // Handle Self first, before all regions. - let mut types = defs.types.iter(); - if defs.parent.is_none() && defs.has_self { - let def = types.next().unwrap(); - let ty = mk_type(def, substs); - assert_eq!(def.index as usize, substs.len()); - substs.push(ty.into()); - } - - for def in &defs.regions { - let region = mk_region(def, substs); - assert_eq!(def.index as usize, substs.len()); - substs.push(Kind::from(region)); + Substs::fill_item(substs, tcx, parent_defs, mk_kind); } + Substs::fill_single(substs, defs, mk_kind) + } - for def in types { - let ty = mk_type(def, substs); - assert_eq!(def.index as usize, substs.len()); - substs.push(Kind::from(ty)); + fn fill_single(substs: &mut AccumulateVec<[Kind<'tcx>; 8]>, + defs: &ty::Generics, + mk_kind: &mut F) + where F: FnMut(&ty::GenericParamDef, &[Kind<'tcx>]) -> Kind<'tcx> + { + for param in &defs.params { + let kind = mk_kind(param, substs); + assert_eq!(param.index as usize, substs.len()); + match *substs { + AccumulateVec::Array(ref mut arr) => arr.push(kind), + AccumulateVec::Heap(ref mut vec) => vec.push(kind), + } } } @@ -308,13 +299,8 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { } #[inline] - pub fn type_for_def(&self, ty_param_def: &ty::TypeParameterDef) -> Ty<'tcx> { - self.type_at(ty_param_def.index as usize) - } - - #[inline] - pub fn region_for_def(&self, def: &ty::RegionParameterDef) -> ty::Region<'tcx> { - self.region_at(def.index as usize) + pub fn type_for_def(&self, def: &ty::GenericParamDef) -> Kind<'tcx> { + self.type_at(def.index as usize).into() } /// Transform from substitutions for a child of `source_ancestor` @@ -327,7 +313,7 @@ impl<'a, 'gcx, 'tcx> Substs<'tcx> { target_substs: &Substs<'tcx>) -> &'tcx Substs<'tcx> { let defs = tcx.generics_of(source_ancestor); - tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned()) + tcx.mk_substs(target_substs.iter().chain(&self[defs.params.len()..]).cloned()) } pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics) @@ -568,54 +554,3 @@ impl<'a, 'gcx, 'tcx> SubstFolder<'a, 'gcx, 'tcx> { self.tcx().mk_region(ty::fold::shift_region(*region, self.region_binders_passed)) } } - -// Helper methods that modify substitutions. - -impl<'a, 'gcx, 'tcx> ty::TraitRef<'tcx> { - pub fn from_method(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_id: DefId, - substs: &Substs<'tcx>) - -> ty::TraitRef<'tcx> { - let defs = tcx.generics_of(trait_id); - - ty::TraitRef { - def_id: trait_id, - substs: tcx.intern_substs(&substs[..defs.own_count()]) - } - } -} - -impl<'a, 'gcx, 'tcx> ty::ExistentialTraitRef<'tcx> { - pub fn erase_self_ty(tcx: TyCtxt<'a, 'gcx, 'tcx>, - trait_ref: ty::TraitRef<'tcx>) - -> ty::ExistentialTraitRef<'tcx> { - // Assert there is a Self. - trait_ref.substs.type_at(0); - - ty::ExistentialTraitRef { - def_id: trait_ref.def_id, - substs: tcx.intern_substs(&trait_ref.substs[1..]) - } - } -} - -impl<'a, 'gcx, 'tcx> ty::PolyExistentialTraitRef<'tcx> { - /// Object types don't have a self-type specified. Therefore, when - /// we convert the principal trait-ref into a normal trait-ref, - /// you must give *some* self-type. A common choice is `mk_err()` - /// or some skolemized type. - pub fn with_self_ty(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, - self_ty: Ty<'tcx>) - -> ty::PolyTraitRef<'tcx> { - // otherwise the escaping regions would be captured by the binder - assert!(!self_ty.has_escaping_regions()); - - self.map_bound(|trait_ref| { - ty::TraitRef { - def_id: trait_ref.def_id, - substs: tcx.mk_substs( - iter::once(self_ty.into()).chain(trait_ref.substs.iter().cloned())) - } - }) - } -} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 4aa70e1f7e006..95caa0c185be1 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -15,24 +15,18 @@ use hir::def_id::DefId; use hir::map::{DefPathData, Node}; use hir; use ich::NodeIdHashingMode; -use middle::const_val::ConstVal; -use traits; -use ty::{self, Ty, TyCtxt, TypeFoldable}; -use ty::fold::TypeVisitor; -use ty::subst::UnpackedKind; -use ty::maps::TyCtxtAt; +use traits::{self, ObligationCause}; +use ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; +use ty::subst::{Substs, UnpackedKind}; +use ty::query::TyCtxtAt; use ty::TypeVariants::*; use ty::layout::{Integer, IntegerExt}; use util::common::ErrorReported; use middle::lang_items; -use mir::interpret::{Value, PrimVal}; -use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult, - HashStable}; +use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; use rustc_data_structures::fx::FxHashMap; use std::{cmp, fmt}; -use std::hash::Hash; -use std::intrinsics; use syntax::ast; use syntax::attr::{self, SignedInt, UnsignedInt}; use syntax_pos::{Span, DUMMY_SP}; @@ -74,14 +68,14 @@ impl<'tcx> Discr<'tcx> { }; let bit_size = int.size().bits(); - let amt = 128 - bit_size; + let shift = 128 - bit_size; if signed { let sext = |u| { let i = u as i128; - (i << amt) >> amt + (i << shift) >> shift }; let min = sext(1_u128 << (bit_size - 1)); - let max = i128::max_value() >> amt; + let max = i128::max_value() >> shift; let val = sext(self.val); assert!(n < (i128::max_value() as u128)); let n = n as i128; @@ -93,13 +87,13 @@ impl<'tcx> Discr<'tcx> { }; // zero the upper bits let val = val as u128; - let val = (val << amt) >> amt; + let val = (val << shift) >> shift; (Self { val: val as u128, ty: self.ty, }, oflo) } else { - let max = u128::max_value() >> amt; + let max = u128::max_value() >> shift; let val = self.val; let oflo = val > max - n; let val = if oflo { @@ -167,9 +161,9 @@ impl IntTypeExt for attr::IntType { } -#[derive(Copy, Clone)] +#[derive(Clone)] pub enum CopyImplementationError<'tcx> { - InfrigingField(&'tcx ty::FieldDef), + InfrigingFields(Vec<&'tcx ty::FieldDef>), NotAnAdt, HasDestructor, } @@ -192,7 +186,7 @@ pub enum Representability { impl<'tcx> ty::ParamEnv<'tcx> { pub fn can_type_implement_copy<'a>(self, tcx: TyCtxt<'a, 'tcx, 'tcx>, - self_type: Ty<'tcx>, span: Span) + self_type: Ty<'tcx>) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { @@ -201,29 +195,36 @@ impl<'tcx> ty::ParamEnv<'tcx> { // Now libcore provides that impl. ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) | ty::TyChar | ty::TyRawPtr(..) | ty::TyNever | - ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => return Ok(()), + ty::TyRef(_, _, hir::MutImmutable) => return Ok(()), ty::TyAdt(adt, substs) => (adt, substs), _ => return Err(CopyImplementationError::NotAnAdt), }; - let field_implements_copy = |field: &ty::FieldDef| { - let cause = traits::ObligationCause::dummy(); - match traits::fully_normalize(&infcx, cause, self, &field.ty(tcx, substs)) { - Ok(ty) => !infcx.type_moves_by_default(self, ty, span), - Err(..) => false, - } - }; - + let mut infringing = Vec::new(); for variant in &adt.variants { for field in &variant.fields { - if !field_implements_copy(field) { - return Err(CopyImplementationError::InfrigingField(field)); + let span = tcx.def_span(field.did); + let ty = field.ty(tcx, substs); + if ty.references_error() { + continue; } + let cause = ObligationCause { span, ..ObligationCause::dummy() }; + let ctx = traits::FulfillmentContext::new(); + match traits::fully_normalize(&infcx, ctx, cause, self, &ty) { + Ok(ty) => if infcx.type_moves_by_default(self, ty, span) { + infringing.push(field); + } + Err(errors) => { + infcx.report_fulfillment_errors(&errors, None, false); + } + }; } } - + if !infringing.is_empty() { + return Err(CopyImplementationError::InfrigingFields(infringing)); + } if adt.has_dtor(tcx) { return Err(CopyImplementationError::HasDestructor); } @@ -414,7 +415,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { return None; }; - ty::maps::queries::coherent_trait::ensure(self, drop_trait); + ty::query::queries::coherent_trait::ensure(self, drop_trait); let mut dtor_did = None; let ty = self.type_of(adt_did); @@ -517,10 +518,31 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { result } + /// True if `def_id` refers to a closure (e.g., `|x| x * 2`). Note + /// that closures have a def-id, but the closure *expression* also + /// has a `HirId` that is located within the context where the + /// closure appears (and, sadly, a corresponding `NodeId`, since + /// those are not yet phased out). The parent of the closure's + /// def-id will also be the context where it appears. pub fn is_closure(self, def_id: DefId) -> bool { self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr } + /// True if `def_id` refers to a trait (e.g., `trait Foo { ... }`). + pub fn is_trait(self, def_id: DefId) -> bool { + if let DefPathData::Trait(_) = self.def_key(def_id).disambiguated_data.data { + true + } else { + false + } + } + + /// True if this def-id refers to the implicit constructor for + /// a tuple struct like `struct Foo(u32)`. + pub fn is_struct_constructor(self, def_id: DefId) -> bool { + self.def_key(def_id).disambiguated_data.data == DefPathData::StructCtor + } + /// Given the `DefId` of a fn or closure, returns the `DefId` of /// the innermost fn item that the closure is contained within. /// This is a significant def-id because, when we do @@ -554,7 +576,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { -> Option>> { let closure_ty = self.mk_closure(closure_def_id, closure_substs); - let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv); + let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self); let closure_kind = closure_kind_ty.to_opt_closure_kind()?; let env_ty = match closure_kind { @@ -567,11 +589,14 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { /// Given the def-id of some item that has no type parameters, make /// a suitable "empty substs" for it. - pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx ty::Substs<'tcx> { - ty::Substs::for_item(self, item_def_id, - |_, _| self.types.re_erased, - |_, _| { - bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) + pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx Substs<'tcx> { + Substs::for_item(self, item_def_id, |param, _| { + match param.kind { + GenericParamDefKind::Lifetime => self.types.re_erased.into(), + GenericParamDefKind::Type {..} => { + bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) + } + } }) } @@ -580,10 +605,10 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { if let Some(node) = self.hir.get_if_local(def_id) { match node { Node::NodeItem(&hir::Item { - node: hir::ItemStatic(_, mutbl, _), .. + node: hir::ItemKind::Static(_, mutbl, _), .. }) => Some(mutbl), Node::NodeForeignItem(&hir::ForeignItem { - node: hir::ForeignItemStatic(_, is_mutbl), .. + node: hir::ForeignItemKind::Static(_, is_mutbl), .. }) => Some(if is_mutbl { hir::Mutability::MutMutable @@ -606,151 +631,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } } -pub struct TypeIdHasher<'a, 'gcx: 'a+'tcx, 'tcx: 'a, W> { - tcx: TyCtxt<'a, 'gcx, 'tcx>, - state: StableHasher, -} - -impl<'a, 'gcx, 'tcx, W> TypeIdHasher<'a, 'gcx, 'tcx, W> - where W: StableHasherResult -{ - pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self { - TypeIdHasher { tcx: tcx, state: StableHasher::new() } - } - - pub fn finish(self) -> W { - self.state.finish() - } - - pub fn hash(&mut self, x: T) { - x.hash(&mut self.state); - } - - fn hash_discriminant_u8(&mut self, x: &T) { - let v = unsafe { - intrinsics::discriminant_value(x) - }; - let b = v as u8; - assert_eq!(v, b as u64); - self.hash(b) - } - - fn def_id(&mut self, did: DefId) { - // Hash the DefPath corresponding to the DefId, which is independent - // of compiler internal state. We already have a stable hash value of - // all DefPaths available via tcx.def_path_hash(), so we just feed that - // into the hasher. - let hash = self.tcx.def_path_hash(did); - self.hash(hash); - } -} - -impl<'a, 'gcx, 'tcx, W> TypeVisitor<'tcx> for TypeIdHasher<'a, 'gcx, 'tcx, W> - where W: StableHasherResult -{ - fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - // Distinguish between the Ty variants uniformly. - self.hash_discriminant_u8(&ty.sty); - - match ty.sty { - TyInt(i) => self.hash(i), - TyUint(u) => self.hash(u), - TyFloat(f) => self.hash(f), - TyArray(_, n) => { - self.hash_discriminant_u8(&n.val); - match n.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => self.hash(b), - ConstVal::Unevaluated(def_id, _) => self.def_id(def_id), - _ => bug!("arrays should not have {:?} as length", n) - } - } - TyRawPtr(m) | - TyRef(_, m) => self.hash(m.mutbl), - TyClosure(def_id, _) | - TyGenerator(def_id, _, _) | - TyAnon(def_id, _) | - TyFnDef(def_id, _) => self.def_id(def_id), - TyAdt(d, _) => self.def_id(d.did), - TyForeign(def_id) => self.def_id(def_id), - TyFnPtr(f) => { - self.hash(f.unsafety()); - self.hash(f.abi()); - self.hash(f.variadic()); - self.hash(f.inputs().skip_binder().len()); - } - TyDynamic(ref data, ..) => { - if let Some(p) = data.principal() { - self.def_id(p.def_id()); - } - for d in data.auto_traits() { - self.def_id(d); - } - } - TyGeneratorWitness(tys) => { - self.hash(tys.skip_binder().len()); - } - TyTuple(tys) => { - self.hash(tys.len()); - } - TyParam(p) => { - self.hash(p.idx); - self.hash(p.name); - } - TyProjection(ref data) => { - self.def_id(data.item_def_id); - } - TyNever | - TyBool | - TyChar | - TyStr | - TySlice(_) => {} - - TyError | - TyInfer(_) => bug!("TypeIdHasher: unexpected type {}", ty) - } - - ty.super_visit_with(self) - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - self.hash_discriminant_u8(r); - match *r { - ty::ReErased | - ty::ReStatic | - ty::ReEmpty => { - // No variant fields to hash for these ... - } - ty::ReCanonical(c) => { - self.hash(c); - } - ty::ReLateBound(db, ty::BrAnon(i)) => { - self.hash(db.depth); - self.hash(i); - } - ty::ReEarlyBound(ty::EarlyBoundRegion { def_id, .. }) => { - self.def_id(def_id); - } - - ty::ReClosureBound(..) | - ty::ReLateBound(..) | - ty::ReFree(..) | - ty::ReScope(..) | - ty::ReVar(..) | - ty::ReSkolemized(..) => { - bug!("TypeIdHasher: unexpected region {:?}", r) - } - } - false - } - - fn visit_binder>(&mut self, x: &ty::Binder) -> bool { - // Anonymize late-bound regions so that, for example: - // `for<'a, b> fn(&'a &'b T)` and `for<'a, b> fn(&'b &'a T)` - // result in the same TypeId (the two types are equivalent). - self.tcx.anonymize_late_bound_regions(x).super_visit_with(self) - } -} - impl<'a, 'tcx> ty::TyS<'tcx> { pub fn moves_by_default(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1024,7 +904,7 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let (param_env, ty) = query.into_parts(); let needs_drop = |ty: Ty<'tcx>| -> bool { - match tcx.try_get_query::(DUMMY_SP, param_env.and(ty)) { + match tcx.try_needs_drop_raw(DUMMY_SP, param_env.and(ty)) { Ok(v) => v, Err(mut bug) => { // Cycles should be reported as an error by `check_representable`. @@ -1052,6 +932,9 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Foreign types can never have destructors ty::TyForeign(..) => false, + // `ManuallyDrop` doesn't have a destructor regardless of field types. + ty::TyAdt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false, + // Issue #22536: We first query type_moves_by_default. It sees a // normalized version of the type, and therefore will definitely // know whether the type implements Copy (and thus needs no @@ -1087,7 +970,8 @@ fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty::TyTuple(ref tys) => tys.iter().cloned().any(needs_drop), - // unions don't have destructors regardless of the child types + // unions don't have destructors because of the child types, + // only if they manually implement `Drop` (handled above). ty::TyAdt(def, _) if def.is_union() => false, ty::TyAdt(def, substs) => @@ -1141,7 +1025,7 @@ impl<'tcx> ExplicitSelf<'tcx> { match self_arg_ty.sty { _ if is_self_ty(self_arg_ty) => ByValue, - ty::TyRef(region, ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => { + ty::TyRef(region, ty, mutbl) if is_self_ty(ty) => { ByReference(region, mutbl) } ty::TyRawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => { @@ -1155,8 +1039,8 @@ impl<'tcx> ExplicitSelf<'tcx> { } } -pub fn provide(providers: &mut ty::maps::Providers) { - *providers = ty::maps::Providers { +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { is_copy_raw, is_sized_raw, is_freeze_raw, diff --git a/src/librustc/ty/walk.rs b/src/librustc/ty/walk.rs index 46c048e839b4b..d12f73144269b 100644 --- a/src/librustc/ty/walk.rs +++ b/src/librustc/ty/walk.rs @@ -11,7 +11,7 @@ //! An iterator over the type substructure. //! WARNING: this does not keep track of the region depth. -use middle::const_val::ConstVal; +use mir::interpret::ConstValue; use ty::{self, Ty}; use rustc_data_structures::small_vec::SmallVec; use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter; @@ -92,9 +92,12 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::TySlice(ty) => { stack.push(ty); } - ty::TyRawPtr(ref mt) | ty::TyRef(_, ref mt) => { + ty::TyRawPtr(ref mt) => { stack.push(mt.ty); } + ty::TyRef(_, ty, _) => { + stack.push(ty); + } ty::TyProjection(ref data) => { stack.extend(data.substs.types().rev()); } @@ -118,8 +121,7 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { ty::TyClosure(_, ref substs) => { stack.extend(substs.substs.types().rev()); } - ty::TyGenerator(_, ref substs, ref interior) => { - stack.push(interior.witness); + ty::TyGenerator(_, ref substs, _) => { stack.extend(substs.substs.types().rev()); } ty::TyGeneratorWitness(ts) => { @@ -139,11 +141,8 @@ fn push_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent_ty: Ty<'tcx>) { } fn push_const<'tcx>(stack: &mut TypeWalkerStack<'tcx>, constant: &'tcx ty::Const<'tcx>) { - match constant.val { - ConstVal::Value(_) => {} - ConstVal::Unevaluated(_, substs) => { - stack.extend(substs.types().rev()); - } + if let ConstValue::Unevaluated(_, substs) = constant.val { + stack.extend(substs.types().rev()); } stack.push(constant.ty); } diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs index aea84791fe86b..b99cdd59773aa 100644 --- a/src/librustc/ty/wf.rs +++ b/src/librustc/ty/wf.rs @@ -9,7 +9,7 @@ // except according to those terms. use hir::def_id::DefId; -use middle::const_val::ConstVal; +use mir::interpret::ConstValue; use infer::InferCtxt; use ty::subst::Substs; use traits; @@ -216,18 +216,15 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { /// into `self.out`. fn compute_const(&mut self, constant: &'tcx ty::Const<'tcx>) { self.require_sized(constant.ty, traits::ConstSized); - match constant.val { - ConstVal::Value(_) => {} - ConstVal::Unevaluated(def_id, substs) => { - let obligations = self.nominal_obligations(def_id, substs); - self.out.extend(obligations); - - let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); - let cause = self.cause(traits::MiscObligation); - self.out.push(traits::Obligation::new(cause, - self.param_env, - predicate)); - } + if let ConstValue::Unevaluated(def_id, substs) = constant.val { + let obligations = self.nominal_obligations(def_id, substs); + self.out.extend(obligations); + + let predicate = ty::Predicate::ConstEvaluatable(def_id, substs); + let cause = self.cause(traits::MiscObligation); + self.out.push(traits::Obligation::new(cause, + self.param_env, + predicate)); } } @@ -298,9 +295,9 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { self.out.extend(obligations); } - ty::TyRef(r, mt) => { + ty::TyRef(r, rty, _) => { // WfReference - if !r.has_escaping_regions() && !mt.ty.has_escaping_regions() { + if !r.has_escaping_regions() && !rty.has_escaping_regions() { let cause = self.cause(traits::ReferenceOutlivesReferent(ty)); self.out.push( traits::Obligation::new( @@ -308,7 +305,7 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { param_env, ty::Predicate::TypeOutlives( ty::Binder::dummy( - ty::OutlivesPredicate(mt.ty, r))))); + ty::OutlivesPredicate(rty, r))))); } } @@ -363,10 +360,16 @@ impl<'a, 'gcx, 'tcx> WfPredicates<'a, 'gcx, 'tcx> { // types appearing in the fn signature } - ty::TyAnon(..) => { + ty::TyAnon(did, substs) => { // all of the requirements on type parameters // should've been checked by the instantiation // of whatever returned this exact `impl Trait`. + + // for named existential types we still need to check them + if super::is_impl_trait_defn(self.infcx.tcx, did).is_none() { + let obligations = self.nominal_obligations(did, substs); + self.out.extend(obligations); + } } ty::TyDynamic(data, r) => { diff --git a/src/librustc/util/common.rs b/src/librustc/util/common.rs index 85533caffce2e..990fbc4bc917e 100644 --- a/src/librustc/util/common.rs +++ b/src/librustc/util/common.rs @@ -17,7 +17,6 @@ use std::collections::HashMap; use std::ffi::CString; use std::fmt::Debug; use std::hash::{Hash, BuildHasher}; -use std::iter::repeat; use std::panic; use std::env; use std::path::Path; @@ -219,7 +218,7 @@ fn print_time_passes_entry_internal(what: &str, dur: Duration) { None => "".to_owned(), }; println!("{}time: {}{}\t{}", - repeat(" ").take(indentation).collect::(), + " ".repeat(indentation), duration_to_secs_str(dur), mem_string, what); @@ -243,7 +242,7 @@ pub fn to_readable_str(mut val: usize) -> String { val /= 1000; if val == 0 { - groups.push(format!("{}", group)); + groups.push(group.to_string()); break; } else { groups.push(format!("{:03}", group)); diff --git a/src/librustc/util/nodemap.rs b/src/librustc/util/nodemap.rs index f98a8f834df8a..0dc71af9db694 100644 --- a/src/librustc/util/nodemap.rs +++ b/src/librustc/util/nodemap.rs @@ -19,20 +19,16 @@ use syntax::ast; pub use rustc_data_structures::fx::FxHashMap; pub use rustc_data_structures::fx::FxHashSet; -pub type NodeMap = FxHashMap; -pub type DefIdMap = FxHashMap; -pub type HirIdMap = FxHashMap; -pub type ItemLocalMap = FxHashMap; - -pub type NodeSet = FxHashSet; -pub type DefIdSet = FxHashSet; -pub type HirIdSet = FxHashSet; -pub type ItemLocalSet = FxHashSet; - -pub fn NodeMap() -> NodeMap { FxHashMap() } -pub fn DefIdMap() -> DefIdMap { FxHashMap() } -pub fn ItemLocalMap() -> ItemLocalMap { FxHashMap() } -pub fn NodeSet() -> NodeSet { FxHashSet() } -pub fn DefIdSet() -> DefIdSet { FxHashSet() } -pub fn ItemLocalSet() -> ItemLocalSet { FxHashSet() } - +macro_rules! define_id_collections { + ($map_name:ident, $set_name:ident, $key:ty) => { + pub type $map_name = FxHashMap<$key, T>; + pub fn $map_name() -> $map_name { FxHashMap() } + pub type $set_name = FxHashSet<$key>; + pub fn $set_name() -> $set_name { FxHashSet() } + } +} + +define_id_collections!(NodeMap, NodeSet, ast::NodeId); +define_id_collections!(DefIdMap, DefIdSet, DefId); +define_id_collections!(HirIdMap, HirIdSet, HirId); +define_id_collections!(ItemLocalMap, ItemLocalSet, ItemLocalId); diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 894a18b79ccb2..15b5edaa3d5d7 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -10,7 +10,7 @@ use hir::def_id::DefId; use hir::map::definitions::DefPathData; -use middle::const_val::ConstVal; +use mir::interpret::ConstValue; use middle::region::{self, BlockRemainder}; use ty::subst::{self, Subst}; use ty::{BrAnon, BrEnv, BrFresh, BrNamed}; @@ -19,9 +19,8 @@ use ty::{TyError, TyStr, TyArray, TySlice, TyFloat, TyFnDef, TyFnPtr}; use ty::{TyParam, TyRawPtr, TyRef, TyNever, TyTuple}; use ty::{TyClosure, TyGenerator, TyGeneratorWitness, TyForeign, TyProjection, TyAnon}; use ty::{TyDynamic, TyInt, TyUint, TyInfer}; -use ty::{self, Ty, TyCtxt, TypeFoldable}; +use ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, GenericParamCount, GenericParamDefKind}; use util::nodemap::FxHashSet; -use mir::interpret::{Value, PrimVal}; use std::cell::Cell; use std::fmt; @@ -33,6 +32,12 @@ use syntax::ast::CRATE_NODE_ID; use syntax::symbol::{Symbol, InternedString}; use hir; +thread_local! { + /// Mechanism for highlighting of specific regions for display in NLL region inference errors. + /// Contains region to highlight and counter for number to use when highlighting. + static HIGHLIGHT_REGION: Cell> = Cell::new(None) +} + macro_rules! gen_display_debug_body { ( $with:path ) => { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -257,8 +262,10 @@ impl PrintContext { let verbose = self.is_verbose; let mut num_supplied_defaults = 0; let mut has_self = false; - let mut num_regions = 0; - let mut num_types = 0; + let mut own_counts = GenericParamCount { + lifetimes: 0, + types: 0, + }; let mut is_value_path = false; let fn_trait_kind = ty::tls::with(|tcx| { // Unfortunately, some kinds of items (e.g., closures) don't have @@ -270,6 +277,7 @@ impl PrintContext { match key.disambiguated_data.data { DefPathData::AssocTypeInTrait(_) | DefPathData::AssocTypeInImpl(_) | + DefPathData::AssocExistentialInImpl(_) | DefPathData::Trait(_) | DefPathData::TypeNs(_) => { break; @@ -286,12 +294,11 @@ impl PrintContext { DefPathData::MacroDef(_) | DefPathData::ClosureExpr | DefPathData::TypeParam(_) | - DefPathData::LifetimeDef(_) | + DefPathData::LifetimeParam(_) | DefPathData::Field(_) | DefPathData::StructCtor | - DefPathData::Initializer | + DefPathData::AnonConst | DefPathData::ImplTrait | - DefPathData::Typeof | DefPathData::GlobalMetaData(_) => { // if we're making a symbol for something, there ought // to be a value or type-def or something in there @@ -304,6 +311,7 @@ impl PrintContext { } } let mut generics = tcx.generics_of(item_def_id); + let child_own_counts = generics.own_counts(); let mut path_def_id = did; has_self = generics.has_self; @@ -311,10 +319,9 @@ impl PrintContext { if let Some(def_id) = generics.parent { // Methods. assert!(is_value_path); - child_types = generics.types.len(); + child_types = child_own_counts.types; generics = tcx.generics_of(def_id); - num_regions = generics.regions.len(); - num_types = generics.types.len(); + own_counts = generics.own_counts(); if has_self { print!(f, self, write("<"), print_display(substs.type_at(0)), write(" as "))?; @@ -329,20 +336,30 @@ impl PrintContext { assert_eq!(has_self, false); } else { // Types and traits. - num_regions = generics.regions.len(); - num_types = generics.types.len(); + own_counts = child_own_counts; } } if !verbose { - if generics.types.last().map_or(false, |def| def.has_default) { + let mut type_params = + generics.params.iter().rev().filter_map(|param| match param.kind { + GenericParamDefKind::Lifetime => None, + GenericParamDefKind::Type { has_default, .. } => { + Some((param.def_id, has_default)) + } + }).peekable(); + let has_default = { + let has_default = type_params.peek().map(|(_, has_default)| has_default); + *has_default.unwrap_or(&false) + }; + if has_default { if let Some(substs) = tcx.lift(&substs) { - let tps = substs.types().rev().skip(child_types); - for (def, actual) in generics.types.iter().rev().zip(tps) { - if !def.has_default { + let mut types = substs.types().rev().skip(child_types); + for ((def_id, has_default), actual) in type_params.zip(types) { + if !has_default { break; } - if tcx.type_of(def.def_id).subst(tcx, substs) != actual { + if tcx.type_of(def_id).subst(tcx, substs) != actual { break; } num_supplied_defaults += 1; @@ -402,10 +419,11 @@ impl PrintContext { Ok(()) }; - print_regions(f, "<", 0, num_regions)?; + print_regions(f, "<", 0, own_counts.lifetimes)?; - let tps = substs.types().take(num_types - num_supplied_defaults) - .skip(has_self as usize); + let tps = substs.types() + .take(own_counts.types - num_supplied_defaults) + .skip(has_self as usize); for ty in tps { start_or_continue(f, "<", ", ")?; @@ -417,7 +435,7 @@ impl PrintContext { ty::tls::with(|tcx| print!(f, self, write("{}=", - tcx.associated_item(projection.projection_ty.item_def_id).name), + tcx.associated_item(projection.projection_ty.item_def_id).ident), print_display(projection.ty)) )?; } @@ -436,10 +454,10 @@ impl PrintContext { write!(f, "::{}", item_name)?; } - print_regions(f, "::<", num_regions, usize::MAX)?; + print_regions(f, "::<", own_counts.lifetimes, usize::MAX)?; // FIXME: consider being smart with defaults here too - for ty in substs.types().skip(num_types) { + for ty in substs.types().skip(own_counts.types) { start_or_continue(f, "::<", ", ")?; ty.print_display(f, self)?; } @@ -513,7 +531,7 @@ impl PrintContext { ty::BrNamed(tcx.hir.local_def_id(CRATE_NODE_ID), name) } }; - tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1), br)) + tcx.mk_region(ty::ReLateBound(ty::INNERMOST, br)) }).0; start_or_continue(f, "", "> ")?; @@ -550,6 +568,19 @@ pub fn parameterized(f: &mut F, PrintContext::new().parameterized(f, substs, did, projections) } +fn get_highlight_region() -> Option<(RegionVid, usize)> { + HIGHLIGHT_REGION.with(|hr| hr.get()) +} + +pub fn with_highlight_region(r: RegionVid, counter: usize, op: impl FnOnce() -> R) -> R { + HIGHLIGHT_REGION.with(|hr| { + assert_eq!(hr.get(), None); + hr.set(Some((r, counter))); + let r = op(); + hr.set(None); + r + }) +} impl<'a, T: Print> Print for &'a T { fn print(&self, f: &mut F, cx: &mut PrintContext) -> fmt::Result { @@ -589,18 +620,14 @@ define_print! { } } -impl fmt::Debug for ty::TypeParameterDef { +impl fmt::Debug for ty::GenericParamDef { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "TypeParameterDef({}, {:?}, {})", - self.name, - self.def_id, - self.index) - } -} - -impl fmt::Debug for ty::RegionParameterDef { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "RegionParameterDef({}, {:?}, {})", + let type_name = match self.kind { + ty::GenericParamDefKind::Lifetime => "Lifetime", + ty::GenericParamDefKind::Type {..} => "Type", + }; + write!(f, "{}({}, {:?}, {})", + type_name, self.name, self.def_id, self.index) @@ -725,7 +752,7 @@ define_print! { define_print! { () ty::RegionKind, (self, f, cx) { display { - if cx.is_verbose { + if cx.is_verbose || get_highlight_region().is_some() { return self.print_debug(f, cx); } @@ -897,6 +924,15 @@ impl fmt::Debug for ty::FloatVid { impl fmt::Debug for ty::RegionVid { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if let Some((region, counter)) = get_highlight_region() { + debug!("RegionVid.fmt: region={:?} self={:?} counter={:?}", region, self, counter); + return if *self == region { + write!(f, "'{:?}", counter) + } else { + write!(f, "'_") + } + } + write!(f, "'_#{}r", self.index()) } } @@ -995,14 +1031,6 @@ define_print! { } } -define_print! { - ('tcx) ty::GeneratorInterior<'tcx>, (self, f, cx) { - display { - self.witness.print(f, cx) - } - } -} - define_print! { ('tcx) ty::TypeVariants<'tcx>, (self, f, cx) { display { @@ -1019,14 +1047,16 @@ define_print! { })?; tm.ty.print(f, cx) } - TyRef(r, ref tm) => { + TyRef(r, ty, mutbl) => { write!(f, "&")?; let s = r.print_to_string(cx); - write!(f, "{}", s)?; - if !s.is_empty() { - write!(f, " ")?; + if s != "'_" { + write!(f, "{}", s)?; + if !s.is_empty() { + write!(f, " ")?; + } } - tm.print(f, cx) + ty::TypeAndMut { ty, mutbl }.print(f, cx) } TyNever => write!(f, "!"), TyTuple(ref tys) => { @@ -1062,10 +1092,14 @@ define_print! { TyParam(ref param_ty) => write!(f, "{}", param_ty), TyAdt(def, substs) => cx.parameterized(f, substs, def.did, &[]), TyDynamic(data, r) => { - data.print(f, cx)?; let r = r.print_to_string(cx); if !r.is_empty() { - write!(f, " + {}", r) + write!(f, "(")?; + } + write!(f, "dyn ")?; + data.print(f, cx)?; + if !r.is_empty() { + write!(f, " + {})", r) } else { Ok(()) } @@ -1078,6 +1112,20 @@ define_print! { } ty::tls::with(|tcx| { + let def_key = tcx.def_key(def_id); + if let Some(name) = def_key.disambiguated_data.data.get_opt_name() { + write!(f, "{}", name)?; + let mut substs = substs.iter(); + if let Some(first) = substs.next() { + write!(f, "::<")?; + write!(f, "{}", first)?; + for subst in substs { + write!(f, ", {}", subst)?; + } + write!(f, ">")?; + } + return Ok(()); + } // Grab the "TraitA + TraitB" from `impl TraitA + TraitB`, // by looking up the projections associated with the def_id. let predicates_of = tcx.predicates_of(def_id); @@ -1110,9 +1158,10 @@ define_print! { }) } TyStr => write!(f, "str"), - TyGenerator(did, substs, interior) => ty::tls::with(|tcx| { + TyGenerator(did, substs, movability) => ty::tls::with(|tcx| { let upvar_tys = substs.upvar_tys(did, tcx); - if interior.movable { + let witness = substs.witness(did, tcx); + if movability == hir::GeneratorMovability::Movable { write!(f, "[generator")?; } else { write!(f, "[static generator")?; @@ -1134,7 +1183,7 @@ define_print! { })? } else { // cross-crate closure types should only be - // visible in trans bug reports, I imagine. + // visible in codegen bug reports, I imagine. write!(f, "@{:?}", did)?; let mut sep = " "; for (index, upvar_ty) in upvar_tys.enumerate() { @@ -1145,7 +1194,7 @@ define_print! { } } - print!(f, cx, write(" "), print(interior), write("]")) + print!(f, cx, write(" "), print(witness), write("]")) }), TyGeneratorWitness(types) => { ty::tls::with(|tcx| cx.in_binder(f, tcx, &types, tcx.lift(&types))) @@ -1174,7 +1223,7 @@ define_print! { })? } else { // cross-crate closure types should only be - // visible in trans bug reports, I imagine. + // visible in codegen bug reports, I imagine. write!(f, "@{:?}", did)?; let mut sep = " "; for (index, upvar_ty) in upvar_tys.enumerate() { @@ -1190,15 +1239,12 @@ define_print! { TyArray(ty, sz) => { print!(f, cx, write("["), print(ty), write("; "))?; match sz.val { - ConstVal::Value(Value::ByVal(PrimVal::Bytes(sz))) => { - write!(f, "{}", sz)?; - } - ConstVal::Unevaluated(_def_id, _substs) => { + ConstValue::Unevaluated(_def_id, _substs) => { write!(f, "_")?; } - _ => { - write!(f, "{:?}", sz)?; - } + _ => ty::tls::with(|tcx| { + write!(f, "{}", sz.unwrap_usize(tcx)) + })?, } write!(f, "]") } @@ -1284,7 +1330,7 @@ define_print! { // parameterized(f, self.substs, self.item_def_id, &[]) // (which currently ICEs). let (trait_ref, item_name) = ty::tls::with(|tcx| - (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).name) + (self.trait_ref(tcx), tcx.associated_item(self.item_def_id).ident) ); print!(f, cx, print_debug(trait_ref), write("::{}", item_name)) } diff --git a/src/librustc_trans/time_graph.rs b/src/librustc/util/time_graph.rs similarity index 100% rename from src/librustc_trans/time_graph.rs rename to src/librustc/util/time_graph.rs diff --git a/src/librustc_allocator/Cargo.toml b/src/librustc_allocator/Cargo.toml index 765cb80f35710..1cbde181cafae 100644 --- a/src/librustc_allocator/Cargo.toml +++ b/src/librustc_allocator/Cargo.toml @@ -14,3 +14,4 @@ rustc_errors = { path = "../librustc_errors" } rustc_target = { path = "../librustc_target" } syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } +log = "0.4" diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index de8814d3d6a73..ffbbd8a33a1d0 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -10,31 +10,36 @@ use rustc::middle::allocator::AllocatorKind; use rustc_errors; -use rustc_target::spec::abi::Abi; -use syntax::ast::{Attribute, Crate, LitKind, StrStyle}; -use syntax::ast::{Arg, Constness, Generics, Mac, Mutability, Ty, Unsafety}; -use syntax::ast::{self, Expr, Ident, Item, ItemKind, TyKind, VisibilityKind}; -use syntax::attr; -use syntax::codemap::{dummy_spanned, respan}; -use syntax::codemap::{ExpnInfo, MacroAttribute, NameAndSpan}; -use syntax::ext::base::ExtCtxt; -use syntax::ext::base::Resolver; -use syntax::ext::build::AstBuilder; -use syntax::ext::expand::ExpansionConfig; -use syntax::ext::hygiene::{Mark, SyntaxContext}; -use syntax::fold::{self, Folder}; -use syntax::parse::ParseSess; -use syntax::ptr::P; -use syntax::symbol::Symbol; -use syntax::util::small_vector::SmallVector; -use syntax_pos::{Span, DUMMY_SP}; +use syntax::{ + ast::{ + self, Arg, Attribute, Crate, Expr, FnHeader, Generics, Ident, Item, ItemKind, + LitKind, Mac, Mod, Mutability, StrStyle, Ty, TyKind, Unsafety, VisibilityKind, + }, + attr, + codemap::{ + respan, ExpnInfo, MacroAttribute, + }, + ext::{ + base::{ExtCtxt, Resolver}, + build::AstBuilder, + expand::ExpansionConfig, + hygiene::{self, Mark, SyntaxContext}, + }, + fold::{self, Folder}, + parse::ParseSess, + ptr::P, + symbol::Symbol, + util::small_vector::SmallVector, +}; +use syntax_pos::Span; use {AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS}; pub fn modify( sess: &ParseSess, - resolver: &mut Resolver, + resolver: &mut dyn Resolver, krate: Crate, + crate_name: String, handler: &rustc_errors::Handler, ) -> ast::Crate { ExpandAllocatorDirectives { @@ -42,6 +47,8 @@ pub fn modify( sess, resolver, found: false, + crate_name: Some(crate_name), + in_submod: -1, // -1 to account for the "root" module }.fold_crate(krate) } @@ -49,11 +56,18 @@ struct ExpandAllocatorDirectives<'a> { found: bool, handler: &'a rustc_errors::Handler, sess: &'a ParseSess, - resolver: &'a mut Resolver, + resolver: &'a mut dyn Resolver, + crate_name: Option, + + // For now, we disallow `global_allocator` in submodules because hygiene is hard. Keep track of + // whether we are in a submodule or not. If `in_submod > 0` we are in a submodule. + in_submod: isize, } impl<'a> Folder for ExpandAllocatorDirectives<'a> { fn fold_item(&mut self, item: P) -> SmallVector> { + debug!("in submodule {}", self.in_submod); + let name = if attr::contains_name(&item.attrs, "global_allocator") { "global_allocator" } else { @@ -68,28 +82,38 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { } } + if self.in_submod > 0 { + self.handler + .span_err(item.span, "`global_allocator` cannot be used in submodules"); + return SmallVector::one(item); + } + if self.found { - self.handler.span_err( - item.span, - "cannot define more than one \ - #[global_allocator]", - ); + self.handler + .span_err(item.span, "cannot define more than one #[global_allocator]"); return SmallVector::one(item); } self.found = true; + // Create a fresh Mark for the new macro expansion we are about to do let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo { - call_site: DUMMY_SP, - callee: NameAndSpan { - format: MacroAttribute(Symbol::intern(name)), - span: None, - allow_internal_unstable: true, - allow_internal_unsafe: false, - }, + call_site: item.span, // use the call site of the static + def_site: None, + format: MacroAttribute(Symbol::intern(name)), + allow_internal_unstable: true, + allow_internal_unsafe: false, + local_inner_macros: false, + edition: hygiene::default_edition(), }); + + // Tie the span to the macro expansion info we just created let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); - let ecfg = ExpansionConfig::default(name.to_string()); + + // Create an expansion config + let ecfg = ExpansionConfig::default(self.crate_name.take().unwrap()); + + // Generate a bunch of new items using the AllocFnFactory let mut f = AllocFnFactory { span, kind: AllocatorKind::Global, @@ -97,29 +121,55 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> { core: Ident::from_str("core"), cx: ExtCtxt::new(self.sess, ecfg, self.resolver), }; + + // We will generate a new submodule. To `use` the static from that module, we need to get + // the `super::...` path. let super_path = f.cx.path(f.span, vec![Ident::from_str("super"), f.global]); + + // Generate the items in the submodule let mut items = vec![ + // import `core` to use allocators f.cx.item_extern_crate(f.span, f.core), + // `use` the `global_allocator` in `super` f.cx.item_use_simple( f.span, respan(f.span.shrink_to_lo(), VisibilityKind::Inherited), super_path, ), ]; - for method in ALLOCATOR_METHODS { - items.push(f.allocator_fn(method)); - } + + // Add the allocator methods to the submodule + items.extend( + ALLOCATOR_METHODS + .iter() + .map(|method| f.allocator_fn(method)), + ); + + // Generate the submodule itself let name = f.kind.fn_name("allocator_abi"); let allocator_abi = Ident::with_empty_ctxt(Symbol::gensym(&name)); let module = f.cx.item_mod(span, span, allocator_abi, Vec::new(), items); let module = f.cx.monotonic_expander().fold_item(module).pop().unwrap(); - let mut ret = SmallVector::new(); + // Return the item and new submodule + let mut ret = SmallVector::with_capacity(2); ret.push(item); ret.push(module); + return ret; } + // If we enter a submodule, take note. + fn fold_mod(&mut self, m: Mod) -> Mod { + debug!("enter submodule"); + self.in_submod += 1; + let ret = fold::noop_fold_mod(m, self); + self.in_submod -= 1; + debug!("exit submodule"); + ret + } + + // `fold_mac` is disabled by default. Enable it here. fn fold_mac(&mut self, mac: Mac) -> Mac { fold::noop_fold_mac(mac, self) } @@ -151,9 +201,10 @@ impl<'a> AllocFnFactory<'a> { let (output_ty, output_expr) = self.ret_ty(&method.output, result); let kind = ItemKind::Fn( self.cx.fn_decl(abi_args, ast::FunctionRetTy::Ty(output_ty)), - Unsafety::Unsafe, - dummy_spanned(Constness::NotConst), - Abi::Rust, + FnHeader { + unsafety: Unsafety::Unsafe, + ..FnHeader::default() + }, Generics::default(), self.cx.block_expr(output_expr), ); @@ -205,7 +256,7 @@ impl<'a> AllocFnFactory<'a> { &self, ty: &AllocatorTy, args: &mut Vec, - ident: &mut FnMut() -> Ident, + ident: &mut dyn FnMut() -> Ident, ) -> P { match *ty { AllocatorTy::Layout => { @@ -236,7 +287,7 @@ impl<'a> AllocFnFactory<'a> { let ident = ident(); args.push(self.cx.arg(self.span, ident, self.ptr_u8())); let arg = self.cx.expr_ident(self.span, ident); - self.cx.expr_cast(self.span, arg, self.ptr_opaque()) + self.cx.expr_cast(self.span, arg, self.ptr_u8()) } AllocatorTy::Usize => { @@ -280,17 +331,4 @@ impl<'a> AllocFnFactory<'a> { let ty_u8 = self.cx.ty_path(u8); self.cx.ty_ptr(self.span, ty_u8, Mutability::Mutable) } - - fn ptr_opaque(&self) -> P { - let opaque = self.cx.path( - self.span, - vec![ - self.core, - Ident::from_str("alloc"), - Ident::from_str("Opaque"), - ], - ); - let ty_opaque = self.cx.ty_path(opaque); - self.cx.ty_ptr(self.span, ty_opaque, Mutability::Mutable) - } } diff --git a/src/librustc_allocator/lib.rs b/src/librustc_allocator/lib.rs index 6595564fb30b5..b217d3665a245 100644 --- a/src/librustc_allocator/lib.rs +++ b/src/librustc_allocator/lib.rs @@ -10,6 +10,7 @@ #![feature(rustc_private)] +#[macro_use] extern crate log; extern crate rustc; extern crate rustc_errors; extern crate rustc_target; diff --git a/src/librustc_apfloat/ieee.rs b/src/librustc_apfloat/ieee.rs index 7abd02b6656f3..b21448df582a9 100644 --- a/src/librustc_apfloat/ieee.rs +++ b/src/librustc_apfloat/ieee.rs @@ -1753,9 +1753,9 @@ impl IeeeFloat { } else { loss = Some(match hex_value { 0 => Loss::ExactlyZero, - 1...7 => Loss::LessThanHalf, + 1..=7 => Loss::LessThanHalf, 8 => Loss::ExactlyHalf, - 9...15 => Loss::MoreThanHalf, + 9..=15 => Loss::MoreThanHalf, _ => unreachable!(), }); } diff --git a/src/librustc_asan/build.rs b/src/librustc_asan/build.rs index cb7721affe761..b8614c520e7cf 100644 --- a/src/librustc_asan/build.rs +++ b/src/librustc_asan/build.rs @@ -18,7 +18,7 @@ use cmake::Config; fn main() { if let Some(llvm_config) = env::var_os("LLVM_CONFIG") { - let native = match sanitizer_lib_boilerplate("asan") { + let (native, target) = match sanitizer_lib_boilerplate("asan") { Ok(native) => native, _ => return, }; @@ -29,7 +29,7 @@ fn main() { .define("COMPILER_RT_BUILD_XRAY", "OFF") .define("LLVM_CONFIG_PATH", llvm_config) .out_dir(&native.out_dir) - .build_target("asan") + .build_target(&target) .build(); } println!("cargo:rerun-if-env-changed=LLVM_CONFIG"); diff --git a/src/librustc_asan/lib.rs b/src/librustc_asan/lib.rs index 3429e3bda0f67..0c78fd74a234e 100644 --- a/src/librustc_asan/lib.rs +++ b/src/librustc_asan/lib.rs @@ -10,8 +10,6 @@ #![sanitizer_runtime] #![feature(alloc_system)] -#![feature(allocator_api)] -#![feature(global_allocator)] #![feature(sanitizer_runtime)] #![feature(staged_api)] #![no_std] diff --git a/src/librustc_borrowck/borrowck/README.md b/src/librustc_borrowck/borrowck/README.md index 29f03c06ab759..8bc0b4969b8f9 100644 --- a/src/librustc_borrowck/borrowck/README.md +++ b/src/librustc_borrowck/borrowck/README.md @@ -3,7 +3,7 @@ > WARNING: This README is more or less obsolete, and will be removed > soon! The new system is described in the [rustc guide]. -[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir-borrowck.html +[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir/borrowck.html This pass has the job of enforcing memory safety. This is a subtle topic. This docs aim to explain both the practice and the theory @@ -1126,7 +1126,7 @@ fn foo(a: [D; 10], b: [D; 10], i: i32, t: bool) -> D { } ``` -There are a number of ways that the trans backend could choose to +There are a number of ways that the codegen backend could choose to compile this (e.g. a `[bool; 10]` array for each such moved array; or an `Option` for each moved array). From the viewpoint of the borrow-checker, the important thing is to record what kind of fragment diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs index 79baf0ec15178..49bd69f826216 100644 --- a/src/librustc_borrowck/borrowck/check_loans.rs +++ b/src/librustc_borrowck/borrowck/check_loans.rs @@ -168,8 +168,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { // have to be *FULLY* initialized, but we still // must be careful lest it contains derefs of // pointers. - let hir_id = self.tcx().hir.node_to_hir_id(assignee_cmt.id); - self.check_if_assigned_path_is_moved(hir_id.local_id, + self.check_if_assigned_path_is_moved(assignee_cmt.hir_id.local_id, assignment_span, MovedInUse, &lp); @@ -178,8 +177,7 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for CheckLoanCtxt<'a, 'tcx> { // In a case like `path += 1`, then path must be // fully initialized, since we will read it before // we write it. - let hir_id = self.tcx().hir.node_to_hir_id(assignee_cmt.id); - self.check_if_path_is_moved(hir_id.local_id, + self.check_if_path_is_moved(assignee_cmt.hir_id.local_id, assignment_span, MovedInUse, &lp); @@ -205,7 +203,7 @@ pub fn check_loans<'a, 'b, 'c, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, let node_id = bccx.tcx.hir.as_local_node_id(def_id).unwrap(); let movable_generator = !match bccx.tcx.hir.get(node_id) { hir::map::Node::NodeExpr(&hir::Expr { - node: hir::ExprClosure(.., Some(hir::GeneratorMovability::Static)), + node: hir::ExprKind::Closure(.., Some(hir::GeneratorMovability::Static)), .. }) => true, _ => false, @@ -448,11 +446,13 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { if let Some(yield_span) = self.bccx .region_scope_tree .yield_in_scope_for_expr(scope, - cmt.id, - self.bccx.body) { + cmt.hir_id, + self.bccx.body) + { self.bccx.cannot_borrow_across_generator_yield(borrow_span, yield_span, Origin::Ast).emit(); + self.bccx.signal_error(); } } @@ -509,9 +509,13 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { new_loan, old_loan, old_loan, new_loan).err(); match (err_old_new, err_new_old) { - (Some(mut err), None) | (None, Some(mut err)) => err.emit(), + (Some(mut err), None) | (None, Some(mut err)) => { + err.emit(); + self.bccx.signal_error(); + } (Some(mut err_old), Some(mut err_new)) => { err_old.emit(); + self.bccx.signal_error(); err_new.cancel(); } (None, None) => return true, @@ -697,6 +701,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { loan_span, &self.bccx.loan_path_to_string(&loan_path), Origin::Ast) .emit(); + self.bccx.signal_error(); } } } @@ -747,6 +752,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { }; err.emit(); + self.bccx.signal_error(); } } } @@ -916,5 +922,6 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { self.bccx.cannot_assign_to_borrowed( span, loan.span, &self.bccx.loan_path_to_string(loan_path), Origin::Ast) .emit(); + self.bccx.signal_error(); } } diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs index ac905d6de5d3c..7ce6863a7c986 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs @@ -63,7 +63,7 @@ fn get_pattern_source<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pat: &Pat) -> Patte NodeExpr(ref e) => { // the enclosing expression must be a `match` or something else assert!(match e.node { - ExprMatch(..) => true, + ExprKind::Match(..) => true, _ => return PatternSource::Other, }); PatternSource::MatchExpr(e) @@ -109,10 +109,10 @@ pub fn gather_move_from_pat<'a, 'c, 'tcx: 'c>(bccx: &BorrowckCtxt<'a, 'tcx>, cmt: &'c mc::cmt_<'tcx>) { let source = get_pattern_source(bccx.tcx,move_pat); let pat_span_path_opt = match move_pat.node { - PatKind::Binding(_, _, ref path1, _) => { + PatKind::Binding(_, _, ident, _) => { Some(MovePlace { span: move_pat.span, - name: path1.node, + name: ident.name, pat_source: source, }) } @@ -180,7 +180,6 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, -> Option> { match cmt.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { Some(cmt.clone()) diff --git a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs index 6d73500d31802..323e0997e3e47 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/lifetime.rs @@ -74,7 +74,6 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { Categorization::Local(..) | // L-Local Categorization::Upvar(..) | Categorization::Deref(_, mc::BorrowedPtr(..)) | // L-Deref-Borrowed - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) => { self.check_scope(self.scope(cmt)) } @@ -122,8 +121,7 @@ impl<'a, 'tcx> GuaranteeLifetimeContext<'a, 'tcx> { Categorization::Deref(_, mc::UnsafePtr(..)) => { self.bccx.tcx.types.re_static } - Categorization::Deref(_, mc::BorrowedPtr(_, r)) | - Categorization::Deref(_, mc::Implicit(_, r)) => { + Categorization::Deref(_, mc::BorrowedPtr(_, r)) => { r } Categorization::Downcast(ref cmt, _) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/mod.rs b/src/librustc_borrowck/borrowck/gather_loans/mod.rs index a74eba3995518..d08814138719a 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/mod.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/mod.rs @@ -283,7 +283,7 @@ impl<'a, 'tcx> GatherLoanCtxt<'a, 'tcx> { .local_id, assignment_span, lp, - self.bccx.tcx.hir.node_to_hir_id(cmt.id).local_id, + cmt.hir_id.local_id, mode); } None => { diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs index 1f2b917bdb994..b217e6a856471 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs @@ -68,7 +68,7 @@ pub struct GroupedMoveErrors<'tcx> { move_to_places: Vec> } -fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec>) { +fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &[MoveError<'tcx>]) { let grouped_errors = group_errors_with_same_origin(errors); for error in &grouped_errors { let mut err = report_cannot_move_out_of(bccx, error.move_from.clone()); @@ -99,10 +99,11 @@ fn report_move_errors<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>, errors: &Vec(errors: &Vec>) +fn group_errors_with_same_origin<'tcx>(errors: &[MoveError<'tcx>]) -> Vec> { let mut grouped_errors = Vec::new(); for error in errors { @@ -112,15 +113,15 @@ fn group_errors_with_same_origin<'tcx>(errors: &Vec>) fn append_to_grouped_errors<'tcx>(grouped_errors: &mut Vec>, error: &MoveError<'tcx>) { - let move_from_id = error.move_from.id; - debug!("append_to_grouped_errors(move_from_id={})", move_from_id); + let move_from_id = error.move_from.hir_id; + debug!("append_to_grouped_errors(move_from_id={:?})", move_from_id); let move_to = if error.move_to.is_some() { vec![error.move_to.clone().unwrap()] } else { Vec::new() }; for ge in &mut *grouped_errors { - if move_from_id == ge.move_from.id && error.move_to.is_some() { + if move_from_id == ge.move_from.hir_id && error.move_to.is_some() { debug!("appending move_to to list"); ge.move_to_places.extend(move_to); return @@ -140,7 +141,6 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, -> DiagnosticBuilder<'a> { match move_from.cat { Categorization::Deref(_, mc::BorrowedPtr(..)) | - Categorization::Deref(_, mc::Implicit(..)) | Categorization::Deref(_, mc::UnsafePtr(..)) | Categorization::StaticItem => { bccx.cannot_move_out_of( @@ -148,7 +148,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &'a BorrowckCtxt<'a, 'tcx>, } Categorization::Interior(ref b, mc::InteriorElement(ik)) => { bccx.cannot_move_out_of_interior_noncopy( - move_from.span, b.ty, ik == Kind::Index, Origin::Ast) + move_from.span, b.ty, Some(ik == Kind::Index), Origin::Ast) } Categorization::Downcast(ref b, _) | diff --git a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs index 0b90127cc7e1e..e332f68327546 100644 --- a/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs +++ b/src/librustc_borrowck/borrowck/gather_loans/restrictions.rs @@ -108,8 +108,9 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { RestrictionResult::Safe => RestrictionResult::Safe, RestrictionResult::SafeIf(base_lp, mut base_vec) => { for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { - let field = - InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); + let field = InteriorKind::InteriorField( + mc::FieldIndex(i, field.ident.name) + ); let field_ty = if field == interior { cmt.ty } else { @@ -148,7 +149,7 @@ impl<'a, 'tcx> RestrictionsContext<'a, 'tcx> { let result = self.restrict(&cmt_base); self.extend(result, &cmt, LpDeref(pk)) } - mc::Implicit(bk, lt) | mc::BorrowedPtr(bk, lt) => { + mc::BorrowedPtr(bk, lt) => { // R-Deref-[Mut-]Borrowed if !self.bccx.is_subregion_of(self.loan_region, lt) { self.bccx.report( diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 9d0d8c2f909af..ddd0b691aec21 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -28,7 +28,7 @@ use rustc::middle::dataflow::DataFlowContext; use rustc::middle::dataflow::BitwiseOperator; use rustc::middle::dataflow::DataFlowOperator; use rustc::middle::dataflow::KillFrom; -use rustc::middle::borrowck::BorrowCheckResult; +use rustc::middle::borrowck::{BorrowCheckResult, SignalledError}; use rustc::hir::def_id::{DefId, LocalDefId}; use rustc::middle::expr_use_visitor as euv; use rustc::middle::mem_categorization as mc; @@ -37,11 +37,12 @@ use rustc::middle::mem_categorization::ImmutabilityBlame; use rustc::middle::region; use rustc::middle::free_region::RegionRelations; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc_mir::util::borrowck_errors::{BorrowckErrors, Origin}; +use rustc_mir::util::suggest_ref_mut; use rustc::util::nodemap::FxHashSet; -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::fmt; use std::rc::Rc; use rustc_data_structures::sync::Lrc; @@ -67,9 +68,9 @@ pub struct LoanDataFlowOperator; pub type LoanDataFlow<'a, 'tcx> = DataFlowContext<'a, 'tcx, LoanDataFlowOperator>; pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { - for body_owner_def_id in tcx.body_owners() { + tcx.par_body_owners(|body_owner_def_id| { tcx.borrowck(body_owner_def_id); - } + }); } pub fn provide(providers: &mut Providers) { @@ -89,6 +90,8 @@ pub struct AnalysisData<'a, 'tcx: 'a> { fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) -> Lrc { + assert!(tcx.use_ast_borrowck() || tcx.migrate_borrowck()); + debug!("borrowck(body_owner_def_id={:?})", owner_def_id); let owner_id = tcx.hir.as_local_node_id(owner_def_id).unwrap(); @@ -102,6 +105,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) // and do not need borrowchecking. return Lrc::new(BorrowCheckResult { used_mut_nodes: FxHashSet(), + signalled_any_error: SignalledError::NoErrorsSeen, }) } _ => { } @@ -118,6 +122,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) owner_def_id, body, used_mut_nodes: RefCell::new(FxHashSet()), + signalled_any_error: Cell::new(SignalledError::NoErrorsSeen), }; // Eventually, borrowck will always read the MIR, but at the @@ -128,7 +133,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) // Note that `mir_validated` is a "stealable" result; the // thief, `optimized_mir()`, forces borrowck, so we know that // is not yet stolen. - ty::maps::queries::mir_validated::ensure(tcx, owner_def_id); + ty::query::queries::mir_validated::ensure(tcx, owner_def_id); // option dance because you can't capture an uninitialized variable // by mut-ref. @@ -151,6 +156,7 @@ fn borrowck<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, owner_def_id: DefId) Lrc::new(BorrowCheckResult { used_mut_nodes: bccx.used_mut_nodes.into_inner(), + signalled_any_error: bccx.signalled_any_error.into_inner(), }) } @@ -231,6 +237,7 @@ pub fn build_borrowck_dataflow_data_for_fn<'a, 'tcx>( owner_def_id, body, used_mut_nodes: RefCell::new(FxHashSet()), + signalled_any_error: Cell::new(SignalledError::NoErrorsSeen), }; let dataflow_data = build_borrowck_dataflow_data(&mut bccx, true, body_id, |_| cfg); @@ -254,6 +261,15 @@ pub struct BorrowckCtxt<'a, 'tcx: 'a> { body: &'tcx hir::Body, used_mut_nodes: RefCell>, + + signalled_any_error: Cell, +} + + +impl<'a, 'tcx: 'a> BorrowckCtxt<'a, 'tcx> { + fn signal_error(&self) { + self.signalled_any_error.set(SignalledError::SawSomeError); + } } impl<'a, 'b, 'tcx: 'b> BorrowckErrors<'a> for &'a BorrowckCtxt<'b, 'tcx> { @@ -406,7 +422,7 @@ fn closure_to_block(closure_id: LocalDefId, let closure_id = tcx.hir.local_def_id_to_node_id(closure_id); match tcx.hir.get(closure_id) { hir_map::NodeExpr(expr) => match expr.node { - hir::ExprClosure(.., body_id, _, _) => { + hir::ExprKind::Closure(.., body_id, _, _) => { body_id.node_id } _ => { @@ -642,6 +658,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { .span_label(use_span, format!("use of possibly uninitialized `{}`", self.loan_path_to_string(lp))) .emit(); + self.signal_error(); return; } _ => { @@ -680,7 +697,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let mut err = self.cannot_act_on_moved_value(use_span, verb, msg, - &format!("{}", nl), + Some(nl.to_string()), Origin::Ast); let need_note = match lp.ty.sty { ty::TypeVariants::TyClosure(id, _) => { @@ -719,7 +736,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { move_data::Captured => (match self.tcx.hir.expect_expr(node_id).node { - hir::ExprClosure(.., fn_decl_span, _) => fn_decl_span, + hir::ExprKind::Closure(.., fn_decl_span, _) => fn_decl_span, ref r => bug!("Captured({:?}) maps to non-closure: {:?}", the_move.id, r), }, " (into closure)"), @@ -757,6 +774,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { // not considered particularly helpful. err.emit(); + self.signal_error(); } pub fn report_partial_reinitialization_of_uninitialized_structure( @@ -767,6 +785,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { &self.loan_path_to_string(lp), Origin::Ast) .emit(); + self.signal_error(); } pub fn report_reassigned_immutable_variable(&self, @@ -784,6 +803,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.loan_path_to_string(lp))); } err.emit(); + self.signal_error(); } pub fn struct_span_err_with_code>(&self, @@ -899,8 +919,13 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { }; self.note_and_explain_mutbl_error(&mut db, &err, &error_span); - self.note_immutability_blame(&mut db, err.cmt.immutability_blame()); + self.note_immutability_blame( + &mut db, + err.cmt.immutability_blame(), + self.tcx.hir.hir_to_node_id(err.cmt.hir_id) + ); db.emit(); + self.signal_error(); } err_out_of_scope(super_scope, sub_scope, cause) => { let msg = match opt_loan_path(&err.cmt) { @@ -1005,13 +1030,17 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { let node_id = scope.node_id(self.tcx, &self.region_scope_tree); match self.tcx.hir.find(node_id) { Some(hir_map::NodeStmt(_)) => { - db.note("consider using a `let` binding to increase its lifetime"); + if *sub_scope != ty::ReStatic { + db.note("consider using a `let` binding to increase its lifetime"); + } + } _ => {} } } db.emit(); + self.signal_error(); } err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { let descr = self.cmt_to_path_or_string(err.cmt); @@ -1037,6 +1066,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { ""); db.emit(); + self.signal_error(); } } } @@ -1105,19 +1135,24 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { Origin::Ast) } }; - self.note_immutability_blame(&mut err, blame); + self.note_immutability_blame( + &mut err, + blame, + self.tcx.hir.hir_to_node_id(cmt.hir_id) + ); if is_closure { err.help("closures behind references must be called via `&mut`"); } err.emit(); + self.signal_error(); } /// Given a type, if it is an immutable reference, return a suggestion to make it mutable fn suggest_mut_for_immutable(&self, pty: &hir::Ty, is_implicit_self: bool) -> Option { // Check whether the argument is an immutable reference debug!("suggest_mut_for_immutable({:?}, {:?})", pty, is_implicit_self); - if let hir::TyRptr(lifetime, hir::MutTy { + if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::MutImmutable, ref ty }) = pty.node { @@ -1184,36 +1219,24 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { fn note_immutability_blame(&self, db: &mut DiagnosticBuilder, - blame: Option) { + blame: Option, + error_node_id: ast::NodeId) { match blame { None => {} Some(ImmutabilityBlame::ClosureEnv(_)) => {} Some(ImmutabilityBlame::ImmLocal(node_id)) => { - let let_span = self.tcx.hir.span(node_id); - if let ty::BindByValue(..) = self.local_binding_mode(node_id) { - if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { - let (_, is_implicit_self) = self.local_ty(node_id); - if is_implicit_self && snippet != "self" { - // avoid suggesting `mut &self`. - return - } - db.span_label( - let_span, - format!("consider changing this to `mut {}`", snippet) - ); - } - } + self.note_immutable_local(db, error_node_id, node_id) } Some(ImmutabilityBlame::LocalDeref(node_id)) => { - let let_span = self.tcx.hir.span(node_id); match self.local_binding_mode(node_id) { ty::BindByReference(..) => { - let snippet = self.tcx.sess.codemap().span_to_snippet(let_span); - if let Ok(snippet) = snippet { - db.span_label( + let let_span = self.tcx.hir.span(node_id); + let suggestion = suggest_ref_mut(self.tcx, let_span); + if let Some((let_span, replace_str)) = suggestion { + db.span_suggestion( let_span, - format!("consider changing this to `{}`", - snippet.replace("ref ", "ref mut ")) + "use a mutable reference instead", + replace_str, ); } } @@ -1242,6 +1265,46 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } } + // Suggest a fix when trying to mutably borrow an immutable local + // binding: either to make the binding mutable (if its type is + // not a mutable reference) or to avoid borrowing altogether + fn note_immutable_local(&self, + db: &mut DiagnosticBuilder, + borrowed_node_id: ast::NodeId, + binding_node_id: ast::NodeId) { + let let_span = self.tcx.hir.span(binding_node_id); + if let ty::BindByValue(..) = self.local_binding_mode(binding_node_id) { + if let Ok(snippet) = self.tcx.sess.codemap().span_to_snippet(let_span) { + let (ty, is_implicit_self) = self.local_ty(binding_node_id); + if is_implicit_self && snippet != "self" { + // avoid suggesting `mut &self`. + return + } + if let Some(&hir::TyKind::Rptr( + _, + hir::MutTy { + mutbl: hir::MutMutable, + .. + }, + )) = ty.map(|t| &t.node) + { + let borrow_expr_id = self.tcx.hir.get_parent_node(borrowed_node_id); + db.span_suggestion( + self.tcx.hir.span(borrow_expr_id), + "consider removing the `&mut`, as it is an \ + immutable binding to a mutable reference", + snippet + ); + } else { + db.span_label( + let_span, + format!("consider changing this to `mut {}`", snippet), + ); + } + } + } + } + fn report_out_of_scope_escaping_closure_capture(&self, err: &BckError<'a, 'tcx>, capture_span: Span) @@ -1265,6 +1328,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { cmt_path_or_string), suggestion) .emit(); + self.signal_error(); } fn region_end_span(&self, region: ty::Region<'tcx>) -> Option { diff --git a/src/librustc_borrowck/borrowck/move_data.rs b/src/librustc_borrowck/borrowck/move_data.rs index 1f4050a5b3624..4091ca046f44d 100644 --- a/src/librustc_borrowck/borrowck/move_data.rs +++ b/src/librustc_borrowck/borrowck/move_data.rs @@ -343,7 +343,8 @@ impl<'a, 'tcx> MoveData<'tcx> { = (&base_lp.ty.sty, lp_elem) { if adt_def.is_union() { for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { - let field = InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); + let field = + InteriorKind::InteriorField(mc::FieldIndex(i, field.ident.name)); if field != interior { let sibling_lp_kind = LpExtend(base_lp.clone(), mutbl, LpInterior(opt_variant_id, field)); @@ -395,7 +396,8 @@ impl<'a, 'tcx> MoveData<'tcx> { if let ty::TyAdt(adt_def, _) = base_lp.ty.sty { if adt_def.is_union() { for (i, field) in adt_def.non_enum_variant().fields.iter().enumerate() { - let field = InteriorKind::InteriorField(mc::FieldIndex(i, field.name)); + let field = + InteriorKind::InteriorField(mc::FieldIndex(i, field.ident.name)); let field_ty = if field == interior { lp.ty } else { diff --git a/src/librustc_borrowck/borrowck/unused.rs b/src/librustc_borrowck/borrowck/unused.rs index 7bcd8a185453b..475ff0b744349 100644 --- a/src/librustc_borrowck/borrowck/unused.rs +++ b/src/librustc_borrowck/borrowck/unused.rs @@ -46,45 +46,43 @@ impl<'a, 'tcx> UnusedMutCx<'a, 'tcx> { let tcx = self.bccx.tcx; let mut mutables = FxHashMap(); for p in pats { - p.each_binding(|_, id, span, path1| { - let name = path1.node; - + p.each_binding(|_, hir_id, span, ident| { // Skip anything that looks like `_foo` - if name.as_str().starts_with("_") { - return + if ident.as_str().starts_with("_") { + return; } // Skip anything that looks like `&foo` or `&mut foo`, only look // for by-value bindings - let hir_id = tcx.hir.node_to_hir_id(id); - let bm = match self.bccx.tables.pat_binding_modes().get(hir_id) { - Some(&bm) => bm, - None => span_bug!(span, "missing binding mode"), - }; - match bm { - ty::BindByValue(hir::MutMutable) => {} - _ => return, + if let Some(&bm) = self.bccx.tables.pat_binding_modes().get(hir_id) { + match bm { + ty::BindByValue(hir::MutMutable) => {} + _ => return, + } + + mutables.entry(ident.name).or_insert(Vec::new()).push((hir_id, span)); + } else { + tcx.sess.delay_span_bug(span, "missing binding mode"); } - - mutables.entry(name).or_insert(Vec::new()).push((id, hir_id, span)); }); } for (_name, ids) in mutables { // If any id for this name was used mutably then consider them all // ok, so move on to the next - if ids.iter().any(|&(_, ref id, _)| self.used_mut.contains(id)) { - continue + if ids.iter().any(|&(ref hir_id, _)| self.used_mut.contains(hir_id)) { + continue; } - let mut_span = tcx.sess.codemap().span_until_non_whitespace(ids[0].2); + let (hir_id, span) = ids[0]; + let mut_span = tcx.sess.codemap().span_until_non_whitespace(span); // Ok, every name wasn't used mutably, so issue a warning that this // didn't need to be mutable. - tcx.struct_span_lint_node(UNUSED_MUT, - ids[0].0, - ids[0].2, - "variable does not need to be mutable") + tcx.struct_span_lint_hir(UNUSED_MUT, + hir_id, + span, + "variable does not need to be mutable") .span_suggestion_short(mut_span, "remove this `mut`", "".to_owned()) .emit(); } diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs index 52a357e1a1d31..a5a20af0e4e4a 100644 --- a/src/librustc_borrowck/lib.rs +++ b/src/librustc_borrowck/lib.rs @@ -17,6 +17,8 @@ #![feature(from_ref)] #![feature(quote)] +#![recursion_limit="256"] + #[macro_use] extern crate log; extern crate syntax; extern crate syntax_pos; diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml new file mode 100644 index 0000000000000..6ddae57e336ed --- /dev/null +++ b/src/librustc_codegen_llvm/Cargo.toml @@ -0,0 +1,49 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_codegen_llvm" +version = "0.0.0" + +[lib] +name = "rustc_codegen_llvm" +path = "lib.rs" +crate-type = ["dylib"] +test = false + +[dependencies] +bitflags = "1.0.1" +cc = "1.0.1" +flate2 = "1.0" +jobserver = "0.1.5" +libc = "0.2" +log = "0.4" +num_cpus = "1.0" +rustc = { path = "../librustc" } +rustc-demangle = "0.1.4" +rustc_allocator = { path = "../librustc_allocator" } +rustc_apfloat = { path = "../librustc_apfloat" } +rustc_target = { path = "../librustc_target" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_errors = { path = "../librustc_errors" } +rustc_incremental = { path = "../librustc_incremental" } +rustc_llvm = { path = "../librustc_llvm" } +rustc_platform_intrinsics = { path = "../librustc_platform_intrinsics" } +rustc_codegen_utils = { path = "../librustc_codegen_utils" } +rustc_mir = { path = "../librustc_mir" } +serialize = { path = "../libserialize" } +syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } +tempfile = "3.0" + +# not actually used but needed to make sure we enable the same feature set as +# winapi used in librustc +env_logger = { version = "0.5", default-features = false } + +[features] +# Used to communicate the feature to `rustc_target` in the same manner that the +# `rustc` driver script communicate this. +jemalloc = ["rustc_target/jemalloc"] + +# This is used to convince Cargo to separately cache builds of `rustc_codegen_llvm` +# when this option is enabled or not. That way we can build two, cache two +# artifacts, and have nice speedy rebuilds. +emscripten = ["rustc_llvm/emscripten"] diff --git a/src/librustc_codegen_llvm/README.md b/src/librustc_codegen_llvm/README.md new file mode 100644 index 0000000000000..8d1c9a52b2428 --- /dev/null +++ b/src/librustc_codegen_llvm/README.md @@ -0,0 +1,7 @@ +The `codegen` crate contains the code to convert from MIR into LLVM IR, +and then from LLVM IR into machine code. In general it contains code +that runs towards the end of the compilation process. + +For more information about how codegen works, see the [rustc guide]. + +[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/codegen.html diff --git a/src/librustc_trans/abi.rs b/src/librustc_codegen_llvm/abi.rs similarity index 89% rename from src/librustc_trans/abi.rs rename to src/librustc_codegen_llvm/abi.rs index 1838dae049ad7..f1a6e9913d6bd 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_codegen_llvm/abi.rs @@ -10,7 +10,7 @@ use llvm::{self, ValueRef, AttributePlace}; use base; -use builder::Builder; +use builder::{Builder, MemFlags}; use common::{ty_fn_sig, C_usize}; use context::CodegenCx; use mir::place::PlaceRef; @@ -127,8 +127,12 @@ impl LlvmType for Reg { impl LlvmType for CastTarget { fn llvm_type(&self, cx: &CodegenCx) -> Type { let rest_ll_unit = self.rest.unit.llvm_type(cx); - let rest_count = self.rest.total.bytes() / self.rest.unit.size.bytes(); - let rem_bytes = self.rest.total.bytes() % self.rest.unit.size.bytes(); + let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 { + (0, 0) + } else { + (self.rest.total.bytes() / self.rest.unit.size.bytes(), + self.rest.total.bytes() % self.rest.unit.size.bytes()) + }; if self.prefix.iter().all(|x| x.is_none()) { // Simplify to a single unit when there is no prefix and size <= unit size @@ -220,7 +224,8 @@ impl<'a, 'tcx> ArgTypeExt<'a, 'tcx> for ArgType<'tcx, Ty<'tcx>> { bx.pointercast(dst.llval, Type::i8p(cx)), bx.pointercast(llscratch, Type::i8p(cx)), C_usize(cx, self.layout.size.bytes()), - self.layout.align.min(scratch_align)); + self.layout.align.min(scratch_align), + MemFlags::empty()); bx.lifetime_end(llscratch, scratch_size); } @@ -256,9 +261,12 @@ pub trait FnTypeExt<'a, 'tcx> { fn new_vtable(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self; - fn unadjusted(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self; + fn new_internal( + cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self; fn adjust_for_abi(&mut self, cx: &CodegenCx<'a, 'tcx>, abi: Abi); @@ -280,40 +288,40 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { fn new(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); - fn_ty.adjust_for_abi(cx, sig.abi); - fn_ty + FnType::new_internal(cx, sig, extra_args, |ty, _| { + ArgType::new(cx.layout_of(ty)) + }) } fn new_vtable(cx: &CodegenCx<'a, 'tcx>, sig: ty::FnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - let mut fn_ty = FnType::unadjusted(cx, sig, extra_args); - // Don't pass the vtable, it's not an argument of the virtual fn. - { - let self_arg = &mut fn_ty.args[0]; - match self_arg.mode { - PassMode::Pair(data_ptr, _) => { - self_arg.mode = PassMode::Direct(data_ptr); - } - _ => bug!("FnType::new_vtable: non-pair self {:?}", self_arg) - } - - let pointee = self_arg.layout.ty.builtin_deref(true) - .unwrap_or_else(|| { - bug!("FnType::new_vtable: non-pointer self {:?}", self_arg) - }).ty; - let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee); - self_arg.layout = cx.layout_of(fat_ptr_ty).field(cx, 0); - } - fn_ty.adjust_for_abi(cx, sig.abi); - fn_ty + FnType::new_internal(cx, sig, extra_args, |ty, arg_idx| { + let mut layout = cx.layout_of(ty); + // Don't pass the vtable, it's not an argument of the virtual fn. + // Instead, pass just the (thin pointer) first field of `*dyn Trait`. + if arg_idx == Some(0) { + // FIXME(eddyb) `layout.field(cx, 0)` is not enough because e.g. + // `Box` has a few newtype wrappers around the raw + // pointer, so we'd have to "dig down" to find `*dyn Trait`. + let pointee = layout.ty.builtin_deref(true) + .unwrap_or_else(|| { + bug!("FnType::new_vtable: non-pointer self {:?}", layout) + }).ty; + let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee); + layout = cx.layout_of(fat_ptr_ty).field(cx, 0); + } + ArgType::new(layout) + }) } - fn unadjusted(cx: &CodegenCx<'a, 'tcx>, - sig: ty::FnSig<'tcx>, - extra_args: &[Ty<'tcx>]) -> Self { - debug!("FnType::unadjusted({:?}, {:?})", sig, extra_args); + fn new_internal( + cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>, + extra_args: &[Ty<'tcx>], + mk_arg_type: impl Fn(Ty<'tcx>, Option) -> ArgType<'tcx, Ty<'tcx>>, + ) -> Self { + debug!("FnType::new_internal({:?}, {:?})", sig, extra_args); use self::Abi::*; let conv = match cx.sess().target.target.adjust_abi(sig.abi) { @@ -335,6 +343,7 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { PtxKernel => Conv::PtxKernel, Msp430Interrupt => Conv::Msp430Intr, X86Interrupt => Conv::X86Intr, + AmdGpuKernel => Conv::AmdGpuKernel, // These API constants ought to be more specific... Cdecl => Conv::C, @@ -430,8 +439,9 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { } }; - let arg_of = |ty: Ty<'tcx>, is_return: bool| { - let mut arg = ArgType::new(cx.layout_of(ty)); + let arg_of = |ty: Ty<'tcx>, arg_idx: Option| { + let is_return = arg_idx.is_none(); + let mut arg = mk_arg_type(ty, arg_idx); if arg.layout.is_zst() { // For some forsaken reason, x86_64-pc-windows-gnu // doesn't ignore zero-sized struct arguments. @@ -449,7 +459,7 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, - Size::from_bytes(0), + Size::ZERO, false); adjust_for_rust_scalar(&mut b_attrs, b, @@ -466,7 +476,7 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { adjust_for_rust_scalar(attrs, scalar, arg.layout, - Size::from_bytes(0), + Size::ZERO, is_return); } } @@ -474,14 +484,16 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { arg }; - FnType { - ret: arg_of(sig.output(), true), - args: inputs.iter().chain(extra_args.iter()).map(|ty| { - arg_of(ty, false) + let mut fn_ty = FnType { + ret: arg_of(sig.output(), None), + args: inputs.iter().chain(extra_args).enumerate().map(|(i, ty)| { + arg_of(ty, Some(i)) }).collect(), variadic: sig.variadic, conv, - } + }; + fn_ty.adjust_for_abi(cx, sig.abi); + fn_ty } fn adjust_for_abi(&mut self, @@ -553,7 +565,13 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { } fn llvm_type(&self, cx: &CodegenCx<'a, 'tcx>) -> Type { - let mut llargument_tys = Vec::new(); + let args_capacity: usize = self.args.iter().map(|arg| + if arg.pad.is_some() { 1 } else { 0 } + + if let PassMode::Pair(_, _) = arg.mode { 2 } else { 1 } + ).sum(); + let mut llargument_tys = Vec::with_capacity( + if let PassMode::Indirect(_) = self.ret.mode { 1 } else { 0 } + args_capacity + ); let llreturn_ty = match self.ret.mode { PassMode::Ignore => Type::void(cx), @@ -577,8 +595,8 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { PassMode::Ignore => continue, PassMode::Direct(_) => arg.layout.immediate_llvm_type(cx), PassMode::Pair(..) => { - llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0)); - llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1)); + llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 0, true)); + llargument_tys.push(arg.layout.scalar_pair_element_llvm_type(cx, 1, true)); continue; } PassMode::Cast(cast) => cast.llvm_type(cx), @@ -597,6 +615,7 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { fn llvm_cconv(&self) -> llvm::CallConv { match self.conv { Conv::C => llvm::CCallConv, + Conv::AmdGpuKernel => llvm::AmdGpuKernel, Conv::ArmAapcs => llvm::ArmAapcsCallConv, Conv::Msp430Intr => llvm::Msp430Intr, Conv::PtxKernel => llvm::PtxKernel, @@ -661,11 +680,7 @@ impl<'a, 'tcx> FnTypeExt<'a, 'tcx> for FnType<'tcx, Ty<'tcx>> { layout::Int(..) if !scalar.is_bool() => { let range = scalar.valid_range_exclusive(bx.cx); if range.start != range.end { - // FIXME(nox): This causes very weird type errors about - // SHL operators in constants in stage 2 with LLVM 3.9. - if unsafe { llvm::LLVMRustVersionMajor() >= 4 } { - bx.range_metadata(callsite, range); - } + bx.range_metadata(callsite, range); } } _ => {} diff --git a/src/librustc_trans/allocator.rs b/src/librustc_codegen_llvm/allocator.rs similarity index 98% rename from src/librustc_trans/allocator.rs rename to src/librustc_codegen_llvm/allocator.rs index 871fe98ec0187..eeb02e948f1cc 100644 --- a/src/librustc_trans/allocator.rs +++ b/src/librustc_codegen_llvm/allocator.rs @@ -20,7 +20,7 @@ use rustc_allocator::{ALLOCATOR_METHODS, AllocatorTy}; use ModuleLlvm; use llvm::{self, False, True}; -pub(crate) unsafe fn trans(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) { +pub(crate) unsafe fn codegen(tcx: TyCtxt, mods: &ModuleLlvm, kind: AllocatorKind) { let llcx = mods.llcx; let llmod = mods.llmod; let usize = match &tcx.sess.target.target.target_pointer_width[..] { diff --git a/src/librustc_trans/asm.rs b/src/librustc_codegen_llvm/asm.rs similarity index 96% rename from src/librustc_trans/asm.rs rename to src/librustc_codegen_llvm/asm.rs index 751f8148a2a90..82f068106ff71 100644 --- a/src/librustc_trans/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! # Translation of inline assembly. - use llvm::{self, ValueRef}; use common::*; use type_::Type; @@ -26,7 +24,7 @@ use syntax::ast::AsmDialect; use libc::{c_uint, c_char}; // Take an inline assembly expression and splat it out via LLVM -pub fn trans_inline_asm<'a, 'tcx>( +pub fn codegen_inline_asm<'a, 'tcx>( bx: &Builder<'a, 'tcx>, ia: &hir::InlineAsm, outputs: Vec>, @@ -120,7 +118,7 @@ pub fn trans_inline_asm<'a, 'tcx>( } } -pub fn trans_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, +pub fn codegen_global_asm<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ga: &hir::GlobalAsm) { let asm = CString::new(ga.asm.as_str().as_bytes()).unwrap(); unsafe { diff --git a/src/librustc_trans/attributes.rs b/src/librustc_codegen_llvm/attributes.rs similarity index 78% rename from src/librustc_trans/attributes.rs rename to src/librustc_codegen_llvm/attributes.rs index 5baed57092d0f..3b5f927d52f00 100644 --- a/src/librustc_trans/attributes.rs +++ b/src/librustc_codegen_llvm/attributes.rs @@ -11,16 +11,17 @@ use std::ffi::{CStr, CString}; -use rustc::hir::{self, TransFnAttrFlags}; +use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; -use rustc::hir::itemlikevisit::ItemLikeVisitor; use rustc::session::Session; use rustc::session::config::Sanitizer; use rustc::ty::TyCtxt; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc_data_structures::sync::Lrc; use rustc_data_structures::fx::FxHashMap; +use rustc_target::spec::PanicStrategy; +use attributes; use llvm::{self, Attribute, ValueRef}; use llvm::AttributePlace::Function; use llvm_util; @@ -96,6 +97,11 @@ pub fn set_probestack(cx: &CodegenCx, llfn: ValueRef) { return; } + // probestack doesn't play nice either with gcov profiling. + if cx.sess().opts.debugging_opts.profile { + return; + } + // Flag our internal `__rust_probestack` function as the stack probe symbol. // This is defined in the `compiler-builtins` crate for each architecture. llvm::AddFunctionAttrStringValue( @@ -118,34 +124,51 @@ pub fn llvm_target_features(sess: &Session) -> impl Iterator { /// Composite function which sets LLVM attributes for function depending on its AST (#[attribute]) /// attributes. pub fn from_fn_attrs(cx: &CodegenCx, llfn: ValueRef, id: DefId) { - let trans_fn_attrs = cx.tcx.trans_fn_attrs(id); + let codegen_fn_attrs = cx.tcx.codegen_fn_attrs(id); - inline(llfn, trans_fn_attrs.inline); + inline(llfn, codegen_fn_attrs.inline); set_frame_pointer_elimination(cx, llfn); set_probestack(cx, llfn); - if trans_fn_attrs.flags.contains(TransFnAttrFlags::COLD) { + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::COLD) { Attribute::Cold.apply_llfn(Function, llfn); } - if trans_fn_attrs.flags.contains(TransFnAttrFlags::NAKED) { + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { naked(llfn, true); } - if trans_fn_attrs.flags.contains(TransFnAttrFlags::ALLOCATOR) { + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { Attribute::NoAlias.apply_llfn( llvm::AttributePlace::ReturnValue, llfn); } - if trans_fn_attrs.flags.contains(TransFnAttrFlags::UNWIND) { - unwind(llfn, true); - } - if trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { - unwind(llfn, false); + + let can_unwind = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::UNWIND) { + Some(true) + } else if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND) { + Some(false) + + // Perhaps questionable, but we assume that anything defined + // *in Rust code* may unwind. Foreign items like `extern "C" { + // fn foo(); }` are assumed not to unwind **unless** they have + // a `#[unwind]` attribute. + } else if !cx.tcx.is_foreign_item(id) { + Some(true) + } else { + None + }; + + match can_unwind { + Some(false) => attributes::unwind(llfn, false), + Some(true) if cx.tcx.sess.panic_strategy() == PanicStrategy::Unwind => { + attributes::unwind(llfn, true); + } + Some(true) | None => {} } let features = llvm_target_features(cx.tcx.sess) .map(|s| s.to_string()) .chain( - trans_fn_attrs.target_features + codegen_fn_attrs.target_features .iter() .map(|f| { let feature = &*f.as_str(); @@ -198,46 +221,27 @@ pub fn provide(providers: &mut Providers) { } }; - providers.wasm_custom_sections = |tcx, cnum| { - assert_eq!(cnum, LOCAL_CRATE); - let mut finder = WasmSectionFinder { tcx, list: Vec::new() }; - tcx.hir.krate().visit_all_item_likes(&mut finder); - Lrc::new(finder.list) - }; - provide_extern(providers); } -struct WasmSectionFinder<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - list: Vec, -} - -impl<'a, 'tcx: 'a> ItemLikeVisitor<'tcx> for WasmSectionFinder<'a, 'tcx> { - fn visit_item(&mut self, i: &'tcx hir::Item) { - match i.node { - hir::ItemConst(..) => {} - _ => return, - } - if i.attrs.iter().any(|i| i.check_name("wasm_custom_section")) { - self.list.push(self.tcx.hir.local_def_id(i.id)); - } - } - - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {} - - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {} -} - pub fn provide_extern(providers: &mut Providers) { providers.wasm_import_module_map = |tcx, cnum| { + // Build up a map from DefId to a `NativeLibrary` structure, where + // `NativeLibrary` internally contains information about + // `#[link(wasm_import_module = "...")]` for example. + let native_libs = tcx.native_libraries(cnum); + let mut def_id_to_native_lib = FxHashMap(); + for lib in native_libs.iter() { + if let Some(id) = lib.foreign_module { + def_id_to_native_lib.insert(id, lib); + } + } + let mut ret = FxHashMap(); for lib in tcx.foreign_modules(cnum).iter() { - let attrs = tcx.get_attrs(lib.def_id); - let mut module = None; - for attr in attrs.iter().filter(|a| a.check_name("wasm_import_module")) { - module = attr.value_str(); - } + let module = def_id_to_native_lib + .get(&lib.def_id) + .and_then(|s| s.wasm_import_module); let module = match module { Some(s) => s, None => continue, @@ -249,7 +253,7 @@ pub fn provide_extern(providers: &mut Providers) { } Lrc::new(ret) - } + }; } fn wasm_import_module(tcx: TyCtxt, id: DefId) -> Option { diff --git a/src/librustc_trans/back/archive.rs b/src/librustc_codegen_llvm/back/archive.rs similarity index 99% rename from src/librustc_trans/back/archive.rs rename to src/librustc_codegen_llvm/back/archive.rs index 609629bffb9da..b99835cb5c649 100644 --- a/src/librustc_trans/back/archive.rs +++ b/src/librustc_codegen_llvm/back/archive.rs @@ -48,7 +48,7 @@ enum Addition { }, Archive { archive: ArchiveRO, - skip: Box bool>, + skip: Box bool>, }, } @@ -149,7 +149,7 @@ impl<'a> ArchiveBuilder<'a> { // Ignoring obj file starting with the crate name // as simple comparison is not enough - there // might be also an extra name suffix - let obj_start = format!("{}", name); + let obj_start = name.to_owned(); self.add_archive(rlib, move |fname: &str| { // Ignore bytecode/metadata files, no matter the name. diff --git a/src/librustc_trans/back/bytecode.rs b/src/librustc_codegen_llvm/back/bytecode.rs similarity index 100% rename from src/librustc_trans/back/bytecode.rs rename to src/librustc_codegen_llvm/back/bytecode.rs diff --git a/src/librustc_trans/back/command.rs b/src/librustc_codegen_llvm/back/command.rs similarity index 100% rename from src/librustc_trans/back/command.rs rename to src/librustc_codegen_llvm/back/command.rs diff --git a/src/librustc_trans/back/link.rs b/src/librustc_codegen_llvm/back/link.rs similarity index 87% rename from src/librustc_trans/back/link.rs rename to src/librustc_codegen_llvm/back/link.rs index 92f9a9e8ba974..83ff8bc821c68 100644 --- a/src/librustc_trans/back/link.rs +++ b/src/librustc_codegen_llvm/back/link.rs @@ -24,12 +24,12 @@ use rustc::session::search_paths::PathKind; use rustc::session::Session; use rustc::middle::cstore::{NativeLibrary, LibSource, NativeLibraryKind}; use rustc::middle::dependency_format::Linkage; -use {CrateTranslation, CrateInfo}; +use {CodegenResults, CrateInfo}; use rustc::util::common::time; use rustc::util::fs::fix_windows_verbatim_for_gcc; use rustc::hir::def_id::CrateNum; -use tempdir::TempDir; -use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor, TargetTriple}; +use tempfile::{Builder as TempFileBuilder, TempDir}; +use rustc_target::spec::{PanicStrategy, RelroLevel, LinkerFlavor}; use rustc_data_structures::fx::FxHashSet; use context::get_reloc_model; use llvm; @@ -40,6 +40,7 @@ use std::env; use std::fmt; use std::fs; use std::io; +use std::iter; use std::path::{Path, PathBuf}; use std::process::{Output, Stdio}; use std::str; @@ -52,7 +53,7 @@ pub const METADATA_MODULE_NAME: &'static str = "crate.metadata"; // same as for metadata above, but for allocator shim pub const ALLOCATOR_MODULE_NAME: &'static str = "crate.allocator"; -pub use rustc_trans_utils::link::{find_crate_name, filename_for_input, default_output_for_target, +pub use rustc_codegen_utils::link::{find_crate_name, filename_for_input, default_output_for_target, invalid_output_for_target, build_link_meta, out_filename, check_file_is_writeable}; @@ -141,14 +142,14 @@ pub fn remove(sess: &Session, path: &Path) { /// Perform the linkage portion of the compilation phase. This will generate all /// of the requested outputs for this compilation session. pub(crate) fn link_binary(sess: &Session, - trans: &CrateTranslation, + codegen_results: &CodegenResults, outputs: &OutputFilenames, crate_name: &str) -> Vec { let mut out_filenames = Vec::new(); for &crate_type in sess.crate_types.borrow().iter() { - // Ignore executable crates if we have -Z no-trans, as they will error. + // Ignore executable crates if we have -Z no-codegen, as they will error. let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); - if (sess.opts.debugging_opts.no_trans || !sess.opts.output_types.should_trans()) && + if (sess.opts.debugging_opts.no_codegen || !sess.opts.output_types.should_codegen()) && !output_metadata && crate_type == config::CrateTypeExecutable { continue; @@ -159,7 +160,7 @@ pub(crate) fn link_binary(sess: &Session, crate_type, sess.opts.target_triple); } let mut out_files = link_binary_output(sess, - trans, + codegen_results, crate_type, outputs, crate_name); @@ -168,20 +169,20 @@ pub(crate) fn link_binary(sess: &Session, // Remove the temporary object file and metadata if we aren't saving temps if !sess.opts.cg.save_temps { - if sess.opts.output_types.should_trans() && + if sess.opts.output_types.should_codegen() && !preserve_objects_for_their_debuginfo(sess) { - for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { remove(sess, obj); } } - for obj in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { + for obj in codegen_results.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { remove(sess, obj); } - if let Some(ref obj) = trans.metadata_module.object { + if let Some(ref obj) = codegen_results.metadata_module.object { remove(sess, obj); } - if let Some(ref allocator) = trans.allocator_module { + if let Some(ref allocator) = codegen_results.allocator_module { if let Some(ref obj) = allocator.object { remove(sess, obj); } @@ -251,7 +252,7 @@ fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilen pub(crate) fn each_linked_rlib(sess: &Session, info: &CrateInfo, - f: &mut FnMut(CrateNum, &Path)) -> Result<(), String> { + f: &mut dyn FnMut(CrateNum, &Path)) -> Result<(), String> { let crates = info.used_crates_static.iter(); let fmts = sess.dependency_formats.borrow(); let fmts = fmts.get(&config::CrateTypeExecutable) @@ -304,11 +305,11 @@ pub(crate) fn ignored_for_lto(sess: &Session, info: &CrateInfo, cnum: CrateNum) } fn link_binary_output(sess: &Session, - trans: &CrateTranslation, + codegen_results: &CodegenResults, crate_type: config::CrateType, outputs: &OutputFilenames, crate_name: &str) -> Vec { - for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { check_file_is_writeable(obj, sess); } @@ -321,37 +322,40 @@ fn link_binary_output(sess: &Session, // final destination, with a `fs::rename` call. In order for the rename to // always succeed, the temporary file needs to be on the same filesystem, // which is why we create it inside the output directory specifically. - let metadata_tmpdir = match TempDir::new_in(out_filename.parent().unwrap(), "rmeta") { + let metadata_tmpdir = match TempFileBuilder::new() + .prefix("rmeta") + .tempdir_in(out_filename.parent().unwrap()) + { Ok(tmpdir) => tmpdir, Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), }; - let metadata = emit_metadata(sess, trans, &metadata_tmpdir); + let metadata = emit_metadata(sess, codegen_results, &metadata_tmpdir); if let Err(e) = fs::rename(metadata, &out_filename) { sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); } out_filenames.push(out_filename); } - let tmpdir = match TempDir::new("rustc") { + let tmpdir = match TempFileBuilder::new().prefix("rustc").tempdir() { Ok(tmpdir) => tmpdir, Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)), }; - if outputs.outputs.should_trans() { + if outputs.outputs.should_codegen() { let out_filename = out_filename(sess, crate_type, outputs, crate_name); match crate_type { config::CrateTypeRlib => { link_rlib(sess, - trans, + codegen_results, RlibFlavor::Normal, &out_filename, &tmpdir).build(); } config::CrateTypeStaticlib => { - link_staticlib(sess, trans, &out_filename, &tmpdir); + link_staticlib(sess, codegen_results, &out_filename, &tmpdir); } _ => { - link_natively(sess, crate_type, &out_filename, trans, tmpdir.path()); + link_natively(sess, crate_type, &out_filename, codegen_results, tmpdir.path()); } } out_filenames.push(out_filename); @@ -388,10 +392,10 @@ fn archive_config<'a>(sess: &'a Session, /// building an `.rlib` (stomping over one another), or writing an `.rmeta` into a /// directory being searched for `extern crate` (observing an incomplete file). /// The returned path is the temporary file containing the complete metadata. -fn emit_metadata<'a>(sess: &'a Session, trans: &CrateTranslation, tmpdir: &TempDir) +fn emit_metadata<'a>(sess: &'a Session, codegen_results: &CodegenResults, tmpdir: &TempDir) -> PathBuf { let out_filename = tmpdir.path().join(METADATA_FILENAME); - let result = fs::write(&out_filename, &trans.metadata.raw_data); + let result = fs::write(&out_filename, &codegen_results.metadata.raw_data); if let Err(e) = result { sess.fatal(&format!("failed to write {}: {}", out_filename.display(), e)); @@ -412,14 +416,14 @@ enum RlibFlavor { // all of the object files from native libraries. This is done by unzipping // native libraries and inserting all of the contents into this archive. fn link_rlib<'a>(sess: &'a Session, - trans: &CrateTranslation, + codegen_results: &CodegenResults, flavor: RlibFlavor, out_filename: &Path, tmpdir: &TempDir) -> ArchiveBuilder<'a> { info!("preparing rlib to {:?}", out_filename); let mut ab = ArchiveBuilder::new(archive_config(sess, out_filename, None)); - for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { ab.add_file(obj); } @@ -439,14 +443,16 @@ fn link_rlib<'a>(sess: &'a Session, // feature then we'll need to figure out how to record what objects were // loaded from the libraries found here and then encode that into the // metadata of the rlib we're generating somehow. - for lib in trans.crate_info.used_libraries.iter() { + for lib in codegen_results.crate_info.used_libraries.iter() { match lib.kind { NativeLibraryKind::NativeStatic => {} NativeLibraryKind::NativeStaticNobundle | NativeLibraryKind::NativeFramework | NativeLibraryKind::NativeUnknown => continue, } - ab.add_native_library(&lib.name.as_str()); + if let Some(name) = lib.name { + ab.add_native_library(&name.as_str()); + } } // After adding all files to the archive, we need to update the @@ -478,11 +484,15 @@ fn link_rlib<'a>(sess: &'a Session, RlibFlavor::Normal => { // Instead of putting the metadata in an object file section, rlibs // contain the metadata in a separate file. - ab.add_file(&emit_metadata(sess, trans, tmpdir)); + ab.add_file(&emit_metadata(sess, codegen_results, tmpdir)); // For LTO purposes, the bytecode of this library is also inserted // into the archive. - for bytecode in trans.modules.iter().filter_map(|m| m.bytecode_compressed.as_ref()) { + for bytecode in codegen_results + .modules + .iter() + .filter_map(|m| m.bytecode_compressed.as_ref()) + { ab.add_file(bytecode); } @@ -495,7 +505,7 @@ fn link_rlib<'a>(sess: &'a Session, } RlibFlavor::StaticlibBase => { - let obj = trans.allocator_module + let obj = codegen_results.allocator_module .as_ref() .and_then(|m| m.object.as_ref()); if let Some(obj) = obj { @@ -520,19 +530,19 @@ fn link_rlib<'a>(sess: &'a Session, // link in the metadata object file (and also don't prepare the archive with a // metadata file). fn link_staticlib(sess: &Session, - trans: &CrateTranslation, + codegen_results: &CodegenResults, out_filename: &Path, tempdir: &TempDir) { let mut ab = link_rlib(sess, - trans, + codegen_results, RlibFlavor::StaticlibBase, out_filename, tempdir); let mut all_native_libs = vec![]; - let res = each_linked_rlib(sess, &trans.crate_info, &mut |cnum, path| { - let name = &trans.crate_info.crate_name[&cnum]; - let native_libs = &trans.crate_info.native_libraries[&cnum]; + let res = each_linked_rlib(sess, &codegen_results.crate_info, &mut |cnum, path| { + let name = &codegen_results.crate_info.crate_name[&cnum]; + let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; // Here when we include the rlib into our staticlib we need to make a // decision whether to include the extra object files along the way. @@ -554,10 +564,10 @@ fn link_staticlib(sess: &Session, ab.add_rlib(path, &name.as_str(), is_full_lto_enabled(sess) && - !ignored_for_lto(sess, &trans.crate_info, cnum), + !ignored_for_lto(sess, &codegen_results.crate_info, cnum), skip_object_files).unwrap(); - all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned()); + all_native_libs.extend(codegen_results.crate_info.native_libraries[&cnum].iter().cloned()); }); if let Err(e) = res { sess.fatal(&e); @@ -576,21 +586,24 @@ fn link_staticlib(sess: &Session, fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { let lib_args: Vec<_> = all_native_libs.iter() .filter(|l| relevant_lib(sess, l)) - .filter_map(|lib| match lib.kind { - NativeLibraryKind::NativeStaticNobundle | - NativeLibraryKind::NativeUnknown => { - if sess.target.target.options.is_like_msvc { - Some(format!("{}.lib", lib.name)) - } else { - Some(format!("-l{}", lib.name)) - } - }, - NativeLibraryKind::NativeFramework => { - // ld-only syntax, since there are no frameworks in MSVC - Some(format!("-framework {}", lib.name)) - }, - // These are included, no need to print them - NativeLibraryKind::NativeStatic => None, + .filter_map(|lib| { + let name = lib.name?; + match lib.kind { + NativeLibraryKind::NativeStaticNobundle | + NativeLibraryKind::NativeUnknown => { + if sess.target.target.options.is_like_msvc { + Some(format!("{}.lib", name)) + } else { + Some(format!("-l{}", name)) + } + }, + NativeLibraryKind::NativeFramework => { + // ld-only syntax, since there are no frameworks in MSVC + Some(format!("-framework {}", name)) + }, + // These are included, no need to print them + NativeLibraryKind::NativeStatic => None, + } }) .collect(); if !lib_args.is_empty() { @@ -609,7 +622,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLibrary]) { fn link_natively(sess: &Session, crate_type: config::CrateType, out_filename: &Path, - trans: &CrateTranslation, + codegen_results: &CodegenResults, tmpdir: &Path) { info!("preparing {:?} to {:?}", crate_type, out_filename); let flavor = sess.linker_flavor(); @@ -621,6 +634,11 @@ fn link_natively(sess: &Session, if let Some(args) = sess.target.target.options.pre_link_args.get(&flavor) { cmd.args(args); } + if let Some(args) = sess.target.target.options.pre_link_args_crt.get(&flavor) { + if sess.crt_static() { + cmd.args(args); + } + } if let Some(ref args) = sess.opts.debugging_opts.pre_link_args { cmd.args(args); } @@ -635,6 +653,12 @@ fn link_natively(sess: &Session, cmd.arg(root.join(obj)); } + if crate_type == config::CrateTypeExecutable && sess.crt_static() { + for obj in &sess.target.target.options.pre_link_objects_exe_crt { + cmd.arg(root.join(obj)); + } + } + if sess.target.target.options.is_like_emscripten { cmd.arg("-s"); cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { @@ -645,9 +669,9 @@ fn link_natively(sess: &Session, } { - let mut linker = trans.linker_info.to_linker(cmd, &sess); + let mut linker = codegen_results.linker_info.to_linker(cmd, &sess); link_args(&mut *linker, sess, crate_type, tmpdir, - out_filename, trans); + out_filename, codegen_results); cmd = linker.finalize(); } if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { @@ -656,6 +680,11 @@ fn link_natively(sess: &Session, for obj in &sess.target.target.options.post_link_objects { cmd.arg(root.join(obj)); } + if sess.crt_static() { + for obj in &sess.target.target.options.post_link_objects_crt { + cmd.arg(root.join(obj)); + } + } if let Some(args) = sess.target.target.options.post_link_args.get(&flavor) { cmd.args(args); } @@ -782,7 +811,7 @@ fn link_natively(sess: &Session, } }; - linker_error.note(&format!("{}", e)); + linker_error.note(&e.to_string()); if !linker_not_found { linker_error.note(&format!("{:?}", &cmd)); @@ -793,8 +822,8 @@ fn link_natively(sess: &Session, if sess.target.target.options.is_like_msvc && linker_not_found { sess.note_without_error("the msvc targets depend on the msvc linker \ but `link.exe` was not found"); - sess.note_without_error("please ensure that VS 2013 or VS 2015 was installed \ - with the Visual C++ option"); + sess.note_without_error("please ensure that VS 2013, VS 2015 or VS 2017 \ + was installed with the Visual C++ option"); } sess.abort_if_errors(); } @@ -814,10 +843,8 @@ fn link_natively(sess: &Session, } } - if sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown") { - wasm::rewrite_imports(&out_filename, &trans.crate_info.wasm_imports); - wasm::add_custom_sections(&out_filename, - &trans.crate_info.wasm_custom_sections); + if sess.opts.target_triple.triple() == "wasm32-unknown-unknown" { + wasm::rewrite_imports(&out_filename, &codegen_results.crate_info.wasm_imports); } } @@ -859,9 +886,9 @@ fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: & } let file = tmpdir.join("linker-arguments"); let bytes = if sess.target.target.options.is_like_msvc { - let mut out = vec![]; + let mut out = Vec::with_capacity((1 + args.len()) * 2); // start the stream with a UTF-16 BOM - for c in vec![0xFEFF].into_iter().chain(args.encode_utf16()) { + for c in iter::once(0xFEFF).chain(args.encode_utf16()) { // encode in little endian out.push(c as u8); out.push((c >> 8) as u8); @@ -963,12 +990,15 @@ fn exec_linker(sess: &Session, cmd: &mut Command, out_filename: &Path, tmpdir: & } } -fn link_args(cmd: &mut Linker, +fn link_args(cmd: &mut dyn Linker, sess: &Session, crate_type: config::CrateType, tmpdir: &Path, out_filename: &Path, - trans: &CrateTranslation) { + codegen_results: &CodegenResults) { + + // Linker plugins should be specified early in the list of arguments + cmd.cross_lang_lto(); // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. @@ -978,14 +1008,14 @@ fn link_args(cmd: &mut Linker, let t = &sess.target.target; cmd.include_path(&fix_windows_verbatim_for_gcc(&lib_path)); - for obj in trans.modules.iter().filter_map(|m| m.object.as_ref()) { + for obj in codegen_results.modules.iter().filter_map(|m| m.object.as_ref()) { cmd.add_object(obj); } cmd.output_filename(out_filename); if crate_type == config::CrateTypeExecutable && sess.target.target.options.is_like_windows { - if let Some(ref s) = trans.windows_subsystem { + if let Some(ref s) = codegen_results.windows_subsystem { cmd.subsystem(s); } } @@ -1002,12 +1032,12 @@ fn link_args(cmd: &mut Linker, // object file, so we link that in here. if crate_type == config::CrateTypeDylib || crate_type == config::CrateTypeProcMacro { - if let Some(obj) = trans.metadata_module.object.as_ref() { + if let Some(obj) = codegen_results.metadata_module.object.as_ref() { cmd.add_object(obj); } } - let obj = trans.allocator_module + let obj = codegen_results.allocator_module .as_ref() .and_then(|m| m.object.as_ref()); if let Some(obj) = obj { @@ -1021,7 +1051,7 @@ fn link_args(cmd: &mut Linker, cmd.gc_sections(keep_metadata); } - let used_link_args = &trans.crate_info.link_args; + let used_link_args = &codegen_results.crate_info.link_args; if crate_type == config::CrateTypeExecutable { let mut position_independent_executable = false; @@ -1110,9 +1140,9 @@ fn link_args(cmd: &mut Linker, // link line. And finally upstream native libraries can't depend on anything // in this DAG so far because they're only dylibs and dylibs can only depend // on other dylibs (e.g. other native deps). - add_local_native_libraries(cmd, sess, trans); - add_upstream_rust_crates(cmd, sess, trans, crate_type, tmpdir); - add_upstream_native_libraries(cmd, sess, trans, crate_type); + add_local_native_libraries(cmd, sess, codegen_results); + add_upstream_rust_crates(cmd, sess, codegen_results, crate_type, tmpdir); + add_upstream_native_libraries(cmd, sess, codegen_results, crate_type); // Tell the linker what we're doing. if crate_type != config::CrateTypeExecutable { @@ -1141,7 +1171,7 @@ fn link_args(cmd: &mut Linker, path }; let mut rpath_config = RPathConfig { - used_crates: &trans.crate_info.used_crates_dynamic, + used_crates: &codegen_results.crate_info.used_crates_dynamic, out_filename: out_filename.to_path_buf(), has_rpath: sess.target.target.options.has_rpath, is_like_osx: sess.target.target.options.is_like_osx, @@ -1171,9 +1201,9 @@ fn link_args(cmd: &mut Linker, // Also note that the native libraries linked here are only the ones located // in the current crate. Upstream crates with native library dependencies // may have their native library pulled in above. -fn add_local_native_libraries(cmd: &mut Linker, +fn add_local_native_libraries(cmd: &mut dyn Linker, sess: &Session, - trans: &CrateTranslation) { + codegen_results: &CodegenResults) { sess.target_filesearch(PathKind::All).for_each_lib_search_path(|path, k| { match k { PathKind::Framework => { cmd.framework_path(path); } @@ -1181,17 +1211,21 @@ fn add_local_native_libraries(cmd: &mut Linker, } }); - let relevant_libs = trans.crate_info.used_libraries.iter().filter(|l| { + let relevant_libs = codegen_results.crate_info.used_libraries.iter().filter(|l| { relevant_lib(sess, l) }); let search_path = archive_search_paths(sess); for lib in relevant_libs { + let name = match lib.name { + Some(ref l) => l, + None => continue, + }; match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), - NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), - NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&lib.name.as_str()), - NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&lib.name.as_str(), + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()), + NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()), + NativeLibraryKind::NativeStaticNobundle => cmd.link_staticlib(&name.as_str()), + NativeLibraryKind::NativeStatic => cmd.link_whole_staticlib(&name.as_str(), &search_path) } } @@ -1202,9 +1236,9 @@ fn add_local_native_libraries(cmd: &mut Linker, // Rust crates are not considered at all when creating an rlib output. All // dependencies will be linked when producing the final output (instead of // the intermediate rlib version) -fn add_upstream_rust_crates(cmd: &mut Linker, +fn add_upstream_rust_crates(cmd: &mut dyn Linker, sess: &Session, - trans: &CrateTranslation, + codegen_results: &CodegenResults, crate_type: config::CrateType, tmpdir: &Path) { // All of the heavy lifting has previously been accomplished by the @@ -1220,7 +1254,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // Invoke get_used_crates to ensure that we get a topological sorting of // crates. - let deps = &trans.crate_info.used_crates_dynamic; + let deps = &codegen_results.crate_info.used_crates_dynamic; // There's a few internal crates in the standard library (aka libcore and // libstd) which actually have a circular dependence upon one another. This @@ -1243,7 +1277,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, let mut group_end = None; let mut group_start = None; let mut end_with = FxHashSet(); - let info = &trans.crate_info; + let info = &codegen_results.crate_info; for &(cnum, _) in deps.iter().rev() { if let Some(missing) = info.missing_lang_items.get(&cnum) { end_with.extend(missing.iter().cloned()); @@ -1275,24 +1309,24 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // We may not pass all crates through to the linker. Some crates may // appear statically in an existing dylib, meaning we'll pick up all the // symbols from the dylib. - let src = &trans.crate_info.used_crate_source[&cnum]; + let src = &codegen_results.crate_info.used_crate_source[&cnum]; match data[cnum.as_usize() - 1] { - _ if trans.crate_info.profiler_runtime == Some(cnum) => { - add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); + _ if codegen_results.crate_info.profiler_runtime == Some(cnum) => { + add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); } - _ if trans.crate_info.sanitizer_runtime == Some(cnum) => { - link_sanitizer_runtime(cmd, sess, trans, tmpdir, cnum); + _ if codegen_results.crate_info.sanitizer_runtime == Some(cnum) => { + link_sanitizer_runtime(cmd, sess, codegen_results, tmpdir, cnum); } // compiler-builtins are always placed last to ensure that they're // linked correctly. - _ if trans.crate_info.compiler_builtins == Some(cnum) => { + _ if codegen_results.crate_info.compiler_builtins == Some(cnum) => { assert!(compiler_builtins.is_none()); compiler_builtins = Some(cnum); } Linkage::NotLinked | Linkage::IncludedFromDylib => {} Linkage::Static => { - add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); + add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); } Linkage::Dynamic => { add_dynamic_crate(cmd, sess, &src.dylib.as_ref().unwrap().0) @@ -1310,7 +1344,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // was already "included" in a dylib (e.g. `libstd` when `-C prefer-dynamic` // is used) if let Some(cnum) = compiler_builtins { - add_static_crate(cmd, sess, trans, tmpdir, crate_type, cnum); + add_static_crate(cmd, sess, codegen_results, tmpdir, crate_type, cnum); } // Converts a library file-stem into a cc -l argument @@ -1326,12 +1360,12 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // it's packed in a .rlib, it contains stuff that are not objects that will // make the linker error. So we must remove those bits from the .rlib before // linking it. - fn link_sanitizer_runtime(cmd: &mut Linker, + fn link_sanitizer_runtime(cmd: &mut dyn Linker, sess: &Session, - trans: &CrateTranslation, + codegen_results: &CodegenResults, tmpdir: &Path, cnum: CrateNum) { - let src = &trans.crate_info.used_crate_source[&cnum]; + let src = &codegen_results.crate_info.used_crate_source[&cnum]; let cratepath = &src.rlib.as_ref().unwrap().0; if sess.target.target.options.is_like_osx { @@ -1395,25 +1429,25 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // (aka we're making an executable), we can just pass the rlib blindly to // the linker (fast) because it's fine if it's not actually included as // we're at the end of the dependency chain. - fn add_static_crate(cmd: &mut Linker, + fn add_static_crate(cmd: &mut dyn Linker, sess: &Session, - trans: &CrateTranslation, + codegen_results: &CodegenResults, tmpdir: &Path, crate_type: config::CrateType, cnum: CrateNum) { - let src = &trans.crate_info.used_crate_source[&cnum]; + let src = &codegen_results.crate_info.used_crate_source[&cnum]; let cratepath = &src.rlib.as_ref().unwrap().0; // See the comment above in `link_staticlib` and `link_rlib` for why if // there's a static library that's not relevant we skip all object // files. - let native_libs = &trans.crate_info.native_libraries[&cnum]; + let native_libs = &codegen_results.crate_info.native_libraries[&cnum]; let skip_native = native_libs.iter().any(|lib| { lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib) }); if (!is_full_lto_enabled(sess) || - ignored_for_lto(sess, &trans.crate_info, cnum)) && + ignored_for_lto(sess, &codegen_results.crate_info, cnum)) && crate_type != config::CrateTypeDylib && !skip_native { cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath)); @@ -1469,7 +1503,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, let skip_because_lto = is_full_lto_enabled(sess) && is_rust_object && (sess.target.target.options.no_builtins || - !trans.crate_info.is_no_builtins.contains(&cnum)); + !codegen_results.crate_info.is_no_builtins.contains(&cnum)); if skip_because_cfg_say_so || skip_because_lto { archive.remove_file(&f); @@ -1491,7 +1525,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // compiler-builtins crate (e.g. compiler-rt) because it'll get // repeatedly linked anyway. if crate_type == config::CrateTypeDylib && - trans.crate_info.compiler_builtins != Some(cnum) { + codegen_results.crate_info.compiler_builtins != Some(cnum) { cmd.link_whole_rlib(&fix_windows_verbatim_for_gcc(&dst)); } else { cmd.link_rlib(&fix_windows_verbatim_for_gcc(&dst)); @@ -1500,7 +1534,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker, } // Same thing as above, but for dynamic crates instead of static crates. - fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) { + fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { // If we're performing LTO, then it should have been previously required // that all upstream rust dependencies were available in an rlib format. assert!(!is_full_lto_enabled(sess)); @@ -1535,9 +1569,9 @@ fn add_upstream_rust_crates(cmd: &mut Linker, // generic function calls a native function, then the generic function must // be instantiated in the target crate, meaning that the native symbol must // also be resolved in the target crate. -fn add_upstream_native_libraries(cmd: &mut Linker, +fn add_upstream_native_libraries(cmd: &mut dyn Linker, sess: &Session, - trans: &CrateTranslation, + codegen_results: &CodegenResults, crate_type: config::CrateType) { // Be sure to use a topological sorting of crates because there may be // interdependencies between native libraries. When passing -nodefaultlibs, @@ -1551,22 +1585,26 @@ fn add_upstream_native_libraries(cmd: &mut Linker, let formats = sess.dependency_formats.borrow(); let data = formats.get(&crate_type).unwrap(); - let crates = &trans.crate_info.used_crates_static; + let crates = &codegen_results.crate_info.used_crates_static; for &(cnum, _) in crates { - for lib in trans.crate_info.native_libraries[&cnum].iter() { + for lib in codegen_results.crate_info.native_libraries[&cnum].iter() { + let name = match lib.name { + Some(ref l) => l, + None => continue, + }; if !relevant_lib(sess, &lib) { continue } match lib.kind { - NativeLibraryKind::NativeUnknown => cmd.link_dylib(&lib.name.as_str()), - NativeLibraryKind::NativeFramework => cmd.link_framework(&lib.name.as_str()), + NativeLibraryKind::NativeUnknown => cmd.link_dylib(&name.as_str()), + NativeLibraryKind::NativeFramework => cmd.link_framework(&name.as_str()), NativeLibraryKind::NativeStaticNobundle => { // Link "static-nobundle" native libs only if the crate they originate from // is being linked statically to the current crate. If it's linked dynamically // or is an rlib already included via some other dylib crate, the symbols from // native libs will have already been included in that dylib. if data[cnum.as_usize() - 1] == Linkage::Static { - cmd.link_staticlib(&lib.name.as_str()) + cmd.link_staticlib(&name.as_str()) } }, // ignore statically included native libraries here as we've diff --git a/src/librustc_trans/back/linker.rs b/src/librustc_codegen_llvm/back/linker.rs similarity index 87% rename from src/librustc_trans/back/linker.rs rename to src/librustc_codegen_llvm/back/linker.rs index ea3f5b408604e..f5bd31a67e5ce 100644 --- a/src/librustc_trans/back/linker.rs +++ b/src/librustc_codegen_llvm/back/linker.rs @@ -21,7 +21,8 @@ use back::symbol_export; use rustc::hir::def_id::{LOCAL_CRATE, CrateNum}; use rustc::middle::dependency_format::Linkage; use rustc::session::Session; -use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel}; +use rustc::session::config::{self, CrateType, OptLevel, DebugInfoLevel, + CrossLangLto}; use rustc::ty::TyCtxt; use rustc_target::spec::{LinkerFlavor, LldFlavor}; use serialize::{json, Encoder}; @@ -43,7 +44,7 @@ impl LinkerInfo { pub fn to_linker<'a>(&'a self, cmd: Command, - sess: &'a Session) -> Box { + sess: &'a Session) -> Box { match sess.linker_flavor() { LinkerFlavor::Lld(LldFlavor::Link) | LinkerFlavor::Msvc => { @@ -51,14 +52,14 @@ impl LinkerInfo { cmd, sess, info: self - }) as Box + }) as Box } LinkerFlavor::Em => { Box::new(EmLinker { cmd, sess, info: self - }) as Box + }) as Box } LinkerFlavor::Gcc => { Box::new(GccLinker { @@ -67,7 +68,7 @@ impl LinkerInfo { info: self, hinted_static: false, is_ld: false, - }) as Box + }) as Box } LinkerFlavor::Lld(LldFlavor::Ld) | @@ -79,13 +80,14 @@ impl LinkerInfo { info: self, hinted_static: false, is_ld: true, - }) as Box + }) as Box } LinkerFlavor::Lld(LldFlavor::Wasm) => { Box::new(WasmLd { cmd, - }) as Box + sess, + }) as Box } } } @@ -127,6 +129,7 @@ pub trait Linker { fn subsystem(&mut self, subsystem: &str); fn group_start(&mut self); fn group_end(&mut self); + fn cross_lang_lto(&mut self); // Should have been finalize(self), but we don't support self-by-value on trait objects (yet?). fn finalize(&mut self) -> Command; } @@ -180,11 +183,45 @@ impl<'a> GccLinker<'a> { self.hinted_static = false; } } + + fn push_cross_lang_lto_args(&mut self, plugin_path: Option<&OsStr>) { + if let Some(plugin_path) = plugin_path { + let mut arg = OsString::from("-plugin="); + arg.push(plugin_path); + self.linker_arg(&arg); + } + + let opt_level = match self.sess.opts.optimize { + config::OptLevel::No => "O0", + config::OptLevel::Less => "O1", + config::OptLevel::Default => "O2", + config::OptLevel::Aggressive => "O3", + config::OptLevel::Size => "Os", + config::OptLevel::SizeMin => "Oz", + }; + + self.linker_arg(&format!("-plugin-opt={}", opt_level)); + self.linker_arg(&format!("-plugin-opt=mcpu={}", self.sess.target_cpu())); + + match self.sess.opts.cg.lto { + config::Lto::Thin | + config::Lto::ThinLocal => { + self.linker_arg(&format!("-plugin-opt=thin")); + } + config::Lto::Fat | + config::Lto::Yes | + config::Lto::No => { + // default to regular LTO + } + } + } } impl<'a> Linker for GccLinker<'a> { - fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg("-l").arg(lib); } - fn link_staticlib(&mut self, lib: &str) { self.hint_static(); self.cmd.arg("-l").arg(lib); } + fn link_dylib(&mut self, lib: &str) { self.hint_dynamic(); self.cmd.arg(format!("-l{}",lib)); } + fn link_staticlib(&mut self, lib: &str) { + self.hint_static(); self.cmd.arg(format!("-l{}",lib)); + } fn link_rlib(&mut self, lib: &Path) { self.hint_static(); self.cmd.arg(lib); } fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } fn framework_path(&mut self, path: &Path) { self.cmd.arg("-F").arg(path); } @@ -192,15 +229,15 @@ impl<'a> Linker for GccLinker<'a> { fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } fn position_independent_executable(&mut self) { self.cmd.arg("-pie"); } fn no_position_independent_executable(&mut self) { self.cmd.arg("-no-pie"); } - fn full_relro(&mut self) { self.linker_arg("-z,relro,-z,now"); } - fn partial_relro(&mut self) { self.linker_arg("-z,relro"); } - fn no_relro(&mut self) { self.linker_arg("-z,norelro"); } + fn full_relro(&mut self) { self.linker_arg("-zrelro"); self.linker_arg("-znow"); } + fn partial_relro(&mut self) { self.linker_arg("-zrelro"); } + fn no_relro(&mut self) { self.linker_arg("-znorelro"); } fn build_static_executable(&mut self) { self.cmd.arg("-static"); } fn args(&mut self, args: &[String]) { self.cmd.args(args); } fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { self.hint_dynamic(); - self.cmd.arg("-l").arg(lib); + self.cmd.arg(format!("-l{}",lib)); } fn link_framework(&mut self, framework: &str) { @@ -218,23 +255,22 @@ impl<'a> Linker for GccLinker<'a> { self.hint_static(); let target = &self.sess.target.target; if !target.options.is_like_osx { - self.linker_arg("--whole-archive").cmd.arg("-l").arg(lib); + self.linker_arg("--whole-archive").cmd.arg(format!("-l{}",lib)); self.linker_arg("--no-whole-archive"); } else { // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. - let mut v = OsString::from("-force_load,"); - v.push(&archive::find_library(lib, search_path, &self.sess)); - self.linker_arg(&v); + self.linker_arg("-force_load"); + let lib = archive::find_library(lib, search_path, &self.sess); + self.linker_arg(&lib); } } fn link_whole_rlib(&mut self, lib: &Path) { self.hint_static(); if self.sess.target.target.options.is_like_osx { - let mut v = OsString::from("-force_load,"); - v.push(lib); - self.linker_arg(&v); + self.linker_arg("-force_load"); + self.linker_arg(&lib); } else { self.linker_arg("--whole-archive").cmd.arg(lib); self.linker_arg("--no-whole-archive"); @@ -259,8 +295,7 @@ impl<'a> Linker for GccLinker<'a> { if self.sess.target.target.options.is_like_osx { self.linker_arg("-dead_strip"); } else if self.sess.target.target.options.is_like_solaris { - self.linker_arg("-z"); - self.linker_arg("ignore"); + self.linker_arg("-zignore"); // If we're building a dylib, we don't use --gc-sections because LLVM // has already done the best it can do, and we also don't want to @@ -334,7 +369,8 @@ impl<'a> Linker for GccLinker<'a> { // the right `-Wl,-install_name` with an `@rpath` in it. if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { - let mut v = OsString::from("-install_name,@rpath/"); + self.linker_arg("-install_name"); + let mut v = OsString::from("@rpath/"); v.push(out_filename.file_name().unwrap()); self.linker_arg(&v); } @@ -413,7 +449,8 @@ impl<'a> Linker for GccLinker<'a> { } fn subsystem(&mut self, subsystem: &str) { - self.linker_arg(&format!("--subsystem,{}", subsystem)); + self.linker_arg("--subsystem"); + self.linker_arg(&subsystem); } fn finalize(&mut self) -> Command { @@ -434,6 +471,20 @@ impl<'a> Linker for GccLinker<'a> { self.linker_arg("--end-group"); } } + + fn cross_lang_lto(&mut self) { + match self.sess.opts.debugging_opts.cross_lang_lto { + CrossLangLto::Disabled => { + // Nothing to do + } + CrossLangLto::LinkerPluginAuto => { + self.push_cross_lang_lto_args(None); + } + CrossLangLto::LinkerPlugin(ref path) => { + self.push_cross_lang_lto_args(Some(path.as_os_str())); + } + } + } } pub struct MsvcLinker<'a> { @@ -603,7 +654,7 @@ impl<'a> Linker for MsvcLinker<'a> { // // The linker will read this `*.def` file and export all the symbols from // the dynamic library. Note that this is not as simple as just exporting - // all the symbols in the current crate (as specified by `trans.reachable`) + // all the symbols in the current crate (as specified by `codegen.reachable`) // but rather we also need to possibly export the symbols of upstream // crates. Upstream rlibs may be linked statically to this dynamic library, // in which case they may continue to transitively be used and hence need @@ -666,6 +717,10 @@ impl<'a> Linker for MsvcLinker<'a> { // MSVC doesn't need group indicators fn group_start(&mut self) {} fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing + } } pub struct EmLinker<'a> { @@ -832,6 +887,10 @@ impl<'a> Linker for EmLinker<'a> { // Appears not necessary on Emscripten fn group_start(&mut self) {} fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing + } } fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { @@ -863,11 +922,12 @@ fn exported_symbols(tcx: TyCtxt, crate_type: CrateType) -> Vec { symbols } -pub struct WasmLd { +pub struct WasmLd<'a> { cmd: Command, + sess: &'a Session, } -impl Linker for WasmLd { +impl<'a> Linker for WasmLd<'a> { fn link_dylib(&mut self, lib: &str) { self.cmd.arg("-l").arg(lib); } @@ -932,9 +992,20 @@ impl Linker for WasmLd { } fn gc_sections(&mut self, _keep_metadata: bool) { + self.cmd.arg("--gc-sections"); } fn optimize(&mut self) { + self.cmd.arg(match self.sess.opts.optimize { + OptLevel::No => "-O0", + OptLevel::Less => "-O1", + OptLevel::Default => "-O2", + OptLevel::Aggressive => "-O3", + // Currently LLD doesn't support `Os` and `Oz`, so pass through `O2` + // instead. + OptLevel::Size => "-O2", + OptLevel::SizeMin => "-O2" + }); } fn pgo_gen(&mut self) { @@ -964,8 +1035,28 @@ impl Linker for WasmLd { // this isn't yet the bottleneck of compilation at all anyway. self.cmd.arg("--no-threads"); + // By default LLD only gives us one page of stack (64k) which is a + // little small. Default to a larger stack closer to other PC platforms + // (1MB) and users can always inject their own link-args to override this. self.cmd.arg("-z").arg("stack-size=1048576"); + // By default LLD's memory layout is: + // + // 1. First, a blank page + // 2. Next, all static data + // 3. Finally, the main stack (which grows down) + // + // This has the unfortunate consequence that on stack overflows you + // corrupt static data and can cause some exceedingly weird bugs. To + // help detect this a little sooner we instead request that the stack is + // placed before static data. + // + // This means that we'll generate slightly larger binaries as references + // to static data will take more bytes in the ULEB128 encoding, but + // stack overflow will be guaranteed to trap as it underflows instead of + // corrupting static data. + self.cmd.arg("--stack-first"); + // FIXME we probably shouldn't pass this but instead pass an explicit // whitelist of symbols we'll allow to be undefined. Unfortunately // though we can't handle symbols like `log10` that LLVM injects at a @@ -984,4 +1075,8 @@ impl Linker for WasmLd { // Not needed for now with LLD fn group_start(&mut self) {} fn group_end(&mut self) {} + + fn cross_lang_lto(&mut self) { + // Do nothing for now + } } diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs similarity index 87% rename from src/librustc_trans/back/lto.rs rename to src/librustc_codegen_llvm/back/lto.rs index 2a473f1ecbcc5..60b5cf2ec7651 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -21,7 +21,7 @@ use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config::{self, Lto}; use rustc::util::common::time_ext; use time_graph::Timeline; -use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource}; +use {ModuleCodegen, ModuleLlvm, ModuleKind, ModuleSource}; use libc; @@ -42,45 +42,45 @@ pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { } } -pub(crate) enum LtoModuleTranslation { +pub(crate) enum LtoModuleCodegen { Fat { - module: Option, + module: Option, _serialized_bitcode: Vec, }, Thin(ThinModule), } -impl LtoModuleTranslation { +impl LtoModuleCodegen { pub fn name(&self) -> &str { match *self { - LtoModuleTranslation::Fat { .. } => "everything", - LtoModuleTranslation::Thin(ref m) => m.name(), + LtoModuleCodegen::Fat { .. } => "everything", + LtoModuleCodegen::Thin(ref m) => m.name(), } } /// Optimize this module within the given codegen context. /// - /// This function is unsafe as it'll return a `ModuleTranslation` still - /// points to LLVM data structures owned by this `LtoModuleTranslation`. + /// This function is unsafe as it'll return a `ModuleCodegen` still + /// points to LLVM data structures owned by this `LtoModuleCodegen`. /// It's intended that the module returned is immediately code generated and /// dropped, and then this LTO module is dropped. pub(crate) unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline) - -> Result + -> Result { match *self { - LtoModuleTranslation::Fat { ref mut module, .. } => { - let trans = module.take().unwrap(); - let config = cgcx.config(trans.kind); - let llmod = trans.llvm().unwrap().llmod; - let tm = trans.llvm().unwrap().tm; + LtoModuleCodegen::Fat { ref mut module, .. } => { + let module = module.take().unwrap(); + let config = cgcx.config(module.kind); + let llmod = module.llvm().unwrap().llmod; + let tm = module.llvm().unwrap().tm; run_pass_manager(cgcx, tm, llmod, config, false); timeline.record("fat-done"); - Ok(trans) + Ok(module) } - LtoModuleTranslation::Thin(ref mut thin) => thin.optimize(cgcx, timeline), + LtoModuleCodegen::Thin(ref mut thin) => thin.optimize(cgcx, timeline), } } @@ -89,16 +89,16 @@ impl LtoModuleTranslation { pub fn cost(&self) -> u64 { match *self { // Only one module with fat LTO, so the cost doesn't matter. - LtoModuleTranslation::Fat { .. } => 0, - LtoModuleTranslation::Thin(ref m) => m.cost(), + LtoModuleCodegen::Fat { .. } => 0, + LtoModuleCodegen::Thin(ref m) => m.cost(), } } } pub(crate) fn run(cgcx: &CodegenContext, - modules: Vec, + modules: Vec, timeline: &mut Timeline) - -> Result, FatalError> + -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); let export_threshold = match cgcx.lto { @@ -201,11 +201,11 @@ pub(crate) fn run(cgcx: &CodegenContext, fn fat_lto(cgcx: &CodegenContext, diag_handler: &Handler, - mut modules: Vec, + mut modules: Vec, mut serialized_modules: Vec<(SerializedModule, CString)>, symbol_white_list: &[*const libc::c_char], timeline: &mut Timeline) - -> Result, FatalError> + -> Result, FatalError> { info!("going for a fat lto"); @@ -228,18 +228,18 @@ fn fat_lto(cgcx: &CodegenContext, (cost, i) }) .max() - .expect("must be trans'ing at least one module"); + .expect("must be codegen'ing at least one module"); let module = modules.remove(costliest_module); - let llmod = module.llvm().expect("can't lto pre-translated modules").llmod; + let llmod = module.llvm().expect("can't lto pre-codegened modules").llmod; info!("using {:?} as a base module", module.llmod_id); - // For all other modules we translated we'll need to link them into our own - // bitcode. All modules were translated in their own LLVM context, however, + // For all other modules we codegened we'll need to link them into our own + // bitcode. All modules were codegened in their own LLVM context, however, // and we want to move everything to the same LLVM context. Currently the // way we know of to do that is to serialize them to a string and them parse // them later. Not great but hey, that's why it's "fat" LTO, right? for module in modules { - let llvm = module.llvm().expect("can't lto pre-translated modules"); + let llvm = module.llvm().expect("can't lto pre-codegened modules"); let buffer = ModuleBuffer::new(llvm.llmod); let llmod_id = CString::new(&module.llmod_id[..]).unwrap(); serialized_modules.push((SerializedModule::Local(buffer), llmod_id)); @@ -284,7 +284,7 @@ fn fat_lto(cgcx: &CodegenContext, } timeline.record("passes"); - Ok(vec![LtoModuleTranslation::Fat { + Ok(vec![LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode, }]) @@ -344,14 +344,14 @@ impl Drop for Linker { /// /// With all that in mind, the function here is designed at specifically just /// calculating the *index* for ThinLTO. This index will then be shared amongst -/// all of the `LtoModuleTranslation` units returned below and destroyed once +/// all of the `LtoModuleCodegen` units returned below and destroyed once /// they all go out of scope. fn thin_lto(diag_handler: &Handler, - modules: Vec, + modules: Vec, serialized_modules: Vec<(SerializedModule, CString)>, symbol_white_list: &[*const libc::c_char], timeline: &mut Timeline) - -> Result, FatalError> + -> Result, FatalError> { unsafe { info!("going for that thin, thin LTO"); @@ -369,7 +369,7 @@ fn thin_lto(diag_handler: &Handler, // analysis! for (i, module) in modules.iter().enumerate() { info!("local module: {} - {}", i, module.llmod_id); - let llvm = module.llvm().expect("can't lto pretranslated module"); + let llvm = module.llvm().expect("can't lto precodegened module"); let name = CString::new(module.llmod_id.clone()).unwrap(); let buffer = ThinBuffer::new(llvm.llmod); thin_modules.push(llvm::ThinLTOModule { @@ -431,7 +431,7 @@ fn thin_lto(diag_handler: &Handler, // Throw our data in an `Arc` as we'll be sharing it across threads. We // also put all memory referenced by the C++ data (buffers, ids, etc) // into the arc as well. After this we'll create a thin module - // translation per module in this data. + // codegen per module in this data. let shared = Arc::new(ThinShared { data, thin_buffers, @@ -439,7 +439,7 @@ fn thin_lto(diag_handler: &Handler, module_names, }); Ok((0..shared.module_names.len()).map(|i| { - LtoModuleTranslation::Thin(ThinModule { + LtoModuleCodegen::Thin(ThinModule { shared: shared.clone(), idx: i, }) @@ -461,9 +461,12 @@ fn run_pass_manager(cgcx: &CodegenContext, unsafe { let pm = llvm::LLVMCreatePassManager(); llvm::LLVMRustAddAnalysisPasses(tm, pm, llmod); - let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); - assert!(!pass.is_null()); - llvm::LLVMRustAddPass(pm, pass); + + if config.verify_llvm_ir { + let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); + assert!(!pass.is_null()); + llvm::LLVMRustAddPass(pm, pass); + } // When optimizing for LTO we don't actually pass in `-O0`, but we force // it to always happen at least with `-O1`. @@ -482,7 +485,7 @@ fn run_pass_manager(cgcx: &CodegenContext, llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less, level => level, }; - with_llvm_pmb(llmod, config, opt_level, &mut |b| { + with_llvm_pmb(llmod, config, opt_level, false, &mut |b| { if thin { if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) { panic!("this version of LLVM does not support ThinLTO"); @@ -494,9 +497,11 @@ fn run_pass_manager(cgcx: &CodegenContext, } }); - let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); - assert!(!pass.is_null()); - llvm::LLVMRustAddPass(pm, pass); + if config.verify_llvm_ir { + let pass = llvm::LLVMRustFindAndCreatePass("verify\0".as_ptr() as *const _); + assert!(!pass.is_null()); + llvm::LLVMRustAddPass(pm, pass); + } time_ext(cgcx.time_passes, None, "LTO passes", || llvm::LLVMRunPassManager(pm, llmod)); @@ -622,7 +627,7 @@ impl ThinModule { } unsafe fn optimize(&mut self, cgcx: &CodegenContext, timeline: &mut Timeline) - -> Result + -> Result { let diag_handler = cgcx.create_diag_handler(); let tm = (cgcx.tm_factory)().map_err(|e| { @@ -632,7 +637,7 @@ impl ThinModule { // Right now the implementation we've got only works over serialized // modules, so we create a fresh new LLVM context and parse the module // into that context. One day, however, we may do this for upstream - // crates but for locally translated modules we may be able to reuse + // crates but for locally codegened modules we may be able to reuse // that LLVM Context and Module. let llcx = llvm::LLVMRustContextCreate(cgcx.fewer_names); let llmod = llvm::LLVMRustParseBitcodeForThinLTO( @@ -645,8 +650,8 @@ impl ThinModule { let msg = format!("failed to parse bitcode for thin LTO module"); return Err(write::llvm_err(&diag_handler, msg)); } - let mtrans = ModuleTranslation { - source: ModuleSource::Translated(ModuleLlvm { + let module = ModuleCodegen { + source: ModuleSource::Codegened(ModuleLlvm { llmod, llcx, tm, @@ -655,7 +660,7 @@ impl ThinModule { name: self.name().to_string(), kind: ModuleKind::Regular, }; - cgcx.save_temp_bitcode(&mtrans, "thin-lto-input"); + cgcx.save_temp_bitcode(&module, "thin-lto-input"); // Before we do much else find the "main" `DICompileUnit` that we'll be // using below. If we find more than one though then rustc has changed @@ -673,7 +678,7 @@ impl ThinModule { // are disabled by removing all landing pads. if cgcx.no_landing_pads { llvm::LLVMRustMarkAllFunctionsNounwind(llmod); - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-nounwind"); + cgcx.save_temp_bitcode(&module, "thin-lto-after-nounwind"); timeline.record("nounwind"); } @@ -689,25 +694,25 @@ impl ThinModule { let msg = format!("failed to prepare thin LTO module"); return Err(write::llvm_err(&diag_handler, msg)) } - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-rename"); + cgcx.save_temp_bitcode(&module, "thin-lto-after-rename"); timeline.record("rename"); if !llvm::LLVMRustPrepareThinLTOResolveWeak(self.shared.data.0, llmod) { let msg = format!("failed to prepare thin LTO module"); return Err(write::llvm_err(&diag_handler, msg)) } - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-resolve"); + cgcx.save_temp_bitcode(&module, "thin-lto-after-resolve"); timeline.record("resolve"); if !llvm::LLVMRustPrepareThinLTOInternalize(self.shared.data.0, llmod) { let msg = format!("failed to prepare thin LTO module"); return Err(write::llvm_err(&diag_handler, msg)) } - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-internalize"); + cgcx.save_temp_bitcode(&module, "thin-lto-after-internalize"); timeline.record("internalize"); if !llvm::LLVMRustPrepareThinLTOImport(self.shared.data.0, llmod) { let msg = format!("failed to prepare thin LTO module"); return Err(write::llvm_err(&diag_handler, msg)) } - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-import"); + cgcx.save_temp_bitcode(&module, "thin-lto-after-import"); timeline.record("import"); // Ok now this is a bit unfortunate. This is also something you won't @@ -740,7 +745,7 @@ impl ThinModule { // so it appears). Hopefully we can remove this once upstream bugs are // fixed in LLVM. llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-patch"); + cgcx.save_temp_bitcode(&module, "thin-lto-after-patch"); timeline.record("patch"); // Alright now that we've done everything related to the ThinLTO @@ -748,26 +753,12 @@ impl ThinModule { // `run_pass_manager` as the "fat" LTO above except that we tell it to // populate a thin-specific pass manager, which presumably LLVM treats a // little differently. - info!("running thin lto passes over {}", mtrans.name); - let config = cgcx.config(mtrans.kind); + info!("running thin lto passes over {}", module.name); + let config = cgcx.config(module.kind); run_pass_manager(cgcx, tm, llmod, config, true); - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-pm"); + cgcx.save_temp_bitcode(&module, "thin-lto-after-pm"); timeline.record("thin-done"); - // FIXME: this is a hack around a bug in LLVM right now. Discovered in - // #46910 it was found out that on 32-bit MSVC LLVM will hit a codegen - // error if there's an available_externally function in the LLVM module. - // Typically we don't actually use these functions but ThinLTO makes - // heavy use of them when inlining across modules. - // - // Tracked upstream at https://bugs.llvm.org/show_bug.cgi?id=35736 this - // function call (and its definition on the C++ side of things) - // shouldn't be necessary eventually and we can safetly delete these few - // lines. - llvm::LLVMRustThinLTORemoveAvailableExternally(llmod); - cgcx.save_temp_bitcode(&mtrans, "thin-lto-after-rm-ae"); - timeline.record("no-ae"); - - Ok(mtrans) + Ok(module) } } diff --git a/src/librustc_trans/back/rpath.rs b/src/librustc_codegen_llvm/back/rpath.rs similarity index 96% rename from src/librustc_trans/back/rpath.rs rename to src/librustc_codegen_llvm/back/rpath.rs index 8e5e7d376488b..2c3a143646c24 100644 --- a/src/librustc_trans/back/rpath.rs +++ b/src/librustc_codegen_llvm/back/rpath.rs @@ -22,7 +22,7 @@ pub struct RPathConfig<'a> { pub is_like_osx: bool, pub has_rpath: bool, pub linker_is_gnu: bool, - pub get_install_prefix_lib_path: &'a mut FnMut() -> PathBuf, + pub get_install_prefix_lib_path: &'a mut dyn FnMut() -> PathBuf, } pub fn get_rpath_flags(config: &mut RPathConfig) -> Vec { @@ -114,8 +114,8 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig, lib: &Path) -> String let mut output = cwd.join(&config.out_filename); output.pop(); let output = fs::canonicalize(&output).unwrap_or(output); - let relative = path_relative_from(&lib, &output) - .expect(&format!("couldn't create relative path from {:?} to {:?}", output, lib)); + let relative = path_relative_from(&lib, &output).unwrap_or_else(|| + panic!("couldn't create relative path from {:?} to {:?}", output, lib)); // FIXME (#9639): This needs to handle non-utf8 paths format!("{}/{}", prefix, relative.to_str().expect("non-utf8 component in path")) @@ -152,9 +152,7 @@ fn path_relative_from(path: &Path, base: &Path) -> Option { (Some(_), Some(b)) if b == Component::ParentDir => return None, (Some(a), Some(_)) => { comps.push(Component::ParentDir); - for _ in itb { - comps.push(Component::ParentDir); - } + comps.extend(itb.map(|_| Component::ParentDir)); comps.push(a); comps.extend(ita.by_ref()); break; diff --git a/src/librustc_trans/back/symbol_export.rs b/src/librustc_codegen_llvm/back/symbol_export.rs similarity index 94% rename from src/librustc_trans/back/symbol_export.rs rename to src/librustc_codegen_llvm/back/symbol_export.rs index d8520b61d9157..48de2f3beedfb 100644 --- a/src/librustc_trans/back/symbol_export.rs +++ b/src/librustc_codegen_llvm/back/symbol_export.rs @@ -13,13 +13,13 @@ use std::sync::Arc; use monomorphize::Instance; use rustc::hir; -use rustc::hir::TransFnAttrFlags; +use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE, CRATE_DEF_INDEX}; use rustc::ich::Fingerprint; use rustc::middle::exported_symbols::{SymbolExportLevel, ExportedSymbol, metadata_symbol_name}; use rustc::session::config; use rustc::ty::{TyCtxt, SymbolName}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::subst::Substs; use rustc::util::nodemap::{FxHashMap, DefIdMap}; use rustc_allocator::ALLOCATOR_METHODS; @@ -63,7 +63,7 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { assert_eq!(cnum, LOCAL_CRATE); - if !tcx.sess.opts.output_types.should_trans() { + if !tcx.sess.opts.output_types.should_codegen() { return Lrc::new(DefIdMap()) } @@ -105,11 +105,11 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // Only consider nodes that actually have exported symbols. hir::map::NodeItem(&hir::Item { - node: hir::ItemStatic(..), + node: hir::ItemKind::Static(..), .. }) | hir::map::NodeItem(&hir::Item { - node: hir::ItemFn(..), .. + node: hir::ItemKind::Fn(..), .. }) | hir::map::NodeImplItem(&hir::ImplItem { node: hir::ImplItemKind::Method(..), @@ -117,8 +117,8 @@ fn reachable_non_generics_provider<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) => { let def_id = tcx.hir.local_def_id(node_id); let generics = tcx.generics_of(def_id); - if (generics.parent_types == 0 && generics.types.is_empty()) && - // Functions marked with #[inline] are only ever translated + if !generics.requires_monomorphization(tcx) && + // Functions marked with #[inline] are only ever codegened // with "internal" linkage and are never exported. !Instance::mono(tcx, def_id).def.requires_local(tcx) { Some(def_id) @@ -195,7 +195,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, { assert_eq!(cnum, LOCAL_CRATE); - if !tcx.sess.opts.output_types.should_trans() { + if !tcx.sess.opts.output_types.should_codegen() { return Arc::new(vec![]) } @@ -206,9 +206,8 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }) .collect(); - if let Some(_) = *tcx.sess.entry_fn.borrow() { - let symbol_name = "main".to_string(); - let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new(&symbol_name)); + if tcx.sess.entry_fn.borrow().is_some() { + let exported_symbol = ExportedSymbol::NoDefId(SymbolName::new("main")); symbols.push((exported_symbol, SymbolExportLevel::C)); } @@ -255,7 +254,7 @@ fn exported_symbols_provider_local<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let need_visibility = tcx.sess.target.target.options.dynamic_linking && !tcx.sess.target.target.options.only_cdylib; - let (_, cgus) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); + let (_, cgus) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); for (mono_item, &(linkage, visibility)) in cgus.iter() .flat_map(|cgu| cgu.items().iter()) { @@ -383,9 +382,10 @@ fn symbol_export_level(tcx: TyCtxt, sym_def_id: DefId) -> SymbolExportLevel { // special symbols in the standard library for various plumbing between // core/std/allocators/etc. For example symbols used to hook up allocation // are not considered for export - let trans_fn_attrs = tcx.trans_fn_attrs(sym_def_id); - let is_extern = trans_fn_attrs.contains_extern_indicator(); - let std_internal = trans_fn_attrs.flags.contains(TransFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); + let codegen_fn_attrs = tcx.codegen_fn_attrs(sym_def_id); + let is_extern = codegen_fn_attrs.contains_extern_indicator(); + let std_internal = + codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); if is_extern && !std_internal { SymbolExportLevel::C diff --git a/src/librustc_trans/back/wasm.rs b/src/librustc_codegen_llvm/back/wasm.rs similarity index 76% rename from src/librustc_trans/back/wasm.rs rename to src/librustc_codegen_llvm/back/wasm.rs index d6d386c9fbe77..f37854b7bcae0 100644 --- a/src/librustc_trans/back/wasm.rs +++ b/src/librustc_codegen_llvm/back/wasm.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::BTreeMap; use std::fs; use std::path::Path; use std::str; @@ -24,45 +23,6 @@ const WASM_EXTERNAL_KIND_TABLE: u8 = 1; const WASM_EXTERNAL_KIND_MEMORY: u8 = 2; const WASM_EXTERNAL_KIND_GLOBAL: u8 = 3; -/// Append all the custom sections listed in `sections` to the wasm binary -/// specified at `path`. -/// -/// LLVM 6 which we're using right now doesn't have the ability to create custom -/// sections in wasm files nor does LLD have the ability to merge these sections -/// into one larger section when linking. It's expected that this will -/// eventually get implemented, however! -/// -/// Until that time though this is a custom implementation in rustc to append -/// all sections to a wasm file to the finished product that LLD produces. -/// -/// Support for this is landing in LLVM in https://reviews.llvm.org/D43097, -/// although after that support will need to be in LLD as well. -pub fn add_custom_sections(path: &Path, sections: &BTreeMap>) { - if sections.len() == 0 { - return - } - - let wasm = fs::read(path).expect("failed to read wasm output"); - - // see https://webassembly.github.io/spec/core/binary/modules.html#custom-section - let mut wasm = WasmEncoder { data: wasm }; - for (section, bytes) in sections { - // write the `id` identifier, 0 for a custom section - wasm.byte(0); - - // figure out how long our name descriptor will be - let mut name = WasmEncoder::new(); - name.str(section); - - // write the length of the payload followed by all its contents - wasm.u32((bytes.len() + name.data.len()) as u32); - wasm.data.extend_from_slice(&name.data); - wasm.data.extend_from_slice(bytes); - } - - fs::write(path, &wasm.data).expect("failed to write wasm output"); -} - /// Rewrite the module imports are listed from in a wasm module given the field /// name to module name mapping in `import_map`. /// @@ -74,13 +34,13 @@ pub fn add_custom_sections(path: &Path, sections: &BTreeMap>) { /// /// This function is intended as a hack for now where we manually rewrite the /// wasm output by LLVM to have the correct import modules listed. The -/// `#[wasm_import_module]` attribute in Rust translates to the module that each -/// symbol is imported from, so here we manually go through the wasm file, -/// decode it, rewrite imports, and then rewrite the wasm module. +/// `#[link(wasm_import_module = "...")]` attribute in Rust translates to the +/// module that each symbol is imported from, so here we manually go through the +/// wasm file, decode it, rewrite imports, and then rewrite the wasm module. /// /// Support for this was added to LLVM in /// https://github.com/llvm-mirror/llvm/commit/0f32e1365, although support still -/// needs to be added (AFAIK at the time of this writing) to LLD +/// needs to be added, tracked at https://bugs.llvm.org/show_bug.cgi?id=37168 pub fn rewrite_imports(path: &Path, import_map: &FxHashMap) { if import_map.len() == 0 { return @@ -230,8 +190,7 @@ impl WasmEncoder { } fn u32(&mut self, val: u32) { - let at = self.data.len(); - leb128::write_u32_leb128(&mut self.data, at, val); + leb128::write_u32_leb128(&mut self.data, val); } fn byte(&mut self, val: u8) { diff --git a/src/librustc_trans/back/write.rs b/src/librustc_codegen_llvm/back/write.rs similarity index 91% rename from src/librustc_trans/back/write.rs rename to src/librustc_codegen_llvm/back/write.rs index 148e3d0025c83..d36142af56c65 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_codegen_llvm/back/write.rs @@ -17,8 +17,8 @@ use back::linker::LinkerInfo; use back::symbol_export::ExportedSymbols; use base; use consts; -use rustc_incremental::{save_trans_partition, in_incr_comp_dir}; -use rustc::dep_graph::{DepGraph, WorkProductFileKind}; +use rustc_incremental::{copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir}; +use rustc::dep_graph::{WorkProduct, WorkProductId, WorkProductFileKind}; use rustc::middle::cstore::{LinkMeta, EncodedMetadata}; use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses, AllPasses, Sanitizer, Lto}; @@ -28,7 +28,7 @@ use time_graph::{self, TimeGraph, Timeline}; use llvm; use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef}; use llvm::{SMDiagnosticRef, ContextRef}; -use {CrateTranslation, ModuleSource, ModuleTranslation, CompiledModule, ModuleKind}; +use {CodegenResults, ModuleSource, ModuleCodegen, CompiledModule, ModuleKind}; use CrateInfo; use rustc::hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc::ty::TyCtxt; @@ -140,7 +140,7 @@ pub fn create_target_machine(sess: &Session, find_features: bool) -> TargetMachi // that `is_pie_binary` is false. When we discover LLVM target features // `sess.crate_types` is uninitialized so we cannot access it. pub fn target_machine_factory(sess: &Session, find_features: bool) - -> Arc Result + Send + Sync> + -> Arc Result + Send + Sync> { let reloc_model = get_reloc_model(sess); @@ -174,10 +174,7 @@ pub fn target_machine_factory(sess: &Session, find_features: bool) let triple = &sess.target.target.llvm_target; let triple = CString::new(triple.as_bytes()).unwrap(); - let cpu = match sess.opts.cg.target_cpu { - Some(ref s) => &**s, - None => &*sess.target.target.options.cpu - }; + let cpu = sess.target_cpu(); let cpu = CString::new(cpu.as_bytes()).unwrap(); let features = attributes::llvm_target_features(sess) .collect::>() @@ -235,7 +232,7 @@ pub struct ModuleConfig { emit_obj: bool, // Miscellaneous flags. These are mostly copied from command-line // options. - no_verify: bool, + pub verify_llvm_ir: bool, no_prepopulate_passes: bool, no_builtins: bool, time_passes: bool, @@ -274,7 +271,7 @@ impl ModuleConfig { embed_bitcode_marker: false, no_integrated_as: false, - no_verify: false, + verify_llvm_ir: false, no_prepopulate_passes: false, no_builtins: false, time_passes: false, @@ -286,14 +283,15 @@ impl ModuleConfig { } fn set_flags(&mut self, sess: &Session, no_builtins: bool) { - self.no_verify = sess.no_verify(); + self.verify_llvm_ir = sess.verify_llvm_ir(); self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes; self.no_builtins = no_builtins || sess.target.target.options.no_builtins; self.time_passes = sess.time_passes(); self.inline_threshold = sess.opts.cg.inline_threshold; - self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; + self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode || + sess.opts.debugging_opts.cross_lang_lto.enabled(); let embed_bitcode = sess.target.target.options.embed_bitcode || - sess.opts.debugging_opts.embed_bitcode; + sess.opts.debugging_opts.embed_bitcode; if embed_bitcode { match sess.opts.optimize { config::OptLevel::No | @@ -345,7 +343,7 @@ pub struct CodegenContext { regular_module_config: Arc, metadata_module_config: Arc, allocator_module_config: Arc, - pub tm_factory: Arc Result + Send + Sync>, + pub tm_factory: Arc Result + Send + Sync>, pub msvc_imps_needed: bool, pub target_pointer_width: String, debuginfo: config::DebugInfoLevel, @@ -364,7 +362,7 @@ pub struct CodegenContext { // compiling incrementally pub incr_comp_session_dir: Option, // Channel back to the main control thread to send messages to - coordinator_send: Sender>, + coordinator_send: Sender>, // A reference to the TimeGraph so we can register timings. None means that // measuring is disabled. time_graph: Option, @@ -385,23 +383,23 @@ impl CodegenContext { } } - pub(crate) fn save_temp_bitcode(&self, trans: &ModuleTranslation, name: &str) { + pub(crate) fn save_temp_bitcode(&self, module: &ModuleCodegen, name: &str) { if !self.save_temps { return } unsafe { let ext = format!("{}.bc", name); - let cgu = Some(&trans.name[..]); + let cgu = Some(&module.name[..]); let path = self.output_filenames.temp_path_ext(&ext, cgu); let cstr = path2cstr(&path); - let llmod = trans.llvm().unwrap().llmod; + let llmod = module.llvm().unwrap().llmod; llvm::LLVMWriteBitcodeToFile(llmod, cstr.as_ptr()); } } } struct DiagnosticHandlers<'a> { - inner: Box<(&'a CodegenContext, &'a Handler)>, + data: *mut (&'a CodegenContext, &'a Handler), llcx: ContextRef, } @@ -409,24 +407,22 @@ impl<'a> DiagnosticHandlers<'a> { fn new(cgcx: &'a CodegenContext, handler: &'a Handler, llcx: ContextRef) -> DiagnosticHandlers<'a> { - let data = Box::new((cgcx, handler)); + let data = Box::into_raw(Box::new((cgcx, handler))); unsafe { - let arg = &*data as &(_, _) as *const _ as *mut _; - llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, arg); - llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, arg); - } - DiagnosticHandlers { - inner: data, - llcx: llcx, + llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, data as *mut _); + llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, data as *mut _); } + DiagnosticHandlers { data, llcx } } } impl<'a> Drop for DiagnosticHandlers<'a> { fn drop(&mut self) { + use std::ptr::null_mut; unsafe { - llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, 0 as *mut _); - llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, 0 as *mut _); + llvm::LLVMRustSetInlineAsmDiagnosticHandler(self.llcx, inline_asm_handler, null_mut()); + llvm::LLVMContextSetDiagnosticHandler(self.llcx, diagnostic_handler, null_mut()); + drop(Box::from_raw(self.data)); } } } @@ -493,13 +489,13 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo // Unsafe due to LLVM calls. unsafe fn optimize(cgcx: &CodegenContext, diag_handler: &Handler, - mtrans: &ModuleTranslation, + module: &ModuleCodegen, config: &ModuleConfig, timeline: &mut Timeline) -> Result<(), FatalError> { - let (llmod, llcx, tm) = match mtrans.source { - ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm), + let (llmod, llcx, tm) = match module.source { + ModuleSource::Codegened(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm), ModuleSource::Preexisting(_) => { bug!("optimize_and_codegen: called with ModuleSource::Preexisting") } @@ -507,7 +503,7 @@ unsafe fn optimize(cgcx: &CodegenContext, let _handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx); - let module_name = mtrans.name.clone(); + let module_name = module.name.clone(); let module_name = Some(&module_name[..]); if config.emit_no_opt_bc { @@ -544,12 +540,13 @@ unsafe fn optimize(cgcx: &CodegenContext, true }; - if !config.no_verify { assert!(addpass("verify")); } + if config.verify_llvm_ir { assert!(addpass("verify")); } if !config.no_prepopulate_passes { llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod); llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod); let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None); - with_llvm_pmb(llmod, &config, opt_level, &mut |b| { + let prepare_for_thin_lto = cgcx.lto == Lto::Thin || cgcx.lto == Lto::ThinLocal; + with_llvm_pmb(llmod, &config, opt_level, prepare_for_thin_lto, &mut |b| { llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm); llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm); }) @@ -595,12 +592,12 @@ unsafe fn optimize(cgcx: &CodegenContext, } fn generate_lto_work(cgcx: &CodegenContext, - modules: Vec) + modules: Vec) -> Vec<(WorkItem, u64)> { let mut timeline = cgcx.time_graph.as_ref().map(|tg| { - tg.start(TRANS_WORKER_TIMELINE, - TRANS_WORK_PACKAGE_KIND, + tg.start(CODEGEN_WORKER_TIMELINE, + CODEGEN_WORK_PACKAGE_KIND, "generate lto") }).unwrap_or(Timeline::noop()); let lto_modules = lto::run(cgcx, modules, &mut timeline) @@ -614,19 +611,19 @@ fn generate_lto_work(cgcx: &CodegenContext, unsafe fn codegen(cgcx: &CodegenContext, diag_handler: &Handler, - mtrans: ModuleTranslation, + module: ModuleCodegen, config: &ModuleConfig, timeline: &mut Timeline) -> Result { timeline.record("codegen"); - let (llmod, llcx, tm) = match mtrans.source { - ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm), + let (llmod, llcx, tm) = match module.source { + ModuleSource::Codegened(ref llvm) => (llvm.llmod, llvm.llcx, llvm.tm), ModuleSource::Preexisting(_) => { bug!("codegen: called with ModuleSource::Preexisting") } }; - let module_name = mtrans.name.clone(); + let module_name = module.name.clone(); let module_name = Some(&module_name[..]); let handlers = DiagnosticHandlers::new(cgcx, diag_handler, llcx); @@ -697,7 +694,7 @@ unsafe fn codegen(cgcx: &CodegenContext, if config.emit_bc_compressed { let dst = bc_out.with_extension(RLIB_BYTECODE_EXTENSION); - let data = bytecode::encode(&mtrans.llmod_id, data); + let data = bytecode::encode(&module.llmod_id, data); if let Err(e) = fs::write(&dst, data) { diag_handler.err(&format!("failed to write bytecode: {}", e)); } @@ -806,7 +803,7 @@ unsafe fn codegen(cgcx: &CodegenContext, } drop(handlers); - Ok(mtrans.into_compiled_module(config.emit_obj, + Ok(module.into_compiled_module(config.emit_obj, config.emit_bc, config.emit_bc_compressed, &cgcx.output_filenames)) @@ -841,13 +838,18 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, "rustc.embedded.module\0".as_ptr() as *const _, ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if cgcx.opts.target_triple.triple().contains("-ios") { + + let is_apple = cgcx.opts.target_triple.triple().contains("-ios") || + cgcx.opts.target_triple.triple().contains("-darwin"); + + let section = if is_apple { "__LLVM,__bitcode\0" } else { ".llvmbc\0" }; llvm::LLVMSetSection(llglobal, section.as_ptr() as *const _); llvm::LLVMRustSetLinkage(llglobal, llvm::Linkage::PrivateLinkage); + llvm::LLVMSetGlobalConstant(llglobal, llvm::True); let llconst = C_bytes_in_context(llcx, &[]); let llglobal = llvm::LLVMAddGlobal( @@ -856,7 +858,7 @@ unsafe fn embed_bitcode(cgcx: &CodegenContext, "rustc.embedded.cmdline\0".as_ptr() as *const _, ); llvm::LLVMSetInitializer(llglobal, llconst); - let section = if cgcx.opts.target_triple.triple().contains("-ios") { + let section = if is_apple { "__LLVM,__cmdline\0" } else { ".llvmcmd\0" @@ -876,13 +878,13 @@ fn need_crate_bitcode_for_rlib(sess: &Session) -> bool { sess.opts.output_types.contains_key(&OutputType::Exe) } -pub fn start_async_translation(tcx: TyCtxt, +pub fn start_async_codegen(tcx: TyCtxt, time_graph: Option, link: LinkMeta, metadata: EncodedMetadata, - coordinator_receive: Receiver>, + coordinator_receive: Receiver>, total_cgus: usize) - -> OngoingCrateTranslation { + -> OngoingCodegen { let sess = tcx.sess; let crate_name = tcx.crate_name(LOCAL_CRATE); let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins"); @@ -987,12 +989,12 @@ pub fn start_async_translation(tcx: TyCtxt, allocator_config.time_passes = false; let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); - let (trans_worker_send, trans_worker_receive) = channel(); + let (codegen_worker_send, codegen_worker_receive) = channel(); let coordinator_thread = start_executing_work(tcx, &crate_info, shared_emitter, - trans_worker_send, + codegen_worker_send, coordinator_receive, total_cgus, sess.jobserver.clone(), @@ -1001,7 +1003,7 @@ pub fn start_async_translation(tcx: TyCtxt, Arc::new(metadata_config), Arc::new(allocator_config)); - OngoingCrateTranslation { + OngoingCodegen { crate_name, link, metadata, @@ -1011,18 +1013,21 @@ pub fn start_async_translation(tcx: TyCtxt, time_graph, coordinator_send: tcx.tx_to_llvm_workers.lock().clone(), - trans_worker_receive, + codegen_worker_receive, shared_emitter_main, future: coordinator_thread, output_filenames: tcx.output_filenames(LOCAL_CRATE), } } -fn copy_module_artifacts_into_incr_comp_cache(sess: &Session, - dep_graph: &DepGraph, - compiled_modules: &CompiledModules) { +fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( + sess: &Session, + compiled_modules: &CompiledModules +) -> FxHashMap { + let mut work_products = FxHashMap::default(); + if sess.opts.incremental.is_none() { - return; + return work_products; } for module in compiled_modules.modules.iter() { @@ -1038,8 +1043,13 @@ fn copy_module_artifacts_into_incr_comp_cache(sess: &Session, files.push((WorkProductFileKind::BytecodeCompressed, path.clone())); } - save_trans_partition(sess, dep_graph, &module.name, &files); + if let Some((id, product)) = + copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files) { + work_products.insert(id, product); + } } + + work_products } fn produce_final_output_artifacts(sess: &Session, @@ -1192,15 +1202,15 @@ fn produce_final_output_artifacts(sess: &Session, // These are used in linking steps and will be cleaned up afterward. } -pub(crate) fn dump_incremental_data(trans: &CrateTranslation) { +pub(crate) fn dump_incremental_data(codegen_results: &CodegenResults) { println!("[incremental] Re-using {} out of {} modules", - trans.modules.iter().filter(|m| m.pre_existing).count(), - trans.modules.len()); + codegen_results.modules.iter().filter(|m| m.pre_existing).count(), + codegen_results.modules.len()); } enum WorkItem { - Optimize(ModuleTranslation), - LTO(lto::LtoModuleTranslation), + Optimize(ModuleCodegen), + LTO(lto::LtoModuleCodegen), } impl WorkItem { @@ -1221,7 +1231,7 @@ impl WorkItem { enum WorkItemResult { Compiled(CompiledModule), - NeedsLTO(ModuleTranslation), + NeedsLTO(ModuleCodegen), } fn execute_work_item(cgcx: &CodegenContext, @@ -1231,8 +1241,8 @@ fn execute_work_item(cgcx: &CodegenContext, { let diag_handler = cgcx.create_diag_handler(); let config = cgcx.config(work_item.kind()); - let mtrans = match work_item { - WorkItem::Optimize(mtrans) => mtrans, + let module = match work_item { + WorkItem::Optimize(module) => module, WorkItem::LTO(mut lto) => { unsafe { let module = lto.optimize(cgcx, timeline)?; @@ -1241,10 +1251,10 @@ fn execute_work_item(cgcx: &CodegenContext, } } }; - let module_name = mtrans.name.clone(); + let module_name = module.name.clone(); - let pre_existing = match mtrans.source { - ModuleSource::Translated(_) => None, + let pre_existing = match module.source { + ModuleSource::Codegened(_) => None, ModuleSource::Preexisting(ref wp) => Some(wp.clone()), }; @@ -1252,7 +1262,7 @@ fn execute_work_item(cgcx: &CodegenContext, let incr_comp_session_dir = cgcx.incr_comp_session_dir .as_ref() .unwrap(); - let name = &mtrans.name; + let name = &module.name; let mut object = None; let mut bytecode = None; let mut bytecode_compressed = None; @@ -1278,7 +1288,7 @@ fn execute_work_item(cgcx: &CodegenContext, let source_file = in_incr_comp_dir(&incr_comp_session_dir, &saved_file); debug!("copying pre-existing module `{}` from {:?} to {}", - mtrans.name, + module.name, source_file, obj_out.display()); match link_or_copy(&source_file, &obj_out) { @@ -1296,7 +1306,7 @@ fn execute_work_item(cgcx: &CodegenContext, assert_eq!(bytecode_compressed.is_some(), config.emit_bc_compressed); Ok(WorkItemResult::Compiled(CompiledModule { - llmod_id: mtrans.llmod_id.clone(), + llmod_id: module.llmod_id.clone(), name: module_name, kind: ModuleKind::Regular, pre_existing: true, @@ -1308,7 +1318,7 @@ fn execute_work_item(cgcx: &CodegenContext, debug!("llvm-optimizing {:?}", module_name); unsafe { - optimize(cgcx, &diag_handler, &mtrans, config, timeline)?; + optimize(cgcx, &diag_handler, &module, config, timeline)?; // After we've done the initial round of optimizations we need to // decide whether to synchronously codegen this module or ship it @@ -1316,7 +1326,7 @@ fn execute_work_item(cgcx: &CodegenContext, // has to wait for all the initial modules to be optimized). // // Here we dispatch based on the `cgcx.lto` and kind of module we're - // translating... + // codegenning... let needs_lto = match cgcx.lto { Lto::No => false, @@ -1341,19 +1351,24 @@ fn execute_work_item(cgcx: &CodegenContext, // Additionally here's where we also factor in the current LLVM // version. If it doesn't support ThinLTO we skip this. Lto::ThinLocal => { - mtrans.kind != ModuleKind::Allocator && + module.kind != ModuleKind::Allocator && llvm::LLVMRustThinLTOAvailable() } }; // Metadata modules never participate in LTO regardless of the lto // settings. - let needs_lto = needs_lto && mtrans.kind != ModuleKind::Metadata; + let needs_lto = needs_lto && module.kind != ModuleKind::Metadata; + + // Don't run LTO passes when cross-lang LTO is enabled. The linker + // will do that for us in this case. + let needs_lto = needs_lto && + !cgcx.opts.debugging_opts.cross_lang_lto.enabled(); if needs_lto { - Ok(WorkItemResult::NeedsLTO(mtrans)) + Ok(WorkItemResult::NeedsLTO(module)) } else { - let module = codegen(cgcx, &diag_handler, mtrans, config, timeline)?; + let module = codegen(cgcx, &diag_handler, module, config, timeline)?; Ok(WorkItemResult::Compiled(module)) } } @@ -1363,19 +1378,19 @@ fn execute_work_item(cgcx: &CodegenContext, enum Message { Token(io::Result), NeedsLTO { - result: ModuleTranslation, + result: ModuleCodegen, worker_id: usize, }, Done { result: Result, worker_id: usize, }, - TranslationDone { + CodegenDone { llvm_work_item: WorkItem, cost: u64, }, - TranslationComplete, - TranslateItem, + CodegenComplete, + CodegenItem, } struct Diagnostic { @@ -1387,15 +1402,15 @@ struct Diagnostic { #[derive(PartialEq, Clone, Copy, Debug)] enum MainThreadWorkerState { Idle, - Translating, + Codegenning, LLVMing, } fn start_executing_work(tcx: TyCtxt, crate_info: &CrateInfo, shared_emitter: SharedEmitter, - trans_worker_send: Sender, - coordinator_receive: Receiver>, + codegen_worker_send: Sender, + coordinator_receive: Receiver>, total_cgus: usize, jobserver: Client, time_graph: Option, @@ -1503,7 +1518,7 @@ fn start_executing_work(tcx: TyCtxt, // - Error reporting only can happen on the main thread because that's the // only place where we have access to the compiler `Session`. // - LLVM work can be done on any thread. - // - Translation can only happen on the main thread. + // - Codegen can only happen on the main thread. // - Each thread doing substantial work most be in possession of a `Token` // from the `Jobserver`. // - The compiler process always holds one `Token`. Any additional `Tokens` @@ -1519,7 +1534,7 @@ fn start_executing_work(tcx: TyCtxt, // any error messages it has received. It might even abort compilation if // has received a fatal error. In this case we rely on all other threads // being torn down automatically with the main thread. - // Since the main thread will often be busy doing translation work, error + // Since the main thread will often be busy doing codegen work, error // reporting will be somewhat delayed, since the message queue can only be // checked in between to work packages. // @@ -1535,10 +1550,10 @@ fn start_executing_work(tcx: TyCtxt, // thread about what work to do when, and it will spawn off LLVM worker // threads as open LLVM WorkItems become available. // - // The job of the main thread is to translate CGUs into LLVM work package + // The job of the main thread is to codegen CGUs into LLVM work package // (since the main thread is the only thread that can do this). The main // thread will block until it receives a message from the coordinator, upon - // which it will translate one CGU, send it to the coordinator and block + // which it will codegen one CGU, send it to the coordinator and block // again. This way the coordinator can control what the main thread is // doing. // @@ -1556,7 +1571,7 @@ fn start_executing_work(tcx: TyCtxt, // if possible. These two goals are at odds with each other: If memory // consumption were not an issue, we could just let the main thread produce // LLVM WorkItems at full speed, assuring maximal utilization of - // Tokens/LLVM worker threads. However, since translation usual is faster + // Tokens/LLVM worker threads. However, since codegen usual is faster // than LLVM processing, the queue of LLVM WorkItems would fill up and each // WorkItem potentially holds on to a substantial amount of memory. // @@ -1620,7 +1635,7 @@ fn start_executing_work(tcx: TyCtxt, // The final job the coordinator thread is responsible for is managing LTO // and how that works. When LTO is requested what we'll to is collect all // optimized LLVM modules into a local vector on the coordinator. Once all - // modules have been translated and optimized we hand this to the `lto` + // modules have been codegened and optimized we hand this to the `lto` // module for further optimization. The `lto` module will return back a list // of more modules to work on, which the coordinator will continue to spawn // work for. @@ -1646,15 +1661,15 @@ fn start_executing_work(tcx: TyCtxt, }; // This is where we collect codegen units that have gone all the way - // through translation and LLVM. + // through codegen and LLVM. let mut compiled_modules = vec![]; let mut compiled_metadata_module = None; let mut compiled_allocator_module = None; let mut needs_lto = Vec::new(); let mut started_lto = false; - // This flag tracks whether all items have gone through translations - let mut translation_done = false; + // This flag tracks whether all items have gone through codegens + let mut codegen_done = false; // This is the queue of LLVM work items that still need processing. let mut work_items = Vec::<(WorkItem, u64)>::new(); @@ -1670,23 +1685,23 @@ fn start_executing_work(tcx: TyCtxt, // Run the message loop while there's still anything that needs message // processing: - while !translation_done || + while !codegen_done || work_items.len() > 0 || running > 0 || needs_lto.len() > 0 || main_thread_worker_state != MainThreadWorkerState::Idle { - // While there are still CGUs to be translated, the coordinator has + // While there are still CGUs to be codegened, the coordinator has // to decide how to utilize the compiler processes implicit Token: - // For translating more CGU or for running them through LLVM. - if !translation_done { + // For codegenning more CGU or for running them through LLVM. + if !codegen_done { if main_thread_worker_state == MainThreadWorkerState::Idle { if !queue_full_enough(work_items.len(), running, max_workers) { - // The queue is not full enough, translate more items: - if let Err(_) = trans_worker_send.send(Message::TranslateItem) { - panic!("Could not send Message::TranslateItem to main thread") + // The queue is not full enough, codegen more items: + if let Err(_) = codegen_worker_send.send(Message::CodegenItem) { + panic!("Could not send Message::CodegenItem to main thread") } - main_thread_worker_state = MainThreadWorkerState::Translating; + main_thread_worker_state = MainThreadWorkerState::Codegenning; } else { // The queue is full enough to not let the worker // threads starve. Use the implicit Token to do some @@ -1704,7 +1719,7 @@ fn start_executing_work(tcx: TyCtxt, } } } else { - // If we've finished everything related to normal translation + // If we've finished everything related to normal codegen // then it must be the case that we've got some LTO work to do. // Perform the serial work here of figuring out what we're // going to LTO and then push a bunch of work items onto our @@ -1721,11 +1736,13 @@ fn start_executing_work(tcx: TyCtxt, .binary_search_by_key(&cost, |&(_, cost)| cost) .unwrap_or_else(|e| e); work_items.insert(insertion_index, (work, cost)); - helper.request_token(); + if !cgcx.opts.debugging_opts.no_parallel_llvm { + helper.request_token(); + } } } - // In this branch, we know that everything has been translated, + // In this branch, we know that everything has been codegened, // so it's just a matter of determining whether the implicit // Token is free to use for LLVM work. match main_thread_worker_state { @@ -1751,9 +1768,9 @@ fn start_executing_work(tcx: TyCtxt, main_thread_worker_state = MainThreadWorkerState::LLVMing; } } - MainThreadWorkerState::Translating => { - bug!("trans worker should not be translating after \ - translation was already completed") + MainThreadWorkerState::Codegenning => { + bug!("codegen worker should not be codegenning after \ + codegen was already completed") } MainThreadWorkerState::LLVMing => { // Already making good use of that token @@ -1795,7 +1812,7 @@ fn start_executing_work(tcx: TyCtxt, // If the main thread token is used for LLVM work // at the moment, we turn that thread into a regular // LLVM worker thread, so the main thread is free - // to react to translation demand. + // to react to codegen demand. main_thread_worker_state = MainThreadWorkerState::Idle; running += 1; } @@ -1809,7 +1826,7 @@ fn start_executing_work(tcx: TyCtxt, } } - Message::TranslationDone { llvm_work_item, cost } => { + Message::CodegenDone { llvm_work_item, cost } => { // We keep the queue sorted by estimated processing cost, // so that more expensive items are processed earlier. This // is good for throughput as it gives the main thread more @@ -1825,16 +1842,18 @@ fn start_executing_work(tcx: TyCtxt, }; work_items.insert(insertion_index, (llvm_work_item, cost)); - helper.request_token(); + if !cgcx.opts.debugging_opts.no_parallel_llvm { + helper.request_token(); + } assert_eq!(main_thread_worker_state, - MainThreadWorkerState::Translating); + MainThreadWorkerState::Codegenning); main_thread_worker_state = MainThreadWorkerState::Idle; } - Message::TranslationComplete => { - translation_done = true; + Message::CodegenComplete => { + codegen_done = true; assert_eq!(main_thread_worker_state, - MainThreadWorkerState::Translating); + MainThreadWorkerState::Codegenning); main_thread_worker_state = MainThreadWorkerState::Idle; } @@ -1885,8 +1904,8 @@ fn start_executing_work(tcx: TyCtxt, // Exit the coordinator thread return Err(()) } - Message::TranslateItem => { - bug!("the coordinator should not receive translation requests") + Message::CodegenItem => { + bug!("the coordinator should not receive codegen requests") } } } @@ -1917,7 +1936,7 @@ fn start_executing_work(tcx: TyCtxt, }); // A heuristic that determines if we have enough LLVM WorkItems in the - // queue so that the main thread can do LLVM work instead of translation + // queue so that the main thread can do LLVM work instead of codegen fn queue_full_enough(items_in_queue: usize, workers_running: usize, max_workers: usize) -> bool { @@ -1938,10 +1957,10 @@ fn start_executing_work(tcx: TyCtxt, } } -pub const TRANS_WORKER_ID: usize = ::std::usize::MAX; -pub const TRANS_WORKER_TIMELINE: time_graph::TimelineId = - time_graph::TimelineId(TRANS_WORKER_ID); -pub const TRANS_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = +pub const CODEGEN_WORKER_ID: usize = ::std::usize::MAX; +pub const CODEGEN_WORKER_TIMELINE: time_graph::TimelineId = + time_graph::TimelineId(CODEGEN_WORKER_ID); +pub const CODEGEN_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]); const LLVM_WORK_PACKAGE_KIND: time_graph::WorkPackageKind = time_graph::WorkPackageKind(&["#7DB67A", "#C6EEC4", "#ACDAAA", "#579354", "#3E6F3C"]); @@ -1955,7 +1974,7 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) { // Set up a destructor which will fire off a message that we're done as // we exit. struct Bomb { - coordinator_send: Sender>, + coordinator_send: Sender>, result: Option, worker_id: usize, } @@ -2034,7 +2053,8 @@ pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path, pub unsafe fn with_llvm_pmb(llmod: ModuleRef, config: &ModuleConfig, opt_level: llvm::CodeGenOptLevel, - f: &mut FnMut(llvm::PassManagerBuilderRef)) { + prepare_for_thin_lto: bool, + f: &mut dyn FnMut(llvm::PassManagerBuilderRef)) { use std::ptr; // Create the PassManagerBuilder for LLVM. We configure it with @@ -2061,6 +2081,7 @@ pub unsafe fn with_llvm_pmb(llmod: ModuleRef, config.merge_functions, config.vectorize_slp, config.vectorize_loop, + prepare_for_thin_lto, pgo_gen_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), pgo_use_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()), ); @@ -2212,7 +2233,7 @@ impl SharedEmitterMain { } } -pub struct OngoingCrateTranslation { +pub struct OngoingCodegen { crate_name: Symbol, link: LinkMeta, metadata: EncodedMetadata, @@ -2220,15 +2241,18 @@ pub struct OngoingCrateTranslation { linker_info: LinkerInfo, crate_info: CrateInfo, time_graph: Option, - coordinator_send: Sender>, - trans_worker_receive: Receiver, + coordinator_send: Sender>, + codegen_worker_receive: Receiver, shared_emitter_main: SharedEmitterMain, future: thread::JoinHandle>, output_filenames: Arc, } -impl OngoingCrateTranslation { - pub(crate) fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation { +impl OngoingCodegen { + pub(crate) fn join( + self, + sess: &Session + ) -> (CodegenResults, FxHashMap) { self.shared_emitter_main.check(sess, true); let compiled_modules = match self.future.join() { Ok(Ok(compiled_modules)) => compiled_modules, @@ -2237,7 +2261,7 @@ impl OngoingCrateTranslation { panic!("expected abort due to worker thread errors") }, Err(_) => { - sess.fatal("Error during translation/LLVM phase."); + sess.fatal("Error during codegen/LLVM phase."); } }; @@ -2247,9 +2271,9 @@ impl OngoingCrateTranslation { time_graph.dump(&format!("{}-timings", self.crate_name)); } - copy_module_artifacts_into_incr_comp_cache(sess, - dep_graph, - &compiled_modules); + let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir(sess, + &compiled_modules); + produce_final_output_artifacts(sess, &compiled_modules, &self.output_filenames); @@ -2260,7 +2284,7 @@ impl OngoingCrateTranslation { unsafe { llvm::LLVMRustPrintPassTimings(); } } - let trans = CrateTranslation { + (CodegenResults { crate_name: self.crate_name, link: self.link, metadata: self.metadata, @@ -2271,35 +2295,33 @@ impl OngoingCrateTranslation { modules: compiled_modules.modules, allocator_module: compiled_modules.allocator_module, metadata_module: compiled_modules.metadata_module, - }; - - trans + }, work_products) } - pub(crate) fn submit_pre_translated_module_to_llvm(&self, + pub(crate) fn submit_pre_codegened_module_to_llvm(&self, tcx: TyCtxt, - mtrans: ModuleTranslation) { - self.wait_for_signal_to_translate_item(); + module: ModuleCodegen) { + self.wait_for_signal_to_codegen_item(); self.check_for_errors(tcx.sess); // These are generally cheap and won't through off scheduling. let cost = 0; - submit_translated_module_to_llvm(tcx, mtrans, cost); + submit_codegened_module_to_llvm(tcx, module, cost); } - pub fn translation_finished(&self, tcx: TyCtxt) { - self.wait_for_signal_to_translate_item(); + pub fn codegen_finished(&self, tcx: TyCtxt) { + self.wait_for_signal_to_codegen_item(); self.check_for_errors(tcx.sess); - drop(self.coordinator_send.send(Box::new(Message::TranslationComplete))); + drop(self.coordinator_send.send(Box::new(Message::CodegenComplete))); } pub fn check_for_errors(&self, sess: &Session) { self.shared_emitter_main.check(sess, false); } - pub fn wait_for_signal_to_translate_item(&self) { - match self.trans_worker_receive.recv() { - Ok(Message::TranslateItem) => { + pub fn wait_for_signal_to_codegen_item(&self) { + match self.codegen_worker_receive.recv() { + Ok(Message::CodegenItem) => { // Nothing to do } Ok(_) => panic!("unexpected message"), @@ -2311,11 +2333,11 @@ impl OngoingCrateTranslation { } } -pub(crate) fn submit_translated_module_to_llvm(tcx: TyCtxt, - mtrans: ModuleTranslation, +pub(crate) fn submit_codegened_module_to_llvm(tcx: TyCtxt, + module: ModuleCodegen, cost: u64) { - let llvm_work_item = WorkItem::Optimize(mtrans); - drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::TranslationDone { + let llvm_work_item = WorkItem::Optimize(module); + drop(tcx.tx_to_llvm_workers.lock().send(Box::new(Message::CodegenDone { llvm_work_item, cost, }))); diff --git a/src/librustc_trans/base.rs b/src/librustc_codegen_llvm/base.rs similarity index 82% rename from src/librustc_trans/base.rs rename to src/librustc_codegen_llvm/base.rs index b756a6695f941..223c04f420f3f 100644 --- a/src/librustc_trans/base.rs +++ b/src/librustc_codegen_llvm/base.rs @@ -8,14 +8,14 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Translate the completed AST to the LLVM IR. +//! Codegen the completed AST to the LLVM IR. //! -//! Some functions here, such as trans_block and trans_expr, return a value -- -//! the result of the translation to LLVM -- while others, such as trans_fn -//! and trans_item, are called only for the side effect of adding a +//! Some functions here, such as codegen_block and codegen_expr, return a value -- +//! the result of the codegen to LLVM -- while others, such as codegen_fn +//! and mono_item, are called only for the side effect of adding a //! particular definition to the LLVM IR output we're producing. //! -//! Hopefully useful general knowledge about trans: +//! Hopefully useful general knowledge about codegen: //! //! * There's no way to find out the Ty type of a ValueRef. Doing so //! would be "trying to get the eggs out of an omelette" (credit: @@ -25,12 +25,12 @@ use super::ModuleLlvm; use super::ModuleSource; -use super::ModuleTranslation; +use super::ModuleCodegen; use super::ModuleKind; use abi; use back::link; -use back::write::{self, OngoingCrateTranslation, create_target_machine}; +use back::write::{self, OngoingCodegen, create_target_machine}; use llvm::{ContextRef, ModuleRef, ValueRef, Vector, get_param}; use llvm; use metadata; @@ -41,9 +41,8 @@ use rustc::mir::mono::{Linkage, Visibility, Stats}; use rustc::middle::cstore::{EncodedMetadata}; use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::dep_graph::{DepNode, DepConstructor}; -use rustc::ty::subst::Kind; use rustc::middle::cstore::{self, LinkMeta, LinkagePreference}; use rustc::middle::exported_symbols; use rustc::util::common::{time, print_time_passes_entry}; @@ -53,10 +52,11 @@ use rustc_incremental; use allocator; use mir::place::PlaceRef; use attributes; -use builder::Builder; +use builder::{Builder, MemFlags}; use callee; use common::{C_bool, C_bytes_in_context, C_i32, C_usize}; use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode}; +use rustc_mir::monomorphize::item::DefPathBasedNames; use common::{self, C_struct_in_context, C_array, val_ty}; use consts; use context::{self, CodegenCx}; @@ -66,18 +66,16 @@ use meth; use mir; use monomorphize::Instance; use monomorphize::partitioning::{self, PartitioningStrategy, CodegenUnit, CodegenUnitExt}; -use rustc_trans_utils::symbol_names_test; +use rustc_codegen_utils::symbol_names_test; use time_graph; -use trans_item::{MonoItem, BaseMonoItemExt, MonoItemExt, DefPathBasedNames}; +use mono_item::{MonoItem, BaseMonoItemExt, MonoItemExt}; use type_::Type; use type_of::LayoutLlvmExt; use rustc::util::nodemap::{FxHashMap, FxHashSet, DefIdSet}; use CrateInfo; use rustc_data_structures::sync::Lrc; -use rustc_target::spec::TargetTriple; use std::any::Any; -use std::collections::BTreeMap; use std::ffi::CString; use std::str; use std::sync::Arc; @@ -88,12 +86,11 @@ use std::sync::mpsc; use syntax_pos::Span; use syntax_pos::symbol::InternedString; use syntax::attr; -use rustc::hir; -use syntax::ast; +use rustc::hir::{self, CodegenFnAttrs}; use mir::operand::OperandValue; -pub use rustc_trans_utils::check_for_rustc_errors_attr; +use rustc_codegen_utils::check_for_rustc_errors_attr; pub struct StatRecorder<'a, 'tcx: 'a> { cx: &'a CodegenCx<'a, 'tcx>, @@ -114,7 +111,7 @@ impl<'a, 'tcx> StatRecorder<'a, 'tcx> { impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { fn drop(&mut self) { - if self.cx.sess().trans_stats() { + if self.cx.sess().codegen_stats() { let mut stats = self.cx.stats.borrow_mut(); let iend = stats.n_llvm_insns; stats.fn_stats.push((self.name.take().unwrap(), iend - self.istart)); @@ -125,16 +122,16 @@ impl<'a, 'tcx> Drop for StatRecorder<'a, 'tcx> { } } -pub fn bin_op_to_icmp_predicate(op: hir::BinOp_, +pub fn bin_op_to_icmp_predicate(op: hir::BinOpKind, signed: bool) -> llvm::IntPredicate { match op { - hir::BiEq => llvm::IntEQ, - hir::BiNe => llvm::IntNE, - hir::BiLt => if signed { llvm::IntSLT } else { llvm::IntULT }, - hir::BiLe => if signed { llvm::IntSLE } else { llvm::IntULE }, - hir::BiGt => if signed { llvm::IntSGT } else { llvm::IntUGT }, - hir::BiGe => if signed { llvm::IntSGE } else { llvm::IntUGE }, + hir::BinOpKind::Eq => llvm::IntEQ, + hir::BinOpKind::Ne => llvm::IntNE, + hir::BinOpKind::Lt => if signed { llvm::IntSLT } else { llvm::IntULT }, + hir::BinOpKind::Le => if signed { llvm::IntSLE } else { llvm::IntULE }, + hir::BinOpKind::Gt => if signed { llvm::IntSGT } else { llvm::IntUGT }, + hir::BinOpKind::Ge => if signed { llvm::IntSGE } else { llvm::IntUGE }, op => { bug!("comparison_op_to_icmp_predicate: expected comparison operator, \ found {:?}", @@ -143,14 +140,14 @@ pub fn bin_op_to_icmp_predicate(op: hir::BinOp_, } } -pub fn bin_op_to_fcmp_predicate(op: hir::BinOp_) -> llvm::RealPredicate { +pub fn bin_op_to_fcmp_predicate(op: hir::BinOpKind) -> llvm::RealPredicate { match op { - hir::BiEq => llvm::RealOEQ, - hir::BiNe => llvm::RealUNE, - hir::BiLt => llvm::RealOLT, - hir::BiLe => llvm::RealOLE, - hir::BiGt => llvm::RealOGT, - hir::BiGe => llvm::RealOGE, + hir::BinOpKind::Eq => llvm::RealOEQ, + hir::BinOpKind::Ne => llvm::RealUNE, + hir::BinOpKind::Lt => llvm::RealOLT, + hir::BinOpKind::Le => llvm::RealOLE, + hir::BinOpKind::Gt => llvm::RealOGT, + hir::BinOpKind::Ge => llvm::RealOGE, op => { bug!("comparison_op_to_fcmp_predicate: expected comparison operator, \ found {:?}", @@ -165,7 +162,7 @@ pub fn compare_simd_types<'a, 'tcx>( rhs: ValueRef, t: Ty<'tcx>, ret_ty: Type, - op: hir::BinOp_ + op: hir::BinOpKind ) -> ValueRef { let signed = match t.sty { ty::TyFloat(_) => { @@ -199,7 +196,7 @@ pub fn unsized_info<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, let (source, target) = cx.tcx.struct_lockstep_tails(source, target); match (&source.sty, &target.sty) { (&ty::TyArray(_, len), &ty::TySlice(_)) => { - C_usize(cx, len.val.unwrap_u64()) + C_usize(cx, len.unwrap_usize(cx.tcx)) } (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { // For now, upcasts are limited to changes in marker @@ -228,9 +225,9 @@ pub fn unsize_thin_ptr<'a, 'tcx>( ) -> (ValueRef, ValueRef) { debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); match (&src_ty.sty, &dst_ty.sty) { - (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), - &ty::TyRef(_, ty::TypeAndMut { ty: b, .. })) | - (&ty::TyRef(_, ty::TypeAndMut { ty: a, .. }), + (&ty::TyRef(_, a, _), + &ty::TyRef(_, b, _)) | + (&ty::TyRef(_, a, _), &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) | (&ty::TyRawPtr(ty::TypeAndMut { ty: a, .. }), &ty::TyRawPtr(ty::TypeAndMut { ty: b, .. })) => { @@ -266,8 +263,8 @@ pub fn unsize_thin_ptr<'a, 'tcx>( } let (lldata, llextra) = result.unwrap(); // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0)), - bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1))) + (bx.bitcast(lldata, dst_layout.scalar_pair_element_llvm_type(bx.cx, 0, true)), + bx.bitcast(llextra, dst_layout.scalar_pair_element_llvm_type(bx.cx, 1, true))) } _ => bug!("unsize_thin_ptr: called on bad types"), } @@ -320,7 +317,7 @@ pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>, if src_f.layout.ty == dst_f.layout.ty { memcpy_ty(bx, dst_f.llval, src_f.llval, src_f.layout, - src_f.align.min(dst_f.align)); + src_f.align.min(dst_f.align), MemFlags::empty()); } else { coerce_unsized_into(bx, src_f, dst_f); } @@ -333,12 +330,12 @@ pub fn coerce_unsized_into<'a, 'tcx>(bx: &Builder<'a, 'tcx>, } pub fn cast_shift_expr_rhs( - cx: &Builder, op: hir::BinOp_, lhs: ValueRef, rhs: ValueRef + cx: &Builder, op: hir::BinOpKind, lhs: ValueRef, rhs: ValueRef ) -> ValueRef { cast_shift_rhs(op, lhs, rhs, |a, b| cx.trunc(a, b), |a, b| cx.zext(a, b)) } -fn cast_shift_rhs(op: hir::BinOp_, +fn cast_shift_rhs(op: hir::BinOpKind, lhs: ValueRef, rhs: ValueRef, trunc: F, @@ -397,9 +394,14 @@ pub fn from_immediate(bx: &Builder, val: ValueRef) -> ValueRef { pub fn to_immediate(bx: &Builder, val: ValueRef, layout: layout::TyLayout) -> ValueRef { if let layout::Abi::Scalar(ref scalar) = layout.abi { - if scalar.is_bool() { - return bx.trunc(val, Type::i1(bx.cx)); - } + return to_immediate_scalar(bx, val, scalar); + } + val +} + +pub fn to_immediate_scalar(bx: &Builder, val: ValueRef, scalar: &layout::Scalar) -> ValueRef { + if scalar.is_bool() { + return bx.trunc(val, Type::i1(bx.cx)); } val } @@ -408,7 +410,15 @@ pub fn call_memcpy(bx: &Builder, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, - align: Align) { + align: Align, + flags: MemFlags) { + if flags.contains(MemFlags::NONTEMPORAL) { + // HACK(nox): This is inefficient but there is no nontemporal memcpy. + let val = bx.load(src, align); + let ptr = bx.pointercast(dst, val_ty(val).ptr_to()); + bx.store_with_flags(val, ptr, align, flags); + return; + } let cx = bx.cx; let ptr_width = &cx.sess().target.target.target_pointer_width; let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width); @@ -417,7 +427,7 @@ pub fn call_memcpy(bx: &Builder, let dst_ptr = bx.pointercast(dst, Type::i8p(cx)); let size = bx.intcast(n_bytes, cx.isize_ty, false); let align = C_i32(cx, align.abi() as i32); - let volatile = C_bool(cx, false); + let volatile = C_bool(cx, flags.contains(MemFlags::VOLATILE)); bx.call(memcpy, &[dst_ptr, src_ptr, size, align, volatile], None); } @@ -427,13 +437,14 @@ pub fn memcpy_ty<'a, 'tcx>( src: ValueRef, layout: TyLayout<'tcx>, align: Align, + flags: MemFlags, ) { let size = layout.size.bytes(); if size == 0 { return; } - call_memcpy(bx, dst, src, C_usize(bx.cx, size), align); + call_memcpy(bx, dst, src, C_usize(bx.cx, size), align, flags); } pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>, @@ -449,8 +460,8 @@ pub fn call_memset<'a, 'tcx>(bx: &Builder<'a, 'tcx>, bx.call(llintrinsicfn, &[ptr, fill_byte, size, align, volatile], None) } -pub fn trans_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>) { - let _s = if cx.sess().trans_stats() { +pub fn codegen_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tcx>) { + let _s = if cx.sess().codegen_stats() { let mut instance_name = String::new(); DefPathBasedNames::new(cx.tcx, true, true) .push_def_path(instance.def_id(), &mut instance_name); @@ -462,7 +473,7 @@ pub fn trans_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tc // this is an info! to allow collecting monomorphization statistics // and to allow finding the last function before LLVM aborts from // release builds. - info!("trans_instance({})", instance); + info!("codegen_instance({})", instance); let fn_ty = instance.ty(cx.tcx); let sig = common::ty_fn_sig(cx, fn_ty); @@ -497,20 +508,17 @@ pub fn trans_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'tc } let mir = cx.tcx.instance_mir(instance.def); - mir::trans_mir(cx, lldecl, &mir, instance, sig); + mir::codegen_mir(cx, lldecl, &mir, instance, sig); } -pub fn set_link_section(cx: &CodegenCx, - llval: ValueRef, - attrs: &[ast::Attribute]) { - if let Some(sect) = attr::first_attr_value_str_by_name(attrs, "link_section") { - if contains_null(§.as_str()) { - cx.sess().fatal(&format!("Illegal null byte in link_section value: `{}`", §)); - } - unsafe { - let buf = CString::new(sect.as_str().as_bytes()).unwrap(); - llvm::LLVMSetSection(llval, buf.as_ptr()); - } +pub fn set_link_section(llval: ValueRef, attrs: &CodegenFnAttrs) { + let sect = match attrs.link_section { + Some(name) => name, + None => return, + }; + unsafe { + let buf = CString::new(sect.as_str().as_bytes()).unwrap(); + llvm::LLVMSetSection(llval, buf.as_ptr()); } } @@ -586,7 +594,7 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) { let start_fn = callee::resolve_and_get_fn( cx, start_def_id, - cx.tcx.intern_substs(&[Kind::from(main_ret_ty)]), + cx.tcx.intern_substs(&[main_ret_ty.into()]), ); (start_fn, vec![bx.pointercast(rust_main, Type::i8p(cx).ptr_to()), arg_argc, arg_argv]) @@ -600,10 +608,6 @@ fn maybe_create_entry_wrapper(cx: &CodegenCx) { } } -fn contains_null(s: &str) -> bool { - s.bytes().any(|b| b == 0) -} - fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, llmod_id: &str, link_meta: &LinkMeta) @@ -634,7 +638,7 @@ fn write_metadata<'a, 'gcx>(tcx: TyCtxt<'a, 'gcx, 'gcx>, config::CrateTypeDylib | config::CrateTypeProcMacro => MetadataKind::Compressed, } - }).max().unwrap(); + }).max().unwrap_or(MetadataKind::None); if kind == MetadataKind::None { return (metadata_llcx, @@ -703,9 +707,9 @@ pub fn iter_globals(llmod: llvm::ModuleRef) -> ValueIter { } } -pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver>) - -> OngoingCrateTranslation { +pub fn codegen_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + rx: mpsc::Receiver>) + -> OngoingCodegen { check_for_rustc_errors_attr(tcx); @@ -725,17 +729,17 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let crate_hash = tcx.crate_hash(LOCAL_CRATE); let link_meta = link::build_link_meta(crate_hash); - // Translate the metadata. + // Codegen the metadata. let llmod_id = "metadata"; let (metadata_llcx, metadata_llmod, metadata) = time(tcx.sess, "write metadata", || { write_metadata(tcx, llmod_id, &link_meta) }); - let metadata_module = ModuleTranslation { + let metadata_module = ModuleCodegen { name: link::METADATA_MODULE_NAME.to_string(), llmod_id: llmod_id.to_string(), - source: ModuleSource::Translated(ModuleLlvm { + source: ModuleSource::Codegened(ModuleLlvm { llcx: metadata_llcx, llmod: metadata_llmod, tm: create_target_machine(tcx.sess, false), @@ -743,16 +747,16 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, kind: ModuleKind::Metadata, }; - let time_graph = if tcx.sess.opts.debugging_opts.trans_time_graph { + let time_graph = if tcx.sess.opts.debugging_opts.codegen_time_graph { Some(time_graph::TimeGraph::new()) } else { None }; - // Skip crate items and just output metadata in -Z no-trans mode. - if tcx.sess.opts.debugging_opts.no_trans || - !tcx.sess.opts.output_types.should_trans() { - let ongoing_translation = write::start_async_translation( + // Skip crate items and just output metadata in -Z no-codegen mode. + if tcx.sess.opts.debugging_opts.no_codegen || + !tcx.sess.opts.output_types.should_codegen() { + let ongoing_codegen = write::start_async_codegen( tcx, time_graph.clone(), link_meta, @@ -760,20 +764,20 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, rx, 1); - ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module); - ongoing_translation.translation_finished(tcx); + ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); + ongoing_codegen.codegen_finished(tcx); assert_and_save_dep_graph(tcx); - ongoing_translation.check_for_errors(tcx.sess); + ongoing_codegen.check_for_errors(tcx.sess); - return ongoing_translation; + return ongoing_codegen; } - // Run the translation item collector and partition the collected items into + // Run the monomorphization collector and partition the collected items into // codegen units. let codegen_units = - tcx.collect_and_partition_translation_items(LOCAL_CRATE).1; + tcx.collect_and_partition_mono_items(LOCAL_CRATE).1; let codegen_units = (*codegen_units).clone(); // Force all codegen_unit queries so they are already either red or green @@ -787,7 +791,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - let ongoing_translation = write::start_async_translation( + let ongoing_codegen = write::start_async_codegen( tcx, time_graph.clone(), link_meta, @@ -795,7 +799,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, rx, codegen_units.len()); - // Translate an allocator shim, if any + // Codegen an allocator shim, if any let allocator_module = if let Some(kind) = *tcx.sess.allocator_kind.get() { unsafe { let llmod_id = "allocator"; @@ -807,13 +811,13 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tm: create_target_machine(tcx.sess, false), }; time(tcx.sess, "write allocator module", || { - allocator::trans(tcx, &modules, kind) + allocator::codegen(tcx, &modules, kind) }); - Some(ModuleTranslation { + Some(ModuleCodegen { name: link::ALLOCATOR_MODULE_NAME.to_string(), llmod_id: llmod_id.to_string(), - source: ModuleSource::Translated(modules), + source: ModuleSource::Codegened(modules), kind: ModuleKind::Allocator, }) } @@ -822,10 +826,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; if let Some(allocator_module) = allocator_module { - ongoing_translation.submit_pre_translated_module_to_llvm(tcx, allocator_module); + ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, allocator_module); } - ongoing_translation.submit_pre_translated_module_to_llvm(tcx, metadata_module); + ongoing_codegen.submit_pre_codegened_module_to_llvm(tcx, metadata_module); // We sort the codegen units by size. This way we can schedule work for LLVM // a bit more efficiently. @@ -835,12 +839,12 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, codegen_units }; - let mut total_trans_time = Duration::new(0, 0); + let mut total_codegen_time = Duration::new(0, 0); let mut all_stats = Stats::default(); for cgu in codegen_units.into_iter() { - ongoing_translation.wait_for_signal_to_translate_item(); - ongoing_translation.check_for_errors(tcx.sess); + ongoing_codegen.wait_for_signal_to_codegen_item(); + ongoing_codegen.check_for_errors(tcx.sess); // First, if incremental compilation is enabled, we try to re-use the // codegen unit from the cache. @@ -869,14 +873,14 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // 1. http://llvm.org/bugs/show_bug.cgi?id=11479 let llmod_id = format!("{}.rs", cgu.name()); - let module = ModuleTranslation { + let module = ModuleCodegen { name: cgu.name().to_string(), source: ModuleSource::Preexisting(buf), kind: ModuleKind::Regular, llmod_id, }; tcx.dep_graph.mark_loaded_from_cache(dep_node_index, true); - write::submit_translated_module_to_llvm(tcx, module, 0); + write::submit_codegened_module_to_llvm(tcx, module, 0); // Continue to next cgu, this one is done. continue } @@ -887,23 +891,23 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } let _timing_guard = time_graph.as_ref().map(|time_graph| { - time_graph.start(write::TRANS_WORKER_TIMELINE, - write::TRANS_WORK_PACKAGE_KIND, + time_graph.start(write::CODEGEN_WORKER_TIMELINE, + write::CODEGEN_WORK_PACKAGE_KIND, &format!("codegen {}", cgu.name())) }); let start_time = Instant::now(); all_stats.extend(tcx.compile_codegen_unit(*cgu.name())); - total_trans_time += start_time.elapsed(); - ongoing_translation.check_for_errors(tcx.sess); + total_codegen_time += start_time.elapsed(); + ongoing_codegen.check_for_errors(tcx.sess); } - ongoing_translation.translation_finished(tcx); + ongoing_codegen.codegen_finished(tcx); - // Since the main thread is sometimes blocked during trans, we keep track + // Since the main thread is sometimes blocked during codegen, we keep track // -Ztime-passes output manually. print_time_passes_entry(tcx.sess.time_passes(), - "translate to LLVM IR", - total_trans_time); + "codegen to LLVM IR", + total_codegen_time); if tcx.sess.opts.incremental.is_some() { ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); @@ -911,8 +915,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, symbol_names_test::report_symbol_names(tcx); - if tcx.sess.trans_stats() { - println!("--- trans stats ---"); + if tcx.sess.codegen_stats() { + println!("--- codegen stats ---"); println!("n_glues_created: {}", all_stats.n_glues_created); println!("n_null_glues: {}", all_stats.n_null_glues); println!("n_real_glues: {}", all_stats.n_real_glues); @@ -933,10 +937,10 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } } - ongoing_translation.check_for_errors(tcx.sess); + ongoing_codegen.check_for_errors(tcx.sess); assert_and_save_dep_graph(tcx); - ongoing_translation + ongoing_codegen } fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { @@ -949,14 +953,14 @@ fn assert_and_save_dep_graph<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { || rustc_incremental::save_dep_graph(tcx)); } -fn collect_and_partition_translation_items<'a, 'tcx>( +fn collect_and_partition_mono_items<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cnum: CrateNum, ) -> (Arc, Arc>>>) { assert_eq!(cnum, LOCAL_CRATE); - let collection_mode = match tcx.sess.opts.debugging_opts.print_trans_items { + let collection_mode = match tcx.sess.opts.debugging_opts.print_mono_items { Some(ref s) => { let mode_string = s.to_lowercase(); let mode_string = mode_string.trim(); @@ -983,7 +987,7 @@ fn collect_and_partition_translation_items<'a, 'tcx>( }; let (items, inlining_map) = - time(tcx.sess, "translation item collection", || { + time(tcx.sess, "monomorphization collection", || { collector::collect_crate_mono_items(tcx, collection_mode) }); @@ -1007,20 +1011,20 @@ fn collect_and_partition_translation_items<'a, 'tcx>( .collect::>() }); - let translation_items: DefIdSet = items.iter().filter_map(|trans_item| { - match *trans_item { + let mono_items: DefIdSet = items.iter().filter_map(|mono_item| { + match *mono_item { MonoItem::Fn(ref instance) => Some(instance.def_id()), MonoItem::Static(def_id) => Some(def_id), _ => None, } }).collect(); - if tcx.sess.opts.debugging_opts.print_trans_items.is_some() { + if tcx.sess.opts.debugging_opts.print_mono_items.is_some() { let mut item_to_cgus = FxHashMap(); for cgu in &codegen_units { - for (&trans_item, &linkage) in cgu.items() { - item_to_cgus.entry(trans_item) + for (&mono_item, &linkage) in cgu.items() { + item_to_cgus.entry(mono_item) .or_insert(Vec::new()) .push((cgu.name().clone(), linkage)); } @@ -1064,11 +1068,11 @@ fn collect_and_partition_translation_items<'a, 'tcx>( item_keys.sort(); for item in item_keys { - println!("TRANS_ITEM {}", item); + println!("MONO_ITEM {}", item); } } - (Arc::new(translation_items), Arc::new(codegen_units)) + (Arc::new(mono_items), Arc::new(codegen_units)) } impl CrateInfo { @@ -1086,7 +1090,6 @@ impl CrateInfo { used_crates_dynamic: cstore::used_crates(tcx, LinkagePreference::RequireDynamic), used_crates_static: cstore::used_crates(tcx, LinkagePreference::RequireStatic), used_crate_source: FxHashMap(), - wasm_custom_sections: BTreeMap::new(), wasm_imports: FxHashMap(), lang_item_to_crate: FxHashMap(), missing_lang_items: FxHashMap(), @@ -1096,16 +1099,9 @@ impl CrateInfo { let load_wasm_items = tcx.sess.crate_types.borrow() .iter() .any(|c| *c != config::CrateTypeRlib) && - tcx.sess.opts.target_triple == TargetTriple::from_triple("wasm32-unknown-unknown"); + tcx.sess.opts.target_triple.triple() == "wasm32-unknown-unknown"; if load_wasm_items { - info!("attempting to load all wasm sections"); - for &id in tcx.wasm_custom_sections(LOCAL_CRATE).iter() { - let (name, contents) = fetch_wasm_section(tcx, id); - info.wasm_custom_sections.entry(name) - .or_insert(Vec::new()) - .extend(contents); - } info.load_wasm_imports(tcx, LOCAL_CRATE); } @@ -1129,12 +1125,6 @@ impl CrateInfo { info.is_no_builtins.insert(cnum); } if load_wasm_items { - for &id in tcx.wasm_custom_sections(cnum).iter() { - let (name, contents) = fetch_wasm_section(tcx, id); - info.wasm_custom_sections.entry(name) - .or_insert(Vec::new()) - .extend(contents); - } info.load_wasm_imports(tcx, cnum); } let missing = tcx.missing_lang_items(cnum); @@ -1165,10 +1155,10 @@ impl CrateInfo { } } -fn is_translated_item(tcx: TyCtxt, id: DefId) -> bool { - let (all_trans_items, _) = - tcx.collect_and_partition_translation_items(LOCAL_CRATE); - all_trans_items.contains(&id) +fn is_codegened_item(tcx: TyCtxt, id: DefId) -> bool { + let (all_mono_items, _) = + tcx.collect_and_partition_mono_items(LOCAL_CRATE); + all_mono_items.contains(&id) } fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -1176,23 +1166,23 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let cgu = tcx.codegen_unit(cgu); let start_time = Instant::now(); - let (stats, module) = module_translation(tcx, cgu); - let time_to_translate = start_time.elapsed(); + let (stats, module) = module_codegen(tcx, cgu); + let time_to_codegen = start_time.elapsed(); // We assume that the cost to run LLVM on a CGU is proportional to - // the time we needed for translating it. - let cost = time_to_translate.as_secs() * 1_000_000_000 + - time_to_translate.subsec_nanos() as u64; + // the time we needed for codegenning it. + let cost = time_to_codegen.as_secs() * 1_000_000_000 + + time_to_codegen.subsec_nanos() as u64; - write::submit_translated_module_to_llvm(tcx, + write::submit_codegened_module_to_llvm(tcx, module, cost); return stats; - fn module_translation<'a, 'tcx>( + fn module_codegen<'a, 'tcx>( tcx: TyCtxt<'a, 'tcx, 'tcx>, cgu: Arc>) - -> (Stats, ModuleTranslation) + -> (Stats, ModuleCodegen) { let cgu_name = cgu.name().to_string(); @@ -1209,18 +1199,18 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx.crate_disambiguator(LOCAL_CRATE) .to_fingerprint().to_hex()); - // Instantiate translation items without filling out definitions yet... + // Instantiate monomorphizations without filling out definitions yet... let cx = CodegenCx::new(tcx, cgu, &llmod_id); let module = { - let trans_items = cx.codegen_unit + let mono_items = cx.codegen_unit .items_in_deterministic_order(cx.tcx); - for &(trans_item, (linkage, visibility)) in &trans_items { - trans_item.predefine(&cx, linkage, visibility); + for &(mono_item, (linkage, visibility)) in &mono_items { + mono_item.predefine(&cx, linkage, visibility); } // ... and now that we have everything pre-defined, fill out those definitions. - for &(trans_item, _) in &trans_items { - trans_item.define(&cx); + for &(mono_item, _) in &mono_items { + mono_item.define(&cx); } // If this codegen unit contains the main function, also create the @@ -1264,9 +1254,9 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, tm: create_target_machine(cx.sess(), false), }; - ModuleTranslation { + ModuleCodegen { name: cgu_name, - source: ModuleSource::Translated(llvm_module), + source: ModuleSource::Codegened(llvm_module), kind: ModuleKind::Regular, llmod_id, } @@ -1277,17 +1267,17 @@ fn compile_codegen_unit<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } pub fn provide(providers: &mut Providers) { - providers.collect_and_partition_translation_items = - collect_and_partition_translation_items; + providers.collect_and_partition_mono_items = + collect_and_partition_mono_items; - providers.is_translated_item = is_translated_item; + providers.is_codegened_item = is_codegened_item; providers.codegen_unit = |tcx, name| { - let (_, all) = tcx.collect_and_partition_translation_items(LOCAL_CRATE); + let (_, all) = tcx.collect_and_partition_mono_items(LOCAL_CRATE); all.iter() .find(|cgu| *cgu.name() == name) .cloned() - .expect(&format!("failed to find cgu with name {:?}", name)) + .unwrap_or_else(|| panic!("failed to find cgu with name {:?}", name)) }; providers.compile_codegen_unit = compile_codegen_unit; @@ -1360,9 +1350,9 @@ pub fn visibility_to_llvm(linkage: Visibility) -> llvm::Visibility { mod temp_stable_hash_impls { use rustc_data_structures::stable_hasher::{StableHasherResult, StableHasher, HashStable}; - use ModuleTranslation; + use ModuleCodegen; - impl HashStable for ModuleTranslation { + impl HashStable for ModuleCodegen { fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) { @@ -1370,44 +1360,3 @@ mod temp_stable_hash_impls { } } } - -fn fetch_wasm_section(tcx: TyCtxt, id: DefId) -> (String, Vec) { - use rustc::mir::interpret::{GlobalId, Value, PrimVal}; - use rustc::middle::const_val::ConstVal; - - info!("loading wasm section {:?}", id); - - let section = tcx.get_attrs(id) - .iter() - .find(|a| a.check_name("wasm_custom_section")) - .expect("missing #[wasm_custom_section] attribute") - .value_str() - .expect("malformed #[wasm_custom_section] attribute"); - - let instance = ty::Instance::mono(tcx, id); - let cid = GlobalId { - instance, - promoted: None - }; - let param_env = ty::ParamEnv::reveal_all(); - let val = tcx.const_eval(param_env.and(cid)).unwrap(); - - let val = match val.val { - ConstVal::Value(val) => val, - ConstVal::Unevaluated(..) => bug!("should be evaluated"), - }; - let val = match val { - Value::ByRef(ptr, _align) => ptr.into_inner_primval(), - ref v => bug!("should be ByRef, was {:?}", v), - }; - let mem = match val { - PrimVal::Ptr(mem) => mem, - ref v => bug!("should be Ptr, was {:?}", v), - }; - assert_eq!(mem.offset, 0); - let alloc = tcx - .interpret_interner - .get_alloc(mem.alloc_id) - .expect("miri allocation never successfully created"); - (section.to_string(), alloc.bytes.clone()) -} diff --git a/src/librustc_trans/build.rs b/src/librustc_codegen_llvm/build.rs similarity index 100% rename from src/librustc_trans/build.rs rename to src/librustc_codegen_llvm/build.rs diff --git a/src/librustc_trans/builder.rs b/src/librustc_codegen_llvm/builder.rs similarity index 94% rename from src/librustc_trans/builder.rs rename to src/librustc_codegen_llvm/builder.rs index db803ca8209d9..b34d0f1cd9070 100644 --- a/src/librustc_trans/builder.rs +++ b/src/librustc_codegen_llvm/builder.rs @@ -13,7 +13,7 @@ use llvm; use llvm::{AtomicRmwBinOp, AtomicOrdering, SynchronizationScope, AsmDialect}; use llvm::{Opcode, IntPredicate, RealPredicate, False, OperandBundleDef}; -use llvm::{ValueRef, BasicBlockRef, BuilderRef, ModuleRef}; +use llvm::{ValueRef, BasicBlockRef, BuilderRef}; use common::*; use type_::Type; use value::Value; @@ -50,6 +50,14 @@ fn noname() -> *const c_char { &CNULL } +bitflags! { + pub struct MemFlags: u8 { + const VOLATILE = 1 << 0; + const NONTEMPORAL = 1 << 1; + const UNALIGNED = 1 << 2; + } +} + impl<'a, 'tcx> Builder<'a, 'tcx> { pub fn new_block<'b>(cx: &'a CodegenCx<'a, 'tcx>, llfn: ValueRef, name: &'b str) -> Self { let bx = Builder::with_cx(cx); @@ -101,7 +109,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } fn count_insn(&self, category: &str) { - if self.cx.sess().trans_stats() { + if self.cx.sess().codegen_stats() { self.cx.stats.borrow_mut().n_llvm_insns += 1; } if self.cx.sess().count_llvm_insns() { @@ -270,7 +278,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } pub fn nswsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("nwsub"); + self.count_insn("nswsub"); unsafe { llvm::LLVMBuildNSWSub(self.llbuilder, lhs, rhs, noname()) } @@ -284,14 +292,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } pub fn fsub(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("sub"); + self.count_insn("fsub"); unsafe { llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname()) } } pub fn fsub_fast(&self, lhs: ValueRef, rhs: ValueRef) -> ValueRef { - self.count_insn("sub"); + self.count_insn("fsub"); unsafe { let instr = llvm::LLVMBuildFSub(self.llbuilder, lhs, rhs, noname()); llvm::LLVMRustSetHasUnsafeAlgebra(instr); @@ -579,29 +587,44 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } pub fn store(&self, val: ValueRef, ptr: ValueRef, align: Align) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); + self.store_with_flags(val, ptr, align, MemFlags::empty()) + } + + pub fn store_with_flags( + &self, + val: ValueRef, + ptr: ValueRef, + align: Align, + flags: MemFlags, + ) -> ValueRef { + debug!("Store {:?} -> {:?} ({:?})", Value(val), Value(ptr), flags); assert!(!self.llbuilder.is_null()); self.count_insn("store"); let ptr = self.check_store(val, ptr); unsafe { let store = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - llvm::LLVMSetAlignment(store, align.abi() as c_uint); + let align = if flags.contains(MemFlags::UNALIGNED) { + 1 + } else { + align.abi() as c_uint + }; + llvm::LLVMSetAlignment(store, align); + if flags.contains(MemFlags::VOLATILE) { + llvm::LLVMSetVolatile(store, llvm::True); + } + if flags.contains(MemFlags::NONTEMPORAL) { + // According to LLVM [1] building a nontemporal store must + // *always* point to a metadata value of the integer 1. + // + // [1]: http://llvm.org/docs/LangRef.html#store-instruction + let one = C_i32(self.cx, 1); + let node = llvm::LLVMMDNodeInContext(self.cx.llcx, &one, 1); + llvm::LLVMSetMetadata(store, llvm::MD_nontemporal as c_uint, node); + } store } } - pub fn volatile_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); - assert!(!self.llbuilder.is_null()); - self.count_insn("store.volatile"); - let ptr = self.check_store(val, ptr); - unsafe { - let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - llvm::LLVMSetVolatile(insn, llvm::True); - insn - } - } - pub fn atomic_store(&self, val: ValueRef, ptr: ValueRef, order: AtomicOrdering, align: Align) { debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); @@ -615,29 +638,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn nontemporal_store(&self, val: ValueRef, ptr: ValueRef) -> ValueRef { - debug!("Store {:?} -> {:?}", Value(val), Value(ptr)); - assert!(!self.llbuilder.is_null()); - self.count_insn("store.nontemporal"); - let ptr = self.check_store(val, ptr); - unsafe { - let insn = llvm::LLVMBuildStore(self.llbuilder, val, ptr); - - // According to LLVM [1] building a nontemporal store must *always* - // point to a metadata value of the integer 1. Who knew? - // - // [1]: http://llvm.org/docs/LangRef.html#store-instruction - let one = C_i32(self.cx, 1); - let node = llvm::LLVMMDNodeInContext(self.cx.llcx, - &one, - 1); - llvm::LLVMSetMetadata(insn, - llvm::MD_nontemporal as c_uint, - node); - insn - } - } - pub fn gep(&self, ptr: ValueRef, indices: &[ValueRef]) -> ValueRef { self.count_insn("gep"); unsafe { @@ -1163,23 +1163,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - pub fn trap(&self) { - unsafe { - let bb: BasicBlockRef = llvm::LLVMGetInsertBlock(self.llbuilder); - let fn_: ValueRef = llvm::LLVMGetBasicBlockParent(bb); - let m: ModuleRef = llvm::LLVMGetGlobalParent(fn_); - let p = "llvm.trap\0".as_ptr(); - let t: ValueRef = llvm::LLVMGetNamedFunction(m, p as *const _); - assert!((t as isize != 0)); - let args: &[ValueRef] = &[]; - self.count_insn("trap"); - llvm::LLVMRustBuildCall(self.llbuilder, t, - args.as_ptr(), args.len() as c_uint, - ptr::null_mut(), - noname()); - } - } - pub fn landing_pad(&self, ty: Type, pers_fn: ValueRef, num_clauses: usize) -> ValueRef { self.count_insn("landingpad"); @@ -1321,6 +1304,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } pub fn add_incoming_to_phi(&self, phi: ValueRef, val: ValueRef, bb: BasicBlockRef) { + self.count_insn("addincoming"); unsafe { llvm::LLVMAddIncoming(phi, &val, &bb, 1 as c_uint); } diff --git a/src/librustc_trans/callee.rs b/src/librustc_codegen_llvm/callee.rs similarity index 91% rename from src/librustc_trans/callee.rs rename to src/librustc_codegen_llvm/callee.rs index 9263d9a5f5dc2..2c01bd42cc77a 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_codegen_llvm/callee.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Handles translation of callees as well as other call-related +//! Handles codegen of callees as well as other call-related //! things. Callees are a superset of normal rust values and sometimes //! have different representations. In particular, top-level fn items //! and methods are represented as just a fn ptr and not a full @@ -26,9 +26,8 @@ use rustc::hir::def_id::DefId; use rustc::ty::{self, TypeFoldable}; use rustc::ty::layout::LayoutOf; use rustc::ty::subst::Substs; -use rustc_target::spec::PanicStrategy; -/// Translates a reference to a fn/method item, monomorphizing and +/// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. /// /// # Parameters @@ -102,23 +101,13 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let instance_def_id = instance.def_id(); - // Perhaps questionable, but we assume that anything defined - // *in Rust code* may unwind. Foreign items like `extern "C" { - // fn foo(); }` are assumed not to unwind **unless** they have - // a `#[unwind]` attribute. - if tcx.sess.panic_strategy() == PanicStrategy::Unwind { - if !tcx.is_foreign_item(instance_def_id) { - attributes::unwind(llfn, true); - } - } - // Apply an appropriate linkage/visibility value to our item that we // just declared. // // This is sort of subtle. Inside our codegen unit we started off - // compilation by predefining all our own `TransItem` instances. That - // is, everything we're translating ourselves is already defined. That - // means that anything we're actually translating in this codegen unit + // compilation by predefining all our own `MonoItem` instances. That + // is, everything we're codegenning ourselves is already defined. That + // means that anything we're actually codegenning in this codegen unit // will have hit the above branch in `get_declared_value`. As a result, // we're guaranteed here that we're declaring a symbol that won't get // defined, or in other words we're referencing a value from another @@ -181,7 +170,7 @@ pub fn get_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, } } else { // This is a non-generic function - if cx.tcx.is_translated_item(instance_def_id) { + if cx.tcx.is_codegened_item(instance_def_id) { // This is a function that is instantiated in the local crate if instance_def_id.is_local() { diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs new file mode 100644 index 0000000000000..60bba635a7887 --- /dev/null +++ b/src/librustc_codegen_llvm/common.rs @@ -0,0 +1,450 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(non_camel_case_types, non_snake_case)] + +//! Code that is useful in various codegen modules. + +use llvm; +use llvm::{ValueRef, ContextRef, TypeKind}; +use llvm::{True, False, Bool, OperandBundleDef}; +use rustc::hir::def_id::DefId; +use rustc::middle::lang_items::LangItem; +use abi; +use base; +use builder::Builder; +use consts; +use declare; +use type_::Type; +use type_of::LayoutLlvmExt; +use value::Value; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::layout::{HasDataLayout, LayoutOf}; +use rustc::hir; + +use libc::{c_uint, c_char}; +use std::iter; + +use rustc_target::spec::abi::Abi; +use syntax::symbol::LocalInternedString; +use syntax_pos::{Span, DUMMY_SP}; + +pub use context::CodegenCx; + +pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) +} + +pub fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_sized(tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) +} + +pub fn type_is_freeze<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { + ty.is_freeze(tcx, ty::ParamEnv::reveal_all(), DUMMY_SP) +} + +/* +* A note on nomenclature of linking: "extern", "foreign", and "upcall". +* +* An "extern" is an LLVM symbol we wind up emitting an undefined external +* reference to. This means "we don't have the thing in this compilation unit, +* please make sure you link it in at runtime". This could be a reference to +* C code found in a C library, or rust code found in a rust crate. +* +* Most "externs" are implicitly declared (automatically) as a result of a +* user declaring an extern _module_ dependency; this causes the rust driver +* to locate an extern crate, scan its compilation metadata, and emit extern +* declarations for any symbols used by the declaring crate. +* +* A "foreign" is an extern that references C (or other non-rust ABI) code. +* There is no metadata to scan for extern references so in these cases either +* a header-digester like bindgen, or manual function prototypes, have to +* serve as declarators. So these are usually given explicitly as prototype +* declarations, in rust code, with ABI attributes on them noting which ABI to +* link via. +* +* An "upcall" is a foreign call generated by the compiler (not corresponding +* to any user-written call in the code) into the runtime library, to perform +* some helper task such as bringing a task to life, allocating memory, etc. +* +*/ + +/// A structure representing an active landing pad for the duration of a basic +/// block. +/// +/// Each `Block` may contain an instance of this, indicating whether the block +/// is part of a landing pad or not. This is used to make decision about whether +/// to emit `invoke` instructions (e.g. in a landing pad we don't continue to +/// use `invoke`) and also about various function call metadata. +/// +/// For GNU exceptions (`landingpad` + `resume` instructions) this structure is +/// just a bunch of `None` instances (not too interesting), but for MSVC +/// exceptions (`cleanuppad` + `cleanupret` instructions) this contains data. +/// When inside of a landing pad, each function call in LLVM IR needs to be +/// annotated with which landing pad it's a part of. This is accomplished via +/// the `OperandBundleDef` value created for MSVC landing pads. +pub struct Funclet { + cleanuppad: ValueRef, + operand: OperandBundleDef, +} + +impl Funclet { + pub fn new(cleanuppad: ValueRef) -> Funclet { + Funclet { + cleanuppad, + operand: OperandBundleDef::new("funclet", &[cleanuppad]), + } + } + + pub fn cleanuppad(&self) -> ValueRef { + self.cleanuppad + } + + pub fn bundle(&self) -> &OperandBundleDef { + &self.operand + } +} + +pub fn val_ty(v: ValueRef) -> Type { + unsafe { + Type::from_ref(llvm::LLVMTypeOf(v)) + } +} + +// LLVM constant constructors. +pub fn C_null(t: Type) -> ValueRef { + unsafe { + llvm::LLVMConstNull(t.to_ref()) + } +} + +pub fn C_undef(t: Type) -> ValueRef { + unsafe { + llvm::LLVMGetUndef(t.to_ref()) + } +} + +pub fn C_int(t: Type, i: i64) -> ValueRef { + unsafe { + llvm::LLVMConstInt(t.to_ref(), i as u64, True) + } +} + +pub fn C_uint(t: Type, i: u64) -> ValueRef { + unsafe { + llvm::LLVMConstInt(t.to_ref(), i, False) + } +} + +pub fn C_uint_big(t: Type, u: u128) -> ValueRef { + unsafe { + let words = [u as u64, (u >> 64) as u64]; + llvm::LLVMConstIntOfArbitraryPrecision(t.to_ref(), 2, words.as_ptr()) + } +} + +pub fn C_bool(cx: &CodegenCx, val: bool) -> ValueRef { + C_uint(Type::i1(cx), val as u64) +} + +pub fn C_i32(cx: &CodegenCx, i: i32) -> ValueRef { + C_int(Type::i32(cx), i as i64) +} + +pub fn C_u32(cx: &CodegenCx, i: u32) -> ValueRef { + C_uint(Type::i32(cx), i as u64) +} + +pub fn C_u64(cx: &CodegenCx, i: u64) -> ValueRef { + C_uint(Type::i64(cx), i) +} + +pub fn C_usize(cx: &CodegenCx, i: u64) -> ValueRef { + let bit_size = cx.data_layout().pointer_size.bits(); + if bit_size < 64 { + // make sure it doesn't overflow + assert!(i < (1< ValueRef { + C_uint(Type::i8(cx), i as u64) +} + + +// This is a 'c-like' raw string, which differs from +// our boxed-and-length-annotated strings. +pub fn C_cstr(cx: &CodegenCx, s: LocalInternedString, null_terminated: bool) -> ValueRef { + unsafe { + if let Some(&llval) = cx.const_cstr_cache.borrow().get(&s) { + return llval; + } + + let sc = llvm::LLVMConstStringInContext(cx.llcx, + s.as_ptr() as *const c_char, + s.len() as c_uint, + !null_terminated as Bool); + let sym = cx.generate_local_symbol_name("str"); + let g = declare::define_global(cx, &sym[..], val_ty(sc)).unwrap_or_else(||{ + bug!("symbol `{}` is already defined", sym); + }); + llvm::LLVMSetInitializer(g, sc); + llvm::LLVMSetGlobalConstant(g, True); + llvm::LLVMRustSetLinkage(g, llvm::Linkage::InternalLinkage); + + cx.const_cstr_cache.borrow_mut().insert(s, g); + g + } +} + +// NB: Do not use `do_spill_noroot` to make this into a constant string, or +// you will be kicked off fast isel. See issue #4352 for an example of this. +pub fn C_str_slice(cx: &CodegenCx, s: LocalInternedString) -> ValueRef { + let len = s.len(); + let cs = consts::ptrcast(C_cstr(cx, s, false), + cx.layout_of(cx.tcx.mk_str()).llvm_type(cx).ptr_to()); + C_fat_ptr(cx, cs, C_usize(cx, len as u64)) +} + +pub fn C_fat_ptr(cx: &CodegenCx, ptr: ValueRef, meta: ValueRef) -> ValueRef { + assert_eq!(abi::FAT_PTR_ADDR, 0); + assert_eq!(abi::FAT_PTR_EXTRA, 1); + C_struct(cx, &[ptr, meta], false) +} + +pub fn C_struct(cx: &CodegenCx, elts: &[ValueRef], packed: bool) -> ValueRef { + C_struct_in_context(cx.llcx, elts, packed) +} + +pub fn C_struct_in_context(llcx: ContextRef, elts: &[ValueRef], packed: bool) -> ValueRef { + unsafe { + llvm::LLVMConstStructInContext(llcx, + elts.as_ptr(), elts.len() as c_uint, + packed as Bool) + } +} + +pub fn C_array(ty: Type, elts: &[ValueRef]) -> ValueRef { + unsafe { + return llvm::LLVMConstArray(ty.to_ref(), elts.as_ptr(), elts.len() as c_uint); + } +} + +pub fn C_vector(elts: &[ValueRef]) -> ValueRef { + unsafe { + return llvm::LLVMConstVector(elts.as_ptr(), elts.len() as c_uint); + } +} + +pub fn C_bytes(cx: &CodegenCx, bytes: &[u8]) -> ValueRef { + C_bytes_in_context(cx.llcx, bytes) +} + +pub fn C_bytes_in_context(llcx: ContextRef, bytes: &[u8]) -> ValueRef { + unsafe { + let ptr = bytes.as_ptr() as *const c_char; + return llvm::LLVMConstStringInContext(llcx, ptr, bytes.len() as c_uint, True); + } +} + +pub fn const_get_elt(v: ValueRef, idx: u64) -> ValueRef { + unsafe { + assert_eq!(idx as c_uint as u64, idx); + let us = &[idx as c_uint]; + let r = llvm::LLVMConstExtractValue(v, us.as_ptr(), us.len() as c_uint); + + debug!("const_get_elt(v={:?}, idx={}, r={:?})", + Value(v), idx, Value(r)); + + r + } +} + +pub fn const_get_real(v: ValueRef) -> Option<(f64, bool)> { + unsafe { + if is_const_real(v) { + let mut loses_info: llvm::Bool = ::std::mem::uninitialized(); + let r = llvm::LLVMConstRealGetDouble(v, &mut loses_info as *mut llvm::Bool); + let loses_info = if loses_info == 1 { true } else { false }; + Some((r, loses_info)) + } else { + None + } + } +} + +pub fn const_to_uint(v: ValueRef) -> u64 { + unsafe { + llvm::LLVMConstIntGetZExtValue(v) + } +} + +pub fn is_const_integral(v: ValueRef) -> bool { + unsafe { + !llvm::LLVMIsAConstantInt(v).is_null() + } +} + +pub fn is_const_real(v: ValueRef) -> bool { + unsafe { + !llvm::LLVMIsAConstantFP(v).is_null() + } +} + + +#[inline] +fn hi_lo_to_u128(lo: u64, hi: u64) -> u128 { + ((hi as u128) << 64) | (lo as u128) +} + +pub fn const_to_opt_u128(v: ValueRef, sign_ext: bool) -> Option { + unsafe { + if is_const_integral(v) { + let (mut lo, mut hi) = (0u64, 0u64); + let success = llvm::LLVMRustConstInt128Get(v, sign_ext, + &mut hi as *mut u64, &mut lo as *mut u64); + if success { + Some(hi_lo_to_u128(lo, hi)) + } else { + None + } + } else { + None + } + } +} + +pub fn langcall(tcx: TyCtxt, + span: Option, + msg: &str, + li: LangItem) + -> DefId { + match tcx.lang_items().require(li) { + Ok(id) => id, + Err(s) => { + let msg = format!("{} {}", msg, s); + match span { + Some(span) => tcx.sess.span_fatal(span, &msg[..]), + None => tcx.sess.fatal(&msg[..]), + } + } + } +} + +// To avoid UB from LLVM, these two functions mask RHS with an +// appropriate mask unconditionally (i.e. the fallback behavior for +// all shifts). For 32- and 64-bit types, this matches the semantics +// of Java. (See related discussion on #1877 and #10183.) + +pub fn build_unchecked_lshift<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + lhs: ValueRef, + rhs: ValueRef +) -> ValueRef { + let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shl, lhs, rhs); + // #1877, #10183: Ensure that input is always valid + let rhs = shift_mask_rhs(bx, rhs); + bx.shl(lhs, rhs) +} + +pub fn build_unchecked_rshift<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef +) -> ValueRef { + let rhs = base::cast_shift_expr_rhs(bx, hir::BinOpKind::Shr, lhs, rhs); + // #1877, #10183: Ensure that input is always valid + let rhs = shift_mask_rhs(bx, rhs); + let is_signed = lhs_t.is_signed(); + if is_signed { + bx.ashr(lhs, rhs) + } else { + bx.lshr(lhs, rhs) + } +} + +fn shift_mask_rhs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, rhs: ValueRef) -> ValueRef { + let rhs_llty = val_ty(rhs); + bx.and(rhs, shift_mask_val(bx, rhs_llty, rhs_llty, false)) +} + +pub fn shift_mask_val<'a, 'tcx>( + bx: &Builder<'a, 'tcx>, + llty: Type, + mask_llty: Type, + invert: bool +) -> ValueRef { + let kind = llty.kind(); + match kind { + TypeKind::Integer => { + // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. + let val = llty.int_width() - 1; + if invert { + C_int(mask_llty, !val as i64) + } else { + C_uint(mask_llty, val) + } + }, + TypeKind::Vector => { + let mask = shift_mask_val(bx, llty.element_type(), mask_llty.element_type(), invert); + bx.vector_splat(mask_llty.vector_length(), mask) + }, + _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind), + } +} + +pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + ty: Ty<'tcx>) + -> ty::PolyFnSig<'tcx> +{ + match ty.sty { + ty::TyFnDef(..) | + // Shims currently have type TyFnPtr. Not sure this should remain. + ty::TyFnPtr(_) => ty.fn_sig(cx.tcx), + ty::TyClosure(def_id, substs) => { + let tcx = cx.tcx; + let sig = substs.closure_sig(def_id, tcx); + + let env_ty = tcx.closure_env_ty(def_id, substs).unwrap(); + sig.map_bound(|sig| tcx.mk_fn_sig( + iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()), + sig.output(), + sig.variadic, + sig.unsafety, + sig.abi + )) + } + ty::TyGenerator(def_id, substs, _) => { + let tcx = cx.tcx; + let sig = substs.poly_sig(def_id, cx.tcx); + + let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); + let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty); + + sig.map_bound(|sig| { + let state_did = tcx.lang_items().gen_state().unwrap(); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.intern_substs(&[ + sig.yield_ty.into(), + sig.return_ty.into(), + ]); + let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); + + tcx.mk_fn_sig(iter::once(env_ty), + ret_ty, + false, + hir::Unsafety::Normal, + Abi::Rust + ) + }) + } + _ => bug!("unexpected type {:?} to ty_fn_sig", ty) + } +} diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs new file mode 100644 index 0000000000000..f0b5f4b887971 --- /dev/null +++ b/src/librustc_codegen_llvm/consts.rs @@ -0,0 +1,418 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc::c_uint; +use llvm; +use llvm::{SetUnnamedAddr}; +use llvm::{ValueRef, True}; +use rustc::hir::def_id::DefId; +use rustc::hir::map as hir_map; +use debuginfo; +use base; +use monomorphize::MonoItem; +use common::{CodegenCx, val_ty}; +use declare; +use monomorphize::Instance; +use syntax_pos::Span; +use syntax_pos::symbol::LocalInternedString; +use type_::Type; +use type_of::LayoutLlvmExt; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::{Align, LayoutOf}; + +use rustc::hir::{self, CodegenFnAttrs, CodegenFnAttrFlags}; + +use std::ffi::{CStr, CString}; + +pub fn ptrcast(val: ValueRef, ty: Type) -> ValueRef { + unsafe { + llvm::LLVMConstPointerCast(val, ty.to_ref()) + } +} + +pub fn bitcast(val: ValueRef, ty: Type) -> ValueRef { + unsafe { + llvm::LLVMConstBitCast(val, ty.to_ref()) + } +} + +fn set_global_alignment(cx: &CodegenCx, + gv: ValueRef, + mut align: Align) { + // The target may require greater alignment for globals than the type does. + // Note: GCC and Clang also allow `__attribute__((aligned))` on variables, + // which can force it to be smaller. Rust doesn't support this yet. + if let Some(min) = cx.sess().target.target.options.min_global_align { + match ty::layout::Align::from_bits(min, min) { + Ok(min) => align = align.max(min), + Err(err) => { + cx.sess().err(&format!("invalid minimum global alignment: {}", err)); + } + } + } + unsafe { + llvm::LLVMSetAlignment(gv, align.abi() as u32); + } +} + +pub fn addr_of_mut(cx: &CodegenCx, + cv: ValueRef, + align: Align, + kind: &str) + -> ValueRef { + unsafe { + let name = cx.generate_local_symbol_name(kind); + let gv = declare::define_global(cx, &name[..], val_ty(cv)).unwrap_or_else(||{ + bug!("symbol `{}` is already defined", name); + }); + llvm::LLVMSetInitializer(gv, cv); + set_global_alignment(cx, gv, align); + llvm::LLVMRustSetLinkage(gv, llvm::Linkage::PrivateLinkage); + SetUnnamedAddr(gv, true); + gv + } +} + +pub fn addr_of(cx: &CodegenCx, + cv: ValueRef, + align: Align, + kind: &str) + -> ValueRef { + if let Some(&gv) = cx.const_globals.borrow().get(&cv) { + unsafe { + // Upgrade the alignment in cases where the same constant is used with different + // alignment requirements + let llalign = align.abi() as u32; + if llalign > llvm::LLVMGetAlignment(gv) { + llvm::LLVMSetAlignment(gv, llalign); + } + } + return gv; + } + let gv = addr_of_mut(cx, cv, align, kind); + unsafe { + llvm::LLVMSetGlobalConstant(gv, True); + } + cx.const_globals.borrow_mut().insert(cv, gv); + gv +} + +pub fn get_static(cx: &CodegenCx, def_id: DefId) -> ValueRef { + let instance = Instance::mono(cx.tcx, def_id); + if let Some(&g) = cx.instances.borrow().get(&instance) { + return g; + } + + let defined_in_current_codegen_unit = cx.codegen_unit + .items() + .contains_key(&MonoItem::Static(def_id)); + assert!(!defined_in_current_codegen_unit, + "consts::get_static() should always hit the cache for \ + statics defined in the same CGU, but did not for `{:?}`", + def_id); + + let ty = instance.ty(cx.tcx); + let sym = cx.tcx.symbol_name(instance).as_str(); + + debug!("get_static: sym={} instance={:?}", sym, instance); + + let g = if let Some(id) = cx.tcx.hir.as_local_node_id(def_id) { + + let llty = cx.layout_of(ty).llvm_type(cx); + let (g, attrs) = match cx.tcx.hir.get(id) { + hir_map::NodeItem(&hir::Item { + ref attrs, span, node: hir::ItemKind::Static(..), .. + }) => { + if declare::get_declared_value(cx, &sym[..]).is_some() { + span_bug!(span, "Conflicting symbol names for static?"); + } + + let g = declare::define_global(cx, &sym[..], llty).unwrap(); + + if !cx.tcx.is_reachable_non_generic(def_id) { + unsafe { + llvm::LLVMRustSetVisibility(g, llvm::Visibility::Hidden); + } + } + + (g, attrs) + } + + hir_map::NodeForeignItem(&hir::ForeignItem { + ref attrs, span, node: hir::ForeignItemKind::Static(..), .. + }) => { + let fn_attrs = cx.tcx.codegen_fn_attrs(def_id); + (check_and_apply_linkage(cx, &fn_attrs, ty, sym, Some(span)), attrs) + } + + item => bug!("get_static: expected static, found {:?}", item) + }; + + debug!("get_static: sym={} attrs={:?}", sym, attrs); + + for attr in attrs { + if attr.check_name("thread_local") { + llvm::set_thread_local_mode(g, cx.tls_model); + } + } + + g + } else { + // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow? + debug!("get_static: sym={} item_attr={:?}", sym, cx.tcx.item_attrs(def_id)); + + let attrs = cx.tcx.codegen_fn_attrs(def_id); + let g = check_and_apply_linkage(cx, &attrs, ty, sym, None); + + // Thread-local statics in some other crate need to *always* be linked + // against in a thread-local fashion, so we need to be sure to apply the + // thread-local attribute locally if it was present remotely. If we + // don't do this then linker errors can be generated where the linker + // complains that one object files has a thread local version of the + // symbol and another one doesn't. + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + llvm::set_thread_local_mode(g, cx.tls_model); + } + + if cx.use_dll_storage_attrs && !cx.tcx.is_foreign_item(def_id) { + // This item is external but not foreign, i.e. it originates from an external Rust + // crate. Since we don't know whether this crate will be linked dynamically or + // statically in the final application, we always mark such symbols as 'dllimport'. + // If final linkage happens to be static, we rely on compiler-emitted __imp_ stubs to + // make things work. + // + // However, in some scenarios we defer emission of statics to downstream + // crates, so there are cases where a static with an upstream DefId + // is actually present in the current crate. We can find out via the + // is_codegened_item query. + if !cx.tcx.is_codegened_item(def_id) { + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } + } + } + g + }; + + if cx.use_dll_storage_attrs && cx.tcx.is_dllimport_foreign_item(def_id) { + // For foreign (native) libs we know the exact storage type to use. + unsafe { + llvm::LLVMSetDLLStorageClass(g, llvm::DLLStorageClass::DllImport); + } + } + + cx.instances.borrow_mut().insert(instance, g); + cx.statics.borrow_mut().insert(g, def_id); + g +} + +fn check_and_apply_linkage<'tcx>( + cx: &CodegenCx<'_, 'tcx>, + attrs: &CodegenFnAttrs, + ty: Ty<'tcx>, + sym: LocalInternedString, + span: Option +) -> ValueRef { + let llty = cx.layout_of(ty).llvm_type(cx); + if let Some(linkage) = attrs.linkage { + debug!("get_static: sym={} linkage={:?}", sym, linkage); + + // If this is a static with a linkage specified, then we need to handle + // it a little specially. The typesystem prevents things like &T and + // extern "C" fn() from being non-null, so we can't just declare a + // static and call it a day. Some linkages (like weak) will make it such + // that the static actually has a null value. + let llty2 = match ty.sty { + ty::TyRawPtr(ref mt) => cx.layout_of(mt.ty).llvm_type(cx), + _ => { + if span.is_some() { + cx.sess().span_fatal(span.unwrap(), "must have type `*const T` or `*mut T`") + } else { + bug!("must have type `*const T` or `*mut T`") + } + } + }; + unsafe { + // Declare a symbol `foo` with the desired linkage. + let g1 = declare::declare_global(cx, &sym, llty2); + llvm::LLVMRustSetLinkage(g1, base::linkage_to_llvm(linkage)); + + // Declare an internal global `extern_with_linkage_foo` which + // is initialized with the address of `foo`. If `foo` is + // discarded during linking (for example, if `foo` has weak + // linkage and there are no definitions), then + // `extern_with_linkage_foo` will instead be initialized to + // zero. + let mut real_name = "_rust_extern_with_linkage_".to_string(); + real_name.push_str(&sym); + let g2 = declare::define_global(cx, &real_name, llty).unwrap_or_else(||{ + if span.is_some() { + cx.sess().span_fatal( + span.unwrap(), + &format!("symbol `{}` is already defined", &sym) + ) + } else { + bug!("symbol `{}` is already defined", &sym) + } + }); + llvm::LLVMRustSetLinkage(g2, llvm::Linkage::InternalLinkage); + llvm::LLVMSetInitializer(g2, g1); + g2 + } + } else { + // Generate an external declaration. + // FIXME(nagisa): investigate whether it can be changed into define_global + declare::declare_global(cx, &sym, llty) + } +} + +pub fn codegen_static<'a, 'tcx>( + cx: &CodegenCx<'a, 'tcx>, + def_id: DefId, + is_mutable: bool, +) { + unsafe { + let attrs = cx.tcx.codegen_fn_attrs(def_id); + + let (v, alloc) = match ::mir::codegen_static_initializer(cx, def_id) { + Ok(v) => v, + // Error has already been reported + Err(_) => return, + }; + + let g = get_static(cx, def_id); + + // boolean SSA values are i1, but they have to be stored in i8 slots, + // otherwise some LLVM optimization passes don't work as expected + let mut val_llty = val_ty(v); + let v = if val_llty == Type::i1(cx) { + val_llty = Type::i8(cx); + llvm::LLVMConstZExt(v, val_llty.to_ref()) + } else { + v + }; + + let instance = Instance::mono(cx.tcx, def_id); + let ty = instance.ty(cx.tcx); + let llty = cx.layout_of(ty).llvm_type(cx); + let g = if val_llty == llty { + g + } else { + // If we created the global with the wrong type, + // correct the type. + let empty_string = CString::new("").unwrap(); + let name_str_ref = CStr::from_ptr(llvm::LLVMGetValueName(g)); + let name_string = CString::new(name_str_ref.to_bytes()).unwrap(); + llvm::LLVMSetValueName(g, empty_string.as_ptr()); + + let linkage = llvm::LLVMRustGetLinkage(g); + let visibility = llvm::LLVMRustGetVisibility(g); + + let new_g = llvm::LLVMRustGetOrInsertGlobal( + cx.llmod, name_string.as_ptr(), val_llty.to_ref()); + + llvm::LLVMRustSetLinkage(new_g, linkage); + llvm::LLVMRustSetVisibility(new_g, visibility); + + // To avoid breaking any invariants, we leave around the old + // global for the moment; we'll replace all references to it + // with the new global later. (See base::codegen_backend.) + cx.statics_to_rauw.borrow_mut().push((g, new_g)); + new_g + }; + set_global_alignment(cx, g, cx.align_of(ty)); + llvm::LLVMSetInitializer(g, v); + + // As an optimization, all shared statics which do not have interior + // mutability are placed into read-only memory. + if !is_mutable { + if cx.type_is_freeze(ty) { + llvm::LLVMSetGlobalConstant(g, llvm::True); + } + } + + debuginfo::create_global_var_metadata(cx, def_id, g); + + if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) { + llvm::set_thread_local_mode(g, cx.tls_model); + + // Do not allow LLVM to change the alignment of a TLS on macOS. + // + // By default a global's alignment can be freely increased. + // This allows LLVM to generate more performant instructions + // e.g. using load-aligned into a SIMD register. + // + // However, on macOS 10.10 or below, the dynamic linker does not + // respect any alignment given on the TLS (radar 24221680). + // This will violate the alignment assumption, and causing segfault at runtime. + // + // This bug is very easy to trigger. In `println!` and `panic!`, + // the `LOCAL_STDOUT`/`LOCAL_STDERR` handles are stored in a TLS, + // which the values would be `mem::replace`d on initialization. + // The implementation of `mem::replace` will use SIMD + // whenever the size is 32 bytes or higher. LLVM notices SIMD is used + // and tries to align `LOCAL_STDOUT`/`LOCAL_STDERR` to a 32-byte boundary, + // which macOS's dyld disregarded and causing crashes + // (see issues #51794, #51758, #50867, #48866 and #44056). + // + // To workaround the bug, we trick LLVM into not increasing + // the global's alignment by explicitly assigning a section to it + // (equivalent to automatically generating a `#[link_section]` attribute). + // See the comment in the `GlobalValue::canIncreaseAlignment()` function + // of `lib/IR/Globals.cpp` for why this works. + // + // When the alignment is not increased, the optimized `mem::replace` + // will use load-unaligned instructions instead, and thus avoiding the crash. + // + // We could remove this hack whenever we decide to drop macOS 10.10 support. + if cx.tcx.sess.target.target.options.is_like_osx { + let sect_name = if alloc.bytes.iter().all(|b| *b == 0) { + CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") + } else { + CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0") + }; + llvm::LLVMSetSection(g, sect_name.as_ptr()); + } + } + + + // Wasm statics with custom link sections get special treatment as they + // go into custom sections of the wasm executable. + if cx.tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + if let Some(section) = attrs.link_section { + let section = llvm::LLVMMDStringInContext( + cx.llcx, + section.as_str().as_ptr() as *const _, + section.as_str().len() as c_uint, + ); + let alloc = llvm::LLVMMDStringInContext( + cx.llcx, + alloc.bytes.as_ptr() as *const _, + alloc.bytes.len() as c_uint, + ); + let data = [section, alloc]; + let meta = llvm::LLVMMDNodeInContext(cx.llcx, data.as_ptr(), 2); + llvm::LLVMAddNamedMetadataOperand( + cx.llmod, + "wasm.custom_sections\0".as_ptr() as *const _, + meta, + ); + } + } else { + base::set_link_section(g, &attrs); + } + + if attrs.flags.contains(CodegenFnAttrFlags::USED) { + // This static will be stored in the llvm.used variable which is an array of i8* + let cast = llvm::LLVMConstPointerCast(g, Type::i8p(cx).to_ref()); + cx.used_statics.borrow_mut().push(cast); + } + } +} diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs new file mode 100644 index 0000000000000..b774d7c5def21 --- /dev/null +++ b/src/librustc_codegen_llvm/context.rs @@ -0,0 +1,783 @@ +// Copyright 2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use common; +use llvm; +use llvm::{ContextRef, ModuleRef, ValueRef}; +use rustc::dep_graph::DepGraphSafe; +use rustc::hir; +use rustc::hir::def_id::DefId; +use debuginfo; +use callee; +use base; +use declare; +use monomorphize::Instance; + +use monomorphize::partitioning::CodegenUnit; +use type_::Type; +use type_of::PointeeInfo; + +use rustc_data_structures::base_n; +use rustc::mir::mono::Stats; +use rustc::session::config::{self, NoDebugInfo}; +use rustc::session::Session; +use rustc::ty::layout::{LayoutError, LayoutOf, Size, TyLayout}; +use rustc::ty::{self, Ty, TyCtxt}; +use rustc::util::nodemap::FxHashMap; +use rustc_target::spec::{HasTargetSpec, Target}; + +use std::ffi::{CStr, CString}; +use std::cell::{Cell, RefCell}; +use std::ptr; +use std::iter; +use std::str; +use std::sync::Arc; +use syntax::symbol::LocalInternedString; +use abi::Abi; + +/// There is one `CodegenCx` per compilation unit. Each one has its own LLVM +/// `ContextRef` so that several compilation units may be optimized in parallel. +/// All other LLVM data structures in the `CodegenCx` are tied to that `ContextRef`. +pub struct CodegenCx<'a, 'tcx: 'a> { + pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub check_overflow: bool, + pub use_dll_storage_attrs: bool, + pub tls_model: llvm::ThreadLocalMode, + + pub llmod: ModuleRef, + pub llcx: ContextRef, + pub stats: RefCell, + pub codegen_unit: Arc>, + + /// Cache instances of monomorphic and polymorphic items + pub instances: RefCell, ValueRef>>, + /// Cache generated vtables + pub vtables: RefCell, + Option>), ValueRef>>, + /// Cache of constant strings, + pub const_cstr_cache: RefCell>, + + /// Reverse-direction for const ptrs cast from globals. + /// Key is a ValueRef holding a *T, + /// Val is a ValueRef holding a *[T]. + /// + /// Needed because LLVM loses pointer->pointee association + /// when we ptrcast, and we have to ptrcast during codegen + /// of a [T] const because we form a slice, a (*T,usize) pair, not + /// a pointer to an LLVM array type. Similar for trait objects. + pub const_unsized: RefCell>, + + /// Cache of emitted const globals (value -> global) + pub const_globals: RefCell>, + + /// Mapping from static definitions to their DefId's. + pub statics: RefCell>, + + /// List of globals for static variables which need to be passed to the + /// LLVM function ReplaceAllUsesWith (RAUW) when codegen is complete. + /// (We have to make sure we don't invalidate any ValueRefs referring + /// to constants.) + pub statics_to_rauw: RefCell>, + + /// Statics that will be placed in the llvm.used variable + /// See http://llvm.org/docs/LangRef.html#the-llvm-used-global-variable for details + pub used_statics: RefCell>, + + pub lltypes: RefCell, Option), Type>>, + pub scalar_lltypes: RefCell, Type>>, + pub pointee_infos: RefCell, Size), Option>>, + pub isize_ty: Type, + + pub dbg_cx: Option>, + + eh_personality: Cell>, + eh_unwind_resume: Cell>, + pub rust_try_fn: Cell>, + + intrinsics: RefCell>, + + /// A counter that is used for generating local symbol names + local_gen_sym_counter: Cell, +} + +impl<'a, 'tcx> DepGraphSafe for CodegenCx<'a, 'tcx> { +} + +pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode { + let reloc_model_arg = match sess.opts.cg.relocation_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.relocation_model[..], + }; + + match ::back::write::RELOC_MODEL_ARGS.iter().find( + |&&arg| arg.0 == reloc_model_arg) { + Some(x) => x.1, + _ => { + sess.err(&format!("{:?} is not a valid relocation mode", + reloc_model_arg)); + sess.abort_if_errors(); + bug!(); + } + } +} + +fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode { + let tls_model_arg = match sess.opts.debugging_opts.tls_model { + Some(ref s) => &s[..], + None => &sess.target.target.options.tls_model[..], + }; + + match ::back::write::TLS_MODEL_ARGS.iter().find( + |&&arg| arg.0 == tls_model_arg) { + Some(x) => x.1, + _ => { + sess.err(&format!("{:?} is not a valid TLS model", + tls_model_arg)); + sess.abort_if_errors(); + bug!(); + } + } +} + +fn is_any_library(sess: &Session) -> bool { + sess.crate_types.borrow().iter().any(|ty| { + *ty != config::CrateTypeExecutable + }) +} + +pub fn is_pie_binary(sess: &Session) -> bool { + !is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC +} + +pub unsafe fn create_context_and_module(sess: &Session, mod_name: &str) -> (ContextRef, ModuleRef) { + let llcx = llvm::LLVMRustContextCreate(sess.fewer_names()); + let mod_name = CString::new(mod_name).unwrap(); + let llmod = llvm::LLVMModuleCreateWithNameInContext(mod_name.as_ptr(), llcx); + + // Ensure the data-layout values hardcoded remain the defaults. + if sess.target.target.options.is_builtin { + let tm = ::back::write::create_target_machine(sess, false); + llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm); + llvm::LLVMRustDisposeTargetMachine(tm); + + let data_layout = llvm::LLVMGetDataLayout(llmod); + let data_layout = str::from_utf8(CStr::from_ptr(data_layout).to_bytes()) + .ok().expect("got a non-UTF8 data-layout from LLVM"); + + // Unfortunately LLVM target specs change over time, and right now we + // don't have proper support to work with any more than one + // `data_layout` than the one that is in the rust-lang/rust repo. If + // this compiler is configured against a custom LLVM, we may have a + // differing data layout, even though we should update our own to use + // that one. + // + // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we + // disable this check entirely as we may be configured with something + // that has a different target layout. + // + // Unsure if this will actually cause breakage when rustc is configured + // as such. + // + // FIXME(#34960) + let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); + let custom_llvm_used = cfg_llvm_root.trim() != ""; + + if !custom_llvm_used && sess.target.target.data_layout != data_layout { + bug!("data-layout for builtin `{}` target, `{}`, \ + differs from LLVM default, `{}`", + sess.target.target.llvm_target, + sess.target.target.data_layout, + data_layout); + } + } + + let data_layout = CString::new(&sess.target.target.data_layout[..]).unwrap(); + llvm::LLVMSetDataLayout(llmod, data_layout.as_ptr()); + + let llvm_target = sess.target.target.llvm_target.as_bytes(); + let llvm_target = CString::new(llvm_target).unwrap(); + llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr()); + + if is_pie_binary(sess) { + llvm::LLVMRustSetModulePIELevel(llmod); + } + + (llcx, llmod) +} + +impl<'a, 'tcx> CodegenCx<'a, 'tcx> { + pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, + codegen_unit: Arc>, + llmod_id: &str) + -> CodegenCx<'a, 'tcx> { + // An interesting part of Windows which MSVC forces our hand on (and + // apparently MinGW didn't) is the usage of `dllimport` and `dllexport` + // attributes in LLVM IR as well as native dependencies (in C these + // correspond to `__declspec(dllimport)`). + // + // Whenever a dynamic library is built by MSVC it must have its public + // interface specified by functions tagged with `dllexport` or otherwise + // they're not available to be linked against. This poses a few problems + // for the compiler, some of which are somewhat fundamental, but we use + // the `use_dll_storage_attrs` variable below to attach the `dllexport` + // attribute to all LLVM functions that are exported e.g. they're + // already tagged with external linkage). This is suboptimal for a few + // reasons: + // + // * If an object file will never be included in a dynamic library, + // there's no need to attach the dllexport attribute. Most object + // files in Rust are not destined to become part of a dll as binaries + // are statically linked by default. + // * If the compiler is emitting both an rlib and a dylib, the same + // source object file is currently used but with MSVC this may be less + // feasible. The compiler may be able to get around this, but it may + // involve some invasive changes to deal with this. + // + // The flipside of this situation is that whenever you link to a dll and + // you import a function from it, the import should be tagged with + // `dllimport`. At this time, however, the compiler does not emit + // `dllimport` for any declarations other than constants (where it is + // required), which is again suboptimal for even more reasons! + // + // * Calling a function imported from another dll without using + // `dllimport` causes the linker/compiler to have extra overhead (one + // `jmp` instruction on x86) when calling the function. + // * The same object file may be used in different circumstances, so a + // function may be imported from a dll if the object is linked into a + // dll, but it may be just linked against if linked into an rlib. + // * The compiler has no knowledge about whether native functions should + // be tagged dllimport or not. + // + // For now the compiler takes the perf hit (I do not have any numbers to + // this effect) by marking very little as `dllimport` and praying the + // linker will take care of everything. Fixing this problem will likely + // require adding a few attributes to Rust itself (feature gated at the + // start) and then strongly recommending static linkage on MSVC! + let use_dll_storage_attrs = tcx.sess.target.target.options.is_like_msvc; + + let check_overflow = tcx.sess.overflow_checks(); + + let tls_model = get_tls_model(&tcx.sess); + + unsafe { + let (llcx, llmod) = create_context_and_module(&tcx.sess, + &llmod_id[..]); + + let dbg_cx = if tcx.sess.opts.debuginfo != NoDebugInfo { + let dctx = debuginfo::CrateDebugContext::new(llmod); + debuginfo::metadata::compile_unit_metadata(tcx, + &codegen_unit.name().as_str(), + &dctx); + Some(dctx) + } else { + None + }; + + let mut cx = CodegenCx { + tcx, + check_overflow, + use_dll_storage_attrs, + tls_model, + llmod, + llcx, + stats: RefCell::new(Stats::default()), + codegen_unit, + instances: RefCell::new(FxHashMap()), + vtables: RefCell::new(FxHashMap()), + const_cstr_cache: RefCell::new(FxHashMap()), + const_unsized: RefCell::new(FxHashMap()), + const_globals: RefCell::new(FxHashMap()), + statics: RefCell::new(FxHashMap()), + statics_to_rauw: RefCell::new(Vec::new()), + used_statics: RefCell::new(Vec::new()), + lltypes: RefCell::new(FxHashMap()), + scalar_lltypes: RefCell::new(FxHashMap()), + pointee_infos: RefCell::new(FxHashMap()), + isize_ty: Type::from_ref(ptr::null_mut()), + dbg_cx, + eh_personality: Cell::new(None), + eh_unwind_resume: Cell::new(None), + rust_try_fn: Cell::new(None), + intrinsics: RefCell::new(FxHashMap()), + local_gen_sym_counter: Cell::new(0), + }; + cx.isize_ty = Type::isize(&cx); + cx + } + } + + pub fn into_stats(self) -> Stats { + self.stats.into_inner() + } +} + +impl<'b, 'tcx> CodegenCx<'b, 'tcx> { + pub fn sess<'a>(&'a self) -> &'a Session { + &self.tcx.sess + } + + pub fn get_intrinsic(&self, key: &str) -> ValueRef { + if let Some(v) = self.intrinsics.borrow().get(key).cloned() { + return v; + } + match declare_intrinsic(self, key) { + Some(v) => return v, + None => bug!("unknown intrinsic '{}'", key) + } + } + + /// Generate a new symbol name with the given prefix. This symbol name must + /// only be used for definitions with `internal` or `private` linkage. + pub fn generate_local_symbol_name(&self, prefix: &str) -> String { + let idx = self.local_gen_sym_counter.get(); + self.local_gen_sym_counter.set(idx + 1); + // Include a '.' character, so there can be no accidental conflicts with + // user defined names + let mut name = String::with_capacity(prefix.len() + 6); + name.push_str(prefix); + name.push_str("."); + base_n::push_str(idx as u128, base_n::ALPHANUMERIC_ONLY, &mut name); + name + } + + pub fn eh_personality(&self) -> ValueRef { + // The exception handling personality function. + // + // If our compilation unit has the `eh_personality` lang item somewhere + // within it, then we just need to codegen that. Otherwise, we're + // building an rlib which will depend on some upstream implementation of + // this function, so we just codegen a generic reference to it. We don't + // specify any of the types for the function, we just make it a symbol + // that LLVM can later use. + // + // Note that MSVC is a little special here in that we don't use the + // `eh_personality` lang item at all. Currently LLVM has support for + // both Dwarf and SEH unwind mechanisms for MSVC targets and uses the + // *name of the personality function* to decide what kind of unwind side + // tables/landing pads to emit. It looks like Dwarf is used by default, + // injecting a dependency on the `_Unwind_Resume` symbol for resuming + // an "exception", but for MSVC we want to force SEH. This means that we + // can't actually have the personality function be our standard + // `rust_eh_personality` function, but rather we wired it up to the + // CRT's custom personality function, which forces LLVM to consider + // landing pads as "landing pads for SEH". + if let Some(llpersonality) = self.eh_personality.get() { + return llpersonality + } + let tcx = self.tcx; + let llfn = match tcx.lang_items().eh_personality() { + Some(def_id) if !base::wants_msvc_seh(self.sess()) => { + callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[])) + } + _ => { + let name = if base::wants_msvc_seh(self.sess()) { + "__CxxFrameHandler3" + } else { + "rust_eh_personality" + }; + let fty = Type::variadic_func(&[], &Type::i32(self)); + declare::declare_cfn(self, name, fty) + } + }; + self.eh_personality.set(Some(llfn)); + llfn + } + + // Returns a ValueRef of the "eh_unwind_resume" lang item if one is defined, + // otherwise declares it as an external function. + pub fn eh_unwind_resume(&self) -> ValueRef { + use attributes; + let unwresume = &self.eh_unwind_resume; + if let Some(llfn) = unwresume.get() { + return llfn; + } + + let tcx = self.tcx; + assert!(self.sess().target.target.options.custom_unwind_resume); + if let Some(def_id) = tcx.lang_items().eh_unwind_resume() { + let llfn = callee::resolve_and_get_fn(self, def_id, tcx.intern_substs(&[])); + unwresume.set(Some(llfn)); + return llfn; + } + + let ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig( + iter::once(tcx.mk_mut_ptr(tcx.types.u8)), + tcx.types.never, + false, + hir::Unsafety::Unsafe, + Abi::C + ))); + + let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty); + attributes::unwind(llfn, true); + unwresume.set(Some(llfn)); + llfn + } + + pub fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool { + common::type_needs_drop(self.tcx, ty) + } + + pub fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { + common::type_is_sized(self.tcx, ty) + } + + pub fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool { + common::type_is_freeze(self.tcx, ty) + } + + pub fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool { + use syntax_pos::DUMMY_SP; + if ty.is_sized(self.tcx.at(DUMMY_SP), ty::ParamEnv::reveal_all()) { + return false; + } + + let tail = self.tcx.struct_tail(ty); + match tail.sty { + ty::TyForeign(..) => false, + ty::TyStr | ty::TySlice(..) | ty::TyDynamic(..) => true, + _ => bug!("unexpected unsized tail: {:?}", tail.sty), + } + } +} + +impl<'a, 'tcx> ty::layout::HasDataLayout for &'a CodegenCx<'a, 'tcx> { + fn data_layout(&self) -> &ty::layout::TargetDataLayout { + &self.tcx.data_layout + } +} + +impl<'a, 'tcx> HasTargetSpec for &'a CodegenCx<'a, 'tcx> { + fn target_spec(&self) -> &Target { + &self.tcx.sess.target.target + } +} + +impl<'a, 'tcx> ty::layout::HasTyCtxt<'tcx> for &'a CodegenCx<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { + self.tcx + } +} + +impl<'a, 'tcx> LayoutOf for &'a CodegenCx<'a, 'tcx> { + type Ty = Ty<'tcx>; + type TyLayout = TyLayout<'tcx>; + + fn layout_of(self, ty: Ty<'tcx>) -> Self::TyLayout { + self.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)) + .unwrap_or_else(|e| match e { + LayoutError::SizeOverflow(_) => self.sess().fatal(&e.to_string()), + _ => bug!("failed to get layout for `{}`: {}", ty, e) + }) + } +} + +/// Declare any llvm intrinsics that you might need +fn declare_intrinsic(cx: &CodegenCx, key: &str) -> Option { + macro_rules! ifn { + ($name:expr, fn() -> $ret:expr) => ( + if key == $name { + let f = declare::declare_cfn(cx, $name, Type::func(&[], &$ret)); + llvm::SetUnnamedAddr(f, false); + cx.intrinsics.borrow_mut().insert($name, f.clone()); + return Some(f); + } + ); + ($name:expr, fn(...) -> $ret:expr) => ( + if key == $name { + let f = declare::declare_cfn(cx, $name, Type::variadic_func(&[], &$ret)); + llvm::SetUnnamedAddr(f, false); + cx.intrinsics.borrow_mut().insert($name, f.clone()); + return Some(f); + } + ); + ($name:expr, fn($($arg:expr),*) -> $ret:expr) => ( + if key == $name { + let f = declare::declare_cfn(cx, $name, Type::func(&[$($arg),*], &$ret)); + llvm::SetUnnamedAddr(f, false); + cx.intrinsics.borrow_mut().insert($name, f.clone()); + return Some(f); + } + ); + } + macro_rules! mk_struct { + ($($field_ty:expr),*) => (Type::struct_(cx, &[$($field_ty),*], false)) + } + + let i8p = Type::i8p(cx); + let void = Type::void(cx); + let i1 = Type::i1(cx); + let t_i8 = Type::i8(cx); + let t_i16 = Type::i16(cx); + let t_i32 = Type::i32(cx); + let t_i64 = Type::i64(cx); + let t_i128 = Type::i128(cx); + let t_f32 = Type::f32(cx); + let t_f64 = Type::f64(cx); + + let t_v2f32 = Type::vector(&t_f32, 2); + let t_v4f32 = Type::vector(&t_f32, 4); + let t_v8f32 = Type::vector(&t_f32, 8); + let t_v16f32 = Type::vector(&t_f32, 16); + + let t_v2f64 = Type::vector(&t_f64, 2); + let t_v4f64 = Type::vector(&t_f64, 4); + let t_v8f64 = Type::vector(&t_f64, 8); + + ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); + ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); + ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); + ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void); + ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void); + ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void); + ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void); + ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void); + ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void); + + ifn!("llvm.trap", fn() -> void); + ifn!("llvm.debugtrap", fn() -> void); + ifn!("llvm.frameaddress", fn(t_i32) -> i8p); + + ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32); + ifn!("llvm.powi.v2f32", fn(t_v2f32, t_i32) -> t_v2f32); + ifn!("llvm.powi.v4f32", fn(t_v4f32, t_i32) -> t_v4f32); + ifn!("llvm.powi.v8f32", fn(t_v8f32, t_i32) -> t_v8f32); + ifn!("llvm.powi.v16f32", fn(t_v16f32, t_i32) -> t_v16f32); + ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64); + ifn!("llvm.powi.v2f64", fn(t_v2f64, t_i32) -> t_v2f64); + ifn!("llvm.powi.v4f64", fn(t_v4f64, t_i32) -> t_v4f64); + ifn!("llvm.powi.v8f64", fn(t_v8f64, t_i32) -> t_v8f64); + + ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.pow.v2f32", fn(t_v2f32, t_v2f32) -> t_v2f32); + ifn!("llvm.pow.v4f32", fn(t_v4f32, t_v4f32) -> t_v4f32); + ifn!("llvm.pow.v8f32", fn(t_v8f32, t_v8f32) -> t_v8f32); + ifn!("llvm.pow.v16f32", fn(t_v16f32, t_v16f32) -> t_v16f32); + ifn!("llvm.pow.f64", fn(t_f64, t_f64) -> t_f64); + ifn!("llvm.pow.v2f64", fn(t_v2f64, t_v2f64) -> t_v2f64); + ifn!("llvm.pow.v4f64", fn(t_v4f64, t_v4f64) -> t_v4f64); + ifn!("llvm.pow.v8f64", fn(t_v8f64, t_v8f64) -> t_v8f64); + + ifn!("llvm.sqrt.f32", fn(t_f32) -> t_f32); + ifn!("llvm.sqrt.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.sqrt.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.sqrt.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.sqrt.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.sqrt.f64", fn(t_f64) -> t_f64); + ifn!("llvm.sqrt.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.sqrt.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.sqrt.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.sin.f32", fn(t_f32) -> t_f32); + ifn!("llvm.sin.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.sin.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.sin.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.sin.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.sin.f64", fn(t_f64) -> t_f64); + ifn!("llvm.sin.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.sin.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.sin.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.cos.f32", fn(t_f32) -> t_f32); + ifn!("llvm.cos.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.cos.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.cos.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.cos.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.cos.f64", fn(t_f64) -> t_f64); + ifn!("llvm.cos.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.cos.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.cos.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.exp.f32", fn(t_f32) -> t_f32); + ifn!("llvm.exp.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.exp.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.exp.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.exp.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.exp.f64", fn(t_f64) -> t_f64); + ifn!("llvm.exp.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.exp.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.exp.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.exp2.f32", fn(t_f32) -> t_f32); + ifn!("llvm.exp2.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.exp2.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.exp2.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.exp2.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.exp2.f64", fn(t_f64) -> t_f64); + ifn!("llvm.exp2.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.exp2.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.exp2.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.log.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.log.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.log.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.log.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.log.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.log.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.log.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.log10.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log10.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.log10.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.log10.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.log10.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.log10.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log10.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.log10.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.log10.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.log2.f32", fn(t_f32) -> t_f32); + ifn!("llvm.log2.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.log2.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.log2.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.log2.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.log2.f64", fn(t_f64) -> t_f64); + ifn!("llvm.log2.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.log2.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.log2.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.fma.f32", fn(t_f32, t_f32, t_f32) -> t_f32); + ifn!("llvm.fma.v2f32", fn(t_v2f32, t_v2f32, t_v2f32) -> t_v2f32); + ifn!("llvm.fma.v4f32", fn(t_v4f32, t_v4f32, t_v4f32) -> t_v4f32); + ifn!("llvm.fma.v8f32", fn(t_v8f32, t_v8f32, t_v8f32) -> t_v8f32); + ifn!("llvm.fma.v16f32", fn(t_v16f32, t_v16f32, t_v16f32) -> t_v16f32); + ifn!("llvm.fma.f64", fn(t_f64, t_f64, t_f64) -> t_f64); + ifn!("llvm.fma.v2f64", fn(t_v2f64, t_v2f64, t_v2f64) -> t_v2f64); + ifn!("llvm.fma.v4f64", fn(t_v4f64, t_v4f64, t_v4f64) -> t_v4f64); + ifn!("llvm.fma.v8f64", fn(t_v8f64, t_v8f64, t_v8f64) -> t_v8f64); + + ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); + ifn!("llvm.fabs.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.fabs.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.fabs.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.fabs.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); + ifn!("llvm.fabs.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.fabs.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.fabs.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); + ifn!("llvm.floor.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.floor.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.floor.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.floor.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); + ifn!("llvm.floor.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.floor.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.floor.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); + ifn!("llvm.ceil.v2f32", fn(t_v2f32) -> t_v2f32); + ifn!("llvm.ceil.v4f32", fn(t_v4f32) -> t_v4f32); + ifn!("llvm.ceil.v8f32", fn(t_v8f32) -> t_v8f32); + ifn!("llvm.ceil.v16f32", fn(t_v16f32) -> t_v16f32); + ifn!("llvm.ceil.f64", fn(t_f64) -> t_f64); + ifn!("llvm.ceil.v2f64", fn(t_v2f64) -> t_v2f64); + ifn!("llvm.ceil.v4f64", fn(t_v4f64) -> t_v4f64); + ifn!("llvm.ceil.v8f64", fn(t_v8f64) -> t_v8f64); + + ifn!("llvm.trunc.f32", fn(t_f32) -> t_f32); + ifn!("llvm.trunc.f64", fn(t_f64) -> t_f64); + + ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64); + ifn!("llvm.round.f32", fn(t_f32) -> t_f32); + ifn!("llvm.round.f64", fn(t_f64) -> t_f64); + + ifn!("llvm.rint.f32", fn(t_f32) -> t_f32); + ifn!("llvm.rint.f64", fn(t_f64) -> t_f64); + ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32); + ifn!("llvm.nearbyint.f64", fn(t_f64) -> t_f64); + + ifn!("llvm.ctpop.i8", fn(t_i8) -> t_i8); + ifn!("llvm.ctpop.i16", fn(t_i16) -> t_i16); + ifn!("llvm.ctpop.i32", fn(t_i32) -> t_i32); + ifn!("llvm.ctpop.i64", fn(t_i64) -> t_i64); + ifn!("llvm.ctpop.i128", fn(t_i128) -> t_i128); + + ifn!("llvm.ctlz.i8", fn(t_i8 , i1) -> t_i8); + ifn!("llvm.ctlz.i16", fn(t_i16, i1) -> t_i16); + ifn!("llvm.ctlz.i32", fn(t_i32, i1) -> t_i32); + ifn!("llvm.ctlz.i64", fn(t_i64, i1) -> t_i64); + ifn!("llvm.ctlz.i128", fn(t_i128, i1) -> t_i128); + + ifn!("llvm.cttz.i8", fn(t_i8 , i1) -> t_i8); + ifn!("llvm.cttz.i16", fn(t_i16, i1) -> t_i16); + ifn!("llvm.cttz.i32", fn(t_i32, i1) -> t_i32); + ifn!("llvm.cttz.i64", fn(t_i64, i1) -> t_i64); + ifn!("llvm.cttz.i128", fn(t_i128, i1) -> t_i128); + + ifn!("llvm.bswap.i16", fn(t_i16) -> t_i16); + ifn!("llvm.bswap.i32", fn(t_i32) -> t_i32); + ifn!("llvm.bswap.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bswap.i128", fn(t_i128) -> t_i128); + + ifn!("llvm.bitreverse.i8", fn(t_i8) -> t_i8); + ifn!("llvm.bitreverse.i16", fn(t_i16) -> t_i16); + ifn!("llvm.bitreverse.i32", fn(t_i32) -> t_i32); + ifn!("llvm.bitreverse.i64", fn(t_i64) -> t_i64); + ifn!("llvm.bitreverse.i128", fn(t_i128) -> t_i128); + + ifn!("llvm.sadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.sadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.sadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.sadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.sadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.uadd.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.uadd.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.uadd.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.uadd.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.uadd.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.ssub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.ssub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.ssub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.ssub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.ssub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.usub.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.usub.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.usub.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.usub.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.usub.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.smul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.smul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.smul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.smul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.smul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.umul.with.overflow.i8", fn(t_i8, t_i8) -> mk_struct!{t_i8, i1}); + ifn!("llvm.umul.with.overflow.i16", fn(t_i16, t_i16) -> mk_struct!{t_i16, i1}); + ifn!("llvm.umul.with.overflow.i32", fn(t_i32, t_i32) -> mk_struct!{t_i32, i1}); + ifn!("llvm.umul.with.overflow.i64", fn(t_i64, t_i64) -> mk_struct!{t_i64, i1}); + ifn!("llvm.umul.with.overflow.i128", fn(t_i128, t_i128) -> mk_struct!{t_i128, i1}); + + ifn!("llvm.lifetime.start", fn(t_i64,i8p) -> void); + ifn!("llvm.lifetime.end", fn(t_i64, i8p) -> void); + + ifn!("llvm.expect.i1", fn(i1, i1) -> i1); + ifn!("llvm.eh.typeid.for", fn(i8p) -> t_i32); + ifn!("llvm.localescape", fn(...) -> void); + ifn!("llvm.localrecover", fn(i8p, i8p, t_i32) -> i8p); + ifn!("llvm.x86.seh.recoverfp", fn(i8p, i8p) -> i8p); + + ifn!("llvm.assume", fn(i1) -> void); + ifn!("llvm.prefetch", fn(i8p, t_i32, t_i32, t_i32) -> void); + + if cx.sess().opts.debuginfo != NoDebugInfo { + ifn!("llvm.dbg.declare", fn(Type::metadata(cx), Type::metadata(cx)) -> void); + ifn!("llvm.dbg.value", fn(Type::metadata(cx), t_i64, Type::metadata(cx)) -> void); + } + return None; +} diff --git a/src/librustc_trans/debuginfo/create_scope_map.rs b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs similarity index 85% rename from src/librustc_trans/debuginfo/create_scope_map.rs rename to src/librustc_codegen_llvm/debuginfo/create_scope_map.rs index bddb3d909402e..fcde7f9bbc33d 100644 --- a/src/librustc_trans/debuginfo/create_scope_map.rs +++ b/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs @@ -15,7 +15,7 @@ use super::utils::{DIB, span_start}; use llvm; use llvm::debuginfo::DIScope; use common::CodegenCx; -use rustc::mir::{Mir, VisibilityScope}; +use rustc::mir::{Mir, SourceScope}; use libc::c_uint; use std::ptr; @@ -45,13 +45,13 @@ impl MirDebugScope { /// Produce DIScope DIEs for each MIR Scope which has variables defined in it. /// If debuginfo is disabled, the returned vector is empty. pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebugContext) - -> IndexVec { + -> IndexVec { let null_scope = MirDebugScope { scope_metadata: ptr::null_mut(), file_start_pos: BytePos(0), file_end_pos: BytePos(0) }; - let mut scopes = IndexVec::from_elem(null_scope, &mir.visibility_scopes); + let mut scopes = IndexVec::from_elem(null_scope, &mir.source_scopes); let debug_context = match *debug_context { FunctionDebugContext::RegularContext(ref data) => data, @@ -62,15 +62,15 @@ pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebu }; // Find all the scopes with variables defined in them. - let mut has_variables = BitVector::new(mir.visibility_scopes.len()); + let mut has_variables = BitVector::new(mir.source_scopes.len()); for var in mir.vars_iter() { let decl = &mir.local_decls[var]; - has_variables.insert(decl.source_info.scope.index()); + has_variables.insert(decl.visibility_scope); } // Instantiate all scopes. - for idx in 0..mir.visibility_scopes.len() { - let scope = VisibilityScope::new(idx); + for idx in 0..mir.source_scopes.len() { + let scope = SourceScope::new(idx); make_mir_scope(cx, &mir, &has_variables, debug_context, scope, &mut scopes); } @@ -79,15 +79,15 @@ pub fn create_mir_scopes(cx: &CodegenCx, mir: &Mir, debug_context: &FunctionDebu fn make_mir_scope(cx: &CodegenCx, mir: &Mir, - has_variables: &BitVector, + has_variables: &BitVector, debug_context: &FunctionDebugContextData, - scope: VisibilityScope, - scopes: &mut IndexVec) { + scope: SourceScope, + scopes: &mut IndexVec) { if scopes[scope].is_valid() { return; } - let scope_data = &mir.visibility_scopes[scope]; + let scope_data = &mir.source_scopes[scope]; let parent_scope = if let Some(parent) = scope_data.parent_scope { make_mir_scope(cx, mir, has_variables, debug_context, parent, scopes); scopes[parent] @@ -102,7 +102,7 @@ fn make_mir_scope(cx: &CodegenCx, return; }; - if !has_variables.contains(scope.index()) { + if !has_variables.contains(scope) { // Do not create a DIScope if there are no variables // defined in this MIR Scope, to avoid debuginfo bloat. diff --git a/src/librustc_trans/debuginfo/doc.rs b/src/librustc_codegen_llvm/debuginfo/doc.rs similarity index 99% rename from src/librustc_trans/debuginfo/doc.rs rename to src/librustc_codegen_llvm/debuginfo/doc.rs index cbecc0eb7d1b5..ce0476b07eb43 100644 --- a/src/librustc_trans/debuginfo/doc.rs +++ b/src/librustc_codegen_llvm/debuginfo/doc.rs @@ -131,9 +131,9 @@ //! when generating prologue instructions we have to make sure that we don't //! emit source location information until the 'real' function body begins. For //! this reason, source location emission is disabled by default for any new -//! function being translated and is only activated after a call to the third +//! function being codegened and is only activated after a call to the third //! function from the list above, `start_emitting_source_locations()`. This -//! function should be called right before regularly starting to translate the +//! function should be called right before regularly starting to codegen the //! top-level block of the given function. //! //! There is one exception to the above rule: `llvm.dbg.declare` instruction diff --git a/src/librustc_trans/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs similarity index 100% rename from src/librustc_trans/debuginfo/gdb.rs rename to src/librustc_codegen_llvm/debuginfo/gdb.rs diff --git a/src/librustc_trans/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs similarity index 97% rename from src/librustc_trans/debuginfo/metadata.rs rename to src/librustc_codegen_llvm/debuginfo/metadata.rs index 2fc6c9d443301..2f4dd5a7ce5bb 100644 --- a/src/librustc_trans/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -23,12 +23,11 @@ use llvm::{self, ValueRef}; use llvm::debuginfo::{DIType, DIFile, DIScope, DIDescriptor, DICompositeType, DILexicalBlock, DIFlags}; -use rustc::hir::TransFnAttrFlags; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc::hir::CodegenFnAttrFlags; use rustc::hir::def::CtorKind; use rustc::hir::def_id::{DefId, CrateNum, LOCAL_CRATE}; -use rustc::ty::fold::TypeVisitor; -use rustc::ty::util::TypeIdHasher; -use rustc::ich::Fingerprint; +use rustc::ich::{Fingerprint, NodeIdHashingMode}; use rustc::ty::Instance; use common::CodegenCx; use rustc::ty::{self, AdtKind, ParamEnv, Ty, TyCtxt}; @@ -40,6 +39,7 @@ use rustc::util::common::path2cstr; use libc::{c_uint, c_longlong}; use std::ffi::CString; use std::fmt::Write; +use std::iter; use std::ptr; use std::path::{Path, PathBuf}; use syntax::ast; @@ -144,9 +144,15 @@ impl<'tcx> TypeMap<'tcx> { // The hasher we are using to generate the UniqueTypeId. We want // something that provides more than the 64 bits of the DefaultHasher. - let mut type_id_hasher = TypeIdHasher::::new(cx.tcx); - type_id_hasher.visit_ty(type_); - let unique_type_id = type_id_hasher.finish().to_hex(); + let mut hasher = StableHasher::::new(); + let mut hcx = cx.tcx.create_stable_hashing_context(); + let type_ = cx.tcx.erase_regions(&type_); + hcx.while_hashing_spans(false, |hcx| { + hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { + type_.hash_stable(hcx, &mut hasher); + }); + }); + let unique_type_id = hasher.finish().to_hex(); let key = self.unique_id_interner.intern(&unique_type_id); self.type_to_unique_id.insert(type_, UniqueTypeId(key)); @@ -277,7 +283,7 @@ fn fixed_vec_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let upper_bound = match array_or_slice_type.sty { ty::TyArray(_, len) => { - len.val.unwrap_u64() as c_longlong + len.unwrap_usize(cx.tcx) as c_longlong } _ => -1 }; @@ -320,7 +326,7 @@ fn vec_slice_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, MemberDescription { name: "data_ptr".to_string(), type_metadata: data_ptr_metadata, - offset: Size::from_bytes(0), + offset: Size::ZERO, size: pointer_size, align: pointer_align, flags: DIFlags::FlagZero, @@ -359,18 +365,16 @@ fn subroutine_type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, &signature, ); - let mut signature_metadata: Vec = Vec::with_capacity(signature.inputs().len() + 1); - - // return type - signature_metadata.push(match signature.output().sty { - ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), - _ => type_metadata(cx, signature.output(), span) - }); - - // regular arguments - for &argument_type in signature.inputs() { - signature_metadata.push(type_metadata(cx, argument_type, span)); - } + let signature_metadata: Vec = iter::once( + // return type + match signature.output().sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, signature.output(), span) + } + ).chain( + // regular arguments + signature.inputs().iter().map(|argument_type| type_metadata(cx, argument_type, span)) + ).collect(); return_if_metadata_created_in_meantime!(cx, unique_type_id); @@ -555,7 +559,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, false) } ty::TyRawPtr(ty::TypeAndMut{ty, ..}) | - ty::TyRef(_, ty::TypeAndMut{ty, ..}) => { + ty::TyRef(_, ty, _) => { match ptr_metadata(ty) { Ok(res) => res, Err(metadata) => return metadata, @@ -591,7 +595,7 @@ pub fn type_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, unique_type_id, usage_site_span).finalize(cx) } - ty::TyGenerator(def_id, substs, _) => { + ty::TyGenerator(def_id, substs, _) => { let upvar_tys : Vec<_> = substs.field_tys(def_id, cx.tcx).map(|t| { cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), t) }).collect(); @@ -946,7 +950,7 @@ impl<'tcx> StructMemberDescriptionFactory<'tcx> { let name = if self.variant.ctor_kind == CtorKind::Fn { format!("__{}", i) } else { - f.name.to_string() + f.ident.to_string() }; let field = layout.field(cx, i); let (size, align) = field.size_and_align(); @@ -1067,9 +1071,9 @@ impl<'tcx> UnionMemberDescriptionFactory<'tcx> { let field = self.layout.field(cx, i); let (size, align) = field.size_and_align(); MemberDescription { - name: f.name.to_string(), + name: f.ident.to_string(), type_metadata: type_metadata(cx, field.ty, self.span), - offset: Size::from_bytes(0), + offset: Size::ZERO, size, align, flags: DIFlags::FlagZero, @@ -1153,7 +1157,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { MemberDescription { name: "".to_string(), type_metadata: variant_type_metadata, - offset: Size::from_bytes(0), + offset: Size::ZERO, size: self.layout.size, align: self.layout.align, flags: DIFlags::FlagZero @@ -1182,7 +1186,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { MemberDescription { name: "".to_string(), type_metadata: variant_type_metadata, - offset: Size::from_bytes(0), + offset: Size::ZERO, size: variant.size, align: variant.align, flags: DIFlags::FlagZero @@ -1243,7 +1247,7 @@ impl<'tcx> EnumMemberDescriptionFactory<'tcx> { MemberDescription { name, type_metadata: variant_type_metadata, - offset: Size::from_bytes(0), + offset: Size::ZERO, size: variant.size, align: variant.align, flags: DIFlags::FlagZero @@ -1333,7 +1337,7 @@ fn describe_enum_variant<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let name = if variant.ctor_kind == CtorKind::Fn { format!("__{}", i) } else { - variant.fields[i].name.to_string() + variant.fields[i].ident.to_string() }; (name, layout.field(cx, i).ty) })).collect(); @@ -1429,8 +1433,8 @@ fn prepare_enum_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let discriminant_type_metadata = match layout.variants { layout::Variants::Single { .. } | layout::Variants::NicheFilling { .. } => None, - layout::Variants::Tagged { ref discr, .. } => { - Some(discriminant_type_metadata(discr.value)) + layout::Variants::Tagged { ref tag, .. } => { + Some(discriminant_type_metadata(tag.value)) } }; @@ -1645,19 +1649,19 @@ pub fn create_global_var_metadata(cx: &CodegenCx, } let tcx = cx.tcx; - let attrs = tcx.trans_fn_attrs(def_id); + let attrs = tcx.codegen_fn_attrs(def_id); - if attrs.flags.contains(TransFnAttrFlags::NO_DEBUG) { + if attrs.flags.contains(CodegenFnAttrFlags::NO_DEBUG) { return; } - let no_mangle = attrs.flags.contains(TransFnAttrFlags::NO_MANGLE); + let no_mangle = attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE); // We may want to remove the namespace scope if we're in an extern block, see: // https://github.com/rust-lang/rust/pull/46457#issuecomment-351750952 let var_scope = get_namespace_for_item(cx, def_id); let span = tcx.def_span(def_id); - let (file_metadata, line_number) = if span != syntax_pos::DUMMY_SP { + let (file_metadata, line_number) = if !span.is_dummy() { let loc = span_start(cx, span); (file_metadata(cx, &loc.file.name, LOCAL_CRATE), loc.line as c_uint) } else { @@ -1742,7 +1746,7 @@ pub fn create_vtable_metadata<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name.as_ptr(), unknown_file_metadata(cx), UNKNOWN_LINE_NUMBER, - Size::from_bytes(0).bits(), + Size::ZERO.bits(), cx.tcx.data_layout.pointer_align.abi_bits() as u32, DIFlags::FlagArtificial, ptr::null_mut(), diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/src/librustc_codegen_llvm/debuginfo/mod.rs new file mode 100644 index 0000000000000..9671db75baffe --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/mod.rs @@ -0,0 +1,535 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// See doc.rs for documentation. +mod doc; + +use self::VariableAccess::*; +use self::VariableKind::*; + +use self::utils::{DIB, span_start, create_DIArray, is_node_local_to_unit}; +use self::namespace::mangled_name_of_instance; +use self::type_names::compute_debuginfo_type_name; +use self::metadata::{type_metadata, file_metadata, TypeMap}; +use self::source_loc::InternalDebugLocation::{self, UnknownLocation}; + +use llvm; +use llvm::{ModuleRef, ContextRef, ValueRef}; +use llvm::debuginfo::{DIFile, DIType, DIScope, DIBuilderRef, DISubprogram, DIArray, DIFlags}; +use rustc::hir::CodegenFnAttrFlags; +use rustc::hir::def_id::{DefId, CrateNum}; +use rustc::ty::subst::{Substs, UnpackedKind}; + +use abi::Abi; +use common::CodegenCx; +use builder::Builder; +use monomorphize::Instance; +use rustc::ty::{self, ParamEnv, Ty, InstanceDef}; +use rustc::mir; +use rustc::session::config::{self, FullDebugInfo, LimitedDebugInfo, NoDebugInfo}; +use rustc::util::nodemap::{DefIdMap, FxHashMap, FxHashSet}; + +use libc::c_uint; +use std::cell::{Cell, RefCell}; +use std::ffi::CString; +use std::ptr; + +use syntax_pos::{self, Span, Pos}; +use syntax::ast; +use syntax::symbol::{Symbol, InternedString}; +use rustc::ty::layout::{self, LayoutOf}; + +pub mod gdb; +mod utils; +mod namespace; +mod type_names; +pub mod metadata; +mod create_scope_map; +mod source_loc; + +pub use self::create_scope_map::{create_mir_scopes, MirDebugScope}; +pub use self::source_loc::start_emitting_source_locations; +pub use self::metadata::create_global_var_metadata; +pub use self::metadata::create_vtable_metadata; +pub use self::metadata::extend_scope_to_file; +pub use self::source_loc::set_source_location; + +#[allow(non_upper_case_globals)] +const DW_TAG_auto_variable: c_uint = 0x100; +#[allow(non_upper_case_globals)] +const DW_TAG_arg_variable: c_uint = 0x101; + +/// A context object for maintaining all state needed by the debuginfo module. +pub struct CrateDebugContext<'tcx> { + llcontext: ContextRef, + llmod: ModuleRef, + builder: DIBuilderRef, + created_files: RefCell>, + created_enum_disr_types: RefCell>, + + type_map: RefCell>, + namespace_map: RefCell>, + + // This collection is used to assert that composite types (structs, enums, + // ...) have their members only set once: + composite_types_completed: RefCell>, +} + +impl<'tcx> CrateDebugContext<'tcx> { + pub fn new(llmod: ModuleRef) -> CrateDebugContext<'tcx> { + debug!("CrateDebugContext::new"); + let builder = unsafe { llvm::LLVMRustDIBuilderCreate(llmod) }; + // DIBuilder inherits context from the module, so we'd better use the same one + let llcontext = unsafe { llvm::LLVMGetModuleContext(llmod) }; + CrateDebugContext { + llcontext, + llmod, + builder, + created_files: RefCell::new(FxHashMap()), + created_enum_disr_types: RefCell::new(FxHashMap()), + type_map: RefCell::new(TypeMap::new()), + namespace_map: RefCell::new(DefIdMap()), + composite_types_completed: RefCell::new(FxHashSet()), + } + } +} + +pub enum FunctionDebugContext { + RegularContext(FunctionDebugContextData), + DebugInfoDisabled, + FunctionWithoutDebugInfo, +} + +impl FunctionDebugContext { + pub fn get_ref<'a>(&'a self, span: Span) -> &'a FunctionDebugContextData { + match *self { + FunctionDebugContext::RegularContext(ref data) => data, + FunctionDebugContext::DebugInfoDisabled => { + span_bug!(span, "{}", FunctionDebugContext::debuginfo_disabled_message()); + } + FunctionDebugContext::FunctionWithoutDebugInfo => { + span_bug!(span, "{}", FunctionDebugContext::should_be_ignored_message()); + } + } + } + + fn debuginfo_disabled_message() -> &'static str { + "debuginfo: Error trying to access FunctionDebugContext although debug info is disabled!" + } + + fn should_be_ignored_message() -> &'static str { + "debuginfo: Error trying to access FunctionDebugContext for function that should be \ + ignored by debug info!" + } +} + +pub struct FunctionDebugContextData { + fn_metadata: DISubprogram, + source_locations_enabled: Cell, + pub defining_crate: CrateNum, +} + +pub enum VariableAccess<'a> { + // The llptr given is an alloca containing the variable's value + DirectVariable { alloca: ValueRef }, + // The llptr given is an alloca containing the start of some pointer chain + // leading to the variable's content. + IndirectVariable { alloca: ValueRef, address_operations: &'a [i64] } +} + +pub enum VariableKind { + ArgumentVariable(usize /*index*/), + LocalVariable, +} + +/// Create any deferred debug metadata nodes +pub fn finalize(cx: &CodegenCx) { + if cx.dbg_cx.is_none() { + return; + } + + debug!("finalize"); + + if gdb::needs_gdb_debug_scripts_section(cx) { + // Add a .debug_gdb_scripts section to this compile-unit. This will + // cause GDB to try and load the gdb_load_rust_pretty_printers.py file, + // which activates the Rust pretty printers for binary this section is + // contained in. + gdb::get_or_insert_gdb_debug_scripts_section_global(cx); + } + + unsafe { + llvm::LLVMRustDIBuilderFinalize(DIB(cx)); + llvm::LLVMRustDIBuilderDispose(DIB(cx)); + // Debuginfo generation in LLVM by default uses a higher + // version of dwarf than macOS currently understands. We can + // instruct LLVM to emit an older version of dwarf, however, + // for macOS to understand. For more info see #11352 + // This can be overridden using --llvm-opts -dwarf-version,N. + // Android has the same issue (#22398) + if cx.sess().target.target.options.is_like_osx || + cx.sess().target.target.options.is_like_android { + llvm::LLVMRustAddModuleFlag(cx.llmod, + "Dwarf Version\0".as_ptr() as *const _, + 2) + } + + // Indicate that we want CodeView debug information on MSVC + if cx.sess().target.target.options.is_like_msvc { + llvm::LLVMRustAddModuleFlag(cx.llmod, + "CodeView\0".as_ptr() as *const _, + 1) + } + + // Prevent bitcode readers from deleting the debug info. + let ptr = "Debug Info Version\0".as_ptr(); + llvm::LLVMRustAddModuleFlag(cx.llmod, ptr as *const _, + llvm::LLVMRustDebugMetadataVersion()); + }; +} + +/// Creates the function-specific debug context. +/// +/// Returns the FunctionDebugContext for the function which holds state needed +/// for debug info creation. The function may also return another variant of the +/// FunctionDebugContext enum which indicates why no debuginfo should be created +/// for the function. +pub fn create_function_debug_context<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + instance: Instance<'tcx>, + sig: ty::FnSig<'tcx>, + llfn: ValueRef, + mir: &mir::Mir) -> FunctionDebugContext { + if cx.sess().opts.debuginfo == NoDebugInfo { + return FunctionDebugContext::DebugInfoDisabled; + } + + if let InstanceDef::Item(def_id) = instance.def { + if cx.tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::NO_DEBUG) { + return FunctionDebugContext::FunctionWithoutDebugInfo; + } + } + + let span = mir.span; + + // This can be the case for functions inlined from another crate + if span.is_dummy() { + // FIXME(simulacrum): Probably can't happen; remove. + return FunctionDebugContext::FunctionWithoutDebugInfo; + } + + let def_id = instance.def_id(); + let containing_scope = get_containing_scope(cx, instance); + let loc = span_start(cx, span); + let file_metadata = file_metadata(cx, &loc.file.name, def_id.krate); + + let function_type_metadata = unsafe { + let fn_signature = get_function_signature(cx, sig); + llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature) + }; + + // Find the enclosing function, in case this is a closure. + let def_key = cx.tcx.def_key(def_id); + let mut name = def_key.disambiguated_data.data.to_string(); + + let enclosing_fn_def_id = cx.tcx.closure_base_def_id(def_id); + + // Get_template_parameters() will append a `<...>` clause to the function + // name if necessary. + let generics = cx.tcx.generics_of(enclosing_fn_def_id); + let substs = instance.substs.truncate_to(cx.tcx, generics); + let template_parameters = get_template_parameters(cx, + &generics, + substs, + file_metadata, + &mut name); + + // Get the linkage_name, which is just the symbol name + let linkage_name = mangled_name_of_instance(cx, instance); + + let scope_line = span_start(cx, span).line; + let is_local_to_unit = is_node_local_to_unit(cx, def_id); + + let function_name = CString::new(name).unwrap(); + let linkage_name = CString::new(linkage_name.to_string()).unwrap(); + + let mut flags = DIFlags::FlagPrototyped; + + let local_id = cx.tcx.hir.as_local_node_id(def_id); + match *cx.sess().entry_fn.borrow() { + Some((id, _, _)) => { + if local_id == Some(id) { + flags = flags | DIFlags::FlagMainSubprogram; + } + } + None => {} + }; + if cx.layout_of(sig.output()).abi == ty::layout::Abi::Uninhabited { + flags = flags | DIFlags::FlagNoReturn; + } + + let fn_metadata = unsafe { + llvm::LLVMRustDIBuilderCreateFunction( + DIB(cx), + containing_scope, + function_name.as_ptr(), + linkage_name.as_ptr(), + file_metadata, + loc.line as c_uint, + function_type_metadata, + is_local_to_unit, + true, + scope_line as c_uint, + flags, + cx.sess().opts.optimize != config::OptLevel::No, + llfn, + template_parameters, + ptr::null_mut()) + }; + + // Initialize fn debug context (including scope map and namespace map) + let fn_debug_context = FunctionDebugContextData { + fn_metadata, + source_locations_enabled: Cell::new(false), + defining_crate: def_id.krate, + }; + + return FunctionDebugContext::RegularContext(fn_debug_context); + + fn get_function_signature<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + sig: ty::FnSig<'tcx>) -> DIArray { + if cx.sess().opts.debuginfo == LimitedDebugInfo { + return create_DIArray(DIB(cx), &[]); + } + + let mut signature = Vec::with_capacity(sig.inputs().len() + 1); + + // Return type -- llvm::DIBuilder wants this at index 0 + signature.push(match sig.output().sty { + ty::TyTuple(ref tys) if tys.is_empty() => ptr::null_mut(), + _ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP) + }); + + let inputs = if sig.abi == Abi::RustCall { + &sig.inputs()[..sig.inputs().len() - 1] + } else { + sig.inputs() + }; + + // Arguments types + if cx.sess().target.target.options.is_like_msvc { + // FIXME(#42800): + // There is a bug in MSDIA that leads to a crash when it encounters + // a fixed-size array of `u8` or something zero-sized in a + // function-type (see #40477). + // As a workaround, we replace those fixed-size arrays with a + // pointer-type. So a function `fn foo(a: u8, b: [u8; 4])` would + // appear as `fn foo(a: u8, b: *const u8)` in debuginfo, + // and a function `fn bar(x: [(); 7])` as `fn bar(x: *const ())`. + // This transformed type is wrong, but these function types are + // already inaccurate due to ABI adjustments (see #42800). + signature.extend(inputs.iter().map(|&t| { + let t = match t.sty { + ty::TyArray(ct, _) + if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { + cx.tcx.mk_imm_ptr(ct) + } + _ => t + }; + type_metadata(cx, t, syntax_pos::DUMMY_SP) + })); + } else { + signature.extend(inputs.iter().map(|t| { + type_metadata(cx, t, syntax_pos::DUMMY_SP) + })); + } + + if sig.abi == Abi::RustCall && !sig.inputs().is_empty() { + if let ty::TyTuple(args) = sig.inputs()[sig.inputs().len() - 1].sty { + signature.extend( + args.iter().map(|argument_type| + type_metadata(cx, argument_type, syntax_pos::DUMMY_SP)) + ); + } + } + + return create_DIArray(DIB(cx), &signature[..]); + } + + fn get_template_parameters<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + generics: &ty::Generics, + substs: &Substs<'tcx>, + file_metadata: DIFile, + name_to_append_suffix_to: &mut String) + -> DIArray + { + if substs.types().next().is_none() { + return create_DIArray(DIB(cx), &[]); + } + + name_to_append_suffix_to.push('<'); + for (i, actual_type) in substs.types().enumerate() { + if i != 0 { + name_to_append_suffix_to.push_str(","); + } + + let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), actual_type); + // Add actual type name to <...> clause of function name + let actual_type_name = compute_debuginfo_type_name(cx, + actual_type, + true); + name_to_append_suffix_to.push_str(&actual_type_name[..]); + } + name_to_append_suffix_to.push('>'); + + // Again, only create type information if full debuginfo is enabled + let template_params: Vec<_> = if cx.sess().opts.debuginfo == FullDebugInfo { + let names = get_parameter_names(cx, generics); + substs.iter().zip(names).filter_map(|(kind, name)| { + if let UnpackedKind::Type(ty) = kind.unpack() { + let actual_type = cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty); + let actual_type_metadata = + type_metadata(cx, actual_type, syntax_pos::DUMMY_SP); + let name = CString::new(name.as_str().as_bytes()).unwrap(); + Some(unsafe { + llvm::LLVMRustDIBuilderCreateTemplateTypeParameter( + DIB(cx), + ptr::null_mut(), + name.as_ptr(), + actual_type_metadata, + file_metadata, + 0, + 0) + }) + } else { + None + } + }).collect() + } else { + vec![] + }; + + return create_DIArray(DIB(cx), &template_params[..]); + } + + fn get_parameter_names(cx: &CodegenCx, + generics: &ty::Generics) + -> Vec { + let mut names = generics.parent.map_or(vec![], |def_id| { + get_parameter_names(cx, cx.tcx.generics_of(def_id)) + }); + names.extend(generics.params.iter().map(|param| param.name)); + names + } + + fn get_containing_scope<'cx, 'tcx>(cx: &CodegenCx<'cx, 'tcx>, + instance: Instance<'tcx>) + -> DIScope { + // First, let's see if this is a method within an inherent impl. Because + // if yes, we want to make the result subroutine DIE a child of the + // subroutine's self-type. + let self_type = cx.tcx.impl_of_method(instance.def_id()).and_then(|impl_def_id| { + // If the method does *not* belong to a trait, proceed + if cx.tcx.trait_id_of_impl(impl_def_id).is_none() { + let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions( + instance.substs, + ty::ParamEnv::reveal_all(), + &cx.tcx.type_of(impl_def_id), + ); + + // Only "class" methods are generally understood by LLVM, + // so avoid methods on other types (e.g. `<*mut T>::null`). + match impl_self_ty.sty { + ty::TyAdt(def, ..) if !def.is_box() => { + Some(type_metadata(cx, impl_self_ty, syntax_pos::DUMMY_SP)) + } + _ => None + } + } else { + // For trait method impls we still use the "parallel namespace" + // strategy + None + } + }); + + self_type.unwrap_or_else(|| { + namespace::item_namespace(cx, DefId { + krate: instance.def_id().krate, + index: cx.tcx + .def_key(instance.def_id()) + .parent + .expect("get_containing_scope: missing parent?") + }) + }) + } +} + +pub fn declare_local<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + dbg_context: &FunctionDebugContext, + variable_name: ast::Name, + variable_type: Ty<'tcx>, + scope_metadata: DIScope, + variable_access: VariableAccess, + variable_kind: VariableKind, + span: Span) { + assert!(!dbg_context.get_ref(span).source_locations_enabled.get()); + let cx = bx.cx; + + let file = span_start(cx, span).file; + let file_metadata = file_metadata(cx, + &file.name, + dbg_context.get_ref(span).defining_crate); + + let loc = span_start(cx, span); + let type_metadata = type_metadata(cx, variable_type, span); + + let (argument_index, dwarf_tag) = match variable_kind { + ArgumentVariable(index) => (index as c_uint, DW_TAG_arg_variable), + LocalVariable => (0, DW_TAG_auto_variable) + }; + let align = cx.align_of(variable_type); + + let name = CString::new(variable_name.as_str().as_bytes()).unwrap(); + match (variable_access, &[][..]) { + (DirectVariable { alloca }, address_operations) | + (IndirectVariable {alloca, address_operations}, _) => { + let metadata = unsafe { + llvm::LLVMRustDIBuilderCreateVariable( + DIB(cx), + dwarf_tag, + scope_metadata, + name.as_ptr(), + file_metadata, + loc.line as c_uint, + type_metadata, + cx.sess().opts.optimize != config::OptLevel::No, + DIFlags::FlagZero, + argument_index, + align.abi() as u32, + ) + }; + source_loc::set_debug_location(bx, + InternalDebugLocation::new(scope_metadata, loc.line, loc.col.to_usize())); + unsafe { + let debug_loc = llvm::LLVMGetCurrentDebugLocation(bx.llbuilder); + let instr = llvm::LLVMRustDIBuilderInsertDeclareAtEnd( + DIB(cx), + alloca, + metadata, + address_operations.as_ptr(), + address_operations.len() as c_uint, + debug_loc, + bx.llbb()); + + llvm::LLVMSetInstDebugLocation(bx.llbuilder, instr); + } + source_loc::set_debug_location(bx, UnknownLocation); + } + } +} diff --git a/src/librustc_trans/debuginfo/namespace.rs b/src/librustc_codegen_llvm/debuginfo/namespace.rs similarity index 100% rename from src/librustc_trans/debuginfo/namespace.rs rename to src/librustc_codegen_llvm/debuginfo/namespace.rs diff --git a/src/librustc_trans/debuginfo/source_loc.rs b/src/librustc_codegen_llvm/debuginfo/source_loc.rs similarity index 84% rename from src/librustc_trans/debuginfo/source_loc.rs rename to src/librustc_codegen_llvm/debuginfo/source_loc.rs index 7440296ce5d7b..958d09413edfa 100644 --- a/src/librustc_trans/debuginfo/source_loc.rs +++ b/src/librustc_codegen_llvm/debuginfo/source_loc.rs @@ -50,9 +50,9 @@ pub fn set_source_location( /// Enables emitting source locations for the given functions. /// /// Since we don't want source locations to be emitted for the function prelude, -/// they are disabled when beginning to translate a new function. This functions +/// they are disabled when beginning to codegen a new function. This functions /// switches source location emitting on and must therefore be called before the -/// first real statement/expression of the function is translated. +/// first real statement/expression of the function is codegened. pub fn start_emitting_source_locations(dbg_context: &FunctionDebugContext) { match *dbg_context { FunctionDebugContext::RegularContext(ref data) => { @@ -81,16 +81,22 @@ impl InternalDebugLocation { pub fn set_debug_location(bx: &Builder, debug_location: InternalDebugLocation) { let metadata_node = match debug_location { - KnownLocation { scope, line, .. } => { - // Always set the column to zero like Clang and GCC - let col = UNKNOWN_COLUMN_NUMBER; + KnownLocation { scope, line, col } => { + // For MSVC, set the column number to zero. + // Otherwise, emit it. This mimics clang behaviour. + // See discussion in https://github.com/rust-lang/rust/issues/42921 + let col_used = if bx.cx.sess().target.target.options.is_like_msvc { + UNKNOWN_COLUMN_NUMBER + } else { + col as c_uint + }; debug!("setting debug location to {} {}", line, col); unsafe { llvm::LLVMRustDIBuilderCreateDebugLocation( debug_context(bx.cx).llcontext, line as c_uint, - col as c_uint, + col_used, scope, ptr::null_mut()) } diff --git a/src/librustc_trans/debuginfo/type_names.rs b/src/librustc_codegen_llvm/debuginfo/type_names.rs similarity index 98% rename from src/librustc_trans/debuginfo/type_names.rs rename to src/librustc_codegen_llvm/debuginfo/type_names.rs index 825fac36c93d7..05a74db3a6ca9 100644 --- a/src/librustc_trans/debuginfo/type_names.rs +++ b/src/librustc_codegen_llvm/debuginfo/type_names.rs @@ -80,7 +80,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, output.push('*'); } }, - ty::TyRef(_, ty::TypeAndMut { ty: inner_type, mutbl }) => { + ty::TyRef(_, inner_type, mutbl) => { if !cpp_like_names { output.push('&'); } @@ -97,7 +97,7 @@ pub fn push_debuginfo_type_name<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ty::TyArray(inner_type, len) => { output.push('['); push_debuginfo_type_name(cx, inner_type, true, output); - output.push_str(&format!("; {}", len.val.unwrap_u64())); + output.push_str(&format!("; {}", len.unwrap_usize(cx.tcx))); output.push(']'); }, ty::TySlice(inner_type) => { diff --git a/src/librustc_codegen_llvm/debuginfo/utils.rs b/src/librustc_codegen_llvm/debuginfo/utils.rs new file mode 100644 index 0000000000000..9d37f99cb2a59 --- /dev/null +++ b/src/librustc_codegen_llvm/debuginfo/utils.rs @@ -0,0 +1,65 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Utility Functions. + +use super::{CrateDebugContext}; +use super::namespace::item_namespace; + +use rustc::hir::def_id::DefId; +use rustc::ty::DefIdTree; + +use llvm; +use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray}; +use common::{CodegenCx}; + +use syntax_pos::{self, Span}; + +pub fn is_node_local_to_unit(cx: &CodegenCx, def_id: DefId) -> bool +{ + // The is_local_to_unit flag indicates whether a function is local to the + // current compilation unit (i.e. if it is *static* in the C-sense). The + // *reachable* set should provide a good approximation of this, as it + // contains everything that might leak out of the current crate (by being + // externally visible or by being inlined into something externally + // visible). It might better to use the `exported_items` set from + // `driver::CrateAnalysis` in the future, but (atm) this set is not + // available in the codegen pass. + !cx.tcx.is_reachable_non_generic(def_id) +} + +#[allow(non_snake_case)] +pub fn create_DIArray(builder: DIBuilderRef, arr: &[DIDescriptor]) -> DIArray { + return unsafe { + llvm::LLVMRustDIBuilderGetOrCreateArray(builder, arr.as_ptr(), arr.len() as u32) + }; +} + +/// Return syntax_pos::Loc corresponding to the beginning of the span +pub fn span_start(cx: &CodegenCx, span: Span) -> syntax_pos::Loc { + cx.sess().codemap().lookup_char_pos(span.lo()) +} + +#[inline] +pub fn debug_context<'a, 'tcx>(cx: &'a CodegenCx<'a, 'tcx>) + -> &'a CrateDebugContext<'tcx> { + cx.dbg_cx.as_ref().unwrap() +} + +#[inline] +#[allow(non_snake_case)] +pub fn DIB(cx: &CodegenCx) -> DIBuilderRef { + cx.dbg_cx.as_ref().unwrap().builder +} + +pub fn get_namespace_for_item(cx: &CodegenCx, def_id: DefId) -> DIScope { + item_namespace(cx, cx.tcx.parent(def_id) + .expect("get_namespace_for_item: missing parent?")) +} diff --git a/src/librustc_trans/declare.rs b/src/librustc_codegen_llvm/declare.rs similarity index 99% rename from src/librustc_trans/declare.rs rename to src/librustc_codegen_llvm/declare.rs index 97721ffbf0685..fdc84f914f502 100644 --- a/src/librustc_trans/declare.rs +++ b/src/librustc_codegen_llvm/declare.rs @@ -11,7 +11,7 @@ //! //! Prefer using functions and methods from this module rather than calling LLVM //! functions directly. These functions do some additional work to ensure we do -//! the right thing given the preconceptions of trans. +//! the right thing given the preconceptions of codegen. //! //! Some useful guidelines: //! diff --git a/src/librustc_trans/diagnostics.rs b/src/librustc_codegen_llvm/diagnostics.rs similarity index 96% rename from src/librustc_trans/diagnostics.rs rename to src/librustc_codegen_llvm/diagnostics.rs index 57cc33d09bbea..94776f17c7989 100644 --- a/src/librustc_trans/diagnostics.rs +++ b/src/librustc_codegen_llvm/diagnostics.rs @@ -48,8 +48,3 @@ unsafe { simd_add(i32x2(0, 0), i32x2(1, 2)); } // ok! "##, } - - -register_diagnostics! { - E0558 -} diff --git a/src/librustc_trans/glue.rs b/src/librustc_codegen_llvm/glue.rs similarity index 100% rename from src/librustc_trans/glue.rs rename to src/librustc_codegen_llvm/glue.rs diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs similarity index 77% rename from src/librustc_trans/intrinsic.rs rename to src/librustc_codegen_llvm/intrinsic.rs index 49a207a2d8ab5..9c5c0f730c161 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -84,8 +84,8 @@ fn get_simple_intrinsic(cx: &CodegenCx, name: &str) -> Option { /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, -/// add them to librustc_trans/trans/context.rs -pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, +/// add them to librustc_codegen_llvm/context.rs +pub fn codegen_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, callee_ty: Ty<'tcx>, fn_ty: &FnType<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx>], @@ -234,39 +234,31 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, memset_intrinsic(bx, true, substs.type_at(0), args[0].immediate(), args[1].immediate(), args[2].immediate()) } - "volatile_load" => { + "volatile_load" | "unaligned_volatile_load" => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); if let PassMode::Cast(ty) = fn_ty.ret.mode { ptr = bx.pointercast(ptr, ty.llvm_type(cx).ptr_to()); } let load = bx.volatile_load(ptr); + let align = if name == "unaligned_volatile_load" { + 1 + } else { + cx.align_of(tp_ty).abi() as u32 + }; unsafe { - llvm::LLVMSetAlignment(load, cx.align_of(tp_ty).abi() as u32); + llvm::LLVMSetAlignment(load, align); } to_immediate(bx, load, cx.layout_of(tp_ty)) }, "volatile_store" => { - let tp_ty = substs.type_at(0); let dst = args[0].deref(bx.cx); - if let OperandValue::Pair(a, b) = args[1].val { - bx.volatile_store(a, dst.project_field(bx, 0).llval); - bx.volatile_store(b, dst.project_field(bx, 1).llval); - } else { - let val = if let OperandValue::Ref(ptr, align) = args[1].val { - bx.load(ptr, align) - } else { - if dst.layout.is_zst() { - return; - } - from_immediate(bx, args[1].immediate()) - }; - let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to()); - let store = bx.volatile_store(val, ptr); - unsafe { - llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32); - } - } + args[1].val.volatile_store(bx, dst); + return; + }, + "unaligned_volatile_store" => { + let dst = args[0].deref(bx.cx); + args[1].val.unaligned_volatile_store(bx, dst); return; }, "prefetch_read_data" | "prefetch_write_data" | @@ -404,21 +396,9 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, }, "discriminant_value" => { - args[0].deref(bx.cx).trans_get_discr(bx, ret_ty) + args[0].deref(bx.cx).codegen_get_discr(bx, ret_ty) } - "align_offset" => { - // `ptr as usize` - let ptr_val = bx.ptrtoint(args[0].immediate(), bx.cx.isize_ty); - // `ptr_val % align` - let align = args[1].immediate(); - let offset = bx.urem(ptr_val, align); - let zero = C_null(bx.cx.isize_ty); - // `offset == 0` - let is_zero = bx.icmp(llvm::IntPredicate::IntEQ, offset, zero); - // `if offset == 0 { 0 } else { align - offset }` - bx.select(is_zero, zero, bx.sub(align, offset)) - } name if name.starts_with("simd_") => { match generic_simd_intrinsic(bx, name, callee_ty, @@ -551,19 +531,9 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bx: &Builder<'a, 'tcx>, } "nontemporal_store" => { - let tp_ty = substs.type_at(0); let dst = args[0].deref(bx.cx); - let val = if let OperandValue::Ref(ptr, align) = args[1].val { - bx.load(ptr, align) - } else { - from_immediate(bx, args[1].immediate()) - }; - let ptr = bx.pointercast(dst.llval, val_ty(val).ptr_to()); - let store = bx.nontemporal_store(val, ptr); - unsafe { - llvm::LLVMSetAlignment(store, cx.align_of(tp_ty).abi() as u32); - } - return + args[1].val.nontemporal_store(bx, dst); + return; } _ => { @@ -771,9 +741,9 @@ fn try_intrinsic<'a, 'tcx>( let ptr_align = bx.tcx().data_layout.pointer_align; bx.store(C_null(Type::i8p(&bx.cx)), dest, ptr_align); } else if wants_msvc_seh(bx.sess()) { - trans_msvc_try(bx, cx, func, data, local_ptr, dest); + codegen_msvc_try(bx, cx, func, data, local_ptr, dest); } else { - trans_gnu_try(bx, cx, func, data, local_ptr, dest); + codegen_gnu_try(bx, cx, func, data, local_ptr, dest); } } @@ -784,7 +754,7 @@ fn try_intrinsic<'a, 'tcx>( // instructions are meant to work for all targets, as of the time of this // writing, however, LLVM does not recommend the usage of these new instructions // as the old ones are still more optimized. -fn trans_msvc_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, +fn codegen_msvc_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, cx: &CodegenCx, func: ValueRef, data: ValueRef, @@ -885,14 +855,14 @@ fn trans_msvc_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, // of exceptions (e.g. the normal semantics of LLVM's landingpad and invoke // instructions). // -// This translation is a little surprising because we always call a shim +// This codegen is a little surprising because we always call a shim // function instead of inlining the call to `invoke` manually here. This is done // because in LLVM we're only allowed to have one personality per function // definition. The call to the `try` intrinsic is being inlined into the // function calling it, and that function may already have other personality // functions in play. By calling a shim we're guaranteed that our shim will have // the right personality function. -fn trans_gnu_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, +fn codegen_gnu_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, cx: &CodegenCx, func: ValueRef, data: ValueRef, @@ -901,7 +871,7 @@ fn trans_gnu_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, let llfn = get_rust_try_fn(cx, &mut |bx| { let cx = bx.cx; - // Translates the shims described above: + // Codegens the shims described above: // // bx: // invoke %func(%args...) normal %normal unwind %catch @@ -950,13 +920,13 @@ fn trans_gnu_try<'a, 'tcx>(bx: &Builder<'a, 'tcx>, bx.store(ret, dest, i32_align); } -// Helper function to give a Block to a closure to translate a shim function. +// Helper function to give a Block to a closure to codegen a shim function. // This is currently primarily used for the `try` intrinsic functions above. fn gen_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, name: &str, inputs: Vec>, output: Ty<'tcx>, - trans: &mut for<'b> FnMut(Builder<'b, 'tcx>)) + codegen: &mut dyn for<'b> FnMut(Builder<'b, 'tcx>)) -> ValueRef { let rust_fn_ty = cx.tcx.mk_fn_ptr(ty::Binder::bind(cx.tcx.mk_fn_sig( inputs.into_iter(), @@ -967,7 +937,7 @@ fn gen_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, ))); let llfn = declare::define_internal_fn(cx, name, rust_fn_ty); let bx = Builder::new_block(cx, llfn, "entry-block"); - trans(bx); + codegen(bx); llfn } @@ -976,7 +946,7 @@ fn gen_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, // // This function is only generated once and is then cached. fn get_rust_try_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, - trans: &mut for<'b> FnMut(Builder<'b, 'tcx>)) + codegen: &mut dyn for<'b> FnMut(Builder<'b, 'tcx>)) -> ValueRef { if let Some(llfn) = cx.rust_try_fn.get() { return llfn; @@ -993,7 +963,7 @@ fn get_rust_try_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, Abi::Rust ))); let output = tcx.types.i32; - let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans); + let rust_try = gen_fn(cx, "__rust_try", vec![fn_ty, i8p, i8p], output, codegen); cx.rust_try_fn.set(Some(rust_try)); return rust_try } @@ -1062,12 +1032,12 @@ fn generic_simd_intrinsic<'a, 'tcx>( let in_len = arg_tys[0].simd_size(tcx); let comparison = match name { - "simd_eq" => Some(hir::BiEq), - "simd_ne" => Some(hir::BiNe), - "simd_lt" => Some(hir::BiLt), - "simd_le" => Some(hir::BiLe), - "simd_gt" => Some(hir::BiGt), - "simd_ge" => Some(hir::BiGe), + "simd_eq" => Some(hir::BinOpKind::Eq), + "simd_ne" => Some(hir::BinOpKind::Ne), + "simd_lt" => Some(hir::BinOpKind::Lt), + "simd_le" => Some(hir::BinOpKind::Le), + "simd_gt" => Some(hir::BinOpKind::Gt), + "simd_ge" => Some(hir::BinOpKind::Ge), _ => None }; @@ -1097,7 +1067,7 @@ fn generic_simd_intrinsic<'a, 'tcx>( let n: usize = match name["simd_shuffle".len()..].parse() { Ok(n) => n, Err(_) => span_bug!(span, - "bad `simd_shuffle` instruction only caught in trans?") + "bad `simd_shuffle` instruction only caught in codegen?") }; require_simd!(ret_ty, "return"); @@ -1180,6 +1150,359 @@ fn generic_simd_intrinsic<'a, 'tcx>( return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate())); } + fn simd_simple_float_intrinsic<'a, 'tcx>(name: &str, + in_elem: &::rustc::ty::TyS, + in_ty: &::rustc::ty::TyS, + in_len: usize, + bx: &Builder<'a, 'tcx>, + span: Span, + args: &[OperandRef<'tcx>]) + -> Result { + macro_rules! emit_error { + ($msg: tt) => { + emit_error!($msg, ) + }; + ($msg: tt, $($fmt: tt)*) => { + span_invalid_monomorphization_error( + bx.sess(), span, + &format!(concat!("invalid monomorphization of `{}` intrinsic: ", + $msg), + name, $($fmt)*)); + } + } + macro_rules! return_error { + ($($fmt: tt)*) => { + { + emit_error!($($fmt)*); + return Err(()); + } + } + } + let ety = match in_elem.sty { + ty::TyFloat(f) if f.bit_width() == 32 => { + if in_len < 2 || in_len > 16 { + return_error!( + "unsupported floating-point vector `{}` with length `{}` \ + out-of-range [2, 16]", + in_ty, in_len); + } + "f32" + }, + ty::TyFloat(f) if f.bit_width() == 64 => { + if in_len < 2 || in_len > 8 { + return_error!("unsupported floating-point vector `{}` with length `{}` \ + out-of-range [2, 8]", + in_ty, in_len); + } + "f64" + }, + ty::TyFloat(f) => { + return_error!("unsupported element type `{}` of floating-point vector `{}`", + f, in_ty); + }, + _ => { + return_error!("`{}` is not a floating-point type", in_ty); + } + }; + + let llvm_name = &format!("llvm.{0}.v{1}{2}", name, in_len, ety); + let intrinsic = bx.cx.get_intrinsic(&llvm_name); + let c = bx.call(intrinsic, + &args.iter().map(|arg| arg.immediate()).collect::>(), + None); + unsafe { llvm::LLVMRustSetHasUnsafeAlgebra(c) }; + return Ok(c); + } + + if name == "simd_fsqrt" { + return simd_simple_float_intrinsic("sqrt", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fsin" { + return simd_simple_float_intrinsic("sin", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fcos" { + return simd_simple_float_intrinsic("cos", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fabs" { + return simd_simple_float_intrinsic("fabs", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_floor" { + return simd_simple_float_intrinsic("floor", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_ceil" { + return simd_simple_float_intrinsic("ceil", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fexp" { + return simd_simple_float_intrinsic("exp", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fexp2" { + return simd_simple_float_intrinsic("exp2", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_flog10" { + return simd_simple_float_intrinsic("log10", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_flog2" { + return simd_simple_float_intrinsic("log2", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_flog" { + return simd_simple_float_intrinsic("log", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fpowi" { + return simd_simple_float_intrinsic("powi", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fpow" { + return simd_simple_float_intrinsic("pow", in_elem, in_ty, in_len, bx, span, args); + } + + if name == "simd_fma" { + return simd_simple_float_intrinsic("fma", in_elem, in_ty, in_len, bx, span, args); + } + + // FIXME: use: + // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182 + // https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81 + fn llvm_vector_str(elem_ty: ty::Ty, vec_len: usize, no_pointers: usize) -> String { + let p0s: String = "p0".repeat(no_pointers); + match elem_ty.sty { + ty::TyInt(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::TyUint(v) => format!("v{}{}i{}", vec_len, p0s, v.bit_width().unwrap()), + ty::TyFloat(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), + _ => unreachable!(), + } + } + + fn llvm_vector_ty(cx: &CodegenCx, elem_ty: ty::Ty, vec_len: usize, + mut no_pointers: usize) -> Type { + // FIXME: use cx.layout_of(ty).llvm_type() ? + let mut elem_ty = match elem_ty.sty { + ty::TyInt(v) => Type::int_from_ty(cx, v), + ty::TyUint(v) => Type::uint_from_ty(cx, v), + ty::TyFloat(v) => Type::float_from_ty(cx, v), + _ => unreachable!(), + }; + while no_pointers > 0 { + elem_ty = elem_ty.ptr_to(); + no_pointers -= 1; + } + Type::vector(&elem_ty, vec_len as u64) + } + + + if name == "simd_gather" { + // simd_gather(values: , pointers: , + // mask: ) -> + // * N: number of elements in the input vectors + // * T: type of the element to load + // * M: any integer width is supported, will be truncated to i1 + + // All types must be simd vector types + require_simd!(in_ty, "first"); + require_simd!(arg_tys[1], "second"); + require_simd!(arg_tys[2], "third"); + require_simd!(ret_ty, "return"); + + // Of the same length: + require!(in_len == arg_tys[1].simd_size(tcx), + "expected {} argument with length {} (same as input type `{}`), \ + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], + arg_tys[1].simd_size(tcx)); + require!(in_len == arg_tys[2].simd_size(tcx), + "expected {} argument with length {} (same as input type `{}`), \ + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], + arg_tys[2].simd_size(tcx)); + + // The return type must match the first argument type + require!(ret_ty == in_ty, + "expected return type `{}`, found `{}`", + in_ty, ret_ty); + + // This counts how many pointers + fn ptr_count(t: ty::Ty) -> usize { + match t.sty { + ty::TyRawPtr(p) => 1 + ptr_count(p.ty), + _ => 0, + } + } + + // Non-ptr type + fn non_ptr(t: ty::Ty) -> ty::Ty { + match t.sty { + ty::TyRawPtr(p) => non_ptr(p.ty), + _ => t, + } + } + + // The second argument must be a simd vector with an element type that's a pointer + // to the element type of the first argument + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).sty { + ty::TyRawPtr(p) if p.ty == in_elem => (ptr_count(arg_tys[1].simd_type(tcx)), + non_ptr(arg_tys[1].simd_type(tcx))), + _ => { + require!(false, "expected element type `{}` of second argument `{}` \ + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*_ {}`", + arg_tys[1].simd_type(tcx).sty, arg_tys[1], in_elem, in_ty, + arg_tys[1].simd_type(tcx).sty, in_elem); + unreachable!(); + } + }; + assert!(pointer_count > 0); + assert!(pointer_count - 1 == ptr_count(arg_tys[0].simd_type(tcx))); + assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + + // The element type of the third argument must be a signed integer type of any width: + match arg_tys[2].simd_type(tcx).sty { + ty::TyInt(_) => (), + _ => { + require!(false, "expected element type `{}` of third argument `{}` \ + to be a signed integer type", + arg_tys[2].simd_type(tcx).sty, arg_tys[2]); + } + } + + // Alignment of T, must be a constant integer value: + let alignment_ty = Type::i32(bx.cx); + let alignment = C_i32(bx.cx, bx.cx.align_of(in_elem).abi() as i32); + + // Truncate the mask vector to a vector of i1s: + let (mask, mask_ty) = { + let i1 = Type::i1(bx.cx); + let i1xn = Type::vector(&i1, in_len as u64); + (bx.trunc(args[2].immediate(), i1xn), i1xn) + }; + + // Type of the vector of pointers: + let llvm_pointer_vec_ty = llvm_vector_ty(bx.cx, underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + + // Type of the vector of elements: + let llvm_elem_vec_ty = llvm_vector_ty(bx.cx, underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + + let llvm_intrinsic = format!("llvm.masked.gather.{}.{}", + llvm_elem_vec_str, llvm_pointer_vec_str); + let f = declare::declare_cfn(bx.cx, &llvm_intrinsic, + Type::func(&[llvm_pointer_vec_ty, alignment_ty, mask_ty, + llvm_elem_vec_ty], &llvm_elem_vec_ty)); + llvm::SetUnnamedAddr(f, false); + let v = bx.call(f, &[args[1].immediate(), alignment, mask, args[0].immediate()], + None); + return Ok(v); + } + + if name == "simd_scatter" { + // simd_scatter(values: , pointers: , + // mask: ) -> () + // * N: number of elements in the input vectors + // * T: type of the element to load + // * M: any integer width is supported, will be truncated to i1 + + // All types must be simd vector types + require_simd!(in_ty, "first"); + require_simd!(arg_tys[1], "second"); + require_simd!(arg_tys[2], "third"); + + // Of the same length: + require!(in_len == arg_tys[1].simd_size(tcx), + "expected {} argument with length {} (same as input type `{}`), \ + found `{}` with length {}", "second", in_len, in_ty, arg_tys[1], + arg_tys[1].simd_size(tcx)); + require!(in_len == arg_tys[2].simd_size(tcx), + "expected {} argument with length {} (same as input type `{}`), \ + found `{}` with length {}", "third", in_len, in_ty, arg_tys[2], + arg_tys[2].simd_size(tcx)); + + // This counts how many pointers + fn ptr_count(t: ty::Ty) -> usize { + match t.sty { + ty::TyRawPtr(p) => 1 + ptr_count(p.ty), + _ => 0, + } + } + + // Non-ptr type + fn non_ptr(t: ty::Ty) -> ty::Ty { + match t.sty { + ty::TyRawPtr(p) => non_ptr(p.ty), + _ => t, + } + } + + // The second argument must be a simd vector with an element type that's a pointer + // to the element type of the first argument + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).sty { + ty::TyRawPtr(p) if p.ty == in_elem && p.mutbl == hir::MutMutable + => (ptr_count(arg_tys[1].simd_type(tcx)), + non_ptr(arg_tys[1].simd_type(tcx))), + _ => { + require!(false, "expected element type `{}` of second argument `{}` \ + to be a pointer to the element type `{}` of the first \ + argument `{}`, found `{}` != `*mut {}`", + arg_tys[1].simd_type(tcx).sty, arg_tys[1], in_elem, in_ty, + arg_tys[1].simd_type(tcx).sty, in_elem); + unreachable!(); + } + }; + assert!(pointer_count > 0); + assert!(pointer_count - 1 == ptr_count(arg_tys[0].simd_type(tcx))); + assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); + + // The element type of the third argument must be a signed integer type of any width: + match arg_tys[2].simd_type(tcx).sty { + ty::TyInt(_) => (), + _ => { + require!(false, "expected element type `{}` of third argument `{}` \ + to be a signed integer type", + arg_tys[2].simd_type(tcx).sty, arg_tys[2]); + } + } + + // Alignment of T, must be a constant integer value: + let alignment_ty = Type::i32(bx.cx); + let alignment = C_i32(bx.cx, bx.cx.align_of(in_elem).abi() as i32); + + // Truncate the mask vector to a vector of i1s: + let (mask, mask_ty) = { + let i1 = Type::i1(bx.cx); + let i1xn = Type::vector(&i1, in_len as u64); + (bx.trunc(args[2].immediate(), i1xn), i1xn) + }; + + let ret_t = Type::void(bx.cx); + + // Type of the vector of pointers: + let llvm_pointer_vec_ty = llvm_vector_ty(bx.cx, underlying_ty, in_len, pointer_count); + let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count); + + // Type of the vector of elements: + let llvm_elem_vec_ty = llvm_vector_ty(bx.cx, underlying_ty, in_len, pointer_count - 1); + let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1); + + let llvm_intrinsic = format!("llvm.masked.scatter.{}.{}", + llvm_elem_vec_str, llvm_pointer_vec_str); + let f = declare::declare_cfn(bx.cx, &llvm_intrinsic, + Type::func(&[llvm_elem_vec_ty, + llvm_pointer_vec_ty, + alignment_ty, + mask_ty], &ret_t)); + llvm::SetUnnamedAddr(f, false); + let v = bx.call(f, &[args[0].immediate(), args[1].immediate(), alignment, mask], + None); + return Ok(v); + } + macro_rules! arith_red { ($name:tt : $integer_reduce:ident, $float_reduce:ident, $ordered:expr) => { if name == $name { diff --git a/src/librustc_codegen_llvm/lib.rs b/src/librustc_codegen_llvm/lib.rs new file mode 100644 index 0000000000000..90f96c9687bc1 --- /dev/null +++ b/src/librustc_codegen_llvm/lib.rs @@ -0,0 +1,389 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Rust compiler. +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] + +#![feature(box_patterns)] +#![feature(box_syntax)] +#![feature(custom_attribute)] +#![feature(fs_read_write)] +#![allow(unused_attributes)] +#![feature(libc)] +#![feature(quote)] +#![feature(range_contains)] +#![feature(rustc_diagnostic_macros)] +#![feature(slice_sort_by_cached_key)] +#![feature(optin_builtin_traits)] + +use rustc::dep_graph::WorkProduct; +use syntax_pos::symbol::Symbol; + +#[macro_use] extern crate bitflags; +extern crate flate2; +extern crate libc; +#[macro_use] extern crate rustc; +extern crate jobserver; +extern crate num_cpus; +extern crate rustc_mir; +extern crate rustc_allocator; +extern crate rustc_apfloat; +extern crate rustc_target; +#[macro_use] extern crate rustc_data_structures; +extern crate rustc_demangle; +extern crate rustc_incremental; +extern crate rustc_llvm as llvm; +extern crate rustc_platform_intrinsics as intrinsics; +extern crate rustc_codegen_utils; + +#[macro_use] extern crate log; +#[macro_use] extern crate syntax; +extern crate syntax_pos; +extern crate rustc_errors as errors; +extern crate serialize; +extern crate cc; // Used to locate MSVC +extern crate tempfile; + +use back::bytecode::RLIB_BYTECODE_EXTENSION; + +pub use llvm_util::target_features; + +use std::any::Any; +use std::path::PathBuf; +use std::sync::mpsc; +use rustc_data_structures::sync::Lrc; + +use rustc::dep_graph::DepGraph; +use rustc::hir::def_id::CrateNum; +use rustc::middle::cstore::MetadataLoader; +use rustc::middle::cstore::{NativeLibrary, CrateSource, LibSource}; +use rustc::middle::lang_items::LangItem; +use rustc::session::{Session, CompileIncomplete}; +use rustc::session::config::{OutputFilenames, OutputType, PrintRequest}; +use rustc::ty::{self, TyCtxt}; +use rustc::util::time_graph; +use rustc::util::nodemap::{FxHashSet, FxHashMap}; +use rustc_mir::monomorphize; +use rustc_codegen_utils::codegen_backend::CodegenBackend; + +mod diagnostics; + +mod back { + pub use rustc_codegen_utils::symbol_names; + mod archive; + pub mod bytecode; + mod command; + pub mod linker; + pub mod link; + mod lto; + pub mod symbol_export; + pub mod write; + mod rpath; + pub mod wasm; +} + +mod abi; +mod allocator; +mod asm; +mod attributes; +mod base; +mod builder; +mod callee; +mod common; +mod consts; +mod context; +mod debuginfo; +mod declare; +mod glue; +mod intrinsic; +mod llvm_util; +mod metadata; +mod meth; +mod mir; +mod mono_item; +mod type_; +mod type_of; +mod value; + +pub struct LlvmCodegenBackend(()); + +impl !Send for LlvmCodegenBackend {} // Llvm is on a per-thread basis +impl !Sync for LlvmCodegenBackend {} + +impl LlvmCodegenBackend { + pub fn new() -> Box { + box LlvmCodegenBackend(()) + } +} + +impl CodegenBackend for LlvmCodegenBackend { + fn init(&self, sess: &Session) { + llvm_util::init(sess); // Make sure llvm is inited + } + + fn print(&self, req: PrintRequest, sess: &Session) { + match req { + PrintRequest::RelocationModels => { + println!("Available relocation models:"); + for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() { + println!(" {}", name); + } + println!(""); + } + PrintRequest::CodeModels => { + println!("Available code models:"); + for &(name, _) in back::write::CODE_GEN_MODEL_ARGS.iter(){ + println!(" {}", name); + } + println!(""); + } + PrintRequest::TlsModels => { + println!("Available TLS models:"); + for &(name, _) in back::write::TLS_MODEL_ARGS.iter(){ + println!(" {}", name); + } + println!(""); + } + req => llvm_util::print(req, sess), + } + } + + fn print_passes(&self) { + llvm_util::print_passes(); + } + + fn print_version(&self) { + llvm_util::print_version(); + } + + fn diagnostics(&self) -> &[(&'static str, &'static str)] { + &DIAGNOSTICS + } + + fn target_features(&self, sess: &Session) -> Vec { + target_features(sess) + } + + fn metadata_loader(&self) -> Box { + box metadata::LlvmMetadataLoader + } + + fn provide(&self, providers: &mut ty::query::Providers) { + back::symbol_names::provide(providers); + back::symbol_export::provide(providers); + base::provide(providers); + attributes::provide(providers); + } + + fn provide_extern(&self, providers: &mut ty::query::Providers) { + back::symbol_export::provide_extern(providers); + base::provide_extern(providers); + attributes::provide_extern(providers); + } + + fn codegen_crate<'a, 'tcx>( + &self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + rx: mpsc::Receiver> + ) -> Box { + box base::codegen_crate(tcx, rx) + } + + fn join_codegen_and_link( + &self, + ongoing_codegen: Box, + sess: &Session, + dep_graph: &DepGraph, + outputs: &OutputFilenames, + ) -> Result<(), CompileIncomplete>{ + use rustc::util::common::time; + let (ongoing_codegen, work_products) = + ongoing_codegen.downcast::<::back::write::OngoingCodegen>() + .expect("Expected LlvmCodegenBackend's OngoingCodegen, found Box") + .join(sess); + if sess.opts.debugging_opts.incremental_info { + back::write::dump_incremental_data(&ongoing_codegen); + } + + time(sess, + "serialize work products", + move || rustc_incremental::save_work_product_index(sess, &dep_graph, work_products)); + + sess.compile_status()?; + + if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe || + i == OutputType::Metadata) { + return Ok(()); + } + + // Run the linker on any artifacts that resulted from the LLVM run. + // This should produce either a finished executable or library. + time(sess, "linking", || { + back::link::link_binary(sess, &ongoing_codegen, + outputs, &ongoing_codegen.crate_name.as_str()); + }); + + // Now that we won't touch anything in the incremental compilation directory + // any more, we can finalize it (which involves renaming it) + rustc_incremental::finalize_session_directory(sess, ongoing_codegen.link.crate_hash); + + Ok(()) + } +} + +/// This is the entrypoint for a hot plugged rustc_codegen_llvm +#[no_mangle] +pub fn __rustc_codegen_backend() -> Box { + LlvmCodegenBackend::new() +} + +struct ModuleCodegen { + /// The name of the module. When the crate may be saved between + /// compilations, incremental compilation requires that name be + /// unique amongst **all** crates. Therefore, it should contain + /// something unique to this crate (e.g., a module path) as well + /// as the crate name and disambiguator. + name: String, + llmod_id: String, + source: ModuleSource, + kind: ModuleKind, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +enum ModuleKind { + Regular, + Metadata, + Allocator, +} + +impl ModuleCodegen { + fn llvm(&self) -> Option<&ModuleLlvm> { + match self.source { + ModuleSource::Codegened(ref llvm) => Some(llvm), + ModuleSource::Preexisting(_) => None, + } + } + + fn into_compiled_module(self, + emit_obj: bool, + emit_bc: bool, + emit_bc_compressed: bool, + outputs: &OutputFilenames) -> CompiledModule { + let pre_existing = match self.source { + ModuleSource::Preexisting(_) => true, + ModuleSource::Codegened(_) => false, + }; + let object = if emit_obj { + Some(outputs.temp_path(OutputType::Object, Some(&self.name))) + } else { + None + }; + let bytecode = if emit_bc { + Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name))) + } else { + None + }; + let bytecode_compressed = if emit_bc_compressed { + Some(outputs.temp_path(OutputType::Bitcode, Some(&self.name)) + .with_extension(RLIB_BYTECODE_EXTENSION)) + } else { + None + }; + + CompiledModule { + llmod_id: self.llmod_id, + name: self.name.clone(), + kind: self.kind, + pre_existing, + object, + bytecode, + bytecode_compressed, + } + } +} + +#[derive(Debug)] +struct CompiledModule { + name: String, + llmod_id: String, + kind: ModuleKind, + pre_existing: bool, + object: Option, + bytecode: Option, + bytecode_compressed: Option, +} + +enum ModuleSource { + /// Copy the `.o` files or whatever from the incr. comp. directory. + Preexisting(WorkProduct), + + /// Rebuild from this LLVM module. + Codegened(ModuleLlvm), +} + +#[derive(Debug)] +struct ModuleLlvm { + llcx: llvm::ContextRef, + llmod: llvm::ModuleRef, + tm: llvm::TargetMachineRef, +} + +unsafe impl Send for ModuleLlvm { } +unsafe impl Sync for ModuleLlvm { } + +impl Drop for ModuleLlvm { + fn drop(&mut self) { + unsafe { + llvm::LLVMDisposeModule(self.llmod); + llvm::LLVMContextDispose(self.llcx); + llvm::LLVMRustDisposeTargetMachine(self.tm); + } + } +} + +struct CodegenResults { + crate_name: Symbol, + modules: Vec, + allocator_module: Option, + metadata_module: CompiledModule, + link: rustc::middle::cstore::LinkMeta, + metadata: rustc::middle::cstore::EncodedMetadata, + windows_subsystem: Option, + linker_info: back::linker::LinkerInfo, + crate_info: CrateInfo, +} + +/// Misc info we load from metadata to persist beyond the tcx +struct CrateInfo { + panic_runtime: Option, + compiler_builtins: Option, + profiler_runtime: Option, + sanitizer_runtime: Option, + is_no_builtins: FxHashSet, + native_libraries: FxHashMap>>, + crate_name: FxHashMap, + used_libraries: Lrc>, + link_args: Lrc>, + used_crate_source: FxHashMap>, + used_crates_static: Vec<(CrateNum, LibSource)>, + used_crates_dynamic: Vec<(CrateNum, LibSource)>, + wasm_imports: FxHashMap, + lang_item_to_crate: FxHashMap, + missing_lang_items: FxHashMap>, +} + +__build_diagnostic_array! { librustc_codegen_llvm, DIAGNOSTICS } diff --git a/src/librustc_trans/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs similarity index 97% rename from src/librustc_trans/llvm_util.rs rename to src/librustc_codegen_llvm/llvm_util.rs index bbd1c39a19e0e..e941998098d00 100644 --- a/src/librustc_trans/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -84,6 +84,9 @@ unsafe fn configure_llvm(sess: &Session) { // array, leading to crashes. const ARM_WHITELIST: &[(&str, Option<&str>)] = &[ + ("mclass", Some("arm_target_feature")), + ("rclass", Some("arm_target_feature")), + ("dsp", Some("arm_target_feature")), ("neon", Some("arm_target_feature")), ("v7", Some("arm_target_feature")), ("vfp2", Some("arm_target_feature")), @@ -249,7 +252,7 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) { match req { PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm), PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm), - _ => bug!("rustc_trans can't handle print request: {:?}", req), + _ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req), } } } diff --git a/src/librustc_trans/metadata.rs b/src/librustc_codegen_llvm/metadata.rs similarity index 100% rename from src/librustc_trans/metadata.rs rename to src/librustc_codegen_llvm/metadata.rs diff --git a/src/librustc_trans/meth.rs b/src/librustc_codegen_llvm/meth.rs similarity index 100% rename from src/librustc_trans/meth.rs rename to src/librustc_codegen_llvm/meth.rs diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_codegen_llvm/mir/analyze.rs similarity index 98% rename from src/librustc_trans/mir/analyze.rs rename to src/librustc_codegen_llvm/mir/analyze.rs index 9e5298eb736a3..e105baba8aa2e 100644 --- a/src/librustc_trans/mir/analyze.rs +++ b/src/librustc_codegen_llvm/mir/analyze.rs @@ -12,7 +12,7 @@ //! which do not. use rustc_data_structures::bitvec::BitVector; -use rustc_data_structures::control_flow_graph::dominators::Dominators; +use rustc_data_structures::graph::dominators::Dominators; use rustc_data_structures::indexed_vec::{Idx, IndexVec}; use rustc::mir::{self, Location, TerminatorKind}; use rustc::mir::visit::{Visitor, PlaceContext}; @@ -22,7 +22,7 @@ use rustc::ty::layout::LayoutOf; use type_of::LayoutLlvmExt; use super::FunctionCx; -pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { +pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { let mir = fx.mir; let mut analyzer = LocalAnalyzer::new(fx); @@ -54,7 +54,7 @@ pub fn non_ssa_locals<'a, 'tcx>(fx: &FunctionCx<'a, 'tcx>) -> BitVector { struct LocalAnalyzer<'mir, 'a: 'mir, 'tcx: 'a> { fx: &'mir FunctionCx<'a, 'tcx>, dominators: Dominators, - non_ssa_locals: BitVector, + non_ssa_locals: BitVector, // The location of the first visited direct assignment to each // local, or an invalid location (out of bounds `block` index). first_assignment: IndexVec @@ -90,7 +90,7 @@ impl<'mir, 'a, 'tcx> LocalAnalyzer<'mir, 'a, 'tcx> { fn not_ssa(&mut self, local: mir::Local) { debug!("marking {:?} as non-SSA", local); - self.non_ssa_locals.insert(local.index()); + self.non_ssa_locals.insert(local); } fn assign(&mut self, local: mir::Local, location: Location) { diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs similarity index 85% rename from src/librustc_trans/mir/block.rs rename to src/librustc_codegen_llvm/mir/block.rs index b666c2b211525..dc4b9e0ae99d8 100644 --- a/src/librustc_trans/mir/block.rs +++ b/src/librustc_codegen_llvm/mir/block.rs @@ -17,7 +17,7 @@ use rustc::mir::interpret::EvalErrorKind; use abi::{Abi, ArgType, ArgTypeExt, FnType, FnTypeExt, LlvmType, PassMode}; use base; use callee; -use builder::Builder; +use builder::{Builder, MemFlags}; use common::{self, C_bool, C_str_slice, C_struct, C_u32, C_uint_big, C_undef}; use consts; use meth; @@ -34,25 +34,25 @@ use super::operand::OperandRef; use super::operand::OperandValue::{Pair, Ref, Immediate}; impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn trans_block(&mut self, bb: mir::BasicBlock) { + pub fn codegen_block(&mut self, bb: mir::BasicBlock) { let mut bx = self.build_block(bb); let data = &self.mir[bb]; - debug!("trans_block({:?}={:?})", bb, data); + debug!("codegen_block({:?}={:?})", bb, data); for statement in &data.statements { - bx = self.trans_statement(bx, statement); + bx = self.codegen_statement(bx, statement); } - self.trans_terminator(bx, bb, data.terminator()); + self.codegen_terminator(bx, bb, data.terminator()); } - fn trans_terminator(&mut self, + fn codegen_terminator(&mut self, mut bx: Builder<'a, 'tcx>, bb: mir::BasicBlock, terminator: &mir::Terminator<'tcx>) { - debug!("trans_terminator: {:?}", terminator); + debug!("codegen_terminator: {:?}", terminator); // Create the cleanup bundle, if needed. let tcx = bx.tcx(); @@ -190,15 +190,24 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } mir::TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => { - let discr = self.trans_operand(&bx, discr); - if switch_ty == bx.tcx().types.bool { + let discr = self.codegen_operand(&bx, discr); + if targets.len() == 2 { + // If there are two targets, emit br instead of switch let lltrue = llblock(self, targets[0]); let llfalse = llblock(self, targets[1]); - if let [0] = values[..] { - bx.cond_br(discr.immediate(), llfalse, lltrue); + if switch_ty == bx.tcx().types.bool { + // Don't generate trivial icmps when switching on bool + if let [0] = values[..] { + bx.cond_br(discr.immediate(), llfalse, lltrue); + } else { + assert_eq!(&values[..], &[1]); + bx.cond_br(discr.immediate(), lltrue, llfalse); + } } else { - assert_eq!(&values[..], &[1]); - bx.cond_br(discr.immediate(), lltrue, llfalse); + let switch_llty = bx.cx.layout_of(switch_ty).immediate_llvm_type(bx.cx); + let llval = C_uint_big(switch_llty, values[0]); + let cmp = bx.icmp(llvm::IntEQ, discr.immediate(), llval); + bx.cond_br(cmp, lltrue, llfalse); } } else { let (otherwise, targets) = targets.split_last().unwrap(); @@ -221,7 +230,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } PassMode::Direct(_) | PassMode::Pair(..) => { - let op = self.trans_consume(&bx, &mir::Place::Local(mir::RETURN_PLACE)); + let op = self.codegen_consume(&bx, &mir::Place::Local(mir::RETURN_PLACE)); if let Ref(llval, align) = op.val { bx.load(llval, align) } else { @@ -233,10 +242,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let op = match self.locals[mir::RETURN_PLACE] { LocalRef::Operand(Some(op)) => op, LocalRef::Operand(None) => bug!("use of return before def"), - LocalRef::Place(tr_place) => { + LocalRef::Place(cg_place) => { OperandRef { - val: Ref(tr_place.llval, tr_place.align), - layout: tr_place.layout + val: Ref(cg_place.llval, cg_place.align), + layout: cg_place.layout } } }; @@ -275,7 +284,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { return } - let place = self.trans_place(&bx, location); + let place = self.codegen_place(&bx, location); let mut args: &[_] = &[place.llval, place.llextra]; args = &args[..1 + place.has_extra() as usize]; let (drop_fn, fn_ty) = match ty.sty { @@ -301,7 +310,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } mir::TerminatorKind::Assert { ref cond, expected, ref msg, target, cleanup } => { - let cond = self.trans_operand(&bx, cond).immediate(); + let cond = self.codegen_operand(&bx, cond).immediate(); let mut const_cond = common::const_to_opt_u128(cond, false).map(|c| c == 1); // This case can currently arise only from functions marked @@ -317,7 +326,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } - // Don't translate the panic block if success if known. + // Don't codegen the panic block if success if known. if const_cond == Some(expected) { funclet_br(self, bx, target); return; @@ -353,8 +362,8 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // Put together the arguments to the panic entry point. let (lang_item, args) = match *msg { EvalErrorKind::BoundsCheck { ref len, ref index } => { - let len = self.trans_operand(&mut bx, len).immediate(); - let index = self.trans_operand(&mut bx, index).immediate(); + let len = self.codegen_operand(&mut bx, len).immediate(); + let index = self.codegen_operand(&mut bx, index).immediate(); let file_line_col = C_struct(bx.cx, &[filename, line, col], false); let file_line_col = consts::addr_of(bx.cx, @@ -386,17 +395,17 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let fn_ty = FnType::of_instance(bx.cx, &instance); let llfn = callee::get_fn(bx.cx, instance); - // Translate the actual panic invoke/call. + // Codegen the actual panic invoke/call. do_call(self, bx, fn_ty, llfn, &args, None, cleanup); } mir::TerminatorKind::DropAndReplace { .. } => { - bug!("undesugared DropAndReplace in trans: {:?}", terminator); + bug!("undesugared DropAndReplace in codegen: {:?}", terminator); } mir::TerminatorKind::Call { ref func, ref args, ref destination, cleanup } => { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. - let callee = self.trans_operand(&bx, func); + let callee = self.codegen_operand(&bx, func); let (instance, mut llfn) = match callee.layout.ty.sty { ty::TyFnDef(def_id, substs) => { @@ -419,7 +428,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { ); let abi = sig.abi; - // Handle intrinsics old trans wants Expr's for, ourselves. + // Handle intrinsics old codegen wants Expr's for, ourselves. let intrinsic = match def { Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().item_name(def_id).as_str()), @@ -428,9 +437,20 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let intrinsic = intrinsic.as_ref().map(|s| &s[..]); if intrinsic == Some("transmute") { - let &(ref dest, target) = destination.as_ref().unwrap(); - self.trans_transmute(&bx, &args[0], dest); - funclet_br(self, bx, target); + if let Some(destination_ref) = destination.as_ref() { + let &(ref dest, target) = destination_ref; + self.codegen_transmute(&bx, &args[0], dest); + funclet_br(self, bx, target); + } else { + // If we are trying to transmute to an uninhabited type, + // it is likely there is no allotted destination. In fact, + // transmuting to an uninhabited type is UB, which means + // we can do what we like. Here, we declare that transmuting + // into an uninhabited type is impossible, so anything following + // it must be unreachable. + assert_eq!(bx.cx.layout_of(sig.output()).abi, layout::Abi::Uninhabited); + bx.unreachable(); + } return; } @@ -467,7 +487,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { }; if intrinsic.is_some() && intrinsic != Some("drop_in_place") { - use intrinsic::trans_intrinsic_call; + use intrinsic::codegen_intrinsic_call; let dest = match ret_dest { _ if fn_ty.ret.is_indirect() => llargs[0], @@ -487,14 +507,40 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // promotes any complex rvalues to constants. if i == 2 && intrinsic.unwrap().starts_with("simd_shuffle") { match *arg { + // The shuffle array argument is usually not an explicit constant, + // but specified directly in the code. This means it gets promoted + // and we can then extract the value by evaluating the promoted. + mir::Operand::Copy(mir::Place::Promoted(box(index, ty))) | + mir::Operand::Move(mir::Place::Promoted(box(index, ty))) => { + let param_env = ty::ParamEnv::reveal_all(); + let cid = mir::interpret::GlobalId { + instance: self.instance, + promoted: Some(index), + }; + let c = bx.tcx().const_eval(param_env.and(cid)); + let (llval, ty) = self.simd_shuffle_indices( + &bx, + terminator.source_info.span, + ty, + c, + ); + return OperandRef { + val: Immediate(llval), + layout: bx.cx.layout_of(ty), + }; + + }, mir::Operand::Copy(_) | mir::Operand::Move(_) => { span_bug!(span, "shuffle indices must be constant"); } mir::Operand::Constant(ref constant) => { + let c = self.eval_mir_constant(&bx, constant); let (llval, ty) = self.simd_shuffle_indices( &bx, - constant, + constant.span, + constant.ty, + c, ); return OperandRef { val: Immediate(llval), @@ -504,12 +550,12 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } - self.trans_operand(&bx, arg) + self.codegen_operand(&bx, arg) }).collect(); let callee_ty = instance.as_ref().unwrap().ty(bx.cx.tcx); - trans_intrinsic_call(&bx, callee_ty, &fn_ty, &args, dest, + codegen_intrinsic_call(&bx, callee_ty, &fn_ty, &args, dest, terminator.source_info.span); if let ReturnDest::IndirectOperand(dst, _) = ret_dest { @@ -534,7 +580,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { }; for (i, arg) in first_args.iter().enumerate() { - let mut op = self.trans_operand(&bx, arg); + let mut op = self.codegen_operand(&bx, arg); if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { if let Pair(data_ptr, meta) = op.val { llfn = Some(meth::VirtualIndex::from_index(idx) @@ -556,10 +602,10 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { _ => {} } - self.trans_argument(&bx, op, &mut llargs, &fn_ty.args[i]); + self.codegen_argument(&bx, op, &mut llargs, &fn_ty.args[i]); } if let Some(tup) = untuple { - self.trans_arguments_untupled(&bx, tup, &mut llargs, + self.codegen_arguments_untupled(&bx, tup, &mut llargs, &fn_ty.args[first_args.len()..]) } @@ -574,13 +620,13 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { cleanup); } mir::TerminatorKind::GeneratorDrop | - mir::TerminatorKind::Yield { .. } => bug!("generator ops in trans"), + mir::TerminatorKind::Yield { .. } => bug!("generator ops in codegen"), mir::TerminatorKind::FalseEdges { .. } | - mir::TerminatorKind::FalseUnwind { .. } => bug!("borrowck false edges in trans"), + mir::TerminatorKind::FalseUnwind { .. } => bug!("borrowck false edges in codegen"), } } - fn trans_argument(&mut self, + fn codegen_argument(&mut self, bx: &Builder<'a, 'tcx>, op: OperandRef<'tcx>, llargs: &mut Vec, @@ -601,7 +647,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { llargs.push(b); return; } - _ => bug!("trans_argument: {:?} invalid for pair arugment", op) + _ => bug!("codegen_argument: {:?} invalid for pair arugment", op) } } @@ -626,7 +672,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // have scary latent bugs around. let scratch = PlaceRef::alloca(bx, arg.layout, "arg"); - base::memcpy_ty(bx, scratch.llval, llval, op.layout, align); + base::memcpy_ty(bx, scratch.llval, llval, op.layout, align, MemFlags::empty()); (scratch.llval, scratch.align, true) } else { (llval, align, true) @@ -659,25 +705,25 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { llargs.push(llval); } - fn trans_arguments_untupled(&mut self, + fn codegen_arguments_untupled(&mut self, bx: &Builder<'a, 'tcx>, operand: &mir::Operand<'tcx>, llargs: &mut Vec, args: &[ArgType<'tcx, Ty<'tcx>>]) { - let tuple = self.trans_operand(bx, operand); + let tuple = self.codegen_operand(bx, operand); // Handle both by-ref and immediate tuples. if let Ref(llval, align) = tuple.val { let tuple_ptr = PlaceRef::new_sized(llval, tuple.layout, align); for i in 0..tuple.layout.fields.count() { let field_ptr = tuple_ptr.project_field(bx, i); - self.trans_argument(bx, field_ptr.load(bx), llargs, &args[i]); + self.codegen_argument(bx, field_ptr.load(bx), llargs, &args[i]); } } else { // If the tuple is immediate, the elements are as well. for i in 0..tuple.layout.fields.count() { let op = tuple.extract_field(bx, i); - self.trans_argument(bx, op, llargs, &args[i]); + self.codegen_argument(bx, op, llargs, &args[i]); } } } @@ -792,7 +838,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } } else { - self.trans_place(bx, dest) + self.codegen_place(bx, dest) }; if fn_ret.is_indirect() { if dest.align.abi() < dest.layout.align.abi() { @@ -811,18 +857,18 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } - fn trans_transmute(&mut self, bx: &Builder<'a, 'tcx>, + fn codegen_transmute(&mut self, bx: &Builder<'a, 'tcx>, src: &mir::Operand<'tcx>, dst: &mir::Place<'tcx>) { if let mir::Place::Local(index) = *dst { match self.locals[index] { - LocalRef::Place(place) => self.trans_transmute_into(bx, src, place), + LocalRef::Place(place) => self.codegen_transmute_into(bx, src, place), LocalRef::Operand(None) => { let dst_layout = bx.cx.layout_of(self.monomorphized_place_ty(dst)); assert!(!dst_layout.ty.has_erasable_regions()); let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp"); place.storage_live(bx); - self.trans_transmute_into(bx, src, place); + self.codegen_transmute_into(bx, src, place); let op = place.load(bx); place.storage_dead(bx); self.locals[index] = LocalRef::Operand(Some(op)); @@ -833,15 +879,15 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } } else { - let dst = self.trans_place(bx, dst); - self.trans_transmute_into(bx, src, dst); + let dst = self.codegen_place(bx, dst); + self.codegen_transmute_into(bx, src, dst); } } - fn trans_transmute_into(&mut self, bx: &Builder<'a, 'tcx>, + fn codegen_transmute_into(&mut self, bx: &Builder<'a, 'tcx>, src: &mir::Operand<'tcx>, dst: PlaceRef<'tcx>) { - let src = self.trans_operand(bx, src); + let src = self.codegen_operand(bx, src); let llty = src.layout.llvm_type(bx.cx); let cast_ptr = bx.pointercast(dst.llval, llty.ptr_to()); let align = src.layout.align.min(dst.layout.align); diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs new file mode 100644 index 0000000000000..0d682d5d6f6a1 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/constant.rs @@ -0,0 +1,220 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::{self, ValueRef}; +use rustc::mir::interpret::ConstEvalErr; +use rustc_mir::interpret::{read_target_uint, const_val_field}; +use rustc::hir::def_id::DefId; +use rustc::mir; +use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::sync::Lrc; +use rustc::mir::interpret::{GlobalId, Pointer, Scalar, Allocation, ConstValue, AllocType}; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Size}; +use builder::Builder; +use common::{CodegenCx}; +use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize}; +use consts; +use type_of::LayoutLlvmExt; +use type_::Type; +use syntax::ast::Mutability; +use syntax::codemap::Span; + +use super::super::callee; +use super::FunctionCx; + +pub fn scalar_to_llvm(cx: &CodegenCx, + cv: Scalar, + layout: &layout::Scalar, + llty: Type) -> ValueRef { + let bitsize = if layout.is_bool() { 1 } else { layout.value.size(cx).bits() }; + match cv { + Scalar::Bits { defined, .. } if (defined as u64) < bitsize || defined == 0 => { + C_undef(Type::ix(cx, bitsize)) + }, + Scalar::Bits { bits, .. } => { + let llval = C_uint_big(Type::ix(cx, bitsize), bits); + if layout.value == layout::Pointer { + unsafe { llvm::LLVMConstIntToPtr(llval, llty.to_ref()) } + } else { + consts::bitcast(llval, llty) + } + }, + Scalar::Ptr(ptr) => { + let alloc_type = cx.tcx.alloc_map.lock().get(ptr.alloc_id); + let base_addr = match alloc_type { + Some(AllocType::Memory(alloc)) => { + let init = const_alloc_to_llvm(cx, alloc); + if alloc.runtime_mutability == Mutability::Mutable { + consts::addr_of_mut(cx, init, alloc.align, "byte_str") + } else { + consts::addr_of(cx, init, alloc.align, "byte_str") + } + } + Some(AllocType::Function(fn_instance)) => { + callee::get_fn(cx, fn_instance) + } + Some(AllocType::Static(def_id)) => { + assert!(cx.tcx.is_static(def_id).is_some()); + consts::get_static(cx, def_id) + } + None => bug!("missing allocation {:?}", ptr.alloc_id), + }; + let llval = unsafe { llvm::LLVMConstInBoundsGEP( + consts::bitcast(base_addr, Type::i8p(cx)), + &C_usize(cx, ptr.offset.bytes()), + 1, + ) }; + if layout.value != layout::Pointer { + unsafe { llvm::LLVMConstPtrToInt(llval, llty.to_ref()) } + } else { + consts::bitcast(llval, llty) + } + } + } +} + +pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { + let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); + let layout = cx.data_layout(); + let pointer_size = layout.pointer_size.bytes() as usize; + + let mut next_offset = 0; + for &(offset, alloc_id) in alloc.relocations.iter() { + let offset = offset.bytes(); + assert_eq!(offset as usize as u64, offset); + let offset = offset as usize; + if offset > next_offset { + llvals.push(C_bytes(cx, &alloc.bytes[next_offset..offset])); + } + let ptr_offset = read_target_uint( + layout.endian, + &alloc.bytes[offset..(offset + pointer_size)], + ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; + llvals.push(scalar_to_llvm( + cx, + Pointer { alloc_id, offset: Size::from_bytes(ptr_offset) }.into(), + &layout::Scalar { + value: layout::Primitive::Pointer, + valid_range: 0..=!0 + }, + Type::i8p(cx) + )); + next_offset = offset + pointer_size; + } + if alloc.bytes.len() >= next_offset { + llvals.push(C_bytes(cx, &alloc.bytes[next_offset ..])); + } + + C_struct(cx, &llvals, true) +} + +pub fn codegen_static_initializer<'a, 'tcx>( + cx: &CodegenCx<'a, 'tcx>, + def_id: DefId, +) -> Result<(ValueRef, &'tcx Allocation), Lrc>> { + let instance = ty::Instance::mono(cx.tcx, def_id); + let cid = GlobalId { + instance, + promoted: None, + }; + let param_env = ty::ParamEnv::reveal_all(); + let static_ = cx.tcx.const_eval(param_env.and(cid))?; + + let alloc = match static_.val { + ConstValue::ByRef(alloc, n) if n.bytes() == 0 => alloc, + _ => bug!("static const eval returned {:#?}", static_), + }; + Ok((const_alloc_to_llvm(cx, alloc), alloc)) +} + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + fn fully_evaluate( + &mut self, + bx: &Builder<'a, 'tcx>, + constant: &'tcx ty::Const<'tcx>, + ) -> Result<&'tcx ty::Const<'tcx>, Lrc>> { + match constant.val { + ConstValue::Unevaluated(def_id, ref substs) => { + let tcx = bx.tcx(); + let param_env = ty::ParamEnv::reveal_all(); + let instance = ty::Instance::resolve(tcx, param_env, def_id, substs).unwrap(); + let cid = GlobalId { + instance, + promoted: None, + }; + tcx.const_eval(param_env.and(cid)) + }, + _ => Ok(constant), + } + } + + pub fn eval_mir_constant( + &mut self, + bx: &Builder<'a, 'tcx>, + constant: &mir::Constant<'tcx>, + ) -> Result<&'tcx ty::Const<'tcx>, Lrc>> { + let c = self.monomorphize(&constant.literal); + self.fully_evaluate(bx, c) + } + + /// process constant containing SIMD shuffle indices + pub fn simd_shuffle_indices( + &mut self, + bx: &Builder<'a, 'tcx>, + span: Span, + ty: Ty<'tcx>, + constant: Result<&'tcx ty::Const<'tcx>, Lrc>>, + ) -> (ValueRef, Ty<'tcx>) { + constant + .and_then(|c| { + let field_ty = c.ty.builtin_index().unwrap(); + let fields = match c.ty.sty { + ty::TyArray(_, n) => n.unwrap_usize(bx.tcx()), + ref other => bug!("invalid simd shuffle type: {}", other), + }; + let values: Result, Lrc<_>> = (0..fields).map(|field| { + let field = const_val_field( + bx.tcx(), + ty::ParamEnv::reveal_all(), + self.instance, + None, + mir::Field::new(field as usize), + c, + )?; + if let Some(prim) = field.to_scalar() { + let layout = bx.cx.layout_of(field_ty); + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + Ok(scalar_to_llvm( + bx.cx, prim, scalar, + layout.immediate_llvm_type(bx.cx), + )) + } else { + bug!("simd shuffle field {:?}", field) + } + }).collect(); + let llval = C_struct(bx.cx, &values?, false); + Ok((llval, c.ty)) + }) + .unwrap_or_else(|e| { + e.report_as_error( + bx.tcx().at(span), + "could not evaluate shuffle_indices at compile time", + ); + // We've errored, so we don't have to produce working code. + let ty = self.monomorphize(&ty); + let llty = bx.cx.layout_of(ty).llvm_type(bx.cx); + (C_undef(llty), ty) + }) + } +} diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs new file mode 100644 index 0000000000000..312939408c62c --- /dev/null +++ b/src/librustc_codegen_llvm/mir/mod.rs @@ -0,0 +1,621 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use common::{C_i32, C_null}; +use libc::c_uint; +use llvm::{self, ValueRef, BasicBlockRef}; +use llvm::debuginfo::DIScope; +use rustc::ty::{self, Ty, TypeFoldable, UpvarSubsts}; +use rustc::ty::layout::{LayoutOf, TyLayout}; +use rustc::mir::{self, Mir}; +use rustc::ty::subst::Substs; +use rustc::session::config::FullDebugInfo; +use base; +use builder::Builder; +use common::{CodegenCx, Funclet}; +use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext}; +use monomorphize::Instance; +use abi::{ArgTypeExt, FnType, FnTypeExt, PassMode}; +use type_::Type; + +use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span}; +use syntax::symbol::keywords; + +use std::iter; + +use rustc_data_structures::bitvec::BitVector; +use rustc_data_structures::indexed_vec::{IndexVec, Idx}; + +pub use self::constant::codegen_static_initializer; + +use self::analyze::CleanupKind; +use self::place::PlaceRef; +use rustc::mir::traversal; + +use self::operand::{OperandRef, OperandValue}; + +/// Master context for codegenning from MIR. +pub struct FunctionCx<'a, 'tcx:'a> { + instance: Instance<'tcx>, + + mir: &'a mir::Mir<'tcx>, + + debug_context: debuginfo::FunctionDebugContext, + + llfn: ValueRef, + + cx: &'a CodegenCx<'a, 'tcx>, + + fn_ty: FnType<'tcx, Ty<'tcx>>, + + /// When unwinding is initiated, we have to store this personality + /// value somewhere so that we can load it and re-use it in the + /// resume instruction. The personality is (afaik) some kind of + /// value used for C++ unwinding, which must filter by type: we + /// don't really care about it very much. Anyway, this value + /// contains an alloca into which the personality is stored and + /// then later loaded when generating the DIVERGE_BLOCK. + personality_slot: Option>, + + /// A `Block` for each MIR `BasicBlock` + blocks: IndexVec, + + /// The funclet status of each basic block + cleanup_kinds: IndexVec, + + /// When targeting MSVC, this stores the cleanup info for each funclet + /// BB. This is initialized as we compute the funclets' head block in RPO. + funclets: &'a IndexVec>, + + /// This stores the landing-pad block for a given BB, computed lazily on GNU + /// and eagerly on MSVC. + landing_pads: IndexVec>, + + /// Cached unreachable block + unreachable_block: Option, + + /// The location where each MIR arg/var/tmp/ret is stored. This is + /// usually an `PlaceRef` representing an alloca, but not always: + /// sometimes we can skip the alloca and just store the value + /// directly using an `OperandRef`, which makes for tighter LLVM + /// IR. The conditions for using an `OperandRef` are as follows: + /// + /// - the type of the local must be judged "immediate" by `is_llvm_immediate` + /// - the operand must never be referenced indirectly + /// - we should not take its address using the `&` operator + /// - nor should it appear in a place path like `tmp.a` + /// - the operand must be defined by an rvalue that can generate immediate + /// values + /// + /// Avoiding allocs can also be important for certain intrinsics, + /// notably `expect`. + locals: IndexVec>, + + /// Debug information for MIR scopes. + scopes: IndexVec, + + /// If this function is being monomorphized, this contains the type substitutions used. + param_substs: &'tcx Substs<'tcx>, +} + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + pub fn monomorphize(&self, value: &T) -> T + where T: TypeFoldable<'tcx> + { + self.cx.tcx.subst_and_normalize_erasing_regions( + self.param_substs, + ty::ParamEnv::reveal_all(), + value, + ) + } + + pub fn set_debug_loc(&mut self, bx: &Builder, source_info: mir::SourceInfo) { + let (scope, span) = self.debug_loc(source_info); + debuginfo::set_source_location(&self.debug_context, bx, scope, span); + } + + pub fn debug_loc(&mut self, source_info: mir::SourceInfo) -> (DIScope, Span) { + // Bail out if debug info emission is not enabled. + match self.debug_context { + FunctionDebugContext::DebugInfoDisabled | + FunctionDebugContext::FunctionWithoutDebugInfo => { + return (self.scopes[source_info.scope].scope_metadata, source_info.span); + } + FunctionDebugContext::RegularContext(_) =>{} + } + + // In order to have a good line stepping behavior in debugger, we overwrite debug + // locations of macro expansions with that of the outermost expansion site + // (unless the crate is being compiled with `-Z debug-macros`). + if source_info.span.ctxt() == NO_EXPANSION || + self.cx.sess().opts.debugging_opts.debug_macros { + let scope = self.scope_metadata_for_loc(source_info.scope, source_info.span.lo()); + (scope, source_info.span) + } else { + // Walk up the macro expansion chain until we reach a non-expanded span. + // We also stop at the function body level because no line stepping can occur + // at the level above that. + let mut span = source_info.span; + while span.ctxt() != NO_EXPANSION && span.ctxt() != self.mir.span.ctxt() { + if let Some(info) = span.ctxt().outer().expn_info() { + span = info.call_site; + } else { + break; + } + } + let scope = self.scope_metadata_for_loc(source_info.scope, span.lo()); + // Use span of the outermost expansion site, while keeping the original lexical scope. + (scope, span) + } + } + + // DILocations inherit source file name from the parent DIScope. Due to macro expansions + // it may so happen that the current span belongs to a different file than the DIScope + // corresponding to span's containing source scope. If so, we need to create a DIScope + // "extension" into that file. + fn scope_metadata_for_loc(&self, scope_id: mir::SourceScope, pos: BytePos) + -> llvm::debuginfo::DIScope { + let scope_metadata = self.scopes[scope_id].scope_metadata; + if pos < self.scopes[scope_id].file_start_pos || + pos >= self.scopes[scope_id].file_end_pos { + let cm = self.cx.sess().codemap(); + let defining_crate = self.debug_context.get_ref(DUMMY_SP).defining_crate; + debuginfo::extend_scope_to_file(self.cx, + scope_metadata, + &cm.lookup_char_pos(pos).file, + defining_crate) + } else { + scope_metadata + } + } +} + +enum LocalRef<'tcx> { + Place(PlaceRef<'tcx>), + Operand(Option>), +} + +impl<'a, 'tcx> LocalRef<'tcx> { + fn new_operand(cx: &CodegenCx<'a, 'tcx>, layout: TyLayout<'tcx>) -> LocalRef<'tcx> { + if layout.is_zst() { + // Zero-size temporaries aren't always initialized, which + // doesn't matter because they don't contain data, but + // we need something in the operand. + LocalRef::Operand(Some(OperandRef::new_zst(cx, layout))) + } else { + LocalRef::Operand(None) + } + } +} + +/////////////////////////////////////////////////////////////////////////// + +pub fn codegen_mir<'a, 'tcx: 'a>( + cx: &'a CodegenCx<'a, 'tcx>, + llfn: ValueRef, + mir: &'a Mir<'tcx>, + instance: Instance<'tcx>, + sig: ty::FnSig<'tcx>, +) { + let fn_ty = FnType::new(cx, sig, &[]); + debug!("fn_ty: {:?}", fn_ty); + let debug_context = + debuginfo::create_function_debug_context(cx, instance, sig, llfn, mir); + let bx = Builder::new_block(cx, llfn, "start"); + + if mir.basic_blocks().iter().any(|bb| bb.is_cleanup) { + bx.set_personality_fn(cx.eh_personality()); + } + + let cleanup_kinds = analyze::cleanup_kinds(&mir); + // Allocate a `Block` for every basic block, except + // the start block, if nothing loops back to it. + let reentrant_start_block = !mir.predecessors_for(mir::START_BLOCK).is_empty(); + let block_bxs: IndexVec = + mir.basic_blocks().indices().map(|bb| { + if bb == mir::START_BLOCK && !reentrant_start_block { + bx.llbb() + } else { + bx.build_sibling_block(&format!("{:?}", bb)).llbb() + } + }).collect(); + + // Compute debuginfo scopes from MIR scopes. + let scopes = debuginfo::create_mir_scopes(cx, mir, &debug_context); + let (landing_pads, funclets) = create_funclets(mir, &bx, &cleanup_kinds, &block_bxs); + + let mut fx = FunctionCx { + instance, + mir, + llfn, + fn_ty, + cx, + personality_slot: None, + blocks: block_bxs, + unreachable_block: None, + cleanup_kinds, + landing_pads, + funclets: &funclets, + scopes, + locals: IndexVec::new(), + debug_context, + param_substs: { + assert!(!instance.substs.needs_infer()); + instance.substs + }, + }; + + let memory_locals = analyze::non_ssa_locals(&fx); + + // Allocate variable and temp allocas + fx.locals = { + let args = arg_local_refs(&bx, &fx, &fx.scopes, &memory_locals); + + let mut allocate_local = |local| { + let decl = &mir.local_decls[local]; + let layout = bx.cx.layout_of(fx.monomorphize(&decl.ty)); + assert!(!layout.ty.has_erasable_regions()); + + if let Some(name) = decl.name { + // User variable + let debug_scope = fx.scopes[decl.visibility_scope]; + let dbg = debug_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo; + + if !memory_locals.contains(local) && !dbg { + debug!("alloc: {:?} ({}) -> operand", local, name); + return LocalRef::new_operand(bx.cx, layout); + } + + debug!("alloc: {:?} ({}) -> place", local, name); + let place = PlaceRef::alloca(&bx, layout, &name.as_str()); + if dbg { + let (scope, span) = fx.debug_loc(mir::SourceInfo { + span: decl.source_info.span, + scope: decl.visibility_scope, + }); + declare_local(&bx, &fx.debug_context, name, layout.ty, scope, + VariableAccess::DirectVariable { alloca: place.llval }, + VariableKind::LocalVariable, span); + } + LocalRef::Place(place) + } else { + // Temporary or return place + if local == mir::RETURN_PLACE && fx.fn_ty.ret.is_indirect() { + debug!("alloc: {:?} (return place) -> place", local); + let llretptr = llvm::get_param(llfn, 0); + LocalRef::Place(PlaceRef::new_sized(llretptr, layout, layout.align)) + } else if memory_locals.contains(local) { + debug!("alloc: {:?} -> place", local); + LocalRef::Place(PlaceRef::alloca(&bx, layout, &format!("{:?}", local))) + } else { + // If this is an immediate local, we do not create an + // alloca in advance. Instead we wait until we see the + // definition and update the operand there. + debug!("alloc: {:?} -> operand", local); + LocalRef::new_operand(bx.cx, layout) + } + } + }; + + let retptr = allocate_local(mir::RETURN_PLACE); + iter::once(retptr) + .chain(args.into_iter()) + .chain(mir.vars_and_temps_iter().map(allocate_local)) + .collect() + }; + + // Branch to the START block, if it's not the entry block. + if reentrant_start_block { + bx.br(fx.blocks[mir::START_BLOCK]); + } + + // Up until here, IR instructions for this function have explicitly not been annotated with + // source code location, so we don't step into call setup code. From here on, source location + // emitting should be enabled. + debuginfo::start_emitting_source_locations(&fx.debug_context); + + let rpo = traversal::reverse_postorder(&mir); + let mut visited = BitVector::new(mir.basic_blocks().len()); + + // Codegen the body of each block using reverse postorder + for (bb, _) in rpo { + visited.insert(bb.index()); + fx.codegen_block(bb); + } + + // Remove blocks that haven't been visited, or have no + // predecessors. + for bb in mir.basic_blocks().indices() { + // Unreachable block + if !visited.contains(bb.index()) { + debug!("codegen_mir: block {:?} was not visited", bb); + unsafe { + llvm::LLVMDeleteBasicBlock(fx.blocks[bb]); + } + } + } +} + +fn create_funclets<'a, 'tcx>( + mir: &'a Mir<'tcx>, + bx: &Builder<'a, 'tcx>, + cleanup_kinds: &IndexVec, + block_bxs: &IndexVec) + -> (IndexVec>, + IndexVec>) +{ + block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| { + match *cleanup_kind { + CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {} + _ => return (None, None) + } + + let cleanup; + let ret_llbb; + match mir[bb].terminator.as_ref().map(|t| &t.kind) { + // This is a basic block that we're aborting the program for, + // notably in an `extern` function. These basic blocks are inserted + // so that we assert that `extern` functions do indeed not panic, + // and if they do we abort the process. + // + // On MSVC these are tricky though (where we're doing funclets). If + // we were to do a cleanuppad (like below) the normal functions like + // `longjmp` would trigger the abort logic, terminating the + // program. Instead we insert the equivalent of `catch(...)` for C++ + // which magically doesn't trigger when `longjmp` files over this + // frame. + // + // Lots more discussion can be found on #48251 but this codegen is + // modeled after clang's for: + // + // try { + // foo(); + // } catch (...) { + // bar(); + // } + Some(&mir::TerminatorKind::Abort) => { + let cs_bx = bx.build_sibling_block(&format!("cs_funclet{:?}", bb)); + let cp_bx = bx.build_sibling_block(&format!("cp_funclet{:?}", bb)); + ret_llbb = cs_bx.llbb(); + + let cs = cs_bx.catch_switch(None, None, 1); + cs_bx.add_handler(cs, cp_bx.llbb()); + + // The "null" here is actually a RTTI type descriptor for the + // C++ personality function, but `catch (...)` has no type so + // it's null. The 64 here is actually a bitfield which + // represents that this is a catch-all block. + let null = C_null(Type::i8p(bx.cx)); + let sixty_four = C_i32(bx.cx, 64); + cleanup = cp_bx.catch_pad(cs, &[null, sixty_four, null]); + cp_bx.br(llbb); + } + _ => { + let cleanup_bx = bx.build_sibling_block(&format!("funclet_{:?}", bb)); + ret_llbb = cleanup_bx.llbb(); + cleanup = cleanup_bx.cleanup_pad(None, &[]); + cleanup_bx.br(llbb); + } + }; + + (Some(ret_llbb), Some(Funclet::new(cleanup))) + }).unzip() +} + +/// Produce, for each argument, a `ValueRef` pointing at the +/// argument's value. As arguments are places, these are always +/// indirect. +fn arg_local_refs<'a, 'tcx>(bx: &Builder<'a, 'tcx>, + fx: &FunctionCx<'a, 'tcx>, + scopes: &IndexVec, + memory_locals: &BitVector) + -> Vec> { + let mir = fx.mir; + let tcx = bx.tcx(); + let mut idx = 0; + let mut llarg_idx = fx.fn_ty.ret.is_indirect() as usize; + + // Get the argument scope, if it exists and if we need it. + let arg_scope = scopes[mir::OUTERMOST_SOURCE_SCOPE]; + let arg_scope = if arg_scope.is_valid() && bx.sess().opts.debuginfo == FullDebugInfo { + Some(arg_scope.scope_metadata) + } else { + None + }; + + mir.args_iter().enumerate().map(|(arg_index, local)| { + let arg_decl = &mir.local_decls[local]; + + let name = if let Some(name) = arg_decl.name { + name.as_str().to_string() + } else { + format!("arg{}", arg_index) + }; + + if Some(local) == mir.spread_arg { + // This argument (e.g. the last argument in the "rust-call" ABI) + // is a tuple that was spread at the ABI level and now we have + // to reconstruct it into a tuple local variable, from multiple + // individual LLVM function arguments. + + let arg_ty = fx.monomorphize(&arg_decl.ty); + let tupled_arg_tys = match arg_ty.sty { + ty::TyTuple(ref tys) => tys, + _ => bug!("spread argument isn't a tuple?!") + }; + + let place = PlaceRef::alloca(bx, bx.cx.layout_of(arg_ty), &name); + for i in 0..tupled_arg_tys.len() { + let arg = &fx.fn_ty.args[idx]; + idx += 1; + if arg.pad.is_some() { + llarg_idx += 1; + } + arg.store_fn_arg(bx, &mut llarg_idx, place.project_field(bx, i)); + } + + // Now that we have one alloca that contains the aggregate value, + // we can create one debuginfo entry for the argument. + arg_scope.map(|scope| { + let variable_access = VariableAccess::DirectVariable { + alloca: place.llval + }; + declare_local( + bx, + &fx.debug_context, + arg_decl.name.unwrap_or(keywords::Invalid.name()), + arg_ty, scope, + variable_access, + VariableKind::ArgumentVariable(arg_index + 1), + DUMMY_SP + ); + }); + + return LocalRef::Place(place); + } + + let arg = &fx.fn_ty.args[idx]; + idx += 1; + if arg.pad.is_some() { + llarg_idx += 1; + } + + if arg_scope.is_none() && !memory_locals.contains(local) { + // We don't have to cast or keep the argument in the alloca. + // FIXME(eddyb): We should figure out how to use llvm.dbg.value instead + // of putting everything in allocas just so we can use llvm.dbg.declare. + let local = |op| LocalRef::Operand(Some(op)); + match arg.mode { + PassMode::Ignore => { + return local(OperandRef::new_zst(bx.cx, arg.layout)); + } + PassMode::Direct(_) => { + let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + bx.set_value_name(llarg, &name); + llarg_idx += 1; + return local( + OperandRef::from_immediate_or_packed_pair(bx, llarg, arg.layout)); + } + PassMode::Pair(..) => { + let a = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + bx.set_value_name(a, &(name.clone() + ".0")); + llarg_idx += 1; + + let b = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + bx.set_value_name(b, &(name + ".1")); + llarg_idx += 1; + + return local(OperandRef { + val: OperandValue::Pair(a, b), + layout: arg.layout + }); + } + _ => {} + } + } + + let place = if arg.is_indirect() { + // Don't copy an indirect argument to an alloca, the caller + // already put it in a temporary alloca and gave it up. + // FIXME: lifetimes + let llarg = llvm::get_param(bx.llfn(), llarg_idx as c_uint); + bx.set_value_name(llarg, &name); + llarg_idx += 1; + PlaceRef::new_sized(llarg, arg.layout, arg.layout.align) + } else { + let tmp = PlaceRef::alloca(bx, arg.layout, &name); + arg.store_fn_arg(bx, &mut llarg_idx, tmp); + tmp + }; + arg_scope.map(|scope| { + // Is this a regular argument? + if arg_index > 0 || mir.upvar_decls.is_empty() { + // The Rust ABI passes indirect variables using a pointer and a manual copy, so we + // need to insert a deref here, but the C ABI uses a pointer and a copy using the + // byval attribute, for which LLVM always does the deref itself, + // so we must not add it. + let variable_access = VariableAccess::DirectVariable { + alloca: place.llval + }; + + declare_local( + bx, + &fx.debug_context, + arg_decl.name.unwrap_or(keywords::Invalid.name()), + arg.layout.ty, + scope, + variable_access, + VariableKind::ArgumentVariable(arg_index + 1), + DUMMY_SP + ); + return; + } + + // Or is it the closure environment? + let (closure_layout, env_ref) = match arg.layout.ty.sty { + ty::TyRawPtr(ty::TypeAndMut { ty, .. }) | + ty::TyRef(_, ty, _) => (bx.cx.layout_of(ty), true), + _ => (arg.layout, false) + }; + + let (def_id, upvar_substs) = match closure_layout.ty.sty { + ty::TyClosure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), + ty::TyGenerator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), + _ => bug!("upvar_decls with non-closure arg0 type `{}`", closure_layout.ty) + }; + let upvar_tys = upvar_substs.upvar_tys(def_id, tcx); + + for (i, (decl, ty)) in mir.upvar_decls.iter().zip(upvar_tys).enumerate() { + let byte_offset_of_var_in_env = closure_layout.fields.offset(i).bytes(); + + let ops = unsafe { + [llvm::LLVMRustDIBuilderCreateOpDeref(), + llvm::LLVMRustDIBuilderCreateOpPlusUconst(), + byte_offset_of_var_in_env as i64, + llvm::LLVMRustDIBuilderCreateOpDeref()] + }; + + // The environment and the capture can each be indirect. + let mut ops = if env_ref { &ops[..] } else { &ops[1..] }; + + let ty = if let (true, &ty::TyRef(_, ty, _)) = (decl.by_ref, &ty.sty) { + ty + } else { + ops = &ops[..ops.len() - 1]; + ty + }; + + let variable_access = VariableAccess::IndirectVariable { + alloca: place.llval, + address_operations: &ops + }; + declare_local( + bx, + &fx.debug_context, + decl.debug_name, + ty, + scope, + variable_access, + VariableKind::LocalVariable, + DUMMY_SP + ); + } + }); + LocalRef::Place(place) + }).collect() +} + +mod analyze; +mod block; +mod constant; +pub mod place; +pub mod operand; +mod rvalue; +mod statement; diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs new file mode 100644 index 0000000000000..c433df51110e3 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -0,0 +1,424 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use llvm::ValueRef; +use rustc::mir::interpret::ConstEvalErr; +use rustc::mir; +use rustc::mir::interpret::ConstValue; +use rustc::ty; +use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc_data_structures::indexed_vec::Idx; +use rustc_data_structures::sync::Lrc; + +use base; +use common::{CodegenCx, C_undef, C_usize}; +use builder::{Builder, MemFlags}; +use value::Value; +use type_of::LayoutLlvmExt; + +use std::fmt; +use std::ptr; + +use super::{FunctionCx, LocalRef}; +use super::constant::scalar_to_llvm; +use super::place::PlaceRef; + +/// The representation of a Rust value. The enum variant is in fact +/// uniquely determined by the value's type, but is kept as a +/// safety check. +#[derive(Copy, Clone)] +pub enum OperandValue { + /// A reference to the actual operand. The data is guaranteed + /// to be valid for the operand's lifetime. + Ref(ValueRef, Align), + /// A single LLVM value. + Immediate(ValueRef), + /// A pair of immediate LLVM values. Used by fat pointers too. + Pair(ValueRef, ValueRef) +} + +impl fmt::Debug for OperandValue { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + OperandValue::Ref(r, align) => { + write!(f, "Ref({:?}, {:?})", Value(r), align) + } + OperandValue::Immediate(i) => { + write!(f, "Immediate({:?})", Value(i)) + } + OperandValue::Pair(a, b) => { + write!(f, "Pair({:?}, {:?})", Value(a), Value(b)) + } + } + } +} + +/// An `OperandRef` is an "SSA" reference to a Rust value, along with +/// its type. +/// +/// NOTE: unless you know a value's type exactly, you should not +/// generate LLVM opcodes acting on it and instead act via methods, +/// to avoid nasty edge cases. In particular, using `Builder::store` +/// directly is sure to cause problems -- use `OperandRef::store` +/// instead. +#[derive(Copy, Clone)] +pub struct OperandRef<'tcx> { + // The value. + pub val: OperandValue, + + // The layout of value, based on its Rust type. + pub layout: TyLayout<'tcx>, +} + +impl<'tcx> fmt::Debug for OperandRef<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "OperandRef({:?} @ {:?})", self.val, self.layout) + } +} + +impl<'a, 'tcx> OperandRef<'tcx> { + pub fn new_zst(cx: &CodegenCx<'a, 'tcx>, + layout: TyLayout<'tcx>) -> OperandRef<'tcx> { + assert!(layout.is_zst()); + OperandRef { + val: OperandValue::Immediate(C_undef(layout.immediate_llvm_type(cx))), + layout + } + } + + pub fn from_const(bx: &Builder<'a, 'tcx>, + val: &'tcx ty::Const<'tcx>) + -> Result, Lrc>> { + let layout = bx.cx.layout_of(val.ty); + + if layout.is_zst() { + return Ok(OperandRef::new_zst(bx.cx, layout)); + } + + let val = match val.val { + ConstValue::Unevaluated(..) => bug!(), + ConstValue::Scalar(x) => { + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + let llval = scalar_to_llvm( + bx.cx, + x, + scalar, + layout.immediate_llvm_type(bx.cx), + ); + OperandValue::Immediate(llval) + }, + ConstValue::ScalarPair(a, b) => { + let (a_scalar, b_scalar) = match layout.abi { + layout::Abi::ScalarPair(ref a, ref b) => (a, b), + _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout) + }; + let a_llval = scalar_to_llvm( + bx.cx, + a, + a_scalar, + layout.scalar_pair_element_llvm_type(bx.cx, 0, true), + ); + let b_llval = scalar_to_llvm( + bx.cx, + b, + b_scalar, + layout.scalar_pair_element_llvm_type(bx.cx, 1, true), + ); + OperandValue::Pair(a_llval, b_llval) + }, + ConstValue::ByRef(alloc, offset) => { + return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx)); + }, + }; + + Ok(OperandRef { + val, + layout + }) + } + + /// Asserts that this operand refers to a scalar and returns + /// a reference to its value. + pub fn immediate(self) -> ValueRef { + match self.val { + OperandValue::Immediate(s) => s, + _ => bug!("not immediate: {:?}", self) + } + } + + pub fn deref(self, cx: &CodegenCx<'a, 'tcx>) -> PlaceRef<'tcx> { + let projected_ty = self.layout.ty.builtin_deref(true) + .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self)).ty; + let (llptr, llextra) = match self.val { + OperandValue::Immediate(llptr) => (llptr, ptr::null_mut()), + OperandValue::Pair(llptr, llextra) => (llptr, llextra), + OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self) + }; + let layout = cx.layout_of(projected_ty); + PlaceRef { + llval: llptr, + llextra, + layout, + align: layout.align, + } + } + + /// If this operand is a `Pair`, we return an aggregate with the two values. + /// For other cases, see `immediate`. + pub fn immediate_or_packed_pair(self, bx: &Builder<'a, 'tcx>) -> ValueRef { + if let OperandValue::Pair(a, b) = self.val { + let llty = self.layout.llvm_type(bx.cx); + debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", + self, llty); + // Reconstruct the immediate aggregate. + let mut llpair = C_undef(llty); + llpair = bx.insert_value(llpair, base::from_immediate(bx, a), 0); + llpair = bx.insert_value(llpair, base::from_immediate(bx, b), 1); + llpair + } else { + self.immediate() + } + } + + /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`. + pub fn from_immediate_or_packed_pair(bx: &Builder<'a, 'tcx>, + llval: ValueRef, + layout: TyLayout<'tcx>) + -> OperandRef<'tcx> { + let val = if let layout::Abi::ScalarPair(ref a, ref b) = layout.abi { + debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}", + llval, layout); + + // Deconstruct the immediate aggregate. + let a_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 0), a); + let b_llval = base::to_immediate_scalar(bx, bx.extract_value(llval, 1), b); + OperandValue::Pair(a_llval, b_llval) + } else { + OperandValue::Immediate(llval) + }; + OperandRef { val, layout } + } + + pub fn extract_field(&self, bx: &Builder<'a, 'tcx>, i: usize) -> OperandRef<'tcx> { + let field = self.layout.field(bx.cx, i); + let offset = self.layout.fields.offset(i); + + let mut val = match (self.val, &self.layout.abi) { + // If the field is ZST, it has no data. + _ if field.is_zst() => { + return OperandRef::new_zst(bx.cx, field); + } + + // Newtype of a scalar, scalar pair or vector. + (OperandValue::Immediate(_), _) | + (OperandValue::Pair(..), _) if field.size == self.layout.size => { + assert_eq!(offset.bytes(), 0); + self.val + } + + // Extract a scalar component from a pair. + (OperandValue::Pair(a_llval, b_llval), &layout::Abi::ScalarPair(ref a, ref b)) => { + if offset.bytes() == 0 { + assert_eq!(field.size, a.value.size(bx.cx)); + OperandValue::Immediate(a_llval) + } else { + assert_eq!(offset, a.value.size(bx.cx) + .abi_align(b.value.align(bx.cx))); + assert_eq!(field.size, b.value.size(bx.cx)); + OperandValue::Immediate(b_llval) + } + } + + // `#[repr(simd)]` types are also immediate. + (OperandValue::Immediate(llval), &layout::Abi::Vector { .. }) => { + OperandValue::Immediate( + bx.extract_element(llval, C_usize(bx.cx, i as u64))) + } + + _ => bug!("OperandRef::extract_field({:?}): not applicable", self) + }; + + // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + match val { + OperandValue::Immediate(ref mut llval) => { + *llval = bx.bitcast(*llval, field.immediate_llvm_type(bx.cx)); + } + OperandValue::Pair(ref mut a, ref mut b) => { + *a = bx.bitcast(*a, field.scalar_pair_element_llvm_type(bx.cx, 0, true)); + *b = bx.bitcast(*b, field.scalar_pair_element_llvm_type(bx.cx, 1, true)); + } + OperandValue::Ref(..) => bug!() + } + + OperandRef { + val, + layout: field + } + } +} + +impl<'a, 'tcx> OperandValue { + pub fn store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::empty()); + } + + pub fn volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::VOLATILE); + } + + pub fn unaligned_volatile_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::VOLATILE | MemFlags::UNALIGNED); + } + + pub fn nontemporal_store(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>) { + self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL); + } + + fn store_with_flags(self, bx: &Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, flags: MemFlags) { + debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest); + // Avoid generating stores of zero-sized values, because the only way to have a zero-sized + // value is through `undef`, and store itself is useless. + if dest.layout.is_zst() { + return; + } + match self { + OperandValue::Ref(r, source_align) => { + base::memcpy_ty(bx, dest.llval, r, dest.layout, + source_align.min(dest.align), flags) + } + OperandValue::Immediate(s) => { + let val = base::from_immediate(bx, s); + bx.store_with_flags(val, dest.llval, dest.align, flags); + } + OperandValue::Pair(a, b) => { + for (i, &x) in [a, b].iter().enumerate() { + let llptr = bx.struct_gep(dest.llval, i as u64); + let val = base::from_immediate(bx, x); + bx.store_with_flags(val, llptr, dest.align, flags); + } + } + } + } +} + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + fn maybe_codegen_consume_direct(&mut self, + bx: &Builder<'a, 'tcx>, + place: &mir::Place<'tcx>) + -> Option> + { + debug!("maybe_codegen_consume_direct(place={:?})", place); + + // watch out for locals that do not have an + // alloca; they are handled somewhat differently + if let mir::Place::Local(index) = *place { + match self.locals[index] { + LocalRef::Operand(Some(o)) => { + return Some(o); + } + LocalRef::Operand(None) => { + bug!("use of {:?} before def", place); + } + LocalRef::Place(..) => { + // use path below + } + } + } + + // Moves out of scalar and scalar pair fields are trivial. + if let &mir::Place::Projection(ref proj) = place { + if let Some(o) = self.maybe_codegen_consume_direct(bx, &proj.base) { + match proj.elem { + mir::ProjectionElem::Field(ref f, _) => { + return Some(o.extract_field(bx, f.index())); + } + mir::ProjectionElem::Index(_) | + mir::ProjectionElem::ConstantIndex { .. } => { + // ZSTs don't require any actual memory access. + // FIXME(eddyb) deduplicate this with the identical + // checks in `codegen_consume` and `extract_field`. + let elem = o.layout.field(bx.cx, 0); + if elem.is_zst() { + return Some(OperandRef::new_zst(bx.cx, elem)); + } + } + _ => {} + } + } + } + + None + } + + pub fn codegen_consume(&mut self, + bx: &Builder<'a, 'tcx>, + place: &mir::Place<'tcx>) + -> OperandRef<'tcx> + { + debug!("codegen_consume(place={:?})", place); + + let ty = self.monomorphized_place_ty(place); + let layout = bx.cx.layout_of(ty); + + // ZSTs don't require any actual memory access. + if layout.is_zst() { + return OperandRef::new_zst(bx.cx, layout); + } + + if let Some(o) = self.maybe_codegen_consume_direct(bx, place) { + return o; + } + + // for most places, to consume them we just load them + // out from their home + self.codegen_place(bx, place).load(bx) + } + + pub fn codegen_operand(&mut self, + bx: &Builder<'a, 'tcx>, + operand: &mir::Operand<'tcx>) + -> OperandRef<'tcx> + { + debug!("codegen_operand(operand={:?})", operand); + + match *operand { + mir::Operand::Copy(ref place) | + mir::Operand::Move(ref place) => { + self.codegen_consume(bx, place) + } + + mir::Operand::Constant(ref constant) => { + let ty = self.monomorphize(&constant.ty); + self.eval_mir_constant(bx, constant) + .and_then(|c| OperandRef::from_const(bx, c)) + .unwrap_or_else(|err| { + err.report_as_error( + bx.tcx().at(constant.span), + "could not evaluate constant operand", + ); + // Allow RalfJ to sleep soundly knowing that even refactorings that remove + // the above error (or silence it under some conditions) will not cause UB + let fnname = bx.cx.get_intrinsic(&("llvm.trap")); + bx.call(fnname, &[], None); + // We've errored, so we don't have to produce working code. + let layout = bx.cx.layout_of(ty); + PlaceRef::new_sized( + C_undef(layout.llvm_type(bx.cx).ptr_to()), + layout, + layout.align, + ).load(bx) + }) + } + } + } +} diff --git a/src/librustc_trans/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs similarity index 82% rename from src/librustc_trans/mir/place.rs rename to src/librustc_codegen_llvm/mir/place.rs index 79859aee64d87..9abf9077a9577 100644 --- a/src/librustc_trans/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::{self, ValueRef}; +use llvm::{self, ValueRef, LLVMConstInBoundsGEP}; use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, TyLayout, LayoutOf}; +use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, Size}; use rustc::mir; use rustc::mir::tcx::PlaceTy; use rustc_data_structures::indexed_vec::Idx; @@ -22,6 +22,7 @@ use type_of::LayoutLlvmExt; use type_::Type; use value::Value; use glue; +use mir::constant::const_alloc_to_llvm; use std::ptr; @@ -56,6 +57,24 @@ impl<'a, 'tcx> PlaceRef<'tcx> { } } + pub fn from_const_alloc( + bx: &Builder<'a, 'tcx>, + layout: TyLayout<'tcx>, + alloc: &mir::interpret::Allocation, + offset: Size, + ) -> PlaceRef<'tcx> { + let init = const_alloc_to_llvm(bx.cx, alloc); + let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str"); + + let llval = unsafe { LLVMConstInBoundsGEP( + consts::bitcast(base_addr, Type::i8p(bx.cx)), + &C_usize(bx.cx, offset.bytes()), + 1, + )}; + let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to()); + PlaceRef::new_sized(llval, layout, alloc.align) + } + pub fn alloca(bx: &Builder<'a, 'tcx>, layout: TyLayout<'tcx>, name: &str) -> PlaceRef<'tcx> { debug!("alloca({:?}: {:?})", name, layout); @@ -127,11 +146,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { OperandValue::Immediate(base::to_immediate(bx, llval, self.layout)) } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi { let load = |i, scalar: &layout::Scalar| { - let mut llptr = bx.struct_gep(self.llval, i as u64); - // Make sure to always load i1 as i8. - if scalar.is_bool() { - llptr = bx.pointercast(llptr, Type::i8p(bx.cx)); - } + let llptr = bx.struct_gep(self.llval, i as u64); let load = bx.load(llptr, self.align); scalar_load_metadata(load, scalar); if scalar.is_bool() { @@ -253,7 +268,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { } /// Obtain the actual discriminant of a value. - pub fn trans_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef { + pub fn codegen_get_discr(self, bx: &Builder<'a, 'tcx>, cast_to: Ty<'tcx>) -> ValueRef { let cast_to = bx.cx.layout_of(cast_to).immediate_llvm_type(bx.cx); if self.layout.abi == layout::Abi::Uninhabited { return C_undef(cast_to); @@ -273,9 +288,13 @@ impl<'a, 'tcx> PlaceRef<'tcx> { let lldiscr = discr.load(bx).immediate(); match self.layout.variants { layout::Variants::Single { .. } => bug!(), - layout::Variants::Tagged { ref discr, .. } => { - let signed = match discr.value { - layout::Int(_, signed) => signed, + layout::Variants::Tagged { ref tag, .. } => { + let signed = match tag.value { + // We use `i1` for bytes that are always `0` or `1`, + // e.g. `#[repr(i8)] enum E { A, B }`, but we can't + // let LLVM interpret the `i1` as signed, because + // then `i1 1` (i.e. E::B) is effectively `i8 -1`. + layout::Int(_, signed) => !tag.is_bool() && signed, _ => false }; bx.intcast(lldiscr, cast_to, signed) @@ -313,7 +332,7 @@ impl<'a, 'tcx> PlaceRef<'tcx> { /// Set the discriminant for a new value of the given case of the given /// representation. - pub fn trans_set_discr(&self, bx: &Builder<'a, 'tcx>, variant_index: usize) { + pub fn codegen_set_discr(&self, bx: &Builder<'a, 'tcx>, variant_index: usize) { if self.layout.for_variant(bx.cx, variant_index).abi == layout::Abi::Uninhabited { return; } @@ -399,11 +418,11 @@ impl<'a, 'tcx> PlaceRef<'tcx> { } impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn trans_place(&mut self, + pub fn codegen_place(&mut self, bx: &Builder<'a, 'tcx>, place: &mir::Place<'tcx>) -> PlaceRef<'tcx> { - debug!("trans_place(place={:?})", place); + debug!("codegen_place(place={:?})", place); let cx = bx.cx; let tcx = cx.tcx; @@ -421,6 +440,32 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let result = match *place { mir::Place::Local(_) => bug!(), // handled above + mir::Place::Promoted(box (index, ty)) => { + let param_env = ty::ParamEnv::reveal_all(); + let cid = mir::interpret::GlobalId { + instance: self.instance, + promoted: Some(index), + }; + let layout = cx.layout_of(self.monomorphize(&ty)); + match bx.tcx().const_eval(param_env.and(cid)) { + Ok(val) => match val.val { + mir::interpret::ConstValue::ByRef(alloc, offset) => { + PlaceRef::from_const_alloc(bx, layout, alloc, offset) + } + _ => bug!("promoteds should have an allocation: {:?}", val), + }, + Err(_) => { + // this is unreachable as long as runtime + // and compile-time agree on values + // With floats that won't always be true + // so we generate an abort + let fnname = bx.cx.get_intrinsic(&("llvm.trap")); + bx.call(fnname, &[], None); + let llval = C_undef(layout.llvm_type(bx.cx).ptr_to()); + PlaceRef::new_sized(llval, layout, layout.align) + } + } + } mir::Place::Static(box mir::Static { def_id, ty }) => { let layout = cx.layout_of(self.monomorphize(&ty)); PlaceRef::new_sized(consts::get_static(cx, def_id), layout, layout.align) @@ -430,46 +475,46 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { elem: mir::ProjectionElem::Deref }) => { // Load the pointer from its location. - self.trans_consume(bx, base).deref(bx.cx) + self.codegen_consume(bx, base).deref(bx.cx) } mir::Place::Projection(ref projection) => { - let tr_base = self.trans_place(bx, &projection.base); + let cg_base = self.codegen_place(bx, &projection.base); match projection.elem { mir::ProjectionElem::Deref => bug!(), mir::ProjectionElem::Field(ref field, _) => { - tr_base.project_field(bx, field.index()) + cg_base.project_field(bx, field.index()) } mir::ProjectionElem::Index(index) => { let index = &mir::Operand::Copy(mir::Place::Local(index)); - let index = self.trans_operand(bx, index); + let index = self.codegen_operand(bx, index); let llindex = index.immediate(); - tr_base.project_index(bx, llindex) + cg_base.project_index(bx, llindex) } mir::ProjectionElem::ConstantIndex { offset, from_end: false, min_length: _ } => { let lloffset = C_usize(bx.cx, offset as u64); - tr_base.project_index(bx, lloffset) + cg_base.project_index(bx, lloffset) } mir::ProjectionElem::ConstantIndex { offset, from_end: true, min_length: _ } => { let lloffset = C_usize(bx.cx, offset as u64); - let lllen = tr_base.len(bx.cx); + let lllen = cg_base.len(bx.cx); let llindex = bx.sub(lllen, lloffset); - tr_base.project_index(bx, llindex) + cg_base.project_index(bx, llindex) } mir::ProjectionElem::Subslice { from, to } => { - let mut subslice = tr_base.project_index(bx, + let mut subslice = cg_base.project_index(bx, C_usize(bx.cx, from as u64)); - let projected_ty = PlaceTy::Ty { ty: tr_base.layout.ty } + let projected_ty = PlaceTy::Ty { ty: cg_base.layout.ty } .projection_ty(tcx, &projection.elem).to_ty(bx.tcx()); subslice.layout = bx.cx.layout_of(self.monomorphize(&projected_ty)); if subslice.layout.is_unsized() { - assert!(tr_base.has_extra()); - subslice.llextra = bx.sub(tr_base.llextra, + assert!(cg_base.has_extra()); + subslice.llextra = bx.sub(cg_base.llextra, C_usize(bx.cx, (from as u64) + (to as u64))); } @@ -481,12 +526,12 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { subslice } mir::ProjectionElem::Downcast(_, v) => { - tr_base.project_downcast(bx, v) + cg_base.project_downcast(bx, v) } } } }; - debug!("trans_place(place={:?}) => {:?}", place, result); + debug!("codegen_place(place={:?}) => {:?}", place, result); result } @@ -496,4 +541,3 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { self.monomorphize(&place_ty.to_ty(tcx)) } } - diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_codegen_llvm/mir/rvalue.rs similarity index 92% rename from src/librustc_trans/mir/rvalue.rs rename to src/librustc_codegen_llvm/mir/rvalue.rs index 0cd823391b9b6..2e81fc16a5838 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_codegen_llvm/mir/rvalue.rs @@ -33,21 +33,21 @@ use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; impl<'a, 'tcx> FunctionCx<'a, 'tcx> { - pub fn trans_rvalue(&mut self, + pub fn codegen_rvalue(&mut self, bx: Builder<'a, 'tcx>, dest: PlaceRef<'tcx>, rvalue: &mir::Rvalue<'tcx>) -> Builder<'a, 'tcx> { - debug!("trans_rvalue(dest.llval={:?}, rvalue={:?})", + debug!("codegen_rvalue(dest.llval={:?}, rvalue={:?})", Value(dest.llval), rvalue); match *rvalue { mir::Rvalue::Use(ref operand) => { - let tr_operand = self.trans_operand(&bx, operand); - // FIXME: consider not copying constants through stack. (fixable by translating + let cg_operand = self.codegen_operand(&bx, operand); + // FIXME: consider not copying constants through stack. (fixable by codegenning // constants into OperandValue::Ref, why don’t we do that yet if we don’t?) - tr_operand.val.store(&bx, dest); + cg_operand.val.store(&bx, dest); bx } @@ -57,16 +57,16 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if dest.layout.is_llvm_scalar_pair() { // into-coerce of a thin pointer to a fat pointer - just // use the operand path. - let (bx, temp) = self.trans_rvalue_operand(bx, rvalue); + let (bx, temp) = self.codegen_rvalue_operand(bx, rvalue); temp.val.store(&bx, dest); return bx; } // Unsize of a nontrivial struct. I would prefer for - // this to be eliminated by MIR translation, but + // this to be eliminated by MIR building, but // `CoerceUnsized` can be passed by a where-clause, // so the (generic) MIR may not be able to expand it. - let operand = self.trans_operand(&bx, source); + let operand = self.codegen_operand(&bx, source); match operand.val { OperandValue::Pair(..) | OperandValue::Immediate(_) => { @@ -76,7 +76,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // `coerce_unsized_into` use extractvalue to // index into the struct, and this case isn't // important enough for it. - debug!("trans_rvalue: creating ugly alloca"); + debug!("codegen_rvalue: creating ugly alloca"); let scratch = PlaceRef::alloca(&bx, operand.layout, "__unsize_temp"); scratch.storage_live(&bx); operand.val.store(&bx, scratch); @@ -92,7 +92,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } mir::Rvalue::Repeat(ref elem, count) => { - let tr_elem = self.trans_operand(&bx, elem); + let cg_elem = self.codegen_operand(&bx, elem); // Do not generate the loop for zero-sized elements or empty arrays. if dest.layout.is_zst() { @@ -101,7 +101,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let start = dest.project_index(&bx, C_usize(bx.cx, 0)).llval; - if let OperandValue::Immediate(v) = tr_elem.val { + if let OperandValue::Immediate(v) = cg_elem.val { let align = C_i32(bx.cx, dest.align.abi() as i32); let size = C_usize(bx.cx, dest.layout.size.bytes()); @@ -133,8 +133,8 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let keep_going = header_bx.icmp(llvm::IntNE, current, end); header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb()); - tr_elem.val.store(&body_bx, - PlaceRef::new_sized(current, tr_elem.layout, dest.align)); + cg_elem.val.store(&body_bx, + PlaceRef::new_sized(current, cg_elem.layout, dest.align)); let next = body_bx.inbounds_gep(current, &[C_usize(bx.cx, 1)]); body_bx.br(header_bx.llbb()); @@ -146,7 +146,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { mir::Rvalue::Aggregate(ref kind, ref operands) => { let (dest, active_field_index) = match **kind { mir::AggregateKind::Adt(adt_def, variant_index, _, active_field_index) => { - dest.trans_set_discr(&bx, variant_index); + dest.codegen_set_discr(&bx, variant_index); if adt_def.is_enum() { (dest.project_downcast(&bx, variant_index), active_field_index) } else { @@ -156,7 +156,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { _ => (dest, None) }; for (i, operand) in operands.iter().enumerate() { - let op = self.trans_operand(&bx, operand); + let op = self.codegen_operand(&bx, operand); // Do not generate stores and GEPis for zero-sized fields. if !op.layout.is_zst() { let field_index = active_field_index.unwrap_or(i); @@ -168,23 +168,23 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { _ => { assert!(self.rvalue_creates_operand(rvalue)); - let (bx, temp) = self.trans_rvalue_operand(bx, rvalue); + let (bx, temp) = self.codegen_rvalue_operand(bx, rvalue); temp.val.store(&bx, dest); bx } } } - pub fn trans_rvalue_operand(&mut self, + pub fn codegen_rvalue_operand(&mut self, bx: Builder<'a, 'tcx>, rvalue: &mir::Rvalue<'tcx>) -> (Builder<'a, 'tcx>, OperandRef<'tcx>) { - assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + assert!(self.rvalue_creates_operand(rvalue), "cannot codegen {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Cast(ref kind, ref source, mir_cast_ty) => { - let operand = self.trans_operand(&bx, source); + let operand = self.codegen_operand(&bx, source); debug!("cast operand is {:?}", operand); let cast = bx.cx.layout_of(self.monomorphize(&mir_cast_ty)); @@ -232,7 +232,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // HACK(eddyb) have to bitcast pointers // until LLVM removes pointee types. let lldata = bx.pointercast(lldata, - cast.scalar_pair_element_llvm_type(bx.cx, 0)); + cast.scalar_pair_element_llvm_type(bx.cx, 0, true)); OperandValue::Pair(lldata, llextra) } OperandValue::Immediate(lldata) => { @@ -242,7 +242,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { OperandValue::Pair(lldata, llextra) } OperandValue::Ref(..) => { - bug!("by-ref operand {:?} in trans_rvalue_operand", + bug!("by-ref operand {:?} in codegen_rvalue_operand", operand); } } @@ -251,7 +251,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { if let OperandValue::Pair(data_ptr, meta) = operand.val { if cast.is_llvm_scalar_pair() { let data_cast = bx.pointercast(data_ptr, - cast.scalar_pair_element_llvm_type(bx.cx, 0)); + cast.scalar_pair_element_llvm_type(bx.cx, 0, true)); OperandValue::Pair(data_cast, meta) } else { // cast to thin-ptr // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and @@ -298,7 +298,11 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let mut signed = false; if let layout::Abi::Scalar(ref scalar) = operand.layout.abi { if let layout::Int(_, s) = scalar.value { - signed = s; + // We use `i1` for bytes that are always `0` or `1`, + // e.g. `#[repr(i8)] enum E { A, B }`, but we can't + // let LLVM interpret the `i1` as signed, because + // then `i1 1` (i.e. E::B) is effectively `i8 -1`. + signed = !scalar.is_bool() && s; if scalar.valid_range.end() > scalar.valid_range.start() { // We want `table[e as usize]` to not @@ -358,16 +362,16 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } mir::Rvalue::Ref(_, bk, ref place) => { - let tr_place = self.trans_place(&bx, place); + let cg_place = self.codegen_place(&bx, place); - let ty = tr_place.layout.ty; + let ty = cg_place.layout.ty; // Note: places are indirect, so storing the `llval` into the // destination effectively creates a reference. let val = if !bx.cx.type_has_metadata(ty) { - OperandValue::Immediate(tr_place.llval) + OperandValue::Immediate(cg_place.llval) } else { - OperandValue::Pair(tr_place.llval, tr_place.llextra) + OperandValue::Pair(cg_place.llval, cg_place.llextra) }; (bx, OperandRef { val, @@ -388,12 +392,12 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { - let lhs = self.trans_operand(&bx, lhs); - let rhs = self.trans_operand(&bx, rhs); + let lhs = self.codegen_operand(&bx, lhs); + let rhs = self.codegen_operand(&bx, rhs); let llresult = match (lhs.val, rhs.val) { (OperandValue::Pair(lhs_addr, lhs_extra), OperandValue::Pair(rhs_addr, rhs_extra)) => { - self.trans_fat_ptr_binop(&bx, op, + self.codegen_fat_ptr_binop(&bx, op, lhs_addr, lhs_extra, rhs_addr, rhs_extra, lhs.layout.ty) @@ -401,7 +405,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { (OperandValue::Immediate(lhs_val), OperandValue::Immediate(rhs_val)) => { - self.trans_scalar_binop(&bx, op, lhs_val, rhs_val, lhs.layout.ty) + self.codegen_scalar_binop(&bx, op, lhs_val, rhs_val, lhs.layout.ty) } _ => bug!() @@ -414,9 +418,9 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { (bx, operand) } mir::Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) => { - let lhs = self.trans_operand(&bx, lhs); - let rhs = self.trans_operand(&bx, rhs); - let result = self.trans_scalar_checked_binop(&bx, op, + let lhs = self.codegen_operand(&bx, lhs); + let rhs = self.codegen_operand(&bx, rhs); + let result = self.codegen_scalar_checked_binop(&bx, op, lhs.immediate(), rhs.immediate(), lhs.layout.ty); let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty); @@ -430,7 +434,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } mir::Rvalue::UnaryOp(op, ref operand) => { - let operand = self.trans_operand(&bx, operand); + let operand = self.codegen_operand(&bx, operand); let lloperand = operand.immediate(); let is_float = operand.layout.ty.is_fp(); let llval = match op { @@ -449,8 +453,8 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { mir::Rvalue::Discriminant(ref place) => { let discr_ty = rvalue.ty(&*self.mir, bx.tcx()); - let discr = self.trans_place(&bx, place) - .trans_get_discr(&bx, discr_ty); + let discr = self.codegen_place(&bx, place) + .codegen_get_discr(&bx, discr_ty); (bx, OperandRef { val: OperandValue::Immediate(discr), layout: self.cx.layout_of(discr_ty) @@ -493,7 +497,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { (bx, operand) } mir::Rvalue::Use(ref operand) => { - let operand = self.trans_operand(&bx, operand); + let operand = self.codegen_operand(&bx, operand); (bx, operand) } mir::Rvalue::Repeat(..) | @@ -512,21 +516,21 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { place: &mir::Place<'tcx>) -> ValueRef { // ZST are passed as operands and require special handling - // because trans_place() panics if Local is operand. + // because codegen_place() panics if Local is operand. if let mir::Place::Local(index) = *place { if let LocalRef::Operand(Some(op)) = self.locals[index] { if let ty::TyArray(_, n) = op.layout.ty.sty { - let n = n.val.unwrap_u64(); + let n = n.unwrap_usize(bx.cx.tcx); return common::C_usize(bx.cx, n); } } } // use common size calculation for non zero-sized types - let tr_value = self.trans_place(&bx, place); - return tr_value.len(bx.cx); + let cg_value = self.codegen_place(&bx, place); + return cg_value.len(bx.cx); } - pub fn trans_scalar_binop(&mut self, + pub fn codegen_scalar_binop(&mut self, bx: &Builder<'a, 'tcx>, op: mir::BinOp, lhs: ValueRef, @@ -592,7 +596,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } - pub fn trans_fat_ptr_binop(&mut self, + pub fn codegen_fat_ptr_binop(&mut self, bx: &Builder<'a, 'tcx>, op: mir::BinOp, lhs_addr: ValueRef, @@ -639,7 +643,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { } } - pub fn trans_scalar_checked_binop(&mut self, + pub fn codegen_scalar_checked_binop(&mut self, bx: &Builder<'a, 'tcx>, op: mir::BinOp, lhs: ValueRef, @@ -650,7 +654,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { // another crate (mostly core::num generic/#[inline] fns), // while the current crate doesn't use overflow checks. if !bx.cx.check_overflow { - let val = self.trans_scalar_binop(bx, op, lhs, rhs, input_ty); + let val = self.codegen_scalar_binop(bx, op, lhs, rhs, input_ty); return OperandValue::Pair(val, C_bool(bx.cx, false)); } @@ -676,7 +680,7 @@ impl<'a, 'tcx> FunctionCx<'a, 'tcx> { let outer_bits = bx.and(rhs, invert_mask); let of = bx.icmp(llvm::IntNE, outer_bits, C_null(rhs_llty)); - let val = self.trans_scalar_binop(bx, op, lhs, rhs, input_ty); + let val = self.codegen_scalar_binop(bx, op, lhs, rhs, input_ty); (val, of) } diff --git a/src/librustc_codegen_llvm/mir/statement.rs b/src/librustc_codegen_llvm/mir/statement.rs new file mode 100644 index 0000000000000..c0cce297ef6a9 --- /dev/null +++ b/src/librustc_codegen_llvm/mir/statement.rs @@ -0,0 +1,92 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use rustc::mir; + +use asm; +use builder::Builder; + +use super::FunctionCx; +use super::LocalRef; + +impl<'a, 'tcx> FunctionCx<'a, 'tcx> { + pub fn codegen_statement(&mut self, + bx: Builder<'a, 'tcx>, + statement: &mir::Statement<'tcx>) + -> Builder<'a, 'tcx> { + debug!("codegen_statement(statement={:?})", statement); + + self.set_debug_loc(&bx, statement.source_info); + match statement.kind { + mir::StatementKind::Assign(ref place, ref rvalue) => { + if let mir::Place::Local(index) = *place { + match self.locals[index] { + LocalRef::Place(cg_dest) => { + self.codegen_rvalue(bx, cg_dest, rvalue) + } + LocalRef::Operand(None) => { + let (bx, operand) = self.codegen_rvalue_operand(bx, rvalue); + self.locals[index] = LocalRef::Operand(Some(operand)); + bx + } + LocalRef::Operand(Some(op)) => { + if !op.layout.is_zst() { + span_bug!(statement.source_info.span, + "operand {:?} already assigned", + rvalue); + } + + // If the type is zero-sized, it's already been set here, + // but we still need to make sure we codegen the operand + self.codegen_rvalue_operand(bx, rvalue).0 + } + } + } else { + let cg_dest = self.codegen_place(&bx, place); + self.codegen_rvalue(bx, cg_dest, rvalue) + } + } + mir::StatementKind::SetDiscriminant{ref place, variant_index} => { + self.codegen_place(&bx, place) + .codegen_set_discr(&bx, variant_index); + bx + } + mir::StatementKind::StorageLive(local) => { + if let LocalRef::Place(cg_place) = self.locals[local] { + cg_place.storage_live(&bx); + } + bx + } + mir::StatementKind::StorageDead(local) => { + if let LocalRef::Place(cg_place) = self.locals[local] { + cg_place.storage_dead(&bx); + } + bx + } + mir::StatementKind::InlineAsm { ref asm, ref outputs, ref inputs } => { + let outputs = outputs.iter().map(|output| { + self.codegen_place(&bx, output) + }).collect(); + + let input_vals = inputs.iter().map(|input| { + self.codegen_operand(&bx, input).immediate() + }).collect(); + + asm::codegen_inline_asm(&bx, asm, outputs, input_vals); + bx + } + mir::StatementKind::ReadForMatch(_) | + mir::StatementKind::EndRegion(_) | + mir::StatementKind::Validate(..) | + mir::StatementKind::UserAssertTy(..) | + mir::StatementKind::Nop => bx, + } + } +} diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs new file mode 100644 index 0000000000000..a528008e3b4bd --- /dev/null +++ b/src/librustc_codegen_llvm/mono_item.rs @@ -0,0 +1,189 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Walks the crate looking for items/impl-items/trait-items that have +//! either a `rustc_symbol_name` or `rustc_item_path` attribute and +//! generates an error giving, respectively, the symbol name or +//! item-path. This is used for unit testing the code that generates +//! paths etc in all kinds of annoying scenarios. + +use asm; +use attributes; +use base; +use consts; +use context::CodegenCx; +use declare; +use llvm; +use monomorphize::Instance; +use type_of::LayoutLlvmExt; +use rustc::hir; +use rustc::hir::def::Def; +use rustc::hir::def_id::{DefId, LOCAL_CRATE}; +use rustc::mir::mono::{Linkage, Visibility}; +use rustc::ty::TypeFoldable; +use rustc::ty::layout::LayoutOf; +use std::fmt; + +pub use rustc::mir::mono::MonoItem; + +pub use rustc_mir::monomorphize::item::MonoItemExt as BaseMonoItemExt; + +pub trait MonoItemExt<'a, 'tcx>: fmt::Debug + BaseMonoItemExt<'a, 'tcx> { + fn define(&self, cx: &CodegenCx<'a, 'tcx>) { + debug!("BEGIN IMPLEMENTING '{} ({})' in cgu {}", + self.to_string(cx.tcx), + self.to_raw_string(), + cx.codegen_unit.name()); + + match *self.as_mono_item() { + MonoItem::Static(def_id) => { + let tcx = cx.tcx; + let is_mutable = match tcx.describe_def(def_id) { + Some(Def::Static(_, is_mutable)) => is_mutable, + Some(other) => { + bug!("Expected Def::Static, found {:?}", other) + } + None => { + bug!("Expected Def::Static for {:?}, found nothing", def_id) + } + }; + consts::codegen_static(&cx, def_id, is_mutable); + } + MonoItem::GlobalAsm(node_id) => { + let item = cx.tcx.hir.expect_item(node_id); + if let hir::ItemKind::GlobalAsm(ref ga) = item.node { + asm::codegen_global_asm(cx, ga); + } else { + span_bug!(item.span, "Mismatch between hir::Item type and MonoItem type") + } + } + MonoItem::Fn(instance) => { + base::codegen_instance(&cx, instance); + } + } + + debug!("END IMPLEMENTING '{} ({})' in cgu {}", + self.to_string(cx.tcx), + self.to_raw_string(), + cx.codegen_unit.name()); + } + + fn predefine(&self, + cx: &CodegenCx<'a, 'tcx>, + linkage: Linkage, + visibility: Visibility) { + debug!("BEGIN PREDEFINING '{} ({})' in cgu {}", + self.to_string(cx.tcx), + self.to_raw_string(), + cx.codegen_unit.name()); + + let symbol_name = self.symbol_name(cx.tcx).as_str(); + + debug!("symbol {}", &symbol_name); + + match *self.as_mono_item() { + MonoItem::Static(def_id) => { + predefine_static(cx, def_id, linkage, visibility, &symbol_name); + } + MonoItem::Fn(instance) => { + predefine_fn(cx, instance, linkage, visibility, &symbol_name); + } + MonoItem::GlobalAsm(..) => {} + } + + debug!("END PREDEFINING '{} ({})' in cgu {}", + self.to_string(cx.tcx), + self.to_raw_string(), + cx.codegen_unit.name()); + } + + fn to_raw_string(&self) -> String { + match *self.as_mono_item() { + MonoItem::Fn(instance) => { + format!("Fn({:?}, {})", + instance.def, + instance.substs.as_ptr() as usize) + } + MonoItem::Static(id) => { + format!("Static({:?})", id) + } + MonoItem::GlobalAsm(id) => { + format!("GlobalAsm({:?})", id) + } + } + } +} + +impl<'a, 'tcx> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> {} + +fn predefine_static<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + def_id: DefId, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { + let instance = Instance::mono(cx.tcx, def_id); + let ty = instance.ty(cx.tcx); + let llty = cx.layout_of(ty).llvm_type(cx); + + let g = declare::define_global(cx, symbol_name, llty).unwrap_or_else(|| { + cx.sess().span_fatal(cx.tcx.def_span(def_id), + &format!("symbol `{}` is already defined", symbol_name)) + }); + + unsafe { + llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage)); + llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility)); + } + + cx.instances.borrow_mut().insert(instance, g); + cx.statics.borrow_mut().insert(g, def_id); +} + +fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str) { + assert!(!instance.substs.needs_infer() && + !instance.substs.has_param_types()); + + let mono_ty = instance.ty(cx.tcx); + let attrs = cx.tcx.codegen_fn_attrs(instance.def_id()); + let lldecl = declare::declare_fn(cx, symbol_name, mono_ty); + unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) }; + base::set_link_section(lldecl, &attrs); + if linkage == Linkage::LinkOnceODR || + linkage == Linkage::WeakODR { + llvm::SetUniqueComdat(cx.llmod, lldecl); + } + + // If we're compiling the compiler-builtins crate, e.g. the equivalent of + // compiler-rt, then we want to implicitly compile everything with hidden + // visibility as we're going to link this object all over the place but + // don't want the symbols to get exported. + if linkage != Linkage::Internal && linkage != Linkage::Private && + cx.tcx.is_compiler_builtins(LOCAL_CRATE) { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, llvm::Visibility::Hidden); + } + } else { + unsafe { + llvm::LLVMRustSetVisibility(lldecl, base::visibility_to_llvm(visibility)); + } + } + + debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance); + if instance.def.is_inline(cx.tcx) { + attributes::inline(lldecl, attributes::InlineAttr::Hint); + } + attributes::from_fn_attrs(cx, lldecl, instance.def.def_id()); + + cx.instances.borrow_mut().insert(instance, lldecl); +} diff --git a/src/librustc_trans/type_.rs b/src/librustc_codegen_llvm/type_.rs similarity index 100% rename from src/librustc_trans/type_.rs rename to src/librustc_codegen_llvm/type_.rs diff --git a/src/librustc_trans/type_of.rs b/src/librustc_codegen_llvm/type_of.rs similarity index 90% rename from src/librustc_trans/type_of.rs rename to src/librustc_codegen_llvm/type_of.rs index 5e6b276495764..4728d7717a1e1 100644 --- a/src/librustc_trans/type_of.rs +++ b/src/librustc_codegen_llvm/type_of.rs @@ -10,11 +10,13 @@ use abi::{FnType, FnTypeExt}; use common::*; +use llvm; use rustc::hir; use rustc::ty::{self, Ty, TypeFoldable}; use rustc::ty::layout::{self, Align, LayoutOf, Size, TyLayout}; use rustc_target::spec::PanicStrategy; -use trans_item::DefPathBasedNames; +use rustc_target::abi::FloatTy; +use rustc_mir::monomorphize::item::DefPathBasedNames; use type_::Type; use std::fmt::Write; @@ -39,14 +41,14 @@ fn uncached_llvm_type<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, if use_x86_mmx { return Type::x86_mmx(cx) } else { - let element = layout.scalar_llvm_type_at(cx, element, Size::from_bytes(0)); + let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); return Type::vector(&element, count); } } layout::Abi::ScalarPair(..) => { return Type::struct_(cx, &[ - layout.scalar_pair_element_llvm_type(cx, 0), - layout.scalar_pair_element_llvm_type(cx, 1), + layout.scalar_pair_element_llvm_type(cx, 0, false), + layout.scalar_pair_element_llvm_type(cx, 1, false), ], false); } layout::Abi::Uninhabited | @@ -119,7 +121,7 @@ fn struct_llfields<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, let field_count = layout.fields.count(); let mut packed = false; - let mut offset = Size::from_bytes(0); + let mut offset = Size::ZERO; let mut prev_align = layout.align; let mut result: Vec = Vec::with_capacity(1 + field_count * 2); for i in layout.fields.index_by_increasing_offset() { @@ -204,7 +206,7 @@ pub trait LayoutLlvmExt<'tcx> { fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: &layout::Scalar, offset: Size) -> Type; fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - index: usize) -> Type; + index: usize, immediate: bool) -> Type; fn llvm_field_index(&self, index: usize) -> u64; fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option; @@ -213,10 +215,10 @@ pub trait LayoutLlvmExt<'tcx> { impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { fn is_llvm_immediate(&self) -> bool { match self.abi { - layout::Abi::Uninhabited | layout::Abi::Scalar(_) | layout::Abi::Vector { .. } => true, layout::Abi::ScalarPair(..) => false, + layout::Abi::Uninhabited | layout::Abi::Aggregate { .. } => self.is_zst() } } @@ -250,7 +252,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { return llty; } let llty = match self.ty.sty { - ty::TyRef(_, ty::TypeAndMut { ty, .. }) | + ty::TyRef(_, ty, _) | ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => { cx.layout_of(ty).llvm_type(cx).ptr_to() } @@ -264,7 +266,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { ); FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to() } - _ => self.scalar_llvm_type_at(cx, scalar, Size::from_bytes(0)) + _ => self.scalar_llvm_type_at(cx, scalar, Size::ZERO) }; cx.scalar_lltypes.borrow_mut().insert(self.ty, llty); return llty; @@ -323,8 +325,8 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { scalar: &layout::Scalar, offset: Size) -> Type { match scalar.value { layout::Int(i, _) => Type::from_integer(cx, i), - layout::F32 => Type::f32(cx), - layout::F64 => Type::f64(cx), + layout::Float(FloatTy::F32) => Type::f32(cx), + layout::Float(FloatTy::F64) => Type::f64(cx), layout::Pointer => { // If we know the alignment, pick something better than i8. let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) { @@ -338,7 +340,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } fn scalar_pair_element_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>, - index: usize) -> Type { + index: usize, immediate: bool) -> Type { // HACK(eddyb) special-case fat pointers until LLVM removes // pointee types, to avoid bitcasting every `OperandRef::deref`. match self.ty.sty { @@ -348,7 +350,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { } ty::TyAdt(def, _) if def.is_box() => { let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty()); - return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index); + return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate); } _ => {} } @@ -359,19 +361,18 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { }; let scalar = [a, b][index]; - // Make sure to return the same type `immediate_llvm_type` would, - // to avoid dealing with two types and the associated conversions. - // This means that `(bool, bool)` is represented as `{i1, i1}`, - // both in memory and as an immediate, while `bool` is typically - // `i8` in memory and only `i1` when immediate. While we need to - // load/store `bool` as `i8` to avoid crippling LLVM optimizations, - // `i1` in a LLVM aggregate is valid and mostly equivalent to `i8`. - if scalar.is_bool() { + // Make sure to return the same type `immediate_llvm_type` would when + // dealing with an immediate pair. This means that `(bool, bool)` is + // effectively represented as `{i8, i8}` in memory and two `i1`s as an + // immediate, just like `bool` is typically `i8` in memory and only `i1` + // when immediate. We need to load/store `bool` as `i8` to avoid + // crippling LLVM optimizations or triggering other LLVM bugs with `i1`. + if immediate && scalar.is_bool() { return Type::i1(cx); } let offset = if index == 0 { - Size::from_bytes(0) + Size::ZERO } else { a.value.size(cx).abi_align(b.value.align(cx)) }; @@ -418,18 +419,23 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> { }); } - ty::TyRef(_, mt) if offset.bytes() == 0 => { - let (size, align) = cx.size_and_align_of(mt.ty); + ty::TyRef(_, ty, mt) if offset.bytes() == 0 => { + let (size, align) = cx.size_and_align_of(ty); - let kind = match mt.mutbl { - hir::MutImmutable => if cx.type_is_freeze(mt.ty) { + let kind = match mt { + hir::MutImmutable => if cx.type_is_freeze(ty) { PointerKind::Frozen } else { PointerKind::Shared }, hir::MutMutable => { - if cx.tcx.sess.opts.debugging_opts.mutable_noalias || - cx.tcx.sess.panic_strategy() == PanicStrategy::Abort { + // Only emit noalias annotations for LLVM >= 6 or in panic=abort + // mode, as prior versions had many bugs in conjunction with + // unwinding. See also issue #31681. + let mutable_noalias = cx.tcx.sess.opts.debugging_opts.mutable_noalias + .unwrap_or(unsafe { llvm::LLVMRustVersionMajor() >= 6 } + || cx.tcx.sess.panic_strategy() == PanicStrategy::Abort); + if mutable_noalias { PointerKind::UniqueBorrowed } else { PointerKind::Shared diff --git a/src/librustc_trans/value.rs b/src/librustc_codegen_llvm/value.rs similarity index 100% rename from src/librustc_trans/value.rs rename to src/librustc_codegen_llvm/value.rs diff --git a/src/librustc_codegen_utils/Cargo.toml b/src/librustc_codegen_utils/Cargo.toml new file mode 100644 index 0000000000000..30f533285ddfd --- /dev/null +++ b/src/librustc_codegen_utils/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_codegen_utils" +version = "0.0.0" + +[lib] +name = "rustc_codegen_utils" +path = "lib.rs" +crate-type = ["dylib"] +test = false + +[dependencies] +flate2 = "1.0" +log = "0.4" + +syntax = { path = "../libsyntax" } +syntax_pos = { path = "../libsyntax_pos" } +rustc = { path = "../librustc" } +rustc_target = { path = "../librustc_target" } +rustc_data_structures = { path = "../librustc_data_structures" } +rustc_mir = { path = "../librustc_mir" } +rustc_incremental = { path = "../librustc_incremental" } diff --git a/src/librustc_codegen_utils/codegen_backend.rs b/src/librustc_codegen_utils/codegen_backend.rs new file mode 100644 index 0000000000000..3f230dd5d451b --- /dev/null +++ b/src/librustc_codegen_utils/codegen_backend.rs @@ -0,0 +1,230 @@ +// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! The Rust compiler. +//! +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] +#![deny(warnings)] + +#![feature(box_syntax)] + +use std::any::Any; +use std::io::{self, Write}; +use std::fs::File; +use std::path::Path; +use std::sync::{mpsc, Arc}; + +use rustc_data_structures::owning_ref::OwningRef; +use rustc_data_structures::sync::Lrc; +use flate2::Compression; +use flate2::write::DeflateEncoder; + +use syntax::symbol::Symbol; +use rustc::hir::def_id::LOCAL_CRATE; +use rustc::session::{Session, CompileIncomplete}; +use rustc::session::config::{CrateType, OutputFilenames, PrintRequest}; +use rustc::ty::TyCtxt; +use rustc::ty::query::Providers; +use rustc::middle::cstore::EncodedMetadata; +use rustc::middle::cstore::MetadataLoader; +use rustc::dep_graph::DepGraph; +use rustc_target::spec::Target; +use rustc_data_structures::fx::FxHashMap; +use rustc_mir::monomorphize::collector; +use link::{build_link_meta, out_filename}; + +pub use rustc_data_structures::sync::MetadataRef; + +pub trait CodegenBackend { + fn init(&self, _sess: &Session) {} + fn print(&self, _req: PrintRequest, _sess: &Session) {} + fn target_features(&self, _sess: &Session) -> Vec { vec![] } + fn print_passes(&self) {} + fn print_version(&self) {} + fn diagnostics(&self) -> &[(&'static str, &'static str)] { &[] } + + fn metadata_loader(&self) -> Box; + fn provide(&self, _providers: &mut Providers); + fn provide_extern(&self, _providers: &mut Providers); + fn codegen_crate<'a, 'tcx>( + &self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + rx: mpsc::Receiver> + ) -> Box; + + /// This is called on the returned `Box` from `codegen_backend` + /// + /// # Panics + /// + /// Panics when the passed `Box` was not returned by `codegen_backend`. + fn join_codegen_and_link( + &self, + ongoing_codegen: Box, + sess: &Session, + dep_graph: &DepGraph, + outputs: &OutputFilenames, + ) -> Result<(), CompileIncomplete>; +} + +pub struct NoLlvmMetadataLoader; + +impl MetadataLoader for NoLlvmMetadataLoader { + fn get_rlib_metadata(&self, _: &Target, filename: &Path) -> Result { + let mut file = File::open(filename) + .map_err(|e| format!("metadata file open err: {:?}", e))?; + + let mut buf = Vec::new(); + io::copy(&mut file, &mut buf).unwrap(); + let buf: OwningRef, [u8]> = OwningRef::new(buf).into(); + return Ok(rustc_erase_owner!(buf.map_owner_box())); + } + + fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result { + self.get_rlib_metadata(target, filename) + } +} + +pub struct MetadataOnlyCodegenBackend(()); +pub struct OngoingCodegen { + metadata: EncodedMetadata, + metadata_version: Vec, + crate_name: Symbol, +} + +impl MetadataOnlyCodegenBackend { + pub fn new() -> Box { + box MetadataOnlyCodegenBackend(()) + } +} + +impl CodegenBackend for MetadataOnlyCodegenBackend { + fn init(&self, sess: &Session) { + for cty in sess.opts.crate_types.iter() { + match *cty { + CrateType::CrateTypeRlib | CrateType::CrateTypeDylib | + CrateType::CrateTypeExecutable => {}, + _ => { + sess.parse_sess.span_diagnostic.warn( + &format!("LLVM unsupported, so output type {} is not supported", cty) + ); + }, + } + } + } + + fn metadata_loader(&self) -> Box { + box NoLlvmMetadataLoader + } + + fn provide(&self, providers: &mut Providers) { + ::symbol_names::provide(providers); + + providers.target_features_whitelist = |_tcx, _cnum| { + Lrc::new(FxHashMap()) // Just a dummy + }; + providers.is_reachable_non_generic = |_tcx, _defid| true; + providers.exported_symbols = |_tcx, _crate| Arc::new(Vec::new()); + } + fn provide_extern(&self, providers: &mut Providers) { + providers.is_reachable_non_generic = |_tcx, _defid| true; + } + + fn codegen_crate<'a, 'tcx>( + &self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + _rx: mpsc::Receiver> + ) -> Box { + use rustc_mir::monomorphize::item::MonoItem; + + ::check_for_rustc_errors_attr(tcx); + ::symbol_names_test::report_symbol_names(tcx); + ::rustc_incremental::assert_dep_graph(tcx); + ::rustc_incremental::assert_module_sources::assert_module_sources(tcx); + ::rustc_mir::monomorphize::assert_symbols_are_distinct(tcx, + collector::collect_crate_mono_items( + tcx, + collector::MonoItemCollectionMode::Eager + ).0.iter() + ); + // FIXME: Fix this + // ::rustc::middle::dependency_format::calculate(tcx); + let _ = tcx.link_args(LOCAL_CRATE); + let _ = tcx.native_libraries(LOCAL_CRATE); + for mono_item in + collector::collect_crate_mono_items( + tcx, + collector::MonoItemCollectionMode::Eager + ).0 { + match mono_item { + MonoItem::Fn(inst) => { + let def_id = inst.def_id(); + if def_id.is_local() { + let _ = inst.def.is_inline(tcx); + let _ = tcx.codegen_fn_attrs(def_id); + } + } + _ => {} + } + } + tcx.sess.abort_if_errors(); + + let link_meta = build_link_meta(tcx.crate_hash(LOCAL_CRATE)); + let metadata = tcx.encode_metadata(&link_meta); + + box OngoingCodegen { + metadata: metadata, + metadata_version: tcx.metadata_encoding_version().to_vec(), + crate_name: tcx.crate_name(LOCAL_CRATE), + } + } + + fn join_codegen_and_link( + &self, + ongoing_codegen: Box, + sess: &Session, + _dep_graph: &DepGraph, + outputs: &OutputFilenames, + ) -> Result<(), CompileIncomplete> { + let ongoing_codegen = ongoing_codegen.downcast::() + .expect("Expected MetadataOnlyCodegenBackend's OngoingCodegen, found Box"); + for &crate_type in sess.opts.crate_types.iter() { + if crate_type != CrateType::CrateTypeRlib && crate_type != CrateType::CrateTypeDylib { + continue; + } + let output_name = + out_filename(sess, crate_type, &outputs, &ongoing_codegen.crate_name.as_str()); + let mut compressed = ongoing_codegen.metadata_version.clone(); + let metadata = if crate_type == CrateType::CrateTypeDylib { + DeflateEncoder::new(&mut compressed, Compression::fast()) + .write_all(&ongoing_codegen.metadata.raw_data) + .unwrap(); + &compressed + } else { + &ongoing_codegen.metadata.raw_data + }; + let mut file = File::create(&output_name).unwrap(); + file.write_all(metadata).unwrap(); + } + + sess.abort_if_errors(); + if !sess.opts.crate_types.contains(&CrateType::CrateTypeRlib) + && !sess.opts.crate_types.contains(&CrateType::CrateTypeDylib) + { + sess.fatal("Executables are not supported by the metadata-only backend."); + } + Ok(()) + } +} diff --git a/src/librustc_codegen_utils/lib.rs b/src/librustc_codegen_utils/lib.rs new file mode 100644 index 0000000000000..f59cf5832fcb4 --- /dev/null +++ b/src/librustc_codegen_utils/lib.rs @@ -0,0 +1,62 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! # Note +//! +//! This API is completely unstable and subject to change. + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/nightly/")] + +#![feature(box_patterns)] +#![feature(box_syntax)] +#![feature(custom_attribute)] +#![allow(unused_attributes)] +#![feature(quote)] +#![feature(rustc_diagnostic_macros)] + +#![recursion_limit="256"] + +extern crate flate2; +#[macro_use] +extern crate log; + +#[macro_use] +extern crate rustc; +extern crate rustc_target; +extern crate rustc_mir; +extern crate rustc_incremental; +extern crate syntax; +extern crate syntax_pos; +#[macro_use] extern crate rustc_data_structures; + +use rustc::ty::TyCtxt; + +pub mod link; +pub mod codegen_backend; +pub mod symbol_names; +pub mod symbol_names_test; + +/// check for the #[rustc_error] annotation, which forces an +/// error in codegen. This is used to write compile-fail tests +/// that actually test that compilation succeeds without +/// reporting an error. +pub fn check_for_rustc_errors_attr(tcx: TyCtxt) { + if let Some((id, span, _)) = *tcx.sess.entry_fn.borrow() { + let main_def_id = tcx.hir.local_def_id(id); + + if tcx.has_attr(main_def_id, "rustc_error") { + tcx.sess.span_fatal(span, "compilation successful"); + } + } +} + +__build_diagnostic_array! { librustc_codegen_utils, DIAGNOSTICS } diff --git a/src/librustc_trans_utils/link.rs b/src/librustc_codegen_utils/link.rs similarity index 100% rename from src/librustc_trans_utils/link.rs rename to src/librustc_codegen_utils/link.rs diff --git a/src/librustc_trans_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs similarity index 82% rename from src/librustc_trans_utils/symbol_names.rs rename to src/librustc_codegen_utils/symbol_names.rs index be5bff60805c3..ac71ecff96457 100644 --- a/src/librustc_trans_utils/symbol_names.rs +++ b/src/librustc_codegen_utils/symbol_names.rs @@ -97,18 +97,19 @@ //! 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::middle::weak_lang_items; -use rustc_mir::monomorphize::Instance; -use rustc_mir::monomorphize::item::{MonoItem, MonoItemExt, InstantiationMode}; use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map as hir_map; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::fold::TypeVisitor; +use rustc::hir::map::definitions::DefPathData; +use rustc::ich::NodeIdHashingMode; +use rustc::middle::weak_lang_items; use rustc::ty::item_path::{self, ItemPathBuffer, RootMode}; -use rustc::ty::maps::Providers; +use rustc::ty::query::Providers; use rustc::ty::subst::Substs; -use rustc::hir::map::definitions::DefPathData; +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::item::{InstantiationMode, MonoItem, MonoItemExt}; +use rustc_mir::monomorphize::Instance; use syntax::attr; use syntax_pos::symbol::Symbol; @@ -124,51 +125,60 @@ pub fn provide(providers: &mut Providers) { }; } -fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, +fn get_symbol_hash<'a, 'tcx>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, - // the DefId of the item this name is for - def_id: DefId, + // the DefId of the item this name is for + def_id: DefId, - // instance this name will be for - instance: Instance<'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>, + // 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: &'tcx Substs<'tcx>) - -> u64 { - debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs); + // values for generic type parameters, + // if any. + substs: &'tcx Substs<'tcx>, +) -> u64 { + debug!( + "get_symbol_hash(def_id={:?}, parameters={:?})", + def_id, substs + ); - let mut hasher = ty::util::TypeIdHasher::::new(tcx); + let mut hasher = StableHasher::::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 - hasher.hash(tcx.def_path_hash(def_id)); + 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()); - hasher.visit_ty(item_type); + 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::TyFnDef(..) = item_type.sty { - item_type.fn_sig(tcx).visit_with(&mut hasher); + 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.visit_with(&mut hasher); + substs.hash_stable(&mut hcx, &mut hasher); let is_generic = substs.types().next().is_some(); let avoid_cross_crate_conflicts = @@ -194,12 +204,11 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, if !def_id.is_local() && tcx.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); + let upstream_monomorphizations = tcx.upstream_monomorphizations_for(def_id); - upstream_monomorphizations.and_then(|monos| monos.get(&substs) - .cloned()) - .unwrap_or(LOCAL_CRATE) + upstream_monomorphizations + .and_then(|monos| monos.get(&substs).cloned()) + .unwrap_or(LOCAL_CRATE) } else { LOCAL_CRATE } @@ -207,8 +216,9 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, LOCAL_CRATE }; - hasher.hash(&tcx.original_crate_name(instantiating_crate).as_str()[..]); - hasher.hash(&tcx.crate_disambiguator(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); } }); @@ -216,9 +226,7 @@ fn get_symbol_hash<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, hasher.finish() } -fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) - -> ty::SymbolName -{ +fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::SymbolName { let mut buffer = SymbolPathBuffer::new(); item_path::with_forced_absolute_paths(|| { tcx.push_item_path(&mut buffer, def_id); @@ -226,20 +234,17 @@ fn def_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) buffer.into_interned() } -fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) - -> ty::SymbolName -{ - ty::SymbolName { name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str() } +fn symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> ty::SymbolName { + ty::SymbolName { + name: Symbol::intern(&compute_symbol_name(tcx, instance)).as_interned_str(), + } } -fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) - -> String -{ +fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance<'tcx>) -> String { let def_id = instance.def_id(); let substs = instance.substs; - debug!("symbol_name(def_id={:?}, substs={:?})", - def_id, substs); + debug!("symbol_name(def_id={:?}, substs={:?})", def_id, substs); let node_id = tcx.hir.as_local_node_id(def_id); @@ -259,7 +264,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance let is_foreign = if let Some(id) = node_id { match tcx.hir.get(id) { hir_map::NodeForeignItem(_) => true, - _ => false + _ => false, } } else { tcx.is_foreign_item(def_id) @@ -277,7 +282,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance return tcx.item_name(def_id).to_string(); } - if let Some(name) = tcx.trans_fn_attrs(def_id).export_name { + if let Some(name) = tcx.codegen_fn_attrs(def_id).export_name { // Use provided name return name.to_string(); } @@ -296,8 +301,7 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance loop { let key = tcx.def_key(ty_def_id); match key.disambiguated_data.data { - DefPathData::TypeNs(_) | - DefPathData::ValueNs(_) => { + DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => { instance_ty = tcx.type_of(ty_def_id); break; } @@ -306,8 +310,12 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance // 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); + bug!( + "finding type for {:?}, encountered def-id {:?} with no \ + parent", + def_id, + ty_def_id + ); }); } } @@ -337,14 +345,14 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance // use C++ name-mangling. struct SymbolPathBuffer { result: String, - temp_buf: String + temp_buf: String, } impl SymbolPathBuffer { fn new() -> Self { let mut result = SymbolPathBuffer { result: String::with_capacity(64), - temp_buf: String::with_capacity(16) + temp_buf: String::with_capacity(16), }; result.result.push_str("_ZN"); // _Z == Begin name-sequence, N == nested result @@ -353,14 +361,16 @@ impl SymbolPathBuffer { fn from_interned(symbol: ty::SymbolName) -> Self { let mut result = SymbolPathBuffer { result: String::with_capacity(64), - temp_buf: String::with_capacity(16) + temp_buf: String::with_capacity(16), }; - result.result.push_str(&symbol.name.as_str()); + result.result.push_str(&symbol.as_str()); result } fn into_interned(self) -> ty::SymbolName { - ty::SymbolName { name: Symbol::intern(&self.result).as_interned_str() } + ty::SymbolName { + name: Symbol::intern(&self.result).as_interned_str(), + } } fn finish(mut self, hash: u64) -> String { @@ -379,7 +389,11 @@ impl ItemPathBuffer for SymbolPathBuffer { fn push(&mut self, text: &str) { self.temp_buf.clear(); let need_underscore = sanitize(&mut self.temp_buf, text); - let _ = write!(self.result, "{}", self.temp_buf.len() + (need_underscore as usize)); + let _ = write!( + self.result, + "{}", + self.temp_buf.len() + (need_underscore as usize) + ); if need_underscore { self.result.push('_'); } @@ -410,16 +424,13 @@ pub fn sanitize(result: &mut String, s: &str) -> bool { '-' | ':' => result.push('.'), // These are legal symbols - 'a' ... 'z' - | 'A' ... 'Z' - | '0' ... '9' - | '_' | '.' | '$' => result.push(c), + 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' | '.' | '$' => result.push(c), _ => { result.push('$'); for c in c.escape_unicode().skip(1) { match c { - '{' => {}, + '{' => {} '}' => result.push('$'), c => result.push(c), } @@ -429,7 +440,6 @@ pub fn sanitize(result: &mut String, s: &str) -> bool { } // Underscore-qualify anything that didn't start as an ident. - !result.is_empty() && - result.as_bytes()[0] != '_' as u8 && - ! (result.as_bytes()[0] as char).is_xid_start() + !result.is_empty() && result.as_bytes()[0] != '_' as u8 + && !(result.as_bytes()[0] as char).is_xid_start() } diff --git a/src/librustc_trans_utils/symbol_names_test.rs b/src/librustc_codegen_utils/symbol_names_test.rs similarity index 100% rename from src/librustc_trans_utils/symbol_names_test.rs rename to src/librustc_codegen_utils/symbol_names_test.rs diff --git a/src/librustc_data_structures/Cargo.toml b/src/librustc_data_structures/Cargo.toml index 9178d0d00faa4..fc5fe91c977d4 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/src/librustc_data_structures/Cargo.toml @@ -9,13 +9,16 @@ path = "lib.rs" crate-type = ["dylib"] [dependencies] -ena = "0.9.1" +ena = "0.9.3" log = "0.4" rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } serialize = { path = "../libserialize" } cfg-if = "0.1.2" stable_deref_trait = "1.0.0" parking_lot_core = "0.2.8" +rustc-rayon = "0.1.1" +rustc-rayon-core = "0.1.1" +rustc-hash = "1.0.1" [dependencies.parking_lot] version = "0.5" diff --git a/src/librustc_data_structures/accumulate_vec.rs b/src/librustc_data_structures/accumulate_vec.rs index f50b8cadf15ab..2e8cca3f4f9bd 100644 --- a/src/librustc_data_structures/accumulate_vec.rs +++ b/src/librustc_data_structures/accumulate_vec.rs @@ -46,6 +46,13 @@ impl AccumulateVec { AccumulateVec::Array(ArrayVec::new()) } + pub fn is_array(&self) -> bool { + match self { + AccumulateVec::Array(..) => true, + AccumulateVec::Heap(..) => false, + } + } + pub fn one(el: A::Element) -> Self { iter::once(el).collect() } diff --git a/src/librustc_data_structures/array_vec.rs b/src/librustc_data_structures/array_vec.rs index 7b33ee40d8cdb..56bb961324210 100644 --- a/src/librustc_data_structures/array_vec.rs +++ b/src/librustc_data_structures/array_vec.rs @@ -119,12 +119,12 @@ impl ArrayVec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = match range.start() { + let start = match range.start_bound() { Included(&n) => n, Excluded(&n) => n + 1, Unbounded => 0, }; - let end = match range.end() { + let end = match range.end_bound() { Included(&n) => n + 1, Excluded(&n) => n, Unbounded => len, diff --git a/src/librustc_data_structures/bitslice.rs b/src/librustc_data_structures/bitslice.rs index 2678861be0634..79435aa398779 100644 --- a/src/librustc_data_structures/bitslice.rs +++ b/src/librustc_data_structures/bitslice.rs @@ -28,9 +28,9 @@ impl BitSlice for [Word] { fn clear_bit(&mut self, idx: usize) -> bool { let words = self; debug!("clear_bit: words={} idx={}", - bits_to_string(words, words.len() * mem::size_of::()), bit_str(idx)); + bits_to_string(words, words.len() * mem::size_of::() * 8), idx); let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx); - debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask); + debug!("word={} bit_in_word={} bit_mask=0x{:x}", word, bit_in_word, bit_mask); let oldv = words[word]; let newv = oldv & !bit_mask; words[word] = newv; @@ -42,7 +42,7 @@ impl BitSlice for [Word] { fn set_bit(&mut self, idx: usize) -> bool { let words = self; debug!("set_bit: words={} idx={}", - bits_to_string(words, words.len() * mem::size_of::()), bit_str(idx)); + bits_to_string(words, words.len() * mem::size_of::() * 8), idx); let BitLookup { word, bit_in_word, bit_mask } = bit_lookup(idx); debug!("word={} bit_in_word={} bit_mask={}", word, bit_in_word, bit_mask); let oldv = words[word]; @@ -78,13 +78,6 @@ fn bit_lookup(bit: usize) -> BitLookup { BitLookup { word: word, bit_in_word: bit_in_word, bit_mask: bit_mask } } - -fn bit_str(bit: Word) -> String { - let byte = bit >> 3; - let lobits = 1 << (bit & 0b111); - format!("[{}:{}-{:02x}]", bit, byte, lobits) -} - pub fn bits_to_string(words: &[Word], bits: usize) -> String { let mut result = String::new(); let mut sep = '['; @@ -95,7 +88,7 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String { let mut i = 0; for &word in words.iter() { let mut v = word; - loop { // for each byte in `v`: + for _ in 0..mem::size_of::() { // for each byte in `v`: let remain = bits - i; // If less than a byte remains, then mask just that many bits. let mask = if remain <= 8 { (1 << remain) - 1 } else { 0xFF }; @@ -110,14 +103,15 @@ pub fn bits_to_string(words: &[Word], bits: usize) -> String { i += 8; sep = '-'; } + sep = '|'; } result.push(']'); return result } #[inline] -pub fn bitwise(out_vec: &mut [usize], - in_vec: &[usize], +pub fn bitwise(out_vec: &mut [Word], + in_vec: &[Word], op: &Op) -> bool { assert_eq!(out_vec.len(), in_vec.len()); let mut changed = false; @@ -132,21 +126,21 @@ pub fn bitwise(out_vec: &mut [usize], pub trait BitwiseOperator { /// Applies some bit-operation pointwise to each of the bits in the two inputs. - fn join(&self, pred1: usize, pred2: usize) -> usize; + fn join(&self, pred1: Word, pred2: Word) -> Word; } pub struct Intersect; impl BitwiseOperator for Intersect { #[inline] - fn join(&self, a: usize, b: usize) -> usize { a & b } + fn join(&self, a: Word, b: Word) -> Word { a & b } } pub struct Union; impl BitwiseOperator for Union { #[inline] - fn join(&self, a: usize, b: usize) -> usize { a | b } + fn join(&self, a: Word, b: Word) -> Word { a | b } } pub struct Subtract; impl BitwiseOperator for Subtract { #[inline] - fn join(&self, a: usize, b: usize) -> usize { a & !b } + fn join(&self, a: Word, b: Word) -> Word { a & !b } } diff --git a/src/librustc_data_structures/bitvec.rs b/src/librustc_data_structures/bitvec.rs index 28e3180063c17..04d6cb5e2a6d2 100644 --- a/src/librustc_data_structures/bitvec.rs +++ b/src/librustc_data_structures/bitvec.rs @@ -8,27 +8,27 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::collections::BTreeMap; -use std::collections::btree_map::Entry; -use std::marker::PhantomData; -use std::iter::FromIterator; use indexed_vec::{Idx, IndexVec}; +use std::iter::FromIterator; +use std::marker::PhantomData; type Word = u128; const WORD_BITS: usize = 128; /// A very simple BitVector type. #[derive(Clone, Debug, PartialEq)] -pub struct BitVector { +pub struct BitVector { data: Vec, + marker: PhantomData, } -impl BitVector { +impl BitVector { #[inline] - pub fn new(num_bits: usize) -> BitVector { + pub fn new(num_bits: usize) -> BitVector { let num_words = words(num_bits); BitVector { data: vec![0; num_words], + marker: PhantomData, } } @@ -43,15 +43,30 @@ impl BitVector { self.data.iter().map(|e| e.count_ones() as usize).sum() } + /// True if `self` contains the bit `bit`. #[inline] - pub fn contains(&self, bit: usize) -> bool { + pub fn contains(&self, bit: C) -> bool { let (word, mask) = word_mask(bit); (self.data[word] & mask) != 0 } + /// True if `self` contains all the bits in `other`. + /// + /// The two vectors must have the same length. + #[inline] + pub fn contains_all(&self, other: &BitVector) -> bool { + assert_eq!(self.data.len(), other.data.len()); + self.data.iter().zip(&other.data).all(|(a, b)| (a & b) == *b) + } + + #[inline] + pub fn is_empty(&self) -> bool { + self.data.iter().all(|a| *a == 0) + } + /// Returns true if the bit has changed. #[inline] - pub fn insert(&mut self, bit: usize) -> bool { + pub fn insert(&mut self, bit: C) -> bool { let (word, mask) = word_mask(bit); let data = &mut self.data[word]; let value = *data; @@ -60,9 +75,16 @@ impl BitVector { new_value != value } + /// Sets all bits to true. + pub fn insert_all(&mut self) { + for data in &mut self.data { + *data = u128::max_value(); + } + } + /// Returns true if the bit has changed. #[inline] - pub fn remove(&mut self, bit: usize) -> bool { + pub fn remove(&mut self, bit: C) -> bool { let (word, mask) = word_mask(bit); let data = &mut self.data[word]; let value = *data; @@ -72,7 +94,7 @@ impl BitVector { } #[inline] - pub fn insert_all(&mut self, all: &BitVector) -> bool { + pub fn merge(&mut self, all: &BitVector) -> bool { assert!(self.data.len() == all.data.len()); let mut changed = false; for (i, j) in self.data.iter_mut().zip(&all.data) { @@ -86,7 +108,7 @@ impl BitVector { } #[inline] - pub fn grow(&mut self, num_bits: usize) { + pub fn grow(&mut self, num_bits: C) { let num_words = words(num_bits); if self.data.len() < num_words { self.data.resize(num_words, 0) @@ -95,24 +117,26 @@ impl BitVector { /// Iterates over indexes of set bits in a sorted order #[inline] - pub fn iter<'a>(&'a self) -> BitVectorIter<'a> { + pub fn iter<'a>(&'a self) -> BitVectorIter<'a, C> { BitVectorIter { iter: self.data.iter(), current: 0, idx: 0, + marker: PhantomData, } } } -pub struct BitVectorIter<'a> { +pub struct BitVectorIter<'a, C: Idx> { iter: ::std::slice::Iter<'a, Word>, current: Word, idx: usize, + marker: PhantomData } -impl<'a> Iterator for BitVectorIter<'a> { - type Item = usize; - fn next(&mut self) -> Option { +impl<'a, C: Idx> Iterator for BitVectorIter<'a, C> { + type Item = C; + fn next(&mut self) -> Option { while self.current == 0 { self.current = if let Some(&i) = self.iter.next() { if i == 0 { @@ -130,7 +154,7 @@ impl<'a> Iterator for BitVectorIter<'a> { self.current >>= offset; self.current >>= 1; // shift otherwise overflows for 0b1000_0000_…_0000 self.idx += offset + 1; - return Some(self.idx - 1); + return Some(C::new(self.idx - 1)); } fn size_hint(&self) -> (usize, Option) { @@ -139,8 +163,8 @@ impl<'a> Iterator for BitVectorIter<'a> { } } -impl FromIterator for BitVector { - fn from_iter(iter: I) -> BitVector +impl FromIterator for BitVector { + fn from_iter(iter: I) -> BitVector where I: IntoIterator, { @@ -152,10 +176,10 @@ impl FromIterator for BitVector { let mut bv = BitVector::new(len); for (idx, val) in iter.enumerate() { if idx > len { - bv.grow(idx); + bv.grow(C::new(idx)); } if val { - bv.insert(idx); + bv.insert(C::new(idx)); } } @@ -167,25 +191,28 @@ impl FromIterator for BitVector { /// one gigantic bitvector. In other words, it is as if you have /// `rows` bitvectors, each of length `columns`. #[derive(Clone, Debug)] -pub struct BitMatrix { +pub struct BitMatrix { columns: usize, vector: Vec, + phantom: PhantomData<(R, C)>, } -impl BitMatrix { +impl BitMatrix { /// Create a new `rows x columns` matrix, initially empty. - pub fn new(rows: usize, columns: usize) -> BitMatrix { + pub fn new(rows: usize, columns: usize) -> BitMatrix { // For every element, we need one bit for every other // element. Round up to an even number of words. let words_per_row = words(columns); BitMatrix { columns, vector: vec![0; rows * words_per_row], + phantom: PhantomData, } } /// The range of bits for a given row. - fn range(&self, row: usize) -> (usize, usize) { + fn range(&self, row: R) -> (usize, usize) { + let row = row.index(); let words_per_row = words(self.columns); let start = row * words_per_row; (start, start + words_per_row) @@ -195,7 +222,7 @@ impl BitMatrix { /// `column` to the bitset for `row`. /// /// Returns true if this changed the matrix, and false otherwise. - pub fn add(&mut self, row: usize, column: usize) -> bool { + pub fn add(&mut self, row: R, column: R) -> bool { let (start, _) = self.range(row); let (word, mask) = word_mask(column); let vector = &mut self.vector[..]; @@ -209,7 +236,7 @@ impl BitMatrix { /// the matrix cell at `(row, column)` true? Put yet another way, /// if the matrix represents (transitive) reachability, can /// `row` reach `column`? - pub fn contains(&self, row: usize, column: usize) -> bool { + pub fn contains(&self, row: R, column: R) -> bool { let (start, _) = self.range(row); let (word, mask) = word_mask(column); (self.vector[start + word] & mask) != 0 @@ -219,7 +246,7 @@ impl BitMatrix { /// is an O(n) operation where `n` is the number of elements /// (somewhat independent from the actual size of the /// intersection, in particular). - pub fn intersection(&self, a: usize, b: usize) -> Vec { + pub fn intersection(&self, a: R, b: R) -> Vec { let (a_start, a_end) = self.range(a); let (b_start, b_end) = self.range(b); let mut result = Vec::with_capacity(self.columns); @@ -230,7 +257,7 @@ impl BitMatrix { break; } if v & 0x1 != 0 { - result.push(base * WORD_BITS + bit); + result.push(C::new(base * WORD_BITS + bit)); } v >>= 1; } @@ -245,7 +272,7 @@ impl BitMatrix { /// you have an edge `write -> read`, because in that case /// `write` can reach everything that `read` can (and /// potentially more). - pub fn merge(&mut self, read: usize, write: usize) -> bool { + pub fn merge(&mut self, read: R, write: R) -> bool { let (read_start, read_end) = self.range(read); let (write_start, write_end) = self.range(write); let vector = &mut self.vector[..]; @@ -261,38 +288,50 @@ impl BitMatrix { /// Iterates through all the columns set to true in a given row of /// the matrix. - pub fn iter<'a>(&'a self, row: usize) -> BitVectorIter<'a> { + pub fn iter<'a>(&'a self, row: R) -> BitVectorIter<'a, C> { let (start, end) = self.range(row); BitVectorIter { iter: self.vector[start..end].iter(), current: 0, idx: 0, + marker: PhantomData, } } } +/// A moderately sparse bit matrix: rows are appended lazily, but columns +/// within appended rows are instantiated fully upon creation. #[derive(Clone, Debug)] pub struct SparseBitMatrix where R: Idx, C: Idx, { - vector: IndexVec>, + columns: usize, + vector: IndexVec>, } impl SparseBitMatrix { - /// Create a new `rows x columns` matrix, initially empty. - pub fn new(rows: R, _columns: C) -> SparseBitMatrix { - SparseBitMatrix { - vector: IndexVec::from_elem_n(SparseBitSet::new(), rows.index()), + /// Create a new empty sparse bit matrix with no rows or columns. + pub fn new(columns: usize) -> Self { + Self { + columns, + vector: IndexVec::new(), } } + fn ensure_row(&mut self, row: R) { + let columns = self.columns; + self.vector + .ensure_contains_elem(row, || BitVector::new(columns)); + } + /// Sets the cell at `(row, column)` to true. Put another way, insert /// `column` to the bitset for `row`. /// /// Returns true if this changed the matrix, and false otherwise. pub fn add(&mut self, row: R, column: C) -> bool { + self.ensure_row(row); self.vector[row].insert(column) } @@ -301,7 +340,7 @@ impl SparseBitMatrix { /// if the matrix represents (transitive) reachability, can /// `row` reach `column`? pub fn contains(&self, row: R, column: C) -> bool { - self.vector[row].contains(column) + self.vector.get(row).map_or(false, |r| r.contains(column)) } /// Add the bits from row `read` to the bits from row `write`, @@ -312,171 +351,60 @@ impl SparseBitMatrix { /// `write` can reach everything that `read` can (and /// potentially more). pub fn merge(&mut self, read: R, write: R) -> bool { - let mut changed = false; - - if read != write { - let (bit_set_read, bit_set_write) = self.vector.pick2_mut(read, write); - - for read_val in bit_set_read.iter() { - changed = changed | bit_set_write.insert(read_val); - } - } - - changed - } - - /// Iterates through all the columns set to true in a given row of - /// the matrix. - pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { - self.vector[row].iter() - } -} - -#[derive(Clone, Debug)] -pub struct SparseBitSet { - chunk_bits: BTreeMap, - _marker: PhantomData, -} - -#[derive(Copy, Clone)] -pub struct SparseChunk { - key: u32, - bits: Word, - _marker: PhantomData, -} - -impl SparseChunk { - pub fn one(index: I) -> Self { - let index = index.index(); - let key_usize = index / 128; - let key = key_usize as u32; - assert_eq!(key as usize, key_usize); - SparseChunk { - key, - bits: 1 << (index % 128), - _marker: PhantomData, + if read == write || self.vector.get(read).is_none() { + return false; } - } - pub fn any(&self) -> bool { - self.bits != 0 + self.ensure_row(write); + let (bitvec_read, bitvec_write) = self.vector.pick2_mut(read, write); + bitvec_write.merge(bitvec_read) } - pub fn iter(&self) -> impl Iterator { - let base = self.key as usize * 128; - let mut bits = self.bits; - (0..128) - .map(move |i| { - let current_bits = bits; - bits >>= 1; - (i, current_bits) - }) - .take_while(|&(_, bits)| bits != 0) - .filter_map(move |(i, bits)| { - if (bits & 1) != 0 { - Some(I::new(base + i)) - } else { - None - } - }) + /// Merge a row, `from`, into the `into` row. + pub fn merge_into(&mut self, into: R, from: &BitVector) -> bool { + self.ensure_row(into); + self.vector[into].merge(from) } -} -impl SparseBitSet { - pub fn new() -> Self { - SparseBitSet { - chunk_bits: BTreeMap::new(), - _marker: PhantomData, - } + /// Add all bits to the given row. + pub fn add_all(&mut self, row: R) { + self.ensure_row(row); + self.vector[row].insert_all(); } - pub fn capacity(&self) -> usize { - self.chunk_bits.len() * 128 + /// Number of elements in the matrix. + pub fn len(&self) -> usize { + self.vector.len() } - pub fn contains_chunk(&self, chunk: SparseChunk) -> SparseChunk { - SparseChunk { - bits: self.chunk_bits - .get(&chunk.key) - .map_or(0, |bits| bits & chunk.bits), - ..chunk - } + pub fn rows(&self) -> impl Iterator { + self.vector.indices() } - pub fn insert_chunk(&mut self, chunk: SparseChunk) -> SparseChunk { - if chunk.bits == 0 { - return chunk; - } - let bits = self.chunk_bits.entry(chunk.key).or_insert(0); - let old_bits = *bits; - let new_bits = old_bits | chunk.bits; - *bits = new_bits; - let changed = new_bits ^ old_bits; - SparseChunk { - bits: changed, - ..chunk - } - } - - pub fn remove_chunk(&mut self, chunk: SparseChunk) -> SparseChunk { - if chunk.bits == 0 { - return chunk; - } - let changed = match self.chunk_bits.entry(chunk.key) { - Entry::Occupied(mut bits) => { - let old_bits = *bits.get(); - let new_bits = old_bits & !chunk.bits; - if new_bits == 0 { - bits.remove(); - } else { - bits.insert(new_bits); - } - new_bits ^ old_bits - } - Entry::Vacant(_) => 0, - }; - SparseChunk { - bits: changed, - ..chunk - } - } - - pub fn clear(&mut self) { - self.chunk_bits.clear(); - } - - pub fn chunks<'a>(&'a self) -> impl Iterator> + 'a { - self.chunk_bits.iter().map(|(&key, &bits)| SparseChunk { - key, - bits, - _marker: PhantomData, - }) - } - - pub fn contains(&self, index: I) -> bool { - self.contains_chunk(SparseChunk::one(index)).any() - } - - pub fn insert(&mut self, index: I) -> bool { - self.insert_chunk(SparseChunk::one(index)).any() + /// Iterates through all the columns set to true in a given row of + /// the matrix. + pub fn iter<'a>(&'a self, row: R) -> impl Iterator + 'a { + self.vector.get(row).into_iter().flat_map(|r| r.iter()) } - pub fn remove(&mut self, index: I) -> bool { - self.remove_chunk(SparseChunk::one(index)).any() + /// Iterates through each row and the accompanying bit set. + pub fn iter_enumerated<'a>(&'a self) -> impl Iterator)> + 'a { + self.vector.iter_enumerated() } - pub fn iter<'a>(&'a self) -> impl Iterator + 'a { - self.chunks().flat_map(|chunk| chunk.iter()) + pub fn row(&self, row: R) -> Option<&BitVector> { + self.vector.get(row) } } #[inline] -fn words(elements: usize) -> usize { - (elements + WORD_BITS - 1) / WORD_BITS +fn words(elements: C) -> usize { + (elements.index() + WORD_BITS - 1) / WORD_BITS } #[inline] -fn word_mask(index: usize) -> (usize, Word) { +fn word_mask(index: C) -> (usize, Word) { + let index = index.index(); let word = index / WORD_BITS; let mask = 1 << (index % WORD_BITS); (word, mask) @@ -484,7 +412,7 @@ fn word_mask(index: usize) -> (usize, Word) { #[test] fn bitvec_iter_works() { - let mut bitvec = BitVector::new(100); + let mut bitvec: BitVector = BitVector::new(100); bitvec.insert(1); bitvec.insert(10); bitvec.insert(19); @@ -502,7 +430,7 @@ fn bitvec_iter_works() { #[test] fn bitvec_iter_works_2() { - let mut bitvec = BitVector::new(319); + let mut bitvec: BitVector = BitVector::new(319); bitvec.insert(0); bitvec.insert(127); bitvec.insert(191); @@ -513,14 +441,14 @@ fn bitvec_iter_works_2() { #[test] fn union_two_vecs() { - let mut vec1 = BitVector::new(65); - let mut vec2 = BitVector::new(65); + let mut vec1: BitVector = BitVector::new(65); + let mut vec2: BitVector = BitVector::new(65); assert!(vec1.insert(3)); assert!(!vec1.insert(3)); assert!(vec2.insert(5)); assert!(vec2.insert(64)); - assert!(vec1.insert_all(&vec2)); - assert!(!vec1.insert_all(&vec2)); + assert!(vec1.merge(&vec2)); + assert!(!vec1.merge(&vec2)); assert!(vec1.contains(3)); assert!(!vec1.contains(4)); assert!(vec1.contains(5)); @@ -530,7 +458,7 @@ fn union_two_vecs() { #[test] fn grow() { - let mut vec1 = BitVector::new(65); + let mut vec1: BitVector = BitVector::new(65); for index in 0..65 { assert!(vec1.insert(index)); assert!(!vec1.insert(index)); @@ -556,7 +484,7 @@ fn grow() { #[test] fn matrix_intersection() { - let mut vec1 = BitMatrix::new(200, 200); + let mut vec1: BitMatrix = BitMatrix::new(200, 200); // (*) Elements reachable from both 2 and 65. @@ -587,7 +515,49 @@ fn matrix_intersection() { #[test] fn matrix_iter() { - let mut matrix = BitMatrix::new(64, 100); + let mut matrix: BitMatrix = BitMatrix::new(64, 100); + matrix.add(3, 22); + matrix.add(3, 75); + matrix.add(2, 99); + matrix.add(4, 0); + matrix.merge(3, 5); + + let expected = [99]; + let mut iter = expected.iter(); + for i in matrix.iter(2) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [22, 75]; + let mut iter = expected.iter(); + for i in matrix.iter(3) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [0]; + let mut iter = expected.iter(); + for i in matrix.iter(4) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); + + let expected = [22, 75]; + let mut iter = expected.iter(); + for i in matrix.iter(5) { + let j = *iter.next().unwrap(); + assert_eq!(i, j); + } + assert!(iter.next().is_none()); +} + +#[test] +fn sparse_matrix_iter() { + let mut matrix: SparseBitMatrix = SparseBitMatrix::new(100); matrix.add(3, 22); matrix.add(3, 75); matrix.add(2, 99); diff --git a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs deleted file mode 100644 index dc487f1162ca9..0000000000000 --- a/src/librustc_data_structures/control_flow_graph/dominators/mod.rs +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Algorithm citation: -//! A Simple, Fast Dominance Algorithm. -//! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy -//! Rice Computer Science TS-06-33870 -//! - -use super::ControlFlowGraph; -use super::iterate::reverse_post_order; -use super::super::indexed_vec::{IndexVec, Idx}; - -use std::fmt; - -#[cfg(test)] -mod test; - -pub fn dominators(graph: &G) -> Dominators { - let start_node = graph.start_node(); - let rpo = reverse_post_order(graph, start_node); - dominators_given_rpo(graph, &rpo) -} - -pub fn dominators_given_rpo(graph: &G, - rpo: &[G::Node]) - -> Dominators { - let start_node = graph.start_node(); - assert_eq!(rpo[0], start_node); - - // compute the post order index (rank) for each node - let mut post_order_rank: IndexVec = IndexVec::from_elem_n(usize::default(), - graph.num_nodes()); - for (index, node) in rpo.iter().rev().cloned().enumerate() { - post_order_rank[node] = index; - } - - let mut immediate_dominators: IndexVec> = - IndexVec::from_elem_n(Option::default(), graph.num_nodes()); - immediate_dominators[start_node] = Some(start_node); - - let mut changed = true; - while changed { - changed = false; - - for &node in &rpo[1..] { - let mut new_idom = None; - for pred in graph.predecessors(node) { - if immediate_dominators[pred].is_some() { - // (*) - // (*) dominators for `pred` have been calculated - new_idom = intersect_opt(&post_order_rank, - &immediate_dominators, - new_idom, - Some(pred)); - } - } - - if new_idom != immediate_dominators[node] { - immediate_dominators[node] = new_idom; - changed = true; - } - } - } - - Dominators { - post_order_rank, - immediate_dominators, - } -} - -fn intersect_opt(post_order_rank: &IndexVec, - immediate_dominators: &IndexVec>, - node1: Option, - node2: Option) - -> Option { - match (node1, node2) { - (None, None) => None, - (Some(n), None) | (None, Some(n)) => Some(n), - (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)), - } -} - -fn intersect(post_order_rank: &IndexVec, - immediate_dominators: &IndexVec>, - mut node1: Node, - mut node2: Node) - -> Node { - while node1 != node2 { - while post_order_rank[node1] < post_order_rank[node2] { - node1 = immediate_dominators[node1].unwrap(); - } - - while post_order_rank[node2] < post_order_rank[node1] { - node2 = immediate_dominators[node2].unwrap(); - } - } - return node1; -} - -#[derive(Clone, Debug)] -pub struct Dominators { - post_order_rank: IndexVec, - immediate_dominators: IndexVec>, -} - -impl Dominators { - pub fn is_reachable(&self, node: Node) -> bool { - self.immediate_dominators[node].is_some() - } - - pub fn immediate_dominator(&self, node: Node) -> Node { - assert!(self.is_reachable(node), "node {:?} is not reachable", node); - self.immediate_dominators[node].unwrap() - } - - pub fn dominators(&self, node: Node) -> Iter { - assert!(self.is_reachable(node), "node {:?} is not reachable", node); - Iter { - dominators: self, - node: Some(node), - } - } - - pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool { - // FIXME -- could be optimized by using post-order-rank - self.dominators(node).any(|n| n == dom) - } - - #[cfg(test)] - fn all_immediate_dominators(&self) -> &IndexVec> { - &self.immediate_dominators - } -} - -pub struct Iter<'dom, Node: Idx + 'dom> { - dominators: &'dom Dominators, - node: Option, -} - -impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { - type Item = Node; - - fn next(&mut self) -> Option { - if let Some(node) = self.node { - let dom = self.dominators.immediate_dominator(node); - if dom == node { - self.node = None; // reached the root - } else { - self.node = Some(dom); - } - return Some(node); - } else { - return None; - } - } -} - -pub struct DominatorTree { - root: N, - children: IndexVec>, -} - -impl DominatorTree { - pub fn children(&self, node: Node) -> &[Node] { - &self.children[node] - } -} - -impl fmt::Debug for DominatorTree { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - fmt::Debug::fmt(&DominatorTreeNode { - tree: self, - node: self.root, - }, - fmt) - } -} - -struct DominatorTreeNode<'tree, Node: Idx> { - tree: &'tree DominatorTree, - node: Node, -} - -impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - let subtrees: Vec<_> = self.tree - .children(self.node) - .iter() - .map(|&child| { - DominatorTreeNode { - tree: self.tree, - node: child, - } - }) - .collect(); - fmt.debug_tuple("") - .field(&self.node) - .field(&subtrees) - .finish() - } -} diff --git a/src/librustc_data_structures/control_flow_graph/iterate/mod.rs b/src/librustc_data_structures/control_flow_graph/iterate/mod.rs deleted file mode 100644 index 2d70b4063426d..0000000000000 --- a/src/librustc_data_structures/control_flow_graph/iterate/mod.rs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::ControlFlowGraph; -use super::super::indexed_vec::IndexVec; - -#[cfg(test)] -mod test; - -pub fn post_order_from(graph: &G, start_node: G::Node) -> Vec { - post_order_from_to(graph, start_node, None) -} - -pub fn post_order_from_to(graph: &G, - start_node: G::Node, - end_node: Option) - -> Vec { - let mut visited: IndexVec = IndexVec::from_elem_n(false, graph.num_nodes()); - let mut result: Vec = Vec::with_capacity(graph.num_nodes()); - if let Some(end_node) = end_node { - visited[end_node] = true; - } - post_order_walk(graph, start_node, &mut result, &mut visited); - result -} - -fn post_order_walk(graph: &G, - node: G::Node, - result: &mut Vec, - visited: &mut IndexVec) { - if visited[node] { - return; - } - visited[node] = true; - - for successor in graph.successors(node) { - post_order_walk(graph, successor, result, visited); - } - - result.push(node); -} - -pub fn reverse_post_order(graph: &G, start_node: G::Node) -> Vec { - let mut vec = post_order_from(graph, start_node); - vec.reverse(); - vec -} diff --git a/src/librustc_data_structures/control_flow_graph/mod.rs b/src/librustc_data_structures/control_flow_graph/mod.rs deleted file mode 100644 index 7bf776675c6a0..0000000000000 --- a/src/librustc_data_structures/control_flow_graph/mod.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::indexed_vec::Idx; - -pub mod dominators; -pub mod iterate; -mod reference; - -#[cfg(test)] -mod test; - -pub trait ControlFlowGraph - where Self: for<'graph> GraphPredecessors<'graph, Item=::Node>, - Self: for<'graph> GraphSuccessors<'graph, Item=::Node> -{ - type Node: Idx; - - fn num_nodes(&self) -> usize; - fn start_node(&self) -> Self::Node; - fn predecessors<'graph>(&'graph self, node: Self::Node) - -> >::Iter; - fn successors<'graph>(&'graph self, node: Self::Node) - -> >::Iter; -} - -pub trait GraphPredecessors<'graph> { - type Item; - type Iter: Iterator; -} - -pub trait GraphSuccessors<'graph> { - type Item; - type Iter: Iterator; -} diff --git a/src/librustc_data_structures/control_flow_graph/reference.rs b/src/librustc_data_structures/control_flow_graph/reference.rs deleted file mode 100644 index 3b8b01f2ff43b..0000000000000 --- a/src/librustc_data_structures/control_flow_graph/reference.rs +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use super::*; - -impl<'graph, G: ControlFlowGraph> ControlFlowGraph for &'graph G { - type Node = G::Node; - - fn num_nodes(&self) -> usize { - (**self).num_nodes() - } - - fn start_node(&self) -> Self::Node { - (**self).start_node() - } - - fn predecessors<'iter>(&'iter self, - node: Self::Node) - -> >::Iter { - (**self).predecessors(node) - } - - fn successors<'iter>(&'iter self, node: Self::Node) -> >::Iter { - (**self).successors(node) - } -} - -impl<'iter, 'graph, G: ControlFlowGraph> GraphPredecessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = >::Iter; -} - -impl<'iter, 'graph, G: ControlFlowGraph> GraphSuccessors<'iter> for &'graph G { - type Item = G::Node; - type Iter = >::Iter; -} diff --git a/src/librustc_data_structures/control_flow_graph/test.rs b/src/librustc_data_structures/control_flow_graph/test.rs deleted file mode 100644 index f04b536bc185f..0000000000000 --- a/src/librustc_data_structures/control_flow_graph/test.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::collections::HashMap; -use std::cmp::max; -use std::slice; -use std::iter; - -use super::{ControlFlowGraph, GraphPredecessors, GraphSuccessors}; - -pub struct TestGraph { - num_nodes: usize, - start_node: usize, - successors: HashMap>, - predecessors: HashMap>, -} - -impl TestGraph { - pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { - let mut graph = TestGraph { - num_nodes: start_node + 1, - start_node, - successors: HashMap::new(), - predecessors: HashMap::new(), - }; - for &(source, target) in edges { - graph.num_nodes = max(graph.num_nodes, source + 1); - graph.num_nodes = max(graph.num_nodes, target + 1); - graph.successors.entry(source).or_insert(vec![]).push(target); - graph.predecessors.entry(target).or_insert(vec![]).push(source); - } - for node in 0..graph.num_nodes { - graph.successors.entry(node).or_insert(vec![]); - graph.predecessors.entry(node).or_insert(vec![]); - } - graph - } -} - -impl ControlFlowGraph for TestGraph { - type Node = usize; - - fn start_node(&self) -> usize { - self.start_node - } - - fn num_nodes(&self) -> usize { - self.num_nodes - } - - fn predecessors<'graph>(&'graph self, - node: usize) - -> >::Iter { - self.predecessors[&node].iter().cloned() - } - - fn successors<'graph>(&'graph self, node: usize) -> >::Iter { - self.successors[&node].iter().cloned() - } -} - -impl<'graph> GraphPredecessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned>; -} - -impl<'graph> GraphSuccessors<'graph> for TestGraph { - type Item = usize; - type Iter = iter::Cloned>; -} diff --git a/src/librustc_data_structures/fx.rs b/src/librustc_data_structures/fx.rs index 5bf25437763cc..3bf3170d1df1a 100644 --- a/src/librustc_data_structures/fx.rs +++ b/src/librustc_data_structures/fx.rs @@ -10,11 +10,11 @@ use std::collections::{HashMap, HashSet}; use std::default::Default; -use std::hash::{Hasher, Hash, BuildHasherDefault}; -use std::ops::BitXor; +use std::hash::Hash; -pub type FxHashMap = HashMap>; -pub type FxHashSet = HashSet>; +pub use rustc_hash::FxHashMap; +pub use rustc_hash::FxHashSet; +pub use rustc_hash::FxHasher; #[allow(non_snake_case)] pub fn FxHashMap() -> FxHashMap { @@ -26,84 +26,3 @@ pub fn FxHashSet() -> FxHashSet { HashSet::default() } -/// A speedy hash algorithm for use within rustc. The hashmap in liballoc -/// by default uses SipHash which isn't quite as speedy as we want. In the -/// compiler we're not really worried about DOS attempts, so we use a fast -/// non-cryptographic hash. -/// -/// This is the same as the algorithm used by Firefox -- which is a homespun -/// one not based on any widely-known algorithm -- though modified to produce -/// 64-bit hash values instead of 32-bit hash values. It consistently -/// out-performs an FNV-based hash within rustc itself -- the collision rate is -/// similar or slightly worse than FNV, but the speed of the hash function -/// itself is much higher because it works on up to 8 bytes at a time. -pub struct FxHasher { - hash: usize -} - -#[cfg(target_pointer_width = "32")] -const K: usize = 0x9e3779b9; -#[cfg(target_pointer_width = "64")] -const K: usize = 0x517cc1b727220a95; - -impl Default for FxHasher { - #[inline] - fn default() -> FxHasher { - FxHasher { hash: 0 } - } -} - -impl FxHasher { - #[inline] - fn add_to_hash(&mut self, i: usize) { - self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(K); - } -} - -impl Hasher for FxHasher { - #[inline] - fn write(&mut self, bytes: &[u8]) { - for byte in bytes { - let i = *byte; - self.add_to_hash(i as usize); - } - } - - #[inline] - fn write_u8(&mut self, i: u8) { - self.add_to_hash(i as usize); - } - - #[inline] - fn write_u16(&mut self, i: u16) { - self.add_to_hash(i as usize); - } - - #[inline] - fn write_u32(&mut self, i: u32) { - self.add_to_hash(i as usize); - } - - #[cfg(target_pointer_width = "32")] - #[inline] - fn write_u64(&mut self, i: u64) { - self.add_to_hash(i as usize); - self.add_to_hash((i >> 32) as usize); - } - - #[cfg(target_pointer_width = "64")] - #[inline] - fn write_u64(&mut self, i: u64) { - self.add_to_hash(i as usize); - } - - #[inline] - fn write_usize(&mut self, i: usize) { - self.add_to_hash(i); - } - - #[inline] - fn finish(&self) -> u64 { - self.hash as u64 - } -} diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/src/librustc_data_structures/graph/dominators/mod.rs new file mode 100644 index 0000000000000..d134fad2855bb --- /dev/null +++ b/src/librustc_data_structures/graph/dominators/mod.rs @@ -0,0 +1,214 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Algorithm citation: +//! A Simple, Fast Dominance Algorithm. +//! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy +//! Rice Computer Science TS-06-33870 +//! + +use super::super::indexed_vec::{Idx, IndexVec}; +use super::iterate::reverse_post_order; +use super::ControlFlowGraph; + +use std::fmt; + +#[cfg(test)] +mod test; + +pub fn dominators(graph: &G) -> Dominators { + let start_node = graph.start_node(); + let rpo = reverse_post_order(graph, start_node); + dominators_given_rpo(graph, &rpo) +} + +pub fn dominators_given_rpo( + graph: &G, + rpo: &[G::Node], +) -> Dominators { + let start_node = graph.start_node(); + assert_eq!(rpo[0], start_node); + + // compute the post order index (rank) for each node + let mut post_order_rank: IndexVec = + IndexVec::from_elem_n(usize::default(), graph.num_nodes()); + for (index, node) in rpo.iter().rev().cloned().enumerate() { + post_order_rank[node] = index; + } + + let mut immediate_dominators: IndexVec> = + IndexVec::from_elem_n(Option::default(), graph.num_nodes()); + immediate_dominators[start_node] = Some(start_node); + + let mut changed = true; + while changed { + changed = false; + + for &node in &rpo[1..] { + let mut new_idom = None; + for pred in graph.predecessors(node) { + if immediate_dominators[pred].is_some() { + // (*) + // (*) dominators for `pred` have been calculated + new_idom = intersect_opt( + &post_order_rank, + &immediate_dominators, + new_idom, + Some(pred), + ); + } + } + + if new_idom != immediate_dominators[node] { + immediate_dominators[node] = new_idom; + changed = true; + } + } + } + + Dominators { + post_order_rank, + immediate_dominators, + } +} + +fn intersect_opt( + post_order_rank: &IndexVec, + immediate_dominators: &IndexVec>, + node1: Option, + node2: Option, +) -> Option { + match (node1, node2) { + (None, None) => None, + (Some(n), None) | (None, Some(n)) => Some(n), + (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)), + } +} + +fn intersect( + post_order_rank: &IndexVec, + immediate_dominators: &IndexVec>, + mut node1: Node, + mut node2: Node, +) -> Node { + while node1 != node2 { + while post_order_rank[node1] < post_order_rank[node2] { + node1 = immediate_dominators[node1].unwrap(); + } + + while post_order_rank[node2] < post_order_rank[node1] { + node2 = immediate_dominators[node2].unwrap(); + } + } + return node1; +} + +#[derive(Clone, Debug)] +pub struct Dominators { + post_order_rank: IndexVec, + immediate_dominators: IndexVec>, +} + +impl Dominators { + pub fn is_reachable(&self, node: Node) -> bool { + self.immediate_dominators[node].is_some() + } + + pub fn immediate_dominator(&self, node: Node) -> Node { + assert!(self.is_reachable(node), "node {:?} is not reachable", node); + self.immediate_dominators[node].unwrap() + } + + pub fn dominators(&self, node: Node) -> Iter { + assert!(self.is_reachable(node), "node {:?} is not reachable", node); + Iter { + dominators: self, + node: Some(node), + } + } + + pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool { + // FIXME -- could be optimized by using post-order-rank + self.dominators(node).any(|n| n == dom) + } + + #[cfg(test)] + fn all_immediate_dominators(&self) -> &IndexVec> { + &self.immediate_dominators + } +} + +pub struct Iter<'dom, Node: Idx + 'dom> { + dominators: &'dom Dominators, + node: Option, +} + +impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { + type Item = Node; + + fn next(&mut self) -> Option { + if let Some(node) = self.node { + let dom = self.dominators.immediate_dominator(node); + if dom == node { + self.node = None; // reached the root + } else { + self.node = Some(dom); + } + return Some(node); + } else { + return None; + } + } +} + +pub struct DominatorTree { + root: N, + children: IndexVec>, +} + +impl DominatorTree { + pub fn children(&self, node: Node) -> &[Node] { + &self.children[node] + } +} + +impl fmt::Debug for DominatorTree { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt( + &DominatorTreeNode { + tree: self, + node: self.root, + }, + fmt, + ) + } +} + +struct DominatorTreeNode<'tree, Node: Idx> { + tree: &'tree DominatorTree, + node: Node, +} + +impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + let subtrees: Vec<_> = self.tree + .children(self.node) + .iter() + .map(|&child| DominatorTreeNode { + tree: self.tree, + node: child, + }) + .collect(); + fmt.debug_tuple("") + .field(&self.node) + .field(&subtrees) + .finish() + } +} diff --git a/src/librustc_data_structures/control_flow_graph/dominators/test.rs b/src/librustc_data_structures/graph/dominators/test.rs similarity index 100% rename from src/librustc_data_structures/control_flow_graph/dominators/test.rs rename to src/librustc_data_structures/graph/dominators/test.rs diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/src/librustc_data_structures/graph/implementation/mod.rs new file mode 100644 index 0000000000000..dbfc09116bbaa --- /dev/null +++ b/src/librustc_data_structures/graph/implementation/mod.rs @@ -0,0 +1,417 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A graph module for use in dataflow, region resolution, and elsewhere. +//! +//! # Interface details +//! +//! You customize the graph by specifying a "node data" type `N` and an +//! "edge data" type `E`. You can then later gain access (mutable or +//! immutable) to these "user-data" bits. Currently, you can only add +//! nodes or edges to the graph. You cannot remove or modify them once +//! added. This could be changed if we have a need. +//! +//! # Implementation details +//! +//! The main tricky thing about this code is the way that edges are +//! stored. The edges are stored in a central array, but they are also +//! threaded onto two linked lists for each node, one for incoming edges +//! and one for outgoing edges. Note that every edge is a member of some +//! incoming list and some outgoing list. Basically you can load the +//! first index of the linked list from the node data structures (the +//! field `first_edge`) and then, for each edge, load the next index from +//! the field `next_edge`). Each of those fields is an array that should +//! be indexed by the direction (see the type `Direction`). + +use bitvec::BitVector; +use std::fmt::Debug; +use std::usize; +use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; + +#[cfg(test)] +mod tests; + +pub struct Graph { + nodes: SnapshotVec>, + edges: SnapshotVec>, +} + +pub struct Node { + first_edge: [EdgeIndex; 2], // see module comment + pub data: N, +} + +#[derive(Debug)] +pub struct Edge { + next_edge: [EdgeIndex; 2], // see module comment + source: NodeIndex, + target: NodeIndex, + pub data: E, +} + +impl SnapshotVecDelegate for Node { + type Value = Node; + type Undo = (); + + fn reverse(_: &mut Vec>, _: ()) {} +} + +impl SnapshotVecDelegate for Edge { + type Value = Edge; + type Undo = (); + + fn reverse(_: &mut Vec>, _: ()) {} +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub struct NodeIndex(pub usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub struct EdgeIndex(pub usize); + +pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); + +// Use a private field here to guarantee no more instances are created: +#[derive(Copy, Clone, Debug, PartialEq)] +pub struct Direction { + repr: usize, +} + +pub const OUTGOING: Direction = Direction { repr: 0 }; + +pub const INCOMING: Direction = Direction { repr: 1 }; + +impl NodeIndex { + /// Returns unique id (unique with respect to the graph holding associated node). + pub fn node_id(&self) -> usize { + self.0 + } +} + +impl Graph { + pub fn new() -> Graph { + Graph { + nodes: SnapshotVec::new(), + edges: SnapshotVec::new(), + } + } + + pub fn with_capacity(nodes: usize, edges: usize) -> Graph { + Graph { + nodes: SnapshotVec::with_capacity(nodes), + edges: SnapshotVec::with_capacity(edges), + } + } + + // # Simple accessors + + #[inline] + pub fn all_nodes(&self) -> &[Node] { + &self.nodes + } + + #[inline] + pub fn len_nodes(&self) -> usize { + self.nodes.len() + } + + #[inline] + pub fn all_edges(&self) -> &[Edge] { + &self.edges + } + + #[inline] + pub fn len_edges(&self) -> usize { + self.edges.len() + } + + // # Node construction + + pub fn next_node_index(&self) -> NodeIndex { + NodeIndex(self.nodes.len()) + } + + pub fn add_node(&mut self, data: N) -> NodeIndex { + let idx = self.next_node_index(); + self.nodes.push(Node { + first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], + data, + }); + idx + } + + pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { + &mut self.nodes[idx.0].data + } + + pub fn node_data(&self, idx: NodeIndex) -> &N { + &self.nodes[idx.0].data + } + + pub fn node(&self, idx: NodeIndex) -> &Node { + &self.nodes[idx.0] + } + + // # Edge construction and queries + + pub fn next_edge_index(&self) -> EdgeIndex { + EdgeIndex(self.edges.len()) + } + + pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { + debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); + + let idx = self.next_edge_index(); + + // read current first of the list of edges from each node + let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; + let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; + + // create the new edge, with the previous firsts from each node + // as the next pointers + self.edges.push(Edge { + next_edge: [source_first, target_first], + source, + target, + data, + }); + + // adjust the firsts for each node target be the next object. + self.nodes[source.0].first_edge[OUTGOING.repr] = idx; + self.nodes[target.0].first_edge[INCOMING.repr] = idx; + + return idx; + } + + pub fn edge(&self, idx: EdgeIndex) -> &Edge { + &self.edges[idx.0] + } + + // # Iterating over nodes, edges + + pub fn enumerated_nodes(&self) -> impl Iterator)> { + self.nodes + .iter() + .enumerate() + .map(|(idx, n)| (NodeIndex(idx), n)) + } + + pub fn enumerated_edges(&self) -> impl Iterator)> { + self.edges + .iter() + .enumerate() + .map(|(idx, e)| (EdgeIndex(idx), e)) + } + + pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { + //! Iterates over all edges defined in the graph. + self.enumerated_nodes() + .all(|(node_idx, node)| f(node_idx, node)) + } + + pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { + //! Iterates over all edges defined in the graph + self.enumerated_edges() + .all(|(edge_idx, edge)| f(edge_idx, edge)) + } + + pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { + self.adjacent_edges(source, OUTGOING) + } + + pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges { + self.adjacent_edges(source, INCOMING) + } + + pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges { + let first_edge = self.node(source).first_edge[direction.repr]; + AdjacentEdges { + graph: self, + direction, + next: first_edge, + } + } + + pub fn successor_nodes<'a>( + &'a self, + source: NodeIndex, + ) -> impl Iterator + 'a { + self.outgoing_edges(source).targets() + } + + pub fn predecessor_nodes<'a>( + &'a self, + target: NodeIndex, + ) -> impl Iterator + 'a { + self.incoming_edges(target).sources() + } + + pub fn depth_traverse<'a>( + &'a self, + start: NodeIndex, + direction: Direction, + ) -> DepthFirstTraversal<'a, N, E> { + DepthFirstTraversal::with_start_node(self, start, direction) + } + + pub fn nodes_in_postorder<'a>( + &'a self, + direction: Direction, + entry_node: NodeIndex, + ) -> Vec { + let mut visited = BitVector::new(self.len_nodes()); + let mut stack = vec![]; + let mut result = Vec::with_capacity(self.len_nodes()); + let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { + if visited.insert(node.0) { + stack.push((node, self.adjacent_edges(node, direction))); + } + }; + + for node in Some(entry_node) + .into_iter() + .chain(self.enumerated_nodes().map(|(node, _)| node)) + { + push_node(&mut stack, node); + while let Some((node, mut iter)) = stack.pop() { + if let Some((_, child)) = iter.next() { + let target = child.source_or_target(direction); + // the current node needs more processing, so + // add it back to the stack + stack.push((node, iter)); + // and then push the new node + push_node(&mut stack, target); + } else { + result.push(node); + } + } + } + + assert_eq!(result.len(), self.len_nodes()); + result + } +} + +// # Iterators + +pub struct AdjacentEdges<'g, N, E> +where + N: 'g, + E: 'g, +{ + graph: &'g Graph, + direction: Direction, + next: EdgeIndex, +} + +impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { + fn targets(self) -> impl Iterator + 'g { + self.into_iter().map(|(_, edge)| edge.target) + } + + fn sources(self) -> impl Iterator + 'g { + self.into_iter().map(|(_, edge)| edge.source) + } +} + +impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { + type Item = (EdgeIndex, &'g Edge); + + fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { + let edge_index = self.next; + if edge_index == INVALID_EDGE_INDEX { + return None; + } + + let edge = self.graph.edge(edge_index); + self.next = edge.next_edge[self.direction.repr]; + Some((edge_index, edge)) + } + + fn size_hint(&self) -> (usize, Option) { + // At most, all the edges in the graph. + (0, Some(self.graph.len_edges())) + } +} + +pub struct DepthFirstTraversal<'g, N, E> +where + N: 'g, + E: 'g, +{ + graph: &'g Graph, + stack: Vec, + visited: BitVector, + direction: Direction, +} + +impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { + pub fn with_start_node( + graph: &'g Graph, + start_node: NodeIndex, + direction: Direction, + ) -> Self { + let mut visited = BitVector::new(graph.len_nodes()); + visited.insert(start_node.node_id()); + DepthFirstTraversal { + graph, + stack: vec![start_node], + visited, + direction, + } + } + + fn visit(&mut self, node: NodeIndex) { + if self.visited.insert(node.node_id()) { + self.stack.push(node); + } + } +} + +impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { + type Item = NodeIndex; + + fn next(&mut self) -> Option { + let next = self.stack.pop(); + if let Some(idx) = next { + for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { + let target = edge.source_or_target(self.direction); + self.visit(target); + } + } + next + } + + fn size_hint(&self) -> (usize, Option) { + // We will visit every node in the graph exactly once. + let remaining = self.graph.len_nodes() - self.visited.count(); + (remaining, Some(remaining)) + } +} + +impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} + +impl Edge { + pub fn source(&self) -> NodeIndex { + self.source + } + + pub fn target(&self) -> NodeIndex { + self.target + } + + pub fn source_or_target(&self, direction: Direction) -> NodeIndex { + if direction == OUTGOING { + self.target + } else { + self.source + } + } +} diff --git a/src/librustc_data_structures/graph/tests.rs b/src/librustc_data_structures/graph/implementation/tests.rs similarity index 99% rename from src/librustc_data_structures/graph/tests.rs rename to src/librustc_data_structures/graph/implementation/tests.rs index 007704357af4f..3814827b5df6e 100644 --- a/src/librustc_data_structures/graph/tests.rs +++ b/src/librustc_data_structures/graph/implementation/tests.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use graph::*; +use graph::implementation::*; use std::fmt::Debug; type TestGraph = Graph<&'static str, &'static str>; diff --git a/src/librustc_data_structures/graph/iterate/mod.rs b/src/librustc_data_structures/graph/iterate/mod.rs new file mode 100644 index 0000000000000..3afdc88d60279 --- /dev/null +++ b/src/librustc_data_structures/graph/iterate/mod.rs @@ -0,0 +1,63 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::super::indexed_vec::IndexVec; +use super::{DirectedGraph, WithSuccessors, WithNumNodes}; + +#[cfg(test)] +mod test; + +pub fn post_order_from( + graph: &G, + start_node: G::Node, +) -> Vec { + post_order_from_to(graph, start_node, None) +} + +pub fn post_order_from_to( + graph: &G, + start_node: G::Node, + end_node: Option, +) -> Vec { + let mut visited: IndexVec = IndexVec::from_elem_n(false, graph.num_nodes()); + let mut result: Vec = Vec::with_capacity(graph.num_nodes()); + if let Some(end_node) = end_node { + visited[end_node] = true; + } + post_order_walk(graph, start_node, &mut result, &mut visited); + result +} + +fn post_order_walk( + graph: &G, + node: G::Node, + result: &mut Vec, + visited: &mut IndexVec, +) { + if visited[node] { + return; + } + visited[node] = true; + + for successor in graph.successors(node) { + post_order_walk(graph, successor, result, visited); + } + + result.push(node); +} + +pub fn reverse_post_order( + graph: &G, + start_node: G::Node, +) -> Vec { + let mut vec = post_order_from(graph, start_node); + vec.reverse(); + vec +} diff --git a/src/librustc_data_structures/control_flow_graph/iterate/test.rs b/src/librustc_data_structures/graph/iterate/test.rs similarity index 100% rename from src/librustc_data_structures/control_flow_graph/iterate/test.rs rename to src/librustc_data_structures/graph/iterate/test.rs diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index e2b393071ff5c..7265e4e8c7c66 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,410 +8,72 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A graph module for use in dataflow, region resolution, and elsewhere. -//! -//! # Interface details -//! -//! You customize the graph by specifying a "node data" type `N` and an -//! "edge data" type `E`. You can then later gain access (mutable or -//! immutable) to these "user-data" bits. Currently, you can only add -//! nodes or edges to the graph. You cannot remove or modify them once -//! added. This could be changed if we have a need. -//! -//! # Implementation details -//! -//! The main tricky thing about this code is the way that edges are -//! stored. The edges are stored in a central array, but they are also -//! threaded onto two linked lists for each node, one for incoming edges -//! and one for outgoing edges. Note that every edge is a member of some -//! incoming list and some outgoing list. Basically you can load the -//! first index of the linked list from the node data structures (the -//! field `first_edge`) and then, for each edge, load the next index from -//! the field `next_edge`). Each of those fields is an array that should -//! be indexed by the direction (see the type `Direction`). +use super::indexed_vec::Idx; -use bitvec::BitVector; -use std::fmt::Debug; -use std::usize; -use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; +pub mod dominators; +pub mod implementation; +pub mod iterate; +mod reference; +pub mod scc; #[cfg(test)] -mod tests; +mod test; -pub struct Graph { - nodes: SnapshotVec>, - edges: SnapshotVec>, +pub trait DirectedGraph { + type Node: Idx; } -pub struct Node { - first_edge: [EdgeIndex; 2], // see module comment - pub data: N, +pub trait WithNumNodes: DirectedGraph { + fn num_nodes(&self) -> usize; } -#[derive(Debug)] -pub struct Edge { - next_edge: [EdgeIndex; 2], // see module comment - source: NodeIndex, - target: NodeIndex, - pub data: E, -} - -impl SnapshotVecDelegate for Node { - type Value = Node; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -impl SnapshotVecDelegate for Edge { - type Value = Edge; - type Undo = (); - - fn reverse(_: &mut Vec>, _: ()) {} -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub struct NodeIndex(pub usize); - -#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] -pub struct EdgeIndex(pub usize); - -pub const INVALID_EDGE_INDEX: EdgeIndex = EdgeIndex(usize::MAX); - -// Use a private field here to guarantee no more instances are created: -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Direction { - repr: usize, -} - -pub const OUTGOING: Direction = Direction { repr: 0 }; - -pub const INCOMING: Direction = Direction { repr: 1 }; - -impl NodeIndex { - /// Returns unique id (unique with respect to the graph holding associated node). - pub fn node_id(&self) -> usize { - self.0 - } -} - -impl Graph { - pub fn new() -> Graph { - Graph { - nodes: SnapshotVec::new(), - edges: SnapshotVec::new(), - } - } - - pub fn with_capacity(nodes: usize, edges: usize) -> Graph { - Graph { - nodes: SnapshotVec::with_capacity(nodes), - edges: SnapshotVec::with_capacity(edges), - } - } - - // # Simple accessors - - #[inline] - pub fn all_nodes(&self) -> &[Node] { - &self.nodes - } - - #[inline] - pub fn len_nodes(&self) -> usize { - self.nodes.len() - } - - #[inline] - pub fn all_edges(&self) -> &[Edge] { - &self.edges - } - - #[inline] - pub fn len_edges(&self) -> usize { - self.edges.len() - } - - // # Node construction - - pub fn next_node_index(&self) -> NodeIndex { - NodeIndex(self.nodes.len()) - } - - pub fn add_node(&mut self, data: N) -> NodeIndex { - let idx = self.next_node_index(); - self.nodes.push(Node { - first_edge: [INVALID_EDGE_INDEX, INVALID_EDGE_INDEX], - data, - }); - idx - } - - pub fn mut_node_data(&mut self, idx: NodeIndex) -> &mut N { - &mut self.nodes[idx.0].data - } - - pub fn node_data(&self, idx: NodeIndex) -> &N { - &self.nodes[idx.0].data - } - - pub fn node(&self, idx: NodeIndex) -> &Node { - &self.nodes[idx.0] - } - - // # Edge construction and queries - - pub fn next_edge_index(&self) -> EdgeIndex { - EdgeIndex(self.edges.len()) - } - - pub fn add_edge(&mut self, source: NodeIndex, target: NodeIndex, data: E) -> EdgeIndex { - debug!("graph: add_edge({:?}, {:?}, {:?})", source, target, data); - - let idx = self.next_edge_index(); - - // read current first of the list of edges from each node - let source_first = self.nodes[source.0].first_edge[OUTGOING.repr]; - let target_first = self.nodes[target.0].first_edge[INCOMING.repr]; - - // create the new edge, with the previous firsts from each node - // as the next pointers - self.edges.push(Edge { - next_edge: [source_first, target_first], - source, - target, - data, - }); - - // adjust the firsts for each node target be the next object. - self.nodes[source.0].first_edge[OUTGOING.repr] = idx; - self.nodes[target.0].first_edge[INCOMING.repr] = idx; - - return idx; - } - - pub fn edge(&self, idx: EdgeIndex) -> &Edge { - &self.edges[idx.0] - } - - // # Iterating over nodes, edges - - pub fn enumerated_nodes(&self) -> impl Iterator)> { - self.nodes - .iter() - .enumerate() - .map(|(idx, n)| (NodeIndex(idx), n)) - } - - pub fn enumerated_edges(&self) -> impl Iterator)> { - self.edges - .iter() - .enumerate() - .map(|(idx, e)| (EdgeIndex(idx), e)) - } - - pub fn each_node<'a>(&'a self, mut f: impl FnMut(NodeIndex, &'a Node) -> bool) -> bool { - //! Iterates over all edges defined in the graph. - self.enumerated_nodes() - .all(|(node_idx, node)| f(node_idx, node)) - } - - pub fn each_edge<'a>(&'a self, mut f: impl FnMut(EdgeIndex, &'a Edge) -> bool) -> bool { - //! Iterates over all edges defined in the graph - self.enumerated_edges() - .all(|(edge_idx, edge)| f(edge_idx, edge)) - } - - pub fn outgoing_edges(&self, source: NodeIndex) -> AdjacentEdges { - self.adjacent_edges(source, OUTGOING) - } - - pub fn incoming_edges(&self, source: NodeIndex) -> AdjacentEdges { - self.adjacent_edges(source, INCOMING) - } - - pub fn adjacent_edges(&self, source: NodeIndex, direction: Direction) -> AdjacentEdges { - let first_edge = self.node(source).first_edge[direction.repr]; - AdjacentEdges { - graph: self, - direction, - next: first_edge, - } - } - - pub fn successor_nodes<'a>( - &'a self, - source: NodeIndex, - ) -> impl Iterator + 'a { - self.outgoing_edges(source).targets() - } - - pub fn predecessor_nodes<'a>( - &'a self, - target: NodeIndex, - ) -> impl Iterator + 'a { - self.incoming_edges(target).sources() - } - - pub fn depth_traverse<'a>( - &'a self, - start: NodeIndex, - direction: Direction, - ) -> DepthFirstTraversal<'a, N, E> { - DepthFirstTraversal::with_start_node(self, start, direction) - } - - pub fn nodes_in_postorder<'a>( - &'a self, - direction: Direction, - entry_node: NodeIndex, - ) -> Vec { - let mut visited = BitVector::new(self.len_nodes()); - let mut stack = vec![]; - let mut result = Vec::with_capacity(self.len_nodes()); - let mut push_node = |stack: &mut Vec<_>, node: NodeIndex| { - if visited.insert(node.0) { - stack.push((node, self.adjacent_edges(node, direction))); - } - }; - - for node in Some(entry_node) - .into_iter() - .chain(self.enumerated_nodes().map(|(node, _)| node)) - { - push_node(&mut stack, node); - while let Some((node, mut iter)) = stack.pop() { - if let Some((_, child)) = iter.next() { - let target = child.source_or_target(direction); - // the current node needs more processing, so - // add it back to the stack - stack.push((node, iter)); - // and then push the new node - push_node(&mut stack, target); - } else { - result.push(node); - } - } - } - - assert_eq!(result.len(), self.len_nodes()); - result - } -} - -// # Iterators - -pub struct AdjacentEdges<'g, N, E> +pub trait WithSuccessors: DirectedGraph where - N: 'g, - E: 'g, + Self: for<'graph> GraphSuccessors<'graph, Item = ::Node>, { - graph: &'g Graph, - direction: Direction, - next: EdgeIndex, + fn successors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter; } -impl<'g, N: Debug, E: Debug> AdjacentEdges<'g, N, E> { - fn targets(self) -> impl Iterator + 'g { - self.into_iter().map(|(_, edge)| edge.target) - } - - fn sources(self) -> impl Iterator + 'g { - self.into_iter().map(|(_, edge)| edge.source) - } +pub trait GraphSuccessors<'graph> { + type Item; + type Iter: Iterator; } -impl<'g, N: Debug, E: Debug> Iterator for AdjacentEdges<'g, N, E> { - type Item = (EdgeIndex, &'g Edge); - - fn next(&mut self) -> Option<(EdgeIndex, &'g Edge)> { - let edge_index = self.next; - if edge_index == INVALID_EDGE_INDEX { - return None; - } - - let edge = self.graph.edge(edge_index); - self.next = edge.next_edge[self.direction.repr]; - Some((edge_index, edge)) - } - - fn size_hint(&self) -> (usize, Option) { - // At most, all the edges in the graph. - (0, Some(self.graph.len_edges())) - } -} - -pub struct DepthFirstTraversal<'g, N, E> +pub trait WithPredecessors: DirectedGraph where - N: 'g, - E: 'g, + Self: for<'graph> GraphPredecessors<'graph, Item = ::Node>, { - graph: &'g Graph, - stack: Vec, - visited: BitVector, - direction: Direction, + fn predecessors<'graph>( + &'graph self, + node: Self::Node, + ) -> >::Iter; } -impl<'g, N: Debug, E: Debug> DepthFirstTraversal<'g, N, E> { - pub fn with_start_node( - graph: &'g Graph, - start_node: NodeIndex, - direction: Direction, - ) -> Self { - let mut visited = BitVector::new(graph.len_nodes()); - visited.insert(start_node.node_id()); - DepthFirstTraversal { - graph, - stack: vec![start_node], - visited, - direction, - } - } - - fn visit(&mut self, node: NodeIndex) { - if self.visited.insert(node.node_id()) { - self.stack.push(node); - } - } +pub trait GraphPredecessors<'graph> { + type Item; + type Iter: Iterator; } -impl<'g, N: Debug, E: Debug> Iterator for DepthFirstTraversal<'g, N, E> { - type Item = NodeIndex; - - fn next(&mut self) -> Option { - let next = self.stack.pop(); - if let Some(idx) = next { - for (_, edge) in self.graph.adjacent_edges(idx, self.direction) { - let target = edge.source_or_target(self.direction); - self.visit(target); - } - } - next - } - - fn size_hint(&self) -> (usize, Option) { - // We will visit every node in the graph exactly once. - let remaining = self.graph.len_nodes() - self.visited.count(); - (remaining, Some(remaining)) - } +pub trait WithStartNode: DirectedGraph { + fn start_node(&self) -> Self::Node; } -impl<'g, N: Debug, E: Debug> ExactSizeIterator for DepthFirstTraversal<'g, N, E> {} - -impl Edge { - pub fn source(&self) -> NodeIndex { - self.source - } - - pub fn target(&self) -> NodeIndex { - self.target - } +pub trait ControlFlowGraph: + DirectedGraph + WithStartNode + WithPredecessors + WithStartNode + WithSuccessors + WithNumNodes +{ + // convenient trait +} - pub fn source_or_target(&self, direction: Direction) -> NodeIndex { - if direction == OUTGOING { - self.target - } else { - self.source - } - } +impl ControlFlowGraph for T +where + T: DirectedGraph + + WithStartNode + + WithPredecessors + + WithStartNode + + WithSuccessors + + WithNumNodes, +{ } diff --git a/src/librustc_data_structures/graph/reference.rs b/src/librustc_data_structures/graph/reference.rs new file mode 100644 index 0000000000000..a7b763db8da29 --- /dev/null +++ b/src/librustc_data_structures/graph/reference.rs @@ -0,0 +1,51 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::*; + +impl<'graph, G: DirectedGraph> DirectedGraph for &'graph G { + type Node = G::Node; +} + +impl<'graph, G: WithNumNodes> WithNumNodes for &'graph G { + fn num_nodes(&self) -> usize { + (**self).num_nodes() + } +} + +impl<'graph, G: WithStartNode> WithStartNode for &'graph G { + fn start_node(&self) -> Self::Node { + (**self).start_node() + } +} + +impl<'graph, G: WithSuccessors> WithSuccessors for &'graph G { + fn successors<'iter>(&'iter self, node: Self::Node) -> >::Iter { + (**self).successors(node) + } +} + +impl<'graph, G: WithPredecessors> WithPredecessors for &'graph G { + fn predecessors<'iter>(&'iter self, + node: Self::Node) + -> >::Iter { + (**self).predecessors(node) + } +} + +impl<'iter, 'graph, G: WithPredecessors> GraphPredecessors<'iter> for &'graph G { + type Item = G::Node; + type Iter = >::Iter; +} + +impl<'iter, 'graph, G: WithSuccessors> GraphSuccessors<'iter> for &'graph G { + type Item = G::Node; + type Iter = >::Iter; +} diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/src/librustc_data_structures/graph/scc/mod.rs new file mode 100644 index 0000000000000..a989a54010222 --- /dev/null +++ b/src/librustc_data_structures/graph/scc/mod.rs @@ -0,0 +1,361 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Routine to compute the strongly connected components (SCCs) of a +//! graph, as well as the resulting DAG if each SCC is replaced with a +//! node in the graph. This uses Tarjan's algorithm that completes in +//! O(n) time. + +use fx::FxHashSet; +use graph::{DirectedGraph, WithNumNodes, WithSuccessors}; +use indexed_vec::{Idx, IndexVec}; +use std::ops::Range; + +mod test; + +/// Strongly connected components (SCC) of a graph. The type `N` is +/// the index type for the graph nodes and `S` is the index type for +/// the SCCs. We can map from each node to the SCC that it +/// participates in, and we also have the successors of each SCC. +pub struct Sccs { + /// For each node, what is the SCC index of the SCC to which it + /// belongs. + scc_indices: IndexVec, + + /// Data about each SCC. + scc_data: SccData, +} + +struct SccData { + /// For each SCC, the range of `all_successors` where its + /// successors can be found. + ranges: IndexVec>, + + /// Contains the succcessors for all the Sccs, concatenated. The + /// range of indices corresponding to a given SCC is found in its + /// SccData. + all_successors: Vec, +} + +impl Sccs { + pub fn new(graph: &(impl DirectedGraph + WithNumNodes + WithSuccessors)) -> Self { + SccsConstruction::construct(graph) + } + + /// Returns the number of SCCs in the graph. + pub fn num_sccs(&self) -> usize { + self.scc_data.len() + } + + /// Returns an iterator over the SCCs in the graph. + pub fn all_sccs(&self) -> impl Iterator { + (0 .. self.scc_data.len()).map(S::new) + } + + /// Returns the SCC to which a node `r` belongs. + pub fn scc(&self, r: N) -> S { + self.scc_indices[r] + } + + /// Returns the successors of the given SCC. + pub fn successors(&self, scc: S) -> &[S] { + self.scc_data.successors(scc) + } +} + +impl SccData { + /// Number of SCCs, + fn len(&self) -> usize { + self.ranges.len() + } + + /// Returns the successors of the given SCC. + fn successors(&self, scc: S) -> &[S] { + // Annoyingly, `range` does not implement `Copy`, so we have + // to do `range.start..range.end`: + let range = &self.ranges[scc]; + &self.all_successors[range.start..range.end] + } + + /// Creates a new SCC with `successors` as its successors and + /// returns the resulting index. + fn create_scc(&mut self, successors: impl IntoIterator) -> S { + // Store the successors on `scc_successors_vec`, remembering + // the range of indices. + let all_successors_start = self.all_successors.len(); + self.all_successors.extend(successors); + let all_successors_end = self.all_successors.len(); + + debug!( + "create_scc({:?}) successors={:?}", + self.ranges.len(), + &self.all_successors[all_successors_start..all_successors_end], + ); + + self.ranges.push(all_successors_start..all_successors_end) + } +} + +struct SccsConstruction<'c, G: DirectedGraph + WithNumNodes + WithSuccessors + 'c, S: Idx> { + graph: &'c G, + + /// The state of each node; used during walk to record the stack + /// and after walk to record what cycle each node ended up being + /// in. + node_states: IndexVec>, + + /// The stack of nodes that we are visiting as part of the DFS. + node_stack: Vec, + + /// The stack of successors: as we visit a node, we mark our + /// position in this stack, and when we encounter a successor SCC, + /// we push it on the stack. When we complete an SCC, we can pop + /// everything off the stack that was found along the way. + successors_stack: Vec, + + /// A set used to strip duplicates. As we accumulate successors + /// into the successors_stack, we sometimes get duplicate entries. + /// We use this set to remove those -- we also keep its storage + /// around between successors to amortize memory allocation costs. + duplicate_set: FxHashSet, + + scc_data: SccData, +} + +#[derive(Copy, Clone, Debug)] +enum NodeState { + /// This node has not yet been visited as part of the DFS. + /// + /// After SCC construction is complete, this state ought to be + /// impossible. + NotVisited, + + /// This node is currently being walk as part of our DFS. It is on + /// the stack at the depth `depth`. + /// + /// After SCC construction is complete, this state ought to be + /// impossible. + BeingVisited { depth: usize }, + + /// Indicates that this node is a member of the given cycle. + InCycle { scc_index: S }, + + /// Indicates that this node is a member of whatever cycle + /// `parent` is a member of. This state is transient: whenever we + /// see it, we try to overwrite it with the current state of + /// `parent` (this is the "path compression" step of a union-find + /// algorithm). + InCycleWith { parent: N }, +} + +#[derive(Copy, Clone, Debug)] +enum WalkReturn { + Cycle { min_depth: usize }, + Complete { scc_index: S }, +} + +impl<'c, G, S> SccsConstruction<'c, G, S> +where + G: DirectedGraph + WithNumNodes + WithSuccessors, + S: Idx, +{ + /// Identifies SCCs in the graph `G` and computes the resulting + /// DAG. This uses a variant of [Tarjan's + /// algorithm][wikipedia]. The high-level summary of the algorithm + /// is that we do a depth-first search. Along the way, we keep a + /// stack of each node whose successors are being visited. We + /// track the depth of each node on this stack (there is no depth + /// if the node is not on the stack). When we find that some node + /// N with depth D can reach some other node N' with lower depth + /// D' (i.e., D' < D), we know that N, N', and all nodes in + /// between them on the stack are part of an SCC. + /// + /// [wikipedia]: https://bit.ly/2EZIx84 + fn construct(graph: &'c G) -> Sccs { + let num_nodes = graph.num_nodes(); + + let mut this = Self { + graph, + node_states: IndexVec::from_elem_n(NodeState::NotVisited, num_nodes), + node_stack: Vec::with_capacity(num_nodes), + successors_stack: Vec::new(), + scc_data: SccData { + ranges: IndexVec::new(), + all_successors: Vec::new(), + }, + duplicate_set: FxHashSet::default(), + }; + + let scc_indices = (0..num_nodes) + .map(G::Node::new) + .map(|node| match this.walk_node(0, node) { + WalkReturn::Complete { scc_index } => scc_index, + WalkReturn::Cycle { min_depth } => panic!( + "`walk_node(0, {:?})` returned cycle with depth {:?}", + node, min_depth + ), + }) + .collect(); + + Sccs { + scc_indices, + scc_data: this.scc_data, + } + } + + /// Visit a node during the DFS. We first examine its current + /// state -- if it is not yet visited (`NotVisited`), we can push + /// it onto the stack and start walking its successors. + /// + /// If it is already on the DFS stack it will be in the state + /// `BeingVisited`. In that case, we have found a cycle and we + /// return the depth from the stack. + /// + /// Otherwise, we are looking at a node that has already been + /// completely visited. We therefore return `WalkReturn::Complete` + /// with its associated SCC index. + fn walk_node(&mut self, depth: usize, node: G::Node) -> WalkReturn { + debug!("walk_node(depth = {:?}, node = {:?})", depth, node); + match self.find_state(node) { + NodeState::InCycle { scc_index } => WalkReturn::Complete { scc_index }, + + NodeState::BeingVisited { depth: min_depth } => WalkReturn::Cycle { min_depth }, + + NodeState::NotVisited => self.walk_unvisited_node(depth, node), + + NodeState::InCycleWith { parent } => panic!( + "`find_state` returned `InCycleWith({:?})`, which ought to be impossible", + parent + ), + } + } + + /// Fetches the state of the node `r`. If `r` is recorded as being + /// in a cycle with some other node `r2`, then fetches the state + /// of `r2` (and updates `r` to reflect current result). This is + /// basically the "find" part of a standard union-find algorithm + /// (with path compression). + fn find_state(&mut self, r: G::Node) -> NodeState { + debug!("find_state(r = {:?} in state {:?})", r, self.node_states[r]); + match self.node_states[r] { + NodeState::InCycle { scc_index } => NodeState::InCycle { scc_index }, + NodeState::BeingVisited { depth } => NodeState::BeingVisited { depth }, + NodeState::NotVisited => NodeState::NotVisited, + NodeState::InCycleWith { parent } => { + let parent_state = self.find_state(parent); + debug!("find_state: parent_state = {:?}", parent_state); + match parent_state { + NodeState::InCycle { .. } => { + self.node_states[r] = parent_state; + parent_state + } + + NodeState::BeingVisited { depth } => { + self.node_states[r] = NodeState::InCycleWith { + parent: self.node_stack[depth], + }; + parent_state + } + + NodeState::NotVisited | NodeState::InCycleWith { .. } => { + panic!("invalid parent state: {:?}", parent_state) + } + } + } + } + } + + /// Walks a node that has never been visited before. + fn walk_unvisited_node(&mut self, depth: usize, node: G::Node) -> WalkReturn { + debug!( + "walk_unvisited_node(depth = {:?}, node = {:?})", + depth, node + ); + + debug_assert!(match self.node_states[node] { + NodeState::NotVisited => true, + _ => false, + }); + + // Push `node` onto the stack. + self.node_states[node] = NodeState::BeingVisited { depth }; + self.node_stack.push(node); + + // Walk each successor of the node, looking to see if any of + // them can reach a node that is presently on the stack. If + // so, that means they can also reach us. + let mut min_depth = depth; + let mut min_cycle_root = node; + let successors_len = self.successors_stack.len(); + for successor_node in self.graph.successors(node) { + debug!( + "walk_unvisited_node: node = {:?} successor_ode = {:?}", + node, successor_node + ); + match self.walk_node(depth + 1, successor_node) { + WalkReturn::Cycle { + min_depth: successor_min_depth, + } => { + // Track the minimum depth we can reach. + assert!(successor_min_depth <= depth); + if successor_min_depth < min_depth { + debug!( + "walk_unvisited_node: node = {:?} successor_min_depth = {:?}", + node, successor_min_depth + ); + min_depth = successor_min_depth; + min_cycle_root = successor_node; + } + } + + WalkReturn::Complete { + scc_index: successor_scc_index, + } => { + // Push the completed SCC indices onto + // the `successors_stack` for later. + debug!( + "walk_unvisited_node: node = {:?} successor_scc_index = {:?}", + node, successor_scc_index + ); + self.successors_stack.push(successor_scc_index); + } + } + } + + // Completed walk, remove `node` from the stack. + let r = self.node_stack.pop(); + debug_assert_eq!(r, Some(node)); + + // If `min_depth == depth`, then we are the root of the + // cycle: we can't reach anyone further down the stack. + if min_depth == depth { + // Note that successor stack may have duplicates, so we + // want to remove those: + let deduplicated_successors = { + let duplicate_set = &mut self.duplicate_set; + duplicate_set.clear(); + self.successors_stack + .drain(successors_len..) + .filter(move |&i| duplicate_set.insert(i)) + }; + let scc_index = self.scc_data.create_scc(deduplicated_successors); + self.node_states[node] = NodeState::InCycle { scc_index }; + WalkReturn::Complete { scc_index } + } else { + // We are not the head of the cycle. Return back to our + // caller. They will take ownership of the + // `self.successors` data that we pushed. + self.node_states[node] = NodeState::InCycleWith { + parent: min_cycle_root, + }; + WalkReturn::Cycle { min_depth } + } + } +} diff --git a/src/librustc_data_structures/graph/scc/test.rs b/src/librustc_data_structures/graph/scc/test.rs new file mode 100644 index 0000000000000..405e1b3a61748 --- /dev/null +++ b/src/librustc_data_structures/graph/scc/test.rs @@ -0,0 +1,180 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(test)] + +use graph::test::TestGraph; +use super::*; + +#[test] +fn diamond() { + let graph = TestGraph::new(0, &[(0, 1), (0, 2), (1, 3), (2, 3)]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 4); + assert_eq!(sccs.num_sccs(), 4); +} + +#[test] +fn test_big_scc() { + // The order in which things will be visited is important to this + // test. + // + // We will visit: + // + // 0 -> 1 -> 2 -> 0 + // + // and at this point detect a cycle. 2 will return back to 1 which + // will visit 3. 3 will visit 2 before the cycle is complete, and + // hence it too will return a cycle. + + /* ++-> 0 +| | +| v +| 1 -> 3 +| | | +| v | ++-- 2 <--+ + */ + let graph = TestGraph::new(0, &[ + (0, 1), + (1, 2), + (1, 3), + (2, 0), + (3, 2), + ]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 1); +} + +#[test] +fn test_three_sccs() { + /* + 0 + | + v ++-> 1 3 +| | | +| v | ++-- 2 <--+ + */ + let graph = TestGraph::new(0, &[ + (0, 1), + (1, 2), + (2, 1), + (3, 2), + ]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 3); + assert_eq!(sccs.scc(0), 1); + assert_eq!(sccs.scc(1), 0); + assert_eq!(sccs.scc(2), 0); + assert_eq!(sccs.scc(3), 2); + assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(1), &[0]); + assert_eq!(sccs.successors(2), &[0]); +} + +#[test] +fn test_find_state_2() { + // The order in which things will be visited is important to this + // test. It tests part of the `find_state` behavior. Here is the + // graph: + // + // + // /----+ + // 0 <--+ | + // | | | + // v | | + // +-> 1 -> 3 4 + // | | | + // | v | + // +-- 2 <----+ + + let graph = TestGraph::new(0, &[ + (0, 1), + (0, 4), + (1, 2), + (1, 3), + (2, 1), + (3, 0), + (4, 2), + ]); + + // For this graph, we will start in our DFS by visiting: + // + // 0 -> 1 -> 2 -> 1 + // + // and at this point detect a cycle. The state of 2 will thus be + // `InCycleWith { 1 }`. We will then visit the 1 -> 3 edge, which + // will attempt to visit 0 as well, thus going to the state + // `InCycleWith { 0 }`. Finally, node 1 will complete; the lowest + // depth of any successor was 3 which had depth 0, and thus it + // will be in the state `InCycleWith { 3 }`. + // + // When we finally traverse the `0 -> 4` edge and then visit node 2, + // the states of the nodes are: + // + // 0 BeingVisited { 0 } + // 1 InCycleWith { 3 } + // 2 InCycleWith { 1 } + // 3 InCycleWith { 0 } + // + // and hence 4 will traverse the links, finding an ultimate depth of 0. + // If will also collapse the states to the following: + // + // 0 BeingVisited { 0 } + // 1 InCycleWith { 3 } + // 2 InCycleWith { 1 } + // 3 InCycleWith { 0 } + + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 1); + assert_eq!(sccs.scc(0), 0); + assert_eq!(sccs.scc(1), 0); + assert_eq!(sccs.scc(2), 0); + assert_eq!(sccs.scc(3), 0); + assert_eq!(sccs.scc(4), 0); + assert_eq!(sccs.successors(0), &[]); +} + +#[test] +fn test_find_state_3() { + /* + /----+ + 0 <--+ | + | | | + v | | ++-> 1 -> 3 4 5 +| | | | +| v | | ++-- 2 <----+-+ + */ + let graph = TestGraph::new(0, &[ + (0, 1), + (0, 4), + (1, 2), + (1, 3), + (2, 1), + (3, 0), + (4, 2), + (5, 2), + ]); + let sccs: Sccs<_, usize> = Sccs::new(&graph); + assert_eq!(sccs.num_sccs(), 2); + assert_eq!(sccs.scc(0), 0); + assert_eq!(sccs.scc(1), 0); + assert_eq!(sccs.scc(2), 0); + assert_eq!(sccs.scc(3), 0); + assert_eq!(sccs.scc(4), 0); + assert_eq!(sccs.scc(5), 1); + assert_eq!(sccs.successors(0), &[]); + assert_eq!(sccs.successors(1), &[0]); +} diff --git a/src/librustc_data_structures/graph/test.rs b/src/librustc_data_structures/graph/test.rs new file mode 100644 index 0000000000000..48b654726b8f2 --- /dev/null +++ b/src/librustc_data_structures/graph/test.rs @@ -0,0 +1,85 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::collections::HashMap; +use std::cmp::max; +use std::slice; +use std::iter; + +use super::*; + +pub struct TestGraph { + num_nodes: usize, + start_node: usize, + successors: HashMap>, + predecessors: HashMap>, +} + +impl TestGraph { + pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self { + let mut graph = TestGraph { + num_nodes: start_node + 1, + start_node, + successors: HashMap::new(), + predecessors: HashMap::new(), + }; + for &(source, target) in edges { + graph.num_nodes = max(graph.num_nodes, source + 1); + graph.num_nodes = max(graph.num_nodes, target + 1); + graph.successors.entry(source).or_insert(vec![]).push(target); + graph.predecessors.entry(target).or_insert(vec![]).push(source); + } + for node in 0..graph.num_nodes { + graph.successors.entry(node).or_insert(vec![]); + graph.predecessors.entry(node).or_insert(vec![]); + } + graph + } +} + +impl DirectedGraph for TestGraph { + type Node = usize; +} + +impl WithStartNode for TestGraph { + fn start_node(&self) -> usize { + self.start_node + } +} + +impl WithNumNodes for TestGraph { + fn num_nodes(&self) -> usize { + self.num_nodes + } +} + +impl WithPredecessors for TestGraph { + fn predecessors<'graph>(&'graph self, + node: usize) + -> >::Iter { + self.predecessors[&node].iter().cloned() + } +} + +impl WithSuccessors for TestGraph { + fn successors<'graph>(&'graph self, node: usize) -> >::Iter { + self.successors[&node].iter().cloned() + } +} + +impl<'graph> GraphPredecessors<'graph> for TestGraph { + type Item = usize; + type Iter = iter::Cloned>; +} + +impl<'graph> GraphSuccessors<'graph> for TestGraph { + type Item = usize; + type Iter = iter::Cloned>; +} diff --git a/src/librustc_data_structures/indexed_set.rs b/src/librustc_data_structures/indexed_set.rs index c9495587c4687..2e95a45479c4f 100644 --- a/src/librustc_data_structures/indexed_set.rs +++ b/src/librustc_data_structures/indexed_set.rs @@ -233,18 +233,26 @@ impl IdxSet { &mut self.bits } - pub fn clone_from(&mut self, other: &IdxSet) { + /// Efficiently overwrite `self` with `other`. Panics if `self` and `other` + /// don't have the same length. + pub fn overwrite(&mut self, other: &IdxSet) { self.words_mut().clone_from_slice(other.words()); } + /// Set `self = self | other` and return true if `self` changed + /// (i.e., if new bits were added). pub fn union(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Union) } + /// Set `self = self - other` and return true if `self` changed. + /// (i.e., if any bits were removed). pub fn subtract(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Subtract) } + /// Set `self = self & other` and return true if `self` changed. + /// (i.e., if any bits were removed). pub fn intersect(&mut self, other: &IdxSet) -> bool { bitwise(self.words_mut(), other.words(), &Intersect) } diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index 1fb63afc72fa7..c358f2f852e18 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -14,6 +14,7 @@ use std::slice; use std::marker::PhantomData; use std::ops::{Index, IndexMut, Range, RangeBounds}; use std::fmt; +use std::hash::Hash; use std::vec; use std::u32; @@ -22,9 +23,15 @@ use rustc_serialize as serialize; /// Represents some newtyped `usize` wrapper. /// /// (purpose: avoid mixing indexes for different bitvector domains.) -pub trait Idx: Copy + 'static + Eq + Debug { +pub trait Idx: Copy + 'static + Ord + Debug + Hash { fn new(idx: usize) -> Self; + fn index(self) -> usize; + + fn increment_by(&mut self, amount: usize) { + let v = self.index() + amount; + *self = Self::new(v); + } } impl Idx for usize { @@ -88,6 +95,35 @@ macro_rules! newtype_index { } } + impl ::std::iter::Step for $type { + fn steps_between(start: &Self, end: &Self) -> Option { + ::steps_between( + &Idx::index(*start), + &Idx::index(*end), + ) + } + + fn replace_one(&mut self) -> Self { + ::std::mem::replace(self, Self::new(1)) + } + + fn replace_zero(&mut self) -> Self { + ::std::mem::replace(self, Self::new(0)) + } + + fn add_one(&self) -> Self { + Self::new(Idx::index(*self) + 1) + } + + fn sub_one(&self) -> Self { + Self::new(Idx::index(*self) - 1) + } + + fn add_usize(&self, u: usize) -> Option { + Idx::index(*self).checked_add(u).map(Self::new) + } + } + newtype_index!( @handle_debug @derives [$($derives,)*] @@ -367,6 +403,11 @@ impl IndexVec { IndexVec { raw: Vec::new(), _marker: PhantomData } } + #[inline] + pub fn from_raw(raw: Vec) -> Self { + IndexVec { raw, _marker: PhantomData } + } + #[inline] pub fn with_capacity(capacity: usize) -> Self { IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData } @@ -469,8 +510,8 @@ impl IndexVec { } #[inline] - pub fn swap(&mut self, a: usize, b: usize) { - self.raw.swap(a, b) + pub fn swap(&mut self, a: I, b: I) { + self.raw.swap(a.index(), b.index()) } #[inline] @@ -512,10 +553,28 @@ impl IndexVec { } impl IndexVec { + /// Grows the index vector so that it contains an entry for + /// `elem`; if that is already true, then has no + /// effect. Otherwise, inserts new values as needed by invoking + /// `fill_value`. + #[inline] + pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { + let min_new_len = elem.index() + 1; + if self.len() < min_new_len { + self.raw.resize_with(min_new_len, fill_value); + } + } + #[inline] pub fn resize(&mut self, new_len: usize, value: T) { self.raw.resize(new_len, value) } + + #[inline] + pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) { + let min_new_len = elem.index() + 1; + self.raw.resize_with(min_new_len, fill_value); + } } impl IndexVec { diff --git a/src/librustc_data_structures/lazy_btree_map.rs b/src/librustc_data_structures/lazy_btree_map.rs deleted file mode 100644 index 74f91af10fe63..0000000000000 --- a/src/librustc_data_structures/lazy_btree_map.rs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright 2018 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::collections::btree_map; -use std::collections::BTreeMap; - -/// A thin wrapper around BTreeMap that avoids allocating upon creation. -/// -/// Vec, HashSet and HashMap all have the nice feature that they don't do any -/// heap allocation when creating a new structure of the default size. In -/// contrast, BTreeMap *does* allocate in that situation. The compiler uses -/// B-Tree maps in some places such that many maps are created but few are -/// inserted into, so having a BTreeMap alternative that avoids allocating on -/// creation is a performance win. -/// -/// Only a fraction of BTreeMap's functionality is currently supported. -/// Additional functionality should be added on demand. -#[derive(Debug)] -pub struct LazyBTreeMap(Option>); - -impl LazyBTreeMap { - pub fn new() -> LazyBTreeMap { - LazyBTreeMap(None) - } - - pub fn iter(&self) -> Iter { - Iter(self.0.as_ref().map(|btm| btm.iter())) - } - - pub fn is_empty(&self) -> bool { - self.0.as_ref().map_or(true, |btm| btm.is_empty()) - } -} - -impl LazyBTreeMap { - fn instantiate(&mut self) -> &mut BTreeMap { - if let Some(ref mut btm) = self.0 { - btm - } else { - let btm = BTreeMap::new(); - self.0 = Some(btm); - self.0.as_mut().unwrap() - } - } - - pub fn insert(&mut self, key: K, value: V) -> Option { - self.instantiate().insert(key, value) - } - - pub fn entry(&mut self, key: K) -> btree_map::Entry { - self.instantiate().entry(key) - } - - pub fn values<'a>(&'a self) -> Values<'a, K, V> { - Values(self.0.as_ref().map(|btm| btm.values())) - } -} - -impl Default for LazyBTreeMap { - fn default() -> LazyBTreeMap { - LazyBTreeMap::new() - } -} - -impl<'a, K: 'a, V: 'a> IntoIterator for &'a LazyBTreeMap { - type Item = (&'a K, &'a V); - type IntoIter = Iter<'a, K, V>; - - fn into_iter(self) -> Iter<'a, K, V> { - self.iter() - } -} - -pub struct Iter<'a, K: 'a, V: 'a>(Option>); - -impl<'a, K: 'a, V: 'a> Iterator for Iter<'a, K, V> { - type Item = (&'a K, &'a V); - - fn next(&mut self) -> Option<(&'a K, &'a V)> { - self.0.as_mut().and_then(|iter| iter.next()) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.as_ref().map_or_else(|| (0, Some(0)), |iter| iter.size_hint()) - } -} - -pub struct Values<'a, K: 'a, V: 'a>(Option>); - -impl<'a, K, V> Iterator for Values<'a, K, V> { - type Item = &'a V; - - fn next(&mut self) -> Option<&'a V> { - self.0.as_mut().and_then(|values| values.next()) - } - - fn size_hint(&self) -> (usize, Option) { - self.0.as_ref().map_or_else(|| (0, Some(0)), |values| values.size_hint()) - } -} - diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 597d1627ada03..a9e582e510e78 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -21,7 +21,6 @@ html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(collections_range)] -#![feature(nonzero)] #![feature(unboxed_closures)] #![feature(fn_traits)] #![feature(unsize)] @@ -29,6 +28,7 @@ #![feature(optin_builtin_traits)] #![feature(macro_vis_matcher)] #![feature(allow_internal_unstable)] +#![feature(vec_resize_with)] #![cfg_attr(unix, feature(libc))] #![cfg_attr(test, feature(test))] @@ -44,6 +44,9 @@ extern crate parking_lot; #[macro_use] extern crate cfg_if; extern crate stable_deref_trait; +extern crate rustc_rayon as rayon; +extern crate rustc_rayon_core as rayon_core; +extern crate rustc_hash; // See librustc_cratesio_shim/Cargo.toml for a comment explaining this. #[allow(unused_extern_crates)] @@ -51,32 +54,42 @@ extern crate rustc_cratesio_shim; pub use rustc_serialize::hex::ToHex; -pub mod array_vec; pub mod accumulate_vec; -pub mod small_vec; +pub mod array_vec; pub mod base_n; pub mod bitslice; pub mod bitvec; +pub mod flock; +pub mod fx; pub mod graph; pub mod indexed_set; pub mod indexed_vec; -pub mod lazy_btree_map; pub mod obligation_forest; +pub mod owning_ref; +pub mod ptr_key; pub mod sip128; +pub mod small_vec; pub mod snapshot_map; pub use ena::snapshot_vec; +pub mod sorted_map; pub mod stable_hasher; +pub mod sync; +pub mod tiny_list; pub mod transitive_relation; -pub use ena::unify; -pub mod fx; pub mod tuple_slice; -pub mod control_flow_graph; -pub mod flock; -pub mod sync; -pub mod owning_ref; +pub use ena::unify; +pub mod work_queue; pub struct OnDrop(pub F); +impl OnDrop { + /// Forgets the function which prevents it from running. + /// Ensure that the function owns no memory, otherwise it will be leaked. + pub fn disable(self) { + std::mem::forget(self); + } +} + impl Drop for OnDrop { fn drop(&mut self) { (self.0)(); diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs index 42a17d33fa6f5..0d6cf260dcd98 100644 --- a/src/librustc_data_structures/obligation_forest/mod.rs +++ b/src/librustc_data_structures/obligation_forest/mod.rs @@ -41,7 +41,7 @@ pub trait ObligationProcessor { fn process_obligation(&mut self, obligation: &mut Self::Obligation) - -> Result>, Self::Error>; + -> ProcessResult; /// As we do the cycle check, we invoke this callback when we /// encounter an actual cycle. `cycle` is an iterator that starts @@ -57,6 +57,14 @@ pub trait ObligationProcessor { where I: Clone + Iterator; } +/// The result type used by `process_obligation`. +#[derive(Debug)] +pub enum ProcessResult { + Unchanged, + Changed(Vec), + Error(E), +} + pub struct ObligationForest { /// The list of obligations. In between calls to /// `process_obligations`, this list only contains nodes in the @@ -75,9 +83,6 @@ pub struct ObligationForest { done_cache: FxHashSet, /// An cache of the nodes in `nodes`, indexed by predicate. waiting_cache: FxHashMap, - /// A list of the obligations added in snapshots, to allow - /// for their removal. - cache_list: Vec, scratch: Option>, } @@ -86,13 +91,14 @@ struct Node { obligation: O, state: Cell, - /// Obligations that depend on this obligation for their - /// completion. They must all be in a non-pending state. - dependents: Vec, /// The parent of a node - the original obligation of /// which it is a subobligation. Except for error reporting, - /// this is just another member of `dependents`. + /// it is just like any member of `dependents`. parent: Option, + + /// Obligations that depend on this obligation for their + /// completion. They must all be in a non-pending state. + dependents: Vec, } /// The state of one node in some tree within the forest. This @@ -139,8 +145,8 @@ pub struct Outcome { /// If true, then we saw no successful obligations, which means /// there is no point in further iteration. This is based on the - /// assumption that when trait matching returns `Err` or - /// `Ok(None)`, those results do not affect environmental + /// assumption that when trait matching returns `Error` or + /// `Unchanged`, those results do not affect environmental /// inference state. (Note that if we invoke `process_obligations` /// with no pending obligations, stalled will be true.) pub stalled: bool, @@ -158,7 +164,6 @@ impl ObligationForest { nodes: vec![], done_cache: FxHashSet(), waiting_cache: FxHashMap(), - cache_list: vec![], scratch: Some(vec![]), } } @@ -189,15 +194,18 @@ impl ObligationForest { Entry::Occupied(o) => { debug!("register_obligation_at({:?}, {:?}) - duplicate of {:?}!", obligation, parent, o.get()); + let node = &mut self.nodes[o.get().get()]; if let Some(parent) = parent { - if self.nodes[o.get().get()].dependents.contains(&parent) { - debug!("register_obligation_at({:?}, {:?}) - duplicate subobligation", - obligation, parent); - } else { - self.nodes[o.get().get()].dependents.push(parent); + // If the node is already in `waiting_cache`, it's already + // been marked with a parent. (It's possible that parent + // has been cleared by `apply_rewrites`, though.) So just + // dump `parent` into `node.dependents`... unless it's + // already in `node.dependents` or `node.parent`. + if !node.dependents.contains(&parent) && Some(parent) != node.parent { + node.dependents.push(parent); } } - if let NodeState::Error = self.nodes[o.get().get()].state.get() { + if let NodeState::Error = node.state.get() { Err(()) } else { Ok(()) @@ -207,7 +215,6 @@ impl ObligationForest { debug!("register_obligation_at({:?}, {:?}) - ok, new index is {}", obligation, parent, self.nodes.len()); v.insert(NodeIndex::new(self.nodes.len())); - self.cache_list.push(obligation.as_predicate().clone()); self.nodes.push(Node::new(parent, obligation)); Ok(()) } @@ -234,13 +241,13 @@ impl ObligationForest { } /// Returns the set of obligations that are in a pending state. - pub fn pending_obligations(&self) -> Vec - where O: Clone + pub fn map_pending_obligations(&self, f: F) -> Vec

+ where F: Fn(&O) -> P { self.nodes .iter() .filter(|n| n.state.get() == NodeState::Pending) - .map(|n| n.obligation.clone()) + .map(|n| f(&n.obligation)) .collect() } @@ -275,11 +282,11 @@ impl ObligationForest { result); match result { - Ok(None) => { - // no change in state + ProcessResult::Unchanged => { + // No change in state. } - Ok(Some(children)) => { - // if we saw a Some(_) result, we are not (yet) stalled + ProcessResult::Changed(children) => { + // We are not (yet) stalled. stalled = false; self.nodes[index].state.set(NodeState::Success); @@ -295,7 +302,7 @@ impl ObligationForest { } } } - Err(err) => { + ProcessResult::Error(err) => { stalled = false; let backtrace = self.error_at(index); errors.push(Error { @@ -377,10 +384,7 @@ impl ObligationForest { NodeState::Success => { node.state.set(NodeState::OnDfsStack); stack.push(index); - if let Some(parent) = node.parent { - self.find_cycles_from_node(stack, processor, parent.get()); - } - for dependent in &node.dependents { + for dependent in node.parent.iter().chain(node.dependents.iter()) { self.find_cycles_from_node(stack, processor, dependent.get()); } stack.pop(); @@ -424,7 +428,7 @@ impl ObligationForest { } error_stack.extend( - node.dependents.iter().cloned().chain(node.parent).map(|x| x.get()) + node.parent.iter().chain(node.dependents.iter()).map(|x| x.get()) ); } @@ -434,11 +438,7 @@ impl ObligationForest { #[inline] fn mark_neighbors_as_waiting_from(&self, node: &Node) { - if let Some(parent) = node.parent { - self.mark_as_waiting_from(&self.nodes[parent.get()]); - } - - for dependent in &node.dependents { + for dependent in node.parent.iter().chain(node.dependents.iter()) { self.mark_as_waiting_from(&self.nodes[dependent.get()]); } } @@ -496,9 +496,14 @@ impl ObligationForest { } } NodeState::Done => { - self.waiting_cache.remove(self.nodes[i].obligation.as_predicate()); - // FIXME(HashMap): why can't I get my key back? - self.done_cache.insert(self.nodes[i].obligation.as_predicate().clone()); + // Avoid cloning the key (predicate) in case it exists in the waiting cache + if let Some((predicate, _)) = self.waiting_cache + .remove_entry(self.nodes[i].obligation.as_predicate()) + { + self.done_cache.insert(predicate); + } else { + self.done_cache.insert(self.nodes[i].obligation.as_predicate().clone()); + } node_rewrites[i] = nodes_len; dead_nodes += 1; } @@ -585,8 +590,8 @@ impl Node { fn new(parent: Option, obligation: O) -> Node { Node { obligation, - parent, state: Cell::new(NodeState::Pending), + parent, dependents: vec![], } } diff --git a/src/librustc_data_structures/obligation_forest/node_index.rs b/src/librustc_data_structures/obligation_forest/node_index.rs index 37512e4bcd57f..d89bd22ec9637 100644 --- a/src/librustc_data_structures/obligation_forest/node_index.rs +++ b/src/librustc_data_structures/obligation_forest/node_index.rs @@ -17,11 +17,13 @@ pub struct NodeIndex { } impl NodeIndex { + #[inline] pub fn new(value: usize) -> NodeIndex { assert!(value < (u32::MAX as usize)); NodeIndex { index: NonZeroU32::new((value as u32) + 1).unwrap() } } + #[inline] pub fn get(self) -> usize { (self.index.get() - 1) as usize } diff --git a/src/librustc_data_structures/obligation_forest/test.rs b/src/librustc_data_structures/obligation_forest/test.rs index a95b2b84b34c8..527a1ef0ec441 100644 --- a/src/librustc_data_structures/obligation_forest/test.rs +++ b/src/librustc_data_structures/obligation_forest/test.rs @@ -10,7 +10,7 @@ #![cfg(test)] -use super::{ObligationForest, ObligationProcessor, Outcome, Error}; +use super::{Error, ObligationForest, ObligationProcessor, Outcome, ProcessResult}; use std::fmt; use std::marker::PhantomData; @@ -31,7 +31,7 @@ struct ClosureObligationProcessor { #[allow(non_snake_case)] fn C(of: OF, bf: BF) -> ClosureObligationProcessor - where OF: FnMut(&mut O) -> Result>, &'static str>, + where OF: FnMut(&mut O) -> ProcessResult, BF: FnMut(&[O]) { ClosureObligationProcessor { @@ -44,7 +44,7 @@ fn C(of: OF, bf: BF) -> ClosureObligationProcessor ObligationProcessor for ClosureObligationProcessor where O: super::ForestObligation + fmt::Debug, E: fmt::Debug, - OF: FnMut(&mut O) -> Result>, E>, + OF: FnMut(&mut O) -> ProcessResult, BF: FnMut(&[O]) { type Obligation = O; @@ -52,7 +52,7 @@ impl ObligationProcessor for ClosureObligationProcessor Result>, Self::Error> + -> ProcessResult { (self.process_obligation)(obligation) } @@ -78,9 +78,9 @@ fn push_pop() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), - "B" => Err("B is for broken"), - "C" => Ok(Some(vec![])), + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), + "B" => ProcessResult::Error("B is for broken"), + "C" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_| {})); @@ -101,10 +101,10 @@ fn push_pop() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.1" => Ok(None), - "A.2" => Ok(None), - "A.3" => Ok(Some(vec!["A.3.i"])), - "D" => Ok(Some(vec!["D.1", "D.2"])), + "A.1" => ProcessResult::Unchanged, + "A.2" => ProcessResult::Unchanged, + "A.3" => ProcessResult::Changed(vec!["A.3.i"]), + "D" => ProcessResult::Changed(vec!["D.1", "D.2"]), _ => unreachable!(), } }, |_| {})); @@ -119,11 +119,11 @@ fn push_pop() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.1" => Ok(Some(vec![])), - "A.2" => Err("A is for apple"), - "A.3.i" => Ok(Some(vec![])), - "D.1" => Ok(Some(vec!["D.1.i"])), - "D.2" => Ok(Some(vec!["D.2.i"])), + "A.1" => ProcessResult::Changed(vec![]), + "A.2" => ProcessResult::Error("A is for apple"), + "A.3.i" => ProcessResult::Changed(vec![]), + "D.1" => ProcessResult::Changed(vec!["D.1.i"]), + "D.2" => ProcessResult::Changed(vec!["D.2.i"]), _ => unreachable!(), } }, |_| {})); @@ -138,8 +138,8 @@ fn push_pop() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D.1.i" => Err("D is for dumb"), - "D.2.i" => Ok(Some(vec![])), + "D.1.i" => ProcessResult::Error("D is for dumb"), + "D.2.i" => ProcessResult::Changed(vec![]), _ => panic!("unexpected obligation {:?}", obligation), } }, |_| {})); @@ -167,7 +167,7 @@ fn success_in_grandchildren() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), _ => unreachable!(), } }, |_| {})); @@ -177,9 +177,9 @@ fn success_in_grandchildren() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.1" => Ok(Some(vec![])), - "A.2" => Ok(Some(vec!["A.2.i", "A.2.ii"])), - "A.3" => Ok(Some(vec![])), + "A.1" => ProcessResult::Changed(vec![]), + "A.2" => ProcessResult::Changed(vec!["A.2.i", "A.2.ii"]), + "A.3" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_| {})); @@ -189,8 +189,8 @@ fn success_in_grandchildren() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.2.i" => Ok(Some(vec!["A.2.i.a"])), - "A.2.ii" => Ok(Some(vec![])), + "A.2.i" => ProcessResult::Changed(vec!["A.2.i.a"]), + "A.2.ii" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_| {})); @@ -200,7 +200,7 @@ fn success_in_grandchildren() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.2.i.a" => Ok(Some(vec![])), + "A.2.i.a" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_| {})); @@ -223,7 +223,7 @@ fn to_errors_no_throw() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2", "A.3"])), + "A" => ProcessResult::Changed(vec!["A.1", "A.2", "A.3"]), _ => unreachable!(), } }, |_|{})); @@ -244,7 +244,7 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["A.1", "A.2"])), + "A" => ProcessResult::Changed(vec!["A.1", "A.2"]), _ => unreachable!(), } }, |_|{})); @@ -254,8 +254,8 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A.1" => Ok(Some(vec!["D"])), - "A.2" => Ok(Some(vec!["D"])), + "A.1" => ProcessResult::Changed(vec!["D"]), + "A.2" => ProcessResult::Changed(vec!["D"]), _ => unreachable!(), } }, |_|{})); @@ -266,7 +266,7 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D" => { d_count += 1; Ok(Some(vec![])) }, + "D" => { d_count += 1; ProcessResult::Changed(vec![]) }, _ => unreachable!(), } }, |_|{})); @@ -281,7 +281,7 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A'" => Ok(Some(vec!["A'.1", "A'.2"])), + "A'" => ProcessResult::Changed(vec!["A'.1", "A'.2"]), _ => unreachable!(), } }, |_|{})); @@ -291,8 +291,8 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A'.1" => Ok(Some(vec!["D'", "A'"])), - "A'.2" => Ok(Some(vec!["D'"])), + "A'.1" => ProcessResult::Changed(vec!["D'", "A'"]), + "A'.2" => ProcessResult::Changed(vec!["D'"]), _ => unreachable!(), } }, |_|{})); @@ -303,7 +303,7 @@ fn diamond() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D'" => { d_count += 1; Err("operation failed") }, + "D'" => { d_count += 1; ProcessResult::Error("operation failed") }, _ => unreachable!(), } }, |_|{})); @@ -329,7 +329,7 @@ fn done_dependency() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A: Sized" | "B: Sized" | "C: Sized" => Ok(Some(vec![])), + "A: Sized" | "B: Sized" | "C: Sized" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_|{})); @@ -340,11 +340,11 @@ fn done_dependency() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "(A,B,C): Sized" => Ok(Some(vec![ + "(A,B,C): Sized" => ProcessResult::Changed(vec![ "A: Sized", "B: Sized", "C: Sized" - ])), + ]), _ => unreachable!(), } }, |_|{})); @@ -367,10 +367,10 @@ fn orphan() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Ok(Some(vec!["D", "E"])), - "B" => Ok(None), - "C1" => Ok(Some(vec![])), - "C2" => Ok(Some(vec![])), + "A" => ProcessResult::Changed(vec!["D", "E"]), + "B" => ProcessResult::Unchanged, + "C1" => ProcessResult::Changed(vec![]), + "C2" => ProcessResult::Changed(vec![]), _ => unreachable!(), } }, |_|{})); @@ -380,8 +380,8 @@ fn orphan() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D" | "E" => Ok(None), - "B" => Ok(Some(vec!["D"])), + "D" | "E" => ProcessResult::Unchanged, + "B" => ProcessResult::Changed(vec!["D"]), _ => unreachable!(), } }, |_|{})); @@ -391,8 +391,8 @@ fn orphan() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D" => Ok(None), - "E" => Err("E is for error"), + "D" => ProcessResult::Unchanged, + "E" => ProcessResult::Error("E is for error"), _ => unreachable!(), } }, |_|{})); @@ -405,7 +405,7 @@ fn orphan() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "D" => Err("D is dead"), + "D" => ProcessResult::Error("D is dead"), _ => unreachable!(), } }, |_|{})); @@ -429,8 +429,8 @@ fn simultaneous_register_and_error() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Err("An error"), - "B" => Ok(Some(vec!["A"])), + "A" => ProcessResult::Error("An error"), + "B" => ProcessResult::Changed(vec!["A"]), _ => unreachable!(), } }, |_|{})); @@ -447,8 +447,8 @@ fn simultaneous_register_and_error() { let Outcome { completed: ok, errors: err, .. } = forest.process_obligations(&mut C(|obligation| { match *obligation { - "A" => Err("An error"), - "B" => Ok(Some(vec!["A"])), + "A" => ProcessResult::Error("An error"), + "B" => ProcessResult::Changed(vec!["A"]), _ => unreachable!(), } }, |_|{})); diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/src/librustc_data_structures/owning_ref/mod.rs index c466b8f8ad1b5..02640a71010e2 100644 --- a/src/librustc_data_structures/owning_ref/mod.rs +++ b/src/librustc_data_structures/owning_ref/mod.rs @@ -1002,7 +1002,7 @@ impl Debug for OwningRef where O: Debug, T: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "OwningRef {{ owner: {:?}, reference: {:?} }}", self.owner(), @@ -1014,7 +1014,7 @@ impl Debug for OwningRefMut where O: Debug, T: Debug, { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "OwningRefMut {{ owner: {:?}, reference: {:?} }}", self.owner(), @@ -1046,8 +1046,8 @@ unsafe impl Send for OwningRefMut unsafe impl Sync for OwningRefMut where O: Sync, for<'a> (&'a mut T): Sync {} -impl Debug for Erased { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { +impl Debug for dyn Erased { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "",) } } @@ -1166,35 +1166,35 @@ pub type MutexGuardRefMut<'a, T, U = T> = OwningRefMut, U>; pub type RwLockWriteGuardRefMut<'a, T, U = T> = OwningRef, U>; unsafe impl<'a, T: 'a> IntoErased<'a> for Box { - type Erased = Box; + type Erased = Box; fn into_erased(self) -> Self::Erased { self } } unsafe impl<'a, T: 'a> IntoErased<'a> for Rc { - type Erased = Rc; + type Erased = Rc; fn into_erased(self) -> Self::Erased { self } } unsafe impl<'a, T: 'a> IntoErased<'a> for Arc { - type Erased = Arc; + type Erased = Arc; fn into_erased(self) -> Self::Erased { self } } unsafe impl<'a, T: Send + 'a> IntoErasedSend<'a> for Box { - type Erased = Box; + type Erased = Box; fn into_erased_send(self) -> Self::Erased { self } } unsafe impl<'a, T: Send + 'a> IntoErasedSendSync<'a> for Box { - type Erased = Box; + type Erased = Box; fn into_erased_send_sync(self) -> Self::Erased { - let result: Box = self; + let result: Box = self; // This is safe since Erased can always implement Sync // Only the destructor is available and it takes &mut self unsafe { @@ -1204,21 +1204,21 @@ unsafe impl<'a, T: Send + 'a> IntoErasedSendSync<'a> for Box { } unsafe impl<'a, T: Send + Sync + 'a> IntoErasedSendSync<'a> for Arc { - type Erased = Arc; + type Erased = Arc; fn into_erased_send_sync(self) -> Self::Erased { self } } /// Typedef of a owning reference that uses an erased `Box` as the owner. -pub type ErasedBoxRef = OwningRef, U>; +pub type ErasedBoxRef = OwningRef, U>; /// Typedef of a owning reference that uses an erased `Rc` as the owner. -pub type ErasedRcRef = OwningRef, U>; +pub type ErasedRcRef = OwningRef, U>; /// Typedef of a owning reference that uses an erased `Arc` as the owner. -pub type ErasedArcRef = OwningRef, U>; +pub type ErasedArcRef = OwningRef, U>; /// Typedef of a mutable owning reference that uses an erased `Box` as the owner. -pub type ErasedBoxRefMut = OwningRefMut, U>; +pub type ErasedBoxRefMut = OwningRefMut, U>; #[cfg(test)] mod tests { @@ -1443,8 +1443,8 @@ mod tests { let c: OwningRef>, [u8]> = unsafe {a.map_owner(Rc::new)}; let d: OwningRef>, [u8]> = unsafe {b.map_owner(Rc::new)}; - let e: OwningRef, [u8]> = c.erase_owner(); - let f: OwningRef, [u8]> = d.erase_owner(); + let e: OwningRef, [u8]> = c.erase_owner(); + let f: OwningRef, [u8]> = d.erase_owner(); let _g = e.clone(); let _h = f.clone(); @@ -1460,8 +1460,8 @@ mod tests { let c: OwningRef>, [u8]> = a.map_owner_box(); let d: OwningRef>, [u8]> = b.map_owner_box(); - let _e: OwningRef, [u8]> = c.erase_owner(); - let _f: OwningRef, [u8]> = d.erase_owner(); + let _e: OwningRef, [u8]> = c.erase_owner(); + let _f: OwningRef, [u8]> = d.erase_owner(); } #[test] @@ -1469,7 +1469,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok(); } @@ -1479,7 +1479,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRef::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err(); } @@ -1843,8 +1843,8 @@ mod tests { let c: OwningRefMut>, [u8]> = unsafe {a.map_owner(Box::new)}; let d: OwningRefMut>, [u8]> = unsafe {b.map_owner(Box::new)}; - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); + let _e: OwningRefMut, [u8]> = c.erase_owner(); + let _f: OwningRefMut, [u8]> = d.erase_owner(); } #[test] @@ -1857,8 +1857,8 @@ mod tests { let c: OwningRefMut>, [u8]> = a.map_owner_box(); let d: OwningRefMut>, [u8]> = b.map_owner_box(); - let _e: OwningRefMut, [u8]> = c.erase_owner(); - let _f: OwningRefMut, [u8]> = d.erase_owner(); + let _e: OwningRefMut, [u8]> = c.erase_owner(); + let _f: OwningRefMut, [u8]> = d.erase_owner(); } #[test] @@ -1866,7 +1866,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_ok(); } @@ -1876,7 +1876,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRefMut::new(y).try_map_mut(|x| x.downcast_mut::().ok_or(())).is_err(); } @@ -1886,7 +1886,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_ok(); } @@ -1896,7 +1896,7 @@ mod tests { use std::any::Any; let x = Box::new(123_i32); - let y: Box = x; + let y: Box = x; OwningRefMut::new(y).try_map(|x| x.downcast_ref::().ok_or(())).is_err(); } diff --git a/src/librustc_data_structures/ptr_key.rs b/src/librustc_data_structures/ptr_key.rs new file mode 100644 index 0000000000000..6835dab38df0a --- /dev/null +++ b/src/librustc_data_structures/ptr_key.rs @@ -0,0 +1,45 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::{hash, ptr}; +use std::ops::Deref; + +/// A wrapper around reference that compares and hashes like a pointer. +/// Can be used as a key in sets/maps indexed by pointers to avoid `unsafe`. +#[derive(Debug)] +pub struct PtrKey<'a, T: 'a>(pub &'a T); + +impl<'a, T> Clone for PtrKey<'a, T> { + fn clone(&self) -> Self { *self } +} + +impl<'a, T> Copy for PtrKey<'a, T> {} + +impl<'a, T> PartialEq for PtrKey<'a, T> { + fn eq(&self, rhs: &Self) -> bool { + ptr::eq(self.0, rhs.0) + } +} + +impl<'a, T> Eq for PtrKey<'a, T> {} + +impl<'a, T> hash::Hash for PtrKey<'a, T> { + fn hash(&self, hasher: &mut H) { + (self.0 as *const T).hash(hasher) + } +} + +impl<'a, T> Deref for PtrKey<'a, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + self.0 + } +} diff --git a/src/librustc_data_structures/small_vec.rs b/src/librustc_data_structures/small_vec.rs index 74738e61b4467..83eb54fade177 100644 --- a/src/librustc_data_structures/small_vec.rs +++ b/src/librustc_data_structures/small_vec.rs @@ -50,6 +50,10 @@ impl SmallVec { SmallVec(AccumulateVec::new()) } + pub fn is_array(&self) -> bool { + self.0.is_array() + } + pub fn with_capacity(cap: usize) -> Self { let mut vec = SmallVec::new(); vec.reserve(cap); diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/src/librustc_data_structures/snapshot_map/mod.rs index cede6f147821b..6ee8c3579f543 100644 --- a/src/librustc_data_structures/snapshot_map/mod.rs +++ b/src/librustc_data_structures/snapshot_map/mod.rs @@ -67,6 +67,12 @@ impl SnapshotMap } } + pub fn insert_noop(&mut self) { + if !self.undo_log.is_empty() { + self.undo_log.push(UndoLog::Noop); + } + } + pub fn remove(&mut self, key: K) -> bool { match self.map.remove(&key) { Some(old_value) => { diff --git a/src/librustc_data_structures/sorted_map.rs b/src/librustc_data_structures/sorted_map.rs new file mode 100644 index 0000000000000..92b0bffd7529b --- /dev/null +++ b/src/librustc_data_structures/sorted_map.rs @@ -0,0 +1,489 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::borrow::Borrow; +use std::cmp::Ordering; +use std::convert::From; +use std::mem; +use std::ops::{RangeBounds, Bound, Index, IndexMut}; + +/// `SortedMap` is a data structure with similar characteristics as BTreeMap but +/// slightly different trade-offs: lookup, inseration, and removal are O(log(N)) +/// and elements can be iterated in order cheaply. +/// +/// `SortedMap` can be faster than a `BTreeMap` for small sizes (<50) since it +/// stores data in a more compact way. It also supports accessing contiguous +/// ranges of elements as a slice, and slices of already sorted elements can be +/// inserted efficiently. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug, RustcEncodable, + RustcDecodable)] +pub struct SortedMap { + data: Vec<(K,V)> +} + +impl SortedMap { + + #[inline] + pub fn new() -> SortedMap { + SortedMap { + data: vec![] + } + } + + /// Construct a `SortedMap` from a presorted set of elements. This is faster + /// than creating an empty map and then inserting the elements individually. + /// + /// It is up to the caller to make sure that the elements are sorted by key + /// and that there are no duplicates. + #[inline] + pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap + { + debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + + SortedMap { + data: elements + } + } + + #[inline] + pub fn insert(&mut self, key: K, mut value: V) -> Option { + match self.lookup_index_for(&key) { + Ok(index) => { + let mut slot = unsafe { + self.data.get_unchecked_mut(index) + }; + mem::swap(&mut slot.1, &mut value); + Some(value) + } + Err(index) => { + self.data.insert(index, (key, value)); + None + } + } + } + + #[inline] + pub fn remove(&mut self, key: &K) -> Option { + match self.lookup_index_for(key) { + Ok(index) => { + Some(self.data.remove(index).1) + } + Err(_) => { + None + } + } + } + + #[inline] + pub fn get(&self, key: &K) -> Option<&V> { + match self.lookup_index_for(key) { + Ok(index) => { + unsafe { + Some(&self.data.get_unchecked(index).1) + } + } + Err(_) => { + None + } + } + } + + #[inline] + pub fn get_mut(&mut self, key: &K) -> Option<&mut V> { + match self.lookup_index_for(key) { + Ok(index) => { + unsafe { + Some(&mut self.data.get_unchecked_mut(index).1) + } + } + Err(_) => { + None + } + } + } + + #[inline] + pub fn clear(&mut self) { + self.data.clear(); + } + + /// Iterate over elements, sorted by key + #[inline] + pub fn iter(&self) -> ::std::slice::Iter<(K, V)> { + self.data.iter() + } + + /// Iterate over the keys, sorted + #[inline] + pub fn keys(&self) -> impl Iterator + ExactSizeIterator { + self.data.iter().map(|&(ref k, _)| k) + } + + /// Iterate over values, sorted by key + #[inline] + pub fn values(&self) -> impl Iterator + ExactSizeIterator { + self.data.iter().map(|&(_, ref v)| v) + } + + #[inline] + pub fn len(&self) -> usize { + self.data.len() + } + + #[inline] + pub fn range(&self, range: R) -> &[(K, V)] + where R: RangeBounds + { + let (start, end) = self.range_slice_indices(range); + (&self.data[start .. end]) + } + + #[inline] + pub fn remove_range(&mut self, range: R) + where R: RangeBounds + { + let (start, end) = self.range_slice_indices(range); + self.data.splice(start .. end, ::std::iter::empty()); + } + + /// Mutate all keys with the given function `f`. This mutation must not + /// change the sort-order of keys. + #[inline] + pub fn offset_keys(&mut self, f: F) + where F: Fn(&mut K) + { + self.data.iter_mut().map(|&mut (ref mut k, _)| k).for_each(f); + } + + /// Inserts a presorted range of elements into the map. If the range can be + /// inserted as a whole in between to existing elements of the map, this + /// will be faster than inserting the elements individually. + /// + /// It is up to the caller to make sure that the elements are sorted by key + /// and that there are no duplicates. + #[inline] + pub fn insert_presorted(&mut self, mut elements: Vec<(K, V)>) { + if elements.is_empty() { + return + } + + debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + + let start_index = self.lookup_index_for(&elements[0].0); + + let drain = match start_index { + Ok(index) => { + let mut drain = elements.drain(..); + self.data[index] = drain.next().unwrap(); + drain + } + Err(index) => { + if index == self.data.len() || + elements.last().unwrap().0 < self.data[index].0 { + // We can copy the whole range without having to mix with + // existing elements. + self.data.splice(index .. index, elements.drain(..)); + return + } + + let mut drain = elements.drain(..); + self.data.insert(index, drain.next().unwrap()); + drain + } + }; + + // Insert the rest + for (k, v) in drain { + self.insert(k, v); + } + } + + /// Looks up the key in `self.data` via `slice::binary_search()`. + #[inline(always)] + fn lookup_index_for(&self, key: &K) -> Result { + self.data.binary_search_by(|&(ref x, _)| x.cmp(key)) + } + + #[inline] + fn range_slice_indices(&self, range: R) -> (usize, usize) + where R: RangeBounds + { + let start = match range.start_bound() { + Bound::Included(ref k) => { + match self.lookup_index_for(k) { + Ok(index) | Err(index) => index + } + } + Bound::Excluded(ref k) => { + match self.lookup_index_for(k) { + Ok(index) => index + 1, + Err(index) => index, + } + } + Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + Bound::Included(ref k) => { + match self.lookup_index_for(k) { + Ok(index) => index + 1, + Err(index) => index, + } + } + Bound::Excluded(ref k) => { + match self.lookup_index_for(k) { + Ok(index) | Err(index) => index, + } + } + Bound::Unbounded => self.data.len(), + }; + + (start, end) + } +} + +impl IntoIterator for SortedMap { + type Item = (K, V); + type IntoIter = ::std::vec::IntoIter<(K, V)>; + fn into_iter(self) -> Self::IntoIter { + self.data.into_iter() + } +} + +impl> Index for SortedMap { + type Output = V; + fn index(&self, index: Q) -> &Self::Output { + let k: &K = index.borrow(); + self.get(k).unwrap() + } +} + +impl> IndexMut for SortedMap { + fn index_mut(&mut self, index: Q) -> &mut Self::Output { + let k: &K = index.borrow(); + self.get_mut(k).unwrap() + } +} + +impl> From for SortedMap { + fn from(data: I) -> Self { + let mut data: Vec<(K, V)> = data.collect(); + data.sort_unstable_by(|&(ref k1, _), &(ref k2, _)| k1.cmp(k2)); + data.dedup_by(|&mut (ref k1, _), &mut (ref k2, _)| { + k1.cmp(k2) == Ordering::Equal + }); + SortedMap { + data + } + } +} + +#[cfg(test)] +mod tests { + use super::SortedMap; + + #[test] + fn test_insert_and_iter() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0 .. 100 { + assert_eq!(map.iter().cloned().collect::>(), expected); + + let x = 1000 - x * 2; + map.insert(x, x); + expected.insert(0, (x, x)); + } + } + + #[test] + fn test_get_and_index() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0 .. 100 { + let x = 1000 - x; + if x & 1 == 0 { + map.insert(x, x); + } + expected.push(x); + } + + for mut x in expected { + if x & 1 == 0 { + assert_eq!(map.get(&x), Some(&x)); + assert_eq!(map.get_mut(&x), Some(&mut x)); + assert_eq!(map[&x], x); + assert_eq!(&mut map[&x], &mut x); + } else { + assert_eq!(map.get(&x), None); + assert_eq!(map.get_mut(&x), None); + } + } + } + + #[test] + fn test_range() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + map.insert(9, 9); + + let keys = |s: &[(_, _)]| { + s.into_iter().map(|e| e.0).collect::>() + }; + + for start in 0 .. 11 { + for end in 0 .. 11 { + if end < start { + continue + } + + let mut expected = vec![1, 3, 6, 9]; + expected.retain(|&x| x >= start && x < end); + + assert_eq!(keys(map.range(start..end)), expected, "range = {}..{}", start, end); + } + } + } + + + #[test] + fn test_offset_keys() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + + map.offset_keys(|k| *k += 1); + + let mut expected = SortedMap::new(); + expected.insert(2, 1); + expected.insert(4, 3); + expected.insert(7, 6); + + assert_eq!(map, expected); + } + + fn keys(s: SortedMap) -> Vec { + s.into_iter().map(|(k, _)| k).collect::>() + } + + fn elements(s: SortedMap) -> Vec<(u32, u32)> { + s.into_iter().collect::>() + } + + #[test] + fn test_remove_range() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(3, 3); + map.insert(6, 6); + map.insert(9, 9); + + for start in 0 .. 11 { + for end in 0 .. 11 { + if end < start { + continue + } + + let mut expected = vec![1, 3, 6, 9]; + expected.retain(|&x| x < start || x >= end); + + let mut map = map.clone(); + map.remove_range(start .. end); + + assert_eq!(keys(map), expected, "range = {}..{}", start, end); + } + } + } + + #[test] + fn test_remove() { + let mut map = SortedMap::new(); + let mut expected = Vec::new(); + + for x in 0..10 { + map.insert(x, x); + expected.push((x, x)); + } + + for x in 0 .. 10 { + let mut map = map.clone(); + let mut expected = expected.clone(); + + assert_eq!(map.remove(&x), Some(x)); + expected.remove(x as usize); + + assert_eq!(map.iter().cloned().collect::>(), expected); + } + } + + #[test] + fn test_insert_presorted_non_overlapping() { + let mut map = SortedMap::new(); + map.insert(2, 0); + map.insert(8, 0); + + map.insert_presorted(vec![(3, 0), (7, 0)]); + + let expected = vec![2, 3, 7, 8]; + assert_eq!(keys(map), expected); + } + + #[test] + fn test_insert_presorted_first_elem_equal() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(8, 8); + + map.insert_presorted(vec![(2, 0), (7, 7)]); + + let expected = vec![(2, 0), (7, 7), (8, 8)]; + assert_eq!(elements(map), expected); + } + + #[test] + fn test_insert_presorted_last_elem_equal() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(8, 8); + + map.insert_presorted(vec![(3, 3), (8, 0)]); + + let expected = vec![(2, 2), (3, 3), (8, 0)]; + assert_eq!(elements(map), expected); + } + + #[test] + fn test_insert_presorted_shuffle() { + let mut map = SortedMap::new(); + map.insert(2, 2); + map.insert(7, 7); + + map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]); + + let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)]; + assert_eq!(elements(map), expected); + } + + #[test] + fn test_insert_presorted_at_end() { + let mut map = SortedMap::new(); + map.insert(1, 1); + map.insert(2, 2); + + map.insert_presorted(vec![(3, 3), (8, 8)]); + + let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)]; + assert_eq!(elements(map), expected); + } +} diff --git a/src/librustc_data_structures/sync.rs b/src/librustc_data_structures/sync.rs index 3b7d6efbdae1e..d4c6b1c2ced81 100644 --- a/src/librustc_data_structures/sync.rs +++ b/src/librustc_data_structures/sync.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! This mdoule defines types which are thread safe if cfg!(parallel_queries) is true. +//! This module defines types which are thread safe if cfg!(parallel_queries) is true. //! //! `Lrc` is an alias of either Rc or Arc. //! @@ -26,6 +26,8 @@ //! //! `MTLock` is a mutex which disappears if cfg!(parallel_queries) is false. //! +//! `MTRef` is a immutable refernce if cfg!(parallel_queries), and an mutable reference otherwise. +//! //! `rustc_erase_owner!` erases a OwningRef owner into Erased or Erased + Send + Sync //! depending on the value of cfg!(parallel_queries). @@ -36,10 +38,32 @@ use std::marker::PhantomData; use std::fmt::Debug; use std::fmt::Formatter; use std::fmt; -use std; use std::ops::{Deref, DerefMut}; use owning_ref::{Erased, OwningRef}; +pub fn serial_join(oper_a: A, oper_b: B) -> (RA, RB) + where A: FnOnce() -> RA, + B: FnOnce() -> RB +{ + (oper_a(), oper_b()) +} + +pub struct SerialScope; + +impl SerialScope { + pub fn spawn(&self, f: F) + where F: FnOnce(&SerialScope) + { + f(self) + } +} + +pub fn serial_scope(f: F) -> R + where F: FnOnce(&SerialScope) -> R +{ + f(&SerialScope) +} + cfg_if! { if #[cfg(not(parallel_queries))] { pub auto trait Send {} @@ -55,9 +79,19 @@ cfg_if! { } } - pub type MetadataRef = OwningRef, [u8]>; + pub use self::serial_join as join; + pub use self::serial_scope as scope; + + pub use std::iter::Iterator as ParallelIterator; + + pub fn par_iter(t: T) -> T::IntoIter { + t.into_iter() + } + + pub type MetadataRef = OwningRef, [u8]>; pub use std::rc::Rc as Lrc; + pub use std::rc::Weak as Weak; pub use std::cell::Ref as ReadGuard; pub use std::cell::RefMut as WriteGuard; pub use std::cell::RefMut as LockGuard; @@ -67,6 +101,35 @@ cfg_if! { use std::cell::Cell; + #[derive(Debug)] + pub struct WorkerLocal(OneThread); + + impl WorkerLocal { + /// Creates a new worker local where the `initial` closure computes the + /// value this worker local should take for each thread in the thread pool. + #[inline] + pub fn new T>(mut f: F) -> WorkerLocal { + WorkerLocal(OneThread::new(f(0))) + } + + /// Returns the worker-local value for each thread + #[inline] + pub fn into_inner(self) -> Vec { + vec![OneThread::into_inner(self.0)] + } + } + + impl Deref for WorkerLocal { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &*self.0 + } + } + + pub type MTRef<'a, T> = &'a mut T; + #[derive(Debug)] pub struct MTLock(T); @@ -92,13 +155,8 @@ cfg_if! { } #[inline(always)] - pub fn borrow(&self) -> &T { - &self.0 - } - - #[inline(always)] - pub fn borrow_mut(&self) -> &T { - &self.0 + pub fn lock_mut(&mut self) -> &mut T { + &mut self.0 } } @@ -160,15 +218,57 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; pub use std::sync::Arc as Lrc; + pub use std::sync::Weak as Weak; - pub use self::Lock as MTLock; + pub type MTRef<'a, T> = &'a T; + + #[derive(Debug)] + pub struct MTLock(Lock); + + impl MTLock { + #[inline(always)] + pub fn new(inner: T) -> Self { + MTLock(Lock::new(inner)) + } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0.into_inner() + } + + #[inline(always)] + pub fn get_mut(&mut self) -> &mut T { + self.0.get_mut() + } + + #[inline(always)] + pub fn lock(&self) -> LockGuard { + self.0.lock() + } + + #[inline(always)] + pub fn lock_mut(&self) -> LockGuard { + self.lock() + } + } use parking_lot::Mutex as InnerLock; use parking_lot::RwLock as InnerRwLock; + use std; use std::thread; + pub use rayon::{join, scope}; + + pub use rayon_core::WorkerLocal; + + pub use rayon::iter::ParallelIterator; + use rayon::iter::IntoParallelIterator; + + pub fn par_iter(t: T) -> T::Iter { + t.into_par_iter() + } - pub type MetadataRef = OwningRef, [u8]>; + pub type MetadataRef = OwningRef, [u8]>; /// This makes locks panic if they are already held. /// It is only useful when you are running in a single thread @@ -448,6 +548,18 @@ impl Lock { self.0.get_mut() } + #[cfg(parallel_queries)] + #[inline(always)] + pub fn try_lock(&self) -> Option> { + self.0.try_lock() + } + + #[cfg(not(parallel_queries))] + #[inline(always)] + pub fn try_lock(&self) -> Option> { + self.0.try_borrow_mut().ok() + } + #[cfg(parallel_queries)] #[inline(always)] pub fn lock(&self) -> LockGuard { @@ -596,7 +708,9 @@ pub struct OneThread { inner: T, } +#[cfg(parallel_queries)] unsafe impl std::marker::Sync for OneThread {} +#[cfg(parallel_queries)] unsafe impl std::marker::Send for OneThread {} impl OneThread { diff --git a/src/librustc_data_structures/tiny_list.rs b/src/librustc_data_structures/tiny_list.rs new file mode 100644 index 0000000000000..5b1b2aadec563 --- /dev/null +++ b/src/librustc_data_structures/tiny_list.rs @@ -0,0 +1,251 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + + +//! A singly-linked list. +//! +//! Using this data structure only makes sense under very specific +//! circumstances: +//! +//! - If you have a list that rarely stores more than one element, then this +//! data-structure can store the element without allocating and only uses as +//! much space as a `Option<(T, usize)>`. If T can double as the `Option` +//! discriminant, it will even only be as large as `T, usize`. +//! +//! If you expect to store more than 1 element in the common case, steer clear +//! and use a `Vec`, `Box<[T]>`, or a `SmallVec`. + +use std::mem; + +#[derive(Clone, Hash, Debug, PartialEq)] +pub struct TinyList { + head: Option> +} + +impl TinyList { + + #[inline] + pub fn new() -> TinyList { + TinyList { + head: None + } + } + + #[inline] + pub fn new_single(data: T) -> TinyList { + TinyList { + head: Some(Element { + data, + next: None, + }) + } + } + + #[inline] + pub fn insert(&mut self, data: T) { + let current_head = mem::replace(&mut self.head, None); + + if let Some(current_head) = current_head { + let current_head = Box::new(current_head); + self.head = Some(Element { + data, + next: Some(current_head) + }); + } else { + self.head = Some(Element { + data, + next: None, + }) + } + } + + #[inline] + pub fn remove(&mut self, data: &T) -> bool { + let remove_head = if let Some(ref mut head) = self.head { + if head.data == *data { + Some(mem::replace(&mut head.next, None)) + } else { + None + } + } else { + return false + }; + + if let Some(remove_head) = remove_head { + if let Some(next) = remove_head { + self.head = Some(*next); + } else { + self.head = None; + } + return true + } + + self.head.as_mut().unwrap().remove_next(data) + } + + #[inline] + pub fn contains(&self, data: &T) -> bool { + if let Some(ref head) = self.head { + head.contains(data) + } else { + false + } + } + + #[inline] + pub fn len(&self) -> usize { + if let Some(ref head) = self.head { + head.len() + } else { + 0 + } + } +} + +#[derive(Clone, Hash, Debug, PartialEq)] +struct Element { + data: T, + next: Option>>, +} + +impl Element { + + fn remove_next(&mut self, data: &T) -> bool { + let new_next = if let Some(ref mut next) = self.next { + if next.data != *data { + return next.remove_next(data) + } else { + mem::replace(&mut next.next, None) + } + } else { + return false + }; + + self.next = new_next; + return true + } + + fn len(&self) -> usize { + if let Some(ref next) = self.next { + 1 + next.len() + } else { + 1 + } + } + + fn contains(&self, data: &T) -> bool { + if self.data == *data { + return true + } + + if let Some(ref next) = self.next { + next.contains(data) + } else { + false + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_contains_and_insert() { + fn do_insert(i : u32) -> bool { + i % 2 == 0 + } + + let mut list = TinyList::new(); + + for i in 0 .. 10 { + for j in 0 .. i { + if do_insert(j) { + assert!(list.contains(&j)); + } else { + assert!(!list.contains(&j)); + } + } + + assert!(!list.contains(&i)); + + if do_insert(i) { + list.insert(i); + assert!(list.contains(&i)); + } + } + } + + #[test] + fn test_remove_first() { + let mut list = TinyList::new(); + list.insert(1); + list.insert(2); + list.insert(3); + list.insert(4); + assert_eq!(list.len(), 4); + + assert!(list.remove(&4)); + assert!(!list.contains(&4)); + + assert_eq!(list.len(), 3); + assert!(list.contains(&1)); + assert!(list.contains(&2)); + assert!(list.contains(&3)); + } + + #[test] + fn test_remove_last() { + let mut list = TinyList::new(); + list.insert(1); + list.insert(2); + list.insert(3); + list.insert(4); + assert_eq!(list.len(), 4); + + assert!(list.remove(&1)); + assert!(!list.contains(&1)); + + assert_eq!(list.len(), 3); + assert!(list.contains(&2)); + assert!(list.contains(&3)); + assert!(list.contains(&4)); + } + + #[test] + fn test_remove_middle() { + let mut list = TinyList::new(); + list.insert(1); + list.insert(2); + list.insert(3); + list.insert(4); + assert_eq!(list.len(), 4); + + assert!(list.remove(&2)); + assert!(!list.contains(&2)); + + assert_eq!(list.len(), 3); + assert!(list.contains(&1)); + assert!(list.contains(&3)); + assert!(list.contains(&4)); + } + + #[test] + fn test_remove_single() { + let mut list = TinyList::new(); + list.insert(1); + assert_eq!(list.len(), 1); + + assert!(list.remove(&1)); + assert!(!list.contains(&1)); + + assert_eq!(list.len(), 0); + } +} diff --git a/src/librustc_data_structures/transitive_relation.rs b/src/librustc_data_structures/transitive_relation.rs index 6d63bc4436fe8..a8124fb7c5b62 100644 --- a/src/librustc_data_structures/transitive_relation.rs +++ b/src/librustc_data_structures/transitive_relation.rs @@ -39,7 +39,7 @@ pub struct TransitiveRelation { // are added with new elements. Perhaps better would be to ask the // user for a batch of edges to minimize this effect, but I // already wrote the code this way. :P -nmatsakis - closure: Lock>, + closure: Lock>>, } #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, Debug)] @@ -354,7 +354,7 @@ impl TransitiveRelation { } fn with_closure(&self, op: OP) -> R - where OP: FnOnce(&BitMatrix) -> R + where OP: FnOnce(&BitMatrix) -> R { let mut closure_cell = self.closure.borrow_mut(); let mut closure = closure_cell.take(); @@ -366,7 +366,7 @@ impl TransitiveRelation { result } - fn compute_closure(&self) -> BitMatrix { + fn compute_closure(&self) -> BitMatrix { let mut matrix = BitMatrix::new(self.elements.len(), self.elements.len()); let mut changed = true; @@ -396,7 +396,7 @@ impl TransitiveRelation { /// - Input: `[a, b, x]`. Output: `[a, x]`. /// - Input: `[b, a, x]`. Output: `[b, a, x]`. /// - Input: `[a, x, b, y]`. Output: `[a, x]`. -fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { +fn pare_down(candidates: &mut Vec, closure: &BitMatrix) { let mut i = 0; while i < candidates.len() { let candidate_i = candidates[i]; diff --git a/src/librustc_data_structures/work_queue.rs b/src/librustc_data_structures/work_queue.rs new file mode 100644 index 0000000000000..b8e8b249bb504 --- /dev/null +++ b/src/librustc_data_structures/work_queue.rs @@ -0,0 +1,72 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use indexed_set::IdxSetBuf; +use indexed_vec::Idx; +use std::collections::VecDeque; + +/// A work queue is a handy data structure for tracking work left to +/// do. (For example, basic blocks left to process.) It is basically a +/// de-duplicating queue; so attempting to insert X if X is already +/// enqueued has no effect. This implementation assumes that the +/// elements are dense indices, so it can allocate the queue to size +/// and also use a bit set to track occupancy. +pub struct WorkQueue { + deque: VecDeque, + set: IdxSetBuf, +} + +impl WorkQueue { + /// Create a new work queue with all the elements from (0..len). + #[inline] + pub fn with_all(len: usize) -> Self { + WorkQueue { + deque: (0..len).map(T::new).collect(), + set: IdxSetBuf::new_filled(len), + } + } + + /// Create a new work queue that starts empty, where elements range from (0..len). + #[inline] + pub fn with_none(len: usize) -> Self { + WorkQueue { + deque: VecDeque::with_capacity(len), + set: IdxSetBuf::new_empty(len), + } + } + + /// Attempt to enqueue `element` in the work queue. Returns false if it was already present. + #[inline] + pub fn insert(&mut self, element: T) -> bool { + if self.set.add(&element) { + self.deque.push_back(element); + true + } else { + false + } + } + + /// Attempt to enqueue `element` in the work queue. Returns false if it was already present. + #[inline] + pub fn pop(&mut self) -> Option { + if let Some(element) = self.deque.pop_front() { + self.set.remove(&element); + Some(element) + } else { + None + } + } + + /// True if nothing is enqueued. + #[inline] + pub fn is_empty(&self) -> bool { + self.deque.is_empty() + } +} diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml index 5aae1bcad896f..7a020f331e50b 100644 --- a/src/librustc_driver/Cargo.toml +++ b/src/librustc_driver/Cargo.toml @@ -13,6 +13,8 @@ arena = { path = "../libarena" } graphviz = { path = "../libgraphviz" } log = "0.4" env_logger = { version = "0.5", default-features = false } +rustc-rayon = "0.1.1" +scoped-tls = { version = "0.1.1", features = ["nightly"] } rustc = { path = "../librustc" } rustc_allocator = { path = "../librustc_allocator" } rustc_target = { path = "../librustc_target" } @@ -29,11 +31,9 @@ rustc_privacy = { path = "../librustc_privacy" } rustc_resolve = { path = "../librustc_resolve" } rustc_save_analysis = { path = "../librustc_save_analysis" } rustc_traits = { path = "../librustc_traits" } -rustc_trans_utils = { path = "../librustc_trans_utils" } +rustc_codegen_utils = { path = "../librustc_codegen_utils" } rustc_typeck = { path = "../librustc_typeck" } serialize = { path = "../libserialize" } syntax = { path = "../libsyntax" } syntax_ext = { path = "../libsyntax_ext" } syntax_pos = { path = "../libsyntax_pos" } - -ar = "0.3.0" diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 2fb811eba1e9a..24a2354775cb5 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -20,7 +20,7 @@ use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; use rustc::lint; use rustc::middle::{self, reachable, resolve_lifetime, stability}; -use rustc::middle::cstore::CrateStore; +use rustc::middle::cstore::CrateStoreDyn; use rustc::middle::privacy::AccessLevels; use rustc::ty::{self, AllArenas, Resolutions, TyCtxt}; use rustc::traits; @@ -32,7 +32,7 @@ use rustc_resolve::{MakeGlobMap, Resolver, ResolverArenas}; use rustc_metadata::creader::CrateLoader; use rustc_metadata::cstore::{self, CStore}; use rustc_traits; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc_typeck as typeck; use rustc_privacy; use rustc_plugin::registry::Registry; @@ -49,9 +49,10 @@ use std::fs; use std::io::{self, Write}; use std::iter; use std::path::{Path, PathBuf}; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{self, Lrc, Lock}; use std::sync::mpsc; use syntax::{self, ast, attr, diagnostics, visit}; +use syntax::early_buffered_lints::BufferedEarlyLint; use syntax::ext::base::ExtCtxt; use syntax::fold::Folder; use syntax::parse::{self, PResult}; @@ -64,8 +65,61 @@ use pretty::ReplaceBodyWithLoop; use profile; +#[cfg(not(parallel_queries))] +pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( + opts: config::Options, + f: F +) -> R { + ty::tls::GCX_PTR.set(&Lock::new(0), || { + f(opts) + }) +} + +#[cfg(parallel_queries)] +pub fn spawn_thread_pool R + sync::Send, R: sync::Send>( + opts: config::Options, + f: F +) -> R { + use syntax; + use syntax_pos; + use rayon::{ThreadPoolBuilder, ThreadPool}; + + let gcx_ptr = &Lock::new(0); + + let config = ThreadPoolBuilder::new() + .num_threads(Session::query_threads_from_opts(&opts)) + .deadlock_handler(|| unsafe { ty::query::handle_deadlock() }) + .stack_size(16 * 1024 * 1024); + + let with_pool = move |pool: &ThreadPool| { + pool.install(move || f(opts)) + }; + + syntax::GLOBALS.with(|syntax_globals| { + syntax_pos::GLOBALS.with(|syntax_pos_globals| { + // The main handler run for each Rayon worker thread and sets up + // the thread local rustc uses. syntax_globals and syntax_pos_globals are + // captured and set on the new threads. ty::tls::with_thread_locals sets up + // thread local callbacks from libsyntax + let main_handler = move |worker: &mut dyn FnMut()| { + syntax::GLOBALS.set(syntax_globals, || { + syntax_pos::GLOBALS.set(syntax_pos_globals, || { + ty::tls::with_thread_locals(|| { + ty::tls::GCX_PTR.set(gcx_ptr, || { + worker() + }) + }) + }) + }) + }; + + ThreadPool::scoped_pool(config, main_handler, with_pool).unwrap() + }) + }) +} + pub fn compile_input( - trans: Box, + codegen_backend: Box, sess: &Session, cstore: &CStore, input_path: &Option, @@ -98,7 +152,7 @@ pub fn compile_input( // We need nested scopes here, because the intermediate results can keep // large chunks of memory alive and we want to free them as soon as // possible to keep the peak memory usage low - let (outputs, ongoing_trans, dep_graph) = { + let (outputs, ongoing_codegen, dep_graph) = { let krate = match phase_1_parse_input(control, sess, input) { Ok(krate) => krate, Err(mut parse_error) => { @@ -117,7 +171,7 @@ pub fn compile_input( let outputs = build_output_filenames(input, outdir, output, &krate.attrs, sess); let crate_name = - ::rustc_trans_utils::link::find_crate_name(Some(sess), &krate.attrs, input); + ::rustc_codegen_utils::link::find_crate_name(Some(sess), &krate.attrs, input); install_panic_hook(); let ExpansionResult { @@ -229,7 +283,7 @@ pub fn compile_input( }; phase_3_run_analysis_passes( - &*trans, + &*codegen_backend, control, sess, cstore, @@ -265,14 +319,14 @@ pub fn compile_input( result?; if log_enabled!(::log::Level::Info) { - println!("Pre-trans"); + println!("Pre-codegen"); tcx.print_debug_stats(); } - let ongoing_trans = phase_4_translate_to_llvm(&*trans, tcx, rx); + let ongoing_codegen = phase_4_codegen(&*codegen_backend, tcx, rx); if log_enabled!(::log::Level::Info) { - println!("Post-trans"); + println!("Post-codegen"); tcx.print_debug_stats(); } @@ -283,7 +337,7 @@ pub fn compile_input( } } - Ok((outputs.clone(), ongoing_trans, tcx.dep_graph.clone())) + Ok((outputs.clone(), ongoing_codegen, tcx.dep_graph.clone())) }, )?? }; @@ -292,7 +346,7 @@ pub fn compile_input( sess.code_stats.borrow().print_type_sizes(); } - trans.join_trans_and_link(ongoing_trans, sess, &dep_graph, &outputs)?; + codegen_backend.join_codegen_and_link(ongoing_codegen, sess, &dep_graph, &outputs)?; if sess.opts.debugging_opts.perf_stats { sess.print_perf_stats(); @@ -346,10 +400,10 @@ pub struct CompileController<'a> { /// Allows overriding default rustc query providers, /// after `default_provide` has installed them. - pub provide: Box, + pub provide: Box, /// Same as `provide`, but only for non-local crates, /// applied after `default_provide_extern`. - pub provide_extern: Box, + pub provide_extern: Box, } impl<'a> CompileController<'a> { @@ -369,12 +423,81 @@ impl<'a> CompileController<'a> { } } +/// This implementation makes it easier to create a custom driver when you only want to hook +/// into callbacks from `CompileController`. +/// +/// # Example +/// +/// ```no_run +/// # extern crate rustc_driver; +/// # use rustc_driver::driver::CompileController; +/// let mut controller = CompileController::basic(); +/// controller.after_analysis.callback = Box::new(move |_state| {}); +/// rustc_driver::run_compiler(&[], Box::new(controller), None, None); +/// ``` +impl<'a> ::CompilerCalls<'a> for CompileController<'a> { + fn early_callback( + &mut self, + matches: &::getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + descriptions: &::errors::registry::Registry, + output: ::ErrorOutputType, + ) -> Compilation { + ::RustcDefaultCalls.early_callback( + matches, + sopts, + cfg, + descriptions, + output, + ) + } + fn no_input( + &mut self, + matches: &::getopts::Matches, + sopts: &config::Options, + cfg: &ast::CrateConfig, + odir: &Option, + ofile: &Option, + descriptions: &::errors::registry::Registry, + ) -> Option<(Input, Option)> { + ::RustcDefaultCalls.no_input( + matches, + sopts, + cfg, + odir, + ofile, + descriptions, + ) + } + fn late_callback( + &mut self, + codegen_backend: &dyn (::CodegenBackend), + matches: &::getopts::Matches, + sess: &Session, + cstore: &dyn (::CrateStore), + input: &Input, + odir: &Option, + ofile: &Option, + ) -> Compilation { + ::RustcDefaultCalls + .late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) + } + fn build_controller( + self: Box, + _: &Session, + _: &::getopts::Matches + ) -> CompileController<'a> { + *self + } +} + pub struct PhaseController<'a> { pub stop: Compilation, // If true then the compiler will try to run the callback even if the phase // ends with an error. Note that this is not always possible. pub run_callback_on_error: bool, - pub callback: Box, + pub callback: Box, } impl<'a> PhaseController<'a> { @@ -675,7 +798,7 @@ where pub fn phase_2_configure_and_expand_inner<'a, F>( sess: &'a Session, cstore: &'a CStore, - krate: ast::Crate, + mut krate: ast::Crate, registry: Option, crate_name: &str, addl_plugins: Option>, @@ -687,6 +810,10 @@ pub fn phase_2_configure_and_expand_inner<'a, F>( where F: FnOnce(&ast::Crate) -> CompileResult, { + krate = time(sess, "attributes injection", || { + syntax::attr::inject(krate, &sess.parse_sess, &sess.opts.debugging_opts.crate_attr) + }); + let (mut krate, features) = syntax::config::features( krate, &sess.parse_sess, @@ -800,6 +927,10 @@ where return Err(CompileIncomplete::Stopped); } + time(sess, "pre ast expansion lint checks", || { + lint::check_ast_crate(sess, &krate, true) + }); + let mut resolver = Resolver::new( sess, cstore, @@ -929,10 +1060,28 @@ where }); } + // Expand global allocators, which are treated as an in-tree proc macro krate = time(sess, "creating allocators", || { - allocator::expand::modify(&sess.parse_sess, &mut resolver, krate, sess.diagnostic()) + allocator::expand::modify( + &sess.parse_sess, + &mut resolver, + krate, + crate_name.to_string(), + sess.diagnostic(), + ) + }); + + // Add all buffered lints from the `ParseSess` to the `Session`. + sess.parse_sess.buffered_lints.with_lock(|buffered_lints| { + info!("{} parse sess buffered_lints", buffered_lints.len()); + for BufferedEarlyLint{id, span, msg, lint_id} in buffered_lints.drain(..) { + let lint = lint::Lint::from_parser_lint_id(lint_id); + sess.buffer_lint(lint, id, span, &msg); + } }); + // Done with macro expansion! + after_expand(&krate)?; if sess.opts.debugging_opts.input_stats { @@ -980,15 +1129,16 @@ where let dep_graph = match future_dep_graph { None => DepGraph::new_disabled(), Some(future) => { - let prev_graph = time(sess, "blocked while dep-graph loading finishes", || { - future - .open() - .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { - message: format!("could not decode incremental cache: {:?}", e), - }) - .open(sess) - }); - DepGraph::new(prev_graph) + let (prev_graph, prev_work_products) = + time(sess, "blocked while dep-graph loading finishes", || { + future + .open() + .unwrap_or_else(|e| rustc_incremental::LoadResult::Error { + message: format!("could not decode incremental cache: {:?}", e), + }) + .open(sess) + }); + DepGraph::new(prev_graph, prev_work_products) } }; let hir_forest = time(sess, "lowering ast -> hir", || { @@ -1002,7 +1152,7 @@ where }); time(sess, "early lint checks", || { - lint::check_ast_crate(sess, &krate) + lint::check_ast_crate(sess, &krate, false) }); // Discard hygiene data, which isn't required after lowering to HIR. @@ -1017,7 +1167,7 @@ where }) } -pub fn default_provide(providers: &mut ty::maps::Providers) { +pub fn default_provide(providers: &mut ty::query::Providers) { hir::provide(providers); borrowck::provide(providers); mir::provide(providers); @@ -1035,7 +1185,7 @@ pub fn default_provide(providers: &mut ty::maps::Providers) { lint::provide(providers); } -pub fn default_provide_extern(providers: &mut ty::maps::Providers) { +pub fn default_provide_extern(providers: &mut ty::query::Providers) { cstore::provide_extern(providers); } @@ -1043,10 +1193,10 @@ pub fn default_provide_extern(providers: &mut ty::maps::Providers) { /// miscellaneous analysis passes on the crate. Return various /// structures carrying the results of the analysis. pub fn phase_3_run_analysis_passes<'tcx, F, R>( - trans: &TransCrate, + codegen_backend: &dyn CodegenBackend, control: &CompileController, sess: &'tcx Session, - cstore: &'tcx CrateStore, + cstore: &'tcx CrateStoreDyn, hir_map: hir_map::Map<'tcx>, mut analysis: ty::CrateAnalysis, resolutions: Resolutions, @@ -1059,7 +1209,7 @@ where F: for<'a> FnOnce( TyCtxt<'a, 'tcx, 'tcx>, ty::CrateAnalysis, - mpsc::Receiver>, + mpsc::Receiver>, CompileResult, ) -> R, { @@ -1080,14 +1230,14 @@ where time(sess, "loop checking", || loops::check_crate(sess, &hir_map)); - let mut local_providers = ty::maps::Providers::default(); + let mut local_providers = ty::query::Providers::default(); default_provide(&mut local_providers); - trans.provide(&mut local_providers); + codegen_backend.provide(&mut local_providers); (control.provide)(&mut local_providers); let mut extern_providers = local_providers; default_provide_extern(&mut extern_providers); - trans.provide_extern(&mut extern_providers); + codegen_backend.provide_extern(&mut extern_providers); (control.provide_extern)(&mut extern_providers); let (tx, rx) = mpsc::channel(); @@ -1147,14 +1297,16 @@ where middle::liveness::check_crate(tcx) }); - time(sess, "borrow checking", || borrowck::check_crate(tcx)); - - time(sess, "MIR borrow checking", || { - for def_id in tcx.body_owners() { - tcx.mir_borrowck(def_id); + time(sess, "borrow checking", || { + if tcx.use_ast_borrowck() { + borrowck::check_crate(tcx); } }); + time(sess, + "MIR borrow checking", + || tcx.par_body_owners(|def_id| { tcx.mir_borrowck(def_id); })); + time(sess, "dumping chalk-like clauses", || { rustc_traits::lowering::dump_program_clauses(tcx); }); @@ -1187,23 +1339,23 @@ where ) } -/// Run the translation phase to LLVM, after which the AST and analysis can +/// Run the codegen backend, after which the AST and analysis can /// be discarded. -pub fn phase_4_translate_to_llvm<'a, 'tcx>( - trans: &TransCrate, +pub fn phase_4_codegen<'a, 'tcx>( + codegen_backend: &dyn CodegenBackend, tcx: TyCtxt<'a, 'tcx, 'tcx>, - rx: mpsc::Receiver>, -) -> Box { + rx: mpsc::Receiver>, +) -> Box { time(tcx.sess, "resolving dependency formats", || { ::rustc::middle::dependency_format::calculate(tcx) }); - let translation = time(tcx.sess, "translation", move || trans.trans_crate(tcx, rx)); + let codegen = time(tcx.sess, "codegen", move || codegen_backend.codegen_crate(tcx, rx)); if tcx.sess.profile_queries() { profile::dump(&tcx.sess, "profile_queries".to_string()) } - translation + codegen } fn escape_dep_filename(filename: &FileName) -> String { @@ -1226,7 +1378,7 @@ fn generated_output_paths( // If the filename has been overridden using `-o`, it will not be modified // by appending `.rlib`, `.exe`, etc., so we can skip this transformation. OutputType::Exe if !exact_name => for crate_type in sess.crate_types.borrow().iter() { - let p = ::rustc_trans_utils::link::filename_for_input( + let p = ::rustc_codegen_utils::link::filename_for_input( sess, *crate_type, crate_name, @@ -1247,7 +1399,7 @@ fn generated_output_paths( // Runs `f` on every output file path and returns the first non-None result, or None if `f` // returns None for every file path. -fn check_output(output_paths: &Vec, f: F) -> Option +fn check_output(output_paths: &[PathBuf], f: F) -> Option where F: Fn(&PathBuf) -> Option, { @@ -1259,7 +1411,7 @@ where None } -pub fn output_contains_path(output_paths: &Vec, input_path: &PathBuf) -> bool { +pub fn output_contains_path(output_paths: &[PathBuf], input_path: &PathBuf) -> bool { let input_path = input_path.canonicalize().ok(); if input_path.is_none() { return false; @@ -1274,7 +1426,7 @@ pub fn output_contains_path(output_paths: &Vec, input_path: &PathBuf) - check_output(output_paths, check).is_some() } -pub fn output_conflicts_with_dir(output_paths: &Vec) -> Option { +pub fn output_conflicts_with_dir(output_paths: &[PathBuf]) -> Option { let check = |output_path: &PathBuf| { if output_path.is_dir() { Some(output_path.clone()) @@ -1285,7 +1437,7 @@ pub fn output_conflicts_with_dir(output_paths: &Vec) -> Option check_output(output_paths, check) } -fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &Vec) { +fn write_out_deps(sess: &Session, outputs: &OutputFilenames, out_filenames: &[PathBuf]) { // Write out dependency rules to the dep-info file if requested if !sess.opts.output_types.contains_key(&OutputType::DepInfo) { return; @@ -1378,7 +1530,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec Vec(result: Result, sess: &Session) -> pub fn run(run_compiler: F) -> isize where F: FnOnce() -> (CompileResult, Option) + Send + 'static { - monitor(move || { + let result = monitor(move || { let (result, session) = run_compiler(); if let Err(CompileIncomplete::Errored(_)) = result { match session { @@ -193,10 +206,14 @@ pub fn run(run_compiler: F) -> isize } } }); - 0 + + match result { + Ok(()) => EXIT_SUCCESS, + Err(_) => EXIT_FAILURE, + } } -fn load_backend_from_dylib(path: &Path) -> fn() -> Box { +fn load_backend_from_dylib(path: &Path) -> fn() -> Box { // Note that we're specifically using `open_global_now` here rather than // `open`, namely we want the behavior on Unix of RTLD_GLOBAL and RTLD_NOW, // where NOW means "bind everything right now" because we don't want @@ -229,24 +246,24 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { } } -pub fn get_trans(sess: &Session) -> Box { +pub fn get_codegen_backend(sess: &Session) -> Box { static INIT: Once = ONCE_INIT; #[allow(deprecated)] #[no_debug] - static mut LOAD: fn() -> Box = || unreachable!(); + static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { - let trans_name = sess.opts.debugging_opts.codegen_backend.as_ref() + let codegen_name = sess.opts.debugging_opts.codegen_backend.as_ref() .unwrap_or(&sess.target.target.options.codegen_backend); - let backend = match &trans_name[..] { + let backend = match &codegen_name[..] { "metadata_only" => { - rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new + rustc_codegen_utils::codegen_backend::MetadataOnlyCodegenBackend::new } filename if filename.contains(".") => { load_backend_from_dylib(filename.as_ref()) } - trans_name => get_trans_sysroot(trans_name), + codegen_name => get_codegen_sysroot(codegen_name), }; unsafe { @@ -258,15 +275,15 @@ pub fn get_trans(sess: &Session) -> Box { backend } -fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { +fn get_codegen_sysroot(backend_name: &str) -> fn() -> Box { // For now we only allow this function to be called once as it'll dlopen a // few things, which seems to work best if we only do that once. In - // general this assertion never trips due to the once guard in `get_trans`, + // general this assertion never trips due to the once guard in `get_codegen_backend`, // but there's a few manual calls to this function in this file we protect // against. static LOADED: AtomicBool = ATOMIC_BOOL_INIT; assert!(!LOADED.fetch_or(true, Ordering::SeqCst), - "cannot load the default trans backend twice"); + "cannot load the default codegen backend twice"); // When we're compiling this library with `--test` it'll run as a binary but // not actually exercise much functionality. As a result most of the logic @@ -274,7 +291,7 @@ fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { // let's just return a dummy creation function which won't be used in // general anyway. if cfg!(test) { - return rustc_trans_utils::trans_crate::MetadataOnlyTransCrate::new + return rustc_codegen_utils::codegen_backend::MetadataOnlyCodegenBackend::new } let target = session::config::host_triple(); @@ -342,7 +359,7 @@ fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { let mut file: Option = None; - let expected_name = format!("rustc_trans-{}", backend_name); + let expected_name = format!("rustc_codegen_llvm-{}", backend_name); for entry in d.filter_map(|e| e.ok()) { let path = entry.path(); let filename = match path.file_name().and_then(|s| s.to_str()) { @@ -448,22 +465,34 @@ fn get_trans_sysroot(backend_name: &str) -> fn() -> Box { // See comments on CompilerCalls below for details about the callbacks argument. // The FileLoader provides a way to load files from sources other than the file system. pub fn run_compiler<'a>(args: &[String], - callbacks: &mut CompilerCalls<'a>, - file_loader: Option>, - emitter_dest: Option>) + callbacks: Box + sync::Send + 'a>, + file_loader: Option>, + emitter_dest: Option>) -> (CompileResult, Option) { syntax::with_globals(|| { - run_compiler_impl(args, callbacks, file_loader, emitter_dest) + let matches = match handle_options(args) { + Some(matches) => matches, + None => return (Ok(()), None), + }; + + let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); + hygiene::set_default_edition(sopts.edition); + + driver::spawn_thread_pool(sopts, |sopts| { + run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest) + }) }) } -fn run_compiler_impl<'a>(args: &[String], - callbacks: &mut CompilerCalls<'a>, - file_loader: Option>, - emitter_dest: Option>) - -> (CompileResult, Option) -{ +fn run_compiler_with_pool<'a>( + matches: getopts::Matches, + sopts: config::Options, + cfg: ast::CrateConfig, + mut callbacks: Box + sync::Send + 'a>, + file_loader: Option>, + emitter_dest: Option> +) -> (CompileResult, Option) { macro_rules! do_or_return {($expr: expr, $sess: expr) => { match $expr { Compilation::Stop => return (Ok(()), $sess), @@ -471,13 +500,6 @@ fn run_compiler_impl<'a>(args: &[String], } }} - let matches = match handle_options(args) { - Some(matches) => matches, - None => return (Ok(()), None), - }; - - let (sopts, cfg) = config::build_session_options_and_crate_config(&matches); - let descriptions = diagnostics_registry(); do_or_return!(callbacks.early_callback(&matches, @@ -508,24 +530,24 @@ fn run_compiler_impl<'a>(args: &[String], if let Some(err) = input_err { // Immediately stop compilation if there was an issue reading // the input (for example if the input stream is not UTF-8). - sess.err(&format!("{}", err)); + sess.err(&err.to_string()); return (Err(CompileIncomplete::Stopped), Some(sess)); } - let trans = get_trans(&sess); + let codegen_backend = get_codegen_backend(&sess); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg); - target_features::add_configuration(&mut cfg, &sess, &*trans); + target_features::add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; let result = { let plugins = sess.opts.debugging_opts.extra_plugins.clone(); - let cstore = CStore::new(trans.metadata_loader()); + let cstore = CStore::new(codegen_backend.metadata_loader()); - do_or_return!(callbacks.late_callback(&*trans, + do_or_return!(callbacks.late_callback(&*codegen_backend, &matches, &sess, &cstore, @@ -537,7 +559,7 @@ fn run_compiler_impl<'a>(args: &[String], let control = callbacks.build_controller(&sess, &matches); - driver::compile_input(trans, + driver::compile_input(codegen_backend, &sess, &cstore, &input_file_path, @@ -631,12 +653,12 @@ impl Compilation { } } -// A trait for customising the compilation process. Offers a number of hooks for -// executing custom code or customising input. +/// A trait for customising the compilation process. Offers a number of hooks for +/// executing custom code or customising input. pub trait CompilerCalls<'a> { - // Hook for a callback early in the process of handling arguments. This will - // be called straight after options have been parsed but before anything - // else (e.g., selecting input and output). + /// Hook for a callback early in the process of handling arguments. This will + /// be called straight after options have been parsed but before anything + /// else (e.g., selecting input and output). fn early_callback(&mut self, _: &getopts::Matches, _: &config::Options, @@ -647,14 +669,14 @@ pub trait CompilerCalls<'a> { Compilation::Continue } - // Hook for a callback late in the process of handling arguments. This will - // be called just before actual compilation starts (and before build_controller - // is called), after all arguments etc. have been completely handled. + /// Hook for a callback late in the process of handling arguments. This will + /// be called just before actual compilation starts (and before build_controller + /// is called), after all arguments etc. have been completely handled. fn late_callback(&mut self, - _: &TransCrate, + _: &dyn CodegenBackend, _: &getopts::Matches, _: &Session, - _: &CrateStore, + _: &dyn CrateStore, _: &Input, _: &Option, _: &Option) @@ -662,9 +684,9 @@ pub trait CompilerCalls<'a> { Compilation::Continue } - // Called after we extract the input from the arguments. Gives the implementer - // an opportunity to change the inputs or to add some custom input handling. - // The default behaviour is to simply pass through the inputs. + /// Called after we extract the input from the arguments. Gives the implementer + /// an opportunity to change the inputs or to add some custom input handling. + /// The default behaviour is to simply pass through the inputs. fn some_input(&mut self, input: Input, input_path: Option) @@ -672,11 +694,11 @@ pub trait CompilerCalls<'a> { (input, input_path) } - // Called after we extract the input from the arguments if there is no valid - // input. Gives the implementer an opportunity to supply alternate input (by - // returning a Some value) or to add custom behaviour for this error such as - // emitting error messages. Returning None will cause compilation to stop - // at this point. + /// Called after we extract the input from the arguments if there is no valid + /// input. Gives the implementer an opportunity to supply alternate input (by + /// returning a Some value) or to add custom behaviour for this error such as + /// emitting error messages. Returning None will cause compilation to stop + /// at this point. fn no_input(&mut self, _: &getopts::Matches, _: &config::Options, @@ -690,10 +712,14 @@ pub trait CompilerCalls<'a> { // Create a CompilController struct for controlling the behaviour of // compilation. - fn build_controller(&mut self, _: &Session, _: &getopts::Matches) -> CompileController<'a>; + fn build_controller( + self: Box, + _: &Session, + _: &getopts::Matches + ) -> CompileController<'a>; } -// CompilerCalls instance for a regular rustc build. +/// CompilerCalls instance for a regular rustc build. #[derive(Copy, Clone)] pub struct RustcDefaultCalls; @@ -833,11 +859,11 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let mut cfg = config::build_configuration(&sess, cfg.clone()); - let trans = get_trans(&sess); - target_features::add_configuration(&mut cfg, &sess, &*trans); + let codegen_backend = get_codegen_backend(&sess); + target_features::add_configuration(&mut cfg, &sess, &*codegen_backend); sess.parse_sess.config = cfg; let should_stop = RustcDefaultCalls::print_crate_info( - &*trans, + &*codegen_backend, &sess, None, odir, @@ -855,19 +881,19 @@ impl<'a> CompilerCalls<'a> for RustcDefaultCalls { } fn late_callback(&mut self, - trans: &TransCrate, + codegen_backend: &dyn CodegenBackend, matches: &getopts::Matches, sess: &Session, - cstore: &CrateStore, + cstore: &dyn CrateStore, input: &Input, odir: &Option, ofile: &Option) -> Compilation { - RustcDefaultCalls::print_crate_info(trans, sess, Some(input), odir, ofile) + RustcDefaultCalls::print_crate_info(codegen_backend, sess, Some(input), odir, ofile) .and_then(|| RustcDefaultCalls::list_metadata(sess, cstore, matches, input)) } - fn build_controller(&mut self, + fn build_controller(self: Box, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { @@ -964,7 +990,7 @@ pub fn enable_save_analysis(control: &mut CompileController) { impl RustcDefaultCalls { pub fn list_metadata(sess: &Session, - cstore: &CrateStore, + cstore: &dyn CrateStore, matches: &getopts::Matches, input: &Input) -> Compilation { @@ -992,7 +1018,7 @@ impl RustcDefaultCalls { } - fn print_crate_info(trans: &TransCrate, + fn print_crate_info(codegen_backend: &dyn CodegenBackend, sess: &Session, input: Option<&Input>, odir: &Option, @@ -1034,14 +1060,14 @@ impl RustcDefaultCalls { }; let attrs = attrs.as_ref().unwrap(); let t_outputs = driver::build_output_filenames(input, odir, ofile, attrs, sess); - let id = rustc_trans_utils::link::find_crate_name(Some(sess), attrs, input); + let id = rustc_codegen_utils::link::find_crate_name(Some(sess), attrs, input); if *req == PrintRequest::CrateName { println!("{}", id); continue; } let crate_types = driver::collect_crate_types(sess, attrs); for &style in &crate_types { - let fname = rustc_trans_utils::link::filename_for_input( + let fname = rustc_codegen_utils::link::filename_for_input( sess, style, &id, @@ -1060,7 +1086,7 @@ impl RustcDefaultCalls { let mut cfgs = Vec::new(); for &(name, ref value) in sess.parse_sess.config.iter() { let gated_cfg = GatedCfg::gate(&ast::MetaItem { - ident: ast::Path::from_ident(name.to_ident()), + ident: ast::Path::from_ident(ast::Ident::with_empty_ctxt(name)), node: ast::MetaItemKind::Word, span: DUMMY_SP, }); @@ -1084,7 +1110,7 @@ impl RustcDefaultCalls { cfgs.push(if let Some(value) = value { format!("{}=\"{}\"", name, value) } else { - format!("{}", name) + name.to_string() }); } @@ -1094,7 +1120,7 @@ impl RustcDefaultCalls { } } RelocationModels | CodeModels | TlsModels | TargetCPUs | TargetFeatures => { - trans.print(*req, sess); + codegen_backend.print(*req, sess); } // Any output here interferes with Cargo's parsing of other printed output PrintRequest::NativeStaticLibs => {} @@ -1135,7 +1161,7 @@ pub fn version(binary: &str, matches: &getopts::Matches) { println!("commit-date: {}", unw(commit_date_str())); println!("host: {}", config::host_triple()); println!("release: {}", unw(release_str())); - get_trans_sysroot("llvm")().print_version(); + get_codegen_sysroot("llvm")().print_version(); } } @@ -1200,10 +1226,7 @@ Available lint options: fn sort_lint_groups(lints: Vec<(&'static str, Vec, bool)>) -> Vec<(&'static str, Vec)> { let mut lints: Vec<_> = lints.into_iter().map(|(x, y, _)| (x, y)).collect(); - lints.sort_by(|&(x, _): &(&'static str, Vec), - &(y, _): &(&'static str, Vec)| { - x.cmp(y) - }); + lints.sort_by_key(|l| l.0); lints } @@ -1227,9 +1250,7 @@ Available lint options: .max() .unwrap_or(0); let padded = |x: &str| { - let mut s = repeat(" ") - .take(max_name_len - x.chars().count()) - .collect::(); + let mut s = " ".repeat(max_name_len - x.chars().count()); s.push_str(x); s }; @@ -1261,9 +1282,7 @@ Available lint options: .unwrap_or(0)); let padded = |x: &str| { - let mut s = repeat(" ") - .take(max_name_len - x.chars().count()) - .collect::(); + let mut s = " ".repeat(max_name_len - x.chars().count()); s.push_str(x); s }; @@ -1443,7 +1462,7 @@ pub fn handle_options(args: &[String]) -> Option { } if cg_flags.contains(&"passes=list".to_string()) { - get_trans_sysroot("llvm")().print_passes(); + get_codegen_sysroot("llvm")().print_passes(); return None; } @@ -1468,17 +1487,19 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec(f: F) -> Result> +/// Runs `f` in a suitable thread for running `rustc`; returns a `Result` with either the return +/// value of `f` or -- if a panic occurs -- the panic value. +/// +/// This version applies the given name to the thread. This is used by rustdoc to ensure consistent +/// doctest output across platforms and executions. +pub fn in_named_rustc_thread(name: String, f: F) -> Result> where F: FnOnce() -> R + Send + 'static, R: Send + 'static, { // Temporarily have stack size set to 16MB to deal with nom-using crates failing const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB - #[cfg(unix)] + #[cfg(all(unix,not(target_os = "haiku")))] let spawn_thread = unsafe { // Fetch the current resource limits let mut rlim = libc::rlimit { @@ -1510,12 +1531,32 @@ pub fn in_rustc_thread(f: F) -> Result> #[cfg(windows)] let spawn_thread = false; + #[cfg(target_os = "haiku")] + let spawn_thread = unsafe { + // Haiku does not have setrlimit implemented for the stack size. + // By default it does have the 16 MB stack limit, but we check this in + // case the minimum STACK_SIZE changes or Haiku's defaults change. + let mut rlim = libc::rlimit { + rlim_cur: 0, + rlim_max: 0, + }; + if libc::getrlimit(libc::RLIMIT_STACK, &mut rlim) != 0 { + let err = io::Error::last_os_error(); + error!("in_rustc_thread: error calling getrlimit: {}", err); + true + } else if rlim.rlim_cur >= STACK_SIZE { + false + } else { + true + } + }; + #[cfg(not(any(windows,unix)))] let spawn_thread = true; // The or condition is added from backward compatibility. if spawn_thread || env::var_os("RUST_MIN_STACK").is_some() { - let mut cfg = thread::Builder::new().name("rustc".to_string()); + let mut cfg = thread::Builder::new().name(name); // FIXME: Hacks on hacks. If the env is trying to override the stack size // then *don't* set it explicitly. @@ -1531,16 +1572,23 @@ pub fn in_rustc_thread(f: F) -> Result> } } +/// Runs `f` in a suitable thread for running `rustc`; returns a +/// `Result` with either the return value of `f` or -- if a panic +/// occurs -- the panic value. +pub fn in_rustc_thread(f: F) -> Result> + where F: FnOnce() -> R + Send + 'static, + R: Send + 'static, +{ + in_named_rustc_thread("rustc".to_string(), f) +} + /// Get a list of extra command-line flags provided by the user, as strings. /// /// This function is used during ICEs to show more information useful for /// debugging, since some ICEs only happens with non-default compiler flags /// (and the users don't always report them). fn extra_compiler_flags() -> Option<(Vec, bool)> { - let mut args = Vec::new(); - for arg in env::args_os() { - args.push(arg.to_string_lossy().to_string()); - } + let args = env::args_os().map(|arg| arg.to_string_lossy().to_string()).collect::>(); // Avoid printing help because of empty args. This can suggest the compiler // itself is not the program root (consider RLS). @@ -1588,20 +1636,30 @@ fn extra_compiler_flags() -> Option<(Vec, bool)> { } } +#[derive(Debug)] +pub struct CompilationFailure; + +impl Error for CompilationFailure {} + +impl Display for CompilationFailure { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "compilation had errors") + } +} + /// Run a procedure which will detect panics in the compiler and print nicer /// error messages rather than just failing the test. /// /// The diagnostic emitter yielded to the procedure should be used for reporting /// errors of the compiler. -pub fn monitor(f: F) { - let result = in_rustc_thread(move || { +pub fn monitor(f: F) -> Result<(), CompilationFailure> { + in_rustc_thread(move || { f() - }); - - if let Err(value) = result { - // Thread panicked without emitting a fatal diagnostic - if !value.is::() { - // Emit a newline + }).map_err(|value| { + if value.is::() { + CompilationFailure + } else { + // Thread panicked without emitting a fatal diagnostic eprintln!(""); let emitter = @@ -1640,10 +1698,10 @@ pub fn monitor(f: F) { ¬e, errors::Level::Note); } - } - panic::resume_unwind(Box::new(errors::FatalErrorMarker)); - } + panic::resume_unwind(Box::new(errors::FatalErrorMarker)); + } + }) } pub fn diagnostics_registry() -> errors::registry::Registry { @@ -1655,8 +1713,8 @@ pub fn diagnostics_registry() -> errors::registry::Registry { all_errors.extend_from_slice(&rustc_resolve::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_privacy::DIAGNOSTICS); // FIXME: need to figure out a way to get these back in here - // all_errors.extend_from_slice(get_trans(sess).diagnostics()); - all_errors.extend_from_slice(&rustc_trans_utils::DIAGNOSTICS); + // all_errors.extend_from_slice(get_codegen_backend(sess).diagnostics()); + all_errors.extend_from_slice(&rustc_codegen_utils::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_metadata::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_passes::DIAGNOSTICS); all_errors.extend_from_slice(&rustc_plugin::DIAGNOSTICS); @@ -1682,7 +1740,7 @@ pub fn main() { })) .collect::>(); run_compiler(&args, - &mut RustcDefaultCalls, + Box::new(RustcDefaultCalls), None, None) }); diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index 70b73ebb8cdeb..6433a93a317a6 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -20,7 +20,7 @@ use {abort_on_err, driver}; use rustc::ty::{self, TyCtxt, Resolutions, AllArenas}; use rustc::cfg; use rustc::cfg::graphviz::LabelledCFG; -use rustc::middle::cstore::CrateStore; +use rustc::middle::cstore::CrateStoreDyn; use rustc::session::Session; use rustc::session::config::{Input, OutputFilenames}; use rustc_borrowck as borrowck; @@ -170,7 +170,7 @@ impl PpSourceMode { hir_map: Option<&hir_map::Map<'tcx>>, f: F) -> A - where F: FnOnce(&PrinterSupport) -> A + where F: FnOnce(&dyn PrinterSupport) -> A { match *self { PpmNormal | PpmEveryBodyLoops | PpmExpanded => { @@ -199,7 +199,7 @@ impl PpSourceMode { } fn call_with_pp_support_hir<'tcx, A, F>(&self, sess: &'tcx Session, - cstore: &'tcx CrateStore, + cstore: &'tcx CrateStoreDyn, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, @@ -208,7 +208,7 @@ impl PpSourceMode { id: &str, f: F) -> A - where F: FnOnce(&HirPrinterSupport, &hir::Crate) -> A + where F: FnOnce(&dyn HirPrinterSupport, &hir::Crate) -> A { match *self { PpmNormal => { @@ -228,8 +228,8 @@ impl PpSourceMode { } PpmTyped => { let control = &driver::CompileController::basic(); - let trans = ::get_trans(sess); - abort_on_err(driver::phase_3_run_analysis_passes(&*trans, + let codegen_backend = ::get_codegen_backend(sess); + abort_on_err(driver::phase_3_run_analysis_passes(&*codegen_backend, control, sess, cstore, @@ -265,7 +265,7 @@ trait PrinterSupport: pprust::PpAnn { /// /// (Rust does not yet support upcasting from a trait object to /// an object for one of its super-traits.) - fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn; + fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn; } trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { @@ -281,7 +281,7 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { /// /// (Rust does not yet support upcasting from a trait object to /// an object for one of its super-traits.) - fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn; + fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn; /// Computes an user-readable representation of a path, if possible. fn node_path(&self, id: ast::NodeId) -> Option { @@ -305,7 +305,7 @@ impl<'hir> PrinterSupport for NoAnn<'hir> { self.sess } - fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { + fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn { self } } @@ -319,7 +319,7 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { self.hir_map.as_ref() } - fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { + fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { self } } @@ -346,7 +346,7 @@ impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { self.sess } - fn pp_ann<'a>(&'a self) -> &'a pprust::PpAnn { + fn pp_ann<'a>(&'a self) -> &'a dyn pprust::PpAnn { self } } @@ -397,7 +397,7 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { self.hir_map.as_ref() } - fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { + fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { self } } @@ -458,7 +458,7 @@ impl<'a> PrinterSupport for HygieneAnnotation<'a> { self.sess } - fn pp_ann(&self) -> &pprust::PpAnn { + fn pp_ann(&self) -> &dyn pprust::PpAnn { self } } @@ -496,7 +496,7 @@ impl<'b, 'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'b, 'tcx> { Some(&self.tcx.hir) } - fn pp_ann<'a>(&'a self) -> &'a pprust_hir::PpAnn { + fn pp_ann<'a>(&'a self) -> &'a dyn pprust_hir::PpAnn { self } @@ -669,7 +669,7 @@ impl<'a> ReplaceBodyWithLoop<'a> { if let ast::FunctionRetTy::Ty(ref ty) = ret_ty.output { fn involves_impl_trait(ty: &ast::Ty) -> bool { match ty.node { - ast::TyKind::ImplTrait(_) => true, + ast::TyKind::ImplTrait(..) => true, ast::TyKind::Slice(ref subty) | ast::TyKind::Array(ref subty, _) | ast::TyKind::Ptr(ast::MutTy { ty: ref subty, .. }) | @@ -677,14 +677,20 @@ impl<'a> ReplaceBodyWithLoop<'a> { ast::TyKind::Paren(ref subty) => involves_impl_trait(subty), ast::TyKind::Tup(ref tys) => any_involves_impl_trait(tys.iter()), ast::TyKind::Path(_, ref path) => path.segments.iter().any(|seg| { - match seg.parameters.as_ref().map(|p| &**p) { + match seg.args.as_ref().map(|generic_arg| &**generic_arg) { None => false, - Some(&ast::PathParameters::AngleBracketed(ref data)) => - any_involves_impl_trait(data.types.iter()) || - any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty)), - Some(&ast::PathParameters::Parenthesized(ref data)) => + Some(&ast::GenericArgs::AngleBracketed(ref data)) => { + let types = data.args.iter().filter_map(|arg| match arg { + ast::GenericArg::Type(ty) => Some(ty), + _ => None, + }); + any_involves_impl_trait(types.into_iter()) || + any_involves_impl_trait(data.bindings.iter().map(|b| &b.ty)) + }, + Some(&ast::GenericArgs::Parenthesized(ref data)) => { any_involves_impl_trait(data.inputs.iter()) || - any_involves_impl_trait(data.output.iter()), + any_involves_impl_trait(data.output.iter()) + } } }), _ => false, @@ -706,8 +712,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { fn fold_item_kind(&mut self, i: ast::ItemKind) -> ast::ItemKind { let is_const = match i { ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => true, - ast::ItemKind::Fn(ref decl, _, ref constness, _, _, _) => - constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::ItemKind::Fn(ref decl, ref header, _, _) => + header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; self.run(is_const, |s| fold::noop_fold_item_kind(i, s)) @@ -716,8 +722,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { fn fold_trait_item(&mut self, i: ast::TraitItem) -> SmallVector { let is_const = match i.node { ast::TraitItemKind::Const(..) => true, - ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) => - constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::TraitItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => + header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; self.run(is_const, |s| fold::noop_fold_trait_item(i, s)) @@ -726,8 +732,8 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> { fn fold_impl_item(&mut self, i: ast::ImplItem) -> SmallVector { let is_const = match i.node { ast::ImplItemKind::Const(..) => true, - ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref constness, .. }, _) => - constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), + ast::ImplItemKind::Method(ast::MethodSig { ref decl, ref header, .. }, _) => + header.constness.node == ast::Constness::Const || Self::should_ignore_fn(decl), _ => false, }; self.run(is_const, |s| fold::noop_fold_impl_item(i, s)) @@ -890,7 +896,7 @@ pub fn print_after_parsing(sess: &Session, if let PpmSource(s) = ppm { // Silently ignores an identified node. - let out: &mut Write = &mut out; + let out: &mut dyn Write = &mut out; s.call_with_pp_support(sess, None, move |annotation| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); @@ -912,7 +918,7 @@ pub fn print_after_parsing(sess: &Session, } pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'tcx CrateStore, + cstore: &'tcx CrateStoreDyn, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, @@ -947,7 +953,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, match (ppm, opt_uii) { (PpmSource(s), _) => { // Silently ignores an identified node. - let out: &mut Write = &mut out; + let out: &mut dyn Write = &mut out; s.call_with_pp_support(sess, Some(hir_map), move |annotation| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); @@ -963,7 +969,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, } (PpmHir(s), None) => { - let out: &mut Write = &mut out; + let out: &mut dyn Write = &mut out; s.call_with_pp_support_hir(sess, cstore, hir_map, @@ -987,7 +993,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, } (PpmHirTree(s), None) => { - let out: &mut Write = &mut out; + let out: &mut dyn Write = &mut out; s.call_with_pp_support_hir(sess, cstore, hir_map, @@ -1003,7 +1009,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, } (PpmHir(s), Some(uii)) => { - let out: &mut Write = &mut out; + let out: &mut dyn Write = &mut out; s.call_with_pp_support_hir(sess, cstore, hir_map, @@ -1037,7 +1043,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, } (PpmHirTree(s), Some(uii)) => { - let out: &mut Write = &mut out; + let out: &mut dyn Write = &mut out; s.call_with_pp_support_hir(sess, cstore, hir_map, @@ -1068,7 +1074,7 @@ pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session, // with a different callback than the standard driver, so that isn't easy. // Instead, we call that function ourselves. fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, - cstore: &'a CrateStore, + cstore: &'a CrateStoreDyn, hir_map: &hir_map::Map<'tcx>, analysis: &ty::CrateAnalysis, resolutions: &Resolutions, @@ -1089,8 +1095,8 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, let mut out = Vec::new(); let control = &driver::CompileController::basic(); - let trans = ::get_trans(sess); - abort_on_err(driver::phase_3_run_analysis_passes(&*trans, + let codegen_backend = ::get_codegen_backend(sess); + abort_on_err(driver::phase_3_run_analysis_passes(&*codegen_backend, control, sess, cstore, @@ -1131,7 +1137,7 @@ fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session, Some(code) => { let variants = gather_flowgraph_variants(tcx.sess); - let out: &mut Write = &mut out; + let out: &mut dyn Write = &mut out; print_flowgraph(variants, tcx, code, mode, out) } diff --git a/src/librustc_driver/profile/mod.rs b/src/librustc_driver/profile/mod.rs index a362556717bdd..2ec85e1c27f1d 100644 --- a/src/librustc_driver/profile/mod.rs +++ b/src/librustc_driver/profile/mod.rs @@ -62,7 +62,7 @@ struct StackFrame { pub traces: Vec, } -fn total_duration(traces: &Vec) -> Duration { +fn total_duration(traces: &[trace::Rec]) -> Duration { let mut sum : Duration = Duration::new(0,0); for t in traces.iter() { sum += t.dur_total; } return sum diff --git a/src/librustc_driver/profile/trace.rs b/src/librustc_driver/profile/trace.rs index 6426286ccbc6c..3d4f4b029e543 100644 --- a/src/librustc_driver/profile/trace.rs +++ b/src/librustc_driver/profile/trace.rs @@ -107,7 +107,7 @@ fn html_of_fraction(frac: f64) -> (String, String) { else { (format!("< 0.1%", ), css) } } -fn total_duration(traces: &Vec) -> Duration { +fn total_duration(traces: &[Rec]) -> Duration { let mut sum : Duration = Duration::new(0,0); for t in traces.iter() { sum += t.dur_total; @@ -123,7 +123,7 @@ fn duration_div(nom: Duration, den: Duration) -> f64 { to_nanos(nom) as f64 / to_nanos(den) as f64 } -fn write_traces_rec(file: &mut File, traces: &Vec, total: Duration, depth: usize) { +fn write_traces_rec(file: &mut File, traces: &[Rec], total: Duration, depth: usize) { for t in traces { let (eff_text, eff_css_classes) = html_of_effect(&t.effect); let (dur_text, dur_css_classes) = html_of_duration(&t.start, &t.dur_total); @@ -149,7 +149,7 @@ fn write_traces_rec(file: &mut File, traces: &Vec, total: Duration, depth: } } -fn compute_counts_rec(counts: &mut HashMap, traces: &Vec) { +fn compute_counts_rec(counts: &mut HashMap, traces: &[Rec]) { for t in traces.iter() { match t.effect { Effect::TimeBegin(ref msg) => { @@ -202,14 +202,12 @@ fn compute_counts_rec(counts: &mut HashMap, traces: &Vec) { use rustc::util::common::duration_to_secs_str; - use std::cmp::Ordering; + use std::cmp::Reverse; - let mut data = vec![]; - for (ref cons, ref qm) in counts.iter() { - data.push((cons.clone(), qm.count.clone(), qm.dur_total.clone(), qm.dur_self.clone())); - }; - data.sort_by(|&(_,_,_,self1),&(_,_,_,self2)| - if self1 > self2 { Ordering::Less } else { Ordering::Greater } ); + let mut data = counts.iter().map(|(ref cons, ref qm)| + (cons.clone(), qm.count.clone(), qm.dur_total.clone(), qm.dur_self.clone()) + ).collect::>(); + data.sort_by_key(|k| Reverse(k.3)); for (cons, count, dur_total, dur_self) in data { write!(count_file, "{}, {}, {}, {}\n", cons, count, @@ -219,8 +217,9 @@ pub fn write_counts(count_file: &mut File, counts: &mut HashMap) { - let mut counts : HashMap = HashMap::new(); +pub fn write_traces(html_file: &mut File, counts_file: &mut File, traces: &[Rec]) { + let capacity = traces.iter().fold(0, |acc, t| acc + 1 + t.extent.len()); + let mut counts : HashMap = HashMap::with_capacity(capacity); compute_counts_rec(&mut counts, traces); write_counts(counts_file, &mut counts); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index d2ee3d8743c2c..5b2092ea9eb11 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -20,7 +20,7 @@ use rustc::middle::region; use rustc::ty::subst::Subst; use rustc::traits::ObligationCause; use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc::ty::maps::OnDiskCache; +use rustc::ty::query::OnDiskCache; use rustc::infer::{self, InferOk, InferResult}; use rustc::infer::outlives::env::OutlivesEnvironment; use rustc::infer::type_variable::TypeVariableOrigin; @@ -88,36 +88,41 @@ impl Emitter for ExpectErrorEmitter { } } -fn errors(msgs: &[&str]) -> (Box, usize) { +fn errors(msgs: &[&str]) -> (Box, usize) { let v = msgs.iter().map(|m| m.to_string()).collect(); - (box ExpectErrorEmitter { messages: v } as Box, msgs.len()) + (box ExpectErrorEmitter { messages: v } as Box, msgs.len()) } fn test_env(source_string: &str, - args: (Box, usize), + args: (Box, usize), body: F) where F: FnOnce(Env) { syntax::with_globals(|| { - test_env_impl(source_string, args, body) + let mut options = config::basic_options(); + options.debugging_opts.verbose = true; + options.unstable_features = UnstableFeatures::Allow; + + driver::spawn_thread_pool(options, |options| { + test_env_with_pool(options, source_string, args, body) + }) }); } -fn test_env_impl(source_string: &str, - (emitter, expected_err_count): (Box, usize), - body: F) +fn test_env_with_pool( + options: config::Options, + source_string: &str, + (emitter, expected_err_count): (Box, usize), + body: F +) where F: FnOnce(Env) { - let mut options = config::basic_options(); - options.debugging_opts.verbose = true; - options.unstable_features = UnstableFeatures::Allow; let diagnostic_handler = errors::Handler::with_emitter(true, false, emitter); - let sess = session::build_session_(options, None, diagnostic_handler, Lrc::new(CodeMap::new(FilePathMapping::empty()))); - let cstore = CStore::new(::get_trans(&sess).metadata_loader()); + let cstore = CStore::new(::get_codegen_backend(&sess).metadata_loader()); rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess)); let input = config::Input::Str { name: FileName::Anon, @@ -152,8 +157,8 @@ fn test_env_impl(source_string: &str, }; TyCtxt::create_and_enter(&sess, &cstore, - ty::maps::Providers::default(), - ty::maps::Providers::default(), + ty::query::Providers::default(), + ty::query::Providers::default(), &arenas, resolutions, hir_map, @@ -178,16 +183,20 @@ fn test_env_impl(source_string: &str, }); } +const D1: ty::DebruijnIndex = ty::INNERMOST; +const D2: ty::DebruijnIndex = D1.shifted_in(1); + impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> { self.infcx.tcx } - pub fn create_region_hierarchy(&mut self, rh: &RH, parent: region::Scope) { + pub fn create_region_hierarchy(&mut self, rh: &RH, + parent: (region::Scope, region::ScopeDepth)) { let me = region::Scope::Node(rh.id); self.region_scope_tree.record_scope_parent(me, Some(parent)); for child_rh in rh.sub { - self.create_region_hierarchy(child_rh, me); + self.create_region_hierarchy(child_rh, (me, parent.1 + 1)); } } @@ -207,7 +216,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { id: hir::ItemLocalId(11), sub: &[], }], - }, dscope); + }, (dscope, 1)); } #[allow(dead_code)] // this seems like it could be useful, even if we don't use it now @@ -240,23 +249,24 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } return match it.node { - hir::ItemUse(..) | - hir::ItemExternCrate(..) | - hir::ItemConst(..) | - hir::ItemStatic(..) | - hir::ItemFn(..) | - hir::ItemForeignMod(..) | - hir::ItemGlobalAsm(..) | - hir::ItemTy(..) => None, - - hir::ItemEnum(..) | - hir::ItemStruct(..) | - hir::ItemUnion(..) | - hir::ItemTrait(..) | - hir::ItemTraitAlias(..) | - hir::ItemImpl(..) => None, - - hir::ItemMod(ref m) => search_mod(this, m, idx, names), + hir::ItemKind::Use(..) | + hir::ItemKind::ExternCrate(..) | + hir::ItemKind::Const(..) | + hir::ItemKind::Static(..) | + hir::ItemKind::Fn(..) | + hir::ItemKind::ForeignMod(..) | + hir::ItemKind::GlobalAsm(..) | + hir::ItemKind::Existential(..) | + hir::ItemKind::Ty(..) => None, + + hir::ItemKind::Enum(..) | + hir::ItemKind::Struct(..) | + hir::ItemKind::Union(..) | + hir::ItemKind::Trait(..) | + hir::ItemKind::TraitAlias(..) | + hir::ItemKind::Impl(..) => None, + + hir::ItemKind::Mod(ref m) => search_mod(this, m, idx, names), }; } } @@ -303,7 +313,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { pub fn t_param(&self, index: u32) -> Ty<'tcx> { let name = format!("T{}", index); - self.infcx.tcx.mk_param(index, Symbol::intern(&name).as_interned_str()) + self.infcx.tcx.mk_ty_param(index, Symbol::intern(&name).as_interned_str()) } pub fn re_early_bound(&self, index: u32, name: &'static str) -> ty::Region<'tcx> { @@ -327,7 +337,7 @@ impl<'a, 'gcx, 'tcx> Env<'a, 'gcx, 'tcx> { } pub fn t_rptr_late_bound(&self, id: u32) -> Ty<'tcx> { - let r = self.re_late_bound_with_debruijn(id, ty::DebruijnIndex::new(1)); + let r = self.re_late_bound_with_debruijn(id, D1); self.infcx.tcx.mk_imm_ref(r, self.tcx().types.isize) } @@ -484,7 +494,7 @@ fn subst_ty_renumber_bound() { // t_expected = fn(&'a isize) let t_expected = { - let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); + let t_ptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, D2); env.t_fn(&[t_ptr_bound2], env.t_nil()) }; @@ -521,7 +531,7 @@ fn subst_ty_renumber_some_bounds() { // // but not that the Debruijn index is different in the different cases. let t_expected = { - let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); + let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, D2); env.t_pair(t_rptr_bound1, env.t_fn(&[t_rptr_bound2], env.t_nil())) }; @@ -549,10 +559,10 @@ fn escaping() { let t_rptr_free1 = env.t_rptr_free(1); assert!(!t_rptr_free1.has_escaping_regions()); - let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)); + let t_rptr_bound1 = env.t_rptr_late_bound_with_debruijn(1, D1); assert!(t_rptr_bound1.has_escaping_regions()); - let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); + let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, D2); assert!(t_rptr_bound2.has_escaping_regions()); // t_fn = fn(A) @@ -568,7 +578,7 @@ fn escaping() { #[test] fn subst_region_renumber_region() { test_env(EMPTY_SOURCE_STR, errors(&[]), |env| { - let re_bound1 = env.re_late_bound_with_debruijn(1, ty::DebruijnIndex::new(1)); + let re_bound1 = env.re_late_bound_with_debruijn(1, D1); // type t_source<'a> = fn(&'a isize) let t_source = { @@ -583,7 +593,7 @@ fn subst_region_renumber_region() { // // but not that the Debruijn index is different in the different cases. let t_expected = { - let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, ty::DebruijnIndex::new(2)); + let t_rptr_bound2 = env.t_rptr_late_bound_with_debruijn(1, D2); env.t_fn(&[t_rptr_bound2], env.t_nil()) }; diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs index 75401f21862b6..825e31539c8be 100644 --- a/src/librustc_errors/diagnostic.rs +++ b/src/librustc_errors/diagnostic.rs @@ -99,6 +99,25 @@ impl Diagnostic { } } + pub fn is_error(&self) -> bool { + match self.level { + Level::Bug | + Level::Fatal | + Level::PhaseFatal | + Level::Error | + Level::FailureNote => { + true + } + + Level::Warning | + Level::Note | + Level::Help | + Level::Cancelled => { + false + } + } + } + /// Cancel the diagnostic (a structured diagnostic must either be emitted or /// canceled or it will panic when dropped). pub fn cancel(&mut self) { @@ -121,7 +140,7 @@ impl Diagnostic { } pub fn note_expected_found(&mut self, - label: &fmt::Display, + label: &dyn fmt::Display, expected: DiagnosticStyledString, found: DiagnosticStyledString) -> &mut Self @@ -130,11 +149,11 @@ impl Diagnostic { } pub fn note_expected_found_extra(&mut self, - label: &fmt::Display, + label: &dyn fmt::Display, expected: DiagnosticStyledString, found: DiagnosticStyledString, - expected_extra: &fmt::Display, - found_extra: &fmt::Display) + expected_extra: &dyn fmt::Display, + found_extra: &dyn fmt::Display) -> &mut Self { let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)]; @@ -259,6 +278,25 @@ impl Diagnostic { self } + pub fn multipart_suggestion( + &mut self, + msg: &str, + suggestion: Vec<(Span, String)>, + ) -> &mut Self { + self.suggestions.push(CodeSuggestion { + substitutions: vec![Substitution { + parts: suggestion + .into_iter() + .map(|(span, snippet)| SubstitutionPart { snippet, span }) + .collect(), + }], + msg: msg.to_owned(), + show_code_when_inline: true, + applicability: Applicability::Unspecified, + }); + self + } + /// Prints out a message with multiple suggested edits of the code. pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec) -> &mut Self { self.suggestions.push(CodeSuggestion { @@ -311,6 +349,23 @@ impl Diagnostic { self } + pub fn span_suggestion_short_with_applicability( + &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability + ) -> &mut Self { + self.suggestions.push(CodeSuggestion { + substitutions: vec![Substitution { + parts: vec![SubstitutionPart { + snippet: suggestion, + span: sp, + }], + }], + msg: msg.to_owned(), + show_code_when_inline: false, + applicability: applicability, + }); + self + } + pub fn set_span>(&mut self, sp: S) -> &mut Self { self.span = sp.into(); self @@ -343,7 +398,7 @@ impl Diagnostic { /// Convenience function for internal use, clients should use one of the /// public methods above. - pub(crate) fn sub(&mut self, + pub fn sub(&mut self, level: Level, message: &str, span: MultiSpan, diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs index 7e9ca8633a53e..a0f3abda077f9 100644 --- a/src/librustc_errors/diagnostic_builder.rs +++ b/src/librustc_errors/diagnostic_builder.rs @@ -88,23 +88,16 @@ impl<'a> DiagnosticBuilder<'a> { self.cancel(); } - pub fn is_error(&self) -> bool { - match self.level { - Level::Bug | - Level::Fatal | - Level::PhaseFatal | - Level::Error | - Level::FailureNote => { - true - } - - Level::Warning | - Level::Note | - Level::Help | - Level::Cancelled => { - false - } - } + /// Buffers the diagnostic for later emission. + pub fn buffer(self, buffered_diagnostics: &mut Vec) { + // We need to use `ptr::read` because `DiagnosticBuilder` + // implements `Drop`. + let diagnostic; + unsafe { + diagnostic = ::std::ptr::read(&self.diagnostic); + ::std::mem::forget(self); + }; + buffered_diagnostics.push(diagnostic); } /// Convenience function for internal use, clients should use one of the @@ -132,7 +125,7 @@ impl<'a> DiagnosticBuilder<'a> { /// locally in whichever way makes the most sense. pub fn delay_as_bug(&mut self) { self.level = Level::Bug; - *self.handler.delayed_span_bug.borrow_mut() = Some(self.diagnostic.clone()); + self.handler.delay_as_bug(self.diagnostic.clone()); self.cancel(); } @@ -148,17 +141,17 @@ impl<'a> DiagnosticBuilder<'a> { } forward!(pub fn note_expected_found(&mut self, - label: &fmt::Display, + label: &dyn fmt::Display, expected: DiagnosticStyledString, found: DiagnosticStyledString) -> &mut Self); forward!(pub fn note_expected_found_extra(&mut self, - label: &fmt::Display, + label: &dyn fmt::Display, expected: DiagnosticStyledString, found: DiagnosticStyledString, - expected_extra: &fmt::Display, - found_extra: &fmt::Display) + expected_extra: &dyn fmt::Display, + found_extra: &dyn fmt::Display) -> &mut Self); forward!(pub fn note(&mut self, msg: &str) -> &mut Self); @@ -178,6 +171,11 @@ impl<'a> DiagnosticBuilder<'a> { msg: &str, suggestion: String) -> &mut Self); + forward!(pub fn multipart_suggestion( + &mut self, + msg: &str, + suggestion: Vec<(Span, String)> + ) -> &mut Self); forward!(pub fn span_suggestion(&mut self, sp: Span, msg: &str, @@ -200,6 +198,12 @@ impl<'a> DiagnosticBuilder<'a> { suggestions: Vec, applicability: Applicability) -> &mut Self); + forward!(pub fn span_suggestion_short_with_applicability(&mut self, + sp: Span, + msg: &str, + suggestion: String, + applicability: Applicability) + -> &mut Self); forward!(pub fn set_span>(&mut self, sp: S) -> &mut Self); forward!(pub fn code(&mut self, s: DiagnosticId) -> &mut Self); diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 91075ddcfa422..09295e2c7ff00 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -10,7 +10,7 @@ use self::Destination::*; -use syntax_pos::{DUMMY_SP, FileMap, Span, MultiSpan}; +use syntax_pos::{FileMap, Span, MultiSpan}; use {Level, CodeSuggestion, DiagnosticBuilder, SubDiagnostic, CodeMapperDyn, DiagnosticId}; use snippet::{Annotation, AnnotationType, Line, MultilineAnnotation, StyledString, Style}; @@ -22,7 +22,7 @@ use std::borrow::Cow; use std::io::prelude::*; use std::io; use std::collections::HashMap; -use std::cmp::min; +use std::cmp::{min, Reverse}; use termcolor::{StandardStream, ColorChoice, ColorSpec, BufferWriter}; use termcolor::{WriteColor, Color, Buffer}; use unicode_width; @@ -148,7 +148,7 @@ impl EmitterWriter { } } - pub fn new(dst: Box, + pub fn new(dst: Box, code_map: Option>, short_message: bool, teach: bool) @@ -216,7 +216,7 @@ impl EmitterWriter { if let Some(ref cm) = self.cm { for span_label in msp.span_labels() { - if span_label.span == DUMMY_SP { + if span_label.span.is_dummy() { continue; } @@ -265,9 +265,7 @@ impl EmitterWriter { } // Find overlapping multiline annotations, put them at different depths - multiline_annotations.sort_by(|a, b| { - (a.1.line_start, a.1.line_end).cmp(&(b.1.line_start, b.1.line_end)) - }); + multiline_annotations.sort_by_key(|&(_, ref ml)| (ml.line_start, ml.line_end)); for item in multiline_annotations.clone() { let ann = item.1; for item in multiline_annotations.iter_mut() { @@ -403,7 +401,7 @@ impl EmitterWriter { // otherwise the lines would end up needing to go over a message. let mut annotations = line.annotations.clone(); - annotations.sort_by(|a,b| b.start_col.cmp(&a.start_col)); + annotations.sort_by_key(|a| Reverse(a.start_col)); // First, figure out where each label will be positioned. // @@ -530,9 +528,7 @@ impl EmitterWriter { // If there are no annotations or the only annotations on this line are // MultilineLine, then there's only code being shown, stop processing. - if line.annotations.is_empty() || line.annotations.iter() - .filter(|a| !a.is_line()).collect::>().len() == 0 - { + if line.annotations.iter().all(|a| a.is_line()) { return vec![]; } @@ -730,7 +726,7 @@ impl EmitterWriter { let mut max = 0; if let Some(ref cm) = self.cm { for primary_span in msp.primary_spans() { - if primary_span != &DUMMY_SP { + if !primary_span.is_dummy() { let hi = cm.lookup_char_pos(primary_span.hi()); if hi.line > max { max = hi.line; @@ -739,7 +735,7 @@ impl EmitterWriter { } if !self.short_message { for span_label in msp.span_labels() { - if span_label.span != DUMMY_SP { + if !span_label.span.is_dummy() { let hi = cm.lookup_char_pos(span_label.span.hi()); if hi.line > max { max = hi.line; @@ -751,7 +747,7 @@ impl EmitterWriter { max } - fn get_max_line_num(&mut self, span: &MultiSpan, children: &Vec) -> usize { + fn get_max_line_num(&mut self, span: &MultiSpan, children: &[SubDiagnostic]) -> usize { let mut max = 0; let primary = self.get_multispan_max_line_num(span); @@ -778,7 +774,7 @@ impl EmitterWriter { // First, find all the spans in <*macros> and point instead at their use site for sp in span.primary_spans() { - if *sp == DUMMY_SP { + if sp.is_dummy() { continue; } let call_sp = cm.call_span_if_macro(*sp); @@ -790,7 +786,7 @@ impl EmitterWriter { // Only show macro locations that are local // and display them like a span_note if let Some(def_site) = trace.def_site_span { - if def_site == DUMMY_SP { + if def_site.is_dummy() { continue; } if always_backtrace { @@ -830,7 +826,7 @@ impl EmitterWriter { span.push_span_label(label_span, label_text); } for sp_label in span.span_labels() { - if sp_label.span == DUMMY_SP { + if sp_label.span.is_dummy() { continue; } if cm.span_to_filename(sp_label.span.clone()).is_macros() && @@ -903,9 +899,7 @@ impl EmitterWriter { // | | length of label // | magic `3` // `max_line_num_len` - let padding = (0..padding + label.len() + 5) - .map(|_| " ") - .collect::(); + let padding = " ".repeat(padding + label.len() + 5); /// Return whether `style`, or the override if present and the style is `NoStyle`. fn style_or_override(style: Style, override_style: Option