]> git.lizzy.rs Git - rust.git/commitdiff
Rollup merge of #89235 - yaahc:junit-formatting, r=kennytm
authorGuillaume Gomez <guillaume1.gomez@gmail.com>
Tue, 28 Sep 2021 18:00:15 +0000 (20:00 +0200)
committerGitHub <noreply@github.com>
Tue, 28 Sep 2021 18:00:15 +0000 (20:00 +0200)
make junit output more consistent with default format

The default format of libtest includes new-lines between each section to ensure the label output from cargo is on it's own line

<pre><font color="#A1B56C"><b>❯</b></font> <font color="#A1B56C">cargo</font><font color="#D8D8D8"> </font><font color="#A1B56C">test</font>
<font color="#A1B56C"><b>   Compiling</b></font> test-test v0.1.0 (/home/jlusby/tmp/test-test)
<font color="#A1B56C"><b>    Finished</b></font> test [unoptimized + debuginfo] target(s) in 0.59s
<font color="#A1B56C"><b>     Running</b></font> unittests (target/debug/deps/test_test-639f369234319c09)

running 1 test
test tests::it_works ... <font color="#A1B56C">ok</font>

test result: <font color="#A1B56C">ok</font>. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

<font color="#A1B56C"><b>   Doc-tests</b></font> test-test

running 0 tests

test result: <font color="#A1B56C">ok</font>. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

</pre>

But when the junit outputter was added to libtest these newlines were omitted, resulting in some "fun" output when run via cargo.

Note the `Doc-tests` text at the end of the first line of xml.

<pre><font color="#A1B56C"><b>❯</b></font> <font color="#A1B56C">cargo</font><font color="#D8D8D8"> </font><font color="#A1B56C">test</font><font color="#D8D8D8"> </font><font color="#A1B56C">--</font><font color="#D8D8D8"> </font><font color="#A1B56C">-Zunstable-options</font><font color="#D8D8D8"> </font><font color="#A1B56C">--format</font><font color="#D8D8D8"> </font><font color="#A1B56C">junit</font>
<font color="#A1B56C"><b>    Finished</b></font> test [unoptimized + debuginfo] target(s) in 0.00s
<font color="#A1B56C"><b>     Running</b></font> unittests (target/debug/deps/test_test-639f369234319c09)
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;testsuites&gt;&lt;testsuite name=&quot;test&quot; package=&quot;test&quot; id=&quot;0&quot; errors=&quot;0&quot; failures=&quot;0&quot; tests=&quot;1&quot; skipped=&quot;0&quot; &gt;&lt;testcase classname=&quot;tests&quot; name=&quot;it_works&quot; time=&quot;0&quot;/&gt;&lt;system-out/&gt;&lt;system-err/&gt;&lt;/testsuite&gt;&lt;/testsuites&gt;<font color="#A1B56C"><b>   Doc-tests</b></font> test-test
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;testsuites&gt;&lt;testsuite name=&quot;test&quot; package=&quot;test&quot; id=&quot;0&quot; errors=&quot;0&quot; failures=&quot;0&quot; tests=&quot;0&quot; skipped=&quot;0&quot; &gt;&lt;system-out/&gt;&lt;system-err/&gt;&lt;/testsuite&gt;&lt;/testsuites&gt;

</pre>

After this PR the junit output includes the same style of newlines as the pretty format

<pre><font color="#A1B56C"><b>❯</b></font> <font color="#A1B56C">cargo</font><font color="#D8D8D8"> </font><font color="#A1B56C">test</font><font color="#D8D8D8"> </font><font color="#A1B56C">--</font><font color="#D8D8D8"> </font><font color="#A1B56C">-Zunstable-options</font><font color="#D8D8D8"> </font><font color="#A1B56C">--format</font><font color="#D8D8D8"> </font><font color="#A1B56C">junit</font>
<font color="#A1B56C"><b>   Compiling</b></font> test-test v0.1.0 (/home/jlusby/tmp/test-test)
<font color="#A1B56C"><b>    Finished</b></font> test [unoptimized + debuginfo] target(s) in 0.39s
<font color="#A1B56C"><b>     Running</b></font> unittests (target/debug/deps/test_test-42c2320bb9450c69)

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;testsuites&gt;&lt;testsuite name=&quot;test&quot; package=&quot;test&quot; id=&quot;0&quot; errors=&quot;0&quot; failures=&quot;0&quot; tests=&quot;1&quot; skipped=&quot;0&quot; &gt;&lt;testcase classname=&quot;tests&quot; name=&quot;it_works&quot; time=&quot;0&quot;/&gt;&lt;system-out/&gt;&lt;system-err/&gt;&lt;/testsuite&gt;&lt;/testsuites&gt;

<font color="#A1B56C"><b>   Doc-tests</b></font> test-test

&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;&lt;testsuites&gt;&lt;testsuite name=&quot;test&quot; package=&quot;test&quot; id=&quot;0&quot; errors=&quot;0&quot; failures=&quot;0&quot; tests=&quot;0&quot; skipped=&quot;0&quot; &gt;&lt;system-out/&gt;&lt;system-err/&gt;&lt;/testsuite&gt;&lt;/testsuites&gt;

</pre>

837 files changed:
Cargo.toml
RELEASES.md
compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
compiler/rustc_borrowck/src/diagnostics/region_errors.rs
compiler/rustc_borrowck/src/invalidation.rs
compiler/rustc_borrowck/src/lib.rs
compiler/rustc_borrowck/src/region_infer/mod.rs
compiler/rustc_borrowck/src/type_check/canonical.rs
compiler/rustc_borrowck/src/type_check/mod.rs
compiler/rustc_builtin_macros/src/cfg_eval.rs
compiler/rustc_builtin_macros/src/derive.rs
compiler/rustc_codegen_cranelift/.gitignore
compiler/rustc_codegen_cranelift/Cargo.lock
compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
compiler/rustc_codegen_cranelift/build_system/prepare.rs
compiler/rustc_codegen_cranelift/clean_all.sh
compiler/rustc_codegen_cranelift/docs/usage.md
compiler/rustc_codegen_cranelift/example/alloc_example.rs
compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch [new file with mode: 0644]
compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch [deleted file]
compiler/rustc_codegen_cranelift/patches/0027-sysroot-128bit-atomic-operations.patch
compiler/rustc_codegen_cranelift/rust-toolchain
compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
compiler/rustc_codegen_cranelift/scripts/tests.sh
compiler/rustc_codegen_cranelift/src/archive.rs
compiler/rustc_codegen_cranelift/src/backend.rs [deleted file]
compiler/rustc_codegen_cranelift/src/base.rs
compiler/rustc_codegen_cranelift/src/bin/cg_clif.rs
compiler/rustc_codegen_cranelift/src/bin/cg_clif_build_sysroot.rs
compiler/rustc_codegen_cranelift/src/debuginfo/emit.rs
compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs
compiler/rustc_codegen_cranelift/src/debuginfo/object.rs [new file with mode: 0644]
compiler/rustc_codegen_cranelift/src/debuginfo/unwind.rs
compiler/rustc_codegen_cranelift/src/driver/aot.rs
compiler/rustc_codegen_cranelift/src/lib.rs
compiler/rustc_codegen_cranelift/src/metadata.rs
compiler/rustc_codegen_gcc/.github/workflows/main.yml [new file with mode: 0644]
compiler/rustc_codegen_gcc/.gitignore [new file with mode: 0644]
compiler/rustc_codegen_gcc/Cargo.lock [new file with mode: 0644]
compiler/rustc_codegen_gcc/Cargo.toml [new file with mode: 0644]
compiler/rustc_codegen_gcc/LICENSE-APACHE [new file with mode: 0644]
compiler/rustc_codegen_gcc/LICENSE-MIT [new file with mode: 0644]
compiler/rustc_codegen_gcc/Readme.md [new file with mode: 0644]
compiler/rustc_codegen_gcc/build.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml [new file with mode: 0644]
compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/cargo.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/clean_all.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/config.sh [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/alloc_example.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/alloc_system.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/dst-field-align.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/example.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/mini_core.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/mod_bench.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/std_example.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/example/track-caller-attribute.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch [new file with mode: 0644]
compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch [new file with mode: 0644]
compiler/rustc_codegen_gcc/prepare.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/prepare_build.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/rust-toolchain [new file with mode: 0644]
compiler/rustc_codegen_gcc/rustup.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/src/abi.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/allocator.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/archive.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/asm.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/back/mod.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/back/write.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/base.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/builder.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/callee.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/common.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/consts.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/context.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/coverageinfo.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/debuginfo.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/declare.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/intrinsic/mod.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/intrinsic/simd.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/lib.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/mono_item.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/type_.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/src/type_of.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/test.sh [new file with mode: 0755]
compiler/rustc_codegen_gcc/tests/lib.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/abort1.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/abort2.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/array.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/asm.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/assign.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/closure.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/condition.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/empty_main.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/exit.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/exit_code.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/int_overflow.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/mut_ref.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/operations.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/return-tuple.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/slice.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/static.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/structs.rs [new file with mode: 0644]
compiler/rustc_codegen_gcc/tests/run/tuple.rs [new file with mode: 0644]
compiler/rustc_codegen_llvm/src/back/write.rs
compiler/rustc_codegen_llvm/src/intrinsic.rs
compiler/rustc_codegen_ssa/src/mir/rvalue.rs
compiler/rustc_const_eval/src/interpret/step.rs
compiler/rustc_const_eval/src/transform/check_consts/check.rs
compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
compiler/rustc_const_eval/src/transform/promote_consts.rs
compiler/rustc_data_structures/src/graph/scc/mod.rs
compiler/rustc_data_structures/src/sorted_map.rs
compiler/rustc_data_structures/src/steal.rs
compiler/rustc_expand/src/module.rs
compiler/rustc_expand/src/proc_macro_server.rs
compiler/rustc_feature/src/accepted.rs
compiler/rustc_feature/src/active.rs
compiler/rustc_infer/src/infer/canonical/query_response.rs
compiler/rustc_infer/src/infer/combine.rs
compiler/rustc_infer/src/infer/error_reporting/mod.rs
compiler/rustc_infer/src/infer/sub.rs
compiler/rustc_infer/src/traits/engine.rs
compiler/rustc_infer/src/traits/util.rs
compiler/rustc_interface/src/lib.rs
compiler/rustc_interface/src/passes.rs
compiler/rustc_interface/src/util.rs
compiler/rustc_lint/src/context.rs
compiler/rustc_lint/src/early.rs
compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
compiler/rustc_middle/src/mir/mod.rs
compiler/rustc_middle/src/mir/query.rs
compiler/rustc_middle/src/mir/tcx.rs
compiler/rustc_middle/src/mir/type_foldable.rs
compiler/rustc_middle/src/mir/visit.rs
compiler/rustc_middle/src/ty/mod.rs
compiler/rustc_middle/src/ty/sty.rs
compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
compiler/rustc_mir_dataflow/src/move_paths/builder.rs
compiler/rustc_mir_transform/src/const_prop.rs
compiler/rustc_mir_transform/src/dest_prop.rs
compiler/rustc_mir_transform/src/separate_const_switch.rs
compiler/rustc_parse/src/parser/item.rs
compiler/rustc_parse/src/validate_attr.rs
compiler/rustc_resolve/src/diagnostics.rs
compiler/rustc_resolve/src/late/diagnostics.rs
compiler/rustc_resolve/src/lib.rs
compiler/rustc_resolve/src/macros.rs
compiler/rustc_span/src/symbol.rs
compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs [new file with mode: 0644]
compiler/rustc_target/src/spec/mod.rs
compiler/rustc_target/src/spec/solid_base.rs [new file with mode: 0644]
compiler/rustc_trait_selection/src/autoderef.rs
compiler/rustc_trait_selection/src/infer.rs
compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
compiler/rustc_trait_selection/src/traits/fulfill.rs
compiler/rustc_trait_selection/src/traits/mod.rs
compiler/rustc_trait_selection/src/traits/object_safety.rs
compiler/rustc_trait_selection/src/traits/project.rs
compiler/rustc_trait_selection/src/traits/query/normalize.rs
compiler/rustc_trait_selection/src/traits/select/confirmation.rs
compiler/rustc_trait_selection/src/traits/util.rs
compiler/rustc_trait_selection/src/traits/wf.rs
compiler/rustc_traits/src/lib.rs
compiler/rustc_traits/src/type_op.rs
compiler/rustc_ty_utils/src/needs_drop.rs
compiler/rustc_typeck/src/check/_match.rs
compiler/rustc_typeck/src/check/callee.rs
compiler/rustc_typeck/src/check/coercion.rs
compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs
compiler/rustc_typeck/src/check/method/mod.rs
compiler/rustc_typeck/src/check/method/probe.rs
compiler/rustc_typeck/src/check/method/suggest.rs
compiler/rustc_typeck/src/check/upvar.rs
compiler/rustc_typeck/src/check/wfcheck.rs
compiler/rustc_typeck/src/collect.rs
compiler/rustc_typeck/src/hir_wf_check.rs
compiler/rustc_typeck/src/outlives/mod.rs
compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
library/alloc/src/alloc.rs
library/alloc/src/collections/binary_heap.rs
library/alloc/src/collections/btree/map.rs
library/alloc/src/collections/btree/set.rs
library/alloc/src/collections/linked_list.rs
library/alloc/src/collections/vec_deque/into_iter.rs
library/alloc/src/collections/vec_deque/mod.rs
library/alloc/src/fmt.rs
library/alloc/src/rc.rs
library/alloc/src/string.rs
library/alloc/src/sync.rs
library/alloc/src/vec/into_iter.rs
library/alloc/src/vec/mod.rs
library/core/src/array/iter.rs
library/core/src/iter/mod.rs
library/core/src/iter/traits/iterator.rs
library/core/src/option.rs
library/core/src/pin.rs
library/core/src/result.rs
library/core/src/stream/stream/mod.rs
library/core/src/task/poll.rs
library/panic_abort/src/lib.rs
library/panic_unwind/src/lib.rs
library/std/Cargo.toml
library/std/build.rs
library/std/src/collections/hash/map.rs
library/std/src/collections/hash/set.rs
library/std/src/collections/mod.rs
library/std/src/ffi/c_str.rs
library/std/src/ffi/mod.rs
library/std/src/ffi/os_str.rs
library/std/src/fs.rs
library/std/src/io/buffered/bufreader.rs
library/std/src/io/buffered/bufwriter.rs
library/std/src/io/cursor.rs
library/std/src/io/mod.rs
library/std/src/io/util.rs
library/std/src/net/addr.rs
library/std/src/net/mod.rs
library/std/src/os/mod.rs
library/std/src/os/solid/ffi.rs [new file with mode: 0644]
library/std/src/os/solid/io.rs [new file with mode: 0644]
library/std/src/os/solid/mod.rs [new file with mode: 0644]
library/std/src/path.rs
library/std/src/sys/itron/abi.rs [new file with mode: 0644]
library/std/src/sys/itron/condvar.rs [new file with mode: 0644]
library/std/src/sys/itron/error.rs [new file with mode: 0644]
library/std/src/sys/itron/mutex.rs [new file with mode: 0644]
library/std/src/sys/itron/spin.rs [new file with mode: 0644]
library/std/src/sys/itron/task.rs [new file with mode: 0644]
library/std/src/sys/itron/thread.rs [new file with mode: 0644]
library/std/src/sys/itron/time.rs [new file with mode: 0644]
library/std/src/sys/itron/time/tests.rs [new file with mode: 0644]
library/std/src/sys/mod.rs
library/std/src/sys/solid/abi/fs.rs [new file with mode: 0644]
library/std/src/sys/solid/abi/mod.rs [new file with mode: 0644]
library/std/src/sys/solid/abi/sockets.rs [new file with mode: 0644]
library/std/src/sys/solid/alloc.rs [new file with mode: 0644]
library/std/src/sys/solid/env.rs [new file with mode: 0644]
library/std/src/sys/solid/error.rs [new file with mode: 0644]
library/std/src/sys/solid/fs.rs [new file with mode: 0644]
library/std/src/sys/solid/io.rs [new file with mode: 0644]
library/std/src/sys/solid/memchr.rs [new file with mode: 0644]
library/std/src/sys/solid/mod.rs [new file with mode: 0644]
library/std/src/sys/solid/net.rs [new file with mode: 0644]
library/std/src/sys/solid/os.rs [new file with mode: 0644]
library/std/src/sys/solid/path.rs [new file with mode: 0644]
library/std/src/sys/solid/rwlock.rs [new file with mode: 0644]
library/std/src/sys/solid/stdio.rs [new file with mode: 0644]
library/std/src/sys/solid/thread_local_dtor.rs [new file with mode: 0644]
library/std/src/sys/solid/thread_local_key.rs [new file with mode: 0644]
library/std/src/sys/solid/time.rs [new file with mode: 0644]
library/std/src/time.rs
library/stdarch
library/test/Cargo.toml
library/unwind/src/lib.rs
rustfmt.toml
src/bootstrap/builder.rs
src/bootstrap/check.rs
src/bootstrap/doc.rs
src/bootstrap/setup.rs
src/doc/rustc/src/SUMMARY.md
src/doc/rustc/src/platform-support.md
src/doc/rustc/src/platform-support/kmc-solid.md [new file with mode: 0644]
src/librustdoc/clean/auto_trait.rs
src/librustdoc/clean/blanket_impl.rs
src/librustdoc/clean/inline.rs
src/librustdoc/clean/mod.rs
src/librustdoc/clean/types.rs
src/librustdoc/clean/utils.rs
src/librustdoc/html/format.rs
src/librustdoc/html/markdown.rs
src/librustdoc/html/render/print_item.rs
src/librustdoc/json/conversions.rs
src/librustdoc/passes/check_code_block_syntax.rs
src/librustdoc/passes/stripper.rs
src/test/codegen-units/partitioning/extern-drop-glue.rs
src/test/codegen-units/partitioning/extern-generic.rs
src/test/codegen-units/partitioning/incremental-merging.rs
src/test/codegen-units/partitioning/inlining-from-extern-crate.rs
src/test/codegen-units/partitioning/local-drop-glue.rs
src/test/codegen-units/partitioning/local-generic.rs
src/test/codegen-units/partitioning/local-inlining-but-not-all.rs
src/test/codegen-units/partitioning/local-inlining.rs
src/test/codegen-units/partitioning/local-transitive-inlining.rs
src/test/codegen-units/partitioning/methods-are-with-self-type.rs
src/test/codegen-units/partitioning/regular-modules.rs
src/test/codegen-units/partitioning/shared-generics.rs
src/test/codegen-units/partitioning/statics.rs
src/test/codegen-units/partitioning/vtable-through-const.rs
src/test/codegen/panic-in-drop-abort.rs
src/test/debuginfo/borrowed-struct.rs
src/test/debuginfo/borrowed-tuple.rs
src/test/debuginfo/borrowed-unique-basic.rs
src/test/debuginfo/box.rs
src/test/debuginfo/boxed-struct.rs
src/test/debuginfo/closure-in-generic-function.rs
src/test/debuginfo/destructured-fn-argument.rs
src/test/debuginfo/destructured-for-loop-variable.rs
src/test/debuginfo/destructured-local.rs
src/test/debuginfo/generic-method-on-generic-struct.rs
src/test/debuginfo/method-on-enum.rs
src/test/debuginfo/method-on-generic-struct.rs
src/test/debuginfo/method-on-struct.rs
src/test/debuginfo/method-on-trait.rs
src/test/debuginfo/method-on-tuple-struct.rs
src/test/debuginfo/recursive-struct.rs
src/test/debuginfo/self-in-default-method.rs
src/test/debuginfo/self-in-generic-default-method.rs
src/test/debuginfo/trait-pointers.rs
src/test/debuginfo/type-names.rs
src/test/debuginfo/unique-enum.rs
src/test/debuginfo/var-captured-in-nested-closure.rs
src/test/debuginfo/var-captured-in-sendable-closure.rs
src/test/debuginfo/var-captured-in-stack-closure.rs
src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir
src/test/mir-opt/const_prop/boxes.main.ConstProp.diff
src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff
src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff
src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir
src/test/mir-opt/uniform_array_move_out.move_out_by_subslice.mir_map.0.mir
src/test/mir-opt/uniform_array_move_out.move_out_from_end.mir_map.0.mir
src/test/rustdoc-ui/doctest-edition.rs [new file with mode: 0644]
src/test/rustdoc-ui/doctest-edition.stderr [new file with mode: 0644]
src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs [new file with mode: 0644]
src/test/rustdoc/hidden-trait-methods.rs [new file with mode: 0644]
src/test/ui-fulldeps/auxiliary/issue-40001-plugin.rs
src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs
src/test/ui-fulldeps/auxiliary/lint-for-crate.rs
src/test/ui-fulldeps/auxiliary/lint-group-plugin-test.rs
src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs
src/test/ui-fulldeps/auxiliary/lint-tool-test.rs
src/test/ui-fulldeps/auxiliary/outlive-expansion-phase.rs
src/test/ui-fulldeps/deriving-encodable-decodable-box.rs
src/test/ui/alignment-gep-tup-like-1.rs
src/test/ui/array-slice-vec/vec-dst.rs
src/test/ui/array-slice-vec/vector-no-ann-2.rs
src/test/ui/asm/aarch64/bad-options.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/bad-options.stderr [new file with mode: 0644]
src/test/ui/asm/aarch64/bad-reg.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/bad-reg.stderr [new file with mode: 0644]
src/test/ui/asm/aarch64/const.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/duplicate-options.fixed [new file with mode: 0644]
src/test/ui/asm/aarch64/duplicate-options.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/duplicate-options.stderr [new file with mode: 0644]
src/test/ui/asm/aarch64/interpolated-idents.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/interpolated-idents.stderr [new file with mode: 0644]
src/test/ui/asm/aarch64/parse-error.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/parse-error.stderr [new file with mode: 0644]
src/test/ui/asm/aarch64/srcloc.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/srcloc.stderr [new file with mode: 0644]
src/test/ui/asm/aarch64/sym.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/type-check-2.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/type-check-2.stderr [new file with mode: 0644]
src/test/ui/asm/aarch64/type-check-3.rs [new file with mode: 0644]
src/test/ui/asm/aarch64/type-check-3.stderr [new file with mode: 0644]
src/test/ui/asm/bad-options.rs [deleted file]
src/test/ui/asm/bad-options.stderr [deleted file]
src/test/ui/asm/bad-reg.rs [deleted file]
src/test/ui/asm/bad-reg.stderr [deleted file]
src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr [new file with mode: 0644]
src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr [new file with mode: 0644]
src/test/ui/asm/bad-template.mirunsafeck.stderr [deleted file]
src/test/ui/asm/bad-template.rs
src/test/ui/asm/bad-template.thirunsafeck.stderr [deleted file]
src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr [new file with mode: 0644]
src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr [new file with mode: 0644]
src/test/ui/asm/const.rs [deleted file]
src/test/ui/asm/duplicate-options.fixed [deleted file]
src/test/ui/asm/duplicate-options.rs [deleted file]
src/test/ui/asm/duplicate-options.stderr [deleted file]
src/test/ui/asm/interpolated-idents.rs [deleted file]
src/test/ui/asm/interpolated-idents.stderr [deleted file]
src/test/ui/asm/issue-72570.rs
src/test/ui/asm/issue-82869.rs [deleted file]
src/test/ui/asm/issue-82869.stderr [deleted file]
src/test/ui/asm/issue-87802.rs
src/test/ui/asm/issue-87802.stderr
src/test/ui/asm/naked-functions-ffi.rs
src/test/ui/asm/naked-functions-unused.aarch64.stderr [new file with mode: 0644]
src/test/ui/asm/naked-functions-unused.rs
src/test/ui/asm/naked-functions-unused.stderr [deleted file]
src/test/ui/asm/naked-functions-unused.x86_64.stderr [new file with mode: 0644]
src/test/ui/asm/naked-functions.rs
src/test/ui/asm/naked-functions.stderr
src/test/ui/asm/named-asm-labels.rs
src/test/ui/asm/named-asm-labels.stderr
src/test/ui/asm/noreturn.rs
src/test/ui/asm/parse-error.rs [deleted file]
src/test/ui/asm/parse-error.stderr [deleted file]
src/test/ui/asm/rustfix-asm.fixed
src/test/ui/asm/rustfix-asm.rs
src/test/ui/asm/srcloc.rs [deleted file]
src/test/ui/asm/srcloc.stderr [deleted file]
src/test/ui/asm/sym.rs [deleted file]
src/test/ui/asm/type-check-1.rs
src/test/ui/asm/type-check-1.stderr
src/test/ui/asm/type-check-2.rs [deleted file]
src/test/ui/asm/type-check-2.stderr [deleted file]
src/test/ui/asm/type-check-3.rs [deleted file]
src/test/ui/asm/type-check-3.stderr [deleted file]
src/test/ui/asm/type-check-4.rs
src/test/ui/asm/type-check-4.stderr
src/test/ui/asm/x86_64/bad-options.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/bad-options.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/bad-reg.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/bad-reg.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/const.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/duplicate-options.fixed [new file with mode: 0644]
src/test/ui/asm/x86_64/duplicate-options.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/duplicate-options.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/interpolated-idents.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/interpolated-idents.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/issue-82869.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/issue-82869.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/parse-error.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/parse-error.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/srcloc.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/srcloc.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/sym.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/type-check-2.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/type-check-2.stderr [new file with mode: 0644]
src/test/ui/asm/x86_64/type-check-3.rs [new file with mode: 0644]
src/test/ui/asm/x86_64/type-check-3.stderr [new file with mode: 0644]
src/test/ui/associated-type-bounds/traits-assoc-type-macros.rs
src/test/ui/associated-types/associated-types-doubleendediterator-object.rs
src/test/ui/associated-types/higher-ranked-projection.bad.nll.stderr
src/test/ui/async-await/issue-72442.rs
src/test/ui/async-await/issues/issue-64964.rs
src/test/ui/attributes/register-attr-tool-fail.stderr
src/test/ui/autoderef-full-lval.rs
src/test/ui/autoref-autoderef/autoderef-method-on-trait.rs
src/test/ui/autoref-autoderef/autoderef-method-priority.rs
src/test/ui/autoref-autoderef/autoderef-method-twice-but-not-thrice.rs
src/test/ui/autoref-autoderef/autoderef-method-twice.rs
src/test/ui/autoref-autoderef/autoderef-method.rs
src/test/ui/autoref-autoderef/autoref-intermediate-types-issue-3585.rs
src/test/ui/binding/expr-match-generic-unique1.rs
src/test/ui/binding/expr-match-generic-unique2.rs
src/test/ui/binding/expr-match-unique.rs
src/test/ui/binding/func-arg-incomplete-pattern.rs
src/test/ui/binding/func-arg-ref-pattern.rs
src/test/ui/binding/let-assignability.rs
src/test/ui/binding/match-implicit-copy-unique.rs
src/test/ui/binding/match-unique-bind.rs
src/test/ui/binding/match-value-binding-in-guard-3291.rs
src/test/ui/borrowck/borrow-tuple-fields.rs
src/test/ui/borrowck/borrowck-bad-nested-calls-free.rs
src/test/ui/borrowck/borrowck-bad-nested-calls-move.rs
src/test/ui/borrowck/borrowck-borrow-from-expr-block.rs
src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.rs
src/test/ui/borrowck/borrowck-borrow-immut-deref-of-box-as-mut.stderr
src/test/ui/borrowck/borrowck-borrowed-uniq-rvalue.rs
src/test/ui/borrowck/borrowck-box-sensitivity.rs
src/test/ui/borrowck/borrowck-closures-mut-and-imm.rs
src/test/ui/borrowck/borrowck-closures-two-mut-fail.rs
src/test/ui/borrowck/borrowck-closures-two-mut.rs
src/test/ui/borrowck/borrowck-closures-use-after-free.rs
src/test/ui/borrowck/borrowck-closures-use-after-free.stderr
src/test/ui/borrowck/borrowck-field-sensitivity-rpass.rs
src/test/ui/borrowck/borrowck-field-sensitivity.rs
src/test/ui/borrowck/borrowck-field-sensitivity.stderr
src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.rs
src/test/ui/borrowck/borrowck-issue-14498.rs
src/test/ui/borrowck/borrowck-issue-2657-1.rs
src/test/ui/borrowck/borrowck-issue-2657-2.rs
src/test/ui/borrowck/borrowck-lend-flow-if.rs
src/test/ui/borrowck/borrowck-lend-flow-loop.rs
src/test/ui/borrowck/borrowck-lend-flow-loop.stderr
src/test/ui/borrowck/borrowck-lend-flow.rs
src/test/ui/borrowck/borrowck-loan-blocks-move-cc.rs
src/test/ui/borrowck/borrowck-loan-blocks-move.rs
src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.rs
src/test/ui/borrowck/borrowck-loan-blocks-mut-uniq.stderr
src/test/ui/borrowck/borrowck-loan-in-overloaded-op.rs
src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
src/test/ui/borrowck/borrowck-macro-interaction-issue-6304.rs
src/test/ui/borrowck/borrowck-move-by-capture-ok.rs
src/test/ui/borrowck/borrowck-move-by-capture.rs
src/test/ui/borrowck/borrowck-move-by-capture.stderr
src/test/ui/borrowck/borrowck-move-error-with-note.rs
src/test/ui/borrowck/borrowck-move-from-subpath-of-borrowed-path.rs
src/test/ui/borrowck/borrowck-move-moved-value-into-closure.rs
src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr
src/test/ui/borrowck/borrowck-move-subcomponent.rs
src/test/ui/borrowck/borrowck-multiple-captures.rs
src/test/ui/borrowck/borrowck-multiple-captures.stderr
src/test/ui/borrowck/borrowck-mut-uniq.rs
src/test/ui/borrowck/borrowck-no-cycle-in-exchange-heap.rs
src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs
src/test/ui/borrowck/borrowck-uniq-via-lend.rs
src/test/ui/borrowck/borrowck-use-mut-borrow-rpass.rs
src/test/ui/borrowck/borrowck-use-mut-borrow.rs
src/test/ui/borrowck/borrowck-vec-pattern-nesting.rs
src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr
src/test/ui/borrowck/fsu-moves-and-copies.rs
src/test/ui/borrowck/issue-17263.rs
src/test/ui/cancel-clean-via-immediate-rvalue-ref.rs
src/test/ui/class-cast-to-trait.rs
src/test/ui/cleanup-arm-conditional.rs
src/test/ui/cleanup-rvalue-scopes.rs
src/test/ui/cleanup-rvalue-temp-during-incomplete-alloc.rs
src/test/ui/clone-with-exterior.rs
src/test/ui/close-over-big-then-small-data.rs
src/test/ui/closures/2229_closure_analysis/diagnostics/borrowck/borrowck-closures-mut-and-imm.rs
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.fixed
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.rs
src/test/ui/closures/2229_closure_analysis/migrations/auto_traits.stderr
src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.fixed
src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.rs
src/test/ui/closures/2229_closure_analysis/migrations/closure-body-macro-fragment.stderr
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.fixed
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.rs
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr [deleted file]
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.fixed
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.rs
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_migrations.stderr
src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop_attr_no_migrations.rs
src/test/ui/closures/2229_closure_analysis/migrations/macro.fixed
src/test/ui/closures/2229_closure_analysis/migrations/macro.rs
src/test/ui/closures/2229_closure_analysis/migrations/macro.stderr
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.fixed
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.rs
src/test/ui/closures/2229_closure_analysis/migrations/multi_diagnostics.stderr
src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.fixed
src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.rs
src/test/ui/closures/2229_closure_analysis/migrations/significant_drop.stderr
src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout [new file with mode: 0644]
src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout [new file with mode: 0644]
src/test/ui/coercion/coerce-expect-unsized.rs
src/test/ui/consts/miri_unleashed/box.rs
src/test/ui/consts/miri_unleashed/box.stderr
src/test/ui/crate-method-reexport-grrrrrrr.rs
src/test/ui/cross-crate/auxiliary/cci_nested_lib.rs
src/test/ui/cross-crate/cci_borrow.rs
src/test/ui/dep-graph/dep-graph-assoc-type-codegen.rs
src/test/ui/dep-graph/dep-graph-assoc-type-codegen.stderr
src/test/ui/dep-graph/dep-graph-caller-callee.rs
src/test/ui/dep-graph/dep-graph-caller-callee.stderr
src/test/ui/dep-graph/dep-graph-struct-signature.rs
src/test/ui/dep-graph/dep-graph-struct-signature.stderr
src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.rs
src/test/ui/dep-graph/dep-graph-trait-impl-two-traits-same-method.stderr
src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.rs
src/test/ui/dep-graph/dep-graph-trait-impl-two-traits.stderr
src/test/ui/dep-graph/dep-graph-trait-impl.rs
src/test/ui/dep-graph/dep-graph-trait-impl.stderr
src/test/ui/dep-graph/dep-graph-type-alias.rs
src/test/ui/dep-graph/dep-graph-type-alias.stderr
src/test/ui/dep-graph/dep-graph-variance-alias.rs
src/test/ui/dep-graph/dep-graph-variance-alias.stderr
src/test/ui/deref.rs
src/test/ui/derives/deriving-copyclone.stderr
src/test/ui/deriving/deriving-default-box.rs
src/test/ui/destructure-trait-ref.rs
src/test/ui/destructure-trait-ref.stderr
src/test/ui/drop/drop-on-empty-block-exit.rs
src/test/ui/drop/drop-struct-as-object.rs
src/test/ui/drop/drop-trait-enum.rs
src/test/ui/dynamically-sized-types/dst-trait-tuple.rs
src/test/ui/dynamically-sized-types/dst-tuple.rs
src/test/ui/expr-block-generic-unique1.rs
src/test/ui/expr-block-generic-unique2.rs
src/test/ui/expr-block-unique.rs
src/test/ui/expr-if-unique.rs
src/test/ui/fn/fn-trait-formatting.rs
src/test/ui/fn/fn-trait-formatting.stderr
src/test/ui/for-loop-while/cleanup-rvalue-during-if-and-while.rs
src/test/ui/gated-bad-feature.stderr
src/test/ui/generator/resume-arg-late-bound.nll.stderr
src/test/ui/generics/generic-alias-unique.rs
src/test/ui/generics/generic-exterior-unique.rs
src/test/ui/generics/generic-fn-unique.rs
src/test/ui/generics/generic-object.rs
src/test/ui/generics/generic-recursive-tag.rs
src/test/ui/generics/generic-tag.rs
src/test/ui/generics/generic-unique.rs
src/test/ui/infinite/infinite-autoderef.rs
src/test/ui/infinite/infinite-autoderef.stderr
src/test/ui/init-res-into-things.rs
src/test/ui/intrinsics/intrinsic-atomics.rs
src/test/ui/invalid/invalid-crate-type-macro.rs [new file with mode: 0644]
src/test/ui/invalid/invalid-crate-type-macro.stderr [new file with mode: 0644]
src/test/ui/invalid_crate_type_syntax.stderr
src/test/ui/issues/issue-20605.stderr
src/test/ui/kindck/kindck-impl-type-params-2.rs
src/test/ui/kindck/kindck-impl-type-params.rs
src/test/ui/kindck/kindck-inherited-copy-bound.rs
src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs [new file with mode: 0644]
src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr [new file with mode: 0644]
src/test/ui/lang-items/issue-83471.rs [new file with mode: 0644]
src/test/ui/lang-items/issue-83471.stderr [new file with mode: 0644]
src/test/ui/last-use-is-capture.rs
src/test/ui/leak-unique-as-tydesc.rs
src/test/ui/lifetimes/issue-79187-2.nll.stderr
src/test/ui/lifetimes/issue-79187.nll.stderr
src/test/ui/lifetimes/lifetime-errors/issue_74400.nll.stderr
src/test/ui/lint/known-tool-in-submodule/root.rs [new file with mode: 0644]
src/test/ui/lint/known-tool-in-submodule/submodule.rs [new file with mode: 0644]
src/test/ui/lint/lint-malformed.stderr
src/test/ui/lint/lint-owned-heap-memory.rs
src/test/ui/lint/lint-owned-heap-memory.stderr
src/test/ui/lint/unused/issue-47390-unused-variable-in-struct-pattern.rs
src/test/ui/list.rs
src/test/ui/liveness/liveness-move-call-arg.rs
src/test/ui/liveness/liveness-move-call-arg.stderr
src/test/ui/liveness/liveness-move-in-loop.rs
src/test/ui/liveness/liveness-move-in-loop.stderr
src/test/ui/liveness/liveness-move-in-while.rs
src/test/ui/liveness/liveness-move-in-while.stderr
src/test/ui/liveness/liveness-use-after-move.rs
src/test/ui/liveness/liveness-use-after-move.stderr
src/test/ui/macros/bang-after-name.fixed [new file with mode: 0644]
src/test/ui/macros/bang-after-name.rs [new file with mode: 0644]
src/test/ui/macros/bang-after-name.stderr [new file with mode: 0644]
src/test/ui/malformed/malformed-plugin-1.stderr
src/test/ui/malformed/malformed-plugin-2.stderr
src/test/ui/map-types.rs
src/test/ui/methods/auxiliary/method_self_arg1.rs
src/test/ui/methods/auxiliary/method_self_arg2.rs
src/test/ui/methods/method-self-arg-aux1.rs
src/test/ui/methods/method-self-arg-aux2.rs
src/test/ui/methods/method-self-arg-trait.rs
src/test/ui/methods/method-self-arg.rs
src/test/ui/methods/method-two-trait-defer-resolution-2.rs
src/test/ui/mismatched_types/closure-mismatch.nll.stderr
src/test/ui/modules/path-invalid-form.rs [new file with mode: 0644]
src/test/ui/modules/path-invalid-form.stderr [new file with mode: 0644]
src/test/ui/modules/path-macro.rs [new file with mode: 0644]
src/test/ui/modules/path-macro.stderr [new file with mode: 0644]
src/test/ui/moves/move-1-unique.rs
src/test/ui/moves/move-2-unique.rs
src/test/ui/moves/move-2.rs
src/test/ui/moves/move-3-unique.rs
src/test/ui/moves/move-4-unique.rs
src/test/ui/moves/move-4.rs
src/test/ui/moves/move-arg-2-unique.rs
src/test/ui/moves/move-arg-2.rs
src/test/ui/moves/move-guard-same-consts.rs
src/test/ui/moves/move-guard-same-consts.stderr
src/test/ui/moves/move-in-guard-1.rs
src/test/ui/moves/move-in-guard-1.stderr
src/test/ui/moves/move-in-guard-2.rs
src/test/ui/moves/move-in-guard-2.stderr
src/test/ui/moves/move-out-of-tuple-field.rs
src/test/ui/moves/moves-based-on-type-block-bad.rs
src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.rs
src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr
src/test/ui/moves/moves-based-on-type-tuple.rs
src/test/ui/moves/moves-based-on-type-tuple.stderr
src/test/ui/moves/moves-sru-moved-field.rs
src/test/ui/mut-function-arguments.rs
src/test/ui/mut/mut-cross-borrowing.rs
src/test/ui/new-box-syntax.rs
src/test/ui/new-box.rs
src/test/ui/nll/issue-52663-trait-object.rs
src/test/ui/nll/issue-52663-trait-object.stderr
src/test/ui/no_crate_type.stderr
src/test/ui/nullable-pointer-iotareduction.rs
src/test/ui/objects-owned-object-borrowed-method-headerless.rs
src/test/ui/objects-owned-object-owned-method.rs
src/test/ui/occurs-check-2.rs
src/test/ui/occurs-check-2.stderr
src/test/ui/occurs-check.rs
src/test/ui/occurs-check.stderr
src/test/ui/output-slot-variants.rs
src/test/ui/overloaded/overloaded-autoderef.rs
src/test/ui/overloaded/overloaded-index-autoderef.rs
src/test/ui/panics/args-panic.rs
src/test/ui/panics/panic-macro-any.rs
src/test/ui/parser/trailing-plus-in-bounds.rs
src/test/ui/pattern/usefulness/issue-12116.rs
src/test/ui/pattern/usefulness/issue-12116.stderr
src/test/ui/pattern/usefulness/issue-3601.rs
src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs [deleted file]
src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr [deleted file]
src/test/ui/proc-macro/attribute-after-derive.rs
src/test/ui/proc-macro/attribute-after-derive.stdout
src/test/ui/pure-sum.rs
src/test/ui/rcvr-borrowed-to-region.rs
src/test/ui/reachable/expr_again.rs
src/test/ui/reachable/unreachable-arm.rs
src/test/ui/recursion_limit/invalid_digit_type.rs [new file with mode: 0644]
src/test/ui/recursion_limit/invalid_digit_type.stderr [new file with mode: 0644]
src/test/ui/recursion_limit/invalid_macro.rs [new file with mode: 0644]
src/test/ui/recursion_limit/invalid_macro.stderr [new file with mode: 0644]
src/test/ui/regions/issue-12470.rs
src/test/ui/regions/regions-borrow-at.rs
src/test/ui/regions/regions-borrow-uniq.rs
src/test/ui/regions/regions-close-associated-type-into-object.rs
src/test/ui/regions/regions-close-object-into-object-1.rs
src/test/ui/regions/regions-close-object-into-object-1.stderr
src/test/ui/regions/regions-close-object-into-object-2.nll.stderr
src/test/ui/regions/regions-close-object-into-object-2.rs
src/test/ui/regions/regions-close-object-into-object-2.stderr
src/test/ui/regions/regions-close-object-into-object-3.rs
src/test/ui/regions/regions-close-object-into-object-3.stderr
src/test/ui/regions/regions-close-object-into-object-4.nll.stderr
src/test/ui/regions/regions-close-object-into-object-4.rs
src/test/ui/regions/regions-close-object-into-object-4.stderr
src/test/ui/regions/regions-close-object-into-object-5.nll.stderr
src/test/ui/regions/regions-close-object-into-object-5.rs
src/test/ui/regions/regions-close-object-into-object-5.stderr
src/test/ui/regions/regions-close-over-type-parameter-1.nll.stderr
src/test/ui/regions/regions-close-over-type-parameter-1.rs
src/test/ui/regions/regions-close-over-type-parameter-1.stderr
src/test/ui/regions/regions-close-over-type-parameter-multiple.nll.stderr
src/test/ui/regions/regions-close-over-type-parameter-multiple.rs
src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr
src/test/ui/regions/regions-close-over-type-parameter-successfully.rs
src/test/ui/regions/regions-dependent-addr-of.rs
src/test/ui/regions/regions-early-bound-trait-param.rs
src/test/ui/regions/regions-escape-into-other-fn.rs
src/test/ui/regions/regions-infer-borrow-scope-within-loop-ok.rs
src/test/ui/regions/regions-infer-borrow-scope.rs
src/test/ui/regions/regions-lifetime-nonfree-late-bound.rs
src/test/ui/regions/regions-ref-in-fn-arg.rs
src/test/ui/regions/regions-relate-bound-regions-on-closures-to-inference-variables.rs
src/test/ui/regions/regions-trait-variance.rs
src/test/ui/resolve/suggest-path-for-tuple-struct.rs [new file with mode: 0644]
src/test/ui/resolve/suggest-path-for-tuple-struct.stderr [new file with mode: 0644]
src/test/ui/rfcs/rfc-2005-default-binding-mode/box.rs
src/test/ui/self/explicit-self-generic.rs
src/test/ui/self/explicit-self-objects-uniq.rs
src/test/ui/self/explicit-self.rs
src/test/ui/self/self-impl-2.rs
src/test/ui/self/self-in-mut-slot-default-method.rs
src/test/ui/self/self-re-assign.rs
src/test/ui/self/ufcs-explicit-self.rs
src/test/ui/self/uniq-self-in-mut-slot.rs
src/test/ui/shadowed/shadowed-type-parameter.rs
src/test/ui/span/coerce-suggestions.rs
src/test/ui/span/coerce-suggestions.stderr
src/test/ui/span/issue-11925.rs
src/test/ui/span/regions-close-over-borrowed-ref-in-obj.rs
src/test/ui/span/regions-close-over-type-parameter-2.rs
src/test/ui/static/static-region-bound.rs
src/test/ui/structs-enums/class-cast-to-trait-cross-crate-2.rs
src/test/ui/structs-enums/class-separate-impl.rs
src/test/ui/structs-enums/enum-nullable-simplifycfg-misopt.rs
src/test/ui/suggestions/imm-ref-trait-object-literal.stderr
src/test/ui/suggestions/issue-62843.stderr
src/test/ui/suggestions/issue-72766.rs
src/test/ui/suggestions/issue-84973-2.stderr
src/test/ui/suggestions/issue-84973-negative.stderr
src/test/ui/suggestions/issue-84973.stderr
src/test/ui/suggestions/slice-issue-87994.stderr
src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs [new file with mode: 0644]
src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr [new file with mode: 0644]
src/test/ui/threads-sendsync/sendfn-spawn-with-fn-arg.rs
src/test/ui/threads-sendsync/task-spawn-move-and-copy.rs
src/test/ui/traits/bound/in-arc.rs
src/test/ui/traits/coercion.rs
src/test/ui/traits/conditional-dispatch.rs
src/test/ui/traits/issue-6128.rs
src/test/ui/traits/kindck-owned-contains-1.rs
src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr
src/test/ui/traits/object-one-type-two-traits.rs
src/test/ui/traits/object/generics.rs
src/test/ui/traits/test-2.rs
src/test/ui/traits/test-2.stderr
src/test/ui/traits/trait-upcasting/issue-11515-upcast-fn_mut-fn.rs
src/test/ui/type-param-constraints.rs
src/test/ui/typeclasses-eq-example-static.rs
src/test/ui/typeclasses-eq-example.rs
src/test/ui/ufcs/ufcs-explicit-self-bad.rs
src/test/ui/unboxed-closures/unboxed-closures-boxed.rs
src/test/ui/uninhabited/uninhabited-patterns.rs
src/test/ui/unique-object-noncopyable.rs
src/test/ui/unique/unique-assign-copy.rs
src/test/ui/unique/unique-assign-drop.rs
src/test/ui/unique/unique-assign-generic.rs
src/test/ui/unique/unique-assign.rs
src/test/ui/unique/unique-autoderef-field.rs
src/test/ui/unique/unique-autoderef-index.rs
src/test/ui/unique/unique-cmp.rs
src/test/ui/unique/unique-containing-tag.rs
src/test/ui/unique/unique-create.rs
src/test/ui/unique/unique-decl-init-copy.rs
src/test/ui/unique/unique-decl-init.rs
src/test/ui/unique/unique-decl-move.rs
src/test/ui/unique/unique-deref.rs
src/test/ui/unique/unique-destructure.rs
src/test/ui/unique/unique-drop-complex.rs
src/test/ui/unique/unique-fn-arg-move.rs
src/test/ui/unique/unique-fn-arg-mut.rs
src/test/ui/unique/unique-fn-arg.rs
src/test/ui/unique/unique-fn-ret.rs
src/test/ui/unique/unique-in-tag.rs
src/test/ui/unique/unique-in-vec-copy.rs
src/test/ui/unique/unique-in-vec.rs
src/test/ui/unique/unique-init.rs
src/test/ui/unique/unique-kinds.rs
src/test/ui/unique/unique-log.rs
src/test/ui/unique/unique-move-drop.rs
src/test/ui/unique/unique-move-temp.rs
src/test/ui/unique/unique-move.rs
src/test/ui/unique/unique-mutable.rs
src/test/ui/unique/unique-object-move.rs
src/test/ui/unique/unique-pat-2.rs
src/test/ui/unique/unique-pat-3.rs
src/test/ui/unique/unique-pat.rs
src/test/ui/unique/unique-rec.rs
src/test/ui/unique/unique-send-2.rs
src/test/ui/unique/unique-send.rs
src/test/ui/unique/unique-swap.rs
src/test/ui/unsized/unsized2.rs
src/test/ui/unsized/unsized3-rpass.rs
src/test/ui/unused-move-capture.rs
src/test/ui/unused-move.rs
src/test/ui/unwind-unique.rs
src/test/ui/use/use-after-move-implicity-coerced-object.rs
src/test/ui/use/use-after-move-implicity-coerced-object.stderr
src/test/ui/use/use-after-move-self.rs
src/test/ui/wf/hir-wf-check-erase-regions.rs
src/tools/clippy/clippy_lints/src/escape.rs
src/tools/clippy/clippy_lints/src/methods/mod.rs
src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
src/tools/compiletest/src/common.rs
src/tools/compiletest/src/header.rs
src/tools/compiletest/src/runtest.rs
src/tools/tidy/src/lib.rs

index 3822da2ccd5e4694756480493eb2ff55afcce26e..ce7073886c20e95658065773511c7a05174d5274 100644 (file)
@@ -41,6 +41,7 @@ members = [
 exclude = [
   "build",
   "compiler/rustc_codegen_cranelift",
+  "compiler/rustc_codegen_gcc",
   "src/test/rustdoc-gui",
   # HACK(eddyb) This hardcodes the fact that our CI uses `/checkout/obj`.
   "obj",
index c0851a1506e130eb017b21334e7454ee23c89a04..ef1377a4a32dfe8abe45318ad38a563d0133abcf 100644 (file)
@@ -1,3 +1,188 @@
+Rust 1.56.0 (2021-10-21)
+========================
+
+Language
+--------
+
+- [The 2021 Edition is now stable.][rust#88100]
+  See [the edition guide][rust-2021-edition-guide] for more details.
+- [You can now specify explicit discriminant values on any Rust enum.][rust#86860]
+- [The pattern in `binding @ pattern` can now also introduce new bindings.][rust#85305]
+- [Union field access is permitted in `const fn`.][rust#85769]
+
+[rust-2021-edition-guide]: https://doc.rust-lang.org/nightly/edition-guide/rust-2021/index.html
+
+Compiler
+--------
+
+- [Upgrade to LLVM 13.][rust#87570]
+- [Support memory, address, and thread sanitizers on aarch64-unknown-freebsd.][rust#88023]
+- [Allow specifying a deployment target version for all iOS targets][rust#87699]
+- [Warnings can be forced on with `--force-warn`.][rust#87472]
+  This feature is primarily intended for usage by `cargo fix`, rather than end users.
+- [Promote `aarch64-apple-ios-sim` to Tier 2\*.][rust#87760]
+- [Add `powerpc-unknown-freebsd` at Tier 3\*.][rust#87370]
+
+\* Refer to Rust's [platform support page][platform-support-doc] for more
+information on Rust's tiered platform support.
+
+Libraries
+---------
+
+- [Allow writing of incomplete UTF-8 sequences via stdout/stderr on Windows.][rust#83342]
+  The Windows console still requires valid Unicode, but this change allows
+  splitting a UTF-8 character across multiple write calls. This allows, for
+  instance, programs that just read and write data buffers (e.g. copying a file
+  to stdout) without regard for Unicode or character boundaries.
+- [Prefer `AtomicU{64,128}` over Mutex for Instant backsliding protection.][rust#83093]
+  For this use case, atomics scale much better under contention.
+- [Implement `Extend<(A, B)>` for `(Extend<A>, Extend<B>)`][rust#85835]
+- [impl Default, Copy, Clone for std::io::Sink and std::io::Empty][rust#86744]
+- [`impl From<[(K, V); N]>` for all collections.][rust#84111]
+- [Remove `P: Unpin` bound on impl Future for Pin.][rust#81363]
+- [Treat invalid environment variable names as non-existent.][rust#86183]
+  Previously, the environment functions would panic if given a variable name
+  with an internal null character or equal sign (`=`). Now, these functions will
+  just treat such names as non-existent variables, since the OS cannot represent
+  the existence of a variable with such a name.
+
+Stabilised APIs
+---------------
+
+- [`std::os::unix::fs::chroot`]
+- [`Iterator::intersperse`]
+- [`Iterator::intersperse_with`]
+- [`UnsafeCell::raw_get`]
+- [`BufWriter::into_parts`]
+- [`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`]
+  These APIs were previously stable in `std`, but are now also available in `core`.
+- [`Vec::shrink_to`]
+- [`String::shrink_to`]
+- [`OsString::shrink_to`]
+- [`PathBuf::shrink_to`]
+- [`BinaryHeap::shrink_to`]
+- [`VecDeque::shrink_to`]
+- [`HashMap::shrink_to`]
+- [`HashSet::shrink_to`]
+- [`task::ready!`]
+
+These APIs are now usable in const contexts:
+
+- [`std::mem::transmute`]
+- [`[T]::first`][`slice::first`]
+- [`[T]::split_first`][`slice::split_first`]
+- [`[T]::last`][`slice::last`]
+- [`[T]::split_last`][`slice::split_last`]
+
+Cargo
+-----
+
+- [Cargo supports specifying a minimum supported Rust version in Cargo.toml.][`rust-version`]
+  This has no effect at present on dependency version selection.
+  We encourage crates to specify their minimum supported Rust version, and we encourage CI systems
+  that support Rust code to include a crate's specified minimum version in the text matrix for that
+  crate by default.
+
+Compatibility notes
+-------------------
+
+- [Update to new argument parsing rules on Windows.][rust#87580]
+  This adjusts Rust's standard library to match the behavior of the standard
+  libraries for C/C++. The rules have changed slightly over time, and this PR
+  brings us to the latest set of rules (changed in 2008).
+- [Disallow the aapcs calling convention on aarch64][rust#88399]
+  This was already not supported by LLVM; this change surfaces this lack of
+  support with a better error message.
+- [Make `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` warn by default][rust#87385]
+- [Warn when an escaped newline skips multiple lines.][rust#87671]
+- [Calls to `libc::getpid` / `std::process::id` from `Command::pre_exec`
+   may return different values on glibc <= 2.24.][rust#81825]
+   Rust now invokes the `clone3` system call directly, when available, to use new functionality
+   available via that system call. Older versions of glibc cache the result of `getpid`, and only
+   update that cache when calling glibc's clone/fork functions, so a direct system call bypasses
+   that cache update. glibc 2.25 and newer no longer cache `getpid` for exactly this reason.
+
+Internal changes
+----------------
+These changes provide no direct user facing benefits, but represent significant
+improvements to the internals and overall performance of rustc
+and related tools.
+
+- [LLVM is compiled with PGO in published x86_64-unknown-linux-gnu artifacts.][rust#88069]
+  This improves the performance of most Rust builds.
+- [Unify representation of macros in internal data structures.][rust#88019]
+  This change fixes a host of bugs with the handling of macros by the compiler,
+  as well as rustdoc.
+
+[`std::os::unix::fs::chroot`]: https://doc.rust-lang.org/stable/std/os/unix/fs/fn.chroot.html
+[`Iterator::intersperse`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse
+[`Iterator::intersperse_with`]: https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html#method.intersperse
+[`UnsafeCell::raw_get`]: https://doc.rust-lang.org/stable/std/cell/struct.UnsafeCell.html#method.raw_get
+[`BufWriter::into_parts`]: https://doc.rust-lang.org/stable/std/io/struct.BufWriter.html#method.into_parts
+[`core::panic::{UnwindSafe, RefUnwindSafe, AssertUnwindSafe}`]: https://github.com/rust-lang/rust/pull/84662
+[`Vec::shrink_to`]: https://doc.rust-lang.org/stable/std/vec/struct.Vec.html#method.shrink_to
+[`String::shrink_to`]: https://doc.rust-lang.org/stable/std/string/struct.String.html#method.shrink_to
+[`OsString::shrink_to`]: https://doc.rust-lang.org/stable/std/ffi/struct.OsString.html#method.shrink_to
+[`PathBuf::shrink_to`]: https://doc.rust-lang.org/stable/std/path/struct.PathBuf.html#method.shrink_to
+[`BinaryHeap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.BinaryHeap.html#method.shrink_to
+[`VecDeque::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/struct.VecDeque.html#method.shrink_to
+[`HashMap::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_map/struct.HashMap.html#method.shrink_to
+[`HashSet::shrink_to`]: https://doc.rust-lang.org/stable/std/collections/hash_set/struct.HashSet.html#method.shrink_to
+[`task::ready!`]: https://doc.rust-lang.org/stable/std/task/macro.ready.html
+[`std::mem::transmute`]: https://doc.rust-lang.org/stable/std/mem/fn.transmute.html
+[`slice::first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.first
+[`slice::split_first`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_first
+[`slice::last`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.last
+[`slice::split_last`]: https://doc.rust-lang.org/stable/std/primitive.slice.html#method.split_last
+[`rust-version`]: https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-rust-version-field
+[rust#87671]: https://github.com/rust-lang/rust/pull/87671
+[rust#86183]: https://github.com/rust-lang/rust/pull/86183
+[rust#87385]: https://github.com/rust-lang/rust/pull/87385
+[rust#88100]: https://github.com/rust-lang/rust/pull/88100
+[rust#86860]: https://github.com/rust-lang/rust/pull/86860
+[rust#84039]: https://github.com/rust-lang/rust/pull/84039
+[rust#86492]: https://github.com/rust-lang/rust/pull/86492
+[rust#88363]: https://github.com/rust-lang/rust/pull/88363
+[rust#85305]: https://github.com/rust-lang/rust/pull/85305
+[rust#87832]: https://github.com/rust-lang/rust/pull/87832
+[rust#88069]: https://github.com/rust-lang/rust/pull/88069
+[rust#87472]: https://github.com/rust-lang/rust/pull/87472
+[rust#87699]: https://github.com/rust-lang/rust/pull/87699
+[rust#87570]: https://github.com/rust-lang/rust/pull/87570
+[rust#88023]: https://github.com/rust-lang/rust/pull/88023
+[rust#87760]: https://github.com/rust-lang/rust/pull/87760
+[rust#87370]: https://github.com/rust-lang/rust/pull/87370
+[rust#87580]: https://github.com/rust-lang/rust/pull/87580
+[rust#83342]: https://github.com/rust-lang/rust/pull/83342
+[rust#83093]: https://github.com/rust-lang/rust/pull/83093
+[rust#88177]: https://github.com/rust-lang/rust/pull/88177
+[rust#88548]: https://github.com/rust-lang/rust/pull/88548
+[rust#88551]: https://github.com/rust-lang/rust/pull/88551
+[rust#88299]: https://github.com/rust-lang/rust/pull/88299
+[rust#88220]: https://github.com/rust-lang/rust/pull/88220
+[rust#85835]: https://github.com/rust-lang/rust/pull/85835
+[rust#86879]: https://github.com/rust-lang/rust/pull/86879
+[rust#86744]: https://github.com/rust-lang/rust/pull/86744
+[rust#84662]: https://github.com/rust-lang/rust/pull/84662
+[rust#86593]: https://github.com/rust-lang/rust/pull/86593
+[rust#81050]: https://github.com/rust-lang/rust/pull/81050
+[rust#81363]: https://github.com/rust-lang/rust/pull/81363
+[rust#84111]: https://github.com/rust-lang/rust/pull/84111
+[rust#85769]: https://github.com/rust-lang/rust/pull/85769#issuecomment-854363720
+[rust#88490]: https://github.com/rust-lang/rust/pull/88490
+[rust#88269]: https://github.com/rust-lang/rust/pull/88269
+[rust#84176]: https://github.com/rust-lang/rust/pull/84176
+[rust#88399]: https://github.com/rust-lang/rust/pull/88399
+[rust#88227]: https://github.com/rust-lang/rust/pull/88227
+[rust#88200]: https://github.com/rust-lang/rust/pull/88200
+[rust#82776]: https://github.com/rust-lang/rust/pull/82776
+[rust#88077]: https://github.com/rust-lang/rust/pull/88077
+[rust#87728]: https://github.com/rust-lang/rust/pull/87728
+[rust#87050]: https://github.com/rust-lang/rust/pull/87050
+[rust#87619]: https://github.com/rust-lang/rust/pull/87619
+[rust#81825]: https://github.com/rust-lang/rust/pull/81825#issuecomment-808406918
+[rust#88019]: https://github.com/rust-lang/rust/pull/88019
+
 Version 1.55.0 (2021-09-09)
 ============================
 
@@ -4985,7 +5170,7 @@ Libraries
 - [Upgrade to Unicode 10.0.0][42999]
 - [Reimplemented `{f32, f64}::{min, max}` in Rust instead of using CMath.][42430]
 - [Skip the main thread's manual stack guard on Linux][43072]
-- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in O(1) time][43077]
+- [Iterator::nth for `ops::{Range, RangeFrom}` is now done in *O*(1) time][43077]
 - [`#[repr(align(N))]` attribute max number is now 2^31 - 1.][43097] This was
   previously 2^15.
 - [`{OsStr, Path}::Display` now avoids allocations where possible][42613]
@@ -8288,7 +8473,7 @@ Libraries
   algorithm][s].
 * [`std::io::copy` allows `?Sized` arguments][cc].
 * The `Windows`, `Chunks`, and `ChunksMut` iterators over slices all
-  [override `count`, `nth` and `last` with an O(1)
+  [override `count`, `nth` and `last` with an *O*(1)
   implementation][it].
 * [`Default` is implemented for arrays up to `[T; 32]`][d].
 * [`IntoRawFd` has been added to the Unix-specific prelude,
@@ -8810,7 +8995,7 @@ Libraries
 * The `Default` implementation for `Arc` [no longer requires `Sync +
   Send`][arc].
 * [The `Iterator` methods `count`, `nth`, and `last` have been
-  overridden for slices to have O(1) performance instead of O(n)][si].
+  overridden for slices to have *O*(1) performance instead of *O*(*n*)][si].
 * Incorrect handling of paths on Windows has been improved in both the
   compiler and the standard library.
 * [`AtomicPtr` gained a `Default` implementation][ap].
index 76e779bfec608d25279bd40f4912cedb0e530332..366ade1a71388940210cec5d8f6a3d699dfb8bcf 100644 (file)
@@ -9,7 +9,7 @@
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::{SelectionContext, TraitEngineExt as _};
-use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
+use rustc_traits::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
 
 use std::fmt;
 use std::rc::Rc;
@@ -45,13 +45,12 @@ impl UniverseInfo<'tcx> {
         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         placeholder: ty::PlaceholderRegion,
         error_element: RegionElement,
-        span: Span,
+        cause: ObligationCause<'tcx>,
     ) {
         match self.0 {
             UniverseInfoInner::RelateTys { expected, found } => {
-                let body_id = mbcx.infcx.tcx.hir().local_def_id_to_hir_id(mbcx.mir_def_id());
                 let err = mbcx.infcx.report_mismatched_types(
-                    &ObligationCause::misc(span, body_id),
+                    &cause,
                     expected,
                     found,
                     TypeError::RegionsPlaceholderMismatch,
@@ -59,7 +58,7 @@ impl UniverseInfo<'tcx> {
                 err.buffer(&mut mbcx.errors_buffer);
             }
             UniverseInfoInner::TypeOp(ref type_op_info) => {
-                type_op_info.report_error(mbcx, placeholder, error_element, span);
+                type_op_info.report_error(mbcx, placeholder, error_element, cause);
             }
             UniverseInfoInner::Other => {
                 // FIXME: This error message isn't great, but it doesn't show
@@ -68,7 +67,7 @@ impl UniverseInfo<'tcx> {
                 mbcx.infcx
                     .tcx
                     .sess
-                    .struct_span_err(span, "higher-ranked subtype error")
+                    .struct_span_err(cause.span, "higher-ranked subtype error")
                     .buffer(&mut mbcx.errors_buffer);
             }
         }
@@ -130,7 +129,7 @@ trait TypeOpInfo<'tcx> {
     fn nice_error(
         &self,
         tcx: TyCtxt<'tcx>,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx>>;
@@ -140,7 +139,7 @@ fn report_error(
         mbcx: &mut MirBorrowckCtxt<'_, 'tcx>,
         placeholder: ty::PlaceholderRegion,
         error_element: RegionElement,
-        span: Span,
+        cause: ObligationCause<'tcx>,
     ) {
         let tcx = mbcx.infcx.tcx;
         let base_universe = self.base_universe();
@@ -150,7 +149,7 @@ fn report_error(
         {
             adjusted
         } else {
-            self.fallback_error(tcx, span).buffer(&mut mbcx.errors_buffer);
+            self.fallback_error(tcx, cause.span).buffer(&mut mbcx.errors_buffer);
             return;
         };
 
@@ -175,7 +174,8 @@ fn report_error(
 
         debug!(?placeholder_region);
 
-        let nice_error = self.nice_error(tcx, span, placeholder_region, error_region);
+        let span = cause.span;
+        let nice_error = self.nice_error(tcx, cause, placeholder_region, error_region);
 
         if let Some(nice_error) = nice_error {
             nice_error.buffer(&mut mbcx.errors_buffer);
@@ -205,15 +205,24 @@ fn base_universe(&self) -> ty::UniverseIndex {
     fn nice_error(
         &self,
         tcx: TyCtxt<'tcx>,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
-        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
-            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
-            type_op_prove_predicate_with_span(infcx, &mut *fulfill_cx, key, Some(span));
-            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
-        })
+        tcx.infer_ctxt().enter_with_canonical(
+            cause.span,
+            &self.canonical_query,
+            |ref infcx, key, _| {
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+                type_op_prove_predicate_with_cause(infcx, &mut *fulfill_cx, key, cause);
+                try_extract_error_from_fulfill_cx(
+                    fulfill_cx,
+                    infcx,
+                    placeholder_region,
+                    error_region,
+                )
+            },
+        )
     }
 }
 
@@ -239,32 +248,41 @@ fn base_universe(&self) -> ty::UniverseIndex {
     fn nice_error(
         &self,
         tcx: TyCtxt<'tcx>,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
-        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
-            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
-
-            let mut selcx = SelectionContext::new(infcx);
-
-            // FIXME(lqd): Unify and de-duplicate the following with the actual
-            // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
-            // `ObligationCause`. The normalization results are currently different between
-            // `AtExt::normalize` used in the query and `normalize` called below: the former fails
-            // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
-            // after #85499 lands to see if its fixes have erased this difference.
-            let (param_env, value) = key.into_parts();
-            let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
-                &mut selcx,
-                param_env,
-                ObligationCause::dummy_with_span(span),
-                value.value,
-            );
-            fulfill_cx.register_predicate_obligations(infcx, obligations);
-
-            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
-        })
+        tcx.infer_ctxt().enter_with_canonical(
+            cause.span,
+            &self.canonical_query,
+            |ref infcx, key, _| {
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+
+                let mut selcx = SelectionContext::new(infcx);
+
+                // FIXME(lqd): Unify and de-duplicate the following with the actual
+                // `rustc_traits::type_op::type_op_normalize` query to allow the span we need in the
+                // `ObligationCause`. The normalization results are currently different between
+                // `AtExt::normalize` used in the query and `normalize` called below: the former fails
+                // to normalize the `nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs` test. Check
+                // after #85499 lands to see if its fixes have erased this difference.
+                let (param_env, value) = key.into_parts();
+                let Normalized { value: _, obligations } = rustc_trait_selection::traits::normalize(
+                    &mut selcx,
+                    param_env,
+                    cause,
+                    value.value,
+                );
+                fulfill_cx.register_predicate_obligations(infcx, obligations);
+
+                try_extract_error_from_fulfill_cx(
+                    fulfill_cx,
+                    infcx,
+                    placeholder_region,
+                    error_region,
+                )
+            },
+        )
     }
 }
 
@@ -287,15 +305,25 @@ fn base_universe(&self) -> ty::UniverseIndex {
     fn nice_error(
         &self,
         tcx: TyCtxt<'tcx>,
-        span: Span,
+        cause: ObligationCause<'tcx>,
         placeholder_region: ty::Region<'tcx>,
         error_region: Option<ty::Region<'tcx>>,
     ) -> Option<DiagnosticBuilder<'tcx>> {
-        tcx.infer_ctxt().enter_with_canonical(span, &self.canonical_query, |ref infcx, key, _| {
-            let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
-            type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(span)).ok()?;
-            try_extract_error_from_fulfill_cx(fulfill_cx, infcx, placeholder_region, error_region)
-        })
+        tcx.infer_ctxt().enter_with_canonical(
+            cause.span,
+            &self.canonical_query,
+            |ref infcx, key, _| {
+                let mut fulfill_cx = <dyn TraitEngine<'_>>::new(tcx);
+                type_op_ascribe_user_type_with_span(infcx, &mut *fulfill_cx, key, Some(cause.span))
+                    .ok()?;
+                try_extract_error_from_fulfill_cx(
+                    fulfill_cx,
+                    infcx,
+                    placeholder_region,
+                    error_region,
+                )
+            },
+        )
     }
 }
 
index 2d12a682e7ae6d9c5c598fa1834b4b4b75f6b2e4..d5de0801ac4431ccfcaab25872a16923501b8925 100644 (file)
@@ -300,7 +300,7 @@ fn free_region_constraint_info(
         borrow_region: RegionVid,
         outlived_region: RegionVid,
     ) -> (ConstraintCategory, bool, Span, Option<RegionName>) {
-        let BlameConstraint { category, from_closure, span, variance_info: _ } =
+        let BlameConstraint { category, from_closure, cause, variance_info: _ } =
             self.regioncx.best_blame_constraint(
                 &self.body,
                 borrow_region,
@@ -310,7 +310,7 @@ fn free_region_constraint_info(
 
         let outlived_fr_name = self.give_region_a_name(outlived_region);
 
-        (category, from_closure, span, outlived_fr_name)
+        (category, from_closure, cause.span, outlived_fr_name)
     }
 
     /// Returns structured explanation for *why* the borrow contains the
index 0761d63c665402a589b483d18391f98beac93e5f..d05cfebc5f02e113d6d887eb41adb7e2f8c51e34 100644 (file)
@@ -13,6 +13,7 @@
 
 use crate::borrowck_errors;
 
+use super::{OutlivesSuggestionBuilder, RegionName};
 use crate::region_infer::BlameConstraint;
 use crate::{
     nll::ConstraintDescription,
@@ -21,8 +22,6 @@
     MirBorrowckCtxt,
 };
 
-use super::{OutlivesSuggestionBuilder, RegionName};
-
 impl ConstraintDescription for ConstraintCategory {
     fn description(&self) -> &'static str {
         // Must end with a space. Allows for empty names to be provided.
@@ -41,7 +40,8 @@ fn description(&self) -> &'static str {
             ConstraintCategory::OpaqueType => "opaque type ",
             ConstraintCategory::ClosureUpvar(_) => "closure capture ",
             ConstraintCategory::Usage => "this usage ",
-            ConstraintCategory::Boring
+            ConstraintCategory::Predicate(_)
+            | ConstraintCategory::Boring
             | ConstraintCategory::BoringNoLocation
             | ConstraintCategory::Internal => "",
         }
@@ -217,7 +217,7 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
                     let error_vid = self.regioncx.region_from_element(longer_fr, &error_element);
 
                     // Find the code to blame for the fact that `longer_fr` outlives `error_fr`.
-                    let (_, span) = self.regioncx.find_outlives_blame_span(
+                    let (_, cause) = self.regioncx.find_outlives_blame_span(
                         &self.body,
                         longer_fr,
                         NllRegionVariableOrigin::Placeholder(placeholder),
@@ -227,7 +227,7 @@ pub(crate) fn report_region_errors(&mut self, nll_errors: RegionErrors<'tcx>) {
                     let universe = placeholder.universe;
                     let universe_info = self.regioncx.universe_info(universe);
 
-                    universe_info.report_error(self, placeholder, error_element, span);
+                    universe_info.report_error(self, placeholder, error_element, cause);
                 }
 
                 RegionErrorKind::RegionError { fr_origin, longer_fr, shorter_fr, is_reported } => {
@@ -275,15 +275,15 @@ pub(crate) fn report_region_error(
     ) {
         debug!("report_region_error(fr={:?}, outlived_fr={:?})", fr, outlived_fr);
 
-        let BlameConstraint { category, span, variance_info, from_closure: _ } =
+        let BlameConstraint { category, cause, variance_info, from_closure: _ } =
             self.regioncx.best_blame_constraint(&self.body, fr, fr_origin, |r| {
                 self.regioncx.provides_universal_region(r, fr, outlived_fr)
             });
 
-        debug!("report_region_error: category={:?} {:?} {:?}", category, span, variance_info);
+        debug!("report_region_error: category={:?} {:?} {:?}", category, cause, variance_info);
         // Check if we can use one of the "nice region errors".
         if let (Some(f), Some(o)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) {
-            let nice = NiceRegionError::new_from_span(self.infcx, span, o, f);
+            let nice = NiceRegionError::new_from_span(self.infcx, cause.span, o, f);
             if let Some(diag) = nice.try_report_from_nll() {
                 diag.buffer(&mut self.errors_buffer);
                 return;
@@ -306,7 +306,7 @@ pub(crate) fn report_region_error(
             fr_is_local,
             outlived_fr_is_local,
             category,
-            span,
+            span: cause.span,
         };
 
         let mut diag = match (category, fr_is_local, outlived_fr_is_local) {
index 016fe0bb6dedffbe9ff419991993903f2c5cbde4..efd34f4e0a58e38b6098f47333c0a22165ce2599 100644 (file)
@@ -316,7 +316,8 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) {
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
-            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
+            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/)
+            | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
                 self.consume_operand(location, operand)
             }
 
index b3b7d7e02ccef068b444607116f3058a20ba0f10..72f4907a09f9849e4cf86f3ab54afd8b901629f7 100644 (file)
@@ -1361,7 +1361,8 @@ fn consume_rvalue(
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::UnaryOp(_ /*un_op*/, ref operand)
-            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/) => {
+            | Rvalue::Cast(_ /*cast_kind*/, ref operand, _ /*ty*/)
+            | Rvalue::ShallowInitBox(ref operand, _ /*ty*/) => {
                 self.consume_operand(location, (operand, span), flow_state)
             }
 
index 128faab8d722e204e189031a418ca24407465c53..917d69a5c866446ac4fc7ac6046d40642341326e 100644 (file)
@@ -5,7 +5,8 @@
 use rustc_data_structures::frozen::Frozen;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_data_structures::graph::scc::Sccs;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+use rustc_hir::CRATE_HIR_ID;
 use rustc_index::vec::IndexVec;
 use rustc_infer::infer::canonical::QueryOutlivesConstraint;
 use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound};
@@ -14,6 +15,8 @@
     Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureRegionRequirements,
     ConstraintCategory, Local, Location, ReturnConstraint,
 };
+use rustc_middle::traits::ObligationCause;
+use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::{self, subst::SubstsRef, RegionVid, Ty, TyCtxt, TypeFoldable};
 use rustc_span::Span;
 
@@ -1596,7 +1599,7 @@ fn try_propagate_universal_region_error(
                     propagated_outlives_requirements.push(ClosureOutlivesRequirement {
                         subject: ClosureOutlivesSubject::Region(fr_minus),
                         outlived_free_region: fr,
-                        blame_span: blame_span_category.1,
+                        blame_span: blame_span_category.1.span,
                         category: blame_span_category.0,
                     });
                 }
@@ -1738,7 +1741,7 @@ fn check_member_constraints(
                 return BlameConstraint {
                     category: constraint.category,
                     from_closure: false,
-                    span,
+                    cause: ObligationCause::dummy_with_span(span),
                     variance_info: constraint.variance_info,
                 };
             }
@@ -1751,30 +1754,30 @@ fn check_member_constraints(
             .map(|&(category, span)| BlameConstraint {
                 category,
                 from_closure: true,
-                span: span,
+                cause: ObligationCause::dummy_with_span(span),
                 variance_info: constraint.variance_info,
             })
             .unwrap_or(BlameConstraint {
                 category: constraint.category,
                 from_closure: false,
-                span: body.source_info(loc).span,
+                cause: ObligationCause::dummy_with_span(body.source_info(loc).span),
                 variance_info: constraint.variance_info,
             })
     }
 
-    /// Finds a good span to blame for the fact that `fr1` outlives `fr2`.
+    /// Finds a good `ObligationCause` to blame for the fact that `fr1` outlives `fr2`.
     crate fn find_outlives_blame_span(
         &self,
         body: &Body<'tcx>,
         fr1: RegionVid,
         fr1_origin: NllRegionVariableOrigin,
         fr2: RegionVid,
-    ) -> (ConstraintCategory, Span) {
-        let BlameConstraint { category, span, .. } =
+    ) -> (ConstraintCategory, ObligationCause<'tcx>) {
+        let BlameConstraint { category, cause, .. } =
             self.best_blame_constraint(body, fr1, fr1_origin, |r| {
                 self.provides_universal_region(r, fr1, fr2)
             });
-        (category, span)
+        (category, cause)
     }
 
     /// Walks the graph of constraints (where `'a: 'b` is considered
@@ -1990,6 +1993,27 @@ fn check_member_constraints(
                 .collect::<Vec<_>>()
         );
 
+        // We try to avoid reporting a `ConstraintCategory::Predicate` as our best constraint.
+        // Instead, we use it to produce an improved `ObligationCauseCode`.
+        // FIXME - determine what we should do if we encounter multiple `ConstraintCategory::Predicate`
+        // constraints. Currently, we just pick the first one.
+        let cause_code = path
+            .iter()
+            .find_map(|constraint| {
+                if let ConstraintCategory::Predicate(predicate_span) = constraint.category {
+                    // We currentl'y doesn't store the `DefId` in the `ConstraintCategory`
+                    // for perforamnce reasons. The error reporting code used by NLL only
+                    // uses the span, so this doesn't cause any problems at the moment.
+                    Some(ObligationCauseCode::BindingObligation(
+                        CRATE_DEF_ID.to_def_id(),
+                        predicate_span,
+                    ))
+                } else {
+                    None
+                }
+            })
+            .unwrap_or_else(|| ObligationCauseCode::MiscObligation);
+
         // Classify each of the constraints along the path.
         let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
             .iter()
@@ -2000,7 +2024,11 @@ fn check_member_constraints(
                     BlameConstraint {
                         category: constraint.category,
                         from_closure: false,
-                        span: constraint.locations.span(body),
+                        cause: ObligationCause::new(
+                            constraint.locations.span(body),
+                            CRATE_HIR_ID,
+                            cause_code.clone(),
+                        ),
                         variance_info: constraint.variance_info,
                     }
                 }
@@ -2083,7 +2111,8 @@ fn check_member_constraints(
                     ConstraintCategory::OpaqueType
                     | ConstraintCategory::Boring
                     | ConstraintCategory::BoringNoLocation
-                    | ConstraintCategory::Internal => false,
+                    | ConstraintCategory::Internal
+                    | ConstraintCategory::Predicate(_) => false,
                     ConstraintCategory::TypeAnnotation
                     | ConstraintCategory::Return(_)
                     | ConstraintCategory::Yield => true,
@@ -2094,7 +2123,8 @@ fn check_member_constraints(
                     ConstraintCategory::OpaqueType
                     | ConstraintCategory::Boring
                     | ConstraintCategory::BoringNoLocation
-                    | ConstraintCategory::Internal => false,
+                    | ConstraintCategory::Internal
+                    | ConstraintCategory::Predicate(_) => false,
                     _ => true,
                 }
             }
@@ -2249,6 +2279,6 @@ fn apply_requirements(
 pub struct BlameConstraint<'tcx> {
     pub category: ConstraintCategory,
     pub from_closure: bool,
-    pub span: Span,
+    pub cause: ObligationCause<'tcx>,
     pub variance_info: ty::VarianceDiagInfo<'tcx>,
 }
index 18070164e82195f7430c297fe9926b07f86f5f15..df28fb6e28e06acbcaaaf222ed85e8f26d0a62e2 100644 (file)
@@ -4,6 +4,7 @@
 use rustc_infer::traits::query::NoSolution;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::{self, ToPredicate, TypeFoldable};
+use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
 use rustc_trait_selection::traits::query::Fallible;
@@ -89,10 +90,10 @@ pub(super) fn prove_trait_ref(
         category: ConstraintCategory,
     ) {
         self.prove_predicates(
-            Some(ty::PredicateKind::Trait(ty::TraitPredicate {
+            Some(ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
                 trait_ref,
                 constness: ty::BoundConstness::NotConst,
-            })),
+            }))),
             locations,
             category,
         );
@@ -100,12 +101,19 @@ pub(super) fn prove_trait_ref(
 
     pub(super) fn normalize_and_prove_instantiated_predicates(
         &mut self,
+        // Keep this parameter for now, in case we start using
+        // it in `ConstraintCategory` at some point.
+        _def_id: DefId,
         instantiated_predicates: ty::InstantiatedPredicates<'tcx>,
         locations: Locations,
     ) {
-        for predicate in instantiated_predicates.predicates {
+        for (predicate, span) in instantiated_predicates
+            .predicates
+            .into_iter()
+            .zip(instantiated_predicates.spans.into_iter())
+        {
             let predicate = self.normalize(predicate, locations);
-            self.prove_predicate(predicate, locations, ConstraintCategory::Boring);
+            self.prove_predicate(predicate, locations, ConstraintCategory::Predicate(span));
         }
     }
 
index 3e536eb845f620eb50f72d0800f5e2795d45dd39..4bbeed39e45ae313d9ed5f7191bdb1cab35c75b8 100644 (file)
@@ -32,6 +32,7 @@
     self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueTypeKey, RegionVid,
     ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, WithConstness,
 };
+use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
 use rustc_trait_selection::infer::InferCtxtExt as _;
@@ -449,6 +450,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
             if let ty::FnDef(def_id, substs) = *constant.literal.ty().kind() {
                 let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
                 self.cx.normalize_and_prove_instantiated_predicates(
+                    def_id,
                     instantiated_predicates,
                     location.to_locations(),
                 );
@@ -1080,7 +1082,8 @@ fn check_user_type_annotations(&mut self) {
                     }
 
                     self.prove_predicate(
-                        ty::PredicateKind::WellFormed(inferred_ty.into()).to_predicate(self.tcx()),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(inferred_ty.into()))
+                            .to_predicate(self.tcx()),
                         Locations::All(span),
                         ConstraintCategory::TypeAnnotation,
                     );
@@ -1316,7 +1319,8 @@ fn eq_opaque_type_and_type(
                     obligations.obligations.push(traits::Obligation::new(
                         ObligationCause::dummy(),
                         param_env,
-                        ty::PredicateKind::WellFormed(revealed_ty.into()).to_predicate(infcx.tcx),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(revealed_ty.into()))
+                            .to_predicate(infcx.tcx),
                     ));
                     obligations.add(
                         infcx
@@ -1599,7 +1603,9 @@ fn check_terminator(
                 self.check_call_dest(body, term, &sig, destination, term_location);
 
                 self.prove_predicates(
-                    sig.inputs_and_output.iter().map(|ty| ty::PredicateKind::WellFormed(ty.into())),
+                    sig.inputs_and_output
+                        .iter()
+                        .map(|ty| ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))),
                     term_location.to_locations(),
                     ConstraintCategory::Boring,
                 );
@@ -2020,13 +2026,7 @@ fn check_rvalue(&mut self, body: &Body<'tcx>, rvalue: &Rvalue<'tcx>, location: L
                 }
             }
 
-            Rvalue::NullaryOp(_, ty) => {
-                // Even with unsized locals cannot box an unsized value.
-                if self.unsized_feature_enabled() {
-                    let span = body.source_info(location).span;
-                    self.ensure_place_sized(ty, span);
-                }
-
+            Rvalue::NullaryOp(_, ty) | Rvalue::ShallowInitBox(_, ty) => {
                 let trait_ref = ty::TraitRef {
                     def_id: tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
                     substs: tcx.mk_substs_trait(ty, &[]),
@@ -2359,6 +2359,7 @@ fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<UserTypeAnnotationInde
             | Rvalue::AddressOf(..)
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
+            | Rvalue::ShallowInitBox(..)
             | Rvalue::BinaryOp(..)
             | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
@@ -2573,9 +2574,9 @@ fn prove_aggregate_predicates(
             aggregate_kind, location
         );
 
-        let instantiated_predicates = match aggregate_kind {
+        let (def_id, instantiated_predicates) = match aggregate_kind {
             AggregateKind::Adt(def, _, substs, _, _) => {
-                tcx.predicates_of(def.did).instantiate(tcx, substs)
+                (def.did, tcx.predicates_of(def.did).instantiate(tcx, substs))
             }
 
             // For closures, we have some **extra requirements** we
@@ -2600,13 +2601,16 @@ fn prove_aggregate_predicates(
             // clauses on the struct.
             AggregateKind::Closure(def_id, substs)
             | AggregateKind::Generator(def_id, substs, _) => {
-                self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location)
+                (*def_id, self.prove_closure_bounds(tcx, def_id.expect_local(), substs, location))
             }
 
-            AggregateKind::Array(_) | AggregateKind::Tuple => ty::InstantiatedPredicates::empty(),
+            AggregateKind::Array(_) | AggregateKind::Tuple => {
+                (CRATE_DEF_ID.to_def_id(), ty::InstantiatedPredicates::empty())
+            }
         };
 
         self.normalize_and_prove_instantiated_predicates(
+            def_id,
             instantiated_predicates,
             location.to_locations(),
         );
index d7b46f282151fe32ac11e8dc1432d98f0ba58bb6..307730f7f5f14a9f88f4f627fe2a3b03f84fc3e8 100644 (file)
@@ -2,6 +2,7 @@
 
 use rustc_ast as ast;
 use rustc_ast::mut_visit::MutVisitor;
+use rustc_ast::ptr::P;
 use rustc_ast::tokenstream::CanSynthesizeMissingTokens;
 use rustc_ast::visit::Visitor;
 use rustc_ast::{mut_visit, visit};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_expand::config::StripUnconfigured;
 use rustc_expand::configure;
+use rustc_feature::Features;
 use rustc_parse::parser::ForceCollect;
 use rustc_session::utils::FlattenNonterminals;
-
-use rustc_ast::ptr::P;
+use rustc_session::Session;
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use smallvec::SmallVec;
     annotatable: Annotatable,
 ) -> Vec<Annotatable> {
     check_builtin_macro_attribute(ecx, meta_item, sym::cfg_eval);
-    vec![cfg_eval(ecx, annotatable)]
+    vec![cfg_eval(ecx.sess, ecx.ecfg.features, annotatable)]
 }
 
-crate fn cfg_eval(ecx: &ExtCtxt<'_>, annotatable: Annotatable) -> Annotatable {
-    CfgEval {
-        cfg: &mut StripUnconfigured {
-            sess: ecx.sess,
-            features: ecx.ecfg.features,
-            config_tokens: true,
-        },
-    }
-    .configure_annotatable(annotatable)
-    // Since the item itself has already been configured by the `InvocationCollector`,
-    // we know that fold result vector will contain exactly one element.
-    .unwrap()
+crate fn cfg_eval(
+    sess: &Session,
+    features: Option<&Features>,
+    annotatable: Annotatable,
+) -> Annotatable {
+    CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true } }
+        .configure_annotatable(annotatable)
+        // Since the item itself has already been configured by the `InvocationCollector`,
+        // we know that fold result vector will contain exactly one element.
+        .unwrap()
 }
 
 struct CfgEval<'a, 'b> {
index e0389f448ebf29abf7a48d5bc6bedbfba329fdb7..241c90c157125e5c90daae48737a863c763dead1 100644 (file)
@@ -1,12 +1,13 @@
 use crate::cfg_eval::cfg_eval;
 
-use rustc_ast::{self as ast, attr, token, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
+use rustc_ast as ast;
+use rustc_ast::{attr, token, GenericParamKind, ItemKind, MetaItemKind, NestedMetaItem, StmtKind};
 use rustc_errors::{struct_span_err, Applicability};
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt, Indeterminate, MultiItemModifier};
 use rustc_feature::AttributeTemplate;
 use rustc_parse::validate_attr;
 use rustc_session::Session;
-use rustc_span::symbol::sym;
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 
 crate struct Expander;
@@ -26,8 +27,7 @@ fn expand(
             return ExpandResult::Ready(vec![item]);
         }
 
-        let item = cfg_eval(ecx, item);
-
+        let (sess, features) = (ecx.sess, ecx.ecfg.features);
         let result =
             ecx.resolver.resolve_derives(ecx.current_expansion.id, ecx.force_mode, &|| {
                 let template =
@@ -40,7 +40,8 @@ fn expand(
                     template,
                 );
 
-                attr.meta_item_list()
+                let mut resolutions: Vec<_> = attr
+                    .meta_item_list()
                     .unwrap_or_default()
                     .into_iter()
                     .filter_map(|nested_meta| match nested_meta {
@@ -56,8 +57,21 @@ fn expand(
                         report_path_args(sess, &meta);
                         meta.path
                     })
-                    .map(|path| (path, item.clone(), None))
-                    .collect()
+                    .map(|path| (path, dummy_annotatable(), None))
+                    .collect();
+
+                // Do not configure or clone items unless necessary.
+                match &mut resolutions[..] {
+                    [] => {}
+                    [(_, first_item, _), others @ ..] => {
+                        *first_item = cfg_eval(sess, features, item.clone());
+                        for (_, item, _) in others {
+                            *item = first_item.clone();
+                        }
+                    }
+                }
+
+                resolutions
             });
 
         match result {
@@ -67,6 +81,18 @@ fn expand(
     }
 }
 
+// The cheapest `Annotatable` to construct.
+fn dummy_annotatable() -> Annotatable {
+    Annotatable::GenericParam(ast::GenericParam {
+        id: ast::DUMMY_NODE_ID,
+        ident: Ident::invalid(),
+        attrs: Default::default(),
+        bounds: Default::default(),
+        is_placeholder: false,
+        kind: GenericParamKind::Lifetime,
+    })
+}
+
 fn report_bad_target(sess: &Session, item: &Annotatable, span: Span) -> bool {
     let item_kind = match item {
         Annotatable::Item(item) => Some(&item.kind),
index 25080488a88b525f30b290caee0f6874851564fb..b6567aca78679cc0fe53bfd4967636832eda11ff 100644 (file)
@@ -15,4 +15,4 @@ perf.data.old
 /rand
 /regex
 /simple-raytracer
-/stdsimd
+/portable-simd
index 23c1fdc6ee425c7b73404c78a0303fc6aea9e73c..4afddf76869de4a872b1a49bd5e2f6e7814ff046 100644 (file)
@@ -33,16 +33,16 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "cranelift-bforest"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-entity",
 ]
 
 [[package]]
 name = "cranelift-codegen"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-bforest",
  "cranelift-codegen-meta",
@@ -57,8 +57,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-meta"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-codegen-shared",
  "cranelift-entity",
@@ -66,18 +66,18 @@ dependencies = [
 
 [[package]]
 name = "cranelift-codegen-shared"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 
 [[package]]
 name = "cranelift-entity"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 
 [[package]]
 name = "cranelift-frontend"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-codegen",
  "log",
@@ -87,8 +87,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-jit"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -104,8 +104,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-module"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
@@ -115,8 +115,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-native"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "cranelift-codegen",
  "libc",
@@ -125,8 +125,8 @@ dependencies = [
 
 [[package]]
 name = "cranelift-object"
-version = "0.75.0"
-source = "git+https://github.com/bytecodealliance/wasmtime.git#5deda279775dca5e37449c829cda1f6276d6542b"
+version = "0.76.0"
+source = "git+https://github.com/bytecodealliance/wasmtime.git#9c550fcf41425942ed97c747f0169b2ca81f9c1b"
 dependencies = [
  "anyhow",
  "cranelift-codegen",
index e068f084234bc734fc2e21c5e218a8089dc10d92..22be21cb8dee9a3d1a4ff4096218a2abfbbea13f 100644 (file)
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.14.1"
+version = "0.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
+checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd"
 dependencies = [
  "compiler_builtins",
  "gimli",
@@ -40,9 +40,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
 
 [[package]]
 name = "cc"
-version = "1.0.69"
+version = "1.0.70"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
+checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
 
 [[package]]
 name = "cfg-if"
@@ -56,7 +56,7 @@ dependencies = [
 
 [[package]]
 name = "compiler_builtins"
-version = "0.1.46"
+version = "0.1.50"
 dependencies = [
  "rustc-std-workspace-core",
 ]
@@ -99,9 +99,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.23.0"
+version = "0.25.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce"
+checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-alloc",
@@ -132,13 +132,23 @@ dependencies = [
 
 [[package]]
 name = "libc"
-version = "0.2.98"
+version = "0.2.102"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790"
+checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
 dependencies = [
  "rustc-std-workspace-core",
 ]
 
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+dependencies = [
+ "compiler_builtins",
+ "rustc-std-workspace-core",
+]
+
 [[package]]
 name = "miniz_oxide"
 version = "0.4.4"
@@ -154,11 +164,12 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.22.0"
+version = "0.26.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d3b63360ec3cb337817c2dbd47ab4a0f170d285d8e5a2064600f3def1402397"
+checksum = "39f37e50073ccad23b6d09bcb5b263f4e76d3bb6038e4a3c08e52162ffa8abc2"
 dependencies = [
  "compiler_builtins",
+ "memchr",
  "rustc-std-workspace-alloc",
  "rustc-std-workspace-core",
 ]
@@ -195,9 +206,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.20"
+version = "0.1.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dead70b0b5e03e9c814bcb6b01e03e68f7c57a80aa48c72ec92152ab3e818d49"
+checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -286,9 +297,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-width"
-version = "0.1.8"
+version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
index 4b2051b605abdd726c99682639f95f5c8a7deeb3..ae9a35048bda9a56873fec5e678bb835e80e6e10 100644 (file)
@@ -28,11 +28,11 @@ pub(crate) fn prepare() {
     );
 
     clone_repo(
-        "stdsimd",
-        "https://github.com/rust-lang/stdsimd",
-        "be96995d8ddec03fac9a0caf4d4c51c7fbc33507",
+        "portable-simd",
+        "https://github.com/rust-lang/portable-simd",
+        "8cf7a62e5d2552961df51e5200aaa5b7c890a4bf",
     );
-    apply_patches("stdsimd", Path::new("stdsimd"));
+    apply_patches("portable-simd", Path::new("portable-simd"));
 
     clone_repo(
         "simple-raytracer",
@@ -92,7 +92,7 @@ fn prepare_sysroot() {
     clone_repo(
         "build_sysroot/compiler-builtins",
         "https://github.com/rust-lang/compiler-builtins.git",
-        "0.1.46",
+        "0.1.50",
     );
     apply_patches("compiler-builtins", Path::new("build_sysroot/compiler-builtins"));
 }
index 23e5bf2e0a8fd77fd08e877fe1a2d2baa29cecaf..865de7d234f1419affc4a673bab58986e6d6a790 100755 (executable)
@@ -3,4 +3,4 @@ set -e
 
 rm -rf build_sysroot/{sysroot_src/,target/,compiler-builtins/,rustc_version}
 rm -rf target/ build/ perf.data{,.old}
-rm -rf rand/ regex/ simple-raytracer/ stdsimd/
+rm -rf rand/ regex/ simple-raytracer/ portable-simd/
index 87eec0e818bb2407695c4fa6b82ff49eada037a1..bcc5745d9d1974af3115e83f9004151b10eeeba2 100644 (file)
@@ -24,6 +24,8 @@ $ $cg_clif_dir/build/bin/cg_clif my_crate.rs
 
 ## Jit mode
 
+> ⚠⚠⚠ The JIT mode is highly experimental. It may be slower than AOT compilation due to lack of incremental compilation. It may also be hard to setup if you have cargo dependencies. ⚠⚠⚠
+
 In jit mode cg_clif will immediately execute your code without creating an executable file.
 
 > This requires all dependencies to be available as dynamic library.
index 2a9f7e58e01c2f93db91629a11a21132188bbedf..d0d492e96742d6601819878ee7f94e4126639b7a 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler)]
+#![feature(start, core_intrinsics, alloc_prelude, alloc_error_handler, box_syntax)]
 #![no_std]
 
 extern crate alloc;
index 6e13e4dcbfbffcb1084d4bb9b2c27e41c760c62e..cbfdb3c44f33e1170c2e9d6a8b9abfb5654c7c7a 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local)]
+#![feature(no_core, lang_items, never_type, linkage, extern_types, thread_local, box_syntax)]
 #![no_core]
 #![allow(dead_code, non_camel_case_types)]
 
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-portable-simd-Disable-unsupported-tests.patch
new file mode 100644 (file)
index 0000000..2e68369
--- /dev/null
@@ -0,0 +1,152 @@
+From 6bfce5dc2cbf834c74dbccb7538adc08c6eb57e7 Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Sun, 25 Jul 2021 18:39:31 +0200
+Subject: [PATCH] Disable unsupported tests
+
+---
+ crates/core_simd/src/vector.rs        |  2 ++
+ crates/core_simd/src/math.rs         |  4 ++++
+ crates/core_simd/tests/masks.rs      | 12 ------------
+ crates/core_simd/tests/ops_macros.rs |  6 ++++++
+ crates/core_simd/tests/round.rs      |  2 ++
+ 6 files changed, 15 insertions(+), 13 deletions(-)
+
+diff --git a/crates/core_simd/src/vector.rs b/crates/core_simd/src/vector.rs
+index 25c5309..2b3d819 100644
+--- a/crates/core_simd/src/vector.rs
++++ b/crates/core_simd/src/vector.rs
+@@ -22,6 +22,7 @@ where
+         self.0
+     }
++    /*
+     /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
+     /// If an index is out of bounds, that lane instead selects the value from the "or" vector.
+     /// ```
+@@ -150,6 +151,7 @@ where
+             // Cleared ☢️ *mut T Zone
+         }
+     }
++    */
+ }
+ impl<T, const LANES: usize> Copy for Simd<T, LANES>
+diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
+index 7290a28..e394730 100644
+--- a/crates/core_simd/src/math.rs
++++ b/crates/core_simd/src/math.rs
+@@ -2,6 +2,7 @@ macro_rules! impl_uint_arith {
+     ($($ty:ty),+) => {
+         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
++            /*
+             /// Lanewise saturating add.
+             ///
+             /// # Examples
+@@ -38,6 +39,7 @@ macro_rules! impl_uint_arith {
+             pub fn saturating_sub(self, second: Self) -> Self {
+                 unsafe { crate::intrinsics::simd_saturating_sub(self, second) }
+             }
++            */
+         })+
+     }
+ }
+@@ -46,6 +48,7 @@ macro_rules! impl_int_arith {
+     ($($ty:ty),+) => {
+         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
++            /*
+             /// Lanewise saturating add.
+             ///
+             /// # Examples
+@@ -141,6 +144,7 @@ macro_rules! impl_int_arith {
+             pub fn saturating_neg(self) -> Self {
+                 Self::splat(0).saturating_sub(self)
+             }
++            */
+         })+
+     }
+ }
+diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
+index 61d8e44..2bccae2 100644
+--- a/crates/core_simd/tests/masks.rs
++++ b/crates/core_simd/tests/masks.rs
+@@ -67,19 +67,6 @@ macro_rules! test_mask_api {
+                 assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]);
+                 assert_eq!(core_simd::Mask::<$type, 8>::from_int(int), mask);
+             }
+-
+-            #[cfg(feature = "generic_const_exprs")]
+-            #[test]
+-            fn roundtrip_bitmask_conversion() {
+-                let values = [
+-                    true, false, false, true, false, false, true, false,
+-                    true, true, false, false, false, false, false, true,
+-                ];
+-                let mask = core_simd::Mask::<$type, 16>::from_array(values);
+-                let bitmask = mask.to_bitmask();
+-                assert_eq!(bitmask, [0b01001001, 0b10000011]);
+-                assert_eq!(core_simd::Mask::<$type, 16>::from_bitmask(bitmask), mask);
+-            }
+         }
+     }
+ }
+diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
+index cb39e73..fc0ebe1 100644
+--- a/crates/core_simd/tests/ops_macros.rs
++++ b/crates/core_simd/tests/ops_macros.rs
+@@ -435,6 +435,7 @@ macro_rules! impl_float_tests {
+                     )
+                 }
++                /*
+                 fn mul_add<const LANES: usize>() {
+                     test_helpers::test_ternary_elementwise(
+                         &Vector::<LANES>::mul_add,
+@@ -442,6 +443,7 @@ macro_rules! impl_float_tests {
+                         &|_, _, _| true,
+                     )
+                 }
++                */
+                 fn recip<const LANES: usize>() {
+                     test_helpers::test_unary_elementwise(
+@@ -581,6 +585,7 @@ macro_rules! impl_float_tests {
+                     });
+                 }
++                /*
+                 fn horizontal_max<const LANES: usize>() {
+                     test_helpers::test_1(&|x| {
+                         let vmax = Vector::<LANES>::from_array(x).horizontal_max();
+@@ -604,6 +609,7 @@ macro_rules! impl_float_tests {
+                         Ok(())
+                     });
+                 }
++                */
+             }
+             #[cfg(feature = "std")]
+diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs
+index 37044a7..4cdc6b7 100644
+--- a/crates/core_simd/tests/round.rs
++++ b/crates/core_simd/tests/round.rs
+@@ -25,6 +25,7 @@ macro_rules! float_rounding_test {
+                     )
+                 }
++                /*
+                 fn round<const LANES: usize>() {
+                     test_helpers::test_unary_elementwise(
+                         &Vector::<LANES>::round,
+@@ -32,6 +33,7 @@ macro_rules! float_rounding_test {
+                         &|_| true,
+                     )
+                 }
++                */
+                 fn trunc<const LANES: usize>() {
+                     test_helpers::test_unary_elementwise(
+-- 
+2.26.2.7.g19db9cfb68
+
diff --git a/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch b/compiler/rustc_codegen_cranelift/patches/0001-stdsimd-Disable-unsupported-tests.patch
deleted file mode 100644 (file)
index 731c60f..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-From 6bfce5dc2cbf834c74dbccb7538adc08c6eb57e7 Mon Sep 17 00:00:00 2001
-From: bjorn3 <bjorn3@users.noreply.github.com>
-Date: Sun, 25 Jul 2021 18:39:31 +0200
-Subject: [PATCH] Disable unsupported tests
-
----
- crates/core_simd/src/array.rs        |  2 ++
- crates/core_simd/src/lib.rs          |  2 +-
- crates/core_simd/src/math.rs         |  4 ++++
- crates/core_simd/tests/masks.rs      | 12 ------------
- crates/core_simd/tests/ops_macros.rs |  6 ++++++
- crates/core_simd/tests/round.rs      |  2 ++
- 6 files changed, 15 insertions(+), 13 deletions(-)
-
-diff --git a/crates/core_simd/src/array.rs b/crates/core_simd/src/array.rs
-index 25c5309..2b3d819 100644
---- a/crates/core_simd/src/array.rs
-+++ b/crates/core_simd/src/array.rs
-@@ -22,6 +22,7 @@ where
-     #[must_use]
-     fn splat(val: Self::Scalar) -> Self;
-+    /*
-     /// SIMD gather: construct a SIMD vector by reading from a slice, using potentially discontiguous indices.
-     /// If an index is out of bounds, that lane instead selects the value from the "or" vector.
-     /// ```
-@@ -150,6 +151,7 @@ where
-             // Cleared ☢️ *mut T Zone
-         }
-     }
-+    */
- }
- macro_rules! impl_simdarray_for {
-diff --git a/crates/core_simd/src/lib.rs b/crates/core_simd/src/lib.rs
-index a64904d..299eb11 100644
---- a/crates/core_simd/src/lib.rs
-+++ b/crates/core_simd/src/lib.rs
-@@ -1,7 +1,7 @@
- #![no_std]
- #![allow(incomplete_features)]
- #![feature(
--    const_generics, 
-+    const_generics,
-     platform_intrinsics,
-     repr_simd,
-     simd_ffi,
-diff --git a/crates/core_simd/src/math.rs b/crates/core_simd/src/math.rs
-index 7290a28..e394730 100644
---- a/crates/core_simd/src/math.rs
-+++ b/crates/core_simd/src/math.rs
-@@ -2,6 +2,7 @@ macro_rules! impl_uint_arith {
-     ($(($name:ident, $n:ident)),+) => {
-         $( impl<const LANES: usize> $name<LANES> where Self: crate::LanesAtMost32 {
-+            /*
-             /// Lanewise saturating add.
-             ///
-             /// # Examples
-@@ -38,6 +39,7 @@ macro_rules! impl_uint_arith {
-             pub fn saturating_sub(self, second: Self) -> Self {
-                 unsafe { crate::intrinsics::simd_saturating_sub(self, second) }
-             }
-+            */
-         })+
-     }
- }
-@@ -46,6 +48,7 @@ macro_rules! impl_int_arith {
-     ($(($name:ident, $n:ident)),+) => {
-         $( impl<const LANES: usize> $name<LANES> where Self: crate::LanesAtMost32 {
-+            /*
-             /// Lanewise saturating add.
-             ///
-             /// # Examples
-@@ -141,6 +144,7 @@ macro_rules! impl_int_arith {
-             pub fn saturating_neg(self) -> Self {
-                 Self::splat(0).saturating_sub(self)
-             }
-+            */
-         })+
-     }
- }
-diff --git a/crates/core_simd/tests/masks.rs b/crates/core_simd/tests/masks.rs
-index 61d8e44..2bccae2 100644
---- a/crates/core_simd/tests/masks.rs
-+++ b/crates/core_simd/tests/masks.rs
-@@ -67,18 +67,6 @@ macro_rules! test_mask_api {
-                 assert_eq!(int.to_array(), [-1, 0, 0, -1, 0, 0, -1, 0]);
-                 assert_eq!(core_simd::$name::<8>::from_int(int), mask);
-             }
--
--            #[test]
--            fn roundtrip_bitmask_conversion() {
--                let values = [
--                    true, false, false, true, false, false, true, false,
--                    true, true, false, false, false, false, false, true,
--                ];
--                let mask = core_simd::$name::<16>::from_array(values);
--                let bitmask = mask.to_bitmask();
--                assert_eq!(bitmask, [0b01001001, 0b10000011]);
--                assert_eq!(core_simd::$name::<16>::from_bitmask(bitmask), mask);
--            }
-         }
-     }
- }
-diff --git a/crates/core_simd/tests/ops_macros.rs b/crates/core_simd/tests/ops_macros.rs
-index cb39e73..fc0ebe1 100644
---- a/crates/core_simd/tests/ops_macros.rs
-+++ b/crates/core_simd/tests/ops_macros.rs
-@@ -435,6 +435,7 @@ macro_rules! impl_float_tests {
-                     )
-                 }
-+                /*
-                 fn mul_add<const LANES: usize>() {
-                     test_helpers::test_ternary_elementwise(
-                         &Vector::<LANES>::mul_add,
-@@ -442,6 +443,7 @@ macro_rules! impl_float_tests {
-                         &|_, _, _| true,
-                     )
-                 }
-+                */
-                 fn sqrt<const LANES: usize>() {
-                     test_helpers::test_unary_elementwise(
-@@ -581,6 +585,7 @@ macro_rules! impl_float_tests {
-                     });
-                 }
-+                /*
-                 fn horizontal_max<const LANES: usize>() {
-                     test_helpers::test_1(&|x| {
-                         let vmax = Vector::<LANES>::from_array(x).horizontal_max();
-@@ -604,6 +609,7 @@ macro_rules! impl_float_tests {
-                         Ok(())
-                     });
-                 }
-+                */
-             }
-         }
-     }
-diff --git a/crates/core_simd/tests/round.rs b/crates/core_simd/tests/round.rs
-index 37044a7..4cdc6b7 100644
---- a/crates/core_simd/tests/round.rs
-+++ b/crates/core_simd/tests/round.rs
-@@ -25,6 +25,7 @@ macro_rules! float_rounding_test {
-                     )
-                 }
-+                /*
-                 fn round<const LANES: usize>() {
-                     test_helpers::test_unary_elementwise(
-                         &Vector::<LANES>::round,
-@@ -32,6 +33,7 @@ macro_rules! float_rounding_test {
-                         &|_| true,
-                     )
-                 }
-+                */
-                 fn trunc<const LANES: usize>() {
-                     test_helpers::test_unary_elementwise(
--- 
-2.26.2.7.g19db9cfb68
-
index cda8153083c337fd004cf2e3d5c0ac631156fd19..e2d07bd12670264d2674919a63809eb55d15a112 100644 (file)
@@ -1,4 +1,4 @@
-From 6a4e6f5dc8c8a529a822eb9b57f9e57519595439 Mon Sep 17 00:00:00 2001
+From ad7ffe71baba46865f2e65266ab025920dfdc20b Mon Sep 17 00:00:00 2001
 From: bjorn3 <bjorn3@users.noreply.github.com>
 Date: Thu, 18 Feb 2021 18:45:28 +0100
 Subject: [PATCH] Disable 128bit atomic operations
@@ -8,7 +8,8 @@ Cranelift doesn't support them yet
  library/core/src/panic/unwind_safe.rs |  6 -----
  library/core/src/sync/atomic.rs       | 38 ---------------------------
  library/core/tests/atomic.rs          |  4 ---
- 3 files changed, 48 deletions(-)
+ library/std/src/time/monotonic.rs     |  6 +++--
+ 4 files changed, 4 insertions(+), 50 deletions(-)
 
 diff --git a/library/core/src/panic/unwind_safe.rs b/library/core/src/panic/unwind_safe.rs
 index 092b7cf..158cf71 100644
@@ -35,10 +36,10 @@ index 092b7cf..158cf71 100644
  #[cfg(target_has_atomic_load_store = "8")]
  #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")]
 diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
-index 0194c58..25a0038 100644
+index d9de37e..8293fce 100644
 --- a/library/core/src/sync/atomic.rs
 +++ b/library/core/src/sync/atomic.rs
-@@ -2229,44 +2229,6 @@ atomic_int! {
+@@ -2234,44 +2234,6 @@ atomic_int! {
      "AtomicU64::new(0)",
      u64 AtomicU64 ATOMIC_U64_INIT
  }
@@ -98,6 +99,38 @@ index b735957..ea728b6 100644
      #[cfg(target_has_atomic = "ptr")]
      assert_eq!(align_of::<AtomicUsize>(), size_of::<AtomicUsize>());
      #[cfg(target_has_atomic = "ptr")]
+diff --git a/library/std/src/time/monotonic.rs b/library/std/src/time/monotonic.rs
+index fa96b7a..2854f9c 100644
+--- a/library/std/src/time/monotonic.rs
++++ b/library/std/src/time/monotonic.rs
+@@ -5,7 +5,7 @@ pub(super) fn monotonize(raw: time::Instant) -> time::Instant {
+     inner::monotonize(raw)
+ }
+-#[cfg(all(target_has_atomic = "64", not(target_has_atomic = "128")))]
++#[cfg(target_has_atomic = "64")]
+ pub mod inner {
+     use crate::sync::atomic::AtomicU64;
+     use crate::sync::atomic::Ordering::*;
+@@ -70,6 +70,7 @@ pub mod inner {
+     }
+ }
++/*
+ #[cfg(target_has_atomic = "128")]
+ pub mod inner {
+     use crate::sync::atomic::AtomicU128;
+@@ -94,8 +95,9 @@ pub mod inner {
+         ZERO.checked_add_duration(&Duration::new(secs, nanos)).unwrap()
+     }
+ }
++*/
+-#[cfg(not(any(target_has_atomic = "64", target_has_atomic = "128")))]
++#[cfg(not(target_has_atomic = "64"))]
+ pub mod inner {
+     use crate::cmp;
+     use crate::sys::time;
 -- 
 2.26.2.7.g19db9cfb68
 
index f074ebe7a42e0dabf88c234aadb2ebcf9896ef64..360570b3ae7a145c8bd24f7496878f6997912678 100644 (file)
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2021-08-05"
+channel = "nightly-2021-09-19"
 components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
index 0ac49dd35740f51e36f1a7ba9265a5ef1f63f0cf..b714d47fec2a6d3d63fedc5d4b80ae3fcdb4b071 100755 (executable)
@@ -11,7 +11,7 @@ pushd rust
 cargo install ripgrep
 
 rm -r src/test/ui/{extern/,panics/,unsized-locals/,thinlto/,simd*,*lto*.rs,linkage*,unwind-*.rs} || true
-for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto" src/test/ui); do
+for test in $(rg --files-with-matches "asm!|catch_unwind|should_panic|lto|// needs-asm-support" src/test/ui); do
   rm $test
 done
 
index 0eef710239bdd456e90df4ce7f69a8f2d5832a6b..28a7980d6613cf0eef6c013879a59f3f442950f4 100755 (executable)
@@ -137,8 +137,8 @@ function extended_sysroot_tests() {
     fi
     popd
 
-    pushd stdsimd
-    echo "[TEST] rust-lang/stdsimd"
+    pushd portable-simd
+    echo "[TEST] rust-lang/portable-simd"
     ../build/cargo clean
     ../build/cargo build --all-targets --target $TARGET_TRIPLE
     if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
index 0fa228fc944a160c226f21c2ebec660c1192ba7c..8a1f654399004a3c80280754aa57d4ff6bc3179f 100644 (file)
@@ -1,17 +1,20 @@
 //! Creation of ar archives like for the lib and staticlib crate type
 
 use std::collections::BTreeMap;
+use std::convert::TryFrom;
 use std::fs::File;
+use std::io::{self, Read, Seek};
 use std::path::{Path, PathBuf};
 
 use rustc_codegen_ssa::back::archive::ArchiveBuilder;
 use rustc_session::Session;
 
-use object::{Object, ObjectSymbol, SymbolKind};
+use object::read::archive::ArchiveFile;
+use object::{Object, ObjectSymbol, ReadCache, SymbolKind};
 
 #[derive(Debug)]
 enum ArchiveEntry {
-    FromArchive { archive_index: usize, entry_index: usize },
+    FromArchive { archive_index: usize, file_range: (u64, u64) },
     File(PathBuf),
 }
 
@@ -21,29 +24,28 @@ pub(crate) struct ArArchiveBuilder<'a> {
     use_gnu_style_archive: bool,
     no_builtin_ranlib: bool,
 
-    src_archives: Vec<(PathBuf, ar::Archive<File>)>,
+    src_archives: Vec<File>,
     // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
     // the end of an archive for linkers to not get confused.
-    entries: Vec<(String, ArchiveEntry)>,
+    entries: Vec<(Vec<u8>, ArchiveEntry)>,
 }
 
 impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
     fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
         let (src_archives, entries) = if let Some(input) = input {
-            let mut archive = ar::Archive::new(File::open(input).unwrap());
+            let read_cache = ReadCache::new(File::open(input).unwrap());
+            let archive = ArchiveFile::parse(&read_cache).unwrap();
             let mut entries = Vec::new();
 
-            let mut i = 0;
-            while let Some(entry) = archive.next_entry() {
+            for entry in archive.members() {
                 let entry = entry.unwrap();
                 entries.push((
-                    String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
-                    ArchiveEntry::FromArchive { archive_index: 0, entry_index: i },
+                    entry.name().to_vec(),
+                    ArchiveEntry::FromArchive { archive_index: 0, file_range: entry.file_range() },
                 ));
-                i += 1;
             }
 
-            (vec![(input.to_owned(), archive)], entries)
+            (vec![read_cache.into_inner()], entries)
         } else {
             (vec![], Vec::new())
         };
@@ -61,21 +63,21 @@ fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
     }
 
     fn src_files(&mut self) -> Vec<String> {
-        self.entries.iter().map(|(name, _)| name.clone()).collect()
+        self.entries.iter().map(|(name, _)| String::from_utf8(name.clone()).unwrap()).collect()
     }
 
     fn remove_file(&mut self, name: &str) {
         let index = self
             .entries
             .iter()
-            .position(|(entry_name, _)| entry_name == name)
+            .position(|(entry_name, _)| entry_name == name.as_bytes())
             .expect("Tried to remove file not existing in src archive");
         self.entries.remove(index);
     }
 
     fn add_file(&mut self, file: &Path) {
         self.entries.push((
-            file.file_name().unwrap().to_str().unwrap().to_string(),
+            file.file_name().unwrap().to_str().unwrap().to_string().into_bytes(),
             ArchiveEntry::File(file.to_owned()),
         ));
     }
@@ -84,22 +86,23 @@ fn add_archive<F>(&mut self, archive_path: &Path, mut skip: F) -> std::io::Resul
     where
         F: FnMut(&str) -> bool + 'static,
     {
-        let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
+        let read_cache = ReadCache::new(std::fs::File::open(&archive_path)?);
+        let archive = ArchiveFile::parse(&read_cache).unwrap();
         let archive_index = self.src_archives.len();
 
-        let mut i = 0;
-        while let Some(entry) = archive.next_entry() {
-            let entry = entry?;
-            let file_name = String::from_utf8(entry.header().identifier().to_vec())
-                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
+        for entry in archive.members() {
+            let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
+            let file_name = String::from_utf8(entry.name().to_vec())
+                .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?;
             if !skip(&file_name) {
-                self.entries
-                    .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i }));
+                self.entries.push((
+                    file_name.into_bytes(),
+                    ArchiveEntry::FromArchive { archive_index, file_range: entry.file_range() },
+                ));
             }
-            i += 1;
         }
 
-        self.src_archives.push((archive_path.to_owned(), archive));
+        self.src_archives.push(read_cache.into_inner());
         Ok(())
     }
 
@@ -121,14 +124,14 @@ enum BuilderKind {
             // FIXME only read the symbol table of the object files to avoid having to keep all
             // object files in memory at once, or read them twice.
             let data = match entry {
-                ArchiveEntry::FromArchive { archive_index, entry_index } => {
+                ArchiveEntry::FromArchive { archive_index, file_range } => {
                     // FIXME read symbols from symtab
-                    use std::io::Read;
-                    let (ref _src_archive_path, ref mut src_archive) =
-                        self.src_archives[archive_index];
-                    let mut entry = src_archive.jump_to_entry(entry_index).unwrap();
-                    let mut data = Vec::new();
-                    entry.read_to_end(&mut data).unwrap();
+                    let src_read_cache = &mut self.src_archives[archive_index];
+
+                    src_read_cache.seek(io::SeekFrom::Start(file_range.0)).unwrap();
+                    let mut data = std::vec::from_elem(0, usize::try_from(file_range.1).unwrap());
+                    src_read_cache.read_exact(&mut data).unwrap();
+
                     data
                 }
                 ArchiveEntry::File(file) => std::fs::read(file).unwrap_or_else(|err| {
@@ -143,7 +146,7 @@ enum BuilderKind {
                 match object::File::parse(&*data) {
                     Ok(object) => {
                         symbol_table.insert(
-                            entry_name.as_bytes().to_vec(),
+                            entry_name.to_vec(),
                             object
                                 .symbols()
                                 .filter_map(|symbol| {
@@ -168,7 +171,8 @@ enum BuilderKind {
                         } else {
                             sess.fatal(&format!(
                                 "error parsing `{}` during archive creation: {}",
-                                entry_name, err
+                                String::from_utf8_lossy(&entry_name),
+                                err
                             ));
                         }
                     }
@@ -187,7 +191,7 @@ enum BuilderKind {
                             err
                         ));
                     }),
-                    entries.iter().map(|(name, _)| name.as_bytes().to_vec()).collect(),
+                    entries.iter().map(|(name, _)| name.clone()).collect(),
                     ar::GnuSymbolTableFormat::Size32,
                     symbol_table,
                 )
@@ -210,7 +214,7 @@ enum BuilderKind {
 
         // Add all files
         for (entry_name, data) in entries.into_iter() {
-            let header = ar::Header::new(entry_name.into_bytes(), data.len() as u64);
+            let header = ar::Header::new(entry_name, data.len() as u64);
             match builder {
                 BuilderKind::Bsd(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
                 BuilderKind::Gnu(ref mut builder) => builder.append(&header, &mut &*data).unwrap(),
diff --git a/compiler/rustc_codegen_cranelift/src/backend.rs b/compiler/rustc_codegen_cranelift/src/backend.rs
deleted file mode 100644 (file)
index 05c06ba..0000000
+++ /dev/null
@@ -1,152 +0,0 @@
-//! Abstraction around the object writing crate
-
-use std::convert::{TryFrom, TryInto};
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_session::Session;
-
-use cranelift_codegen::isa::TargetIsa;
-use cranelift_module::FuncId;
-use cranelift_object::{ObjectBuilder, ObjectModule, ObjectProduct};
-
-use object::write::*;
-use object::{RelocationEncoding, SectionKind, SymbolFlags};
-
-use gimli::SectionId;
-
-use crate::debuginfo::{DebugReloc, DebugRelocName};
-
-pub(crate) trait WriteMetadata {
-    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>);
-}
-
-impl WriteMetadata for object::write::Object {
-    fn add_rustc_section(&mut self, symbol_name: String, data: Vec<u8>) {
-        let segment = self.segment_name(object::write::StandardSegment::Data).to_vec();
-        let section_id = self.add_section(segment, b".rustc".to_vec(), object::SectionKind::Data);
-        let offset = self.append_section_data(section_id, &data, 1);
-        // For MachO and probably PE this is necessary to prevent the linker from throwing away the
-        // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
-        self.add_symbol(object::write::Symbol {
-            name: symbol_name.into_bytes(),
-            value: offset,
-            size: data.len() as u64,
-            kind: object::SymbolKind::Data,
-            scope: object::SymbolScope::Dynamic,
-            weak: false,
-            section: SymbolSection::Section(section_id),
-            flags: SymbolFlags::None,
-        });
-    }
-}
-
-pub(crate) trait WriteDebugInfo {
-    type SectionId: Copy;
-
-    fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
-    fn add_debug_reloc(
-        &mut self,
-        section_map: &FxHashMap<SectionId, Self::SectionId>,
-        from: &Self::SectionId,
-        reloc: &DebugReloc,
-    );
-}
-
-impl WriteDebugInfo for ObjectProduct {
-    type SectionId = (object::write::SectionId, object::write::SymbolId);
-
-    fn add_debug_section(
-        &mut self,
-        id: SectionId,
-        data: Vec<u8>,
-    ) -> (object::write::SectionId, object::write::SymbolId) {
-        let name = if self.object.format() == object::BinaryFormat::MachO {
-            id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
-        } else {
-            id.name().to_string()
-        }
-        .into_bytes();
-
-        let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
-        // FIXME use SHT_X86_64_UNWIND for .eh_frame
-        let section_id = self.object.add_section(
-            segment,
-            name,
-            if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
-        );
-        self.object
-            .section_mut(section_id)
-            .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
-        let symbol_id = self.object.section_symbol(section_id);
-        (section_id, symbol_id)
-    }
-
-    fn add_debug_reloc(
-        &mut self,
-        section_map: &FxHashMap<SectionId, Self::SectionId>,
-        from: &Self::SectionId,
-        reloc: &DebugReloc,
-    ) {
-        let (symbol, symbol_offset) = match reloc.name {
-            DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
-            DebugRelocName::Symbol(id) => {
-                let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
-                self.object
-                    .symbol_section_and_offset(symbol_id)
-                    .expect("Debug reloc for undef sym???")
-            }
-        };
-        self.object
-            .add_relocation(
-                from.0,
-                Relocation {
-                    offset: u64::from(reloc.offset),
-                    symbol,
-                    kind: reloc.kind,
-                    encoding: RelocationEncoding::Generic,
-                    size: reloc.size * 8,
-                    addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
-                },
-            )
-            .unwrap();
-    }
-}
-
-pub(crate) fn with_object(sess: &Session, name: &str, f: impl FnOnce(&mut Object)) -> Vec<u8> {
-    let triple = crate::target_triple(sess);
-
-    let binary_format = match triple.binary_format {
-        target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
-        target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
-        target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
-        binary_format => sess.fatal(&format!("binary format {} is unsupported", binary_format)),
-    };
-    let architecture = match triple.architecture {
-        target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
-        target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
-        target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
-        target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
-        architecture => {
-            sess.fatal(&format!("target architecture {:?} is unsupported", architecture,))
-        }
-    };
-    let endian = match triple.endianness().unwrap() {
-        target_lexicon::Endianness::Little => object::Endianness::Little,
-        target_lexicon::Endianness::Big => object::Endianness::Big,
-    };
-
-    let mut metadata_object = object::write::Object::new(binary_format, architecture, endian);
-    metadata_object.add_file_symbol(name.as_bytes().to_vec());
-    f(&mut metadata_object);
-    metadata_object.write().unwrap()
-}
-
-pub(crate) fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
-    let mut builder =
-        ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
-    // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
-    // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
-    // can easily double the amount of time necessary to perform linking.
-    builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
-    ObjectModule::new(builder)
-}
index d8fa2c769046827fa36c332f1e5d71047ef68507..1b30edd293862b1d221cbfb4529c1b9f8883a52e 100644 (file)
@@ -701,6 +701,13 @@ fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
                     let len = codegen_array_len(fx, place);
                     lval.write_cvalue(fx, CValue::by_val(len, usize_layout));
                 }
+                Rvalue::ShallowInitBox(ref operand, content_ty) => {
+                    let content_ty = fx.monomorphize(content_ty);
+                    let box_layout = fx.layout_of(fx.tcx.mk_box(content_ty));
+                    let operand = codegen_operand(fx, operand);
+                    let operand = operand.load_scalar(fx);
+                    lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
+                }
                 Rvalue::NullaryOp(NullOp::Box, content_ty) => {
                     let usize_type = fx.clif_type(fx.tcx.types.usize).unwrap();
                     let content_ty = fx.monomorphize(content_ty);
index a044b43b86470a3c3e83f99ea5eb0cec9d4ea92e..b924f2085a0fc5546936a82df6019233e48f053a 100644 (file)
@@ -1,4 +1,7 @@
 #![feature(rustc_private, once_cell)]
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+#![warn(unreachable_pub)]
 
 extern crate rustc_data_structures;
 extern crate rustc_driver;
index 89e0cb8d90ecd6c58bef18c764a66f9cc59b8654..bde4d71b9a33c4f385b9640410e68b0bff51d5e5 100644 (file)
@@ -7,6 +7,9 @@
 //! target crates.
 
 #![feature(rustc_private)]
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+#![warn(unreachable_pub)]
 
 extern crate rustc_driver;
 extern crate rustc_interface;
index fb6ccd7c535845b85d9582de3d82f4638bc1cbe4..c8c2d50b03409619bcc05a668f4e0002a5d3e0d4 100644 (file)
@@ -1,16 +1,16 @@
 //! Write the debuginfo into an object file.
 
+use cranelift_object::ObjectProduct;
 use rustc_data_structures::fx::FxHashMap;
 
 use gimli::write::{Address, AttributeValue, EndianVec, Result, Sections, Writer};
 use gimli::{RunTimeEndian, SectionId};
 
-use crate::backend::WriteDebugInfo;
-
+use super::object::WriteDebugInfo;
 use super::DebugContext;
 
 impl DebugContext<'_> {
-    pub(crate) fn emit<P: WriteDebugInfo>(&mut self, product: &mut P) {
+    pub(crate) fn emit(&mut self, product: &mut ObjectProduct) {
         let unit_range_list_id = self.dwarf.unit.ranges.add(self.unit_range_list.clone());
         let root = self.dwarf.unit.root();
         let root = self.dwarf.unit.get_mut(root);
index cabe3e43b342c5bc8f9e20bb336fb0bb9fdc2c50..6d172817cb12ef129fd78aad78ec101d3fb1cf82 100644 (file)
@@ -2,6 +2,7 @@
 
 mod emit;
 mod line_info;
+mod object;
 mod unwind;
 
 use crate::prelude::*;
diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/object.rs
new file mode 100644 (file)
index 0000000..9984dc9
--- /dev/null
@@ -0,0 +1,85 @@
+use std::convert::{TryFrom, TryInto};
+
+use rustc_data_structures::fx::FxHashMap;
+
+use cranelift_module::FuncId;
+use cranelift_object::ObjectProduct;
+
+use object::write::{Relocation, StandardSegment};
+use object::{RelocationEncoding, SectionKind};
+
+use gimli::SectionId;
+
+use crate::debuginfo::{DebugReloc, DebugRelocName};
+
+pub(super) trait WriteDebugInfo {
+    type SectionId: Copy;
+
+    fn add_debug_section(&mut self, name: SectionId, data: Vec<u8>) -> Self::SectionId;
+    fn add_debug_reloc(
+        &mut self,
+        section_map: &FxHashMap<SectionId, Self::SectionId>,
+        from: &Self::SectionId,
+        reloc: &DebugReloc,
+    );
+}
+
+impl WriteDebugInfo for ObjectProduct {
+    type SectionId = (object::write::SectionId, object::write::SymbolId);
+
+    fn add_debug_section(
+        &mut self,
+        id: SectionId,
+        data: Vec<u8>,
+    ) -> (object::write::SectionId, object::write::SymbolId) {
+        let name = if self.object.format() == object::BinaryFormat::MachO {
+            id.name().replace('.', "__") // machO expects __debug_info instead of .debug_info
+        } else {
+            id.name().to_string()
+        }
+        .into_bytes();
+
+        let segment = self.object.segment_name(StandardSegment::Debug).to_vec();
+        // FIXME use SHT_X86_64_UNWIND for .eh_frame
+        let section_id = self.object.add_section(
+            segment,
+            name,
+            if id == SectionId::EhFrame { SectionKind::ReadOnlyData } else { SectionKind::Debug },
+        );
+        self.object
+            .section_mut(section_id)
+            .set_data(data, if id == SectionId::EhFrame { 8 } else { 1 });
+        let symbol_id = self.object.section_symbol(section_id);
+        (section_id, symbol_id)
+    }
+
+    fn add_debug_reloc(
+        &mut self,
+        section_map: &FxHashMap<SectionId, Self::SectionId>,
+        from: &Self::SectionId,
+        reloc: &DebugReloc,
+    ) {
+        let (symbol, symbol_offset) = match reloc.name {
+            DebugRelocName::Section(id) => (section_map.get(&id).unwrap().1, 0),
+            DebugRelocName::Symbol(id) => {
+                let symbol_id = self.function_symbol(FuncId::from_u32(id.try_into().unwrap()));
+                self.object
+                    .symbol_section_and_offset(symbol_id)
+                    .expect("Debug reloc for undef sym???")
+            }
+        };
+        self.object
+            .add_relocation(
+                from.0,
+                Relocation {
+                    offset: u64::from(reloc.offset),
+                    symbol,
+                    kind: reloc.kind,
+                    encoding: RelocationEncoding::Generic,
+                    size: reloc.size * 8,
+                    addend: i64::try_from(symbol_offset).unwrap() + reloc.addend,
+                },
+            )
+            .unwrap();
+    }
+}
index d1251e749f31fe90687312a9ff7837d7a0149d9b..f0896ea0e167fd09d2ec81e8f29b04e86484cdee 100644 (file)
@@ -4,10 +4,11 @@
 
 use cranelift_codegen::isa::{unwind::UnwindInfo, TargetIsa};
 
+use cranelift_object::ObjectProduct;
 use gimli::write::{Address, CieId, EhFrame, FrameTable, Section};
 use gimli::RunTimeEndian;
 
-use crate::backend::WriteDebugInfo;
+use super::object::WriteDebugInfo;
 
 pub(crate) struct UnwindContext {
     endian: RunTimeEndian,
@@ -55,7 +56,7 @@ pub(crate) fn add_function(&mut self, func_id: FuncId, context: &Context, isa: &
         }
     }
 
-    pub(crate) fn emit<P: WriteDebugInfo>(self, product: &mut P) {
+    pub(crate) fn emit(self, product: &mut ObjectProduct) {
         let mut eh_frame = EhFrame::from(super::emit::WriterRelocate::new(self.endian));
         self.frame_table.write_eh_frame(&mut eh_frame).unwrap();
 
index 3de706ed6d7afdb547d7171819dbc0a2a711b453..40cbc5e1a7ee473fd317a4f046b602e11722bde6 100644 (file)
 use rustc_middle::mir::mono::{CodegenUnit, MonoItem};
 use rustc_session::cgu_reuse_tracker::CguReuse;
 use rustc_session::config::{DebugInfo, OutputType};
+use rustc_session::Session;
 
-use cranelift_object::ObjectModule;
+use cranelift_codegen::isa::TargetIsa;
+use cranelift_object::{ObjectBuilder, ObjectModule};
 
 use crate::{prelude::*, BackendConfig};
 
@@ -24,6 +26,16 @@ fn hash_stable(&self, _: &mut HCX, _: &mut StableHasher) {
     }
 }
 
+fn make_module(sess: &Session, isa: Box<dyn TargetIsa>, name: String) -> ObjectModule {
+    let mut builder =
+        ObjectBuilder::new(isa, name + ".o", cranelift_module::default_libcall_names()).unwrap();
+    // Unlike cg_llvm, cg_clif defaults to disabling -Zfunction-sections. For cg_llvm binary size
+    // is important, while cg_clif cares more about compilation times. Enabling -Zfunction-sections
+    // can easily double the amount of time necessary to perform linking.
+    builder.per_function_section(sess.opts.debugging_opts.function_sections.unwrap_or(false));
+    ObjectModule::new(builder)
+}
+
 fn emit_module(
     tcx: TyCtxt<'_>,
     backend_config: &BackendConfig,
@@ -104,7 +116,7 @@ fn module_codegen(
     let mono_items = cgu.items_in_deterministic_order(tcx);
 
     let isa = crate::build_isa(tcx.sess, &backend_config);
-    let mut module = crate::backend::make_module(tcx.sess, isa, cgu_name.as_str().to_string());
+    let mut module = make_module(tcx.sess, isa, cgu_name.as_str().to_string());
 
     let mut cx = crate::CodegenCx::new(
         tcx,
@@ -227,8 +239,7 @@ pub(crate) fn run_aot(
     tcx.sess.abort_if_errors();
 
     let isa = crate::build_isa(tcx.sess, &backend_config);
-    let mut allocator_module =
-        crate::backend::make_module(tcx.sess, isa, "allocator_shim".to_string());
+    let mut allocator_module = make_module(tcx.sess, isa, "allocator_shim".to_string());
     assert_eq!(pointer_ty(tcx), allocator_module.target_config().pointer_type());
     let mut allocator_unwind_context = UnwindContext::new(tcx, allocator_module.isa(), true);
     let created_alloc_shim =
@@ -266,9 +277,7 @@ pub(crate) fn run_aot(
             let tmp_file =
                 tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name));
 
-            let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| {
-                crate::metadata::write_metadata(tcx, object);
-            });
+            let obj = crate::metadata::new_metadata_object(tcx, &metadata_cgu_name, &metadata);
 
             if let Err(err) = std::fs::write(&tmp_file, obj) {
                 tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
index 87193e3ef5341a060567ac6dac79fce80d6a62a3..2ceccdd34994d038781f6509bac70cb76f00d086 100644 (file)
@@ -1,4 +1,5 @@
-#![feature(rustc_private, decl_macro, never_type, hash_drain_filter, vec_into_raw_parts, once_cell)]
+#![feature(rustc_private, decl_macro)]
+#![cfg_attr(feature = "jit", feature(never_type, vec_into_raw_parts, once_cell))]
 #![warn(rust_2018_idioms)]
 #![warn(unused_lifetimes)]
 #![warn(unreachable_pub)]
@@ -44,7 +45,6 @@
 mod allocator;
 mod analyze;
 mod archive;
-mod backend;
 mod base;
 mod cast;
 mod codegen_i128;
index db24bf65eb5a2e015620822b67b81592feeff024..9afa999a87d8d20b3687bd29c2add1215b5e40d2 100644 (file)
@@ -1,20 +1,72 @@
 //! Writing of the rustc metadata for dylibs
 
-use rustc_middle::ty::TyCtxt;
+use object::write::{Object, StandardSegment, Symbol, SymbolSection};
+use object::{SectionKind, SymbolFlags, SymbolKind, SymbolScope};
 
-use crate::backend::WriteMetadata;
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::ty::TyCtxt;
 
 // Adapted from https://github.com/rust-lang/rust/blob/da573206f87b5510de4b0ee1a9c044127e409bd3/src/librustc_codegen_llvm/base.rs#L47-L112
-pub(crate) fn write_metadata<O: WriteMetadata>(tcx: TyCtxt<'_>, object: &mut O) {
+pub(crate) fn new_metadata_object(tcx: TyCtxt<'_>, cgu_name: &str, metadata: &EncodedMetadata) -> Vec<u8> {
     use snap::write::FrameEncoder;
     use std::io::Write;
 
-    let metadata = tcx.encode_metadata();
     let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
     FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
 
-    object.add_rustc_section(
-        rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx),
-        compressed,
-    );
+    let triple = crate::target_triple(tcx.sess);
+
+    let binary_format = match triple.binary_format {
+        target_lexicon::BinaryFormat::Elf => object::BinaryFormat::Elf,
+        target_lexicon::BinaryFormat::Coff => object::BinaryFormat::Coff,
+        target_lexicon::BinaryFormat::Macho => object::BinaryFormat::MachO,
+        binary_format => tcx.sess.fatal(&format!("binary format {} is unsupported", binary_format)),
+    };
+    let architecture = match triple.architecture {
+        target_lexicon::Architecture::Aarch64(_) => object::Architecture::Aarch64,
+        target_lexicon::Architecture::Arm(_) => object::Architecture::Arm,
+        target_lexicon::Architecture::Avr => object::Architecture::Avr,
+        target_lexicon::Architecture::Hexagon => object::Architecture::Hexagon,
+        target_lexicon::Architecture::Mips32(_) => object::Architecture::Mips,
+        target_lexicon::Architecture::Mips64(_) => object::Architecture::Mips64,
+        target_lexicon::Architecture::Msp430 => object::Architecture::Msp430,
+        target_lexicon::Architecture::Powerpc => object::Architecture::PowerPc,
+        target_lexicon::Architecture::Powerpc64 => object::Architecture::PowerPc64,
+        target_lexicon::Architecture::Powerpc64le => todo!(),
+        target_lexicon::Architecture::Riscv32(_) => object::Architecture::Riscv32,
+        target_lexicon::Architecture::Riscv64(_) => object::Architecture::Riscv64,
+        target_lexicon::Architecture::S390x => object::Architecture::S390x,
+        target_lexicon::Architecture::Sparc64 => object::Architecture::Sparc64,
+        target_lexicon::Architecture::Sparcv9 => object::Architecture::Sparc64,
+        target_lexicon::Architecture::X86_32(_) => object::Architecture::I386,
+        target_lexicon::Architecture::X86_64 => object::Architecture::X86_64,
+        architecture => {
+            tcx.sess.fatal(&format!("target architecture {:?} is unsupported", architecture,))
+        }
+    };
+    let endian = match triple.endianness().unwrap() {
+        target_lexicon::Endianness::Little => object::Endianness::Little,
+        target_lexicon::Endianness::Big => object::Endianness::Big,
+    };
+
+    let mut object = Object::new(binary_format, architecture, endian);
+    object.add_file_symbol(cgu_name.as_bytes().to_vec());
+
+    let segment = object.segment_name(StandardSegment::Data).to_vec();
+    let section_id = object.add_section(segment, b".rustc".to_vec(), SectionKind::Data);
+    let offset = object.append_section_data(section_id, &compressed, 1);
+    // For MachO and probably PE this is necessary to prevent the linker from throwing away the
+    // .rustc section. For ELF this isn't necessary, but it also doesn't harm.
+    object.add_symbol(Symbol {
+        name: rustc_middle::middle::exported_symbols::metadata_symbol_name(tcx).into_bytes(),
+        value: offset,
+        size: compressed.len() as u64,
+        kind: SymbolKind::Data,
+        scope: SymbolScope::Dynamic,
+        weak: false,
+        section: SymbolSection::Section(section_id),
+        flags: SymbolFlags::None,
+    });
+
+    object.write().unwrap()
 }
diff --git a/compiler/rustc_codegen_gcc/.github/workflows/main.yml b/compiler/rustc_codegen_gcc/.github/workflows/main.yml
new file mode 100644 (file)
index 0000000..98bed8e
--- /dev/null
@@ -0,0 +1,96 @@
+name: CI
+
+on:
+  - push
+  - pull_request
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+
+    strategy:
+      fail-fast: false
+
+    steps:
+    - uses: actions/checkout@v2
+
+    - name: Install packages
+      run: sudo apt-get install ninja-build ripgrep
+
+    - name: Download artifact
+      uses: dawidd6/action-download-artifact@v2
+      with:
+          workflow: main.yml
+          name: libgccjit.so
+          path: gcc-build
+          repo: antoyo/gcc
+
+    - name: Setup path to libgccjit
+      run: |
+          echo $(readlink -f gcc-build) > gcc_path
+          ln gcc-build/libgccjit.so gcc-build/libgccjit.so.0
+
+    - name: Set LIBRARY_PATH
+      run: |
+        echo "LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
+        echo "LD_LIBRARY_PATH=$(cat gcc_path)" >> $GITHUB_ENV
+
+    # https://github.com/actions/cache/issues/133
+    - name: Fixup owner of ~/.cargo/
+      # Don't remove the trailing /. It is necessary to follow the symlink.
+      run: sudo chown -R $(whoami):$(id -ng) ~/.cargo/
+
+    - name: Cache cargo installed crates
+      uses: actions/cache@v1.1.2
+      with:
+        path: ~/.cargo/bin
+        key: cargo-installed-crates2-ubuntu-latest
+
+    - name: Cache cargo registry
+      uses: actions/cache@v1
+      with:
+        path: ~/.cargo/registry
+        key: ${{ runner.os }}-cargo-registry2-${{ hashFiles('**/Cargo.lock') }}
+
+    - name: Cache cargo index
+      uses: actions/cache@v1
+      with:
+        path: ~/.cargo/git
+        key: ${{ runner.os }}-cargo-index-${{ hashFiles('**/Cargo.lock') }}
+
+    - name: Cache cargo target dir
+      uses: actions/cache@v1.1.2
+      with:
+        path: target
+        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain') }}
+
+    - name: Build
+      run: |
+        ./prepare_build.sh
+        ./build.sh
+        cargo test
+        ./clean_all.sh
+
+    - name: Prepare dependencies
+      run: |
+        git config --global user.email "user@example.com"
+        git config --global user.name "User"
+        ./prepare.sh
+
+    # Compile is a separate step, as the actions-rs/cargo action supports error annotations
+    - name: Compile
+      uses: actions-rs/cargo@v1.0.3
+      with:
+        command: build
+        args: --release
+
+    - name: Test
+      run: |
+        # Enable backtraces for easier debugging
+        export RUST_BACKTRACE=1
+
+        # Reduce amount of benchmark runs as they are slow
+        export COMPILE_RUNS=2
+        export RUN_RUNS=2
+
+        ./test.sh --release
diff --git a/compiler/rustc_codegen_gcc/.gitignore b/compiler/rustc_codegen_gcc/.gitignore
new file mode 100644 (file)
index 0000000..1e2f9e3
--- /dev/null
@@ -0,0 +1,20 @@
+target
+**/*.rs.bk
+*.rlib
+*.o
+perf.data
+perf.data.old
+*.events
+*.string*
+/build_sysroot/sysroot
+/build_sysroot/sysroot_src
+/build_sysroot/Cargo.lock
+/build_sysroot/test_target/Cargo.lock
+/rust
+/simple-raytracer
+/regex
+gimple*
+*asm
+res
+test-backend
+gcc_path
diff --git a/compiler/rustc_codegen_gcc/Cargo.lock b/compiler/rustc_codegen_gcc/Cargo.lock
new file mode 100644 (file)
index 0000000..60a2101
--- /dev/null
@@ -0,0 +1,373 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "ar"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "450575f58f7bee32816abbff470cbc47797397c2a81e0eaced4b98436daf52e1"
+
+[[package]]
+name = "autocfg"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "crc32fast"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "fm"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68fda3cff2cce84c19e5dfa5179a4b35d2c0f18b893f108002b8a6a54984acca"
+dependencies = [
+ "regex",
+]
+
+[[package]]
+name = "gccjit"
+version = "1.0.0"
+source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+dependencies = [
+ "gccjit_sys",
+]
+
+[[package]]
+name = "gccjit_sys"
+version = "0.0.1"
+source = "git+https://github.com/antoyo/gccjit.rs#2d4fea7319f80531b2e5d264fca9f1c498a3a62e"
+dependencies = [
+ "libc 0.1.12",
+]
+
+[[package]]
+name = "getopts"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
+dependencies = [
+ "unicode-width",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753"
+dependencies = [
+ "cfg-if",
+ "libc 0.2.102",
+ "wasi",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
+
+[[package]]
+name = "lang_tester"
+version = "0.3.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bd995a092cac79868250589869b5a5d656b02a02bd74c8ebdc566dc7203090"
+dependencies = [
+ "fm",
+ "getopts",
+ "libc 0.2.102",
+ "num_cpus",
+ "termcolor",
+ "threadpool",
+ "wait-timeout",
+ "walkdir",
+]
+
+[[package]]
+name = "libc"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e32a70cf75e5846d53a673923498228bbec6a8624708a9ea5645f075d6276122"
+
+[[package]]
+name = "libc"
+version = "0.2.102"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2a5ac8f984bfcf3a823267e5fde638acc3325f6496633a5da6bb6eb2171e103"
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "num_cpus"
+version = "1.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
+dependencies = [
+ "hermit-abi",
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "object"
+version = "0.25.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a38f2be3697a57b4060074ff41b44c16870d916ad7877c17696e063257482bc7"
+dependencies = [
+ "crc32fast",
+ "indexmap",
+ "memchr",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857"
+
+[[package]]
+name = "rand"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
+dependencies = [
+ "libc 0.2.102",
+ "rand_chacha",
+ "rand_core",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7"
+dependencies = [
+ "rand_core",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+
+[[package]]
+name = "remove_dir_all"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "rustc_codegen_gcc"
+version = "0.1.0"
+dependencies = [
+ "ar",
+ "gccjit",
+ "lang_tester",
+ "object",
+ "target-lexicon",
+ "tempfile",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "target-lexicon"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab0e7238dcc7b40a7be719a25365910f6807bd864f4cce6b2e6b873658e2b19d"
+
+[[package]]
+name = "tempfile"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
+dependencies = [
+ "cfg-if",
+ "libc 0.2.102",
+ "rand",
+ "redox_syscall",
+ "remove_dir_all",
+ "winapi",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "threadpool"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa"
+dependencies = [
+ "num_cpus",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+
+[[package]]
+name = "wait-timeout"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6"
+dependencies = [
+ "libc 0.2.102",
+]
+
+[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.10.2+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
diff --git a/compiler/rustc_codegen_gcc/Cargo.toml b/compiler/rustc_codegen_gcc/Cargo.toml
new file mode 100644 (file)
index 0000000..9e8c195
--- /dev/null
@@ -0,0 +1,51 @@
+[package]
+name = "rustc_codegen_gcc"
+version = "0.1.0"
+authors = ["Antoni Boucher <bouanto@zoho.com>"]
+edition = "2018"
+license = "MIT OR Apache-2.0"
+
+[lib]
+crate-type = ["dylib"]
+
+[[test]]
+name = "lang_tests"
+path = "tests/lib.rs"
+harness = false
+
+[dependencies]
+gccjit = { git = "https://github.com/antoyo/gccjit.rs" }
+
+# Local copy.
+#gccjit = { path = "../gccjit.rs" }
+
+target-lexicon = "0.10.0"
+
+ar = "0.8.0"
+
+[dependencies.object]
+version = "0.25.0"
+default-features = false
+features = ["read", "std", "write"] # We don't need WASM support.
+
+[dev-dependencies]
+lang_tester = "0.3.9"
+tempfile = "3.1.0"
+
+[profile.dev]
+# By compiling dependencies with optimizations, performing tests gets much faster.
+opt-level = 3
+
+[profile.dev.package.rustc_codegen_gcc]
+# Disabling optimizations for cg_gccjit itself makes compilation after a change faster.
+opt-level = 0
+
+# Disable optimizations and debuginfo of build scripts and some of the heavy build deps, as the
+# execution time of build scripts is so fast that optimizing them slows down the total build time.
+[profile.dev.build-override]
+opt-level = 0
+debug = false
+
+[profile.release.build-override]
+opt-level = 0
+debug = false
diff --git a/compiler/rustc_codegen_gcc/LICENSE-APACHE b/compiler/rustc_codegen_gcc/LICENSE-APACHE
new file mode 100644 (file)
index 0000000..1b5ec8b
--- /dev/null
@@ -0,0 +1,176 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
diff --git a/compiler/rustc_codegen_gcc/LICENSE-MIT b/compiler/rustc_codegen_gcc/LICENSE-MIT
new file mode 100644 (file)
index 0000000..31aa793
--- /dev/null
@@ -0,0 +1,23 @@
+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 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/compiler/rustc_codegen_gcc/Readme.md b/compiler/rustc_codegen_gcc/Readme.md
new file mode 100644 (file)
index 0000000..709d93c
--- /dev/null
@@ -0,0 +1,135 @@
+# WIP libgccjit codegen backend for rust
+
+This is a GCC codegen for rustc, which means it can be loaded by the existing rustc frontend, but benefits from GCC: more architectures are supported and GCC's optimizations are used.
+
+**Despite its name, libgccjit can be used for ahead-of-time compilation, as is used here.**
+
+## Motivation
+
+The primary goal of this project is to be able to compile Rust code on platforms unsupported by LLVM.
+A secondary goal is to check if using the gcc backend will provide any run-time speed improvement for the programs compiled using rustc.
+
+## Building
+
+**This requires a patched libgccjit in order to work.
+The patches in [this repostory](https://github.com/antoyo/libgccjit-patches) need to be applied.
+(Those patches should work when applied on master, but in case it doesn't work, they are known to work when applied on 079c23cfe079f203d5df83fea8e92a60c7d7e878.)
+You can also use my [fork of gcc](https://github.com/antoyo/gcc) which already includes these patches.**
+
+**Put the path to your custom build of libgccjit in the file `gcc_path`.**
+
+```bash
+$ git clone https://github.com/rust-lang/rustc_codegen_gcc.git
+$ cd rustc_codegen_gcc
+$ ./prepare_build.sh # download and patch sysroot src
+$ ./build.sh --release
+```
+
+To run the tests:
+
+```bash
+$ ./prepare.sh # download and patch sysroot src and install hyperfine for benchmarking
+$ ./test.sh --release
+```
+
+## Usage
+
+`$cg_gccjit_dir` is the directory you cloned this repo into in the following instructions.
+
+### Cargo
+
+```bash
+$ CHANNEL="release" $cg_gccjit_dir/cargo.sh run
+```
+
+If you compiled cg_gccjit in debug mode (aka you didn't pass `--release` to `./test.sh`) you should use `CHANNEL="debug"` instead or omit `CHANNEL="release"` completely.
+
+### Rustc
+
+> You should prefer using the Cargo method.
+
+```bash
+$ rustc +$(cat $cg_gccjit_dir/rust-toolchain) -Cpanic=abort -Zcodegen-backend=$cg_gccjit_dir/target/release/librustc_codegen_gcc.so --sysroot $cg_gccjit_dir/build_sysroot/sysroot my_crate.rs
+```
+
+## Env vars
+
+<dl>
+    <dt>CG_GCCJIT_INCR_CACHE_DISABLED</dt>
+    <dd>Don't cache object files in the incremental cache. Useful during development of cg_gccjit
+    to make it possible to use incremental mode for all analyses performed by rustc without caching
+    object files when their content should have been changed by a change to cg_gccjit.</dd>
+    <dt>CG_GCCJIT_DISPLAY_CG_TIME</dt>
+    <dd>Display the time it took to perform codegen for a crate</dd>
+</dl>
+
+## Debugging
+
+Sometimes, libgccjit will crash and output an error like this:
+
+```
+during RTL pass: expand
+libgccjit.so: error: in expmed_mode_index, at expmed.h:249
+0x7f0da2e61a35 expmed_mode_index
+       ../../../gcc/gcc/expmed.h:249
+0x7f0da2e61aa4 expmed_op_cost_ptr
+       ../../../gcc/gcc/expmed.h:271
+0x7f0da2e620dc sdiv_cost_ptr
+       ../../../gcc/gcc/expmed.h:540
+0x7f0da2e62129 sdiv_cost
+       ../../../gcc/gcc/expmed.h:558
+0x7f0da2e73c12 expand_divmod(int, tree_code, machine_mode, rtx_def*, rtx_def*, rtx_def*, int)
+       ../../../gcc/gcc/expmed.c:4335
+0x7f0da2ea1423 expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier)
+       ../../../gcc/gcc/expr.c:9240
+0x7f0da2cd1a1e expand_gimple_stmt_1
+       ../../../gcc/gcc/cfgexpand.c:3796
+0x7f0da2cd1c30 expand_gimple_stmt
+       ../../../gcc/gcc/cfgexpand.c:3857
+0x7f0da2cd90a9 expand_gimple_basic_block
+       ../../../gcc/gcc/cfgexpand.c:5898
+0x7f0da2cdade8 execute
+       ../../../gcc/gcc/cfgexpand.c:6582
+```
+
+To see the code which causes this error, call the following function:
+
+```c
+gcc_jit_context_dump_to_file(ctxt, "/tmp/output.c", 1 /* update_locations */)
+```
+
+This will create a C-like file and add the locations into the IR pointing to this C file.
+Then, rerun the program and it will output the location in the second line:
+
+```
+libgccjit.so: /tmp/something.c:61322:0: error: in expmed_mode_index, at expmed.h:249
+```
+
+Or add a breakpoint to `add_error` in gdb and print the line number using:
+
+```
+p loc->m_line
+```
+
+### How to use a custom-build rustc
+
+ * Build the stage2 compiler (`rustup toolchain link debug-current build/x86_64-unknown-linux-gnu/stage2`).
+ * Clean and rebuild the codegen with `debug-current` in the file `rust-toolchain`.
+
+### How to build a cross-compiling libgccjit
+
+#### Building libgccjit
+
+ * Follow these instructions: https://preshing.com/20141119/how-to-build-a-gcc-cross-compiler/ with the following changes:
+ * Configure gcc with `../gcc/configure --enable-host-shared --disable-multilib --enable-languages=c,jit,c++ --disable-bootstrap --enable-checking=release --prefix=/opt/m68k-gcc/ --target=m68k-linux --without-headers`.
+ * Some shells, like fish, don't define the environment variable `$MACHTYPE`.
+ * Add `CFLAGS="-Wno-error=attributes -g -O2"` at the end of the configure command for building glibc (`CFLAGS="-Wno-error=attributes -Wno-error=array-parameter -Wno-error=stringop-overflow -Wno-error=array-bounds -g -O2"` for glibc 2.31, which is useful for Debian).
+
+#### Configuring rustc_codegen_gcc
+
+ * Set `TARGET_TRIPLE="m68k-unknown-linux-gnu"` in config.sh.
+ * Since rustc doesn't support this architecture yet, set it back to `TARGET_TRIPLE="mips-unknown-linux-gnu"` (or another target having the same attributes). Alternatively, create a [target specification file](https://book.avr-rust.com/005.1-the-target-specification-json-file.html) (note that the `arch` specified in this file must be supported by the rust compiler).
+ * Set `linker='-Clinker=m68k-linux-gcc'`.
+ * Set the path to the cross-compiling libgccjit in `gcc_path`.
+ * Disable the 128-bit integer types if the target doesn't support them by using `let i128_type = context.new_type::<i64>();` in `context.rs` (same for u128_type).
+ * (might not be necessary) Disable the compilation of libstd.so (and possibly libcore.so?).
diff --git a/compiler/rustc_codegen_gcc/build.sh b/compiler/rustc_codegen_gcc/build.sh
new file mode 100755 (executable)
index 0000000..17a0d2a
--- /dev/null
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+#set -x
+set -e
+
+if [ -f ./gcc_path ]; then 
+    export GCC_PATH=$(cat gcc_path)
+else
+    echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
+    exit 1
+fi
+
+export LD_LIBRARY_PATH="$GCC_PATH"
+export LIBRARY_PATH="$GCC_PATH"
+
+if [[ "$1" == "--release" ]]; then
+    export CHANNEL='release'
+    CARGO_INCREMENTAL=1 cargo rustc --release
+else
+    echo $LD_LIBRARY_PATH
+    export CHANNEL='debug'
+    cargo rustc
+fi
+
+source config.sh
+
+rm -r target/out || true
+mkdir -p target/out/gccjit
+
+echo "[BUILD] sysroot"
+time ./build_sysroot/build_sysroot.sh $CHANNEL
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml b/compiler/rustc_codegen_gcc/build_sysroot/Cargo.toml
new file mode 100644 (file)
index 0000000..cfadf47
--- /dev/null
@@ -0,0 +1,19 @@
+[package]
+authors = ["bjorn3 <bjorn3@users.noreply.github.com>"]
+name = "sysroot"
+version = "0.0.0"
+
+[dependencies]
+core = { path = "./sysroot_src/library/core" }
+compiler_builtins = "0.1"
+alloc = { path = "./sysroot_src/library/alloc" }
+std = { path = "./sysroot_src/library/std", features = ["panic_unwind", "backtrace"] }
+test = { path = "./sysroot_src/library/test" }
+
+[patch.crates-io]
+rustc-std-workspace-core = { path = "./sysroot_src/library/rustc-std-workspace-core" }
+rustc-std-workspace-alloc = { path = "./sysroot_src/library/rustc-std-workspace-alloc" }
+rustc-std-workspace-std = { path = "./sysroot_src/library/rustc-std-workspace-std" }
+
+[profile.release]
+debug = true
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh b/compiler/rustc_codegen_gcc/build_sysroot/build_sysroot.sh
new file mode 100755 (executable)
index 0000000..d1dcf49
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash
+
+# Requires the CHANNEL env var to be set to `debug` or `release.`
+
+set -e
+cd $(dirname "$0")
+
+pushd ../ >/dev/null
+source ./config.sh
+popd >/dev/null
+
+# Cleanup for previous run
+#     v Clean target dir except for build scripts and incremental cache
+rm -r target/*/{debug,release}/{build,deps,examples,libsysroot*,native} 2>/dev/null || true
+rm Cargo.lock test_target/Cargo.lock 2>/dev/null || true
+rm -r sysroot/ 2>/dev/null || true
+
+# Build libs
+export RUSTFLAGS="$RUSTFLAGS -Z force-unstable-if-unmarked -Cpanic=abort"
+if [[ "$1" == "--release" ]]; then
+    sysroot_channel='release'
+    RUSTFLAGS="$RUSTFLAGS -Zmir-opt-level=3" cargo build --target $TARGET_TRIPLE --release
+else
+    sysroot_channel='debug'
+    cargo build --target $TARGET_TRIPLE
+fi
+
+# Copy files to sysroot
+mkdir -p sysroot/lib/rustlib/$TARGET_TRIPLE/lib/
+cp -r target/$TARGET_TRIPLE/$sysroot_channel/deps/* sysroot/lib/rustlib/$TARGET_TRIPLE/lib/
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_gcc/build_sysroot/prepare_sysroot_src.sh
new file mode 100755 (executable)
index 0000000..071e7ed
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/bash
+set -e
+cd $(dirname "$0")
+
+SRC_DIR=$(dirname $(rustup which rustc))"/../lib/rustlib/src/rust/"
+DST_DIR="sysroot_src"
+
+if [ ! -e $SRC_DIR ]; then
+    echo "Please install rust-src component"
+    exit 1
+fi
+
+rm -rf $DST_DIR
+mkdir -p $DST_DIR/library
+cp -r $SRC_DIR/library $DST_DIR/
+
+pushd $DST_DIR
+echo "[GIT] init"
+git init
+echo "[GIT] add"
+git add .
+echo "[GIT] commit"
+
+# This is needed on systems where nothing is configured.
+# git really needs something here, or it will fail.
+# Even using --author is not enough.
+git config user.email || git config user.email "none@example.com"
+git config user.name || git config user.name "None"
+
+git commit -m "Initial commit" -q
+for file in $(ls ../../patches/ | grep -v patcha); do
+echo "[GIT] apply" $file
+git apply ../../patches/$file
+git add -A
+git commit --no-gpg-sign -m "Patch $file"
+done
+popd
+
+echo "Successfully prepared libcore for building"
diff --git a/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs b/compiler/rustc_codegen_gcc/build_sysroot/src/lib.rs
new file mode 100644 (file)
index 0000000..0c9ac1a
--- /dev/null
@@ -0,0 +1 @@
+#![no_std]
diff --git a/compiler/rustc_codegen_gcc/cargo.sh b/compiler/rustc_codegen_gcc/cargo.sh
new file mode 100755 (executable)
index 0000000..1001c52
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/bash
+
+if [ -z $CHANNEL ]; then
+export CHANNEL='debug'
+fi
+
+pushd $(dirname "$0") >/dev/null
+source config.sh
+
+# read nightly compiler from rust-toolchain file
+TOOLCHAIN=$(cat rust-toolchain)
+
+popd >/dev/null
+
+if [[ $(rustc -V) != $(rustc +${TOOLCHAIN} -V) ]]; then
+    echo "rustc_codegen_gcc is build for $(rustc +${TOOLCHAIN} -V) but the default rustc version is $(rustc -V)."
+    echo "Using $(rustc +${TOOLCHAIN} -V)."
+fi
+
+cmd=$1
+shift
+
+RUSTDOCFLAGS="$RUSTFLAGS" cargo +${TOOLCHAIN} $cmd --target $TARGET_TRIPLE $@
diff --git a/compiler/rustc_codegen_gcc/clean_all.sh b/compiler/rustc_codegen_gcc/clean_all.sh
new file mode 100755 (executable)
index 0000000..a77d148
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash --verbose
+set -e
+
+rm -rf target/ build_sysroot/{sysroot/,sysroot_src/,target/,Cargo.lock} perf.data{,.old}
+rm -rf regex/ simple-raytracer/
diff --git a/compiler/rustc_codegen_gcc/config.sh b/compiler/rustc_codegen_gcc/config.sh
new file mode 100644 (file)
index 0000000..87df2f2
--- /dev/null
@@ -0,0 +1,52 @@
+set -e
+
+export CARGO_INCREMENTAL=0
+
+if [ -f ./gcc_path ]; then 
+    export GCC_PATH=$(cat gcc_path)
+else
+    echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
+    exit 1
+fi
+
+unamestr=`uname`
+if [[ "$unamestr" == 'Linux' ]]; then
+   dylib_ext='so'
+elif [[ "$unamestr" == 'Darwin' ]]; then
+   dylib_ext='dylib'
+else
+   echo "Unsupported os"
+   exit 1
+fi
+
+HOST_TRIPLE=$(rustc -vV | grep host | cut -d: -f2 | tr -d " ")
+TARGET_TRIPLE=$HOST_TRIPLE
+#TARGET_TRIPLE="m68k-unknown-linux-gnu"
+
+linker=''
+RUN_WRAPPER=''
+if [[ "$HOST_TRIPLE" != "$TARGET_TRIPLE" ]]; then
+   if [[ "$TARGET_TRIPLE" == "m68k-unknown-linux-gnu" ]]; then
+       TARGET_TRIPLE="mips-unknown-linux-gnu"
+       linker='-Clinker=m68k-linux-gcc'
+   elif [[ "$TARGET_TRIPLE" == "aarch64-unknown-linux-gnu" ]]; then
+      # We are cross-compiling for aarch64. Use the correct linker and run tests in qemu.
+      linker='-Clinker=aarch64-linux-gnu-gcc'
+      RUN_WRAPPER='qemu-aarch64 -L /usr/aarch64-linux-gnu'
+   else
+      echo "Unknown non-native platform"
+   fi
+fi
+
+export RUSTFLAGS="$linker -Cpanic=abort -Zsymbol-mangling-version=v0 -Cdebuginfo=2 -Clto=off -Zpanic-abort-tests -Zcodegen-backend=$(pwd)/target/${CHANNEL:-debug}/librustc_codegen_gcc.$dylib_ext --sysroot $(pwd)/build_sysroot/sysroot"
+
+# FIXME(antoyo): remove once the atomic shim is gone
+if [[ `uname` == 'Darwin' ]]; then
+   export RUSTFLAGS="$RUSTFLAGS -Clink-arg=-undefined -Clink-arg=dynamic_lookup"
+fi
+
+RUSTC="rustc $RUSTFLAGS -L crate=target/out --out-dir target/out"
+export RUSTC_LOG=warn # display metadata load errors
+
+export LD_LIBRARY_PATH="$(pwd)/target/out:$(pwd)/build_sysroot/sysroot/lib/rustlib/$TARGET_TRIPLE/lib:$GCC_PATH"
+export DYLD_LIBRARY_PATH=$LD_LIBRARY_PATH
diff --git a/compiler/rustc_codegen_gcc/example/alloc_example.rs b/compiler/rustc_codegen_gcc/example/alloc_example.rs
new file mode 100644 (file)
index 0000000..bc6dd00
--- /dev/null
@@ -0,0 +1,41 @@
+#![feature(start, box_syntax, core_intrinsics, alloc_prelude, alloc_error_handler)]
+#![no_std]
+
+extern crate alloc;
+extern crate alloc_system;
+
+use alloc::prelude::v1::*;
+
+use alloc_system::System;
+
+#[global_allocator]
+static ALLOC: System = System;
+
+#[link(name = "c")]
+extern "C" {
+    fn puts(s: *const u8) -> i32;
+}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        core::intrinsics::abort();
+    }
+}
+
+#[alloc_error_handler]
+fn alloc_error_handler(_: alloc::alloc::Layout) -> ! {
+    unsafe {
+        core::intrinsics::abort();
+    }
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    let world: Box<&str> = box "Hello World!\0";
+    unsafe {
+        puts(*world as *const str as *const u8);
+    }
+
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/example/alloc_system.rs b/compiler/rustc_codegen_gcc/example/alloc_system.rs
new file mode 100644 (file)
index 0000000..5f66ca6
--- /dev/null
@@ -0,0 +1,212 @@
+// 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+#![no_std]
+#![feature(allocator_api, rustc_private)]
+#![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
+
+// The minimum alignment guaranteed by the architecture. This value is used to
+// add fast paths for low alignment values.
+#[cfg(all(any(target_arch = "x86",
+              target_arch = "arm",
+              target_arch = "mips",
+              target_arch = "powerpc",
+              target_arch = "powerpc64")))]
+const MIN_ALIGN: usize = 8;
+#[cfg(all(any(target_arch = "x86_64",
+              target_arch = "aarch64",
+              target_arch = "mips64",
+              target_arch = "s390x",
+              target_arch = "sparc64")))]
+const MIN_ALIGN: usize = 16;
+
+pub struct System;
+#[cfg(any(windows, unix, target_os = "redox"))]
+mod realloc_fallback {
+    use core::alloc::{GlobalAlloc, Layout};
+    use core::cmp;
+    use core::ptr;
+    impl super::System {
+        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, new_ptr, size);
+                GlobalAlloc::dealloc(self, ptr, old_layout);
+            }
+            new_ptr
+        }
+    }
+}
+#[cfg(any(unix, target_os = "redox"))]
+mod platform {
+    extern crate libc;
+    use core::ptr;
+    use MIN_ALIGN;
+    use System;
+    use core::alloc::{GlobalAlloc, Layout};
+    unsafe impl GlobalAlloc for System {
+        #[inline]
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+                libc::malloc(layout.size()) as *mut u8
+            } else {
+                #[cfg(target_os = "macos")]
+                {
+                    if layout.align() > (1 << 31) {
+                        return ptr::null_mut()
+                    }
+                }
+                aligned_malloc(&layout)
+            }
+        }
+        #[inline]
+        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 u8
+            } else {
+                let ptr = self.alloc(layout.clone());
+                if !ptr.is_null() {
+                    ptr::write_bytes(ptr, 0, layout.size());
+                }
+                ptr
+            }
+        }
+        #[inline]
+        unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+            libc::free(ptr as *mut libc::c_void)
+        }
+        #[inline]
+        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 u8
+            } else {
+                self.realloc_fallback(ptr, layout, new_size)
+            }
+        }
+    }
+    #[cfg(any(target_os = "android",
+              target_os = "hermit",
+              target_os = "redox",
+              target_os = "solaris"))]
+    #[inline]
+    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
+        // where the memory returned cannot be deallocated by `free`!
+        //
+        // Upon closer inspection, however, this appears to work just fine with
+        // Android, so for this platform we should be fine to call `memalign`
+        // (which is present in API level 9). Some helpful references could
+        // possibly be chromium using memalign [1], attempts at documenting that
+        // memalign + free is ok [2] [3], or the current source of chromium
+        // which still uses memalign on android [4].
+        //
+        // [1]: https://codereview.chromium.org/10796020/
+        // [2]: https://code.google.com/p/android/issues/detail?id=35391
+        // [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 u8
+    }
+    #[cfg(not(any(target_os = "android",
+                  target_os = "hermit",
+                  target_os = "redox",
+                  target_os = "solaris")))]
+    #[inline]
+    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 {
+            ptr::null_mut()
+        } else {
+            out as *mut u8
+        }
+    }
+}
+#[cfg(windows)]
+#[allow(nonstandard_style)]
+mod platform {
+    use MIN_ALIGN;
+    use System;
+    use core::alloc::{GlobalAlloc, Layout};
+    type LPVOID = *mut u8;
+    type HANDLE = LPVOID;
+    type SIZE_T = usize;
+    type DWORD = u32;
+    type BOOL = i32;
+    extern "system" {
+        fn GetProcessHeap() -> HANDLE;
+        fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID;
+        fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID;
+        fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL;
+        fn GetLastError() -> DWORD;
+    }
+    #[repr(C)]
+    struct Header(*mut u8);
+    const HEAP_ZERO_MEMORY: DWORD = 0x00000008;
+    unsafe fn get_header<'a>(ptr: *mut u8) -> &'a mut Header {
+        &mut *(ptr as *mut Header).offset(-1)
+    }
+    unsafe fn align_ptr(ptr: *mut u8, align: usize) -> *mut u8 {
+        let aligned = ptr.add(align - (ptr as usize & (align - 1)));
+        *get_header(aligned) = Header(ptr);
+        aligned
+    }
+    #[inline]
+    unsafe fn allocate_with_flags(layout: Layout, flags: DWORD) -> *mut u8 {
+        let ptr = if layout.align() <= MIN_ALIGN {
+            HeapAlloc(GetProcessHeap(), flags, layout.size())
+        } else {
+            let size = layout.size() + layout.align();
+            let ptr = HeapAlloc(GetProcessHeap(), flags, size);
+            if ptr.is_null() {
+                ptr
+            } else {
+                align_ptr(ptr, layout.align())
+            }
+        };
+        ptr as *mut u8
+    }
+    unsafe impl GlobalAlloc for System {
+        #[inline]
+        unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+            allocate_with_flags(layout, 0)
+        }
+        #[inline]
+        unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+            allocate_with_flags(layout, HEAP_ZERO_MEMORY)
+        }
+        #[inline]
+        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);
+                let err = HeapFree(GetProcessHeap(), 0, header.0 as LPVOID);
+                debug_assert!(err != 0, "Failed to free heap memory: {}",
+                              GetLastError());
+            }
+        }
+        #[inline]
+        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 u8
+            } else {
+                self.realloc_fallback(ptr, layout, new_size)
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_gcc/example/arbitrary_self_types_pointers_and_wrappers.rs
new file mode 100644 (file)
index 0000000..ddeb752
--- /dev/null
@@ -0,0 +1,69 @@
+// Adapted from rustc run-pass test suite
+
+#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
+#![feature(rustc_attrs)]
+
+use std::{
+    ops::{Deref, CoerceUnsized, DispatchFromDyn},
+    marker::Unsize,
+};
+
+struct Ptr<T: ?Sized>(Box<T>);
+
+impl<T: ?Sized> Deref for Ptr<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &*self.0
+    }
+}
+
+impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {}
+impl<T: Unsize<U> + ?Sized, U: ?Sized> DispatchFromDyn<Ptr<U>> for Ptr<T> {}
+
+struct Wrapper<T: ?Sized>(T);
+
+impl<T: ?Sized> Deref for Wrapper<T> {
+    type Target = T;
+
+    fn deref(&self) -> &T {
+        &self.0
+    }
+}
+
+impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
+impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
+
+
+trait Trait {
+    // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
+    // without unsized_locals), but wrappers arond `Self` currently are not.
+    // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented
+    // fn wrapper(self: Wrapper<Self>) -> i32;
+    fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32;
+    fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32;
+    fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32;
+}
+
+impl Trait for i32 {
+    fn ptr_wrapper(self: Ptr<Wrapper<Self>>) -> i32 {
+        **self
+    }
+    fn wrapper_ptr(self: Wrapper<Ptr<Self>>) -> i32 {
+        **self
+    }
+    fn wrapper_ptr_wrapper(self: Wrapper<Ptr<Wrapper<Self>>>) -> i32 {
+        ***self
+    }
+}
+
+fn main() {
+    let pw = Ptr(Box::new(Wrapper(5))) as Ptr<Wrapper<dyn Trait>>;
+    assert_eq!(pw.ptr_wrapper(), 5);
+
+    let wp = Wrapper(Ptr(Box::new(6))) as Wrapper<Ptr<dyn Trait>>;
+    assert_eq!(wp.wrapper_ptr(), 6);
+
+    let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper<Ptr<Wrapper<dyn Trait>>>;
+    assert_eq!(wpw.wrapper_ptr_wrapper(), 7);
+}
diff --git a/compiler/rustc_codegen_gcc/example/dst-field-align.rs b/compiler/rustc_codegen_gcc/example/dst-field-align.rs
new file mode 100644 (file)
index 0000000..6c338e9
--- /dev/null
@@ -0,0 +1,67 @@
+// run-pass
+#![allow(dead_code)]
+struct Foo<T: ?Sized> {
+    a: u16,
+    b: T
+}
+
+trait Bar {
+    fn get(&self) -> usize;
+}
+
+impl Bar for usize {
+    fn get(&self) -> usize { *self }
+}
+
+struct Baz<T: ?Sized> {
+    a: T
+}
+
+struct HasDrop<T: ?Sized> {
+    ptr: Box<usize>,
+    data: T
+}
+
+fn main() {
+    // Test that zero-offset works properly
+    let b : Baz<usize> = Baz { a: 7 };
+    assert_eq!(b.a.get(), 7);
+    let b : &Baz<dyn Bar> = &b;
+    assert_eq!(b.a.get(), 7);
+
+    // Test that the field is aligned properly
+    let f : Foo<usize> = Foo { a: 0, b: 11 };
+    assert_eq!(f.b.get(), 11);
+    let ptr1 : *const u8 = &f.b as *const _ as *const u8;
+
+    let f : &Foo<dyn Bar> = &f;
+    let ptr2 : *const u8 = &f.b as *const _ as *const u8;
+    assert_eq!(f.b.get(), 11);
+
+    // The pointers should be the same
+    assert_eq!(ptr1, ptr2);
+
+    // Test that nested DSTs work properly
+    let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
+    assert_eq!(f.b.b.get(), 17);
+    let f : &Foo<Foo<dyn Bar>> = &f;
+    assert_eq!(f.b.b.get(), 17);
+
+    // Test that get the pointer via destructuring works
+
+    let f : Foo<usize> = Foo { a: 0, b: 11 };
+    let f : &Foo<dyn Bar> = &f;
+    let &Foo { a: _, b: ref bar } = f;
+    assert_eq!(bar.get(), 11);
+
+    // Make sure that drop flags don't screw things up
+
+    let d : HasDrop<Baz<[i32; 4]>> = HasDrop {
+        ptr: Box::new(0),
+        data: Baz { a: [1,2,3,4] }
+    };
+    assert_eq!([1,2,3,4], d.data.a);
+
+    let d : &HasDrop<Baz<[i32]>> = &d;
+    assert_eq!(&[1,2,3,4], &d.data.a);
+}
diff --git a/compiler/rustc_codegen_gcc/example/example.rs b/compiler/rustc_codegen_gcc/example/example.rs
new file mode 100644 (file)
index 0000000..5878e85
--- /dev/null
@@ -0,0 +1,208 @@
+#![feature(no_core, unboxed_closures)]
+#![no_core]
+#![allow(dead_code)]
+
+extern crate mini_core;
+
+use mini_core::*;
+
+fn abc(a: u8) -> u8 {
+    a * 2
+}
+
+fn bcd(b: bool, a: u8) -> u8 {
+    if b {
+        a * 2
+    } else {
+        a * 3
+    }
+}
+
+fn call() {
+    abc(42);
+}
+
+fn indirect_call() {
+    let f: fn() = call;
+    f();
+}
+
+enum BoolOption {
+    Some(bool),
+    None,
+}
+
+fn option_unwrap_or(o: BoolOption, d: bool) -> bool {
+    match o {
+        BoolOption::Some(b) => b,
+        BoolOption::None => d,
+    }
+}
+
+fn ret_42() -> u8 {
+    42
+}
+
+fn return_str() -> &'static str {
+    "hello world"
+}
+
+fn promoted_val() -> &'static u8 {
+    &(1 * 2)
+}
+
+fn cast_ref_to_raw_ptr(abc: &u8) -> *const u8 {
+    abc as *const u8
+}
+
+fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool {
+    a == b
+}
+
+fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
+    (
+        a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8,
+        b as u32,
+    )
+}
+
+fn char_cast(c: char) -> u8 {
+    c as u8
+}
+
+pub struct DebugTuple(());
+
+fn debug_tuple() -> DebugTuple {
+    DebugTuple(())
+}
+
+fn size_of<T>() -> usize {
+    intrinsics::size_of::<T>()
+}
+
+fn use_size_of() -> usize {
+    size_of::<u64>()
+}
+
+unsafe fn use_copy_intrinsic(src: *const u8, dst: *mut u8) {
+    intrinsics::copy::<u8>(src, dst, 1);
+}
+
+unsafe fn use_copy_intrinsic_ref(src: *const u8, dst: *mut u8) {
+    let copy2 = &intrinsics::copy::<u8>;
+    copy2(src, dst, 1);
+}
+
+const ABC: u8 = 6 * 7;
+
+fn use_const() -> u8 {
+    ABC
+}
+
+pub fn call_closure_3arg() {
+    (|_, _, _| {})(0u8, 42u16, 0u8)
+}
+
+pub fn call_closure_2arg() {
+    (|_, _| {})(0u8, 42u16)
+}
+
+struct IsNotEmpty;
+
+impl<'a, 'b> FnOnce<(&'a &'b [u16],)> for IsNotEmpty {
+    type Output = (u8, u8);
+
+    #[inline]
+    extern "rust-call" fn call_once(mut self, arg: (&'a &'b [u16],)) -> (u8, u8) {
+        self.call_mut(arg)
+    }
+}
+
+impl<'a, 'b> FnMut<(&'a &'b [u16],)> for IsNotEmpty {
+    #[inline]
+    extern "rust-call" fn call_mut(&mut self, _arg: (&'a &'b [u16],)) -> (u8, u8) {
+        (0, 42)
+    }
+}
+
+pub fn call_is_not_empty() {
+    IsNotEmpty.call_once((&(&[0u16] as &[_]),));
+}
+
+fn eq_char(a: char, b: char) -> bool {
+    a == b
+}
+
+unsafe fn transmute(c: char) -> u32 {
+    intrinsics::transmute(c)
+}
+
+unsafe fn deref_str_ptr(s: *const str) -> &'static str {
+    &*s
+}
+
+fn use_array(arr: [u8; 3]) -> u8 {
+    arr[1]
+}
+
+fn repeat_array() -> [u8; 3] {
+    [0; 3]
+}
+
+fn array_as_slice(arr: &[u8; 3]) -> &[u8] {
+    arr
+}
+
+unsafe fn use_ctlz_nonzero(a: u16) -> u16 {
+    intrinsics::ctlz_nonzero(a)
+}
+
+fn ptr_as_usize(ptr: *const u8) -> usize {
+    ptr as usize
+}
+
+fn float_cast(a: f32, b: f64) -> (f64, f32) {
+    (a as f64, b as f32)
+}
+
+fn int_to_float(a: u8, b: i32) -> (f64, f32) {
+    (a as f64, b as f32)
+}
+
+fn make_array() -> [u8; 3] {
+    [42, 0, 5]
+}
+
+fn some_promoted_tuple() -> &'static (&'static str, &'static str) {
+    &("abc", "some")
+}
+
+fn index_slice(s: &[u8]) -> u8 {
+    s[2]
+}
+
+pub struct StrWrapper {
+    s: str,
+}
+
+fn str_wrapper_get(w: &StrWrapper) -> &str {
+    &w.s
+}
+
+fn i16_as_i8(a: i16) -> i8 {
+    a as i8
+}
+
+struct Unsized(u8, str);
+
+fn get_sized_field_ref_from_unsized_type(u: &Unsized) -> &u8 {
+    &u.0
+}
+
+fn get_unsized_field_ref_from_unsized_type(u: &Unsized) -> &str {
+    &u.1
+}
+
+pub fn reuse_byref_argument_storage(a: (u8, u16, u32)) -> u8 {
+    a.0
+}
diff --git a/compiler/rustc_codegen_gcc/example/mini_core.rs b/compiler/rustc_codegen_gcc/example/mini_core.rs
new file mode 100644 (file)
index 0000000..1067cee
--- /dev/null
@@ -0,0 +1,585 @@
+#![feature(
+    no_core, lang_items, intrinsics, unboxed_closures, type_ascription, extern_types,
+    untagged_unions, decl_macro, rustc_attrs, transparent_unions, auto_traits,
+    thread_local
+)]
+#![no_core]
+#![allow(dead_code)]
+
+#[no_mangle]
+unsafe extern "C" fn _Unwind_Resume() {
+    intrinsics::unreachable();
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "dispatch_from_dyn"]
+pub trait DispatchFromDyn<T> {}
+
+// &T -> &U
+impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+// &mut T -> &mut U
+impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+// *const T -> *const U
+impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+// *mut T -> *mut U
+impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
+
+#[lang = "receiver"]
+pub trait Receiver {}
+
+impl<T: ?Sized> Receiver for &T {}
+impl<T: ?Sized> Receiver for &mut T {}
+impl<T: ?Sized> Receiver for Box<T> {}
+
+#[lang = "copy"]
+pub unsafe trait Copy {}
+
+unsafe impl Copy for bool {}
+unsafe impl Copy for u8 {}
+unsafe impl Copy for u16 {}
+unsafe impl Copy for u32 {}
+unsafe impl Copy for u64 {}
+unsafe impl Copy for usize {}
+unsafe impl Copy for i8 {}
+unsafe impl Copy for i16 {}
+unsafe impl Copy for i32 {}
+unsafe impl Copy for isize {}
+unsafe impl Copy for f32 {}
+unsafe impl Copy for char {}
+unsafe impl<'a, T: ?Sized> Copy for &'a T {}
+unsafe impl<T: ?Sized> Copy for *const T {}
+unsafe impl<T: ?Sized> Copy for *mut T {}
+
+#[lang = "sync"]
+pub unsafe trait Sync {}
+
+unsafe impl Sync for bool {}
+unsafe impl Sync for u8 {}
+unsafe impl Sync for u16 {}
+unsafe impl Sync for u32 {}
+unsafe impl Sync for u64 {}
+unsafe impl Sync for usize {}
+unsafe impl Sync for i8 {}
+unsafe impl Sync for i16 {}
+unsafe impl Sync for i32 {}
+unsafe impl Sync for isize {}
+unsafe impl Sync for char {}
+unsafe impl<'a, T: ?Sized> Sync for &'a T {}
+unsafe impl Sync for [u8; 16] {}
+
+#[lang = "freeze"]
+unsafe auto trait Freeze {}
+
+unsafe impl<T: ?Sized> Freeze for PhantomData<T> {}
+unsafe impl<T: ?Sized> Freeze for *const T {}
+unsafe impl<T: ?Sized> Freeze for *mut T {}
+unsafe impl<T: ?Sized> Freeze for &T {}
+unsafe impl<T: ?Sized> Freeze for &mut T {}
+
+#[lang = "structural_peq"]
+pub trait StructuralPartialEq {}
+
+#[lang = "structural_teq"]
+pub trait StructuralEq {}
+
+#[lang = "not"]
+pub trait Not {
+    type Output;
+
+    fn not(self) -> Self::Output;
+}
+
+impl Not for bool {
+    type Output = bool;
+
+    fn not(self) -> bool {
+        !self
+    }
+}
+
+#[lang = "mul"]
+pub trait Mul<RHS = Self> {
+    type Output;
+
+    #[must_use]
+    fn mul(self, rhs: RHS) -> Self::Output;
+}
+
+impl Mul for u8 {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+impl Mul for usize {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+#[lang = "add"]
+pub trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+#[lang = "rem"]
+pub trait Rem<RHS = Self> {
+    type Output;
+
+    fn rem(self, rhs: RHS) -> Self::Output;
+}
+
+impl Rem for usize {
+    type Output = Self;
+
+    fn rem(self, rhs: Self) -> Self {
+        self % rhs
+    }
+}
+
+#[lang = "bitor"]
+pub trait BitOr<RHS = Self> {
+    type Output;
+
+    #[must_use]
+    fn bitor(self, rhs: RHS) -> Self::Output;
+}
+
+impl BitOr for bool {
+    type Output = bool;
+
+    fn bitor(self, rhs: bool) -> bool {
+        self | rhs
+    }
+}
+
+impl<'a> BitOr<bool> for &'a bool {
+    type Output = bool;
+
+    fn bitor(self, rhs: bool) -> bool {
+        *self | rhs
+    }
+}
+
+#[lang = "eq"]
+pub trait PartialEq<Rhs: ?Sized = Self> {
+    fn eq(&self, other: &Rhs) -> bool;
+    fn ne(&self, other: &Rhs) -> bool;
+}
+
+impl PartialEq for u8 {
+    fn eq(&self, other: &u8) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u8) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for u16 {
+    fn eq(&self, other: &u16) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u16) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for u32 {
+    fn eq(&self, other: &u32) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u32) -> bool {
+        (*self) != (*other)
+    }
+}
+
+
+impl PartialEq for u64 {
+    fn eq(&self, other: &u64) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u64) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for usize {
+    fn eq(&self, other: &usize) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &usize) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for i8 {
+    fn eq(&self, other: &i8) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &i8) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for i32 {
+    fn eq(&self, other: &i32) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &i32) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for isize {
+    fn eq(&self, other: &isize) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &isize) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for char {
+    fn eq(&self, other: &char) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &char) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl<T: ?Sized> PartialEq for *const T {
+    fn eq(&self, other: &*const T) -> bool {
+        *self == *other
+    }
+    fn ne(&self, other: &*const T) -> bool {
+        *self != *other
+    }
+}
+
+#[lang = "neg"]
+pub trait Neg {
+    type Output;
+
+    fn neg(self) -> Self::Output;
+}
+
+impl Neg for i8 {
+    type Output = i8;
+
+    fn neg(self) -> i8 {
+        -self
+    }
+}
+
+impl Neg for i16 {
+    type Output = i16;
+
+    fn neg(self) -> i16 {
+        self
+    }
+}
+
+impl Neg for isize {
+    type Output = isize;
+
+    fn neg(self) -> isize {
+        -self
+    }
+}
+
+impl Neg for f32 {
+    type Output = f32;
+
+    fn neg(self) -> f32 {
+        -self
+    }
+}
+
+pub enum Option<T> {
+    Some(T),
+    None,
+}
+
+pub use Option::*;
+
+#[lang = "phantom_data"]
+pub struct PhantomData<T: ?Sized>;
+
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+pub trait FnOnce<Args> {
+    #[lang = "fn_once_output"]
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+pub trait FnMut<Args>: FnOnce<Args> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "panic"]
+#[track_caller]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\n\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "eh_personality"]
+fn eh_personality() -> ! {
+    loop {}
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "deref"]
+pub trait Deref {
+    type Target: ?Sized;
+
+    fn deref(&self) -> &Self::Target;
+}
+
+#[lang = "owned_box"]
+pub struct Box<T: ?Sized>(*mut T);
+
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {}
+
+impl<T: ?Sized> Drop for Box<T> {
+    fn drop(&mut self) {
+        // drop is currently performed by compiler.
+    }
+}
+
+impl<T> Deref for Box<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &**self
+    }
+}
+
+#[lang = "exchange_malloc"]
+unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
+    libc::malloc(size)
+}
+
+#[lang = "box_free"]
+unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
+    libc::free(ptr as *mut u8);
+}
+
+#[lang = "drop"]
+pub trait Drop {
+    fn drop(&mut self);
+}
+
+#[lang = "manually_drop"]
+#[repr(transparent)]
+pub struct ManuallyDrop<T: ?Sized> {
+    pub value: T,
+}
+
+#[lang = "maybe_uninit"]
+#[repr(transparent)]
+pub union MaybeUninit<T> {
+    pub uninit: (),
+    pub value: ManuallyDrop<T>,
+}
+
+pub mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+        pub fn size_of<T>() -> usize;
+        pub fn size_of_val<T: ?::Sized>(val: *const T) -> usize;
+        pub fn min_align_of<T>() -> usize;
+        pub fn min_align_of_val<T: ?::Sized>(val: *const T) -> usize;
+        pub fn copy<T>(src: *const T, dst: *mut T, count: usize);
+        pub fn transmute<T, U>(e: T) -> U;
+        pub fn ctlz_nonzero<T>(x: T) -> T;
+        pub fn needs_drop<T>() -> bool;
+        pub fn bitreverse<T>(x: T) -> T;
+        pub fn bswap<T>(x: T) -> T;
+        pub fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
+        pub fn unreachable() -> !;
+    }
+}
+
+pub mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn malloc(size: usize) -> *mut u8;
+        pub fn free(ptr: *mut u8);
+        pub fn memcpy(dst: *mut u8, src: *const u8, size: usize);
+        pub fn memmove(dst: *mut u8, src: *const u8, size: usize);
+        pub fn strncpy(dst: *mut u8, src: *const u8, size: usize);
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+extern {
+    type VaListImpl;
+}
+
+#[lang = "va_list"]
+#[repr(transparent)]
+pub struct VaList<'a>(&'a mut VaListImpl);
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro stringify($($t:tt)*) { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro file() { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro line() { /* compiler built-in */ }
+
+#[rustc_builtin_macro]
+#[rustc_macro_transparency = "semitransparent"]
+pub macro cfg() { /* compiler built-in */ }
+
+pub static A_STATIC: u8 = 42;
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[no_mangle]
+pub fn get_tls() -> u8 {
+    #[thread_local]
+    static A: u8 = 42;
+
+    A
+}
diff --git a/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs b/compiler/rustc_codegen_gcc/example/mini_core_hello_world.rs
new file mode 100644 (file)
index 0000000..69d5915
--- /dev/null
@@ -0,0 +1,424 @@
+// Adapted from https://github.com/sunfishcode/mir2cranelift/blob/master/rust-examples/nocore-hello-world.rs
+
+#![feature(
+    no_core, unboxed_closures, start, lang_items, box_syntax, never_type, linkage,
+    extern_types, thread_local
+)]
+#![no_core]
+#![allow(dead_code, non_camel_case_types)]
+
+extern crate mini_core;
+
+use mini_core::*;
+use mini_core::libc::*;
+
+unsafe extern "C" fn my_puts(s: *const u8) {
+    puts(s);
+}
+
+#[lang = "termination"]
+trait Termination {
+    fn report(self) -> i32;
+}
+
+impl Termination for () {
+    fn report(self) -> i32 {
+        unsafe {
+            NUM = 6 * 7 + 1 + (1u8 == 1u8) as u8; // 44
+            *NUM_REF as i32
+        }
+    }
+}
+
+trait SomeTrait {
+    fn object_safe(&self);
+}
+
+impl SomeTrait for &'static str {
+    fn object_safe(&self) {
+        unsafe {
+            puts(*self as *const str as *const u8);
+        }
+    }
+}
+
+struct NoisyDrop {
+    text: &'static str,
+    inner: NoisyDropInner,
+}
+
+struct NoisyDropInner;
+
+impl Drop for NoisyDrop {
+    fn drop(&mut self) {
+        unsafe {
+            puts(self.text as *const str as *const u8);
+        }
+    }
+}
+
+impl Drop for NoisyDropInner {
+    fn drop(&mut self) {
+        unsafe {
+            puts("Inner got dropped!\0" as *const str as *const u8);
+        }
+    }
+}
+
+impl SomeTrait for NoisyDrop {
+    fn object_safe(&self) {}
+}
+
+enum Ordering {
+    Less = -1,
+    Equal = 0,
+    Greater = 1,
+}
+
+#[lang = "start"]
+fn start<T: Termination + 'static>(
+    main: fn() -> T,
+    argc: isize,
+    argv: *const *const u8,
+) -> isize {
+    if argc == 3 {
+        unsafe { puts(*argv); }
+        unsafe { puts(*((argv as usize + intrinsics::size_of::<*const u8>()) as *const *const u8)); }
+        unsafe { puts(*((argv as usize + 2 * intrinsics::size_of::<*const u8>()) as *const *const u8)); }
+    }
+
+    main().report();
+    0
+}
+
+static mut NUM: u8 = 6 * 7;
+static NUM_REF: &'static u8 = unsafe { &NUM };
+
+macro_rules! assert {
+    ($e:expr) => {
+        if !$e {
+            panic(stringify!(! $e));
+        }
+    };
+}
+
+macro_rules! assert_eq {
+    ($l:expr, $r: expr) => {
+        if $l != $r {
+            panic(stringify!($l != $r));
+        }
+    }
+}
+
+struct Unique<T: ?Sized> {
+    pointer: *const T,
+    _marker: PhantomData<T>,
+}
+
+impl<T: ?Sized, U: ?Sized> CoerceUnsized<Unique<U>> for Unique<T> where T: Unsize<U> {}
+
+unsafe fn zeroed<T>() -> T {
+    let mut uninit = MaybeUninit { uninit: () };
+    intrinsics::write_bytes(&mut uninit.value.value as *mut T, 0, 1);
+    uninit.value.value
+}
+
+fn take_f32(_f: f32) {}
+fn take_unique(_u: Unique<()>) {}
+
+fn return_u128_pair() -> (u128, u128) {
+    (0, 0)
+}
+
+fn call_return_u128_pair() {
+    return_u128_pair();
+}
+
+fn main() {
+    take_unique(Unique {
+        pointer: 0 as *const (),
+        _marker: PhantomData,
+    });
+    take_f32(0.1);
+
+    //call_return_u128_pair();
+
+    let slice = &[0, 1] as &[i32];
+    let slice_ptr = slice as *const [i32] as *const i32;
+
+    assert_eq!(slice_ptr as usize % 4, 0);
+
+    //return;
+
+    unsafe {
+        printf("Hello %s\n\0" as *const str as *const i8, "printf\0" as *const str as *const i8);
+
+        let hello: &[u8] = b"Hello\0" as &[u8; 6];
+        let ptr: *const u8 = hello as *const [u8] as *const u8;
+        puts(ptr);
+
+        let world: Box<&str> = box "World!\0";
+        puts(*world as *const str as *const u8);
+        world as Box<dyn SomeTrait>;
+
+        assert_eq!(intrinsics::bitreverse(0b10101000u8), 0b00010101u8);
+
+        assert_eq!(intrinsics::bswap(0xabu8), 0xabu8);
+        assert_eq!(intrinsics::bswap(0xddccu16), 0xccddu16);
+        assert_eq!(intrinsics::bswap(0xffee_ddccu32), 0xccdd_eeffu32);
+        assert_eq!(intrinsics::bswap(0x1234_5678_ffee_ddccu64), 0xccdd_eeff_7856_3412u64);
+
+        assert_eq!(intrinsics::size_of_val(hello) as u8, 6);
+
+        let chars = &['C', 'h', 'a', 'r', 's'];
+        let chars = chars as &[char];
+        assert_eq!(intrinsics::size_of_val(chars) as u8, 4 * 5);
+
+        let a: &dyn SomeTrait = &"abc\0";
+        a.object_safe();
+
+        assert_eq!(intrinsics::size_of_val(a) as u8, 16);
+        assert_eq!(intrinsics::size_of_val(&0u32) as u8, 4);
+
+        assert_eq!(intrinsics::min_align_of::<u16>() as u8, 2);
+        assert_eq!(intrinsics::min_align_of_val(&a) as u8, intrinsics::min_align_of::<&str>() as u8);
+
+        assert!(!intrinsics::needs_drop::<u8>());
+        assert!(intrinsics::needs_drop::<NoisyDrop>());
+
+        Unique {
+            pointer: 0 as *const &str,
+            _marker: PhantomData,
+        } as Unique<dyn SomeTrait>;
+
+        struct MyDst<T: ?Sized>(T);
+
+        intrinsics::size_of_val(&MyDst([0u8; 4]) as &MyDst<[u8]>);
+
+        struct Foo {
+            x: u8,
+            y: !,
+        }
+
+        unsafe fn uninitialized<T>() -> T {
+            MaybeUninit { uninit: () }.value.value
+        }
+
+        zeroed::<(u8, u8)>();
+        #[allow(unreachable_code)]
+        {
+            if false {
+                zeroed::<!>();
+                zeroed::<Foo>();
+                uninitialized::<Foo>();
+            }
+        }
+    }
+
+    let _ = box NoisyDrop {
+        text: "Boxed outer got dropped!\0",
+        inner: NoisyDropInner,
+    } as Box<dyn SomeTrait>;
+
+    const FUNC_REF: Option<fn()> = Some(main);
+    match FUNC_REF {
+        Some(_) => {},
+        None => assert!(false),
+    }
+
+    match Ordering::Less {
+        Ordering::Less => {},
+        _ => assert!(false),
+    }
+
+    [NoisyDropInner, NoisyDropInner];
+
+    let x = &[0u32, 42u32] as &[u32];
+    match x {
+        [] => assert_eq!(0u32, 1),
+        [_, ref y @ ..] => assert_eq!(&x[1] as *const u32 as usize, &y[0] as *const u32 as usize),
+    }
+
+    assert_eq!(((|()| 42u8) as fn(()) -> u8)(()), 42);
+
+    extern {
+        #[linkage = "weak"]
+        static ABC: *const u8;
+    }
+
+    {
+        extern {
+            #[linkage = "weak"]
+            static ABC: *const u8;
+        }
+    }
+
+    // TODO(antoyo): to make this work, support weak linkage.
+    //unsafe { assert_eq!(ABC as usize, 0); }
+
+    &mut (|| Some(0 as *const ())) as &mut dyn FnMut() -> Option<*const ()>;
+
+    let f = 1000.0;
+    assert_eq!(f as u8, 255);
+    let f2 = -1000.0;
+    assert_eq!(f2 as i8, -128);
+    assert_eq!(f2 as u8, 0);
+
+    static ANOTHER_STATIC: &u8 = &A_STATIC;
+    assert_eq!(*ANOTHER_STATIC, 42);
+
+    check_niche_behavior();
+
+    extern "C" {
+        type ExternType;
+    }
+
+    struct ExternTypeWrapper {
+        _a: ExternType,
+    }
+
+    let nullptr = 0 as *const ();
+    let extern_nullptr = nullptr as *const ExternTypeWrapper;
+    extern_nullptr as *const ();
+    let slice_ptr = &[] as *const [u8];
+    slice_ptr as *const u8;
+
+    #[cfg(not(jit))]
+    test_tls();
+}
+
+#[repr(C)]
+enum c_void {
+    _1,
+    _2,
+}
+
+type c_int = i32;
+type c_ulong = u64;
+
+type pthread_t = c_ulong;
+
+#[repr(C)]
+struct pthread_attr_t {
+    __size: [u64; 7],
+}
+
+#[link(name = "pthread")]
+extern "C" {
+    fn pthread_attr_init(attr: *mut pthread_attr_t) -> c_int;
+
+    fn pthread_create(
+        native: *mut pthread_t,
+        attr: *const pthread_attr_t,
+        f: extern "C" fn(_: *mut c_void) -> *mut c_void,
+        value: *mut c_void
+    ) -> c_int;
+
+    fn pthread_join(
+        native: pthread_t,
+        value: *mut *mut c_void
+    ) -> c_int;
+}
+
+#[thread_local]
+#[cfg(not(jit))]
+static mut TLS: u8 = 42;
+
+#[cfg(not(jit))]
+extern "C" fn mutate_tls(_: *mut c_void) -> *mut c_void {
+    unsafe { TLS = 0; }
+    0 as *mut c_void
+}
+
+#[cfg(not(jit))]
+fn test_tls() {
+    unsafe {
+        let mut attr: pthread_attr_t = zeroed();
+        let mut thread: pthread_t = 0;
+
+        assert_eq!(TLS, 42);
+
+        if pthread_attr_init(&mut attr) != 0 {
+            assert!(false);
+        }
+
+        if pthread_create(&mut thread, &attr, mutate_tls, 0 as *mut c_void) != 0 {
+            assert!(false);
+        }
+
+        let mut res = 0 as *mut c_void;
+        pthread_join(thread, &mut res);
+
+        // TLS of main thread must not have been changed by the other thread.
+        assert_eq!(TLS, 42);
+
+        puts("TLS works!\n\0" as *const str as *const u8);
+    }
+}
+
+// Copied ui/issues/issue-61696.rs
+
+pub enum Infallible {}
+
+// The check that the `bool` field of `V1` is encoding a "niche variant"
+// (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect,
+// causing valid `V1` values to be interpreted as other variants.
+pub enum E1 {
+    V1 { f: bool },
+    V2 { f: Infallible },
+    V3,
+    V4,
+}
+
+// Computing the discriminant used to be done using the niche type (here `u8`,
+// from the `bool` field of `V1`), overflowing for variants with large enough
+// indices (`V3` and `V4`), causing them to be interpreted as other variants.
+pub enum E2<X> {
+    V1 { f: bool },
+
+    /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X),
+    _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X),
+    _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X),
+    _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X),
+    _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X),
+    _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X),
+    _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X),
+    _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X),
+    _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X),
+    _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X),
+    _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X),
+    _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X),
+    _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X),
+    _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X),
+    _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X),
+    _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X),
+    _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X),
+    _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X),
+    _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X),
+    _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X),
+    _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X),
+    _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X),
+    _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X),
+    _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X),
+    _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X),
+    _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X),
+    _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X),
+    _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X),
+    _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X),
+    _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X),
+    _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X),
+    _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X),
+
+    V3,
+    V4,
+}
+
+fn check_niche_behavior () {
+    if let E1::V2 { .. } = (E1::V1 { f: true }) {
+        intrinsics::abort();
+    }
+
+    if let E2::V1 { .. } = E2::V3::<Infallible> {
+        intrinsics::abort();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/example/mod_bench.rs b/compiler/rustc_codegen_gcc/example/mod_bench.rs
new file mode 100644 (file)
index 0000000..2e2b005
--- /dev/null
@@ -0,0 +1,37 @@
+#![feature(start, box_syntax, core_intrinsics, lang_items)]
+#![no_std]
+
+#[link(name = "c")]
+extern {}
+
+#[panic_handler]
+fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+    unsafe {
+        core::intrinsics::abort();
+    }
+}
+
+#[lang="eh_personality"]
+fn eh_personality(){}
+
+// Required for rustc_codegen_llvm
+#[no_mangle]
+unsafe extern "C" fn _Unwind_Resume() {
+    core::intrinsics::unreachable();
+}
+
+#[start]
+fn main(_argc: isize, _argv: *const *const u8) -> isize {
+    for i in 2..100_000_000 {
+        black_box((i + 1) % i);
+    }
+
+    0
+}
+
+#[inline(never)]
+fn black_box(i: u32) {
+    if i != 1 {
+        unsafe { core::intrinsics::abort(); }
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/example/std_example.rs b/compiler/rustc_codegen_gcc/example/std_example.rs
new file mode 100644 (file)
index 0000000..eba0eb8
--- /dev/null
@@ -0,0 +1,278 @@
+#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
+
+use std::arch::x86_64::*;
+use std::io::Write;
+use std::ops::Generator;
+
+extern {
+    pub fn printf(format: *const i8, ...) -> i32;
+}
+
+fn main() {
+    let mutex = std::sync::Mutex::new(());
+    let _guard = mutex.lock().unwrap();
+
+    let _ = ::std::iter::repeat('a' as u8).take(10).collect::<Vec<_>>();
+    let stderr = ::std::io::stderr();
+    let mut stderr = stderr.lock();
+
+    std::thread::spawn(move || {
+        println!("Hello from another thread!");
+    });
+
+    writeln!(stderr, "some {} text", "<unknown>").unwrap();
+
+    let _ = std::process::Command::new("true").env("c", "d").spawn();
+
+    println!("cargo:rustc-link-lib=z");
+
+    static ONCE: std::sync::Once = std::sync::Once::new();
+    ONCE.call_once(|| {});
+
+    let _eq = LoopState::Continue(()) == LoopState::Break(());
+
+    // Make sure ByValPair values with differently sized components are correctly passed
+    map(None::<(u8, Box<Instruction>)>);
+
+    println!("{}", 2.3f32.exp());
+    println!("{}", 2.3f32.exp2());
+    println!("{}", 2.3f32.abs());
+    println!("{}", 2.3f32.sqrt());
+    println!("{}", 2.3f32.floor());
+    println!("{}", 2.3f32.ceil());
+    println!("{}", 2.3f32.min(1.0));
+    println!("{}", 2.3f32.max(1.0));
+    println!("{}", 2.3f32.powi(2));
+    println!("{}", 2.3f32.log2());
+    assert_eq!(2.3f32.copysign(-1.0), -2.3f32);
+    println!("{}", 2.3f32.powf(2.0));
+
+    assert_eq!(-128i8, (-128i8).saturating_sub(1));
+    assert_eq!(127i8, 127i8.saturating_sub(-128));
+    assert_eq!(-128i8, (-128i8).saturating_add(-128));
+    assert_eq!(127i8, 127i8.saturating_add(1));
+
+    assert_eq!(-32768i16, (-32768i16).saturating_add(-32768));
+    assert_eq!(32767i16, 32767i16.saturating_add(1));
+
+    assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
+    assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
+
+    let _d = 0i128.checked_div(2i128);
+    let _d = 0u128.checked_div(2u128);
+    assert_eq!(1u128 + 2, 3);
+
+    assert_eq!(0b100010000000000000000000000000000u128 >> 10, 0b10001000000000000000000u128);
+    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 >> 64, 0xFEDCBA98765432u128);
+    assert_eq!(0xFEDCBA987654321123456789ABCDEFu128 as i128 >> 64, 0xFEDCBA98765432i128);
+
+    let tmp = 353985398u128;
+    assert_eq!(tmp * 932490u128, 330087843781020u128);
+
+    let tmp = -0x1234_5678_9ABC_DEF0i64;
+    assert_eq!(tmp as i128, -0x1234_5678_9ABC_DEF0i128);
+
+    // Check that all u/i128 <-> float casts work correctly.
+    let houndred_u128 = 100u128;
+    let houndred_i128 = 100i128;
+    let houndred_f32 = 100.0f32;
+    let houndred_f64 = 100.0f64;
+    assert_eq!(houndred_u128 as f32, 100.0);
+    assert_eq!(houndred_u128 as f64, 100.0);
+    assert_eq!(houndred_f32 as u128, 100);
+    assert_eq!(houndred_f64 as u128, 100);
+    assert_eq!(houndred_i128 as f32, 100.0);
+    assert_eq!(houndred_i128 as f64, 100.0);
+    assert_eq!(houndred_f32 as i128, 100);
+    assert_eq!(houndred_f64 as i128, 100);
+
+    let _a = 1u32 << 2u8;
+
+    let empty: [i32; 0] = [];
+    assert!(empty.is_sorted());
+
+    println!("{:?}", std::intrinsics::caller_location());
+
+    /*unsafe {
+        test_simd();
+    }*/
+
+    Box::pin(move |mut _task_context| {
+        yield ();
+    }).as_mut().resume(0);
+
+    println!("End");
+}
+
+/*#[target_feature(enable = "sse2")]
+unsafe fn test_simd() {
+    let x = _mm_setzero_si128();
+    let y = _mm_set1_epi16(7);
+    let or = _mm_or_si128(x, y);
+    let cmp_eq = _mm_cmpeq_epi8(y, y);
+    let cmp_lt = _mm_cmplt_epi8(y, y);
+
+    /*assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
+    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
+    assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
+
+    test_mm_slli_si128();
+    test_mm_movemask_epi8();
+    test_mm256_movemask_epi8();
+    test_mm_add_epi8();
+    test_mm_add_pd();
+    test_mm_cvtepi8_epi16();
+    test_mm_cvtsi128_si64();
+
+    // FIXME(#666) implement `#[rustc_arg_required_const(..)]` support
+    //test_mm_extract_epi8();
+
+    let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
+    assert_eq!(mask1, 1);*/
+}*/
+
+/*#[target_feature(enable = "sse2")]
+unsafe fn test_mm_slli_si128() {
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+    );
+    let r = _mm_slli_si128(a, 1);
+    let e = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+    assert_eq_m128i(r, e);
+
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+    );
+    let r = _mm_slli_si128(a, 15);
+    let e = _mm_setr_epi8(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1);
+    assert_eq_m128i(r, e);
+
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+    );
+    let r = _mm_slli_si128(a, 16);
+    assert_eq_m128i(r, _mm_set1_epi8(0));
+
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+    );
+    let r = _mm_slli_si128(a, -1);
+    assert_eq_m128i(_mm_set1_epi8(0), r);
+
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+    );
+    let r = _mm_slli_si128(a, -0x80000000);
+    assert_eq_m128i(r, _mm_set1_epi8(0));
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_movemask_epi8() {
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8, 0b01,
+        0b0101, 0b1111_0000u8 as i8, 0, 0,
+        0, 0, 0b1111_0000u8 as i8, 0b0101,
+        0b01, 0b1000_0000u8 as i8, 0b0, 0b1000_0000u8 as i8,
+    );
+    let r = _mm_movemask_epi8(a);
+    assert_eq!(r, 0b10100100_00100101);
+}
+
+#[target_feature(enable = "avx2")]
+unsafe fn test_mm256_movemask_epi8() {
+    let a = _mm256_set1_epi8(-1);
+    let r = _mm256_movemask_epi8(a);
+    let e = -1;
+    assert_eq!(r, e);
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_add_epi8() {
+    let a = _mm_setr_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
+    #[rustfmt::skip]
+    let b = _mm_setr_epi8(
+        16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+    );
+    let r = _mm_add_epi8(a, b);
+    #[rustfmt::skip]
+    let e = _mm_setr_epi8(
+        16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46,
+    );
+    assert_eq_m128i(r, e);
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_add_pd() {
+    let a = _mm_setr_pd(1.0, 2.0);
+    let b = _mm_setr_pd(5.0, 10.0);
+    let r = _mm_add_pd(a, b);
+    assert_eq_m128d(r, _mm_setr_pd(6.0, 12.0));
+}
+
+fn assert_eq_m128i(x: std::arch::x86_64::__m128i, y: std::arch::x86_64::__m128i) {
+    unsafe {
+        assert_eq!(std::mem::transmute::<_, [u8; 16]>(x), std::mem::transmute::<_, [u8; 16]>(y));
+    }
+}
+
+#[target_feature(enable = "sse2")]
+pub unsafe fn assert_eq_m128d(a: __m128d, b: __m128d) {
+    if _mm_movemask_pd(_mm_cmpeq_pd(a, b)) != 0b11 {
+        panic!("{:?} != {:?}", a, b);
+    }
+}
+
+#[target_feature(enable = "sse2")]
+unsafe fn test_mm_cvtsi128_si64() {
+    let r = _mm_cvtsi128_si64(std::mem::transmute::<[i64; 2], _>([5, 0]));
+    assert_eq!(r, 5);
+}
+
+#[target_feature(enable = "sse4.1")]
+unsafe fn test_mm_cvtepi8_epi16() {
+    let a = _mm_set1_epi8(10);
+    let r = _mm_cvtepi8_epi16(a);
+    let e = _mm_set1_epi16(10);
+    assert_eq_m128i(r, e);
+    let a = _mm_set1_epi8(-10);
+    let r = _mm_cvtepi8_epi16(a);
+    let e = _mm_set1_epi16(-10);
+    assert_eq_m128i(r, e);
+}
+
+#[target_feature(enable = "sse4.1")]
+unsafe fn test_mm_extract_epi8() {
+    #[rustfmt::skip]
+    let a = _mm_setr_epi8(
+        -1, 1, 2, 3, 4, 5, 6, 7,
+        8, 9, 10, 11, 12, 13, 14, 15
+    );
+    let r1 = _mm_extract_epi8(a, 0);
+    let r2 = _mm_extract_epi8(a, 19);
+    assert_eq!(r1, 0xFF);
+    assert_eq!(r2, 3);
+}*/
+
+#[derive(PartialEq)]
+enum LoopState {
+    Continue(()),
+    Break(())
+}
+
+pub enum Instruction {
+    Increment,
+    Loop,
+}
+
+fn map(a: Option<(u8, Box<Instruction>)>) -> Option<Box<Instruction>> {
+    match a {
+        None => None,
+        Some((_, instr)) => Some(instr),
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs b/compiler/rustc_codegen_gcc/example/subslice-patterns-const-eval.rs
new file mode 100644 (file)
index 0000000..2cb8478
--- /dev/null
@@ -0,0 +1,97 @@
+// Based on https://github.com/rust-lang/rust/blob/c5840f9d252c2f5cc16698dbf385a29c5de3ca07/src/test/ui/array-slice-vec/subslice-patterns-const-eval-match.rs
+
+// Test that array subslice patterns are correctly handled in const evaluation.
+
+// run-pass
+
+#[derive(PartialEq, Debug, Clone)]
+struct N(u8);
+
+#[derive(PartialEq, Debug, Clone)]
+struct Z;
+
+macro_rules! n {
+    ($($e:expr),* $(,)?) => {
+        [$(N($e)),*]
+    }
+}
+
+// This macro has an unused variable so that it can be repeated base on the
+// number of times a repeated variable (`$e` in `z`) occurs.
+macro_rules! zed {
+    ($e:expr) => { Z }
+}
+
+macro_rules! z {
+    ($($e:expr),* $(,)?) => {
+        [$(zed!($e)),*]
+    }
+}
+
+// Compare constant evaluation and runtime evaluation of a given expression.
+macro_rules! compare_evaluation {
+    ($e:expr, $t:ty $(,)?) => {{
+        const CONST_EVAL: $t = $e;
+        const fn const_eval() -> $t { $e }
+        static CONST_EVAL2: $t = const_eval();
+        let runtime_eval = $e;
+        assert_eq!(CONST_EVAL, runtime_eval);
+        assert_eq!(CONST_EVAL2, runtime_eval);
+    }}
+}
+
+// Repeat `$test`, substituting the given macro variables with the given
+// identifiers.
+//
+// For example:
+//
+// repeat! {
+//     ($name); X; Y:
+//     struct $name;
+// }
+//
+// Expands to:
+//
+// struct X; struct Y;
+//
+// This is used to repeat the tests using both the `N` and `Z`
+// types.
+macro_rules! repeat {
+    (($($dollar:tt $placeholder:ident)*); $($($values:ident),+);*: $($test:tt)*) => {
+        macro_rules! single {
+            ($($dollar $placeholder:ident),*) => { $($test)* }
+        }
+        $(single!($($values),+);)*
+    }
+}
+
+fn main() {
+    repeat! {
+        ($arr $Ty); n, N; z, Z:
+        compare_evaluation!({ let [_, x @ .., _] = $arr!(1, 2, 3, 4); x }, [$Ty; 2]);
+        compare_evaluation!({ let [_, ref x @ .., _] = $arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]);
+        compare_evaluation!({ let [_, x @ .., _] = &$arr!(1, 2, 3, 4); x }, &'static [$Ty; 2]);
+
+        compare_evaluation!({ let [_, _, x @ .., _, _] = $arr!(1, 2, 3, 4); x }, [$Ty; 0]);
+        compare_evaluation!(
+            { let [_, _, ref x @ .., _, _] = $arr!(1, 2, 3, 4); x },
+            &'static [$Ty; 0],
+        );
+        compare_evaluation!(
+            { let [_, _, x @ .., _, _] = &$arr!(1, 2, 3, 4); x },
+            &'static [$Ty; 0],
+        );
+
+        compare_evaluation!({ let [_, .., x] = $arr!(1, 2, 3, 4); x }, $Ty);
+        compare_evaluation!({ let [_, .., ref x] = $arr!(1, 2, 3, 4); x }, &'static $Ty);
+        compare_evaluation!({ let [_, _y @ .., x] = &$arr!(1, 2, 3, 4); x }, &'static $Ty);
+    }
+
+    compare_evaluation!({ let [_, .., N(x)] = n!(1, 2, 3, 4); x }, u8);
+    compare_evaluation!({ let [_, .., N(ref x)] = n!(1, 2, 3, 4); x }, &'static u8);
+    compare_evaluation!({ let [_, .., N(x)] = &n!(1, 2, 3, 4); x }, &'static u8);
+
+    compare_evaluation!({ let [N(x), .., _] = n!(1, 2, 3, 4); x }, u8);
+    compare_evaluation!({ let [N(ref x), .., _] = n!(1, 2, 3, 4); x }, &'static u8);
+    compare_evaluation!({ let [N(x), .., _] = &n!(1, 2, 3, 4); x }, &'static u8);
+}
diff --git a/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs b/compiler/rustc_codegen_gcc/example/track-caller-attribute.rs
new file mode 100644 (file)
index 0000000..93bab17
--- /dev/null
@@ -0,0 +1,40 @@
+// Based on https://github.com/anp/rust/blob/175631311716d7dfeceec40d2587cde7142ffa8c/src/test/ui/rfc-2091-track-caller/track-caller-attribute.rs
+
+// run-pass
+
+use std::panic::Location;
+
+#[track_caller]
+fn tracked() -> &'static Location<'static> {
+    Location::caller()
+}
+
+fn nested_intrinsic() -> &'static Location<'static> {
+    Location::caller()
+}
+
+fn nested_tracked() -> &'static Location<'static> {
+    tracked()
+}
+
+fn main() {
+    let location = Location::caller();
+    assert_eq!(location.file(), file!());
+    assert_eq!(location.line(), 21);
+    assert_eq!(location.column(), 20);
+
+    let tracked = tracked();
+    assert_eq!(tracked.file(), file!());
+    assert_eq!(tracked.line(), 26);
+    assert_eq!(tracked.column(), 19);
+
+    let nested = nested_intrinsic();
+    assert_eq!(nested.file(), file!());
+    assert_eq!(nested.line(), 13);
+    assert_eq!(nested.column(), 5);
+
+    let contained = nested_tracked();
+    assert_eq!(contained.file(), file!());
+    assert_eq!(contained.line(), 17);
+    assert_eq!(contained.column(), 5);
+}
diff --git a/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_gcc/patches/0022-core-Disable-not-compiling-tests.patch
new file mode 100644 (file)
index 0000000..aae62a9
--- /dev/null
@@ -0,0 +1,63 @@
+From f6befc4bb51d84f5f1cf35938a168c953d421350 Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Sun, 24 Nov 2019 15:10:23 +0100
+Subject: [PATCH] [core] Disable not compiling tests
+
+---
+ library/core/tests/Cargo.toml         | 8 ++++++++
+ library/core/tests/num/flt2dec/mod.rs | 1 -
+ library/core/tests/num/int_macros.rs  | 2 ++
+ library/core/tests/num/uint_macros.rs | 2 ++
+ library/core/tests/ptr.rs             | 2 ++
+ library/core/tests/slice.rs           | 2 ++
+ 6 files changed, 16 insertions(+), 1 deletion(-)
+ create mode 100644 library/core/tests/Cargo.toml
+
+diff --git a/library/core/tests/Cargo.toml b/library/core/tests/Cargo.toml
+new file mode 100644
+index 0000000..46fd999
+--- /dev/null
++++ b/library/core/tests/Cargo.toml
+@@ -0,0 +1,8 @@
++[package]
++name = "core"
++version = "0.0.0"
++edition = "2018"
++
++[lib]
++name = "coretests"
++path = "lib.rs"
+diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs
+index a35897e..f0bf645 100644
+--- a/library/core/tests/num/flt2dec/mod.rs
++++ b/library/core/tests/num/flt2dec/mod.rs
+@@ -13,7 +13,6 @@ mod strategy {
+     mod dragon;
+     mod grisu;
+ }
+-mod random;
+ pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded {
+     match decode(v).1 {
+diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
+index 6609bc3..241b497 100644
+--- a/library/core/tests/slice.rs
++++ b/library/core/tests/slice.rs
+@@ -1209,6 +1209,7 @@ fn brute_force_rotate_test_1() {
+     }
+ }
++/*
+ #[test]
+ #[cfg(not(target_arch = "wasm32"))]
+ fn sort_unstable() {
+@@ -1394,6 +1395,7 @@ fn partition_at_index() {
+     v.select_nth_unstable(0);
+     assert!(v == [0xDEADBEEF]);
+ }
++*/
+ #[test]
+ #[should_panic(expected = "index 0 greater than length of slice")]
+--
+2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch b/compiler/rustc_codegen_gcc/patches/0023-core-Ignore-failing-tests.patch
new file mode 100644 (file)
index 0000000..ee5ba44
--- /dev/null
@@ -0,0 +1,49 @@
+From dd82e95c9de212524e14fc60155de1ae40156dfc Mon Sep 17 00:00:00 2001
+From: bjorn3 <bjorn3@users.noreply.github.com>
+Date: Sun, 24 Nov 2019 15:34:06 +0100
+Subject: [PATCH] [core] Ignore failing tests
+
+---
+ library/core/tests/iter.rs       |  4 ++++
+ library/core/tests/num/bignum.rs | 10 ++++++++++
+ library/core/tests/num/mod.rs    |  5 +++--
+ library/core/tests/time.rs       |  1 +
+ 4 files changed, 18 insertions(+), 2 deletions(-)
+
+diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs
+index 4bc44e9..8e3c7a4 100644
+--- a/library/core/tests/array.rs
++++ b/library/core/tests/array.rs
+@@ -242,6 +242,7 @@ fn iterator_drops() {
+     assert_eq!(i.get(), 5);
+ }
++/*
+ // This test does not work on targets without panic=unwind support.
+ // To work around this problem, test is marked is should_panic, so it will
+ // be automagically skipped on unsuitable targets, such as
+@@ -283,6 +284,7 @@ fn array_default_impl_avoids_leaks_on_panic() {
+     assert_eq!(COUNTER.load(Relaxed), 0);
+     panic!("test succeeded")
+ }
++*/
+ #[test]
+ fn empty_array_is_always_default() {
+@@ -304,6 +304,7 @@ fn array_map() {
+     assert_eq!(b, [1, 2, 3]);
+ }
++/*
+ // See note on above test for why `should_panic` is used.
+ #[test]
+ #[should_panic(expected = "test succeeded")]
+@@ -332,6 +333,7 @@ fn array_map_drop_safety() {
+     assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create);
+     panic!("test succeeded")
+ }
++*/
+ #[test]
+ fn cell_allows_array_cycle() {
+-- 2.21.0 (Apple Git-122)
diff --git a/compiler/rustc_codegen_gcc/prepare.sh b/compiler/rustc_codegen_gcc/prepare.sh
new file mode 100755 (executable)
index 0000000..503fa29
--- /dev/null
@@ -0,0 +1,22 @@
+#!/bin/bash --verbose
+set -e
+
+source prepare_build.sh
+
+cargo install hyperfine || echo "Skipping hyperfine install"
+
+git clone https://github.com/rust-lang/regex.git || echo "rust-lang/regex has already been cloned"
+pushd regex
+git checkout -- .
+git checkout 341f207c1071f7290e3f228c710817c280c8dca1
+popd
+
+git clone https://github.com/ebobby/simple-raytracer || echo "ebobby/simple-raytracer has already been cloned"
+pushd simple-raytracer
+git checkout -- .
+git checkout 804a7a21b9e673a482797aa289a18ed480e4d813
+
+# build with cg_llvm for perf comparison
+cargo build
+mv target/debug/main raytracer_cg_llvm
+popd
diff --git a/compiler/rustc_codegen_gcc/prepare_build.sh b/compiler/rustc_codegen_gcc/prepare_build.sh
new file mode 100755 (executable)
index 0000000..ccf5350
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/bash --verbose
+set -e
+
+rustup component add rust-src rustc-dev llvm-tools-preview
+./build_sysroot/prepare_sysroot_src.sh
diff --git a/compiler/rustc_codegen_gcc/rust-toolchain b/compiler/rustc_codegen_gcc/rust-toolchain
new file mode 100644 (file)
index 0000000..d311a33
--- /dev/null
@@ -0,0 +1 @@
+nightly-2021-09-28
diff --git a/compiler/rustc_codegen_gcc/rustup.sh b/compiler/rustc_codegen_gcc/rustup.sh
new file mode 100755 (executable)
index 0000000..01ce5bb
--- /dev/null
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+set -e
+
+case $1 in
+    "prepare")
+        TOOLCHAIN=$(date +%Y-%m-%d)
+
+        echo "=> Installing new nightly"
+        rustup toolchain install --profile minimal nightly-${TOOLCHAIN} # Sanity check to see if the nightly exists
+        echo nightly-${TOOLCHAIN} > rust-toolchain
+
+        echo "=> Uninstalling all old nighlies"
+        for nightly in $(rustup toolchain list | grep nightly | grep -v $TOOLCHAIN | grep -v nightly-x86_64); do
+            rustup toolchain uninstall $nightly
+        done
+
+        ./clean_all.sh
+        ./prepare.sh
+        ;;
+    "commit")
+        git add rust-toolchain
+        git commit -m "Rustup to $(rustc -V)"
+        ;;
+    *)
+        echo "Unknown command '$1'"
+        echo "Usage: ./rustup.sh prepare|commit"
+        ;;
+esac
diff --git a/compiler/rustc_codegen_gcc/src/abi.rs b/compiler/rustc_codegen_gcc/src/abi.rs
new file mode 100644 (file)
index 0000000..ce428c5
--- /dev/null
@@ -0,0 +1,160 @@
+use gccjit::{ToRValue, Type};
+use rustc_codegen_ssa::traits::{AbiBuilderMethods, BaseTypeMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::Ty;
+use rustc_target::abi::call::{CastTarget, FnAbi, PassMode, Reg, RegKind};
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::intrinsic::ArgAbiExt;
+use crate::type_of::LayoutGccExt;
+
+impl<'a, 'gcc, 'tcx> AbiBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn apply_attrs_callsite(&mut self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _callsite: Self::Value) {
+        // TODO(antoyo)
+    }
+
+    fn get_param(&self, index: usize) -> Self::Value {
+        self.cx.current_func.borrow().expect("current func")
+            .get_param(index as i32)
+            .to_rvalue()
+    }
+}
+
+impl GccType for CastTarget {
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
+        let rest_gcc_unit = self.rest.unit.gcc_type(cx);
+        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
+            if self.rest.total <= self.rest.unit.size {
+                return rest_gcc_unit;
+            }
+
+            // Simplify to array when all chunks are the same size and type
+            if rem_bytes == 0 {
+                return cx.type_array(rest_gcc_unit, rest_count);
+            }
+        }
+
+        // Create list of fields in the main structure
+        let mut args: Vec<_> = self
+            .prefix
+            .iter()
+            .flat_map(|option_kind| {
+                option_kind.map(|kind| Reg { kind, size: self.prefix_chunk_size }.gcc_type(cx))
+            })
+            .chain((0..rest_count).map(|_| rest_gcc_unit))
+            .collect();
+
+        // Append final integer
+        if rem_bytes != 0 {
+            // Only integers can be really split further.
+            assert_eq!(self.rest.unit.kind, RegKind::Integer);
+            args.push(cx.type_ix(rem_bytes * 8));
+        }
+
+        cx.type_struct(&args, false)
+    }
+}
+
+pub trait GccType {
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc>;
+}
+
+impl GccType for Reg {
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, '_>) -> Type<'gcc> {
+        match self.kind {
+            RegKind::Integer => cx.type_ix(self.size.bits()),
+            RegKind::Float => {
+                match self.size.bits() {
+                    32 => cx.type_f32(),
+                    64 => cx.type_f64(),
+                    _ => bug!("unsupported float: {:?}", self),
+                }
+            },
+            RegKind::Vector => unimplemented!(), //cx.type_vector(cx.type_i8(), self.size.bytes()),
+        }
+    }
+}
+
+pub trait FnAbiGccExt<'gcc, 'tcx> {
+    // TODO(antoyo): return a function pointer type instead?
+    fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool);
+    fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+}
+
+impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
+    fn gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> (Type<'gcc>, Vec<Type<'gcc>>, bool) {
+        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 argument_tys = Vec::with_capacity(
+            if let PassMode::Indirect { .. } = self.ret.mode {
+                1
+            }
+            else {
+                0
+            } + args_capacity,
+        );
+
+        let return_ty =
+            match self.ret.mode {
+                PassMode::Ignore => cx.type_void(),
+                PassMode::Direct(_) | PassMode::Pair(..) => self.ret.layout.immediate_gcc_type(cx),
+                PassMode::Cast(cast) => cast.gcc_type(cx),
+                PassMode::Indirect { .. } => {
+                    argument_tys.push(cx.type_ptr_to(self.ret.memory_ty(cx)));
+                    cx.type_void()
+                }
+            };
+
+        for arg in &self.args {
+            // add padding
+            if let Some(ty) = arg.pad {
+                argument_tys.push(ty.gcc_type(cx));
+            }
+
+            let arg_ty = match arg.mode {
+                PassMode::Ignore => continue,
+                PassMode::Direct(_) => arg.layout.immediate_gcc_type(cx),
+                PassMode::Pair(..) => {
+                    argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 0, true));
+                    argument_tys.push(arg.layout.scalar_pair_element_gcc_type(cx, 1, true));
+                    continue;
+                }
+                PassMode::Indirect { extra_attrs: Some(_), .. } => {
+                    unimplemented!();
+                }
+                PassMode::Cast(cast) => cast.gcc_type(cx),
+                PassMode::Indirect { extra_attrs: None, .. } => cx.type_ptr_to(arg.memory_ty(cx)),
+            };
+            argument_tys.push(arg_ty);
+        }
+
+        (return_ty, argument_tys, self.c_variadic)
+    }
+
+    fn ptr_to_gcc_type(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        let (return_type, params, variadic) = self.gcc_type(cx);
+        let pointer_type = cx.context.new_function_pointer_type(None, return_type, &params, variadic);
+        pointer_type
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
new file mode 100644 (file)
index 0000000..6378a31
--- /dev/null
@@ -0,0 +1,116 @@
+use gccjit::{FunctionType, ToRValue};
+use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc_middle::bug;
+use rustc_middle::ty::TyCtxt;
+use rustc_span::symbol::sym;
+
+use crate::GccContext;
+
+pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+    let context = &mods.context;
+    let usize =
+        match tcx.sess.target.pointer_width {
+            16 => context.new_type::<u16>(),
+            32 => context.new_type::<u32>(),
+            64 => context.new_type::<u64>(),
+            tws => bug!("Unsupported target word size for int: {}", tws),
+        };
+    let i8 = context.new_type::<i8>();
+    let i8p = i8.make_pointer();
+    let void = context.new_type::<()>();
+
+    for method in ALLOCATOR_METHODS {
+        let mut types = Vec::with_capacity(method.inputs.len());
+        for ty in method.inputs.iter() {
+            match *ty {
+                AllocatorTy::Layout => {
+                    types.push(usize);
+                    types.push(usize);
+                }
+                AllocatorTy::Ptr => types.push(i8p),
+                AllocatorTy::Usize => types.push(usize),
+
+                AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
+            }
+        }
+        let output = match method.output {
+            AllocatorTy::ResultPtr => Some(i8p),
+            AllocatorTy::Unit => None,
+
+            AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
+                panic!("invalid allocator output")
+            }
+        };
+        let name = format!("__rust_{}", method.name);
+
+        let args: Vec<_> = types.iter().enumerate()
+            .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+            .collect();
+        let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
+
+        if tcx.sess.target.options.default_hidden_visibility {
+            // TODO(antoyo): set visibility.
+        }
+        if tcx.sess.must_emit_unwind_tables() {
+            // TODO(antoyo): emit unwind tables.
+        }
+
+        let callee = kind.fn_name(method.name);
+        let args: Vec<_> = types.iter().enumerate()
+            .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+            .collect();
+        let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
+        // TODO(antoyo): set visibility.
+
+        let block = func.new_block("entry");
+
+        let args = args
+            .iter()
+            .enumerate()
+            .map(|(i, _)| func.get_param(i as i32).to_rvalue())
+            .collect::<Vec<_>>();
+        let ret = context.new_call(None, callee, &args);
+        //llvm::LLVMSetTailCall(ret, True);
+        if output.is_some() {
+            block.end_with_return(None, ret);
+        }
+        else {
+            block.end_with_void_return(None);
+        }
+
+        // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
+        // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
+    }
+
+    let types = [usize, usize];
+    let name = "__rust_alloc_error_handler".to_string();
+    let args: Vec<_> = types.iter().enumerate()
+        .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+        .collect();
+    let func = context.new_function(None, FunctionType::Exported, void, &args, name, false);
+
+    let kind =
+        if has_alloc_error_handler {
+            AllocatorKind::Global
+        }
+        else {
+            AllocatorKind::Default
+        };
+    let callee = kind.fn_name(sym::oom);
+    let args: Vec<_> = types.iter().enumerate()
+        .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+        .collect();
+    let callee = context.new_function(None, FunctionType::Extern, void, &args, callee, false);
+    //llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+
+    let block = func.new_block("entry");
+
+    let args = args
+        .iter()
+        .enumerate()
+        .map(|(i, _)| func.get_param(i as i32).to_rvalue())
+        .collect::<Vec<_>>();
+    let _ret = context.new_call(None, callee, &args);
+    //llvm::LLVMSetTailCall(ret, True);
+    block.end_with_void_return(None);
+}
diff --git a/compiler/rustc_codegen_gcc/src/archive.rs b/compiler/rustc_codegen_gcc/src/archive.rs
new file mode 100644 (file)
index 0000000..d749d76
--- /dev/null
@@ -0,0 +1,218 @@
+use std::fs::File;
+use std::path::{Path, PathBuf};
+
+use rustc_session::Session;
+use rustc_codegen_ssa::back::archive::ArchiveBuilder;
+
+use rustc_data_structures::temp_dir::MaybeTempDir;
+use rustc_middle::middle::cstore::DllImport;
+
+
+struct ArchiveConfig<'a> {
+    sess: &'a Session,
+    dst: PathBuf,
+    use_native_ar: bool,
+    use_gnu_style_archive: bool,
+}
+
+#[derive(Debug)]
+enum ArchiveEntry {
+    FromArchive {
+        archive_index: usize,
+        entry_index: usize,
+    },
+    File(PathBuf),
+}
+
+pub struct ArArchiveBuilder<'a> {
+    config: ArchiveConfig<'a>,
+    src_archives: Vec<(PathBuf, ar::Archive<File>)>,
+    // Don't use `HashMap` here, as the order is important. `rust.metadata.bin` must always be at
+    // the end of an archive for linkers to not get confused.
+    entries: Vec<(String, ArchiveEntry)>,
+}
+
+impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> {
+    fn new(sess: &'a Session, output: &Path, input: Option<&Path>) -> Self {
+        let config = ArchiveConfig {
+            sess,
+            dst: output.to_path_buf(),
+            use_native_ar: false,
+            // FIXME test for linux and System V derivatives instead
+            use_gnu_style_archive: sess.target.options.archive_format == "gnu",
+        };
+
+        let (src_archives, entries) = if let Some(input) = input {
+            let mut archive = ar::Archive::new(File::open(input).unwrap());
+            let mut entries = Vec::new();
+
+            let mut i = 0;
+            while let Some(entry) = archive.next_entry() {
+                let entry = entry.unwrap();
+                entries.push((
+                    String::from_utf8(entry.header().identifier().to_vec()).unwrap(),
+                    ArchiveEntry::FromArchive {
+                        archive_index: 0,
+                        entry_index: i,
+                    },
+                ));
+                i += 1;
+            }
+
+            (vec![(input.to_owned(), archive)], entries)
+        } else {
+            (vec![], Vec::new())
+        };
+
+        ArArchiveBuilder {
+            config,
+            src_archives,
+            entries,
+        }
+    }
+
+    fn src_files(&mut self) -> Vec<String> {
+        self.entries.iter().map(|(name, _)| name.clone()).collect()
+    }
+
+    fn remove_file(&mut self, name: &str) {
+        let index = self
+            .entries
+            .iter()
+            .position(|(entry_name, _)| entry_name == name)
+            .expect("Tried to remove file not existing in src archive");
+        self.entries.remove(index);
+    }
+
+    fn add_file(&mut self, file: &Path) {
+        self.entries.push((
+            file.file_name().unwrap().to_str().unwrap().to_string(),
+            ArchiveEntry::File(file.to_owned()),
+        ));
+    }
+
+    fn add_archive<F>(&mut self, archive_path: &Path, mut skip: F) -> std::io::Result<()>
+    where
+        F: FnMut(&str) -> bool + 'static,
+    {
+        let mut archive = ar::Archive::new(std::fs::File::open(&archive_path)?);
+        let archive_index = self.src_archives.len();
+
+        let mut i = 0;
+        while let Some(entry) = archive.next_entry() {
+            let entry = entry?;
+            let file_name = String::from_utf8(entry.header().identifier().to_vec())
+                .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err))?;
+            if !skip(&file_name) {
+                self.entries
+                    .push((file_name, ArchiveEntry::FromArchive { archive_index, entry_index: i }));
+            }
+            i += 1;
+        }
+
+        self.src_archives.push((archive_path.to_owned(), archive));
+        Ok(())
+    }
+
+    fn update_symbols(&mut self) {
+    }
+
+    fn build(mut self) {
+        use std::process::Command;
+
+        fn add_file_using_ar(archive: &Path, file: &Path) {
+            Command::new("ar")
+                .arg("r") // add or replace file
+                .arg("-c") // silence created file message
+                .arg(archive)
+                .arg(&file)
+                .status()
+                .unwrap();
+        }
+
+        enum BuilderKind<'a> {
+            Bsd(ar::Builder<File>),
+            Gnu(ar::GnuBuilder<File>),
+            NativeAr(&'a Path),
+        }
+
+        let mut builder = if self.config.use_native_ar {
+            BuilderKind::NativeAr(&self.config.dst)
+        } else if self.config.use_gnu_style_archive {
+            BuilderKind::Gnu(ar::GnuBuilder::new(
+                File::create(&self.config.dst).unwrap(),
+                self.entries
+                    .iter()
+                    .map(|(name, _)| name.as_bytes().to_vec())
+                    .collect(),
+            ))
+        } else {
+            BuilderKind::Bsd(ar::Builder::new(File::create(&self.config.dst).unwrap()))
+        };
+
+        // Add all files
+        for (entry_name, entry) in self.entries.into_iter() {
+            match entry {
+                ArchiveEntry::FromArchive {
+                    archive_index,
+                    entry_index,
+                } => {
+                    let (ref src_archive_path, ref mut src_archive) =
+                        self.src_archives[archive_index];
+                    let entry = src_archive.jump_to_entry(entry_index).unwrap();
+                    let header = entry.header().clone();
+
+                    match builder {
+                        BuilderKind::Bsd(ref mut builder) => {
+                            builder.append(&header, entry).unwrap()
+                        }
+                        BuilderKind::Gnu(ref mut builder) => {
+                            builder.append(&header, entry).unwrap()
+                        }
+                        BuilderKind::NativeAr(archive_file) => {
+                            Command::new("ar")
+                                .arg("x")
+                                .arg(src_archive_path)
+                                .arg(&entry_name)
+                                .status()
+                                .unwrap();
+                            add_file_using_ar(archive_file, Path::new(&entry_name));
+                            std::fs::remove_file(entry_name).unwrap();
+                        }
+                    }
+                }
+                ArchiveEntry::File(file) =>
+                    match builder {
+                        BuilderKind::Bsd(ref mut builder) => {
+                            builder
+                                .append_file(entry_name.as_bytes(), &mut File::open(file).expect("file for bsd builder"))
+                                .unwrap()
+                        },
+                        BuilderKind::Gnu(ref mut builder) => {
+                            builder
+                                .append_file(entry_name.as_bytes(), &mut File::open(&file).expect(&format!("file {:?} for gnu builder", file)))
+                                .unwrap()
+                        },
+                        BuilderKind::NativeAr(archive_file) => add_file_using_ar(archive_file, &file),
+                    },
+            }
+        }
+
+        // Finalize archive
+        std::mem::drop(builder);
+
+        // Run ranlib to be able to link the archive
+        let status = std::process::Command::new("ranlib")
+            .arg(self.config.dst)
+            .status()
+            .expect("Couldn't run ranlib");
+
+        if !status.success() {
+            self.config.sess.fatal(&format!("Ranlib exited with code {:?}", status.code()));
+        }
+    }
+
+    fn inject_dll_import_lib(&mut self, _lib_name: &str, _dll_imports: &[DllImport], _tmpdir: &MaybeTempDir) {
+        unimplemented!();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
new file mode 100644 (file)
index 0000000..3b77097
--- /dev/null
@@ -0,0 +1,785 @@
+use gccjit::{LValue, RValue, ToRValue, Type};
+use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_codegen_ssa::mir::operand::OperandValue;
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
+
+use rustc_hir::LlvmInlineAsmInner;
+use rustc_middle::{bug, ty::Instance};
+use rustc_span::{Span, Symbol};
+use rustc_target::asm::*;
+
+use std::borrow::Cow;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+
+// Rust asm! and GCC Extended Asm semantics differ substantially.
+//
+// 1. Rust asm operands go along as one list of operands. Operands themselves indicate 
+//    if they're "in" or "out". "In" and "out" operands can interleave. One operand can be 
+//    both "in" and "out" (`inout(reg)`).
+//
+//    GCC asm has two different lists for "in" and "out" operands. In terms of gccjit, 
+//    this means that all "out" operands must go before "in" operands. "In" and "out" operands 
+//    cannot interleave.
+//
+// 2. Operand lists in both Rust and GCC are indexed. Index starts from 0. Indexes are important 
+//    because the asm template refers to operands by index.
+//
+//    Mapping from Rust to GCC index would be 1-1 if it wasn't for...
+//
+// 3. Clobbers. GCC has a separate list of clobbers, and clobbers don't have indexes. 
+//    Contrary, Rust expresses clobbers through "out" operands that aren't tied to 
+//    a variable (`_`),  and such "clobbers" do have index.
+//
+// 4. Furthermore, GCC Extended Asm does not support explicit register constraints 
+//    (like `out("eax")`) directly, offering so-called "local register variables" 
+//    as a workaround. These variables need to be declared and initialized *before* 
+//    the Extended Asm block but *after* normal local variables 
+//    (see comment in `codegen_inline_asm` for explanation).
+//
+// With that in mind, let's see how we translate Rust syntax to GCC 
+// (from now on, `CC` stands for "constraint code"):
+//
+// * `out(reg_class) var`   -> translated to output operand: `"=CC"(var)`
+// * `inout(reg_class) var` -> translated to output operand: `"+CC"(var)`
+// * `in(reg_class) var`    -> translated to input operand: `"CC"(var)`
+//
+// * `out(reg_class) _` -> translated to one `=r(tmp)`, where "tmp" is a temporary unused variable
+//
+// * `out("explicit register") _` -> not translated to any operands, register is simply added to clobbers list
+//
+// * `inout(reg_class) in_var => out_var` -> translated to two operands: 
+//                              output: `"=CC"(in_var)`
+//                              input:  `"num"(out_var)` where num is the GCC index 
+//                                       of the corresponding output operand
+//
+// * `inout(reg_class) in_var => _` -> same as `inout(reg_class) in_var => tmp`, 
+//                                      where "tmp" is a temporary unused variable
+//
+// * `out/in/inout("explicit register") var` -> translated to one or two operands as described above 
+//                                              with `"r"(var)` constraint, 
+//                                              and one register variable assigned to the desired register.
+// 
+
+const ATT_SYNTAX_INS: &str = ".att_syntax noprefix\n\t";
+const INTEL_SYNTAX_INS: &str = "\n\t.intel_syntax noprefix";
+
+
+struct AsmOutOperand<'a, 'tcx, 'gcc> {
+    rust_idx: usize,
+    constraint: &'a str,
+    late: bool,
+    readwrite: bool,
+
+    tmp_var: LValue<'gcc>,
+    out_place: Option<PlaceRef<'tcx, RValue<'gcc>>>
+}
+
+struct AsmInOperand<'a, 'tcx> {
+    rust_idx: usize,
+    constraint: Cow<'a, str>,
+    val: RValue<'tcx>
+}
+
+impl AsmOutOperand<'_, '_, '_> {
+    fn to_constraint(&self) -> String {
+        let mut res = String::with_capacity(self.constraint.len() + self.late as usize + 1);
+
+        let sign = if self.readwrite { '+' } else { '=' };
+        res.push(sign);
+        if !self.late {
+            res.push('&');
+        }
+
+        res.push_str(&self.constraint);
+        res
+    }
+}
+
+enum ConstraintOrRegister {
+    Constraint(&'static str),
+    Register(&'static str)
+}
+
+
+impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec<PlaceRef<'tcx, RValue<'gcc>>>, _inputs: Vec<RValue<'gcc>>, span: Span) -> bool {
+        self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`")
+            .help("consider using the `asm!` macro instead")
+            .emit();
+
+        // We return `true` even if we've failed to generate the asm
+        // because we want to suppress the "malformed inline assembly" error
+        // generated by the frontend.
+        true
+    }
+
+    fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, _span: &[Span]) {
+        let asm_arch = self.tcx.sess.asm_arch.unwrap();
+        let is_x86 = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64);
+        let att_dialect = is_x86 && options.contains(InlineAsmOptions::ATT_SYNTAX);
+        let intel_dialect = is_x86 && !options.contains(InlineAsmOptions::ATT_SYNTAX);
+
+        // GCC index of an output operand equals its position in the array 
+        let mut outputs = vec![];
+
+        // GCC index of an input operand equals its position in the array
+        // added to `outputs.len()`
+        let mut inputs = vec![];
+
+        // Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _`
+        let mut clobbers = vec![];
+
+        // We're trying to preallocate space for the template
+        let mut constants_len = 0;
+
+        // There are rules we must adhere to if we want GCC to do the right thing:
+        // 
+        // * Every local variable that the asm block uses as an output must be declared *before*
+        //   the asm block. 
+        // * There must be no instructions whatsoever between the register variables and the asm.
+        //
+        // Therefore, the backend must generate the instructions strictly in this order:
+        //
+        // 1. Output variables.
+        // 2. Register variables.
+        // 3. The asm block.
+        //
+        // We also must make sure that no input operands are emitted before output operands.
+        //
+        // This is why we work in passes, first emitting local vars, then local register vars.
+        // Also, we don't emit any asm operands immediately; we save them to 
+        // the one of the buffers to be emitted later.
+
+        // 1. Normal variables (and saving operands to buffers).
+        for (rust_idx, op) in rust_operands.iter().enumerate() {
+            match *op {
+                InlineAsmOperandRef::Out { reg, late, place } => {
+                    use ConstraintOrRegister::*;
+
+                    let (constraint, ty) = match (reg_to_gcc(reg), place) {
+                        (Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx, false)),
+                        // When `reg` is a class and not an explicit register but the out place is not specified,
+                        // we need to create an unused output variable to assign the output to. This var
+                        // needs to be of a type that's "compatible" with the register class, but specific type 
+                        // doesn't matter.
+                        (Constraint(constraint), None) => (constraint, dummy_output_type(self.cx, reg.reg_class())),
+                        (Register(_), Some(_)) => {
+                            // left for the next pass
+                            continue
+                        },
+                        (Register(reg_name), None) => {
+                            // `clobber_abi` can add lots of clobbers that are not supported by the target,
+                            // such as AVX-512 registers, so we just ignore unsupported registers
+                            let is_target_supported = reg.reg_class().supported_types(asm_arch).iter()
+                                .any(|&(_, feature)| {
+                                    if let Some(feature) = feature {
+                                        self.tcx.sess.target_features.contains(&Symbol::intern(feature))
+                                    } else {
+                                        true // Register class is unconditionally supported
+                                    }
+                                });
+
+                            if is_target_supported && !clobbers.contains(&reg_name) {
+                                clobbers.push(reg_name);
+                            }
+                            continue
+                        }
+                    };
+
+                    let tmp_var = self.current_func().new_local(None, ty, "output_register");
+                    outputs.push(AsmOutOperand {
+                        constraint, 
+                        rust_idx,
+                        late,
+                        readwrite: false,
+                        tmp_var,
+                        out_place: place
+                    });
+                }
+
+                InlineAsmOperandRef::In { reg, value } => {
+                    if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
+                        inputs.push(AsmInOperand { 
+                            constraint: Cow::Borrowed(constraint), 
+                            rust_idx, 
+                            val: value.immediate()
+                        });
+                    } 
+                    else {
+                        // left for the next pass
+                        continue
+                    }
+                }
+
+                InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
+                    let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
+                        constraint
+                    } 
+                    else {
+                        // left for the next pass
+                        continue
+                    };
+
+                    // Rustc frontend guarantees that input and output types are "compatible",
+                    // so we can just use input var's type for the output variable.
+                    //
+                    // This decision is also backed by the fact that LLVM needs in and out 
+                    // values to be of *exactly the same type*, not just "compatible". 
+                    // I'm not sure if GCC is so picky too, but better safe than sorry.
+                    let ty = in_value.layout.gcc_type(self.cx, false);
+                    let tmp_var = self.current_func().new_local(None, ty, "output_register");
+
+                    // If the out_place is None (i.e `inout(reg) _` syntax was used), we translate
+                    // it to one "readwrite (+) output variable", otherwise we translate it to two 
+                    // "out and tied in" vars as described above.
+                    let readwrite = out_place.is_none();
+                    outputs.push(AsmOutOperand {
+                        constraint, 
+                        rust_idx,
+                        late,
+                        readwrite,
+                        tmp_var, 
+                        out_place,
+                    });
+
+                    if !readwrite {
+                        let out_gcc_idx = outputs.len() - 1;
+                        let constraint = Cow::Owned(out_gcc_idx.to_string());
+
+                        inputs.push(AsmInOperand {
+                            constraint, 
+                            rust_idx, 
+                            val: in_value.immediate()
+                        });
+                    }
+                }
+
+                InlineAsmOperandRef::Const { ref string } => {
+                    constants_len += string.len() + att_dialect as usize;
+                }
+
+                InlineAsmOperandRef::SymFn { instance } => {
+                    constants_len += self.tcx.symbol_name(instance).name.len();
+                }
+                InlineAsmOperandRef::SymStatic { def_id } => {
+                    constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
+                }
+            }
+        }
+
+        // 2. Register variables.
+        for (rust_idx, op) in rust_operands.iter().enumerate() {
+            match *op {
+                // `out("explicit register") var`
+                InlineAsmOperandRef::Out { reg, late, place } => {
+                    if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+                        let out_place = if let Some(place) = place {
+                            place
+                        } 
+                        else {
+                            // processed in the previous pass
+                            continue
+                        };
+
+                        let ty = out_place.layout.gcc_type(self.cx, false);
+                        let tmp_var = self.current_func().new_local(None, ty, "output_register");
+                        tmp_var.set_register_name(reg_name);
+
+                        outputs.push(AsmOutOperand {
+                            constraint: "r".into(), 
+                            rust_idx,
+                            late,
+                            readwrite: false,
+                            tmp_var,
+                            out_place: Some(out_place)
+                        });
+                    }
+
+                    // processed in the previous pass
+                }
+
+                // `in("explicit register") var`
+                InlineAsmOperandRef::In { reg, value } => {
+                    if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+                        let ty = value.layout.gcc_type(self.cx, false);
+                        let reg_var = self.current_func().new_local(None, ty, "input_register");
+                        reg_var.set_register_name(reg_name);
+                        self.llbb().add_assignment(None, reg_var, value.immediate());
+
+                        inputs.push(AsmInOperand { 
+                            constraint: "r".into(), 
+                            rust_idx, 
+                            val: reg_var.to_rvalue()
+                        });
+                    }
+
+                    // processed in the previous pass
+                }
+
+                // `inout("explicit register") in_var => out_var`
+                InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
+                    if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
+                        let out_place = if let Some(place) = out_place {
+                            place
+                        } 
+                        else {
+                            // processed in the previous pass
+                            continue
+                        };
+
+                        // See explanation in the first pass.
+                        let ty = in_value.layout.gcc_type(self.cx, false);
+                        let tmp_var = self.current_func().new_local(None, ty, "output_register");
+                        tmp_var.set_register_name(reg_name);
+
+                        outputs.push(AsmOutOperand {
+                            constraint: "r".into(), 
+                            rust_idx,
+                            late,
+                            readwrite: false,
+                            tmp_var,
+                            out_place: Some(out_place)
+                        });
+
+                        let constraint = Cow::Owned((outputs.len() - 1).to_string());
+                        inputs.push(AsmInOperand { 
+                            constraint, 
+                            rust_idx,
+                            val: in_value.immediate()
+                        });
+                    }
+
+                    // processed in the previous pass
+                }
+
+                InlineAsmOperandRef::Const { .. } 
+                | InlineAsmOperandRef::SymFn { .. } 
+                | InlineAsmOperandRef::SymStatic { .. } => {
+                    // processed in the previous pass
+                }
+            }
+        }
+
+        // 3. Build the template string
+
+        let mut template_str = String::with_capacity(estimate_template_length(template, constants_len, att_dialect));
+        if !intel_dialect {
+            template_str.push_str(ATT_SYNTAX_INS);
+        }
+
+        for piece in template {
+            match *piece {
+                InlineAsmTemplatePiece::String(ref string) => {
+                    // TODO(@Commeownist): switch to `Iterator::intersperse` once it's stable
+                    let mut iter = string.split('%');
+                    if let Some(s) = iter.next() {
+                        template_str.push_str(s);
+                    }
+
+                    for s in iter {
+                        template_str.push_str("%%");
+                        template_str.push_str(s);
+                    }
+                }
+                InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => {
+                    let mut push_to_template = |modifier, gcc_idx| {
+                        use std::fmt::Write;
+
+                        template_str.push('%');
+                        if let Some(modifier) = modifier {
+                            template_str.push(modifier);
+                        }
+                        write!(template_str, "{}", gcc_idx).expect("pushing to string failed");
+                    };
+
+                    match rust_operands[operand_idx] {
+                        InlineAsmOperandRef::Out { reg, ..  } => {
+                            let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+                            let gcc_index = outputs.iter()
+                                .position(|op| operand_idx == op.rust_idx)
+                                .expect("wrong rust index");
+                            push_to_template(modifier, gcc_index);
+                        }
+
+                        InlineAsmOperandRef::In { reg, .. } => {
+                            let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+                            let in_gcc_index = inputs.iter()
+                                .position(|op| operand_idx == op.rust_idx)
+                                .expect("wrong rust index");
+                            let gcc_index = in_gcc_index + outputs.len();
+                            push_to_template(modifier, gcc_index);
+                        }
+
+                        InlineAsmOperandRef::InOut { reg, .. } => {
+                            let modifier = modifier_to_gcc(asm_arch, reg.reg_class(), modifier);
+
+                            // The input register is tied to the output, so we can just use the index of the output register
+                            let gcc_index = outputs.iter()
+                                .position(|op| operand_idx == op.rust_idx)
+                                .expect("wrong rust index");
+                            push_to_template(modifier, gcc_index);
+                        }
+
+                        InlineAsmOperandRef::SymFn { instance } => {
+                            let name = self.tcx.symbol_name(instance).name;
+                            template_str.push_str(name);
+                        }
+
+                        InlineAsmOperandRef::SymStatic { def_id } => {
+                            // TODO(@Commeownist): This may not be sufficient for all kinds of statics.
+                            // Some statics may need the `@plt` suffix, like thread-local vars.
+                            let instance = Instance::mono(self.tcx, def_id);
+                            let name = self.tcx.symbol_name(instance).name;
+                            template_str.push_str(name);
+                        }
+
+                        InlineAsmOperandRef::Const { ref string } => {
+                            // Const operands get injected directly into the template
+                            if att_dialect {
+                                template_str.push('$');
+                            }
+                            template_str.push_str(string);
+                        }
+                    }
+                }
+            }
+        }
+
+        if !intel_dialect {
+            template_str.push_str(INTEL_SYNTAX_INS);
+        }
+        
+        // 4. Generate Extended Asm block
+
+        let block = self.llbb();
+        let extended_asm = block.add_extended_asm(None, &template_str);
+
+        for op in &outputs {
+            extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var);
+        }
+
+        for op in &inputs {
+            extended_asm.add_input_operand(None, &op.constraint, op.val);
+        }
+
+        for clobber in clobbers.iter() {
+            extended_asm.add_clobber(clobber);
+        }
+
+        if !options.contains(InlineAsmOptions::PRESERVES_FLAGS) {
+            // TODO(@Commeownist): I'm not 100% sure this one clobber is sufficient 
+            // on all architectures. For instance, what about FP stack?
+            extended_asm.add_clobber("cc");
+        }
+        if !options.contains(InlineAsmOptions::NOMEM) {
+            extended_asm.add_clobber("memory");
+        }
+        if !options.contains(InlineAsmOptions::PURE) {
+            extended_asm.set_volatile_flag(true);
+        }
+        if !options.contains(InlineAsmOptions::NOSTACK) {
+            // TODO(@Commeownist): figure out how to align stack
+        }
+        if options.contains(InlineAsmOptions::NORETURN) {
+            let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
+            let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
+            self.call(self.type_void(), builtin_unreachable, &[], None);
+        }
+
+        // Write results to outputs. 
+        //
+        // We need to do this because:
+        //  1. Turning `PlaceRef` into `RValue` is error-prone and has nasty edge cases 
+        //     (especially with current `rustc_backend_ssa` API).
+        //  2. Not every output operand has an `out_place`, and it's required by `add_output_operand`.
+        //
+        // Instead, we generate a temporary output variable for each output operand, and then this loop,
+        // generates `out_place = tmp_var;` assignments if out_place exists.
+        for op in &outputs {
+            if let Some(place) = op.out_place {
+                OperandValue::Immediate(op.tmp_var.to_rvalue()).store(self, place);                
+            }
+        }
+
+    }
+}
+
+fn estimate_template_length(template: &[InlineAsmTemplatePiece], constants_len: usize, att_dialect: bool) -> usize {
+    let len: usize = template.iter().map(|piece| {
+        match *piece {
+            InlineAsmTemplatePiece::String(ref string) => {
+                string.len()
+            }
+            InlineAsmTemplatePiece::Placeholder { .. } => {
+                // '%' + 1 char modifier + 1 char index
+                3
+            }
+        }
+    })
+    .sum();
+
+    // increase it by 5% to account for possible '%' signs that'll be duplicated
+    // I pulled the number out of blue, but should be fair enough
+    // as the upper bound
+    let mut res = (len as f32 * 1.05) as usize + constants_len;
+
+    if att_dialect {
+        res += INTEL_SYNTAX_INS.len() + ATT_SYNTAX_INS.len();
+    }
+    res
+}
+
+/// Converts a register class to a GCC constraint code.
+fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
+    let constraint = match reg {
+        // For vector registers LLVM wants the register name to match the type size.
+        InlineAsmRegOrRegClass::Reg(reg) => {
+            match reg {
+                InlineAsmReg::X86(_) => {
+                    // TODO(antoyo): add support for vector register.
+                    //
+                    // // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
+                    return ConstraintOrRegister::Register(match reg.name() {
+                        // Some of registers' names does not map 1-1 from rust to gcc
+                        "st(0)" => "st",
+
+                        name => name,
+                    });
+                }
+
+                _ => unimplemented!(),
+            }
+        },
+        InlineAsmRegOrRegClass::RegClass(reg) => match reg {
+            InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(),
+            InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(),
+            InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => unimplemented!(),
+            InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+            | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => unimplemented!(),
+            InlineAsmRegClass::Bpf(_) => unimplemented!(),
+            InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(),
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(),
+            InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(),
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => unimplemented!(),
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+            | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+                unreachable!("clobber-only")
+            },
+            InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(),
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
+            | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
+            InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => unimplemented!(),
+            InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
+            InlineAsmRegClass::X86(
+                X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg,
+            ) => unreachable!("clobber-only"),
+            InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+                bug!("GCC backend does not support SPIR-V")
+            }
+            InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(),
+            InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(),
+            InlineAsmRegClass::Err => unreachable!(),
+        }
+    };
+
+    ConstraintOrRegister::Constraint(constraint)
+}
+
+/// Type to use for outputs that are discarded. It doesn't really matter what
+/// the type is, as long as it is valid for the constraint code.
+fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegClass) -> Type<'gcc> {
+    match reg {
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(),
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
+        | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
+            unimplemented!()
+        }
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => cx.type_i32(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => cx.type_f32(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => cx.type_f64(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
+            unimplemented!()
+        }
+        InlineAsmRegClass::Bpf(_) => unimplemented!(),
+        InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(),
+        InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => cx.type_i32(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
+        | InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
+            unreachable!("clobber-only")
+        },
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(),
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => cx.type_f32(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
+        | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::mmx_reg) => unimplemented!(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
+        | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg)
+        | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg) => unimplemented!(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => cx.type_i16(),
+        InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(),
+        InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+            bug!("LLVM backend does not support SPIR-V")
+        },
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => cx.type_i32(),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => cx.type_f64(),
+        InlineAsmRegClass::Err => unreachable!(),
+    }
+}
+
+impl<'gcc, 'tcx> AsmMethods for CodegenCx<'gcc, 'tcx> {
+    fn codegen_global_asm(&self, template: &[InlineAsmTemplatePiece], operands: &[GlobalAsmOperandRef], options: InlineAsmOptions, _line_spans: &[Span]) {
+        let asm_arch = self.tcx.sess.asm_arch.unwrap();
+
+        // Default to Intel syntax on x86
+        let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64)
+            && !options.contains(InlineAsmOptions::ATT_SYNTAX);
+
+        // Build the template string
+        let mut template_str = String::new();
+        for piece in template {
+            match *piece {
+                InlineAsmTemplatePiece::String(ref string) => {
+                    for line in string.lines() {
+                        // NOTE: gcc does not allow inline comment, so remove them.
+                        let line =
+                            if let Some(index) = line.rfind("//") {
+                                &line[..index]
+                            }
+                            else {
+                                line
+                            };
+                        template_str.push_str(line);
+                        template_str.push('\n');
+                    }
+                },
+                InlineAsmTemplatePiece::Placeholder { operand_idx, modifier: _, span: _ } => {
+                    match operands[operand_idx] {
+                        GlobalAsmOperandRef::Const { ref string } => {
+                            // Const operands get injected directly into the
+                            // template. Note that we don't need to escape %
+                            // here unlike normal inline assembly.
+                            template_str.push_str(string);
+                        }
+                    }
+                }
+            }
+        }
+
+        let template_str =
+            if intel_syntax {
+                format!("{}\n\t.intel_syntax noprefix", template_str)
+            }
+            else {
+                format!(".att_syntax\n\t{}\n\t.intel_syntax noprefix", template_str)
+            };
+        // NOTE: seems like gcc will put the asm in the wrong section, so set it to .text manually.
+        let template_str = format!(".pushsection .text\n{}\n.popsection", template_str);
+        self.context.add_top_level_asm(None, &template_str);
+    }
+}
+
+fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option<char>) -> Option<char> {
+    match reg {
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => modifier,
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => modifier,
+        InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg)
+        | InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => {
+            unimplemented!()
+        }
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg_thumb) => unimplemented!(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16) => unimplemented!(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8) => unimplemented!(),
+        InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
+        | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => {
+            unimplemented!()
+        }
+        InlineAsmRegClass::Bpf(_) => unimplemented!(),
+        InlineAsmRegClass::Hexagon(_) => unimplemented!(),
+        InlineAsmRegClass::Mips(_) => unimplemented!(),
+        InlineAsmRegClass::Nvptx(_) => unimplemented!(),
+        InlineAsmRegClass::PowerPC(_) => unimplemented!(),
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg)
+        | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(),
+        InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(),
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg)
+        | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => match modifier {
+            None => if arch == InlineAsmArch::X86_64 { Some('q') } else { Some('k') },
+            Some('l') => Some('b'),
+            Some('h') => Some('h'),
+            Some('x') => Some('w'),
+            Some('e') => Some('k'),
+            Some('r') => Some('q'),
+            _ => unreachable!(),
+        },
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => None,
+        InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::xmm_reg)
+        | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::ymm_reg)
+        | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) {
+            (X86InlineAsmRegClass::xmm_reg, None) => Some('x'),
+            (X86InlineAsmRegClass::ymm_reg, None) => Some('t'),
+            (X86InlineAsmRegClass::zmm_reg, None) => Some('g'),
+            (_, Some('x')) => Some('x'),
+            (_, Some('y')) => Some('t'),
+            (_, Some('z')) => Some('g'),
+            _ => unreachable!(),
+        },
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => None,
+        InlineAsmRegClass::X86(X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg) => {
+            unreachable!("clobber-only")
+        }
+        InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
+        InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
+            bug!("LLVM backend does not support SPIR-V")
+        },
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(),
+        InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(),
+        InlineAsmRegClass::Err => unreachable!(),
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/back/mod.rs b/compiler/rustc_codegen_gcc/src/back/mod.rs
new file mode 100644 (file)
index 0000000..d692799
--- /dev/null
@@ -0,0 +1 @@
+pub mod write;
diff --git a/compiler/rustc_codegen_gcc/src/back/write.rs b/compiler/rustc_codegen_gcc/src/back/write.rs
new file mode 100644 (file)
index 0000000..c3e3847
--- /dev/null
@@ -0,0 +1,78 @@
+use std::fs;
+
+use gccjit::OutputKind;
+use rustc_codegen_ssa::{CompiledModule, ModuleCodegen};
+use rustc_codegen_ssa::back::write::{CodegenContext, EmitObj, ModuleConfig};
+use rustc_errors::Handler;
+use rustc_session::config::OutputType;
+use rustc_span::fatal_error::FatalError;
+use rustc_target::spec::SplitDebuginfo;
+
+use crate::{GccCodegenBackend, GccContext};
+
+pub(crate) unsafe fn codegen(cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, module: ModuleCodegen<GccContext>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+    let _timer = cgcx.prof.generic_activity_with_arg("LLVM_module_codegen", &module.name[..]);
+    {
+        let context = &module.module_llvm.context;
+
+        let module_name = module.name.clone();
+        let module_name = Some(&module_name[..]);
+
+        let _bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
+        let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, module_name);
+
+        if config.bitcode_needed() {
+            // TODO(antoyo)
+        }
+
+        if config.emit_ir {
+            unimplemented!();
+        }
+
+        if config.emit_asm {
+            let _timer = cgcx
+                .prof
+                .generic_activity_with_arg("LLVM_module_codegen_emit_asm", &module.name[..]);
+            let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
+            context.compile_to_file(OutputKind::Assembler, path.to_str().expect("path to str"));
+        }
+
+        match config.emit_obj {
+            EmitObj::ObjectCode(_) => {
+                let _timer = cgcx
+                    .prof
+                    .generic_activity_with_arg("LLVM_module_codegen_emit_obj", &module.name[..]);
+                match &*module.name {
+                    "std_example.7rcbfp3g-cgu.15" => {
+                        println!("Dumping reproducer {}", module.name);
+                        let _ = fs::create_dir("/tmp/reproducers");
+                        // FIXME(antoyo): segfault in dump_reproducer_to_file() might be caused by
+                        // transmuting an rvalue to an lvalue.
+                        // Segfault is actually in gcc::jit::reproducer::get_identifier_as_lvalue
+                        context.dump_reproducer_to_file(&format!("/tmp/reproducers/{}.c", module.name));
+                        println!("Dumped reproducer {}", module.name);
+                    },
+                    _ => (),
+                }
+                context.compile_to_file(OutputKind::ObjectFile, obj_out.to_str().expect("path to str"));
+            }
+
+            EmitObj::Bitcode => {
+                // TODO(antoyo)
+            }
+
+            EmitObj::None => {}
+        }
+    }
+
+    Ok(module.into_compiled_module(
+        config.emit_obj != EmitObj::None,
+        cgcx.target_can_use_split_dwarf && cgcx.split_debuginfo == SplitDebuginfo::Unpacked,
+        config.emit_bc,
+        &cgcx.output_filenames,
+    ))
+}
+
+pub(crate) fn link(_cgcx: &CodegenContext<GccCodegenBackend>, _diag_handler: &Handler, mut _modules: Vec<ModuleCodegen<GccContext>>) -> Result<ModuleCodegen<GccContext>, FatalError> {
+    unimplemented!();
+}
diff --git a/compiler/rustc_codegen_gcc/src/base.rs b/compiler/rustc_codegen_gcc/src/base.rs
new file mode 100644 (file)
index 0000000..9fd0436
--- /dev/null
@@ -0,0 +1,165 @@
+use std::env;
+use std::time::Instant;
+
+use gccjit::{
+    Context,
+    FunctionType,
+    GlobalKind,
+};
+use rustc_middle::dep_graph;
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::middle::exported_symbols;
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::mir::mono::Linkage;
+use rustc_codegen_ssa::{ModuleCodegen, ModuleKind};
+use rustc_codegen_ssa::base::maybe_create_entry_wrapper;
+use rustc_codegen_ssa::mono_item::MonoItemExt;
+use rustc_codegen_ssa::traits::DebugInfoMethods;
+use rustc_session::config::DebugInfo;
+use rustc_span::Symbol;
+
+use crate::GccContext;
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+pub fn global_linkage_to_gcc(linkage: Linkage) -> GlobalKind {
+    match linkage {
+        Linkage::External => GlobalKind::Imported,
+        Linkage::AvailableExternally => GlobalKind::Imported,
+        Linkage::LinkOnceAny => unimplemented!(),
+        Linkage::LinkOnceODR => unimplemented!(),
+        Linkage::WeakAny => unimplemented!(),
+        Linkage::WeakODR => unimplemented!(),
+        Linkage::Appending => unimplemented!(),
+        Linkage::Internal => GlobalKind::Internal,
+        Linkage::Private => GlobalKind::Internal,
+        Linkage::ExternalWeak => GlobalKind::Imported, // TODO(antoyo): should be weak linkage.
+        Linkage::Common => unimplemented!(),
+    }
+}
+
+pub fn linkage_to_gcc(linkage: Linkage) -> FunctionType {
+    match linkage {
+        Linkage::External => FunctionType::Exported,
+        Linkage::AvailableExternally => FunctionType::Extern,
+        Linkage::LinkOnceAny => unimplemented!(),
+        Linkage::LinkOnceODR => unimplemented!(),
+        Linkage::WeakAny => FunctionType::Exported, // FIXME(antoyo): should be similar to linkonce.
+        Linkage::WeakODR => unimplemented!(),
+        Linkage::Appending => unimplemented!(),
+        Linkage::Internal => FunctionType::Internal,
+        Linkage::Private => FunctionType::Internal,
+        Linkage::ExternalWeak => unimplemented!(),
+        Linkage::Common => unimplemented!(),
+    }
+}
+
+pub fn compile_codegen_unit<'tcx>(tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<GccContext>, u64) {
+    let prof_timer = tcx.prof.generic_activity("codegen_module");
+    let start_time = Instant::now();
+
+    let dep_node = tcx.codegen_unit(cgu_name).codegen_dep_node(tcx);
+    let (module, _) = tcx.dep_graph.with_task(dep_node, tcx, cgu_name, module_codegen, dep_graph::hash_result);
+    let time_to_codegen = start_time.elapsed();
+    drop(prof_timer);
+
+    // We assume that the cost to run GCC on a CGU is proportional to
+    // 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;
+
+    fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen<GccContext> {
+        let cgu = tcx.codegen_unit(cgu_name);
+        // Instantiate monomorphizations without filling out definitions yet...
+        //let llvm_module = ModuleLlvm::new(tcx, &cgu_name.as_str());
+        let context = Context::default();
+        // TODO(antoyo): only set on x86 platforms.
+        context.add_command_line_option("-masm=intel");
+        for arg in &tcx.sess.opts.cg.llvm_args {
+            context.add_command_line_option(arg);
+        }
+        context.add_command_line_option("-fno-semantic-interposition");
+        if env::var("CG_GCCJIT_DUMP_CODE").as_deref() == Ok("1") {
+            context.set_dump_code_on_compile(true);
+        }
+        if env::var("CG_GCCJIT_DUMP_GIMPLE").as_deref() == Ok("1") {
+            context.set_dump_initial_gimple(true);
+        }
+        context.set_debug_info(true);
+        if env::var("CG_GCCJIT_DUMP_EVERYTHING").as_deref() == Ok("1") {
+            context.set_dump_everything(true);
+        }
+        if env::var("CG_GCCJIT_KEEP_INTERMEDIATES").as_deref() == Ok("1") {
+            context.set_keep_intermediates(true);
+        }
+
+        {
+            let cx = CodegenCx::new(&context, cgu, tcx);
+
+            let mono_items = cgu.items_in_deterministic_order(tcx);
+            for &(mono_item, (linkage, visibility)) in &mono_items {
+                mono_item.predefine::<Builder<'_, '_, '_>>(&cx, linkage, visibility);
+            }
+
+            // ... and now that we have everything pre-defined, fill out those definitions.
+            for &(mono_item, _) in &mono_items {
+                mono_item.define::<Builder<'_, '_, '_>>(&cx);
+            }
+
+            // If this codegen unit contains the main function, also create the
+            // wrapper here
+            maybe_create_entry_wrapper::<Builder<'_, '_, '_>>(&cx);
+
+            // Finalize debuginfo
+            if cx.sess().opts.debuginfo != DebugInfo::None {
+                cx.debuginfo_finalize();
+            }
+        }
+
+        ModuleCodegen {
+            name: cgu_name.to_string(),
+            module_llvm: GccContext {
+                context
+            },
+            kind: ModuleKind::Regular,
+        }
+    }
+
+    (module, cost)
+}
+
+pub fn write_compressed_metadata<'tcx>(tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut GccContext) {
+    use snap::write::FrameEncoder;
+    use std::io::Write;
+
+    // Historical note:
+    //
+    // When using link.exe it was seen that the section name `.note.rustc`
+    // was getting shortened to `.note.ru`, and according to the PE and COFF
+    // specification:
+    //
+    // > Executable images do not use a string table and do not support
+    // > section names longer than 8 characters
+    //
+    // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+    //
+    // As a result, we choose a slightly shorter name! As to why
+    // `.note.rustc` works on MinGW, see
+    // https://github.com/llvm/llvm-project/blob/llvmorg-12.0.0/lld/COFF/Writer.cpp#L1190-L1197
+    let section_name = if tcx.sess.target.is_like_osx { "__DATA,.rustc" } else { ".rustc" };
+
+    let context = &gcc_module.context;
+    let mut compressed = rustc_metadata::METADATA_HEADER.to_vec();
+    FrameEncoder::new(&mut compressed).write_all(&metadata.raw_data).unwrap();
+
+    let name = exported_symbols::metadata_symbol_name(tcx);
+    let typ = context.new_array_type(None, context.new_type::<u8>(), compressed.len() as i32);
+    let global = context.new_global(None, GlobalKind::Exported, typ, name);
+    global.global_set_initializer(&compressed);
+    global.set_link_section(section_name);
+
+    // Also generate a .section directive to force no
+    // flags, at least for ELF outputs, so that the
+    // metadata doesn't get loaded into memory.
+    let directive = format!(".section {}", section_name);
+    context.add_top_level_asm(None, &directive);
+}
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
new file mode 100644 (file)
index 0000000..ac90841
--- /dev/null
@@ -0,0 +1,1540 @@
+use std::borrow::Cow;
+use std::cell::Cell;
+use std::convert::TryFrom;
+use std::ops::Deref;
+
+use gccjit::FunctionType;
+use gccjit::{
+    BinaryOp,
+    Block,
+    ComparisonOp,
+    Function,
+    LValue,
+    RValue,
+    ToRValue,
+    Type,
+    UnaryOp,
+};
+use rustc_codegen_ssa::MemFlags;
+use rustc_codegen_ssa::common::{AtomicOrdering, AtomicRmwBinOp, IntPredicate, RealPredicate, SynchronizationScope};
+use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{
+    BackendTypes,
+    BaseTypeMethods,
+    BuilderMethods,
+    ConstMethods,
+    DerivedTypeMethods,
+    LayoutTypeMethods,
+    HasCodegen,
+    OverflowOp,
+    StaticBuilderMethods,
+};
+use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
+use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
+use rustc_span::Span;
+use rustc_span::def_id::DefId;
+use rustc_target::abi::{
+    self,
+    call::FnAbi,
+    Align,
+    HasDataLayout,
+    Size,
+    TargetDataLayout,
+    WrappingRange,
+};
+use rustc_target::spec::{HasTargetSpec, Target};
+
+use crate::common::{SignType, TypeReflection, type_is_pointer};
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+// TODO(antoyo)
+type Funclet = ();
+
+// TODO(antoyo): remove this variable.
+static mut RETURN_VALUE_COUNT: usize = 0;
+
+enum ExtremumOperation {
+    Max,
+    Min,
+}
+
+trait EnumClone {
+    fn clone(&self) -> Self;
+}
+
+impl EnumClone for AtomicOrdering {
+    fn clone(&self) -> Self {
+        match *self {
+            AtomicOrdering::NotAtomic => AtomicOrdering::NotAtomic,
+            AtomicOrdering::Unordered => AtomicOrdering::Unordered,
+            AtomicOrdering::Monotonic => AtomicOrdering::Monotonic,
+            AtomicOrdering::Acquire => AtomicOrdering::Acquire,
+            AtomicOrdering::Release => AtomicOrdering::Release,
+            AtomicOrdering::AcquireRelease => AtomicOrdering::AcquireRelease,
+            AtomicOrdering::SequentiallyConsistent => AtomicOrdering::SequentiallyConsistent,
+        }
+    }
+}
+
+pub struct Builder<'a: 'gcc, 'gcc, 'tcx> {
+    pub cx: &'a CodegenCx<'gcc, 'tcx>,
+    pub block: Option<Block<'gcc>>,
+    stack_var_count: Cell<usize>,
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+    fn with_cx(cx: &'a CodegenCx<'gcc, 'tcx>) -> Self {
+        Builder {
+            cx,
+            block: None,
+            stack_var_count: Cell::new(0),
+        }
+    }
+
+    fn atomic_extremum(&mut self, operation: ExtremumOperation, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> {
+        let size = self.cx.int_width(src.get_type()) / 8;
+
+        let func = self.current_func();
+
+        let load_ordering =
+            match order {
+                // TODO(antoyo): does this make sense?
+                AtomicOrdering::AcquireRelease | AtomicOrdering::Release => AtomicOrdering::Acquire,
+                _ => order.clone(),
+            };
+        let previous_value = self.atomic_load(dst.get_type(), dst, load_ordering.clone(), Size::from_bytes(size));
+        let previous_var = func.new_local(None, previous_value.get_type(), "previous_value");
+        let return_value = func.new_local(None, previous_value.get_type(), "return_value");
+        self.llbb().add_assignment(None, previous_var, previous_value);
+        self.llbb().add_assignment(None, return_value, previous_var.to_rvalue());
+
+        let while_block = func.new_block("while");
+        let after_block = func.new_block("after_while");
+        self.llbb().end_with_jump(None, while_block);
+
+        // NOTE: since jumps were added and compare_exchange doesn't expect this, the current blocks in the
+        // state need to be updated.
+        self.block = Some(while_block);
+        *self.cx.current_block.borrow_mut() = Some(while_block);
+
+        let comparison_operator =
+            match operation {
+                ExtremumOperation::Max => ComparisonOp::LessThan,
+                ExtremumOperation::Min => ComparisonOp::GreaterThan,
+            };
+
+        let cond1 = self.context.new_comparison(None, comparison_operator, previous_var.to_rvalue(), self.context.new_cast(None, src, previous_value.get_type()));
+        let compare_exchange = self.compare_exchange(dst, previous_var, src, order, load_ordering, false);
+        let cond2 = self.cx.context.new_unary_op(None, UnaryOp::LogicalNegate, compare_exchange.get_type(), compare_exchange);
+        let cond = self.cx.context.new_binary_op(None, BinaryOp::LogicalAnd, self.cx.bool_type, cond1, cond2);
+
+        while_block.end_with_conditional(None, cond, while_block, after_block);
+
+        // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the
+        // state need to be updated.
+        self.block = Some(after_block);
+        *self.cx.current_block.borrow_mut() = Some(after_block);
+
+        return_value.to_rvalue()
+    }
+
+    fn compare_exchange(&self, dst: RValue<'gcc>, cmp: LValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
+        let size = self.cx.int_width(src.get_type());
+        let compare_exchange = self.context.get_builtin_function(&format!("__atomic_compare_exchange_{}", size / 8));
+        let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+        let failure_order = self.context.new_rvalue_from_int(self.i32_type, failure_order.to_gcc());
+        let weak = self.context.new_rvalue_from_int(self.bool_type, weak as i32);
+
+        let void_ptr_type = self.context.new_type::<*mut ()>();
+        let volatile_void_ptr_type = void_ptr_type.make_volatile();
+        let dst = self.context.new_cast(None, dst, volatile_void_ptr_type);
+        let expected = self.context.new_cast(None, cmp.get_address(None), void_ptr_type);
+
+        // NOTE: not sure why, but we have the wrong type here.
+        let int_type = compare_exchange.get_param(2).to_rvalue().get_type();
+        let src = self.context.new_cast(None, src, int_type);
+        self.context.new_call(None, compare_exchange, &[dst, expected, src, weak, order, failure_order])
+    }
+
+    pub fn assign(&self, lvalue: LValue<'gcc>, value: RValue<'gcc>) {
+        self.llbb().add_assignment(None, lvalue, value);
+    }
+
+    fn check_call<'b>(&mut self, _typ: &str, func: Function<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
+        let mut all_args_match = true;
+        let mut param_types = vec![];
+        let param_count = func.get_param_count();
+        for (index, arg) in args.iter().enumerate().take(param_count) {
+            let param = func.get_param(index as i32);
+            let param = param.to_rvalue().get_type();
+            if param != arg.get_type() {
+                all_args_match = false;
+            }
+            param_types.push(param);
+        }
+
+        if all_args_match {
+            return Cow::Borrowed(args);
+        }
+
+        let casted_args: Vec<_> = param_types
+            .into_iter()
+            .zip(args.iter())
+            .enumerate()
+            .map(|(_i, (expected_ty, &actual_val))| {
+                let actual_ty = actual_val.get_type();
+                if expected_ty != actual_ty {
+                    self.bitcast(actual_val, expected_ty)
+                }
+                else {
+                    actual_val
+                }
+            })
+            .collect();
+
+        Cow::Owned(casted_args)
+    }
+
+    fn check_ptr_call<'b>(&mut self, _typ: &str, func_ptr: RValue<'gcc>, args: &'b [RValue<'gcc>]) -> Cow<'b, [RValue<'gcc>]> {
+        let mut all_args_match = true;
+        let mut param_types = vec![];
+        let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+        for (index, arg) in args.iter().enumerate().take(gcc_func.get_param_count()) {
+            let param = gcc_func.get_param_type(index);
+            if param != arg.get_type() {
+                all_args_match = false;
+            }
+            param_types.push(param);
+        }
+
+        if all_args_match {
+            return Cow::Borrowed(args);
+        }
+
+        let casted_args: Vec<_> = param_types
+            .into_iter()
+            .zip(args.iter())
+            .enumerate()
+            .map(|(_i, (expected_ty, &actual_val))| {
+                let actual_ty = actual_val.get_type();
+                if expected_ty != actual_ty {
+                    self.bitcast(actual_val, expected_ty)
+                }
+                else {
+                    actual_val
+                }
+            })
+            .collect();
+
+        Cow::Owned(casted_args)
+    }
+
+    fn check_store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
+        let dest_ptr_ty = self.cx.val_ty(ptr).make_pointer(); // TODO(antoyo): make sure make_pointer() is okay here.
+        let stored_ty = self.cx.val_ty(val);
+        let stored_ptr_ty = self.cx.type_ptr_to(stored_ty);
+
+        if dest_ptr_ty == stored_ptr_ty {
+            ptr
+        }
+        else {
+            self.bitcast(ptr, stored_ptr_ty)
+        }
+    }
+
+    pub fn current_func(&self) -> Function<'gcc> {
+        self.block.expect("block").get_function()
+    }
+
+    fn function_call(&mut self, func: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        // TODO(antoyo): remove when the API supports a different type for functions.
+        let func: Function<'gcc> = self.cx.rvalue_as_function(func);
+        let args = self.check_call("call", func, args);
+
+        // gccjit requires to use the result of functions, even when it's not used.
+        // That's why we assign the result to a local or call add_eval().
+        let return_type = func.get_return_type();
+        let current_block = self.current_block.borrow().expect("block");
+        let void_type = self.context.new_type::<()>();
+        let current_func = current_block.get_function();
+        if return_type != void_type {
+            unsafe { RETURN_VALUE_COUNT += 1 };
+            let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+            current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args));
+            result.to_rvalue()
+        }
+        else {
+            current_block.add_eval(None, self.cx.context.new_call(None, func, &args));
+            // Return dummy value when not having return value.
+            self.context.new_rvalue_from_long(self.isize_type, 0)
+        }
+    }
+
+    fn function_ptr_call(&mut self, func_ptr: RValue<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        let args = self.check_ptr_call("call", func_ptr, args);
+
+        // gccjit requires to use the result of functions, even when it's not used.
+        // That's why we assign the result to a local or call add_eval().
+        let gcc_func = func_ptr.get_type().is_function_ptr_type().expect("function ptr");
+        let mut return_type = gcc_func.get_return_type();
+        let current_block = self.current_block.borrow().expect("block");
+        let void_type = self.context.new_type::<()>();
+        let current_func = current_block.get_function();
+
+        // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
+        if gcc_func.get_param_count() == 0 && format!("{:?}", func_ptr) == "__builtin_ia32_pmovmskb128" {
+            return_type = self.int_type;
+        }
+
+        if return_type != void_type {
+            unsafe { RETURN_VALUE_COUNT += 1 };
+            let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+            current_block.add_assignment(None, result, self.cx.context.new_call_through_ptr(None, func_ptr, &args));
+            result.to_rvalue()
+        }
+        else {
+            if gcc_func.get_param_count() == 0 {
+                // FIXME(antoyo): As a temporary workaround for unsupported LLVM intrinsics.
+                current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &[]));
+            }
+            else {
+                current_block.add_eval(None, self.cx.context.new_call_through_ptr(None, func_ptr, &args));
+            }
+            // Return dummy value when not having return value.
+            let result = current_func.new_local(None, self.isize_type, "dummyValueThatShouldNeverBeUsed");
+            current_block.add_assignment(None, result, self.context.new_rvalue_from_long(self.isize_type, 0));
+            result.to_rvalue()
+        }
+    }
+
+    pub fn overflow_call(&mut self, func: Function<'gcc>, args: &[RValue<'gcc>], _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        // gccjit requires to use the result of functions, even when it's not used.
+        // That's why we assign the result to a local.
+        let return_type = self.context.new_type::<bool>();
+        let current_block = self.current_block.borrow().expect("block");
+        let current_func = current_block.get_function();
+        // TODO(antoyo): return the new_call() directly? Since the overflow function has no side-effects.
+        unsafe { RETURN_VALUE_COUNT += 1 };
+        let result = current_func.new_local(None, return_type, &format!("returnValue{}", unsafe { RETURN_VALUE_COUNT }));
+        current_block.add_assignment(None, result, self.cx.context.new_call(None, func, &args));
+        result.to_rvalue()
+    }
+}
+
+impl<'gcc, 'tcx> HasCodegen<'tcx> for Builder<'_, 'gcc, 'tcx> {
+    type CodegenCx = CodegenCx<'gcc, 'tcx>;
+}
+
+impl<'tcx> HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.cx.tcx()
+    }
+}
+
+impl HasDataLayout for Builder<'_, '_, '_> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        self.cx.data_layout()
+    }
+}
+
+impl<'tcx> LayoutOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
+
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        self.cx.handle_layout_err(err, span, ty)
+    }
+}
+
+impl<'tcx> FnAbiOfHelpers<'tcx> for Builder<'_, '_, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        self.cx.handle_fn_abi_err(err, span, fn_abi_request)
+    }
+}
+
+impl<'gcc, 'tcx> Deref for Builder<'_, 'gcc, 'tcx> {
+    type Target = CodegenCx<'gcc, 'tcx>;
+
+    fn deref(&self) -> &Self::Target {
+        self.cx
+    }
+}
+
+impl<'gcc, 'tcx> BackendTypes for Builder<'_, 'gcc, 'tcx> {
+    type Value = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Value;
+    type Function = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Function;
+    type BasicBlock = <CodegenCx<'gcc, 'tcx> as BackendTypes>::BasicBlock;
+    type Type = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Type;
+    type Funclet = <CodegenCx<'gcc, 'tcx> as BackendTypes>::Funclet;
+
+    type DIScope = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DIScope;
+    type DILocation = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DILocation;
+    type DIVariable = <CodegenCx<'gcc, 'tcx> as BackendTypes>::DIVariable;
+}
+
+impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn build(cx: &'a CodegenCx<'gcc, 'tcx>, block: Block<'gcc>) -> Self {
+        let mut bx = Builder::with_cx(cx);
+        *cx.current_block.borrow_mut() = Some(block);
+        bx.block = Some(block);
+        bx
+    }
+
+    fn build_sibling_block(&mut self, name: &str) -> Self {
+        let block = self.append_sibling_block(name);
+        Self::build(self.cx, block)
+    }
+
+    fn llbb(&self) -> Block<'gcc> {
+        self.block.expect("block")
+    }
+
+    fn append_block(cx: &'a CodegenCx<'gcc, 'tcx>, func: RValue<'gcc>, name: &str) -> Block<'gcc> {
+        let func = cx.rvalue_as_function(func);
+        func.new_block(name)
+    }
+
+    fn append_sibling_block(&mut self, name: &str) -> Block<'gcc> {
+        let func = self.current_func();
+        func.new_block(name)
+    }
+
+    fn ret_void(&mut self) {
+        self.llbb().end_with_void_return(None)
+    }
+
+    fn ret(&mut self, value: RValue<'gcc>) {
+        let value =
+            if self.structs_as_pointer.borrow().contains(&value) {
+                // NOTE: hack to workaround a limitation of the rustc API: see comment on
+                // CodegenCx.structs_as_pointer
+                value.dereference(None).to_rvalue()
+            }
+            else {
+                value
+            };
+        self.llbb().end_with_return(None, value);
+    }
+
+    fn br(&mut self, dest: Block<'gcc>) {
+        self.llbb().end_with_jump(None, dest)
+    }
+
+    fn cond_br(&mut self, cond: RValue<'gcc>, then_block: Block<'gcc>, else_block: Block<'gcc>) {
+        self.llbb().end_with_conditional(None, cond, then_block, else_block)
+    }
+
+    fn switch(&mut self, value: RValue<'gcc>, default_block: Block<'gcc>, cases: impl ExactSizeIterator<Item = (u128, Block<'gcc>)>) {
+        let mut gcc_cases = vec![];
+        let typ = self.val_ty(value);
+        for (on_val, dest) in cases {
+            let on_val = self.const_uint_big(typ, on_val);
+            gcc_cases.push(self.context.new_case(on_val, on_val, dest));
+        }
+        self.block.expect("block").end_with_switch(None, value, default_block, &gcc_cases);
+    }
+
+    fn invoke(&mut self, _typ: Type<'gcc>, _func: RValue<'gcc>, _args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
+        let condition = self.context.new_rvalue_from_int(self.bool_type, 0);
+        self.llbb().end_with_conditional(None, condition, then, catch);
+        self.context.new_rvalue_from_int(self.int_type, 0)
+
+        // TODO(antoyo)
+    }
+
+    fn unreachable(&mut self) {
+        let func = self.context.get_builtin_function("__builtin_unreachable");
+        let block = self.block.expect("block");
+        block.add_eval(None, self.context.new_call(None, func, &[]));
+        let return_type = block.get_function().get_return_type();
+        let void_type = self.context.new_type::<()>();
+        if return_type == void_type {
+            block.end_with_void_return(None)
+        }
+        else {
+            let return_value = self.current_func()
+                .new_local(None, return_type, "unreachableReturn");
+            block.end_with_return(None, return_value)
+        }
+    }
+
+    fn add(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): this should not be required.
+        if format!("{:?}", a.get_type()) != format!("{:?}", b.get_type()) {
+            b = self.context.new_cast(None, b, a.get_type());
+        }
+        a + b
+    }
+
+    fn fadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a + b
+    }
+
+    fn sub(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+        if a.get_type() != b.get_type() {
+            b = self.context.new_cast(None, b, a.get_type());
+        }
+        a - b
+    }
+
+    fn fsub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a - b
+    }
+
+    fn mul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a * b
+    }
+
+    fn fmul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a * b
+    }
+
+    fn udiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): convert the arguments to unsigned?
+        a / b
+    }
+
+    fn exactudiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): convert the arguments to unsigned?
+        // TODO(antoyo): poison if not exact.
+        a / b
+    }
+
+    fn sdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): convert the arguments to signed?
+        a / b
+    }
+
+    fn exactsdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): posion if not exact.
+        // FIXME(antoyo): rustc_codegen_ssa::mir::intrinsic uses different types for a and b but they
+        // should be the same.
+        let typ = a.get_type().to_signed(self);
+        let b = self.context.new_cast(None, b, typ);
+        a / b
+    }
+
+    fn fdiv(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a / b
+    }
+
+    fn urem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a % b
+    }
+
+    fn srem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a % b
+    }
+
+    fn frem(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        if a.get_type() == self.cx.float_type {
+            let fmodf = self.context.get_builtin_function("fmodf");
+            // FIXME(antoyo): this seems to produce the wrong result.
+            return self.context.new_call(None, fmodf, &[a, b]);
+        }
+        assert_eq!(a.get_type(), self.cx.double_type);
+
+        let fmod = self.context.get_builtin_function("fmod");
+        return self.context.new_call(None, fmod, &[a, b]);
+    }
+
+    fn shl(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+        let a_type = a.get_type();
+        let b_type = b.get_type();
+        if a_type.is_unsigned(self) && b_type.is_signed(self) {
+            let a = self.context.new_cast(None, a, b_type);
+            let result = a << b;
+            self.context.new_cast(None, result, a_type)
+        }
+        else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+            let b = self.context.new_cast(None, b, a_type);
+            a << b
+        }
+        else {
+            a << b
+        }
+    }
+
+    fn lshr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+        // TODO(antoyo): cast to unsigned to do a logical shift if that does not work.
+        let a_type = a.get_type();
+        let b_type = b.get_type();
+        if a_type.is_unsigned(self) && b_type.is_signed(self) {
+            let a = self.context.new_cast(None, a, b_type);
+            let result = a >> b;
+            self.context.new_cast(None, result, a_type)
+        }
+        else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+            let b = self.context.new_cast(None, b, a_type);
+            a >> b
+        }
+        else {
+            a >> b
+        }
+    }
+
+    fn ashr(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): check whether behavior is an arithmetic shift for >> .
+        // FIXME(antoyo): remove the casts when libgccjit can shift an unsigned number by an unsigned number.
+        let a_type = a.get_type();
+        let b_type = b.get_type();
+        if a_type.is_unsigned(self) && b_type.is_signed(self) {
+            let a = self.context.new_cast(None, a, b_type);
+            let result = a >> b;
+            self.context.new_cast(None, result, a_type)
+        }
+        else if a_type.is_signed(self) && b_type.is_unsigned(self) {
+            let b = self.context.new_cast(None, b, a_type);
+            a >> b
+        }
+        else {
+            a >> b
+        }
+    }
+
+    fn and(&mut self, a: RValue<'gcc>, mut b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
+        // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
+        if a.get_type() != b.get_type() {
+            b = self.context.new_cast(None, b, a.get_type());
+        }
+        let res = self.current_func().new_local(None, b.get_type(), "andResult");
+        self.llbb().add_assignment(None, res, a & b);
+        res.to_rvalue()
+    }
+
+    fn or(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): hack by putting the result in a variable to workaround this bug:
+        // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=95498
+        let res = self.current_func().new_local(None, b.get_type(), "orResult");
+        self.llbb().add_assignment(None, res, a | b);
+        res.to_rvalue()
+    }
+
+    fn xor(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a ^ b
+    }
+
+    fn neg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use new_unary_op()?
+        self.cx.context.new_rvalue_from_long(a.get_type(), 0) - a
+    }
+
+    fn fneg(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+        self.cx.context.new_unary_op(None, UnaryOp::Minus, a.get_type(), a)
+    }
+
+    fn not(&mut self, a: RValue<'gcc>) -> RValue<'gcc> {
+        let operation =
+            if a.get_type().is_bool() {
+                UnaryOp::LogicalNegate
+            }
+            else {
+                UnaryOp::BitwiseNegate
+            };
+        self.cx.context.new_unary_op(None, operation, a.get_type(), a)
+    }
+
+    fn unchecked_sadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a + b
+    }
+
+    fn unchecked_uadd(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a + b
+    }
+
+    fn unchecked_ssub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a - b
+    }
+
+    fn unchecked_usub(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): should generate poison value?
+        a - b
+    }
+
+    fn unchecked_smul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a * b
+    }
+
+    fn unchecked_umul(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> {
+        a * b
+    }
+
+    fn fadd_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn fsub_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn fmul_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn fdiv_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn frem_fast(&mut self, _lhs: RValue<'gcc>, _rhs: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn checked_binop(&mut self, oop: OverflowOp, typ: Ty<'_>, lhs: Self::Value, rhs: Self::Value) -> (Self::Value, Self::Value) {
+        use rustc_middle::ty::{Int, IntTy::*, Uint, UintTy::*};
+
+        let new_kind =
+            match typ.kind() {
+                Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.pointer_width)),
+                Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.pointer_width)),
+                t @ (Uint(_) | Int(_)) => t.clone(),
+                _ => panic!("tried to get overflow intrinsic for op applied to non-int type"),
+            };
+
+        // TODO(antoyo): remove duplication with intrinsic?
+        let name =
+            match oop {
+                OverflowOp::Add =>
+                    match new_kind {
+                        Int(I8) => "__builtin_add_overflow",
+                        Int(I16) => "__builtin_add_overflow",
+                        Int(I32) => "__builtin_sadd_overflow",
+                        Int(I64) => "__builtin_saddll_overflow",
+                        Int(I128) => "__builtin_add_overflow",
+
+                        Uint(U8) => "__builtin_add_overflow",
+                        Uint(U16) => "__builtin_add_overflow",
+                        Uint(U32) => "__builtin_uadd_overflow",
+                        Uint(U64) => "__builtin_uaddll_overflow",
+                        Uint(U128) => "__builtin_add_overflow",
+
+                        _ => unreachable!(),
+                    },
+                OverflowOp::Sub =>
+                    match new_kind {
+                        Int(I8) => "__builtin_sub_overflow",
+                        Int(I16) => "__builtin_sub_overflow",
+                        Int(I32) => "__builtin_ssub_overflow",
+                        Int(I64) => "__builtin_ssubll_overflow",
+                        Int(I128) => "__builtin_sub_overflow",
+
+                        Uint(U8) => "__builtin_sub_overflow",
+                        Uint(U16) => "__builtin_sub_overflow",
+                        Uint(U32) => "__builtin_usub_overflow",
+                        Uint(U64) => "__builtin_usubll_overflow",
+                        Uint(U128) => "__builtin_sub_overflow",
+
+                        _ => unreachable!(),
+                    },
+                OverflowOp::Mul =>
+                    match new_kind {
+                        Int(I8) => "__builtin_mul_overflow",
+                        Int(I16) => "__builtin_mul_overflow",
+                        Int(I32) => "__builtin_smul_overflow",
+                        Int(I64) => "__builtin_smulll_overflow",
+                        Int(I128) => "__builtin_mul_overflow",
+
+                        Uint(U8) => "__builtin_mul_overflow",
+                        Uint(U16) => "__builtin_mul_overflow",
+                        Uint(U32) => "__builtin_umul_overflow",
+                        Uint(U64) => "__builtin_umulll_overflow",
+                        Uint(U128) => "__builtin_mul_overflow",
+
+                        _ => unreachable!(),
+                    },
+            };
+
+        let intrinsic = self.context.get_builtin_function(&name);
+        let res = self.current_func()
+            // TODO(antoyo): is it correct to use rhs type instead of the parameter typ?
+            .new_local(None, rhs.get_type(), "binopResult")
+            .get_address(None);
+        let overflow = self.overflow_call(intrinsic, &[lhs, rhs, res], None);
+        (res.dereference(None).to_rvalue(), overflow)
+    }
+
+    fn alloca(&mut self, ty: Type<'gcc>, align: Align) -> RValue<'gcc> {
+        // FIXME(antoyo): this check that we don't call get_aligned() a second time on a type.
+        // Ideally, we shouldn't need to do this check.
+        let aligned_type =
+            if ty == self.cx.u128_type || ty == self.cx.i128_type {
+                ty
+            }
+            else {
+                ty.get_aligned(align.bytes())
+            };
+        // TODO(antoyo): It might be better to return a LValue, but fixing the rustc API is non-trivial.
+        self.stack_var_count.set(self.stack_var_count.get() + 1);
+        self.current_func().new_local(None, aligned_type, &format!("stack_var_{}", self.stack_var_count.get())).get_address(None)
+    }
+
+    fn dynamic_alloca(&mut self, _ty: Type<'gcc>, _align: Align) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn array_alloca(&mut self, _ty: Type<'gcc>, _len: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, _align: Align) -> RValue<'gcc> {
+        // TODO(antoyo): use ty.
+        let block = self.llbb();
+        let function = block.get_function();
+        // NOTE: instead of returning the dereference here, we have to assign it to a variable in
+        // the current basic block. Otherwise, it could be used in another basic block, causing a
+        // dereference after a drop, for instance.
+        // TODO(antoyo): handle align.
+        let deref = ptr.dereference(None).to_rvalue();
+        let value_type = deref.get_type();
+        unsafe { RETURN_VALUE_COUNT += 1 };
+        let loaded_value = function.new_local(None, value_type, &format!("loadedValue{}", unsafe { RETURN_VALUE_COUNT }));
+        block.add_assignment(None, loaded_value, deref);
+        loaded_value.to_rvalue()
+    }
+
+    fn volatile_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use ty.
+        let ptr = self.context.new_cast(None, ptr, ptr.get_type().make_volatile());
+        ptr.dereference(None).to_rvalue()
+    }
+
+    fn atomic_load(&mut self, _ty: Type<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) -> RValue<'gcc> {
+        // TODO(antoyo): use ty.
+        // TODO(antoyo): handle alignment.
+        let atomic_load = self.context.get_builtin_function(&format!("__atomic_load_{}", size.bytes()));
+        let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+
+        let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+        let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
+        self.context.new_call(None, atomic_load, &[ptr, ordering])
+    }
+
+    fn load_operand(&mut self, place: PlaceRef<'tcx, RValue<'gcc>>) -> OperandRef<'tcx, RValue<'gcc>> {
+        assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
+
+        if place.layout.is_zst() {
+            return OperandRef::new_zst(self, place.layout);
+        }
+
+        fn scalar_load_metadata<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, load: RValue<'gcc>, scalar: &abi::Scalar) {
+            let vr = scalar.valid_range.clone();
+            match scalar.value {
+                abi::Int(..) => {
+                    if !scalar.is_always_valid(bx) {
+                        bx.range_metadata(load, scalar.valid_range);
+                    }
+                }
+                abi::Pointer if vr.start < vr.end && !vr.contains(0) => {
+                    bx.nonnull_metadata(load);
+                }
+                _ => {}
+            }
+        }
+
+        let val =
+            if let Some(llextra) = place.llextra {
+                OperandValue::Ref(place.llval, Some(llextra), place.align)
+            }
+            else if place.layout.is_gcc_immediate() {
+                let load = self.load(place.llval.get_type(), place.llval, place.align);
+                if let abi::Abi::Scalar(ref scalar) = place.layout.abi {
+                    scalar_load_metadata(self, load, scalar);
+                }
+                OperandValue::Immediate(self.to_immediate(load, place.layout))
+            }
+            else if let abi::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
+                let b_offset = a.value.size(self).align_to(b.value.align(self).abi);
+                let pair_type = place.layout.gcc_type(self, false);
+
+                let mut load = |i, scalar: &abi::Scalar, align| {
+                    let llptr = self.struct_gep(pair_type, place.llval, i as u64);
+                    let load = self.load(llptr.get_type(), llptr, align);
+                    scalar_load_metadata(self, load, scalar);
+                    if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load }
+                };
+
+                OperandValue::Pair(
+                    load(0, a, place.align),
+                    load(1, b, place.align.restrict_for_offset(b_offset)),
+                )
+            }
+            else {
+                OperandValue::Ref(place.llval, None, place.align)
+            };
+
+        OperandRef { val, layout: place.layout }
+    }
+
+    fn write_operand_repeatedly(mut self, cg_elem: OperandRef<'tcx, RValue<'gcc>>, count: u64, dest: PlaceRef<'tcx, RValue<'gcc>>) -> Self {
+        let zero = self.const_usize(0);
+        let count = self.const_usize(count);
+        let start = dest.project_index(&mut self, zero).llval;
+        let end = dest.project_index(&mut self, count).llval;
+
+        let mut header_bx = self.build_sibling_block("repeat_loop_header");
+        let mut body_bx = self.build_sibling_block("repeat_loop_body");
+        let next_bx = self.build_sibling_block("repeat_loop_next");
+
+        let ptr_type = start.get_type();
+        let current = self.llbb().get_function().new_local(None, ptr_type, "loop_var");
+        let current_val = current.to_rvalue();
+        self.assign(current, start);
+
+        self.br(header_bx.llbb());
+
+        let keep_going = header_bx.icmp(IntPredicate::IntNE, current_val, end);
+        header_bx.cond_br(keep_going, body_bx.llbb(), next_bx.llbb());
+
+        let align = dest.align.restrict_for_offset(dest.layout.field(self.cx(), 0).size);
+        cg_elem.val.store(&mut body_bx, PlaceRef::new_sized_aligned(current_val, cg_elem.layout, align));
+
+        let next = body_bx.inbounds_gep(self.backend_type(cg_elem.layout), current.to_rvalue(), &[self.const_usize(1)]);
+        body_bx.llbb().add_assignment(None, current, next);
+        body_bx.br(header_bx.llbb());
+
+        next_bx
+    }
+
+    fn range_metadata(&mut self, _load: RValue<'gcc>, _range: WrappingRange) {
+        // TODO(antoyo)
+    }
+
+    fn nonnull_metadata(&mut self, _load: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn store(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, align: Align) -> RValue<'gcc> {
+        self.store_with_flags(val, ptr, align, MemFlags::empty())
+    }
+
+    fn store_with_flags(&mut self, val: RValue<'gcc>, ptr: RValue<'gcc>, _align: Align, _flags: MemFlags) -> RValue<'gcc> {
+        let ptr = self.check_store(val, ptr);
+        self.llbb().add_assignment(None, ptr.dereference(None), val);
+        // TODO(antoyo): handle align and flags.
+        // NOTE: dummy value here since it's never used. FIXME(antoyo): API should not return a value here?
+        self.cx.context.new_rvalue_zero(self.type_i32())
+    }
+
+    fn atomic_store(&mut self, value: RValue<'gcc>, ptr: RValue<'gcc>, order: AtomicOrdering, size: Size) {
+        // TODO(antoyo): handle alignment.
+        let atomic_store = self.context.get_builtin_function(&format!("__atomic_store_{}", size.bytes()));
+        let ordering = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+        let volatile_const_void_ptr_type = self.context.new_type::<*mut ()>().make_const().make_volatile();
+        let ptr = self.context.new_cast(None, ptr, volatile_const_void_ptr_type);
+
+        // FIXME(antoyo): fix libgccjit to allow comparing an integer type with an aligned integer type because
+        // the following cast is required to avoid this error:
+        // gcc_jit_context_new_call: mismatching types for argument 2 of function "__atomic_store_4": assignment to param arg1 (type: int) from loadedValue3577 (type: unsigned int  __attribute__((aligned(4))))
+        let int_type = atomic_store.get_param(1).to_rvalue().get_type();
+        let value = self.context.new_cast(None, value, int_type);
+        self.llbb()
+            .add_eval(None, self.context.new_call(None, atomic_store, &[ptr, value, ordering]));
+    }
+
+    fn gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
+        let mut result = ptr;
+        for index in indices {
+            result = self.context.new_array_access(None, result, *index).get_address(None).to_rvalue();
+        }
+        result
+    }
+
+    fn inbounds_gep(&mut self, _typ: Type<'gcc>, ptr: RValue<'gcc>, indices: &[RValue<'gcc>]) -> RValue<'gcc> {
+        // FIXME(antoyo): would be safer if doing the same thing (loop) as gep.
+        // TODO(antoyo): specify inbounds somehow.
+        match indices.len() {
+            1 => {
+                self.context.new_array_access(None, ptr, indices[0]).get_address(None)
+            },
+            2 => {
+                let array = ptr.dereference(None); // TODO(antoyo): assert that first index is 0?
+                self.context.new_array_access(None, array, indices[1]).get_address(None)
+            },
+            _ => unimplemented!(),
+        }
+    }
+
+    fn struct_gep(&mut self, value_type: Type<'gcc>, ptr: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+        // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+        assert_eq!(idx as usize as u64, idx);
+        let value = ptr.dereference(None).to_rvalue();
+
+        if value_type.is_array().is_some() {
+            let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+            let element = self.context.new_array_access(None, value, index);
+            element.get_address(None)
+        }
+        else if let Some(vector_type) = value_type.is_vector() {
+            let array_type = vector_type.get_element_type().make_pointer();
+            let array = self.bitcast(ptr, array_type);
+            let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+            let element = self.context.new_array_access(None, array, index);
+            element.get_address(None)
+        }
+        else if let Some(struct_type) = value_type.is_struct() {
+            ptr.dereference_field(None, struct_type.get_field(idx as i32)).get_address(None)
+        }
+        else {
+            panic!("Unexpected type {:?}", value_type);
+        }
+    }
+
+    /* Casts */
+    fn trunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): check that it indeed truncate the value.
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn sext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): check that it indeed sign extend the value.
+        if dest_ty.is_vector().is_some() {
+            // TODO(antoyo): nothing to do as it is only for LLVM?
+            return value;
+        }
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn fptoui(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn fptosi(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn uitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn sitofp(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn fptrunc(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): make sure it truncates.
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn fpext(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, value, dest_ty)
+    }
+
+    fn ptrtoint(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.cx.ptrtoint(self.block.expect("block"), value, dest_ty)
+    }
+
+    fn inttoptr(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.cx.inttoptr(self.block.expect("block"), value, dest_ty)
+    }
+
+    fn bitcast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        self.cx.const_bitcast(value, dest_ty)
+    }
+
+    fn intcast(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>, _is_signed: bool) -> RValue<'gcc> {
+        // NOTE: is_signed is for value, not dest_typ.
+        self.cx.context.new_cast(None, value, dest_typ)
+    }
+
+    fn pointercast(&mut self, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        let val_type = value.get_type();
+        match (type_is_pointer(val_type), type_is_pointer(dest_ty)) {
+            (false, true) => {
+                // NOTE: Projecting a field of a pointer type will attemp a cast from a signed char to
+                // a pointer, which is not supported by gccjit.
+                return self.cx.context.new_cast(None, self.inttoptr(value, val_type.make_pointer()), dest_ty);
+            },
+            (false, false) => {
+                // When they are not pointers, we want a transmute (or reinterpret_cast).
+                self.bitcast(value, dest_ty)
+            },
+            (true, true) => self.cx.context.new_cast(None, value, dest_ty),
+            (true, false) => unimplemented!(),
+        }
+    }
+
+    /* Comparisons */
+    fn icmp(&mut self, op: IntPredicate, mut lhs: RValue<'gcc>, mut rhs: RValue<'gcc>) -> RValue<'gcc> {
+        let left_type = lhs.get_type();
+        let right_type = rhs.get_type();
+        if left_type != right_type {
+            // NOTE: because libgccjit cannot compare function pointers.
+            if left_type.is_function_ptr_type().is_some() && right_type.is_function_ptr_type().is_some() {
+                lhs = self.context.new_cast(None, lhs, self.usize_type.make_pointer());
+                rhs = self.context.new_cast(None, rhs, self.usize_type.make_pointer());
+            }
+            // NOTE: hack because we try to cast a vector type to the same vector type.
+            else if format!("{:?}", left_type) != format!("{:?}", right_type) {
+                rhs = self.context.new_cast(None, rhs, left_type);
+            }
+        }
+        self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
+    }
+
+    fn fcmp(&mut self, op: RealPredicate, lhs: RValue<'gcc>, rhs: RValue<'gcc>) -> RValue<'gcc> {
+        self.context.new_comparison(None, op.to_gcc_comparison(), lhs, rhs)
+    }
+
+    /* Miscellaneous instructions */
+    fn memcpy(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) {
+        if flags.contains(MemFlags::NONTEMPORAL) {
+            // HACK(nox): This is inefficient but there is no nontemporal memcpy.
+            let val = self.load(src.get_type(), src, src_align);
+            let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val)));
+            self.store_with_flags(val, ptr, dst_align, flags);
+            return;
+        }
+        let size = self.intcast(size, self.type_size_t(), false);
+        let _is_volatile = flags.contains(MemFlags::VOLATILE);
+        let dst = self.pointercast(dst, self.type_i8p());
+        let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
+        let memcpy = self.context.get_builtin_function("memcpy");
+        let block = self.block.expect("block");
+        // TODO(antoyo): handle aligns and is_volatile.
+        block.add_eval(None, self.context.new_call(None, memcpy, &[dst, src, size]));
+    }
+
+    fn memmove(&mut self, dst: RValue<'gcc>, dst_align: Align, src: RValue<'gcc>, src_align: Align, size: RValue<'gcc>, flags: MemFlags) {
+        if flags.contains(MemFlags::NONTEMPORAL) {
+            // HACK(nox): This is inefficient but there is no nontemporal memmove.
+            let val = self.load(src.get_type(), src, src_align);
+            let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val)));
+            self.store_with_flags(val, ptr, dst_align, flags);
+            return;
+        }
+        let size = self.intcast(size, self.type_size_t(), false);
+        let _is_volatile = flags.contains(MemFlags::VOLATILE);
+        let dst = self.pointercast(dst, self.type_i8p());
+        let src = self.pointercast(src, self.type_ptr_to(self.type_void()));
+
+        let memmove = self.context.get_builtin_function("memmove");
+        let block = self.block.expect("block");
+        // TODO(antoyo): handle is_volatile.
+        block.add_eval(None, self.context.new_call(None, memmove, &[dst, src, size]));
+    }
+
+    fn memset(&mut self, ptr: RValue<'gcc>, fill_byte: RValue<'gcc>, size: RValue<'gcc>, _align: Align, flags: MemFlags) {
+        let _is_volatile = flags.contains(MemFlags::VOLATILE);
+        let ptr = self.pointercast(ptr, self.type_i8p());
+        let memset = self.context.get_builtin_function("memset");
+        let block = self.block.expect("block");
+        // TODO(antoyo): handle align and is_volatile.
+        let fill_byte = self.context.new_cast(None, fill_byte, self.i32_type);
+        let size = self.intcast(size, self.type_size_t(), false);
+        block.add_eval(None, self.context.new_call(None, memset, &[ptr, fill_byte, size]));
+    }
+
+    fn select(&mut self, cond: RValue<'gcc>, then_val: RValue<'gcc>, mut else_val: RValue<'gcc>) -> RValue<'gcc> {
+        let func = self.current_func();
+        let variable = func.new_local(None, then_val.get_type(), "selectVar");
+        let then_block = func.new_block("then");
+        let else_block = func.new_block("else");
+        let after_block = func.new_block("after");
+        self.llbb().end_with_conditional(None, cond, then_block, else_block);
+
+        then_block.add_assignment(None, variable, then_val);
+        then_block.end_with_jump(None, after_block);
+
+        if then_val.get_type() != else_val.get_type() {
+            else_val = self.context.new_cast(None, else_val, then_val.get_type());
+        }
+        else_block.add_assignment(None, variable, else_val);
+        else_block.end_with_jump(None, after_block);
+
+        // NOTE: since jumps were added in a place rustc does not expect, the current blocks in the
+        // state need to be updated.
+        self.block = Some(after_block);
+        *self.cx.current_block.borrow_mut() = Some(after_block);
+
+        variable.to_rvalue()
+    }
+
+    #[allow(dead_code)]
+    fn va_arg(&mut self, _list: RValue<'gcc>, _ty: Type<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn extract_element(&mut self, _vec: RValue<'gcc>, _idx: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn vector_splat(&mut self, _num_elts: usize, _elt: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn extract_value(&mut self, aggregate_value: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+        // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+        assert_eq!(idx as usize as u64, idx);
+        let value_type = aggregate_value.get_type();
+
+        if value_type.is_array().is_some() {
+            let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+            let element = self.context.new_array_access(None, aggregate_value, index);
+            element.get_address(None)
+        }
+        else if value_type.is_vector().is_some() {
+            panic!();
+        }
+        else if let Some(pointer_type) = value_type.get_pointee() {
+            if let Some(struct_type) = pointer_type.is_struct() {
+                // NOTE: hack to workaround a limitation of the rustc API: see comment on
+                // CodegenCx.structs_as_pointer
+                aggregate_value.dereference_field(None, struct_type.get_field(idx as i32)).to_rvalue()
+            }
+            else {
+                panic!("Unexpected type {:?}", value_type);
+            }
+        }
+        else if let Some(struct_type) = value_type.is_struct() {
+            aggregate_value.access_field(None, struct_type.get_field(idx as i32)).to_rvalue()
+        }
+        else {
+            panic!("Unexpected type {:?}", value_type);
+        }
+    }
+
+    fn insert_value(&mut self, aggregate_value: RValue<'gcc>, value: RValue<'gcc>, idx: u64) -> RValue<'gcc> {
+        // FIXME(antoyo): it would be better if the API only called this on struct, not on arrays.
+        assert_eq!(idx as usize as u64, idx);
+        let value_type = aggregate_value.get_type();
+
+        let lvalue =
+            if value_type.is_array().is_some() {
+                let index = self.context.new_rvalue_from_long(self.u64_type, i64::try_from(idx).expect("i64::try_from"));
+                self.context.new_array_access(None, aggregate_value, index)
+            }
+            else if value_type.is_vector().is_some() {
+                panic!();
+            }
+            else if let Some(pointer_type) = value_type.get_pointee() {
+                if let Some(struct_type) = pointer_type.is_struct() {
+                    // NOTE: hack to workaround a limitation of the rustc API: see comment on
+                    // CodegenCx.structs_as_pointer
+                    aggregate_value.dereference_field(None, struct_type.get_field(idx as i32))
+                }
+                else {
+                    panic!("Unexpected type {:?}", value_type);
+                }
+            }
+            else {
+                panic!("Unexpected type {:?}", value_type);
+            };
+
+        let lvalue_type = lvalue.to_rvalue().get_type();
+        let value =
+            // NOTE: sometimes, rustc will create a value with the wrong type.
+            if lvalue_type != value.get_type() {
+                self.context.new_cast(None, value, lvalue_type)
+            }
+            else {
+                value
+            };
+
+        self.llbb().add_assignment(None, lvalue, value);
+
+        aggregate_value
+    }
+
+    fn landing_pad(&mut self, _ty: Type<'gcc>, _pers_fn: RValue<'gcc>, _num_clauses: usize) -> RValue<'gcc> {
+        let field1 = self.context.new_field(None, self.u8_type, "landing_pad_field_1");
+        let field2 = self.context.new_field(None, self.i32_type, "landing_pad_field_1");
+        let struct_type = self.context.new_struct_type(None, "landing_pad", &[field1, field2]);
+        self.current_func().new_local(None, struct_type.as_type(), "landing_pad")
+            .to_rvalue()
+        // TODO(antoyo): Properly implement unwinding.
+        // the above is just to make the compilation work as it seems
+        // rustc_codegen_ssa now calls the unwinding builder methods even on panic=abort.
+    }
+
+    fn set_cleanup(&mut self, _landing_pad: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn resume(&mut self, _exn: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn cleanup_pad(&mut self, _parent: Option<RValue<'gcc>>, _args: &[RValue<'gcc>]) -> Funclet {
+        unimplemented!();
+    }
+
+    fn cleanup_ret(&mut self, _funclet: &Funclet, _unwind: Option<Block<'gcc>>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn catch_pad(&mut self, _parent: RValue<'gcc>, _args: &[RValue<'gcc>]) -> Funclet {
+        unimplemented!();
+    }
+
+    fn catch_switch(&mut self, _parent: Option<RValue<'gcc>>, _unwind: Option<Block<'gcc>>, _num_handlers: usize) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn add_handler(&mut self, _catch_switch: RValue<'gcc>, _handler: Block<'gcc>) {
+        unimplemented!();
+    }
+
+    fn set_personality_fn(&mut self, _personality: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    // Atomic Operations
+    fn atomic_cmpxchg(&mut self, dst: RValue<'gcc>, cmp: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering, failure_order: AtomicOrdering, weak: bool) -> RValue<'gcc> {
+        let expected = self.current_func().new_local(None, cmp.get_type(), "expected");
+        self.llbb().add_assignment(None, expected, cmp);
+        let success = self.compare_exchange(dst, expected, src, order, failure_order, weak);
+
+        let pair_type = self.cx.type_struct(&[src.get_type(), self.bool_type], false);
+        let result = self.current_func().new_local(None, pair_type, "atomic_cmpxchg_result");
+        let align = Align::from_bits(64).expect("align"); // TODO(antoyo): use good align.
+
+        let value_type = result.to_rvalue().get_type();
+        if let Some(struct_type) = value_type.is_struct() {
+            self.store(success, result.access_field(None, struct_type.get_field(1)).get_address(None), align);
+            // NOTE: since success contains the call to the intrinsic, it must be stored before
+            // expected so that we store expected after the call.
+            self.store(expected.to_rvalue(), result.access_field(None, struct_type.get_field(0)).get_address(None), align);
+        }
+        // TODO(antoyo): handle when value is not a struct.
+
+        result.to_rvalue()
+    }
+
+    fn atomic_rmw(&mut self, op: AtomicRmwBinOp, dst: RValue<'gcc>, src: RValue<'gcc>, order: AtomicOrdering) -> RValue<'gcc> {
+        let size = self.cx.int_width(src.get_type()) / 8;
+        let name =
+            match op {
+                AtomicRmwBinOp::AtomicXchg => format!("__atomic_exchange_{}", size),
+                AtomicRmwBinOp::AtomicAdd => format!("__atomic_fetch_add_{}", size),
+                AtomicRmwBinOp::AtomicSub => format!("__atomic_fetch_sub_{}", size),
+                AtomicRmwBinOp::AtomicAnd => format!("__atomic_fetch_and_{}", size),
+                AtomicRmwBinOp::AtomicNand => format!("__atomic_fetch_nand_{}", size),
+                AtomicRmwBinOp::AtomicOr => format!("__atomic_fetch_or_{}", size),
+                AtomicRmwBinOp::AtomicXor => format!("__atomic_fetch_xor_{}", size),
+                AtomicRmwBinOp::AtomicMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order),
+                AtomicRmwBinOp::AtomicMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order),
+                AtomicRmwBinOp::AtomicUMax => return self.atomic_extremum(ExtremumOperation::Max, dst, src, order),
+                AtomicRmwBinOp::AtomicUMin => return self.atomic_extremum(ExtremumOperation::Min, dst, src, order),
+            };
+
+
+        let atomic_function = self.context.get_builtin_function(name);
+        let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+
+        let void_ptr_type = self.context.new_type::<*mut ()>();
+        let volatile_void_ptr_type = void_ptr_type.make_volatile();
+        let dst = self.context.new_cast(None, dst, volatile_void_ptr_type);
+        // FIXME(antoyo): not sure why, but we have the wrong type here.
+        let new_src_type = atomic_function.get_param(1).to_rvalue().get_type();
+        let src = self.context.new_cast(None, src, new_src_type);
+        let res = self.context.new_call(None, atomic_function, &[dst, src, order]);
+        self.context.new_cast(None, res, src.get_type())
+    }
+
+    fn atomic_fence(&mut self, order: AtomicOrdering, scope: SynchronizationScope) {
+        let name =
+            match scope {
+                SynchronizationScope::SingleThread => "__atomic_signal_fence",
+                SynchronizationScope::CrossThread => "__atomic_thread_fence",
+            };
+        let thread_fence = self.context.get_builtin_function(name);
+        let order = self.context.new_rvalue_from_int(self.i32_type, order.to_gcc());
+        self.llbb().add_eval(None, self.context.new_call(None, thread_fence, &[order]));
+    }
+
+    fn set_invariant_load(&mut self, load: RValue<'gcc>) {
+        // NOTE: Hack to consider vtable function pointer as non-global-variable function pointer.
+        self.normal_function_addresses.borrow_mut().insert(load);
+        // TODO(antoyo)
+    }
+
+    fn lifetime_start(&mut self, _ptr: RValue<'gcc>, _size: Size) {
+        // TODO(antoyo)
+    }
+
+    fn lifetime_end(&mut self, _ptr: RValue<'gcc>, _size: Size) {
+        // TODO(antoyo)
+    }
+
+    fn call(&mut self, _typ: Type<'gcc>, func: RValue<'gcc>, args: &[RValue<'gcc>], funclet: Option<&Funclet>) -> RValue<'gcc> {
+        // FIXME(antoyo): remove when having a proper API.
+        let gcc_func = unsafe { std::mem::transmute(func) };
+        if self.functions.borrow().values().find(|value| **value == gcc_func).is_some() {
+            self.function_call(func, args, funclet)
+        }
+        else {
+            // If it's a not function that was defined, it's a function pointer.
+            self.function_ptr_call(func, args, funclet)
+        }
+    }
+
+    fn zext(&mut self, value: RValue<'gcc>, dest_typ: Type<'gcc>) -> RValue<'gcc> {
+        // FIXME(antoyo): this does not zero-extend.
+        if value.get_type().is_bool() && dest_typ.is_i8(&self.cx) {
+            // FIXME(antoyo): hack because base::from_immediate converts i1 to i8.
+            // Fix the code in codegen_ssa::base::from_immediate.
+            return value;
+        }
+        self.context.new_cast(None, value, dest_typ)
+    }
+
+    fn cx(&self) -> &CodegenCx<'gcc, 'tcx> {
+        self.cx
+    }
+
+    fn do_not_inline(&mut self, _llret: RValue<'gcc>) {
+        unimplemented!();
+    }
+
+    fn set_span(&mut self, _span: Span) {}
+
+    fn from_immediate(&mut self, val: Self::Value) -> Self::Value {
+        if self.cx().val_ty(val) == self.cx().type_i1() {
+            self.zext(val, self.cx().type_i8())
+        }
+        else {
+            val
+        }
+    }
+
+    fn to_immediate_scalar(&mut self, val: Self::Value, scalar: abi::Scalar) -> Self::Value {
+        if scalar.is_bool() {
+            return self.trunc(val, self.cx().type_i1());
+        }
+        val
+    }
+
+    fn fptoui_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
+        None
+    }
+
+    fn fptosi_sat(&mut self, _val: RValue<'gcc>, _dest_ty: Type<'gcc>) -> Option<RValue<'gcc>> {
+        None
+    }
+
+    fn instrprof_increment(&mut self, _fn_name: RValue<'gcc>, _hash: RValue<'gcc>, _num_counters: RValue<'gcc>, _index: RValue<'gcc>) {
+        unimplemented!();
+    }
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+    pub fn shuffle_vector(&mut self, v1: RValue<'gcc>, v2: RValue<'gcc>, mask: RValue<'gcc>) -> RValue<'gcc> {
+        let return_type = v1.get_type();
+        let params = [
+            self.context.new_parameter(None, return_type, "v1"),
+            self.context.new_parameter(None, return_type, "v2"),
+            self.context.new_parameter(None, mask.get_type(), "mask"),
+        ];
+        let shuffle = self.context.new_function(None, FunctionType::Extern, return_type, &params, "_mm_shuffle_epi8", false);
+        self.context.new_call(None, shuffle, &[v1, v2, mask])
+    }
+}
+
+impl<'a, 'gcc, 'tcx> StaticBuilderMethods for Builder<'a, 'gcc, 'tcx> {
+    fn get_static(&mut self, def_id: DefId) -> RValue<'gcc> {
+        // Forward to the `get_static` method of `CodegenCx`
+        self.cx().get_static(def_id).get_address(None)
+    }
+}
+
+impl<'tcx> HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> {
+    fn param_env(&self) -> ParamEnv<'tcx> {
+        self.cx.param_env()
+    }
+}
+
+impl<'tcx> HasTargetSpec for Builder<'_, '_, 'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.cx.target_spec()
+    }
+}
+
+trait ToGccComp {
+    fn to_gcc_comparison(&self) -> ComparisonOp;
+}
+
+impl ToGccComp for IntPredicate {
+    fn to_gcc_comparison(&self) -> ComparisonOp {
+        match *self {
+            IntPredicate::IntEQ => ComparisonOp::Equals,
+            IntPredicate::IntNE => ComparisonOp::NotEquals,
+            IntPredicate::IntUGT => ComparisonOp::GreaterThan,
+            IntPredicate::IntUGE => ComparisonOp::GreaterThanEquals,
+            IntPredicate::IntULT => ComparisonOp::LessThan,
+            IntPredicate::IntULE => ComparisonOp::LessThanEquals,
+            IntPredicate::IntSGT => ComparisonOp::GreaterThan,
+            IntPredicate::IntSGE => ComparisonOp::GreaterThanEquals,
+            IntPredicate::IntSLT => ComparisonOp::LessThan,
+            IntPredicate::IntSLE => ComparisonOp::LessThanEquals,
+        }
+    }
+}
+
+impl ToGccComp for RealPredicate {
+    fn to_gcc_comparison(&self) -> ComparisonOp {
+        // TODO(antoyo): check that ordered vs non-ordered is respected.
+        match *self {
+            RealPredicate::RealPredicateFalse => unreachable!(),
+            RealPredicate::RealOEQ => ComparisonOp::Equals,
+            RealPredicate::RealOGT => ComparisonOp::GreaterThan,
+            RealPredicate::RealOGE => ComparisonOp::GreaterThanEquals,
+            RealPredicate::RealOLT => ComparisonOp::LessThan,
+            RealPredicate::RealOLE => ComparisonOp::LessThanEquals,
+            RealPredicate::RealONE => ComparisonOp::NotEquals,
+            RealPredicate::RealORD => unreachable!(),
+            RealPredicate::RealUNO => unreachable!(),
+            RealPredicate::RealUEQ => ComparisonOp::Equals,
+            RealPredicate::RealUGT => ComparisonOp::GreaterThan,
+            RealPredicate::RealUGE => ComparisonOp::GreaterThan,
+            RealPredicate::RealULT => ComparisonOp::LessThan,
+            RealPredicate::RealULE => ComparisonOp::LessThan,
+            RealPredicate::RealUNE => ComparisonOp::NotEquals,
+            RealPredicate::RealPredicateTrue => unreachable!(),
+        }
+    }
+}
+
+#[repr(C)]
+#[allow(non_camel_case_types)]
+enum MemOrdering {
+    __ATOMIC_RELAXED,
+    __ATOMIC_CONSUME,
+    __ATOMIC_ACQUIRE,
+    __ATOMIC_RELEASE,
+    __ATOMIC_ACQ_REL,
+    __ATOMIC_SEQ_CST,
+}
+
+trait ToGccOrdering {
+    fn to_gcc(self) -> i32;
+}
+
+impl ToGccOrdering for AtomicOrdering {
+    fn to_gcc(self) -> i32 {
+        use MemOrdering::*;
+
+        let ordering =
+            match self {
+                AtomicOrdering::NotAtomic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
+                AtomicOrdering::Unordered => __ATOMIC_RELAXED,
+                AtomicOrdering::Monotonic => __ATOMIC_RELAXED, // TODO(antoyo): check if that's the same.
+                AtomicOrdering::Acquire => __ATOMIC_ACQUIRE,
+                AtomicOrdering::Release => __ATOMIC_RELEASE,
+                AtomicOrdering::AcquireRelease => __ATOMIC_ACQ_REL,
+                AtomicOrdering::SequentiallyConsistent => __ATOMIC_SEQ_CST,
+            };
+        ordering as i32
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs
new file mode 100644 (file)
index 0000000..76419b1
--- /dev/null
@@ -0,0 +1,77 @@
+use gccjit::{FunctionType, RValue};
+use rustc_codegen_ssa::traits::BaseTypeMethods;
+use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt};
+
+use crate::abi::FnAbiGccExt;
+use crate::context::CodegenCx;
+
+/// Codegens a reference to a fn/method item, monomorphizing and
+/// inlining as it goes.
+///
+/// # Parameters
+///
+/// - `cx`: the crate context
+/// - `instance`: the instance to be instantiated
+pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> RValue<'gcc> {
+    let tcx = cx.tcx();
+
+    assert!(!instance.substs.needs_infer());
+    assert!(!instance.substs.has_escaping_bound_vars());
+
+    if let Some(&func) = cx.function_instances.borrow().get(&instance) {
+        return func;
+    }
+
+    let sym = tcx.symbol_name(instance).name;
+
+    let fn_abi = cx.fn_abi_of_instance(instance, ty::List::empty());
+
+    let func =
+        if let Some(func) = cx.get_declared_value(&sym) {
+            // Create a fn pointer with the new signature.
+            let ptrty = fn_abi.ptr_to_gcc_type(cx);
+
+            // This is subtle and surprising, but sometimes we have to bitcast
+            // the resulting fn pointer.  The reason has to do with external
+            // functions.  If you have two crates that both bind the same C
+            // library, they may not use precisely the same types: for
+            // example, they will probably each declare their own structs,
+            // which are distinct types from LLVM's point of view (nominal
+            // types).
+            //
+            // Now, if those two crates are linked into an application, and
+            // they contain inlined code, you can wind up with a situation
+            // where both of those functions wind up being loaded into this
+            // application simultaneously. In that case, the same function
+            // (from LLVM's point of view) requires two types. But of course
+            // LLVM won't allow one function to have two types.
+            //
+            // What we currently do, therefore, is declare the function with
+            // one of the two types (whichever happens to come first) and then
+            // bitcast as needed when the function is referenced to make sure
+            // it has the type we expect.
+            //
+            // This can occur on either a crate-local or crate-external
+            // reference. It also occurs when testing libcore and in some
+            // other weird situations. Annoying.
+            if cx.val_ty(func) != ptrty {
+                // TODO(antoyo): cast the pointer.
+                func
+            }
+            else {
+                func
+            }
+        }
+        else {
+            cx.linkage.set(FunctionType::Extern);
+            let func = cx.declare_fn(&sym, &fn_abi);
+
+            // TODO(antoyo): set linkage and attributes.
+            func
+        };
+
+    cx.function_instances.borrow_mut().insert(instance, func);
+
+    func
+}
diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs
new file mode 100644 (file)
index 0000000..bda08b6
--- /dev/null
@@ -0,0 +1,450 @@
+use std::convert::TryFrom;
+use std::convert::TryInto;
+
+use gccjit::LValue;
+use gccjit::{Block, CType, RValue, Type, ToRValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{
+    BaseTypeMethods,
+    ConstMethods,
+    DerivedTypeMethods,
+    MiscMethods,
+    StaticMethods,
+};
+use rustc_middle::mir::Mutability;
+use rustc_middle::ty::ScalarInt;
+use rustc_middle::ty::layout::{TyAndLayout, LayoutOf};
+use rustc_middle::mir::interpret::{Allocation, GlobalAlloc, Scalar};
+use rustc_span::Symbol;
+use rustc_target::abi::{self, HasDataLayout, Pointer, Size};
+
+use crate::consts::const_alloc_to_gcc;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn const_bytes(&self, bytes: &[u8]) -> RValue<'gcc> {
+        bytes_in_context(self, bytes)
+    }
+
+    fn const_cstr(&self, symbol: Symbol, _null_terminated: bool) -> LValue<'gcc> {
+        // TODO(antoyo): handle null_terminated.
+        if let Some(&value) = self.const_cstr_cache.borrow().get(&symbol) {
+            return value;
+        }
+
+        let global = self.global_string(&*symbol.as_str());
+
+        self.const_cstr_cache.borrow_mut().insert(symbol, global);
+        global
+    }
+
+    fn global_string(&self, string: &str) -> LValue<'gcc> {
+        // TODO(antoyo): handle non-null-terminated strings.
+        let string = self.context.new_string_literal(&*string);
+        let sym = self.generate_local_symbol_name("str");
+        let global = self.declare_private_global(&sym, self.val_ty(string));
+        global.global_set_initializer_value(string);
+        global
+        // TODO(antoyo): set linkage.
+    }
+
+    pub fn inttoptr(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        let func = block.get_function();
+        let local = func.new_local(None, value.get_type(), "intLocal");
+        block.add_assignment(None, local, value);
+        let value_address = local.get_address(None);
+
+        let ptr = self.context.new_cast(None, value_address, dest_ty.make_pointer());
+        ptr.dereference(None).to_rvalue()
+    }
+
+    pub fn ptrtoint(&self, block: Block<'gcc>, value: RValue<'gcc>, dest_ty: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): when libgccjit allow casting from pointer to int, remove this.
+        let func = block.get_function();
+        let local = func.new_local(None, value.get_type(), "ptrLocal");
+        block.add_assignment(None, local, value);
+        let ptr_address = local.get_address(None);
+
+        let ptr = self.context.new_cast(None, ptr_address, dest_ty.make_pointer());
+        ptr.dereference(None).to_rvalue()
+    }
+}
+
+pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> {
+    let context = &cx.context;
+    let byte_type = context.new_type::<u8>();
+    let typ = context.new_array_type(None, byte_type, bytes.len() as i32);
+    let elements: Vec<_> =
+        bytes.iter()
+        .map(|&byte| context.new_rvalue_from_int(byte_type, byte as i32))
+        .collect();
+    context.new_rvalue_from_array(None, typ, &elements)
+}
+
+pub fn type_is_pointer<'gcc>(typ: Type<'gcc>) -> bool {
+    typ.get_pointee().is_some()
+}
+
+impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn const_null(&self, typ: Type<'gcc>) -> RValue<'gcc> {
+        if type_is_pointer(typ) {
+            self.context.new_null(typ)
+        }
+        else {
+            self.const_int(typ, 0)
+        }
+    }
+
+    fn const_undef(&self, typ: Type<'gcc>) -> RValue<'gcc> {
+        let local = self.current_func.borrow().expect("func")
+            .new_local(None, typ, "undefined");
+        if typ.is_struct().is_some() {
+            // NOTE: hack to workaround a limitation of the rustc API: see comment on
+            // CodegenCx.structs_as_pointer
+            let pointer = local.get_address(None);
+            self.structs_as_pointer.borrow_mut().insert(pointer);
+            pointer
+        }
+        else {
+            local.to_rvalue()
+        }
+    }
+
+    fn const_int(&self, typ: Type<'gcc>, int: i64) -> RValue<'gcc> {
+        self.context.new_rvalue_from_long(typ, i64::try_from(int).expect("i64::try_from"))
+    }
+
+    fn const_uint(&self, typ: Type<'gcc>, int: u64) -> RValue<'gcc> {
+        self.context.new_rvalue_from_long(typ, u64::try_from(int).expect("u64::try_from") as i64)
+    }
+
+    fn const_uint_big(&self, typ: Type<'gcc>, num: u128) -> RValue<'gcc> {
+        let num64: Result<i64, _> = num.try_into();
+        if let Ok(num) = num64 {
+            // FIXME(antoyo): workaround for a bug where libgccjit is expecting a constant.
+            // The operations >> 64 and | low are making the normal case a non-constant.
+            return self.context.new_rvalue_from_long(typ, num as i64);
+        }
+
+        if num >> 64 != 0 {
+            // FIXME(antoyo): use a new function new_rvalue_from_unsigned_long()?
+            let low = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
+            let high = self.context.new_rvalue_from_long(typ, (num >> 64) as u64 as i64);
+
+            let sixty_four = self.context.new_rvalue_from_long(typ, 64);
+            (high << sixty_four) | self.context.new_cast(None, low, typ)
+        }
+        else if typ.is_i128(self) {
+            let num = self.context.new_rvalue_from_long(self.u64_type, num as u64 as i64);
+            self.context.new_cast(None, num, typ)
+        }
+        else {
+            self.context.new_rvalue_from_long(typ, num as u64 as i64)
+        }
+    }
+
+    fn const_bool(&self, val: bool) -> RValue<'gcc> {
+        self.const_uint(self.type_i1(), val as u64)
+    }
+
+    fn const_i32(&self, i: i32) -> RValue<'gcc> {
+        self.const_int(self.type_i32(), i as i64)
+    }
+
+    fn const_u32(&self, i: u32) -> RValue<'gcc> {
+        self.const_uint(self.type_u32(), i as u64)
+    }
+
+    fn const_u64(&self, i: u64) -> RValue<'gcc> {
+        self.const_uint(self.type_u64(), i)
+    }
+
+    fn const_usize(&self, i: u64) -> RValue<'gcc> {
+        let bit_size = self.data_layout().pointer_size.bits();
+        if bit_size < 64 {
+            // make sure it doesn't overflow
+            assert!(i < (1 << bit_size));
+        }
+
+        self.const_uint(self.usize_type, i)
+    }
+
+    fn const_u8(&self, _i: u8) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn const_real(&self, _t: Type<'gcc>, _val: f64) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn const_str(&self, s: Symbol) -> (RValue<'gcc>, RValue<'gcc>) {
+        let len = s.as_str().len();
+        let cs = self.const_ptrcast(self.const_cstr(s, false).get_address(None),
+            self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self, true)),
+        );
+        (cs, self.const_usize(len as u64))
+    }
+
+    fn const_struct(&self, values: &[RValue<'gcc>], packed: bool) -> RValue<'gcc> {
+        let fields: Vec<_> = values.iter()
+            .map(|value| value.get_type())
+            .collect();
+        // TODO(antoyo): cache the type? It's anonymous, so probably not.
+        let typ = self.type_struct(&fields, packed);
+        let struct_type = typ.is_struct().expect("struct type");
+        self.context.new_rvalue_from_struct(None, struct_type, values)
+    }
+
+    fn const_to_opt_uint(&self, _v: RValue<'gcc>) -> Option<u64> {
+        // TODO(antoyo)
+        None
+    }
+
+    fn const_to_opt_u128(&self, _v: RValue<'gcc>, _sign_ext: bool) -> Option<u128> {
+        // TODO(antoyo)
+        None
+    }
+
+    fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, ty: Type<'gcc>) -> RValue<'gcc> {
+        let bitsize = if layout.is_bool() { 1 } else { layout.value.size(self).bits() };
+        match cv {
+            Scalar::Int(ScalarInt::ZST) => {
+                assert_eq!(0, layout.value.size(self).bytes());
+                self.const_undef(self.type_ix(0))
+            }
+            Scalar::Int(int) => {
+                let data = int.assert_bits(layout.value.size(self));
+
+                // FIXME(antoyo): there's some issues with using the u128 code that follows, so hard-code
+                // the paths for floating-point values.
+                if ty == self.float_type {
+                    return self.context.new_rvalue_from_double(ty, f32::from_bits(data as u32) as f64);
+                }
+                else if ty == self.double_type {
+                    return self.context.new_rvalue_from_double(ty, f64::from_bits(data as u64));
+                }
+
+                let value = self.const_uint_big(self.type_ix(bitsize), data);
+                if layout.value == Pointer {
+                    self.inttoptr(self.current_block.borrow().expect("block"), value, ty)
+                } else {
+                    self.const_bitcast(value, ty)
+                }
+            }
+            Scalar::Ptr(ptr, _size) => {
+                let (alloc_id, offset) = ptr.into_parts();
+                let base_addr =
+                    match self.tcx.global_alloc(alloc_id) {
+                        GlobalAlloc::Memory(alloc) => {
+                            let init = const_alloc_to_gcc(self, alloc);
+                            let value =
+                                match alloc.mutability {
+                                    Mutability::Mut => self.static_addr_of_mut(init, alloc.align, None),
+                                    _ => self.static_addr_of(init, alloc.align, None),
+                                };
+                            if !self.sess().fewer_names() {
+                                // TODO(antoyo): set value name.
+                            }
+                            value
+                        },
+                        GlobalAlloc::Function(fn_instance) => {
+                            self.get_fn_addr(fn_instance)
+                        },
+                        GlobalAlloc::Static(def_id) => {
+                            assert!(self.tcx.is_static(def_id));
+                            self.get_static(def_id).get_address(None)
+                        },
+                    };
+                let ptr_type = base_addr.get_type();
+                let base_addr = self.const_bitcast(base_addr, self.usize_type);
+                let offset = self.context.new_rvalue_from_long(self.usize_type, offset.bytes() as i64);
+                let ptr = self.const_bitcast(base_addr + offset, ptr_type);
+                if layout.value != Pointer {
+                    self.const_bitcast(ptr.dereference(None).to_rvalue(), ty)
+                }
+                else {
+                    self.const_bitcast(ptr, ty)
+                }
+            }
+        }
+    }
+
+    fn const_data_from_alloc(&self, alloc: &Allocation) -> Self::Value {
+        const_alloc_to_gcc(self, alloc)
+    }
+
+    fn from_const_alloc(&self, layout: TyAndLayout<'tcx>, alloc: &Allocation, offset: Size) -> PlaceRef<'tcx, RValue<'gcc>> {
+        assert_eq!(alloc.align, layout.align.abi);
+        let ty = self.type_ptr_to(layout.gcc_type(self, true));
+        let value =
+            if layout.size == Size::ZERO {
+                let value = self.const_usize(alloc.align.bytes());
+                self.context.new_cast(None, value, ty)
+            }
+            else {
+                let init = const_alloc_to_gcc(self, alloc);
+                let base_addr = self.static_addr_of(init, alloc.align, None);
+
+                let array = self.const_bitcast(base_addr, self.type_i8p());
+                let value = self.context.new_array_access(None, array, self.const_usize(offset.bytes())).get_address(None);
+                self.const_bitcast(value, ty)
+            };
+        PlaceRef::new_sized(value, layout)
+    }
+
+    fn const_ptrcast(&self, val: RValue<'gcc>, ty: Type<'gcc>) -> RValue<'gcc> {
+        self.context.new_cast(None, val, ty)
+    }
+}
+
+pub trait SignType<'gcc, 'tcx> {
+    fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+    fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+}
+
+impl<'gcc, 'tcx> SignType<'gcc, 'tcx> for Type<'gcc> {
+    fn is_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.is_i8(cx) || self.is_i16(cx) || self.is_i32(cx) || self.is_i64(cx) || self.is_i128(cx)
+    }
+
+    fn is_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.is_u8(cx) || self.is_u16(cx) || self.is_u32(cx) || self.is_u64(cx) || self.is_u128(cx)
+    }
+
+    fn to_signed(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        if self.is_u8(cx) {
+            cx.i8_type
+        }
+        else if self.is_u16(cx) {
+            cx.i16_type
+        }
+        else if self.is_u32(cx) {
+            cx.i32_type
+        }
+        else if self.is_u64(cx) {
+            cx.i64_type
+        }
+        else if self.is_u128(cx) {
+            cx.i128_type
+        }
+        else {
+            self.clone()
+        }
+    }
+
+    fn to_unsigned(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        if self.is_i8(cx) {
+            cx.u8_type
+        }
+        else if self.is_i16(cx) {
+            cx.u16_type
+        }
+        else if self.is_i32(cx) {
+            cx.u32_type
+        }
+        else if self.is_i64(cx) {
+            cx.u64_type
+        }
+        else if self.is_i128(cx) {
+            cx.u128_type
+        }
+        else {
+            self.clone()
+        }
+    }
+}
+
+pub trait TypeReflection<'gcc, 'tcx>  {
+    fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+
+    fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+
+    fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+    fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
+}
+
+impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
+    fn is_uchar(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u8_type
+    }
+
+    fn is_ushort(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u16_type
+    }
+
+    fn is_uint(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.uint_type
+    }
+
+    fn is_ulong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.ulong_type
+    }
+
+    fn is_ulonglong(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.ulonglong_type
+    }
+
+    fn is_i8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.i8_type
+    }
+
+    fn is_u8(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u8_type
+    }
+
+    fn is_i16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.i16_type
+    }
+
+    fn is_u16(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u16_type
+    }
+
+    fn is_i32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.i32_type
+    }
+
+    fn is_u32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u32_type
+    }
+
+    fn is_i64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.i64_type
+    }
+
+    fn is_u64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.u64_type
+    }
+
+    fn is_i128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.context.new_c_type(CType::Int128t)
+    }
+
+    fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.context.new_c_type(CType::UInt128t)
+    }
+
+    fn is_f32(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.context.new_type::<f32>()
+    }
+
+    fn is_f64(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool {
+        self.unqualified() == cx.context.new_type::<f64>()
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/consts.rs b/compiler/rustc_codegen_gcc/src/consts.rs
new file mode 100644 (file)
index 0000000..205498a
--- /dev/null
@@ -0,0 +1,390 @@
+use gccjit::{LValue, RValue, ToRValue, Type};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods, DerivedTypeMethods, StaticMethods};
+use rustc_hir as hir;
+use rustc_hir::Node;
+use rustc_middle::{bug, span_bug};
+use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
+use rustc_middle::mir::mono::MonoItem;
+use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::mir::interpret::{self, Allocation, ErrorHandled, Scalar as InterpScalar, read_target_uint};
+use rustc_span::Span;
+use rustc_span::def_id::DefId;
+use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size, WrappingRange};
+
+use crate::base;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> {
+        if value.get_type() == self.bool_type.make_pointer() {
+            if let Some(pointee) = typ.get_pointee() {
+                if pointee.is_vector().is_some() {
+                    panic!()
+                }
+            }
+        }
+        self.context.new_bitcast(None, value, typ)
+    }
+}
+
+impl<'gcc, 'tcx> StaticMethods for CodegenCx<'gcc, 'tcx> {
+    fn static_addr_of(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
+        if let Some(global_value) = self.const_globals.borrow().get(&cv) {
+            // TODO(antoyo): upgrade alignment.
+            return *global_value;
+        }
+        let global_value = self.static_addr_of_mut(cv, align, kind);
+        // TODO(antoyo): set global constant.
+        self.const_globals.borrow_mut().insert(cv, global_value);
+        global_value
+    }
+
+    fn codegen_static(&self, def_id: DefId, is_mutable: bool) {
+        let attrs = self.tcx.codegen_fn_attrs(def_id);
+
+        let value =
+            match codegen_static_initializer(&self, def_id) {
+                Ok((value, _)) => value,
+                // Error has already been reported
+                Err(_) => return,
+            };
+
+        let global = self.get_static(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 val_llty = self.val_ty(value);
+        let value =
+            if val_llty == self.type_i1() {
+                unimplemented!();
+            }
+            else {
+                value
+            };
+
+        let instance = Instance::mono(self.tcx, def_id);
+        let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+        let gcc_type = self.layout_of(ty).gcc_type(self, true);
+
+        // TODO(antoyo): set alignment.
+
+        let value =
+            if value.get_type() != gcc_type {
+                self.context.new_bitcast(None, value, gcc_type)
+            }
+            else {
+                value
+            };
+        global.global_set_initializer_value(value);
+
+        // As an optimization, all shared statics which do not have interior
+        // mutability are placed into read-only memory.
+        if !is_mutable {
+            if self.type_is_freeze(ty) {
+                // TODO(antoyo): set global constant.
+            }
+        }
+
+        if attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) {
+            // 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 self.tcx.sess.target.options.is_like_osx {
+                // The `inspect` method is okay here because we checked relocations, and
+                // because we are doing this access to inspect the final interpreter state
+                // (not as part of the interpreter execution).
+                //
+                // FIXME: This check requires that the (arbitrary) value of undefined bytes
+                // happens to be zero. Instead, we should only check the value of defined bytes
+                // and set all undefined bytes to zero if this allocation is headed for the
+                // BSS.
+                unimplemented!();
+            }
+        }
+
+        // Wasm statics with custom link sections get special treatment as they
+        // go into custom sections of the wasm executable.
+        if self.tcx.sess.opts.target_triple.triple().starts_with("wasm32") {
+            if let Some(_section) = attrs.link_section {
+                unimplemented!();
+            }
+        } else {
+            // TODO(antoyo): set link section.
+        }
+
+        if attrs.flags.contains(CodegenFnAttrFlags::USED) {
+            self.add_used_global(global.to_rvalue());
+        }
+    }
+
+    /// Add a global value to a list to be stored in the `llvm.used` variable, an array of i8*.
+    fn add_used_global(&self, _global: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn add_compiler_used_global(&self, _global: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn static_addr_of_mut(&self, cv: RValue<'gcc>, align: Align, kind: Option<&str>) -> RValue<'gcc> {
+        let global =
+            match kind {
+                Some(kind) if !self.tcx.sess.fewer_names() => {
+                    let name = self.generate_local_symbol_name(kind);
+                    // TODO(antoyo): check if it's okay that TLS is off here.
+                    // TODO(antoyo): check if it's okay that link_section is None here.
+                    // TODO(antoyo): set alignment here as well.
+                    let global = self.define_global(&name[..], self.val_ty(cv), false, None);
+                    // TODO(antoyo): set linkage.
+                    global
+                }
+                _ => {
+                    let typ = self.val_ty(cv).get_aligned(align.bytes());
+                    let global = self.declare_unnamed_global(typ);
+                    global
+                },
+            };
+        // FIXME(antoyo): I think the name coming from generate_local_symbol_name() above cannot be used
+        // globally.
+        global.global_set_initializer_value(cv);
+        // TODO(antoyo): set unnamed address.
+        global.get_address(None)
+    }
+
+    pub fn get_static(&self, def_id: DefId) -> LValue<'gcc> {
+        let instance = Instance::mono(self.tcx, def_id);
+        let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
+        if let Some(&global) = self.instances.borrow().get(&instance) {
+            return global;
+        }
+
+        let defined_in_current_codegen_unit =
+            self.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(self.tcx, ty::ParamEnv::reveal_all());
+        let sym = self.tcx.symbol_name(instance).name;
+
+        let global =
+            if let Some(def_id) = def_id.as_local() {
+                let id = self.tcx.hir().local_def_id_to_hir_id(def_id);
+                let llty = self.layout_of(ty).gcc_type(self, true);
+                // FIXME: refactor this to work without accessing the HIR
+                let global = match self.tcx.hir().get(id) {
+                    Node::Item(&hir::Item { span, kind: hir::ItemKind::Static(..), .. }) => {
+                        if let Some(global) = self.get_declared_value(&sym) {
+                            if self.val_ty(global) != self.type_ptr_to(llty) {
+                                span_bug!(span, "Conflicting types for static");
+                            }
+                        }
+
+                        let is_tls = fn_attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+                        let global = self.declare_global(&sym, llty, is_tls, fn_attrs.link_section);
+
+                        if !self.tcx.is_reachable_non_generic(def_id) {
+                            // TODO(antoyo): set visibility.
+                        }
+
+                        global
+                    }
+
+                    Node::ForeignItem(&hir::ForeignItem {
+                        span,
+                        kind: hir::ForeignItemKind::Static(..),
+                        ..
+                    }) => {
+                        let fn_attrs = self.tcx.codegen_fn_attrs(def_id);
+                        check_and_apply_linkage(&self, &fn_attrs, ty, sym, span)
+                    }
+
+                    item => bug!("get_static: expected static, found {:?}", item),
+                };
+
+                global
+            }
+            else {
+                // FIXME(nagisa): perhaps the map of externs could be offloaded to llvm somehow?
+                //debug!("get_static: sym={} item_attr={:?}", sym, self.tcx.item_attrs(def_id));
+
+                let attrs = self.tcx.codegen_fn_attrs(def_id);
+                let span = self.tcx.def_span(def_id);
+                let global = check_and_apply_linkage(&self, &attrs, ty, sym, span);
+
+                let needs_dll_storage_attr = false; // TODO(antoyo)
+
+                // If this assertion triggers, there's something wrong with commandline
+                // argument validation.
+                debug_assert!(
+                    !(self.tcx.sess.opts.cg.linker_plugin_lto.enabled()
+                        && self.tcx.sess.target.options.is_like_msvc
+                        && self.tcx.sess.opts.cg.prefer_dynamic)
+                );
+
+                if needs_dll_storage_attr {
+                    // 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 !self.tcx.is_codegened_item(def_id) {
+                        unimplemented!();
+                    }
+                }
+                global
+            };
+
+        // TODO(antoyo): set dll storage class.
+
+        self.instances.borrow_mut().insert(instance, global);
+        global
+    }
+}
+
+pub fn const_alloc_to_gcc<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, alloc: &Allocation) -> RValue<'gcc> {
+    let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1);
+    let dl = cx.data_layout();
+    let pointer_size = dl.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 {
+            // This `inspect` is okay since we have checked that it is not within a relocation, it
+            // is within the bounds of the allocation, and it doesn't affect interpreter execution
+            // (we inspect the result after interpreter execution). Any undef byte is replaced with
+            // some arbitrary byte value.
+            //
+            // FIXME: relay undef bytes to codegen as undef const bytes
+            let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(next_offset..offset);
+            llvals.push(cx.const_bytes(bytes));
+        }
+        let ptr_offset =
+            read_target_uint( dl.endian,
+                // This `inspect` is okay since it is within the bounds of the allocation, it doesn't
+                // affect interpreter execution (we inspect the result after interpreter execution),
+                // and we properly interpret the relocation as a relocation pointer offset.
+                alloc.inspect_with_uninit_and_ptr_outside_interpreter(offset..(offset + pointer_size)),
+            )
+            .expect("const_alloc_to_llvm: could not read relocation pointer")
+            as u64;
+        llvals.push(cx.scalar_to_backend(
+            InterpScalar::from_pointer(
+                interpret::Pointer::new(alloc_id, Size::from_bytes(ptr_offset)),
+                &cx.tcx,
+            ),
+            abi::Scalar { value: Primitive::Pointer, valid_range: WrappingRange { start: 0, end: !0 } },
+            cx.type_i8p(),
+        ));
+        next_offset = offset + pointer_size;
+    }
+    if alloc.len() >= next_offset {
+        let range = next_offset..alloc.len();
+        // This `inspect` is okay since we have check that it is after all relocations, it is
+        // within the bounds of the allocation, and it doesn't affect interpreter execution (we
+        // inspect the result after interpreter execution). Any undef byte is replaced with some
+        // arbitrary byte value.
+        //
+        // FIXME: relay undef bytes to codegen as undef const bytes
+        let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(range);
+        llvals.push(cx.const_bytes(bytes));
+    }
+
+    cx.const_struct(&llvals, true)
+}
+
+pub fn codegen_static_initializer<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, def_id: DefId) -> Result<(RValue<'gcc>, &'tcx Allocation), ErrorHandled> {
+    let alloc = cx.tcx.eval_static_initializer(def_id)?;
+    Ok((const_alloc_to_gcc(cx, alloc), alloc))
+}
+
+fn check_and_apply_linkage<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, attrs: &CodegenFnAttrs, ty: Ty<'tcx>, sym: &str, span: Span) -> LValue<'gcc> {
+    let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+    let llty = cx.layout_of(ty).gcc_type(cx, true);
+    if let Some(linkage) = attrs.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 =
+            if let ty::RawPtr(ref mt) = ty.kind() {
+                cx.layout_of(mt.ty).gcc_type(cx, true)
+            }
+            else {
+                cx.sess().span_fatal(
+                    span,
+                    "must have type `*const T` or `*mut T` due to `#[linkage]` attribute",
+                )
+            };
+        // Declare a symbol `foo` with the desired linkage.
+        let global1 = cx.declare_global_with_linkage(&sym, llty2, base::global_linkage_to_gcc(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 global2 = cx.define_global(&real_name, llty, is_tls, attrs.link_section);
+        // TODO(antoyo): set linkage.
+        global2.global_set_initializer_value(global1.get_address(None));
+        // TODO(antoyo): use global_set_initializer() when it will work.
+        global2
+    }
+    else {
+        // Generate an external declaration.
+        // FIXME(nagisa): investigate whether it can be changed into define_global
+
+        // 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.
+        cx.declare_global(&sym, llty, is_tls, attrs.link_section)
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs
new file mode 100644 (file)
index 0000000..7677ade
--- /dev/null
@@ -0,0 +1,475 @@
+use std::cell::{Cell, RefCell};
+
+use gccjit::{
+    Block,
+    Context,
+    CType,
+    Function,
+    FunctionType,
+    LValue,
+    RValue,
+    Struct,
+    Type,
+};
+use rustc_codegen_ssa::base::wants_msvc_seh;
+use rustc_codegen_ssa::traits::{
+    BackendTypes,
+    MiscMethods,
+};
+use rustc_data_structures::base_n;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_middle::span_bug;
+use rustc_middle::mir::mono::CodegenUnit;
+use rustc_middle::ty::{self, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, TyAndLayout, LayoutOfHelpers};
+use rustc_session::Session;
+use rustc_span::{Span, Symbol};
+use rustc_target::abi::{call::FnAbi, HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
+use rustc_target::spec::{HasTargetSpec, Target, TlsModel};
+
+use crate::callee::get_fn;
+use crate::declare::mangle_name;
+
+#[derive(Clone)]
+pub struct FuncSig<'gcc> {
+    pub params: Vec<Type<'gcc>>,
+    pub return_type: Type<'gcc>,
+}
+
+pub struct CodegenCx<'gcc, 'tcx> {
+    pub check_overflow: bool,
+    pub codegen_unit: &'tcx CodegenUnit<'tcx>,
+    pub context: &'gcc Context<'gcc>,
+
+    // TODO(antoyo): First set it to a dummy block to avoid using Option?
+    pub current_block: RefCell<Option<Block<'gcc>>>,
+    pub current_func: RefCell<Option<Function<'gcc>>>,
+    pub normal_function_addresses: RefCell<FxHashSet<RValue<'gcc>>>,
+
+    pub functions: RefCell<FxHashMap<String, Function<'gcc>>>,
+
+    pub tls_model: gccjit::TlsModel,
+
+    pub bool_type: Type<'gcc>,
+    pub i8_type: Type<'gcc>,
+    pub i16_type: Type<'gcc>,
+    pub i32_type: Type<'gcc>,
+    pub i64_type: Type<'gcc>,
+    pub i128_type: Type<'gcc>,
+    pub isize_type: Type<'gcc>,
+
+    pub u8_type: Type<'gcc>,
+    pub u16_type: Type<'gcc>,
+    pub u32_type: Type<'gcc>,
+    pub u64_type: Type<'gcc>,
+    pub u128_type: Type<'gcc>,
+    pub usize_type: Type<'gcc>,
+
+    pub int_type: Type<'gcc>,
+    pub uint_type: Type<'gcc>,
+    pub long_type: Type<'gcc>,
+    pub ulong_type: Type<'gcc>,
+    pub ulonglong_type: Type<'gcc>,
+    pub sizet_type: Type<'gcc>,
+
+    pub float_type: Type<'gcc>,
+    pub double_type: Type<'gcc>,
+
+    pub linkage: Cell<FunctionType>,
+    pub scalar_types: RefCell<FxHashMap<Ty<'tcx>, Type<'gcc>>>,
+    pub types: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), Type<'gcc>>>,
+    pub tcx: TyCtxt<'tcx>,
+
+    pub struct_types: RefCell<FxHashMap<Vec<Type<'gcc>>, Type<'gcc>>>,
+
+    pub types_with_fields_to_set: RefCell<FxHashMap<Type<'gcc>, (Struct<'gcc>, TyAndLayout<'tcx>)>>,
+
+    /// Cache instances of monomorphic and polymorphic items
+    pub instances: RefCell<FxHashMap<Instance<'tcx>, LValue<'gcc>>>,
+    /// Cache function instances of monomorphic and polymorphic items
+    pub function_instances: RefCell<FxHashMap<Instance<'tcx>, RValue<'gcc>>>,
+    /// Cache generated vtables
+    pub vtables: RefCell<FxHashMap<(Ty<'tcx>, Option<ty::PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>>,
+
+    /// Cache of emitted const globals (value -> global)
+    pub const_globals: RefCell<FxHashMap<RValue<'gcc>, RValue<'gcc>>>,
+
+    /// Cache of constant strings,
+    pub const_cstr_cache: RefCell<FxHashMap<Symbol, LValue<'gcc>>>,
+
+    /// Cache of globals.
+    pub globals: RefCell<FxHashMap<String, RValue<'gcc>>>,
+
+    /// A counter that is used for generating local symbol names
+    local_gen_sym_counter: Cell<usize>,
+    pub global_gen_sym_counter: Cell<usize>,
+
+    eh_personality: Cell<Option<RValue<'gcc>>>,
+
+    pub pointee_infos: RefCell<FxHashMap<(Ty<'tcx>, Size), Option<PointeeInfo>>>,
+
+    /// NOTE: a hack is used because the rustc API is not suitable to libgccjit and as such,
+    /// `const_undef()` returns struct as pointer so that they can later be assigned a value.
+    /// As such, this set remembers which of these pointers were returned by this function so that
+    /// they can be deferenced later.
+    /// FIXME(antoyo): fix the rustc API to avoid having this hack.
+    pub structs_as_pointer: RefCell<FxHashSet<RValue<'gcc>>>,
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn new(context: &'gcc Context<'gcc>, codegen_unit: &'tcx CodegenUnit<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let check_overflow = tcx.sess.overflow_checks();
+        // TODO(antoyo): fix this mess. libgccjit seems to return random type when using new_int_type().
+        let isize_type = context.new_c_type(CType::LongLong);
+        let usize_type = context.new_c_type(CType::ULongLong);
+        let bool_type = context.new_type::<bool>();
+        let i8_type = context.new_type::<i8>();
+        let i16_type = context.new_type::<i16>();
+        let i32_type = context.new_type::<i32>();
+        let i64_type = context.new_c_type(CType::LongLong);
+        let i128_type = context.new_c_type(CType::Int128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?
+        let u8_type = context.new_type::<u8>();
+        let u16_type = context.new_type::<u16>();
+        let u32_type = context.new_type::<u32>();
+        let u64_type = context.new_c_type(CType::ULongLong);
+        let u128_type = context.new_c_type(CType::UInt128t).get_aligned(8); // TODO(antoyo): should the alignment be hard-coded?
+
+        let tls_model = to_gcc_tls_mode(tcx.sess.tls_model());
+
+        let float_type = context.new_type::<f32>();
+        let double_type = context.new_type::<f64>();
+
+        let int_type = context.new_c_type(CType::Int);
+        let uint_type = context.new_c_type(CType::UInt);
+        let long_type = context.new_c_type(CType::Long);
+        let ulong_type = context.new_c_type(CType::ULong);
+        let ulonglong_type = context.new_c_type(CType::ULongLong);
+        let sizet_type = context.new_c_type(CType::SizeT);
+
+        assert_eq!(isize_type, i64_type);
+        assert_eq!(usize_type, u64_type);
+
+        let mut functions = FxHashMap::default();
+        let builtins = [
+            "__builtin_unreachable", "abort", "__builtin_expect", "__builtin_add_overflow", "__builtin_mul_overflow",
+            "__builtin_saddll_overflow", /*"__builtin_sadd_overflow",*/ "__builtin_smulll_overflow", /*"__builtin_smul_overflow",*/
+            "__builtin_ssubll_overflow", /*"__builtin_ssub_overflow",*/ "__builtin_sub_overflow", "__builtin_uaddll_overflow",
+            "__builtin_uadd_overflow", "__builtin_umulll_overflow", "__builtin_umul_overflow", "__builtin_usubll_overflow",
+            "__builtin_usub_overflow", "sqrtf", "sqrt", "__builtin_powif", "__builtin_powi", "sinf", "sin", "cosf", "cos",
+            "powf", "pow", "expf", "exp", "exp2f", "exp2", "logf", "log", "log10f", "log10", "log2f", "log2", "fmaf",
+            "fma", "fabsf", "fabs", "fminf", "fmin", "fmaxf", "fmax", "copysignf", "copysign", "floorf", "floor", "ceilf",
+            "ceil", "truncf", "trunc", "rintf", "rint", "nearbyintf", "nearbyint", "roundf", "round",
+            "__builtin_expect_with_probability",
+        ];
+
+        for builtin in builtins.iter() {
+            functions.insert(builtin.to_string(), context.get_builtin_function(builtin));
+        }
+
+        Self {
+            check_overflow,
+            codegen_unit,
+            context,
+            current_block: RefCell::new(None),
+            current_func: RefCell::new(None),
+            normal_function_addresses: Default::default(),
+            functions: RefCell::new(functions),
+
+            tls_model,
+
+            bool_type,
+            i8_type,
+            i16_type,
+            i32_type,
+            i64_type,
+            i128_type,
+            isize_type,
+            usize_type,
+            u8_type,
+            u16_type,
+            u32_type,
+            u64_type,
+            u128_type,
+            int_type,
+            uint_type,
+            long_type,
+            ulong_type,
+            ulonglong_type,
+            sizet_type,
+
+            float_type,
+            double_type,
+
+            linkage: Cell::new(FunctionType::Internal),
+            instances: Default::default(),
+            function_instances: Default::default(),
+            vtables: Default::default(),
+            const_globals: Default::default(),
+            const_cstr_cache: Default::default(),
+            globals: Default::default(),
+            scalar_types: Default::default(),
+            types: Default::default(),
+            tcx,
+            struct_types: Default::default(),
+            types_with_fields_to_set: Default::default(),
+            local_gen_sym_counter: Cell::new(0),
+            global_gen_sym_counter: Cell::new(0),
+            eh_personality: Cell::new(None),
+            pointee_infos: Default::default(),
+            structs_as_pointer: Default::default(),
+        }
+    }
+
+    pub fn rvalue_as_function(&self, value: RValue<'gcc>) -> Function<'gcc> {
+        let function: Function<'gcc> = unsafe { std::mem::transmute(value) };
+        debug_assert!(self.functions.borrow().values().find(|value| **value == function).is_some(),
+            "{:?} ({:?}) is not a function", value, value.get_type());
+        function
+    }
+
+    pub fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+}
+
+impl<'gcc, 'tcx> BackendTypes for CodegenCx<'gcc, 'tcx> {
+    type Value = RValue<'gcc>;
+    type Function = RValue<'gcc>;
+
+    type BasicBlock = Block<'gcc>;
+    type Type = Type<'gcc>;
+    type Funclet = (); // TODO(antoyo)
+
+    type DIScope = (); // TODO(antoyo)
+    type DILocation = (); // TODO(antoyo)
+    type DIVariable = (); // TODO(antoyo)
+}
+
+impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn vtables(&self) -> &RefCell<FxHashMap<(Ty<'tcx>, Option<PolyExistentialTraitRef<'tcx>>), RValue<'gcc>>> {
+        &self.vtables
+    }
+
+    fn get_fn(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
+        let func = get_fn(self, instance);
+        *self.current_func.borrow_mut() = Some(self.rvalue_as_function(func));
+        func
+    }
+
+    fn get_fn_addr(&self, instance: Instance<'tcx>) -> RValue<'gcc> {
+        let func = get_fn(self, instance);
+        let func = self.rvalue_as_function(func);
+        let ptr = func.get_address(None);
+
+        // TODO(antoyo): don't do this twice: i.e. in declare_fn and here.
+        // FIXME(antoyo): the rustc API seems to call get_fn_addr() when not needed (e.g. for FFI).
+
+        self.normal_function_addresses.borrow_mut().insert(ptr);
+
+        ptr
+    }
+
+    fn eh_personality(&self) -> RValue<'gcc> {
+        // 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 !wants_msvc_seh(self.sess()) => self.get_fn_addr(
+                ty::Instance::resolve(
+                    tcx,
+                    ty::ParamEnv::reveal_all(),
+                    def_id,
+                    tcx.intern_substs(&[]),
+                )
+                .unwrap().unwrap(),
+            ),
+            _ => {
+                let _name = if wants_msvc_seh(self.sess()) {
+                    "__CxxFrameHandler3"
+                } else {
+                    "rust_eh_personality"
+                };
+                //let func = self.declare_func(name, self.type_i32(), &[], true);
+                // FIXME(antoyo): this hack should not be needed. That will probably be removed when
+                // unwinding support is added.
+                self.context.new_rvalue_from_int(self.int_type, 0)
+            }
+        };
+        // TODO(antoyo): apply target cpu attributes.
+        self.eh_personality.set(Some(llfn));
+        llfn
+    }
+
+    fn sess(&self) -> &Session {
+        &self.tcx.sess
+    }
+
+    fn check_overflow(&self) -> bool {
+        self.check_overflow
+    }
+
+    fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> {
+        self.codegen_unit
+    }
+
+    fn used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
+        unimplemented!();
+    }
+
+    fn set_frame_pointer_type(&self, _llfn: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn apply_target_cpu_attr(&self, _llfn: RValue<'gcc>) {
+        // TODO(antoyo)
+    }
+
+    fn create_used_variable(&self) {
+        unimplemented!();
+    }
+
+    fn declare_c_main(&self, fn_type: Self::Type) -> Option<Self::Function> {
+        if self.get_declared_value("main").is_none() {
+            Some(self.declare_cfn("main", fn_type))
+        }
+        else {
+            // If the symbol already exists, it is an error: for example, the user wrote
+            // #[no_mangle] extern "C" fn main(..) {..}
+            // instead of #[start]
+            None
+        }
+    }
+
+    fn compiler_used_statics(&self) -> &RefCell<Vec<RValue<'gcc>>> {
+        unimplemented!()
+    }
+
+    fn create_compiler_used_variable(&self) {
+        unimplemented!()
+    }
+}
+
+impl<'gcc, 'tcx> HasTyCtxt<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
+
+impl<'gcc, 'tcx> HasDataLayout for CodegenCx<'gcc, 'tcx> {
+    fn data_layout(&self) -> &TargetDataLayout {
+        &self.tcx.data_layout
+    }
+}
+
+impl<'gcc, 'tcx> HasTargetSpec for CodegenCx<'gcc, 'tcx> {
+    fn target_spec(&self) -> &Target {
+        &self.tcx.sess.target
+    }
+}
+
+impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
+    type LayoutOfResult = TyAndLayout<'tcx>;
+
+    #[inline]
+    fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
+        if let LayoutError::SizeOverflow(_) = err {
+            self.sess().span_fatal(span, &err.to_string())
+        } else {
+            span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
+        }
+    }
+}
+
+impl<'gcc, 'tcx> FnAbiOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
+    type FnAbiOfResult = &'tcx FnAbi<'tcx, Ty<'tcx>>;
+
+    #[inline]
+    fn handle_fn_abi_err(
+        &self,
+        err: FnAbiError<'tcx>,
+        span: Span,
+        fn_abi_request: FnAbiRequest<'tcx>,
+    ) -> ! {
+        if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
+            self.sess().span_fatal(span, &err.to_string())
+        } else {
+            match fn_abi_request {
+                FnAbiRequest::OfFnPtr { sig, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_fn_ptr({}, {:?})` failed: {}",
+                        sig,
+                        extra_args,
+                        err
+                    );
+                }
+                FnAbiRequest::OfInstance { instance, extra_args } => {
+                    span_bug!(
+                        span,
+                        "`fn_abi_of_instance({}, {:?})` failed: {}",
+                        instance,
+                        extra_args,
+                        err
+                    );
+                }
+            }
+        }
+    }
+}
+
+impl<'tcx, 'gcc> HasParamEnv<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn param_env(&self) -> ParamEnv<'tcx> {
+        ParamEnv::reveal_all()
+    }
+}
+
+impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
+    /// Generates 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 unit_name<'tcx>(codegen_unit: &CodegenUnit<'tcx>) -> String {
+    let name = &codegen_unit.name().to_string();
+    mangle_name(&name.replace('-', "_"))
+}
+
+fn to_gcc_tls_mode(tls_model: TlsModel) -> gccjit::TlsModel {
+    match tls_model {
+        TlsModel::GeneralDynamic => gccjit::TlsModel::GlobalDynamic,
+        TlsModel::LocalDynamic => gccjit::TlsModel::LocalDynamic,
+        TlsModel::InitialExec => gccjit::TlsModel::InitialExec,
+        TlsModel::LocalExec => gccjit::TlsModel::LocalExec,
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/coverageinfo.rs b/compiler/rustc_codegen_gcc/src/coverageinfo.rs
new file mode 100644 (file)
index 0000000..872fc24
--- /dev/null
@@ -0,0 +1,69 @@
+use gccjit::RValue;
+use rustc_codegen_ssa::traits::{CoverageInfoBuilderMethods, CoverageInfoMethods};
+use rustc_hir::def_id::DefId;
+use rustc_middle::mir::coverage::{
+    CodeRegion,
+    CounterValueReference,
+    ExpressionOperandId,
+    InjectedExpressionId,
+    Op,
+};
+use rustc_middle::ty::Instance;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+impl<'a, 'gcc, 'tcx> CoverageInfoBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn set_function_source_hash(
+        &mut self,
+        _instance: Instance<'tcx>,
+        _function_source_hash: u64,
+    ) -> bool {
+        unimplemented!();
+    }
+
+    fn add_coverage_counter(&mut self, _instance: Instance<'tcx>, _id: CounterValueReference, _region: CodeRegion) -> bool {
+        // TODO(antoyo)
+        false
+    }
+
+    fn add_coverage_counter_expression(&mut self, _instance: Instance<'tcx>, _id: InjectedExpressionId, _lhs: ExpressionOperandId, _op: Op, _rhs: ExpressionOperandId, _region: Option<CodeRegion>) -> bool {
+        // TODO(antoyo)
+        false
+    }
+
+    fn add_coverage_unreachable(&mut self, _instance: Instance<'tcx>, _region: CodeRegion) -> bool {
+        // TODO(antoyo)
+        false
+    }
+}
+
+impl<'gcc, 'tcx> CoverageInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn coverageinfo_finalize(&self) {
+        // TODO(antoyo)
+    }
+
+    fn get_pgo_func_name_var(&self, _instance: Instance<'tcx>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    /// Functions with MIR-based coverage are normally codegenned _only_ if
+    /// called. LLVM coverage tools typically expect every function to be
+    /// defined (even if unused), with at least one call to LLVM intrinsic
+    /// `instrprof.increment`.
+    ///
+    /// Codegen a small function that will never be called, with one counter
+    /// that will never be incremented.
+    ///
+    /// For used/called functions, the coverageinfo was already added to the
+    /// `function_coverage_map` (keyed by function `Instance`) during codegen.
+    /// But in this case, since the unused function was _not_ previously
+    /// codegenned, collect the coverage `CodeRegion`s from the MIR and add
+    /// them. The first `CodeRegion` is used to add a single counter, with the
+    /// same counter ID used in the injected `instrprof.increment` intrinsic
+    /// call. Since the function is never called, all other `CodeRegion`s can be
+    /// added as `unreachable_region`s.
+    fn define_unused_fn(&self, _def_id: DefId) {
+        unimplemented!();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
new file mode 100644 (file)
index 0000000..4d3b4f0
--- /dev/null
@@ -0,0 +1,62 @@
+use gccjit::RValue;
+use rustc_codegen_ssa::mir::debuginfo::{FunctionDebugContext, VariableKind};
+use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
+use rustc_middle::mir;
+use rustc_middle::ty::{Instance, Ty};
+use rustc_span::{SourceFile, Span, Symbol};
+use rustc_target::abi::Size;
+use rustc_target::abi::call::FnAbi;
+
+use crate::builder::Builder;
+use crate::context::CodegenCx;
+
+impl<'a, 'gcc, 'tcx> DebugInfoBuilderMethods for Builder<'a, 'gcc, 'tcx> {
+    // FIXME(eddyb) find a common convention for all of the debuginfo-related
+    // names (choose between `dbg`, `debug`, `debuginfo`, `debug_info` etc.).
+    fn dbg_var_addr(&mut self, _dbg_var: Self::DIVariable, _scope_metadata: Self::DIScope, _variable_alloca: Self::Value, _direct_offset: Size, _indirect_offsets: &[Size]) {
+        unimplemented!();
+    }
+
+    fn insert_reference_to_gdb_debug_scripts_section_global(&mut self) {
+        // TODO(antoyo): insert reference to gdb debug scripts section global.
+    }
+
+    fn set_var_name(&mut self, _value: RValue<'gcc>, _name: &str) {
+        unimplemented!();
+    }
+
+    fn set_dbg_loc(&mut self, _dbg_loc: Self::DILocation) {
+        unimplemented!();
+    }
+}
+
+impl<'gcc, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn create_vtable_metadata(&self, _ty: Ty<'tcx>, _vtable: Self::Value) {
+        // TODO(antoyo)
+    }
+
+    fn create_function_debug_context(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _llfn: RValue<'gcc>, _mir: &mir::Body<'tcx>) -> Option<FunctionDebugContext<Self::DIScope, Self::DILocation>> {
+        // TODO(antoyo)
+        None
+    }
+
+    fn extend_scope_to_file(&self, _scope_metadata: Self::DIScope, _file: &SourceFile) -> Self::DIScope {
+        unimplemented!();
+    }
+
+    fn debuginfo_finalize(&self) {
+        // TODO(antoyo)
+    }
+
+    fn create_dbg_var(&self, _variable_name: Symbol, _variable_type: Ty<'tcx>, _scope_metadata: Self::DIScope, _variable_kind: VariableKind, _span: Span) -> Self::DIVariable {
+        unimplemented!();
+    }
+
+    fn dbg_scope_fn(&self, _instance: Instance<'tcx>, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>, _maybe_definition_llfn: Option<RValue<'gcc>>) -> Self::DIScope {
+        unimplemented!();
+    }
+
+    fn dbg_loc(&self, _scope: Self::DIScope, _inlined_at: Option<Self::DILocation>, _span: Span) -> Self::DILocation {
+        unimplemented!();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/declare.rs b/compiler/rustc_codegen_gcc/src/declare.rs
new file mode 100644 (file)
index 0000000..b79a50d
--- /dev/null
@@ -0,0 +1,144 @@
+use gccjit::{Function, FunctionType, GlobalKind, LValue, RValue, Type};
+use rustc_codegen_ssa::traits::BaseTypeMethods;
+use rustc_middle::ty::Ty;
+use rustc_span::Symbol;
+use rustc_target::abi::call::FnAbi;
+
+use crate::abi::FnAbiGccExt;
+use crate::context::{CodegenCx, unit_name};
+use crate::intrinsic::llvm;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn get_or_insert_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
+        if self.globals.borrow().contains_key(name) {
+            let typ = self.globals.borrow().get(name).expect("global").get_type();
+            let global = self.context.new_global(None, GlobalKind::Imported, typ, name);
+            if is_tls {
+                global.set_tls_model(self.tls_model);
+            }
+            if let Some(link_section) = link_section {
+                global.set_link_section(&link_section.as_str());
+            }
+            global
+        }
+        else {
+            self.declare_global(name, ty, is_tls, link_section)
+        }
+    }
+
+    pub fn declare_unnamed_global(&self, ty: Type<'gcc>) -> LValue<'gcc> {
+        let index = self.global_gen_sym_counter.get();
+        self.global_gen_sym_counter.set(index + 1);
+        let name = format!("global_{}_{}", index, unit_name(&self.codegen_unit));
+        self.context.new_global(None, GlobalKind::Exported, ty, &name)
+    }
+
+    pub fn declare_global_with_linkage(&self, name: &str, ty: Type<'gcc>, linkage: GlobalKind) -> LValue<'gcc> {
+        let global = self.context.new_global(None, linkage, ty, name);
+        let global_address = global.get_address(None);
+        self.globals.borrow_mut().insert(name.to_string(), global_address);
+        global
+    }
+
+    /*pub fn declare_func(&self, name: &str, return_type: Type<'gcc>, params: &[Type<'gcc>], variadic: bool) -> RValue<'gcc> {
+        self.linkage.set(FunctionType::Exported);
+        let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, params, variadic);
+        // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+        unsafe { std::mem::transmute(func) }
+    }*/
+
+    pub fn declare_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
+        let global = self.context.new_global(None, GlobalKind::Exported, ty, name);
+        if is_tls {
+            global.set_tls_model(self.tls_model);
+        }
+        if let Some(link_section) = link_section {
+            global.set_link_section(&link_section.as_str());
+        }
+        let global_address = global.get_address(None);
+        self.globals.borrow_mut().insert(name.to_string(), global_address);
+        global
+    }
+
+    pub fn declare_private_global(&self, name: &str, ty: Type<'gcc>) -> LValue<'gcc> {
+        let global = self.context.new_global(None, GlobalKind::Internal, ty, name);
+        let global_address = global.get_address(None);
+        self.globals.borrow_mut().insert(name.to_string(), global_address);
+        global
+    }
+
+    pub fn declare_cfn(&self, name: &str, _fn_type: Type<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use the fn_type parameter.
+        let const_string = self.context.new_type::<u8>().make_pointer().make_pointer();
+        let return_type = self.type_i32();
+        let variadic = false;
+        self.linkage.set(FunctionType::Exported);
+        let func = declare_raw_fn(self, name, () /*llvm::CCallConv*/, return_type, &[self.type_i32(), const_string], variadic);
+        // NOTE: it is needed to set the current_func here as well, because get_fn() is not called
+        // for the main function.
+        *self.current_func.borrow_mut() = Some(func);
+        // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+        unsafe { std::mem::transmute(func) }
+    }
+
+    pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> RValue<'gcc> {
+        let (return_type, params, variadic) = fn_abi.gcc_type(self);
+        let func = declare_raw_fn(self, name, () /*fn_abi.llvm_cconv()*/, return_type, &params, variadic);
+        // FIXME(antoyo): this is a wrong cast. That requires changing the compiler API.
+        unsafe { std::mem::transmute(func) }
+    }
+
+    pub fn define_global(&self, name: &str, ty: Type<'gcc>, is_tls: bool, link_section: Option<Symbol>) -> LValue<'gcc> {
+        self.get_or_insert_global(name, ty, is_tls, link_section)
+    }
+
+    pub fn get_declared_value(&self, name: &str) -> Option<RValue<'gcc>> {
+        // TODO(antoyo): use a different field than globals, because this seems to return a function?
+        self.globals.borrow().get(name).cloned()
+    }
+}
+
+/// Declare a function.
+///
+/// If there’s a value with the same name already declared, the function will
+/// update the declaration and return existing Value instead.
+fn declare_raw_fn<'gcc>(cx: &CodegenCx<'gcc, '_>, name: &str, _callconv: () /*llvm::CallConv*/, return_type: Type<'gcc>, param_types: &[Type<'gcc>], variadic: bool) -> Function<'gcc> {
+    if name.starts_with("llvm.") {
+        return llvm::intrinsic(name, cx);
+    }
+    let func =
+        if cx.functions.borrow().contains_key(name) {
+            *cx.functions.borrow().get(name).expect("function")
+        }
+        else {
+            let params: Vec<_> = param_types.into_iter().enumerate()
+                .map(|(index, param)| cx.context.new_parameter(None, *param, &format!("param{}", index))) // TODO(antoyo): set name.
+                .collect();
+            let func = cx.context.new_function(None, cx.linkage.get(), return_type, &params, mangle_name(name), variadic);
+            cx.functions.borrow_mut().insert(name.to_string(), func);
+            func
+        };
+
+    // TODO(antoyo): set function calling convention.
+    // TODO(antoyo): set unnamed address.
+    // TODO(antoyo): set no red zone function attribute.
+    // TODO(antoyo): set attributes for optimisation.
+    // TODO(antoyo): set attributes for non lazy bind.
+
+    // FIXME(antoyo): invalid cast.
+    func
+}
+
+// FIXME(antoyo): this is a hack because libgccjit currently only supports alpha, num and _.
+// Unsupported characters: `$` and `.`.
+pub fn mangle_name(name: &str) -> String {
+    name.replace(|char: char| {
+        if !char.is_alphanumeric() && char != '_' {
+            debug_assert!("$.".contains(char), "Unsupported char in function name: {}", char);
+            true
+        }
+        else {
+            false
+        }
+    }, "_")
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs b/compiler/rustc_codegen_gcc/src/intrinsic/llvm.rs
new file mode 100644 (file)
index 0000000..b074feb
--- /dev/null
@@ -0,0 +1,22 @@
+use gccjit::Function;
+
+use crate::context::CodegenCx;
+
+pub fn intrinsic<'gcc, 'tcx>(name: &str, cx: &CodegenCx<'gcc, 'tcx>) -> Function<'gcc> {
+    let _gcc_name =
+        match name {
+            "llvm.x86.xgetbv" => {
+                let gcc_name = "__builtin_trap";
+                let func = cx.context.get_builtin_function(gcc_name);
+                cx.functions.borrow_mut().insert(gcc_name.to_string(), func);
+                return func;
+            },
+            // NOTE: this doc specifies the equivalent GCC builtins: http://huonw.github.io/llvmint/llvmint/x86/index.html
+            "llvm.x86.sse2.cmp.pd" => "__builtin_ia32_cmppd",
+            "llvm.x86.sse2.movmsk.pd" => "__builtin_ia32_movmskpd",
+            "llvm.x86.sse2.pmovmskb.128" => "__builtin_ia32_pmovmskb128",
+            _ => unimplemented!("unsupported LLVM intrinsic {}", name)
+        };
+
+    unimplemented!();
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
new file mode 100644 (file)
index 0000000..375d422
--- /dev/null
@@ -0,0 +1,1067 @@
+pub mod llvm;
+mod simd;
+
+use gccjit::{ComparisonOp, Function, RValue, ToRValue, Type, UnaryOp};
+use rustc_codegen_ssa::MemFlags;
+use rustc_codegen_ssa::base::wants_msvc_seh;
+use rustc_codegen_ssa::common::{IntPredicate, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
+use rustc_codegen_ssa::mir::place::PlaceRef;
+use rustc_codegen_ssa::traits::{ArgAbiMethods, BaseTypeMethods, BuilderMethods, ConstMethods, IntrinsicCallMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Instance, Ty};
+use rustc_middle::ty::layout::LayoutOf;
+use rustc_span::{Span, Symbol, symbol::kw, sym};
+use rustc_target::abi::HasDataLayout;
+use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
+use rustc_target::spec::PanicStrategy;
+
+use crate::abi::GccType;
+use crate::builder::Builder;
+use crate::common::{SignType, TypeReflection};
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+use crate::intrinsic::simd::generic_simd_intrinsic;
+
+fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) -> Option<Function<'gcc>> {
+    let gcc_name = match name {
+        sym::sqrtf32 => "sqrtf",
+        sym::sqrtf64 => "sqrt",
+        sym::powif32 => "__builtin_powif",
+        sym::powif64 => "__builtin_powi",
+        sym::sinf32 => "sinf",
+        sym::sinf64 => "sin",
+        sym::cosf32 => "cosf",
+        sym::cosf64 => "cos",
+        sym::powf32 => "powf",
+        sym::powf64 => "pow",
+        sym::expf32 => "expf",
+        sym::expf64 => "exp",
+        sym::exp2f32 => "exp2f",
+        sym::exp2f64 => "exp2",
+        sym::logf32 => "logf",
+        sym::logf64 => "log",
+        sym::log10f32 => "log10f",
+        sym::log10f64 => "log10",
+        sym::log2f32 => "log2f",
+        sym::log2f64 => "log2",
+        sym::fmaf32 => "fmaf",
+        sym::fmaf64 => "fma",
+        sym::fabsf32 => "fabsf",
+        sym::fabsf64 => "fabs",
+        sym::minnumf32 => "fminf",
+        sym::minnumf64 => "fmin",
+        sym::maxnumf32 => "fmaxf",
+        sym::maxnumf64 => "fmax",
+        sym::copysignf32 => "copysignf",
+        sym::copysignf64 => "copysign",
+        sym::floorf32 => "floorf",
+        sym::floorf64 => "floor",
+        sym::ceilf32 => "ceilf",
+        sym::ceilf64 => "ceil",
+        sym::truncf32 => "truncf",
+        sym::truncf64 => "trunc",
+        sym::rintf32 => "rintf",
+        sym::rintf64 => "rint",
+        sym::nearbyintf32 => "nearbyintf",
+        sym::nearbyintf64 => "nearbyint",
+        sym::roundf32 => "roundf",
+        sym::roundf64 => "round",
+        sym::abort => "abort",
+        _ => return None,
+    };
+    Some(cx.context.get_builtin_function(&gcc_name))
+}
+
+impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn codegen_intrinsic_call(&mut self, instance: Instance<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, args: &[OperandRef<'tcx, RValue<'gcc>>], llresult: RValue<'gcc>, span: Span) {
+        let tcx = self.tcx;
+        let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
+
+        let (def_id, substs) = match *callee_ty.kind() {
+            ty::FnDef(def_id, substs) => (def_id, substs),
+            _ => bug!("expected fn item type, found {}", callee_ty),
+        };
+
+        let sig = callee_ty.fn_sig(tcx);
+        let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
+        let arg_tys = sig.inputs();
+        let ret_ty = sig.output();
+        let name = tcx.item_name(def_id);
+        let name_str = &*name.as_str();
+
+        let llret_ty = self.layout_of(ret_ty).gcc_type(self, true);
+        let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
+
+        let simple = get_simple_intrinsic(self, name);
+        let llval =
+            match name {
+                _ if simple.is_some() => {
+                    // FIXME(antoyo): remove this cast when the API supports function.
+                    let func = unsafe { std::mem::transmute(simple.expect("simple")) };
+                    self.call(self.type_void(), func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
+                },
+                sym::likely => {
+                    self.expect(args[0].immediate(), true)
+                }
+                sym::unlikely => {
+                    self.expect(args[0].immediate(), false)
+                }
+                kw::Try => {
+                    try_intrinsic(
+                        self,
+                        args[0].immediate(),
+                        args[1].immediate(),
+                        args[2].immediate(),
+                        llresult,
+                    );
+                    return;
+                }
+                sym::breakpoint => {
+                    unimplemented!();
+                }
+                sym::va_copy => {
+                    unimplemented!();
+                }
+                sym::va_arg => {
+                    unimplemented!();
+                }
+
+                sym::volatile_load | sym::unaligned_volatile_load => {
+                    let tp_ty = substs.type_at(0);
+                    let mut ptr = args[0].immediate();
+                    if let PassMode::Cast(ty) = fn_abi.ret.mode {
+                        ptr = self.pointercast(ptr, self.type_ptr_to(ty.gcc_type(self)));
+                    }
+                    let load = self.volatile_load(ptr.get_type(), ptr);
+                    // TODO(antoyo): set alignment.
+                    self.to_immediate(load, self.layout_of(tp_ty))
+                }
+                sym::volatile_store => {
+                    let dst = args[0].deref(self.cx());
+                    args[1].val.volatile_store(self, dst);
+                    return;
+                }
+                sym::unaligned_volatile_store => {
+                    let dst = args[0].deref(self.cx());
+                    args[1].val.unaligned_volatile_store(self, dst);
+                    return;
+                }
+                sym::prefetch_read_data
+                    | sym::prefetch_write_data
+                    | sym::prefetch_read_instruction
+                    | sym::prefetch_write_instruction => {
+                        unimplemented!();
+                    }
+                sym::ctlz
+                    | sym::ctlz_nonzero
+                    | sym::cttz
+                    | sym::cttz_nonzero
+                    | sym::ctpop
+                    | sym::bswap
+                    | sym::bitreverse
+                    | sym::rotate_left
+                    | sym::rotate_right
+                    | sym::saturating_add
+                    | sym::saturating_sub => {
+                        let ty = arg_tys[0];
+                        match int_type_width_signed(ty, self) {
+                            Some((width, signed)) => match name {
+                                sym::ctlz | sym::cttz => {
+                                    let func = self.current_func.borrow().expect("func");
+                                    let then_block = func.new_block("then");
+                                    let else_block = func.new_block("else");
+                                    let after_block = func.new_block("after");
+
+                                    let arg = args[0].immediate();
+                                    let result = func.new_local(None, arg.get_type(), "zeros");
+                                    let zero = self.cx.context.new_rvalue_zero(arg.get_type());
+                                    let cond = self.cx.context.new_comparison(None, ComparisonOp::Equals, arg, zero);
+                                    self.llbb().end_with_conditional(None, cond, then_block, else_block);
+
+                                    let zero_result = self.cx.context.new_rvalue_from_long(arg.get_type(), width as i64);
+                                    then_block.add_assignment(None, result, zero_result);
+                                    then_block.end_with_jump(None, after_block);
+
+                                    // NOTE: since jumps were added in a place
+                                    // count_leading_zeroes() does not expect, the current blocks
+                                    // in the state need to be updated.
+                                    *self.current_block.borrow_mut() = Some(else_block);
+                                    self.block = Some(else_block);
+
+                                    let zeros =
+                                        match name {
+                                            sym::ctlz => self.count_leading_zeroes(width, arg),
+                                            sym::cttz => self.count_trailing_zeroes(width, arg),
+                                            _ => unreachable!(),
+                                        };
+                                    else_block.add_assignment(None, result, zeros);
+                                    else_block.end_with_jump(None, after_block);
+
+                                    // NOTE: since jumps were added in a place rustc does not
+                                    // expect, the current blocks in the state need to be updated.
+                                    *self.current_block.borrow_mut() = Some(after_block);
+                                    self.block = Some(after_block);
+
+                                    result.to_rvalue()
+                                }
+                                sym::ctlz_nonzero => {
+                                    self.count_leading_zeroes(width, args[0].immediate())
+                                },
+                                sym::cttz_nonzero => {
+                                    self.count_trailing_zeroes(width, args[0].immediate())
+                                }
+                                sym::ctpop => self.pop_count(args[0].immediate()),
+                                sym::bswap => {
+                                    if width == 8 {
+                                        args[0].immediate() // byte swap a u8/i8 is just a no-op
+                                    }
+                                    else {
+                                        // TODO(antoyo): check if it's faster to use string literals and a
+                                        // match instead of format!.
+                                        let bswap = self.cx.context.get_builtin_function(&format!("__builtin_bswap{}", width));
+                                        let mut arg = args[0].immediate();
+                                        // FIXME(antoyo): this cast should not be necessary. Remove
+                                        // when having proper sized integer types.
+                                        let param_type = bswap.get_param(0).to_rvalue().get_type();
+                                        if param_type != arg.get_type() {
+                                            arg = self.bitcast(arg, param_type);
+                                        }
+                                        self.cx.context.new_call(None, bswap, &[arg])
+                                    }
+                                },
+                                sym::bitreverse => self.bit_reverse(width, args[0].immediate()),
+                                sym::rotate_left | sym::rotate_right => {
+                                    // TODO(antoyo): implement using algorithm from:
+                                    // https://blog.regehr.org/archives/1063
+                                    // for other platforms.
+                                    let is_left = name == sym::rotate_left;
+                                    let val = args[0].immediate();
+                                    let raw_shift = args[1].immediate();
+                                    if is_left {
+                                        self.rotate_left(val, raw_shift, width)
+                                    }
+                                    else {
+                                        self.rotate_right(val, raw_shift, width)
+                                    }
+                                },
+                                sym::saturating_add => {
+                                    self.saturating_add(args[0].immediate(), args[1].immediate(), signed, width)
+                                },
+                                sym::saturating_sub => {
+                                    self.saturating_sub(args[0].immediate(), args[1].immediate(), signed, width)
+                                },
+                                _ => bug!(),
+                            },
+                            None => {
+                                span_invalid_monomorphization_error(
+                                    tcx.sess,
+                                    span,
+                                    &format!(
+                                        "invalid monomorphization of `{}` intrinsic: \
+                                      expected basic integer type, found `{}`",
+                                      name, ty
+                                    ),
+                                );
+                                return;
+                            }
+                        }
+                    }
+
+                sym::raw_eq => {
+                    use rustc_target::abi::Abi::*;
+                    let tp_ty = substs.type_at(0);
+                    let layout = self.layout_of(tp_ty).layout;
+                    let _use_integer_compare = match layout.abi {
+                        Scalar(_) | ScalarPair(_, _) => true,
+                        Uninhabited | Vector { .. } => false,
+                        Aggregate { .. } => {
+                            // For rusty ABIs, small aggregates are actually passed
+                            // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
+                            // so we re-use that same threshold here.
+                            layout.size <= self.data_layout().pointer_size * 2
+                        }
+                    };
+
+                    let a = args[0].immediate();
+                    let b = args[1].immediate();
+                    if layout.size.bytes() == 0 {
+                        self.const_bool(true)
+                    }
+                    /*else if use_integer_compare {
+                        let integer_ty = self.type_ix(layout.size.bits()); // FIXME(antoyo): LLVM creates an integer of 96 bits for [i32; 3], but gcc doesn't support this, so it creates an integer of 128 bits.
+                        let ptr_ty = self.type_ptr_to(integer_ty);
+                        let a_ptr = self.bitcast(a, ptr_ty);
+                        let a_val = self.load(integer_ty, a_ptr, layout.align.abi);
+                        let b_ptr = self.bitcast(b, ptr_ty);
+                        let b_val = self.load(integer_ty, b_ptr, layout.align.abi);
+                        self.icmp(IntPredicate::IntEQ, a_val, b_val)
+                    }*/
+                    else {
+                        let void_ptr_type = self.context.new_type::<*const ()>();
+                        let a_ptr = self.bitcast(a, void_ptr_type);
+                        let b_ptr = self.bitcast(b, void_ptr_type);
+                        let n = self.context.new_cast(None, self.const_usize(layout.size.bytes()), self.sizet_type);
+                        let builtin = self.context.get_builtin_function("memcmp");
+                        let cmp = self.context.new_call(None, builtin, &[a_ptr, b_ptr, n]);
+                        self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0))
+                    }
+                }
+
+                sym::black_box => {
+                    args[0].val.store(self, result);
+
+                    let block = self.llbb();
+                    let extended_asm = block.add_extended_asm(None, "");
+                    extended_asm.add_input_operand(None, "r", result.llval);
+                    extended_asm.add_clobber("memory");
+                    extended_asm.set_volatile_flag(true);
+                    
+                    // We have copied the value to `result` already.
+                    return;
+                }
+
+                _ if name_str.starts_with("simd_") => {
+                    match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
+                        Ok(llval) => llval,
+                        Err(()) => return,
+                    }
+                }
+
+                _ => bug!("unknown intrinsic '{}'", name),
+            };
+
+        if !fn_abi.ret.is_ignore() {
+            if let PassMode::Cast(ty) = fn_abi.ret.mode {
+                let ptr_llty = self.type_ptr_to(ty.gcc_type(self));
+                let ptr = self.pointercast(result.llval, ptr_llty);
+                self.store(llval, ptr, result.align);
+            }
+            else {
+                OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
+                    .val
+                    .store(self, result);
+            }
+        }
+    }
+
+    fn abort(&mut self) {
+        let func = self.context.get_builtin_function("abort");
+        let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
+        self.call(self.type_void(), func, &[], None);
+    }
+
+    fn assume(&mut self, value: Self::Value) {
+        // TODO(antoyo): switch to asumme when it exists.
+        // Or use something like this:
+        // #define __assume(cond) do { if (!(cond)) __builtin_unreachable(); } while (0)
+        self.expect(value, true);
+    }
+
+    fn expect(&mut self, cond: Self::Value, _expected: bool) -> Self::Value {
+        // TODO(antoyo)
+        cond
+    }
+
+    fn sideeffect(&mut self) {
+        // TODO(antoyo)
+    }
+
+    fn va_start(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+
+    fn va_end(&mut self, _va_list: RValue<'gcc>) -> RValue<'gcc> {
+        unimplemented!();
+    }
+}
+
+impl<'a, 'gcc, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
+    fn store_fn_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, idx: &mut usize, dst: PlaceRef<'tcx, Self::Value>) {
+        arg_abi.store_fn_arg(self, idx, dst)
+    }
+
+    fn store_arg(&mut self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+        arg_abi.store(self, val, dst)
+    }
+
+    fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+        arg_abi.memory_ty(self)
+    }
+}
+
+pub trait ArgAbiExt<'gcc, 'tcx> {
+    fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+    fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>);
+    fn store_fn_arg(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>);
+}
+
+impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
+    /// Gets the LLVM type for a place of the original Rust type of
+    /// this argument/return, i.e., the result of `type_of::type_of`.
+    fn memory_ty(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        self.layout.gcc_type(cx, true)
+    }
+
+    /// Stores a direct/indirect value described by this ArgAbi into a
+    /// place for the original Rust type of this argument/return.
+    /// Can be used for both storing formal arguments into Rust variables
+    /// or results of call/invoke instructions into their destinations.
+    fn store(&self, bx: &mut Builder<'_, 'gcc, 'tcx>, val: RValue<'gcc>, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+        if self.is_ignore() {
+            return;
+        }
+        if self.is_sized_indirect() {
+            OperandValue::Ref(val, None, self.layout.align.abi).store(bx, dst)
+        }
+        else if self.is_unsized_indirect() {
+            bug!("unsized `ArgAbi` must be handled through `store_fn_arg`");
+        }
+        else if let PassMode::Cast(cast) = self.mode {
+            // FIXME(eddyb): Figure out when the simpler Store is safe, clang
+            // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}.
+            let can_store_through_cast_ptr = false;
+            if can_store_through_cast_ptr {
+                let cast_ptr_llty = bx.type_ptr_to(cast.gcc_type(bx));
+                let cast_dst = bx.pointercast(dst.llval, cast_ptr_llty);
+                bx.store(val, cast_dst, self.layout.align.abi);
+            }
+            else {
+                // The actual return type is a struct, but the ABI
+                // adaptation code has cast it into some scalar type.  The
+                // code that follows is the only reliable way I have
+                // found to do a transform like i64 -> {i32,i32}.
+                // Basically we dump the data onto the stack then memcpy it.
+                //
+                // Other approaches I tried:
+                // - Casting rust ret pointer to the foreign type and using Store
+                //   is (a) unsafe if size of foreign type > size of rust type and
+                //   (b) runs afoul of strict aliasing rules, yielding invalid
+                //   assembly under -O (specifically, the store gets removed).
+                // - Truncating foreign type to correct integral type and then
+                //   bitcasting to the struct type yields invalid cast errors.
+
+                // We instead thus allocate some scratch space...
+                let scratch_size = cast.size(bx);
+                let scratch_align = cast.align(bx);
+                let llscratch = bx.alloca(cast.gcc_type(bx), scratch_align);
+                bx.lifetime_start(llscratch, scratch_size);
+
+                // ... where we first store the value...
+                bx.store(val, llscratch, scratch_align);
+
+                // ... and then memcpy it to the intended destination.
+                bx.memcpy(
+                    dst.llval,
+                    self.layout.align.abi,
+                    llscratch,
+                    scratch_align,
+                    bx.const_usize(self.layout.size.bytes()),
+                    MemFlags::empty(),
+                );
+
+                bx.lifetime_end(llscratch, scratch_size);
+            }
+        }
+        else {
+            OperandValue::Immediate(val).store(bx, dst);
+        }
+    }
+
+    fn store_fn_arg<'a>(&self, bx: &mut Builder<'a, 'gcc, 'tcx>, idx: &mut usize, dst: PlaceRef<'tcx, RValue<'gcc>>) {
+        let mut next = || {
+            let val = bx.current_func().get_param(*idx as i32);
+            *idx += 1;
+            val.to_rvalue()
+        };
+        match self.mode {
+            PassMode::Ignore => {}
+            PassMode::Pair(..) => {
+                OperandValue::Pair(next(), next()).store(bx, dst);
+            }
+            PassMode::Indirect { extra_attrs: Some(_), .. } => {
+                OperandValue::Ref(next(), Some(next()), self.layout.align.abi).store(bx, dst);
+            }
+            PassMode::Direct(_) | PassMode::Indirect { extra_attrs: None, .. } | PassMode::Cast(_) => {
+                let next_arg = next();
+                self.store(bx, next_arg.to_rvalue(), dst);
+            }
+        }
+    }
+}
+
+fn int_type_width_signed<'gcc, 'tcx>(ty: Ty<'tcx>, cx: &CodegenCx<'gcc, 'tcx>) -> Option<(u64, bool)> {
+    match ty.kind() {
+        ty::Int(t) => Some((
+            match t {
+                rustc_middle::ty::IntTy::Isize => u64::from(cx.tcx.sess.target.pointer_width),
+                rustc_middle::ty::IntTy::I8 => 8,
+                rustc_middle::ty::IntTy::I16 => 16,
+                rustc_middle::ty::IntTy::I32 => 32,
+                rustc_middle::ty::IntTy::I64 => 64,
+                rustc_middle::ty::IntTy::I128 => 128,
+            },
+            true,
+        )),
+        ty::Uint(t) => Some((
+            match t {
+                rustc_middle::ty::UintTy::Usize => u64::from(cx.tcx.sess.target.pointer_width),
+                rustc_middle::ty::UintTy::U8 => 8,
+                rustc_middle::ty::UintTy::U16 => 16,
+                rustc_middle::ty::UintTy::U32 => 32,
+                rustc_middle::ty::UintTy::U64 => 64,
+                rustc_middle::ty::UintTy::U128 => 128,
+            },
+            false,
+        )),
+        _ => None,
+    }
+}
+
+impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
+    fn bit_reverse(&mut self, width: u64, value: RValue<'gcc>) -> RValue<'gcc> {
+        let result_type = value.get_type();
+        let typ = result_type.to_unsigned(self.cx);
+
+        let value =
+            if result_type.is_signed(self.cx) {
+                self.context.new_bitcast(None, value, typ)
+            }
+            else {
+                value
+            };
+
+        let context = &self.cx.context;
+        let result =
+            match width {
+                8 => {
+                    // First step.
+                    let left = self.and(value, context.new_rvalue_from_int(typ, 0xF0));
+                    let left = self.lshr(left, context.new_rvalue_from_int(typ, 4));
+                    let right = self.and(value, context.new_rvalue_from_int(typ, 0x0F));
+                    let right = self.shl(right, context.new_rvalue_from_int(typ, 4));
+                    let step1 = self.or(left, right);
+
+                    // Second step.
+                    let left = self.and(step1, context.new_rvalue_from_int(typ, 0xCC));
+                    let left = self.lshr(left, context.new_rvalue_from_int(typ, 2));
+                    let right = self.and(step1, context.new_rvalue_from_int(typ, 0x33));
+                    let right = self.shl(right, context.new_rvalue_from_int(typ, 2));
+                    let step2 = self.or(left, right);
+
+                    // Third step.
+                    let left = self.and(step2, context.new_rvalue_from_int(typ, 0xAA));
+                    let left = self.lshr(left, context.new_rvalue_from_int(typ, 1));
+                    let right = self.and(step2, context.new_rvalue_from_int(typ, 0x55));
+                    let right = self.shl(right, context.new_rvalue_from_int(typ, 1));
+                    let step3 = self.or(left, right);
+
+                    step3
+                },
+                16 => {
+                    // First step.
+                    let left = self.and(value, context.new_rvalue_from_int(typ, 0x5555));
+                    let left = self.shl(left, context.new_rvalue_from_int(typ, 1));
+                    let right = self.and(value, context.new_rvalue_from_int(typ, 0xAAAA));
+                    let right = self.lshr(right, context.new_rvalue_from_int(typ, 1));
+                    let step1 = self.or(left, right);
+
+                    // Second step.
+                    let left = self.and(step1, context.new_rvalue_from_int(typ, 0x3333));
+                    let left = self.shl(left, context.new_rvalue_from_int(typ, 2));
+                    let right = self.and(step1, context.new_rvalue_from_int(typ, 0xCCCC));
+                    let right = self.lshr(right, context.new_rvalue_from_int(typ, 2));
+                    let step2 = self.or(left, right);
+
+                    // Third step.
+                    let left = self.and(step2, context.new_rvalue_from_int(typ, 0x0F0F));
+                    let left = self.shl(left, context.new_rvalue_from_int(typ, 4));
+                    let right = self.and(step2, context.new_rvalue_from_int(typ, 0xF0F0));
+                    let right = self.lshr(right, context.new_rvalue_from_int(typ, 4));
+                    let step3 = self.or(left, right);
+
+                    // Fourth step.
+                    let left = self.and(step3, context.new_rvalue_from_int(typ, 0x00FF));
+                    let left = self.shl(left, context.new_rvalue_from_int(typ, 8));
+                    let right = self.and(step3, context.new_rvalue_from_int(typ, 0xFF00));
+                    let right = self.lshr(right, context.new_rvalue_from_int(typ, 8));
+                    let step4 = self.or(left, right);
+
+                    step4
+                },
+                32 => {
+                    // TODO(antoyo): Refactor with other implementations.
+                    // First step.
+                    let left = self.and(value, context.new_rvalue_from_long(typ, 0x55555555));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 1));
+                    let right = self.and(value, context.new_rvalue_from_long(typ, 0xAAAAAAAA));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 1));
+                    let step1 = self.or(left, right);
+
+                    // Second step.
+                    let left = self.and(step1, context.new_rvalue_from_long(typ, 0x33333333));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 2));
+                    let right = self.and(step1, context.new_rvalue_from_long(typ, 0xCCCCCCCC));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 2));
+                    let step2 = self.or(left, right);
+
+                    // Third step.
+                    let left = self.and(step2, context.new_rvalue_from_long(typ, 0x0F0F0F0F));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 4));
+                    let right = self.and(step2, context.new_rvalue_from_long(typ, 0xF0F0F0F0));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 4));
+                    let step3 = self.or(left, right);
+
+                    // Fourth step.
+                    let left = self.and(step3, context.new_rvalue_from_long(typ, 0x00FF00FF));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 8));
+                    let right = self.and(step3, context.new_rvalue_from_long(typ, 0xFF00FF00));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 8));
+                    let step4 = self.or(left, right);
+
+                    // Fifth step.
+                    let left = self.and(step4, context.new_rvalue_from_long(typ, 0x0000FFFF));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 16));
+                    let right = self.and(step4, context.new_rvalue_from_long(typ, 0xFFFF0000));
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 16));
+                    let step5 = self.or(left, right);
+
+                    step5
+                },
+                64 => {
+                    // First step.
+                    let left = self.shl(value, context.new_rvalue_from_long(typ, 32));
+                    let right = self.lshr(value, context.new_rvalue_from_long(typ, 32));
+                    let step1 = self.or(left, right);
+
+                    // Second step.
+                    let left = self.and(step1, context.new_rvalue_from_long(typ, 0x0001FFFF0001FFFF));
+                    let left = self.shl(left, context.new_rvalue_from_long(typ, 15));
+                    let right = self.and(step1, context.new_rvalue_from_long(typ, 0xFFFE0000FFFE0000u64 as i64)); // TODO(antoyo): transmute the number instead?
+                    let right = self.lshr(right, context.new_rvalue_from_long(typ, 17));
+                    let step2 = self.or(left, right);
+
+                    // Third step.
+                    let left = self.lshr(step2, context.new_rvalue_from_long(typ, 10));
+                    let left = self.xor(step2, left);
+                    let temp = self.and(left, context.new_rvalue_from_long(typ, 0x003F801F003F801F));
+
+                    let left = self.shl(temp, context.new_rvalue_from_long(typ, 10));
+                    let left = self.or(temp, left);
+                    let step3 = self.xor(left, step2);
+
+                    // Fourth step.
+                    let left = self.lshr(step3, context.new_rvalue_from_long(typ, 4));
+                    let left = self.xor(step3, left);
+                    let temp = self.and(left, context.new_rvalue_from_long(typ, 0x0E0384210E038421));
+
+                    let left = self.shl(temp, context.new_rvalue_from_long(typ, 4));
+                    let left = self.or(temp, left);
+                    let step4 = self.xor(left, step3);
+
+                    // Fifth step.
+                    let left = self.lshr(step4, context.new_rvalue_from_long(typ, 2));
+                    let left = self.xor(step4, left);
+                    let temp = self.and(left, context.new_rvalue_from_long(typ, 0x2248884222488842));
+
+                    let left = self.shl(temp, context.new_rvalue_from_long(typ, 2));
+                    let left = self.or(temp, left);
+                    let step5 = self.xor(left, step4);
+
+                    step5
+                },
+                128 => {
+                    // TODO(antoyo): find a more efficient implementation?
+                    let sixty_four = self.context.new_rvalue_from_long(typ, 64);
+                    let high = self.context.new_cast(None, value >> sixty_four, self.u64_type);
+                    let low = self.context.new_cast(None, value, self.u64_type);
+
+                    let reversed_high = self.bit_reverse(64, high);
+                    let reversed_low = self.bit_reverse(64, low);
+
+                    let new_low = self.context.new_cast(None, reversed_high, typ);
+                    let new_high = self.context.new_cast(None, reversed_low, typ) << sixty_four;
+
+                    new_low | new_high
+                },
+                _ => {
+                    panic!("cannot bit reverse with width = {}", width);
+                },
+            };
+
+        self.context.new_bitcast(None, result, result_type)
+    }
+
+    fn count_leading_zeroes(&self, width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use width?
+        let arg_type = arg.get_type();
+        let count_leading_zeroes =
+            if arg_type.is_uint(&self.cx) {
+                "__builtin_clz"
+            }
+            else if arg_type.is_ulong(&self.cx) {
+                "__builtin_clzl"
+            }
+            else if arg_type.is_ulonglong(&self.cx) {
+                "__builtin_clzll"
+            }
+            else if width == 128 {
+                // Algorithm from: https://stackoverflow.com/a/28433850/389119
+                let array_type = self.context.new_array_type(None, arg_type, 3);
+                let result = self.current_func()
+                    .new_local(None, array_type, "count_loading_zeroes_results");
+
+                let sixty_four = self.context.new_rvalue_from_long(arg_type, 64);
+                let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type);
+                let low = self.context.new_cast(None, arg, self.u64_type);
+
+                let zero = self.context.new_rvalue_zero(self.usize_type);
+                let one = self.context.new_rvalue_one(self.usize_type);
+                let two = self.context.new_rvalue_from_long(self.usize_type, 2);
+
+                let clzll = self.context.get_builtin_function("__builtin_clzll");
+
+                let first_elem = self.context.new_array_access(None, result, zero);
+                let first_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[high]), arg_type);
+                self.llbb()
+                    .add_assignment(None, first_elem, first_value);
+
+                let second_elem = self.context.new_array_access(None, result, one);
+                let second_value = self.context.new_cast(None, self.context.new_call(None, clzll, &[low]), arg_type) + sixty_four;
+                self.llbb()
+                    .add_assignment(None, second_elem, second_value);
+
+                let third_elem = self.context.new_array_access(None, result, two);
+                let third_value = self.context.new_rvalue_from_long(arg_type, 128);
+                self.llbb()
+                    .add_assignment(None, third_elem, third_value);
+
+                let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
+                let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
+                let not_low_and_not_high = not_low & not_high;
+                let index = not_high + not_low_and_not_high;
+
+                let res = self.context.new_array_access(None, result, index);
+
+                return self.context.new_cast(None, res, arg_type);
+            }
+            else {
+                let count_leading_zeroes = self.context.get_builtin_function("__builtin_clz");
+                let arg = self.context.new_cast(None, arg, self.uint_type);
+                let diff = self.int_width(self.uint_type) - self.int_width(arg_type);
+                let diff = self.context.new_rvalue_from_long(self.int_type, diff);
+                let res = self.context.new_call(None, count_leading_zeroes, &[arg]) - diff;
+                return self.context.new_cast(None, res, arg_type);
+            };
+        let count_leading_zeroes = self.context.get_builtin_function(count_leading_zeroes);
+        let res = self.context.new_call(None, count_leading_zeroes, &[arg]);
+        self.context.new_cast(None, res, arg_type)
+    }
+
+    fn count_trailing_zeroes(&self, _width: u64, arg: RValue<'gcc>) -> RValue<'gcc> {
+        let result_type = arg.get_type();
+        let arg =
+            if result_type.is_signed(self.cx) {
+                let new_type = result_type.to_unsigned(self.cx);
+                self.context.new_bitcast(None, arg, new_type)
+            }
+            else {
+                arg
+            };
+        let arg_type = arg.get_type();
+        let (count_trailing_zeroes, expected_type) =
+            if arg_type.is_uchar(&self.cx) || arg_type.is_ushort(&self.cx) || arg_type.is_uint(&self.cx) {
+                // NOTE: we don't need to & 0xFF for uchar because the result is undefined on zero.
+                ("__builtin_ctz", self.cx.uint_type)
+            }
+            else if arg_type.is_ulong(&self.cx) {
+                ("__builtin_ctzl", self.cx.ulong_type)
+            }
+            else if arg_type.is_ulonglong(&self.cx) {
+                ("__builtin_ctzll", self.cx.ulonglong_type)
+            }
+            else if arg_type.is_u128(&self.cx) {
+                // Adapted from the algorithm to count leading zeroes from: https://stackoverflow.com/a/28433850/389119
+                let array_type = self.context.new_array_type(None, arg_type, 3);
+                let result = self.current_func()
+                    .new_local(None, array_type, "count_loading_zeroes_results");
+
+                let sixty_four = self.context.new_rvalue_from_long(arg_type, 64);
+                let high = self.context.new_cast(None, arg >> sixty_four, self.u64_type);
+                let low = self.context.new_cast(None, arg, self.u64_type);
+
+                let zero = self.context.new_rvalue_zero(self.usize_type);
+                let one = self.context.new_rvalue_one(self.usize_type);
+                let two = self.context.new_rvalue_from_long(self.usize_type, 2);
+
+                let ctzll = self.context.get_builtin_function("__builtin_ctzll");
+
+                let first_elem = self.context.new_array_access(None, result, zero);
+                let first_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[low]), arg_type);
+                self.llbb()
+                    .add_assignment(None, first_elem, first_value);
+
+                let second_elem = self.context.new_array_access(None, result, one);
+                let second_value = self.context.new_cast(None, self.context.new_call(None, ctzll, &[high]), arg_type) + sixty_four;
+                self.llbb()
+                    .add_assignment(None, second_elem, second_value);
+
+                let third_elem = self.context.new_array_access(None, result, two);
+                let third_value = self.context.new_rvalue_from_long(arg_type, 128);
+                self.llbb()
+                    .add_assignment(None, third_elem, third_value);
+
+                let not_low = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, low);
+                let not_high = self.context.new_unary_op(None, UnaryOp::LogicalNegate, self.u64_type, high);
+                let not_low_and_not_high = not_low & not_high;
+                let index = not_low + not_low_and_not_high;
+
+                let res = self.context.new_array_access(None, result, index);
+
+                return self.context.new_bitcast(None, res, result_type);
+            }
+            else {
+                unimplemented!("count_trailing_zeroes for {:?}", arg_type);
+            };
+        let count_trailing_zeroes = self.context.get_builtin_function(count_trailing_zeroes);
+        let arg =
+            if arg_type != expected_type {
+                self.context.new_cast(None, arg, expected_type)
+            }
+            else {
+                arg
+            };
+        let res = self.context.new_call(None, count_trailing_zeroes, &[arg]);
+        self.context.new_bitcast(None, res, result_type)
+    }
+
+    fn int_width(&self, typ: Type<'gcc>) -> i64 {
+        self.cx.int_width(typ) as i64
+    }
+
+    fn pop_count(&self, value: RValue<'gcc>) -> RValue<'gcc> {
+        // TODO(antoyo): use the optimized version with fewer operations.
+        let result_type = value.get_type();
+        let value_type = result_type.to_unsigned(self.cx);
+
+        let value =
+            if result_type.is_signed(self.cx) {
+                self.context.new_bitcast(None, value, value_type)
+            }
+            else {
+                value
+            };
+
+        if value_type.is_u128(&self.cx) {
+            // TODO(antoyo): implement in the normal algorithm below to have a more efficient
+            // implementation (that does not require a call to __popcountdi2).
+            let popcount = self.context.get_builtin_function("__builtin_popcountll");
+            let sixty_four = self.context.new_rvalue_from_long(value_type, 64);
+            let high = self.context.new_cast(None, value >> sixty_four, self.cx.ulonglong_type);
+            let high = self.context.new_call(None, popcount, &[high]);
+            let low = self.context.new_cast(None, value, self.cx.ulonglong_type);
+            let low = self.context.new_call(None, popcount, &[low]);
+            let res = high + low;
+            return self.context.new_bitcast(None, res, result_type);
+        }
+
+        // First step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x5555555555555555);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 1);
+        let right = shifted & mask;
+        let value = left + right;
+
+        // Second step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x3333333333333333);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 2);
+        let right = shifted & mask;
+        let value = left + right;
+
+        // Third step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x0F0F0F0F0F0F0F0F);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 4);
+        let right = shifted & mask;
+        let value = left + right;
+
+        if value_type.is_u8(&self.cx) {
+            return self.context.new_bitcast(None, value, result_type);
+        }
+
+        // Fourth step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x00FF00FF00FF00FF);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 8);
+        let right = shifted & mask;
+        let value = left + right;
+
+        if value_type.is_u16(&self.cx) {
+            return self.context.new_bitcast(None, value, result_type);
+        }
+
+        // Fifth step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x0000FFFF0000FFFF);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 16);
+        let right = shifted & mask;
+        let value = left + right;
+
+        if value_type.is_u32(&self.cx) {
+            return self.context.new_bitcast(None, value, result_type);
+        }
+
+        // Sixth step.
+        let mask = self.context.new_rvalue_from_long(value_type, 0x00000000FFFFFFFF);
+        let left = value & mask;
+        let shifted = value >> self.context.new_rvalue_from_int(value_type, 32);
+        let right = shifted & mask;
+        let value = left + right;
+
+        self.context.new_bitcast(None, value, result_type)
+    }
+
+    // Algorithm from: https://blog.regehr.org/archives/1063
+    fn rotate_left(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> {
+        let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64);
+        let shift = shift % max;
+        let lhs = self.shl(value, shift);
+        let result_and =
+            self.and(
+                self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift),
+                self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1),
+            );
+        let rhs = self.lshr(value, result_and);
+        self.or(lhs, rhs)
+    }
+
+    // Algorithm from: https://blog.regehr.org/archives/1063
+    fn rotate_right(&mut self, value: RValue<'gcc>, shift: RValue<'gcc>, width: u64) -> RValue<'gcc> {
+        let max = self.context.new_rvalue_from_long(shift.get_type(), width as i64);
+        let shift = shift % max;
+        let lhs = self.lshr(value, shift);
+        let result_and =
+            self.and(
+                self.context.new_unary_op(None, UnaryOp::Minus, shift.get_type(), shift),
+                self.context.new_rvalue_from_long(shift.get_type(), width as i64 - 1),
+            );
+        let rhs = self.shl(value, result_and);
+        self.or(lhs, rhs)
+    }
+
+    fn saturating_add(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
+        let func = self.current_func.borrow().expect("func");
+
+        if signed {
+            // Algorithm from: https://stackoverflow.com/a/56531252/389119
+            let after_block = func.new_block("after");
+            let func_name =
+                match width {
+                    8 => "__builtin_add_overflow",
+                    16 => "__builtin_add_overflow",
+                    32 => "__builtin_sadd_overflow",
+                    64 => "__builtin_saddll_overflow",
+                    128 => "__builtin_add_overflow",
+                    _ => unreachable!(),
+                };
+            let overflow_func = self.context.get_builtin_function(func_name);
+            let result_type = lhs.get_type();
+            let res = func.new_local(None, result_type, "saturating_sum");
+            let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None);
+
+            let then_block = func.new_block("then");
+
+            let unsigned_type = self.context.new_int_type(width as i32 / 8, false);
+            let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1);
+            let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type,
+                self.context.new_rvalue_from_int(unsigned_type, 0)
+            );
+            let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type);
+            then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type));
+            then_block.end_with_jump(None, after_block);
+
+            self.llbb().end_with_conditional(None, overflow, then_block, after_block);
+
+            // NOTE: since jumps were added in a place rustc does not
+            // expect, the current blocks in the state need to be updated.
+            *self.current_block.borrow_mut() = Some(after_block);
+            self.block = Some(after_block);
+
+            res.to_rvalue()
+        }
+        else {
+            // Algorithm from: http://locklessinc.com/articles/sat_arithmetic/
+            let res = lhs + rhs;
+            let res_type = res.get_type();
+            let cond = self.context.new_comparison(None, ComparisonOp::LessThan, res, lhs);
+            let value = self.context.new_unary_op(None, UnaryOp::Minus, res_type, self.context.new_cast(None, cond, res_type));
+            res | value
+        }
+    }
+
+    // Algorithm from: https://locklessinc.com/articles/sat_arithmetic/
+    fn saturating_sub(&mut self, lhs: RValue<'gcc>, rhs: RValue<'gcc>, signed: bool, width: u64) -> RValue<'gcc> {
+        if signed {
+            // Also based on algorithm from: https://stackoverflow.com/a/56531252/389119
+            let func_name =
+                match width {
+                    8 => "__builtin_sub_overflow",
+                    16 => "__builtin_sub_overflow",
+                    32 => "__builtin_ssub_overflow",
+                    64 => "__builtin_ssubll_overflow",
+                    128 => "__builtin_sub_overflow",
+                    _ => unreachable!(),
+                };
+            let overflow_func = self.context.get_builtin_function(func_name);
+            let result_type = lhs.get_type();
+            let func = self.current_func.borrow().expect("func");
+            let res = func.new_local(None, result_type, "saturating_diff");
+            let overflow = self.overflow_call(overflow_func, &[lhs, rhs, res.get_address(None)], None);
+
+            let then_block = func.new_block("then");
+            let after_block = func.new_block("after");
+
+            let unsigned_type = self.context.new_int_type(width as i32 / 8, false);
+            let shifted = self.context.new_cast(None, lhs, unsigned_type) >> self.context.new_rvalue_from_int(unsigned_type, width as i32 - 1);
+            let uint_max = self.context.new_unary_op(None, UnaryOp::BitwiseNegate, unsigned_type,
+                self.context.new_rvalue_from_int(unsigned_type, 0)
+            );
+            let int_max = uint_max >> self.context.new_rvalue_one(unsigned_type);
+            then_block.add_assignment(None, res, self.context.new_cast(None, shifted + int_max, result_type));
+            then_block.end_with_jump(None, after_block);
+
+            self.llbb().end_with_conditional(None, overflow, then_block, after_block);
+
+            // NOTE: since jumps were added in a place rustc does not
+            // expect, the current blocks in the state need to be updated.
+            *self.current_block.borrow_mut() = Some(after_block);
+            self.block = Some(after_block);
+
+            res.to_rvalue()
+        }
+        else {
+            let res = lhs - rhs;
+            let comparison = self.context.new_comparison(None, ComparisonOp::LessThanEquals, res, lhs);
+            let comparison = self.context.new_cast(None, comparison, lhs.get_type());
+            let unary_op = self.context.new_unary_op(None, UnaryOp::Minus, comparison.get_type(), comparison);
+            self.and(res, unary_op)
+        }
+    }
+}
+
+fn try_intrinsic<'gcc, 'tcx>(bx: &mut Builder<'_, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
+    if bx.sess().panic_strategy() == PanicStrategy::Abort {
+        bx.call(bx.type_void(), try_func, &[data], None);
+        // Return 0 unconditionally from the intrinsic call;
+        // we can never unwind.
+        let ret_align = bx.tcx.data_layout.i32_align.abi;
+        bx.store(bx.const_i32(0), dest, ret_align);
+    }
+    else if wants_msvc_seh(bx.sess()) {
+        unimplemented!();
+    }
+    else {
+        unimplemented!();
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs b/compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
new file mode 100644 (file)
index 0000000..26a4221
--- /dev/null
@@ -0,0 +1,167 @@
+use gccjit::{RValue, Type};
+use rustc_codegen_ssa::base::compare_simd_types;
+use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error};
+use rustc_codegen_ssa::mir::operand::OperandRef;
+use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
+use rustc_hir as hir;
+use rustc_middle::span_bug;
+use rustc_middle::ty::layout::HasTyCtxt;
+use rustc_middle::ty::{self, Ty};
+use rustc_span::{Span, Symbol, sym};
+
+use crate::builder::Builder;
+
+pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
+    // macros for error handling:
+    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(());
+            }
+        }
+    }
+
+    macro_rules! require {
+        ($cond: expr, $($fmt: tt)*) => {
+            if !$cond {
+                return_error!($($fmt)*);
+            }
+        };
+    }
+
+    macro_rules! require_simd {
+        ($ty: expr, $position: expr) => {
+            require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
+        };
+    }
+
+    let tcx = bx.tcx();
+    let sig =
+        tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
+    let arg_tys = sig.inputs();
+    let name_str = &*name.as_str();
+
+    // every intrinsic below takes a SIMD vector as its first argument
+    require_simd!(arg_tys[0], "input");
+    let in_ty = arg_tys[0];
+
+    let comparison = match name {
+        sym::simd_eq => Some(hir::BinOpKind::Eq),
+        sym::simd_ne => Some(hir::BinOpKind::Ne),
+        sym::simd_lt => Some(hir::BinOpKind::Lt),
+        sym::simd_le => Some(hir::BinOpKind::Le),
+        sym::simd_gt => Some(hir::BinOpKind::Gt),
+        sym::simd_ge => Some(hir::BinOpKind::Ge),
+        _ => None,
+    };
+
+    let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
+    if let Some(cmp_op) = comparison {
+        require_simd!(ret_ty, "return");
+
+        let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
+        require!(
+            in_len == out_len,
+            "expected return type with length {} (same as input type `{}`), \
+             found `{}` with length {}",
+            in_len,
+            in_ty,
+            ret_ty,
+            out_len
+        );
+        require!(
+            bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
+            "expected return type with integer elements, found `{}` with non-integer `{}`",
+            ret_ty,
+            out_ty
+        );
+
+        return Ok(compare_simd_types(
+            bx,
+            args[0].immediate(),
+            args[1].immediate(),
+            in_elem,
+            llret_ty,
+            cmp_op,
+        ));
+    }
+
+    if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
+        let n: u64 = stripped.parse().unwrap_or_else(|_| {
+            span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
+        });
+
+        require_simd!(ret_ty, "return");
+
+        let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
+        require!(
+            out_len == n,
+            "expected return type of length {}, found `{}` with length {}",
+            n,
+            ret_ty,
+            out_len
+        );
+        require!(
+            in_elem == out_ty,
+            "expected return element type `{}` (element of input `{}`), \
+             found `{}` with element type `{}`",
+            in_elem,
+            in_ty,
+            ret_ty,
+            out_ty
+        );
+
+        let vector = args[2].immediate();
+
+        return Ok(bx.shuffle_vector(
+            args[0].immediate(),
+            args[1].immediate(),
+            vector,
+        ));
+    }
+
+    macro_rules! arith_binary {
+        ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
+            $(if name == sym::$name {
+                match in_elem.kind() {
+                    $($(ty::$p(_))|* => {
+                        return Ok(bx.$call(args[0].immediate(), args[1].immediate()))
+                    })*
+                    _ => {},
+                }
+                require!(false,
+                         "unsupported operation on `{}` with element `{}`",
+                         in_ty,
+                         in_elem)
+            })*
+        }
+    }
+
+    arith_binary! {
+        simd_add: Uint, Int => add, Float => fadd;
+        simd_sub: Uint, Int => sub, Float => fsub;
+        simd_mul: Uint, Int => mul, Float => fmul;
+        simd_div: Uint => udiv, Int => sdiv, Float => fdiv;
+        simd_rem: Uint => urem, Int => srem, Float => frem;
+        simd_shl: Uint, Int => shl;
+        simd_shr: Uint => lshr, Int => ashr;
+        simd_and: Uint, Int => and;
+        simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors.
+        simd_xor: Uint, Int => xor;
+    }
+
+    unimplemented!("simd {}", name);
+}
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
new file mode 100644 (file)
index 0000000..f3c02e2
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ * TODO(antoyo): support #[inline] attributes.
+ * TODO(antoyo): support LTO.
+ *
+ * TODO(antoyo): remove the patches.
+ */
+
+#![feature(rustc_private, decl_macro, associated_type_bounds, never_type, trusted_len)]
+#![allow(broken_intra_doc_links)]
+#![recursion_limit="256"]
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+
+extern crate rustc_ast;
+extern crate rustc_codegen_ssa;
+extern crate rustc_data_structures;
+extern crate rustc_errors;
+extern crate rustc_hir;
+extern crate rustc_metadata;
+extern crate rustc_middle;
+extern crate rustc_session;
+extern crate rustc_span;
+extern crate rustc_symbol_mangling;
+extern crate rustc_target;
+extern crate snap;
+
+// This prevents duplicating functions and statics that are already part of the host rustc process.
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+
+mod abi;
+mod allocator;
+mod archive;
+mod asm;
+mod back;
+mod base;
+mod builder;
+mod callee;
+mod common;
+mod consts;
+mod context;
+mod coverageinfo;
+mod debuginfo;
+mod declare;
+mod intrinsic;
+mod mono_item;
+mod type_;
+mod type_of;
+
+use std::any::Any;
+use std::sync::Arc;
+
+use gccjit::{Context, OptimizationLevel};
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_codegen_ssa::{CodegenResults, CompiledModule, ModuleCodegen};
+use rustc_codegen_ssa::base::codegen_crate;
+use rustc_codegen_ssa::back::write::{CodegenContext, FatLTOInput, ModuleConfig, TargetMachineFactoryFn};
+use rustc_codegen_ssa::back::lto::{LtoModuleCodegen, SerializedModule, ThinModule};
+use rustc_codegen_ssa::target_features::supported_target_features;
+use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
+use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::{ErrorReported, Handler};
+use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
+use rustc_middle::middle::cstore::EncodedMetadata;
+use rustc_middle::ty::TyCtxt;
+use rustc_session::config::{Lto, OptLevel, OutputFilenames};
+use rustc_session::Session;
+use rustc_span::Symbol;
+use rustc_span::fatal_error::FatalError;
+
+pub struct PrintOnPanic<F: Fn() -> String>(pub F);
+
+impl<F: Fn() -> String> Drop for PrintOnPanic<F> {
+    fn drop(&mut self) {
+        if ::std::thread::panicking() {
+            println!("{}", (self.0)());
+        }
+    }
+}
+
+#[derive(Clone)]
+pub struct GccCodegenBackend;
+
+impl CodegenBackend for GccCodegenBackend {
+    fn init(&self, sess: &Session) {
+        if sess.lto() != Lto::No {
+            sess.warn("LTO is not supported. You may get a linker error.");
+        }
+    }
+
+    fn codegen_crate<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: EncodedMetadata, need_metadata_module: bool) -> Box<dyn Any> {
+        let target_cpu = target_cpu(tcx.sess);
+        let res = codegen_crate(self.clone(), tcx, target_cpu.to_string(), metadata, need_metadata_module);
+
+        rustc_symbol_mangling::test::report_symbol_names(tcx);
+
+        Box::new(res)
+    }
+
+    fn join_codegen(&self, ongoing_codegen: Box<dyn Any>, sess: &Session) -> Result<(CodegenResults, FxHashMap<WorkProductId, WorkProduct>), ErrorReported> {
+        let (codegen_results, work_products) = ongoing_codegen
+            .downcast::<rustc_codegen_ssa::back::write::OngoingCodegen<GccCodegenBackend>>()
+            .expect("Expected GccCodegenBackend's OngoingCodegen, found Box<Any>")
+            .join(sess);
+
+        Ok((codegen_results, work_products))
+    }
+
+    fn link(&self, sess: &Session, codegen_results: CodegenResults, outputs: &OutputFilenames) -> Result<(), ErrorReported> {
+        use rustc_codegen_ssa::back::link::link_binary;
+
+        link_binary::<crate::archive::ArArchiveBuilder<'_>>(
+            sess,
+            &codegen_results,
+            outputs,
+        )
+    }
+
+    fn target_features(&self, sess: &Session) -> Vec<Symbol> {
+        target_features(sess)
+    }
+}
+
+impl ExtraBackendMethods for GccCodegenBackend {
+    fn new_metadata<'tcx>(&self, _tcx: TyCtxt<'tcx>, _mod_name: &str) -> Self::Module {
+        GccContext {
+            context: Context::default(),
+        }
+    }
+
+    fn write_compressed_metadata<'tcx>(&self, tcx: TyCtxt<'tcx>, metadata: &EncodedMetadata, gcc_module: &mut Self::Module) {
+        base::write_compressed_metadata(tcx, metadata, gcc_module)
+    }
+
+    fn codegen_allocator<'tcx>(&self, tcx: TyCtxt<'tcx>, mods: &mut Self::Module, module_name: &str, kind: AllocatorKind, has_alloc_error_handler: bool) {
+        unsafe { allocator::codegen(tcx, mods, module_name, kind, has_alloc_error_handler) }
+    }
+
+    fn compile_codegen_unit<'tcx>(&self, tcx: TyCtxt<'tcx>, cgu_name: Symbol) -> (ModuleCodegen<Self::Module>, u64) {
+        base::compile_codegen_unit(tcx, cgu_name)
+    }
+
+    fn target_machine_factory(&self, _sess: &Session, _opt_level: OptLevel) -> TargetMachineFactoryFn<Self> {
+        // TODO(antoyo): set opt level.
+        Arc::new(|_| {
+            Ok(())
+        })
+    }
+
+    fn target_cpu<'b>(&self, _sess: &'b Session) -> &'b str {
+        unimplemented!();
+    }
+
+    fn tune_cpu<'b>(&self, _sess: &'b Session) -> Option<&'b str> {
+        None
+        // TODO(antoyo)
+    }
+}
+
+pub struct ModuleBuffer;
+
+impl ModuleBufferMethods for ModuleBuffer {
+    fn data(&self) -> &[u8] {
+        unimplemented!();
+    }
+}
+
+pub struct ThinBuffer;
+
+impl ThinBufferMethods for ThinBuffer {
+    fn data(&self) -> &[u8] {
+        unimplemented!();
+    }
+}
+
+pub struct GccContext {
+    context: Context<'static>,
+}
+
+unsafe impl Send for GccContext {}
+// FIXME(antoyo): that shouldn't be Sync. Parallel compilation is currently disabled with "-Zno-parallel-llvm". Try to disable it here.
+unsafe impl Sync for GccContext {}
+
+impl WriteBackendMethods for GccCodegenBackend {
+    type Module = GccContext;
+    type TargetMachine = ();
+    type ModuleBuffer = ModuleBuffer;
+    type Context = ();
+    type ThinData = ();
+    type ThinBuffer = ThinBuffer;
+
+    fn run_fat_lto(_cgcx: &CodegenContext<Self>, mut modules: Vec<FatLTOInput<Self>>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<LtoModuleCodegen<Self>, FatalError> {
+        // TODO(antoyo): implement LTO by sending -flto to libgccjit and adding the appropriate gcc linker plugins.
+        // NOTE: implemented elsewhere.
+        // TODO: what is implemented elsewhere ^ ?
+        let module =
+            match modules.remove(0) {
+                FatLTOInput::InMemory(module) => module,
+                FatLTOInput::Serialized { .. } => {
+                    unimplemented!();
+                }
+            };
+        Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: vec![] })
+    }
+
+    fn run_thin_lto(_cgcx: &CodegenContext<Self>, _modules: Vec<(String, Self::ThinBuffer)>, _cached_modules: Vec<(SerializedModule<Self::ModuleBuffer>, WorkProduct)>) -> Result<(Vec<LtoModuleCodegen<Self>>, Vec<WorkProduct>), FatalError> {
+        unimplemented!();
+    }
+
+    fn print_pass_timings(&self) {
+        unimplemented!();
+    }
+
+    unsafe fn optimize(_cgcx: &CodegenContext<Self>, _diag_handler: &Handler, module: &ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<(), FatalError> {
+        module.module_llvm.context.set_optimization_level(to_gcc_opt_level(config.opt_level));
+        Ok(())
+    }
+
+    unsafe fn optimize_thin(_cgcx: &CodegenContext<Self>, _thin: &mut ThinModule<Self>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+        unimplemented!();
+    }
+
+    unsafe fn codegen(cgcx: &CodegenContext<Self>, diag_handler: &Handler, module: ModuleCodegen<Self::Module>, config: &ModuleConfig) -> Result<CompiledModule, FatalError> {
+        back::write::codegen(cgcx, diag_handler, module, config)
+    }
+
+    fn prepare_thin(_module: ModuleCodegen<Self::Module>) -> (String, Self::ThinBuffer) {
+        unimplemented!();
+    }
+
+    fn serialize_module(_module: ModuleCodegen<Self::Module>) -> (String, Self::ModuleBuffer) {
+        unimplemented!();
+    }
+
+    fn run_lto_pass_manager(_cgcx: &CodegenContext<Self>, _module: &ModuleCodegen<Self::Module>, _config: &ModuleConfig, _thin: bool) -> Result<(), FatalError> {
+        // TODO(antoyo)
+        Ok(())
+    }
+
+    fn run_link(cgcx: &CodegenContext<Self>, diag_handler: &Handler, modules: Vec<ModuleCodegen<Self::Module>>) -> Result<ModuleCodegen<Self::Module>, FatalError> {
+        back::write::link(cgcx, diag_handler, modules)
+    }
+}
+
+/// This is the entrypoint for a hot plugged rustc_codegen_gccjit
+#[no_mangle]
+pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
+    Box::new(GccCodegenBackend)
+}
+
+fn to_gcc_opt_level(optlevel: Option<OptLevel>) -> OptimizationLevel {
+    match optlevel {
+        None => OptimizationLevel::None,
+        Some(level) => {
+            match level {
+                OptLevel::No => OptimizationLevel::None,
+                OptLevel::Less => OptimizationLevel::Limited,
+                OptLevel::Default => OptimizationLevel::Standard,
+                OptLevel::Aggressive => OptimizationLevel::Aggressive,
+                OptLevel::Size | OptLevel::SizeMin => OptimizationLevel::Limited,
+            }
+        },
+    }
+}
+
+fn handle_native(name: &str) -> &str {
+    if name != "native" {
+        return name;
+    }
+
+    unimplemented!();
+}
+
+pub fn target_cpu(sess: &Session) -> &str {
+    let name = sess.opts.cg.target_cpu.as_ref().unwrap_or(&sess.target.cpu);
+    handle_native(name)
+}
+
+pub fn target_features(sess: &Session) -> Vec<Symbol> {
+    supported_target_features(sess)
+        .iter()
+        .filter_map(
+            |&(feature, gate)| {
+                if sess.is_nightly_build() || gate.is_none() { Some(feature) } else { None }
+            },
+        )
+        .filter(|_feature| {
+            // TODO(antoyo): implement a way to get enabled feature in libgccjit.
+            false
+        })
+        .map(|feature| Symbol::intern(feature))
+        .collect()
+}
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
new file mode 100644 (file)
index 0000000..e21d40b
--- /dev/null
@@ -0,0 +1,38 @@
+use rustc_codegen_ssa::traits::PreDefineMethods;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::mono::{Linkage, Visibility};
+use rustc_middle::ty::{self, Instance, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf};
+use rustc_span::def_id::DefId;
+
+use crate::base;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn predefine_static(&self, def_id: DefId, _linkage: Linkage, _visibility: Visibility, symbol_name: &str) {
+        let attrs = self.tcx.codegen_fn_attrs(def_id);
+        let instance = Instance::mono(self.tcx, def_id);
+        let ty = instance.ty(self.tcx, ty::ParamEnv::reveal_all());
+        let gcc_type = self.layout_of(ty).gcc_type(self, true);
+
+        let is_tls = attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL);
+        let global = self.define_global(symbol_name, gcc_type, is_tls, attrs.link_section);
+
+        // TODO(antoyo): set linkage and visibility.
+        self.instances.borrow_mut().insert(instance, global);
+    }
+
+    fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, _visibility: Visibility, symbol_name: &str) {
+        assert!(!instance.substs.needs_infer());
+
+        let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
+        self.linkage.set(base::linkage_to_gcc(linkage));
+        let _decl = self.declare_fn(symbol_name, &fn_abi);
+        //let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
+
+        // TODO(antoyo): call set_link_section() to allow initializing argc/argv.
+        // TODO(antoyo): set unique comdat.
+        // TODO(antoyo): use inline attribute from there in linkage.set() above.
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
new file mode 100644 (file)
index 0000000..3545e1b
--- /dev/null
@@ -0,0 +1,282 @@
+use std::convert::TryInto;
+
+use gccjit::{RValue, Struct, Type};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods};
+use rustc_codegen_ssa::common::TypeKind;
+use rustc_middle::bug;
+use rustc_middle::ty::layout::TyAndLayout;
+use rustc_target::abi::{AddressSpace, Align, Integer, Size};
+
+use crate::common::TypeReflection;
+use crate::context::CodegenCx;
+use crate::type_of::LayoutGccExt;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn type_ix(&self, num_bits: u64) -> Type<'gcc> {
+        // gcc only supports 1, 2, 4 or 8-byte integers.
+        // FIXME(antoyo): this is misleading to use the next power of two as rustc_codegen_ssa
+        // sometimes use 96-bit numbers and the following code will give an integer of a different
+        // size.
+        let bytes = (num_bits / 8).next_power_of_two() as i32;
+        match bytes {
+            1 => self.i8_type,
+            2 => self.i16_type,
+            4 => self.i32_type,
+            8 => self.i64_type,
+            16 => self.i128_type,
+            _ => panic!("unexpected num_bits: {}", num_bits),
+        }
+    }
+
+    pub fn type_void(&self) -> Type<'gcc> {
+        self.context.new_type::<()>()
+    }
+
+    pub fn type_size_t(&self) -> Type<'gcc> {
+        self.context.new_type::<usize>()
+    }
+
+    pub fn type_u8(&self) -> Type<'gcc> {
+        self.u8_type
+    }
+
+    pub fn type_u16(&self) -> Type<'gcc> {
+        self.u16_type
+    }
+
+    pub fn type_u32(&self) -> Type<'gcc> {
+        self.u32_type
+    }
+
+    pub fn type_u64(&self) -> Type<'gcc> {
+        self.u64_type
+    }
+
+    pub fn type_u128(&self) -> Type<'gcc> {
+        self.u128_type
+    }
+
+    pub fn type_pointee_for_align(&self, align: Align) -> Type<'gcc> {
+        // FIXME(eddyb) We could find a better approximation if ity.align < align.
+        let ity = Integer::approximate_align(self, align);
+        self.type_from_integer(ity)
+    }
+}
+
+impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn type_i1(&self) -> Type<'gcc> {
+        self.bool_type
+    }
+
+    fn type_i8(&self) -> Type<'gcc> {
+        self.i8_type
+    }
+
+    fn type_i16(&self) -> Type<'gcc> {
+        self.i16_type
+    }
+
+    fn type_i32(&self) -> Type<'gcc> {
+        self.i32_type
+    }
+
+    fn type_i64(&self) -> Type<'gcc> {
+        self.i64_type
+    }
+
+    fn type_i128(&self) -> Type<'gcc> {
+        self.i128_type
+    }
+
+    fn type_isize(&self) -> Type<'gcc> {
+        self.isize_type
+    }
+
+    fn type_f32(&self) -> Type<'gcc> {
+        self.context.new_type::<f32>()
+    }
+
+    fn type_f64(&self) -> Type<'gcc> {
+        self.context.new_type::<f64>()
+    }
+
+    fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> {
+        self.context.new_function_pointer_type(None, return_type, params, false)
+    }
+
+    fn type_struct(&self, fields: &[Type<'gcc>], _packed: bool) -> Type<'gcc> {
+        let types = fields.to_vec();
+        if let Some(typ) = self.struct_types.borrow().get(fields) {
+            return typ.clone();
+        }
+        let fields: Vec<_> = fields.iter().enumerate()
+            .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index)))
+            .collect();
+        // TODO(antoyo): use packed.
+        let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
+        self.struct_types.borrow_mut().insert(types, typ);
+        typ
+    }
+
+    fn type_kind(&self, typ: Type<'gcc>) -> TypeKind {
+        if typ.is_integral() {
+            TypeKind::Integer
+        }
+        else if typ.is_vector().is_some() {
+            TypeKind::Vector
+        }
+        else {
+            // TODO(antoyo): support other types.
+            TypeKind::Void
+        }
+    }
+
+    fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> {
+        ty.make_pointer()
+    }
+
+    fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
+        // TODO(antoyo): use address_space
+        ty.make_pointer()
+    }
+
+    fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
+        if let Some(typ) = ty.is_array() {
+            typ
+        }
+        else if let Some(vector_type) = ty.is_vector() {
+            vector_type.get_element_type()
+        }
+        else if let Some(typ) = ty.get_pointee() {
+            typ
+        }
+        else {
+            unreachable!()
+        }
+    }
+
+    fn vector_length(&self, _ty: Type<'gcc>) -> usize {
+        unimplemented!();
+    }
+
+    fn float_width(&self, typ: Type<'gcc>) -> usize {
+        let f32 = self.context.new_type::<f32>();
+        let f64 = self.context.new_type::<f64>();
+        if typ == f32 {
+            32
+        }
+        else if typ == f64 {
+            64
+        }
+        else {
+            panic!("Cannot get width of float type {:?}", typ);
+        }
+        // TODO(antoyo): support other sizes.
+    }
+
+    fn int_width(&self, typ: Type<'gcc>) -> u64 {
+        if typ.is_i8(self) || typ.is_u8(self) {
+            8
+        }
+        else if typ.is_i16(self) || typ.is_u16(self) {
+            16
+        }
+        else if typ.is_i32(self) || typ.is_u32(self) {
+            32
+        }
+        else if typ.is_i64(self) || typ.is_u64(self) {
+            64
+        }
+        else if typ.is_i128(self) || typ.is_u128(self) {
+            128
+        }
+        else {
+            panic!("Cannot get width of int type {:?}", typ);
+        }
+    }
+
+    fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> {
+        value.get_type()
+    }
+}
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    pub fn type_padding_filler(&self, size: Size, align: Align) -> Type<'gcc> {
+        let unit = Integer::approximate_align(self, align);
+        let size = size.bytes();
+        let unit_size = unit.size().bytes();
+        assert_eq!(size % unit_size, 0);
+        self.type_array(self.type_from_integer(unit), size / unit_size)
+    }
+
+    pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], _packed: bool) {
+        // TODO(antoyo): use packed.
+        let fields: Vec<_> = fields.iter().enumerate()
+            .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
+            .collect();
+        typ.set_fields(None, &fields);
+    }
+
+    pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> {
+        self.context.new_opaque_struct_type(None, name)
+    }
+
+    pub fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
+        if let Some(struct_type) = ty.is_struct() {
+            if struct_type.get_field_count() == 0 {
+                // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
+                // size of usize::MAX in test_binary_search, we workaround this by setting the size to
+                // zero for ZSTs.
+                // FIXME(antoyo): fix gccjit API.
+                len = 0;
+            }
+        }
+
+        // NOTE: see note above. Some other test uses usize::MAX.
+        if len == u64::MAX {
+            len = 0;
+        }
+
+        let len: i32 = len.try_into().expect("array len");
+
+        self.context.new_array_type(None, ty, len)
+    }
+}
+
+pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec<Type<'gcc>>, bool) {
+    let field_count = layout.fields.count();
+
+    let mut packed = false;
+    let mut offset = Size::ZERO;
+    let mut prev_effective_align = layout.align.abi;
+    let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
+    for i in layout.fields.index_by_increasing_offset() {
+        let target_offset = layout.fields.offset(i as usize);
+        let field = layout.field(cx, i);
+        let effective_field_align =
+            layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset);
+        packed |= effective_field_align < field.align.abi;
+
+        assert!(target_offset >= offset);
+        let padding = target_offset - offset;
+        let padding_align = prev_effective_align.min(effective_field_align);
+        assert_eq!(offset.align_to(padding_align) + padding, target_offset);
+        result.push(cx.type_padding_filler(padding, padding_align));
+
+        result.push(field.gcc_type(cx, !field.ty.is_any_ptr())); // FIXME(antoyo): might need to check if the type is inside another, like Box<Type>.
+        offset = target_offset + field.size;
+        prev_effective_align = effective_field_align;
+    }
+    if !layout.is_unsized() && field_count > 0 {
+        if offset > layout.size {
+            bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
+        }
+        let padding = layout.size - offset;
+        let padding_align = prev_effective_align;
+        assert_eq!(offset.align_to(padding_align) + padding, layout.size);
+        result.push(cx.type_padding_filler(padding, padding_align));
+        assert_eq!(result.len(), 1 + field_count * 2);
+    }
+
+    (result, packed)
+}
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
new file mode 100644 (file)
index 0000000..9c39c8f
--- /dev/null
@@ -0,0 +1,359 @@
+use std::fmt::Write;
+
+use gccjit::{Struct, Type};
+use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
+use rustc_middle::bug;
+use rustc_middle::ty::{self, Ty, TypeFoldable};
+use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout};
+use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, Pointer, PointeeInfo, Size, TyAbiInterface, Variants};
+use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
+
+use crate::abi::{FnAbiGccExt, GccType};
+use crate::context::CodegenCx;
+use crate::type_::struct_fields;
+
+impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
+    fn type_from_unsigned_integer(&self, i: Integer) -> Type<'gcc> {
+        use Integer::*;
+        match i {
+            I8 => self.type_u8(),
+            I16 => self.type_u16(),
+            I32 => self.type_u32(),
+            I64 => self.type_u64(),
+            I128 => self.type_u128(),
+        }
+    }
+}
+
+pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> {
+    match layout.abi {
+        Abi::Scalar(_) => bug!("handled elsewhere"),
+        Abi::Vector { ref element, count } => {
+            let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO);
+            return cx.context.new_vector_type(element, count);
+        },
+        Abi::ScalarPair(..) => {
+            return cx.type_struct(
+                &[
+                    layout.scalar_pair_element_gcc_type(cx, 0, false),
+                    layout.scalar_pair_element_gcc_type(cx, 1, false),
+                ],
+                false,
+            );
+        }
+        Abi::Uninhabited | Abi::Aggregate { .. } => {}
+    }
+
+    let name = match layout.ty.kind() {
+        // FIXME(eddyb) producing readable type names for trait objects can result
+        // in problematically distinct types due to HRTB and subtyping (see #47638).
+        // ty::Dynamic(..) |
+        ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str
+            if !cx.sess().fewer_names() =>
+        {
+            let mut name = with_no_trimmed_paths(|| layout.ty.to_string());
+            if let (&ty::Adt(def, _), &Variants::Single { index }) =
+                (layout.ty.kind(), &layout.variants)
+            {
+                if def.is_enum() && !def.variants.is_empty() {
+                    write!(&mut name, "::{}", def.variants[index].ident).unwrap();
+                }
+            }
+            if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
+                (layout.ty.kind(), &layout.variants)
+            {
+                write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap();
+            }
+            Some(name)
+        }
+        ty::Adt(..) => {
+            // If `Some` is returned then a named struct is created in LLVM. Name collisions are
+            // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that
+            // can improve perf.
+            // FIXME(antoyo): I don't think that's true for libgccjit.
+            Some(String::new())
+        }
+        _ => None,
+    };
+
+    match layout.fields {
+        FieldsShape::Primitive | FieldsShape::Union(_) => {
+            let fill = cx.type_padding_filler(layout.size, layout.align.abi);
+            let packed = false;
+            match name {
+                None => cx.type_struct(&[fill], packed),
+                Some(ref name) => {
+                    let gcc_type = cx.type_named_struct(name);
+                    cx.set_struct_body(gcc_type, &[fill], packed);
+                    gcc_type.as_type()
+                },
+            }
+        }
+        FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx, true), count),
+        FieldsShape::Arbitrary { .. } =>
+            match name {
+                None => {
+                    let (gcc_fields, packed) = struct_fields(cx, layout);
+                    cx.type_struct(&gcc_fields, packed)
+                },
+                Some(ref name) => {
+                    let gcc_type = cx.type_named_struct(name);
+                    *defer = Some((gcc_type, layout));
+                    gcc_type.as_type()
+                },
+            },
+    }
+}
+
+pub trait LayoutGccExt<'tcx> {
+    fn is_gcc_immediate(&self) -> bool;
+    fn is_gcc_scalar_pair(&self) -> bool;
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc>;
+    fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
+    fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>;
+    fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>;
+    fn gcc_field_index(&self, index: usize) -> u64;
+    fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>;
+}
+
+impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
+    fn is_gcc_immediate(&self) -> bool {
+        match self.abi {
+            Abi::Scalar(_) | Abi::Vector { .. } => true,
+            Abi::ScalarPair(..) => false,
+            Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(),
+        }
+    }
+
+    fn is_gcc_scalar_pair(&self) -> bool {
+        match self.abi {
+            Abi::ScalarPair(..) => true,
+            Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false,
+        }
+    }
+
+    /// Gets the GCC type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`.
+    /// The pointee type of the pointer in `PlaceRef` is always this type.
+    /// For sized types, it is also the right LLVM type for an `alloca`
+    /// containing a value of that type, and most immediates (except `bool`).
+    /// Unsized types, however, are represented by a "minimal unit", e.g.
+    /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
+    /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
+    /// If the type is an unsized struct, the regular layout is generated,
+    /// with the inner-most trailing unsized field using the "minimal unit"
+    /// of that field's type - this is useful for taking the address of
+    /// that field and ensuring the struct has the right alignment.
+    //TODO(antoyo): do we still need the set_fields parameter?
+    fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc> {
+        if let Abi::Scalar(ref scalar) = self.abi {
+            // Use a different cache for scalars because pointers to DSTs
+            // can be either fat or thin (data pointers of fat pointers).
+            if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
+                return ty;
+            }
+            let ty =
+                match *self.ty.kind() {
+                    ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
+                        cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx, set_fields))
+                    }
+                    ty::Adt(def, _) if def.is_box() => {
+                        cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx, true))
+                    }
+                    ty::FnPtr(sig) => cx.fn_ptr_backend_type(&cx.fn_abi_of_fn_ptr(sig, ty::List::empty())),
+                    _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
+                };
+            cx.scalar_types.borrow_mut().insert(self.ty, ty);
+            return ty;
+        }
+
+        // Check the cache.
+        let variant_index =
+            match self.variants {
+                Variants::Single { index } => Some(index),
+                _ => None,
+            };
+        let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned();
+        if let Some(ty) = cached_type {
+            let type_to_set_fields = cx.types_with_fields_to_set.borrow_mut().remove(&ty);
+            if let Some((struct_type, layout)) = type_to_set_fields {
+                // Since we might be trying to generate a type containing another type which is not
+                // completely generated yet, we deferred setting the fields until now.
+                let (fields, packed) = struct_fields(cx, layout);
+                cx.set_struct_body(struct_type, &fields, packed);
+            }
+            return ty;
+        }
+
+        assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty);
+
+        // Make sure lifetimes are erased, to avoid generating distinct LLVM
+        // types for Rust types that only differ in the choice of lifetimes.
+        let normal_ty = cx.tcx.erase_regions(self.ty);
+
+        let mut defer = None;
+        let ty =
+            if self.ty != normal_ty {
+                let mut layout = cx.layout_of(normal_ty);
+                if let Some(v) = variant_index {
+                    layout = layout.for_variant(cx, v);
+                }
+                layout.gcc_type(cx, true)
+            }
+            else {
+                uncached_gcc_type(cx, *self, &mut defer)
+            };
+
+        cx.types.borrow_mut().insert((self.ty, variant_index), ty);
+
+        if let Some((ty, layout)) = defer {
+            let (fields, packed) = struct_fields(cx, layout);
+            cx.set_struct_body(ty, &fields, packed);
+        }
+
+        ty
+    }
+
+    fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
+        if let Abi::Scalar(ref scalar) = self.abi {
+            if scalar.is_bool() {
+                return cx.type_i1();
+            }
+        }
+        self.gcc_type(cx, true)
+    }
+
+    fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> {
+        match scalar.value {
+            Int(i, true) => cx.type_from_integer(i),
+            Int(i, false) => cx.type_from_unsigned_integer(i),
+            F32 => cx.type_f32(),
+            F64 => cx.type_f64(),
+            Pointer => {
+                // If we know the alignment, pick something better than i8.
+                let pointee =
+                    if let Some(pointee) = self.pointee_info_at(cx, offset) {
+                        cx.type_pointee_for_align(pointee.align)
+                    }
+                    else {
+                        cx.type_i8()
+                    };
+                cx.type_ptr_to(pointee)
+            }
+        }
+    }
+
+    fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc> {
+        // TODO(antoyo): remove llvm hack:
+        // HACK(eddyb) special-case fat pointers until LLVM removes
+        // pointee types, to avoid bitcasting every `OperandRef::deref`.
+        match self.ty.kind() {
+            ty::Ref(..) | ty::RawPtr(_) => {
+                return self.field(cx, index).gcc_type(cx, true);
+            }
+            ty::Adt(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_gcc_type(cx, index, immediate);
+            }
+            _ => {}
+        }
+
+        let (a, b) = match self.abi {
+            Abi::ScalarPair(ref a, ref b) => (a, b),
+            _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self),
+        };
+        let scalar = [a, b][index];
+
+        // Make sure to return the same type `immediate_gcc_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`.
+        // TODO(antoyo): this bugs certainly don't happen in this case since the bool type is used instead of i1.
+        if scalar.is_bool() {
+            return cx.type_i1();
+        }
+
+        let offset =
+            if index == 0 {
+                Size::ZERO
+            }
+            else {
+                a.value.size(cx).align_to(b.value.align(cx).abi)
+            };
+        self.scalar_gcc_type_at(cx, scalar, offset)
+    }
+
+    fn gcc_field_index(&self, index: usize) -> u64 {
+        match self.abi {
+            Abi::Scalar(_) | Abi::ScalarPair(..) => {
+                bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
+            }
+            _ => {}
+        }
+        match self.fields {
+            FieldsShape::Primitive | FieldsShape::Union(_) => {
+                bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
+            }
+
+            FieldsShape::Array { .. } => index as u64,
+
+            FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2,
+        }
+    }
+
+    fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo> {
+        if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) {
+            return pointee;
+        }
+
+        let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset);
+
+        cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
+        result
+    }
+}
+
+impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
+    fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
+        layout.gcc_type(self, true)
+    }
+
+    fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
+        layout.immediate_gcc_type(self)
+    }
+
+    fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool {
+        layout.is_gcc_immediate()
+    }
+
+    fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool {
+        layout.is_gcc_scalar_pair()
+    }
+
+    fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 {
+        layout.gcc_field_index(index)
+    }
+
+    fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool) -> Type<'gcc> {
+        layout.scalar_pair_element_gcc_type(self, index, immediate)
+    }
+
+    fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> {
+        ty.gcc_type(self)
+    }
+
+    fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+        fn_abi.ptr_to_gcc_type(self)
+    }
+
+    fn reg_backend_type(&self, _ty: &Reg) -> Type<'gcc> {
+        unimplemented!();
+    }
+
+    fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
+        // FIXME(antoyo): return correct type.
+        self.type_void()
+    }
+}
diff --git a/compiler/rustc_codegen_gcc/test.sh b/compiler/rustc_codegen_gcc/test.sh
new file mode 100755 (executable)
index 0000000..944d0ce
--- /dev/null
@@ -0,0 +1,217 @@
+#!/bin/bash
+
+# TODO(antoyo): rewrite to cargo-make (or just) or something like that to only rebuild the sysroot when needed?
+
+set -e
+
+if [ -f ./gcc_path ]; then 
+    export GCC_PATH=$(cat gcc_path)
+else
+    echo 'Please put the path to your custom build of libgccjit in the file `gcc_path`, see Readme.md for details'
+    exit 1
+fi
+
+export LD_LIBRARY_PATH="$GCC_PATH"
+export LIBRARY_PATH="$GCC_PATH"
+
+if [[ "$1" == "--release" ]]; then
+    export CHANNEL='release'
+    CARGO_INCREMENTAL=1 cargo rustc --release
+    shift
+else
+    echo $LD_LIBRARY_PATH
+    export CHANNEL='debug'
+    cargo rustc
+fi
+
+source config.sh
+
+function clean() {
+    rm -r target/out || true
+    mkdir -p target/out/gccjit
+}
+
+function mini_tests() {
+    echo "[BUILD] mini_core"
+    $RUSTC example/mini_core.rs --crate-name mini_core --crate-type lib,dylib --target $TARGET_TRIPLE
+
+    echo "[BUILD] example"
+    $RUSTC example/example.rs --crate-type lib --target $TARGET_TRIPLE
+
+    echo "[AOT] mini_core_hello_world"
+    $RUSTC example/mini_core_hello_world.rs --crate-name mini_core_hello_world --crate-type bin -g --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/mini_core_hello_world abc bcd
+}
+
+function build_sysroot() {
+    echo "[BUILD] sysroot"
+    time ./build_sysroot/build_sysroot.sh
+}
+
+function std_tests() {
+    echo "[AOT] arbitrary_self_types_pointers_and_wrappers"
+    $RUSTC example/arbitrary_self_types_pointers_and_wrappers.rs --crate-name arbitrary_self_types_pointers_and_wrappers --crate-type bin --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/arbitrary_self_types_pointers_and_wrappers
+
+    echo "[AOT] alloc_system"
+    $RUSTC example/alloc_system.rs --crate-type lib --target "$TARGET_TRIPLE"
+
+    echo "[AOT] alloc_example"
+    $RUSTC example/alloc_example.rs --crate-type bin --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/alloc_example
+
+    echo "[AOT] dst_field_align"
+    # FIXME(antoyo): Re-add -Zmir-opt-level=2 once rust-lang/rust#67529 is fixed.
+    $RUSTC example/dst-field-align.rs --crate-name dst_field_align --crate-type bin --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/dst_field_align || (echo $?; false)
+
+    echo "[AOT] std_example"
+    $RUSTC example/std_example.rs --crate-type bin --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/std_example --target $TARGET_TRIPLE
+
+    echo "[AOT] subslice-patterns-const-eval"
+    $RUSTC example/subslice-patterns-const-eval.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/subslice-patterns-const-eval
+
+    echo "[AOT] track-caller-attribute"
+    $RUSTC example/track-caller-attribute.rs --crate-type bin -Cpanic=abort --target $TARGET_TRIPLE
+    $RUN_WRAPPER ./target/out/track-caller-attribute
+
+    echo "[BUILD] mod_bench"
+    $RUSTC example/mod_bench.rs --crate-type bin --target $TARGET_TRIPLE
+}
+
+# FIXME(antoyo): linker gives multiple definitions error on Linux
+#echo "[BUILD] sysroot in release mode"
+#./build_sysroot/build_sysroot.sh --release
+
+# TODO(antoyo): uncomment when it works.
+#pushd simple-raytracer
+#if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then
+    #echo "[BENCH COMPILE] ebobby/simple-raytracer"
+    #hyperfine --runs ${RUN_RUNS:-10} --warmup 1 --prepare "rm -r target/*/debug || true" \
+    #"RUSTFLAGS='' cargo build --target $TARGET_TRIPLE" \
+    #"../cargo.sh build"
+
+    #echo "[BENCH RUN] ebobby/simple-raytracer"
+    #cp ./target/*/debug/main ./raytracer_cg_gccjit
+    #hyperfine --runs ${RUN_RUNS:-10} ./raytracer_cg_llvm ./raytracer_cg_gccjit
+#else
+    #echo "[BENCH COMPILE] ebobby/simple-raytracer (skipped)"
+    #echo "[COMPILE] ebobby/simple-raytracer"
+    #../cargo.sh build
+    #echo "[BENCH RUN] ebobby/simple-raytracer (skipped)"
+#fi
+#popd
+
+function test_libcore() {
+    pushd build_sysroot/sysroot_src/library/core/tests
+    echo "[TEST] libcore"
+    rm -r ./target || true
+    ../../../../../cargo.sh test
+    popd
+}
+
+# TODO(antoyo): uncomment when it works.
+#pushd regex
+#echo "[TEST] rust-lang/regex example shootout-regex-dna"
+#../cargo.sh clean
+## Make sure `[codegen mono items] start` doesn't poison the diff
+#../cargo.sh build --example shootout-regex-dna
+#cat examples/regexdna-input.txt | ../cargo.sh run --example shootout-regex-dna | grep -v "Spawned thread" > res.txt
+#diff -u res.txt examples/regexdna-output.txt
+
+#echo "[TEST] rust-lang/regex tests"
+#../cargo.sh test --tests -- --exclude-should-panic --test-threads 1 -Zunstable-options
+#popd
+
+#echo
+#echo "[BENCH COMPILE] mod_bench"
+
+#COMPILE_MOD_BENCH_INLINE="$RUSTC example/mod_bench.rs --crate-type bin -Zmir-opt-level=3 -O --crate-name mod_bench_inline"
+#COMPILE_MOD_BENCH_LLVM_0="rustc example/mod_bench.rs --crate-type bin -Copt-level=0 -o target/out/mod_bench_llvm_0 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_1="rustc example/mod_bench.rs --crate-type bin -Copt-level=1 -o target/out/mod_bench_llvm_1 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_2="rustc example/mod_bench.rs --crate-type bin -Copt-level=2 -o target/out/mod_bench_llvm_2 -Cpanic=abort"
+#COMPILE_MOD_BENCH_LLVM_3="rustc example/mod_bench.rs --crate-type bin -Copt-level=3 -o target/out/mod_bench_llvm_3 -Cpanic=abort"
+
+## Use 100 runs, because a single compilations doesn't take more than ~150ms, so it isn't very slow
+#hyperfine --runs ${COMPILE_RUNS:-100} "$COMPILE_MOD_BENCH_INLINE" "$COMPILE_MOD_BENCH_LLVM_0" "$COMPILE_MOD_BENCH_LLVM_1" "$COMPILE_MOD_BENCH_LLVM_2" "$COMPILE_MOD_BENCH_LLVM_3"
+
+#echo
+#echo "[BENCH RUN] mod_bench"
+#hyperfine --runs ${RUN_RUNS:-10} ./target/out/mod_bench{,_inline} ./target/out/mod_bench_llvm_*
+
+function test_rustc() {
+    echo
+    echo "[TEST] rust-lang/rust"
+
+    rust_toolchain=$(cat rust-toolchain)
+
+    git clone https://github.com/rust-lang/rust.git || true
+    cd rust
+    git fetch
+    git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(')
+    export RUSTFLAGS=
+
+    rm config.toml || true
+
+    cat > config.toml <<EOF
+[rust]
+codegen-backends = []
+deny-warnings = false
+
+[build]
+cargo = "$(which cargo)"
+local-rebuild = true
+rustc = "$HOME/.rustup/toolchains/$rust_toolchain-$TARGET_TRIPLE/bin/rustc"
+EOF
+
+    rustc -V | cut -d' ' -f3 | tr -d '('
+    git checkout $(rustc -V | cut -d' ' -f3 | tr -d '(') src/test
+
+    for test in $(rg -i --files-with-matches "//(\[\w+\])?~|// error-pattern:|// build-fail|// run-fail|-Cllvm-args" src/test/ui); do
+      rm $test
+    done
+
+    git checkout -- src/test/ui/issues/auxiliary/issue-3136-a.rs # contains //~ERROR, but shouldn't be removed
+
+    rm -r src/test/ui/{abi*,extern/,llvm-asm/,panic-runtime/,panics/,unsized-locals/,proc-macro/,threads-sendsync/,thinlto/,simd*,borrowck/,test*,*lto*.rs} || true
+    for test in $(rg --files-with-matches "catch_unwind|should_panic|thread|lto" src/test/ui); do
+      rm $test
+    done
+    git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice.rs
+    git checkout src/test/ui/type-alias-impl-trait/auxiliary/cross_crate_ice2.rs
+    rm src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs || true # TODO(antoyo): Enable back this test if I ever implement the llvm_asm! macro.
+
+    RUSTC_ARGS="-Zpanic-abort-tests -Zsymbol-mangling-version=v0 -Zcodegen-backend="$(pwd)"/../target/"$CHANNEL"/librustc_codegen_gcc."$dylib_ext" --sysroot "$(pwd)"/../build_sysroot/sysroot -Cpanic=abort"
+
+    echo "[TEST] rustc test suite"
+    COMPILETEST_FORCE_STAGE0=1 ./x.py test --run always --stage 0 src/test/ui/ --rustc-args "$RUSTC_ARGS"
+}
+
+function clean_ui_tests() {
+    find rust/build/x86_64-unknown-linux-gnu/test/ui/ -name stamp -exec rm -rf {} \;
+}
+
+case $1 in
+    "--test-rustc")
+        test_rustc
+        ;;
+
+    "--test-libcore")
+        test_libcore
+        ;;
+
+    "--clean-ui-tests")
+        clean_ui_tests
+        ;;
+
+    *)
+        clean
+        mini_tests
+        build_sysroot
+        std_tests
+        test_libcore
+        test_rustc
+        ;;
+esac
diff --git a/compiler/rustc_codegen_gcc/tests/lib.rs b/compiler/rustc_codegen_gcc/tests/lib.rs
new file mode 100644 (file)
index 0000000..8ee35b3
--- /dev/null
@@ -0,0 +1,50 @@
+use std::{
+    env::{self, current_dir},
+    path::PathBuf,
+    process::Command,
+};
+
+use lang_tester::LangTester;
+use tempfile::TempDir;
+
+fn main() {
+    let tempdir = TempDir::new().expect("temp dir");
+    let current_dir = current_dir().expect("current dir");
+    let current_dir = current_dir.to_str().expect("current dir").to_string();
+    let gcc_path = include_str!("../gcc_path");
+    let gcc_path = gcc_path.trim();
+    env::set_var("LD_LIBRARY_PATH", gcc_path);
+    LangTester::new()
+        .test_dir("tests/run")
+        .test_file_filter(|path| path.extension().expect("extension").to_str().expect("to_str") == "rs")
+        .test_extract(|source| {
+            let lines =
+                source.lines()
+                    .skip_while(|l| !l.starts_with("//"))
+                    .take_while(|l| l.starts_with("//"))
+                    .map(|l| &l[2..])
+                    .collect::<Vec<_>>()
+                    .join("\n");
+            Some(lines)
+        })
+        .test_cmds(move |path| {
+            // Test command 1: Compile `x.rs` into `tempdir/x`.
+            let mut exe = PathBuf::new();
+            exe.push(&tempdir);
+            exe.push(path.file_stem().expect("file_stem"));
+            let mut compiler = Command::new("rustc");
+            compiler.args(&[
+                &format!("-Zcodegen-backend={}/target/debug/librustc_codegen_gcc.so", current_dir),
+                "--sysroot", &format!("{}/build_sysroot/sysroot/", current_dir),
+                "-Zno-parallel-llvm",
+                "-C", "panic=abort",
+                "-C", "link-arg=-lc",
+                "-o", exe.to_str().expect("to_str"),
+                path.to_str().expect("to_str"),
+            ]);
+            // Test command 2: run `tempdir/x`.
+            let runtime = Command::new(exe);
+            vec![("Compiler", compiler), ("Run-time", runtime)]
+        })
+        .run();
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort1.rs b/compiler/rustc_codegen_gcc/tests/run/abort1.rs
new file mode 100644 (file)
index 0000000..291af59
--- /dev/null
@@ -0,0 +1,51 @@
+// Compiler:
+//
+// Run-time:
+//   status: signal
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+    use super::Sized;
+
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+/*
+ * Code
+ */
+
+fn test_fail() -> ! {
+    unsafe { intrinsics::abort() };
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    test_fail();
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/abort2.rs b/compiler/rustc_codegen_gcc/tests/run/abort2.rs
new file mode 100644 (file)
index 0000000..3c87c56
--- /dev/null
@@ -0,0 +1,53 @@
+// Compiler:
+//
+// Run-time:
+//   status: signal
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+    use super::Sized;
+
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+/*
+ * Code
+ */
+
+fn fail() -> i32 {
+    unsafe { intrinsics::abort() };
+    0
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    fail();
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/array.rs b/compiler/rustc_codegen_gcc/tests/run/array.rs
new file mode 100644 (file)
index 0000000..8b621d8
--- /dev/null
@@ -0,0 +1,229 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 42
+//     7
+//     5
+//     10
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+
+/*
+ * Code
+ */
+
+static mut ONE: usize = 1;
+
+fn make_array() -> [u8; 3] {
+    [42, 10, 5]
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    let array = [42, 7, 5];
+    let array2 = make_array();
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE - 1]);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE]);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, array[ONE + 1]);
+
+        libc::printf(b"%d\n\0" as *const u8 as *const i8, array2[argc as usize] as u32);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/asm.rs b/compiler/rustc_codegen_gcc/tests/run/asm.rs
new file mode 100644 (file)
index 0000000..9c0055b
--- /dev/null
@@ -0,0 +1,153 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+
+#![feature(asm, global_asm)]
+
+global_asm!("
+    .global add_asm
+add_asm:
+     mov rax, rdi
+     add rax, rsi
+     ret"
+);
+
+extern "C" {
+    fn add_asm(a: i64, b: i64) -> i64;
+}
+
+fn main() {
+    unsafe {
+        asm!("nop");
+    }
+
+    let x: u64;
+    unsafe {
+        asm!("mov $5, {}",
+            out(reg) x,
+            options(att_syntax)
+        );
+    }
+    assert_eq!(x, 5);
+
+    let x: u64;
+    let input: u64 = 42;
+    unsafe {
+        asm!("mov {input}, {output}",
+             "add $1, {output}",
+            input = in(reg) input,
+            output = out(reg) x,
+            options(att_syntax)
+        );
+    }
+    assert_eq!(x, 43);
+
+    let x: u64;
+    unsafe {
+        asm!("mov {}, 6",
+            out(reg) x,
+        );
+    }
+    assert_eq!(x, 6);
+
+    let x: u64;
+    let input: u64 = 42;
+    unsafe {
+        asm!("mov {output}, {input}",
+             "add {output}, 1",
+            input = in(reg) input,
+            output = out(reg) x,
+        );
+    }
+    assert_eq!(x, 43);
+
+    // check inout(reg_class) x 
+    let mut x: u64 = 42;
+    unsafe {
+        asm!("add {0}, {0}",
+            inout(reg) x 
+        );
+    }
+    assert_eq!(x, 84);
+
+    // check inout("reg") x
+    let mut x: u64 = 42;
+    unsafe {
+        asm!("add r11, r11",
+            inout("r11") x 
+        );
+    }
+    assert_eq!(x, 84);
+
+    // check a mix of
+    // in("reg")
+    // inout(class) x => y
+    // inout (class) x
+    let x: u64 = 702;
+    let y: u64 = 100;
+    let res: u64;
+    let mut rem: u64 = 0;
+    unsafe {
+        asm!("div r11",
+            in("r11") y,
+            inout("eax") x => res,
+            inout("edx") rem,
+        );
+    }
+    assert_eq!(res, 7);
+    assert_eq!(rem, 2);
+
+    // check const 
+    let mut x: u64 = 42;
+    unsafe {
+        asm!("add {}, {}",
+            inout(reg) x,
+            const 1 
+        );
+    }
+    assert_eq!(x, 43);
+
+    // check const (ATT syntax)
+    let mut x: u64 = 42;
+    unsafe {
+        asm!("add {}, {}",
+            const 1,
+            inout(reg) x,
+            options(att_syntax)
+        );
+    }
+    assert_eq!(x, 43);
+
+    // check sym fn
+    extern "C" fn foo() -> u64 { 42 }
+    let x: u64;
+    unsafe {
+        asm!("call {}", sym foo, lateout("rax") x);
+    }
+    assert_eq!(x, 42);
+
+    // check sym fn (ATT syntax)
+    let x: u64;
+    unsafe {
+        asm!("call {}", sym foo, lateout("rax") x, options(att_syntax));
+    }
+    assert_eq!(x, 42);
+
+    // check sym static
+    static FOO: u64 = 42;
+    let x: u64;
+    unsafe {
+        asm!("mov {1}, qword ptr [rip + {0}]", sym FOO, lateout(reg) x);
+    }
+    assert_eq!(x, 42);
+
+    // check sym static (ATT syntax)
+    let x: u64;
+    unsafe {
+        asm!("movq {0}(%rip), {1}", sym FOO, lateout(reg) x, options(att_syntax));
+    }
+    assert_eq!(x, 42);
+
+    assert_eq!(unsafe { add_asm(40, 2) }, 42);
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/assign.rs b/compiler/rustc_codegen_gcc/tests/run/assign.rs
new file mode 100644 (file)
index 0000000..cc86470
--- /dev/null
@@ -0,0 +1,153 @@
+// Compiler:
+//
+// Run-time:
+//   stdout: 2
+//     7 8
+//     10
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn fflush(stream: *mut i32) -> i32;
+        pub fn printf(format: *const i8, ...) -> i32;
+
+        pub static STDOUT: *mut i32;
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        libc::fflush(libc::STDOUT);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+/*
+ * Code
+ */
+
+fn inc_ref(num: &mut isize) -> isize {
+    *num = *num + 5;
+    *num + 1
+}
+
+fn inc(num: isize) -> isize {
+    num + 1
+}
+
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    argc = inc(argc);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+    }
+
+    let b = inc_ref(&mut argc);
+    unsafe {
+        libc::printf(b"%ld %ld\n\0" as *const u8 as *const i8, argc, b);
+    }
+
+    argc = 10;
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/closure.rs b/compiler/rustc_codegen_gcc/tests/run/closure.rs
new file mode 100644 (file)
index 0000000..7121a5f
--- /dev/null
@@ -0,0 +1,230 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: Arg: 1
+//     Argument: 1
+//     String arg: 1
+//     Int argument: 2
+//     Both args: 11
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics,
+    unboxed_closures)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+pub trait FnOnce<Args> {
+    #[lang = "fn_once_output"]
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+pub trait FnMut<Args>: FnOnce<Args> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let string = "Arg: %d\n\0";
+    let mut closure = || {
+        unsafe {
+            libc::printf(string as *const str as *const i8, argc);
+        }
+    };
+    closure();
+
+    let mut closure = || {
+        unsafe {
+            libc::printf("Argument: %d\n\0" as *const str as *const i8, argc);
+        }
+    };
+    closure();
+
+    let mut closure = |string| {
+        unsafe {
+            libc::printf(string as *const str as *const i8, argc);
+        }
+    };
+    closure("String arg: %d\n\0");
+
+    let mut closure = |arg: isize| {
+        unsafe {
+            libc::printf("Int argument: %d\n\0" as *const str as *const i8, arg);
+        }
+    };
+    closure(argc + 1);
+
+    let mut closure = |string, arg: isize| {
+        unsafe {
+            libc::printf(string as *const str as *const i8, arg);
+        }
+    };
+    closure("Both args: %d\n\0", argc + 10);
+
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/condition.rs b/compiler/rustc_codegen_gcc/tests/run/condition.rs
new file mode 100644 (file)
index 0000000..6a2e2d5
--- /dev/null
@@ -0,0 +1,320 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: true
+//     1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for u64 {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+impl Copy for bool {}
+impl Copy for u16 {}
+impl Copy for i16 {}
+impl Copy for char {}
+impl Copy for i8 {}
+impl Copy for u8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+#[lang = "eq"]
+pub trait PartialEq<Rhs: ?Sized = Self> {
+    fn eq(&self, other: &Rhs) -> bool;
+    fn ne(&self, other: &Rhs) -> bool;
+}
+
+impl PartialEq for u8 {
+    fn eq(&self, other: &u8) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u8) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for u16 {
+    fn eq(&self, other: &u16) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u16) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for u32 {
+    fn eq(&self, other: &u32) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u32) -> bool {
+        (*self) != (*other)
+    }
+}
+
+
+impl PartialEq for u64 {
+    fn eq(&self, other: &u64) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &u64) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for usize {
+    fn eq(&self, other: &usize) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &usize) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for i8 {
+    fn eq(&self, other: &i8) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &i8) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for i32 {
+    fn eq(&self, other: &i32) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &i32) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for isize {
+    fn eq(&self, other: &isize) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &isize) -> bool {
+        (*self) != (*other)
+    }
+}
+
+impl PartialEq for char {
+    fn eq(&self, other: &char) -> bool {
+        (*self) == (*other)
+    }
+    fn ne(&self, other: &char) -> bool {
+        (*self) != (*other)
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        if argc == 1 {
+            libc::printf(b"true\n\0" as *const u8 as *const i8);
+        }
+
+        let string =
+            match argc {
+                1 => b"1\n\0",
+                2 => b"2\n\0",
+                3 => b"3\n\0",
+                4 => b"4\n\0",
+                5 => b"5\n\0",
+                _ => b"_\n\0",
+            };
+        libc::printf(string as *const u8 as *const i8);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/empty_main.rs b/compiler/rustc_codegen_gcc/tests/run/empty_main.rs
new file mode 100644 (file)
index 0000000..c02cfd2
--- /dev/null
@@ -0,0 +1,39 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+
+#![feature(auto_traits, lang_items, no_core, start)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit.rs b/compiler/rustc_codegen_gcc/tests/run/exit.rs
new file mode 100644 (file)
index 0000000..956e53d
--- /dev/null
@@ -0,0 +1,49 @@
+// Compiler:
+//
+// Run-time:
+//   status: 2
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn exit(status: i32);
+    }
+}
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        libc::exit(2);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/exit_code.rs b/compiler/rustc_codegen_gcc/tests/run/exit_code.rs
new file mode 100644 (file)
index 0000000..eeab352
--- /dev/null
@@ -0,0 +1,39 @@
+// Compiler:
+//
+// Run-time:
+//   status: 1
+
+#![feature(auto_traits, lang_items, no_core, start)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    1
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs b/compiler/rustc_codegen_gcc/tests/run/fun_ptr.rs
new file mode 100644 (file)
index 0000000..a226fff
--- /dev/null
@@ -0,0 +1,223 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+
+/*
+ * Code
+ */
+
+fn i16_as_i8(a: i16) -> i8 {
+    a as i8
+}
+
+fn call_func(func: fn(i16) -> i8, param: i16) -> i8 {
+    func(param)
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        let result = call_func(i16_as_i8, argc as i16) as isize;
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, result);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs b/compiler/rustc_codegen_gcc/tests/run/int_overflow.rs
new file mode 100644 (file)
index 0000000..7111703
--- /dev/null
@@ -0,0 +1,129 @@
+// Compiler:
+//
+// Run-time:
+//   stdout: Panicking
+//   status: signal
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn fflush(stream: *mut i32) -> i32;
+
+        pub static STDOUT: *mut i32;
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        libc::fflush(libc::STDOUT);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let int = 9223372036854775807isize;
+    let int = int + argc;
+    int
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs b/compiler/rustc_codegen_gcc/tests/run/mut_ref.rs
new file mode 100644 (file)
index 0000000..e887600
--- /dev/null
@@ -0,0 +1,165 @@
+
+// Compiler:
+//
+// Run-time:
+//   stdout: 2
+//     7
+//     6
+//     11
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, track_caller)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn puts(s: *const u8) -> i32;
+        pub fn fflush(stream: *mut i32) -> i32;
+        pub fn printf(format: *const i8, ...) -> i32;
+
+        pub static STDOUT: *mut i32;
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        libc::fflush(libc::STDOUT);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+    field: isize,
+}
+
+fn test(num: isize) -> Test {
+    Test {
+        field: num + 1,
+    }
+}
+
+fn update_num(num: &mut isize) {
+    *num = *num + 5;
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let mut test = test(argc);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+    }
+    update_num(&mut test.field);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+    }
+
+    update_num(&mut argc);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+    }
+
+    let refe = &mut argc;
+    *refe = *refe + 5;
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, argc);
+    }
+
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/operations.rs b/compiler/rustc_codegen_gcc/tests/run/operations.rs
new file mode 100644 (file)
index 0000000..4dc3753
--- /dev/null
@@ -0,0 +1,221 @@
+// Compiler:
+//
+// Run-time:
+//   stdout: 41
+//     39
+//     10
+
+#![allow(unused_attributes)]
+#![feature(auto_traits, lang_items, no_core, start, intrinsics, arbitrary_self_types)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for *mut i32 {}
+impl Copy for usize {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+impl Copy for i32 {}
+
+#[lang = "deref"]
+pub trait Deref {
+    type Target: ?Sized;
+
+    fn deref(&self) -> &Self::Target;
+}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+        pub fn fflush(stream: *mut i32) -> i32;
+
+        pub static STDOUT: *mut i32;
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        libc::fflush(libc::STDOUT);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+#[lang = "mul"]
+pub trait Mul<RHS = Self> {
+    type Output;
+
+    #[must_use]
+    fn mul(self, rhs: RHS) -> Self::Output;
+}
+
+impl Mul for u8 {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+impl Mul for usize {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+impl Mul for isize {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        self * rhs
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 + argc);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, 40 - argc);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, 10 * argc);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs b/compiler/rustc_codegen_gcc/tests/run/ptr_cast.rs
new file mode 100644 (file)
index 0000000..6ac099e
--- /dev/null
@@ -0,0 +1,222 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 1
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u8 {}
+impl Copy for i8 {}
+impl Copy for i16 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+        pub fn puts(s: *const u8) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic"]
+#[track_caller]
+#[no_mangle]
+pub fn panic(_msg: &str) -> ! {
+    unsafe {
+        libc::puts("Panicking\0" as *const str as *const u8);
+        intrinsics::abort();
+    }
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+#[lang = "add"]
+trait Add<RHS = Self> {
+    type Output;
+
+    fn add(self, rhs: RHS) -> Self::Output;
+}
+
+impl Add for u8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i8 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for i32 {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for usize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+impl Add for isize {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self {
+        self + rhs
+    }
+}
+
+#[lang = "sub"]
+pub trait Sub<RHS = Self> {
+    type Output;
+
+    fn sub(self, rhs: RHS) -> Self::Output;
+}
+
+impl Sub for usize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for isize {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for u8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i8 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+impl Sub for i16 {
+    type Output = Self;
+
+    fn sub(self, rhs: Self) -> Self {
+        self - rhs
+    }
+}
+
+
+/*
+ * Code
+ */
+
+static mut ONE: usize = 1;
+
+fn make_array() -> [u8; 3] {
+    [42, 10, 5]
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        let ptr = ONE as *mut usize;
+        let value = ptr as usize;
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, value);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs b/compiler/rustc_codegen_gcc/tests/run/return-tuple.rs
new file mode 100644 (file)
index 0000000..6fa10dc
--- /dev/null
@@ -0,0 +1,72 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 10
+//     10
+//     42
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+#[lang = "copy"]
+pub unsafe trait Copy {}
+
+unsafe impl Copy for bool {}
+unsafe impl Copy for u8 {}
+unsafe impl Copy for u16 {}
+unsafe impl Copy for u32 {}
+unsafe impl Copy for u64 {}
+unsafe impl Copy for usize {}
+unsafe impl Copy for i8 {}
+unsafe impl Copy for i16 {}
+unsafe impl Copy for i32 {}
+unsafe impl Copy for isize {}
+unsafe impl Copy for f32 {}
+unsafe impl Copy for char {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+/*
+ * Code
+ */
+
+fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
+    (
+        a as u8, a as u16, a as u32, a as usize, a as i8, a as i16, a as i32, a as isize, b as u8,
+        b as u32,
+    )
+}
+
+#[start]
+fn main(argc: isize, _argv: *const *const u8) -> isize {
+    let (a, b, c, d, e, f, g, h, i, j) = int_cast(10, 42);
+    unsafe {
+        libc::printf(b"%d\n\0" as *const u8 as *const i8, c);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, d);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, j);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/slice.rs b/compiler/rustc_codegen_gcc/tests/run/slice.rs
new file mode 100644 (file)
index 0000000..ad9258e
--- /dev/null
@@ -0,0 +1,128 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 5
+
+#![feature(arbitrary_self_types, auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+impl Copy for usize {}
+impl Copy for i32 {}
+impl Copy for u32 {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+#[lang = "index"]
+pub trait Index<Idx: ?Sized> {
+    type Output: ?Sized;
+    fn index(&self, index: Idx) -> &Self::Output;
+}
+
+impl<T> Index<usize> for [T; 3] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+impl<T> Index<usize> for [T] {
+    type Output = T;
+
+    fn index(&self, index: usize) -> &Self::Output {
+        &self[index]
+    }
+}
+
+#[lang = "unsize"]
+pub trait Unsize<T: ?Sized> {}
+
+#[lang = "coerce_unsized"]
+pub trait CoerceUnsized<T> {}
+
+impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a mut U> for &'a mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+#[lang = "panic_location"]
+struct PanicLocation {
+    file: &'static str,
+    line: u32,
+    column: u32,
+}
+
+#[lang = "panic_bounds_check"]
+#[track_caller]
+#[no_mangle]
+fn panic_bounds_check(index: usize, len: usize) -> ! {
+    unsafe {
+        libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+        intrinsics::abort();
+    }
+}
+
+mod intrinsics {
+    use super::Sized;
+
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+/*
+ * Code
+ */
+
+static mut TWO: usize = 2;
+
+fn index_slice(s: &[u32]) -> u32 {
+    unsafe {
+        s[TWO]
+    }
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let array = [42, 7, 5];
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, index_slice(&array));
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/static.rs b/compiler/rustc_codegen_gcc/tests/run/static.rs
new file mode 100644 (file)
index 0000000..ab89f6a
--- /dev/null
@@ -0,0 +1,106 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 10
+//      14
+//      1
+//      12
+//      12
+//      1
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod intrinsics {
+    use super::Sized;
+
+    extern "rust-intrinsic" {
+        pub fn abort() -> !;
+    }
+}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+#[lang = "structural_peq"]
+pub trait StructuralPartialEq {}
+
+#[lang = "structural_teq"]
+pub trait StructuralEq {}
+
+#[lang = "drop_in_place"]
+#[allow(unconditional_recursion)]
+pub unsafe fn drop_in_place<T: ?Sized>(to_drop: *mut T) {
+    // Code here does not matter - this is replaced by the
+    // real drop glue by the compiler.
+    drop_in_place(to_drop);
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+    field: isize,
+}
+
+struct WithRef {
+    refe: &'static Test,
+}
+
+static mut CONSTANT: isize = 10;
+
+static mut TEST: Test = Test {
+    field: 12,
+};
+
+static mut TEST2: Test = Test {
+    field: 14,
+};
+
+static mut WITH_REF: WithRef = WithRef {
+    refe: unsafe { &TEST },
+};
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, CONSTANT);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
+        TEST2.field = argc;
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST2.field);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field);
+        WITH_REF.refe = &TEST2;
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, TEST.field);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, WITH_REF.refe.field);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/structs.rs b/compiler/rustc_codegen_gcc/tests/run/structs.rs
new file mode 100644 (file)
index 0000000..6c88848
--- /dev/null
@@ -0,0 +1,70 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 1
+//     2
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+/*
+ * Code
+ */
+
+struct Test {
+    field: isize,
+}
+
+struct Two {
+    two: isize,
+}
+
+fn one() -> isize {
+    1
+}
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let test = Test {
+        field: one(),
+    };
+    let two = Two {
+        two: 2,
+    };
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.field);
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, two.two);
+    }
+    0
+}
diff --git a/compiler/rustc_codegen_gcc/tests/run/tuple.rs b/compiler/rustc_codegen_gcc/tests/run/tuple.rs
new file mode 100644 (file)
index 0000000..0b670bf
--- /dev/null
@@ -0,0 +1,51 @@
+// Compiler:
+//
+// Run-time:
+//   status: 0
+//   stdout: 3
+
+#![feature(auto_traits, lang_items, no_core, start, intrinsics)]
+
+#![no_std]
+#![no_core]
+
+/*
+ * Core
+ */
+
+// Because we don't have core yet.
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "copy"]
+trait Copy {
+}
+
+impl Copy for isize {}
+
+#[lang = "receiver"]
+trait Receiver {
+}
+
+#[lang = "freeze"]
+pub(crate) unsafe auto trait Freeze {}
+
+mod libc {
+    #[link(name = "c")]
+    extern "C" {
+        pub fn printf(format: *const i8, ...) -> i32;
+    }
+}
+
+/*
+ * Code
+ */
+
+#[start]
+fn main(mut argc: isize, _argv: *const *const u8) -> isize {
+    let test: (isize, isize, isize) = (3, 1, 4);
+    unsafe {
+        libc::printf(b"%ld\n\0" as *const u8 as *const i8, test.0);
+    }
+    0
+}
index 791604a18273d62ef6567329572419f50c93c310..92199f611bad03baa517c0425a28e1aa98a4bb36 100644 (file)
@@ -370,8 +370,9 @@ fn get_pgo_use_path(config: &ModuleConfig) -> Option<CString> {
 }
 
 pub(crate) fn should_use_new_llvm_pass_manager(config: &ModuleConfig) -> bool {
-    // The new pass manager is disabled by default.
-    config.new_llvm_pass_manager.unwrap_or(false)
+    // The new pass manager is enabled by default for LLVM >= 13.
+    // This matches Clang, which also enables it since Clang 13.
+    config.new_llvm_pass_manager.unwrap_or_else(|| llvm_util::get_version() >= (13, 0, 0))
 }
 
 pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
index 37b3279fb80966dd3058b49c412e31fe70e9b087..be55a0c868a462c38a37a429c12fe178911d59ff 100644 (file)
@@ -96,7 +96,6 @@ fn codegen_intrinsic_call(
         let arg_tys = sig.inputs();
         let ret_ty = sig.output();
         let name = tcx.item_name(def_id);
-        let name_str = &*name.as_str();
 
         let llret_ty = self.layout_of(ret_ty).llvm_type(self);
         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
@@ -230,9 +229,14 @@ fn codegen_intrinsic_call(
                                 &[args[0].immediate(), y],
                             )
                         }
-                        sym::ctlz_nonzero | sym::cttz_nonzero => {
+                        sym::ctlz_nonzero => {
                             let y = self.const_bool(true);
-                            let llvm_name = &format!("llvm.{}.i{}", &name_str[..4], width);
+                            let llvm_name = &format!("llvm.ctlz.i{}", width);
+                            self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
+                        }
+                        sym::cttz_nonzero => {
+                            let y = self.const_bool(true);
+                            let llvm_name = &format!("llvm.cttz.i{}", width);
                             self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
                         }
                         sym::ctpop => self.call_intrinsic(
@@ -353,7 +357,7 @@ fn codegen_intrinsic_call(
                 return;
             }
 
-            _ if name_str.starts_with("simd_") => {
+            _ if name.as_str().starts_with("simd_") => {
                 match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
                     Ok(llval) => llval,
                     Err(()) => return,
@@ -843,7 +847,6 @@ macro_rules! require_simd {
     let sig =
         tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
     let arg_tys = sig.inputs();
-    let name_str = &*name.as_str();
 
     if name == sym::simd_select_bitmask {
         let in_ty = arg_tys[0];
@@ -917,7 +920,7 @@ macro_rules! require_simd {
         ));
     }
 
-    if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
+    if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") {
         // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
         // If there is no suffix, use the index array length.
         let n: u64 = if stripped.is_empty() {
index 7403c21a9060e0e17da08a9b325d87525970cf99..f087b9f7815da73a1b3bb79661b149a34124f000 100644 (file)
@@ -550,6 +550,18 @@ pub fn codegen_rvalue_operand(
                     OperandRef::new_zst(&mut bx, self.cx.layout_of(self.monomorphize(ty)));
                 (bx, operand)
             }
+            mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {
+                let operand = self.codegen_operand(&mut bx, operand);
+                let lloperand = operand.immediate();
+
+                let content_ty = self.monomorphize(content_ty);
+                let box_layout = bx.cx().layout_of(bx.tcx().mk_box(content_ty));
+                let llty_ptr = bx.cx().backend_type(box_layout);
+
+                let val = bx.pointercast(lloperand, llty_ptr);
+                let operand = OperandRef { val: OperandValue::Immediate(val), layout: box_layout };
+                (bx, operand)
+            }
         }
     }
 
@@ -763,6 +775,7 @@ pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>, span: Span) ->
             mir::Rvalue::AddressOf(..) |
             mir::Rvalue::Len(..) |
             mir::Rvalue::Cast(..) | // (*)
+            mir::Rvalue::ShallowInitBox(..) | // (*)
             mir::Rvalue::BinaryOp(..) |
             mir::Rvalue::CheckedBinaryOp(..) |
             mir::Rvalue::UnaryOp(..) |
index 6e35b33188cd238b858d1f3e696cebe86f49f364..bcce19b28db97444e189f25833a497dd45d9ae96 100644 (file)
@@ -289,6 +289,12 @@ pub fn eval_rvalue_into_place(
                 self.write_scalar(Scalar::from_machine_usize(val, self), &dest)?;
             }
 
+            ShallowInitBox(ref operand, _) => {
+                let src = self.eval_operand(operand, None)?;
+                let v = self.read_immediate(&src)?;
+                self.write_immediate(*v, &dest)?;
+            }
+
             Cast(cast_kind, ref operand, cast_ty) => {
                 let src = self.eval_operand(operand, None)?;
                 let cast_ty = self.subst_from_current_frame_and_normalize_erasing_regions(cast_ty);
index 9eec930f59e525cf5212e02cbadbf2226cd2bcb2..57d92005a56497ce3e63a19efcc73c5c9843d067 100644 (file)
@@ -650,6 +650,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
 
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
             Rvalue::NullaryOp(NullOp::Box, _) => self.check_op(ops::HeapAllocation),
+            Rvalue::ShallowInitBox(_, _) => {}
 
             Rvalue::UnaryOp(_, ref operand) => {
                 let ty = operand.ty(self.body, self.tcx);
@@ -912,6 +913,11 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
                     return;
                 }
 
+                if Some(callee) == tcx.lang_items().exchange_malloc_fn() {
+                    self.check_op(ops::HeapAllocation);
+                    return;
+                }
+
                 // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`.
                 let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn();
                 if is_async_block {
index cb9b4bcb77a8574ea8baa50bd54b1c3e95587de1..5eb7d7a91cc76d5aeec900c92f91fae4e038c6f6 100644 (file)
@@ -206,7 +206,8 @@ pub fn in_rvalue<Q, F>(cx: &ConstCx<'_, 'tcx>, in_local: &mut F, rvalue: &Rvalue
         Rvalue::Use(operand)
         | Rvalue::Repeat(operand, _)
         | Rvalue::UnaryOp(_, operand)
-        | Rvalue::Cast(_, operand, _) => in_operand::<Q, _>(cx, in_local, operand),
+        | Rvalue::Cast(_, operand, _)
+        | Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
 
         Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
             in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
index 52d04cb4ff1e0f689a6794e6d5d7631b4ece72fd..9408dfa956b40c2d799f765514fbcbf4050fd19d 100644 (file)
@@ -523,6 +523,8 @@ fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
                 NullOp::AlignOf => {}
             },
 
+            Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
+
             Rvalue::UnaryOp(op, operand) => {
                 match op {
                     // These operations can never fail.
index e2cbb09ce5e6d29e54c70975f4ff5c49f5903298..d8ac815a15821c114860dca527a26e9fdd62c87e 100644 (file)
@@ -3,7 +3,7 @@
 //! Also computes as the resulting DAG if each SCC is replaced with a
 //! node in the graph. This uses [Tarjan's algorithm](
 //! https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm)
-//! that completes in *O(n)* time.
+//! that completes in *O*(*n*) time.
 
 use crate::fx::FxHashSet;
 use crate::graph::vec_graph::VecGraph;
index 9a28f8f4e21062d5040d9acec2c8da20150b950f..20e2a3b9696e8560cb80d71d50cd9d8d6a0c281d 100644 (file)
@@ -9,7 +9,7 @@
 pub use index_map::SortedIndexMultiMap;
 
 /// `SortedMap` is a data structure with similar characteristics as BTreeMap but
-/// slightly different trade-offs: lookup, insertion, and removal are O(log(N))
+/// slightly different trade-offs: lookup, insertion, 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
index 30f659c2f71bd209946b6b94006f35eb235ccaa5..a1ffbae8b15f6dd7d3c02264ade7a1c2faf2d24d 100644 (file)
@@ -33,10 +33,11 @@ pub fn new(value: T) -> Self {
 
     #[track_caller]
     pub fn borrow(&self) -> MappedReadGuard<'_, T> {
-        ReadGuard::map(self.value.borrow(), |opt| match *opt {
-            None => panic!("attempted to read from stolen value"),
-            Some(ref v) => v,
-        })
+        let borrow = self.value.borrow();
+        if let None = &*borrow {
+            panic!("attempted to read from stolen value: {}", std::any::type_name::<T>());
+        }
+        ReadGuard::map(borrow, |opt| opt.as_ref().unwrap())
     }
 
     #[track_caller]
index 60d653ac8b6f9be426af54ac13c47fe76aaecf46..1c0b2a9b487611a17a15a272975b7dd293ea47b3 100644 (file)
@@ -3,6 +3,7 @@
 use rustc_ast::{token, Attribute, Inline, Item};
 use rustc_errors::{struct_span_err, DiagnosticBuilder};
 use rustc_parse::new_parser_from_file;
+use rustc_parse::validate_attr;
 use rustc_session::parse::ParseSess;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Ident};
@@ -168,7 +169,25 @@ fn mod_file_path_from_attr(
     dir_path: &Path,
 ) -> Option<PathBuf> {
     // Extract path string from first `#[path = "path_string"]` attribute.
-    let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?.as_str();
+    let first_path = attrs.iter().find(|at| at.has_name(sym::path))?;
+    let path_string = match first_path.value_str() {
+        Some(s) => s.as_str(),
+        None => {
+            // This check is here mainly to catch attempting to use a macro,
+            // such as #[path = concat!(...)]. This isn't currently supported
+            // because otherwise the InvocationCollector would need to defer
+            // loading a module until the #[path] attribute was expanded, and
+            // it doesn't support that (and would likely add a bit of
+            // complexity). Usually bad forms are checked in AstValidator (via
+            // `check_builtin_attribute`), but by the time that runs the macro
+            // is expanded, and it doesn't give an error.
+            validate_attr::emit_fatal_malformed_builtin_attribute(
+                &sess.parse_sess,
+                first_path,
+                sym::path,
+            );
+        }
+    };
 
     // On windows, the base path might have the form
     // `\\?\foo\bar` in which case it does not tolerate
index 52b60c3047e1c9180ac3d314b6f3b5e666f91ef8..5cb97198765fe4411a8e691f1990e7e9e2a850c6 100644 (file)
@@ -577,7 +577,7 @@ fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> {
             }
 
             // Synthesize a new symbol that includes the minus sign.
-            let symbol = Symbol::intern(&s[..1 + lit.symbol.len()]);
+            let symbol = Symbol::intern(&s[..1 + lit.symbol.as_str().len()]);
             lit = token::Lit::new(lit.kind, symbol, lit.suffix);
         }
 
index 61e27d2e4cd41053db35dc55d60c8effeabdc63b..69e0e3a0136677b59de5970e43d7849cca86d8cd 100644 (file)
@@ -295,6 +295,8 @@ macro_rules! declare_features {
     (accepted, const_fn_union, "1.56.0", Some(51909), None),
     /// Allows explicit discriminants on non-unit enum variants.
     (accepted, arbitrary_enum_discriminant, "1.56.0", Some(60553), None),
+    /// Allows macro attributes to observe output of `#[derive]`.
+    (accepted, macro_attributes_in_derive_output, "1.57.0", Some(81119), None),
 
     // -------------------------------------------------------------------------
     // feature-group-end: accepted features
index ecc2de14a7914325e6e26e01419ecc33e99e46fe..f8b865e615c2ede9512c906de92add62df4dde73 100644 (file)
@@ -592,9 +592,6 @@ pub fn set(&self, features: &mut Features, span: Span) {
     /// Lessens the requirements for structs to implement `Unsize`.
     (active, relaxed_struct_unsize, "1.51.0", Some(81793), None),
 
-    /// Allows macro attributes to observe output of `#[derive]`.
-    (active, macro_attributes_in_derive_output, "1.51.0", Some(81119), None),
-
     /// Allows associated types in inherent impls.
     (incomplete, inherent_associated_types, "1.52.0", Some(8995), None),
 
index 6a97a6c43c11e564ef12427fc7aa15225aafc1e4..b5c0307255771d3a4d9da59c21e6ca98df076488 100644 (file)
@@ -669,8 +669,10 @@ fn push_outlives(
         self.obligations.push(Obligation {
             cause: self.cause.clone(),
             param_env: self.param_env,
-            predicate: ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(sup, sub))
-                .to_predicate(self.infcx.tcx),
+            predicate: ty::Binder::dummy(ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
+                sup, sub,
+            )))
+            .to_predicate(self.infcx.tcx),
             recursion_depth: 0,
         });
     }
index 8dd7e6af257fc53f1bf74d3ae4328f401af4d552..3f54247ecef211bcd48e6e621b05d39037193e15 100644 (file)
@@ -360,7 +360,8 @@ pub fn instantiate(
             self.obligations.push(Obligation::new(
                 self.trace.cause.clone(),
                 self.param_env,
-                ty::PredicateKind::WellFormed(b_ty.into()).to_predicate(self.infcx.tcx),
+                ty::Binder::dummy(ty::PredicateKind::WellFormed(b_ty.into()))
+                    .to_predicate(self.infcx.tcx),
             ));
         }
 
@@ -463,7 +464,7 @@ pub fn add_const_equate_obligation(
         self.obligations.push(Obligation::new(
             self.trace.cause.clone(),
             self.param_env,
-            predicate.to_predicate(self.tcx()),
+            ty::Binder::dummy(predicate).to_predicate(self.tcx()),
         ));
     }
 }
index d9b7022f03ac1a9ac2e74e61e87f1b22b2556963..45dd8868d6ccad52e1c3f385a15e826c5107567f 100644 (file)
@@ -609,6 +609,7 @@ fn note_error_origin(
         err: &mut DiagnosticBuilder<'tcx>,
         cause: &ObligationCause<'tcx>,
         exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
+        terr: &TypeError<'tcx>,
     ) {
         match cause.code {
             ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
@@ -785,7 +786,15 @@ fn note_error_origin(
                 err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
                 err.help("...or use `match` instead of `let...else`");
             }
-            _ => (),
+            _ => {
+                if let ObligationCauseCode::BindingObligation(_, binding_span) =
+                    cause.code.peel_derives()
+                {
+                    if matches!(terr, TypeError::RegionsPlaceholderMismatch) {
+                        err.span_note(*binding_span, "the lifetime requirement is introduced here");
+                    }
+                }
+            }
         }
     }
 
@@ -1724,7 +1733,7 @@ enum Mismatch<'a> {
 
         // It reads better to have the error origin as the final
         // thing.
-        self.note_error_origin(diag, cause, exp_found);
+        self.note_error_origin(diag, cause, exp_found, terr);
     }
 
     pub fn get_impl_future_output_ty(&self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
index 1692d8ee526d0519474eed4c1016d6715a30130b..8ef0d132cf09fc5692a956adcd3c0c9bfe0da086 100644 (file)
@@ -97,11 +97,11 @@ fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
                 self.fields.obligations.push(Obligation::new(
                     self.fields.trace.cause.clone(),
                     self.fields.param_env,
-                    ty::PredicateKind::Subtype(ty::SubtypePredicate {
+                    ty::Binder::dummy(ty::PredicateKind::Subtype(ty::SubtypePredicate {
                         a_is_expected: self.a_is_expected,
                         a,
                         b,
-                    })
+                    }))
                     .to_predicate(self.tcx()),
                 ));
 
index a12f7dc759c09aa7d5a415896568cb5d557041e1..dce4a87b041189a49910765f763ef7798d781a77 100644 (file)
@@ -35,7 +35,7 @@ fn register_bound(
                 cause,
                 recursion_depth: 0,
                 param_env,
-                predicate: trait_ref.without_const().to_predicate(infcx.tcx),
+                predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(infcx.tcx),
             },
         );
     }
index 3a25cb66896d510c751911d94efaba2d1ff6cb91..30d5613d5820d8664817bab71e3ed0d836ada1f1 100644 (file)
@@ -231,6 +231,7 @@ fn elaborate(&mut self, obligation: &PredicateObligation<'tcx>) {
                                 None
                             }
                         })
+                        .map(ty::Binder::dummy)
                         .map(|predicate_kind| predicate_kind.to_predicate(tcx))
                         .filter(|&predicate| visited.insert(predicate))
                         .map(|predicate| {
index c7424b9e2a120560a39c506abd23157056f73470..2fc3759968fd3531d8c63857a98cbda411de3a00 100644 (file)
@@ -1,6 +1,7 @@
 #![feature(bool_to_option)]
 #![feature(box_patterns)]
 #![feature(internal_output_capture)]
+#![feature(thread_spawn_unchecked)]
 #![feature(nll)]
 #![feature(once_cell)]
 #![recursion_limit = "256"]
index cb7529b527e8f885e322afd9c9988c40f6a0c5f5..45ad2df82455b68f95ade12e96bc45c7924dbd69 100644 (file)
@@ -23,7 +23,7 @@
 use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::{self, GlobalCtxt, ResolverOutputs, TyCtxt};
 use rustc_mir_build as mir_build;
-use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str};
+use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
 use rustc_passes::{self, hir_stats, layout_test};
 use rustc_plugin_impl as plugin;
 use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
@@ -33,8 +33,8 @@
 use rustc_session::lint;
 use rustc_session::output::{filename_for_input, filename_for_metadata};
 use rustc_session::search_paths::PathKind;
-use rustc_session::Session;
-use rustc_span::symbol::{Ident, Symbol};
+use rustc_session::{Limit, Session};
+use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::FileName;
 use rustc_trait_selection::traits;
 use rustc_typeck as typeck;
@@ -240,6 +240,7 @@ fn pre_expansion_lint(
     sess: &Session,
     lint_store: &LintStore,
     krate: &ast::Crate,
+    crate_attrs: &[ast::Attribute],
     crate_name: &str,
 ) {
     sess.prof.generic_activity_with_arg("pre_AST_expansion_lint_checks", crate_name).run(|| {
@@ -247,6 +248,7 @@ fn pre_expansion_lint(
             sess,
             lint_store,
             &krate,
+            crate_attrs,
             true,
             None,
             rustc_lint::BuiltinCombinedPreExpansionLintPass::new(),
@@ -266,7 +268,7 @@ pub fn configure_and_expand(
     resolver: &mut Resolver<'_>,
 ) -> Result<ast::Crate> {
     tracing::trace!("configure_and_expand");
-    pre_expansion_lint(sess, lint_store, &krate, crate_name);
+    pre_expansion_lint(sess, lint_store, &krate, &krate.attrs, crate_name);
     rustc_builtin_macros::register_builtin_macros(resolver);
 
     krate = sess.time("crate_injection", || {
@@ -311,8 +313,7 @@ pub fn configure_and_expand(
 
         // Create the config for macro expansion
         let features = sess.features_untracked();
-        let recursion_limit =
-            rustc_middle::middle::limits::get_recursion_limit(&krate.attrs, &sess);
+        let recursion_limit = get_recursion_limit(&krate.attrs, &sess);
         let cfg = rustc_expand::expand::ExpansionConfig {
             features: Some(&features),
             recursion_limit,
@@ -323,9 +324,10 @@ pub fn configure_and_expand(
             ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
         };
 
+        let crate_attrs = krate.attrs.clone();
         let extern_mod_loaded = |ident: Ident, attrs, items, span| {
             let krate = ast::Crate { attrs, items, span };
-            pre_expansion_lint(sess, lint_store, &krate, &ident.name.as_str());
+            pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str());
             (krate.attrs, krate.items)
         };
         let mut ecx = ExtCtxt::new(&sess, cfg, resolver, Some(&extern_mod_loaded));
@@ -469,6 +471,7 @@ pub fn lower_to_hir<'res, 'tcx>(
             sess,
             lint_store,
             &krate,
+            &krate.attrs,
             false,
             Some(std::mem::take(resolver.lint_buffer())),
             rustc_lint::BuiltinCombinedEarlyLintPass::new(),
@@ -1070,3 +1073,24 @@ pub fn start_codegen<'tcx>(
 
     codegen
 }
+
+fn get_recursion_limit(krate_attrs: &[ast::Attribute], sess: &Session) -> Limit {
+    if let Some(attr) = krate_attrs
+        .iter()
+        .find(|attr| attr.has_name(sym::recursion_limit) && attr.value_str().is_none())
+    {
+        // This is here mainly to check for using a macro, such as
+        // #![recursion_limit = foo!()]. That is not supported since that
+        // would require expanding this while in the middle of expansion,
+        // which needs to know the limit before expanding. Otherwise,
+        // validation would normally be caught in AstValidator (via
+        // `check_builtin_attribute`), but by the time that runs the macro
+        // is expanded, and it doesn't give an error.
+        validate_attr::emit_fatal_malformed_builtin_attribute(
+            &sess.parse_sess,
+            attr,
+            sym::recursion_limit,
+        );
+    }
+    rustc_middle::middle::limits::get_recursion_limit(krate_attrs, sess)
+}
index 3d90a6c9345362d5c4875202661d8a813eeee1e5..a1d1b63c8fafe8a034bbb721fb5a1b20f8e80fe7 100644 (file)
@@ -10,6 +10,7 @@
 use rustc_metadata::dynamic_lib::DynamicLibrary;
 #[cfg(parallel_compiler)]
 use rustc_middle::ty::tls;
+use rustc_parse::validate_attr;
 #[cfg(parallel_compiler)]
 use rustc_query_impl::QueryCtxt;
 use rustc_resolve::{self, Resolver};
@@ -115,25 +116,11 @@ fn get_stack_size() -> Option<usize> {
 /// for `'static` bounds.
 #[cfg(not(parallel_compiler))]
 pub fn scoped_thread<F: FnOnce() -> R + Send, R: Send>(cfg: thread::Builder, f: F) -> R {
-    struct Ptr(*mut ());
-    unsafe impl Send for Ptr {}
-    unsafe impl Sync for Ptr {}
-
-    let mut f = Some(f);
-    let run = Ptr(&mut f as *mut _ as *mut ());
-    let mut result = None;
-    let result_ptr = Ptr(&mut result as *mut _ as *mut ());
-
-    let thread = cfg.spawn(move || {
-        let _ = (&run, &result_ptr);
-        let run = unsafe { (*(run.0 as *mut Option<F>)).take().unwrap() };
-        let result = unsafe { &mut *(result_ptr.0 as *mut Option<R>) };
-        *result = Some(run());
-    });
-
-    match thread.unwrap().join() {
-        Ok(()) => result.unwrap(),
-        Err(p) => panic::resume_unwind(p),
+    // SAFETY: join() is called immediately, so any closure captures are still
+    // alive.
+    match unsafe { cfg.spawn_unchecked(f) }.unwrap().join() {
+        Ok(v) => v,
+        Err(e) => panic::resume_unwind(e),
     }
 }
 
@@ -489,7 +476,7 @@ pub fn get_codegen_sysroot(
 }
 
 pub(crate) fn check_attr_crate_type(
-    _sess: &Session,
+    sess: &Session,
     attrs: &[ast::Attribute],
     lint_buffer: &mut LintBuffer,
 ) {
@@ -529,6 +516,19 @@ pub(crate) fn check_attr_crate_type(
                         );
                     }
                 }
+            } else {
+                // This is here mainly to check for using a macro, such as
+                // #![crate_type = foo!()]. That is not supported since the
+                // crate type needs to be known very early in compilation long
+                // before expansion. Otherwise, validation would normally be
+                // caught in AstValidator (via `check_builtin_attribute`), but
+                // by the time that runs the macro is expanded, and it doesn't
+                // give an error.
+                validate_attr::emit_fatal_malformed_builtin_attribute(
+                    &sess.parse_sess,
+                    a,
+                    sym::crate_type,
+                );
             }
         }
     }
index 4c45e33db79c73976ddb1f07dc78eea6bde5d886..8cbd2ddcbfdf733028ac1f350df837d2471eadb1 100644 (file)
@@ -805,6 +805,7 @@ pub fn new(
         sess: &'a Session,
         lint_store: &'a LintStore,
         krate: &'a ast::Crate,
+        crate_attrs: &'a [ast::Attribute],
         buffered: LintBuffer,
         warn_about_weird_lints: bool,
     ) -> EarlyContext<'a> {
@@ -812,7 +813,7 @@ pub fn new(
             sess,
             krate,
             lint_store,
-            builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, &krate.attrs),
+            builder: LintLevelsBuilder::new(sess, warn_about_weird_lints, lint_store, crate_attrs),
             buffered,
         }
     }
index 7a8b731da5c2ee5d327dd0a882371a9e2149ea93..0bba66d383869469c4728ad299a40ea6342a7d26 100644 (file)
@@ -329,12 +329,20 @@ fn early_lint_crate<T: EarlyLintPass>(
     sess: &Session,
     lint_store: &LintStore,
     krate: &ast::Crate,
+    crate_attrs: &[ast::Attribute],
     pass: T,
     buffered: LintBuffer,
     warn_about_weird_lints: bool,
 ) -> LintBuffer {
     let mut cx = EarlyContextAndPass {
-        context: EarlyContext::new(sess, lint_store, krate, buffered, warn_about_weird_lints),
+        context: EarlyContext::new(
+            sess,
+            lint_store,
+            krate,
+            crate_attrs,
+            buffered,
+            warn_about_weird_lints,
+        ),
         pass,
     };
 
@@ -355,6 +363,7 @@ pub fn check_ast_crate<T: EarlyLintPass>(
     sess: &Session,
     lint_store: &LintStore,
     krate: &ast::Crate,
+    crate_attrs: &[ast::Attribute],
     pre_expansion: bool,
     lint_buffer: Option<LintBuffer>,
     builtin_lints: T,
@@ -365,14 +374,22 @@ pub fn check_ast_crate<T: EarlyLintPass>(
     let mut buffered = lint_buffer.unwrap_or_default();
 
     if !sess.opts.debugging_opts.no_interleave_lints {
-        buffered =
-            early_lint_crate(sess, lint_store, krate, builtin_lints, buffered, pre_expansion);
+        buffered = early_lint_crate(
+            sess,
+            lint_store,
+            krate,
+            crate_attrs,
+            builtin_lints,
+            buffered,
+            pre_expansion,
+        );
 
         if !passes.is_empty() {
             buffered = early_lint_crate(
                 sess,
                 lint_store,
                 krate,
+                crate_attrs,
                 EarlyLintPassObjects { lints: &mut passes[..] },
                 buffered,
                 false,
@@ -386,6 +403,7 @@ pub fn check_ast_crate<T: EarlyLintPass>(
                         sess,
                         lint_store,
                         krate,
+                        crate_attrs,
                         EarlyLintPassObjects { lints: slice::from_mut(pass) },
                         buffered,
                         pre_expansion && i == 0,
index 1a0cfd5888593799f9d228380476cdaee2a51e68..48eb50953a957dc759f4e867a9a3564c9fe6a192 100644 (file)
@@ -1004,7 +1004,10 @@ LLVMRustOptimizeWithNewPassManager(
 #endif
   bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
   if (!NoPrepopulatePasses) {
-    if (OptLevel == OptimizationLevel::O0) {
+    // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead.
+    // At the same time, the LTO pipelines do support O0 and using them is required.
+    bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
+    if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
 #if LLVM_VERSION_GE(12, 0)
       for (const auto &C : PipelineStartEPCallbacks)
         PB.registerPipelineStartEPCallback(C);
index 3e9c02ee268cab9a9e197198ad41c43a5ca13611..2a36c01d221e1cda6d822aa27eec160ef1074d48 100644 (file)
@@ -2200,6 +2200,12 @@ pub enum Rvalue<'tcx> {
     /// that `Foo` has a destructor. These rvalues can be optimized
     /// away after type-checking and before lowering.
     Aggregate(Box<AggregateKind<'tcx>>, Vec<Operand<'tcx>>),
+
+    /// Transmutes a `*mut u8` into shallow-initialized `Box<T>`.
+    ///
+    /// This is different a normal transmute because dataflow analysis will treat the box
+    /// as initialized but its content as uninitialized.
+    ShallowInitBox(Operand<'tcx>, Ty<'tcx>),
 }
 
 #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
@@ -2450,6 +2456,10 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
                     }),
                 }
             }
+
+            ShallowInitBox(ref place, ref ty) => {
+                write!(fmt, "ShallowInitBox({:?}, {:?})", place, ty)
+            }
         }
     }
 }
index b003a504691bbce1f8279209f4e447ed7da449cd..d5541d7890c77de20e6906d5ee913dc8c02aa804 100644 (file)
@@ -309,6 +309,9 @@ pub struct ClosureOutlivesRequirement<'tcx> {
     pub category: ConstraintCategory,
 }
 
+// Make sure this enum doesn't unintentionally grow
+rustc_data_structures::static_assert_size!(ConstraintCategory, 12);
+
 /// Outlives-constraints can be categorized to determine whether and why they
 /// are interesting (for error reporting). Order of variants indicates sort
 /// order of the category, thereby influencing diagnostic output.
@@ -338,6 +341,11 @@ pub enum ConstraintCategory {
     OpaqueType,
     ClosureUpvar(hir::HirId),
 
+    /// A constraint from a user-written predicate
+    /// with the provided span, written on the item
+    /// with the given `DefId`
+    Predicate(Span),
+
     /// A "boring" constraint (caused by the given location) is one that
     /// the user probably doesn't want to see described in diagnostics,
     /// because it is kind of an artifact of the type system setup.
index b48e8a868efdb1cf01a0b9e9abf5cf93fbbad603..c3c5ebe705effa45fd518ad35dc0e00121124515 100644 (file)
@@ -206,6 +206,7 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
                     tcx.mk_generator(did, substs, movability)
                 }
             },
+            Rvalue::ShallowInitBox(_, ty) => tcx.mk_box(ty),
         }
     }
 
@@ -214,7 +215,9 @@ pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx>
     /// whether its only shallowly initialized (`Rvalue::Box`).
     pub fn initialization_state(&self) -> RvalueInitializationState {
         match *self {
-            Rvalue::NullaryOp(NullOp::Box, _) => RvalueInitializationState::Shallow,
+            Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::ShallowInitBox(_, _) => {
+                RvalueInitializationState::Shallow
+            }
             _ => RvalueInitializationState::Deep,
         }
     }
index b2d4a22194c628a25a4cf004e1a215b6a66b204b..b7201f7acf392dac6567e4d4ba7d6e69298b467c 100644 (file)
@@ -210,6 +210,7 @@ fn super_fold_with<F: TypeFolder<'tcx>>(self, folder: &mut F) -> Self {
                 });
                 Aggregate(kind, fields.fold_with(folder))
             }
+            ShallowInitBox(op, ty) => ShallowInitBox(op.fold_with(folder), ty.fold_with(folder)),
         }
     }
 
@@ -255,6 +256,10 @@ fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow
                 }
                 fields.visit_with(visitor)
             }
+            ShallowInitBox(ref op, ty) => {
+                op.visit_with(visitor)?;
+                ty.visit_with(visitor)
+            }
         }
     }
 }
index 13bbb8d1f534d6072cadbfdd4587bb83242053a1..fda7ebe1a49c15c2697ae150b964124af43a019e 100644 (file)
@@ -753,6 +753,11 @@ fn super_rvalue(&mut self,
                             self.visit_operand(operand, location);
                         }
                     }
+
+                    Rvalue::ShallowInitBox(operand, ty) => {
+                        self.visit_operand(operand, location);
+                        self.visit_ty(ty, TyContext::Location(location));
+                    }
                 }
             }
 
index cc81ddbcc01b9806268b7db9f09121013a5d0c01..b3ae76d987167fe84fa32c13f7ed621f42c96aac 100644 (file)
@@ -769,12 +769,6 @@ pub trait ToPolyTraitRef<'tcx> {
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
 }
 
-impl<'tcx> ToPolyTraitRef<'tcx> for TraitRef<'tcx> {
-    fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
-        ty::Binder::dummy(*self)
-    }
-}
-
 impl<'tcx> ToPolyTraitRef<'tcx> for PolyTraitPredicate<'tcx> {
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx> {
         self.map_bound_ref(|trait_pred| trait_pred.trait_ref)
@@ -792,23 +786,6 @@ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
     }
 }
 
-impl ToPredicate<'tcx> for PredicateKind<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(Binder::dummy(self))
-    }
-}
-
-impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<TraitRef<'tcx>> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        PredicateKind::Trait(ty::TraitPredicate {
-            trait_ref: self.value,
-            constness: self.constness,
-        })
-        .to_predicate(tcx)
-    }
-}
-
 impl<'tcx> ToPredicate<'tcx> for ConstnessAnd<PolyTraitRef<'tcx>> {
     fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
         self.value
index 1e17ba204b2c7ff2fc0548e9d0dda3532e0deb04..d3094b3e6ff4d74ccb3ea809de72d01ebcd1bcf2 100644 (file)
@@ -844,8 +844,11 @@ pub fn new(def_id: DefId, substs: SubstsRef<'tcx>) -> TraitRef<'tcx> {
 
     /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
     /// are the parameters defined on trait.
-    pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> {
-        TraitRef { def_id, substs: InternalSubsts::identity_for_item(tcx, def_id) }
+    pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> {
+        ty::Binder::dummy(TraitRef {
+            def_id,
+            substs: InternalSubsts::identity_for_item(tcx, def_id),
+        })
     }
 
     #[inline]
index 4b40faaf1956db04f344bf947ddcca0add3563e4..1464ea58ad02c6581fc0c298d015745e04340534 100644 (file)
@@ -5,6 +5,7 @@
 use crate::build::expr::as_place::PlaceBase;
 use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, Builder};
+use rustc_hir::lang_items::LangItem;
 use rustc_middle::middle::region;
 use rustc_middle::mir::AssertKind;
 use rustc_middle::mir::Place;
@@ -88,6 +89,56 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             }
             ExprKind::Box { value } => {
                 let value = &this.thir[value];
+                let tcx = this.tcx;
+
+                // `exchange_malloc` is unsafe but box is safe, so need a new scope.
+                let synth_scope = this.new_source_scope(
+                    expr_span,
+                    LintLevel::Inherited,
+                    Some(Safety::BuiltinUnsafe),
+                );
+                let synth_info = SourceInfo { span: expr_span, scope: synth_scope };
+
+                let size = this.temp(tcx.types.usize, expr_span);
+                this.cfg.push_assign(
+                    block,
+                    synth_info,
+                    size,
+                    Rvalue::NullaryOp(NullOp::SizeOf, value.ty),
+                );
+
+                let align = this.temp(tcx.types.usize, expr_span);
+                this.cfg.push_assign(
+                    block,
+                    synth_info,
+                    align,
+                    Rvalue::NullaryOp(NullOp::AlignOf, value.ty),
+                );
+
+                // malloc some memory of suitable size and align:
+                let exchange_malloc = Operand::function_handle(
+                    tcx,
+                    tcx.require_lang_item(LangItem::ExchangeMalloc, Some(expr_span)),
+                    ty::List::empty(),
+                    expr_span,
+                );
+                let storage = this.temp(tcx.mk_mut_ptr(tcx.types.u8), expr_span);
+                let success = this.cfg.start_new_block();
+                this.cfg.terminate(
+                    block,
+                    synth_info,
+                    TerminatorKind::Call {
+                        func: exchange_malloc,
+                        args: vec![Operand::Move(size), Operand::Move(align)],
+                        destination: Some((Place::from(storage), success)),
+                        cleanup: None,
+                        from_hir_call: false,
+                        fn_span: expr_span,
+                    },
+                );
+                this.diverge_from(block);
+                block = success;
+
                 // The `Box<T>` temporary created here is not a part of the HIR,
                 // and therefore is not considered during generator auto-trait
                 // determination. See the comment about `box` at `yield_in_scope`.
@@ -101,8 +152,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                     this.schedule_drop_storage_and_value(expr_span, scope, result);
                 }
 
-                // malloc some memory of suitable type (thus far, uninitialized):
-                let box_ = Rvalue::NullaryOp(NullOp::Box, value.ty);
+                // Transmute `*mut u8` to the box (thus far, uninitialized):
+                let box_ = Rvalue::ShallowInitBox(Operand::Move(Place::from(storage)), value.ty);
                 this.cfg.push_assign(block, source_info, Place::from(result), box_);
 
                 // initialize the box contents:
index 81d84f80ad4c19a2cf083639abeb7bee435afe49..158ba1b942528072c7416f70fe9cb434590e83a6 100644 (file)
@@ -169,6 +169,7 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
             }
 
             mir::Rvalue::Cast(..)
+            | mir::Rvalue::ShallowInitBox(..)
             | mir::Rvalue::Use(..)
             | mir::Rvalue::ThreadLocalRef(..)
             | mir::Rvalue::Repeat(..)
index 407ba739463013ddb2346298efcc0774134141d9..e404b49ecb93173f33ca1062399967f3f6a6075b 100644 (file)
@@ -327,6 +327,7 @@ fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) {
             Rvalue::Use(ref operand)
             | Rvalue::Repeat(ref operand, _)
             | Rvalue::Cast(_, ref operand, _)
+            | Rvalue::ShallowInitBox(ref operand, _)
             | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand),
             Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs))
             | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
index 71b3a555587f710c748f332f29c5d99611087f0a..17790ec91c8a3fd17d19132ad21aba33e9255712 100644 (file)
@@ -723,6 +723,7 @@ fn const_prop(
             | Rvalue::Repeat(..)
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
+            | Rvalue::ShallowInitBox(..)
             | Rvalue::Discriminant(..)
             | Rvalue::NullaryOp(..) => {}
         }
index dd95f0014230953d1f96c9139c2c4daed42606e3..790d9243fbaec874db7488ff817c615d5068cb1e 100644 (file)
@@ -967,6 +967,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
             }
 
             Rvalue::Cast(..)
+            | Rvalue::ShallowInitBox(..)
             | Rvalue::Use(..)
             | Rvalue::Repeat(..)
             | Rvalue::Len(..)
index 1945e551485d8fcf939fd8263e3e9f9715916b69..3002e7041b0247dacd18e868907799cbe39b37fa 100644 (file)
@@ -204,6 +204,7 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
                         | Rvalue::AddressOf(_, _)
                         | Rvalue::Cast(_, Operand::Constant(_), _)
                         | Rvalue::NullaryOp(_, _)
+                        | Rvalue::ShallowInitBox(_, _)
                         | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true,
 
                         // These rvalues make things ambiguous
@@ -301,6 +302,7 @@ fn find_determining_place<'tcx>(
                     | Rvalue::ThreadLocalRef(_)
                     | Rvalue::AddressOf(_, _)
                     | Rvalue::NullaryOp(_, _)
+                    | Rvalue::ShallowInitBox(_, _)
                     | Rvalue::UnaryOp(_, Operand::Constant(_))
                     | Rvalue::Cast(_, Operand::Constant(_), _)
                     => return None,
index 0e2222bf84093913d3bfc926621130452c7ac6fd..624390a406ff2bbcfbbbf3b298f6d1e124dec01c 100644 (file)
@@ -1547,6 +1547,20 @@ fn parse_item_macro_rules(&mut self, vis: &Visibility) -> PResult<'a, ItemInfo>
         self.expect(&token::Not)?; // `!`
 
         let ident = self.parse_ident()?;
+
+        if self.eat(&token::Not) {
+            // Handle macro_rules! foo!
+            let span = self.prev_token.span;
+            self.struct_span_err(span, "macro names aren't followed by a `!`")
+                .span_suggestion(
+                    span,
+                    "remove the `!`",
+                    "".to_owned(),
+                    Applicability::MachineApplicable,
+                )
+                .emit();
+        }
+
         let body = self.parse_mac_args()?;
         self.eat_semi_for_macro_if_needed(&body);
         self.complain_if_pub_macro(vis, true);
index 67695dc285092a555cc391e41bbe4e9e6eaedddc..2aa20d02c8830cd38437848b9de82b00040e1bf5 100644 (file)
@@ -4,7 +4,7 @@
 
 use rustc_ast::tokenstream::{DelimSpan, TokenTree};
 use rustc_ast::{self as ast, Attribute, MacArgs, MacDelimiter, MetaItem, MetaItemKind};
-use rustc_errors::{Applicability, PResult};
+use rustc_errors::{Applicability, FatalError, PResult};
 use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
 use rustc_session::parse::ParseSess;
@@ -91,69 +91,11 @@ pub fn check_builtin_attribute(
     // Some special attributes like `cfg` must be checked
     // before the generic check, so we skip them here.
     let should_skip = |name| name == sym::cfg;
-    // Some of previously accepted forms were used in practice,
-    // report them as warnings for now.
-    let should_warn = |name| {
-        name == sym::doc
-            || name == sym::ignore
-            || name == sym::inline
-            || name == sym::link
-            || name == sym::test
-            || name == sym::bench
-    };
 
     match parse_meta(sess, attr) {
         Ok(meta) => {
             if !should_skip(name) && !is_attr_template_compatible(&template, &meta.kind) {
-                let error_msg = format!("malformed `{}` attribute input", name);
-                let mut msg = "attribute must be of the form ".to_owned();
-                let mut suggestions = vec![];
-                let mut first = true;
-                if template.word {
-                    first = false;
-                    let code = format!("#[{}]", name);
-                    msg.push_str(&format!("`{}`", &code));
-                    suggestions.push(code);
-                }
-                if let Some(descr) = template.list {
-                    if !first {
-                        msg.push_str(" or ");
-                    }
-                    first = false;
-                    let code = format!("#[{}({})]", name, descr);
-                    msg.push_str(&format!("`{}`", &code));
-                    suggestions.push(code);
-                }
-                if let Some(descr) = template.name_value_str {
-                    if !first {
-                        msg.push_str(" or ");
-                    }
-                    let code = format!("#[{} = \"{}\"]", name, descr);
-                    msg.push_str(&format!("`{}`", &code));
-                    suggestions.push(code);
-                }
-                if should_warn(name) {
-                    sess.buffer_lint(
-                        &ILL_FORMED_ATTRIBUTE_INPUT,
-                        meta.span,
-                        ast::CRATE_NODE_ID,
-                        &msg,
-                    );
-                } else {
-                    sess.span_diagnostic
-                        .struct_span_err(meta.span, &error_msg)
-                        .span_suggestions(
-                            meta.span,
-                            if suggestions.len() == 1 {
-                                "must be of the form"
-                            } else {
-                                "the following are the possible correct uses"
-                            },
-                            suggestions.into_iter(),
-                            Applicability::HasPlaceholders,
-                        )
-                        .emit();
-                }
+                emit_malformed_attribute(sess, attr, name, template);
             }
         }
         Err(mut err) => {
@@ -161,3 +103,74 @@ pub fn check_builtin_attribute(
         }
     }
 }
+
+fn emit_malformed_attribute(
+    sess: &ParseSess,
+    attr: &Attribute,
+    name: Symbol,
+    template: AttributeTemplate,
+) {
+    // Some of previously accepted forms were used in practice,
+    // report them as warnings for now.
+    let should_warn = |name| {
+        matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench)
+    };
+
+    let error_msg = format!("malformed `{}` attribute input", name);
+    let mut msg = "attribute must be of the form ".to_owned();
+    let mut suggestions = vec![];
+    let mut first = true;
+    let inner = if attr.style == ast::AttrStyle::Inner { "!" } else { "" };
+    if template.word {
+        first = false;
+        let code = format!("#{}[{}]", inner, name);
+        msg.push_str(&format!("`{}`", &code));
+        suggestions.push(code);
+    }
+    if let Some(descr) = template.list {
+        if !first {
+            msg.push_str(" or ");
+        }
+        first = false;
+        let code = format!("#{}[{}({})]", inner, name, descr);
+        msg.push_str(&format!("`{}`", &code));
+        suggestions.push(code);
+    }
+    if let Some(descr) = template.name_value_str {
+        if !first {
+            msg.push_str(" or ");
+        }
+        let code = format!("#{}[{} = \"{}\"]", inner, name, descr);
+        msg.push_str(&format!("`{}`", &code));
+        suggestions.push(code);
+    }
+    if should_warn(name) {
+        sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, attr.span, ast::CRATE_NODE_ID, &msg);
+    } else {
+        sess.span_diagnostic
+            .struct_span_err(attr.span, &error_msg)
+            .span_suggestions(
+                attr.span,
+                if suggestions.len() == 1 {
+                    "must be of the form"
+                } else {
+                    "the following are the possible correct uses"
+                },
+                suggestions.into_iter(),
+                Applicability::HasPlaceholders,
+            )
+            .emit();
+    }
+}
+
+pub fn emit_fatal_malformed_builtin_attribute(
+    sess: &ParseSess,
+    attr: &Attribute,
+    name: Symbol,
+) -> ! {
+    let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").2;
+    emit_malformed_attribute(sess, attr, name, template);
+    // This is fatal, otherwise it will likely cause a cascade of other errors
+    // (and an error here is expected to be very rare).
+    FatalError.raise()
+}
index 435c79d2daf45d19a76f95be8f2e5ec7889ed666..d6ff5a7e90b2173a2d2081a22db86aa7d11c202c 100644 (file)
@@ -1706,6 +1706,9 @@ fn find_span_immediately_after_crate_name(
         candidates.iter().map(|c| path_names_to_string(&c.path)).collect();
 
     path_strings.sort();
+    let core_path_strings =
+        path_strings.drain_filter(|p| p.starts_with("core::")).collect::<Vec<String>>();
+    path_strings.extend(core_path_strings);
     path_strings.dedup();
 
     let (determiner, kind) = if candidates.len() == 1 {
index 19136c6ceeb1f6900e186e62c31cd4fbce3330e6..84219873d55b4e9eb5b3f4139bb03aa17079e915 100644 (file)
@@ -1026,9 +1026,15 @@ fn smart_resolve_context_dependent_help(
 
                 self.suggest_using_enum_variant(err, source, def_id, span);
             }
-            (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => {
+            (Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => {
                 let (ctor_def, ctor_vis, fields) =
                     if let Some(struct_ctor) = self.r.struct_constructors.get(&def_id).cloned() {
+                        if let PathSource::Expr(Some(parent)) = source {
+                            if let ExprKind::Field(..) | ExprKind::MethodCall(..) = parent.kind {
+                                bad_struct_syntax_suggestion(def_id);
+                                return true;
+                            }
+                        }
                         struct_ctor
                     } else {
                         bad_struct_syntax_suggestion(def_id);
index 68db06370ffea1aa462345d2027e05ee58653efe..1cbe8f41d92b0704714e881bc02613765f9dbffd 100644 (file)
@@ -10,6 +10,7 @@
 
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![feature(box_patterns)]
+#![feature(drain_filter)]
 #![feature(bool_to_option)]
 #![feature(crate_visibility_modifier)]
 #![feature(format_args_capture)]
index 39605ec1840f3d398572f1ba2aef5259037a9806..f15cf4bbc3a57cb138a2f4d7ceee244270cf4bf3 100644 (file)
@@ -311,38 +311,6 @@ fn resolve_macro_invocation(
             self.create_stable_hashing_context(),
         );
 
-        if let Res::Def(_, _) = res {
-            // Gate macro attributes in `#[derive]` output.
-            if !self.session.features_untracked().macro_attributes_in_derive_output
-                && kind == MacroKind::Attr
-                && ext.builtin_name != Some(sym::derive)
-            {
-                let mut expn_id = parent_scope.expansion;
-                loop {
-                    // Helper attr table is a quick way to determine whether the attr is `derive`.
-                    if self.helper_attrs.contains_key(&expn_id) {
-                        feature_err(
-                            &self.session.parse_sess,
-                            sym::macro_attributes_in_derive_output,
-                            path.span,
-                            "macro attributes in `#[derive]` output are unstable",
-                        )
-                        .emit();
-                        break;
-                    } else {
-                        let expn_data = expn_id.expn_data();
-                        match expn_data.kind {
-                            ExpnKind::Root
-                            | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => {
-                                break;
-                            }
-                            _ => expn_id = expn_data.parent.expect_local(),
-                        }
-                    }
-                }
-            }
-        }
-
         Ok(ext)
     }
 
index 44137290d78580ee02b32fad0ede58e2fba1ae2f..7cb4e18398cdcddf5cecc90dda0747f30d642349 100644 (file)
@@ -1618,7 +1618,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 pub struct Symbol(SymbolIndex);
 
 rustc_index::newtype_index! {
-    pub struct SymbolIndex { .. }
+    struct SymbolIndex { .. }
 }
 
 impl Symbol {
@@ -1644,10 +1644,6 @@ pub fn as_u32(self) -> u32 {
         self.0.as_u32()
     }
 
-    pub fn len(self) -> usize {
-        with_session_globals(|session_globals| session_globals.symbol_interner.get(self).len())
-    }
-
     pub fn is_empty(self) -> bool {
         self == kw::Empty
     }
diff --git a/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs b/compiler/rustc_target/src/spec/aarch64_kmc_solid_asp3.rs
new file mode 100644 (file)
index 0000000..61e3be6
--- /dev/null
@@ -0,0 +1,19 @@
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = super::solid_base::opts("asp3");
+    Target {
+        llvm_target: "aarch64-unknown-none".to_string(),
+        pointer_width: 64,
+        data_layout: "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128".to_string(),
+        arch: "aarch64".to_string(),
+        options: TargetOptions {
+            linker: Some("aarch64-kmc-elf-gcc".to_owned()),
+            features: "+neon,+fp-armv8".to_string(),
+            relocation_model: RelocModel::Static,
+            disable_redzone: true,
+            max_atomic_width: Some(128),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabi.rs
new file mode 100644 (file)
index 0000000..344c480
--- /dev/null
@@ -0,0 +1,19 @@
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = super::solid_base::opts("asp3");
+    Target {
+        llvm_target: "armv7a-none-eabi".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        options: TargetOptions {
+            linker: Some("arm-kmc-eabi-gcc".to_owned()),
+            features: "+v7,+soft-float,+thumb2,-neon".to_string(),
+            relocation_model: RelocModel::Static,
+            disable_redzone: true,
+            max_atomic_width: Some(64),
+            ..base
+        },
+    }
+}
diff --git a/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_kmc_solid_asp3_eabihf.rs
new file mode 100644 (file)
index 0000000..3755024
--- /dev/null
@@ -0,0 +1,19 @@
+use super::{RelocModel, Target, TargetOptions};
+
+pub fn target() -> Target {
+    let base = super::solid_base::opts("asp3");
+    Target {
+        llvm_target: "armv7a-none-eabihf".to_string(),
+        pointer_width: 32,
+        data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".to_string(),
+        arch: "arm".to_string(),
+        options: TargetOptions {
+            linker: Some("arm-kmc-eabi-gcc".to_owned()),
+            features: "+v7,+vfp3,-d32,+thumb2,-neon".to_string(),
+            relocation_model: RelocModel::Static,
+            disable_redzone: true,
+            max_atomic_width: Some(64),
+            ..base
+        },
+    }
+}
index c947721d63d39bf5f0d9c98fcb0c1dbbfc75ac44..d18e5823cb80c1d406bdf9ec3bfe7d5c5451e1a9 100644 (file)
@@ -75,6 +75,7 @@
 mod openbsd_base;
 mod redox_base;
 mod solaris_base;
+mod solid_base;
 mod thumb_base;
 mod uefi_msvc_base;
 mod vxworks_base;
@@ -932,6 +933,10 @@ fn $module() {
     ("powerpc-wrs-vxworks-spe", powerpc_wrs_vxworks_spe),
     ("powerpc64-wrs-vxworks", powerpc64_wrs_vxworks),
 
+    ("aarch64-kmc-solid_asp3", aarch64_kmc_solid_asp3),
+    ("armv7a-kmc-solid_asp3-eabi", armv7a_kmc_solid_asp3_eabi),
+    ("armv7a-kmc-solid_asp3-eabihf", armv7a_kmc_solid_asp3_eabihf),
+
     ("mipsel-sony-psp", mipsel_sony_psp),
     ("mipsel-unknown-none", mipsel_unknown_none),
     ("thumbv4t-none-eabi", thumbv4t_none_eabi),
diff --git a/compiler/rustc_target/src/spec/solid_base.rs b/compiler/rustc_target/src/spec/solid_base.rs
new file mode 100644 (file)
index 0000000..c6a279d
--- /dev/null
@@ -0,0 +1,12 @@
+use super::FramePointer;
+use crate::spec::TargetOptions;
+
+pub fn opts(kernel: &str) -> TargetOptions {
+    TargetOptions {
+        os: format!("solid_{}", kernel),
+        vendor: "kmc".to_string(),
+        frame_pointer: FramePointer::NonLeaf,
+        has_elf_tls: true,
+        ..Default::default()
+    }
+}
index 969962e55b0df3e4fb963572e1e3e8b06b321da2..a89796f172c5a588c398ce440034b07936bd2857 100644 (file)
@@ -135,7 +135,7 @@ fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
         let obligation = traits::Obligation::new(
             cause.clone(),
             self.param_env,
-            trait_ref.without_const().to_predicate(tcx),
+            ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
         );
         if !self.infcx.predicate_may_hold(&obligation) {
             debug!("overloaded_deref_ty: cannot match obligation");
index 42cbed600d5bf92229ca6f6ff55002ded9d53d2c..8fb4eb641c26a913af2e04053b1e591babf53452 100644 (file)
@@ -120,7 +120,7 @@ fn type_implements_trait(
             cause: traits::ObligationCause::dummy(),
             param_env,
             recursion_depth: 0,
-            predicate: trait_ref.without_const().to_predicate(self.tcx),
+            predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx),
         };
         self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
     }
index ae61988928f78e6ba2f317016718c2cf1df01c3f..2a51e01471398861252d3b3d96fdf31f88d40154 100644 (file)
@@ -714,22 +714,28 @@ fn suggest_add_reference_to_arg(
         let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]);
 
         // Try to apply the original trait binding obligation by borrowing.
-        let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>,
+        let mut try_borrowing = |new_imm_trait_ref: ty::TraitRef<'tcx>,
+                                 new_mut_trait_ref: ty::TraitRef<'tcx>,
                                  expected_trait_ref: ty::TraitRef<'tcx>,
-                                 mtbl: bool,
                                  blacklist: &[DefId]|
          -> bool {
             if blacklist.contains(&expected_trait_ref.def_id) {
                 return false;
             }
 
-            let new_obligation = Obligation::new(
+            let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
                 ObligationCause::dummy(),
                 param_env,
-                new_trait_ref.without_const().to_predicate(self.tcx),
-            );
+                ty::Binder::dummy(new_imm_trait_ref).without_const().to_predicate(self.tcx),
+            ));
 
-            if self.predicate_must_hold_modulo_regions(&new_obligation) {
+            let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new(
+                ObligationCause::dummy(),
+                param_env,
+                ty::Binder::dummy(new_mut_trait_ref).without_const().to_predicate(self.tcx),
+            ));
+
+            if imm_result || mut_result {
                 if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
                     // We have a very specific type of error, where just borrowing this argument
                     // might solve the problem. In cases like this, the important part is the
@@ -773,15 +779,24 @@ fn suggest_add_reference_to_arg(
                         // }
                         // ```
 
-                        err.span_suggestion(
-                            span,
-                            &format!(
-                                "consider{} borrowing here",
-                                if mtbl { " mutably" } else { "" }
-                            ),
-                            format!("&{}{}", if mtbl { "mut " } else { "" }, snippet),
-                            Applicability::MaybeIncorrect,
-                        );
+                        if imm_result && mut_result {
+                            err.span_suggestions(
+                                span.shrink_to_lo(),
+                                "consider borrowing here",
+                                ["&".to_string(), "&mut ".to_string()].into_iter(),
+                                Applicability::MaybeIncorrect,
+                            );
+                        } else {
+                            err.span_suggestion_verbose(
+                                span.shrink_to_lo(),
+                                &format!(
+                                    "consider{} borrowing here",
+                                    if mut_result { " mutably" } else { "" }
+                                ),
+                                format!("&{}", if mut_result { "mut " } else { "" }),
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
                     }
                     return true;
                 }
@@ -795,29 +810,16 @@ fn suggest_add_reference_to_arg(
                 ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs);
             let new_mut_trait_ref =
                 ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs);
-            if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) {
-                return true;
-            } else {
-                return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]);
-            }
+            return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]);
         } else if let ObligationCauseCode::BindingObligation(_, _)
         | ObligationCauseCode::ItemObligation(_) = &*code
         {
-            if try_borrowing(
+            return try_borrowing(
                 ty::TraitRef::new(trait_ref.def_id, imm_substs),
+                ty::TraitRef::new(trait_ref.def_id, mut_substs),
                 trait_ref,
-                false,
                 &never_suggest_borrow[..],
-            ) {
-                return true;
-            } else {
-                return try_borrowing(
-                    ty::TraitRef::new(trait_ref.def_id, mut_substs),
-                    trait_ref,
-                    true,
-                    &never_suggest_borrow[..],
-                );
-            }
+            );
         } else {
             false
         }
index 61462f23886ce650c6e911ad02857ff5fe549bee..465d1465d5d3538325def6ae9dcf226b730f9aa6 100644 (file)
@@ -418,7 +418,8 @@ fn progress_changed_obligations(
                 | ty::PredicateKind::Coerce(_)
                 | ty::PredicateKind::ConstEvaluatable(..)
                 | ty::PredicateKind::ConstEquate(..) => {
-                    let pred = infcx.replace_bound_vars_with_placeholders(binder);
+                    let pred =
+                        ty::Binder::dummy(infcx.replace_bound_vars_with_placeholders(binder));
                     ProcessResult::Changed(mk_pending(vec![
                         obligation.with(pred.to_predicate(self.selcx.tcx())),
                     ]))
index df2422048b9d7b90d60f97b7fc09f26b52675db8..b3c9cf4c173ecdc72fb2c3a12354b7eb3bff8594 100644 (file)
@@ -140,7 +140,8 @@ pub fn type_known_to_meet_bound_modulo_regions<'a, 'tcx>(
         infcx.tcx.def_path_str(def_id)
     );
 
-    let trait_ref = ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) };
+    let trait_ref =
+        ty::Binder::dummy(ty::TraitRef { def_id, substs: infcx.tcx.mk_substs_trait(ty, &[]) });
     let obligation = Obligation {
         param_env,
         cause: ObligationCause::misc(span, hir::CRATE_HIR_ID),
index 4922cf45a4a109565db5478fb7b53c8a3b5c3e8d..0bb00dfeb43ad92fd54f6d035dd4d545403df7f7 100644 (file)
@@ -250,7 +250,7 @@ fn predicates_reference_self(
     trait_def_id: DefId,
     supertraits_only: bool,
 ) -> SmallVec<[Span; 1]> {
-    let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
+    let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
     let predicates = if supertraits_only {
         tcx.super_predicates_of(trait_def_id)
     } else {
@@ -554,11 +554,11 @@ fn object_ty_for_trait<'tcx>(
 
     let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
 
-    let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
-        ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
-    ));
+    let trait_predicate = trait_ref.map_bound(|trait_ref| {
+        ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
+    });
 
-    let mut associated_types = traits::supertraits(tcx, ty::Binder::dummy(trait_ref))
+    let mut associated_types = traits::supertraits(tcx, trait_ref)
         .flat_map(|super_trait_ref| {
             tcx.associated_items(super_trait_ref.def_id())
                 .in_definition_order()
@@ -671,10 +671,10 @@ fn receiver_is_dispatchable<'tcx>(
         let param_env = tcx.param_env(method.def_id);
 
         // Self: Unsize<U>
-        let unsize_predicate = ty::TraitRef {
+        let unsize_predicate = ty::Binder::dummy(ty::TraitRef {
             def_id: unsize_did,
             substs: tcx.mk_substs_trait(tcx.types.self_param, &[unsized_self_ty.into()]),
-        }
+        })
         .without_const()
         .to_predicate(tcx);
 
@@ -689,7 +689,9 @@ fn receiver_is_dispatchable<'tcx>(
                     }
                 });
 
-            ty::TraitRef { def_id: unsize_did, substs }.without_const().to_predicate(tcx)
+            ty::Binder::dummy(ty::TraitRef { def_id: unsize_did, substs })
+                .without_const()
+                .to_predicate(tcx)
         };
 
         let caller_bounds: Vec<Predicate<'tcx>> = param_env
@@ -703,10 +705,10 @@ fn receiver_is_dispatchable<'tcx>(
 
     // Receiver: DispatchFromDyn<Receiver[Self => U]>
     let obligation = {
-        let predicate = ty::TraitRef {
+        let predicate = ty::Binder::dummy(ty::TraitRef {
             def_id: dispatch_from_dyn_did,
             substs: tcx.mk_substs_trait(receiver_ty, &[unsized_receiver_ty.into()]),
-        }
+        })
         .without_const()
         .to_predicate(tcx);
 
@@ -789,8 +791,7 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
 
                     // Compute supertraits of current trait lazily.
                     if self.supertraits.is_none() {
-                        let trait_ref =
-                            ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id));
+                        let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id);
                         self.supertraits = Some(
                             traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
                         );
index 58589e556f2704afddc37f790f6da59ae984c822..47b006985ec569e74d77f7bb7f1caad7de937fb3 100644 (file)
@@ -27,7 +27,7 @@
 use rustc_infer::infer::resolve::OpportunisticRegionResolver;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
 use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness};
 use rustc_span::symbol::sym;
 
 use std::collections::BTreeMap;
@@ -388,15 +388,15 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         // to make sure we don't forget to fold the substs regardless.
 
         match *ty.kind() {
-            ty::Opaque(def_id, substs) => {
+            // This is really important. While we *can* handle this, this has
+            // severe performance implications for large opaque types with
+            // late-bound regions. See `issue-88862` benchmark.
+            ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
                 // Only normalize `impl Trait` after type-checking, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty.super_fold_with(self),
 
                     Reveal::All => {
-                        // N.b. there is an assumption here all this code can handle
-                        // escaping bound vars.
-
                         let recursion_limit = self.tcx().recursion_limit();
                         if !recursion_limit.value_within_limit(self.depth) {
                             let obligation = Obligation::with_depth(
@@ -1028,7 +1028,7 @@ fn normalize_to_error<'a, 'tcx>(
     cause: ObligationCause<'tcx>,
     depth: usize,
 ) -> NormalizedTy<'tcx> {
-    let trait_ref = projection_ty.trait_ref(selcx.tcx()).to_poly_trait_ref();
+    let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx()));
     let trait_obligation = Obligation {
         cause,
         recursion_depth: depth,
@@ -1290,7 +1290,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
 
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
     // start out by selecting the predicate `T as TraitRef<...>`:
-    let poly_trait_ref = obligation.predicate.trait_ref(selcx.tcx()).to_poly_trait_ref();
+    let poly_trait_ref = ty::Binder::dummy(obligation.predicate.trait_ref(selcx.tcx()));
     let trait_obligation = obligation.with(poly_trait_ref.to_poly_trait_predicate());
     let _ = selcx.infcx().commit_if_ok(|_| {
         let impl_source = match selcx.select(&trait_obligation) {
index ed5fe466c69f7579afe644b6d5c0e95228493a15..1364cf1c9953512f925106e382f141a3bc893a5d 100644 (file)
@@ -206,15 +206,15 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
 
         // Wrap this in a closure so we don't accidentally return from the outer function
         let res = (|| match *ty.kind() {
-            ty::Opaque(def_id, substs) => {
+            // This is really important. While we *can* handle this, this has
+            // severe performance implications for large opaque types with
+            // late-bound regions. See `issue-88862` benchmark.
+            ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => {
                 // Only normalize `impl Trait` after type-checking, usually in codegen.
                 match self.param_env.reveal() {
                     Reveal::UserFacing => ty.super_fold_with(self),
 
                     Reveal::All => {
-                        // N.b. there is an assumption here all this code can handle
-                        // escaping bound vars.
-
                         let substs = substs.super_fold_with(self);
                         let recursion_limit = self.tcx().recursion_limit();
                         if !recursion_limit.value_within_limit(self.anon_depth) {
index 3b6555de912e959465d14a13180ee4ed2ffdd9a7..9e1211336a4b01472026ee7a2cb0d53ecdfb3fac 100644 (file)
@@ -141,6 +141,7 @@ fn confirm_projection_candidate(
             let placeholder_trait_predicate =
                 self.infcx().replace_bound_vars_with_placeholders(trait_predicate);
             let placeholder_self_ty = placeholder_trait_predicate.self_ty();
+            let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
             let (def_id, substs) = match *placeholder_self_ty.kind() {
                 ty::Projection(proj) => (proj.item_def_id, proj.substs),
                 ty::Opaque(def_id, substs) => (def_id, substs),
@@ -164,7 +165,7 @@ fn confirm_projection_candidate(
             obligations.extend(self.infcx.commit_if_ok(|_| {
                 self.infcx
                     .at(&obligation.cause, obligation.param_env)
-                    .sup(placeholder_trait_predicate.trait_ref.to_poly_trait_ref(), candidate.value)
+                    .sup(placeholder_trait_predicate.to_poly_trait_ref(), candidate.value)
                     .map(|InferOk { obligations, .. }| obligations)
                     .map_err(|_| Unimplemented)
             })?);
@@ -646,7 +647,7 @@ fn confirm_closure_candidate(
             obligations.push(Obligation::new(
                 obligation.cause.clone(),
                 obligation.param_env,
-                ty::PredicateKind::ClosureKind(closure_def_id, substs, kind)
+                ty::Binder::dummy(ty::PredicateKind::ClosureKind(closure_def_id, substs, kind))
                     .to_predicate(self.tcx()),
             ));
         }
@@ -898,10 +899,10 @@ fn confirm_builtin_unsize_candidate(
                 );
 
                 // We can only make objects from sized types.
-                let tr = ty::TraitRef::new(
+                let tr = ty::Binder::dummy(ty::TraitRef::new(
                     tcx.require_lang_item(LangItem::Sized, None),
                     tcx.mk_substs_trait(source, &[]),
-                );
+                ));
                 nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));
 
                 // If the type is `Foo + 'a`, ensure that the type
index b108d85bb20c9afc2184fab8be73133fc8d05289..ed49abbbedc92dfe8415a16f377c45f0c84ba567 100644 (file)
@@ -248,7 +248,7 @@ pub fn predicate_for_trait_ref<'tcx>(
         cause,
         param_env,
         recursion_depth,
-        predicate: trait_ref.without_const().to_predicate(tcx),
+        predicate: ty::Binder::dummy(trait_ref).without_const().to_predicate(tcx),
     }
 }
 
index 611ff26d652277ebfc3ef482faff31a4624af93f..cb47ba9c360da14401081cfc132e70e61a678641 100644 (file)
@@ -349,7 +349,7 @@ fn compute_trait_ref(&mut self, trait_ref: &ty::TraitRef<'tcx>, elaborate: Elabo
                         new_cause,
                         depth,
                         param_env,
-                        ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
                     )
                 }),
         );
@@ -399,7 +399,7 @@ fn compute_projection(&mut self, data: ty::ProjectionTy<'tcx>) {
                         cause.clone(),
                         depth,
                         param_env,
-                        ty::PredicateKind::WellFormed(arg).to_predicate(tcx),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(tcx),
                     )
                 }),
         );
@@ -416,7 +416,7 @@ fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<
                 cause,
                 self.recursion_depth,
                 self.param_env,
-                trait_ref.without_const().to_predicate(self.infcx.tcx),
+                ty::Binder::dummy(trait_ref).without_const().to_predicate(self.infcx.tcx),
             ));
         }
     }
@@ -443,9 +443,9 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                             let obligations = self.nominal_obligations(uv.def.did, substs);
                             self.out.extend(obligations);
 
-                            let predicate = ty::PredicateKind::ConstEvaluatable(
+                            let predicate = ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(
                                 ty::Unevaluated::new(uv.def, substs),
-                            )
+                            ))
                             .to_predicate(self.tcx());
                             let cause = self.cause(traits::MiscObligation);
                             self.out.push(traits::Obligation::with_depth(
@@ -469,8 +469,10 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                                     cause,
                                     self.recursion_depth,
                                     self.param_env,
-                                    ty::PredicateKind::WellFormed(resolved_constant.into())
-                                        .to_predicate(self.tcx()),
+                                    ty::Binder::dummy(ty::PredicateKind::WellFormed(
+                                        resolved_constant.into(),
+                                    ))
+                                    .to_predicate(self.tcx()),
                                 ));
                             }
                         }
@@ -556,8 +558,10 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                             cause,
                             depth,
                             param_env,
-                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(rty, r))
-                                .to_predicate(self.tcx()),
+                            ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+                                ty::OutlivesPredicate(rty, r),
+                            ))
+                            .to_predicate(self.tcx()),
                         ));
                     }
                 }
@@ -646,7 +650,8 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                                 cause.clone(),
                                 depth,
                                 param_env,
-                                ty::PredicateKind::ObjectSafe(did).to_predicate(tcx),
+                                ty::Binder::dummy(ty::PredicateKind::ObjectSafe(did))
+                                    .to_predicate(tcx),
                             )
                         }));
                     }
@@ -673,7 +678,8 @@ fn compute(&mut self, arg: GenericArg<'tcx>) {
                             cause,
                             self.recursion_depth,
                             param_env,
-                            ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
+                            ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()))
+                                .to_predicate(self.tcx()),
                         ));
                     } else {
                         // Yes, resolved, proceed with the result.
index 48c46c3069328e584d86ecca8ad052c54c62526f..8612499623be628ea17c66230ed0cc2af5b3dd0a 100644 (file)
@@ -19,7 +19,7 @@
 mod normalize_projection_ty;
 mod type_op;
 
-pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_span};
+pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
 
 use rustc_middle::ty::query::Providers;
 
index a76fb842616152af6da34f435c8a1b6a4dd69073..cc0b7d5817b435832a8b9c0ad7c270352a535286 100644 (file)
@@ -156,7 +156,8 @@ fn relate_mir_and_user_ty(
             self.relate(self_ty, Variance::Invariant, impl_self_ty)?;
 
             self.prove_predicate(
-                ty::PredicateKind::WellFormed(impl_self_ty.into()).to_predicate(self.tcx()),
+                ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()))
+                    .to_predicate(self.tcx()),
                 span,
             );
         }
@@ -173,7 +174,7 @@ fn relate_mir_and_user_ty(
         // type were ill-formed but did not appear in `ty`,
         // which...could happen with normalization...
         self.prove_predicate(
-            ty::PredicateKind::WellFormed(ty.into()).to_predicate(self.tcx()),
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into())).to_predicate(self.tcx()),
             span,
         );
         Ok(())
@@ -256,7 +257,7 @@ fn type_op_prove_predicate<'tcx>(
     canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, ProvePredicate<'tcx>>>,
 ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, NoSolution> {
     tcx.infer_ctxt().enter_canonical_trait_query(&canonicalized, |infcx, fulfill_cx, key| {
-        type_op_prove_predicate_with_span(infcx, fulfill_cx, key, None);
+        type_op_prove_predicate_with_cause(infcx, fulfill_cx, key, ObligationCause::dummy());
         Ok(())
     })
 }
@@ -264,17 +265,12 @@ fn type_op_prove_predicate<'tcx>(
 /// The core of the `type_op_prove_predicate` query: for diagnostics purposes in NLL HRTB errors,
 /// this query can be re-run to better track the span of the obligation cause, and improve the error
 /// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_prove_predicate_with_span<'a, 'tcx: 'a>(
+pub fn type_op_prove_predicate_with_cause<'a, 'tcx: 'a>(
     infcx: &'a InferCtxt<'a, 'tcx>,
     fulfill_cx: &'a mut dyn TraitEngine<'tcx>,
     key: ParamEnvAnd<'tcx, ProvePredicate<'tcx>>,
-    span: Option<Span>,
+    cause: ObligationCause<'tcx>,
 ) {
-    let cause = if let Some(span) = span {
-        ObligationCause::dummy_with_span(span)
-    } else {
-        ObligationCause::dummy()
-    };
     let (param_env, ProvePredicate { predicate }) = key.into_parts();
     fulfill_cx.register_predicate_obligation(infcx, Obligation::new(cause, param_env, predicate));
 }
index 32d271d94c8ea2ac79984c2fc5b7562237191e12..98415a84c569bc0191dadf2bf06e08f7788a5dae 100644 (file)
@@ -3,6 +3,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::subst::Subst;
+use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::Limit;
@@ -12,7 +13,7 @@
 
 fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
     let adt_components =
-        move |adt_def: &ty::AdtDef| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
+        move |adt_def: &ty::AdtDef, _| tcx.adt_drop_tys(adt_def.did).map(|tys| tys.iter());
 
     // If we don't know a type doesn't need drop, for example if it's a type
     // parameter without a `Copy` bound, then we conservatively return that it
@@ -28,8 +29,9 @@ fn has_significant_drop_raw<'tcx>(
     tcx: TyCtxt<'tcx>,
     query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
 ) -> bool {
-    let significant_drop_fields =
-        move |adt_def: &ty::AdtDef| tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter());
+    let significant_drop_fields = move |adt_def: &ty::AdtDef, _| {
+        tcx.adt_significant_drop_tys(adt_def.did).map(|tys| tys.iter())
+    };
     let res = NeedsDropTypes::new(tcx, query.param_env, query.value, significant_drop_fields)
         .next()
         .is_some();
@@ -74,7 +76,7 @@ fn new(
 
 impl<'tcx, F, I> Iterator for NeedsDropTypes<'tcx, F>
 where
-    F: Fn(&ty::AdtDef) -> NeedsDropResult<I>,
+    F: Fn(&ty::AdtDef, SubstsRef<'tcx>) -> NeedsDropResult<I>,
     I: Iterator<Item = Ty<'tcx>>,
 {
     type Item = NeedsDropResult<Ty<'tcx>>;
@@ -138,7 +140,7 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
                     // `ManuallyDrop`. If it's a struct or enum without a `Drop`
                     // impl then check whether the field types need `Drop`.
                     ty::Adt(adt_def, substs) => {
-                        let tys = match (self.adt_components)(adt_def) {
+                        let tys = match (self.adt_components)(adt_def, substs) {
                             Err(e) => return Some(Err(e)),
                             Ok(tys) => tys,
                         };
@@ -171,22 +173,44 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
     }
 }
 
+enum DtorType {
+    /// Type has a `Drop` but it is considered insignificant.
+    /// Check the query `adt_significant_drop_tys` for understanding
+    /// "significant" / "insignificant".
+    Insignificant,
+
+    /// Type has a `Drop` implentation.
+    Significant,
+}
+
 // This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`.
 // Depending on the implentation of `adt_has_dtor`, it is used to check if the
 // ADT has a destructor or if the ADT only has a significant destructor. For
 // understanding significant destructor look at `adt_significant_drop_tys`.
-fn adt_drop_tys_helper(
-    tcx: TyCtxt<'_>,
+fn adt_drop_tys_helper<'tcx>(
+    tcx: TyCtxt<'tcx>,
     def_id: DefId,
-    adt_has_dtor: impl Fn(&ty::AdtDef) -> bool,
-) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
-    let adt_components = move |adt_def: &ty::AdtDef| {
+    adt_has_dtor: impl Fn(&ty::AdtDef) -> Option<DtorType>,
+) -> Result<&ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
+    let adt_components = move |adt_def: &ty::AdtDef, substs: SubstsRef<'tcx>| {
         if adt_def.is_manually_drop() {
             debug!("adt_drop_tys: `{:?}` is manually drop", adt_def);
             return Ok(Vec::new().into_iter());
-        } else if adt_has_dtor(adt_def) {
-            debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
-            return Err(AlwaysRequiresDrop);
+        } else if let Some(dtor_info) = adt_has_dtor(adt_def) {
+            match dtor_info {
+                DtorType::Significant => {
+                    debug!("adt_drop_tys: `{:?}` implements `Drop`", adt_def);
+                    return Err(AlwaysRequiresDrop);
+                }
+                DtorType::Insignificant => {
+                    debug!("adt_drop_tys: `{:?}` drop is insignificant", adt_def);
+
+                    // Since the destructor is insignificant, we just want to make sure all of
+                    // the passed in type parameters are also insignificant.
+                    // Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
+                    return Ok(substs.types().collect::<Vec<Ty<'_>>>().into_iter());
+                }
+            }
         } else if adt_def.is_union() {
             debug!("adt_drop_tys: `{:?}` is a union", adt_def);
             return Ok(Vec::new().into_iter());
@@ -204,7 +228,10 @@ fn adt_drop_tys_helper(
 }
 
 fn adt_drop_tys(tcx: TyCtxt<'_>, def_id: DefId) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
-    let adt_has_dtor = |adt_def: &ty::AdtDef| adt_def.destructor(tcx).is_some();
+    // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
+    // significant.
+    let adt_has_dtor =
+        |adt_def: &ty::AdtDef| adt_def.destructor(tcx).map(|_| DtorType::Significant);
     adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
 }
 
@@ -213,10 +240,22 @@ fn adt_significant_drop_tys(
     def_id: DefId,
 ) -> Result<&ty::List<Ty<'_>>, AlwaysRequiresDrop> {
     let adt_has_dtor = |adt_def: &ty::AdtDef| {
-        adt_def
-            .destructor(tcx)
-            .map(|dtor| !tcx.has_attr(dtor.did, sym::rustc_insignificant_dtor))
-            .unwrap_or(false)
+        let is_marked_insig = tcx.has_attr(adt_def.did, sym::rustc_insignificant_dtor);
+        if is_marked_insig {
+            // In some cases like `std::collections::HashMap` where the struct is a wrapper around
+            // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
+            // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
+            // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
+            Some(DtorType::Insignificant)
+        } else if adt_def.destructor(tcx).is_some() {
+            // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be
+            // significant.
+            Some(DtorType::Significant)
+        } else {
+            // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we
+            // treat this as the simple case of Drop impl for type.
+            None
+        }
     };
     adt_drop_tys_helper(tcx, def_id, adt_has_dtor)
 }
index 01227cad334fc783e12d0f79ef97b63a5150ae32..6a231e719e66462a9751bd69392442e3648a124a 100644 (file)
@@ -524,13 +524,14 @@ pub(crate) fn opt_suggest_box_span(
                 for o in obligations {
                     match o.predicate.kind().skip_binder() {
                         ty::PredicateKind::Trait(t) => {
-                            let pred = ty::PredicateKind::Trait(ty::TraitPredicate {
-                                trait_ref: ty::TraitRef {
-                                    def_id: t.def_id(),
-                                    substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
-                                },
-                                constness: t.constness,
-                            });
+                            let pred =
+                                ty::Binder::dummy(ty::PredicateKind::Trait(ty::TraitPredicate {
+                                    trait_ref: ty::TraitRef {
+                                        def_id: t.def_id(),
+                                        substs: self.infcx.tcx.mk_substs_trait(outer_ty, &[]),
+                                    },
+                                    constness: t.constness,
+                                }));
                             let obl = Obligation::new(
                                 o.cause.clone(),
                                 self.param_env,
index 1cc06b8c2e544b9ca5bdf2130cd61ea1dd21b46f..e007d971bb072bd1ae109b0c70fca6803e4915b6 100644 (file)
@@ -246,12 +246,18 @@ fn try_overloaded_call_traits(
                 if borrow {
                     // Check for &self vs &mut self in the method signature. Since this is either
                     // the Fn or FnMut trait, it should be one of those.
-                    let (region, mutbl) =
-                        if let ty::Ref(r, _, mutbl) = method.sig.inputs()[0].kind() {
-                            (r, mutbl)
-                        } else {
-                            span_bug!(call_expr.span, "input to call/call_mut is not a ref?");
-                        };
+                    let (region, mutbl) = if let ty::Ref(r, _, mutbl) =
+                        method.sig.inputs()[0].kind()
+                    {
+                        (r, mutbl)
+                    } else {
+                        // The `fn`/`fn_mut` lang item is ill-formed, which should have
+                        // caused an error elsewhere.
+                        self.tcx
+                            .sess
+                            .delay_span_bug(call_expr.span, "input to call/call_mut is not a ref?");
+                        return None;
+                    };
 
                     let mutbl = match mutbl {
                         hir::Mutability::Not => AutoBorrowMutability::Not,
index 5b9481ce4e1b9d0cd92efa4d1014ce0f4130a83f..ef18c1e7779d862a4a9710eb6cb1c80a98bb02b1 100644 (file)
@@ -256,10 +256,10 @@ fn coerce_from_inference_variable(
                     obligations.push(Obligation::new(
                         self.cause.clone(),
                         self.param_env,
-                        ty::PredicateKind::Coerce(ty::CoercePredicate {
+                        ty::Binder::dummy(ty::PredicateKind::Coerce(ty::CoercePredicate {
                             a: source_ty,
                             b: target_ty,
-                        })
+                        }))
                         .to_predicate(self.tcx()),
                     ));
                 }
index 562d05d3ef9b1b00e803893f1539fd66e5f00397..553f5ed8a0ca4f358cf9c59e1b7241137652dd0b 100644 (file)
@@ -585,7 +585,7 @@ pub fn register_wf_obligation(
         self.register_predicate(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::PredicateKind::WellFormed(arg).to_predicate(self.tcx),
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(arg)).to_predicate(self.tcx),
         ));
     }
 
index 8e09aa97dcf345ea396f06fbbd7002576455d9a8..113d495f0ce93c499238702926154ab5afb2d1bc 100644 (file)
@@ -21,7 +21,7 @@
 use rustc_middle::ty::subst::Subst;
 use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{self, ToPolyTraitRef, ToPredicate, Ty, TypeFoldable, WithConstness};
+use rustc_middle::ty::{self, ToPredicate, Ty, TypeFoldable, WithConstness};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits;
@@ -331,7 +331,7 @@ pub fn lookup_method_in_trait(
         let trait_ref = ty::TraitRef::new(trait_def_id, substs);
 
         // Construct an obligation
-        let poly_trait_ref = trait_ref.to_poly_trait_ref();
+        let poly_trait_ref = ty::Binder::dummy(trait_ref);
         let obligation = traits::Obligation::misc(
             span,
             self.body_id,
@@ -413,7 +413,7 @@ pub fn lookup_method_in_trait(
         obligations.push(traits::Obligation::new(
             cause,
             self.param_env,
-            ty::PredicateKind::WellFormed(method_ty.into()).to_predicate(tcx),
+            ty::Binder::dummy(ty::PredicateKind::WellFormed(method_ty.into())).to_predicate(tcx),
         ));
 
         let callee = MethodCallee { def_id, substs: trait_ref.substs, sig: fn_sig };
index cbfdce96bc57bdd0b1554f8b4e32ec1e8343faf6..5aa579f33a9d2148448ff80a0cd4c64b1d664be0 100644 (file)
@@ -21,9 +21,7 @@
 use rustc_middle::middle::stability;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::{
-    self, ParamEnvAnd, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
-};
+use rustc_middle::ty::{self, ParamEnvAnd, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::lev_distance::{find_best_match_for_name, lev_distance};
@@ -967,7 +965,7 @@ fn assemble_extension_candidates_for_trait(
 
         if self.tcx.is_trait_alias(trait_def_id) {
             // For trait aliases, assume all super-traits are relevant.
-            let bounds = iter::once(trait_ref.to_poly_trait_ref());
+            let bounds = iter::once(ty::Binder::dummy(trait_ref));
             self.elaborate_bounds(bounds, |this, new_trait_ref, item| {
                 let new_trait_ref = this.erase_late_bound_regions(new_trait_ref);
 
@@ -1372,7 +1370,7 @@ fn select_trait_candidate(
         trait_ref: ty::TraitRef<'tcx>,
     ) -> traits::SelectionResult<'tcx, traits::Selection<'tcx>> {
         let cause = traits::ObligationCause::misc(self.span, self.body_id);
-        let predicate = trait_ref.to_poly_trait_ref().to_poly_trait_predicate();
+        let predicate = ty::Binder::dummy(trait_ref).to_poly_trait_predicate();
         let obligation = traits::Obligation::new(cause, self.param_env, predicate);
         traits::SelectionContext::new(self).select(&obligation)
     }
@@ -1470,7 +1468,8 @@ fn consider_probe(
                             }
                         }
                     }
-                    let predicate = trait_ref.without_const().to_predicate(self.tcx);
+                    let predicate =
+                        ty::Binder::dummy(trait_ref).without_const().to_predicate(self.tcx);
                     let obligation = traits::Obligation::new(cause, self.param_env, predicate);
                     if !self.predicate_may_hold(&obligation) {
                         result = ProbeResult::NoMatch;
index 9744f4f6483c75f8fcaf72f9db79c36cbf204219..91a164ce063ea6cae022e8254e572e8149338bb9 100644 (file)
@@ -12,9 +12,7 @@
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_middle::ty::fast_reject::simplify_type;
 use rustc_middle::ty::print::with_crate_prefix;
-use rustc_middle::ty::{
-    self, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness,
-};
+use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness};
 use rustc_span::lev_distance;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{source_map, FileName, Span};
@@ -53,7 +51,7 @@ fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
                                 .into()],
                         );
                         let trait_ref = ty::TraitRef::new(fn_once, fn_once_substs);
-                        let poly_trait_ref = trait_ref.to_poly_trait_ref();
+                        let poly_trait_ref = ty::Binder::dummy(trait_ref);
                         let obligation = Obligation::misc(
                             span,
                             self.body_id,
index 53b99a14f379d2450c5656eaf87f8ed99e58fa5a..917bf4ecd8c4a9117a5e80a6421beadb7836d0e4 100644 (file)
@@ -602,7 +602,78 @@ fn compute_min_captures(
             }
         }
 
-        debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list);
+        debug!(
+            "For closure={:?}, min_captures before sorting={:?}",
+            closure_def_id, root_var_min_capture_list
+        );
+
+        // Now that we have the minimized list of captures, sort the captures by field id.
+        // This causes the closure to capture the upvars in the same order as the fields are
+        // declared which is also the drop order. Thus, in situations where we capture all the
+        // fields of some type, the obserable drop order will remain the same as it previously
+        // was even though we're dropping each capture individually.
+        // See https://github.com/rust-lang/project-rfc-2229/issues/42 and
+        // `src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs`.
+        for (_, captures) in &mut root_var_min_capture_list {
+            captures.sort_by(|capture1, capture2| {
+                for (p1, p2) in capture1.place.projections.iter().zip(&capture2.place.projections) {
+                    // We do not need to look at the `Projection.ty` fields here because at each
+                    // step of the iteration, the projections will either be the same and therefore
+                    // the types must be as well or the current projection will be different and
+                    // we will return the result of comparing the field indexes.
+                    match (p1.kind, p2.kind) {
+                        // Paths are the same, continue to next loop.
+                        (ProjectionKind::Deref, ProjectionKind::Deref) => {}
+                        (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _))
+                            if i1 == i2 => {}
+
+                        // Fields are different, compare them.
+                        (ProjectionKind::Field(i1, _), ProjectionKind::Field(i2, _)) => {
+                            return i1.cmp(&i2);
+                        }
+
+                        // We should have either a pair of `Deref`s or a pair of `Field`s.
+                        // Anything else is a bug.
+                        (
+                            l @ (ProjectionKind::Deref | ProjectionKind::Field(..)),
+                            r @ (ProjectionKind::Deref | ProjectionKind::Field(..)),
+                        ) => bug!(
+                            "ProjectionKinds Deref and Field were mismatched: ({:?}, {:?})",
+                            l,
+                            r
+                        ),
+                        (
+                            l
+                            @
+                            (ProjectionKind::Index
+                            | ProjectionKind::Subslice
+                            | ProjectionKind::Deref
+                            | ProjectionKind::Field(..)),
+                            r
+                            @
+                            (ProjectionKind::Index
+                            | ProjectionKind::Subslice
+                            | ProjectionKind::Deref
+                            | ProjectionKind::Field(..)),
+                        ) => bug!(
+                            "ProjectionKinds Index or Subslice were unexpected: ({:?}, {:?})",
+                            l,
+                            r
+                        ),
+                    }
+                }
+
+                unreachable!(
+                    "we captured two identical projections: capture1 = {:?}, capture2 = {:?}",
+                    capture1, capture2
+                );
+            });
+        }
+
+        debug!(
+            "For closure={:?}, min_captures after sorting={:#?}",
+            closure_def_id, root_var_min_capture_list
+        );
         typeck_results.closure_min_captures.insert(closure_def_id, root_var_min_capture_list);
     }
 
index 01ec801228e2e8f0d35e3e931e94d83f4338b5cd..48204590468a0af0e8faa945446daf3b5390164e 100644 (file)
@@ -200,6 +200,59 @@ pub fn check_trait_item(tcx: TyCtxt<'_>, def_id: LocalDefId) {
     };
     check_object_unsafe_self_trait_by_name(tcx, &trait_item);
     check_associated_item(tcx, trait_item.hir_id(), span, method_sig);
+
+    let encl_trait_hir_id = tcx.hir().get_parent_item(hir_id);
+    let encl_trait = tcx.hir().expect_item(encl_trait_hir_id);
+    let encl_trait_def_id = encl_trait.def_id.to_def_id();
+    let fn_lang_item_name = if Some(encl_trait_def_id) == tcx.lang_items().fn_trait() {
+        Some("fn")
+    } else if Some(encl_trait_def_id) == tcx.lang_items().fn_mut_trait() {
+        Some("fn_mut")
+    } else {
+        None
+    };
+
+    if let (Some(fn_lang_item_name), "call") =
+        (fn_lang_item_name, trait_item.ident.name.to_ident_string().as_str())
+    {
+        // We are looking at the `call` function of the `fn` or `fn_mut` lang item.
+        // Do some rudimentary sanity checking to avoid an ICE later (issue #83471).
+        if let Some(hir::FnSig { decl, span, .. }) = method_sig {
+            if let &[self_ty, _] = &decl.inputs {
+                if !matches!(self_ty.kind, hir::TyKind::Rptr(_, _)) {
+                    tcx.sess
+                        .struct_span_err(
+                            self_ty.span,
+                            &format!(
+                                "first argument of `call` in `{}` lang item must be a reference",
+                                fn_lang_item_name
+                            ),
+                        )
+                        .emit();
+                }
+            } else {
+                tcx.sess
+                    .struct_span_err(
+                        *span,
+                        &format!(
+                            "`call` function in `{}` lang item takes exactly two arguments",
+                            fn_lang_item_name
+                        ),
+                    )
+                    .emit();
+            }
+        } else {
+            tcx.sess
+                .struct_span_err(
+                    trait_item.span,
+                    &format!(
+                        "`call` trait item in `{}` lang item must be a function",
+                        fn_lang_item_name
+                    ),
+                )
+                .emit();
+        }
+    }
 }
 
 fn could_be_self(trait_def_id: LocalDefId, ty: &hir::Ty<'_>) -> bool {
@@ -540,10 +593,10 @@ fn check_type_defn<'tcx, F>(
                 fcx.register_predicate(traits::Obligation::new(
                     cause,
                     fcx.param_env,
-                    ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
+                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(ty::Unevaluated::new(
                         ty::WithOptConstParam::unknown(discr_def_id.to_def_id()),
                         discr_substs,
-                    ))
+                    )))
                     .to_predicate(tcx),
                 ));
             }
@@ -1151,10 +1204,10 @@ fn receiver_is_implemented(
     cause: ObligationCause<'tcx>,
     receiver_ty: Ty<'tcx>,
 ) -> bool {
-    let trait_ref = ty::TraitRef {
+    let trait_ref = ty::Binder::dummy(ty::TraitRef {
         def_id: receiver_trait_def_id,
         substs: fcx.tcx.mk_substs_trait(receiver_ty, &[]),
-    };
+    });
 
     let obligation = traits::Obligation::new(
         cause,
index 231a81421748491275340a71b4801c1aca090b63..51f9f459af1c56390e1e37ffe92633f55eccc64b 100644 (file)
@@ -40,7 +40,7 @@
 use rustc_middle::ty::subst::InternalSubsts;
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::util::IntTypeExt;
-use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, ToPolyTraitRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, DefIdTree, Ty, TyCtxt};
 use rustc_middle::ty::{ReprOptions, ToPredicate, WithConstness};
 use rustc_session::lint;
 use rustc_session::parse::feature_err;
@@ -2042,7 +2042,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
             match item.kind {
                 ItemKind::Impl(ref impl_) => {
                     if impl_.defaultness.is_default() {
-                        is_default_impl_trait = tcx.impl_trait_ref(def_id);
+                        is_default_impl_trait = tcx
+                            .impl_trait_ref(def_id)
+                            .map(|trait_ref| ty::Binder::dummy(trait_ref));
                     }
                     &impl_.generics
                 }
@@ -2122,10 +2124,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
     // (see below). Recall that a default impl is not itself an impl, but rather a
     // set of defaults that can be incorporated into another impl.
     if let Some(trait_ref) = is_default_impl_trait {
-        predicates.insert((
-            trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx),
-            tcx.def_span(def_id),
-        ));
+        predicates.insert((trait_ref.without_const().to_predicate(tcx), tcx.def_span(def_id)));
     }
 
     // Collect the region predicates that were declared inline as
@@ -2238,8 +2237,10 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                         }
                         _ => bug!(),
                     };
-                    let pred = ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
-                        .to_predicate(icx.tcx);
+                    let pred = ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+                        ty::OutlivesPredicate(r1, r2),
+                    ))
+                    .to_predicate(icx.tcx);
 
                     (pred, span)
                 }))
@@ -2304,7 +2305,8 @@ fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) {
                 assert_eq!(uv.promoted, None);
                 let span = self.tcx.hir().span(c.hir_id);
                 self.preds.insert((
-                    ty::PredicateKind::ConstEvaluatable(uv.shrink()).to_predicate(self.tcx),
+                    ty::Binder::dummy(ty::PredicateKind::ConstEvaluatable(uv.shrink()))
+                        .to_predicate(self.tcx),
                     span,
                 ));
             }
index b7ede0e4bf25175ea966b2816a29da71401bd5b8..39bcf8999323d7fb7a9a877cda60ee0d4b355bdb 100644 (file)
@@ -83,7 +83,8 @@ fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) {
                     traits::Obligation::new(
                         cause,
                         self.param_env,
-                        ty::PredicateKind::WellFormed(tcx_ty.into()).to_predicate(self.tcx),
+                        ty::Binder::dummy(ty::PredicateKind::WellFormed(tcx_ty.into()))
+                            .to_predicate(self.tcx),
                     ),
                 );
 
index 70a2ba7fcd9d9cc5e2c54238246e21b2d2ec86f0..9c6efffdaf0fe3d1d043d784c58143ac4281f2aa 100644 (file)
@@ -104,13 +104,15 @@ fn inferred_outlives_crate(tcx: TyCtxt<'_>, (): ()) -> CratePredicatesMap<'_> {
                 |(ty::OutlivesPredicate(kind1, region2), &span)| {
                     match kind1.unpack() {
                         GenericArgKind::Type(ty1) => Some((
-                            ty::PredicateKind::TypeOutlives(ty::OutlivesPredicate(ty1, region2))
-                                .to_predicate(tcx),
+                            ty::Binder::dummy(ty::PredicateKind::TypeOutlives(
+                                ty::OutlivesPredicate(ty1, region2),
+                            ))
+                            .to_predicate(tcx),
                             span,
                         )),
                         GenericArgKind::Lifetime(region1) => Some((
-                            ty::PredicateKind::RegionOutlives(ty::OutlivesPredicate(
-                                region1, region2,
+                            ty::Binder::dummy(ty::PredicateKind::RegionOutlives(
+                                ty::OutlivesPredicate(region1, region2),
                             ))
                             .to_predicate(tcx),
                             span,
index 2e3db4d6d655f53447438c62ec0c76ad90b7a397..c2038f4e047ce96cdd335039c6822df9dd444fdd 100644 (file)
@@ -731,7 +731,11 @@ fn suggest_removing_args_or_generics(&self, err: &mut DiagnosticBuilder<'_>) {
     /// Builds the `type defined here` message.
     fn show_definition(&self, err: &mut DiagnosticBuilder<'_>) {
         let mut spans: MultiSpan = if let Some(def_span) = self.tcx.def_ident_span(self.def_id) {
-            def_span.into()
+            if self.tcx.sess.source_map().span_to_snippet(def_span).is_ok() {
+                def_span.into()
+            } else {
+                return;
+            }
         } else {
             return;
         };
index 3ed3c2382cac69193a07129fa91d9b6e2a9981f3..4a5b0fcf03709ff944fe4e612327bbeaee3cb70e 100644 (file)
@@ -307,7 +307,6 @@ unsafe fn shrink(
 }
 
 /// The allocator for unique pointers.
-// This function must not unwind. If it does, MIR codegen will fail.
 #[cfg(all(not(no_global_oom_handling), not(test)))]
 #[lang = "exchange_malloc"]
 #[inline]
index 28e4f8bba05c8d5272e477f98ad4a00e57f5d3fd..4ed3702f7d22479d8ab1e77be4c49dc139f5b1ec 100644 (file)
@@ -3,7 +3,7 @@
 //! Insertion and popping the largest element have *O*(log(*n*)) time complexity.
 //! Checking the largest element is *O*(1). Converting a vector to a binary heap
 //! can be done in-place, and has *O*(*n*) complexity. A binary heap can also be
-//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* \* log(*n*))
+//! converted to a sorted vector in-place, allowing it to be used for an *O*(*n* * log(*n*))
 //! in-place heapsort.
 //!
 //! # Examples
 /// This will be a max-heap.
 ///
 /// It is a logic error for an item to be modified in such a way that the
-/// item's ordering relative to any other item, as determined by the `Ord`
+/// item's ordering relative to any other item, as determined by the [`Ord`]
 /// trait, changes while it is in the heap. This is normally only possible
-/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. The
+/// through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. The
 /// behavior resulting from such a logic error is not specified, but will
 /// not result in undefined behavior. This could include panics, incorrect
 /// results, aborts, memory leaks, and non-termination.
 ///
 /// ## Min-heap
 ///
-/// Either `std::cmp::Reverse` or a custom `Ord` implementation can be used to
+/// Either [`core::cmp::Reverse`] or a custom [`Ord`] implementation can be used to
 /// make `BinaryHeap` a min-heap. This makes `heap.pop()` return the smallest
 /// value instead of the greatest one.
 ///
 ///
 /// # Time complexity
 ///
-/// | [push] | [pop]     | [peek]/[peek\_mut] |
-/// |--------|-----------|--------------------|
-/// | O(1)~  | *O*(log(*n*)) | *O*(1)               |
+/// | [push]  | [pop]         | [peek]/[peek\_mut] |
+/// |---------|---------------|--------------------|
+/// | *O*(1)~ | *O*(log(*n*)) | *O*(1)             |
 ///
 /// The value for `push` is an expected cost; the method documentation gives a
 /// more detailed analysis.
 ///
+/// [`core::cmp::Reverse`]: core::cmp::Reverse
+/// [`Ord`]: core::cmp::Ord
+/// [`Cell`]: core::cell::Cell
+/// [`RefCell`]: core::cell::RefCell
 /// [push]: BinaryHeap::push
 /// [pop]: BinaryHeap::pop
 /// [peek]: BinaryHeap::peek
@@ -1255,9 +1259,10 @@ impl<T> FusedIterator for Iter<'_, T> {}
 /// An owning iterator over the elements of a `BinaryHeap`.
 ///
 /// This `struct` is created by [`BinaryHeap::into_iter()`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
 ///
 /// [`into_iter`]: BinaryHeap::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone)]
 pub struct IntoIter<T> {
index 501a604e7f76d037fdfbc23c21a22367816491c6..3b7c92818f698facd8ae4aea9d7a12f182f80b6e 100644 (file)
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "BTreeMap")]
+#[rustc_insignificant_dtor]
 pub struct BTreeMap<K, V> {
     root: Option<Root<K, V>>,
     length: usize,
@@ -326,10 +327,12 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// An owning iterator over the entries of a `BTreeMap`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`BTreeMap`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
 ///
 /// [`into_iter`]: IntoIterator::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct IntoIter<K, V> {
     range: LazyLeafRange<marker::Dying, K, V>,
     length: usize,
index c664e201aec544067d825faf5633b9c90a253020..16150ceeb62c116a3a6e701ef74f0338785fe259 100644 (file)
@@ -107,9 +107,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// An owning iterator over the items of a `BTreeSet`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`BTreeSet`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
 ///
 /// [`into_iter`]: BTreeSet#method.into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Debug)]
 pub struct IntoIter<T> {
index 9d45c5082db434cb4a13cf63776f3e529aee1b39..a769c558b4fa90f39e7e8ed344c677ae718edc6b 100644 (file)
 /// let list = LinkedList::from([1, 2, 3]);
 /// ```
 ///
-/// NOTE: It is almost always better to use `Vec` or `VecDeque` because
+/// NOTE: It is almost always better to use [`Vec`] or [`VecDeque`] because
 /// array-based containers are generally faster,
 /// more memory efficient, and make better use of CPU cache.
+///
+/// [`Vec`]: crate::vec::Vec
+/// [`VecDeque`]: super::vec_deque::VecDeque
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "LinkedList")]
+#[rustc_insignificant_dtor]
 pub struct LinkedList<T> {
     head: Option<NonNull<Node<T>>>,
     tail: Option<NonNull<Node<T>>>,
@@ -121,9 +125,10 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 /// An owning iterator over the elements of a `LinkedList`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`LinkedList`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
 ///
 /// [`into_iter`]: LinkedList::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<T> {
@@ -631,6 +636,8 @@ pub fn clear(&mut self) {
     /// Returns `true` if the `LinkedList` contains an element equal to the
     /// given value.
     ///
+    /// This operation should compute in *O*(*n*) time.
+    ///
     /// # Examples
     ///
     /// ```
@@ -656,6 +663,8 @@ pub fn contains(&self, x: &T) -> bool
     /// Provides a reference to the front element, or `None` if the list is
     /// empty.
     ///
+    /// This operation should compute in *O*(1) time.
+    ///
     /// # Examples
     ///
     /// ```
@@ -676,6 +685,8 @@ pub fn front(&self) -> Option<&T> {
     /// Provides a mutable reference to the front element, or `None` if the list
     /// is empty.
     ///
+    /// This operation should compute in *O*(1) time.
+    ///
     /// # Examples
     ///
     /// ```
@@ -702,6 +713,8 @@ pub fn front_mut(&mut self) -> Option<&mut T> {
     /// Provides a reference to the back element, or `None` if the list is
     /// empty.
     ///
+    /// This operation should compute in *O*(1) time.
+    ///
     /// # Examples
     ///
     /// ```
@@ -722,6 +735,8 @@ pub fn back(&self) -> Option<&T> {
     /// Provides a mutable reference to the back element, or `None` if the list
     /// is empty.
     ///
+    /// This operation should compute in *O*(1) time.
+    ///
     /// # Examples
     ///
     /// ```
index 54a157be0b96acdfecab5838f1385f0c1b939db1..55f6138cd0f31407217fd4ef17fb391a5f55c80d 100644 (file)
@@ -8,9 +8,10 @@
 /// An owning iterator over the elements of a `VecDeque`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`VecDeque`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
 ///
 /// [`into_iter`]: VecDeque::into_iter
+/// [`IntoIterator`]: core::iter::IntoIterator
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct IntoIter<
index 10144cc17bf306579ccc1b4e2272fb86b11a644d..cae0f29af8327e4340438426dd50b28b9373542f 100644 (file)
@@ -90,6 +90,7 @@
 /// [`make_contiguous`]: VecDeque::make_contiguous
 #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct VecDeque<
     T,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
index 8c5125d208263ae34003c1284e7f82df66e39920..878d8dc5502df8d552dc4bed84165ad592876d33 100644 (file)
 //! provides some helper methods.
 //!
 //! Additionally, the return value of this function is [`fmt::Result`] which is a
-//! type alias of [`Result`]`<(), `[`std::fmt::Error`]`>`. Formatting implementations
+//! type alias of <code>[Result]<(), [std::fmt::Error]></code>. Formatting implementations
 //! should ensure that they propagate errors from the [`Formatter`] (e.g., when
 //! calling [`write!`]). However, they should never return errors spuriously. That
 //! is, a formatting implementation must and may only return an error if the
 //! it would internally pass around this structure until it has been determined
 //! where output should go to.
 //!
-//! [`fmt::Result`]: Result
-//! [`Result`]: core::result::Result
-//! [`std::fmt::Error`]: Error
-//! [`write!`]: core::write
-//! [`write`]: core::write
-//! [`format!`]: crate::format
-//! [`to_string`]: crate::string::ToString
-//! [`writeln!`]: core::writeln
+//! [`fmt::Result`]: Result "fmt::Result"
+//! [Result]: core::result::Result "std::result::Result"
+//! [std::fmt::Error]: Error "fmt::Error"
+//! [`write`]: write() "fmt::write"
+//! [`to_string`]: crate::string::ToString::to_string "ToString::to_string"
 //! [`write_fmt`]: ../../std/io/trait.Write.html#method.write_fmt
 //! [`std::io::Write`]: ../../std/io/trait.Write.html
-//! [`print!`]: ../../std/macro.print.html
-//! [`println!`]: ../../std/macro.println.html
-//! [`eprint!`]: ../../std/macro.eprint.html
-//! [`eprintln!`]: ../../std/macro.eprintln.html
-//! [`format_args!`]: core::format_args
-//! [`fmt::Arguments`]: Arguments
-//! [`format`]: crate::format
+//! [`print!`]: ../../std/macro.print.html "print!"
+//! [`println!`]: ../../std/macro.println.html "println!"
+//! [`eprint!`]: ../../std/macro.eprint.html "eprint!"
+//! [`eprintln!`]: ../../std/macro.eprintln.html "eprintln!"
+//! [`fmt::Arguments`]: Arguments "fmt::Arguments"
+//! [`format`]: format() "fmt::format"
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index 0814652a5d47d595822ed1a7492d2ad81f97b60c..81e97805a72142a65408b0ebba48e6ad3214bc75 100644 (file)
@@ -305,6 +305,7 @@ struct RcBox<T: ?Sized> {
 /// [get_mut]: Rc::get_mut
 #[cfg_attr(not(test), rustc_diagnostic_item = "Rc")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct Rc<T: ?Sized> {
     ptr: NonNull<RcBox<T>>,
     phantom: PhantomData<RcBox<T>>,
@@ -781,9 +782,7 @@ impl<T: ?Sized> Rc<T> {
     /// Consumes the `Rc`, returning the wrapped pointer.
     ///
     /// To avoid a memory leak the pointer must be converted back to an `Rc` using
-    /// [`Rc::from_raw`][from_raw].
-    ///
-    /// [from_raw]: Rc::from_raw
+    /// [`Rc::from_raw`].
     ///
     /// # Examples
     ///
@@ -834,7 +833,7 @@ pub fn as_ptr(this: &Self) -> *const T {
     /// and alignment as `T`. This is trivially true if `U` is `T`.
     /// Note that if `U` is not `T` but has the same size and alignment, this is
     /// basically like transmuting references of different types. See
-    /// [`mem::transmute`][transmute] for more information on what
+    /// [`mem::transmute`] for more information on what
     /// restrictions apply in this case.
     ///
     /// The user of `from_raw` has to make sure a specific value of `T` is only
@@ -844,7 +843,6 @@ pub fn as_ptr(this: &Self) -> *const T {
     /// even if the returned `Rc<T>` is never accessed.
     ///
     /// [into_raw]: Rc::into_raw
-    /// [transmute]: core::mem::transmute
     ///
     /// # Examples
     ///
@@ -1086,8 +1084,6 @@ pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
     /// assert!(Rc::ptr_eq(&five, &same_five));
     /// assert!(!Rc::ptr_eq(&five, &other_five));
     /// ```
-    ///
-    /// [`ptr::eq`]: core::ptr::eq
     pub fn ptr_eq(this: &Self, other: &Self) -> bool {
         this.ptr.as_ptr() == other.ptr.as_ptr()
     }
@@ -1993,7 +1989,7 @@ fn to_rc_slice(self) -> Rc<[T]> {
 
 /// `Weak` is a version of [`Rc`] that holds a non-owning reference to the
 /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
-/// pointer, which returns an [`Option`]`<`[`Rc`]`<T>>`.
+/// pointer, which returns an <code>[Option]<[Rc]\<T>></code>.
 ///
 /// Since a `Weak` reference does not count towards ownership, it will not
 /// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no
@@ -2090,7 +2086,7 @@ impl<T: ?Sized> Weak<T> {
     /// // assert_eq!("hello", unsafe { &*weak.as_ptr() });
     /// ```
     ///
-    /// [`null`]: core::ptr::null
+    /// [`null`]: ptr::null
     #[stable(feature = "rc_as_ptr", since = "1.45.0")]
     pub fn as_ptr(&self) -> *const T {
         let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
@@ -2317,8 +2313,6 @@ fn inner(&self) -> Option<WeakInner<'_>> {
     /// let third = Rc::downgrade(&third_rc);
     /// assert!(!first.ptr_eq(&third));
     /// ```
-    ///
-    /// [`ptr::eq`]: core::ptr::eq
     #[inline]
     #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
@@ -2400,7 +2394,6 @@ impl<T> Default for Weak<T> {
     /// Constructs a new `Weak<T>`, without allocating any memory.
     /// Calling [`upgrade`] on the return value always gives [`None`].
     ///
-    /// [`None`]: Option
     /// [`upgrade`]: Weak::upgrade
     ///
     /// # Examples
index 6568d9f9907b998156293c7357b19f3eee447c87..57c38f2c0a9c5ef0eb153ce32b48ae94c67b95cb 100644 (file)
@@ -79,7 +79,7 @@
 ///
 /// # Examples
 ///
-/// You can create a `String` from [a literal string][`str`] with [`String::from`]:
+/// You can create a `String` from [a literal string][`&str`] with [`String::from`]:
 ///
 /// [`String::from`]: From::from
 ///
 /// println!("The first letter of s is {}", s[0]); // ERROR!!!
 /// ```
 ///
-/// [`OsString`]: ../../std/ffi/struct.OsString.html
+/// [`OsString`]: ../../std/ffi/struct.OsString.html "ffi::OsString"
 ///
 /// Indexing is intended to be a constant-time operation, but UTF-8 encoding
 /// does not allow us to do this. Furthermore, it's not clear what sort of
 ///
 /// # Deref
 ///
-/// `String`s implement [`Deref`]`<Target=str>`, and so inherit all of [`str`]'s
+/// `String` implements <code>[Deref]<Target = [str]></code>, and so inherits all of [`str`]'s
 /// methods. In addition, this means that you can pass a `String` to a
 /// function which takes a [`&str`] by using an ampersand (`&`):
 ///
 /// to explicitly extract the string slice containing the string. The second
 /// way changes `example_func(&example_string);` to
 /// `example_func(&*example_string);`. In this case we are dereferencing a
-/// `String` to a [`str`][`&str`], then referencing the [`str`][`&str`] back to
+/// `String` to a [`str`], then referencing the [`str`] back to
 /// [`&str`]. The second way is more idiomatic, however both work to do the
 /// conversion explicitly rather than relying on the implicit conversion.
 ///
 ///
 /// Here, there's no need to allocate more memory inside the loop.
 ///
-/// [`str`]: prim@str
-/// [`&str`]: prim@str
-/// [`Deref`]: core::ops::Deref
+/// [str]: prim@str "str"
+/// [`str`]: prim@str "str"
+/// [`&str`]: prim@str "&str"
+/// [Deref]: core::ops::Deref "ops::Deref"
+/// [`Deref`]: core::ops::Deref "ops::Deref"
 /// [`as_str()`]: String::as_str
 #[derive(PartialOrd, Eq, Ord)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "string_type")]
@@ -308,10 +310,10 @@ pub struct String {
 /// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error`
 /// through the [`utf8_error`] method.
 ///
-/// [`Utf8Error`]: core::str::Utf8Error
-/// [`std::str`]: core::str
-/// [`&str`]: prim@str
-/// [`utf8_error`]: Self::utf8_error
+/// [`Utf8Error`]: str::Utf8Error "std::str::Utf8Error"
+/// [`std::str`]: core::str "std::str"
+/// [`&str`]: prim@str "&str"
+/// [`utf8_error`]: FromUtf8Error::utf8_error
 ///
 /// # Examples
 ///
@@ -487,8 +489,8 @@ pub fn from_str(_: &str) -> String {
     /// with this error.
     ///
     /// [`from_utf8_unchecked`]: String::from_utf8_unchecked
-    /// [`Vec<u8>`]: crate::vec::Vec
-    /// [`&str`]: prim@str
+    /// [`Vec<u8>`]: crate::vec::Vec "Vec"
+    /// [`&str`]: prim@str "&str"
     /// [`into_bytes`]: String::into_bytes
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -524,7 +526,7 @@ pub fn from_utf8(vec: Vec<u8>) -> Result<String, FromUtf8Error> {
     /// it's already valid UTF-8, we don't need a new allocation. This return
     /// type allows us to handle both cases.
     ///
-    /// [`Cow<'a, str>`]: crate::borrow::Cow
+    /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow"
     ///
     /// # Examples
     ///
@@ -625,7 +627,7 @@ pub fn from_utf16(v: &[u16]) -> Result<String, FromUtf16Error> {
     /// conversion requires a memory allocation.
     ///
     /// [`from_utf8_lossy`]: String::from_utf8_lossy
-    /// [`Cow<'a, str>`]: crate::borrow::Cow
+    /// [`Cow<'a, str>`]: crate::borrow::Cow "borrow::Cow"
     /// [U+FFFD]: core::char::REPLACEMENT_CHARACTER
     ///
     /// # Examples
@@ -1721,11 +1723,11 @@ pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
         unsafe { self.as_mut_vec() }.splice((start, end), replace_with.bytes());
     }
 
-    /// Converts this `String` into a [`Box`]`<`[`str`]`>`.
+    /// Converts this `String` into a <code>[Box]<[str]></code>.
     ///
     /// This will drop any excess capacity.
     ///
-    /// [`str`]: prim@str
+    /// [str]: prim@str "str"
     ///
     /// # Examples
     ///
@@ -1795,8 +1797,8 @@ pub fn into_bytes(self) -> Vec<u8> {
     /// an analogue to `FromUtf8Error`. See its documentation for more details
     /// on using it.
     ///
-    /// [`std::str`]: core::str
-    /// [`&str`]: prim@str
+    /// [`std::str`]: core::str "std::str"
+    /// [`&str`]: prim@str "&str"
     ///
     /// # Examples
     ///
@@ -2319,7 +2321,7 @@ fn deref_mut(&mut self) -> &mut str {
 ///
 /// This alias exists for backwards compatibility, and may be eventually deprecated.
 ///
-/// [`Infallible`]: core::convert::Infallible
+/// [`Infallible`]: core::convert::Infallible "convert::Infallible"
 #[stable(feature = "str_parse_error", since = "1.5.0")]
 pub type ParseError = core::convert::Infallible;
 
@@ -2606,7 +2608,7 @@ impl<'a> From<&'a str> for Cow<'a, str> {
     /// assert_eq!(Cow::from("eggplant"), Cow::Borrowed("eggplant"));
     /// ```
     ///
-    /// [`Borrowed`]: crate::borrow::Cow::Borrowed
+    /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed"
     #[inline]
     fn from(s: &'a str) -> Cow<'a, str> {
         Cow::Borrowed(s)
@@ -2629,7 +2631,7 @@ impl<'a> From<String> for Cow<'a, str> {
     /// assert_eq!(Cow::from(s), Cow::<'static, str>::Owned(s2));
     /// ```
     ///
-    /// [`Owned`]: crate::borrow::Cow::Owned
+    /// [`Owned`]: crate::borrow::Cow::Owned "borrow::Cow::Owned"
     #[inline]
     fn from(s: String) -> Cow<'a, str> {
         Cow::Owned(s)
@@ -2651,7 +2653,7 @@ impl<'a> From<&'a String> for Cow<'a, str> {
     /// assert_eq!(Cow::from(&s), Cow::Borrowed("eggplant"));
     /// ```
     ///
-    /// [`Borrowed`]: crate::borrow::Cow::Borrowed
+    /// [`Borrowed`]: crate::borrow::Cow::Borrowed "borrow::Cow::Borrowed"
     #[inline]
     fn from(s: &'a String) -> Cow<'a, str> {
         Cow::Borrowed(s.as_str())
index a066e0b49e25c4505381f7d83e037bd8e24e4d86..6e8da849e64cd464baf02714dc9d9f95a9fbaf6f 100644 (file)
@@ -99,8 +99,8 @@ macro_rules! acquire {
 /// first: after all, isn't the point of `Arc<T>` thread safety? The key is
 /// this: `Arc<T>` 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<T>`]`>`. [`RefCell<T>`] isn't [`Sync`], and if `Arc<T>` was always
-/// [`Send`], `Arc<`[`RefCell<T>`]`>` would be as well. But then we'd have a problem:
+/// <code>Arc<[RefCell\<T>]></code>. [`RefCell<T>`] isn't [`Sync`], and if `Arc<T>` was always
+/// [`Send`], <code>Arc<[RefCell\<T>]></code> would be as well. But then we'd have a problem:
 /// [`RefCell<T>`] is not thread safe; it keeps track of the borrowing count using
 /// non-atomic operations.
 ///
@@ -176,6 +176,7 @@ macro_rules! acquire {
 /// [deref]: core::ops::Deref
 /// [downgrade]: Arc::downgrade
 /// [upgrade]: Weak::upgrade
+/// [RefCell\<T>]: core::cell::RefCell
 /// [`RefCell<T>`]: core::cell::RefCell
 /// [`std::sync`]: ../../std/sync/index.html
 /// [`Arc::clone(&from)`]: Arc::clone
@@ -206,7 +207,7 @@ macro_rules! acquire {
 ///
 /// Sharing a mutable [`AtomicUsize`]:
 ///
-/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize
+/// [`AtomicUsize`]: core::sync::atomic::AtomicUsize "sync::atomic::AtomicUsize"
 ///
 /// ```no_run
 /// use std::sync::Arc;
@@ -262,7 +263,7 @@ unsafe fn from_ptr(ptr: *mut ArcInner<T>) -> Self {
 
 /// `Weak` is a version of [`Arc`] that holds a non-owning reference to the
 /// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
-/// pointer, which returns an [`Option`]`<`[`Arc`]`<T>>`.
+/// pointer, which returns an <code>[Option]<[Arc]\<T>></code>.
 ///
 /// Since a `Weak` reference does not count towards ownership, it will not
 /// prevent the value stored in the allocation from being dropped, and `Weak` itself makes no
@@ -476,7 +477,7 @@ pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> {
     /// assert_eq!(*zero, 0)
     /// ```
     ///
-    /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
+    /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> {
@@ -684,7 +685,7 @@ pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
     /// assert_eq!(*values, [0, 0, 0])
     /// ```
     ///
-    /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed
+    /// [zeroed]: mem::MaybeUninit::zeroed
     #[cfg(not(no_global_oom_handling))]
     #[unstable(feature = "new_uninit", issue = "63291")]
     pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> {
@@ -712,7 +713,7 @@ impl<T> Arc<mem::MaybeUninit<T>> {
     /// Calling this when the content is not yet fully initialized
     /// causes immediate undefined behavior.
     ///
-    /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
+    /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init
     ///
     /// # Examples
     ///
@@ -751,7 +752,7 @@ impl<T> Arc<[mem::MaybeUninit<T>]> {
     /// Calling this when the content is not yet fully initialized
     /// causes immediate undefined behavior.
     ///
-    /// [`MaybeUninit::assume_init`]: ../../std/mem/union.MaybeUninit.html#method.assume_init
+    /// [`MaybeUninit::assume_init`]: mem::MaybeUninit::assume_init
     ///
     /// # Examples
     ///
@@ -1086,7 +1087,7 @@ unsafe fn drop_slow(&mut self) {
     /// assert!(!Arc::ptr_eq(&five, &other_five));
     /// ```
     ///
-    /// [`ptr::eq`]: core::ptr::eq
+    /// [`ptr::eq`]: core::ptr::eq "ptr::eq"
     pub fn ptr_eq(this: &Self, other: &Self) -> bool {
         this.ptr.as_ptr() == other.ptr.as_ptr()
     }
@@ -1714,7 +1715,7 @@ impl<T: ?Sized> Weak<T> {
     /// // assert_eq!("hello", unsafe { &*weak.as_ptr() });
     /// ```
     ///
-    /// [`null`]: core::ptr::null
+    /// [`null`]: core::ptr::null "ptr::null"
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub fn as_ptr(&self) -> *const T {
         let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
@@ -1806,7 +1807,6 @@ pub fn into_raw(self) -> *const T {
     /// [`new`]: Weak::new
     /// [`into_raw`]: Weak::into_raw
     /// [`upgrade`]: Weak::upgrade
-    /// [`forget`]: std::mem::forget
     #[stable(feature = "weak_into_raw", since = "1.45.0")]
     pub unsafe fn from_raw(ptr: *const T) -> Self {
         // See Weak::as_ptr for context on how the input pointer is derived.
@@ -1982,7 +1982,7 @@ fn inner(&self) -> Option<WeakInner<'_>> {
     /// assert!(!first.ptr_eq(&third));
     /// ```
     ///
-    /// [`ptr::eq`]: core::ptr::eq
+    /// [`ptr::eq`]: core::ptr::eq "ptr::eq"
     #[inline]
     #[stable(feature = "weak_ptr_eq", since = "1.39.0")]
     pub fn ptr_eq(&self, other: &Self) -> bool {
index 0bd152f17a670e2afa3b4180b812400e1c4865ee..4cb0a4b10bd0cdde6f10816f4af69a19fde12db0 100644 (file)
@@ -22,6 +22,7 @@
 /// let iter: std::vec::IntoIter<_> = v.into_iter();
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct IntoIter<
     T,
     #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global,
index 2f6887229e7a30e744a0a31e32c5a13d2a472b35..c37ec37556157648b9986598487b396c1b709130 100644 (file)
@@ -1,8 +1,8 @@
 //! A contiguous growable array type with heap-allocated contents, written
 //! `Vec<T>`.
 //!
-//! Vectors have `O(1)` indexing, amortized `O(1)` push (to the end) and
-//! `O(1)` pop (from the end).
+//! Vectors have *O*(1) indexing, amortized *O*(1) push (to the end) and
+//! *O*(1) pop (from the end).
 //!
 //! Vectors ensure they never allocate more than `isize::MAX` bytes.
 //!
 /// on an empty Vec, it will not allocate memory. Similarly, if you store zero-sized
 /// types inside a `Vec`, it will not allocate space for them. *Note that in this case
 /// the `Vec` might not report a [`capacity`] of 0*. `Vec` will allocate if and only
-/// if [`mem::size_of::<T>`]`() * capacity() > 0`. In general, `Vec`'s allocation
-/// details are very subtle &mdash; if you intend to allocate memory using a `Vec`
+/// if <code>[mem::size_of::\<T>]\() * [capacity]\() > 0</code>. In general, `Vec`'s allocation
+/// details are very subtle --- if you intend to allocate memory using a `Vec`
 /// and use it for something else (either to pass to unsafe code, or to build your
 /// own memory-backed collection), be sure to deallocate this memory by using
 /// `from_raw_parts` to recover the `Vec` and then dropping it.
 /// If a `Vec` *has* allocated memory, then the memory it points to is on the heap
 /// (as defined by the allocator Rust is configured to use by default), and its
 /// pointer points to [`len`] initialized, contiguous elements in order (what
-/// you would see if you coerced it to a slice), followed by [`capacity`]` -
-/// `[`len`] logically uninitialized, contiguous elements.
+/// you would see if you coerced it to a slice), followed by <code>[capacity] - [len]</code>
+/// logically uninitialized, contiguous elements.
 ///
 /// A vector containing the elements `'a'` and `'b'` with capacity 4 can be
 /// visualized as below. The top part is the `Vec` struct, it contains a
 ///
 /// [`push`] and [`insert`] will never (re)allocate if the reported capacity is
 /// sufficient. [`push`] and [`insert`] *will* (re)allocate if
-/// [`len`]` == `[`capacity`]. That is, the reported capacity is completely
+/// <code>[len] == [capacity]</code>. That is, the reported capacity is completely
 /// accurate, and can be relied on. It can even be used to manually free the memory
 /// allocated by a `Vec` if desired. Bulk insertion methods *may* reallocate, even
 /// when not necessary.
 ///
 /// `vec![x; n]`, `vec![a, b, c, d]`, and
 /// [`Vec::with_capacity(n)`][`Vec::with_capacity`], will all produce a `Vec`
-/// with exactly the requested capacity. If [`len`]` == `[`capacity`],
+/// with exactly the requested capacity. If <code>[len] == [capacity]</code>,
 /// (as is the case for the [`vec!`] macro), then a `Vec<T>` can be converted to
 /// and from a [`Box<[T]>`][owned slice] without reallocating or moving the elements.
 ///
 /// [`&str`]: type@str
 /// [`shrink_to_fit`]: Vec::shrink_to_fit
 /// [`shrink_to`]: Vec::shrink_to
+/// [capacity]: Vec::capacity
 /// [`capacity`]: Vec::capacity
-/// [`mem::size_of::<T>`]: core::mem::size_of
+/// [mem::size_of::\<T>]: core::mem::size_of
+/// [len]: Vec::len
 /// [`len`]: Vec::len
 /// [`push`]: Vec::push
 /// [`insert`]: Vec::insert
 /// [owned slice]: Box
 #[stable(feature = "rust1", since = "1.0.0")]
 #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")]
+#[rustc_insignificant_dtor]
 pub struct Vec<T, #[unstable(feature = "allocator_api", issue = "32838")] A: Allocator = Global> {
     buf: RawVec<T, A>,
     len: usize,
@@ -1268,7 +1271,7 @@ pub unsafe fn set_len(&mut self, new_len: usize) {
     ///
     /// The removed element is replaced by the last element of the vector.
     ///
-    /// This does not preserve ordering, but is O(1).
+    /// This does not preserve ordering, but is *O*(1).
     ///
     /// # Panics
     ///
index ecdbf09881985a9ee7e4ab997c3750994a6142cd..822747dd0e824ff81736c980325824d278b146ce 100644 (file)
@@ -10,6 +10,7 @@
 
 /// A by-value [array] iterator.
 #[stable(feature = "array_value_iter", since = "1.51.0")]
+#[rustc_insignificant_dtor]
 pub struct IntoIter<T, const N: usize> {
     /// This is the array we are iterating over.
     ///
index d6f9edaa046c69e5922678b94d67a68f52373fe8..39c0b1b522c11fbe79fc33b296387a3de135b525 100644 (file)
@@ -39,7 +39,7 @@
 //! ```
 //!
 //! An iterator has a method, [`next`], which when called, returns an
-//! [`Option`]`<Item>`. [`next`] will return [`Some(Item)`] as long as there
+//! <code>[Option]\<Item></code>. Calling [`next`] will return [`Some(Item)`] as long as there
 //! are elements, and once they've all been exhausted, will return `None` to
 //! indicate that iteration is finished. Individual iterators may choose to
 //! resume iteration, and so calling [`next`] again may or may not eventually
index f884340f4e0bd02710d3d96684e8439ac34cacb9..f2336fb2865b09edba5660d34399d6c3150a2926 100644 (file)
@@ -96,7 +96,7 @@ pub trait Iterator {
     /// Specifically, `size_hint()` returns a tuple where the first element
     /// is the lower bound, and the second element is the upper bound.
     ///
-    /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`.
+    /// The second half of the tuple that is returned is an <code>[Option]<[usize]></code>.
     /// A [`None`] here means that either there is no known upper bound, or the
     /// upper bound is larger than [`usize`].
     ///
@@ -115,11 +115,9 @@ pub trait Iterator {
     /// That said, the implementation should provide a correct estimation,
     /// because otherwise it would be a violation of the trait's protocol.
     ///
-    /// The default implementation returns `(0, `[`None`]`)` which is correct for any
+    /// The default implementation returns <code>(0, [None])</code> which is correct for any
     /// iterator.
     ///
-    /// [`usize`]: type@usize
-    ///
     /// # Examples
     ///
     /// Basic usage:
@@ -864,7 +862,6 @@ fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
     /// The returned iterator might panic if the to-be-returned index would
     /// overflow a [`usize`].
     ///
-    /// [`usize`]: type@usize
     /// [`zip`]: Iterator::zip
     ///
     /// # Examples
@@ -1798,10 +1795,11 @@ fn extend<'a, T, B: Extend<T>>(
     /// The relative order of partitioned items is not maintained.
     ///
     /// # Current implementation
+    ///
     /// Current algorithms tries finding the first element for which the predicate evaluates
     /// to false, and the last element for which it evaluates to true and repeatedly swaps them.
     ///
-    /// Time Complexity: *O*(*N*)
+    /// Time complexity: *O*(*n*)
     ///
     /// See also [`is_partitioned()`] and [`partition()`].
     ///
index 907726f0c345c8a3736cbae493697e861aba609c..94d892dd787a6874579ae7db1e405a5a1efbfcc6 100644 (file)
@@ -47,9 +47,9 @@
 //!
 //! Rust's pointer types must always point to a valid location; there are
 //! no "null" references. Instead, Rust has *optional* pointers, like
-//! the optional owned box, [`Option`]`<`[`Box<T>`]`>`.
+//! the optional owned box, <code>[Option]<[Box\<T>]></code>.
 //!
-//! [`Box<T>`]: ../../std/boxed/struct.Box.html
+//! [Box\<T>]: ../../std/boxed/struct.Box.html
 //!
 //! The following example uses [`Option`] to create an optional box of
 //! [`i32`]. Notice that in order to use the inner [`i32`] value, the
 //!
 //! ## Adapters for working with references
 //!
-//! * [`as_ref`] converts from `&Option<T>` to `Option<&T>`
-//! * [`as_mut`] converts from `&mut Option<T>` to `Option<&mut T>`
-//! * [`as_deref`] converts from `&Option<T>` to `Option<&T::Target>`
-//! * [`as_deref_mut`] converts from `&mut Option<T>` to
-//!   `Option<&mut T::Target>`
-//! * [`as_pin_ref`] converts from [`Pin`]`<&Option<T>>` to
-//!   `Option<`[`Pin`]`<&T>>`
-//! * [`as_pin_mut`] converts from [`Pin`]`<&mut Option<T>>` to
-//!   `Option<`[`Pin`]`<&mut T>>`
-//!
+//! * [`as_ref`] converts from <code>[&][][Option]\<T></code> to <code>[Option]<[&]T></code>
+//! * [`as_mut`] converts from <code>[&mut] [Option]\<T></code> to <code>[Option]<[&mut] T></code>
+//! * [`as_deref`] converts from <code>[&][][Option]\<T></code> to
+//!   <code>[Option]<[&]T::[Target]></code>
+//! * [`as_deref_mut`] converts from <code>[&mut] [Option]\<T></code> to
+//!   <code>[Option]<[&mut] T::[Target]></code>
+//! * [`as_pin_ref`] converts from <code>[Pin]<[&][][Option]\<T>></code> to
+//!   <code>[Option]<[Pin]<[&]T>></code>
+//! * [`as_pin_mut`] converts from <code>[Pin]<[&mut] [Option]\<T>></code> to
+//!   <code>[Option]<[Pin]<[&mut] T>></code>
+//!
+//! [&]: reference "shared reference"
+//! [&mut]: reference "mutable reference"
+//! [Target]: Deref::Target "ops::Deref::Target"
 //! [`as_deref`]: Option::as_deref
 //! [`as_deref_mut`]: Option::as_deref_mut
 //! [`as_mut`]: Option::as_mut
@@ -603,13 +607,13 @@ pub fn contains<U>(&self, x: &U) -> bool
     ///
     /// # Examples
     ///
-    /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original.
-    /// The [`map`] method takes the `self` argument by value, consuming the original,
+    /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, preserving
+    /// the original. The [`map`] method takes the `self` argument by value, consuming the original,
     /// so this technique uses `as_ref` to first take an `Option` to a reference
     /// to the value inside the original.
     ///
     /// [`map`]: Option::map
-    /// [`String`]: ../../std/string/struct.String.html
+    /// [String]: ../../std/string/struct.String.html "String"
     ///
     /// ```
     /// let text: Option<String> = Some("Hello, world!".to_string());
@@ -649,7 +653,9 @@ pub fn as_mut(&mut self) -> Option<&mut T> {
         }
     }
 
-    /// Converts from [`Pin`]`<&Option<T>>` to `Option<`[`Pin`]`<&T>>`.
+    /// Converts from <code>[Pin]<[&]Option\<T>></code> to <code>Option<[Pin]<[&]T>></code>.
+    ///
+    /// [&]: reference "shared reference"
     #[inline]
     #[stable(feature = "pin", since = "1.33.0")]
     pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
@@ -658,7 +664,9 @@ pub fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
         unsafe { Pin::get_ref(self).as_ref().map(|x| Pin::new_unchecked(x)) }
     }
 
-    /// Converts from [`Pin`]`<&mut Option<T>>` to `Option<`[`Pin`]`<&mut T>>`.
+    /// Converts from <code>[Pin]<[&mut] Option\<T>></code> to <code>Option<[Pin]<[&mut] T>></code>.
+    ///
+    /// [&mut]: reference "mutable reference"
     #[inline]
     #[stable(feature = "pin", since = "1.33.0")]
     pub fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
@@ -819,9 +827,10 @@ pub unsafe fn unwrap_unchecked(self) -> T {
     ///
     /// # Examples
     ///
-    /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, consuming the original:
+    /// Converts an <code>Option<[String]></code> into an <code>Option<[usize]></code>, consuming
+    /// the original:
     ///
-    /// [`String`]: ../../std/string/struct.String.html
+    /// [String]: ../../std/string/struct.String.html "String"
     /// ```
     /// let maybe_some_string = Some(String::from("Hello, World!"));
     /// // `Option::map` takes self *by value*, consuming `maybe_some_string`
@@ -1581,9 +1590,9 @@ pub fn as_deref_mut(&mut self) -> Option<&mut T::Target> {
 impl<T, E> Option<Result<T, E>> {
     /// Transposes an `Option` of a [`Result`] into a [`Result`] of an `Option`.
     ///
-    /// [`None`] will be mapped to [`Ok`]`(`[`None`]`)`.
-    /// [`Some`]`(`[`Ok`]`(_))` and [`Some`]`(`[`Err`]`(_))` will be mapped to
-    /// [`Ok`]`(`[`Some`]`(_))` and [`Err`]`(_)`.
+    /// [`None`] will be mapped to <code>[Ok]\([None])</code>.
+    /// <code>[Some]\([Ok]\(\_))</code> and <code>[Some]\([Err]\(\_))</code> will be mapped to
+    /// <code>[Ok]\([Some]\(\_))</code> and <code>[Err]\(\_)</code>.
     ///
     /// # Examples
     ///
@@ -1721,13 +1730,13 @@ impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
     ///
     /// # Examples
     ///
-    /// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original.
-    /// The [`map`] method takes the `self` argument by value, consuming the original,
-    /// so this technique uses `from` to first take an `Option` to a reference
+    /// Converts an <code>[Option]<[String]></code> into an <code>[Option]<[usize]></code>, preserving
+    /// the original. The [`map`] method takes the `self` argument by value, consuming the original,
+    /// so this technique uses `from` to first take an [`Option`] to a reference
     /// to the value inside the original.
     ///
     /// [`map`]: Option::map
-    /// [`String`]: ../../std/string/struct.String.html
+    /// [String]: ../../std/string/struct.String.html "String"
     ///
     /// ```
     /// let s: Option<String> = Some(String::from("Hello, Rustaceans!"));
index 6a1a84bafa330acd0d0aec5d4eb13c6f1df7e623..8b645792169155aba160c46382db7721b776265c 100644 (file)
 //! [Vec::push]: ../../std/vec/struct.Vec.html#method.push "Vec::push"
 //! [Rc]: ../../std/rc/struct.Rc.html "rc::Rc"
 //! [RefCell]: crate::cell::RefCell "cell::RefCell"
-//! [`drop`]: Drop::drop "Drop::drop"
+//! [`drop`]: Drop::drop
 //! [VecDeque]: ../../std/collections/struct.VecDeque.html "collections::VecDeque"
 //! [`ptr::write`]: crate::ptr::write "ptr::write"
 //! [`Future`]: crate::future::Future "future::Future"
 //! [drop-impl]: #drop-implementation
 //! [drop-guarantee]: #drop-guarantee
 //! [`poll`]: crate::future::Future::poll "future::Future::poll"
-//! [&]: ../../std/primitive.reference.html "shared reference"
-//! [&mut]: ../../std/primitive.reference.html "mutable reference"
+//! [&]: reference "shared reference"
+//! [&mut]: reference "mutable reference"
 //! [`unsafe`]: ../../std/keyword.unsafe.html "keyword unsafe"
 
 #![stable(feature = "pin", since = "1.33.0")]
index 092e6544342b7f4e2105ce21fd9b81d25d29bede..4a300f857e9ed9dd4623ca07c983dc6f0f5b6cb5 100644 (file)
@@ -88,7 +88,7 @@
 //! ```
 //!
 //! *Note: The actual definition of [`Write`] uses [`io::Result`], which
-//! is just a synonym for [`Result`]`<T, `[`io::Error`]`>`.*
+//! is just a synonym for <code>[Result]<T, [io::Error]></code>.*
 //!
 //! This method doesn't produce a value, but the write may
 //! fail. It's crucial to handle the error case, and *not* write
 //! early return of [`Err`] that it provides.
 //!
 //! [`expect`]: Result::expect
-//! [`Write`]: ../../std/io/trait.Write.html
-//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all
-//! [`io::Result`]: ../../std/io/type.Result.html
+//! [`Write`]: ../../std/io/trait.Write.html "io::Write"
+//! [`write_all`]: ../../std/io/trait.Write.html#method.write_all "io::Write::write_all"
+//! [`io::Result`]: ../../std/io/type.Result.html "io::Result"
 //! [`?`]: crate::ops::Try
 //! [`Ok(T)`]: Ok
 //! [`Err(E)`]: Err
-//! [`io::Error`]: ../../std/io/struct.Error.html
+//! [io::Error]: ../../std/io/struct.Error.html "io::Error"
 //!
 //! # Method overview
 //!
index e37902dae1f2d24de0e5f0752ab2f7b7a5d723f0..d102619b8e5ec135f09090ae7b1e08e5413c3a87 100644 (file)
@@ -52,7 +52,7 @@ pub trait Stream {
     /// Specifically, `size_hint()` returns a tuple where the first element
     /// is the lower bound, and the second element is the upper bound.
     ///
-    /// The second half of the tuple that is returned is an [`Option`]`<`[`usize`]`>`.
+    /// The second half of the tuple that is returned is an <code>[Option]<[usize]></code>.
     /// A [`None`] here means that either there is no known upper bound, or the
     /// upper bound is larger than [`usize`].
     ///
@@ -71,7 +71,7 @@ pub trait Stream {
     /// That said, the implementation should provide a correct estimation,
     /// because otherwise it would be a violation of the trait's protocol.
     ///
-    /// The default implementation returns `(0, `[`None`]`)` which is correct for any
+    /// The default implementation returns <code>(0, [None])</code> which is correct for any
     /// stream.
     #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
index 250704609963217e62828be3ae43c2a1f7eaca10..57416aeb7018fe5712b958018a17cf32a0d0fca4 100644 (file)
@@ -30,9 +30,10 @@ impl<T> Poll<T> {
     ///
     /// # Examples
     ///
-    /// Converts a `Poll<`[`String`]`>` into an `Poll<`[`usize`]`>`, consuming the original:
+    /// Converts a <code>Poll<[String]></code> into a <code>Poll<[usize]></code>, consuming
+    /// the original:
     ///
-    /// [`String`]: ../../std/string/struct.String.html
+    /// [String]: ../../std/string/struct.String.html "String"
     /// ```
     /// # use core::task::Poll;
     /// let poll_some_string = Poll::Ready(String::from("Hello, World!"));
index 4580f9a7758f33351da3a1ca24706121c13982e1..ac75ce7f2211046ac7a17f3d25b170a9dcbb5b46 100644 (file)
@@ -44,6 +44,7 @@ unsafe fn abort() -> ! {
                 libc::abort();
             }
         } else if #[cfg(any(target_os = "hermit",
+                            target_os = "solid_asp3",
                             all(target_vendor = "fortanix", target_env = "sgx")
         ))] {
             unsafe fn abort() -> ! {
index ac7d8c18e3e029282473c1f695ea1ef1d993eb2c..b5d0ca2572c93adc9841a72943b788d67e190b5e 100644 (file)
@@ -45,6 +45,7 @@
     } else if #[cfg(any(
         all(target_family = "windows", target_env = "gnu"),
         target_os = "psp",
+        target_os = "solid_asp3",
         all(target_family = "unix", not(target_os = "espidf")),
         all(target_vendor = "fortanix", target_env = "sgx"),
     ))] {
index 1b051b0d0f6e5079802b5bf394152ab5284901b5..2b77dc54ab35cd3ccece5d7f37d2e85632c92177 100644 (file)
@@ -72,6 +72,7 @@ panic_immediate_abort = ["core/panic_immediate_abort"]
 # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
 std_detect_file_io = ["std_detect/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std_detect/std_detect_dlsym_getauxval"]
+std_detect_env_override = ["std_detect/std_detect_env_override"]
 
 [package.metadata.fortanix-sgx]
 # Maximum possible number of threads when testing
index 726157c1f1a41a9e1dd301264f825dfaeadba2c4..cc7184d57f178a26a94f1139d72c21cad54c6015 100644 (file)
@@ -27,6 +27,7 @@ fn main() {
         || target.contains("wasm32")
         || target.contains("asmjs")
         || target.contains("espidf")
+        || target.contains("solid")
     {
         // These platforms don't have any special requirements.
     } else {
index 36077a42b48ac9a49d8f5acd30e0b4c3ef5bcb46..f96906be540f99e0abd30348f9835f46f619d10e 100644 (file)
 
 #[cfg_attr(not(test), rustc_diagnostic_item = "hashmap_type")]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_insignificant_dtor]
 pub struct HashMap<K, V, S = RandomState> {
     base: base::HashMap<K, V, S>,
 }
@@ -1257,9 +1258,10 @@ pub(super) fn iter(&self) -> Iter<'_, K, V> {
 /// An owning iterator over the entries of a `HashMap`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`HashMap`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
 ///
 /// [`into_iter`]: IntoIterator::into_iter
+/// [`IntoIterator`]: crate::iter::IntoIterator
 ///
 /// # Example
 ///
index 3b61acd122e2e9ddfd91f74626b84ae5a17438d7..941981e3b00f12d55a5450517f5a3197162b67df 100644 (file)
@@ -1237,9 +1237,10 @@ pub struct Iter<'a, K: 'a> {
 /// An owning iterator over the items of a `HashSet`.
 ///
 /// This `struct` is created by the [`into_iter`] method on [`HashSet`]
-/// (provided by the `IntoIterator` trait). See its documentation for more.
+/// (provided by the [`IntoIterator`] trait). See its documentation for more.
 ///
 /// [`into_iter`]: IntoIterator::into_iter
+/// [`IntoIterator`]: crate::iter::IntoIterator
 ///
 /// # Examples
 ///
index 71645aadb1d88b717eb03e341be65ef07a24982b..6ca0525cdbe328de45402ce63fd8c909b19e233b 100644 (file)
 //!
 //! ## Sequences
 //!
-//! |                | get(i)         | insert(i)       | remove(i)      | append | split_off(i)   |
-//! |----------------|----------------|-----------------|----------------|--------|----------------|
-//! | [`Vec`]        | O(1)           | O(n-i)*         | O(n-i)         | O(m)*  | O(n-i)         |
-//! | [`VecDeque`]   | O(1)           | O(min(i, n-i))* | O(min(i, n-i)) | O(m)*  | O(min(i, n-i)) |
-//! | [`LinkedList`] | O(min(i, n-i)) | O(min(i, n-i))  | O(min(i, n-i)) | O(1)   | O(min(i, n-i)) |
+//! |                | get(i)                 | insert(i)               | remove(i)              | append    | split_off(i)           |
+//! |----------------|------------------------|-------------------------|------------------------|-----------|------------------------|
+//! | [`Vec`]        | *O*(1)                 | *O*(*n*-*i*)*           | *O*(*n*-*i*)           | *O*(*m*)* | *O*(*n*-*i*)           |
+//! | [`VecDeque`]   | *O*(1)                 | *O*(min(*i*, *n*-*i*))* | *O*(min(*i*, *n*-*i*)) | *O*(*m*)* | *O*(min(*i*, *n*-*i*)) |
+//! | [`LinkedList`] | *O*(min(*i*, *n*-*i*)) | *O*(min(*i*, *n*-*i*))  | *O*(min(*i*, *n*-*i*)) | *O*(1)    | *O*(min(*i*, *n*-*i*)) |
 //!
 //! Note that where ties occur, [`Vec`] is generally going to be faster than [`VecDeque`], and
 //! [`VecDeque`] is generally going to be faster than [`LinkedList`].
 //!
 //! For Sets, all operations have the cost of the equivalent Map operation.
 //!
-//! |              | get       | insert    | remove    | range     | append |
-//! |--------------|-----------|-----------|-----------|-----------|--------|
-//! | [`HashMap`]  | O(1)~     | O(1)~*    | O(1)~     | N/A       | N/A    |
-//! | [`BTreeMap`] | O(log(n)) | O(log(n)) | O(log(n)) | O(log(n)) | O(n+m) |
+//! |              | get           | insert        | remove        | range         | append       |
+//! |--------------|---------------|---------------|---------------|---------------|--------------|
+//! | [`HashMap`]  | *O*(1)~       | *O*(1)~*      | *O*(1)~       | N/A           | N/A          |
+//! | [`BTreeMap`] | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(log(*n*)) | *O*(*n*+*m*) |
 //!
 //! # Correct and Efficient Usage of Collections
 //!
 //! contents by-value. This is great when the collection itself is no longer
 //! needed, and the values are needed elsewhere. Using `extend` with `into_iter`
 //! is the main way that contents of one collection are moved into another.
-//! `extend` automatically calls `into_iter`, and takes any `T: `[`IntoIterator`].
+//! `extend` automatically calls `into_iter`, and takes any <code>T: [IntoIterator]</code>.
 //! Calling `collect` on an iterator itself is also a great way to convert one
 //! collection into another. Both of these methods should internally use the
 //! capacity management tools discussed in the previous section to do this as
 //! assert_eq!(map.keys().next().unwrap().b, "baz");
 //! ```
 //!
-//! [`IntoIterator`]: crate::iter::IntoIterator
+//! [IntoIterator]: crate::iter::IntoIterator "iter::IntoIterator"
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index 3b9175503080c1e330b2b65a2d67ba420b101a19..ba084987f66e1d532f33767ad2b00d6f112c15a0 100644 (file)
 /// type is a static guarantee that the underlying bytes contain no interior 0
 /// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
 ///
-/// `CString` is to [`&CStr`] as [`String`] is to [`&str`]: the former
+/// `CString` is to <code>&[CStr]</code> as [`String`] is to <code>&[str]</code>: the former
 /// in each pair are owned strings; the latter are borrowed
 /// references.
 ///
 /// # Creating a `CString`
 ///
 /// A `CString` is created from either a byte slice or a byte vector,
-/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for
+/// or anything that implements <code>[Into]<[Vec]<[u8]>></code> (for
 /// example, you can build a `CString` straight out of a [`String`] or
-/// a [`&str`], since both implement that trait).
+/// a <code>&[str]</code>, since both implement that trait).
 ///
-/// The [`CString::new`] method will actually check that the provided `&[u8]`
+/// The [`CString::new`] method will actually check that the provided <code>&[[u8]]</code>
 /// does not have 0 bytes in the middle, and return an error if it
 /// finds one.
 ///
@@ -55,7 +55,7 @@
 ///
 /// # Extracting a slice of the whole C string
 ///
-/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a
+/// Alternatively, you can obtain a <code>&[[u8]]</code> slice from a
 /// `CString` with the [`CString::as_bytes`] method. Slices produced in this
 /// way do *not* contain the trailing nul terminator. This is useful
 /// when you will be calling an extern function that takes a `*const
@@ -64,7 +64,7 @@
 /// You can of course get the slice's length with its
 /// [`len`][slice::len] method.
 ///
-/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
+/// If you need a <code>&[[u8]]</code> slice *with* the nul terminator, you
 /// can use [`CString::as_bytes_with_nul`] instead.
 ///
 /// Once you have the kind of slice you need (with or without a nul
@@ -73,9 +73,8 @@
 /// extern functions. See the documentation for that function for a
 /// discussion on ensuring the lifetime of the raw pointer.
 ///
-/// [`&str`]: prim@str
+/// [str]: prim@str "str"
 /// [`Deref`]: ops::Deref
-/// [`&CStr`]: CStr
 ///
 /// # Examples
 ///
@@ -120,12 +119,12 @@ pub struct CString {
 /// Representation of a borrowed C string.
 ///
 /// This type represents a borrowed reference to a nul-terminated
-/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]`
+/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
 /// slice, or unsafely from a raw `*const c_char`. It can then be
-/// converted to a Rust [`&str`] by performing UTF-8 validation, or
+/// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
 /// into an owned [`CString`].
 ///
-/// `&CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
+/// `&CStr` is to [`CString`] as <code>&[str]</code> is to [`String`]: the former
 /// in each pair are borrowed references; the latter are owned
 /// strings.
 ///
@@ -183,7 +182,7 @@ pub struct CString {
 /// println!("string: {}", my_string_safe());
 /// ```
 ///
-/// [`&str`]: prim@str
+/// [str]: prim@str "str"
 #[derive(Hash)]
 #[cfg_attr(not(test), rustc_diagnostic_item = "CStr")]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -682,7 +681,7 @@ fn into_inner(self) -> Box<[u8]> {
         unsafe { ptr::read(&this.inner) }
     }
 
-    /// Converts a [`Vec`]`<u8>` to a [`CString`] without checking the
+    /// Converts a <code>[Vec]<[u8]></code> to a [`CString`] without checking the
     /// invariants on the given [`Vec`].
     ///
     /// # Safety
@@ -705,7 +704,7 @@ pub unsafe fn from_vec_with_nul_unchecked(v: Vec<u8>) -> Self {
         Self { inner: v.into_boxed_slice() }
     }
 
-    /// Attempts to converts a [`Vec`]`<u8>` to a [`CString`].
+    /// Attempts to converts a <code>[Vec]<[u8]></code> to a [`CString`].
     ///
     /// Runtime checks are present to ensure there is only one nul byte in the
     /// [`Vec`], its last element.
@@ -793,7 +792,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 
 #[stable(feature = "cstring_into", since = "1.7.0")]
 impl From<CString> for Vec<u8> {
-    /// Converts a [`CString`] into a [`Vec`]`<u8>`.
+    /// Converts a [`CString`] into a <code>[Vec]<[u8]></code>.
     ///
     /// The conversion consumes the [`CString`], and removes the terminating NUL byte.
     #[inline]
@@ -867,7 +866,7 @@ fn from(cow: Cow<'_, CStr>) -> Box<CStr> {
 
 #[stable(feature = "c_string_from_box", since = "1.18.0")]
 impl From<Box<CStr>> for CString {
-    /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+    /// Converts a <code>[Box]<[CStr]></code> into a [`CString`] without copying or allocating.
     #[inline]
     fn from(s: Box<CStr>) -> CString {
         s.into_c_string()
@@ -876,7 +875,7 @@ fn from(s: Box<CStr>) -> CString {
 
 #[stable(feature = "cstring_from_vec_of_nonzerou8", since = "1.43.0")]
 impl From<Vec<NonZeroU8>> for CString {
-    /// Converts a [`Vec`]`<`[`NonZeroU8`]`>` into a [`CString`] without
+    /// Converts a <code>[Vec]<[NonZeroU8]></code> into a [`CString`] without
     /// copying nor checking for inner null bytes.
     #[inline]
     fn from(v: Vec<NonZeroU8>) -> CString {
@@ -906,7 +905,7 @@ fn clone(&self) -> Self {
 
 #[stable(feature = "box_from_c_string", since = "1.20.0")]
 impl From<CString> for Box<CStr> {
-    /// Converts a [`CString`] into a [`Box`]`<CStr>` without copying or allocating.
+    /// Converts a [`CString`] into a <code>[Box]<[CStr]></code> without copying or allocating.
     #[inline]
     fn from(s: CString) -> Box<CStr> {
         s.into_boxed_c_str()
@@ -942,7 +941,7 @@ fn from(s: &'a CString) -> Cow<'a, CStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<CString> for Arc<CStr> {
-    /// Converts a [`CString`] into an [`Arc`]`<CStr>` without copying or allocating.
+    /// Converts a [`CString`] into an <code>[Arc]<[CStr]></code> without copying or allocating.
     #[inline]
     fn from(s: CString) -> Arc<CStr> {
         let arc: Arc<[u8]> = Arc::from(s.into_inner());
@@ -961,7 +960,7 @@ fn from(s: &CStr) -> Arc<CStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<CString> for Rc<CStr> {
-    /// Converts a [`CString`] into an [`Rc`]`<CStr>` without copying or allocating.
+    /// Converts a [`CString`] into an <code>[Rc]<[CStr]></code> without copying or allocating.
     #[inline]
     fn from(s: CString) -> Rc<CStr> {
         let rc: Rc<[u8]> = Rc::from(s.into_inner());
@@ -1355,13 +1354,13 @@ pub fn to_bytes_with_nul(&self) -> &[u8] {
         unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
     }
 
-    /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8.
+    /// Yields a <code>&[str]</code> slice if the `CStr` contains valid UTF-8.
     ///
     /// If the contents of the `CStr` are valid UTF-8 data, this
-    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// function will return the corresponding <code>&[str]</code> slice. Otherwise,
     /// it will return an error with details of where UTF-8 validation failed.
     ///
-    /// [`&str`]: prim@str
+    /// [str]: prim@str "str"
     ///
     /// # Examples
     ///
@@ -1380,20 +1379,19 @@ pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
         str::from_utf8(self.to_bytes())
     }
 
-    /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`.
+    /// Converts a `CStr` into a <code>[Cow]<[str]></code>.
     ///
     /// If the contents of the `CStr` are valid UTF-8 data, this
-    /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
-    /// with the corresponding [`&str`] slice. Otherwise, it will
+    /// function will return a <code>[Cow]::[Borrowed]\(&[str])</code>
+    /// with the corresponding <code>&[str]</code> slice. Otherwise, it will
     /// replace any invalid UTF-8 sequences with
     /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD] and return a
-    /// [`Cow`]`::`[`Owned`]`(`[`String`]`)` with the result.
+    /// <code>[Cow]::[Owned]\(&[str])</code> with the result.
     ///
-    /// [`str`]: primitive@str
-    /// [`&str`]: primitive@str
-    /// [`Borrowed`]: Cow::Borrowed
-    /// [`Owned`]: Cow::Owned
-    /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER
+    /// [str]: prim@str "str"
+    /// [Borrowed]: Cow::Borrowed
+    /// [Owned]: Cow::Owned
+    /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER "std::char::REPLACEMENT_CHARACTER"
     ///
     /// # Examples
     ///
@@ -1426,7 +1424,7 @@ pub fn to_string_lossy(&self) -> Cow<'_, str> {
         String::from_utf8_lossy(self.to_bytes())
     }
 
-    /// Converts a [`Box`]`<CStr>` into a [`CString`] without copying or allocating.
+    /// Converts a <code>[Box]<[CStr]></code> into a [`CString`] without copying or allocating.
     ///
     /// # Examples
     ///
index fe4e3af91ad0a6df1a738570ac6a33561a72bb56..82a76aa73c583fb78ecaea7bb101cca179d71547 100644 (file)
@@ -43,8 +43,8 @@
 //! terminator, so the buffer length is really `len+1` characters.
 //! Rust strings don't have a nul terminator; their length is always
 //! stored and does not need to be calculated. While in Rust
-//! accessing a string's length is a `O(1)` operation (because the
-//! length is stored); in C it is an `O(length)` operation because the
+//! accessing a string's length is an *O*(1) operation (because the
+//! length is stored); in C it is an *O*(*n*) operation because the
 //! length needs to be computed by scanning the string for the nul
 //! terminator.
 //!
 //! string: it is nul-terminated, and has no internal nul characters.
 //! Rust code can create a [`CString`] out of a normal string (provided
 //! that the string doesn't have nul characters in the middle), and
-//! then use a variety of methods to obtain a raw `*mut `[`u8`] that can
+//! then use a variety of methods to obtain a raw <code>\*mut [u8]</code> that can
 //! then be passed as an argument to functions which use the C
 //! conventions for strings.
 //!
 //! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
-//! is what you would use to wrap a raw `*const `[`u8`] that you got from
+//! is what you would use to wrap a raw <code>\*const [u8]</code> that you got from
 //! a C function. A [`CStr`] is guaranteed to be a nul-terminated array
 //! of bytes. Once you have a [`CStr`], you can convert it to a Rust
-//! [`&str`][`str`] if it's valid UTF-8, or lossily convert it by adding
+//! <code>&[str]</code> if it's valid UTF-8, or lossily convert it by adding
 //! replacement characters.
 //!
 //! [`OsString`] and [`OsStr`] are useful when you need to transfer
@@ -86,9 +86,9 @@
 //! library, various APIs that transfer strings to/from the operating
 //! system use [`OsString`] instead of plain strings. For example,
 //! [`env::var_os()`] is used to query environment variables; it
-//! returns an [`Option`]`<`[`OsString`]`>`. If the environment variable
-//! exists you will get a [`Some`]`(os_string)`, which you can *then* try to
-//! convert to a Rust string. This yields a [`Result`], so that
+//! returns an <code>[Option]<[OsString]></code>. If the environment variable
+//! exists you will get a <code>[Some]\(os_string)</code>, which you can
+//! *then* try to convert to a Rust string. This yields a [`Result`], so that
 //! your code can detect errors in case the environment variable did
 //! not in fact contain valid Unicode data.
 //!
 //! ## On Unix
 //!
 //! On Unix, [`OsStr`] implements the
-//! `std::os::unix::ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
+//! <code>std::os::unix::ffi::[OsStrExt][unix.OsStrExt]</code> trait, which
 //! augments it with two methods, [`from_bytes`] and [`as_bytes`].
 //! These do inexpensive conversions from and to UTF-8 byte slices.
 //!
 //! Additionally, on Unix [`OsString`] implements the
-//! `std::os::unix::ffi::`[`OsStringExt`][unix.OsStringExt] trait,
+//! <code>std::os::unix::ffi::[OsStringExt][unix.OsStringExt]</code> trait,
 //! which provides [`from_vec`] and [`into_vec`] methods that consume
 //! their arguments, and take or produce vectors of [`u8`].
 //!
 //! ## On Windows
 //!
 //! On Windows, [`OsStr`] implements the
-//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
+//! <code>std::os::windows::ffi::[OsStrExt][windows.OsStrExt]</code> trait,
 //! which provides an [`encode_wide`] method. This provides an
 //! iterator that can be [`collect`]ed into a vector of [`u16`].
 //!
 //! Additionally, on Windows [`OsString`] implements the
-//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
+//! <code>std::os::windows:ffi::[OsStringExt][windows.OsStringExt]</code>
 //! trait, which provides a [`from_wide`] method. The result of this
 //! method is an [`OsString`] which can be round-tripped to a Windows
 //! string losslessly.
 //!
 //! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
 //! [Unicode code point]: https://www.unicode.org/glossary/#code_point
-//! [`env::set_var()`]: crate::env::set_var
-//! [`env::var_os()`]: crate::env::var_os
-//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt
-//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec
-//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec
-//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt
-//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes
-//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes
-//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt
-//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt
-//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide
-//! [`collect`]: crate::iter::Iterator::collect
-//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt
-//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide
+//! [`env::set_var()`]: crate::env::set_var "env::set_var"
+//! [`env::var_os()`]: crate::env::var_os "env::var_os"
+//! [unix.OsStringExt]: crate::os::unix::ffi::OsStringExt "os::unix::ffi::OsStringExt"
+//! [`from_vec`]: crate::os::unix::ffi::OsStringExt::from_vec "os::unix::ffi::OsStringExt::from_vec"
+//! [`into_vec`]: crate::os::unix::ffi::OsStringExt::into_vec "os::unix::ffi::OsStringExt::into_vec"
+//! [unix.OsStrExt]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt"
+//! [`from_bytes`]: crate::os::unix::ffi::OsStrExt::from_bytes "os::unix::ffi::OsStrExt::from_bytes"
+//! [`as_bytes`]: crate::os::unix::ffi::OsStrExt::as_bytes "os::unix::ffi::OsStrExt::as_bytes"
+//! [`OsStrExt`]: crate::os::unix::ffi::OsStrExt "os::unix::ffi::OsStrExt"
+//! [windows.OsStrExt]: crate::os::windows::ffi::OsStrExt "os::windows::ffi::OsStrExt"
+//! [`encode_wide`]: crate::os::windows::ffi::OsStrExt::encode_wide "os::windows::ffi::OsStrExt::encode_wide"
+//! [`collect`]: crate::iter::Iterator::collect "iter::Iterator::collect"
+//! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt "os::windows::ffi::OsStringExt"
+//! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide"
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
index 21f354caf6ae9fba2d1ed486ff7411a5dec7e9ea..7e70901076cdadc96c8855cda6958f786989f9ef 100644 (file)
@@ -33,7 +33,7 @@
 /// of this is that `OsString` instances are *not* `NUL` terminated; in order
 /// to pass to e.g., Unix system call, you should create a [`CStr`].
 ///
-/// `OsString` is to [`&OsStr`] as [`String`] is to [`&str`]: the former
+/// `OsString` is to <code>&[OsStr]</code> as [`String`] is to <code>&[str]</code>: the former
 /// in each pair are owned strings; the latter are borrowed
 /// references.
 ///
 /// # Creating an `OsString`
 ///
 /// **From a Rust string**: `OsString` implements
-/// [`From`]`<`[`String`]`>`, so you can use `my_string.from` to
+/// <code>[From]<[String]></code>, so you can use <code>my_string.[into]\()</code> to
 /// create an `OsString` from a normal Rust string.
 ///
 /// **From slices:** Just like you can start with an empty Rust
-/// [`String`] and then [`String::push_str`] `&str`
+/// [`String`] and then [`String::push_str`] some <code>&[str]</code>
 /// sub-string slices into it, you can create an empty `OsString` with
 /// the [`OsString::new`] method and then push string slices into it with the
 /// [`OsString::push`] method.
 ///
 /// # Extracting a borrowed reference to the whole OS string
 ///
-/// You can use the [`OsString::as_os_str`] method to get an `&`[`OsStr`] from
+/// You can use the [`OsString::as_os_str`] method to get an <code>&[OsStr]</code> from
 /// an `OsString`; this is effectively a borrowed reference to the
 /// whole string.
 ///
 /// See the [module's toplevel documentation about conversions][conversions] for a discussion on
 /// the traits which `OsString` implements for [conversions] from/to native representations.
 ///
-/// [`&OsStr`]: OsStr
-/// [`&str`]: str
 /// [`CStr`]: crate::ffi::CStr
 /// [conversions]: super#conversions
+/// [into]: Into::into
 #[cfg_attr(not(test), rustc_diagnostic_item = "OsString")]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsString {
@@ -86,13 +85,12 @@ impl crate::sealed::Sealed for OsString {}
 /// This type represents a borrowed reference to a string in the operating system's preferred
 /// representation.
 ///
-/// `&OsStr` is to [`OsString`] as [`&str`] is to [`String`]: the former in each pair are borrowed
-/// references; the latter are owned strings.
+/// `&OsStr` is to [`OsString`] as <code>&[str]</code> is to [`String`]: the
+/// former in each pair are borrowed references; the latter are owned strings.
 ///
 /// See the [module's toplevel documentation about conversions][conversions] for a discussion on
 /// the traits which `OsStr` implements for [conversions] from/to native representations.
 ///
-/// [`&str`]: str
 /// [conversions]: super#conversions
 #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")]
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -162,9 +160,7 @@ pub fn into_string(self) -> Result<String, OsString> {
         self.inner.into_string().map_err(|buf| OsString { inner: buf })
     }
 
-    /// Extends the string with the given [`&OsStr`] slice.
-    ///
-    /// [`&OsStr`]: OsStr
+    /// Extends the string with the given <code>&[OsStr]</code> slice.
     ///
     /// # Examples
     ///
@@ -563,12 +559,10 @@ fn from_inner_mut(inner: &mut Slice) -> &mut OsStr {
         unsafe { &mut *(inner as *mut Slice as *mut OsStr) }
     }
 
-    /// Yields a [`&str`] slice if the `OsStr` is valid Unicode.
+    /// Yields a <code>&[str]</code> slice if the `OsStr` is valid Unicode.
     ///
     /// This conversion may entail doing a check for UTF-8 validity.
     ///
-    /// [`&str`]: str
-    ///
     /// # Examples
     ///
     /// ```
@@ -583,7 +577,7 @@ pub fn to_str(&self) -> Option<&str> {
         self.inner.to_str()
     }
 
-    /// Converts an `OsStr` to a [`Cow`]`<`[`str`]`>`.
+    /// Converts an `OsStr` to a <code>[Cow]<[str]></code>.
     ///
     /// Any non-Unicode sequences are replaced with
     /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
@@ -701,7 +695,7 @@ pub fn len(&self) -> usize {
         self.inner.inner.len()
     }
 
-    /// Converts a [`Box`]`<OsStr>` into an [`OsString`] without copying or allocating.
+    /// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or allocating.
     #[stable(feature = "into_boxed_os_str", since = "1.20.0")]
     pub fn into_os_string(self: Box<OsStr>) -> OsString {
         let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) };
@@ -870,7 +864,7 @@ fn from(cow: Cow<'_, OsStr>) -> Box<OsStr> {
 
 #[stable(feature = "os_string_from_box", since = "1.18.0")]
 impl From<Box<OsStr>> for OsString {
-    /// Converts a [`Box`]`<`[`OsStr`]`>` into an [`OsString`] without copying or
+    /// Converts a <code>[Box]<[OsStr]></code> into an [`OsString`] without copying or
     /// allocating.
     #[inline]
     fn from(boxed: Box<OsStr>) -> OsString {
@@ -880,7 +874,7 @@ fn from(boxed: Box<OsStr>) -> OsString {
 
 #[stable(feature = "box_from_os_string", since = "1.20.0")]
 impl From<OsString> for Box<OsStr> {
-    /// Converts an [`OsString`] into a [`Box`]`<OsStr>` without copying or allocating.
+    /// Converts an [`OsString`] into a <code>[Box]<[OsStr]></code> without copying or allocating.
     #[inline]
     fn from(s: OsString) -> Box<OsStr> {
         s.into_boxed_os_str()
@@ -897,7 +891,7 @@ fn clone(&self) -> Self {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<OsString> for Arc<OsStr> {
-    /// Converts an [`OsString`] into an [`Arc`]`<OsStr>` without copying or allocating.
+    /// Converts an [`OsString`] into an <code>[Arc]<[OsStr]></code> without copying or allocating.
     #[inline]
     fn from(s: OsString) -> Arc<OsStr> {
         let arc = s.inner.into_arc();
@@ -916,7 +910,7 @@ fn from(s: &OsStr) -> Arc<OsStr> {
 
 #[stable(feature = "shared_from_slice2", since = "1.24.0")]
 impl From<OsString> for Rc<OsStr> {
-    /// Converts an [`OsString`] into an [`Rc`]`<OsStr>` without copying or allocating.
+    /// Converts an [`OsString`] into an <code>[Rc]<[OsStr]></code> without copying or allocating.
     #[inline]
     fn from(s: OsString) -> Rc<OsStr> {
         let rc = s.inner.into_rc();
index bdb172907ffed39b770d802093c2ea416d485365..e4b44c0489807bca10e7b279d395925c37b7ad3f 100644 (file)
@@ -106,7 +106,7 @@ pub struct File {
 /// Iterator over the entries in a directory.
 ///
 /// This iterator is returned from the [`read_dir`] function of this module and
-/// will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. Through a [`DirEntry`]
+/// will yield instances of <code>[io::Result]<[DirEntry]></code>. Through a [`DirEntry`]
 /// information like the entry's path and possibly other metadata can be
 /// learned.
 ///
@@ -786,17 +786,17 @@ pub fn write(&mut self, write: bool) -> &mut Self {
     /// If a file is opened with both read and append access, beware that after
     /// opening, and after every write, the position for reading may be set at the
     /// end of the file. So, before writing, save the current position (using
-    /// [`seek`]`(`[`SeekFrom`]`::`[`Current`]`(0))`), and restore it before the next read.
+    /// <code>[seek]\([SeekFrom]::[Current]\(0))</code>), and restore it before the next read.
     ///
     /// ## Note
     ///
     /// This function doesn't create the file if it doesn't exist. Use the
     /// [`OpenOptions::create`] method to do so.
     ///
-    /// [`write()`]: Write::write
-    /// [`flush()`]: Write::flush
-    /// [`seek`]: Seek::seek
-    /// [`Current`]: SeekFrom::Current
+    /// [`write()`]: Write::write "io::Write::write"
+    /// [`flush()`]: Write::flush "io::Write::flush"
+    /// [seek]: Seek::seek "io::Seek::seek"
+    /// [Current]: SeekFrom::Current "io::SeekFrom::Current"
     ///
     /// # Examples
     ///
@@ -2043,7 +2043,7 @@ pub fn remove_dir_all<P: AsRef<Path>>(path: P) -> io::Result<()> {
 
 /// Returns an iterator over the entries within a directory.
 ///
-/// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`.
+/// The iterator will yield instances of <code>[io::Result]<[DirEntry]></code>.
 /// New errors may be encountered after an iterator is initially constructed.
 /// Entries for the current and parent directories (typically `.` and `..`) are
 /// skipped.
index 32d194d9616523c6ae46a426acf602139ade7fbe..869ac1ec8596c1324b915b9479a46f7649e9b9b5 100644 (file)
@@ -15,7 +15,7 @@
 /// *repeated* read calls to the same file or network socket. It does not
 /// help when reading very large amounts at once, or reading just one or a few
 /// times. It also provides no advantage when reading from a source that is
-/// already in memory, like a [`Vec`]`<u8>`.
+/// already in memory, like a <code>[Vec]\<u8></code>.
 ///
 /// When the `BufReader<R>` is dropped, the contents of its buffer will be
 /// discarded. Creating multiple instances of a `BufReader<R>` on the same
@@ -347,7 +347,7 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
 impl<R: Seek> Seek for BufReader<R> {
     /// Seek to an offset, in bytes, in the underlying reader.
     ///
-    /// The position used for seeking with [`SeekFrom::Current`]`(_)` is the
+    /// The position used for seeking with <code>[SeekFrom::Current]\(_)</code> is the
     /// position the underlying reader would be at if the `BufReader<R>` had no
     /// internal buffer.
     ///
@@ -360,11 +360,11 @@ impl<R: Seek> Seek for BufReader<R> {
     ///
     /// See [`std::io::Seek`] for more details.
     ///
-    /// Note: In the edge case where you're seeking with [`SeekFrom::Current`]`(n)`
+    /// Note: In the edge case where you're seeking with <code>[SeekFrom::Current]\(n)</code>
     /// where `n` minus the internal buffer length overflows an `i64`, two
     /// seeks will be performed instead of one. If the second seek returns
     /// [`Err`], the underlying reader will be left at the same position it would
-    /// have if you called `seek` with [`SeekFrom::Current`]`(0)`.
+    /// have if you called `seek` with <code>[SeekFrom::Current]\(0)</code>.
     ///
     /// [`std::io::Seek`]: Seek
     fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
index df60af7c36a3e236a73c6fb8abef22fd217fa989..ebbda7c1bf2a0b6fa8a45e563fa0db4f373bc4d2 100644 (file)
@@ -18,7 +18,7 @@
 /// *repeated* write calls to the same file or network socket. It does not
 /// help when writing very large amounts at once, or writing just one or a few
 /// times. It also provides no advantage when writing to a destination that is
-/// in memory, like a [`Vec`]`<u8>`.
+/// in memory, like a <code>[Vec]\<u8></code>.
 ///
 /// It is critical to call [`flush`] before `BufWriter<W>` is dropped. Though
 /// dropping will attempt to flush the contents of the buffer, any errors
index ae0cea985d77c9b8314044d7eaad75e2e07581a1..25cc5e67ad14e37ddfd6ed337edadef5f39dd006 100644 (file)
 /// [`Seek`] implementation.
 ///
 /// `Cursor`s are used with in-memory buffers, anything implementing
-/// [`AsRef`]`<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
+/// <code>[AsRef]<\[u8]></code>, to allow them to implement [`Read`] and/or [`Write`],
 /// allowing these buffers to be used anywhere you might use a reader or writer
 /// that does actual I/O.
 ///
 /// The standard library implements some I/O traits on various types which
-/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
-/// `Cursor<`[`&[u8]`][bytes]`>`.
+/// are commonly used as a buffer, like <code>Cursor<[Vec]\<u8>></code> and
+/// <code>Cursor<[&\[u8\]][bytes]></code>.
 ///
 /// # Examples
 ///
@@ -26,7 +26,7 @@
 /// code, but use an in-memory buffer in our tests. We can do this with
 /// `Cursor`:
 ///
-/// [bytes]: crate::slice
+/// [bytes]: crate::slice "slice"
 /// [`File`]: crate::fs::File
 ///
 /// ```no_run
index 4a35d36a9def72f284b48244219b347a9d140e80..f8ebbe1cba721736cf555e684ee81aef547b83ea 100644 (file)
@@ -854,8 +854,8 @@ fn by_ref(&mut self) -> &mut Self
 
     /// Transforms this `Read` instance to an [`Iterator`] over its bytes.
     ///
-    /// The returned type implements [`Iterator`] where the `Item` is
-    /// [`Result`]`<`[`u8`]`, `[`io::Error`]`>`.
+    /// The returned type implements [`Iterator`] where the [`Item`] is
+    /// <code>[Result]<[u8], [io::Error]></code>.
     /// The yielded item is [`Ok`] if a byte was successfully read and [`Err`]
     /// otherwise. EOF is mapped to returning [`None`] from this iterator.
     ///
@@ -863,9 +863,10 @@ fn by_ref(&mut self) -> &mut Self
     ///
     /// [`File`]s implement `Read`:
     ///
-    /// [`File`]: crate::fs::File
-    /// [`Result`]: crate::result::Result
-    /// [`io::Error`]: self::Error
+    /// [`Item`]: Iterator::Item
+    /// [`File`]: crate::fs::File "fs::File"
+    /// [Result]: crate::result::Result "Result"
+    /// [io::Error]: self::Error "io::Error"
     ///
     /// ```no_run
     /// use std::io;
@@ -2191,13 +2192,13 @@ fn read_line(&mut self, buf: &mut String) -> Result<usize> {
     /// `byte`.
     ///
     /// The iterator returned from this function will return instances of
-    /// [`io::Result`]`<`[`Vec<u8>`]`>`. Each vector returned will *not* have
+    /// <code>[io::Result]<[Vec]\<u8>></code>. Each vector returned will *not* have
     /// the delimiter byte at the end.
     ///
     /// This function will yield errors whenever [`read_until`] would have
     /// also yielded an error.
     ///
-    /// [`io::Result`]: self::Result
+    /// [io::Result]: self::Result "io::Result"
     /// [`read_until`]: BufRead::read_until
     ///
     /// # Examples
@@ -2228,10 +2229,10 @@ fn split(self, byte: u8) -> Split<Self>
     /// Returns an iterator over the lines of this reader.
     ///
     /// The iterator returned from this function will yield instances of
-    /// [`io::Result`]`<`[`String`]`>`. Each string returned will *not* have a newline
+    /// <code>[io::Result]<[String]></code>. Each string returned will *not* have a newline
     /// byte (the `0xA` byte) or `CRLF` (`0xD`, `0xA` bytes) at the end.
     ///
-    /// [`io::Result`]: self::Result
+    /// [io::Result]: self::Result "io::Result"
     ///
     /// # Examples
     ///
index a8812f197d82d3c269dc001d2eb98a5f450a74a1..2f3520ae7a5a5fb4c9aab4c4364b64fe334b5d70 100644 (file)
@@ -19,7 +19,7 @@
 
 /// Constructs a new handle to an empty reader.
 ///
-/// All reads from the returned reader will return [`Ok`]`(0)`.
+/// All reads from the returned reader will return <code>[Ok]\(0)</code>.
 ///
 /// # Examples
 ///
index 43d930677fad3d53e41712f6844bf9b19d54f49c..f4ebcd53a25f7482c3f6736de8d045828c8193b8 100644 (file)
@@ -765,15 +765,15 @@ fn hash<H: hash::Hasher>(&self, s: &mut H) {
 ///
 ///  * [`SocketAddr`]: [`to_socket_addrs`] is the identity function.
 ///
-///  * [`SocketAddrV4`], [`SocketAddrV6`], `(`[`IpAddr`]`, `[`u16`]`)`,
-///    `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`:
+///  * [`SocketAddrV4`], [`SocketAddrV6`], <code>([IpAddr], [u16])</code>,
+///    <code>([Ipv4Addr], [u16])</code>, <code>([Ipv6Addr], [u16])</code>:
 ///    [`to_socket_addrs`] constructs a [`SocketAddr`] trivially.
 ///
-///  * `(`[`&str`]`, `[`u16`]`)`: [`&str`] should be either a string representation
+///  * <code>(&[str], [u16])</code>: <code>&[str]</code> should be either a string representation
 ///    of an [`IpAddr`] address as expected by [`FromStr`] implementation or a host
 ///    name. [`u16`] is the port number.
 ///
-///  * [`&str`]: the string should be either a string representation of a
+///  * <code>&[str]</code>: the string should be either a string representation of a
 ///    [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like
 ///    `<host_name>:<port>` pair where `<port>` is a [`u16`] value.
 ///
@@ -789,11 +789,10 @@ fn hash<H: hash::Hasher>(&self, s: &mut H) {
 /// Addresses returned by the operating system that are not IP addresses are
 /// silently ignored.
 ///
-/// [`FromStr`]: crate::str::FromStr
-/// [`&str`]: str
-/// [`TcpStream`]: crate::net::TcpStream
+/// [`FromStr`]: crate::str::FromStr "std::str::FromStr"
+/// [`TcpStream`]: crate::net::TcpStream "net::TcpStream"
 /// [`to_socket_addrs`]: ToSocketAddrs::to_socket_addrs
-/// [`UdpSocket`]: crate::net::UdpSocket
+/// [`UdpSocket`]: crate::net::UdpSocket "net::UdpSocket"
 ///
 /// # Examples
 ///
@@ -872,7 +871,7 @@ pub trait ToSocketAddrs {
     #[stable(feature = "rust1", since = "1.0.0")]
     type Iter: Iterator<Item = SocketAddr>;
 
-    /// Converts this object to an iterator of resolved `SocketAddr`s.
+    /// Converts this object to an iterator of resolved [`SocketAddr`]s.
     ///
     /// The returned iterator might not actually yield any values depending on the
     /// outcome of any resolution performed.
index d814e9b25ba9a0be62e0a6432289883da51d565d..a0c77b648fe0511a8c56cabbf14e3a09707a9977 100644 (file)
 pub enum Shutdown {
     /// The reading portion of the [`TcpStream`] should be shut down.
     ///
-    /// All currently blocked and future [reads] will return [`Ok`]`(0)`.
+    /// All currently blocked and future [reads] will return <code>[Ok]\(0)</code>.
     ///
-    /// [reads]: crate::io::Read
+    /// [reads]: crate::io::Read "io::Read"
     #[stable(feature = "rust1", since = "1.0.0")]
     Read,
     /// The writing portion of the [`TcpStream`] should be shut down.
     ///
     /// All currently blocked and future [writes] will return an error.
     ///
-    /// [writes]: crate::io::Write
+    /// [writes]: crate::io::Write "io::Write"
     #[stable(feature = "rust1", since = "1.0.0")]
     Write,
     /// Both the reading and the writing portions of the [`TcpStream`] should be shut down.
index 069a5376a441c9062b8e945ba0f7610b46ddcbc4..90c30313dbbda7bc1e94e2d97ac2ecd7af5b1884 100644 (file)
@@ -138,6 +138,8 @@ pub mod windows {}
 #[cfg(target_os = "solaris")]
 pub mod solaris;
 
+#[cfg(target_os = "solid_asp3")]
+pub mod solid;
 #[cfg(target_os = "vxworks")]
 pub mod vxworks;
 
diff --git a/library/std/src/os/solid/ffi.rs b/library/std/src/os/solid/ffi.rs
new file mode 100644 (file)
index 0000000..aaa2070
--- /dev/null
@@ -0,0 +1,41 @@
+//! SOLID-specific extension to the primitives in the `std::ffi` module
+//!
+//! # Examples
+//!
+//! ```
+//! use std::ffi::OsString;
+//! use std::os::solid::ffi::OsStringExt;
+//!
+//! let bytes = b"foo".to_vec();
+//!
+//! // OsStringExt::from_vec
+//! let os_string = OsString::from_vec(bytes);
+//! assert_eq!(os_string.to_str(), Some("foo"));
+//!
+//! // OsStringExt::into_vec
+//! let bytes = os_string.into_vec();
+//! assert_eq!(bytes, b"foo");
+//! ```
+//!
+//! ```
+//! use std::ffi::OsStr;
+//! use std::os::solid::ffi::OsStrExt;
+//!
+//! let bytes = b"foo";
+//!
+//! // OsStrExt::from_bytes
+//! let os_str = OsStr::from_bytes(bytes);
+//! assert_eq!(os_str.to_str(), Some("foo"));
+//!
+//! // OsStrExt::as_bytes
+//! let bytes = os_str.as_bytes();
+//! assert_eq!(bytes, b"foo");
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[path = "../unix/ffi/os_str.rs"]
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
new file mode 100644 (file)
index 0000000..33cc5a0
--- /dev/null
@@ -0,0 +1,113 @@
+//! SOLID-specific extensions to general I/O primitives
+
+#![deny(unsafe_op_in_unsafe_fn)]
+#![unstable(feature = "solid_ext", issue = "none")]
+
+use crate::net;
+use crate::sys;
+use crate::sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+pub type RawFd = i32;
+
+/// A trait to extract the raw SOLID Sockets file descriptor from an underlying
+/// object.
+pub trait AsRawFd {
+    /// Extracts the raw file descriptor.
+    ///
+    /// This method does **not** pass ownership of the raw file descriptor
+    /// to the caller. The descriptor is only guaranteed to be valid while
+    /// the original object has not yet been destroyed.
+    fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+pub trait FromRawFd {
+    /// Constructs a new instance of `Self` from the given raw file
+    /// descriptor.
+    ///
+    /// This function **consumes ownership** of the specified file
+    /// descriptor. The returned object will take responsibility for closing
+    /// it when the object goes out of scope.
+    ///
+    /// This function is also unsafe as the primitives currently returned
+    /// have the contract that they are the sole owner of the file
+    /// descriptor they are wrapping. Usage of this function could
+    /// accidentally allow violating this contract which can cause memory
+    /// unsafety in code that relies on it being true.
+    unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+pub trait IntoRawFd {
+    /// Consumes this object, returning the raw underlying file descriptor.
+    ///
+    /// This function **transfers ownership** of the underlying file descriptor
+    /// to the caller. Callers are then the unique owners of the file descriptor
+    /// and must close the descriptor once it's no longer needed.
+    fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl AsRawFd for RawFd {
+    #[inline]
+    fn as_raw_fd(&self) -> RawFd {
+        *self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl IntoRawFd for RawFd {
+    #[inline]
+    fn into_raw_fd(self) -> RawFd {
+        self
+    }
+}
+#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")]
+impl FromRawFd for RawFd {
+    #[inline]
+    unsafe fn from_raw_fd(fd: RawFd) -> RawFd {
+        fd
+    }
+}
+
+macro_rules! impl_as_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "rust1", since = "1.0.0")]
+        impl AsRawFd for net::$t {
+            #[inline]
+            fn as_raw_fd(&self) -> RawFd {
+                *self.as_inner().socket().as_inner()
+            }
+        }
+    )*};
+}
+impl_as_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_from_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "from_raw_os", since = "1.1.0")]
+        impl FromRawFd for net::$t {
+            #[inline]
+            unsafe fn from_raw_fd(fd: RawFd) -> net::$t {
+                let socket = sys::net::Socket::from_inner(fd);
+                net::$t::from_inner(sys_common::net::$t::from_inner(socket))
+            }
+        }
+    )*};
+}
+impl_from_raw_fd! { TcpStream TcpListener UdpSocket }
+
+macro_rules! impl_into_raw_fd {
+    ($($t:ident)*) => {$(
+        #[stable(feature = "into_raw_os", since = "1.4.0")]
+        impl IntoRawFd for net::$t {
+            #[inline]
+            fn into_raw_fd(self) -> RawFd {
+                self.into_inner().into_socket().into_inner()
+            }
+        }
+    )*};
+}
+impl_into_raw_fd! { TcpStream TcpListener UdpSocket }
diff --git a/library/std/src/os/solid/mod.rs b/library/std/src/os/solid/mod.rs
new file mode 100644 (file)
index 0000000..4328ba7
--- /dev/null
@@ -0,0 +1,17 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+
+pub mod ffi;
+pub mod io;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::ffi::{OsStrExt, OsStringExt};
+    #[doc(no_inline)]
+    #[stable(feature = "rust1", since = "1.0.0")]
+    pub use super::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
+}
index 2a9c361c18afc03ec06972fb8d5af6938d34864e..9d5778ed48cfe5803660f5502b4911d83c1bd70a 100644 (file)
@@ -2552,7 +2552,7 @@ pub fn read_link(&self) -> io::Result<PathBuf> {
 
     /// Returns an iterator over the entries within a directory.
     ///
-    /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New
+    /// The iterator will yield instances of <code>[io::Result]<[fs::DirEntry]></code>. New
     /// errors may be encountered after an iterator is initially constructed.
     ///
     /// This is an alias to [`fs::read_dir`].
diff --git a/library/std/src/sys/itron/abi.rs b/library/std/src/sys/itron/abi.rs
new file mode 100644 (file)
index 0000000..f99ee4f
--- /dev/null
@@ -0,0 +1,155 @@
+//! ABI for μITRON derivatives
+pub type int_t = crate::os::raw::c_int;
+pub type uint_t = crate::os::raw::c_uint;
+pub type bool_t = int_t;
+
+/// Kernel object ID
+pub type ID = int_t;
+
+/// The current task.
+pub const TSK_SELF: ID = 0;
+
+/// Relative time
+pub type RELTIM = u32;
+
+/// Timeout (a valid `RELTIM` value or `TMO_FEVR`)
+pub type TMO = u32;
+
+/// The infinite timeout value
+pub const TMO_FEVR: TMO = TMO::MAX;
+
+/// The maximum valid value of `RELTIM`
+pub const TMAX_RELTIM: RELTIM = 4_000_000_000;
+
+/// System time
+pub type SYSTIM = u64;
+
+/// Error code type
+pub type ER = int_t;
+
+/// Error code type, `ID` on success
+pub type ER_ID = int_t;
+
+/// Task or interrupt priority
+pub type PRI = int_t;
+
+/// The special value of `PRI` representing the current task's priority.
+pub const TPRI_SELF: PRI = 0;
+
+/// Object attributes
+pub type ATR = uint_t;
+
+/// Use the priority inheritance protocol
+#[cfg(target_os = "solid_asp3")]
+pub const TA_INHERIT: ATR = 0x02;
+
+/// Activate the task on creation
+pub const TA_ACT: ATR = 0x01;
+
+/// The maximum count of a semaphore
+pub const TMAX_MAXSEM: uint_t = uint_t::MAX;
+
+/// Callback parameter
+pub type EXINF = isize;
+
+/// Task entrypoint
+pub type TASK = Option<unsafe extern "C" fn(EXINF)>;
+
+// Error codes
+pub const E_OK: ER = 0;
+pub const E_SYS: ER = -5;
+pub const E_NOSPT: ER = -9;
+pub const E_RSFN: ER = -10;
+pub const E_RSATR: ER = -11;
+pub const E_PAR: ER = -17;
+pub const E_ID: ER = -18;
+pub const E_CTX: ER = -25;
+pub const E_MACV: ER = -26;
+pub const E_OACV: ER = -27;
+pub const E_ILUSE: ER = -28;
+pub const E_NOMEM: ER = -33;
+pub const E_NOID: ER = -34;
+pub const E_NORES: ER = -35;
+pub const E_OBJ: ER = -41;
+pub const E_NOEXS: ER = -42;
+pub const E_QOVR: ER = -43;
+pub const E_RLWAI: ER = -49;
+pub const E_TMOUT: ER = -50;
+pub const E_DLT: ER = -51;
+pub const E_CLS: ER = -52;
+pub const E_RASTER: ER = -53;
+pub const E_WBLK: ER = -57;
+pub const E_BOVR: ER = -58;
+pub const E_COMM: ER = -65;
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct T_CSEM {
+    pub sematr: ATR,
+    pub isemcnt: uint_t,
+    pub maxsem: uint_t,
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct T_CMTX {
+    pub mtxatr: ATR,
+    pub ceilpri: PRI,
+}
+
+#[derive(Clone, Copy)]
+#[repr(C)]
+pub struct T_CTSK {
+    pub tskatr: ATR,
+    pub exinf: EXINF,
+    pub task: TASK,
+    pub itskpri: PRI,
+    pub stksz: usize,
+    pub stk: *mut u8,
+}
+
+extern "C" {
+    #[link_name = "__asp3_acre_tsk"]
+    pub fn acre_tsk(pk_ctsk: *const T_CTSK) -> ER_ID;
+    #[link_name = "__asp3_get_tid"]
+    pub fn get_tid(p_tskid: *mut ID) -> ER;
+    #[link_name = "__asp3_dly_tsk"]
+    pub fn dly_tsk(dlytim: RELTIM) -> ER;
+    #[link_name = "__asp3_ter_tsk"]
+    pub fn ter_tsk(tskid: ID) -> ER;
+    #[link_name = "__asp3_del_tsk"]
+    pub fn del_tsk(tskid: ID) -> ER;
+    #[link_name = "__asp3_get_pri"]
+    pub fn get_pri(tskid: ID, p_tskpri: *mut PRI) -> ER;
+    #[link_name = "__asp3_rot_rdq"]
+    pub fn rot_rdq(tskpri: PRI) -> ER;
+    #[link_name = "__asp3_slp_tsk"]
+    pub fn slp_tsk() -> ER;
+    #[link_name = "__asp3_tslp_tsk"]
+    pub fn tslp_tsk(tmout: TMO) -> ER;
+    #[link_name = "__asp3_wup_tsk"]
+    pub fn wup_tsk(tskid: ID) -> ER;
+    #[link_name = "__asp3_unl_cpu"]
+    pub fn unl_cpu() -> ER;
+    #[link_name = "__asp3_dis_dsp"]
+    pub fn dis_dsp() -> ER;
+    #[link_name = "__asp3_ena_dsp"]
+    pub fn ena_dsp() -> ER;
+    #[link_name = "__asp3_sns_dsp"]
+    pub fn sns_dsp() -> bool_t;
+    #[link_name = "__asp3_get_tim"]
+    pub fn get_tim(p_systim: *mut SYSTIM) -> ER;
+    #[link_name = "__asp3_acre_mtx"]
+    pub fn acre_mtx(pk_cmtx: *const T_CMTX) -> ER_ID;
+    #[link_name = "__asp3_del_mtx"]
+    pub fn del_mtx(tskid: ID) -> ER;
+    #[link_name = "__asp3_loc_mtx"]
+    pub fn loc_mtx(mtxid: ID) -> ER;
+    #[link_name = "__asp3_ploc_mtx"]
+    pub fn ploc_mtx(mtxid: ID) -> ER;
+    #[link_name = "__asp3_tloc_mtx"]
+    pub fn tloc_mtx(mtxid: ID, tmout: TMO) -> ER;
+    #[link_name = "__asp3_unl_mtx"]
+    pub fn unl_mtx(mtxid: ID) -> ER;
+    pub fn exd_tsk() -> ER;
+}
diff --git a/library/std/src/sys/itron/condvar.rs b/library/std/src/sys/itron/condvar.rs
new file mode 100644 (file)
index 0000000..dac4b8a
--- /dev/null
@@ -0,0 +1,294 @@
+//! POSIX conditional variable implementation based on user-space wait queues.
+use super::{abi, error::expect_success_aborting, spin::SpinMutex, task, time::with_tmos_strong};
+use crate::{mem::replace, ptr::NonNull, sys::mutex::Mutex, time::Duration};
+
+// The implementation is inspired by the queue-based implementation shown in
+// Andrew D. Birrell's paper "Implementing Condition Variables with Semaphores"
+
+pub struct Condvar {
+    waiters: SpinMutex<waiter_queue::WaiterQueue>,
+}
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+pub type MovableCondvar = Condvar;
+
+impl Condvar {
+    pub const fn new() -> Condvar {
+        Condvar { waiters: SpinMutex::new(waiter_queue::WaiterQueue::new()) }
+    }
+
+    pub unsafe fn init(&mut self) {}
+
+    pub unsafe fn notify_one(&self) {
+        self.waiters.with_locked(|waiters| {
+            if let Some(task) = waiters.pop_front() {
+                // Unpark the task
+                match unsafe { abi::wup_tsk(task) } {
+                    // The task already has a token.
+                    abi::E_QOVR => {}
+                    // Can't undo the effect; abort the program on failure
+                    er => {
+                        expect_success_aborting(er, &"wup_tsk");
+                    }
+                }
+            }
+        });
+    }
+
+    pub unsafe fn notify_all(&self) {
+        self.waiters.with_locked(|waiters| {
+            while let Some(task) = waiters.pop_front() {
+                // Unpark the task
+                match unsafe { abi::wup_tsk(task) } {
+                    // The task already has a token.
+                    abi::E_QOVR => {}
+                    // Can't undo the effect; abort the program on failure
+                    er => {
+                        expect_success_aborting(er, &"wup_tsk");
+                    }
+                }
+            }
+        });
+    }
+
+    pub unsafe fn wait(&self, mutex: &Mutex) {
+        // Construct `Waiter`.
+        let mut waiter = waiter_queue::Waiter::new();
+        let waiter = NonNull::from(&mut waiter);
+
+        self.waiters.with_locked(|waiters| unsafe {
+            waiters.insert(waiter);
+        });
+
+        unsafe { mutex.unlock() };
+
+        // Wait until `waiter` is removed from the queue
+        loop {
+            // Park the current task
+            expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
+
+            if !self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) {
+                break;
+            }
+        }
+
+        unsafe { mutex.lock() };
+    }
+
+    pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+        // Construct and pin `Waiter`
+        let mut waiter = waiter_queue::Waiter::new();
+        let waiter = NonNull::from(&mut waiter);
+
+        self.waiters.with_locked(|waiters| unsafe {
+            waiters.insert(waiter);
+        });
+
+        unsafe { mutex.unlock() };
+
+        // Park the current task and do not wake up until the timeout elapses
+        // or the task gets woken up by `notify_*`
+        match with_tmos_strong(dur, |tmo| {
+            let er = unsafe { abi::tslp_tsk(tmo) };
+            if er == 0 {
+                // We were unparked. Are we really dequeued?
+                if self.waiters.with_locked(|waiters| unsafe { waiters.is_queued(waiter) }) {
+                    // No we are not. Continue waiting.
+                    return abi::E_TMOUT;
+                }
+            }
+            er
+        }) {
+            abi::E_TMOUT => {}
+            er => {
+                expect_success_aborting(er, &"tslp_tsk");
+            }
+        }
+
+        // Remove `waiter` from `self.waiters`. If `waiter` is still in
+        // `waiters`, it means we woke up because of a timeout. Otherwise,
+        // we woke up because of `notify_*`.
+        let success = self.waiters.with_locked(|waiters| unsafe { !waiters.remove(waiter) });
+
+        unsafe { mutex.lock() };
+        success
+    }
+
+    pub unsafe fn destroy(&self) {}
+}
+
+mod waiter_queue {
+    use super::*;
+
+    pub struct WaiterQueue {
+        head: Option<ListHead>,
+    }
+
+    #[derive(Copy, Clone)]
+    struct ListHead {
+        first: NonNull<Waiter>,
+        last: NonNull<Waiter>,
+    }
+
+    unsafe impl Send for ListHead {}
+    unsafe impl Sync for ListHead {}
+
+    pub struct Waiter {
+        // These fields are only accessed through `&[mut] WaiterQueue`.
+        /// The waiting task's ID. Will be zeroed when the task is woken up
+        /// and removed from a queue.
+        task: abi::ID,
+        priority: abi::PRI,
+        prev: Option<NonNull<Waiter>>,
+        next: Option<NonNull<Waiter>>,
+    }
+
+    unsafe impl Send for Waiter {}
+    unsafe impl Sync for Waiter {}
+
+    impl Waiter {
+        #[inline]
+        pub fn new() -> Self {
+            let task = task::current_task_id();
+            let priority = task::task_priority(abi::TSK_SELF);
+
+            // Zeroness of `Waiter::task` indicates whether the `Waiter` is
+            // linked to a queue or not. This invariant is important for
+            // the correctness.
+            debug_assert_ne!(task, 0);
+
+            Self { task, priority, prev: None, next: None }
+        }
+    }
+
+    impl WaiterQueue {
+        #[inline]
+        pub const fn new() -> Self {
+            Self { head: None }
+        }
+
+        /// # Safety
+        ///
+        ///  - The caller must own `*waiter_ptr`. The caller will lose the
+        ///    ownership until `*waiter_ptr` is removed from `self`.
+        ///
+        ///  - `*waiter_ptr` must be valid until it's removed from the queue.
+        ///
+        ///  - `*waiter_ptr` must not have been previously inserted to a `WaiterQueue`.
+        ///
+        pub unsafe fn insert(&mut self, mut waiter_ptr: NonNull<Waiter>) {
+            unsafe {
+                let waiter = waiter_ptr.as_mut();
+
+                debug_assert!(waiter.prev.is_none());
+                debug_assert!(waiter.next.is_none());
+
+                if let Some(head) = &mut self.head {
+                    // Find the insertion position and insert `waiter`
+                    let insert_after = {
+                        let mut cursor = head.last;
+                        loop {
+                            if waiter.priority <= cursor.as_ref().priority {
+                                // `cursor` and all previous waiters have the same or higher
+                                // priority than `current_task_priority`. Insert the new
+                                // waiter right after `cursor`.
+                                break Some(cursor);
+                            }
+                            cursor = if let Some(prev) = cursor.as_ref().prev {
+                                prev
+                            } else {
+                                break None;
+                            };
+                        }
+                    };
+
+                    if let Some(mut insert_after) = insert_after {
+                        // Insert `waiter` after `insert_after`
+                        let insert_before = insert_after.as_ref().prev;
+
+                        waiter.prev = Some(insert_after);
+                        insert_after.as_mut().next = Some(waiter_ptr);
+
+                        waiter.next = insert_before;
+                        if let Some(mut insert_before) = insert_before {
+                            insert_before.as_mut().prev = Some(waiter_ptr);
+                        }
+                    } else {
+                        // Insert `waiter` to the front
+                        waiter.next = Some(head.first);
+                        head.first.as_mut().prev = Some(waiter_ptr);
+                        head.first = waiter_ptr;
+                    }
+                } else {
+                    // `waiter` is the only element
+                    self.head = Some(ListHead { first: waiter_ptr, last: waiter_ptr });
+                }
+            }
+        }
+
+        /// Given a `Waiter` that was previously inserted to `self`, remove
+        /// it from `self` if it's still there.
+        #[inline]
+        pub unsafe fn remove(&mut self, mut waiter_ptr: NonNull<Waiter>) -> bool {
+            unsafe {
+                let waiter = waiter_ptr.as_mut();
+                if waiter.task != 0 {
+                    let head = self.head.as_mut().unwrap();
+
+                    match (waiter.prev, waiter.next) {
+                        (Some(mut prev), Some(mut next)) => {
+                            prev.as_mut().next = Some(next);
+                            next.as_mut().next = Some(prev);
+                        }
+                        (None, Some(mut next)) => {
+                            head.first = next;
+                            next.as_mut().next = None;
+                        }
+                        (Some(mut prev), None) => {
+                            prev.as_mut().next = None;
+                            head.last = prev;
+                        }
+                        (None, None) => {
+                            self.head = None;
+                        }
+                    }
+
+                    waiter.task = 0;
+
+                    true
+                } else {
+                    false
+                }
+            }
+        }
+
+        /// Given a `Waiter` that was previously inserted to `self`, return a
+        /// flag indicating whether it's still in `self`.
+        #[inline]
+        pub unsafe fn is_queued(&self, waiter: NonNull<Waiter>) -> bool {
+            unsafe { waiter.as_ref().task != 0 }
+        }
+
+        pub fn pop_front(&mut self) -> Option<abi::ID> {
+            unsafe {
+                let head = self.head.as_mut()?;
+                let waiter = head.first.as_mut();
+
+                // Get the ID
+                let id = replace(&mut waiter.task, 0);
+
+                // Unlink the waiter
+                if let Some(mut next) = waiter.next {
+                    head.first = next;
+                    next.as_mut().prev = None;
+                } else {
+                    self.head = None;
+                }
+
+                Some(id)
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/itron/error.rs b/library/std/src/sys/itron/error.rs
new file mode 100644 (file)
index 0000000..830c60d
--- /dev/null
@@ -0,0 +1,159 @@
+use crate::{fmt, io::ErrorKind};
+
+use super::abi;
+
+/// Wraps a μITRON error code.
+#[derive(Debug, Copy, Clone)]
+pub struct ItronError {
+    er: abi::ER,
+}
+
+impl ItronError {
+    /// Construct `ItronError` from the specified error code. Returns `None` if the
+    /// error code does not represent a failure or warning.
+    #[inline]
+    pub fn new(er: abi::ER) -> Option<Self> {
+        if er < 0 { Some(Self { er }) } else { None }
+    }
+
+    /// Returns `Ok(er)` if `er` represents a success or `Err(_)` otherwise.
+    #[inline]
+    pub fn err_if_negative(er: abi::ER) -> Result<abi::ER, Self> {
+        if let Some(error) = Self::new(er) { Err(error) } else { Ok(er) }
+    }
+
+    /// Get the raw error code.
+    #[inline]
+    pub fn as_raw(&self) -> abi::ER {
+        self.er
+    }
+}
+
+impl fmt::Display for ItronError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Allow the platforms to extend `error_name`
+        if let Some(name) = crate::sys::error::error_name(self.er) {
+            write!(f, "{} ({})", name, self.er)
+        } else {
+            write!(f, "{}", self.er)
+        }
+    }
+}
+
+/// Describe the specified μITRON error code. Returns `None` if it's an
+/// undefined error code.
+pub fn error_name(er: abi::ER) -> Option<&'static str> {
+    match er {
+        // Success
+        er if er >= 0 => None,
+
+        // μITRON 4.0
+        abi::E_SYS => Some("system error"),
+        abi::E_NOSPT => Some("unsupported function"),
+        abi::E_RSFN => Some("reserved function code"),
+        abi::E_RSATR => Some("reserved attribute"),
+        abi::E_PAR => Some("parameter error"),
+        abi::E_ID => Some("invalid ID number"),
+        abi::E_CTX => Some("context error"),
+        abi::E_MACV => Some("memory access violation"),
+        abi::E_OACV => Some("object access violation"),
+        abi::E_ILUSE => Some("illegal service call use"),
+        abi::E_NOMEM => Some("insufficient memory"),
+        abi::E_NOID => Some("no ID number available"),
+        abi::E_OBJ => Some("object state error"),
+        abi::E_NOEXS => Some("non-existent object"),
+        abi::E_QOVR => Some("queue overflow"),
+        abi::E_RLWAI => Some("forced release from waiting"),
+        abi::E_TMOUT => Some("polling failure or timeout"),
+        abi::E_DLT => Some("waiting object deleted"),
+        abi::E_CLS => Some("waiting object state changed"),
+        abi::E_WBLK => Some("non-blocking code accepted"),
+        abi::E_BOVR => Some("buffer overflow"),
+
+        // The TOPPERS third generation kernels
+        abi::E_NORES => Some("insufficient system resources"),
+        abi::E_RASTER => Some("termination request raised"),
+        abi::E_COMM => Some("communication failure"),
+
+        _ => None,
+    }
+}
+
+pub fn decode_error_kind(er: abi::ER) -> ErrorKind {
+    match er {
+        // Success
+        er if er >= 0 => ErrorKind::Uncategorized,
+
+        // μITRON 4.0
+        // abi::E_SYS
+        abi::E_NOSPT => ErrorKind::Unsupported, // Some("unsupported function"),
+        abi::E_RSFN => ErrorKind::InvalidInput, // Some("reserved function code"),
+        abi::E_RSATR => ErrorKind::InvalidInput, // Some("reserved attribute"),
+        abi::E_PAR => ErrorKind::InvalidInput,  // Some("parameter error"),
+        abi::E_ID => ErrorKind::NotFound,       // Some("invalid ID number"),
+        // abi::E_CTX
+        abi::E_MACV => ErrorKind::PermissionDenied, // Some("memory access violation"),
+        abi::E_OACV => ErrorKind::PermissionDenied, // Some("object access violation"),
+        // abi::E_ILUSE
+        abi::E_NOMEM => ErrorKind::OutOfMemory, // Some("insufficient memory"),
+        abi::E_NOID => ErrorKind::OutOfMemory,  // Some("no ID number available"),
+        // abi::E_OBJ
+        abi::E_NOEXS => ErrorKind::NotFound, // Some("non-existent object"),
+        // abi::E_QOVR
+        abi::E_RLWAI => ErrorKind::Interrupted, // Some("forced release from waiting"),
+        abi::E_TMOUT => ErrorKind::TimedOut,    // Some("polling failure or timeout"),
+        // abi::E_DLT
+        // abi::E_CLS
+        // abi::E_WBLK
+        // abi::E_BOVR
+
+        // The TOPPERS third generation kernels
+        abi::E_NORES => ErrorKind::OutOfMemory, // Some("insufficient system resources"),
+        // abi::E_RASTER
+        // abi::E_COMM
+        _ => ErrorKind::Uncategorized,
+    }
+}
+
+/// Similar to `ItronError::err_if_negative(er).expect()` except that, while
+/// panicking, it prints the message to `panic_output` and aborts the program
+/// instead. This ensures the error message is not obscured by double
+/// panicking.
+///
+/// This is useful for diagnosing creation failures of synchronization
+/// primitives that are used by `std`'s internal mechanisms. Such failures
+/// are common when the system is mis-configured to provide a too-small pool for
+/// kernel objects.
+#[inline]
+pub fn expect_success(er: abi::ER, msg: &&str) -> abi::ER {
+    match ItronError::err_if_negative(er) {
+        Ok(x) => x,
+        Err(e) => fail(e, msg),
+    }
+}
+
+/// Similar to `ItronError::err_if_negative(er).expect()` but aborts instead.
+///
+/// Use this where panicking is not allowed or the effect of the failure
+/// would be persistent.
+#[inline]
+pub fn expect_success_aborting(er: abi::ER, msg: &&str) -> abi::ER {
+    match ItronError::err_if_negative(er) {
+        Ok(x) => x,
+        Err(e) => fail_aborting(e, msg),
+    }
+}
+
+#[cold]
+pub fn fail(e: impl fmt::Display, msg: &&str) -> ! {
+    if crate::thread::panicking() {
+        fail_aborting(e, msg)
+    } else {
+        panic!("{} failed: {}", *msg, e)
+    }
+}
+
+#[cold]
+pub fn fail_aborting(e: impl fmt::Display, msg: &&str) -> ! {
+    rtabort!("{} failed: {}", *msg, e)
+}
diff --git a/library/std/src/sys/itron/mutex.rs b/library/std/src/sys/itron/mutex.rs
new file mode 100644 (file)
index 0000000..e01f595
--- /dev/null
@@ -0,0 +1,183 @@
+//! Mutex implementation backed by μITRON mutexes. Assumes `acre_mtx` and
+//! `TA_INHERIT` are available.
+use super::{
+    abi,
+    error::{expect_success, expect_success_aborting, fail, ItronError},
+    spin::SpinIdOnceCell,
+};
+use crate::cell::UnsafeCell;
+
+pub struct Mutex {
+    /// The ID of the underlying mutex object
+    mtx: SpinIdOnceCell<()>,
+}
+
+pub type MovableMutex = Mutex;
+
+/// Create a mutex object. This function never panics.
+fn new_mtx() -> Result<abi::ID, ItronError> {
+    ItronError::err_if_negative(unsafe {
+        abi::acre_mtx(&abi::T_CMTX {
+            // Priority inheritance mutex
+            mtxatr: abi::TA_INHERIT,
+            // Unused
+            ceilpri: 0,
+        })
+    })
+}
+
+impl Mutex {
+    pub const fn new() -> Mutex {
+        Mutex { mtx: SpinIdOnceCell::new() }
+    }
+
+    pub unsafe fn init(&mut self) {
+        // Initialize `self.mtx` eagerly
+        let id = new_mtx().unwrap_or_else(|e| fail(e, &"acre_mtx"));
+        unsafe { self.mtx.set_unchecked((id, ())) };
+    }
+
+    /// Get the inner mutex's ID, which is lazily created.
+    fn raw(&self) -> abi::ID {
+        match self.mtx.get_or_try_init(|| new_mtx().map(|id| (id, ()))) {
+            Ok((id, ())) => id,
+            Err(e) => fail(e, &"acre_mtx"),
+        }
+    }
+
+    pub unsafe fn lock(&self) {
+        let mtx = self.raw();
+        expect_success(unsafe { abi::loc_mtx(mtx) }, &"loc_mtx");
+    }
+
+    pub unsafe fn unlock(&self) {
+        let mtx = unsafe { self.mtx.get_unchecked().0 };
+        expect_success_aborting(unsafe { abi::unl_mtx(mtx) }, &"unl_mtx");
+    }
+
+    pub unsafe fn try_lock(&self) -> bool {
+        let mtx = self.raw();
+        match unsafe { abi::ploc_mtx(mtx) } {
+            abi::E_TMOUT => false,
+            er => {
+                expect_success(er, &"ploc_mtx");
+                true
+            }
+        }
+    }
+
+    pub unsafe fn destroy(&self) {
+        if let Some(mtx) = self.mtx.get().map(|x| x.0) {
+            expect_success_aborting(unsafe { abi::del_mtx(mtx) }, &"del_mtx");
+        }
+    }
+}
+
+pub(super) struct MutexGuard<'a>(&'a Mutex);
+
+impl<'a> MutexGuard<'a> {
+    #[inline]
+    pub(super) fn lock(x: &'a Mutex) -> Self {
+        unsafe { x.lock() };
+        Self(x)
+    }
+}
+
+impl Drop for MutexGuard<'_> {
+    #[inline]
+    fn drop(&mut self) {
+        unsafe { self.0.unlock() };
+    }
+}
+
+// All empty stubs because this platform does not yet support threads, so lock
+// acquisition always succeeds.
+pub struct ReentrantMutex {
+    /// The ID of the underlying mutex object
+    mtx: abi::ID,
+    /// The lock count.
+    count: UnsafeCell<usize>,
+}
+
+unsafe impl Send for ReentrantMutex {}
+unsafe impl Sync for ReentrantMutex {}
+
+impl ReentrantMutex {
+    pub const unsafe fn uninitialized() -> ReentrantMutex {
+        ReentrantMutex { mtx: 0, count: UnsafeCell::new(0) }
+    }
+
+    pub unsafe fn init(&mut self) {
+        self.mtx = expect_success(
+            unsafe {
+                abi::acre_mtx(&abi::T_CMTX {
+                    // Priority inheritance mutex
+                    mtxatr: abi::TA_INHERIT,
+                    // Unused
+                    ceilpri: 0,
+                })
+            },
+            &"acre_mtx",
+        );
+    }
+
+    pub unsafe fn lock(&self) {
+        match unsafe { abi::loc_mtx(self.mtx) } {
+            abi::E_OBJ => {
+                // Recursive lock
+                unsafe {
+                    let count = &mut *self.count.get();
+                    if let Some(new_count) = count.checked_add(1) {
+                        *count = new_count;
+                    } else {
+                        // counter overflow
+                        rtabort!("lock count overflow");
+                    }
+                }
+            }
+            er => {
+                expect_success(er, &"loc_mtx");
+            }
+        }
+    }
+
+    pub unsafe fn unlock(&self) {
+        unsafe {
+            let count = &mut *self.count.get();
+            if *count > 0 {
+                *count -= 1;
+                return;
+            }
+        }
+
+        expect_success_aborting(unsafe { abi::unl_mtx(self.mtx) }, &"unl_mtx");
+    }
+
+    pub unsafe fn try_lock(&self) -> bool {
+        let er = unsafe { abi::ploc_mtx(self.mtx) };
+        if er == abi::E_OBJ {
+            // Recursive lock
+            unsafe {
+                let count = &mut *self.count.get();
+                if let Some(new_count) = count.checked_add(1) {
+                    *count = new_count;
+                } else {
+                    // counter overflow
+                    rtabort!("lock count overflow");
+                }
+            }
+            true
+        } else if er == abi::E_TMOUT {
+            // Locked by another thread
+            false
+        } else {
+            expect_success(er, &"ploc_mtx");
+            // Top-level lock by the current thread
+            true
+        }
+    }
+
+    pub unsafe fn destroy(&self) {
+        expect_success_aborting(unsafe { abi::del_mtx(self.mtx) }, &"del_mtx");
+    }
+}
diff --git a/library/std/src/sys/itron/spin.rs b/library/std/src/sys/itron/spin.rs
new file mode 100644 (file)
index 0000000..d0149d1
--- /dev/null
@@ -0,0 +1,164 @@
+use super::abi;
+use crate::{
+    cell::UnsafeCell,
+    convert::TryFrom,
+    mem::MaybeUninit,
+    sync::atomic::{AtomicBool, AtomicUsize, Ordering},
+};
+
+/// A mutex implemented by `dis_dsp` (for intra-core synchronization) and a
+/// spinlock (for inter-core synchronization).
+pub struct SpinMutex<T = ()> {
+    locked: AtomicBool,
+    data: UnsafeCell<T>,
+}
+
+impl<T> SpinMutex<T> {
+    #[inline]
+    pub const fn new(x: T) -> Self {
+        Self { locked: AtomicBool::new(false), data: UnsafeCell::new(x) }
+    }
+
+    /// Acquire a lock.
+    #[inline]
+    pub fn with_locked<R>(&self, f: impl FnOnce(&mut T) -> R) -> R {
+        struct SpinMutexGuard<'a>(&'a AtomicBool);
+
+        impl Drop for SpinMutexGuard<'_> {
+            #[inline]
+            fn drop(&mut self) {
+                self.0.store(false, Ordering::Release);
+                unsafe { abi::ena_dsp() };
+            }
+        }
+
+        let _guard;
+        if unsafe { abi::sns_dsp() } == 0 {
+            let er = unsafe { abi::dis_dsp() };
+            debug_assert!(er >= 0);
+
+            // Wait until the current processor acquires a lock.
+            while self.locked.swap(true, Ordering::Acquire) {}
+
+            _guard = SpinMutexGuard(&self.locked);
+        }
+
+        f(unsafe { &mut *self.data.get() })
+    }
+}
+
+/// `OnceCell<(abi::ID, T)>` implemented by `dis_dsp` (for intra-core
+/// synchronization) and a spinlock (for inter-core synchronization).
+///
+/// It's assumed that `0` is not a valid ID, and all kernel
+/// object IDs fall into range `1..=usize::MAX`.
+pub struct SpinIdOnceCell<T = ()> {
+    id: AtomicUsize,
+    spin: SpinMutex<()>,
+    extra: UnsafeCell<MaybeUninit<T>>,
+}
+
+const ID_UNINIT: usize = 0;
+
+impl<T> SpinIdOnceCell<T> {
+    #[inline]
+    pub const fn new() -> Self {
+        Self {
+            id: AtomicUsize::new(ID_UNINIT),
+            extra: UnsafeCell::new(MaybeUninit::uninit()),
+            spin: SpinMutex::new(()),
+        }
+    }
+
+    #[inline]
+    pub fn get(&self) -> Option<(abi::ID, &T)> {
+        match self.id.load(Ordering::Acquire) {
+            ID_UNINIT => None,
+            id => Some((id as abi::ID, unsafe { (&*self.extra.get()).assume_init_ref() })),
+        }
+    }
+
+    #[inline]
+    pub fn get_mut(&mut self) -> Option<(abi::ID, &mut T)> {
+        match *self.id.get_mut() {
+            ID_UNINIT => None,
+            id => Some((id as abi::ID, unsafe { (&mut *self.extra.get()).assume_init_mut() })),
+        }
+    }
+
+    #[inline]
+    pub unsafe fn get_unchecked(&self) -> (abi::ID, &T) {
+        (self.id.load(Ordering::Acquire) as abi::ID, unsafe {
+            (&*self.extra.get()).assume_init_ref()
+        })
+    }
+
+    /// Assign the content without checking if it's already initialized or
+    /// being initialized.
+    pub unsafe fn set_unchecked(&self, (id, extra): (abi::ID, T)) {
+        debug_assert!(self.get().is_none());
+
+        // Assumption: A positive `abi::ID` fits in `usize`.
+        debug_assert!(id >= 0);
+        debug_assert!(usize::try_from(id).is_ok());
+        let id = id as usize;
+
+        unsafe { *self.extra.get() = MaybeUninit::new(extra) };
+        self.id.store(id, Ordering::Release);
+    }
+
+    /// Gets the contents of the cell, initializing it with `f` if
+    /// the cell was empty. If the cell was empty and `f` failed, an
+    /// error is returned.
+    ///
+    /// Warning: `f` must not perform a blocking operation, which
+    /// includes panicking.
+    #[inline]
+    pub fn get_or_try_init<F, E>(&self, f: F) -> Result<(abi::ID, &T), E>
+    where
+        F: FnOnce() -> Result<(abi::ID, T), E>,
+    {
+        // Fast path
+        if let Some(x) = self.get() {
+            return Ok(x);
+        }
+
+        self.initialize(f)?;
+
+        debug_assert!(self.get().is_some());
+
+        // Safety: The inner value has been initialized
+        Ok(unsafe { self.get_unchecked() })
+    }
+
+    fn initialize<F, E>(&self, f: F) -> Result<(), E>
+    where
+        F: FnOnce() -> Result<(abi::ID, T), E>,
+    {
+        self.spin.with_locked(|_| {
+            if self.id.load(Ordering::Relaxed) == ID_UNINIT {
+                let (initialized_id, initialized_extra) = f()?;
+
+                // Assumption: A positive `abi::ID` fits in `usize`.
+                debug_assert!(initialized_id >= 0);
+                debug_assert!(usize::try_from(initialized_id).is_ok());
+                let initialized_id = initialized_id as usize;
+
+                // Store the initialized contents. Use the release ordering to
+                // make sure the write is visible to the callers of `get`.
+                unsafe { *self.extra.get() = MaybeUninit::new(initialized_extra) };
+                self.id.store(initialized_id, Ordering::Release);
+            }
+            Ok(())
+        })
+    }
+}
+
+impl<T> Drop for SpinIdOnceCell<T> {
+    #[inline]
+    fn drop(&mut self) {
+        if self.get_mut().is_some() {
+            unsafe { (&mut *self.extra.get()).assume_init_drop() };
+        }
+    }
+}
diff --git a/library/std/src/sys/itron/task.rs b/library/std/src/sys/itron/task.rs
new file mode 100644 (file)
index 0000000..94beb50
--- /dev/null
@@ -0,0 +1,44 @@
+use super::{
+    abi,
+    error::{fail, fail_aborting, ItronError},
+};
+
+use crate::mem::MaybeUninit;
+
+/// Get the ID of the task in Running state. Panics on failure.
+#[inline]
+pub fn current_task_id() -> abi::ID {
+    try_current_task_id().unwrap_or_else(|e| fail(e, &"get_tid"))
+}
+
+/// Get the ID of the task in Running state. Aborts on failure.
+#[inline]
+pub fn current_task_id_aborting() -> abi::ID {
+    try_current_task_id().unwrap_or_else(|e| fail_aborting(e, &"get_tid"))
+}
+
+/// Get the ID of the task in Running state.
+#[inline]
+pub fn try_current_task_id() -> Result<abi::ID, ItronError> {
+    unsafe {
+        let mut out = MaybeUninit::uninit();
+        ItronError::err_if_negative(abi::get_tid(out.as_mut_ptr()))?;
+        Ok(out.assume_init())
+    }
+}
+
+/// Get the specified task's priority. Panics on failure.
+#[inline]
+pub fn task_priority(task: abi::ID) -> abi::PRI {
+    try_task_priority(task).unwrap_or_else(|e| fail(e, &"get_pri"))
+}
+
+/// Get the specified task's priority.
+#[inline]
+pub fn try_task_priority(task: abi::ID) -> Result<abi::PRI, ItronError> {
+    unsafe {
+        let mut out = MaybeUninit::uninit();
+        ItronError::err_if_negative(abi::get_pri(task, out.as_mut_ptr()))?;
+        Ok(out.assume_init())
+    }
+}
diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs
new file mode 100644 (file)
index 0000000..4feb9c5
--- /dev/null
@@ -0,0 +1,352 @@
+//! Thread implementation backed by μITRON tasks. Assumes `acre_tsk` and
+//! `exd_tsk` are available.
+use super::{
+    abi,
+    error::{expect_success, expect_success_aborting, ItronError},
+    task,
+    time::dur2reltims,
+};
+use crate::{
+    cell::UnsafeCell,
+    convert::TryFrom,
+    ffi::CStr,
+    hint, io,
+    mem::ManuallyDrop,
+    sync::atomic::{AtomicUsize, Ordering},
+    sys::thread_local_dtor::run_dtors,
+    time::Duration,
+};
+
+pub struct Thread {
+    inner: ManuallyDrop<Box<ThreadInner>>,
+
+    /// The ID of the underlying task.
+    task: abi::ID,
+}
+
+/// State data shared between a parent thread and child thread. It's dropped on
+/// a transition to one of the final states.
+struct ThreadInner {
+    /// This field is used on thread creation to pass a closure from
+    /// `Thread::new` to the created task.
+    start: UnsafeCell<ManuallyDrop<Box<dyn FnOnce()>>>,
+
+    /// A state machine. Each transition is annotated with `[...]` in the
+    /// source code.
+    ///
+    /// ```text
+    ///
+    ///    <P>: parent, <C>: child, (?): don't-care
+    ///
+    ///       DETACHED (-1)  -------------------->  EXITED (?)
+    ///                        <C>finish/exd_tsk
+    ///          ^
+    ///          |
+    ///          | <P>detach
+    ///          |
+    ///
+    ///       INIT (0)  ----------------------->  FINISHED (-1)
+    ///                        <C>finish
+    ///          |                                    |
+    ///          | <P>join/slp_tsk                    | <P>join/del_tsk
+    ///          |                                    | <P>detach/del_tsk
+    ///          v                                    v
+    ///
+    ///       JOINING                              JOINED (?)
+    ///     (parent_tid)
+    ///                                            ^
+    ///             \                             /
+    ///              \  <C>finish/wup_tsk        / <P>slp_tsk-complete/ter_tsk
+    ///               \                         /                      & del_tsk
+    ///                \                       /
+    ///                 '--> JOIN_FINALIZE ---'
+    ///                          (-1)
+    ///
+    lifecycle: AtomicUsize,
+}
+
+// Safety: The only `!Sync` field, `ThreadInner::start`, is only touched by
+//         the task represented by `ThreadInner`.
+unsafe impl Sync for ThreadInner {}
+
+const LIFECYCLE_INIT: usize = 0;
+const LIFECYCLE_FINISHED: usize = usize::MAX;
+const LIFECYCLE_DETACHED: usize = usize::MAX;
+const LIFECYCLE_JOIN_FINALIZE: usize = usize::MAX;
+const LIFECYCLE_DETACHED_OR_JOINED: usize = usize::MAX;
+const LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE: usize = usize::MAX;
+// there's no single value for `JOINING`
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * crate::mem::size_of::<usize>();
+
+impl Thread {
+    /// # Safety
+    ///
+    /// See `thread::Builder::spawn_unchecked` for safety requirements.
+    pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+        // Inherit the current task's priority
+        let current_task = task::try_current_task_id().map_err(|e| e.as_io_error())?;
+        let priority = task::try_task_priority(current_task).map_err(|e| e.as_io_error())?;
+
+        let inner = Box::new(ThreadInner {
+            start: UnsafeCell::new(ManuallyDrop::new(p)),
+            lifecycle: AtomicUsize::new(LIFECYCLE_INIT),
+        });
+
+        unsafe extern "C" fn trampoline(exinf: isize) {
+            // Safety: `ThreadInner` is alive at this point
+            let inner = unsafe { &*(exinf as *const ThreadInner) };
+
+            // Safety: Since `trampoline` is called only once for each
+            //         `ThreadInner` and only `trampoline` touches `start`,
+            //         `start` contains contents and is safe to mutably borrow.
+            let p = unsafe { ManuallyDrop::take(&mut *inner.start.get()) };
+            p();
+
+            // Fix the current thread's state just in case, so that the
+            // destructors won't abort
+            // Safety: Not really unsafe
+            let _ = unsafe { abi::unl_cpu() };
+            let _ = unsafe { abi::ena_dsp() };
+
+            // Run TLS destructors now because they are not
+            // called automatically for terminated tasks.
+            unsafe { run_dtors() };
+
+            let old_lifecycle = inner
+                .lifecycle
+                .swap(LIFECYCLE_EXITED_OR_FINISHED_OR_JOIN_FINALIZE, Ordering::Release);
+
+            match old_lifecycle {
+                LIFECYCLE_DETACHED => {
+                    // [DETACHED → EXITED]
+                    // No one will ever join, so we'll ask the collector task to
+                    // delete the task.
+
+                    // In this case, `inner`'s ownership has been moved to us,
+                    // And we are responsible for dropping it. The acquire
+                    // ordering is not necessary because the parent thread made
+                    // no memory acccess needing synchronization since the call
+                    // to `acre_tsk`.
+                    // Safety: See above.
+                    let _ = unsafe { Box::from_raw(inner as *const _ as *mut ThreadInner) };
+
+                    // Safety: There are no pinned references to the stack
+                    unsafe { terminate_and_delete_current_task() };
+                }
+                LIFECYCLE_INIT => {
+                    // [INIT → FINISHED]
+                    // The parent hasn't decided whether to join or detach this
+                    // thread yet. Whichever option the parent chooses,
+                    // it'll have to delete this task.
+                    // Since the parent might drop `*inner` as soon as it sees
+                    // `FINISHED`, the release ordering must be used in the
+                    // above `swap` call.
+                }
+                parent_tid => {
+                    // Since the parent might drop `*inner` and terminate us as
+                    // soon as it sees `JOIN_FINALIZE`, the release ordering
+                    // must be used in the above `swap` call.
+
+                    // [JOINING → JOIN_FINALIZE]
+                    // Wake up the parent task.
+                    expect_success(
+                        unsafe {
+                            let mut er = abi::wup_tsk(parent_tid as _);
+                            if er == abi::E_QOVR {
+                                // `E_QOVR` indicates there's already
+                                // a parking token
+                                er = abi::E_OK;
+                            }
+                            er
+                        },
+                        &"wup_tsk",
+                    );
+                }
+            }
+        }
+
+        let inner_ptr = (&*inner) as *const ThreadInner;
+
+        let new_task = ItronError::err_if_negative(unsafe {
+            abi::acre_tsk(&abi::T_CTSK {
+                // Activate this task immediately
+                tskatr: abi::TA_ACT,
+                exinf: inner_ptr as abi::EXINF,
+                // The entry point
+                task: Some(trampoline),
+                itskpri: priority,
+                stksz: stack,
+                // Let the kernel allocate the stack,
+                stk: crate::ptr::null_mut(),
+            })
+        })
+        .map_err(|e| e.as_io_error())?;
+
+        Ok(Self { inner: ManuallyDrop::new(inner), task: new_task })
+    }
+
+    pub fn yield_now() {
+        expect_success(unsafe { abi::rot_rdq(abi::TPRI_SELF) }, &"rot_rdq");
+    }
+
+    pub fn set_name(_name: &CStr) {
+        // nope
+    }
+
+    pub fn sleep(dur: Duration) {
+        for timeout in dur2reltims(dur) {
+            expect_success(unsafe { abi::dly_tsk(timeout) }, &"dly_tsk");
+        }
+    }
+
+    pub fn join(mut self) {
+        let inner = &*self.inner;
+        // Get the current task ID. Panicking here would cause a resource leak,
+        // so just abort on failure.
+        let current_task = task::current_task_id_aborting();
+        debug_assert!(usize::try_from(current_task).is_ok());
+        debug_assert_ne!(current_task as usize, LIFECYCLE_INIT);
+        debug_assert_ne!(current_task as usize, LIFECYCLE_DETACHED);
+
+        let current_task = current_task as usize;
+
+        match inner.lifecycle.swap(current_task, Ordering::Acquire) {
+            LIFECYCLE_INIT => {
+                // [INIT → JOINING]
+                // The child task will transition the state to `JOIN_FINALIZE`
+                // and wake us up.
+                loop {
+                    expect_success_aborting(unsafe { abi::slp_tsk() }, &"slp_tsk");
+                    // To synchronize with the child task's memory accesses to
+                    // `inner` up to the point of the assignment of
+                    // `JOIN_FINALIZE`, `Ordering::Acquire` must be used for the
+                    // `load`.
+                    if inner.lifecycle.load(Ordering::Acquire) == LIFECYCLE_JOIN_FINALIZE {
+                        break;
+                    }
+                }
+
+                // [JOIN_FINALIZE → JOINED]
+            }
+            LIFECYCLE_FINISHED => {
+                // [FINISHED → JOINED]
+                // To synchronize with the child task's memory accesses to
+                // `inner` up to the point of the assignment of `FINISHED`,
+                // `Ordering::Acquire` must be used for the above `swap` call`.
+            }
+            _ => unsafe { hint::unreachable_unchecked() },
+        }
+
+        // Terminate and delete the task
+        // Safety: `self.task` still represents a task we own (because this
+        //         method or `detach_inner` is called only once for each
+        //         `Thread`). The task indicated that it's safe to delete by
+        //         entering the `FINISHED` or `JOIN_FINALIZE` state.
+        unsafe { terminate_and_delete_task(self.task) };
+
+        // In either case, we are responsible for dropping `inner`.
+        // Safety: The contents of `self.inner` will not be accessed hereafter
+        let _inner = unsafe { ManuallyDrop::take(&mut self.inner) };
+
+        // Skip the destructor (because it would attempt to detach the thread)
+        crate::mem::forget(self);
+    }
+}
+
+impl Drop for Thread {
+    fn drop(&mut self) {
+        // Detach the thread.
+        match self.inner.lifecycle.swap(LIFECYCLE_DETACHED_OR_JOINED, Ordering::Acquire) {
+            LIFECYCLE_INIT => {
+                // [INIT → DETACHED]
+                // When the time comes, the child will figure out that no
+                // one will ever join it.
+                // The ownership of `self.inner` is moved to the child thread.
+                // However, the release ordering is not necessary because we
+                // made no memory acccess needing synchronization since the call
+                // to `acre_tsk`.
+            }
+            LIFECYCLE_FINISHED => {
+                // [FINISHED → JOINED]
+                // The task has already decided that we should delete the task.
+                // To synchronize with the child task's memory accesses to
+                // `inner` up to the point of the assignment of `FINISHED`,
+                // the acquire ordering is required for the above `swap` call.
+
+                // Terminate and delete the task
+                // Safety: `self.task` still represents a task we own (because
+                //         this method or `join_inner` is called only once for
+                //         each `Thread`). The task  indicated that it's safe to
+                //         delete by entering the `FINISHED` state.
+                unsafe { terminate_and_delete_task(self.task) };
+
+                // Wwe are responsible for dropping `inner`.
+                // Safety: The contents of `self.inner` will not be accessed
+                //         hereafter
+                unsafe { ManuallyDrop::drop(&mut self.inner) };
+            }
+            _ => unsafe { hint::unreachable_unchecked() },
+        }
+    }
+}
+
+pub mod guard {
+    pub type Guard = !;
+    pub unsafe fn current() -> Option<Guard> {
+        None
+    }
+    pub unsafe fn init() -> Option<Guard> {
+        None
+    }
+}
+
+/// Terminate and delete the specified task.
+///
+/// This function will abort if `deleted_task` refers to the calling task.
+///
+/// It is assumed that the specified task is solely managed by the caller -
+/// i.e., other threads must not "resuscitate" the specified task or delete it
+/// prematurely while this function is still in progress. It is allowed for the
+/// specified task to exit by its own.
+///
+/// # Safety
+///
+/// The task must be safe to terminate. This is in general not true
+/// because there might be pinned references to the task's stack.
+unsafe fn terminate_and_delete_task(deleted_task: abi::ID) {
+    // Terminate the task
+    // Safety: Upheld by the caller
+    match unsafe { abi::ter_tsk(deleted_task) } {
+        // Indicates the task is already dormant, ignore it
+        abi::E_OBJ => {}
+        er => {
+            expect_success_aborting(er, &"ter_tsk");
+        }
+    }
+
+    // Delete the task
+    // Safety: Upheld by the caller
+    expect_success_aborting(unsafe { abi::del_tsk(deleted_task) }, &"del_tsk");
+}
+
+/// Terminate and delete the calling task.
+///
+/// Atomicity is not required - i.e., it can be assumed that other threads won't
+/// `ter_tsk` the calling task while this function is still in progress. (This
+/// property makes it easy to implement this operation on μITRON-derived kernels
+/// that don't support `exd_tsk`.)
+///
+/// # Safety
+///
+/// The task must be safe to terminate. This is in general not true
+/// because there might be pinned references to the task's stack.
+unsafe fn terminate_and_delete_current_task() -> ! {
+    expect_success_aborting(unsafe { abi::exd_tsk() }, &"exd_tsk");
+    // Safety: `exd_tsk` never returns on success
+    unsafe { crate::hint::unreachable_unchecked() };
+}
+
+pub fn available_concurrency() -> io::Result<crate::num::NonZeroUsize> {
+    super::unsupported()
+}
diff --git a/library/std/src/sys/itron/time.rs b/library/std/src/sys/itron/time.rs
new file mode 100644 (file)
index 0000000..6a992ad
--- /dev/null
@@ -0,0 +1,123 @@
+use super::{abi, error::expect_success};
+use crate::{convert::TryInto, mem::MaybeUninit, time::Duration};
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct Instant(abi::SYSTIM);
+
+impl Instant {
+    pub fn now() -> Instant {
+        // Safety: The provided pointer is valid
+        unsafe {
+            let mut out = MaybeUninit::uninit();
+            expect_success(abi::get_tim(out.as_mut_ptr()), &"get_tim");
+            Instant(out.assume_init())
+        }
+    }
+
+    pub const fn zero() -> Instant {
+        Instant(0)
+    }
+
+    pub fn actually_monotonic() -> bool {
+        // There are ways to change the system time
+        false
+    }
+
+    pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
+        self.0.checked_sub(other.0).map(|ticks| {
+            // `SYSTIM` is measured in microseconds
+            Duration::from_micros(ticks)
+        })
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
+        // `SYSTIM` is measured in microseconds
+        let ticks = other.as_micros();
+
+        Some(Instant(self.0.checked_add(ticks.try_into().ok()?)?))
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+        // `SYSTIM` is measured in microseconds
+        let ticks = other.as_micros();
+
+        Some(Instant(self.0.checked_sub(ticks.try_into().ok()?)?))
+    }
+}
+
+/// Split `Duration` into zero or more `RELTIM`s.
+#[inline]
+pub fn dur2reltims(dur: Duration) -> impl Iterator<Item = abi::RELTIM> {
+    // `RELTIM` is microseconds
+    let mut ticks = dur.as_micros();
+
+    crate::iter::from_fn(move || {
+        if ticks == 0 {
+            None
+        } else if ticks <= abi::TMAX_RELTIM as u128 {
+            Some(crate::mem::replace(&mut ticks, 0) as abi::RELTIM)
+        } else {
+            ticks -= abi::TMAX_RELTIM as u128;
+            Some(abi::TMAX_RELTIM)
+        }
+    })
+}
+
+/// Split `Duration` into one or more `TMO`s.
+#[inline]
+fn dur2tmos(dur: Duration) -> impl Iterator<Item = abi::TMO> {
+    // `TMO` is microseconds
+    let mut ticks = dur.as_micros();
+    let mut end = false;
+
+    crate::iter::from_fn(move || {
+        if end {
+            None
+        } else if ticks <= abi::TMAX_RELTIM as u128 {
+            end = true;
+            Some(crate::mem::replace(&mut ticks, 0) as abi::TMO)
+        } else {
+            ticks -= abi::TMAX_RELTIM as u128;
+            Some(abi::TMAX_RELTIM)
+        }
+    })
+}
+
+/// Split `Duration` into one or more API calls with timeout.
+#[inline]
+pub fn with_tmos(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER {
+    let mut er = abi::E_TMOUT;
+    for tmo in dur2tmos(dur) {
+        er = f(tmo);
+        if er != abi::E_TMOUT {
+            break;
+        }
+    }
+    er
+}
+
+/// Split `Duration` into one or more API calls with timeout. This function can
+/// handle spurious wakeups.
+#[inline]
+pub fn with_tmos_strong(dur: Duration, mut f: impl FnMut(abi::TMO) -> abi::ER) -> abi::ER {
+    // `TMO` and `SYSTIM` are microseconds.
+    // Clamp at `SYSTIM::MAX` for performance reasons. This shouldn't cause
+    // a problem in practice. (`u64::MAX` μs ≈ 584942 years)
+    let ticks = dur.as_micros().min(abi::SYSTIM::MAX as u128) as abi::SYSTIM;
+
+    let start = Instant::now().0;
+    let mut elapsed = 0;
+    let mut er = abi::E_TMOUT;
+    while elapsed <= ticks {
+        er = f(elapsed.min(abi::TMAX_RELTIM as abi::SYSTIM) as abi::TMO);
+        if er != abi::E_TMOUT {
+            break;
+        }
+        elapsed = Instant::now().0.wrapping_sub(start);
+    }
+
+    er
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/library/std/src/sys/itron/time/tests.rs b/library/std/src/sys/itron/time/tests.rs
new file mode 100644 (file)
index 0000000..d14035d
--- /dev/null
@@ -0,0 +1,33 @@
+use super::*;
+
+fn reltim2dur(t: u64) -> Duration {
+    Duration::from_micros(t)
+}
+
+#[test]
+fn test_dur2reltims() {
+    assert_eq!(dur2reltims(reltim2dur(0)).collect::<Vec<_>>(), vec![]);
+    assert_eq!(dur2reltims(reltim2dur(42)).collect::<Vec<_>>(), vec![42]);
+    assert_eq!(
+        dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64)).collect::<Vec<_>>(),
+        vec![abi::TMAX_RELTIM]
+    );
+    assert_eq!(
+        dur2reltims(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::<Vec<_>>(),
+        vec![abi::TMAX_RELTIM, 10000]
+    );
+}
+
+#[test]
+fn test_dur2tmos() {
+    assert_eq!(dur2tmos(reltim2dur(0)).collect::<Vec<_>>(), vec![0]);
+    assert_eq!(dur2tmos(reltim2dur(42)).collect::<Vec<_>>(), vec![42]);
+    assert_eq!(
+        dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64)).collect::<Vec<_>>(),
+        vec![abi::TMAX_RELTIM]
+    );
+    assert_eq!(
+        dur2tmos(reltim2dur(abi::TMAX_RELTIM as u64 + 10000)).collect::<Vec<_>>(),
+        vec![abi::TMAX_RELTIM, 10000]
+    );
+}
index f813587b1b3408a41a0030b935ed4a2e4535c9f9..8b8be6ebc2f55333cf6f68226b1d797dff09f2c1 100644 (file)
@@ -31,6 +31,9 @@
     } else if #[cfg(windows)] {
         mod windows;
         pub use self::windows::*;
+    } else if #[cfg(target_os = "solid_asp3")] {
+        mod solid;
+        pub use self::solid::*;
     } else if #[cfg(target_os = "hermit")] {
         mod hermit;
         pub use self::hermit::*;
diff --git a/library/std/src/sys/solid/abi/fs.rs b/library/std/src/sys/solid/abi/fs.rs
new file mode 100644 (file)
index 0000000..32800bd
--- /dev/null
@@ -0,0 +1,53 @@
+//! `solid_fs.h`
+use crate::os::raw::{c_char, c_int, c_uchar};
+pub use libc::{
+    blksize_t, dev_t, ino_t, off_t, stat, time_t, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR,
+    O_TRUNC, O_WRONLY, SEEK_CUR, SEEK_END, SEEK_SET, S_IEXEC, S_IFBLK, S_IFCHR, S_IFDIR, S_IFIFO,
+    S_IFMT, S_IFREG, S_IREAD, S_IWRITE,
+};
+
+pub const O_ACCMODE: c_int = 0x3;
+
+pub const SOLID_MAX_PATH: usize = 256;
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct dirent {
+    pub d_ino: ino_t,
+    pub d_type: c_uchar,
+    pub d_name: [c_char; 256usize],
+}
+
+pub const DT_UNKNOWN: c_uchar = 0;
+pub const DT_FIFO: c_uchar = 1;
+pub const DT_CHR: c_uchar = 2;
+pub const DT_DIR: c_uchar = 4;
+pub const DT_BLK: c_uchar = 6;
+pub const DT_REG: c_uchar = 8;
+pub const DT_LNK: c_uchar = 10;
+pub const DT_SOCK: c_uchar = 12;
+pub const DT_WHT: c_uchar = 14;
+
+pub type S_DIR = c_int;
+
+extern "C" {
+    pub fn SOLID_FS_Open(fd: *mut c_int, path: *const c_char, mode: c_int) -> c_int;
+    pub fn SOLID_FS_Close(fd: c_int) -> c_int;
+    pub fn SOLID_FS_Read(fd: c_int, buf: *mut u8, size: usize, result: *mut usize) -> c_int;
+    pub fn SOLID_FS_Write(fd: c_int, buf: *const u8, size: usize, result: *mut usize) -> c_int;
+    pub fn SOLID_FS_Lseek(fd: c_int, offset: off_t, whence: c_int) -> c_int;
+    pub fn SOLID_FS_Sync(fd: c_int) -> c_int;
+    pub fn SOLID_FS_Ftell(fd: c_int, result: *mut off_t) -> c_int;
+    pub fn SOLID_FS_Feof(fd: c_int, result: *mut c_int) -> c_int;
+    pub fn SOLID_FS_Fsize(fd: c_int, result: *mut usize) -> c_int;
+    pub fn SOLID_FS_Truncate(path: *const c_char, size: off_t) -> c_int;
+    pub fn SOLID_FS_OpenDir(path: *const c_char, pDir: *mut S_DIR) -> c_int;
+    pub fn SOLID_FS_CloseDir(dir: S_DIR) -> c_int;
+    pub fn SOLID_FS_ReadDir(dir: S_DIR, dirp: *mut dirent) -> c_int;
+    pub fn SOLID_FS_Stat(path: *const c_char, buf: *mut stat) -> c_int;
+    pub fn SOLID_FS_Unlink(path: *const c_char) -> c_int;
+    pub fn SOLID_FS_Rename(oldpath: *const c_char, newpath: *const c_char) -> c_int;
+    pub fn SOLID_FS_Chmod(path: *const c_char, mode: c_int) -> c_int;
+    pub fn SOLID_FS_Utime(path: *const c_char, time: time_t) -> c_int;
+    pub fn SOLID_FS_Mkdir(path: *const c_char) -> c_int;
+}
diff --git a/library/std/src/sys/solid/abi/mod.rs b/library/std/src/sys/solid/abi/mod.rs
new file mode 100644 (file)
index 0000000..3526440
--- /dev/null
@@ -0,0 +1,92 @@
+use crate::os::raw::c_int;
+
+mod fs;
+pub mod sockets;
+pub use self::fs::*;
+
+pub const SOLID_BP_PROGRAM_EXITED: usize = 15;
+pub const SOLID_BP_CSABORT: usize = 16;
+
+#[inline(always)]
+pub fn breakpoint_program_exited(tid: usize) {
+    unsafe {
+        match () {
+            #[cfg(target_arch = "arm")]
+            () => asm!("bkpt #{}", const SOLID_BP_PROGRAM_EXITED, in("r0") tid),
+            #[cfg(target_arch = "aarch64")]
+            () => asm!("hlt #{}", const SOLID_BP_PROGRAM_EXITED, in("x0") tid),
+        }
+    }
+}
+
+#[inline(always)]
+pub fn breakpoint_abort() {
+    unsafe {
+        match () {
+            #[cfg(target_arch = "arm")]
+            () => asm!("bkpt #{}", const SOLID_BP_CSABORT),
+            #[cfg(target_arch = "aarch64")]
+            () => asm!("hlt #{}", const SOLID_BP_CSABORT),
+        }
+    }
+}
+
+// `solid_types.h`
+pub use super::itron::abi::{ER, ER_ID, E_TMOUT, ID};
+
+pub const SOLID_ERR_NOTFOUND: ER = -1000;
+pub const SOLID_ERR_NOTSUPPORTED: ER = -1001;
+pub const SOLID_ERR_EBADF: ER = -1002;
+pub const SOLID_ERR_INVALIDCONTENT: ER = -1003;
+pub const SOLID_ERR_NOTUSED: ER = -1004;
+pub const SOLID_ERR_ALREADYUSED: ER = -1005;
+pub const SOLID_ERR_OUTOFBOUND: ER = -1006;
+pub const SOLID_ERR_BADSEQUENCE: ER = -1007;
+pub const SOLID_ERR_UNKNOWNDEVICE: ER = -1008;
+pub const SOLID_ERR_BUSY: ER = -1009;
+pub const SOLID_ERR_TIMEOUT: ER = -1010;
+pub const SOLID_ERR_INVALIDACCESS: ER = -1011;
+pub const SOLID_ERR_NOTREADY: ER = -1012;
+
+// `solid_rtc.h`
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct SOLID_RTC_TIME {
+    pub tm_sec: c_int,
+    pub tm_min: c_int,
+    pub tm_hour: c_int,
+    pub tm_mday: c_int,
+    pub tm_mon: c_int,
+    pub tm_year: c_int,
+    pub tm_wday: c_int,
+}
+
+extern "C" {
+    pub fn SOLID_RTC_ReadTime(time: *mut SOLID_RTC_TIME) -> c_int;
+}
+
+// `solid_log.h`
+extern "C" {
+    pub fn SOLID_LOG_write(s: *const u8, l: usize);
+}
+
+// `solid_mem.h`
+extern "C" {
+    pub fn SOLID_TLS_AddDestructor(id: i32, dtor: unsafe extern "C" fn(*mut u8));
+}
+
+// `solid_rng.h`
+extern "C" {
+    pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> c_int;
+}
+
+// `rwlock.h`
+extern "C" {
+    pub fn rwl_loc_rdl(id: ID) -> ER;
+    pub fn rwl_loc_wrl(id: ID) -> ER;
+    pub fn rwl_ploc_rdl(id: ID) -> ER;
+    pub fn rwl_ploc_wrl(id: ID) -> ER;
+    pub fn rwl_unl_rwl(id: ID) -> ER;
+    pub fn rwl_acre_rwl() -> ER_ID;
+    pub fn rwl_del_rwl(id: ID) -> ER;
+}
diff --git a/library/std/src/sys/solid/abi/sockets.rs b/library/std/src/sys/solid/abi/sockets.rs
new file mode 100644 (file)
index 0000000..7c21d0d
--- /dev/null
@@ -0,0 +1,274 @@
+use crate::os::raw::{c_char, c_uint, c_void};
+pub use libc::{c_int, c_long, size_t, ssize_t, suseconds_t, time_t, timeval};
+
+pub const SOLID_NET_ERR_BASE: c_int = -2000;
+pub const EINPROGRESS: c_int = SOLID_NET_ERR_BASE - libc::EINPROGRESS;
+
+pub const AF_INET6: i32 = 10;
+pub const AF_INET: i32 = 2;
+pub const IPPROTO_IP: i32 = 0;
+pub const IPPROTO_IPV6: i32 = 41;
+pub const IPPROTO_TCP: i32 = 6;
+pub const IPV6_ADD_MEMBERSHIP: i32 = 12;
+pub const IPV6_DROP_MEMBERSHIP: i32 = 13;
+pub const IPV6_MULTICAST_LOOP: i32 = 19;
+pub const IPV6_V6ONLY: i32 = 27;
+pub const IP_TTL: i32 = 2;
+pub const IP_MULTICAST_TTL: i32 = 5;
+pub const IP_MULTICAST_LOOP: i32 = 7;
+pub const IP_ADD_MEMBERSHIP: i32 = 3;
+pub const IP_DROP_MEMBERSHIP: i32 = 4;
+pub const SHUT_RD: i32 = 0;
+pub const SHUT_RDWR: i32 = 2;
+pub const SHUT_WR: i32 = 1;
+pub const SOCK_DGRAM: i32 = 2;
+pub const SOCK_STREAM: i32 = 1;
+pub const SOL_SOCKET: i32 = 4095;
+pub const SO_BROADCAST: i32 = 32;
+pub const SO_ERROR: i32 = 4103;
+pub const SO_RCVTIMEO: i32 = 4102;
+pub const SO_REUSEADDR: i32 = 4;
+pub const SO_SNDTIMEO: i32 = 4101;
+pub const SO_LINGER: i32 = 128;
+pub const TCP_NODELAY: i32 = 1;
+pub const MSG_PEEK: c_int = 1;
+pub const FIONBIO: c_long = 0x8008667eu32 as c_long;
+pub const EAI_NONAME: i32 = -2200;
+pub const EAI_SERVICE: i32 = -2201;
+pub const EAI_FAIL: i32 = -2202;
+pub const EAI_MEMORY: i32 = -2203;
+pub const EAI_FAMILY: i32 = -2204;
+
+pub type sa_family_t = u8;
+pub type socklen_t = u32;
+pub type in_addr_t = u32;
+pub type in_port_t = u16;
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct in_addr {
+    pub s_addr: in_addr_t,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct in6_addr {
+    pub s6_addr: [u8; 16],
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ip_mreq {
+    pub imr_multiaddr: in_addr,
+    pub imr_interface: in_addr,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct ipv6_mreq {
+    pub ipv6mr_multiaddr: in6_addr,
+    pub ipv6mr_interface: c_uint,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct msghdr {
+    pub msg_name: *mut c_void,
+    pub msg_namelen: socklen_t,
+    pub msg_iov: *mut iovec,
+    pub msg_iovlen: c_int,
+    pub msg_control: *mut c_void,
+    pub msg_controllen: socklen_t,
+    pub msg_flags: c_int,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct sockaddr {
+    pub sa_len: u8,
+    pub sa_family: sa_family_t,
+    pub sa_data: [c_char; 14usize],
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct sockaddr_in {
+    pub sin_len: u8,
+    pub sin_family: sa_family_t,
+    pub sin_port: in_port_t,
+    pub sin_addr: in_addr,
+    pub sin_zero: [c_char; 8usize],
+}
+
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct sockaddr_in6 {
+    pub sin6_len: u8,
+    pub sin6_family: sa_family_t,
+    pub sin6_port: in_port_t,
+    pub sin6_flowinfo: u32,
+    pub sin6_addr: in6_addr,
+    pub sin6_scope_id: u32,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct sockaddr_storage {
+    pub s2_len: u8,
+    pub ss_family: sa_family_t,
+    pub s2_data1: [c_char; 2usize],
+    pub s2_data2: [u32; 3usize],
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct addrinfo {
+    pub ai_flags: c_int,
+    pub ai_family: c_int,
+    pub ai_socktype: c_int,
+    pub ai_protocol: c_int,
+    pub ai_addrlen: socklen_t,
+    pub ai_addr: *mut sockaddr,
+    pub ai_canonname: *mut c_char,
+    pub ai_next: *mut addrinfo,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct linger {
+    pub l_onoff: c_int,
+    pub l_linger: c_int,
+}
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct iovec {
+    pub iov_base: *mut c_void,
+    pub iov_len: usize,
+}
+
+/// This value can be chosen by an application
+pub const SOLID_NET_FD_SETSIZE: usize = 1;
+
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct fd_set {
+    pub num_fds: usize,
+    pub fds: [c_int; SOLID_NET_FD_SETSIZE],
+}
+
+extern "C" {
+    #[link_name = "SOLID_NET_StrError"]
+    pub fn strerror(errnum: c_int) -> *const c_char;
+
+    pub fn SOLID_NET_GetLastError() -> c_int;
+
+    #[link_name = "SOLID_NET_Accept"]
+    pub fn accept(s: c_int, addr: *mut sockaddr, addrlen: *mut socklen_t) -> c_int;
+
+    #[link_name = "SOLID_NET_Bind"]
+    pub fn bind(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int;
+
+    #[link_name = "SOLID_NET_Connect"]
+    pub fn connect(s: c_int, name: *const sockaddr, namelen: socklen_t) -> c_int;
+
+    #[link_name = "SOLID_NET_Close"]
+    pub fn close(s: c_int) -> c_int;
+
+    #[link_name = "SOLID_NET_GetPeerName"]
+    pub fn getpeername(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int;
+
+    #[link_name = "SOLID_NET_GetSockName"]
+    pub fn getsockname(s: c_int, name: *mut sockaddr, namelen: *mut socklen_t) -> c_int;
+
+    #[link_name = "SOLID_NET_GetSockOpt"]
+    pub fn getsockopt(
+        s: c_int,
+        level: c_int,
+        optname: c_int,
+        optval: *mut c_void,
+        optlen: *mut socklen_t,
+    ) -> c_int;
+
+    #[link_name = "SOLID_NET_SetSockOpt"]
+    pub fn setsockopt(
+        s: c_int,
+        level: c_int,
+        optname: c_int,
+        optval: *const c_void,
+        optlen: socklen_t,
+    ) -> c_int;
+
+    #[link_name = "SOLID_NET_Ioctl"]
+    pub fn ioctl(s: c_int, cmd: c_long, argp: *mut c_void) -> c_int;
+
+    #[link_name = "SOLID_NET_Listen"]
+    pub fn listen(s: c_int, backlog: c_int) -> c_int;
+
+    #[link_name = "SOLID_NET_Recv"]
+    pub fn recv(s: c_int, mem: *mut c_void, len: size_t, flags: c_int) -> ssize_t;
+
+    #[link_name = "SOLID_NET_Read"]
+    pub fn read(s: c_int, mem: *mut c_void, len: size_t) -> ssize_t;
+
+    #[link_name = "SOLID_NET_Readv"]
+    pub fn readv(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t;
+
+    #[link_name = "SOLID_NET_RecvFrom"]
+    pub fn recvfrom(
+        s: c_int,
+        mem: *mut c_void,
+        len: size_t,
+        flags: c_int,
+        from: *mut sockaddr,
+        fromlen: *mut socklen_t,
+    ) -> ssize_t;
+
+    #[link_name = "SOLID_NET_Send"]
+    pub fn send(s: c_int, mem: *const c_void, len: size_t, flags: c_int) -> ssize_t;
+
+    #[link_name = "SOLID_NET_SendMsg"]
+    pub fn sendmsg(s: c_int, message: *const msghdr, flags: c_int) -> ssize_t;
+
+    #[link_name = "SOLID_NET_SendTo"]
+    pub fn sendto(
+        s: c_int,
+        mem: *const c_void,
+        len: size_t,
+        flags: c_int,
+        to: *const sockaddr,
+        tolen: socklen_t,
+    ) -> ssize_t;
+
+    #[link_name = "SOLID_NET_Shutdown"]
+    pub fn shutdown(s: c_int, how: c_int) -> c_int;
+
+    #[link_name = "SOLID_NET_Socket"]
+    pub fn socket(domain: c_int, type_: c_int, protocol: c_int) -> c_int;
+
+    #[link_name = "SOLID_NET_Write"]
+    pub fn write(s: c_int, mem: *const c_void, len: size_t) -> ssize_t;
+
+    #[link_name = "SOLID_NET_Writev"]
+    pub fn writev(s: c_int, bufs: *const iovec, bufcnt: c_int) -> ssize_t;
+
+    #[link_name = "SOLID_NET_FreeAddrInfo"]
+    pub fn freeaddrinfo(ai: *mut addrinfo);
+
+    #[link_name = "SOLID_NET_GetAddrInfo"]
+    pub fn getaddrinfo(
+        nodename: *const c_char,
+        servname: *const c_char,
+        hints: *const addrinfo,
+        res: *mut *mut addrinfo,
+    ) -> c_int;
+
+    #[link_name = "SOLID_NET_Select"]
+    pub fn select(
+        maxfdp1: c_int,
+        readset: *mut fd_set,
+        writeset: *mut fd_set,
+        exceptset: *mut fd_set,
+        timeout: *mut timeval,
+    ) -> c_int;
+}
diff --git a/library/std/src/sys/solid/alloc.rs b/library/std/src/sys/solid/alloc.rs
new file mode 100644 (file)
index 0000000..d013bd8
--- /dev/null
@@ -0,0 +1,32 @@
+use crate::{
+    alloc::{GlobalAlloc, Layout, System},
+    sys::common::alloc::{realloc_fallback, MIN_ALIGN},
+};
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+    #[inline]
+    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+        if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
+            unsafe { libc::malloc(layout.size()) as *mut u8 }
+        } else {
+            unsafe { libc::memalign(layout.align(), layout.size()) as *mut u8 }
+        }
+    }
+
+    #[inline]
+    unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
+        unsafe { libc::free(ptr as *mut libc::c_void) }
+    }
+
+    #[inline]
+    unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+        unsafe {
+            if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
+                libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
+            } else {
+                realloc_fallback(self, ptr, layout, new_size)
+            }
+        }
+    }
+}
diff --git a/library/std/src/sys/solid/env.rs b/library/std/src/sys/solid/env.rs
new file mode 100644 (file)
index 0000000..6855c11
--- /dev/null
@@ -0,0 +1,9 @@
+pub mod os {
+    pub const FAMILY: &str = "itron";
+    pub const OS: &str = "solid";
+    pub const DLL_PREFIX: &str = "";
+    pub const DLL_SUFFIX: &str = ".so";
+    pub const DLL_EXTENSION: &str = "so";
+    pub const EXE_SUFFIX: &str = "";
+    pub const EXE_EXTENSION: &str = "";
+}
diff --git a/library/std/src/sys/solid/error.rs b/library/std/src/sys/solid/error.rs
new file mode 100644 (file)
index 0000000..547b4f3
--- /dev/null
@@ -0,0 +1,55 @@
+use super::{abi, itron, net};
+use crate::io::ErrorKind;
+
+pub use self::itron::error::{expect_success, ItronError as SolidError};
+
+/// Describe the specified SOLID error code. Returns `None` if it's an
+/// undefined error code.
+///
+/// The SOLID error codes are a superset of μITRON error codes.
+pub fn error_name(er: abi::ER) -> Option<&'static str> {
+    match er {
+        // Success
+        er if er >= 0 => None,
+        er if er < abi::sockets::SOLID_NET_ERR_BASE => net::error_name(er),
+
+        abi::SOLID_ERR_NOTFOUND => Some("not found"),
+        abi::SOLID_ERR_NOTSUPPORTED => Some("not supported"),
+        abi::SOLID_ERR_EBADF => Some("bad flags"),
+        abi::SOLID_ERR_INVALIDCONTENT => Some("invalid content"),
+        abi::SOLID_ERR_NOTUSED => Some("not used"),
+        abi::SOLID_ERR_ALREADYUSED => Some("already used"),
+        abi::SOLID_ERR_OUTOFBOUND => Some("out of bounds"),
+        abi::SOLID_ERR_BADSEQUENCE => Some("bad sequence"),
+        abi::SOLID_ERR_UNKNOWNDEVICE => Some("unknown device"),
+        abi::SOLID_ERR_BUSY => Some("busy"),
+        abi::SOLID_ERR_TIMEOUT => Some("operation timed out"),
+        abi::SOLID_ERR_INVALIDACCESS => Some("invalid access"),
+        abi::SOLID_ERR_NOTREADY => Some("not ready"),
+
+        _ => itron::error::error_name(er),
+    }
+}
+
+pub fn decode_error_kind(er: abi::ER) -> ErrorKind {
+    match er {
+        // Success
+        er if er >= 0 => ErrorKind::Uncategorized,
+        er if er < abi::sockets::SOLID_NET_ERR_BASE => net::decode_error_kind(er),
+
+        abi::SOLID_ERR_NOTFOUND => ErrorKind::NotFound,
+        abi::SOLID_ERR_NOTSUPPORTED => ErrorKind::Unsupported,
+        abi::SOLID_ERR_EBADF => ErrorKind::InvalidInput,
+        abi::SOLID_ERR_INVALIDCONTENT => ErrorKind::InvalidData,
+        // abi::SOLID_ERR_NOTUSED
+        // abi::SOLID_ERR_ALREADYUSED
+        abi::SOLID_ERR_OUTOFBOUND => ErrorKind::InvalidInput,
+        // abi::SOLID_ERR_BADSEQUENCE
+        abi::SOLID_ERR_UNKNOWNDEVICE => ErrorKind::NotFound,
+        // abi::SOLID_ERR_BUSY
+        abi::SOLID_ERR_TIMEOUT => ErrorKind::TimedOut,
+        // abi::SOLID_ERR_INVALIDACCESS
+        // abi::SOLID_ERR_NOTREADY
+        _ => itron::error::decode_error_kind(er),
+    }
+}
diff --git a/library/std/src/sys/solid/fs.rs b/library/std/src/sys/solid/fs.rs
new file mode 100644 (file)
index 0000000..abc60b5
--- /dev/null
@@ -0,0 +1,529 @@
+use super::{abi, error};
+use crate::{
+    ffi::{CStr, CString, OsStr, OsString},
+    fmt,
+    io::{self, IoSlice, IoSliceMut, SeekFrom},
+    mem::MaybeUninit,
+    os::raw::{c_int, c_short},
+    os::solid::ffi::OsStrExt,
+    path::{Path, PathBuf},
+    sync::Arc,
+    sys::time::SystemTime,
+    sys::unsupported,
+};
+
+pub use crate::sys_common::fs::try_exists;
+
+/// A file descriptor.
+#[derive(Clone, Copy)]
+#[rustc_layout_scalar_valid_range_start(0)]
+// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
+// 32-bit c_int. Below is -2, in two's complement, but that only works out
+// because c_int is 32 bits.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+struct FileDesc {
+    fd: c_int,
+}
+
+impl FileDesc {
+    #[inline]
+    fn new(fd: c_int) -> FileDesc {
+        assert_ne!(fd, -1i32);
+        // Safety: we just asserted that the value is in the valid range and
+        // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+        unsafe { FileDesc { fd } }
+    }
+
+    #[inline]
+    fn raw(&self) -> c_int {
+        self.fd
+    }
+}
+
+pub struct File {
+    fd: FileDesc,
+}
+
+#[derive(Clone)]
+pub struct FileAttr {
+    stat: abi::stat,
+}
+
+// all DirEntry's will have a reference to this struct
+struct InnerReadDir {
+    dirp: abi::S_DIR,
+    root: PathBuf,
+}
+
+pub struct ReadDir {
+    inner: Arc<InnerReadDir>,
+}
+
+pub struct DirEntry {
+    entry: abi::dirent,
+    inner: Arc<InnerReadDir>,
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+    // generic
+    read: bool,
+    write: bool,
+    append: bool,
+    truncate: bool,
+    create: bool,
+    create_new: bool,
+    // system-specific
+    custom_flags: i32,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions(c_short);
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType(c_short);
+
+#[derive(Debug)]
+pub struct DirBuilder {}
+
+impl FileAttr {
+    pub fn size(&self) -> u64 {
+        self.stat.st_size as u64
+    }
+
+    pub fn perm(&self) -> FilePermissions {
+        FilePermissions(self.stat.st_mode)
+    }
+
+    pub fn file_type(&self) -> FileType {
+        FileType(self.stat.st_mode)
+    }
+
+    pub fn modified(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from_time_t(self.stat.st_mtime))
+    }
+
+    pub fn accessed(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from_time_t(self.stat.st_atime))
+    }
+
+    pub fn created(&self) -> io::Result<SystemTime> {
+        Ok(SystemTime::from_time_t(self.stat.st_ctime))
+    }
+}
+
+impl FilePermissions {
+    pub fn readonly(&self) -> bool {
+        (self.0 & abi::S_IWRITE) == 0
+    }
+
+    pub fn set_readonly(&mut self, readonly: bool) {
+        if readonly {
+            self.0 &= !abi::S_IWRITE;
+        } else {
+            self.0 |= abi::S_IWRITE;
+        }
+    }
+}
+
+impl FileType {
+    pub fn is_dir(&self) -> bool {
+        self.is(abi::S_IFDIR)
+    }
+    pub fn is_file(&self) -> bool {
+        self.is(abi::S_IFREG)
+    }
+    pub fn is_symlink(&self) -> bool {
+        false
+    }
+
+    pub fn is(&self, mode: c_short) -> bool {
+        self.0 & abi::S_IFMT == mode
+    }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+    unsafe {
+        let mut dir = MaybeUninit::uninit();
+        error::SolidError::err_if_negative(abi::SOLID_FS_OpenDir(
+            cstr(p)?.as_ptr(),
+            dir.as_mut_ptr(),
+        ))
+        .map_err(|e| e.as_io_error())?;
+        let inner = Arc::new(InnerReadDir { dirp: dir.assume_init(), root: p.to_owned() });
+        Ok(ReadDir { inner })
+    }
+}
+
+impl fmt::Debug for ReadDir {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+        // Thus the result will be e g 'ReadDir("/home")'
+        fmt::Debug::fmt(&*self.inner.root, f)
+    }
+}
+
+impl Iterator for ReadDir {
+    type Item = io::Result<DirEntry>;
+
+    fn next(&mut self) -> Option<io::Result<DirEntry>> {
+        unsafe {
+            let mut out_dirent = MaybeUninit::uninit();
+            error::SolidError::err_if_negative(abi::SOLID_FS_ReadDir(
+                self.inner.dirp,
+                out_dirent.as_mut_ptr(),
+            ))
+            .ok()?;
+            Some(Ok(DirEntry { entry: out_dirent.assume_init(), inner: Arc::clone(&self.inner) }))
+        }
+    }
+}
+
+impl Drop for InnerReadDir {
+    fn drop(&mut self) {
+        unsafe { abi::SOLID_FS_CloseDir(self.dirp) };
+    }
+}
+
+impl DirEntry {
+    pub fn path(&self) -> PathBuf {
+        self.inner.root.join(OsStr::from_bytes(
+            unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes(),
+        ))
+    }
+
+    pub fn file_name(&self) -> OsString {
+        OsStr::from_bytes(unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }.to_bytes())
+            .to_os_string()
+    }
+
+    pub fn metadata(&self) -> io::Result<FileAttr> {
+        lstat(&self.path())
+    }
+
+    pub fn file_type(&self) -> io::Result<FileType> {
+        match self.entry.d_type {
+            abi::DT_CHR => Ok(FileType(abi::S_IFCHR)),
+            abi::DT_FIFO => Ok(FileType(abi::S_IFIFO)),
+            abi::DT_REG => Ok(FileType(abi::S_IFREG)),
+            abi::DT_DIR => Ok(FileType(abi::S_IFDIR)),
+            abi::DT_BLK => Ok(FileType(abi::S_IFBLK)),
+            _ => lstat(&self.path()).map(|m| m.file_type()),
+        }
+    }
+}
+
+impl OpenOptions {
+    pub fn new() -> OpenOptions {
+        OpenOptions {
+            // generic
+            read: false,
+            write: false,
+            append: false,
+            truncate: false,
+            create: false,
+            create_new: false,
+            // system-specific
+            custom_flags: 0,
+        }
+    }
+
+    pub fn read(&mut self, read: bool) {
+        self.read = read;
+    }
+    pub fn write(&mut self, write: bool) {
+        self.write = write;
+    }
+    pub fn append(&mut self, append: bool) {
+        self.append = append;
+    }
+    pub fn truncate(&mut self, truncate: bool) {
+        self.truncate = truncate;
+    }
+    pub fn create(&mut self, create: bool) {
+        self.create = create;
+    }
+    pub fn create_new(&mut self, create_new: bool) {
+        self.create_new = create_new;
+    }
+
+    pub fn custom_flags(&mut self, flags: i32) {
+        self.custom_flags = flags;
+    }
+    pub fn mode(&mut self, _mode: u32) {}
+
+    fn get_access_mode(&self) -> io::Result<c_int> {
+        match (self.read, self.write, self.append) {
+            (true, false, false) => Ok(abi::O_RDONLY),
+            (false, true, false) => Ok(abi::O_WRONLY),
+            (true, true, false) => Ok(abi::O_RDWR),
+            (false, _, true) => Ok(abi::O_WRONLY | abi::O_APPEND),
+            (true, _, true) => Ok(abi::O_RDWR | abi::O_APPEND),
+            (false, false, false) => Err(io::Error::from_raw_os_error(libc::EINVAL)),
+        }
+    }
+
+    fn get_creation_mode(&self) -> io::Result<c_int> {
+        match (self.write, self.append) {
+            (true, false) => {}
+            (false, false) => {
+                if self.truncate || self.create || self.create_new {
+                    return Err(io::Error::from_raw_os_error(libc::EINVAL));
+                }
+            }
+            (_, true) => {
+                if self.truncate && !self.create_new {
+                    return Err(io::Error::from_raw_os_error(libc::EINVAL));
+                }
+            }
+        }
+
+        Ok(match (self.create, self.truncate, self.create_new) {
+            (false, false, false) => 0,
+            (true, false, false) => abi::O_CREAT,
+            (false, true, false) => abi::O_TRUNC,
+            (true, true, false) => abi::O_CREAT | abi::O_TRUNC,
+            (_, _, true) => abi::O_CREAT | abi::O_EXCL,
+        })
+    }
+}
+
+fn cstr(path: &Path) -> io::Result<CString> {
+    Ok(CString::new(path.as_os_str().as_bytes())?)
+}
+
+impl File {
+    pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+        let flags = opts.get_access_mode()?
+            | opts.get_creation_mode()?
+            | (opts.custom_flags as c_int & !abi::O_ACCMODE);
+        unsafe {
+            let mut fd = MaybeUninit::uninit();
+            error::SolidError::err_if_negative(abi::SOLID_FS_Open(
+                fd.as_mut_ptr(),
+                cstr(path)?.as_ptr(),
+                flags,
+            ))
+            .map_err(|e| e.as_io_error())?;
+            Ok(File { fd: FileDesc::new(fd.assume_init()) })
+        }
+    }
+
+    pub fn file_attr(&self) -> io::Result<FileAttr> {
+        unsupported()
+    }
+
+    pub fn fsync(&self) -> io::Result<()> {
+        self.flush()
+    }
+
+    pub fn datasync(&self) -> io::Result<()> {
+        self.flush()
+    }
+
+    pub fn truncate(&self, _size: u64) -> io::Result<()> {
+        unsupported()
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        unsafe {
+            let mut out_num_bytes = MaybeUninit::uninit();
+            error::SolidError::err_if_negative(abi::SOLID_FS_Read(
+                self.fd.raw(),
+                buf.as_mut_ptr(),
+                buf.len(),
+                out_num_bytes.as_mut_ptr(),
+            ))
+            .map_err(|e| e.as_io_error())?;
+            Ok(out_num_bytes.assume_init())
+        }
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        crate::io::default_read_vectored(|buf| self.read(buf), bufs)
+    }
+
+    pub fn is_read_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        unsafe {
+            let mut out_num_bytes = MaybeUninit::uninit();
+            error::SolidError::err_if_negative(abi::SOLID_FS_Write(
+                self.fd.raw(),
+                buf.as_ptr(),
+                buf.len(),
+                out_num_bytes.as_mut_ptr(),
+            ))
+            .map_err(|e| e.as_io_error())?;
+            Ok(out_num_bytes.assume_init())
+        }
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        crate::io::default_write_vectored(|buf| self.write(buf), bufs)
+    }
+
+    pub fn is_write_vectored(&self) -> bool {
+        false
+    }
+
+    pub fn flush(&self) -> io::Result<()> {
+        error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Sync(self.fd.raw()) })
+            .map_err(|e| e.as_io_error())?;
+        Ok(())
+    }
+
+    pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+        let (whence, pos) = match pos {
+            // Casting to `i64` is fine, too large values will end up as
+            // negative which will cause an error in `SOLID_FS_Lseek`.
+            SeekFrom::Start(off) => (abi::SEEK_SET, off as i64),
+            SeekFrom::End(off) => (abi::SEEK_END, off),
+            SeekFrom::Current(off) => (abi::SEEK_CUR, off),
+        };
+        error::SolidError::err_if_negative(unsafe {
+            abi::SOLID_FS_Lseek(self.fd.raw(), pos, whence)
+        })
+        .map_err(|e| e.as_io_error())?;
+
+        // Get the new offset
+        unsafe {
+            let mut out_offset = MaybeUninit::uninit();
+            error::SolidError::err_if_negative(abi::SOLID_FS_Ftell(
+                self.fd.raw(),
+                out_offset.as_mut_ptr(),
+            ))
+            .map_err(|e| e.as_io_error())?;
+            Ok(out_offset.assume_init() as u64)
+        }
+    }
+
+    pub fn duplicate(&self) -> io::Result<File> {
+        unsupported()
+    }
+
+    pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
+        unsupported()
+    }
+}
+
+impl Drop for File {
+    fn drop(&mut self) {
+        unsafe { abi::SOLID_FS_Close(self.fd.raw()) };
+    }
+}
+
+impl DirBuilder {
+    pub fn new() -> DirBuilder {
+        DirBuilder {}
+    }
+
+    pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+        error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Mkdir(cstr(p)?.as_ptr()) })
+            .map_err(|e| e.as_io_error())?;
+        Ok(())
+    }
+}
+
+impl fmt::Debug for File {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("File").field("fd", &self.fd.raw()).finish()
+    }
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+    if stat(p)?.file_type().is_dir() {
+        Err(io::Error::new_const(io::ErrorKind::IsADirectory, &"is a directory"))
+    } else {
+        error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
+            .map_err(|e| e.as_io_error())?;
+        Ok(())
+    }
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+    error::SolidError::err_if_negative(unsafe {
+        abi::SOLID_FS_Rename(cstr(old)?.as_ptr(), cstr(new)?.as_ptr())
+    })
+    .map_err(|e| e.as_io_error())?;
+    Ok(())
+}
+
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+    error::SolidError::err_if_negative(unsafe {
+        abi::SOLID_FS_Chmod(cstr(p)?.as_ptr(), perm.0.into())
+    })
+    .map_err(|e| e.as_io_error())?;
+    Ok(())
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+    if stat(p)?.file_type().is_dir() {
+        error::SolidError::err_if_negative(unsafe { abi::SOLID_FS_Unlink(cstr(p)?.as_ptr()) })
+            .map_err(|e| e.as_io_error())?;
+        Ok(())
+    } else {
+        Err(io::Error::new_const(io::ErrorKind::NotADirectory, &"not a directory"))
+    }
+}
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+    for child in readdir(path)? {
+        let child = child?;
+        let child_type = child.file_type()?;
+        if child_type.is_dir() {
+            remove_dir_all(&child.path())?;
+        } else {
+            unlink(&child.path())?;
+        }
+    }
+    rmdir(path)
+}
+
+pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+    // This target doesn't support symlinks
+    stat(p)?;
+    Err(io::Error::new_const(io::ErrorKind::InvalidInput, &"not a symbolic link"))
+}
+
+pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
+    // This target doesn't support symlinks
+    unsupported()
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+    // This target doesn't support symlinks
+    unsupported()
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+    // This target doesn't support symlinks
+    lstat(p)
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+    unsafe {
+        let mut out_stat = MaybeUninit::uninit();
+        error::SolidError::err_if_negative(abi::SOLID_FS_Stat(
+            cstr(p)?.as_ptr(),
+            out_stat.as_mut_ptr(),
+        ))
+        .map_err(|e| e.as_io_error())?;
+        Ok(FileAttr { stat: out_stat.assume_init() })
+    }
+}
+
+pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+    use crate::fs::File;
+
+    let mut reader = File::open(from)?;
+    let mut writer = File::create(to)?;
+
+    io::copy(&mut reader, &mut writer)
+}
diff --git a/library/std/src/sys/solid/io.rs b/library/std/src/sys/solid/io.rs
new file mode 100644 (file)
index 0000000..9eb17a1
--- /dev/null
@@ -0,0 +1,77 @@
+use crate::marker::PhantomData;
+use crate::slice;
+
+use super::abi::sockets::iovec;
+use libc::c_void;
+
+#[derive(Copy, Clone)]
+#[repr(transparent)]
+pub struct IoSlice<'a> {
+    vec: iovec,
+    _p: PhantomData<&'a [u8]>,
+}
+
+impl<'a> IoSlice<'a> {
+    #[inline]
+    pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
+        IoSlice {
+            vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() },
+            _p: PhantomData,
+        }
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        if self.vec.iov_len < n {
+            panic!("advancing IoSlice beyond its length");
+        }
+
+        unsafe {
+            self.vec.iov_len -= n;
+            self.vec.iov_base = self.vec.iov_base.add(n);
+        }
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+    }
+}
+
+#[repr(transparent)]
+pub struct IoSliceMut<'a> {
+    vec: iovec,
+    _p: PhantomData<&'a mut [u8]>,
+}
+
+impl<'a> IoSliceMut<'a> {
+    #[inline]
+    pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
+        IoSliceMut {
+            vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() },
+            _p: PhantomData,
+        }
+    }
+
+    #[inline]
+    pub fn advance(&mut self, n: usize) {
+        if self.vec.iov_len < n {
+            panic!("advancing IoSliceMut beyond its length");
+        }
+
+        unsafe {
+            self.vec.iov_len -= n;
+            self.vec.iov_base = self.vec.iov_base.add(n);
+        }
+    }
+
+    #[inline]
+    pub fn as_slice(&self) -> &[u8] {
+        unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+    }
+
+    #[inline]
+    pub fn as_mut_slice(&mut self) -> &mut [u8] {
+        unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) }
+    }
+}
diff --git a/library/std/src/sys/solid/memchr.rs b/library/std/src/sys/solid/memchr.rs
new file mode 100644 (file)
index 0000000..452b7a3
--- /dev/null
@@ -0,0 +1,21 @@
+pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+    let p = unsafe {
+        libc::memchr(
+            haystack.as_ptr() as *const libc::c_void,
+            needle as libc::c_int,
+            haystack.len(),
+        )
+    };
+    if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
+}
+
+pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
+    let p = unsafe {
+        libc::memrchr(
+            haystack.as_ptr() as *const libc::c_void,
+            needle as libc::c_int,
+            haystack.len(),
+        )
+    };
+    if p.is_null() { None } else { Some(p as usize - (haystack.as_ptr() as usize)) }
+}
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
new file mode 100644 (file)
index 0000000..211b8d7
--- /dev/null
@@ -0,0 +1,96 @@
+#![allow(dead_code)]
+#![allow(missing_docs, nonstandard_style)]
+#![deny(unsafe_op_in_unsafe_fn)]
+
+mod abi;
+
+#[path = "../itron"]
+mod itron {
+    pub(super) mod abi;
+    pub mod condvar;
+    pub(super) mod error;
+    pub mod mutex;
+    pub(super) mod spin;
+    pub(super) mod task;
+    pub mod thread;
+    pub(super) mod time;
+    use super::unsupported;
+}
+
+pub mod alloc;
+#[path = "../unsupported/args.rs"]
+pub mod args;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+pub mod env;
+// `error` is `pub(crate)` so that it can be accessed by `itron/error.rs` as
+// `crate::sys::error`
+pub(crate) mod error;
+pub mod fs;
+pub mod io;
+pub mod net;
+pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
+pub mod path;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+#[path = "../unsupported/process.rs"]
+pub mod process;
+pub mod rwlock;
+pub mod stdio;
+pub use self::itron::{condvar, mutex, thread};
+pub mod memchr;
+pub mod thread_local_dtor;
+pub mod thread_local_key;
+pub mod time;
+
+// SAFETY: must be called only once during runtime initialization.
+// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
+
+// SAFETY: must be called only once during runtime cleanup.
+pub unsafe fn cleanup() {}
+
+pub fn unsupported<T>() -> crate::io::Result<T> {
+    Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> crate::io::Error {
+    crate::io::Error::new_const(
+        crate::io::ErrorKind::Unsupported,
+        &"operation not supported on this platform",
+    )
+}
+
+pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
+    error::decode_error_kind(code)
+}
+
+#[inline(always)]
+pub fn abort_internal() -> ! {
+    loop {
+        abi::breakpoint_abort();
+    }
+}
+
+// This function is needed by the panic runtime. The symbol is named in
+// pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+// NB. used by both libunwind and libpanic_abort
+pub extern "C" fn __rust_abort() {
+    abort_internal();
+}
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+    unsafe {
+        let mut out = crate::mem::MaybeUninit::<[u64; 2]>::uninit();
+        let result = abi::SOLID_RNG_SampleRandomBytes(out.as_mut_ptr() as *mut u8, 16);
+        assert_eq!(result, 0, "SOLID_RNG_SampleRandomBytes failed: {}", result);
+        let [x1, x2] = out.assume_init();
+        (x1, x2)
+    }
+}
+
+pub use libc::strlen;
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
new file mode 100644 (file)
index 0000000..63ba634
--- /dev/null
@@ -0,0 +1,469 @@
+use super::abi;
+use crate::{
+    cmp,
+    ffi::CStr,
+    io::{self, ErrorKind, IoSlice, IoSliceMut},
+    mem,
+    net::{Shutdown, SocketAddr},
+    ptr, str,
+    sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr},
+    sys_common::{AsInner, FromInner, IntoInner},
+    time::Duration,
+};
+
+use self::netc::{sockaddr, socklen_t, MSG_PEEK};
+use libc::{c_int, c_void, size_t};
+
+pub mod netc {
+    pub use super::super::abi::sockets::*;
+}
+
+pub type wrlen_t = size_t;
+
+const READ_LIMIT: usize = libc::ssize_t::MAX as usize;
+
+const fn max_iov() -> usize {
+    // Judging by the source code, it's unlimited, but specify a lower
+    // value just in case.
+    1024
+}
+
+/// A file descriptor.
+#[rustc_layout_scalar_valid_range_start(0)]
+// libstd/os/raw/mod.rs assures me that every libstd-supported platform has a
+// 32-bit c_int. Below is -2, in two's complement, but that only works out
+// because c_int is 32 bits.
+#[rustc_layout_scalar_valid_range_end(0xFF_FF_FF_FE)]
+struct FileDesc {
+    fd: c_int,
+}
+
+impl FileDesc {
+    #[inline]
+    fn new(fd: c_int) -> FileDesc {
+        assert_ne!(fd, -1i32);
+        // Safety: we just asserted that the value is in the valid range and
+        // isn't `-1` (the only value bigger than `0xFF_FF_FF_FE` unsigned)
+        unsafe { FileDesc { fd } }
+    }
+
+    #[inline]
+    fn raw(&self) -> c_int {
+        self.fd
+    }
+
+    /// Extracts the actual file descriptor without closing it.
+    #[inline]
+    fn into_raw(self) -> c_int {
+        let fd = self.fd;
+        mem::forget(self);
+        fd
+    }
+
+    fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            netc::read(self.fd, buf.as_mut_ptr() as *mut c_void, cmp::min(buf.len(), READ_LIMIT))
+        })?;
+        Ok(ret as usize)
+    }
+
+    fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            netc::readv(
+                self.fd,
+                bufs.as_ptr() as *const netc::iovec,
+                cmp::min(bufs.len(), max_iov()) as c_int,
+            )
+        })?;
+        Ok(ret as usize)
+    }
+
+    #[inline]
+    fn is_read_vectored(&self) -> bool {
+        true
+    }
+
+    fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            netc::write(self.fd, buf.as_ptr() as *const c_void, cmp::min(buf.len(), READ_LIMIT))
+        })?;
+        Ok(ret as usize)
+    }
+
+    fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            netc::writev(
+                self.fd,
+                bufs.as_ptr() as *const netc::iovec,
+                cmp::min(bufs.len(), max_iov()) as c_int,
+            )
+        })?;
+        Ok(ret as usize)
+    }
+
+    #[inline]
+    fn is_write_vectored(&self) -> bool {
+        true
+    }
+
+    fn duplicate(&self) -> io::Result<FileDesc> {
+        super::unsupported()
+    }
+}
+
+impl AsInner<c_int> for FileDesc {
+    fn as_inner(&self) -> &c_int {
+        &self.fd
+    }
+}
+
+impl Drop for FileDesc {
+    fn drop(&mut self) {
+        unsafe { netc::close(self.fd) };
+    }
+}
+
+#[doc(hidden)]
+pub trait IsMinusOne {
+    fn is_minus_one(&self) -> bool;
+}
+
+macro_rules! impl_is_minus_one {
+    ($($t:ident)*) => ($(impl IsMinusOne for $t {
+        fn is_minus_one(&self) -> bool {
+            *self == -1
+        }
+    })*)
+}
+
+impl_is_minus_one! { i8 i16 i32 i64 isize }
+
+pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
+    if t.is_minus_one() { Err(last_error()) } else { Ok(t) }
+}
+
+/// A variant of `cvt` for `getaddrinfo` which return 0 for a success.
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+    if err == 0 {
+        Ok(())
+    } else {
+        let msg: &dyn crate::fmt::Display = match err {
+            netc::EAI_NONAME => &"name or service not known",
+            netc::EAI_SERVICE => &"service not supported",
+            netc::EAI_FAIL => &"non-recoverable failure in name resolution",
+            netc::EAI_MEMORY => &"memory allocation failure",
+            netc::EAI_FAMILY => &"family not supported",
+            _ => &err,
+        };
+        Err(io::Error::new(
+            io::ErrorKind::Uncategorized,
+            &format!("failed to lookup address information: {}", msg)[..],
+        ))
+    }
+}
+
+/// Just to provide the same interface as sys/unix/net.rs
+pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
+where
+    T: IsMinusOne,
+    F: FnMut() -> T,
+{
+    cvt(f())
+}
+
+/// Returns the last error from the network subsystem.
+fn last_error() -> io::Error {
+    io::Error::from_raw_os_error(unsafe { netc::SOLID_NET_GetLastError() })
+}
+
+pub(super) fn error_name(er: abi::ER) -> Option<&'static str> {
+    unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok()
+}
+
+pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind {
+    let errno = netc::SOLID_NET_ERR_BASE - er;
+    match errno as libc::c_int {
+        libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
+        libc::ECONNRESET => ErrorKind::ConnectionReset,
+        libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
+        libc::EPIPE => ErrorKind::BrokenPipe,
+        libc::ENOTCONN => ErrorKind::NotConnected,
+        libc::ECONNABORTED => ErrorKind::ConnectionAborted,
+        libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+        libc::EADDRINUSE => ErrorKind::AddrInUse,
+        libc::ENOENT => ErrorKind::NotFound,
+        libc::EINTR => ErrorKind::Interrupted,
+        libc::EINVAL => ErrorKind::InvalidInput,
+        libc::ETIMEDOUT => ErrorKind::TimedOut,
+        libc::EEXIST => ErrorKind::AlreadyExists,
+        libc::ENOSYS => ErrorKind::Unsupported,
+        libc::ENOMEM => ErrorKind::OutOfMemory,
+        libc::EAGAIN => ErrorKind::WouldBlock,
+
+        _ => ErrorKind::Uncategorized,
+    }
+}
+
+pub fn init() {}
+
+pub struct Socket(FileDesc);
+
+impl Socket {
+    pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+        let fam = match *addr {
+            SocketAddr::V4(..) => netc::AF_INET,
+            SocketAddr::V6(..) => netc::AF_INET6,
+        };
+        Socket::new_raw(fam, ty)
+    }
+
+    pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+        unsafe {
+            let fd = cvt(netc::socket(fam, ty, 0))?;
+            let fd = FileDesc::new(fd);
+            let socket = Socket(fd);
+
+            Ok(socket)
+        }
+    }
+
+    pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+        self.set_nonblocking(true)?;
+        let r = unsafe {
+            let (addrp, len) = addr.into_inner();
+            cvt(netc::connect(self.0.raw(), addrp, len))
+        };
+        self.set_nonblocking(false)?;
+
+        match r {
+            Ok(_) => return Ok(()),
+            // there's no ErrorKind for EINPROGRESS
+            Err(ref e) if e.raw_os_error() == Some(netc::EINPROGRESS) => {}
+            Err(e) => return Err(e),
+        }
+
+        if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+            return Err(io::Error::new_const(
+                io::ErrorKind::InvalidInput,
+                &"cannot set a 0 duration timeout",
+            ));
+        }
+
+        let mut timeout =
+            netc::timeval { tv_sec: timeout.as_secs() as _, tv_usec: timeout.subsec_micros() as _ };
+        if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+            timeout.tv_usec = 1;
+        }
+
+        let fds = netc::fd_set { num_fds: 1, fds: [self.0.raw()] };
+
+        let mut writefds = fds;
+        let mut errorfds = fds;
+
+        let n = unsafe {
+            cvt(netc::select(
+                self.0.raw() + 1,
+                ptr::null_mut(),
+                &mut writefds,
+                &mut errorfds,
+                &mut timeout,
+            ))?
+        };
+
+        match n {
+            0 => Err(io::Error::new_const(io::ErrorKind::TimedOut, &"connection timed out")),
+            _ => {
+                let can_write = writefds.num_fds != 0;
+                if !can_write {
+                    if let Some(e) = self.take_error()? {
+                        return Err(e);
+                    }
+                }
+                Ok(())
+            }
+        }
+    }
+
+    pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t) -> io::Result<Socket> {
+        let fd = cvt_r(|| unsafe { netc::accept(self.0.raw(), storage, len) })?;
+        let fd = FileDesc::new(fd);
+        Ok(Socket(fd))
+    }
+
+    pub fn duplicate(&self) -> io::Result<Socket> {
+        self.0.duplicate().map(Socket)
+    }
+
+    fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+        let ret = cvt(unsafe {
+            netc::recv(self.0.raw(), buf.as_mut_ptr() as *mut c_void, buf.len(), flags)
+        })?;
+        Ok(ret as usize)
+    }
+
+    pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.recv_with_flags(buf, 0)
+    }
+
+    pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+        self.recv_with_flags(buf, MSG_PEEK)
+    }
+
+    pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+        self.0.read_vectored(bufs)
+    }
+
+    #[inline]
+    pub fn is_read_vectored(&self) -> bool {
+        self.0.is_read_vectored()
+    }
+
+    fn recv_from_with_flags(
+        &self,
+        buf: &mut [u8],
+        flags: c_int,
+    ) -> io::Result<(usize, SocketAddr)> {
+        let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
+        let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
+
+        let n = cvt(unsafe {
+            netc::recvfrom(
+                self.0.raw(),
+                buf.as_mut_ptr() as *mut c_void,
+                buf.len(),
+                flags,
+                &mut storage as *mut _ as *mut _,
+                &mut addrlen,
+            )
+        })?;
+        Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+    }
+
+    pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, 0)
+    }
+
+    pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+        self.recv_from_with_flags(buf, MSG_PEEK)
+    }
+
+    pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+        self.0.write(buf)
+    }
+
+    pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+        self.0.write_vectored(bufs)
+    }
+
+    #[inline]
+    pub fn is_write_vectored(&self) -> bool {
+        self.0.is_write_vectored()
+    }
+
+    pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> {
+        let timeout = match dur {
+            Some(dur) => {
+                if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+                    return Err(io::Error::new_const(
+                        io::ErrorKind::InvalidInput,
+                        &"cannot set a 0 duration timeout",
+                    ));
+                }
+
+                let secs = if dur.as_secs() > netc::c_long::MAX as u64 {
+                    netc::c_long::MAX
+                } else {
+                    dur.as_secs() as netc::c_long
+                };
+                let mut timeout = netc::timeval { tv_sec: secs, tv_usec: dur.subsec_micros() as _ };
+                if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+                    timeout.tv_usec = 1;
+                }
+                timeout
+            }
+            None => netc::timeval { tv_sec: 0, tv_usec: 0 },
+        };
+        setsockopt(self, netc::SOL_SOCKET, kind, timeout)
+    }
+
+    pub fn timeout(&self, kind: c_int) -> io::Result<Option<Duration>> {
+        let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
+        if raw.tv_sec == 0 && raw.tv_usec == 0 {
+            Ok(None)
+        } else {
+            let sec = raw.tv_sec as u64;
+            let nsec = (raw.tv_usec as u32) * 1000;
+            Ok(Some(Duration::new(sec, nsec)))
+        }
+    }
+
+    pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+        let how = match how {
+            Shutdown::Write => netc::SHUT_WR,
+            Shutdown::Read => netc::SHUT_RD,
+            Shutdown::Both => netc::SHUT_RDWR,
+        };
+        cvt(unsafe { netc::shutdown(self.0.raw(), how) })?;
+        Ok(())
+    }
+
+    pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+        let linger = netc::linger {
+            l_onoff: linger.is_some() as netc::c_int,
+            l_linger: linger.unwrap_or_default().as_secs() as netc::c_int,
+        };
+
+        setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
+    }
+
+    pub fn linger(&self) -> io::Result<Option<Duration>> {
+        let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
+
+        Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
+    }
+
+    pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+        setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, nodelay as c_int)
+    }
+
+    pub fn nodelay(&self) -> io::Result<bool> {
+        let raw: c_int = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
+        Ok(raw != 0)
+    }
+
+    pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+        let mut nonblocking = nonblocking as c_int;
+        cvt(unsafe {
+            netc::ioctl(*self.as_inner(), netc::FIONBIO, (&mut nonblocking) as *mut c_int as _)
+        })
+        .map(drop)
+    }
+
+    pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+        let raw: c_int = getsockopt(self, netc::SOL_SOCKET, netc::SO_ERROR)?;
+        if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) }
+    }
+
+    // This method is used by sys_common code to abstract over targets.
+    pub fn as_raw(&self) -> c_int {
+        *self.as_inner()
+    }
+}
+
+impl AsInner<c_int> for Socket {
+    fn as_inner(&self) -> &c_int {
+        self.0.as_inner()
+    }
+}
+
+impl FromInner<c_int> for Socket {
+    fn from_inner(fd: c_int) -> Socket {
+        Socket(FileDesc::new(fd))
+    }
+}
+
+impl IntoInner<c_int> for Socket {
+    fn into_inner(self) -> c_int {
+        self.0.into_raw()
+    }
+}
diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs
new file mode 100644 (file)
index 0000000..82542d8
--- /dev/null
@@ -0,0 +1,200 @@
+use super::unsupported;
+use crate::error::Error as StdError;
+use crate::ffi::{CStr, CString, OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::os::{
+    raw::{c_char, c_int},
+    solid::ffi::{OsStrExt, OsStringExt},
+};
+use crate::path::{self, PathBuf};
+use crate::sys_common::rwlock::StaticRWLock;
+use crate::vec;
+
+use super::{abi, error, itron, memchr};
+
+// `solid` directly maps `errno`s to μITRON error codes.
+impl itron::error::ItronError {
+    #[inline]
+    pub(crate) fn as_io_error(self) -> crate::io::Error {
+        crate::io::Error::from_raw_os_error(self.as_raw())
+    }
+}
+
+pub fn errno() -> i32 {
+    0
+}
+
+pub fn error_string(errno: i32) -> String {
+    if let Some(name) = error::error_name(errno) { name.to_owned() } else { format!("{}", errno) }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+    unsupported()
+}
+
+pub struct SplitPaths<'a>(&'a !);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+    panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+    type Item = PathBuf;
+    fn next(&mut self) -> Option<PathBuf> {
+        *self.0
+    }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+    I: Iterator<Item = T>,
+    T: AsRef<OsStr>,
+{
+    Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        "not supported on this platform yet".fmt(f)
+    }
+}
+
+impl StdError for JoinPathsError {
+    #[allow(deprecated)]
+    fn description(&self) -> &str {
+        "not supported on this platform yet"
+    }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+    unsupported()
+}
+
+static ENV_LOCK: StaticRWLock = StaticRWLock::new();
+
+pub struct Env {
+    iter: vec::IntoIter<(OsString, OsString)>,
+}
+
+impl !Send for Env {}
+impl !Sync for Env {}
+
+impl Iterator for Env {
+    type Item = (OsString, OsString);
+    fn next(&mut self) -> Option<(OsString, OsString)> {
+        self.iter.next()
+    }
+    fn size_hint(&self) -> (usize, Option<usize>) {
+        self.iter.size_hint()
+    }
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+    extern "C" {
+        static mut environ: *const *const c_char;
+    }
+
+    unsafe {
+        let _guard = ENV_LOCK.read();
+        let mut result = Vec::new();
+        if !environ.is_null() {
+            while !(*environ).is_null() {
+                if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
+                    result.push(key_value);
+                }
+                environ = environ.add(1);
+            }
+        }
+        return Env { iter: result.into_iter() };
+    }
+
+    fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
+        // Strategy (copied from glibc): Variable name and value are separated
+        // by an ASCII equals sign '='. Since a variable name must not be
+        // empty, allow variable names starting with an equals sign. Skip all
+        // malformed lines.
+        if input.is_empty() {
+            return None;
+        }
+        let pos = memchr::memchr(b'=', &input[1..]).map(|p| p + 1);
+        pos.map(|p| {
+            (
+                OsStringExt::from_vec(input[..p].to_vec()),
+                OsStringExt::from_vec(input[p + 1..].to_vec()),
+            )
+        })
+    }
+}
+
+pub fn getenv(k: &OsStr) -> Option<OsString> {
+    // environment variables with a nul byte can't be set, so their value is
+    // always None as well
+    let k = CString::new(k.as_bytes()).ok()?;
+    unsafe {
+        let _guard = ENV_LOCK.read();
+        let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
+        if s.is_null() {
+            None
+        } else {
+            Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
+        }
+    }
+}
+
+pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
+    let k = CString::new(k.as_bytes())?;
+    let v = CString::new(v.as_bytes())?;
+
+    unsafe {
+        let _guard = ENV_LOCK.write();
+        cvt_env(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(drop)
+    }
+}
+
+pub fn unsetenv(n: &OsStr) -> io::Result<()> {
+    let nbuf = CString::new(n.as_bytes())?;
+
+    unsafe {
+        let _guard = ENV_LOCK.write();
+        cvt_env(libc::unsetenv(nbuf.as_ptr())).map(drop)
+    }
+}
+
+/// In kmclib, `setenv` and `unsetenv` don't always set `errno`, so this
+/// function just returns a generic error.
+fn cvt_env(t: c_int) -> io::Result<c_int> {
+    if t == -1 {
+        Err(io::Error::new_const(io::ErrorKind::Uncategorized, &"failure"))
+    } else {
+        Ok(t)
+    }
+}
+
+pub fn temp_dir() -> PathBuf {
+    panic!("no standard temporary directory on this platform")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+    None
+}
+
+pub fn exit(_code: i32) -> ! {
+    let tid = itron::task::try_current_task_id().unwrap_or(0);
+    loop {
+        abi::breakpoint_program_exited(tid as usize);
+    }
+}
+
+pub fn getpid() -> u32 {
+    panic!("no pids on this platform")
+}
diff --git a/library/std/src/sys/solid/path.rs b/library/std/src/sys/solid/path.rs
new file mode 100644 (file)
index 0000000..4a14332
--- /dev/null
@@ -0,0 +1,19 @@
+use crate::ffi::OsStr;
+use crate::path::Prefix;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+    b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+    b == b'\\'
+}
+
+pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
+    None
+}
+
+pub const MAIN_SEP_STR: &str = "\\";
+pub const MAIN_SEP: char = '\\';
diff --git a/library/std/src/sys/solid/rwlock.rs b/library/std/src/sys/solid/rwlock.rs
new file mode 100644 (file)
index 0000000..4e39ac2
--- /dev/null
@@ -0,0 +1,92 @@
+//! A readers-writer lock implementation backed by the SOLID kernel extension.
+use super::{
+    abi,
+    itron::{
+        error::{expect_success, expect_success_aborting, fail, ItronError},
+        spin::SpinIdOnceCell,
+    },
+};
+
+pub struct RWLock {
+    /// The ID of the underlying mutex object
+    rwl: SpinIdOnceCell<()>,
+}
+
+pub type MovableRWLock = RWLock;
+
+// Safety: `num_readers` is protected by `mtx_num_readers`
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+fn new_rwl() -> Result<abi::ID, ItronError> {
+    ItronError::err_if_negative(unsafe { abi::rwl_acre_rwl() })
+}
+
+impl RWLock {
+    pub const fn new() -> RWLock {
+        RWLock { rwl: SpinIdOnceCell::new() }
+    }
+
+    /// Get the inner mutex's ID, which is lazily created.
+    fn raw(&self) -> abi::ID {
+        match self.rwl.get_or_try_init(|| new_rwl().map(|id| (id, ()))) {
+            Ok((id, ())) => id,
+            Err(e) => fail(e, &"rwl_acre_rwl"),
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read(&self) {
+        let rwl = self.raw();
+        expect_success(unsafe { abi::rwl_loc_rdl(rwl) }, &"rwl_loc_rdl");
+    }
+
+    #[inline]
+    pub unsafe fn try_read(&self) -> bool {
+        let rwl = self.raw();
+        match unsafe { abi::rwl_ploc_rdl(rwl) } {
+            abi::E_TMOUT => false,
+            er => {
+                expect_success(er, &"rwl_ploc_rdl");
+                true
+            }
+        }
+    }
+
+    #[inline]
+    pub unsafe fn write(&self) {
+        let rwl = self.raw();
+        expect_success(unsafe { abi::rwl_loc_wrl(rwl) }, &"rwl_loc_wrl");
+    }
+
+    #[inline]
+    pub unsafe fn try_write(&self) -> bool {
+        let rwl = self.raw();
+        match unsafe { abi::rwl_ploc_wrl(rwl) } {
+            abi::E_TMOUT => false,
+            er => {
+                expect_success(er, &"rwl_ploc_wrl");
+                true
+            }
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        let rwl = self.raw();
+        expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl");
+    }
+
+    #[inline]
+    pub unsafe fn write_unlock(&self) {
+        let rwl = self.raw();
+        expect_success_aborting(unsafe { abi::rwl_unl_rwl(rwl) }, &"rwl_unl_rwl");
+    }
+
+    #[inline]
+    pub unsafe fn destroy(&self) {
+        if let Some(rwl) = self.rwl.get().map(|x| x.0) {
+            expect_success_aborting(unsafe { abi::rwl_del_rwl(rwl) }, &"rwl_del_rwl");
+        }
+    }
+}
diff --git a/library/std/src/sys/solid/stdio.rs b/library/std/src/sys/solid/stdio.rs
new file mode 100644 (file)
index 0000000..50f0176
--- /dev/null
@@ -0,0 +1,80 @@
+use super::abi;
+use crate::io;
+
+pub struct Stdin;
+pub struct Stdout;
+pub struct Stderr;
+struct PanicOutput;
+
+impl Stdin {
+    pub const fn new() -> Stdin {
+        Stdin
+    }
+}
+
+impl io::Read for Stdin {
+    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+        Ok(0)
+    }
+}
+
+impl Stdout {
+    pub const fn new() -> Stdout {
+        Stdout
+    }
+}
+
+impl io::Write for Stdout {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) };
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl Stderr {
+    pub const fn new() -> Stderr {
+        Stderr
+    }
+}
+
+impl io::Write for Stderr {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) };
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+impl PanicOutput {
+    pub const fn new() -> PanicOutput {
+        PanicOutput
+    }
+}
+
+impl io::Write for PanicOutput {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        unsafe { abi::SOLID_LOG_write(buf.as_ptr(), buf.len()) };
+        Ok(buf.len())
+    }
+
+    fn flush(&mut self) -> io::Result<()> {
+        Ok(())
+    }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+    true
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+    Some(PanicOutput::new())
+}
diff --git a/library/std/src/sys/solid/thread_local_dtor.rs b/library/std/src/sys/solid/thread_local_dtor.rs
new file mode 100644 (file)
index 0000000..9735645
--- /dev/null
@@ -0,0 +1,50 @@
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "none")]
+
+// Simplify dtor registration by using a list of destructors.
+
+use super::{abi, itron::task};
+use crate::cell::Cell;
+use crate::ptr;
+
+#[thread_local]
+static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+
+type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
+    if DTORS.get().is_null() {
+        let tid = task::current_task_id_aborting();
+        let v: Box<List> = box Vec::new();
+        DTORS.set(Box::into_raw(v));
+
+        // Register `tls_dtor` to make sure the TLS destructors are called
+        // for tasks created by other means than `std::thread`
+        unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) };
+    }
+
+    let list: &mut List = unsafe { &mut *DTORS.get() };
+    list.push((t, dtor));
+}
+
+pub unsafe fn run_dtors() {
+    let ptr = DTORS.get();
+    if !ptr.is_null() {
+        // Swap the destructor list, call all registered destructors,
+        // and repeat this until the list becomes permanently empty.
+        while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new()))
+            .filter(|list| !list.is_empty())
+        {
+            for (ptr, dtor) in list.into_iter() {
+                unsafe { dtor(ptr) };
+            }
+        }
+
+        // Drop the destructor list
+        unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) };
+    }
+}
+
+unsafe extern "C" fn tls_dtor(_unused: *mut u8) {
+    unsafe { run_dtors() };
+}
diff --git a/library/std/src/sys/solid/thread_local_key.rs b/library/std/src/sys/solid/thread_local_key.rs
new file mode 100644 (file)
index 0000000..b17521f
--- /dev/null
@@ -0,0 +1,26 @@
+pub type Key = usize;
+
+#[inline]
+pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
+    panic!("should not be used on the solid target");
+}
+
+#[inline]
+pub unsafe fn set(_key: Key, _value: *mut u8) {
+    panic!("should not be used on the solid target");
+}
+
+#[inline]
+pub unsafe fn get(_key: Key) -> *mut u8 {
+    panic!("should not be used on the solid target");
+}
+
+#[inline]
+pub unsafe fn destroy(_key: Key) {
+    panic!("should not be used on the solid target");
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+    panic!("should not be used on the solid target");
+}
diff --git a/library/std/src/sys/solid/time.rs b/library/std/src/sys/solid/time.rs
new file mode 100644 (file)
index 0000000..c67a736
--- /dev/null
@@ -0,0 +1,56 @@
+use super::{abi, error::expect_success};
+use crate::{convert::TryInto, mem::MaybeUninit, time::Duration};
+
+pub use super::itron::time::Instant;
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub struct SystemTime(abi::time_t);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(0);
+
+impl SystemTime {
+    pub fn now() -> SystemTime {
+        let rtc = unsafe {
+            let mut out = MaybeUninit::zeroed();
+            expect_success(abi::SOLID_RTC_ReadTime(out.as_mut_ptr()), &"SOLID_RTC_ReadTime");
+            out.assume_init()
+        };
+        let t = unsafe {
+            libc::mktime(&mut libc::tm {
+                tm_sec: rtc.tm_sec,
+                tm_min: rtc.tm_min,
+                tm_hour: rtc.tm_hour,
+                tm_mday: rtc.tm_mday,
+                tm_mon: rtc.tm_mon,
+                tm_year: rtc.tm_year,
+                tm_wday: rtc.tm_wday,
+                tm_yday: 0,
+                tm_isdst: 0,
+                tm_gmtoff: 0,
+                tm_zone: crate::ptr::null_mut(),
+            })
+        };
+        assert_ne!(t, -1, "mktime failed");
+        SystemTime(t)
+    }
+
+    pub(super) fn from_time_t(t: abi::time_t) -> Self {
+        Self(t)
+    }
+
+    pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
+        if self.0 >= other.0 {
+            Ok(Duration::from_secs((self.0 as u64).wrapping_sub(other.0 as u64)))
+        } else {
+            Err(Duration::from_secs((other.0 as u64).wrapping_sub(self.0 as u64)))
+        }
+    }
+
+    pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime(self.0.checked_add(other.as_secs().try_into().ok()?)?))
+    }
+
+    pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
+        Some(SystemTime(self.0.checked_sub(other.as_secs().try_into().ok()?)?))
+    }
+}
index bf3eb5b30c77d356d9b1d256b25c9ae1f22c05ba..5efd8c9be56333be494db209d4f9e4861b9cd62a 100644 (file)
 /// | UNIX      | [clock_gettime (Monotonic Clock)]                                    |
 /// | Darwin    | [mach_absolute_time]                                                 |
 /// | VXWorks   | [clock_gettime (Monotonic Clock)]                                    |
+/// | SOLID     | `get_tim`                                                            |
 /// | WASI      | [__wasi_clock_time_get (Monotonic Clock)]                            |
 /// | Windows   | [QueryPerformanceCounter]                                            |
 ///
 /// | UNIX      | [clock_gettime (Realtime Clock)]                                     |
 /// | Darwin    | [gettimeofday]                                                       |
 /// | VXWorks   | [clock_gettime (Realtime Clock)]                                     |
+/// | SOLID     | `SOLID_RTC_ReadTime`                                                 |
 /// | WASI      | [__wasi_clock_time_get (Realtime Clock)]                             |
 /// | Windows   | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime]         |
 ///
@@ -472,7 +474,7 @@ pub fn now() -> SystemTime {
     /// as the system clock being adjusted either forwards or backwards).
     /// [`Instant`] can be used to measure elapsed time without this risk of failure.
     ///
-    /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents
+    /// If successful, <code>[Ok]\([Duration])</code> is returned where the duration represents
     /// the amount of time elapsed from the specified measurement to this one.
     ///
     /// Returns an [`Err`] if `earlier` is later than `self`, and the error
@@ -499,7 +501,7 @@ pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTime
     ///
     /// This function may fail as the underlying system clock is susceptible to
     /// drift and updates (e.g., the system clock could go backwards), so this
-    /// function might not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is
+    /// function might not always succeed. If successful, <code>[Ok]\([Duration])</code> is
     /// returned where the duration represents the amount of time elapsed from
     /// this time measurement to the current time.
     ///
index 89b0e355bc3cff5cddec2290c84f36eb3a026aad..5fdbc476afc81a789806697fc4a2d9d19b8c9993 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 89b0e355bc3cff5cddec2290c84f36eb3a026aad
+Subproject commit 5fdbc476afc81a789806697fc4a2d9d19b8c9993
index 80d6072e9b5c23376a26a823807cc76f2686b216..04dab6b804acc2e5f2b35556995ad1a318407cf7 100644 (file)
@@ -33,3 +33,4 @@ panic_immediate_abort = ["std/panic_immediate_abort"]
 profiler = ["std/profiler"]
 std_detect_file_io = ["std/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]
+std_detect_env_override = ["std/std_detect_env_override"]
index 06384b159264789108eb7329e14b5eb85437e6d4..25be9e7cc6c0cd217769d902ac6c89b7de8fd09a 100644 (file)
@@ -23,6 +23,7 @@
         unix,
         windows,
         target_os = "psp",
+        target_os = "solid_asp3",
         all(target_vendor = "fortanix", target_env = "sgx"),
     ))] {
         mod libunwind;
index 480b19a5e933685cde31dddb4c6076b1169c2174..053f3e3ee583b9afbe4783715ad4892f80d88569 100644 (file)
@@ -19,6 +19,7 @@ ignore = [
     "library/backtrace",
     "library/stdarch",
     "compiler/rustc_codegen_cranelift",
+    "compiler/rustc_codegen_gcc",
     "src/doc/book",
     "src/doc/edition-guide",
     "src/doc/embedded-book",
index 0a6ed2f49b7877dcc19549b8571ed592509ffbfc..1f2109879d121bc452264f42afbf8f60dae5fecf 100644 (file)
@@ -1617,6 +1617,22 @@ pub(crate) fn ensure_if_default<T, S: Step<Output = Option<T>>>(
         // Only execute if it's supposed to run as default
         if desc.default && should_run.is_really_default() { self.ensure(step) } else { None }
     }
+
+    /// Checks if any of the "should_run" paths is in the `Builder` paths.
+    pub(crate) fn was_invoked_explicitly<S: Step>(&'a self) -> bool {
+        let desc = StepDescription::from::<S>();
+        let should_run = (desc.should_run)(ShouldRun::new(self));
+
+        for path in &self.paths {
+            if should_run.paths.iter().any(|s| s.has(path))
+                && !desc.is_excluded(self, &PathSet::Suite(path.clone()))
+            {
+                return true;
+            }
+        }
+
+        false
+    }
 }
 
 #[cfg(test)]
index f66f282bea933e0bfbf817f589e74c814eb3fd16..28e7f1fdca7a19519e957f93690c8402abf6697e 100644 (file)
@@ -243,11 +243,16 @@ impl Step for CodegenBackend {
     const DEFAULT: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.paths(&["compiler/rustc_codegen_cranelift", "rustc_codegen_cranelift"])
+        run.paths(&[
+            "compiler/rustc_codegen_cranelift",
+            "rustc_codegen_cranelift",
+            "compiler/rustc_codegen_gcc",
+            "rustc_codegen_gcc",
+        ])
     }
 
     fn make_run(run: RunConfig<'_>) {
-        for &backend in &[INTERNER.intern_str("cranelift")] {
+        for &backend in &[INTERNER.intern_str("cranelift"), INTERNER.intern_str("gcc")] {
             run.builder.ensure(CodegenBackend { target: run.target, backend });
         }
     }
index af3774b7c7586ef3f33d38747405153b0eb4dff0..6f2470b706a64ff8d16b979376181196ce976230 100644 (file)
@@ -102,18 +102,10 @@ fn open(builder: &Builder<'_>, path: impl AsRef<Path>) {
 // Used for deciding whether a particular step is one requested by the user on
 // the `x.py doc` command line, which determines whether `--open` will open that
 // page.
-fn components_simplified(path: &PathBuf) -> Vec<&str> {
+pub(crate) fn components_simplified(path: &PathBuf) -> Vec<&str> {
     path.iter().map(|component| component.to_str().unwrap_or("???")).collect()
 }
 
-fn is_explicit_request(builder: &Builder<'_>, path: &str) -> bool {
-    builder
-        .paths
-        .iter()
-        .map(components_simplified)
-        .any(|requested| requested.iter().copied().eq(path.split('/')))
-}
-
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
 pub struct UnstableBook {
     target: TargetSelection,
@@ -248,7 +240,7 @@ fn run(self, builder: &Builder<'_>) {
             invoke_rustdoc(builder, compiler, target, path);
         }
 
-        if is_explicit_request(builder, "src/doc/book") {
+        if builder.was_invoked_explicitly::<Self>() {
             let out = builder.doc_out(target);
             let index = out.join("book").join("index.html");
             open(builder, &index);
@@ -408,7 +400,7 @@ fn run(self, builder: &Builder<'_>) {
 
         // We open doc/index.html as the default if invoked as `x.py doc --open`
         // with no particular explicit doc requested (e.g. library/core).
-        if builder.paths.is_empty() || is_explicit_request(builder, "src/doc") {
+        if builder.paths.is_empty() || builder.was_invoked_explicitly::<Self>() {
             let index = out.join("index.html");
             open(builder, &index);
         }
@@ -553,7 +545,6 @@ fn make_run(run: RunConfig<'_>) {
     fn run(self, builder: &Builder<'_>) {
         let stage = self.stage;
         let target = self.target;
-        let mut is_explicit_request = false;
         builder.info(&format!("Documenting stage{} compiler ({})", stage, target));
 
         let paths = builder
@@ -562,7 +553,6 @@ fn run(self, builder: &Builder<'_>) {
             .map(components_simplified)
             .filter_map(|path| {
                 if path.get(0) == Some(&"compiler") {
-                    is_explicit_request = true;
                     path.get(1).map(|p| p.to_owned())
                 } else {
                     None
@@ -570,7 +560,7 @@ fn run(self, builder: &Builder<'_>) {
             })
             .collect::<Vec<_>>();
 
-        if !builder.config.compiler_docs && !is_explicit_request {
+        if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
             builder.info("\tskipping - compiler/librustdoc docs disabled");
             return;
         }
@@ -700,7 +690,14 @@ fn make_run(run: RunConfig<'_>) {
             fn run(self, builder: &Builder<'_>) {
                 let stage = self.stage;
                 let target = self.target;
-                builder.info(&format!("Documenting stage{} {} ({})", stage, stringify!($tool).to_lowercase(), target));
+                builder.info(
+                    &format!(
+                        "Documenting stage{} {} ({})",
+                        stage,
+                        stringify!($tool).to_lowercase(),
+                        target,
+                    ),
+                );
 
                 // This is the intended out directory for compiler documentation.
                 let out = builder.compiler_doc_out(target);
@@ -708,7 +705,7 @@ fn run(self, builder: &Builder<'_>) {
 
                 let compiler = builder.compiler(stage, builder.config.build);
 
-                if !builder.config.compiler_docs {
+                if !builder.config.compiler_docs && !builder.was_invoked_explicitly::<Self>() {
                     builder.info("\tskipping - compiler/tool docs disabled");
                     return;
                 }
@@ -743,6 +740,7 @@ fn run(self, builder: &Builder<'_>) {
                 cargo.rustdocflag("--document-private-items");
                 cargo.rustdocflag("--enable-index-page");
                 cargo.rustdocflag("--show-type-layout");
+                cargo.rustdocflag("--generate-link-to-definition");
                 cargo.rustdocflag("-Zunstable-options");
                 builder.run(&mut cargo.into());
             }
@@ -912,7 +910,7 @@ fn run(self, builder: &Builder<'_>) {
             name: INTERNER.intern_str("rustc"),
             src: INTERNER.intern_path(out_base),
         });
-        if is_explicit_request(builder, "src/doc/rustc") {
+        if builder.was_invoked_explicitly::<Self>() {
             let out = builder.doc_out(self.target);
             let index = out.join("rustc").join("index.html");
             open(builder, &index);
index a5829dfa9d87905192b6331a780e2f397d519431..5bc0a505bf6954602f44fb94b872126e09c15467 100644 (file)
@@ -1,3 +1,4 @@
+use crate::TargetSelection;
 use crate::{t, VERSION};
 use std::fmt::Write as _;
 use std::path::{Path, PathBuf};
@@ -107,6 +108,17 @@ pub fn setup(src_path: &Path, profile: Profile) {
     let include_path = profile.include_path(src_path);
     println!("`x.py` will now use the configuration at {}", include_path.display());
 
+    let build = TargetSelection::from_user(&env!("BUILD_TRIPLE"));
+    let stage_path = ["build", build.rustc_target_arg(), "stage1"].join("/");
+
+    println!();
+
+    if !rustup_installed() && profile != Profile::User {
+        println!("`rustup` is not installed; cannot link `stage1` toolchain");
+    } else if stage_dir_exists(&stage_path[..]) {
+        attempt_toolchain_link(&stage_path[..]);
+    }
+
     let suggestions = match profile {
         Profile::Codegen | Profile::Compiler => &["check", "build", "test"][..],
         Profile::Tools => &[
@@ -139,6 +151,74 @@ pub fn setup(src_path: &Path, profile: Profile) {
     }
 }
 
+fn rustup_installed() -> bool {
+    Command::new("rustup")
+        .arg("--version")
+        .stdout(std::process::Stdio::null())
+        .output()
+        .map_or(false, |output| output.status.success())
+}
+
+fn stage_dir_exists(stage_path: &str) -> bool {
+    match fs::create_dir(&stage_path[..]) {
+        Ok(_) => true,
+        Err(_) => Path::new(&stage_path[..]).exists(),
+    }
+}
+
+fn attempt_toolchain_link(stage_path: &str) {
+    if toolchain_is_linked() {
+        return;
+    }
+
+    if try_link_toolchain(&stage_path[..]) {
+        println!(
+            "Added `stage1` rustup toolchain; try `cargo +stage1 build` on a separate rust project to run a newly-built toolchain"
+        );
+    } else {
+        println!("`rustup` failed to link stage 1 build to `stage1` toolchain");
+        println!(
+            "To manually link stage 1 build to `stage1` toolchain, run:\n
+            `rustup toolchain link stage1 {}`",
+            &stage_path[..]
+        );
+    }
+}
+
+fn toolchain_is_linked() -> bool {
+    match Command::new("rustup")
+        .args(&["toolchain", "list"])
+        .stdout(std::process::Stdio::piped())
+        .output()
+    {
+        Ok(toolchain_list) => {
+            if !String::from_utf8_lossy(&toolchain_list.stdout).contains("stage1") {
+                return false;
+            }
+            // The toolchain has already been linked.
+            println!(
+                "`stage1` toolchain already linked; not attempting to link `stage1` toolchain"
+            );
+        }
+        Err(_) => {
+            // In this case, we don't know if the `stage1` toolchain has been linked;
+            // but `rustup` failed, so let's not go any further.
+            println!(
+                "`rustup` failed to list current toolchains; not attempting to link `stage1` toolchain"
+            );
+        }
+    }
+    true
+}
+
+fn try_link_toolchain(stage_path: &str) -> bool {
+    Command::new("rustup")
+        .stdout(std::process::Stdio::null())
+        .args(&["toolchain", "link", "stage1", &stage_path[..]])
+        .output()
+        .map_or(false, |output| output.status.success())
+}
+
 // Used to get the path for `Subcommand::Setup`
 pub fn interactive_path() -> io::Result<Profile> {
     fn abbrev_all() -> impl Iterator<Item = ((String, String), Profile)> {
index bc1873b6836be90eeb3ae50ce219764f5aaf3f39..8c41835183797a7a11a3bc4f03a66fa7aee47eb5 100644 (file)
@@ -14,6 +14,7 @@
 - [Tests](tests/index.md)
 - [Platform Support](platform-support.md)
     - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
+    - [\*-kmc-solid_\*](platform-support/kmc-solid.md)
 - [Target Tier Policy](target-tier-policy.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
index 0f106292e96700edc113db4c114965fb9540e231..e871b08c5b13fe42ee0d9e5df03d4f6df5f74f29 100644 (file)
@@ -202,6 +202,7 @@ target | std | host | notes
 -------|:---:|:----:|-------
 `aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
 `aarch64-apple-tvos` | * |  | ARM64 tvOS
+[`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ |  | ARM64 SOLID with TOPPERS/ASP3
 `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
 `aarch64-unknown-hermit` | ? |  |
 `aarch64-unknown-uefi` | * |  | ARM64 UEFI
@@ -222,6 +223,8 @@ target | std | host | notes
 `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD
 `armv7-unknown-netbsd-eabihf` | ✓ | ✓ |
 `armv7-wrs-vxworks-eabihf` | ? |  |
+[`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3
+[`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
 `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat
 `armv7s-apple-ios` | ✓ |  |
 `avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
diff --git a/src/doc/rustc/src/platform-support/kmc-solid.md b/src/doc/rustc/src/platform-support/kmc-solid.md
new file mode 100644 (file)
index 0000000..bbcd0f7
--- /dev/null
@@ -0,0 +1,65 @@
+# \*-kmc-solid_\*
+
+**Tier: 3**
+
+[SOLID] embedded development platform by Kyoto Microcomputer Co., Ltd.
+
+[SOLID]: https://www.kmckk.co.jp/eng/SOLID/
+
+The target names follow this format: `$ARCH-kmc-solid_$KERNEL-$ABI`, where `$ARCH` specifies the target processor architecture, `$KERNEL` the base kernel, and `$ABI` the target ABI (optional). The following targets are currently defined:
+
+|          Target name           | `target_arch` | `target_vendor` | `target_os`  |
+|--------------------------------|---------------|-----------------|--------------|
+| `aarch64-kmc-solid_asp3`       | `aarch64`     | `kmc`           | `solid_asp3` |
+| `armv7a-kmc-solid_asp3-eabi`   | `arm`         | `kmc`           | `solid_asp3` |
+| `armv7a-kmc-solid_asp3-eabihf` | `arm`         | `kmc`           | `solid_asp3` |
+
+## Designated Developers
+
+- [@kawadakk](https://github.com/kawadakk)
+
+## Requirements
+
+This target is cross-compiled.
+A platform-provided C compiler toolchain is required, though it can be substituted by [GNU Arm Embedded Toolchain](https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm) for the purpose of building Rust and functional binaries.
+
+## Building
+
+The target can be built by enabling it for a `rustc` build.
+
+```toml
+[build]
+target = ["aarch64-kmc-solid_asp3"]
+```
+
+Make sure `aarch64-kmc-elf-gcc` is included in `$PATH`. Alternatively, you can use GNU Arm Embedded Toolchain by adding the following to `config.toml`:
+
+```toml
+[target.aarch64-kmc-solid_asp3]
+cc = "arm-none-eabi-gcc"
+```
+
+## Cross-compilation
+
+This target can be cross-compiled from any hosts.
+
+## Testing
+
+Currently there is no support to run the rustc test suite for this target.
+
+## Building Rust programs
+
+Building executables is not supported yet.
+
+If `rustc` has support for that target and the library artifacts are available, then Rust static libraries can be built for that target:
+
+```shell
+$ rustc --target aarch64-kmc-solid_asp3 your-code.rs --crate-type staticlib
+$ ls libyour_code.a
+```
+
+On Rust Nightly it's possible to build without the target artifacts available:
+
+```text
+cargo build -Z build-std --target aarch64-kmc-solid_asp3
+```
index c83ca6ba54ce34942b40f90873729cc94b4b6844..1436e51f31820b27c11003960e1fae161f9a4bc3 100644 (file)
@@ -354,7 +354,7 @@ fn make_final_bounds(
                     let (poly_trait, output) =
                         (data.0.as_ref().unwrap().clone(), data.1.as_ref().cloned().map(Box::new));
                     let new_ty = match poly_trait.trait_ {
-                        Type::ResolvedPath { ref path, ref did, ref is_generic } => {
+                        Type::ResolvedPath { ref path, ref did } => {
                             let mut new_path = path.clone();
                             let last_segment =
                                 new_path.segments.pop().expect("segments were empty");
@@ -389,11 +389,7 @@ fn make_final_bounds(
                                 .segments
                                 .push(PathSegment { name: last_segment.name, args: new_params });
 
-                            Type::ResolvedPath {
-                                path: new_path,
-                                did: *did,
-                                is_generic: *is_generic,
-                            }
+                            Type::ResolvedPath { path: new_path, did: *did }
                         }
                         _ => panic!("Unexpected data: {:?}, {:?}", ty, data),
                     };
@@ -563,11 +559,7 @@ fn param_env_to_generics(
                         Type::QPath { name: left_name, ref self_type, ref trait_, .. } => {
                             let ty = &*self_type;
                             match **trait_ {
-                                Type::ResolvedPath {
-                                    path: ref trait_path,
-                                    ref did,
-                                    ref is_generic,
-                                } => {
+                                Type::ResolvedPath { path: ref trait_path, ref did } => {
                                     let mut new_trait_path = trait_path.clone();
 
                                     if self.is_fn_ty(trait_) && left_name == sym::Output {
@@ -612,7 +604,6 @@ fn param_env_to_generics(
                                             trait_: Type::ResolvedPath {
                                                 path: new_trait_path,
                                                 did: *did,
-                                                is_generic: *is_generic,
                                             },
                                             generic_params: Vec::new(),
                                         },
index 82939c930c4ea811fe0b3eba5e59fc2813cf045a..8135d4a2085dd4c3f8838b00f302bbfdbc2dc47e 100644 (file)
@@ -64,7 +64,11 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
                             .instantiate(self.cx.tcx, impl_substs)
                             .predicates
                             .into_iter()
-                            .chain(Some(trait_ref.without_const().to_predicate(infcx.tcx)));
+                            .chain(Some(
+                                ty::Binder::dummy(trait_ref)
+                                    .without_const()
+                                    .to_predicate(infcx.tcx),
+                            ));
                         for predicate in predicates {
                             debug!("testing predicate {:?}", predicate);
                             let obligation = traits::Obligation::new(
index 15d704eb57f1e67f70284bd33a92273d8cad977a..4a888b22332ee98fa18b915f27de6a52ebe0a3ec 100644 (file)
@@ -389,13 +389,45 @@ fn merge_attrs(
         }
     }
 
+    let document_hidden = cx.render_options.document_hidden;
     let predicates = tcx.explicit_predicates_of(did);
     let (trait_items, generics) = match impl_item {
         Some(impl_) => (
             impl_
                 .items
                 .iter()
-                .map(|item| tcx.hir().impl_item(item.id).clean(cx))
+                .map(|item| tcx.hir().impl_item(item.id))
+                .filter(|item| {
+                    // Filter out impl items whose corresponding trait item has `doc(hidden)`
+                    // not to document such impl items.
+                    // For inherent impls, we don't do any filtering, because that's already done in strip_hidden.rs.
+
+                    // When `--document-hidden-items` is passed, we don't
+                    // do any filtering, too.
+                    if document_hidden {
+                        return true;
+                    }
+                    if let Some(associated_trait) = associated_trait {
+                        let assoc_kind = match item.kind {
+                            hir::ImplItemKind::Const(..) => ty::AssocKind::Const,
+                            hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn,
+                            hir::ImplItemKind::TyAlias(..) => ty::AssocKind::Type,
+                        };
+                        let trait_item = tcx
+                            .associated_items(associated_trait.def_id)
+                            .find_by_name_and_kind(
+                                tcx,
+                                item.ident,
+                                assoc_kind,
+                                associated_trait.def_id,
+                            )
+                            .unwrap(); // SAFETY: For all impl items there exists trait item that has the same name.
+                        !tcx.get_attrs(trait_item.def_id).lists(sym::doc).has_word(sym::hidden)
+                    } else {
+                        true
+                    }
+                })
+                .map(|item| item.clean(cx))
                 .collect::<Vec<_>>(),
             impl_.generics.clean(cx),
         ),
index 3ec979c5ae918a90abd627bca42cdad0a5dd2fa7..611a4d08ab2255ee6612a4e81ab583bfd034748d 100644 (file)
@@ -132,7 +132,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> GenericBound {
             hir::GenericBound::LangItemTrait(lang_item, span, _, generic_args) => {
                 let def_id = cx.tcx.require_lang_item(lang_item, Some(span));
 
-                let trait_ref = ty::TraitRef::identity(cx.tcx, def_id);
+                let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder();
 
                 let generic_args = generic_args.clean(cx);
                 let bindings = match generic_args {
@@ -168,7 +168,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
 
         debug!("ty::TraitRef\n  subst: {:?}\n", trait_ref.substs);
 
-        ResolvedPath { path, did: trait_ref.def_id, is_generic: false }
+        ResolvedPath { path, did: trait_ref.def_id }
     }
 }
 
@@ -1440,12 +1440,12 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                 };
                 inline::record_extern_fqn(cx, did, kind);
                 let path = external_path(cx, did, false, vec![], substs);
-                ResolvedPath { path, did, is_generic: false }
+                ResolvedPath { path, did }
             }
             ty::Foreign(did) => {
                 inline::record_extern_fqn(cx, did, ItemType::ForeignType);
                 let path = external_path(cx, did, false, vec![], InternalSubsts::empty());
-                ResolvedPath { path, did, is_generic: false }
+                ResolvedPath { path, did }
             }
             ty::Dynamic(ref obj, ref reg) => {
                 // HACK: pick the first `did` as the `did` of the trait object. Someone
@@ -1471,7 +1471,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                     let path = external_path(cx, did, false, vec![], empty);
                     inline::record_extern_fqn(cx, did, ItemType::Trait);
                     let bound = PolyTrait {
-                        trait_: ResolvedPath { path, did, is_generic: false },
+                        trait_: ResolvedPath { path, did },
                         generic_params: Vec::new(),
                     };
                     bounds.push(bound);
@@ -1488,10 +1488,7 @@ fn clean(&self, cx: &mut DocContext<'_>) -> Type {
                 let path = external_path(cx, did, false, bindings, substs);
                 bounds.insert(
                     0,
-                    PolyTrait {
-                        trait_: ResolvedPath { path, did, is_generic: false },
-                        generic_params: Vec::new(),
-                    },
+                    PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() },
                 );
 
                 DynTrait(bounds, lifetime)
index d23941d77ba4ff27019c42cd17f56371960f1bbb..68a35e55c268e6e3e98a71613f589b8aa9879f64 100644 (file)
@@ -908,18 +908,10 @@ fn from_iter<T>(iter: T) -> Self
     }
 }
 
-/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
-/// as well as doc comments.
-#[derive(Clone, Debug, Default)]
-crate struct Attributes {
-    crate doc_strings: Vec<DocFragment>,
-    crate other_attrs: Vec<ast::Attribute>,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 /// A link that has not yet been rendered.
 ///
 /// This link will be turned into a rendered link by [`Item::links`].
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
 crate struct ItemLink {
     /// The original link written in the markdown
     pub(crate) link: String,
@@ -944,6 +936,14 @@ pub struct RenderedLink {
     pub(crate) href: String,
 }
 
+/// The attributes on an [`Item`], including attributes like `#[derive(...)]` and `#[inline]`,
+/// as well as doc comments.
+#[derive(Clone, Debug, Default)]
+crate struct Attributes {
+    crate doc_strings: Vec<DocFragment>,
+    crate other_attrs: Vec<ast::Attribute>,
+}
+
 impl Attributes {
     crate fn lists(&self, name: Symbol) -> ListAttributesIter<'_> {
         self.other_attrs.lists(name)
@@ -1114,10 +1114,7 @@ impl GenericBound {
         let path = external_path(cx, did, false, vec![], empty);
         inline::record_extern_fqn(cx, did, ItemType::Trait);
         GenericBound::TraitBound(
-            PolyTrait {
-                trait_: ResolvedPath { path, did, is_generic: false },
-                generic_params: Vec::new(),
-            },
+            PolyTrait { trait_: ResolvedPath { path, did }, generic_params: Vec::new() },
             hir::TraitBoundModifier::Maybe,
         )
     }
@@ -1384,8 +1381,6 @@ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
     ResolvedPath {
         path: Path,
         did: DefId,
-        /// `true` if is a `T::Name` path for associated types.
-        is_generic: bool,
     },
     /// `dyn for<'a> Trait<'a> + Send + 'static`
     DynTrait(Vec<PolyTrait>, Option<Lifetime>),
@@ -1424,37 +1419,6 @@ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
     ImplTrait(Vec<GenericBound>),
 }
 
-#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
-/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't
-/// paths, like `Unit`.
-crate enum PrimitiveType {
-    Isize,
-    I8,
-    I16,
-    I32,
-    I64,
-    I128,
-    Usize,
-    U8,
-    U16,
-    U32,
-    U64,
-    U128,
-    F32,
-    F64,
-    Char,
-    Bool,
-    Str,
-    Slice,
-    Array,
-    Tuple,
-    Unit,
-    RawPointer,
-    Reference,
-    Fn,
-    Never,
-}
-
 crate trait GetDefId {
     /// Use this method to get the [`DefId`] of a [`clean`] AST node.
     /// This will return [`None`] when called on a primitive [`clean::Type`].
@@ -1503,9 +1467,10 @@ impl Type {
         }
     }
 
-    crate fn is_generic(&self) -> bool {
-        match *self {
-            ResolvedPath { is_generic, .. } => is_generic,
+    /// Checks if this is a `T::Name` path for an associated type.
+    crate fn is_assoc_ty(&self) -> bool {
+        match self {
+            ResolvedPath { path, .. } => path.is_assoc_ty(),
             _ => false,
         }
     }
@@ -1569,9 +1534,7 @@ impl Type {
         };
         Some((&self_, trait_did, *name))
     }
-}
 
-impl Type {
     fn inner_def_id(&self, cache: Option<&Cache>) -> Option<DefId> {
         let t: PrimitiveType = match *self {
             ResolvedPath { did, .. } => return Some(did),
@@ -1608,6 +1571,37 @@ fn def_id_full(&self, cache: &Cache) -> Option<DefId> {
     }
 }
 
+/// N.B. this has to be different from `hir::PrimTy` because it also includes types that aren't
+/// paths, like `Unit`.
+#[derive(Clone, PartialEq, Eq, Hash, Copy, Debug)]
+crate enum PrimitiveType {
+    Isize,
+    I8,
+    I16,
+    I32,
+    I64,
+    I128,
+    Usize,
+    U8,
+    U16,
+    U32,
+    U64,
+    U128,
+    F32,
+    F64,
+    Char,
+    Bool,
+    Str,
+    Slice,
+    Array,
+    Tuple,
+    Unit,
+    RawPointer,
+    Reference,
+    Fn,
+    Never,
+}
+
 impl PrimitiveType {
     crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType {
         use ast::{FloatTy, IntTy, UintTy};
@@ -1994,6 +1988,16 @@ impl Path {
         String::from(if self.global { "::" } else { "" })
             + &self.segments.iter().map(|s| s.name.to_string()).collect::<Vec<_>>().join("::")
     }
+
+    /// Checks if this is a `T::Name` path for an associated type.
+    crate fn is_assoc_ty(&self) -> bool {
+        match self.res {
+            Res::SelfTy(..) if self.segments.len() != 1 => true,
+            Res::Def(DefKind::TyParam, _) if self.segments.len() != 1 => true,
+            Res::Def(DefKind::AssocTy, _) => true,
+            _ => false,
+        }
+    }
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
index b0021d1234cd610ecdabb6494631ef10624dcffd..33d460d587a5176e8727c272dd5acdf873d820e7 100644 (file)
@@ -159,9 +159,7 @@ pub(super) fn external_path(
 
 crate fn strip_type(ty: Type) -> Type {
     match ty {
-        Type::ResolvedPath { path, did, is_generic } => {
-            Type::ResolvedPath { path: strip_path(&path), did, is_generic }
-        }
+        Type::ResolvedPath { path, did } => Type::ResolvedPath { path: strip_path(&path), did },
         Type::DynTrait(mut bounds, lt) => {
             let first = bounds.remove(0);
             let stripped_trait = strip_type(first.trait_);
@@ -404,19 +402,15 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
 crate fn resolve_type(cx: &mut DocContext<'_>, path: Path) -> Type {
     debug!("resolve_type({:?})", path);
 
-    let is_generic = match path.res {
-        Res::PrimTy(p) => return Primitive(PrimitiveType::from(p)),
-        Res::SelfTy(..) if path.segments.len() == 1 => {
-            return Generic(kw::SelfUpper);
-        }
-        Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => {
-            return Generic(path.segments[0].name);
+    match path.res {
+        Res::PrimTy(p) => Primitive(PrimitiveType::from(p)),
+        Res::SelfTy(..) if path.segments.len() == 1 => Generic(kw::SelfUpper),
+        Res::Def(DefKind::TyParam, _) if path.segments.len() == 1 => Generic(path.segments[0].name),
+        _ => {
+            let did = register_res(cx, path.res);
+            ResolvedPath { path, did }
         }
-        Res::SelfTy(..) | Res::Def(DefKind::TyParam | DefKind::AssocTy, _) => true,
-        _ => false,
-    };
-    let did = register_res(cx, path.res);
-    ResolvedPath { path, did, is_generic }
+    }
 }
 
 crate fn get_auto_trait_and_blanket_impls(
index 2fde0017dc80c63be5cb8a1ffc6728620da667f9..d11781581a8df6c61daa151e3d22eb257bd1899f 100644 (file)
@@ -752,9 +752,9 @@ fn fmt_type<'cx>(
 
     match *t {
         clean::Generic(name) => write!(f, "{}", name),
-        clean::ResolvedPath { did, ref path, is_generic } => {
+        clean::ResolvedPath { did, ref path } => {
             // Paths like `T::Output` and `Self::Output` should be rendered with all segments.
-            resolved_path(f, did, path, is_generic, use_absolute, cx)
+            resolved_path(f, did, path, path.is_assoc_ty(), use_absolute, cx)
         }
         clean::DynTrait(ref bounds, ref lt) => {
             f.write_str("dyn ")?;
@@ -825,28 +825,17 @@ fn fmt_type<'cx>(
                 hir::Mutability::Mut => "mut",
                 hir::Mutability::Not => "const",
             };
-            match **t {
-                clean::Generic(_) | clean::ResolvedPath { is_generic: true, .. } => {
-                    if f.alternate() {
-                        primitive_link(
-                            f,
-                            clean::PrimitiveType::RawPointer,
-                            &format!("*{} {:#}", m, t.print(cx)),
-                            cx,
-                        )
-                    } else {
-                        primitive_link(
-                            f,
-                            clean::PrimitiveType::RawPointer,
-                            &format!("*{} {}", m, t.print(cx)),
-                            cx,
-                        )
-                    }
-                }
-                _ => {
-                    primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?;
-                    fmt::Display::fmt(&t.print(cx), f)
-                }
+
+            if matches!(**t, clean::Generic(_)) || t.is_assoc_ty() {
+                let text = if f.alternate() {
+                    format!("*{} {:#}", m, t.print(cx))
+                } else {
+                    format!("*{} {}", m, t.print(cx))
+                };
+                primitive_link(f, clean::PrimitiveType::RawPointer, &text, cx)
+            } else {
+                primitive_link(f, clean::PrimitiveType::RawPointer, &format!("*{} ", m), cx)?;
+                fmt::Display::fmt(&t.print(cx), f)
             }
         }
         clean::BorrowedRef { lifetime: ref l, mutability, type_: ref ty } => {
index c971e231463cdc56dd1f58c5871e06a7537f9168..fda2512a05036aff92bfe51fe65140a6cf901a59 100644 (file)
@@ -1316,8 +1316,7 @@ fn markdown_summary_with_limit(
     /// The range in the markdown that the code within the code block occupies.
     crate code: Range<usize>,
     crate is_fenced: bool,
-    crate syntax: Option<String>,
-    crate is_ignore: bool,
+    crate lang_string: LangString,
 }
 
 /// Returns a range of bytes for each code block in the markdown that is tagged as `rust` or
@@ -1333,7 +1332,7 @@ fn markdown_summary_with_limit(
 
     while let Some((event, offset)) = p.next() {
         if let Event::Start(Tag::CodeBlock(syntax)) = event {
-            let (syntax, code_start, code_end, range, is_fenced, is_ignore) = match syntax {
+            let (lang_string, code_start, code_end, range, is_fenced) = match syntax {
                 CodeBlockKind::Fenced(syntax) => {
                     let syntax = syntax.as_ref();
                     let lang_string = if syntax.is_empty() {
@@ -1344,8 +1343,6 @@ fn markdown_summary_with_limit(
                     if !lang_string.rust {
                         continue;
                     }
-                    let is_ignore = lang_string.ignore != Ignore::None;
-                    let syntax = if syntax.is_empty() { None } else { Some(syntax.to_owned()) };
                     let (code_start, mut code_end) = match p.next() {
                         Some((Event::Text(_), offset)) => (offset.start, offset.end),
                         Some((_, sub_offset)) => {
@@ -1354,8 +1351,7 @@ fn markdown_summary_with_limit(
                                 is_fenced: true,
                                 range: offset,
                                 code,
-                                syntax,
-                                is_ignore,
+                                lang_string,
                             });
                             continue;
                         }
@@ -1365,8 +1361,7 @@ fn markdown_summary_with_limit(
                                 is_fenced: true,
                                 range: offset,
                                 code,
-                                syntax,
-                                is_ignore,
+                                lang_string,
                             });
                             continue;
                         }
@@ -1374,22 +1369,21 @@ fn markdown_summary_with_limit(
                     while let Some((Event::Text(_), offset)) = p.next() {
                         code_end = offset.end;
                     }
-                    (syntax, code_start, code_end, offset, true, is_ignore)
+                    (lang_string, code_start, code_end, offset, true)
                 }
                 CodeBlockKind::Indented => {
                     // The ending of the offset goes too far sometime so we reduce it by one in
                     // these cases.
                     if offset.end > offset.start && md.get(offset.end..=offset.end) == Some(&"\n") {
                         (
-                            None,
+                            LangString::default(),
                             offset.start,
                             offset.end,
                             Range { start: offset.start, end: offset.end - 1 },
                             false,
-                            false,
                         )
                     } else {
-                        (None, offset.start, offset.end, offset, false, false)
+                        (LangString::default(), offset.start, offset.end, offset, false)
                     }
                 }
             };
@@ -1398,8 +1392,7 @@ fn markdown_summary_with_limit(
                 is_fenced,
                 range,
                 code: Range { start: code_start, end: code_end },
-                syntax,
-                is_ignore,
+                lang_string,
             });
         }
     }
index 3104cb3a3dd0153a626a3d30084fd07347b143c2..8888b42d948cd0bb072c406ac8f5724cf5df304e 100644 (file)
@@ -712,11 +712,10 @@ fn trait_item(w: &mut Buffer, cx: &Context<'_>, m: &clean::Item, t: &clean::Item
         let mut implementor_dups: FxHashMap<Symbol, (DefId, bool)> = FxHashMap::default();
         for implementor in implementors {
             match implementor.inner_impl().for_ {
-                clean::ResolvedPath { ref path, did, is_generic: false, .. }
+                clean::ResolvedPath { ref path, did, .. }
                 | clean::BorrowedRef {
-                    type_: box clean::ResolvedPath { ref path, did, is_generic: false, .. },
-                    ..
-                } => {
+                    type_: box clean::ResolvedPath { ref path, did, .. }, ..
+                } if !path.is_assoc_ty() => {
                     let &mut (prev_did, ref mut has_duplicates) =
                         implementor_dups.entry(path.last()).or_insert((did, false));
                     if prev_did != did {
@@ -1410,11 +1409,12 @@ fn render_implementor(
     // If there's already another implementor that has the same abridged name, use the
     // full path, for example in `std::iter::ExactSizeIterator`
     let use_absolute = match implementor.inner_impl().for_ {
-        clean::ResolvedPath { ref path, is_generic: false, .. }
-        | clean::BorrowedRef {
-            type_: box clean::ResolvedPath { ref path, is_generic: false, .. },
-            ..
-        } => implementor_dups[&path.last()].1,
+        clean::ResolvedPath { ref path, .. }
+        | clean::BorrowedRef { type_: box clean::ResolvedPath { ref path, .. }, .. }
+            if !path.is_assoc_ty() =>
+        {
+            implementor_dups[&path.last()].1
+        }
         _ => false,
     };
     render_impl(
index f8ea7a499b2340a4dcbd14e991d3f6131a1ba409..fda9070305797ad417e811466eb329380b924d27 100644 (file)
@@ -387,7 +387,7 @@ impl FromWithTcx<clean::Type> for Type {
     fn from_tcx(ty: clean::Type, tcx: TyCtxt<'_>) -> Self {
         use clean::Type::*;
         match ty {
-            ResolvedPath { path, did, is_generic: _ } => Type::ResolvedPath {
+            ResolvedPath { path, did } => Type::ResolvedPath {
                 name: path.whole_name(),
                 id: from_item_id(did.into()),
                 args: path.segments.last().map(|args| Box::new(args.clone().args.into_tcx(tcx))),
index c9f66d096f06cdb383a50fe3380c5865700def95..d2b3c5239c778f4b5c83b1b327e8e95b5a810f33 100644 (file)
@@ -4,7 +4,7 @@
 use rustc_parse::parse_stream_from_source_str;
 use rustc_session::parse::ParseSess;
 use rustc_span::source_map::{FilePathMapping, SourceMap};
-use rustc_span::{FileName, InnerSpan};
+use rustc_span::{hygiene::AstPass, ExpnData, ExpnKind, FileName, InnerSpan, DUMMY_SP};
 
 use crate::clean;
 use crate::core::DocContext;
@@ -36,12 +36,22 @@ fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeB
         let source = dox[code_block.code].to_owned();
         let sess = ParseSess::with_span_handler(handler, sm);
 
+        let edition = code_block.lang_string.edition.unwrap_or(self.cx.tcx.sess.edition());
+        let expn_data = ExpnData::default(
+            ExpnKind::AstPass(AstPass::TestHarness),
+            DUMMY_SP,
+            edition,
+            None,
+            None,
+        );
+        let span = DUMMY_SP.fresh_expansion(expn_data, self.cx.tcx.create_stable_hashing_context());
+
         let is_empty = rustc_driver::catch_fatal_errors(|| {
             parse_stream_from_source_str(
                 FileName::Custom(String::from("doctest")),
                 source,
                 &sess,
-                None,
+                Some(span),
             )
             .is_empty()
         })
@@ -61,8 +71,8 @@ fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeB
         };
 
         let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id);
-        let empty_block = code_block.syntax.is_none() && code_block.is_fenced;
-        let is_ignore = code_block.is_ignore;
+        let empty_block = code_block.lang_string == Default::default() && code_block.is_fenced;
+        let is_ignore = code_block.lang_string.ignore != markdown::Ignore::None;
 
         // The span and whether it is precise or not.
         let (sp, precise_span) = match super::source_span_for_markdown_range(
index a93880453ba274916cca5561235e5179ac9da166..90300dbd16b136261991b283abfeda085b8f6578 100644 (file)
@@ -128,7 +128,7 @@ fn fold_item(&mut self, i: Item) -> Option<Item> {
                 return None;
             }
             if let Some(did) = imp.for_.def_id() {
-                if did.is_local() && !imp.for_.is_generic() && !self.retained.contains(&did.into())
+                if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into())
                 {
                     debug!("ImplStripper: impl item for stripped type; removing");
                     return None;
index 8b0448ec470851d9a8f6e41878745158471829c0..c73d2a10a967bd3911425714e414af06864a340e 100644 (file)
@@ -1,9 +1,10 @@
 //
 
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
 // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/extern-drop-glue
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 // compile-flags:-Zinline-in-all-cgus -Copt-level=0
 
 #![allow(dead_code)]
index c96df6e102ac3391e2773063aae6a6f3b475a626..638ec079a0bce75a454e29f37fdf4e72f984cc2f 100644 (file)
@@ -1,7 +1,8 @@
 //
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/extern-generic -Zshare-generics=y
+// incremental
+// compile-flags:-Zprint-mono-items=eager -Zshare-generics=y
 
 #![allow(dead_code)]
 #![crate_type="lib"]
index 91ae6022931980c07e21b2da8a6dae90f504550a..118b7bdf4da8b9ee0c7a6508cf17089fd6b134a1 100644 (file)
@@ -1,6 +1,7 @@
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/incremental-merging
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 // compile-flags:-Ccodegen-units=3
 
 #![crate_type = "rlib"]
index b86e325537b8171cc08ae3a2c9abdd02950401f1..1cc21632e4818ff8b6980ae76102a97b47baa349 100644 (file)
@@ -1,7 +1,8 @@
 //
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/inlining-from-extern-crate
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 // compile-flags:-Zinline-in-all-cgus
 
 #![crate_type="lib"]
index 78d69fdb7d814ff9f6fefa6f381c3d920200712f..2fd853a44b8ffc12d97d6d0342e426bf10ee0fee 100644 (file)
@@ -1,8 +1,9 @@
 //
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
 // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-drop-glue
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 // compile-flags:-Zinline-in-all-cgus -Copt-level=0
 
 #![allow(dead_code)]
index 9a7743bbf4686c17760c61df4a4c9e5f174e8b70..38aec7291df3f45817157a5f9d415493bb9bbe18 100644 (file)
@@ -1,6 +1,7 @@
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/local-generic
+// incremental
+// compile-flags:-Zprint-mono-items=eager
 
 #![allow(dead_code)]
 #![crate_type="lib"]
index d53f7b622913221c17b65835399616ef29ee86e9..318f0c28a5981a4a44cde8fb580cf2f15de2b111 100644 (file)
@@ -1,7 +1,8 @@
 //
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining-but-not-all
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 // compile-flags:-Zinline-in-all-cgus=no
 
 #![allow(dead_code)]
index 1ea804b2f9d82c5beed1800ae4609b0f319bb7d9..841a428e9dd2ffb9ef0f473737571a89b7b259a9 100644 (file)
@@ -1,7 +1,8 @@
 //
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-inlining
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 // compile-flags:-Zinline-in-all-cgus
 
 #![allow(dead_code)]
index 56d108074e40d0ebacbe046a0df623de190a9e99..03c37954d151363e2252e156cc9c2c1f104ab012 100644 (file)
@@ -1,7 +1,8 @@
 //
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/local-transitive-inlining
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 // compile-flags:-Zinline-in-all-cgus
 
 #![allow(dead_code)]
index e67090303a36387892dae17e809b690bcae1edc0..8220dc12ee0c6ac7dc44f4258edda4e8e45dc997 100644 (file)
@@ -4,9 +4,10 @@
 // ignore-test
 
 //
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/methods-are-with-self-type
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 
 #![allow(dead_code)]
 #![feature(start)]
index f9b8f52b0bb9e7fe0aae9f8fbea48ff2ba080d42..ce7fe9c3a4ff3ae4c1fe30fed39c774d4f329315 100644 (file)
@@ -1,6 +1,7 @@
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/regular-modules
+// incremental
+// compile-flags:-Zprint-mono-items=eager
 
 #![allow(dead_code)]
 #![crate_type="lib"]
index 17c1fbb2f739b13fb723e1d97a9f65be8229389c..ebe96bfb746af1962dcad076d453324b837f445e 100644 (file)
@@ -2,7 +2,8 @@
 // no-prefer-dynamic
 // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels
 //       prevent drop-glue from participating in share-generics.
-// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Cincremental=tmp/partitioning-tests/shared-generics-exe -Copt-level=0
+// incremental
+// compile-flags:-Zprint-mono-items=eager -Zshare-generics=yes -Copt-level=0
 
 #![crate_type="rlib"]
 
index 02d6467577f4c0674fc39f45f5fc45fe3bc90122..b11d6696dc00ad80288c5d78b0cc93f8d4163b7c 100644 (file)
@@ -1,6 +1,7 @@
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/statics
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 
 #![crate_type="rlib"]
 
index f6ae46b0551c28fd76cf7fa76d8541e02909ed5f..cedcca804b36581722e5c75e3d256ec64b2114b9 100644 (file)
@@ -1,8 +1,9 @@
 //
 
-// We specify -C incremental here because we want to test the partitioning for
+// We specify incremental here because we want to test the partitioning for
 // incremental compilation
-// compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/vtable-through-const
+// incremental
+// compile-flags:-Zprint-mono-items=lazy
 // compile-flags:-Zinline-in-all-cgus
 
 // This test case makes sure, that references made through constants are
index 62d093507ddeed0be61ff029e3a0c7a46d227b20..39f73c4e3967eff439afc494819ca778521d7a91 100644 (file)
@@ -1,8 +1,17 @@
-// compile-flags: -Z panic-in-drop=abort -O
+// compile-flags: -Z panic-in-drop=abort -O -Z new-llvm-pass-manager=no
 
 // Ensure that unwinding code paths are eliminated from the output after
 // optimization.
 
+// This test uses -Z new-llvm-pass-manager=no, because the expected optimization does not happen
+// on targets using SEH exceptions (i.e. MSVC) anymore. The core issue is that Rust promises that
+// the drop_in_place() function can't unwind, but implements it in a way that *can*, because we
+// currently go out of our way to allow longjmps, which also use the unwinding mechanism on MSVC
+// targets. We should either forbid longjmps, or not assume nounwind, making this optimization
+// incompatible with the current behavior of running cleanuppads on longjmp unwinding.
+
+// CHECK-NOT: {{(call|invoke).*}}should_not_appear_in_output
+
 #![crate_type = "lib"]
 use std::any::Any;
 use std::mem::forget;
@@ -35,8 +44,6 @@ fn drop(&mut self) {
     }
 }
 
-// CHECK-LABEL: normal_drop
-// CHECK-NOT: should_not_appear_in_output
 #[no_mangle]
 pub fn normal_drop(x: ExternDrop) {
     let guard = AssertNeverDrop;
@@ -44,8 +51,6 @@ pub fn normal_drop(x: ExternDrop) {
     forget(guard);
 }
 
-// CHECK-LABEL: indirect_drop
-// CHECK-NOT: should_not_appear_in_output
 #[no_mangle]
 pub fn indirect_drop(x: Box<dyn Any>) {
     let guard = AssertNeverDrop;
index 7f97d96b8db93a2cf50bcd2fc1192d8174b04d06..fe945266b13ca8a64caf164bfe80a7237d6ff618 100644 (file)
@@ -63,7 +63,6 @@
 // lldbr-check:(f64) *unique_val_interior_ref_2 = 26.5
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -79,7 +78,7 @@ fn main() {
     let stack_val_interior_ref_2: &f64 = &stack_val.y;
     let ref_to_unnamed: &SomeStruct = &SomeStruct { x: 11, y: 24.5 };
 
-    let unique_val: Box<_> = box SomeStruct { x: 13, y: 26.5 };
+    let unique_val: Box<_> = Box::new(SomeStruct { x: 13, y: 26.5 });
     let unique_val_ref: &SomeStruct = &*unique_val;
     let unique_val_interior_ref_1: &isize = &unique_val.x;
     let unique_val_interior_ref_2: &f64 = &unique_val.y;
index be4895ef5363e2907c97d7ea478d682346bc0dc8..cc28e49c4474550132137ebea5d620b0adb8865c 100644 (file)
@@ -37,7 +37,6 @@
 
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -46,7 +45,7 @@ fn main() {
     let stack_val_ref: &(i16, f32) = &stack_val;
     let ref_to_unnamed: &(i16, f32) = &(-15, -20f32);
 
-    let unique_val: Box<(i16, f32)> = box (-17, -22f32);
+    let unique_val: Box<(i16, f32)> = Box::new((-17, -22f32));
     let unique_val_ref: &(i16, f32) = &*unique_val;
 
     zzz(); // #break
index f927a54f02aa69688684678ba28d20b30b6b4daa..b39f24e029e31fc8942979c2d99a9471a9e636b9 100644 (file)
 // lldbr-check:(f64) *f64_ref = 3.5
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
 fn main() {
-    let bool_box: Box<bool> = box true;
+    let bool_box: Box<bool> = Box::new(true);
     let bool_ref: &bool = &*bool_box;
 
-    let int_box: Box<isize> = box -1;
+    let int_box: Box<isize> = Box::new(-1);
     let int_ref: &isize = &*int_box;
 
-    let char_box: Box<char> = box 'a';
+    let char_box: Box<char> = Box::new('a');
     let char_ref: &char = &*char_box;
 
-    let i8_box: Box<i8> = box 68;
+    let i8_box: Box<i8> = Box::new(68);
     let i8_ref: &i8 = &*i8_box;
 
-    let i16_box: Box<i16> = box -16;
+    let i16_box: Box<i16> = Box::new(-16);
     let i16_ref: &i16 = &*i16_box;
 
-    let i32_box: Box<i32> = box -32;
+    let i32_box: Box<i32> = Box::new(-32);
     let i32_ref: &i32 = &*i32_box;
 
-    let i64_box: Box<i64> = box -64;
+    let i64_box: Box<i64> = Box::new(-64);
     let i64_ref: &i64 = &*i64_box;
 
-    let uint_box: Box<usize> = box 1;
+    let uint_box: Box<usize> = Box::new(1);
     let uint_ref: &usize = &*uint_box;
 
-    let u8_box: Box<u8> = box 100;
+    let u8_box: Box<u8> = Box::new(100);
     let u8_ref: &u8 = &*u8_box;
 
-    let u16_box: Box<u16> = box 16;
+    let u16_box: Box<u16> = Box::new(16);
     let u16_ref: &u16 = &*u16_box;
 
-    let u32_box: Box<u32> = box 32;
+    let u32_box: Box<u32> = Box::new(32);
     let u32_ref: &u32 = &*u32_box;
 
-    let u64_box: Box<u64> = box 64;
+    let u64_box: Box<u64> = Box::new(64);
     let u64_ref: &u64 = &*u64_box;
 
-    let f32_box: Box<f32> = box 2.5;
+    let f32_box: Box<f32> = Box::new(2.5);
     let f32_ref: &f32 = &*f32_box;
 
-    let f64_box: Box<f64> = box 3.5;
+    let f64_box: Box<f64> = Box::new(3.5);
     let f64_ref: &f64 = &*f64_box;
 
     zzz(); // #break
index e443b67ebfb31a2803da32c1035a0e404df6b9c1..3713c8c135d2e6721ac2019306a6a4c730a80567 100644 (file)
 // lldbr-check:((i32, f64)) *b = { 0 = 2 1 = 3.5 }
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
 fn main() {
-    let a = box 1;
-    let b = box (2, 3.5f64);
+    let a = Box::new(1);
+    let b = Box::new((2, 3.5f64));
 
     zzz(); // #break
 }
index 155088c61fe3133b16a246a7beaddded0cf41b62..64bc124756d6dd23e54bc67a417fc3f6168f98db 100644 (file)
@@ -28,7 +28,6 @@
 // lldbr-check:(boxed_struct::StructWithDestructor) *boxed_with_dtor = { x = 77 y = 777 z = 7777 w = 77777 }
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -52,9 +51,19 @@ fn drop(&mut self) {}
 
 fn main() {
 
-    let boxed_with_padding: Box<_> = box StructWithSomePadding { x: 99, y: 999, z: 9999, w: 99999 };
-
-    let boxed_with_dtor: Box<_> = box StructWithDestructor { x: 77, y: 777, z: 7777, w: 77777 };
+    let boxed_with_padding: Box<_> = Box::new(StructWithSomePadding {
+        x: 99,
+        y: 999,
+        z: 9999,
+        w: 99999,
+    });
+
+    let boxed_with_dtor: Box<_> = Box::new(StructWithDestructor {
+        x: 77,
+        y: 777,
+        z: 7777,
+        w: 77777,
+    });
     zzz(); // #break
 }
 
index 239055b3a78b63640471c9f776c10b6c71ed8a38..91d7ddc5416d8dcba6420a36afdfb0067c7bdd0e 100644 (file)
@@ -39,7 +39,6 @@
 // lldbr-check:(i32) *y = 110
 // lldb-command:continue
 
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
index a776f51907158aadeb9e4f1bf727a87b06cef0e3..9cd3874a5dfb74aba31c0628d3720a44ddfcade0 100644 (file)
 
 #![allow(unused_variables)]
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -480,7 +479,7 @@ fn main() {
     managed_box(&(34, 35));
     borrowed_pointer(&(36, 37));
     contained_borrowed_pointer((&38, 39));
-    unique_pointer(box (40, 41, 42));
+    unique_pointer(Box::new((40, 41, 42)));
     ref_binding((43, 44, 45));
     ref_binding_in_tuple((46, (47, 48)));
     ref_binding_in_struct(Struct { a: 49, b: 50 });
index 1532c83dfac3a849c99578b202eca7d945425ab3..15cb88ef25d5b437dfca0a9ed1f92be30e9c5834 100644 (file)
 
 #![allow(unused_variables)]
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -214,7 +213,7 @@ fn main() {
             y: -300001.5,
             z: true
          },
-         box 854237.5);
+         Box::new(854237.5));
 
     for &(v1,
           &Struct { x: x1, y: ref y1, z: z1 },
index 712168b5baa870ad6de9cd056cbf2f7e7bbc5da5..3a2a889777ea0f87ce1935583d18c3069b73b9c8 100644 (file)
 
 #![allow(unused_variables)]
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -345,7 +344,7 @@ fn main() {
     let (&cc, _) = (&38, 39);
 
     // unique pointer
-    let box dd = box (40, 41, 42);
+    let box dd = Box::new((40, 41, 42));
 
     // ref binding
     let ref ee = (43, 44, 45);
index 85fe8ac08f3c48241b57ef7bf8f5ef3992a6a7dc..97609ef5d9341e249869301215f3cea39613c32c 100644 (file)
 // lldbr-check:(f32) arg2 = -10.5
 // lldb-command:continue
 
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -155,7 +154,7 @@ fn main() {
     let _ = stack.self_by_ref(-1, 2_u16);
     let _ = stack.self_by_val(-3, -4_i16);
 
-    let owned: Box<_> = box Struct { x: 1234.5f64 };
+    let owned: Box<_> = Box::new(Struct { x: 1234.5f64 });
     let _ = owned.self_by_ref(-5, -6_i32);
     let _ = owned.self_by_val(-7, -8_i64);
     let _ = owned.self_owned(-9, -10.5_f32);
index 80f4c2e1150ec50d89b6b895569eb1fcdfb66f85..aaa9bd9d6f97ad3084d35fff8b923451ad903c76 100644 (file)
 // lldb-check:[...]$14 = -10
 // lldb-command:continue
 
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -140,7 +139,7 @@ fn main() {
     let _ = stack.self_by_ref(-1, -2);
     let _ = stack.self_by_val(-3, -4);
 
-    let owned: Box<_> = box Enum::Variant1{ x: 1799, y: 1799 };
+    let owned: Box<_> = Box::new(Enum::Variant1{ x: 1799, y: 1799 });
     let _ = owned.self_by_ref(-5, -6);
     let _ = owned.self_by_val(-7, -8);
     let _ = owned.self_owned(-9, -10);
index 80cbf7430ca6e8885f0ac121e4128683a6453d5b..bf047449164b000fa850599447dd8c3fe0a22f89 100644 (file)
 // lldbr-check:(isize) arg2 = -10
 // lldb-command:continue
 
-
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -156,7 +154,7 @@ fn main() {
     let _ = stack.self_by_ref(-1, -2);
     let _ = stack.self_by_val(-3, -4);
 
-    let owned: Box<_> = box Struct { x: 1234.5f64 };
+    let owned: Box<_> = Box::new(Struct { x: 1234.5f64 });
     let _ = owned.self_by_ref(-5, -6);
     let _ = owned.self_by_val(-7, -8);
     let _ = owned.self_owned(-9, -10);
index c764cf68323786672408c4656e6dbfe74df8110c..deed4f9cc0ad989920044fc134099ebc9ae89658 100644 (file)
 // lldbr-check:(isize) arg2 = -10
 // lldb-command:continue
 
-
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -154,7 +152,7 @@ fn main() {
     let _ = stack.self_by_ref(-1, -2);
     let _ = stack.self_by_val(-3, -4);
 
-    let owned: Box<_> = box Struct { x: 200 };
+    let owned: Box<_> = Box::new(Struct { x: 200 });
     let _ = owned.self_by_ref(-5, -6);
     let _ = owned.self_by_val(-7, -8);
     let _ = owned.self_owned(-9, -10);
index 6dcf28967776fabe12aca64c0c3b8f337ed61767..7ebebfa72b92bbbd20d3ab25b5b12ea9bf3ef1cd 100644 (file)
 // lldbr-check:(isize) arg2 = -10
 // lldb-command:continue
 
-
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -160,7 +158,7 @@ fn main() {
     let _ = stack.self_by_ref(-1, -2);
     let _ = stack.self_by_val(-3, -4);
 
-    let owned: Box<_> = box Struct { x: 200 };
+    let owned: Box<_> = Box::new(Struct { x: 200 });
     let _ = owned.self_by_ref(-5, -6);
     let _ = owned.self_by_val(-7, -8);
     let _ = owned.self_owned(-9, -10);
index d06b606e973e8e5b5f0a263427285069f62d4188..a5a87b2ad6f26b738dbb87fbd54f2269a4fce05a 100644 (file)
 // lldbr-check:(isize) arg2 = -10
 // lldb-command:continue
 
-
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -152,7 +150,7 @@ fn main() {
     let _ = stack.self_by_ref(-1, -2);
     let _ = stack.self_by_val(-3, -4);
 
-    let owned: Box<_> = box TupleStruct(200, -200.5);
+    let owned: Box<_> = Box::new(TupleStruct(200, -200.5));
     let _ = owned.self_by_ref(-5, -6);
     let _ = owned.self_by_val(-7, -8);
     let _ = owned.self_owned(-9, -10);
index c0bd67367012f51ad3bcc5735868fc54fe0df0ad..eb14af8c588ded436c0dbe349c00bf6cbb3b8de7 100644 (file)
 // gdb-command:print long_cycle4.value
 // gdb-check:$18 = 29.5
 
-// gdbr-command:print long_cycle_w_anonymous_types.value
+// gdbr-command:print long_cycle_w_anon_types.value
 // gdb-check:$19 = 30
 
-// gdbr-command:print long_cycle_w_anonymous_types.next.val.value
+// gdbr-command:print long_cycle_w_anon_types.next.val.value
 // gdb-check:$20 = 31
 
 // gdb-command:continue
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
 use self::Opt::{Empty, Val};
+use std::boxed::Box as B;
 
 enum Opt<T> {
     Empty,
@@ -120,75 +120,75 @@ struct LongCycleWithAnonymousTypes {
 fn main() {
     let stack_unique: UniqueNode<u16> = UniqueNode {
         next: Val {
-            val: box UniqueNode {
+            val: Box::new(UniqueNode {
                 next: Empty,
                 value: 1,
-            }
+            })
         },
         value: 0,
     };
 
-    let unique_unique: Box<UniqueNode<u32>> = box UniqueNode {
+    let unique_unique: Box<UniqueNode<u32>> = Box::new(UniqueNode {
         next: Val {
-            val: box UniqueNode {
+            val: Box::new(UniqueNode {
                 next: Empty,
                 value: 3,
-            }
+            })
         },
         value: 2,
-    };
+    });
 
     let vec_unique: [UniqueNode<f32>; 1] = [UniqueNode {
         next: Val {
-            val: box UniqueNode {
+            val: Box::new(UniqueNode {
                 next: Empty,
                 value: 7.5,
-            }
+            })
         },
         value: 6.5,
     }];
 
     let borrowed_unique: &UniqueNode<f64> = &UniqueNode {
         next: Val {
-            val: box UniqueNode {
+            val: Box::new(UniqueNode {
                 next: Empty,
                 value: 9.5,
-            }
+            })
         },
         value: 8.5,
     };
 
     // LONG CYCLE
     let long_cycle1: LongCycle1<u16> = LongCycle1 {
-        next: box LongCycle2 {
-            next: box LongCycle3 {
-                next: box LongCycle4 {
+        next: Box::new(LongCycle2 {
+            next: Box::new(LongCycle3 {
+                next: Box::new(LongCycle4 {
                     next: None,
                     value: 23,
-                },
+                }),
                 value: 22,
-            },
+            }),
             value: 21
-        },
+        }),
         value: 20
     };
 
     let long_cycle2: LongCycle2<u32> = LongCycle2 {
-        next: box LongCycle3 {
-            next: box LongCycle4 {
+        next: Box::new(LongCycle3 {
+            next: Box::new(LongCycle4 {
                 next: None,
                 value: 26,
-            },
+            }),
             value: 25,
-        },
+        }),
         value: 24
     };
 
     let long_cycle3: LongCycle3<u64> = LongCycle3 {
-        next: box LongCycle4 {
+        next: Box::new(LongCycle4 {
             next: None,
             value: 28,
-        },
+        }),
         value: 27,
     };
 
@@ -199,15 +199,15 @@ fn main() {
 
     // It's important that LongCycleWithAnonymousTypes is encountered only at the end of the
     // `box` chain.
-    let long_cycle_w_anonymous_types = box box box box box LongCycleWithAnonymousTypes {
+    let long_cycle_w_anon_types = B::new(B::new(B::new(B::new(B::new(LongCycleWithAnonymousTypes {
         next: Val {
-            val: box box box box box LongCycleWithAnonymousTypes {
+            val: Box::new(Box::new(Box::new(Box::new(Box::new(LongCycleWithAnonymousTypes {
                 next: Empty,
                 value: 31,
-            }
+            })))))
         },
         value: 30
-    };
+    })))));
 
     zzz(); // #break
 }
index e15c08577e15a7770e2ed527efea9eb9a297ec49..b8b5add0996aad7c3aee0c83b2ad931dc70fbbfa 100644 (file)
 // lldbr-check:(isize) arg2 = -10
 // lldb-command:continue
 
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -154,7 +153,7 @@ fn main() {
     let _ = stack.self_by_ref(-1, -2);
     let _ = stack.self_by_val(-3, -4);
 
-    let owned: Box<_> = box Struct { x: 200 };
+    let owned: Box<_> = Box::new(Struct { x: 200 });
     let _ = owned.self_by_ref(-5, -6);
     let _ = owned.self_by_val(-7, -8);
     let _ = owned.self_owned(-9, -10);
index 7634e3247d591a3465b8fcbe9080740bcd061696..efce449e312edb4b47920d0710ede5b2072a1a15 100644 (file)
 // lldbr-check:(f32) arg2 = -10.5
 // lldb-command:continue
 
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -155,7 +154,7 @@ fn main() {
     let _ = stack.self_by_ref(-1, 2_u16);
     let _ = stack.self_by_val(-3, -4_i16);
 
-    let owned: Box<_> = box Struct { x: 879 };
+    let owned: Box<_> = Box::new(Struct { x: 879 });
     let _ = owned.self_by_ref(-5, -6_i32);
     let _ = owned.self_by_val(-7, -8_i64);
     let _ = owned.self_owned(-9, -10.5_f32);
index a44f30abd6859378c3950dc3f8b11d3afccbcb43..e12daaf114e142c882d43cabce7cc46258c181b8 100644 (file)
@@ -5,7 +5,6 @@
 // lldb-command:run
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -24,5 +23,5 @@ impl Trait for Struct {}
 fn main() {
     let stack_struct = Struct { a:0, b: 1.0 };
     let reference: &Trait = &stack_struct as &Trait;
-    let unique: Box<Trait> = box Struct { a:2, b: 3.0 } as Box<Trait>;
+    let unique: Box<Trait> = Box::new(Struct { a:2, b: 3.0 }) as Box<Trait>;
 }
index 3497f0afb2cb0bd4447872ef8bb0ceb1f2d40111..2c10360fc924e94e3fe7cd8c6d48c0077d1eac1d 100644 (file)
 // cdb-check:struct ForeignType2 * foreign2 = [...]
 // cdb-check:struct ForeignType1 * foreign1 = [...]
 
-#![feature(box_syntax)]
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
@@ -373,8 +372,8 @@ fn main() {
     let tuple2 = ((Struct1, mod1::mod2::Struct3), mod1::Variant1, 'x');
 
     // Box
-    let box1 = (box 1f32, 0i32);
-    let box2 = (box mod1::mod2::Variant2(1f32), 0i32);
+    let box1 = (Box::new(1f32), 0i32);
+    let box2 = (Box::new(mod1::mod2::Variant2(1f32)), 0i32);
 
     // References
     let ref1 = (&Struct1, 0i32);
@@ -404,14 +403,14 @@ fn main() {
     let slice2 = &*vec2;
 
     // Trait Objects
-    let box_trait = (box 0_isize) as Box<dyn Trait1>;
+    let box_trait = Box::new(0_isize) as Box<dyn Trait1>;
     let ref_trait = &0_isize as &dyn Trait1;
     let mut mut_int1 = 0_isize;
     let mut_ref_trait = (&mut mut_int1) as &mut dyn Trait1;
-    let no_principal_trait = (box 0_isize) as Box<(dyn Send + Sync)>;
+    let no_principal_trait = Box::new(0_isize) as Box<(dyn Send + Sync)>;
     let has_associated_type_trait = &0_isize as &(dyn Trait3<u32, AssocType = isize> + Send);
 
-    let generic_box_trait = (box 0_isize) as Box<dyn Trait2<i32, mod1::Struct2>>;
+    let generic_box_trait = Box::new(0_isize) as Box<dyn Trait2<i32, mod1::Struct2>>;
     let generic_ref_trait = (&0_isize) as &dyn Trait2<Struct1, Struct1>;
 
     let mut generic_mut_ref_trait_impl = 0_isize;
index 9d938b6e36919f31f75efab60a220028321a98cb..d7dfaeefe2b7775114db63aea3fb32dc085628fa 100644 (file)
@@ -32,7 +32,6 @@
 // lldbr-check:(unique_enum::Univariant) *univariant = { TheOnlyCase = { = 123234 } }
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -59,15 +58,15 @@ fn main() {
     // 0b01111100011111000111110001111100 = 2088533116
     // 0b0111110001111100 = 31868
     // 0b01111100 = 124
-    let the_a: Box<_> = box ABC::TheA { x: 0, y: 8970181431921507452 };
+    let the_a: Box<_> = Box::new(ABC::TheA { x: 0, y: 8970181431921507452 });
 
     // 0b0001000100010001000100010001000100010001000100010001000100010001 = 1229782938247303441
     // 0b00010001000100010001000100010001 = 286331153
     // 0b0001000100010001 = 4369
     // 0b00010001 = 17
-    let the_b: Box<_> = box ABC::TheB (0, 286331153, 286331153);
+    let the_b: Box<_> = Box::new(ABC::TheB (0, 286331153, 286331153));
 
-    let univariant: Box<_> = box Univariant::TheOnlyCase(123234);
+    let univariant: Box<_> = Box::new(Univariant::TheOnlyCase(123234));
 
     zzz(); // #break
 }
index a2778fc6090d2bf77716bc59817bd59ed43f2848..d811915c38767ac202705fe3428f3173d14d202e 100644 (file)
 // cdb-check:closure_local    : 8 [Type: [...]]
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -154,7 +153,7 @@ fn main() {
     };
 
     let struct_ref = &a_struct;
-    let owned: Box<_> = box 6;
+    let owned: Box<_> = Box::new(6);
 
     let mut closure = || {
         let closure_local = 8;
index bd7c2bfe2c3ffb124bdb9435918779e18e454fa1..39930e04e4c5f5d88f94dcd572b9a571aa6438b6 100644 (file)
@@ -34,7 +34,6 @@
 // lldbr-check:(isize) *owned = 5
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
 
@@ -53,7 +52,7 @@ fn main() {
         c: 4
     };
 
-    let owned: Box<_> = box 5;
+    let owned: Box<_> = Box::new(5);
 
     let closure = move || {
         zzz(); // #break
index 1bbb79c37a4e70a58e93a782484c59246eff4064..d68409a9d5205fa8a0371055211de7fbdec91772 100644 (file)
 // cdb-command: dx owned
 // cdb-check:owned            : 0x[...] : 6 [Type: [...] *]
 
-#![feature(box_syntax)]
 #![allow(unused_variables)]
 #![feature(omit_gdb_pretty_printer_section)]
 #![omit_gdb_pretty_printer_section]
@@ -137,7 +136,7 @@ fn main() {
     };
 
     let struct_ref = &a_struct;
-    let owned: Box<_> = box 6;
+    let owned: Box<_> = Box::new(6);
 
     {
         let mut first_closure = || {
index cfbd3a58637c0edd08c958bf59739c1b9841d761..c6187879ab0a9cca0438a29de9cc8da6e9152ab9 100644 (file)
@@ -3,64 +3,78 @@
 fn main() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/box_expr.rs:6:11: 6:11
     let _1: std::boxed::Box<S>;          // in scope 0 at $DIR/box_expr.rs:7:9: 7:10
-    let mut _2: std::boxed::Box<S>;      // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
-    let _3: ();                          // in scope 0 at $DIR/box_expr.rs:8:5: 8:12
-    let mut _4: std::boxed::Box<S>;      // in scope 0 at $DIR/box_expr.rs:8:10: 8:11
+    let mut _2: usize;                   // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
+    let mut _3: usize;                   // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
+    let mut _4: *mut u8;                 // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
+    let mut _5: std::boxed::Box<S>;      // in scope 0 at $DIR/box_expr.rs:7:13: 7:25
+    let _6: ();                          // in scope 0 at $DIR/box_expr.rs:8:5: 8:12
+    let mut _7: std::boxed::Box<S>;      // in scope 0 at $DIR/box_expr.rs:8:10: 8:11
     scope 1 {
         debug x => _1;                   // in scope 1 at $DIR/box_expr.rs:7:9: 7:10
     }
+    scope 2 {
+    }
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/box_expr.rs:7:9: 7:10
-        StorageLive(_2);                 // scope 0 at $DIR/box_expr.rs:7:13: 7:25
-        _2 = Box(S);                     // scope 0 at $DIR/box_expr.rs:7:13: 7:25
-        (*_2) = S::new() -> [return: bb1, unwind: bb7]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25
+        _2 = SizeOf(S);                  // scope 2 at $DIR/box_expr.rs:7:13: 7:25
+        _3 = AlignOf(S);                 // scope 2 at $DIR/box_expr.rs:7:13: 7:25
+        _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/box_expr.rs:7:13: 7:25
                                          // mir::Constant
-                                         // + span: $DIR/box_expr.rs:7:17: 7:23
-                                         // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar(<ZST>)) }
+                                         // + span: $DIR/box_expr.rs:7:13: 7:25
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
     }
 
     bb1: {
-        _1 = move _2;                    // scope 0 at $DIR/box_expr.rs:7:13: 7:25
-        drop(_2) -> bb2;                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+        StorageLive(_5);                 // scope 0 at $DIR/box_expr.rs:7:13: 7:25
+        _5 = ShallowInitBox(move _4, S); // scope 0 at $DIR/box_expr.rs:7:13: 7:25
+        (*_5) = S::new() -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/box_expr.rs:7:17: 7:25
+                                         // mir::Constant
+                                         // + span: $DIR/box_expr.rs:7:17: 7:23
+                                         // + literal: Const { ty: fn() -> S {S::new}, val: Value(Scalar(<ZST>)) }
     }
 
     bb2: {
-        StorageDead(_2);                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
-        StorageLive(_3);                 // scope 1 at $DIR/box_expr.rs:8:5: 8:12
-        StorageLive(_4);                 // scope 1 at $DIR/box_expr.rs:8:10: 8:11
-        _4 = move _1;                    // scope 1 at $DIR/box_expr.rs:8:10: 8:11
-        _3 = std::mem::drop::<Box<S>>(move _4) -> [return: bb3, unwind: bb5]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12
+        _1 = move _5;                    // scope 0 at $DIR/box_expr.rs:7:13: 7:25
+        drop(_5) -> bb3;                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+    }
+
+    bb3: {
+        StorageDead(_5);                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+        StorageLive(_6);                 // scope 1 at $DIR/box_expr.rs:8:5: 8:12
+        StorageLive(_7);                 // scope 1 at $DIR/box_expr.rs:8:10: 8:11
+        _7 = move _1;                    // scope 1 at $DIR/box_expr.rs:8:10: 8:11
+        _6 = std::mem::drop::<Box<S>>(move _7) -> [return: bb4, unwind: bb6]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12
                                          // mir::Constant
                                          // + span: $DIR/box_expr.rs:8:5: 8:9
                                          // + literal: Const { ty: fn(std::boxed::Box<S>) {std::mem::drop::<std::boxed::Box<S>>}, val: Value(Scalar(<ZST>)) }
     }
 
-    bb3: {
-        StorageDead(_4);                 // scope 1 at $DIR/box_expr.rs:8:11: 8:12
-        StorageDead(_3);                 // scope 1 at $DIR/box_expr.rs:8:12: 8:13
+    bb4: {
+        StorageDead(_7);                 // scope 1 at $DIR/box_expr.rs:8:11: 8:12
+        StorageDead(_6);                 // scope 1 at $DIR/box_expr.rs:8:12: 8:13
         _0 = const ();                   // scope 0 at $DIR/box_expr.rs:6:11: 9:2
-        drop(_1) -> bb4;                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
+        drop(_1) -> bb5;                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
     }
 
-    bb4: {
+    bb5: {
         StorageDead(_1);                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
         return;                          // scope 0 at $DIR/box_expr.rs:9:2: 9:2
     }
 
-    bb5 (cleanup): {
-        drop(_4) -> bb6;                 // scope 1 at $DIR/box_expr.rs:8:11: 8:12
-    }
-
     bb6 (cleanup): {
-        drop(_1) -> bb8;                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
+        drop(_7) -> bb7;                 // scope 1 at $DIR/box_expr.rs:8:11: 8:12
     }
 
     bb7 (cleanup): {
-        drop(_2) -> bb8;                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+        drop(_1) -> bb9;                 // scope 0 at $DIR/box_expr.rs:9:1: 9:2
     }
 
     bb8 (cleanup): {
+        drop(_5) -> bb9;                 // scope 0 at $DIR/box_expr.rs:7:24: 7:25
+    }
+
+    bb9 (cleanup): {
         resume;                          // scope 0 at $DIR/box_expr.rs:6:1: 9:2
     }
 }
index 9fcbd32ca686df22b7cd26cdbf06a6cd055f34d1..342c987343eac911b82231fad01546734c2c1a35 100644 (file)
@@ -6,34 +6,51 @@
       let _1: i32;                         // in scope 0 at $DIR/boxes.rs:12:9: 12:10
       let mut _2: i32;                     // in scope 0 at $DIR/boxes.rs:12:13: 12:22
       let mut _3: std::boxed::Box<i32>;    // in scope 0 at $DIR/boxes.rs:12:14: 12:22
-      let mut _4: std::boxed::Box<i32>;    // in scope 0 at $DIR/boxes.rs:12:14: 12:22
+      let mut _4: usize;                   // in scope 0 at $DIR/boxes.rs:12:14: 12:22
+      let mut _5: usize;                   // in scope 0 at $DIR/boxes.rs:12:14: 12:22
+      let mut _6: *mut u8;                 // in scope 0 at $DIR/boxes.rs:12:14: 12:22
+      let mut _7: std::boxed::Box<i32>;    // in scope 0 at $DIR/boxes.rs:12:14: 12:22
       scope 1 {
           debug x => _1;                   // in scope 1 at $DIR/boxes.rs:12:9: 12:10
       }
+      scope 2 {
+      }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/boxes.rs:12:9: 12:10
           StorageLive(_2);                 // scope 0 at $DIR/boxes.rs:12:13: 12:22
           StorageLive(_3);                 // scope 0 at $DIR/boxes.rs:12:14: 12:22
-          StorageLive(_4);                 // scope 0 at $DIR/boxes.rs:12:14: 12:22
-          _4 = Box(i32);                   // scope 0 at $DIR/boxes.rs:12:14: 12:22
-          (*_4) = const 42_i32;            // scope 0 at $DIR/boxes.rs:12:19: 12:21
-          _3 = move _4;                    // scope 0 at $DIR/boxes.rs:12:14: 12:22
-          StorageDead(_4);                 // scope 0 at $DIR/boxes.rs:12:21: 12:22
+-         _4 = SizeOf(i32);                // scope 2 at $DIR/boxes.rs:12:14: 12:22
+-         _5 = AlignOf(i32);               // scope 2 at $DIR/boxes.rs:12:14: 12:22
+-         _6 = alloc::alloc::exchange_malloc(move _4, move _5) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22
++         _4 = const 4_usize;              // scope 2 at $DIR/boxes.rs:12:14: 12:22
++         _5 = const 4_usize;              // scope 2 at $DIR/boxes.rs:12:14: 12:22
++         _6 = alloc::alloc::exchange_malloc(const 4_usize, const 4_usize) -> bb1; // scope 2 at $DIR/boxes.rs:12:14: 12:22
+                                           // mir::Constant
+                                           // + span: $DIR/boxes.rs:12:14: 12:22
+                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageLive(_7);                 // scope 0 at $DIR/boxes.rs:12:14: 12:22
+          _7 = ShallowInitBox(move _6, i32); // scope 0 at $DIR/boxes.rs:12:14: 12:22
+          (*_7) = const 42_i32;            // scope 0 at $DIR/boxes.rs:12:19: 12:21
+          _3 = move _7;                    // scope 0 at $DIR/boxes.rs:12:14: 12:22
+          StorageDead(_7);                 // scope 0 at $DIR/boxes.rs:12:21: 12:22
           _2 = (*_3);                      // scope 0 at $DIR/boxes.rs:12:13: 12:22
           _1 = Add(move _2, const 0_i32);  // scope 0 at $DIR/boxes.rs:12:13: 12:26
           StorageDead(_2);                 // scope 0 at $DIR/boxes.rs:12:25: 12:26
-          drop(_3) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/boxes.rs:12:26: 12:27
+          drop(_3) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/boxes.rs:12:26: 12:27
       }
   
-      bb1: {
+      bb2: {
           StorageDead(_3);                 // scope 0 at $DIR/boxes.rs:12:26: 12:27
           nop;                             // scope 0 at $DIR/boxes.rs:11:11: 13:2
           StorageDead(_1);                 // scope 0 at $DIR/boxes.rs:13:1: 13:2
           return;                          // scope 0 at $DIR/boxes.rs:13:2: 13:2
       }
   
-      bb2 (cleanup): {
+      bb3 (cleanup): {
           resume;                          // scope 0 at $DIR/boxes.rs:11:1: 13:2
       }
   }
index 0c220eb91a4b1b65a4faa98af2d847d4aa7f7e41..137a1de522b83d3723677aedfec2027f8dc3596d 100644 (file)
@@ -4,23 +4,37 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11
       let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
-      let mut _2: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-      let mut _3: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
-+     let mut _4: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+      let mut _2: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+      let mut _3: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+      let mut _4: *mut u8;                 // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+      let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+      let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
++     let mut _7: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11
       }
-+     scope 2 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
+      scope 2 {
+      }
++     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
-          StorageLive(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-          _2 = Box(std::vec::Vec<u32>);    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
--         (*_2) = Vec::<u32>::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         StorageLive(_4);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         _4 = &mut (*_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
+          _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+                                           // mir::Constant
+                                           // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
+                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageLive(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+-         (*_5) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         _7 = &mut (*_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +                                          // ty::Const
 +                                          // + ty: alloc::raw_vec::RawVec<u32>
 +                                          // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 -                                          // + literal: Const { ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
 -     }
 - 
--     bb1: {
+-     bb2: {
 +                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:43
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [255], len: Size { raw: 8 } }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         StorageDead(_4);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-          _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-          StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
++         ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         StorageDead(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+          _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
           _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
--         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
-+         drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
+-         drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
++         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
       }
   
--     bb2: {
-+     bb1: {
+-     bb3: {
++     bb2: {
           StorageDead(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2
       }
   
--     bb3 (cleanup): {
-+     bb2 (cleanup): {
+-     bb4 (cleanup): {
++     bb3 (cleanup): {
           resume;                          // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2
 -     }
 - 
--     bb4 (cleanup): {
--         _3 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+-     bb5 (cleanup): {
+-         _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // + literal: Const { ty: unsafe fn(std::ptr::Unique<std::vec::Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<std::vec::Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
index 7f3a72ee5ad75d158a96c5fb9d700a2be710b624..26327d055746180cda3506513c1435fa719b1661 100644 (file)
@@ -4,23 +4,37 @@
   fn main() -> () {
       let mut _0: ();                      // return place in scope 0 at $DIR/inline-into-box-place.rs:7:11: 7:11
       let _1: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
-      let mut _2: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-      let mut _3: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
-+     let mut _4: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+      let mut _2: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+      let mut _3: usize;                   // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+      let mut _4: *mut u8;                 // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+      let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+      let mut _6: ();                      // in scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
++     let mut _7: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
       scope 1 {
           debug _x => _1;                  // in scope 1 at $DIR/inline-into-box-place.rs:8:9: 8:11
       }
-+     scope 2 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
+      scope 2 {
+      }
++     scope 3 (inlined Vec::<u32>::new) {  // at $DIR/inline-into-box-place.rs:8:33: 8:43
 +     }
   
       bb0: {
           StorageLive(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:8:9: 8:11
-          StorageLive(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-          _2 = Box(std::vec::Vec<u32>);    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
--         (*_2) = Vec::<u32>::new() -> [return: bb1, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         StorageLive(_4);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         _4 = &mut (*_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         ((*_4).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
+          _2 = SizeOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          _3 = AlignOf(std::vec::Vec<u32>); // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 2 at $DIR/inline-into-box-place.rs:8:29: 8:43
+                                           // mir::Constant
+                                           // + span: $DIR/inline-into-box-place.rs:8:29: 8:43
+                                           // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
+      }
+  
+      bb1: {
+          StorageLive(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          _5 = ShallowInitBox(move _4, std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+-         (*_5) = Vec::<u32>::new() -> [return: bb2, unwind: bb5]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         StorageLive(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         _7 = &mut (*_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         ((*_7).0: alloc::raw_vec::RawVec<u32>) = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: {0x4 as *const u32}, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43
 +                                          // ty::Const
 +                                          // + ty: alloc::raw_vec::RawVec<u32>
 +                                          // + val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } })
 -                                          // + literal: Const { ty: fn() -> std::vec::Vec<u32> {std::vec::Vec::<u32>::new}, val: Value(Scalar(<ZST>)) }
 -     }
 - 
--     bb1: {
+-     bb2: {
 +                                          // + span: $DIR/inline-into-box-place.rs:8:33: 8:43
 +                                          // + user_ty: UserType(0)
 +                                          // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [65535], len: Size { raw: 16 } }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) }
-+         ((*_4).1: usize) = const 0_usize; // scope 2 at $DIR/inline-into-box-place.rs:8:33: 8:43
-+         StorageDead(_4);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
-          _1 = move _2;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
-          StorageDead(_2);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
++         ((*_7).1: usize) = const 0_usize; // scope 3 at $DIR/inline-into-box-place.rs:8:33: 8:43
++         StorageDead(_7);                 // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+          _1 = move _5;                    // scope 0 at $DIR/inline-into-box-place.rs:8:29: 8:43
+          StorageDead(_5);                 // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
           _0 = const ();                   // scope 0 at $DIR/inline-into-box-place.rs:7:11: 9:2
--         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
-+         drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
+-         drop(_1) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
++         drop(_1) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
       }
   
--     bb2: {
-+     bb1: {
+-     bb3: {
++     bb2: {
           StorageDead(_1);                 // scope 0 at $DIR/inline-into-box-place.rs:9:1: 9:2
           return;                          // scope 0 at $DIR/inline-into-box-place.rs:9:2: 9:2
       }
   
--     bb3 (cleanup): {
-+     bb2 (cleanup): {
+-     bb4 (cleanup): {
++     bb3 (cleanup): {
           resume;                          // scope 0 at $DIR/inline-into-box-place.rs:7:1: 9:2
 -     }
 - 
--     bb4 (cleanup): {
--         _3 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_2.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_2.1: std::alloc::Global)) -> bb3; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
+-     bb5 (cleanup): {
+-         _6 = alloc::alloc::box_free::<Vec<u32>, std::alloc::Global>(move (_5.0: std::ptr::Unique<std::vec::Vec<u32>>), move (_5.1: std::alloc::Global)) -> bb4; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // mir::Constant
 -                                          // + span: $DIR/inline-into-box-place.rs:8:42: 8:43
 -                                          // + literal: Const { ty: unsafe fn(std::ptr::Unique<std::vec::Vec<u32>>, std::alloc::Global) {alloc::alloc::box_free::<std::vec::Vec<u32>, std::alloc::Global>}, val: Value(Scalar(<ZST>)) }
index 95efa74289d85b6509f813638dea5abf1ad5d257..dde49c77ae7f5fbdf3cc62fe427eb4ff97c77f62 100644 (file)
 fn test() -> Option<Box<u32>> {
     let mut _0: std::option::Option<std::boxed::Box<u32>>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30
     let mut _1: std::boxed::Box<u32>;    // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-    let mut _2: std::boxed::Box<u32>;    // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-    let mut _3: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
-    let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19
-    let mut _5: isize;                   // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    let _6: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    let mut _7: !;                       // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    let mut _8: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-    let _9: u32;                         // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+    let mut _2: usize;                   // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+    let mut _3: usize;                   // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+    let mut _4: *mut u8;                 // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+    let mut _5: std::boxed::Box<u32>;    // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+    let mut _6: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+    let mut _7: std::option::Option<u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19
+    let mut _8: isize;                   // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+    let _9: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+    let mut _10: !;                      // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+    let mut _11: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+    let _12: u32;                        // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20
     scope 1 {
-        debug residual => _6;            // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20
-        scope 2 {
+    }
+    scope 2 {
+        debug residual => _9;            // in scope 2 at $DIR/issue-62289.rs:9:19: 9:20
+        scope 3 {
         }
     }
-    scope 3 {
-        debug val => _9;                 // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20
-        scope 4 {
+    scope 4 {
+        debug val => _12;                // in scope 4 at $DIR/issue-62289.rs:9:15: 9:20
+        scope 5 {
         }
     }
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-        StorageLive(_2);                 // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-        _2 = Box(u32);                   // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-        StorageLive(_3);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
-        StorageLive(_4);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
-        _4 = Option::<u32>::None;        // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
-        _3 = <Option<u32> as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        _2 = SizeOf(u32);                // scope 1 at $DIR/issue-62289.rs:9:10: 9:21
+        _3 = AlignOf(u32);               // scope 1 at $DIR/issue-62289.rs:9:10: 9:21
+        _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/issue-62289.rs:9:10: 9:21
                                          // mir::Constant
-                                         // + span: $DIR/issue-62289.rs:9:15: 9:20
-                                         // + literal: Const { ty: fn(std::option::Option<u32>) -> std::ops::ControlFlow<<std::option::Option<u32> as std::ops::Try>::Residual, <std::option::Option<u32> as std::ops::Try>::Output> {<std::option::Option<u32> as std::ops::Try>::branch}, val: Value(Scalar(<ZST>)) }
+                                         // + span: $DIR/issue-62289.rs:9:10: 9:21
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
     }
 
     bb1: {
-        StorageDead(_4);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        _5 = discriminant(_3);           // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
-        switchInt(move _5) -> [0_isize: bb2, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        StorageLive(_5);                 // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+        _5 = ShallowInitBox(move _4, u32); // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+        StorageLive(_6);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        StorageLive(_7);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
+        _7 = Option::<u32>::None;        // scope 0 at $DIR/issue-62289.rs:9:15: 9:19
+        _6 = <Option<u32> as Try>::branch(move _7) -> [return: bb2, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+                                         // mir::Constant
+                                         // + span: $DIR/issue-62289.rs:9:15: 9:20
+                                         // + literal: Const { ty: fn(std::option::Option<u32>) -> std::ops::ControlFlow<<std::option::Option<u32> as std::ops::Try>::Residual, <std::option::Option<u32> as std::ops::Try>::Output> {<std::option::Option<u32> as std::ops::Try>::branch}, val: Value(Scalar(<ZST>)) }
     }
 
     bb2: {
-        StorageLive(_9);                 // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
-        _9 = ((_3 as Continue).0: u32);  // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
-        (*_2) = _9;                      // scope 4 at $DIR/issue-62289.rs:9:15: 9:20
-        StorageDead(_9);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        _1 = move _2;                    // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
-        drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        StorageDead(_7);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        _8 = discriminant(_6);           // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        switchInt(move _8) -> [0_isize: bb3, 1_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
     }
 
     bb3: {
-        unreachable;                     // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        StorageLive(_12);                // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        _12 = ((_6 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
+        (*_5) = _12;                     // scope 5 at $DIR/issue-62289.rs:9:15: 9:20
+        StorageDead(_12);                // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        _1 = move _5;                    // scope 0 at $DIR/issue-62289.rs:9:10: 9:21
+        drop(_5) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
     }
 
     bb4: {
-        StorageLive(_6);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        _6 = ((_3 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        StorageLive(_8);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        _8 = _6;                         // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20
-                                         // mir::Constant
-                                         // + span: $DIR/issue-62289.rs:9:19: 9:20
-                                         // + literal: Const { ty: fn(std::option::Option<std::convert::Infallible>) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) }
+        unreachable;                     // scope 0 at $DIR/issue-62289.rs:9:15: 9:20
     }
 
     bb5: {
-        StorageDead(_8);                 // scope 2 at $DIR/issue-62289.rs:9:19: 9:20
-        StorageDead(_6);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
-        drop(_2) -> bb8;                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        StorageLive(_9);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        _9 = ((_6 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        StorageLive(_11);                // scope 3 at $DIR/issue-62289.rs:9:19: 9:20
+        _11 = _9;                        // scope 3 at $DIR/issue-62289.rs:9:19: 9:20
+        _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _11) -> [return: bb6, unwind: bb12]; // scope 3 at $DIR/issue-62289.rs:9:15: 9:20
+                                         // mir::Constant
+                                         // + span: $DIR/issue-62289.rs:9:19: 9:20
+                                         // + literal: Const { ty: fn(std::option::Option<std::convert::Infallible>) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) }
     }
 
     bb6: {
-        StorageDead(_2);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
-        _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
-        drop(_1) -> bb7;                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+        StorageDead(_11);                // scope 3 at $DIR/issue-62289.rs:9:19: 9:20
+        StorageDead(_9);                 // scope 0 at $DIR/issue-62289.rs:9:19: 9:20
+        drop(_5) -> bb9;                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
     }
 
     bb7: {
-        StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
-        StorageDead(_3);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
-        goto -> bb9;                     // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+        StorageDead(_5);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22
+        drop(_1) -> bb8;                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
     }
 
     bb8: {
-        StorageDead(_2);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
         StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
-        StorageDead(_3);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
-        goto -> bb9;                     // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+        StorageDead(_6);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
+        goto -> bb10;                    // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
     }
 
     bb9: {
-        return;                          // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
+        StorageDead(_5);                 // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        StorageDead(_1);                 // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+        StorageDead(_6);                 // scope 0 at $DIR/issue-62289.rs:10:1: 10:2
+        goto -> bb10;                    // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
     }
 
-    bb10 (cleanup): {
-        drop(_1) -> bb12;                // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
+    bb10: {
+        return;                          // scope 0 at $DIR/issue-62289.rs:10:2: 10:2
     }
 
     bb11 (cleanup): {
-        drop(_2) -> bb12;                // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+        drop(_1) -> bb13;                // scope 0 at $DIR/issue-62289.rs:9:21: 9:22
     }
 
     bb12 (cleanup): {
+        drop(_5) -> bb13;                // scope 0 at $DIR/issue-62289.rs:9:20: 9:21
+    }
+
+    bb13 (cleanup): {
         resume;                          // scope 0 at $DIR/issue-62289.rs:8:1: 10:2
     }
 }
index 7f81d9fc482ff91e17445f060855618925bc9e98..d7d2cdf9b0c7577c76c0f828b9af23e2b7db1695 100644 (file)
@@ -4,80 +4,108 @@ fn move_out_by_subslice() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/uniform_array_move_out.rs:10:27: 10:27
     let _1: [std::boxed::Box<i32>; 2];   // in scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
     let mut _2: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
-    let mut _3: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
-    let mut _4: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
-    let mut _5: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+    let mut _3: usize;                   // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+    let mut _4: usize;                   // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+    let mut _5: *mut u8;                 // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+    let mut _6: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+    let mut _7: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+    let mut _8: usize;                   // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+    let mut _9: usize;                   // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+    let mut _10: *mut u8;                // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+    let mut _11: std::boxed::Box<i32>;   // in scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
     scope 1 {
         debug a => _1;                   // in scope 1 at $DIR/uniform_array_move_out.rs:11:9: 11:10
-        let _6: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
-        scope 2 {
-            debug _y => _6;              // in scope 2 at $DIR/uniform_array_move_out.rs:12:10: 12:17
+        let _12: [std::boxed::Box<i32>; 2]; // in scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
+        scope 4 {
+            debug _y => _12;             // in scope 4 at $DIR/uniform_array_move_out.rs:12:10: 12:17
         }
     }
+    scope 2 {
+    }
+    scope 3 {
+    }
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
         StorageLive(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
-        StorageLive(_3);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
-        _3 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
-        (*_3) = const 1_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
-        _2 = move _3;                    // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
-        drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+        _3 = SizeOf(i32);                // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+        _4 = AlignOf(i32);               // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+        _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+                                         // mir::Constant
+                                         // + span: $DIR/uniform_array_move_out.rs:11:14: 11:19
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
     }
 
     bb1: {
-        StorageDead(_3);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
-        StorageLive(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
-        StorageLive(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
-        _5 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
-        (*_5) = const 2_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
-        _4 = move _5;                    // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
-        drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+        StorageLive(_6);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+        _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+        (*_6) = const 1_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+        _2 = move _6;                    // scope 0 at $DIR/uniform_array_move_out.rs:11:14: 11:19
+        drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
     }
 
     bb2: {
-        StorageDead(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
-        _1 = [move _2, move _4];         // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27
-        drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+        StorageDead(_6);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:18: 11:19
+        StorageLive(_7);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+        _8 = SizeOf(i32);                // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+        _9 = AlignOf(i32);               // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+        _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+                                         // mir::Constant
+                                         // + span: $DIR/uniform_array_move_out.rs:11:21: 11:26
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
     }
 
     bb3: {
-        StorageDead(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
-        drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+        StorageLive(_11);                // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+        _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+        (*_11) = const 2_i32;            // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+        _7 = move _11;                   // scope 0 at $DIR/uniform_array_move_out.rs:11:21: 11:26
+        drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
     }
 
     bb4: {
+        StorageDead(_11);                // scope 0 at $DIR/uniform_array_move_out.rs:11:25: 11:26
+        _1 = [move _2, move _7];         // scope 0 at $DIR/uniform_array_move_out.rs:11:13: 11:27
+        drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+    }
+
+    bb5: {
+        StorageDead(_7);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+        drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+    }
+
+    bb6: {
         StorageDead(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
         FakeRead(ForLet(None), _1);      // scope 0 at $DIR/uniform_array_move_out.rs:11:9: 11:10
-        StorageLive(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
-        _6 = move _1[0..2];              // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
+        StorageLive(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
+        _12 = move _1[0..2];             // scope 1 at $DIR/uniform_array_move_out.rs:12:10: 12:17
         _0 = const ();                   // scope 0 at $DIR/uniform_array_move_out.rs:10:27: 13:2
-        drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+        drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
     }
 
-    bb5: {
-        StorageDead(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
-        drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+    bb7: {
+        StorageDead(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+        drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
     }
 
-    bb6: {
+    bb8: {
         StorageDead(_1);                 // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
         return;                          // scope 0 at $DIR/uniform_array_move_out.rs:13:2: 13:2
     }
 
-    bb7 (cleanup): {
-        drop(_1) -> bb10;                // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
+    bb9 (cleanup): {
+        drop(_1) -> bb12;                // scope 0 at $DIR/uniform_array_move_out.rs:13:1: 13:2
     }
 
-    bb8 (cleanup): {
-        drop(_4) -> bb9;                 // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+    bb10 (cleanup): {
+        drop(_7) -> bb11;                // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
     }
 
-    bb9 (cleanup): {
-        drop(_2) -> bb10;                // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
+    bb11 (cleanup): {
+        drop(_2) -> bb12;                // scope 0 at $DIR/uniform_array_move_out.rs:11:26: 11:27
     }
 
-    bb10 (cleanup): {
+    bb12 (cleanup): {
         resume;                          // scope 0 at $DIR/uniform_array_move_out.rs:10:1: 13:2
     }
 }
index 62ab494c066285935830d66237b7b9bcba83a4bc..18bc1a17c1b50abe24a283d5b59c88e73a2b3c8e 100644 (file)
@@ -4,80 +4,108 @@ fn move_out_from_end() -> () {
     let mut _0: ();                      // return place in scope 0 at $DIR/uniform_array_move_out.rs:4:24: 4:24
     let _1: [std::boxed::Box<i32>; 2];   // in scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
     let mut _2: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
-    let mut _3: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
-    let mut _4: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
-    let mut _5: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+    let mut _3: usize;                   // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+    let mut _4: usize;                   // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+    let mut _5: *mut u8;                 // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+    let mut _6: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+    let mut _7: std::boxed::Box<i32>;    // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+    let mut _8: usize;                   // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+    let mut _9: usize;                   // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+    let mut _10: *mut u8;                // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+    let mut _11: std::boxed::Box<i32>;   // in scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
     scope 1 {
         debug a => _1;                   // in scope 1 at $DIR/uniform_array_move_out.rs:5:9: 5:10
-        let _6: std::boxed::Box<i32>;    // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
-        scope 2 {
-            debug _y => _6;              // in scope 2 at $DIR/uniform_array_move_out.rs:6:14: 6:16
+        let _12: std::boxed::Box<i32>;   // in scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
+        scope 4 {
+            debug _y => _12;             // in scope 4 at $DIR/uniform_array_move_out.rs:6:14: 6:16
         }
     }
+    scope 2 {
+    }
+    scope 3 {
+    }
 
     bb0: {
         StorageLive(_1);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
         StorageLive(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
-        StorageLive(_3);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
-        _3 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
-        (*_3) = const 1_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
-        _2 = move _3;                    // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
-        drop(_3) -> [return: bb1, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+        _3 = SizeOf(i32);                // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+        _4 = AlignOf(i32);               // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+        _5 = alloc::alloc::exchange_malloc(move _3, move _4) -> [return: bb1, unwind: bb12]; // scope 2 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+                                         // mir::Constant
+                                         // + span: $DIR/uniform_array_move_out.rs:5:14: 5:19
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
     }
 
     bb1: {
-        StorageDead(_3);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
-        StorageLive(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
-        StorageLive(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
-        _5 = Box(i32);                   // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
-        (*_5) = const 2_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
-        _4 = move _5;                    // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
-        drop(_5) -> [return: bb2, unwind: bb8]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+        StorageLive(_6);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+        _6 = ShallowInitBox(move _5, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+        (*_6) = const 1_i32;             // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+        _2 = move _6;                    // scope 0 at $DIR/uniform_array_move_out.rs:5:14: 5:19
+        drop(_6) -> [return: bb2, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
     }
 
     bb2: {
-        StorageDead(_5);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
-        _1 = [move _2, move _4];         // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27
-        drop(_4) -> [return: bb3, unwind: bb9]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+        StorageDead(_6);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:18: 5:19
+        StorageLive(_7);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+        _8 = SizeOf(i32);                // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+        _9 = AlignOf(i32);               // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+        _10 = alloc::alloc::exchange_malloc(move _8, move _9) -> [return: bb3, unwind: bb11]; // scope 3 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+                                         // mir::Constant
+                                         // + span: $DIR/uniform_array_move_out.rs:5:21: 5:26
+                                         // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(Scalar(<ZST>)) }
     }
 
     bb3: {
-        StorageDead(_4);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
-        drop(_2) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+        StorageLive(_11);                // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+        _11 = ShallowInitBox(move _10, i32); // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+        (*_11) = const 2_i32;            // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+        _7 = move _11;                   // scope 0 at $DIR/uniform_array_move_out.rs:5:21: 5:26
+        drop(_11) -> [return: bb4, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
     }
 
     bb4: {
+        StorageDead(_11);                // scope 0 at $DIR/uniform_array_move_out.rs:5:25: 5:26
+        _1 = [move _2, move _7];         // scope 0 at $DIR/uniform_array_move_out.rs:5:13: 5:27
+        drop(_7) -> [return: bb5, unwind: bb11]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+    }
+
+    bb5: {
+        StorageDead(_7);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+        drop(_2) -> [return: bb6, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+    }
+
+    bb6: {
         StorageDead(_2);                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
         FakeRead(ForLet(None), _1);      // scope 0 at $DIR/uniform_array_move_out.rs:5:9: 5:10
-        StorageLive(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
-        _6 = move _1[1 of 2];            // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
+        StorageLive(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
+        _12 = move _1[1 of 2];           // scope 1 at $DIR/uniform_array_move_out.rs:6:14: 6:16
         _0 = const ();                   // scope 0 at $DIR/uniform_array_move_out.rs:4:24: 7:2
-        drop(_6) -> [return: bb5, unwind: bb7]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+        drop(_12) -> [return: bb7, unwind: bb9]; // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
     }
 
-    bb5: {
-        StorageDead(_6);                 // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
-        drop(_1) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+    bb7: {
+        StorageDead(_12);                // scope 1 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+        drop(_1) -> [return: bb8, unwind: bb12]; // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
     }
 
-    bb6: {
+    bb8: {
         StorageDead(_1);                 // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
         return;                          // scope 0 at $DIR/uniform_array_move_out.rs:7:2: 7:2
     }
 
-    bb7 (cleanup): {
-        drop(_1) -> bb10;                // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
+    bb9 (cleanup): {
+        drop(_1) -> bb12;                // scope 0 at $DIR/uniform_array_move_out.rs:7:1: 7:2
     }
 
-    bb8 (cleanup): {
-        drop(_4) -> bb9;                 // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+    bb10 (cleanup): {
+        drop(_7) -> bb11;                // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
     }
 
-    bb9 (cleanup): {
-        drop(_2) -> bb10;                // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
+    bb11 (cleanup): {
+        drop(_2) -> bb12;                // scope 0 at $DIR/uniform_array_move_out.rs:5:26: 5:27
     }
 
-    bb10 (cleanup): {
+    bb12 (cleanup): {
         resume;                          // scope 0 at $DIR/uniform_array_move_out.rs:4:1: 7:2
     }
 }
diff --git a/src/test/rustdoc-ui/doctest-edition.rs b/src/test/rustdoc-ui/doctest-edition.rs
new file mode 100644 (file)
index 0000000..b0787be
--- /dev/null
@@ -0,0 +1,16 @@
+// edition:2021
+
+#![deny(rustdoc::invalid_rust_codeblocks)]
+//~^ NOTE lint level is defined here
+
+// By default, rustdoc should use the edition of the crate.
+//! ```
+//! foo'b'
+//! ```
+//~^^^ ERROR could not parse
+//~| NOTE prefix `foo` is unknown
+
+// Rustdoc should respect `edition2018` when highlighting syntax.
+//! ```edition2018
+//! foo'b'
+//! ```
diff --git a/src/test/rustdoc-ui/doctest-edition.stderr b/src/test/rustdoc-ui/doctest-edition.stderr
new file mode 100644 (file)
index 0000000..1643d60
--- /dev/null
@@ -0,0 +1,22 @@
+error: could not parse code block as Rust code
+  --> $DIR/doctest-edition.rs:7:5
+   |
+LL |   //! ```
+   |  _____^
+LL | | //! foo'b'
+LL | | //! ```
+   | |_______^
+   |
+note: the lint level is defined here
+  --> $DIR/doctest-edition.rs:3:9
+   |
+LL | #![deny(rustdoc::invalid_rust_codeblocks)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   = note: error from rustc: prefix `foo` is unknown
+help: mark blocks that do not contain Rust code as text
+   |
+LL | //! ```text
+   |        ++++
+
+error: aborting due to previous error
+
diff --git a/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs b/src/test/rustdoc/hidden-trait-methods-with-document-hidden-items.rs
new file mode 100644 (file)
index 0000000..95b3e9b
--- /dev/null
@@ -0,0 +1,31 @@
+// compile-flags: -Z unstable-options --document-hidden-items
+
+// test for trait methods with `doc(hidden)` with `--document-hidden-items` passed.
+#![crate_name = "foo"]
+
+// @has foo/trait.Trait.html
+// @has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @has - '//*[@id="tymethod.f"]' 'fn f()'
+// @has - '//*[@id="tymethod.g"]' 'fn g()'
+pub trait Trait {
+    #[doc(hidden)]
+    type Foo;
+    type Bar;
+    #[doc(hidden)]
+    fn f();
+    fn g();
+}
+
+// @has foo/struct.S.html
+// @has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @has - '//*[@id="method.f"]' 'fn f()'
+// @has - '//*[@id="method.g"]' 'fn g()'
+pub struct S;
+impl Trait for S {
+    type Foo = ();
+    type Bar = ();
+    fn f() {}
+    fn g() {}
+}
diff --git a/src/test/rustdoc/hidden-trait-methods.rs b/src/test/rustdoc/hidden-trait-methods.rs
new file mode 100644 (file)
index 0000000..e924ba7
--- /dev/null
@@ -0,0 +1,29 @@
+// test for trait methods with `doc(hidden)`.
+#![crate_name = "foo"]
+
+// @has foo/trait.Trait.html
+// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @!has - '//*[@id="tymethod.f"]' 'fn f()'
+// @has - '//*[@id="tymethod.g"]' 'fn g()'
+pub trait Trait {
+    #[doc(hidden)]
+    type Foo;
+    type Bar;
+    #[doc(hidden)]
+    fn f();
+    fn g();
+}
+
+// @has foo/struct.S.html
+// @!has - '//*[@id="associatedtype.Foo"]' 'type Foo'
+// @has - '//*[@id="associatedtype.Bar"]' 'type Bar'
+// @!has - '//*[@id="method.f"]' 'fn f()'
+// @has - '//*[@id="method.g"]' 'fn g()'
+pub struct S;
+impl Trait for S {
+    type Foo = ();
+    type Bar = ();
+    fn f() {}
+    fn g() {}
+}
index 0b68d5e04f7a208b262f52e7819f33e38fe548e7..8051c58898e499241a41ead3775deea95e4b85e4 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(box_syntax, plugin, rustc_private)]
+#![feature(plugin, rustc_private)]
 #![crate_type = "dylib"]
 
 extern crate rustc_ast_pretty;
@@ -21,7 +21,7 @@
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&MISSING_ALLOWED_ATTR]);
-    reg.lint_store.register_late_pass(|| box MissingAllowedAttrPass);
+    reg.lint_store.register_late_pass(|| Box::new(MissingAllowedAttrPass));
 }
 
 declare_lint! {
index 0015a826126ff5776117f4511e1c5c12a00dcd70..fc57c14ec32b15e5be62f08720917d25cb502e03 100644 (file)
@@ -1,7 +1,6 @@
 // force-host
 
 #![feature(rustc_private)]
-#![feature(box_syntax)]
 
 extern crate rustc_driver;
 extern crate rustc_hir;
@@ -73,7 +72,7 @@ fn __rustc_plugin_registrar(reg: &mut Registry) {
         &CRATE_NOT_GREY,
         &CRATE_NOT_GREEN,
     ]);
-    reg.lint_store.register_late_pass(|| box PassOkay);
-    reg.lint_store.register_late_pass(|| box PassRedBlue);
-    reg.lint_store.register_late_pass(|| box PassGreyGreen);
+    reg.lint_store.register_late_pass(|| Box::new(PassOkay));
+    reg.lint_store.register_late_pass(|| Box::new(PassRedBlue));
+    reg.lint_store.register_late_pass(|| Box::new(PassGreyGreen));
 }
index 87c90b53648c79901be67c28a50950128554e5c4..78c6c7ed887a903a49215fa90101086854e4879d 100644 (file)
@@ -1,7 +1,6 @@
 // force-host
 
 #![feature(rustc_private)]
-#![feature(box_syntax)]
 
 extern crate rustc_driver;
 extern crate rustc_hir;
@@ -41,5 +40,5 @@ fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) {
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&CRATE_NOT_OKAY]);
-    reg.lint_store.register_late_pass(|| box Pass);
+    reg.lint_store.register_late_pass(|| Box::new(Pass));
 }
index f6ae560411b8e8f4cba0b29c39e8ba93444ffe97..253855fd2edd48edc3b14d7f5021f59f1fd3de6a 100644 (file)
@@ -1,6 +1,6 @@
 // force-host
 
-#![feature(box_syntax, rustc_private)]
+#![feature(rustc_private)]
 
 // Load rustc as a plugin to get macros.
 extern crate rustc_driver;
@@ -36,7 +36,7 @@ fn check_item(&mut self, cx: &LateContext, it: &rustc_hir::Item) {
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&TEST_LINT, &PLEASE_LINT]);
-    reg.lint_store.register_late_pass(|| box Pass);
+    reg.lint_store.register_late_pass(|| Box::new(Pass));
     reg.lint_store.register_group(
         true,
         "lint_me",
index 32326bc8a5e5083ede7cefb6dcab661529106857..42368ec36a028d03103b816740fa031e990740bb 100644 (file)
@@ -1,6 +1,6 @@
 // force-host
 
-#![feature(box_syntax, rustc_private)]
+#![feature(rustc_private)]
 
 extern crate rustc_ast;
 
@@ -31,5 +31,5 @@ fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&TEST_LINT]);
-    reg.lint_store.register_early_pass(|| box Pass);
+    reg.lint_store.register_early_pass(|| Box::new(Pass));
 }
index 42c1c851de8231105e1f7dd3876bbe11aeae6ca4..81feddf571323341dd4c9d224f7d20a865eaa7b4 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(box_syntax, rustc_private)]
+#![feature(rustc_private)]
 
 extern crate rustc_ast;
 
@@ -46,7 +46,7 @@ fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
 #[no_mangle]
 fn __rustc_plugin_registrar(reg: &mut Registry) {
     reg.lint_store.register_lints(&[&TEST_RUSTC_TOOL_LINT, &TEST_LINT, &TEST_GROUP]);
-    reg.lint_store.register_early_pass(|| box Pass);
+    reg.lint_store.register_early_pass(|| Box::new(Pass));
     reg.lint_store.register_group(
         true,
         "clippy::group",
index d0eedf23cafe9661923f7ae9478ba2a5b6a3205a..e83dfe80463d882b715b525ea7f8f0ec97b15802 100644 (file)
@@ -1,6 +1,6 @@
 // force-host
 
-#![feature(box_syntax, rustc_private)]
+#![feature(rustc_private)]
 
 extern crate rustc_middle;
 extern crate rustc_driver;
@@ -20,5 +20,5 @@ fn drop(&mut self) {}
 #[no_mangle]
 fn __rustc_plugin_registrar(_: &mut Registry) {
     thread_local!(static FOO: RefCell<Option<Box<Any+Send>>> = RefCell::new(None));
-    FOO.with(|s| *s.borrow_mut() = Some(box Foo { foo: 10 } as Box<Any+Send>));
+    FOO.with(|s| *s.borrow_mut() = Some(Box::new(Foo { foo: 10 }) as Box<Any+Send>));
 }
index 119fa3d6fa8efcf9ad60ab93805879dce4061812..fab2031d952356a5b136cc8039b25e823c4c076a 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![allow(unused_imports)]
-#![feature(box_syntax)]
 #![feature(rustc_private)]
 
 extern crate rustc_macros;
index adbd05ed8c1757593995a802f856518ad7ae3d6e..eb503dcf3b63bb2083a5bbd1f7f80a640f8c12f6 100644 (file)
@@ -3,8 +3,6 @@
 #![allow(non_camel_case_types)]
 #![allow(dead_code)]
 
-#![feature(box_syntax)]
-
 struct pair<A,B> {
     a: A, b: B
 }
@@ -25,10 +23,10 @@ fn f(&self) -> (A, u16) {
 }
 
 fn f<A:Clone + 'static>(a: A, b: u16) -> Box<dyn Invokable<A>+'static> {
-    box Invoker {
+    Box::new(Invoker {
         a: a,
         b: b,
-    } as Box<dyn Invokable<A>+'static>
+    }) as Box<dyn Invokable<A>+'static>
 }
 
 pub fn main() {
index e741201652ba0d9ff7f82884a078d88e2876778e..c58ddbc4239460029f7128105d107bf31274cec0 100644 (file)
@@ -1,11 +1,9 @@
 // run-pass
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    // Tests for indexing into box/& [T; n]
+    // Tests for indexing into Box<[T; n]>/& [T; n]
     let x: [isize; 3] = [1, 2, 3];
-    let mut x: Box<[isize; 3]> = box x;
+    let mut x: Box<[isize; 3]> = x.into();
     assert_eq!(x[0], 1);
     assert_eq!(x[1], 2);
     assert_eq!(x[2], 3);
index dd8f402f3f6a59570b1808ee361ffd4a3bb0f98e..e2055f551acc4b3d660b4078ce31dd4544b7482c 100644 (file)
@@ -2,6 +2,6 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
-pub fn main() { let _quux: Box<Vec<usize>> = box Vec::new(); }
+pub fn main() {
+    let _quux: Box<Vec<usize>> = Box::new(Vec::new());
+}
diff --git a/src/test/ui/asm/aarch64/bad-options.rs b/src/test/ui/asm/aarch64/bad-options.rs
new file mode 100644 (file)
index 0000000..8775eba
--- /dev/null
@@ -0,0 +1,39 @@
+// only-aarch64
+
+#![feature(asm, global_asm)]
+
+fn main() {
+    let mut foo = 0;
+    unsafe {
+        asm!("", options(nomem, readonly));
+        //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+        asm!("", options(pure, nomem, noreturn));
+        //~^ ERROR the `pure` and `noreturn` options are mutually exclusive
+        //~^^ ERROR asm with the `pure` option must have at least one output
+        asm!("{}", in(reg) foo, options(pure, nomem));
+        //~^ ERROR asm with the `pure` option must have at least one output
+        asm!("{}", out(reg) foo, options(noreturn));
+        //~^ ERROR asm outputs are not allowed with the `noreturn` option
+    }
+
+    unsafe {
+        asm!("", clobber_abi("foo"));
+        //~^ ERROR invalid ABI for `clobber_abi`
+        asm!("{}", out(reg) foo, clobber_abi("C"));
+        //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
+        asm!("", out("x0") foo, clobber_abi("C"));
+    }
+}
+
+global_asm!("", options(nomem));
+//~^ ERROR expected one of
+global_asm!("", options(readonly));
+//~^ ERROR expected one of
+global_asm!("", options(noreturn));
+//~^ ERROR expected one of
+global_asm!("", options(pure));
+//~^ ERROR expected one of
+global_asm!("", options(nostack));
+//~^ ERROR expected one of
+global_asm!("", options(preserves_flags));
+//~^ ERROR expected one of
diff --git a/src/test/ui/asm/aarch64/bad-options.stderr b/src/test/ui/asm/aarch64/bad-options.stderr
new file mode 100644 (file)
index 0000000..21bcc4a
--- /dev/null
@@ -0,0 +1,84 @@
+error: the `nomem` and `readonly` options are mutually exclusive
+  --> $DIR/bad-options.rs:8:18
+   |
+LL |         asm!("", options(nomem, readonly));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the `pure` and `noreturn` options are mutually exclusive
+  --> $DIR/bad-options.rs:10:18
+   |
+LL |         asm!("", options(pure, nomem, noreturn));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: asm with the `pure` option must have at least one output
+  --> $DIR/bad-options.rs:10:18
+   |
+LL |         asm!("", options(pure, nomem, noreturn));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: asm with the `pure` option must have at least one output
+  --> $DIR/bad-options.rs:13:33
+   |
+LL |         asm!("{}", in(reg) foo, options(pure, nomem));
+   |                                 ^^^^^^^^^^^^^^^^^^^^
+
+error: asm outputs are not allowed with the `noreturn` option
+  --> $DIR/bad-options.rs:15:20
+   |
+LL |         asm!("{}", out(reg) foo, options(noreturn));
+   |                    ^^^^^^^^^^^^
+
+error: asm with `clobber_abi` must specify explicit registers for outputs
+  --> $DIR/bad-options.rs:22:20
+   |
+LL |         asm!("{}", out(reg) foo, clobber_abi("C"));
+   |                    ^^^^^^^^^^^^  ---------------- clobber_abi
+   |                    |
+   |                    generic outputs
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+  --> $DIR/bad-options.rs:28:25
+   |
+LL | global_asm!("", options(nomem));
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+  --> $DIR/bad-options.rs:30:25
+   |
+LL | global_asm!("", options(readonly));
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+  --> $DIR/bad-options.rs:32:25
+   |
+LL | global_asm!("", options(noreturn));
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+  --> $DIR/bad-options.rs:34:25
+   |
+LL | global_asm!("", options(pure));
+   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+  --> $DIR/bad-options.rs:36:25
+   |
+LL | global_asm!("", options(nostack));
+   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+  --> $DIR/bad-options.rs:38:25
+   |
+LL | global_asm!("", options(preserves_flags));
+   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: invalid ABI for `clobber_abi`
+  --> $DIR/bad-options.rs:20:18
+   |
+LL |         asm!("", clobber_abi("foo"));
+   |                  ^^^^^^^^^^^^^^^^^^
+   |
+   = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/test/ui/asm/aarch64/bad-reg.rs b/src/test/ui/asm/aarch64/bad-reg.rs
new file mode 100644 (file)
index 0000000..22d0499
--- /dev/null
@@ -0,0 +1,59 @@
+// only-aarch64
+// compile-flags: -C target-feature=+fp
+
+#![feature(asm)]
+
+fn main() {
+    let mut foo = 0;
+    let mut bar = 0;
+    unsafe {
+        // Bad register/register class
+
+        asm!("{}", in(foo) foo);
+        //~^ ERROR invalid register class `foo`: unknown register class
+        asm!("", in("foo") foo);
+        //~^ ERROR invalid register `foo`: unknown register
+        asm!("{:z}", in(reg) foo);
+        //~^ ERROR invalid asm template modifier for this register class
+        asm!("{:r}", in(vreg) foo);
+        //~^ ERROR invalid asm template modifier for this register class
+        asm!("{:r}", in(vreg_low16) foo);
+        //~^ ERROR invalid asm template modifier for this register class
+        asm!("{:a}", const 0);
+        //~^ ERROR asm template modifiers are not allowed for `const` arguments
+        asm!("{:a}", sym main);
+        //~^ ERROR asm template modifiers are not allowed for `sym` arguments
+        asm!("", in("x29") foo);
+        //~^ ERROR invalid register `x29`: the frame pointer cannot be used as an operand
+        asm!("", in("sp") foo);
+        //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand
+        asm!("", in("xzr") foo);
+        //~^ ERROR invalid register `xzr`: the zero register cannot be used as an operand
+        asm!("", in("x18") foo);
+        //~^ ERROR invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
+        asm!("", in("x19") foo);
+        //~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
+
+        asm!("", in("p0") foo);
+        //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output
+        asm!("", out("p0") _);
+        asm!("{}", in(preg) foo);
+        //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output
+        asm!("{}", out(preg) _);
+        //~^ ERROR register class `preg` can only be used as a clobber, not as an input or output
+
+        // Explicit register conflicts
+        // (except in/lateout which don't conflict)
+
+        asm!("", in("x0") foo, in("w0") bar);
+        //~^ ERROR register `x0` conflicts with register `x0`
+        asm!("", in("x0") foo, out("x0") bar);
+        //~^ ERROR register `x0` conflicts with register `x0`
+        asm!("", in("w0") foo, lateout("w0") bar);
+        asm!("", in("v0") foo, in("q0") bar);
+        //~^ ERROR register `v0` conflicts with register `v0`
+        asm!("", in("v0") foo, out("q0") bar);
+        //~^ ERROR register `v0` conflicts with register `v0`
+        asm!("", in("v0") foo, lateout("q0") bar);
+    }
+}
diff --git a/src/test/ui/asm/aarch64/bad-reg.stderr b/src/test/ui/asm/aarch64/bad-reg.stderr
new file mode 100644 (file)
index 0000000..091e607
--- /dev/null
@@ -0,0 +1,152 @@
+error: invalid register class `foo`: unknown register class
+  --> $DIR/bad-reg.rs:12:20
+   |
+LL |         asm!("{}", in(foo) foo);
+   |                    ^^^^^^^^^^^
+
+error: invalid register `foo`: unknown register
+  --> $DIR/bad-reg.rs:14:18
+   |
+LL |         asm!("", in("foo") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: invalid asm template modifier for this register class
+  --> $DIR/bad-reg.rs:16:15
+   |
+LL |         asm!("{:z}", in(reg) foo);
+   |               ^^^^   ----------- argument
+   |               |
+   |               template modifier
+   |
+   = note: the `reg` register class supports the following template modifiers: `w`, `x`
+
+error: invalid asm template modifier for this register class
+  --> $DIR/bad-reg.rs:18:15
+   |
+LL |         asm!("{:r}", in(vreg) foo);
+   |               ^^^^   ------------ argument
+   |               |
+   |               template modifier
+   |
+   = note: the `vreg` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v`
+
+error: invalid asm template modifier for this register class
+  --> $DIR/bad-reg.rs:20:15
+   |
+LL |         asm!("{:r}", in(vreg_low16) foo);
+   |               ^^^^   ------------------ argument
+   |               |
+   |               template modifier
+   |
+   = note: the `vreg_low16` register class supports the following template modifiers: `b`, `h`, `s`, `d`, `q`, `v`
+
+error: asm template modifiers are not allowed for `const` arguments
+  --> $DIR/bad-reg.rs:22:15
+   |
+LL |         asm!("{:a}", const 0);
+   |               ^^^^   ------- argument
+   |               |
+   |               template modifier
+
+error: asm template modifiers are not allowed for `sym` arguments
+  --> $DIR/bad-reg.rs:24:15
+   |
+LL |         asm!("{:a}", sym main);
+   |               ^^^^   -------- argument
+   |               |
+   |               template modifier
+
+error: invalid register `x29`: the frame pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:26:18
+   |
+LL |         asm!("", in("x29") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:28:18
+   |
+LL |         asm!("", in("sp") foo);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `xzr`: the zero register cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:30:18
+   |
+LL |         asm!("", in("xzr") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:32:18
+   |
+LL |         asm!("", in("x18") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:34:18
+   |
+LL |         asm!("", in("x19") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: register class `preg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:37:18
+   |
+LL |         asm!("", in("p0") foo);
+   |                  ^^^^^^^^^^^^
+
+error: register class `preg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:40:20
+   |
+LL |         asm!("{}", in(preg) foo);
+   |                    ^^^^^^^^^^^^
+
+error: register class `preg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:42:20
+   |
+LL |         asm!("{}", out(preg) _);
+   |                    ^^^^^^^^^^^
+
+error: register `x0` conflicts with register `x0`
+  --> $DIR/bad-reg.rs:48:32
+   |
+LL |         asm!("", in("x0") foo, in("w0") bar);
+   |                  ------------  ^^^^^^^^^^^^ register `x0`
+   |                  |
+   |                  register `x0`
+
+error: register `x0` conflicts with register `x0`
+  --> $DIR/bad-reg.rs:50:32
+   |
+LL |         asm!("", in("x0") foo, out("x0") bar);
+   |                  ------------  ^^^^^^^^^^^^^ register `x0`
+   |                  |
+   |                  register `x0`
+   |
+help: use `lateout` instead of `out` to avoid conflict
+  --> $DIR/bad-reg.rs:50:18
+   |
+LL |         asm!("", in("x0") foo, out("x0") bar);
+   |                  ^^^^^^^^^^^^
+
+error: register `v0` conflicts with register `v0`
+  --> $DIR/bad-reg.rs:53:32
+   |
+LL |         asm!("", in("v0") foo, in("q0") bar);
+   |                  ------------  ^^^^^^^^^^^^ register `v0`
+   |                  |
+   |                  register `v0`
+
+error: register `v0` conflicts with register `v0`
+  --> $DIR/bad-reg.rs:55:32
+   |
+LL |         asm!("", in("v0") foo, out("q0") bar);
+   |                  ------------  ^^^^^^^^^^^^^ register `v0`
+   |                  |
+   |                  register `v0`
+   |
+help: use `lateout` instead of `out` to avoid conflict
+  --> $DIR/bad-reg.rs:55:18
+   |
+LL |         asm!("", in("v0") foo, out("q0") bar);
+   |                  ^^^^^^^^^^^^
+
+error: aborting due to 19 previous errors
+
diff --git a/src/test/ui/asm/aarch64/const.rs b/src/test/ui/asm/aarch64/const.rs
new file mode 100644 (file)
index 0000000..906dcb0
--- /dev/null
@@ -0,0 +1,42 @@
+// min-llvm-version: 10.0.1
+// only-aarch64
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![feature(asm, global_asm)]
+
+fn const_generic<const X: usize>() -> usize {
+    unsafe {
+        let a: usize;
+        asm!("mov {}, {}", out(reg) a, const X);
+        a
+    }
+}
+
+const fn constfn(x: usize) -> usize {
+    x
+}
+
+fn main() {
+    unsafe {
+        let a: usize;
+        asm!("mov {}, {}", out(reg) a, const 5);
+        assert_eq!(a, 5);
+
+        let b: usize;
+        asm!("mov {}, {}", out(reg) b, const constfn(5));
+        assert_eq!(b, 5);
+
+        let c: usize;
+        asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5));
+        assert_eq!(c, 10);
+    }
+
+    let d = const_generic::<5>();
+    assert_eq!(d, 5);
+}
+
+global_asm!("mov x0, {}", const 5);
+global_asm!("mov x0, {}", const constfn(5));
+global_asm!("mov x0, {}", const constfn(5) + constfn(5));
diff --git a/src/test/ui/asm/aarch64/duplicate-options.fixed b/src/test/ui/asm/aarch64/duplicate-options.fixed
new file mode 100644 (file)
index 0000000..d95c646
--- /dev/null
@@ -0,0 +1,26 @@
+// only-aarch64
+// run-rustfix
+
+#![feature(asm, global_asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(nomem, ));
+        //~^ ERROR the `nomem` option was already provided
+        asm!("", options(preserves_flags, ));
+        //~^ ERROR the `preserves_flags` option was already provided
+        asm!("", options(nostack, preserves_flags), options());
+        //~^ ERROR the `nostack` option was already provided
+        asm!("", options(nostack, ), options(), options());
+        //~^ ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        asm!(
+            "",
+            options(nomem, noreturn),
+            options(preserves_flags, ), //~ ERROR the `noreturn` option was already provided
+            options( nostack), //~ ERROR the `nomem` option was already provided
+            options(), //~ ERROR the `noreturn` option was already provided
+        );
+    }
+}
diff --git a/src/test/ui/asm/aarch64/duplicate-options.rs b/src/test/ui/asm/aarch64/duplicate-options.rs
new file mode 100644 (file)
index 0000000..eec3564
--- /dev/null
@@ -0,0 +1,26 @@
+// only-aarch64
+// run-rustfix
+
+#![feature(asm, global_asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(nomem, nomem));
+        //~^ ERROR the `nomem` option was already provided
+        asm!("", options(preserves_flags, preserves_flags));
+        //~^ ERROR the `preserves_flags` option was already provided
+        asm!("", options(nostack, preserves_flags), options(nostack));
+        //~^ ERROR the `nostack` option was already provided
+        asm!("", options(nostack, nostack), options(nostack), options(nostack));
+        //~^ ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        asm!(
+            "",
+            options(nomem, noreturn),
+            options(preserves_flags, noreturn), //~ ERROR the `noreturn` option was already provided
+            options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+            options(noreturn), //~ ERROR the `noreturn` option was already provided
+        );
+    }
+}
diff --git a/src/test/ui/asm/aarch64/duplicate-options.stderr b/src/test/ui/asm/aarch64/duplicate-options.stderr
new file mode 100644 (file)
index 0000000..5063b0c
--- /dev/null
@@ -0,0 +1,56 @@
+error: the `nomem` option was already provided
+  --> $DIR/duplicate-options.rs:8:33
+   |
+LL |         asm!("", options(nomem, nomem));
+   |                                 ^^^^^ this option was already provided
+
+error: the `preserves_flags` option was already provided
+  --> $DIR/duplicate-options.rs:10:43
+   |
+LL |         asm!("", options(preserves_flags, preserves_flags));
+   |                                           ^^^^^^^^^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:12:61
+   |
+LL |         asm!("", options(nostack, preserves_flags), options(nostack));
+   |                                                             ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:35
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                   ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:53
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                                     ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:71
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                                                       ^^^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+  --> $DIR/duplicate-options.rs:21:38
+   |
+LL |             options(preserves_flags, noreturn),
+   |                                      ^^^^^^^^ this option was already provided
+
+error: the `nomem` option was already provided
+  --> $DIR/duplicate-options.rs:22:21
+   |
+LL |             options(nomem, nostack),
+   |                     ^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+  --> $DIR/duplicate-options.rs:23:21
+   |
+LL |             options(noreturn),
+   |                     ^^^^^^^^ this option was already provided
+
+error: aborting due to 9 previous errors
+
diff --git a/src/test/ui/asm/aarch64/interpolated-idents.rs b/src/test/ui/asm/aarch64/interpolated-idents.rs
new file mode 100644 (file)
index 0000000..1cdf096
--- /dev/null
@@ -0,0 +1,24 @@
+// only-aarch64
+
+#![feature(asm)]
+
+macro_rules! m {
+    ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
+     $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
+     $noreturn:ident $nostack:ident $options:ident) => {
+        unsafe {
+            asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+            //~^ ERROR asm outputs are not allowed with the `noreturn` option
+            const x, sym x,
+            $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack));
+            //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+            //~| ERROR the `pure` and `noreturn` options are mutually exclusive
+        }
+    };
+}
+
+fn main() {
+    m!(in out lateout inout inlateout const sym
+       pure nomem readonly preserves_flags
+       noreturn nostack options);
+}
diff --git a/src/test/ui/asm/aarch64/interpolated-idents.stderr b/src/test/ui/asm/aarch64/interpolated-idents.stderr
new file mode 100644 (file)
index 0000000..d1ab13a
--- /dev/null
@@ -0,0 +1,51 @@
+error: the `nomem` and `readonly` options are mutually exclusive
+  --> $DIR/interpolated-idents.rs:13:13
+   |
+LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | /     m!(in out lateout inout inlateout const sym
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack options);
+   | |_________________________________- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the `pure` and `noreturn` options are mutually exclusive
+  --> $DIR/interpolated-idents.rs:13:13
+   |
+LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | /     m!(in out lateout inout inlateout const sym
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack options);
+   | |_________________________________- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm outputs are not allowed with the `noreturn` option
+  --> $DIR/interpolated-idents.rs:10:32
+   |
+LL |               asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+   |                                  ^^^^^^^^^  ^^^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^^^^^
+...
+LL |       m!(in out lateout inout inlateout const sym
+   |  _____-
+   | |_____|
+   | |_____|
+   | |_____|
+   | |
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack options);
+   | |                                 -
+   | |_________________________________|
+   | |_________________________________in this macro invocation
+   | |_________________________________in this macro invocation
+   | |_________________________________in this macro invocation
+   |                                   in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/asm/aarch64/parse-error.rs b/src/test/ui/asm/aarch64/parse-error.rs
new file mode 100644 (file)
index 0000000..faa5e37
--- /dev/null
@@ -0,0 +1,135 @@
+// only-aarch64
+
+#![feature(asm, global_asm)]
+
+fn main() {
+    let mut foo = 0;
+    let mut bar = 0;
+    unsafe {
+        asm!();
+        //~^ ERROR requires at least a template string argument
+        asm!(foo);
+        //~^ ERROR asm template must be a string literal
+        asm!("{}" foo);
+        //~^ ERROR expected token: `,`
+        asm!("{}", foo);
+        //~^ ERROR expected operand, clobber_abi, options, or additional template string
+        asm!("{}", in foo);
+        //~^ ERROR expected `(`, found `foo`
+        asm!("{}", in(reg foo));
+        //~^ ERROR expected `)`, found `foo`
+        asm!("{}", in(reg));
+        //~^ ERROR expected expression, found end of macro arguments
+        asm!("{}", inout(=) foo => bar);
+        //~^ ERROR expected register class or explicit register
+        asm!("{}", inout(reg) foo =>);
+        //~^ ERROR expected expression, found end of macro arguments
+        asm!("{}", in(reg) foo => bar);
+        //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+        asm!("{}", sym foo + bar);
+        //~^ ERROR argument to `sym` must be a path expression
+        asm!("", options(foo));
+        //~^ ERROR expected one of
+        asm!("", options(nomem foo));
+        //~^ ERROR expected one of
+        asm!("", options(nomem, foo));
+        //~^ ERROR expected one of
+        asm!("{}", options(), const foo);
+        //~^ ERROR arguments are not allowed after options
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", clobber_abi(foo));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi("C" foo));
+        //~^ ERROR expected `)`, found `foo`
+        asm!("", clobber_abi("C", foo));
+        //~^ ERROR expected `)`, found `,`
+        asm!("{}", clobber_abi("C"), const foo);
+        //~^ ERROR arguments are not allowed after clobber_abi
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", options(), clobber_abi("C"));
+        //~^ ERROR clobber_abi is not allowed after options
+        asm!("{}", options(), clobber_abi("C"), const foo);
+        //~^ ERROR clobber_abi is not allowed after options
+        asm!("", clobber_abi("C"), clobber_abi("C"));
+        //~^ ERROR clobber_abi specified multiple times
+        asm!("{a}", a = const foo, a = const bar);
+        //~^ ERROR duplicate argument named `a`
+        //~^^ ERROR argument never used
+        //~^^^ ERROR attempt to use a non-constant value in a constant
+        //~^^^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", a = in("x0") foo);
+        //~^ ERROR explicit register arguments cannot have names
+        asm!("{a}", in("x0") foo, a = const bar);
+        //~^ ERROR named arguments cannot follow explicit register arguments
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("{a}", in("x0") foo, a = const bar);
+        //~^ ERROR named arguments cannot follow explicit register arguments
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("{1}", in("x0") foo, const bar);
+        //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", options(), "");
+        //~^ ERROR expected one of
+        asm!("{}", in(reg) foo, "{}", out(reg) foo);
+        //~^ ERROR expected one of
+        asm!(format!("{{{}}}", 0), in(reg) foo);
+        //~^ ERROR asm template must be a string literal
+        asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+        //~^ ERROR asm template must be a string literal
+        asm!("{}", in(reg) _);
+        //~^ ERROR _ cannot be used for input operands
+        asm!("{}", inout(reg) _);
+        //~^ ERROR _ cannot be used for input operands
+        asm!("{}", inlateout(reg) _);
+        //~^ ERROR _ cannot be used for input operands
+    }
+}
+
+const FOO: i32 = 1;
+const BAR: i32 = 2;
+global_asm!();
+//~^ ERROR requires at least a template string argument
+global_asm!(FOO);
+//~^ ERROR asm template must be a string literal
+global_asm!("{}" FOO);
+//~^ ERROR expected token: `,`
+global_asm!("{}", FOO);
+//~^ ERROR expected operand, options, or additional template string
+global_asm!("{}", const);
+//~^ ERROR expected expression, found end of macro arguments
+global_asm!("{}", const(reg) FOO);
+//~^ ERROR expected one of
+global_asm!("", options(FOO));
+//~^ ERROR expected one of
+global_asm!("", options(nomem FOO));
+//~^ ERROR expected one of
+global_asm!("", options(nomem, FOO));
+//~^ ERROR expected one of
+global_asm!("{}", options(), const FOO);
+//~^ ERROR arguments are not allowed after options
+global_asm!("", clobber_abi(FOO));
+//~^ ERROR expected string literal
+global_asm!("", clobber_abi("C" FOO));
+//~^ ERROR expected `)`, found `FOO`
+global_asm!("", clobber_abi("C", FOO));
+//~^ ERROR expected `)`, found `,`
+global_asm!("{}", clobber_abi("C"), const FOO);
+//~^ ERROR arguments are not allowed after clobber_abi
+//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
+global_asm!("", options(), clobber_abi("C"));
+//~^ ERROR clobber_abi is not allowed after options
+global_asm!("{}", options(), clobber_abi("C"), const FOO);
+//~^ ERROR clobber_abi is not allowed after options
+global_asm!("", clobber_abi("C"), clobber_abi("C"));
+//~^ ERROR clobber_abi specified multiple times
+global_asm!("{a}", a = const FOO, a = const BAR);
+//~^ ERROR duplicate argument named `a`
+//~^^ ERROR argument never used
+global_asm!("", options(), "");
+//~^ ERROR expected one of
+global_asm!("{}", const FOO, "{}", const FOO);
+//~^ ERROR expected one of
+global_asm!(format!("{{{}}}", 0), const FOO);
+//~^ ERROR asm template must be a string literal
+global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
+//~^ ERROR asm template must be a string literal
diff --git a/src/test/ui/asm/aarch64/parse-error.stderr b/src/test/ui/asm/aarch64/parse-error.stderr
new file mode 100644 (file)
index 0000000..7b9fa90
--- /dev/null
@@ -0,0 +1,462 @@
+error: requires at least a template string argument
+  --> $DIR/parse-error.rs:9:9
+   |
+LL |         asm!();
+   |         ^^^^^^^
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:11:14
+   |
+LL |         asm!(foo);
+   |              ^^^
+
+error: expected token: `,`
+  --> $DIR/parse-error.rs:13:19
+   |
+LL |         asm!("{}" foo);
+   |                   ^^^ expected `,`
+
+error: expected operand, clobber_abi, options, or additional template string
+  --> $DIR/parse-error.rs:15:20
+   |
+LL |         asm!("{}", foo);
+   |                    ^^^ expected operand, clobber_abi, options, or additional template string
+
+error: expected `(`, found `foo`
+  --> $DIR/parse-error.rs:17:23
+   |
+LL |         asm!("{}", in foo);
+   |                       ^^^ expected `(`
+
+error: expected `)`, found `foo`
+  --> $DIR/parse-error.rs:19:27
+   |
+LL |         asm!("{}", in(reg foo));
+   |                           ^^^ expected `)`
+
+error: expected expression, found end of macro arguments
+  --> $DIR/parse-error.rs:21:27
+   |
+LL |         asm!("{}", in(reg));
+   |                           ^ expected expression
+
+error: expected register class or explicit register
+  --> $DIR/parse-error.rs:23:26
+   |
+LL |         asm!("{}", inout(=) foo => bar);
+   |                          ^
+
+error: expected expression, found end of macro arguments
+  --> $DIR/parse-error.rs:25:37
+   |
+LL |         asm!("{}", inout(reg) foo =>);
+   |                                     ^ expected expression
+
+error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+  --> $DIR/parse-error.rs:27:32
+   |
+LL |         asm!("{}", in(reg) foo => bar);
+   |                                ^^ expected one of 7 possible tokens
+
+error: argument to `sym` must be a path expression
+  --> $DIR/parse-error.rs:29:24
+   |
+LL |         asm!("{}", sym foo + bar);
+   |                        ^^^^^^^^^
+
+error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+  --> $DIR/parse-error.rs:31:26
+   |
+LL |         asm!("", options(foo));
+   |                          ^^^ expected one of 9 possible tokens
+
+error: expected one of `)` or `,`, found `foo`
+  --> $DIR/parse-error.rs:33:32
+   |
+LL |         asm!("", options(nomem foo));
+   |                                ^^^ expected one of `)` or `,`
+
+error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+  --> $DIR/parse-error.rs:35:33
+   |
+LL |         asm!("", options(nomem, foo));
+   |                                 ^^^ expected one of 9 possible tokens
+
+error: arguments are not allowed after options
+  --> $DIR/parse-error.rs:37:31
+   |
+LL |         asm!("{}", options(), const foo);
+   |                    ---------  ^^^^^^^^^ argument
+   |                    |
+   |                    previous options
+
+error: expected string literal
+  --> $DIR/parse-error.rs:40:30
+   |
+LL |         asm!("", clobber_abi(foo));
+   |                              ^^^ not a string literal
+
+error: expected `)`, found `foo`
+  --> $DIR/parse-error.rs:42:34
+   |
+LL |         asm!("", clobber_abi("C" foo));
+   |                                  ^^^ expected `)`
+
+error: expected `)`, found `,`
+  --> $DIR/parse-error.rs:44:33
+   |
+LL |         asm!("", clobber_abi("C", foo));
+   |                                 ^ expected `)`
+
+error: arguments are not allowed after clobber_abi
+  --> $DIR/parse-error.rs:46:38
+   |
+LL |         asm!("{}", clobber_abi("C"), const foo);
+   |                    ----------------  ^^^^^^^^^ argument
+   |                    |
+   |                    clobber_abi
+
+error: clobber_abi is not allowed after options
+  --> $DIR/parse-error.rs:49:29
+   |
+LL |         asm!("", options(), clobber_abi("C"));
+   |                  ---------  ^^^^^^^^^^^^^^^^
+   |                  |
+   |                  options
+
+error: clobber_abi is not allowed after options
+  --> $DIR/parse-error.rs:51:31
+   |
+LL |         asm!("{}", options(), clobber_abi("C"), const foo);
+   |                    ---------  ^^^^^^^^^^^^^^^^
+   |                    |
+   |                    options
+
+error: clobber_abi specified multiple times
+  --> $DIR/parse-error.rs:53:36
+   |
+LL |         asm!("", clobber_abi("C"), clobber_abi("C"));
+   |                  ----------------  ^^^^^^^^^^^^^^^^
+   |                  |
+   |                  clobber_abi previously specified here
+
+error: duplicate argument named `a`
+  --> $DIR/parse-error.rs:55:36
+   |
+LL |         asm!("{a}", a = const foo, a = const bar);
+   |                     -------------  ^^^^^^^^^^^^^ duplicate argument
+   |                     |
+   |                     previously here
+
+error: argument never used
+  --> $DIR/parse-error.rs:55:36
+   |
+LL |         asm!("{a}", a = const foo, a = const bar);
+   |                                    ^^^^^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
+
+error: explicit register arguments cannot have names
+  --> $DIR/parse-error.rs:60:18
+   |
+LL |         asm!("", a = in("x0") foo);
+   |                  ^^^^^^^^^^^^^^^^
+
+error: named arguments cannot follow explicit register arguments
+  --> $DIR/parse-error.rs:62:35
+   |
+LL |         asm!("{a}", in("x0") foo, a = const bar);
+   |                     ------------  ^^^^^^^^^^^^^ named argument
+   |                     |
+   |                     explicit register argument
+
+error: named arguments cannot follow explicit register arguments
+  --> $DIR/parse-error.rs:65:35
+   |
+LL |         asm!("{a}", in("x0") foo, a = const bar);
+   |                     ------------  ^^^^^^^^^^^^^ named argument
+   |                     |
+   |                     explicit register argument
+
+error: positional arguments cannot follow named arguments or explicit register arguments
+  --> $DIR/parse-error.rs:68:35
+   |
+LL |         asm!("{1}", in("x0") foo, const bar);
+   |                     ------------  ^^^^^^^^^ positional argument
+   |                     |
+   |                     explicit register argument
+
+error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
+  --> $DIR/parse-error.rs:71:29
+   |
+LL |         asm!("", options(), "");
+   |                             ^^ expected one of 9 possible tokens
+
+error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
+  --> $DIR/parse-error.rs:73:33
+   |
+LL |         asm!("{}", in(reg) foo, "{}", out(reg) foo);
+   |                                 ^^^^ expected one of 9 possible tokens
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:75:14
+   |
+LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:77:21
+   |
+LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+   |                     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: _ cannot be used for input operands
+  --> $DIR/parse-error.rs:79:28
+   |
+LL |         asm!("{}", in(reg) _);
+   |                            ^
+
+error: _ cannot be used for input operands
+  --> $DIR/parse-error.rs:81:31
+   |
+LL |         asm!("{}", inout(reg) _);
+   |                               ^
+
+error: _ cannot be used for input operands
+  --> $DIR/parse-error.rs:83:35
+   |
+LL |         asm!("{}", inlateout(reg) _);
+   |                                   ^
+
+error: requires at least a template string argument
+  --> $DIR/parse-error.rs:90:1
+   |
+LL | global_asm!();
+   | ^^^^^^^^^^^^^^
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:92:13
+   |
+LL | global_asm!(FOO);
+   |             ^^^
+
+error: expected token: `,`
+  --> $DIR/parse-error.rs:94:18
+   |
+LL | global_asm!("{}" FOO);
+   |                  ^^^ expected `,`
+
+error: expected operand, options, or additional template string
+  --> $DIR/parse-error.rs:96:19
+   |
+LL | global_asm!("{}", FOO);
+   |                   ^^^ expected operand, options, or additional template string
+
+error: expected expression, found end of macro arguments
+  --> $DIR/parse-error.rs:98:24
+   |
+LL | global_asm!("{}", const);
+   |                        ^ expected expression
+
+error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
+  --> $DIR/parse-error.rs:100:30
+   |
+LL | global_asm!("{}", const(reg) FOO);
+   |                              ^^^ expected one of `,`, `.`, `?`, or an operator
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+  --> $DIR/parse-error.rs:102:25
+   |
+LL | global_asm!("", options(FOO));
+   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+  --> $DIR/parse-error.rs:104:25
+   |
+LL | global_asm!("", options(nomem FOO));
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+  --> $DIR/parse-error.rs:106:25
+   |
+LL | global_asm!("", options(nomem, FOO));
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: arguments are not allowed after options
+  --> $DIR/parse-error.rs:108:30
+   |
+LL | global_asm!("{}", options(), const FOO);
+   |                   ---------  ^^^^^^^^^ argument
+   |                   |
+   |                   previous options
+
+error: expected string literal
+  --> $DIR/parse-error.rs:110:29
+   |
+LL | global_asm!("", clobber_abi(FOO));
+   |                             ^^^ not a string literal
+
+error: expected `)`, found `FOO`
+  --> $DIR/parse-error.rs:112:33
+   |
+LL | global_asm!("", clobber_abi("C" FOO));
+   |                                 ^^^ expected `)`
+
+error: expected `)`, found `,`
+  --> $DIR/parse-error.rs:114:32
+   |
+LL | global_asm!("", clobber_abi("C", FOO));
+   |                                ^ expected `)`
+
+error: arguments are not allowed after clobber_abi
+  --> $DIR/parse-error.rs:116:37
+   |
+LL | global_asm!("{}", clobber_abi("C"), const FOO);
+   |                   ----------------  ^^^^^^^^^ argument
+   |                   |
+   |                   clobber_abi
+
+error: `clobber_abi` cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:116:19
+   |
+LL | global_asm!("{}", clobber_abi("C"), const FOO);
+   |                   ^^^^^^^^^^^^^^^^
+
+error: clobber_abi is not allowed after options
+  --> $DIR/parse-error.rs:119:28
+   |
+LL | global_asm!("", options(), clobber_abi("C"));
+   |                 ---------  ^^^^^^^^^^^^^^^^
+   |                 |
+   |                 options
+
+error: clobber_abi is not allowed after options
+  --> $DIR/parse-error.rs:121:30
+   |
+LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
+   |                   ---------  ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   options
+
+error: clobber_abi specified multiple times
+  --> $DIR/parse-error.rs:123:35
+   |
+LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
+   |                 ----------------  ^^^^^^^^^^^^^^^^
+   |                 |
+   |                 clobber_abi previously specified here
+
+error: duplicate argument named `a`
+  --> $DIR/parse-error.rs:125:35
+   |
+LL | global_asm!("{a}", a = const FOO, a = const BAR);
+   |                    -------------  ^^^^^^^^^^^^^ duplicate argument
+   |                    |
+   |                    previously here
+
+error: argument never used
+  --> $DIR/parse-error.rs:125:35
+   |
+LL | global_asm!("{a}", a = const FOO, a = const BAR);
+   |                                   ^^^^^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
+
+error: expected one of `clobber_abi`, `const`, or `options`, found `""`
+  --> $DIR/parse-error.rs:128:28
+   |
+LL | global_asm!("", options(), "");
+   |                            ^^ expected one of `clobber_abi`, `const`, or `options`
+
+error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
+  --> $DIR/parse-error.rs:130:30
+   |
+LL | global_asm!("{}", const FOO, "{}", const FOO);
+   |                              ^^^^ expected one of `clobber_abi`, `const`, or `options`
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:132:13
+   |
+LL | global_asm!(format!("{{{}}}", 0), const FOO);
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:134:20
+   |
+LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
+   |                    ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:37:37
+   |
+LL |     let mut foo = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL |         asm!("{}", options(), const foo);
+   |                                     ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:46:44
+   |
+LL |     let mut foo = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL |         asm!("{}", clobber_abi("C"), const foo);
+   |                                            ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:55:31
+   |
+LL |     let mut foo = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL |         asm!("{a}", a = const foo, a = const bar);
+   |                               ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:55:46
+   |
+LL |     let mut bar = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{a}", a = const foo, a = const bar);
+   |                                              ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:62:45
+   |
+LL |     let mut bar = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{a}", in("x0") foo, a = const bar);
+   |                                             ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:65:45
+   |
+LL |     let mut bar = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{a}", in("x0") foo, a = const bar);
+   |                                             ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:68:41
+   |
+LL |     let mut bar = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{1}", in("x0") foo, const bar);
+   |                                         ^^^ non-constant value
+
+error: aborting due to 66 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
diff --git a/src/test/ui/asm/aarch64/srcloc.rs b/src/test/ui/asm/aarch64/srcloc.rs
new file mode 100644 (file)
index 0000000..58feb52
--- /dev/null
@@ -0,0 +1,121 @@
+// min-llvm-version: 10.0.1
+// only-aarch64
+// build-fail
+// compile-flags: -Ccodegen-units=1
+#![feature(asm)]
+
+// Checks that inline asm errors are mapped to the correct line in the source code.
+
+fn main() {
+    unsafe {
+        asm!("invalid_instruction");
+        //~^ ERROR: unrecognized instruction mnemonic
+
+        asm!("
+            invalid_instruction
+        ");
+        //~^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(r#"
+            invalid_instruction
+        "#);
+        //~^^ ERROR: unrecognized instruction mnemonic
+
+        asm!("
+            mov x0, x0
+            invalid_instruction
+            mov x0, x0
+        ");
+        //~^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(r#"
+            mov x0, x0
+            invalid_instruction
+            mov x0, x0
+        "#);
+        //~^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(concat!("invalid", "_", "instruction"));
+        //~^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            "invalid_instruction",
+        );
+        //~^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            "mov x0, x0",
+            "invalid_instruction",
+            "mov x0, x0",
+        );
+        //~^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            "mov x0, x0\n",
+            "invalid_instruction",
+            "mov x0, x0",
+        );
+        //~^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            "mov x0, x0",
+            concat!("invalid", "_", "instruction"),
+            "mov x0, x0",
+        );
+        //~^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            concat!("mov x0", ", ", "x0"),
+            concat!("invalid", "_", "instruction"),
+            concat!("mov x0", ", ", "x0"),
+        );
+        //~^^^ ERROR: unrecognized instruction mnemonic
+
+        // Make sure template strings get separated
+        asm!(
+            "invalid_instruction1",
+            "invalid_instruction2",
+        );
+        //~^^^ ERROR: unrecognized instruction mnemonic
+        //~^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2",
+            ),
+        );
+        //~^^^^^ ERROR: unrecognized instruction mnemonic
+        //~^^^^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2",
+            ),
+            concat!(
+                "invalid", "_", "instruction3", "\n",
+                "invalid", "_", "instruction4",
+            ),
+        );
+        //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic
+        //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic
+        //~^^^^^^^ ERROR: unrecognized instruction mnemonic
+        //~^^^^^^^^ ERROR: unrecognized instruction mnemonic
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2", "\n",
+            ),
+            concat!(
+                "invalid", "_", "instruction3", "\n",
+                "invalid", "_", "instruction4", "\n",
+            ),
+        );
+        //~^^^^^^^^^ ERROR: unrecognized instruction mnemonic
+        //~^^^^^^^^^^ ERROR: unrecognized instruction mnemonic
+        //~^^^^^^^ ERROR: unrecognized instruction mnemonic
+        //~^^^^^^^^ ERROR: unrecognized instruction mnemonic
+    }
+}
diff --git a/src/test/ui/asm/aarch64/srcloc.stderr b/src/test/ui/asm/aarch64/srcloc.stderr
new file mode 100644 (file)
index 0000000..96dab1b
--- /dev/null
@@ -0,0 +1,278 @@
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:11:15
+   |
+LL |         asm!("invalid_instruction");
+   |               ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:2
+   |
+LL |     invalid_instruction
+   |     ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:15:13
+   |
+LL |             invalid_instruction
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:13
+   |
+LL |             invalid_instruction
+   |             ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:20:13
+   |
+LL |             invalid_instruction
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:13
+   |
+LL |             invalid_instruction
+   |             ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:26:13
+   |
+LL |             invalid_instruction
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:13
+   |
+LL |             invalid_instruction
+   |             ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:33:13
+   |
+LL |             invalid_instruction
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:13
+   |
+LL |             invalid_instruction
+   |             ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:38:14
+   |
+LL |         asm!(concat!("invalid", "_", "instruction"));
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:2
+   |
+LL |     invalid_instruction
+   |     ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:42:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:2
+   |
+LL |     invalid_instruction
+   |     ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:48:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:1
+   |
+LL | invalid_instruction
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:55:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:62:13
+   |
+LL |             concat!("invalid", "_", "instruction"),
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:1
+   |
+LL | invalid_instruction
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:69:13
+   |
+LL |             concat!("invalid", "_", "instruction"),
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:1
+   |
+LL | invalid_instruction
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:76:14
+   |
+LL |             "invalid_instruction1",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:2
+   |
+LL |     invalid_instruction1
+   |     ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:77:14
+   |
+LL |             "invalid_instruction2",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:1
+   |
+LL | invalid_instruction2
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:83:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:2
+   |
+LL |     invalid_instruction1
+   |     ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:83:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:1
+   |
+LL | invalid_instruction2
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:92:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:2
+   |
+LL |     invalid_instruction1
+   |     ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:92:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:1
+   |
+LL | invalid_instruction2
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:96:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction3
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:96:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:1
+   |
+LL | invalid_instruction4
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:107:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:2
+   |
+LL |     invalid_instruction1
+   |     ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:107:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:1
+   |
+LL | invalid_instruction2
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:111:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:1
+   |
+LL | invalid_instruction3
+   | ^
+
+error: unrecognized instruction mnemonic
+  --> $DIR/srcloc.rs:111:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:5:1
+   |
+LL | invalid_instruction4
+   | ^
+
+error: aborting due to 23 previous errors
+
diff --git a/src/test/ui/asm/aarch64/sym.rs b/src/test/ui/asm/aarch64/sym.rs
new file mode 100644 (file)
index 0000000..db732e9
--- /dev/null
@@ -0,0 +1,80 @@
+// min-llvm-version: 10.0.1
+// only-aarch64
+// only-linux
+// run-pass
+
+#![feature(asm, thread_local)]
+
+extern "C" fn f1() -> i32 {
+    111
+}
+
+// The compiler will generate a shim to hide the caller location parameter.
+#[track_caller]
+fn f2() -> i32 {
+    222
+}
+
+macro_rules! call {
+    ($func:path) => {
+        unsafe {
+            let result: i32;
+            asm!("bl {}", sym $func,
+                out("w0") result,
+                out("x20") _, out("x21") _, out("x22") _,
+                out("x23") _, out("x24") _, out("x25") _,
+                out("x26") _, out("x27") _, out("x28") _,
+            );
+            result
+        }
+    }
+}
+
+macro_rules! static_addr {
+    ($s:expr) => {
+        unsafe {
+            let result: *const u32;
+            asm!(
+                // ADRP gives the address of a 4KB page from a PC-relative address
+                "adrp {out}, {sym}",
+                // We then add the remaining lower 12 bits
+                "add {out}, {out}, #:lo12:{sym}",
+                out = out(reg) result,
+                sym = sym $s);
+            result
+        }
+    }
+}
+macro_rules! static_tls_addr {
+    ($s:expr) => {
+        unsafe {
+            let result: *const u32;
+            asm!(
+                // Load the thread pointer register
+                "mrs {out}, TPIDR_EL0",
+                // Add the top 12 bits of the symbol's offset
+                "add {out}, {out}, :tprel_hi12:{sym}",
+                // And the bottom 12 bits
+                "add {out}, {out}, :tprel_lo12:{sym}",
+                out = out(reg) result,
+                sym = sym $s
+            );
+            result
+        }
+    }
+}
+
+static S1: u32 = 111;
+#[thread_local]
+static S2: u32 = 222;
+
+fn main() {
+    assert_eq!(call!(f1), 111);
+    assert_eq!(call!(f2), 222);
+    assert_eq!(static_addr!(S1), &S1 as *const u32);
+    assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
+    std::thread::spawn(|| {
+        assert_eq!(static_addr!(S1), &S1 as *const u32);
+        assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
+    }).join().unwrap();
+}
diff --git a/src/test/ui/asm/aarch64/type-check-2.rs b/src/test/ui/asm/aarch64/type-check-2.rs
new file mode 100644 (file)
index 0000000..cf25dcb
--- /dev/null
@@ -0,0 +1,84 @@
+// only-aarch64
+
+#![feature(asm, repr_simd, never_type)]
+
+#[repr(simd)]
+#[derive(Clone, Copy)]
+struct SimdType(f32, f32, f32, f32);
+
+#[repr(simd)]
+struct SimdNonCopy(f32, f32, f32, f32);
+
+fn main() {
+    unsafe {
+        // Inputs must be initialized
+
+        let x: u64;
+        asm!("{}", in(reg) x);
+        //~^ ERROR use of possibly-uninitialized variable: `x`
+        let mut y: u64;
+        asm!("{}", inout(reg) y);
+        //~^ ERROR use of possibly-uninitialized variable: `y`
+        let _ = y;
+
+        // Outputs require mutable places
+
+        let v: Vec<u64> = vec![0, 1, 2];
+        asm!("{}", in(reg) v[0]);
+        asm!("{}", out(reg) v[0]);
+        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+        asm!("{}", inout(reg) v[0]);
+        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+
+        // Sym operands must point to a function or static
+
+        const C: i32 = 0;
+        static S: i32 = 0;
+        asm!("{}", sym S);
+        asm!("{}", sym main);
+        asm!("{}", sym C);
+        //~^ ERROR asm `sym` operand must point to a fn or static
+        asm!("{}", sym x);
+        //~^ ERROR asm `sym` operand must point to a fn or static
+
+        // Register operands must be Copy
+
+        asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
+        //~^ ERROR arguments for inline assembly must be copyable
+
+        // Register operands must be integers, floats, SIMD vectors, pointers or
+        // function pointers.
+
+        asm!("{}", in(reg) 0i64);
+        asm!("{}", in(reg) 0f64);
+        asm!("{:v}", in(vreg) SimdType(0.0, 0.0, 0.0, 0.0));
+        asm!("{}", in(reg) 0 as *const u8);
+        asm!("{}", in(reg) 0 as *mut u8);
+        asm!("{}", in(reg) main as fn());
+        asm!("{}", in(reg) |x: i32| x);
+        //~^ ERROR cannot use value of type
+        asm!("{}", in(reg) vec![0]);
+        //~^ ERROR cannot use value of type `Vec<i32>` for inline assembly
+        asm!("{}", in(reg) (1, 2, 3));
+        //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly
+        asm!("{}", in(reg) [1, 2, 3]);
+        //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly
+
+        // Register inputs (but not outputs) allow references and function types
+
+        let mut f = main;
+        let mut r = &mut 0;
+        asm!("{}", in(reg) f);
+        asm!("{}", inout(reg) f);
+        //~^ ERROR cannot use value of type `fn() {main}` for inline assembly
+        asm!("{}", in(reg) r);
+        asm!("{}", inout(reg) r);
+        //~^ ERROR cannot use value of type `&mut i32` for inline assembly
+        let _ = (f, r);
+
+        // Type checks ignore never type
+
+        let u: ! = unreachable!();
+        asm!("{}", in(reg) u);
+    }
+}
diff --git a/src/test/ui/asm/aarch64/type-check-2.stderr b/src/test/ui/asm/aarch64/type-check-2.stderr
new file mode 100644 (file)
index 0000000..e820906
--- /dev/null
@@ -0,0 +1,103 @@
+error: arguments for inline assembly must be copyable
+  --> $DIR/type-check-2.rs:46:31
+   |
+LL |         asm!("{:v}", in(vreg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
+   |                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `SimdNonCopy` does not implement the Copy trait
+
+error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly
+  --> $DIR/type-check-2.rs:58:28
+   |
+LL |         asm!("{}", in(reg) |x: i32| x);
+   |                            ^^^^^^^^^^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `Vec<i32>` for inline assembly
+  --> $DIR/type-check-2.rs:60:28
+   |
+LL |         asm!("{}", in(reg) vec![0]);
+   |                            ^^^^^^^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot use value of type `(i32, i32, i32)` for inline assembly
+  --> $DIR/type-check-2.rs:62:28
+   |
+LL |         asm!("{}", in(reg) (1, 2, 3));
+   |                            ^^^^^^^^^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `[i32; 3]` for inline assembly
+  --> $DIR/type-check-2.rs:64:28
+   |
+LL |         asm!("{}", in(reg) [1, 2, 3]);
+   |                            ^^^^^^^^^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `fn() {main}` for inline assembly
+  --> $DIR/type-check-2.rs:72:31
+   |
+LL |         asm!("{}", inout(reg) f);
+   |                               ^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `&mut i32` for inline assembly
+  --> $DIR/type-check-2.rs:75:31
+   |
+LL |         asm!("{}", inout(reg) r);
+   |                               ^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: asm `sym` operand must point to a fn or static
+  --> $DIR/type-check-2.rs:39:24
+   |
+LL |         asm!("{}", sym C);
+   |                        ^
+
+error: asm `sym` operand must point to a fn or static
+  --> $DIR/type-check-2.rs:41:24
+   |
+LL |         asm!("{}", sym x);
+   |                        ^
+
+error[E0381]: use of possibly-uninitialized variable: `x`
+  --> $DIR/type-check-2.rs:17:28
+   |
+LL |         asm!("{}", in(reg) x);
+   |                            ^ use of possibly-uninitialized `x`
+
+error[E0381]: use of possibly-uninitialized variable: `y`
+  --> $DIR/type-check-2.rs:20:9
+   |
+LL |         asm!("{}", inout(reg) y);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
+
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/type-check-2.rs:28:29
+   |
+LL |         let v: Vec<u64> = vec![0, 1, 2];
+   |             - help: consider changing this to be mutable: `mut v`
+LL |         asm!("{}", in(reg) v[0]);
+LL |         asm!("{}", out(reg) v[0]);
+   |                             ^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/type-check-2.rs:30:31
+   |
+LL |         let v: Vec<u64> = vec![0, 1, 2];
+   |             - help: consider changing this to be mutable: `mut v`
+...
+LL |         asm!("{}", inout(reg) v[0]);
+   |                               ^ cannot borrow as mutable
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0381, E0596.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/asm/aarch64/type-check-3.rs b/src/test/ui/asm/aarch64/type-check-3.rs
new file mode 100644 (file)
index 0000000..d0d5954
--- /dev/null
@@ -0,0 +1,115 @@
+// only-aarch64
+// compile-flags: -C target-feature=+neon
+
+#![feature(asm, global_asm, repr_simd, stdsimd)]
+
+use std::arch::aarch64::float64x2_t;
+
+#[repr(simd)]
+#[derive(Copy, Clone)]
+struct Simd256bit(f64, f64,f64, f64);
+
+fn main() {
+    let f64x2: float64x2_t = unsafe { std::mem::transmute(0i128) };
+    let f64x4 = Simd256bit(0.0, 0.0, 0.0, 0.0);
+
+    unsafe {
+        // Types must be listed in the register class.
+
+        // Success cases
+        asm!("{:w}", in(reg) 0u8);
+        asm!("{:w}", in(reg) 0u16);
+        asm!("{:w}", in(reg) 0u32);
+        asm!("{:w}", in(reg) 0f32);
+        asm!("{}", in(reg) 0i64);
+        asm!("{}", in(reg) 0f64);
+
+        asm!("{:b}", in(vreg) 0u8);
+        asm!("{:h}", in(vreg) 0u16);
+        asm!("{:s}", in(vreg) 0u32);
+        asm!("{:s}", in(vreg) 0f32);
+        asm!("{:d}", in(vreg) 0u64);
+        asm!("{:d}", in(vreg) 0f64);
+        asm!("{:q}", in(vreg) f64x2);
+        asm!("{:v}", in(vreg) f64x2);
+
+        // Should be the same as vreg
+        asm!("{:q}", in(vreg_low16) f64x2);
+
+        // Template modifiers of a different size to the argument are fine
+        asm!("{:w}", in(reg) 0u64);
+        asm!("{:x}", in(reg) 0u32);
+        asm!("{:b}", in(vreg) 0u64);
+        asm!("{:d}", in(vreg_low16) f64x2);
+
+
+        // Template modifier suggestions for sub-registers
+
+        asm!("{}", in(reg) 0u8);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(reg) 0u16);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(reg) 0i32);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(reg) 0f32);
+        //~^ WARN formatting may not be suitable for sub-register argument
+
+        asm!("{}", in(vreg) 0i16);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(vreg) 0f32);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(vreg) 0f64);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(vreg_low16) 0f64);
+        //~^ WARN formatting may not be suitable for sub-register argument
+
+        asm!("{0} {0}", in(reg) 0i16);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{0} {0:x}", in(reg) 0i16);
+        //~^ WARN formatting may not be suitable for sub-register argument
+
+        // Invalid registers
+
+        asm!("{}", in(reg) 0i128);
+        //~^ ERROR type `i128` cannot be used with this register class
+        asm!("{}", in(reg) f64x2);
+        //~^ ERROR type `float64x2_t` cannot be used with this register class
+        asm!("{}", in(vreg) f64x4);
+        //~^ ERROR type `Simd256bit` cannot be used with this register class
+
+        // Split inout operands must have compatible types
+
+        let mut val_i16: i16;
+        let mut val_f32: f32;
+        let mut val_u32: u32;
+        let mut val_u64: u64;
+        let mut val_ptr: *mut u8;
+        asm!("{:x}", inout(reg) 0u16 => val_i16);
+        asm!("{:x}", inout(reg) 0u32 => val_f32);
+        //~^ ERROR incompatible types for asm inout argument
+        asm!("{:x}", inout(reg) 0u32 => val_ptr);
+        //~^ ERROR incompatible types for asm inout argument
+        asm!("{:x}", inout(reg) main => val_u32);
+        //~^ ERROR incompatible types for asm inout argument
+        asm!("{:x}", inout(reg) 0u64 => val_ptr);
+        asm!("{:x}", inout(reg) main => val_u64);
+    }
+}
+
+// Constants must be... constant
+
+static S: i32 = 1;
+const fn const_foo(x: i32) -> i32 {
+    x
+}
+const fn const_bar<T>(x: T) -> T {
+    x
+}
+global_asm!("{}", const S);
+//~^ ERROR constants cannot refer to statics
+global_asm!("{}", const const_foo(0));
+global_asm!("{}", const const_foo(S));
+//~^ ERROR constants cannot refer to statics
+global_asm!("{}", const const_bar(0));
+global_asm!("{}", const const_bar(S));
+//~^ ERROR constants cannot refer to statics
diff --git a/src/test/ui/asm/aarch64/type-check-3.stderr b/src/test/ui/asm/aarch64/type-check-3.stderr
new file mode 100644 (file)
index 0000000..c31a62a
--- /dev/null
@@ -0,0 +1,172 @@
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:48:15
+   |
+LL |         asm!("{}", in(reg) 0u8);
+   |               ^^           --- for this argument
+   |
+   = note: `#[warn(asm_sub_register)]` on by default
+   = help: use the `w` modifier to have the register formatted as `w0`
+   = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:50:15
+   |
+LL |         asm!("{}", in(reg) 0u16);
+   |               ^^           ---- for this argument
+   |
+   = help: use the `w` modifier to have the register formatted as `w0`
+   = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:52:15
+   |
+LL |         asm!("{}", in(reg) 0i32);
+   |               ^^           ---- for this argument
+   |
+   = help: use the `w` modifier to have the register formatted as `w0`
+   = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:54:15
+   |
+LL |         asm!("{}", in(reg) 0f32);
+   |               ^^           ---- for this argument
+   |
+   = help: use the `w` modifier to have the register formatted as `w0`
+   = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:57:15
+   |
+LL |         asm!("{}", in(vreg) 0i16);
+   |               ^^            ---- for this argument
+   |
+   = help: use the `h` modifier to have the register formatted as `h0`
+   = help: or use the `v` modifier to keep the default formatting of `v0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:59:15
+   |
+LL |         asm!("{}", in(vreg) 0f32);
+   |               ^^            ---- for this argument
+   |
+   = help: use the `s` modifier to have the register formatted as `s0`
+   = help: or use the `v` modifier to keep the default formatting of `v0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:61:15
+   |
+LL |         asm!("{}", in(vreg) 0f64);
+   |               ^^            ---- for this argument
+   |
+   = help: use the `d` modifier to have the register formatted as `d0`
+   = help: or use the `v` modifier to keep the default formatting of `v0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:63:15
+   |
+LL |         asm!("{}", in(vreg_low16) 0f64);
+   |               ^^                  ---- for this argument
+   |
+   = help: use the `d` modifier to have the register formatted as `d0`
+   = help: or use the `v` modifier to keep the default formatting of `v0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:66:15
+   |
+LL |         asm!("{0} {0}", in(reg) 0i16);
+   |               ^^^ ^^^           ---- for this argument
+   |
+   = help: use the `w` modifier to have the register formatted as `w0`
+   = help: or use the `x` modifier to keep the default formatting of `x0`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:68:15
+   |
+LL |         asm!("{0} {0:x}", in(reg) 0i16);
+   |               ^^^                 ---- for this argument
+   |
+   = help: use the `w` modifier to have the register formatted as `w0`
+   = help: or use the `x` modifier to keep the default formatting of `x0`
+
+error: type `i128` cannot be used with this register class
+  --> $DIR/type-check-3.rs:73:28
+   |
+LL |         asm!("{}", in(reg) 0i128);
+   |                            ^^^^^
+   |
+   = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
+
+error: type `float64x2_t` cannot be used with this register class
+  --> $DIR/type-check-3.rs:75:28
+   |
+LL |         asm!("{}", in(reg) f64x2);
+   |                            ^^^^^
+   |
+   = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64
+
+error: type `Simd256bit` cannot be used with this register class
+  --> $DIR/type-check-3.rs:77:29
+   |
+LL |         asm!("{}", in(vreg) f64x4);
+   |                             ^^^^^
+   |
+   = note: register class `vreg` supports these types: i8, i16, i32, i64, f32, f64, i8x8, i16x4, i32x2, i64x1, f32x2, f64x1, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
+
+error: incompatible types for asm inout argument
+  --> $DIR/type-check-3.rs:88:33
+   |
+LL |         asm!("{:x}", inout(reg) 0u32 => val_f32);
+   |                                 ^^^^    ^^^^^^^ type `f32`
+   |                                 |
+   |                                 type `u32`
+   |
+   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error: incompatible types for asm inout argument
+  --> $DIR/type-check-3.rs:90:33
+   |
+LL |         asm!("{:x}", inout(reg) 0u32 => val_ptr);
+   |                                 ^^^^    ^^^^^^^ type `*mut u8`
+   |                                 |
+   |                                 type `u32`
+   |
+   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error: incompatible types for asm inout argument
+  --> $DIR/type-check-3.rs:92:33
+   |
+LL |         asm!("{:x}", inout(reg) main => val_u32);
+   |                                 ^^^^    ^^^^^^^ type `u32`
+   |                                 |
+   |                                 type `fn()`
+   |
+   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/type-check-3.rs:108:25
+   |
+LL | global_asm!("{}", const S);
+   |                         ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/type-check-3.rs:111:35
+   |
+LL | global_asm!("{}", const const_foo(S));
+   |                                   ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/type-check-3.rs:114:35
+   |
+LL | global_asm!("{}", const const_bar(S));
+   |                                   ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error: aborting due to 9 previous errors; 10 warnings emitted
+
+For more information about this error, try `rustc --explain E0013`.
diff --git a/src/test/ui/asm/bad-options.rs b/src/test/ui/asm/bad-options.rs
deleted file mode 100644 (file)
index dc61d16..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-// only-x86_64
-
-#![feature(asm, global_asm)]
-
-fn main() {
-    let mut foo = 0;
-    unsafe {
-        asm!("", options(nomem, readonly));
-        //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
-        asm!("", options(pure, nomem, noreturn));
-        //~^ ERROR the `pure` and `noreturn` options are mutually exclusive
-        //~^^ ERROR asm with the `pure` option must have at least one output
-        asm!("{}", in(reg) foo, options(pure, nomem));
-        //~^ ERROR asm with the `pure` option must have at least one output
-        asm!("{}", out(reg) foo, options(noreturn));
-        //~^ ERROR asm outputs are not allowed with the `noreturn` option
-    }
-
-    unsafe {
-        asm!("", clobber_abi("foo"));
-        //~^ ERROR invalid ABI for `clobber_abi`
-        asm!("{}", out(reg) foo, clobber_abi("C"));
-        //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
-        asm!("", out("eax") foo, clobber_abi("C"));
-    }
-}
-
-global_asm!("", options(nomem));
-//~^ ERROR expected one of
-global_asm!("", options(readonly));
-//~^ ERROR expected one of
-global_asm!("", options(noreturn));
-//~^ ERROR expected one of
-global_asm!("", options(pure));
-//~^ ERROR expected one of
-global_asm!("", options(nostack));
-//~^ ERROR expected one of
-global_asm!("", options(preserves_flags));
-//~^ ERROR expected one of
diff --git a/src/test/ui/asm/bad-options.stderr b/src/test/ui/asm/bad-options.stderr
deleted file mode 100644 (file)
index 8cfd450..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-error: the `nomem` and `readonly` options are mutually exclusive
-  --> $DIR/bad-options.rs:8:18
-   |
-LL |         asm!("", options(nomem, readonly));
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: the `pure` and `noreturn` options are mutually exclusive
-  --> $DIR/bad-options.rs:10:18
-   |
-LL |         asm!("", options(pure, nomem, noreturn));
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: asm with the `pure` option must have at least one output
-  --> $DIR/bad-options.rs:10:18
-   |
-LL |         asm!("", options(pure, nomem, noreturn));
-   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: asm with the `pure` option must have at least one output
-  --> $DIR/bad-options.rs:13:33
-   |
-LL |         asm!("{}", in(reg) foo, options(pure, nomem));
-   |                                 ^^^^^^^^^^^^^^^^^^^^
-
-error: asm outputs are not allowed with the `noreturn` option
-  --> $DIR/bad-options.rs:15:20
-   |
-LL |         asm!("{}", out(reg) foo, options(noreturn));
-   |                    ^^^^^^^^^^^^
-
-error: asm with `clobber_abi` must specify explicit registers for outputs
-  --> $DIR/bad-options.rs:22:20
-   |
-LL |         asm!("{}", out(reg) foo, clobber_abi("C"));
-   |                    ^^^^^^^^^^^^  ---------------- clobber_abi
-   |                    |
-   |                    generic outputs
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/bad-options.rs:28:25
-   |
-LL | global_asm!("", options(nomem));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
-  --> $DIR/bad-options.rs:30:25
-   |
-LL | global_asm!("", options(readonly));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
-  --> $DIR/bad-options.rs:32:25
-   |
-LL | global_asm!("", options(noreturn));
-   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
-  --> $DIR/bad-options.rs:34:25
-   |
-LL | global_asm!("", options(pure));
-   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
-  --> $DIR/bad-options.rs:36:25
-   |
-LL | global_asm!("", options(nostack));
-   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
-  --> $DIR/bad-options.rs:38:25
-   |
-LL | global_asm!("", options(preserves_flags));
-   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: invalid ABI for `clobber_abi`
-  --> $DIR/bad-options.rs:20:18
-   |
-LL |         asm!("", clobber_abi("foo"));
-   |                  ^^^^^^^^^^^^^^^^^^
-   |
-   = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
-
-error: aborting due to 13 previous errors
-
diff --git a/src/test/ui/asm/bad-reg.rs b/src/test/ui/asm/bad-reg.rs
deleted file mode 100644 (file)
index 06af08f..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-// only-x86_64
-// compile-flags: -C target-feature=+avx2
-
-#![feature(asm)]
-
-fn main() {
-    let mut foo = 0;
-    let mut bar = 0;
-    unsafe {
-        // Bad register/register class
-
-        asm!("{}", in(foo) foo);
-        //~^ ERROR invalid register class `foo`: unknown register class
-        asm!("", in("foo") foo);
-        //~^ ERROR invalid register `foo`: unknown register
-        asm!("{:z}", in(reg) foo);
-        //~^ ERROR invalid asm template modifier for this register class
-        asm!("{:r}", in(xmm_reg) foo);
-        //~^ ERROR invalid asm template modifier for this register class
-        asm!("{:a}", const 0);
-        //~^ ERROR asm template modifiers are not allowed for `const` arguments
-        asm!("{:a}", sym main);
-        //~^ ERROR asm template modifiers are not allowed for `sym` arguments
-        asm!("{}", in(zmm_reg) foo);
-        //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
-        asm!("", in("zmm0") foo);
-        //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
-        asm!("", in("ebp") foo);
-        //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand
-        asm!("", in("rsp") foo);
-        //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
-        asm!("", in("ip") foo);
-        //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
-        asm!("", in("k0") foo);
-        //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
-        asm!("", in("ah") foo);
-        //~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand
-
-        asm!("", in("st(2)") foo);
-        //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
-        asm!("", in("mm0") foo);
-        //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
-        asm!("", out("st(2)") _);
-        asm!("", out("mm0") _);
-        asm!("{}", in(x87_reg) foo);
-        //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
-        asm!("{}", in(mmx_reg) foo);
-        //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
-        asm!("{}", out(x87_reg) _);
-        //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
-        asm!("{}", out(mmx_reg) _);
-        //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
-
-        // Explicit register conflicts
-        // (except in/lateout which don't conflict)
-
-        asm!("", in("eax") foo, in("al") bar);
-        //~^ ERROR register `al` conflicts with register `ax`
-        asm!("", in("rax") foo, out("rax") bar);
-        //~^ ERROR register `ax` conflicts with register `ax`
-        asm!("", in("al") foo, lateout("al") bar);
-        asm!("", in("xmm0") foo, in("ymm0") bar);
-        //~^ ERROR register `ymm0` conflicts with register `xmm0`
-        asm!("", in("xmm0") foo, out("ymm0") bar);
-        //~^ ERROR register `ymm0` conflicts with register `xmm0`
-        asm!("", in("xmm0") foo, lateout("ymm0") bar);
-    }
-}
diff --git a/src/test/ui/asm/bad-reg.stderr b/src/test/ui/asm/bad-reg.stderr
deleted file mode 100644 (file)
index 14740bf..0000000
+++ /dev/null
@@ -1,172 +0,0 @@
-error: invalid register class `foo`: unknown register class
-  --> $DIR/bad-reg.rs:12:20
-   |
-LL |         asm!("{}", in(foo) foo);
-   |                    ^^^^^^^^^^^
-
-error: invalid register `foo`: unknown register
-  --> $DIR/bad-reg.rs:14:18
-   |
-LL |         asm!("", in("foo") foo);
-   |                  ^^^^^^^^^^^^^
-
-error: invalid asm template modifier for this register class
-  --> $DIR/bad-reg.rs:16:15
-   |
-LL |         asm!("{:z}", in(reg) foo);
-   |               ^^^^   ----------- argument
-   |               |
-   |               template modifier
-   |
-   = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r`
-
-error: invalid asm template modifier for this register class
-  --> $DIR/bad-reg.rs:18:15
-   |
-LL |         asm!("{:r}", in(xmm_reg) foo);
-   |               ^^^^   --------------- argument
-   |               |
-   |               template modifier
-   |
-   = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z`
-
-error: asm template modifiers are not allowed for `const` arguments
-  --> $DIR/bad-reg.rs:20:15
-   |
-LL |         asm!("{:a}", const 0);
-   |               ^^^^   ------- argument
-   |               |
-   |               template modifier
-
-error: asm template modifiers are not allowed for `sym` arguments
-  --> $DIR/bad-reg.rs:22:15
-   |
-LL |         asm!("{:a}", sym main);
-   |               ^^^^   -------- argument
-   |               |
-   |               template modifier
-
-error: register class `zmm_reg` requires the `avx512f` target feature
-  --> $DIR/bad-reg.rs:24:20
-   |
-LL |         asm!("{}", in(zmm_reg) foo);
-   |                    ^^^^^^^^^^^^^^^
-
-error: register class `zmm_reg` requires the `avx512f` target feature
-  --> $DIR/bad-reg.rs:26:18
-   |
-LL |         asm!("", in("zmm0") foo);
-   |                  ^^^^^^^^^^^^^^
-
-error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:28:18
-   |
-LL |         asm!("", in("ebp") foo);
-   |                  ^^^^^^^^^^^^^
-
-error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:30:18
-   |
-LL |         asm!("", in("rsp") foo);
-   |                  ^^^^^^^^^^^^^
-
-error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:32:18
-   |
-LL |         asm!("", in("ip") foo);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:34:18
-   |
-LL |         asm!("", in("k0") foo);
-   |                  ^^^^^^^^^^^^
-
-error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
-  --> $DIR/bad-reg.rs:36:18
-   |
-LL |         asm!("", in("ah") foo);
-   |                  ^^^^^^^^^^^^
-
-error: register class `x87_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:39:18
-   |
-LL |         asm!("", in("st(2)") foo);
-   |                  ^^^^^^^^^^^^^^^
-
-error: register class `mmx_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", in("mm0") foo);
-   |                  ^^^^^^^^^^^^^
-
-error: register class `x87_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:45:20
-   |
-LL |         asm!("{}", in(x87_reg) foo);
-   |                    ^^^^^^^^^^^^^^^
-
-error: register class `mmx_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:47:20
-   |
-LL |         asm!("{}", in(mmx_reg) foo);
-   |                    ^^^^^^^^^^^^^^^
-
-error: register class `x87_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:49:20
-   |
-LL |         asm!("{}", out(x87_reg) _);
-   |                    ^^^^^^^^^^^^^^
-
-error: register class `mmx_reg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:51:20
-   |
-LL |         asm!("{}", out(mmx_reg) _);
-   |                    ^^^^^^^^^^^^^^
-
-error: register `al` conflicts with register `ax`
-  --> $DIR/bad-reg.rs:57:33
-   |
-LL |         asm!("", in("eax") foo, in("al") bar);
-   |                  -------------  ^^^^^^^^^^^^ register `al`
-   |                  |
-   |                  register `ax`
-
-error: register `ax` conflicts with register `ax`
-  --> $DIR/bad-reg.rs:59:33
-   |
-LL |         asm!("", in("rax") foo, out("rax") bar);
-   |                  -------------  ^^^^^^^^^^^^^^ register `ax`
-   |                  |
-   |                  register `ax`
-   |
-help: use `lateout` instead of `out` to avoid conflict
-  --> $DIR/bad-reg.rs:59:18
-   |
-LL |         asm!("", in("rax") foo, out("rax") bar);
-   |                  ^^^^^^^^^^^^^
-
-error: register `ymm0` conflicts with register `xmm0`
-  --> $DIR/bad-reg.rs:62:34
-   |
-LL |         asm!("", in("xmm0") foo, in("ymm0") bar);
-   |                  --------------  ^^^^^^^^^^^^^^ register `ymm0`
-   |                  |
-   |                  register `xmm0`
-
-error: register `ymm0` conflicts with register `xmm0`
-  --> $DIR/bad-reg.rs:64:34
-   |
-LL |         asm!("", in("xmm0") foo, out("ymm0") bar);
-   |                  --------------  ^^^^^^^^^^^^^^^ register `ymm0`
-   |                  |
-   |                  register `xmm0`
-   |
-help: use `lateout` instead of `out` to avoid conflict
-  --> $DIR/bad-reg.rs:64:18
-   |
-LL |         asm!("", in("xmm0") foo, out("ymm0") bar);
-   |                  ^^^^^^^^^^^^^^
-
-error: aborting due to 23 previous errors
-
diff --git a/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_mirunsafeck.stderr
new file mode 100644 (file)
index 0000000..3b1d922
--- /dev/null
@@ -0,0 +1,187 @@
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:31:15
+   |
+LL |         asm!("{}");
+   |               ^^ from here
+   |
+   = note: no arguments were given
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:33:15
+   |
+LL |         asm!("{1}", in(reg) foo);
+   |               ^^^ from here
+   |
+   = note: there is 1 argument
+
+error: argument never used
+  --> $DIR/bad-template.rs:33:21
+   |
+LL |         asm!("{1}", in(reg) foo);
+   |                     ^^^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+  --> $DIR/bad-template.rs:36:15
+   |
+LL |         asm!("{a}");
+   |               ^^^
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:38:15
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |               ^^   --------------- named argument
+   |               |
+   |               from here
+   |
+   = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+  --> $DIR/bad-template.rs:38:20
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |                    ^^^^^^^^^^^^^^^
+
+error: named argument never used
+  --> $DIR/bad-template.rs:38:20
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |                    ^^^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:41:15
+   |
+LL |         asm!("{1}", a = in(reg) foo);
+   |               ^^^ from here
+   |
+   = note: no positional arguments were given
+
+error: named argument never used
+  --> $DIR/bad-template.rs:41:21
+   |
+LL |         asm!("{1}", a = in(reg) foo);
+   |                     ^^^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:48:15
+   |
+LL |         asm!("{}", in("x0") foo);
+   |               ^^   ------------ explicit register argument
+   |               |
+   |               from here
+   |
+   = note: no positional arguments were given
+note: explicit register arguments cannot be used in the asm template
+  --> $DIR/bad-template.rs:48:20
+   |
+LL |         asm!("{}", in("x0") foo);
+   |                    ^^^^^^^^^^^^
+
+error: asm template modifier must be a single character
+  --> $DIR/bad-template.rs:50:17
+   |
+LL |         asm!("{:foo}", in(reg) foo);
+   |                 ^^^
+
+error: multiple unused asm arguments
+  --> $DIR/bad-template.rs:52:18
+   |
+LL |         asm!("", in(reg) 0, in(reg) 1);
+   |                  ^^^^^^^^^  ^^^^^^^^^ argument never used
+   |                  |
+   |                  argument never used
+   |
+   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:58:14
+   |
+LL | global_asm!("{}");
+   |              ^^ from here
+   |
+   = note: no arguments were given
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:60:14
+   |
+LL | global_asm!("{1}", const FOO);
+   |              ^^^ from here
+   |
+   = note: there is 1 argument
+
+error: argument never used
+  --> $DIR/bad-template.rs:60:20
+   |
+LL | global_asm!("{1}", const FOO);
+   |                    ^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+  --> $DIR/bad-template.rs:63:14
+   |
+LL | global_asm!("{a}");
+   |              ^^^
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:65:14
+   |
+LL | global_asm!("{}", a = const FOO);
+   |              ^^   ------------- named argument
+   |              |
+   |              from here
+   |
+   = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+  --> $DIR/bad-template.rs:65:19
+   |
+LL | global_asm!("{}", a = const FOO);
+   |                   ^^^^^^^^^^^^^
+
+error: named argument never used
+  --> $DIR/bad-template.rs:65:19
+   |
+LL | global_asm!("{}", a = const FOO);
+   |                   ^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:68:14
+   |
+LL | global_asm!("{1}", a = const FOO);
+   |              ^^^ from here
+   |
+   = note: no positional arguments were given
+
+error: named argument never used
+  --> $DIR/bad-template.rs:68:20
+   |
+LL | global_asm!("{1}", a = const FOO);
+   |                    ^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: asm template modifier must be a single character
+  --> $DIR/bad-template.rs:71:16
+   |
+LL | global_asm!("{:foo}", const FOO);
+   |                ^^^
+
+error: multiple unused asm arguments
+  --> $DIR/bad-template.rs:73:17
+   |
+LL | global_asm!("", const FOO, const FOO);
+   |                 ^^^^^^^^^  ^^^^^^^^^ argument never used
+   |                 |
+   |                 argument never used
+   |
+   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: aborting due to 21 previous errors
+
diff --git a/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.aarch64_thirunsafeck.stderr
new file mode 100644 (file)
index 0000000..3b1d922
--- /dev/null
@@ -0,0 +1,187 @@
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:31:15
+   |
+LL |         asm!("{}");
+   |               ^^ from here
+   |
+   = note: no arguments were given
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:33:15
+   |
+LL |         asm!("{1}", in(reg) foo);
+   |               ^^^ from here
+   |
+   = note: there is 1 argument
+
+error: argument never used
+  --> $DIR/bad-template.rs:33:21
+   |
+LL |         asm!("{1}", in(reg) foo);
+   |                     ^^^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+  --> $DIR/bad-template.rs:36:15
+   |
+LL |         asm!("{a}");
+   |               ^^^
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:38:15
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |               ^^   --------------- named argument
+   |               |
+   |               from here
+   |
+   = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+  --> $DIR/bad-template.rs:38:20
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |                    ^^^^^^^^^^^^^^^
+
+error: named argument never used
+  --> $DIR/bad-template.rs:38:20
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |                    ^^^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:41:15
+   |
+LL |         asm!("{1}", a = in(reg) foo);
+   |               ^^^ from here
+   |
+   = note: no positional arguments were given
+
+error: named argument never used
+  --> $DIR/bad-template.rs:41:21
+   |
+LL |         asm!("{1}", a = in(reg) foo);
+   |                     ^^^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:48:15
+   |
+LL |         asm!("{}", in("x0") foo);
+   |               ^^   ------------ explicit register argument
+   |               |
+   |               from here
+   |
+   = note: no positional arguments were given
+note: explicit register arguments cannot be used in the asm template
+  --> $DIR/bad-template.rs:48:20
+   |
+LL |         asm!("{}", in("x0") foo);
+   |                    ^^^^^^^^^^^^
+
+error: asm template modifier must be a single character
+  --> $DIR/bad-template.rs:50:17
+   |
+LL |         asm!("{:foo}", in(reg) foo);
+   |                 ^^^
+
+error: multiple unused asm arguments
+  --> $DIR/bad-template.rs:52:18
+   |
+LL |         asm!("", in(reg) 0, in(reg) 1);
+   |                  ^^^^^^^^^  ^^^^^^^^^ argument never used
+   |                  |
+   |                  argument never used
+   |
+   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:58:14
+   |
+LL | global_asm!("{}");
+   |              ^^ from here
+   |
+   = note: no arguments were given
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:60:14
+   |
+LL | global_asm!("{1}", const FOO);
+   |              ^^^ from here
+   |
+   = note: there is 1 argument
+
+error: argument never used
+  --> $DIR/bad-template.rs:60:20
+   |
+LL | global_asm!("{1}", const FOO);
+   |                    ^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+  --> $DIR/bad-template.rs:63:14
+   |
+LL | global_asm!("{a}");
+   |              ^^^
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:65:14
+   |
+LL | global_asm!("{}", a = const FOO);
+   |              ^^   ------------- named argument
+   |              |
+   |              from here
+   |
+   = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+  --> $DIR/bad-template.rs:65:19
+   |
+LL | global_asm!("{}", a = const FOO);
+   |                   ^^^^^^^^^^^^^
+
+error: named argument never used
+  --> $DIR/bad-template.rs:65:19
+   |
+LL | global_asm!("{}", a = const FOO);
+   |                   ^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:68:14
+   |
+LL | global_asm!("{1}", a = const FOO);
+   |              ^^^ from here
+   |
+   = note: no positional arguments were given
+
+error: named argument never used
+  --> $DIR/bad-template.rs:68:20
+   |
+LL | global_asm!("{1}", a = const FOO);
+   |                    ^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: asm template modifier must be a single character
+  --> $DIR/bad-template.rs:71:16
+   |
+LL | global_asm!("{:foo}", const FOO);
+   |                ^^^
+
+error: multiple unused asm arguments
+  --> $DIR/bad-template.rs:73:17
+   |
+LL | global_asm!("", const FOO, const FOO);
+   |                 ^^^^^^^^^  ^^^^^^^^^ argument never used
+   |                 |
+   |                 argument never used
+   |
+   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: aborting due to 21 previous errors
+
diff --git a/src/test/ui/asm/bad-template.mirunsafeck.stderr b/src/test/ui/asm/bad-template.mirunsafeck.stderr
deleted file mode 100644 (file)
index 13ef032..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:10:15
-   |
-LL |         asm!("{}");
-   |               ^^ from here
-   |
-   = note: no arguments were given
-
-error: invalid reference to argument at index 1
-  --> $DIR/bad-template.rs:12:15
-   |
-LL |         asm!("{1}", in(reg) foo);
-   |               ^^^ from here
-   |
-   = note: there is 1 argument
-
-error: argument never used
-  --> $DIR/bad-template.rs:12:21
-   |
-LL |         asm!("{1}", in(reg) foo);
-   |                     ^^^^^^^^^^^ argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
-
-error: there is no argument named `a`
-  --> $DIR/bad-template.rs:15:15
-   |
-LL |         asm!("{a}");
-   |               ^^^
-
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:17:15
-   |
-LL |         asm!("{}", a = in(reg) foo);
-   |               ^^   --------------- named argument
-   |               |
-   |               from here
-   |
-   = note: no positional arguments were given
-note: named arguments cannot be referenced by position
-  --> $DIR/bad-template.rs:17:20
-   |
-LL |         asm!("{}", a = in(reg) foo);
-   |                    ^^^^^^^^^^^^^^^
-
-error: named argument never used
-  --> $DIR/bad-template.rs:17:20
-   |
-LL |         asm!("{}", a = in(reg) foo);
-   |                    ^^^^^^^^^^^^^^^ named argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 1
-  --> $DIR/bad-template.rs:20:15
-   |
-LL |         asm!("{1}", a = in(reg) foo);
-   |               ^^^ from here
-   |
-   = note: no positional arguments were given
-
-error: named argument never used
-  --> $DIR/bad-template.rs:20:21
-   |
-LL |         asm!("{1}", a = in(reg) foo);
-   |                     ^^^^^^^^^^^^^^^ named argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:23:15
-   |
-LL |         asm!("{}", in("eax") foo);
-   |               ^^   ------------- explicit register argument
-   |               |
-   |               from here
-   |
-   = note: no positional arguments were given
-note: explicit register arguments cannot be used in the asm template
-  --> $DIR/bad-template.rs:23:20
-   |
-LL |         asm!("{}", in("eax") foo);
-   |                    ^^^^^^^^^^^^^
-
-error: asm template modifier must be a single character
-  --> $DIR/bad-template.rs:25:17
-   |
-LL |         asm!("{:foo}", in(reg) foo);
-   |                 ^^^
-
-error: multiple unused asm arguments
-  --> $DIR/bad-template.rs:27:18
-   |
-LL |         asm!("", in(reg) 0, in(reg) 1);
-   |                  ^^^^^^^^^  ^^^^^^^^^ argument never used
-   |                  |
-   |                  argument never used
-   |
-   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
-
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:33:14
-   |
-LL | global_asm!("{}");
-   |              ^^ from here
-   |
-   = note: no arguments were given
-
-error: invalid reference to argument at index 1
-  --> $DIR/bad-template.rs:35:14
-   |
-LL | global_asm!("{1}", const FOO);
-   |              ^^^ from here
-   |
-   = note: there is 1 argument
-
-error: argument never used
-  --> $DIR/bad-template.rs:35:20
-   |
-LL | global_asm!("{1}", const FOO);
-   |                    ^^^^^^^^^ argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
-
-error: there is no argument named `a`
-  --> $DIR/bad-template.rs:38:14
-   |
-LL | global_asm!("{a}");
-   |              ^^^
-
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:40:14
-   |
-LL | global_asm!("{}", a = const FOO);
-   |              ^^   ------------- named argument
-   |              |
-   |              from here
-   |
-   = note: no positional arguments were given
-note: named arguments cannot be referenced by position
-  --> $DIR/bad-template.rs:40:19
-   |
-LL | global_asm!("{}", a = const FOO);
-   |                   ^^^^^^^^^^^^^
-
-error: named argument never used
-  --> $DIR/bad-template.rs:40:19
-   |
-LL | global_asm!("{}", a = const FOO);
-   |                   ^^^^^^^^^^^^^ named argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 1
-  --> $DIR/bad-template.rs:43:14
-   |
-LL | global_asm!("{1}", a = const FOO);
-   |              ^^^ from here
-   |
-   = note: no positional arguments were given
-
-error: named argument never used
-  --> $DIR/bad-template.rs:43:20
-   |
-LL | global_asm!("{1}", a = const FOO);
-   |                    ^^^^^^^^^^^^^ named argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: asm template modifier must be a single character
-  --> $DIR/bad-template.rs:46:16
-   |
-LL | global_asm!("{:foo}", const FOO);
-   |                ^^^
-
-error: multiple unused asm arguments
-  --> $DIR/bad-template.rs:48:17
-   |
-LL | global_asm!("", const FOO, const FOO);
-   |                 ^^^^^^^^^  ^^^^^^^^^ argument never used
-   |                 |
-   |                 argument never used
-   |
-   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
-
-error: aborting due to 21 previous errors
-
index 5aed2c62f0bddaa29aa0bace25bc869dc64f660e..fca77e7aa71f37d9b3841cbaf4e9a1fe31793dd7 100644 (file)
@@ -1,8 +1,29 @@
-// only-x86_64
-// revisions: mirunsafeck thirunsafeck
-// [thirunsafeck]compile-flags: -Z thir-unsafeck
+// revisions: x86_64_mirunsafeck aarch64_mirunsafeck x86_64_thirunsafeck aarch64_thirunsafeck
 
-#![feature(asm, global_asm)]
+// [x86_64_thirunsafeck] compile-flags: -Z thir-unsafeck --target x86_64-unknown-linux-gnu
+// [aarch64_thirunsafeck] compile-flags: -Z thir-unsafeck --target aarch64-unknown-linux-gnu
+// [x86_64_mirunsafeck] compile-flags: --target x86_64-unknown-linux-gnu
+// [aarch64_mirunsafeck] compile-flags: --target aarch64-unknown-linux-gnu
+
+// [x86_64_thirunsafeck] needs-llvm-components: x86
+// [x86_64_mirunsafeck] needs-llvm-components: x86
+// [aarch64_thirunsafeck] needs-llvm-components: aarch64
+// [aarch64_mirunsafeck] needs-llvm-components: aarch64
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+    () => {};
+}
+#[rustc_builtin_macro]
+macro_rules! global_asm {
+    () => {};
+}
+
+#[lang = "sized"]
+trait Sized {}
 
 fn main() {
     let mut foo = 0;
@@ -20,8 +41,12 @@ fn main() {
         asm!("{1}", a = in(reg) foo);
         //~^ ERROR invalid reference to argument at index 1
         //~^^ ERROR named argument never used
+        #[cfg(any(x86_64_thirunsafeck, x86_64_mirunsafeck))]
         asm!("{}", in("eax") foo);
-        //~^ ERROR invalid reference to argument at index 0
+        //[x86_64_thirunsafeck,x86_64_mirunsafeck]~^ ERROR invalid reference to argument at index 0
+        #[cfg(any(aarch64_thirunsafeck, aarch64_mirunsafeck))]
+        asm!("{}", in("x0") foo);
+        //[aarch64_thirunsafeck,aarch64_mirunsafeck]~^ ERROR invalid reference to argument at index 0
         asm!("{:foo}", in(reg) foo);
         //~^ ERROR asm template modifier must be a single character
         asm!("", in(reg) 0, in(reg) 1);
diff --git a/src/test/ui/asm/bad-template.thirunsafeck.stderr b/src/test/ui/asm/bad-template.thirunsafeck.stderr
deleted file mode 100644 (file)
index 13ef032..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:10:15
-   |
-LL |         asm!("{}");
-   |               ^^ from here
-   |
-   = note: no arguments were given
-
-error: invalid reference to argument at index 1
-  --> $DIR/bad-template.rs:12:15
-   |
-LL |         asm!("{1}", in(reg) foo);
-   |               ^^^ from here
-   |
-   = note: there is 1 argument
-
-error: argument never used
-  --> $DIR/bad-template.rs:12:21
-   |
-LL |         asm!("{1}", in(reg) foo);
-   |                     ^^^^^^^^^^^ argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
-
-error: there is no argument named `a`
-  --> $DIR/bad-template.rs:15:15
-   |
-LL |         asm!("{a}");
-   |               ^^^
-
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:17:15
-   |
-LL |         asm!("{}", a = in(reg) foo);
-   |               ^^   --------------- named argument
-   |               |
-   |               from here
-   |
-   = note: no positional arguments were given
-note: named arguments cannot be referenced by position
-  --> $DIR/bad-template.rs:17:20
-   |
-LL |         asm!("{}", a = in(reg) foo);
-   |                    ^^^^^^^^^^^^^^^
-
-error: named argument never used
-  --> $DIR/bad-template.rs:17:20
-   |
-LL |         asm!("{}", a = in(reg) foo);
-   |                    ^^^^^^^^^^^^^^^ named argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 1
-  --> $DIR/bad-template.rs:20:15
-   |
-LL |         asm!("{1}", a = in(reg) foo);
-   |               ^^^ from here
-   |
-   = note: no positional arguments were given
-
-error: named argument never used
-  --> $DIR/bad-template.rs:20:21
-   |
-LL |         asm!("{1}", a = in(reg) foo);
-   |                     ^^^^^^^^^^^^^^^ named argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:23:15
-   |
-LL |         asm!("{}", in("eax") foo);
-   |               ^^   ------------- explicit register argument
-   |               |
-   |               from here
-   |
-   = note: no positional arguments were given
-note: explicit register arguments cannot be used in the asm template
-  --> $DIR/bad-template.rs:23:20
-   |
-LL |         asm!("{}", in("eax") foo);
-   |                    ^^^^^^^^^^^^^
-
-error: asm template modifier must be a single character
-  --> $DIR/bad-template.rs:25:17
-   |
-LL |         asm!("{:foo}", in(reg) foo);
-   |                 ^^^
-
-error: multiple unused asm arguments
-  --> $DIR/bad-template.rs:27:18
-   |
-LL |         asm!("", in(reg) 0, in(reg) 1);
-   |                  ^^^^^^^^^  ^^^^^^^^^ argument never used
-   |                  |
-   |                  argument never used
-   |
-   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
-
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:33:14
-   |
-LL | global_asm!("{}");
-   |              ^^ from here
-   |
-   = note: no arguments were given
-
-error: invalid reference to argument at index 1
-  --> $DIR/bad-template.rs:35:14
-   |
-LL | global_asm!("{1}", const FOO);
-   |              ^^^ from here
-   |
-   = note: there is 1 argument
-
-error: argument never used
-  --> $DIR/bad-template.rs:35:20
-   |
-LL | global_asm!("{1}", const FOO);
-   |                    ^^^^^^^^^ argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
-
-error: there is no argument named `a`
-  --> $DIR/bad-template.rs:38:14
-   |
-LL | global_asm!("{a}");
-   |              ^^^
-
-error: invalid reference to argument at index 0
-  --> $DIR/bad-template.rs:40:14
-   |
-LL | global_asm!("{}", a = const FOO);
-   |              ^^   ------------- named argument
-   |              |
-   |              from here
-   |
-   = note: no positional arguments were given
-note: named arguments cannot be referenced by position
-  --> $DIR/bad-template.rs:40:19
-   |
-LL | global_asm!("{}", a = const FOO);
-   |                   ^^^^^^^^^^^^^
-
-error: named argument never used
-  --> $DIR/bad-template.rs:40:19
-   |
-LL | global_asm!("{}", a = const FOO);
-   |                   ^^^^^^^^^^^^^ named argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: invalid reference to argument at index 1
-  --> $DIR/bad-template.rs:43:14
-   |
-LL | global_asm!("{1}", a = const FOO);
-   |              ^^^ from here
-   |
-   = note: no positional arguments were given
-
-error: named argument never used
-  --> $DIR/bad-template.rs:43:20
-   |
-LL | global_asm!("{1}", a = const FOO);
-   |                    ^^^^^^^^^^^^^ named argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
-
-error: asm template modifier must be a single character
-  --> $DIR/bad-template.rs:46:16
-   |
-LL | global_asm!("{:foo}", const FOO);
-   |                ^^^
-
-error: multiple unused asm arguments
-  --> $DIR/bad-template.rs:48:17
-   |
-LL | global_asm!("", const FOO, const FOO);
-   |                 ^^^^^^^^^  ^^^^^^^^^ argument never used
-   |                 |
-   |                 argument never used
-   |
-   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
-
-error: aborting due to 21 previous errors
-
diff --git a/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_mirunsafeck.stderr
new file mode 100644 (file)
index 0000000..3b69186
--- /dev/null
@@ -0,0 +1,187 @@
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:31:15
+   |
+LL |         asm!("{}");
+   |               ^^ from here
+   |
+   = note: no arguments were given
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:33:15
+   |
+LL |         asm!("{1}", in(reg) foo);
+   |               ^^^ from here
+   |
+   = note: there is 1 argument
+
+error: argument never used
+  --> $DIR/bad-template.rs:33:21
+   |
+LL |         asm!("{1}", in(reg) foo);
+   |                     ^^^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+  --> $DIR/bad-template.rs:36:15
+   |
+LL |         asm!("{a}");
+   |               ^^^
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:38:15
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |               ^^   --------------- named argument
+   |               |
+   |               from here
+   |
+   = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+  --> $DIR/bad-template.rs:38:20
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |                    ^^^^^^^^^^^^^^^
+
+error: named argument never used
+  --> $DIR/bad-template.rs:38:20
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |                    ^^^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:41:15
+   |
+LL |         asm!("{1}", a = in(reg) foo);
+   |               ^^^ from here
+   |
+   = note: no positional arguments were given
+
+error: named argument never used
+  --> $DIR/bad-template.rs:41:21
+   |
+LL |         asm!("{1}", a = in(reg) foo);
+   |                     ^^^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:45:15
+   |
+LL |         asm!("{}", in("eax") foo);
+   |               ^^   ------------- explicit register argument
+   |               |
+   |               from here
+   |
+   = note: no positional arguments were given
+note: explicit register arguments cannot be used in the asm template
+  --> $DIR/bad-template.rs:45:20
+   |
+LL |         asm!("{}", in("eax") foo);
+   |                    ^^^^^^^^^^^^^
+
+error: asm template modifier must be a single character
+  --> $DIR/bad-template.rs:50:17
+   |
+LL |         asm!("{:foo}", in(reg) foo);
+   |                 ^^^
+
+error: multiple unused asm arguments
+  --> $DIR/bad-template.rs:52:18
+   |
+LL |         asm!("", in(reg) 0, in(reg) 1);
+   |                  ^^^^^^^^^  ^^^^^^^^^ argument never used
+   |                  |
+   |                  argument never used
+   |
+   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:58:14
+   |
+LL | global_asm!("{}");
+   |              ^^ from here
+   |
+   = note: no arguments were given
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:60:14
+   |
+LL | global_asm!("{1}", const FOO);
+   |              ^^^ from here
+   |
+   = note: there is 1 argument
+
+error: argument never used
+  --> $DIR/bad-template.rs:60:20
+   |
+LL | global_asm!("{1}", const FOO);
+   |                    ^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+  --> $DIR/bad-template.rs:63:14
+   |
+LL | global_asm!("{a}");
+   |              ^^^
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:65:14
+   |
+LL | global_asm!("{}", a = const FOO);
+   |              ^^   ------------- named argument
+   |              |
+   |              from here
+   |
+   = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+  --> $DIR/bad-template.rs:65:19
+   |
+LL | global_asm!("{}", a = const FOO);
+   |                   ^^^^^^^^^^^^^
+
+error: named argument never used
+  --> $DIR/bad-template.rs:65:19
+   |
+LL | global_asm!("{}", a = const FOO);
+   |                   ^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:68:14
+   |
+LL | global_asm!("{1}", a = const FOO);
+   |              ^^^ from here
+   |
+   = note: no positional arguments were given
+
+error: named argument never used
+  --> $DIR/bad-template.rs:68:20
+   |
+LL | global_asm!("{1}", a = const FOO);
+   |                    ^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: asm template modifier must be a single character
+  --> $DIR/bad-template.rs:71:16
+   |
+LL | global_asm!("{:foo}", const FOO);
+   |                ^^^
+
+error: multiple unused asm arguments
+  --> $DIR/bad-template.rs:73:17
+   |
+LL | global_asm!("", const FOO, const FOO);
+   |                 ^^^^^^^^^  ^^^^^^^^^ argument never used
+   |                 |
+   |                 argument never used
+   |
+   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: aborting due to 21 previous errors
+
diff --git a/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr b/src/test/ui/asm/bad-template.x86_64_thirunsafeck.stderr
new file mode 100644 (file)
index 0000000..3b69186
--- /dev/null
@@ -0,0 +1,187 @@
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:31:15
+   |
+LL |         asm!("{}");
+   |               ^^ from here
+   |
+   = note: no arguments were given
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:33:15
+   |
+LL |         asm!("{1}", in(reg) foo);
+   |               ^^^ from here
+   |
+   = note: there is 1 argument
+
+error: argument never used
+  --> $DIR/bad-template.rs:33:21
+   |
+LL |         asm!("{1}", in(reg) foo);
+   |                     ^^^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+  --> $DIR/bad-template.rs:36:15
+   |
+LL |         asm!("{a}");
+   |               ^^^
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:38:15
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |               ^^   --------------- named argument
+   |               |
+   |               from here
+   |
+   = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+  --> $DIR/bad-template.rs:38:20
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |                    ^^^^^^^^^^^^^^^
+
+error: named argument never used
+  --> $DIR/bad-template.rs:38:20
+   |
+LL |         asm!("{}", a = in(reg) foo);
+   |                    ^^^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:41:15
+   |
+LL |         asm!("{1}", a = in(reg) foo);
+   |               ^^^ from here
+   |
+   = note: no positional arguments were given
+
+error: named argument never used
+  --> $DIR/bad-template.rs:41:21
+   |
+LL |         asm!("{1}", a = in(reg) foo);
+   |                     ^^^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:45:15
+   |
+LL |         asm!("{}", in("eax") foo);
+   |               ^^   ------------- explicit register argument
+   |               |
+   |               from here
+   |
+   = note: no positional arguments were given
+note: explicit register arguments cannot be used in the asm template
+  --> $DIR/bad-template.rs:45:20
+   |
+LL |         asm!("{}", in("eax") foo);
+   |                    ^^^^^^^^^^^^^
+
+error: asm template modifier must be a single character
+  --> $DIR/bad-template.rs:50:17
+   |
+LL |         asm!("{:foo}", in(reg) foo);
+   |                 ^^^
+
+error: multiple unused asm arguments
+  --> $DIR/bad-template.rs:52:18
+   |
+LL |         asm!("", in(reg) 0, in(reg) 1);
+   |                  ^^^^^^^^^  ^^^^^^^^^ argument never used
+   |                  |
+   |                  argument never used
+   |
+   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:58:14
+   |
+LL | global_asm!("{}");
+   |              ^^ from here
+   |
+   = note: no arguments were given
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:60:14
+   |
+LL | global_asm!("{1}", const FOO);
+   |              ^^^ from here
+   |
+   = note: there is 1 argument
+
+error: argument never used
+  --> $DIR/bad-template.rs:60:20
+   |
+LL | global_asm!("{1}", const FOO);
+   |                    ^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {0} */"`
+
+error: there is no argument named `a`
+  --> $DIR/bad-template.rs:63:14
+   |
+LL | global_asm!("{a}");
+   |              ^^^
+
+error: invalid reference to argument at index 0
+  --> $DIR/bad-template.rs:65:14
+   |
+LL | global_asm!("{}", a = const FOO);
+   |              ^^   ------------- named argument
+   |              |
+   |              from here
+   |
+   = note: no positional arguments were given
+note: named arguments cannot be referenced by position
+  --> $DIR/bad-template.rs:65:19
+   |
+LL | global_asm!("{}", a = const FOO);
+   |                   ^^^^^^^^^^^^^
+
+error: named argument never used
+  --> $DIR/bad-template.rs:65:19
+   |
+LL | global_asm!("{}", a = const FOO);
+   |                   ^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: invalid reference to argument at index 1
+  --> $DIR/bad-template.rs:68:14
+   |
+LL | global_asm!("{1}", a = const FOO);
+   |              ^^^ from here
+   |
+   = note: no positional arguments were given
+
+error: named argument never used
+  --> $DIR/bad-template.rs:68:20
+   |
+LL | global_asm!("{1}", a = const FOO);
+   |                    ^^^^^^^^^^^^^ named argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {a} */"`
+
+error: asm template modifier must be a single character
+  --> $DIR/bad-template.rs:71:16
+   |
+LL | global_asm!("{:foo}", const FOO);
+   |                ^^^
+
+error: multiple unused asm arguments
+  --> $DIR/bad-template.rs:73:17
+   |
+LL | global_asm!("", const FOO, const FOO);
+   |                 ^^^^^^^^^  ^^^^^^^^^ argument never used
+   |                 |
+   |                 argument never used
+   |
+   = help: if these arguments are intentionally unused, consider using them in an asm comment: `"/* {0} {1} */"`
+
+error: aborting due to 21 previous errors
+
diff --git a/src/test/ui/asm/const.rs b/src/test/ui/asm/const.rs
deleted file mode 100644 (file)
index d4de9ab..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-// min-llvm-version: 10.0.1
-// only-x86_64
-// run-pass
-// revisions: mirunsafeck thirunsafeck
-// [thirunsafeck]compile-flags: -Z thir-unsafeck
-
-#![feature(asm, global_asm)]
-
-fn const_generic<const X: usize>() -> usize {
-    unsafe {
-        let a: usize;
-        asm!("mov {}, {}", out(reg) a, const X);
-        a
-    }
-}
-
-const fn constfn(x: usize) -> usize {
-    x
-}
-
-fn main() {
-    unsafe {
-        let a: usize;
-        asm!("mov {}, {}", out(reg) a, const 5);
-        assert_eq!(a, 5);
-
-        let b: usize;
-        asm!("mov {}, {}", out(reg) b, const constfn(5));
-        assert_eq!(b, 5);
-
-        let c: usize;
-        asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5));
-        assert_eq!(c, 10);
-    }
-
-    let d = const_generic::<5>();
-    assert_eq!(d, 5);
-}
-
-global_asm!("mov eax, {}", const 5);
-global_asm!("mov eax, {}", const constfn(5));
-global_asm!("mov eax, {}", const constfn(5) + constfn(5));
diff --git a/src/test/ui/asm/duplicate-options.fixed b/src/test/ui/asm/duplicate-options.fixed
deleted file mode 100644 (file)
index d4444e9..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// only-x86_64
-// run-rustfix
-
-#![feature(asm, global_asm)]
-
-fn main() {
-    unsafe {
-        asm!("", options(nomem, ));
-        //~^ ERROR the `nomem` option was already provided
-        asm!("", options(att_syntax, ));
-        //~^ ERROR the `att_syntax` option was already provided
-        asm!("", options(nostack, att_syntax), options());
-        //~^ ERROR the `nostack` option was already provided
-        asm!("", options(nostack, ), options(), options());
-        //~^ ERROR the `nostack` option was already provided
-        //~| ERROR the `nostack` option was already provided
-        //~| ERROR the `nostack` option was already provided
-        asm!(
-            "",
-            options(nomem, noreturn),
-            options(att_syntax, ), //~ ERROR the `noreturn` option was already provided
-            options( nostack), //~ ERROR the `nomem` option was already provided
-            options(), //~ ERROR the `noreturn` option was already provided
-        );
-    }
-}
-
-global_asm!("", options(att_syntax, ));
-//~^ ERROR the `att_syntax` option was already provided
diff --git a/src/test/ui/asm/duplicate-options.rs b/src/test/ui/asm/duplicate-options.rs
deleted file mode 100644 (file)
index fd28311..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-// only-x86_64
-// run-rustfix
-
-#![feature(asm, global_asm)]
-
-fn main() {
-    unsafe {
-        asm!("", options(nomem, nomem));
-        //~^ ERROR the `nomem` option was already provided
-        asm!("", options(att_syntax, att_syntax));
-        //~^ ERROR the `att_syntax` option was already provided
-        asm!("", options(nostack, att_syntax), options(nostack));
-        //~^ ERROR the `nostack` option was already provided
-        asm!("", options(nostack, nostack), options(nostack), options(nostack));
-        //~^ ERROR the `nostack` option was already provided
-        //~| ERROR the `nostack` option was already provided
-        //~| ERROR the `nostack` option was already provided
-        asm!(
-            "",
-            options(nomem, noreturn),
-            options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided
-            options(nomem, nostack), //~ ERROR the `nomem` option was already provided
-            options(noreturn), //~ ERROR the `noreturn` option was already provided
-        );
-    }
-}
-
-global_asm!("", options(att_syntax, att_syntax));
-//~^ ERROR the `att_syntax` option was already provided
diff --git a/src/test/ui/asm/duplicate-options.stderr b/src/test/ui/asm/duplicate-options.stderr
deleted file mode 100644 (file)
index 53edf8f..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-error: the `nomem` option was already provided
-  --> $DIR/duplicate-options.rs:8:33
-   |
-LL |         asm!("", options(nomem, nomem));
-   |                                 ^^^^^ this option was already provided
-
-error: the `att_syntax` option was already provided
-  --> $DIR/duplicate-options.rs:10:38
-   |
-LL |         asm!("", options(att_syntax, att_syntax));
-   |                                      ^^^^^^^^^^ this option was already provided
-
-error: the `nostack` option was already provided
-  --> $DIR/duplicate-options.rs:12:56
-   |
-LL |         asm!("", options(nostack, att_syntax), options(nostack));
-   |                                                        ^^^^^^^ this option was already provided
-
-error: the `nostack` option was already provided
-  --> $DIR/duplicate-options.rs:14:35
-   |
-LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
-   |                                   ^^^^^^^ this option was already provided
-
-error: the `nostack` option was already provided
-  --> $DIR/duplicate-options.rs:14:53
-   |
-LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
-   |                                                     ^^^^^^^ this option was already provided
-
-error: the `nostack` option was already provided
-  --> $DIR/duplicate-options.rs:14:71
-   |
-LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
-   |                                                                       ^^^^^^^ this option was already provided
-
-error: the `noreturn` option was already provided
-  --> $DIR/duplicate-options.rs:21:33
-   |
-LL |             options(att_syntax, noreturn),
-   |                                 ^^^^^^^^ this option was already provided
-
-error: the `nomem` option was already provided
-  --> $DIR/duplicate-options.rs:22:21
-   |
-LL |             options(nomem, nostack),
-   |                     ^^^^^ this option was already provided
-
-error: the `noreturn` option was already provided
-  --> $DIR/duplicate-options.rs:23:21
-   |
-LL |             options(noreturn),
-   |                     ^^^^^^^^ this option was already provided
-
-error: the `att_syntax` option was already provided
-  --> $DIR/duplicate-options.rs:28:37
-   |
-LL | global_asm!("", options(att_syntax, att_syntax));
-   |                                     ^^^^^^^^^^ this option was already provided
-
-error: aborting due to 10 previous errors
-
diff --git a/src/test/ui/asm/interpolated-idents.rs b/src/test/ui/asm/interpolated-idents.rs
deleted file mode 100644 (file)
index f4cb749..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-// only-x86_64
-
-#![feature(asm)]
-
-macro_rules! m {
-    ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
-     $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
-     $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => {
-        unsafe {
-            asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
-            //~^ ERROR asm outputs are not allowed with the `noreturn` option
-            const x, sym x,
-            $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
-            //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
-            //~| ERROR the `pure` and `noreturn` options are mutually exclusive
-        }
-    };
-}
-
-fn main() {
-    m!(in out lateout inout inlateout const sym
-       pure nomem readonly preserves_flags
-       noreturn nostack att_syntax options);
-}
diff --git a/src/test/ui/asm/interpolated-idents.stderr b/src/test/ui/asm/interpolated-idents.stderr
deleted file mode 100644 (file)
index 5de8d20..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-error: the `nomem` and `readonly` options are mutually exclusive
-  --> $DIR/interpolated-idents.rs:13:13
-   |
-LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | /     m!(in out lateout inout inlateout const sym
-LL | |        pure nomem readonly preserves_flags
-LL | |        noreturn nostack att_syntax options);
-   | |____________________________________________- in this macro invocation
-   |
-   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: the `pure` and `noreturn` options are mutually exclusive
-  --> $DIR/interpolated-idents.rs:13:13
-   |
-LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-...
-LL | /     m!(in out lateout inout inlateout const sym
-LL | |        pure nomem readonly preserves_flags
-LL | |        noreturn nostack att_syntax options);
-   | |____________________________________________- in this macro invocation
-   |
-   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: asm outputs are not allowed with the `noreturn` option
-  --> $DIR/interpolated-idents.rs:10:32
-   |
-LL |               asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
-   |                                  ^^^^^^^^^  ^^^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^^^^^
-...
-LL |       m!(in out lateout inout inlateout const sym
-   |  _____-
-   | |_____|
-   | |_____|
-   | |_____|
-   | |
-LL | |        pure nomem readonly preserves_flags
-LL | |        noreturn nostack att_syntax options);
-   | |                                            -
-   | |____________________________________________|
-   | |____________________________________________in this macro invocation
-   | |____________________________________________in this macro invocation
-   | |____________________________________________in this macro invocation
-   |                                              in this macro invocation
-   |
-   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: aborting due to 3 previous errors
-
index 678534657cb31982643303eab649f2ad853a8647..960f7427e3405c3b810e8dda9233a39c1b735fba 100644 (file)
@@ -1,5 +1,5 @@
 // compile-flags: -Zsave-analysis
-// only-x86_64
+// needs-asm-support
 // Also test for #72960
 
 #![feature(asm)]
diff --git a/src/test/ui/asm/issue-82869.rs b/src/test/ui/asm/issue-82869.rs
deleted file mode 100644 (file)
index a8e688c..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// only-x86_64
-// Make sure rustc doesn't ICE on asm! for a foreign architecture.
-
-#![feature(asm)]
-#![crate_type = "rlib"]
-
-pub unsafe fn aarch64(a: f64, b: f64) -> f64 {
-    let c;
-    asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
-        || {};
-        b
-    });
-    //~^^^^ invalid register class
-    //~^^^^^ invalid register class
-    //~^^^^^^ invalid register
-    c
-}
-
-pub unsafe fn x86(a: f64, b: f64) -> f64 {
-    let c;
-    asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b);
-    c
-}
diff --git a/src/test/ui/asm/issue-82869.stderr b/src/test/ui/asm/issue-82869.stderr
deleted file mode 100644 (file)
index d05714e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-error: invalid register class `vreg`: unknown register class
-  --> $DIR/issue-82869.rs:9:32
-   |
-LL |     asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
-   |                                ^^^^^^^^^^^
-
-error: invalid register class `vreg`: unknown register class
-  --> $DIR/issue-82869.rs:9:45
-   |
-LL |     asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
-   |                                             ^^^^^^^^^^
-
-error: invalid register `d0`: unknown register
-  --> $DIR/issue-82869.rs:9:57
-   |
-LL |       asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
-   |  _________________________________________________________^
-LL | |         || {};
-LL | |         b
-LL | |     });
-   | |_____^
-
-error: aborting due to 3 previous errors
-
index b1fc13b6a7e8cfac6141b0c9eebf25e99ad36de9..5b6453c42c6eb950e71d21853b01d3c7db5b8e27 100644 (file)
@@ -1,4 +1,7 @@
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
 // Make sure rustc doesn't ICE on asm! when output type is !.
 
 #![feature(asm)]
index 1eb72b68a7f044bd266a061ad8c83998acf2396b..de3e28fdd12289281101d64550b28171fd6c9f36 100644 (file)
@@ -1,5 +1,5 @@
 error: cannot use value of type `!` for inline assembly
-  --> $DIR/issue-87802.rs:9:36
+  --> $DIR/issue-87802.rs:12:36
    |
 LL |         asm!("/* {0} */", out(reg) x);
    |                                    ^
index 5b2a8ed3034a6cffe1714af6c75902063079cece..f6725605b924b5fb71b05c0b510f7c79cc555126 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// only-x86_64
+// needs-asm-support
 #![feature(asm)]
 #![feature(naked_functions)]
 #![crate_type = "lib"]
diff --git a/src/test/ui/asm/naked-functions-unused.aarch64.stderr b/src/test/ui/asm/naked-functions-unused.aarch64.stderr
new file mode 100644 (file)
index 0000000..a898ab1
--- /dev/null
@@ -0,0 +1,69 @@
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:15:32
+   |
+LL |     pub extern "C" fn function(a: usize, b: usize) -> usize {
+   |                                ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: the lint level is defined here
+  --> $DIR/naked-functions-unused.rs:4:9
+   |
+LL | #![deny(unused)]
+   |         ^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:15:42
+   |
+LL |     pub extern "C" fn function(a: usize, b: usize) -> usize {
+   |                                          ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:24:38
+   |
+LL |         pub extern "C" fn associated(a: usize, b: usize) -> usize {
+   |                                      ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:24:48
+   |
+LL |         pub extern "C" fn associated(a: usize, b: usize) -> usize {
+   |                                                ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:30:41
+   |
+LL |         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
+   |                                         ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:30:51
+   |
+LL |         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
+   |                                                   ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:38:40
+   |
+LL |         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
+   |                                        ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:38:50
+   |
+LL |         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
+   |                                                  ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:44:43
+   |
+LL |         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
+   |                                           ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:44:53
+   |
+LL |         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
+   |                                                     ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: aborting due to 10 previous errors
+
index e1f2362bb6fd075f2d3f8a0fa6c6d496485227be..4c5c2ac1c197e3685ed071566e3bc7c2767f2ca4 100644 (file)
@@ -1,16 +1,18 @@
-// only-x86_64
+// revisions: x86_64 aarch64
+//[x86_64] only-x86_64
+//[aarch64] only-aarch64
 #![deny(unused)]
 #![feature(asm)]
 #![feature(naked_functions)]
 #![crate_type = "lib"]
 
 pub trait Trait {
-    extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize;
-    extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize;
+    extern "C" fn trait_associated(a: usize, b: usize) -> usize;
+    extern "C" fn trait_method(&self, a: usize, b: usize) -> usize;
 }
 
 pub mod normal {
-    pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+    pub extern "C" fn function(a: usize, b: usize) -> usize {
         //~^ ERROR unused variable: `a`
         //~| ERROR unused variable: `b`
         unsafe { asm!("", options(noreturn)); }
@@ -19,13 +21,13 @@ pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
     pub struct Normal;
 
     impl Normal {
-        pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+        pub extern "C" fn associated(a: usize, b: usize) -> usize {
             //~^ ERROR unused variable: `a`
             //~| ERROR unused variable: `b`
             unsafe { asm!("", options(noreturn)); }
         }
 
-        pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+        pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
             //~^ ERROR unused variable: `a`
             //~| ERROR unused variable: `b`
             unsafe { asm!("", options(noreturn)); }
@@ -33,13 +35,13 @@ pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
     }
 
     impl super::Trait for Normal {
-        extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+        extern "C" fn trait_associated(a: usize, b: usize) -> usize {
             //~^ ERROR unused variable: `a`
             //~| ERROR unused variable: `b`
             unsafe { asm!("", options(noreturn)); }
         }
 
-        extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+        extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
             //~^ ERROR unused variable: `a`
             //~| ERROR unused variable: `b`
             unsafe { asm!("", options(noreturn)); }
@@ -49,7 +51,7 @@ extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
 
 pub mod naked {
     #[naked]
-    pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
+    pub extern "C" fn function(a: usize, b: usize) -> usize {
         unsafe { asm!("", options(noreturn)); }
     }
 
@@ -57,24 +59,24 @@ pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
 
     impl Naked {
         #[naked]
-        pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
+        pub extern "C" fn associated(a: usize, b: usize) -> usize {
             unsafe { asm!("", options(noreturn)); }
         }
 
         #[naked]
-        pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
+        pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
             unsafe { asm!("", options(noreturn)); }
         }
     }
 
     impl super::Trait for Naked {
         #[naked]
-        extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
+        extern "C" fn trait_associated(a: usize, b: usize) -> usize {
             unsafe { asm!("", options(noreturn)); }
         }
 
         #[naked]
-        extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
+        extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
             unsafe { asm!("", options(noreturn)); }
         }
     }
diff --git a/src/test/ui/asm/naked-functions-unused.stderr b/src/test/ui/asm/naked-functions-unused.stderr
deleted file mode 100644 (file)
index 8403533..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:13:37
-   |
-LL |     pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
-   |                                     ^ help: if this is intentional, prefix it with an underscore: `_a`
-   |
-note: the lint level is defined here
-  --> $DIR/naked-functions-unused.rs:2:9
-   |
-LL | #![deny(unused)]
-   |         ^^^^^^
-   = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
-
-error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:13:47
-   |
-LL |     pub extern "sysv64" fn function(a: usize, b: usize) -> usize {
-   |                                               ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:22:43
-   |
-LL |         pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
-   |                                           ^ help: if this is intentional, prefix it with an underscore: `_a`
-
-error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:22:53
-   |
-LL |         pub extern "sysv64" fn associated(a: usize, b: usize) -> usize {
-   |                                                     ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:28:46
-   |
-LL |         pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
-   |                                              ^ help: if this is intentional, prefix it with an underscore: `_a`
-
-error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:28:56
-   |
-LL |         pub extern "sysv64" fn method(&self, a: usize, b: usize) -> usize {
-   |                                                        ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:36:45
-   |
-LL |         extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
-   |                                             ^ help: if this is intentional, prefix it with an underscore: `_a`
-
-error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:36:55
-   |
-LL |         extern "sysv64" fn trait_associated(a: usize, b: usize) -> usize {
-   |                                                       ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: unused variable: `a`
-  --> $DIR/naked-functions-unused.rs:42:48
-   |
-LL |         extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
-   |                                                ^ help: if this is intentional, prefix it with an underscore: `_a`
-
-error: unused variable: `b`
-  --> $DIR/naked-functions-unused.rs:42:58
-   |
-LL |         extern "sysv64" fn trait_method(&self, a: usize, b: usize) -> usize {
-   |                                                          ^ help: if this is intentional, prefix it with an underscore: `_b`
-
-error: aborting due to 10 previous errors
-
diff --git a/src/test/ui/asm/naked-functions-unused.x86_64.stderr b/src/test/ui/asm/naked-functions-unused.x86_64.stderr
new file mode 100644 (file)
index 0000000..a898ab1
--- /dev/null
@@ -0,0 +1,69 @@
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:15:32
+   |
+LL |     pub extern "C" fn function(a: usize, b: usize) -> usize {
+   |                                ^ help: if this is intentional, prefix it with an underscore: `_a`
+   |
+note: the lint level is defined here
+  --> $DIR/naked-functions-unused.rs:4:9
+   |
+LL | #![deny(unused)]
+   |         ^^^^^^
+   = note: `#[deny(unused_variables)]` implied by `#[deny(unused)]`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:15:42
+   |
+LL |     pub extern "C" fn function(a: usize, b: usize) -> usize {
+   |                                          ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:24:38
+   |
+LL |         pub extern "C" fn associated(a: usize, b: usize) -> usize {
+   |                                      ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:24:48
+   |
+LL |         pub extern "C" fn associated(a: usize, b: usize) -> usize {
+   |                                                ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:30:41
+   |
+LL |         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
+   |                                         ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:30:51
+   |
+LL |         pub extern "C" fn method(&self, a: usize, b: usize) -> usize {
+   |                                                   ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:38:40
+   |
+LL |         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
+   |                                        ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:38:50
+   |
+LL |         extern "C" fn trait_associated(a: usize, b: usize) -> usize {
+   |                                                  ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: unused variable: `a`
+  --> $DIR/naked-functions-unused.rs:44:43
+   |
+LL |         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
+   |                                           ^ help: if this is intentional, prefix it with an underscore: `_a`
+
+error: unused variable: `b`
+  --> $DIR/naked-functions-unused.rs:44:53
+   |
+LL |         extern "C" fn trait_method(&self, a: usize, b: usize) -> usize {
+   |                                                     ^ help: if this is intentional, prefix it with an underscore: `_b`
+
+error: aborting due to 10 previous errors
+
index 72918a1411755874a8bd2d63a2f03dba9bb0227c..803311d4235058a0a6419f2c44a5a4f94b1692da 100644 (file)
@@ -1,4 +1,8 @@
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
+
 #![feature(asm)]
 #![feature(llvm_asm)]
 #![feature(naked_functions)]
index 3b54757cfe8184af3a154205532bba41b983b2a3..46ceef032427c97487be328b48bcd83f1c5d1ef4 100644 (file)
@@ -1,35 +1,35 @@
 error: asm with the `pure` option must have at least one output
-  --> $DIR/naked-functions.rs:127:14
+  --> $DIR/naked-functions.rs:131:14
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^  ^^^^^^^^^^^^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:14:5
+  --> $DIR/naked-functions.rs:18:5
    |
 LL |     mut a: u32,
    |     ^^^^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:16:5
+  --> $DIR/naked-functions.rs:20:5
    |
 LL |     &b: &i32,
    |     ^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:18:6
+  --> $DIR/naked-functions.rs:22:6
    |
 LL |     (None | Some(_)): Option<std::ptr::NonNull<u8>>,
    |      ^^^^^^^^^^^^^^
 
 error: patterns not allowed in naked function parameters
-  --> $DIR/naked-functions.rs:20:5
+  --> $DIR/naked-functions.rs:24:5
    |
 LL |     P { x, y }: P,
    |     ^^^^^^^^^^
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:30:5
+  --> $DIR/naked-functions.rs:34:5
    |
 LL |     a + 1
    |     ^
@@ -37,7 +37,7 @@ LL |     a + 1
    = help: follow the calling convention in asm block to use parameters
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:27:1
+  --> $DIR/naked-functions.rs:31:1
    |
 LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
 LL | |
@@ -53,7 +53,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:36:31
+  --> $DIR/naked-functions.rs:40:31
    |
 LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    |                               ^
@@ -61,7 +61,7 @@ LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    = help: follow the calling convention in asm block to use parameters
 
 warning: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:36:23
+  --> $DIR/naked-functions.rs:40:23
    |
 LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    |                       ^^^^^^^^^
@@ -70,7 +70,7 @@ LL |     asm!("/* {0} */", in(reg) a, options(noreturn));
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:43:1
+  --> $DIR/naked-functions.rs:47:1
    |
 LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
 LL | |
@@ -84,7 +84,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: only `const` and `sym` operands are supported in naked functions
-  --> $DIR/naked-functions.rs:63:10
+  --> $DIR/naked-functions.rs:67:10
    |
 LL |          in(reg) a,
    |          ^^^^^^^^^
@@ -102,7 +102,7 @@ LL |          out(reg) e,
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:60:5
+  --> $DIR/naked-functions.rs:64:5
    |
 LL | /     asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
 LL | |
@@ -117,7 +117,7 @@ LL | |     );
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:50:1
+  --> $DIR/naked-functions.rs:54:1
    |
 LL | / pub unsafe extern "C" fn unsupported_operands() {
 LL | |
@@ -141,7 +141,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:76:1
+  --> $DIR/naked-functions.rs:80:1
    |
 LL | / pub extern "C" fn missing_assembly() {
 LL | |
@@ -153,7 +153,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:85:5
+  --> $DIR/naked-functions.rs:89:5
    |
 LL |     asm!("");
    |     ^^^^^^^^^
@@ -162,7 +162,7 @@ LL |     asm!("");
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:88:5
+  --> $DIR/naked-functions.rs:92:5
    |
 LL |     asm!("");
    |     ^^^^^^^^^
@@ -171,7 +171,7 @@ LL |     asm!("");
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:91:5
+  --> $DIR/naked-functions.rs:95:5
    |
 LL |     asm!("");
    |     ^^^^^^^^^
@@ -180,7 +180,7 @@ LL |     asm!("");
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:82:1
+  --> $DIR/naked-functions.rs:86:1
    |
 LL | / pub extern "C" fn too_many_asm_blocks() {
 LL | |
@@ -202,7 +202,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 error: referencing function parameters is not allowed in naked functions
-  --> $DIR/naked-functions.rs:102:11
+  --> $DIR/naked-functions.rs:106:11
    |
 LL |         *&y
    |           ^
@@ -210,7 +210,7 @@ LL |         *&y
    = help: follow the calling convention in asm block to use parameters
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:99:5
+  --> $DIR/naked-functions.rs:103:5
    |
 LL | /     pub extern "C" fn inner(y: usize) -> usize {
 LL | |
@@ -225,7 +225,7 @@ LL | |     }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: the LLVM-style inline assembly is unsupported in naked functions
-  --> $DIR/naked-functions.rs:112:5
+  --> $DIR/naked-functions.rs:116:5
    |
 LL |     llvm_asm!("");
    |     ^^^^^^^^^^^^^^
@@ -236,7 +236,7 @@ LL |     llvm_asm!("");
    = note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 warning: naked functions must contain a single asm block
-  --> $DIR/naked-functions.rs:109:1
+  --> $DIR/naked-functions.rs:113:1
    |
 LL | / unsafe extern "C" fn llvm() -> ! {
 LL | |
@@ -252,7 +252,7 @@ LL | | }
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
-  --> $DIR/naked-functions.rs:120:5
+  --> $DIR/naked-functions.rs:124:5
    |
 LL |     asm!("", options(nomem, preserves_flags, noreturn));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -261,7 +261,7 @@ LL |     asm!("", options(nomem, preserves_flags, noreturn));
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
-  --> $DIR/naked-functions.rs:127:5
+  --> $DIR/naked-functions.rs:131:5
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -270,7 +270,7 @@ LL |     asm!("", options(readonly, nostack), options(pure));
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: asm in naked functions must use `noreturn` option
-  --> $DIR/naked-functions.rs:127:5
+  --> $DIR/naked-functions.rs:131:5
    |
 LL |     asm!("", options(readonly, nostack), options(pure));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -279,7 +279,7 @@ LL |     asm!("", options(readonly, nostack), options(pure));
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:136:15
+  --> $DIR/naked-functions.rs:140:15
    |
 LL | pub unsafe fn default_abi() {
    |               ^^^^^^^^^^^
@@ -287,13 +287,13 @@ LL | pub unsafe fn default_abi() {
    = note: `#[warn(undefined_naked_function_abi)]` on by default
 
 warning: Rust ABI is unsupported in naked functions
-  --> $DIR/naked-functions.rs:142:29
+  --> $DIR/naked-functions.rs:146:29
    |
 LL | pub unsafe extern "Rust" fn rust_abi() {
    |                             ^^^^^^^^
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:176:1
+  --> $DIR/naked-functions.rs:180:1
    |
 LL | #[inline]
    | ^^^^^^^^^
@@ -302,7 +302,7 @@ LL | #[inline]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:184:1
+  --> $DIR/naked-functions.rs:188:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -311,7 +311,7 @@ LL | #[inline(always)]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:192:1
+  --> $DIR/naked-functions.rs:196:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^
@@ -320,7 +320,7 @@ LL | #[inline(never)]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:200:1
+  --> $DIR/naked-functions.rs:204:1
    |
 LL | #[inline]
    | ^^^^^^^^^
@@ -329,7 +329,7 @@ LL | #[inline]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:203:1
+  --> $DIR/naked-functions.rs:207:1
    |
 LL | #[inline(always)]
    | ^^^^^^^^^^^^^^^^^
@@ -338,7 +338,7 @@ LL | #[inline(always)]
    = note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
 
 warning: naked functions cannot be inlined
-  --> $DIR/naked-functions.rs:206:1
+  --> $DIR/naked-functions.rs:210:1
    |
 LL | #[inline(never)]
    | ^^^^^^^^^^^^^^^^
index 9f487bd8061fc5994d3c7cfed36dcaf91f3dcce0..82c47945a7b302c4db11ee389e3c54877b98a46c 100644 (file)
@@ -1,4 +1,7 @@
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
 
 // Tests that the use of named labels in the `asm!` macro are linted against
 // except for in `#[naked]` fns.
@@ -99,9 +102,6 @@ fn main() {
         asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70"); //~ ERROR avoid using named labels
 
         // Non-label colons - should pass
-        // (most of these are stolen from other places)
-        asm!("{:l}", in(reg) 0i64);
-        asm!("{:e}", in(reg) 0f32);
         asm!("mov rax, qword ptr fs:[0]");
 
         // Comments
index 396f0a1942428800f0e711f817b4332f941da732..75c848cdc572d37a64b92122b904dbd303b65f94 100644 (file)
@@ -1,5 +1,5 @@
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:19:15
+  --> $DIR/named-asm-labels.rs:22:15
    |
 LL |         asm!("bar: nop");
    |               ^^^
@@ -9,7 +9,7 @@ LL |         asm!("bar: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:22:15
+  --> $DIR/named-asm-labels.rs:25:15
    |
 LL |         asm!("abcd:");
    |               ^^^^
@@ -18,7 +18,7 @@ LL |         asm!("abcd:");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:25:15
+  --> $DIR/named-asm-labels.rs:28:15
    |
 LL |         asm!("foo: bar1: nop");
    |               ^^^  ^^^^
@@ -27,7 +27,7 @@ LL |         asm!("foo: bar1: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:29:15
+  --> $DIR/named-asm-labels.rs:32:15
    |
 LL |         asm!("foo1: nop", "nop");
    |               ^^^^
@@ -36,7 +36,7 @@ LL |         asm!("foo1: nop", "nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:30:15
+  --> $DIR/named-asm-labels.rs:33:15
    |
 LL |         asm!("foo2: foo3: nop", "nop");
    |               ^^^^  ^^^^
@@ -45,7 +45,7 @@ LL |         asm!("foo2: foo3: nop", "nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:32:22
+  --> $DIR/named-asm-labels.rs:35:22
    |
 LL |         asm!("nop", "foo4: nop");
    |                      ^^^^
@@ -54,7 +54,7 @@ LL |         asm!("nop", "foo4: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:33:15
+  --> $DIR/named-asm-labels.rs:36:15
    |
 LL |         asm!("foo5: nop", "foo6: nop");
    |               ^^^^
@@ -63,7 +63,7 @@ LL |         asm!("foo5: nop", "foo6: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:33:28
+  --> $DIR/named-asm-labels.rs:36:28
    |
 LL |         asm!("foo5: nop", "foo6: nop");
    |                            ^^^^
@@ -72,7 +72,7 @@ LL |         asm!("foo5: nop", "foo6: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:38:15
+  --> $DIR/named-asm-labels.rs:41:15
    |
 LL |         asm!("foo7: nop; foo8: nop");
    |               ^^^^       ^^^^
@@ -81,7 +81,7 @@ LL |         asm!("foo7: nop; foo8: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:40:15
+  --> $DIR/named-asm-labels.rs:43:15
    |
 LL |         asm!("foo9: nop; nop");
    |               ^^^^
@@ -90,7 +90,7 @@ LL |         asm!("foo9: nop; nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:41:20
+  --> $DIR/named-asm-labels.rs:44:20
    |
 LL |         asm!("nop; foo10: nop");
    |                    ^^^^^
@@ -99,7 +99,7 @@ LL |         asm!("nop; foo10: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:44:15
+  --> $DIR/named-asm-labels.rs:47:15
    |
 LL |         asm!("bar2: nop\n bar3: nop");
    |               ^^^^        ^^^^
@@ -108,7 +108,7 @@ LL |         asm!("bar2: nop\n bar3: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:46:15
+  --> $DIR/named-asm-labels.rs:49:15
    |
 LL |         asm!("bar4: nop\n nop");
    |               ^^^^
@@ -117,7 +117,7 @@ LL |         asm!("bar4: nop\n nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:47:21
+  --> $DIR/named-asm-labels.rs:50:21
    |
 LL |         asm!("nop\n bar5: nop");
    |                     ^^^^
@@ -126,7 +126,7 @@ LL |         asm!("nop\n bar5: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:48:21
+  --> $DIR/named-asm-labels.rs:51:21
    |
 LL |         asm!("nop\n bar6: bar7: nop");
    |                     ^^^^  ^^^^
@@ -135,7 +135,7 @@ LL |         asm!("nop\n bar6: bar7: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:54:13
+  --> $DIR/named-asm-labels.rs:57:13
    |
 LL |             blah2: nop
    |             ^^^^^
@@ -146,7 +146,7 @@ LL |             blah3: nop
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:63:19
+  --> $DIR/named-asm-labels.rs:66:19
    |
 LL |             nop ; blah4: nop
    |                   ^^^^^
@@ -155,7 +155,7 @@ LL |             nop ; blah4: nop
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:77:15
+  --> $DIR/named-asm-labels.rs:80:15
    |
 LL |         asm!("blah1: 2bar: nop");
    |               ^^^^^
@@ -164,7 +164,7 @@ LL |         asm!("blah1: 2bar: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:80:15
+  --> $DIR/named-asm-labels.rs:83:15
    |
 LL |         asm!("def: def: nop");
    |               ^^^
@@ -173,7 +173,7 @@ LL |         asm!("def: def: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:81:15
+  --> $DIR/named-asm-labels.rs:84:15
    |
 LL |         asm!("def: nop\ndef: nop");
    |               ^^^
@@ -182,7 +182,7 @@ LL |         asm!("def: nop\ndef: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:82:15
+  --> $DIR/named-asm-labels.rs:85:15
    |
 LL |         asm!("def: nop; def: nop");
    |               ^^^
@@ -191,7 +191,7 @@ LL |         asm!("def: nop; def: nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:90:15
+  --> $DIR/named-asm-labels.rs:93:15
    |
 LL |         asm!("fooo\u{003A} nop");
    |               ^^^^^^^^^^^^^^^^
@@ -200,7 +200,7 @@ LL |         asm!("fooo\u{003A} nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:91:15
+  --> $DIR/named-asm-labels.rs:94:15
    |
 LL |         asm!("foooo\x3A nop");
    |               ^^^^^^^^^^^^^
@@ -209,7 +209,7 @@ LL |         asm!("foooo\x3A nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:94:15
+  --> $DIR/named-asm-labels.rs:97:15
    |
 LL |         asm!("fooooo:\u{000A} nop");
    |               ^^^^^^
@@ -218,7 +218,7 @@ LL |         asm!("fooooo:\u{000A} nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:95:15
+  --> $DIR/named-asm-labels.rs:98:15
    |
 LL |         asm!("foooooo:\x0A nop");
    |               ^^^^^^^
@@ -227,7 +227,7 @@ LL |         asm!("foooooo:\x0A nop");
    = note: see the asm section of the unstable book <https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#labels> for more information
 
 error: avoid using named labels in inline assembly
-  --> $DIR/named-asm-labels.rs:99:14
+  --> $DIR/named-asm-labels.rs:102:14
    |
 LL |         asm!("\x41\x42\x43\x3A\x20\x6E\x6F\x70");
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 5e1ee93bfb0735320c3266feaa9b0a4fa0d30034..cb92ff0ad1d6d863aa2dc17d6852dd8c4d4aa262 100644 (file)
@@ -1,4 +1,4 @@
-// only-x86_64
+// needs-asm-support
 // check-pass
 
 #![feature(asm, never_type)]
diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/parse-error.rs
deleted file mode 100644 (file)
index fa14c52..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-// only-x86_64
-
-#![feature(asm, global_asm)]
-
-fn main() {
-    let mut foo = 0;
-    let mut bar = 0;
-    unsafe {
-        asm!();
-        //~^ ERROR requires at least a template string argument
-        asm!(foo);
-        //~^ ERROR asm template must be a string literal
-        asm!("{}" foo);
-        //~^ ERROR expected token: `,`
-        asm!("{}", foo);
-        //~^ ERROR expected operand, clobber_abi, options, or additional template string
-        asm!("{}", in foo);
-        //~^ ERROR expected `(`, found `foo`
-        asm!("{}", in(reg foo));
-        //~^ ERROR expected `)`, found `foo`
-        asm!("{}", in(reg));
-        //~^ ERROR expected expression, found end of macro arguments
-        asm!("{}", inout(=) foo => bar);
-        //~^ ERROR expected register class or explicit register
-        asm!("{}", inout(reg) foo =>);
-        //~^ ERROR expected expression, found end of macro arguments
-        asm!("{}", in(reg) foo => bar);
-        //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
-        asm!("{}", sym foo + bar);
-        //~^ ERROR argument to `sym` must be a path expression
-        asm!("", options(foo));
-        //~^ ERROR expected one of
-        asm!("", options(nomem foo));
-        //~^ ERROR expected one of
-        asm!("", options(nomem, foo));
-        //~^ ERROR expected one of
-        asm!("{}", options(), const foo);
-        //~^ ERROR arguments are not allowed after options
-        //~^^ ERROR attempt to use a non-constant value in a constant
-        asm!("", clobber_abi(foo));
-        //~^ ERROR expected string literal
-        asm!("", clobber_abi("C" foo));
-        //~^ ERROR expected `)`, found `foo`
-        asm!("", clobber_abi("C", foo));
-        //~^ ERROR expected `)`, found `,`
-        asm!("{}", clobber_abi("C"), const foo);
-        //~^ ERROR arguments are not allowed after clobber_abi
-        //~^^ ERROR attempt to use a non-constant value in a constant
-        asm!("", options(), clobber_abi("C"));
-        //~^ ERROR clobber_abi is not allowed after options
-        asm!("{}", options(), clobber_abi("C"), const foo);
-        //~^ ERROR clobber_abi is not allowed after options
-        asm!("", clobber_abi("C"), clobber_abi("C"));
-        //~^ ERROR clobber_abi specified multiple times
-        asm!("{a}", a = const foo, a = const bar);
-        //~^ ERROR duplicate argument named `a`
-        //~^^ ERROR argument never used
-        //~^^^ ERROR attempt to use a non-constant value in a constant
-        //~^^^^ ERROR attempt to use a non-constant value in a constant
-        asm!("", a = in("eax") foo);
-        //~^ ERROR explicit register arguments cannot have names
-        asm!("{a}", in("eax") foo, a = const bar);
-        //~^ ERROR named arguments cannot follow explicit register arguments
-        //~^^ ERROR attempt to use a non-constant value in a constant
-        asm!("{a}", in("eax") foo, a = const bar);
-        //~^ ERROR named arguments cannot follow explicit register arguments
-        //~^^ ERROR attempt to use a non-constant value in a constant
-        asm!("{1}", in("eax") foo, const bar);
-        //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
-        //~^^ ERROR attempt to use a non-constant value in a constant
-        asm!("", options(), "");
-        //~^ ERROR expected one of
-        asm!("{}", in(reg) foo, "{}", out(reg) foo);
-        //~^ ERROR expected one of
-        asm!(format!("{{{}}}", 0), in(reg) foo);
-        //~^ ERROR asm template must be a string literal
-        asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
-        //~^ ERROR asm template must be a string literal
-        asm!("{}", in(reg) _);
-        //~^ ERROR _ cannot be used for input operands
-        asm!("{}", inout(reg) _);
-        //~^ ERROR _ cannot be used for input operands
-        asm!("{}", inlateout(reg) _);
-        //~^ ERROR _ cannot be used for input operands
-    }
-}
-
-const FOO: i32 = 1;
-const BAR: i32 = 2;
-global_asm!();
-//~^ ERROR requires at least a template string argument
-global_asm!(FOO);
-//~^ ERROR asm template must be a string literal
-global_asm!("{}" FOO);
-//~^ ERROR expected token: `,`
-global_asm!("{}", FOO);
-//~^ ERROR expected operand, options, or additional template string
-global_asm!("{}", const);
-//~^ ERROR expected expression, found end of macro arguments
-global_asm!("{}", const(reg) FOO);
-//~^ ERROR expected one of
-global_asm!("", options(FOO));
-//~^ ERROR expected one of
-global_asm!("", options(nomem FOO));
-//~^ ERROR expected one of
-global_asm!("", options(nomem, FOO));
-//~^ ERROR expected one of
-global_asm!("{}", options(), const FOO);
-//~^ ERROR arguments are not allowed after options
-global_asm!("", clobber_abi(FOO));
-//~^ ERROR expected string literal
-global_asm!("", clobber_abi("C" FOO));
-//~^ ERROR expected `)`, found `FOO`
-global_asm!("", clobber_abi("C", FOO));
-//~^ ERROR expected `)`, found `,`
-global_asm!("{}", clobber_abi("C"), const FOO);
-//~^ ERROR arguments are not allowed after clobber_abi
-//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
-global_asm!("", options(), clobber_abi("C"));
-//~^ ERROR clobber_abi is not allowed after options
-global_asm!("{}", options(), clobber_abi("C"), const FOO);
-//~^ ERROR clobber_abi is not allowed after options
-global_asm!("", clobber_abi("C"), clobber_abi("C"));
-//~^ ERROR clobber_abi specified multiple times
-global_asm!("{a}", a = const FOO, a = const BAR);
-//~^ ERROR duplicate argument named `a`
-//~^^ ERROR argument never used
-global_asm!("", options(), "");
-//~^ ERROR expected one of
-global_asm!("{}", const FOO, "{}", const FOO);
-//~^ ERROR expected one of
-global_asm!(format!("{{{}}}", 0), const FOO);
-//~^ ERROR asm template must be a string literal
-global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
-//~^ ERROR asm template must be a string literal
diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr
deleted file mode 100644 (file)
index 78d342c..0000000
+++ /dev/null
@@ -1,462 +0,0 @@
-error: requires at least a template string argument
-  --> $DIR/parse-error.rs:9:9
-   |
-LL |         asm!();
-   |         ^^^^^^^
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:11:14
-   |
-LL |         asm!(foo);
-   |              ^^^
-
-error: expected token: `,`
-  --> $DIR/parse-error.rs:13:19
-   |
-LL |         asm!("{}" foo);
-   |                   ^^^ expected `,`
-
-error: expected operand, clobber_abi, options, or additional template string
-  --> $DIR/parse-error.rs:15:20
-   |
-LL |         asm!("{}", foo);
-   |                    ^^^ expected operand, clobber_abi, options, or additional template string
-
-error: expected `(`, found `foo`
-  --> $DIR/parse-error.rs:17:23
-   |
-LL |         asm!("{}", in foo);
-   |                       ^^^ expected `(`
-
-error: expected `)`, found `foo`
-  --> $DIR/parse-error.rs:19:27
-   |
-LL |         asm!("{}", in(reg foo));
-   |                           ^^^ expected `)`
-
-error: expected expression, found end of macro arguments
-  --> $DIR/parse-error.rs:21:27
-   |
-LL |         asm!("{}", in(reg));
-   |                           ^ expected expression
-
-error: expected register class or explicit register
-  --> $DIR/parse-error.rs:23:26
-   |
-LL |         asm!("{}", inout(=) foo => bar);
-   |                          ^
-
-error: expected expression, found end of macro arguments
-  --> $DIR/parse-error.rs:25:37
-   |
-LL |         asm!("{}", inout(reg) foo =>);
-   |                                     ^ expected expression
-
-error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
-  --> $DIR/parse-error.rs:27:32
-   |
-LL |         asm!("{}", in(reg) foo => bar);
-   |                                ^^ expected one of 7 possible tokens
-
-error: argument to `sym` must be a path expression
-  --> $DIR/parse-error.rs:29:24
-   |
-LL |         asm!("{}", sym foo + bar);
-   |                        ^^^^^^^^^
-
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
-  --> $DIR/parse-error.rs:31:26
-   |
-LL |         asm!("", options(foo));
-   |                          ^^^ expected one of 9 possible tokens
-
-error: expected one of `)` or `,`, found `foo`
-  --> $DIR/parse-error.rs:33:32
-   |
-LL |         asm!("", options(nomem foo));
-   |                                ^^^ expected one of `)` or `,`
-
-error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
-  --> $DIR/parse-error.rs:35:33
-   |
-LL |         asm!("", options(nomem, foo));
-   |                                 ^^^ expected one of 9 possible tokens
-
-error: arguments are not allowed after options
-  --> $DIR/parse-error.rs:37:31
-   |
-LL |         asm!("{}", options(), const foo);
-   |                    ---------  ^^^^^^^^^ argument
-   |                    |
-   |                    previous options
-
-error: expected string literal
-  --> $DIR/parse-error.rs:40:30
-   |
-LL |         asm!("", clobber_abi(foo));
-   |                              ^^^ not a string literal
-
-error: expected `)`, found `foo`
-  --> $DIR/parse-error.rs:42:34
-   |
-LL |         asm!("", clobber_abi("C" foo));
-   |                                  ^^^ expected `)`
-
-error: expected `)`, found `,`
-  --> $DIR/parse-error.rs:44:33
-   |
-LL |         asm!("", clobber_abi("C", foo));
-   |                                 ^ expected `)`
-
-error: arguments are not allowed after clobber_abi
-  --> $DIR/parse-error.rs:46:38
-   |
-LL |         asm!("{}", clobber_abi("C"), const foo);
-   |                    ----------------  ^^^^^^^^^ argument
-   |                    |
-   |                    clobber_abi
-
-error: clobber_abi is not allowed after options
-  --> $DIR/parse-error.rs:49:29
-   |
-LL |         asm!("", options(), clobber_abi("C"));
-   |                  ---------  ^^^^^^^^^^^^^^^^
-   |                  |
-   |                  options
-
-error: clobber_abi is not allowed after options
-  --> $DIR/parse-error.rs:51:31
-   |
-LL |         asm!("{}", options(), clobber_abi("C"), const foo);
-   |                    ---------  ^^^^^^^^^^^^^^^^
-   |                    |
-   |                    options
-
-error: clobber_abi specified multiple times
-  --> $DIR/parse-error.rs:53:36
-   |
-LL |         asm!("", clobber_abi("C"), clobber_abi("C"));
-   |                  ----------------  ^^^^^^^^^^^^^^^^
-   |                  |
-   |                  clobber_abi previously specified here
-
-error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:55:36
-   |
-LL |         asm!("{a}", a = const foo, a = const bar);
-   |                     -------------  ^^^^^^^^^^^^^ duplicate argument
-   |                     |
-   |                     previously here
-
-error: argument never used
-  --> $DIR/parse-error.rs:55:36
-   |
-LL |         asm!("{a}", a = const foo, a = const bar);
-   |                                    ^^^^^^^^^^^^^ argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
-
-error: explicit register arguments cannot have names
-  --> $DIR/parse-error.rs:60:18
-   |
-LL |         asm!("", a = in("eax") foo);
-   |                  ^^^^^^^^^^^^^^^^^
-
-error: named arguments cannot follow explicit register arguments
-  --> $DIR/parse-error.rs:62:36
-   |
-LL |         asm!("{a}", in("eax") foo, a = const bar);
-   |                     -------------  ^^^^^^^^^^^^^ named argument
-   |                     |
-   |                     explicit register argument
-
-error: named arguments cannot follow explicit register arguments
-  --> $DIR/parse-error.rs:65:36
-   |
-LL |         asm!("{a}", in("eax") foo, a = const bar);
-   |                     -------------  ^^^^^^^^^^^^^ named argument
-   |                     |
-   |                     explicit register argument
-
-error: positional arguments cannot follow named arguments or explicit register arguments
-  --> $DIR/parse-error.rs:68:36
-   |
-LL |         asm!("{1}", in("eax") foo, const bar);
-   |                     -------------  ^^^^^^^^^ positional argument
-   |                     |
-   |                     explicit register argument
-
-error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
-  --> $DIR/parse-error.rs:71:29
-   |
-LL |         asm!("", options(), "");
-   |                             ^^ expected one of 9 possible tokens
-
-error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
-  --> $DIR/parse-error.rs:73:33
-   |
-LL |         asm!("{}", in(reg) foo, "{}", out(reg) foo);
-   |                                 ^^^^ expected one of 9 possible tokens
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:75:14
-   |
-LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
-   |              ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:77:21
-   |
-LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
-   |                     ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:79:28
-   |
-LL |         asm!("{}", in(reg) _);
-   |                            ^
-
-error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:81:31
-   |
-LL |         asm!("{}", inout(reg) _);
-   |                               ^
-
-error: _ cannot be used for input operands
-  --> $DIR/parse-error.rs:83:35
-   |
-LL |         asm!("{}", inlateout(reg) _);
-   |                                   ^
-
-error: requires at least a template string argument
-  --> $DIR/parse-error.rs:90:1
-   |
-LL | global_asm!();
-   | ^^^^^^^^^^^^^^
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:92:13
-   |
-LL | global_asm!(FOO);
-   |             ^^^
-
-error: expected token: `,`
-  --> $DIR/parse-error.rs:94:18
-   |
-LL | global_asm!("{}" FOO);
-   |                  ^^^ expected `,`
-
-error: expected operand, options, or additional template string
-  --> $DIR/parse-error.rs:96:19
-   |
-LL | global_asm!("{}", FOO);
-   |                   ^^^ expected operand, options, or additional template string
-
-error: expected expression, found end of macro arguments
-  --> $DIR/parse-error.rs:98:24
-   |
-LL | global_asm!("{}", const);
-   |                        ^ expected expression
-
-error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
-  --> $DIR/parse-error.rs:100:30
-   |
-LL | global_asm!("{}", const(reg) FOO);
-   |                              ^^^ expected one of `,`, `.`, `?`, or an operator
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
-  --> $DIR/parse-error.rs:102:25
-   |
-LL | global_asm!("", options(FOO));
-   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/parse-error.rs:104:25
-   |
-LL | global_asm!("", options(nomem FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
-  --> $DIR/parse-error.rs:106:25
-   |
-LL | global_asm!("", options(nomem, FOO));
-   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
-
-error: arguments are not allowed after options
-  --> $DIR/parse-error.rs:108:30
-   |
-LL | global_asm!("{}", options(), const FOO);
-   |                   ---------  ^^^^^^^^^ argument
-   |                   |
-   |                   previous options
-
-error: expected string literal
-  --> $DIR/parse-error.rs:110:29
-   |
-LL | global_asm!("", clobber_abi(FOO));
-   |                             ^^^ not a string literal
-
-error: expected `)`, found `FOO`
-  --> $DIR/parse-error.rs:112:33
-   |
-LL | global_asm!("", clobber_abi("C" FOO));
-   |                                 ^^^ expected `)`
-
-error: expected `)`, found `,`
-  --> $DIR/parse-error.rs:114:32
-   |
-LL | global_asm!("", clobber_abi("C", FOO));
-   |                                ^ expected `)`
-
-error: arguments are not allowed after clobber_abi
-  --> $DIR/parse-error.rs:116:37
-   |
-LL | global_asm!("{}", clobber_abi("C"), const FOO);
-   |                   ----------------  ^^^^^^^^^ argument
-   |                   |
-   |                   clobber_abi
-
-error: `clobber_abi` cannot be used with `global_asm!`
-  --> $DIR/parse-error.rs:116:19
-   |
-LL | global_asm!("{}", clobber_abi("C"), const FOO);
-   |                   ^^^^^^^^^^^^^^^^
-
-error: clobber_abi is not allowed after options
-  --> $DIR/parse-error.rs:119:28
-   |
-LL | global_asm!("", options(), clobber_abi("C"));
-   |                 ---------  ^^^^^^^^^^^^^^^^
-   |                 |
-   |                 options
-
-error: clobber_abi is not allowed after options
-  --> $DIR/parse-error.rs:121:30
-   |
-LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
-   |                   ---------  ^^^^^^^^^^^^^^^^
-   |                   |
-   |                   options
-
-error: clobber_abi specified multiple times
-  --> $DIR/parse-error.rs:123:35
-   |
-LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
-   |                 ----------------  ^^^^^^^^^^^^^^^^
-   |                 |
-   |                 clobber_abi previously specified here
-
-error: duplicate argument named `a`
-  --> $DIR/parse-error.rs:125:35
-   |
-LL | global_asm!("{a}", a = const FOO, a = const BAR);
-   |                    -------------  ^^^^^^^^^^^^^ duplicate argument
-   |                    |
-   |                    previously here
-
-error: argument never used
-  --> $DIR/parse-error.rs:125:35
-   |
-LL | global_asm!("{a}", a = const FOO, a = const BAR);
-   |                                   ^^^^^^^^^^^^^ argument never used
-   |
-   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
-
-error: expected one of `clobber_abi`, `const`, or `options`, found `""`
-  --> $DIR/parse-error.rs:128:28
-   |
-LL | global_asm!("", options(), "");
-   |                            ^^ expected one of `clobber_abi`, `const`, or `options`
-
-error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
-  --> $DIR/parse-error.rs:130:30
-   |
-LL | global_asm!("{}", const FOO, "{}", const FOO);
-   |                              ^^^^ expected one of `clobber_abi`, `const`, or `options`
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:132:13
-   |
-LL | global_asm!(format!("{{{}}}", 0), const FOO);
-   |             ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: asm template must be a string literal
-  --> $DIR/parse-error.rs:134:20
-   |
-LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
-   |                    ^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:37:37
-   |
-LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
-...
-LL |         asm!("{}", options(), const foo);
-   |                                     ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:46:44
-   |
-LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
-...
-LL |         asm!("{}", clobber_abi("C"), const foo);
-   |                                            ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:55:31
-   |
-LL |     let mut foo = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const foo`
-...
-LL |         asm!("{a}", a = const foo, a = const bar);
-   |                               ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:55:46
-   |
-LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
-...
-LL |         asm!("{a}", a = const foo, a = const bar);
-   |                                              ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:62:46
-   |
-LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
-...
-LL |         asm!("{a}", in("eax") foo, a = const bar);
-   |                                              ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:65:46
-   |
-LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
-...
-LL |         asm!("{a}", in("eax") foo, a = const bar);
-   |                                              ^^^ non-constant value
-
-error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/parse-error.rs:68:42
-   |
-LL |     let mut bar = 0;
-   |      ---------- help: consider using `const` instead of `let`: `const bar`
-...
-LL |         asm!("{1}", in("eax") foo, const bar);
-   |                                          ^^^ non-constant value
-
-error: aborting due to 66 previous errors
-
-For more information about this error, try `rustc --explain E0435`.
index 9251afd3f059f6c7c661d84a57ee118962c2dd05..1d5d2038aa89caa0c8e4ee056a5e9962cc355d4b 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-// only-x86_64
+// needs-asm-support
 
 #![feature(asm, llvm_asm)]
 #![allow(deprecated)] // llvm_asm!
index 1e3bfd077081cf242671ee163c2320cd29d59a63..12be0e666ee141bfad8233f6c3e75f1a7aeec6ff 100644 (file)
@@ -1,5 +1,5 @@
 // run-rustfix
-// only-x86_64
+// needs-asm-support
 
 #![feature(asm, llvm_asm)]
 #![allow(deprecated)] // llvm_asm!
diff --git a/src/test/ui/asm/srcloc.rs b/src/test/ui/asm/srcloc.rs
deleted file mode 100644 (file)
index ed8cefc..0000000
+++ /dev/null
@@ -1,124 +0,0 @@
-// min-llvm-version: 10.0.1
-// only-x86_64
-// build-fail
-// compile-flags: -Ccodegen-units=1
-#![feature(asm)]
-
-// Checks that inline asm errors are mapped to the correct line in the source code.
-
-fn main() {
-    unsafe {
-        asm!("invalid_instruction");
-        //~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!("
-            invalid_instruction
-        ");
-        //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!(r#"
-            invalid_instruction
-        "#);
-        //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!("
-            mov eax, eax
-            invalid_instruction
-            mov eax, eax
-        ");
-        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!(r#"
-            mov eax, eax
-            invalid_instruction
-            mov eax, eax
-        "#);
-        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!(concat!("invalid", "_", "instruction"));
-        //~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
-        //~^ WARN: scale factor without index register is ignored
-
-        asm!(
-            "invalid_instruction",
-        );
-        //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!(
-            "mov eax, eax",
-            "invalid_instruction",
-            "mov eax, eax",
-        );
-        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!(
-            "mov eax, eax\n",
-            "invalid_instruction",
-            "mov eax, eax",
-        );
-        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!(
-            "mov eax, eax",
-            concat!("invalid", "_", "instruction"),
-            "mov eax, eax",
-        );
-        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        asm!(
-            concat!("mov eax", ", ", "eax"),
-            concat!("invalid", "_", "instruction"),
-            concat!("mov eax", ", ", "eax"),
-        );
-        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
-
-        // Make sure template strings get separated
-        asm!(
-            "invalid_instruction1",
-            "invalid_instruction2",
-        );
-        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
-        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
-
-        asm!(
-            concat!(
-                "invalid", "_", "instruction1", "\n",
-                "invalid", "_", "instruction2",
-            ),
-        );
-        //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
-        //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
-
-        asm!(
-            concat!(
-                "invalid", "_", "instruction1", "\n",
-                "invalid", "_", "instruction2",
-            ),
-            concat!(
-                "invalid", "_", "instruction3", "\n",
-                "invalid", "_", "instruction4",
-            ),
-        );
-        //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
-        //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
-        //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
-        //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
-
-        asm!(
-            concat!(
-                "invalid", "_", "instruction1", "\n",
-                "invalid", "_", "instruction2", "\n",
-            ),
-            concat!(
-                "invalid", "_", "instruction3", "\n",
-                "invalid", "_", "instruction4", "\n",
-            ),
-        );
-        //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
-        //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
-        //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
-        //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
-    }
-}
diff --git a/src/test/ui/asm/srcloc.stderr b/src/test/ui/asm/srcloc.stderr
deleted file mode 100644 (file)
index b62c894..0000000
+++ /dev/null
@@ -1,290 +0,0 @@
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:11:15
-   |
-LL |         asm!("invalid_instruction");
-   |               ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:2:2
-   |
-LL |     invalid_instruction
-   |     ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:15:13
-   |
-LL |             invalid_instruction
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:13
-   |
-LL |             invalid_instruction
-   |             ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:20:13
-   |
-LL |             invalid_instruction
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:13
-   |
-LL |             invalid_instruction
-   |             ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:26:13
-   |
-LL |             invalid_instruction
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:4:13
-   |
-LL |             invalid_instruction
-   |             ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:33:13
-   |
-LL |             invalid_instruction
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:4:13
-   |
-LL |             invalid_instruction
-   |             ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:38:14
-   |
-LL |         asm!(concat!("invalid", "_", "instruction"));
-   |              ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:2:2
-   |
-LL |     invalid_instruction
-   |     ^^^^^^^^^^^^^^^^^^^
-
-warning: scale factor without index register is ignored
-  --> $DIR/srcloc.rs:41:15
-   |
-LL |         asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
-   |               ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:1:23
-   |
-LL |     movaps %xmm3, (%esi, 2)
-   |                          ^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:45:14
-   |
-LL |             "invalid_instruction",
-   |              ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:2:2
-   |
-LL |     invalid_instruction
-   |     ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:51:14
-   |
-LL |             "invalid_instruction",
-   |              ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:1
-   |
-LL | invalid_instruction
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:58:14
-   |
-LL |             "invalid_instruction",
-   |              ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:4:1
-   |
-LL | invalid_instruction
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:65:13
-   |
-LL |             concat!("invalid", "_", "instruction"),
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:1
-   |
-LL | invalid_instruction
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction'
-  --> $DIR/srcloc.rs:72:13
-   |
-LL |             concat!("invalid", "_", "instruction"),
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:1
-   |
-LL | invalid_instruction
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:79:14
-   |
-LL |             "invalid_instruction1",
-   |              ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:2:2
-   |
-LL |     invalid_instruction1
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:80:14
-   |
-LL |             "invalid_instruction2",
-   |              ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:1
-   |
-LL | invalid_instruction2
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:86:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:2:2
-   |
-LL |     invalid_instruction1
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:86:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:1
-   |
-LL | invalid_instruction2
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:95:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:2:2
-   |
-LL |     invalid_instruction1
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:95:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:1
-   |
-LL | invalid_instruction2
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction3'
-  --> $DIR/srcloc.rs:99:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:4:1
-   |
-LL | invalid_instruction3
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction4'
-  --> $DIR/srcloc.rs:99:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:5:1
-   |
-LL | invalid_instruction4
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction1'
-  --> $DIR/srcloc.rs:110:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:2:2
-   |
-LL |     invalid_instruction1
-   |     ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction2'
-  --> $DIR/srcloc.rs:110:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:3:1
-   |
-LL | invalid_instruction2
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction3'
-  --> $DIR/srcloc.rs:114:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:5:1
-   |
-LL | invalid_instruction3
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: invalid instruction mnemonic 'invalid_instruction4'
-  --> $DIR/srcloc.rs:114:13
-   |
-LL |             concat!(
-   |             ^
-   |
-note: instantiated into assembly here
-  --> <inline asm>:6:1
-   |
-LL | invalid_instruction4
-   | ^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 23 previous errors; 1 warning emitted
-
diff --git a/src/test/ui/asm/sym.rs b/src/test/ui/asm/sym.rs
deleted file mode 100644 (file)
index 634ef01..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-// min-llvm-version: 10.0.1
-// only-x86_64
-// only-linux
-// run-pass
-
-#![feature(asm, thread_local)]
-
-extern "C" fn f1() -> i32 {
-    111
-}
-
-// The compiler will generate a shim to hide the caller location parameter.
-#[track_caller]
-fn f2() -> i32 {
-    222
-}
-
-macro_rules! call {
-    ($func:path) => {
-        unsafe {
-            let result: i32;
-            asm!("call {}", sym $func,
-                out("rax") result,
-                out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _,
-                out("r8") _, out("r9") _, out("r10") _, out("r11") _,
-                out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
-                out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
-                out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
-                out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
-            );
-            result
-        }
-    }
-}
-
-macro_rules! static_addr {
-    ($s:expr) => {
-        unsafe {
-            let result: *const u32;
-            // LEA performs a RIP-relative address calculation and returns the address
-            asm!("lea {}, [rip + {}]", out(reg) result, sym $s);
-            result
-        }
-    }
-}
-macro_rules! static_tls_addr {
-    ($s:expr) => {
-        unsafe {
-            let result: *const u32;
-            asm!(
-                "
-                    # Load TLS base address
-                    mov {out}, qword ptr fs:[0]
-                    # Calculate the address of sym in the TLS block. The @tpoff
-                    # relocation gives the offset of the symbol from the start
-                    # of the TLS block.
-                    lea {out}, [{out} + {sym}@tpoff]
-                ",
-                out = out(reg) result,
-                sym = sym $s
-            );
-            result
-        }
-    }
-}
-
-static S1: u32 = 111;
-#[thread_local]
-static S2: u32 = 222;
-
-fn main() {
-    assert_eq!(call!(f1), 111);
-    assert_eq!(call!(f2), 222);
-    assert_eq!(static_addr!(S1), &S1 as *const u32);
-    assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
-    std::thread::spawn(|| {
-        assert_eq!(static_addr!(S1), &S1 as *const u32);
-        assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
-    }).join().unwrap();
-}
index 5e38fb70a4adfd7240d7506e9ab238d13d52f7ff..bbbe798d1557b0e095559ae2cff6fcfd19ebede2 100644 (file)
@@ -1,4 +1,7 @@
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
 
 #![feature(asm, global_asm)]
 
@@ -49,6 +52,8 @@ const fn const_bar<T>(x: T) -> T {
         //~^ ERROR mismatched types
         asm!("{}", const 0 as *mut u8);
         //~^ ERROR mismatched types
+        asm!("{}", const &0);
+        //~^ ERROR mismatched types
     }
 }
 
index 5edbcf4a2a7c939a327dc66b1a9e8042d31de97a..c9080a3c0309a2fa819c2e981b95933a572ffce8 100644 (file)
@@ -1,5 +1,5 @@
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/type-check-1.rs:34:26
+  --> $DIR/type-check-1.rs:37:26
    |
 LL |         let x = 0;
    |         ----- help: consider using `const` instead of `let`: `const x`
@@ -8,7 +8,7 @@ LL |         asm!("{}", const x);
    |                          ^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/type-check-1.rs:37:36
+  --> $DIR/type-check-1.rs:40:36
    |
 LL |         let x = 0;
    |         ----- help: consider using `const` instead of `let`: `const x`
@@ -17,7 +17,7 @@ LL |         asm!("{}", const const_foo(x));
    |                                    ^ non-constant value
 
 error[E0435]: attempt to use a non-constant value in a constant
-  --> $DIR/type-check-1.rs:40:36
+  --> $DIR/type-check-1.rs:43:36
    |
 LL |         let x = 0;
    |         ----- help: consider using `const` instead of `let`: `const x`
@@ -26,13 +26,13 @@ LL |         asm!("{}", const const_bar(x));
    |                                    ^ non-constant value
 
 error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:48:26
+  --> $DIR/type-check-1.rs:51:26
    |
 LL |         asm!("{}", const 0f32);
    |                          ^^^^ expected integer, found `f32`
 
 error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:50:26
+  --> $DIR/type-check-1.rs:53:26
    |
 LL |         asm!("{}", const 0 as *mut u8);
    |                          ^^^^^^^^^^^^ expected integer, found *-ptr
@@ -40,20 +40,32 @@ LL |         asm!("{}", const 0 as *mut u8);
    = note:     expected type `{integer}`
            found raw pointer `*mut u8`
 
+error[E0308]: mismatched types
+  --> $DIR/type-check-1.rs:55:26
+   |
+LL |         asm!("{}", const &0);
+   |                          ^^ expected integer, found `&{integer}`
+   |
+help: consider removing the borrow
+   |
+LL -         asm!("{}", const &0);
+LL +         asm!("{}", const 0);
+   | 
+
 error: invalid asm output
-  --> $DIR/type-check-1.rs:10:29
+  --> $DIR/type-check-1.rs:13:29
    |
 LL |         asm!("{}", out(reg) 1 + 2);
    |                             ^^^^^ cannot assign to this expression
 
 error: invalid asm output
-  --> $DIR/type-check-1.rs:12:31
+  --> $DIR/type-check-1.rs:15:31
    |
 LL |         asm!("{}", inout(reg) 1 + 2);
    |                               ^^^^^ cannot assign to this expression
 
 error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
-  --> $DIR/type-check-1.rs:18:28
+  --> $DIR/type-check-1.rs:21:28
    |
 LL |         asm!("{}", in(reg) v[..]);
    |                            ^^^^^ doesn't have a size known at compile-time
@@ -62,7 +74,7 @@ LL |         asm!("{}", in(reg) v[..]);
    = note: all inline asm arguments must have a statically known size
 
 error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
-  --> $DIR/type-check-1.rs:20:29
+  --> $DIR/type-check-1.rs:23:29
    |
 LL |         asm!("{}", out(reg) v[..]);
    |                             ^^^^^ doesn't have a size known at compile-time
@@ -71,7 +83,7 @@ LL |         asm!("{}", out(reg) v[..]);
    = note: all inline asm arguments must have a statically known size
 
 error[E0277]: the size for values of type `[u64]` cannot be known at compilation time
-  --> $DIR/type-check-1.rs:22:31
+  --> $DIR/type-check-1.rs:25:31
    |
 LL |         asm!("{}", inout(reg) v[..]);
    |                               ^^^^^ doesn't have a size known at compile-time
@@ -80,13 +92,13 @@ LL |         asm!("{}", inout(reg) v[..]);
    = note: all inline asm arguments must have a statically known size
 
 error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:60:25
+  --> $DIR/type-check-1.rs:65:25
    |
 LL | global_asm!("{}", const 0f32);
    |                         ^^^^ expected integer, found `f32`
 
 error[E0308]: mismatched types
-  --> $DIR/type-check-1.rs:62:25
+  --> $DIR/type-check-1.rs:67:25
    |
 LL | global_asm!("{}", const 0 as *mut u8);
    |                         ^^^^^^^^^^^^ expected integer, found *-ptr
@@ -94,7 +106,7 @@ LL | global_asm!("{}", const 0 as *mut u8);
    = note:     expected type `{integer}`
            found raw pointer `*mut u8`
 
-error: aborting due to 12 previous errors
+error: aborting due to 13 previous errors
 
 Some errors have detailed explanations: E0277, E0308, E0435.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/src/test/ui/asm/type-check-2.rs b/src/test/ui/asm/type-check-2.rs
deleted file mode 100644 (file)
index c70a880..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-// only-x86_64
-
-#![feature(asm, repr_simd, never_type)]
-
-#[repr(simd)]
-struct SimdNonCopy(f32, f32, f32, f32);
-
-fn main() {
-    unsafe {
-        // Inputs must be initialized
-
-        let x: u64;
-        asm!("{}", in(reg) x);
-        //~^ ERROR use of possibly-uninitialized variable: `x`
-        let mut y: u64;
-        asm!("{}", inout(reg) y);
-        //~^ ERROR use of possibly-uninitialized variable: `y`
-        let _ = y;
-
-        // Outputs require mutable places
-
-        let v: Vec<u64> = vec![0, 1, 2];
-        asm!("{}", in(reg) v[0]);
-        asm!("{}", out(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
-        asm!("{}", inout(reg) v[0]);
-        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
-
-        // This currently causes an ICE: https://github.com/rust-lang/rust/issues/81857
-        // asm!("{}", const &0);
-        // ERROR asm `const` arguments must be integer or floating-point values
-
-        // Sym operands must point to a function or static
-
-        const C: i32 = 0;
-        static S: i32 = 0;
-        asm!("{}", sym S);
-        asm!("{}", sym main);
-        asm!("{}", sym C);
-        //~^ ERROR asm `sym` operand must point to a fn or static
-        asm!("{}", sym x);
-        //~^ ERROR asm `sym` operand must point to a fn or static
-
-        // Register operands must be Copy
-
-        asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
-        //~^ ERROR arguments for inline assembly must be copyable
-
-        // Register operands must be integers, floats, SIMD vectors, pointers or
-        // function pointers.
-
-        asm!("{}", in(reg) 0i64);
-        asm!("{}", in(reg) 0f64);
-        asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps());
-        asm!("{}", in(reg) 0 as *const u8);
-        asm!("{}", in(reg) 0 as *mut u8);
-        asm!("{}", in(reg) main as fn());
-        asm!("{}", in(reg) |x: i32| x);
-        //~^ ERROR cannot use value of type
-        asm!("{}", in(reg) vec![0]);
-        //~^ ERROR cannot use value of type `Vec<i32>` for inline assembly
-        asm!("{}", in(reg) (1, 2, 3));
-        //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly
-        asm!("{}", in(reg) [1, 2, 3]);
-        //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly
-
-        // Register inputs (but not outputs) allow references and function types
-
-        let mut f = main;
-        let mut r = &mut 0;
-        asm!("{}", in(reg) f);
-        asm!("{}", inout(reg) f);
-        //~^ ERROR cannot use value of type `fn() {main}` for inline assembly
-        asm!("{}", in(reg) r);
-        asm!("{}", inout(reg) r);
-        //~^ ERROR cannot use value of type `&mut i32` for inline assembly
-        let _ = (f, r);
-
-        // Type checks ignore never type
-
-        let u: ! = unreachable!();
-        asm!("{}", in(reg) u);
-    }
-}
diff --git a/src/test/ui/asm/type-check-2.stderr b/src/test/ui/asm/type-check-2.stderr
deleted file mode 100644 (file)
index 1354a9d..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-error: arguments for inline assembly must be copyable
-  --> $DIR/type-check-2.rs:46:32
-   |
-LL |         asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
-   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-   = note: `SimdNonCopy` does not implement the Copy trait
-
-error: cannot use value of type `[closure@$DIR/type-check-2.rs:58:28: 58:38]` for inline assembly
-  --> $DIR/type-check-2.rs:58:28
-   |
-LL |         asm!("{}", in(reg) |x: i32| x);
-   |                            ^^^^^^^^^^
-   |
-   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: cannot use value of type `Vec<i32>` for inline assembly
-  --> $DIR/type-check-2.rs:60:28
-   |
-LL |         asm!("{}", in(reg) vec![0]);
-   |                            ^^^^^^^
-   |
-   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
-
-error: cannot use value of type `(i32, i32, i32)` for inline assembly
-  --> $DIR/type-check-2.rs:62:28
-   |
-LL |         asm!("{}", in(reg) (1, 2, 3));
-   |                            ^^^^^^^^^
-   |
-   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: cannot use value of type `[i32; 3]` for inline assembly
-  --> $DIR/type-check-2.rs:64:28
-   |
-LL |         asm!("{}", in(reg) [1, 2, 3]);
-   |                            ^^^^^^^^^
-   |
-   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: cannot use value of type `fn() {main}` for inline assembly
-  --> $DIR/type-check-2.rs:72:31
-   |
-LL |         asm!("{}", inout(reg) f);
-   |                               ^
-   |
-   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: cannot use value of type `&mut i32` for inline assembly
-  --> $DIR/type-check-2.rs:75:31
-   |
-LL |         asm!("{}", inout(reg) r);
-   |                               ^
-   |
-   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
-
-error: asm `sym` operand must point to a fn or static
-  --> $DIR/type-check-2.rs:39:24
-   |
-LL |         asm!("{}", sym C);
-   |                        ^
-
-error: asm `sym` operand must point to a fn or static
-  --> $DIR/type-check-2.rs:41:24
-   |
-LL |         asm!("{}", sym x);
-   |                        ^
-
-error[E0381]: use of possibly-uninitialized variable: `x`
-  --> $DIR/type-check-2.rs:13:28
-   |
-LL |         asm!("{}", in(reg) x);
-   |                            ^ use of possibly-uninitialized `x`
-
-error[E0381]: use of possibly-uninitialized variable: `y`
-  --> $DIR/type-check-2.rs:16:9
-   |
-LL |         asm!("{}", inout(reg) y);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-2.rs:24:29
-   |
-LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
-LL |         asm!("{}", in(reg) v[0]);
-LL |         asm!("{}", out(reg) v[0]);
-   |                             ^ cannot borrow as mutable
-
-error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
-  --> $DIR/type-check-2.rs:26:31
-   |
-LL |         let v: Vec<u64> = vec![0, 1, 2];
-   |             - help: consider changing this to be mutable: `mut v`
-...
-LL |         asm!("{}", inout(reg) v[0]);
-   |                               ^ cannot borrow as mutable
-
-error: aborting due to 13 previous errors
-
-Some errors have detailed explanations: E0381, E0596.
-For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/asm/type-check-3.rs b/src/test/ui/asm/type-check-3.rs
deleted file mode 100644 (file)
index c2c1885..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-// only-x86_64
-// compile-flags: -C target-feature=+avx512f
-
-#![feature(asm, global_asm)]
-
-use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
-
-fn main() {
-    unsafe {
-        // Types must be listed in the register class.
-
-        asm!("{}", in(reg) 0i128);
-        //~^ ERROR type `i128` cannot be used with this register class
-        asm!("{}", in(reg) _mm_setzero_ps());
-        //~^ ERROR type `__m128` cannot be used with this register class
-        asm!("{}", in(reg) _mm256_setzero_ps());
-        //~^ ERROR type `__m256` cannot be used with this register class
-        asm!("{}", in(xmm_reg) 0u8);
-        //~^ ERROR type `u8` cannot be used with this register class
-        asm!("{:e}", in(reg) 0i32);
-        asm!("{}", in(xmm_reg) 0i32);
-        asm!("{:e}", in(reg) 0f32);
-        asm!("{}", in(xmm_reg) 0f32);
-        asm!("{}", in(xmm_reg) _mm_setzero_ps());
-        asm!("{:x}", in(ymm_reg) _mm_setzero_ps());
-        asm!("{}", in(kreg) 0u16);
-        asm!("{}", in(kreg) 0u64);
-        //~^ ERROR `avx512bw` target feature is not enabled
-
-        // Template modifier suggestions for sub-registers
-
-        asm!("{0} {0}", in(reg) 0i16);
-        //~^ WARN formatting may not be suitable for sub-register argument
-        asm!("{0} {0:x}", in(reg) 0i16);
-        //~^ WARN formatting may not be suitable for sub-register argument
-        asm!("{}", in(reg) 0i32);
-        //~^ WARN formatting may not be suitable for sub-register argument
-        asm!("{}", in(reg) 0i64);
-        asm!("{}", in(ymm_reg) 0i64);
-        //~^ WARN formatting may not be suitable for sub-register argument
-        asm!("{}", in(ymm_reg) _mm256_setzero_ps());
-        asm!("{:l}", in(reg) 0i16);
-        asm!("{:l}", in(reg) 0i32);
-        asm!("{:l}", in(reg) 0i64);
-        asm!("{:x}", in(ymm_reg) 0i64);
-        asm!("{:x}", in(ymm_reg) _mm256_setzero_ps());
-
-        // Suggest different register class for type
-
-        asm!("{}", in(reg) 0i8);
-        //~^ ERROR type `i8` cannot be used with this register class
-        asm!("{}", in(reg_byte) 0i8);
-
-        // Split inout operands must have compatible types
-
-        let mut val_i16: i16;
-        let mut val_f32: f32;
-        let mut val_u32: u32;
-        let mut val_u64: u64;
-        let mut val_ptr: *mut u8;
-        asm!("{:r}", inout(reg) 0u16 => val_i16);
-        asm!("{:r}", inout(reg) 0u32 => val_f32);
-        //~^ ERROR incompatible types for asm inout argument
-        asm!("{:r}", inout(reg) 0u32 => val_ptr);
-        //~^ ERROR incompatible types for asm inout argument
-        asm!("{:r}", inout(reg) main => val_u32);
-        //~^ ERROR incompatible types for asm inout argument
-        asm!("{:r}", inout(reg) 0u64 => val_ptr);
-        asm!("{:r}", inout(reg) main => val_u64);
-    }
-}
-
-// Constants must be... constant
-
-static S: i32 = 1;
-const fn const_foo(x: i32) -> i32 {
-    x
-}
-const fn const_bar<T>(x: T) -> T {
-    x
-}
-global_asm!("{}", const S);
-//~^ ERROR constants cannot refer to statics
-global_asm!("{}", const const_foo(0));
-global_asm!("{}", const const_foo(S));
-//~^ ERROR constants cannot refer to statics
-global_asm!("{}", const const_bar(0));
-global_asm!("{}", const const_bar(S));
-//~^ ERROR constants cannot refer to statics
diff --git a/src/test/ui/asm/type-check-3.stderr b/src/test/ui/asm/type-check-3.stderr
deleted file mode 100644 (file)
index 9f6989c..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-error: type `i128` cannot be used with this register class
-  --> $DIR/type-check-3.rs:12:28
-   |
-LL |         asm!("{}", in(reg) 0i128);
-   |                            ^^^^^
-   |
-   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
-
-error: type `__m128` cannot be used with this register class
-  --> $DIR/type-check-3.rs:14:28
-   |
-LL |         asm!("{}", in(reg) _mm_setzero_ps());
-   |                            ^^^^^^^^^^^^^^^^
-   |
-   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
-
-error: type `__m256` cannot be used with this register class
-  --> $DIR/type-check-3.rs:16:28
-   |
-LL |         asm!("{}", in(reg) _mm256_setzero_ps());
-   |                            ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
-
-error: type `u8` cannot be used with this register class
-  --> $DIR/type-check-3.rs:18:32
-   |
-LL |         asm!("{}", in(xmm_reg) 0u8);
-   |                                ^^^
-   |
-   = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
-
-error: `avx512bw` target feature is not enabled
-  --> $DIR/type-check-3.rs:27:29
-   |
-LL |         asm!("{}", in(kreg) 0u64);
-   |                             ^^^^
-   |
-   = note: this is required to use type `u64` with register class `kreg`
-
-warning: formatting may not be suitable for sub-register argument
-  --> $DIR/type-check-3.rs:32:15
-   |
-LL |         asm!("{0} {0}", in(reg) 0i16);
-   |               ^^^ ^^^           ---- for this argument
-   |
-   = note: `#[warn(asm_sub_register)]` on by default
-   = help: use the `x` modifier to have the register formatted as `ax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
-
-warning: formatting may not be suitable for sub-register argument
-  --> $DIR/type-check-3.rs:34:15
-   |
-LL |         asm!("{0} {0:x}", in(reg) 0i16);
-   |               ^^^                 ---- for this argument
-   |
-   = help: use the `x` modifier to have the register formatted as `ax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
-
-warning: formatting may not be suitable for sub-register argument
-  --> $DIR/type-check-3.rs:36:15
-   |
-LL |         asm!("{}", in(reg) 0i32);
-   |               ^^           ---- for this argument
-   |
-   = help: use the `e` modifier to have the register formatted as `eax`
-   = help: or use the `r` modifier to keep the default formatting of `rax`
-
-warning: formatting may not be suitable for sub-register argument
-  --> $DIR/type-check-3.rs:39:15
-   |
-LL |         asm!("{}", in(ymm_reg) 0i64);
-   |               ^^               ---- for this argument
-   |
-   = help: use the `x` modifier to have the register formatted as `xmm0`
-   = help: or use the `y` modifier to keep the default formatting of `ymm0`
-
-error: type `i8` cannot be used with this register class
-  --> $DIR/type-check-3.rs:50:28
-   |
-LL |         asm!("{}", in(reg) 0i8);
-   |                            ^^^
-   |
-   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
-   = help: consider using the `reg_byte` register class instead
-
-error: incompatible types for asm inout argument
-  --> $DIR/type-check-3.rs:62:33
-   |
-LL |         asm!("{:r}", inout(reg) 0u32 => val_f32);
-   |                                 ^^^^    ^^^^^^^ type `f32`
-   |                                 |
-   |                                 type `u32`
-   |
-   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
-
-error: incompatible types for asm inout argument
-  --> $DIR/type-check-3.rs:64:33
-   |
-LL |         asm!("{:r}", inout(reg) 0u32 => val_ptr);
-   |                                 ^^^^    ^^^^^^^ type `*mut u8`
-   |                                 |
-   |                                 type `u32`
-   |
-   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
-
-error: incompatible types for asm inout argument
-  --> $DIR/type-check-3.rs:66:33
-   |
-LL |         asm!("{:r}", inout(reg) main => val_u32);
-   |                                 ^^^^    ^^^^^^^ type `u32`
-   |                                 |
-   |                                 type `fn()`
-   |
-   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
-
-error[E0013]: constants cannot refer to statics
-  --> $DIR/type-check-3.rs:82:25
-   |
-LL | global_asm!("{}", const S);
-   |                         ^
-   |
-   = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error[E0013]: constants cannot refer to statics
-  --> $DIR/type-check-3.rs:85:35
-   |
-LL | global_asm!("{}", const const_foo(S));
-   |                                   ^
-   |
-   = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error[E0013]: constants cannot refer to statics
-  --> $DIR/type-check-3.rs:88:35
-   |
-LL | global_asm!("{}", const const_bar(S));
-   |                                   ^
-   |
-   = help: consider extracting the value of the `static` to a `const`, and referring to that
-
-error: aborting due to 12 previous errors; 4 warnings emitted
-
-For more information about this error, try `rustc --explain E0013`.
index 2be627c11657b4b95e645d3a5af41bc78bd3d5ce..c9826662009857fb5d0e02c1f3c31e199a4e7842 100644 (file)
@@ -1,4 +1,7 @@
-// only-x86_64
+// needs-asm-support
+// ignore-nvptx64
+// ignore-spirv
+// ignore-wasm32
 
 #![feature(asm)]
 
index 8035bbefc1aa1156ffc700fb77b9eff2fcc8c727..db2bf0a69f7fcd50c5e1e3f8c19e87db6f9c3c0a 100644 (file)
@@ -1,5 +1,5 @@
 error[E0506]: cannot assign to `a` because it is borrowed
-  --> $DIR/type-check-4.rs:11:9
+  --> $DIR/type-check-4.rs:14:9
    |
 LL |         let p = &a;
    |                 -- borrow of `a` occurs here
@@ -10,7 +10,7 @@ LL |         println!("{}", p);
    |                        - borrow later used here
 
 error[E0503]: cannot use `a` because it was mutably borrowed
-  --> $DIR/type-check-4.rs:19:28
+  --> $DIR/type-check-4.rs:22:28
    |
 LL |         let p = &mut a;
    |                 ------ borrow of `a` occurs here
diff --git a/src/test/ui/asm/x86_64/bad-options.rs b/src/test/ui/asm/x86_64/bad-options.rs
new file mode 100644 (file)
index 0000000..dc61d16
--- /dev/null
@@ -0,0 +1,39 @@
+// only-x86_64
+
+#![feature(asm, global_asm)]
+
+fn main() {
+    let mut foo = 0;
+    unsafe {
+        asm!("", options(nomem, readonly));
+        //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+        asm!("", options(pure, nomem, noreturn));
+        //~^ ERROR the `pure` and `noreturn` options are mutually exclusive
+        //~^^ ERROR asm with the `pure` option must have at least one output
+        asm!("{}", in(reg) foo, options(pure, nomem));
+        //~^ ERROR asm with the `pure` option must have at least one output
+        asm!("{}", out(reg) foo, options(noreturn));
+        //~^ ERROR asm outputs are not allowed with the `noreturn` option
+    }
+
+    unsafe {
+        asm!("", clobber_abi("foo"));
+        //~^ ERROR invalid ABI for `clobber_abi`
+        asm!("{}", out(reg) foo, clobber_abi("C"));
+        //~^ ERROR asm with `clobber_abi` must specify explicit registers for outputs
+        asm!("", out("eax") foo, clobber_abi("C"));
+    }
+}
+
+global_asm!("", options(nomem));
+//~^ ERROR expected one of
+global_asm!("", options(readonly));
+//~^ ERROR expected one of
+global_asm!("", options(noreturn));
+//~^ ERROR expected one of
+global_asm!("", options(pure));
+//~^ ERROR expected one of
+global_asm!("", options(nostack));
+//~^ ERROR expected one of
+global_asm!("", options(preserves_flags));
+//~^ ERROR expected one of
diff --git a/src/test/ui/asm/x86_64/bad-options.stderr b/src/test/ui/asm/x86_64/bad-options.stderr
new file mode 100644 (file)
index 0000000..8cfd450
--- /dev/null
@@ -0,0 +1,84 @@
+error: the `nomem` and `readonly` options are mutually exclusive
+  --> $DIR/bad-options.rs:8:18
+   |
+LL |         asm!("", options(nomem, readonly));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the `pure` and `noreturn` options are mutually exclusive
+  --> $DIR/bad-options.rs:10:18
+   |
+LL |         asm!("", options(pure, nomem, noreturn));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: asm with the `pure` option must have at least one output
+  --> $DIR/bad-options.rs:10:18
+   |
+LL |         asm!("", options(pure, nomem, noreturn));
+   |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: asm with the `pure` option must have at least one output
+  --> $DIR/bad-options.rs:13:33
+   |
+LL |         asm!("{}", in(reg) foo, options(pure, nomem));
+   |                                 ^^^^^^^^^^^^^^^^^^^^
+
+error: asm outputs are not allowed with the `noreturn` option
+  --> $DIR/bad-options.rs:15:20
+   |
+LL |         asm!("{}", out(reg) foo, options(noreturn));
+   |                    ^^^^^^^^^^^^
+
+error: asm with `clobber_abi` must specify explicit registers for outputs
+  --> $DIR/bad-options.rs:22:20
+   |
+LL |         asm!("{}", out(reg) foo, clobber_abi("C"));
+   |                    ^^^^^^^^^^^^  ---------------- clobber_abi
+   |                    |
+   |                    generic outputs
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+  --> $DIR/bad-options.rs:28:25
+   |
+LL | global_asm!("", options(nomem));
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `readonly`
+  --> $DIR/bad-options.rs:30:25
+   |
+LL | global_asm!("", options(readonly));
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `noreturn`
+  --> $DIR/bad-options.rs:32:25
+   |
+LL | global_asm!("", options(noreturn));
+   |                         ^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `pure`
+  --> $DIR/bad-options.rs:34:25
+   |
+LL | global_asm!("", options(pure));
+   |                         ^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nostack`
+  --> $DIR/bad-options.rs:36:25
+   |
+LL | global_asm!("", options(nostack));
+   |                         ^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `preserves_flags`
+  --> $DIR/bad-options.rs:38:25
+   |
+LL | global_asm!("", options(preserves_flags));
+   |                         ^^^^^^^^^^^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: invalid ABI for `clobber_abi`
+  --> $DIR/bad-options.rs:20:18
+   |
+LL |         asm!("", clobber_abi("foo"));
+   |                  ^^^^^^^^^^^^^^^^^^
+   |
+   = note: the following ABIs are supported on this target: `C`, `system`, `efiapi`, `win64`, `sysv64`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/test/ui/asm/x86_64/bad-reg.rs b/src/test/ui/asm/x86_64/bad-reg.rs
new file mode 100644 (file)
index 0000000..06af08f
--- /dev/null
@@ -0,0 +1,68 @@
+// only-x86_64
+// compile-flags: -C target-feature=+avx2
+
+#![feature(asm)]
+
+fn main() {
+    let mut foo = 0;
+    let mut bar = 0;
+    unsafe {
+        // Bad register/register class
+
+        asm!("{}", in(foo) foo);
+        //~^ ERROR invalid register class `foo`: unknown register class
+        asm!("", in("foo") foo);
+        //~^ ERROR invalid register `foo`: unknown register
+        asm!("{:z}", in(reg) foo);
+        //~^ ERROR invalid asm template modifier for this register class
+        asm!("{:r}", in(xmm_reg) foo);
+        //~^ ERROR invalid asm template modifier for this register class
+        asm!("{:a}", const 0);
+        //~^ ERROR asm template modifiers are not allowed for `const` arguments
+        asm!("{:a}", sym main);
+        //~^ ERROR asm template modifiers are not allowed for `sym` arguments
+        asm!("{}", in(zmm_reg) foo);
+        //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
+        asm!("", in("zmm0") foo);
+        //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature
+        asm!("", in("ebp") foo);
+        //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand
+        asm!("", in("rsp") foo);
+        //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand
+        asm!("", in("ip") foo);
+        //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand
+        asm!("", in("k0") foo);
+        //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand
+        asm!("", in("ah") foo);
+        //~^ ERROR invalid register `ah`: high byte registers cannot be used as an operand
+
+        asm!("", in("st(2)") foo);
+        //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
+        asm!("", in("mm0") foo);
+        //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+        asm!("", out("st(2)") _);
+        asm!("", out("mm0") _);
+        asm!("{}", in(x87_reg) foo);
+        //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
+        asm!("{}", in(mmx_reg) foo);
+        //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+        asm!("{}", out(x87_reg) _);
+        //~^ ERROR register class `x87_reg` can only be used as a clobber, not as an input or output
+        asm!("{}", out(mmx_reg) _);
+        //~^ ERROR register class `mmx_reg` can only be used as a clobber, not as an input or output
+
+        // Explicit register conflicts
+        // (except in/lateout which don't conflict)
+
+        asm!("", in("eax") foo, in("al") bar);
+        //~^ ERROR register `al` conflicts with register `ax`
+        asm!("", in("rax") foo, out("rax") bar);
+        //~^ ERROR register `ax` conflicts with register `ax`
+        asm!("", in("al") foo, lateout("al") bar);
+        asm!("", in("xmm0") foo, in("ymm0") bar);
+        //~^ ERROR register `ymm0` conflicts with register `xmm0`
+        asm!("", in("xmm0") foo, out("ymm0") bar);
+        //~^ ERROR register `ymm0` conflicts with register `xmm0`
+        asm!("", in("xmm0") foo, lateout("ymm0") bar);
+    }
+}
diff --git a/src/test/ui/asm/x86_64/bad-reg.stderr b/src/test/ui/asm/x86_64/bad-reg.stderr
new file mode 100644 (file)
index 0000000..14740bf
--- /dev/null
@@ -0,0 +1,172 @@
+error: invalid register class `foo`: unknown register class
+  --> $DIR/bad-reg.rs:12:20
+   |
+LL |         asm!("{}", in(foo) foo);
+   |                    ^^^^^^^^^^^
+
+error: invalid register `foo`: unknown register
+  --> $DIR/bad-reg.rs:14:18
+   |
+LL |         asm!("", in("foo") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: invalid asm template modifier for this register class
+  --> $DIR/bad-reg.rs:16:15
+   |
+LL |         asm!("{:z}", in(reg) foo);
+   |               ^^^^   ----------- argument
+   |               |
+   |               template modifier
+   |
+   = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r`
+
+error: invalid asm template modifier for this register class
+  --> $DIR/bad-reg.rs:18:15
+   |
+LL |         asm!("{:r}", in(xmm_reg) foo);
+   |               ^^^^   --------------- argument
+   |               |
+   |               template modifier
+   |
+   = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z`
+
+error: asm template modifiers are not allowed for `const` arguments
+  --> $DIR/bad-reg.rs:20:15
+   |
+LL |         asm!("{:a}", const 0);
+   |               ^^^^   ------- argument
+   |               |
+   |               template modifier
+
+error: asm template modifiers are not allowed for `sym` arguments
+  --> $DIR/bad-reg.rs:22:15
+   |
+LL |         asm!("{:a}", sym main);
+   |               ^^^^   -------- argument
+   |               |
+   |               template modifier
+
+error: register class `zmm_reg` requires the `avx512f` target feature
+  --> $DIR/bad-reg.rs:24:20
+   |
+LL |         asm!("{}", in(zmm_reg) foo);
+   |                    ^^^^^^^^^^^^^^^
+
+error: register class `zmm_reg` requires the `avx512f` target feature
+  --> $DIR/bad-reg.rs:26:18
+   |
+LL |         asm!("", in("zmm0") foo);
+   |                  ^^^^^^^^^^^^^^
+
+error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:28:18
+   |
+LL |         asm!("", in("ebp") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:30:18
+   |
+LL |         asm!("", in("rsp") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:32:18
+   |
+LL |         asm!("", in("ip") foo);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm
+  --> $DIR/bad-reg.rs:34:18
+   |
+LL |         asm!("", in("k0") foo);
+   |                  ^^^^^^^^^^^^
+
+error: invalid register `ah`: high byte registers cannot be used as an operand on x86_64
+  --> $DIR/bad-reg.rs:36:18
+   |
+LL |         asm!("", in("ah") foo);
+   |                  ^^^^^^^^^^^^
+
+error: register class `x87_reg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:39:18
+   |
+LL |         asm!("", in("st(2)") foo);
+   |                  ^^^^^^^^^^^^^^^
+
+error: register class `mmx_reg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:41:18
+   |
+LL |         asm!("", in("mm0") foo);
+   |                  ^^^^^^^^^^^^^
+
+error: register class `x87_reg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:45:20
+   |
+LL |         asm!("{}", in(x87_reg) foo);
+   |                    ^^^^^^^^^^^^^^^
+
+error: register class `mmx_reg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:47:20
+   |
+LL |         asm!("{}", in(mmx_reg) foo);
+   |                    ^^^^^^^^^^^^^^^
+
+error: register class `x87_reg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:49:20
+   |
+LL |         asm!("{}", out(x87_reg) _);
+   |                    ^^^^^^^^^^^^^^
+
+error: register class `mmx_reg` can only be used as a clobber, not as an input or output
+  --> $DIR/bad-reg.rs:51:20
+   |
+LL |         asm!("{}", out(mmx_reg) _);
+   |                    ^^^^^^^^^^^^^^
+
+error: register `al` conflicts with register `ax`
+  --> $DIR/bad-reg.rs:57:33
+   |
+LL |         asm!("", in("eax") foo, in("al") bar);
+   |                  -------------  ^^^^^^^^^^^^ register `al`
+   |                  |
+   |                  register `ax`
+
+error: register `ax` conflicts with register `ax`
+  --> $DIR/bad-reg.rs:59:33
+   |
+LL |         asm!("", in("rax") foo, out("rax") bar);
+   |                  -------------  ^^^^^^^^^^^^^^ register `ax`
+   |                  |
+   |                  register `ax`
+   |
+help: use `lateout` instead of `out` to avoid conflict
+  --> $DIR/bad-reg.rs:59:18
+   |
+LL |         asm!("", in("rax") foo, out("rax") bar);
+   |                  ^^^^^^^^^^^^^
+
+error: register `ymm0` conflicts with register `xmm0`
+  --> $DIR/bad-reg.rs:62:34
+   |
+LL |         asm!("", in("xmm0") foo, in("ymm0") bar);
+   |                  --------------  ^^^^^^^^^^^^^^ register `ymm0`
+   |                  |
+   |                  register `xmm0`
+
+error: register `ymm0` conflicts with register `xmm0`
+  --> $DIR/bad-reg.rs:64:34
+   |
+LL |         asm!("", in("xmm0") foo, out("ymm0") bar);
+   |                  --------------  ^^^^^^^^^^^^^^^ register `ymm0`
+   |                  |
+   |                  register `xmm0`
+   |
+help: use `lateout` instead of `out` to avoid conflict
+  --> $DIR/bad-reg.rs:64:18
+   |
+LL |         asm!("", in("xmm0") foo, out("ymm0") bar);
+   |                  ^^^^^^^^^^^^^^
+
+error: aborting due to 23 previous errors
+
diff --git a/src/test/ui/asm/x86_64/const.rs b/src/test/ui/asm/x86_64/const.rs
new file mode 100644 (file)
index 0000000..d4de9ab
--- /dev/null
@@ -0,0 +1,42 @@
+// min-llvm-version: 10.0.1
+// only-x86_64
+// run-pass
+// revisions: mirunsafeck thirunsafeck
+// [thirunsafeck]compile-flags: -Z thir-unsafeck
+
+#![feature(asm, global_asm)]
+
+fn const_generic<const X: usize>() -> usize {
+    unsafe {
+        let a: usize;
+        asm!("mov {}, {}", out(reg) a, const X);
+        a
+    }
+}
+
+const fn constfn(x: usize) -> usize {
+    x
+}
+
+fn main() {
+    unsafe {
+        let a: usize;
+        asm!("mov {}, {}", out(reg) a, const 5);
+        assert_eq!(a, 5);
+
+        let b: usize;
+        asm!("mov {}, {}", out(reg) b, const constfn(5));
+        assert_eq!(b, 5);
+
+        let c: usize;
+        asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5));
+        assert_eq!(c, 10);
+    }
+
+    let d = const_generic::<5>();
+    assert_eq!(d, 5);
+}
+
+global_asm!("mov eax, {}", const 5);
+global_asm!("mov eax, {}", const constfn(5));
+global_asm!("mov eax, {}", const constfn(5) + constfn(5));
diff --git a/src/test/ui/asm/x86_64/duplicate-options.fixed b/src/test/ui/asm/x86_64/duplicate-options.fixed
new file mode 100644 (file)
index 0000000..d4444e9
--- /dev/null
@@ -0,0 +1,29 @@
+// only-x86_64
+// run-rustfix
+
+#![feature(asm, global_asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(nomem, ));
+        //~^ ERROR the `nomem` option was already provided
+        asm!("", options(att_syntax, ));
+        //~^ ERROR the `att_syntax` option was already provided
+        asm!("", options(nostack, att_syntax), options());
+        //~^ ERROR the `nostack` option was already provided
+        asm!("", options(nostack, ), options(), options());
+        //~^ ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        asm!(
+            "",
+            options(nomem, noreturn),
+            options(att_syntax, ), //~ ERROR the `noreturn` option was already provided
+            options( nostack), //~ ERROR the `nomem` option was already provided
+            options(), //~ ERROR the `noreturn` option was already provided
+        );
+    }
+}
+
+global_asm!("", options(att_syntax, ));
+//~^ ERROR the `att_syntax` option was already provided
diff --git a/src/test/ui/asm/x86_64/duplicate-options.rs b/src/test/ui/asm/x86_64/duplicate-options.rs
new file mode 100644 (file)
index 0000000..fd28311
--- /dev/null
@@ -0,0 +1,29 @@
+// only-x86_64
+// run-rustfix
+
+#![feature(asm, global_asm)]
+
+fn main() {
+    unsafe {
+        asm!("", options(nomem, nomem));
+        //~^ ERROR the `nomem` option was already provided
+        asm!("", options(att_syntax, att_syntax));
+        //~^ ERROR the `att_syntax` option was already provided
+        asm!("", options(nostack, att_syntax), options(nostack));
+        //~^ ERROR the `nostack` option was already provided
+        asm!("", options(nostack, nostack), options(nostack), options(nostack));
+        //~^ ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        //~| ERROR the `nostack` option was already provided
+        asm!(
+            "",
+            options(nomem, noreturn),
+            options(att_syntax, noreturn), //~ ERROR the `noreturn` option was already provided
+            options(nomem, nostack), //~ ERROR the `nomem` option was already provided
+            options(noreturn), //~ ERROR the `noreturn` option was already provided
+        );
+    }
+}
+
+global_asm!("", options(att_syntax, att_syntax));
+//~^ ERROR the `att_syntax` option was already provided
diff --git a/src/test/ui/asm/x86_64/duplicate-options.stderr b/src/test/ui/asm/x86_64/duplicate-options.stderr
new file mode 100644 (file)
index 0000000..53edf8f
--- /dev/null
@@ -0,0 +1,62 @@
+error: the `nomem` option was already provided
+  --> $DIR/duplicate-options.rs:8:33
+   |
+LL |         asm!("", options(nomem, nomem));
+   |                                 ^^^^^ this option was already provided
+
+error: the `att_syntax` option was already provided
+  --> $DIR/duplicate-options.rs:10:38
+   |
+LL |         asm!("", options(att_syntax, att_syntax));
+   |                                      ^^^^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:12:56
+   |
+LL |         asm!("", options(nostack, att_syntax), options(nostack));
+   |                                                        ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:35
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                   ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:53
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                                     ^^^^^^^ this option was already provided
+
+error: the `nostack` option was already provided
+  --> $DIR/duplicate-options.rs:14:71
+   |
+LL |         asm!("", options(nostack, nostack), options(nostack), options(nostack));
+   |                                                                       ^^^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+  --> $DIR/duplicate-options.rs:21:33
+   |
+LL |             options(att_syntax, noreturn),
+   |                                 ^^^^^^^^ this option was already provided
+
+error: the `nomem` option was already provided
+  --> $DIR/duplicate-options.rs:22:21
+   |
+LL |             options(nomem, nostack),
+   |                     ^^^^^ this option was already provided
+
+error: the `noreturn` option was already provided
+  --> $DIR/duplicate-options.rs:23:21
+   |
+LL |             options(noreturn),
+   |                     ^^^^^^^^ this option was already provided
+
+error: the `att_syntax` option was already provided
+  --> $DIR/duplicate-options.rs:28:37
+   |
+LL | global_asm!("", options(att_syntax, att_syntax));
+   |                                     ^^^^^^^^^^ this option was already provided
+
+error: aborting due to 10 previous errors
+
diff --git a/src/test/ui/asm/x86_64/interpolated-idents.rs b/src/test/ui/asm/x86_64/interpolated-idents.rs
new file mode 100644 (file)
index 0000000..f4cb749
--- /dev/null
@@ -0,0 +1,24 @@
+// only-x86_64
+
+#![feature(asm)]
+
+macro_rules! m {
+    ($in:ident $out:ident $lateout:ident $inout:ident $inlateout:ident $const:ident $sym:ident
+     $pure:ident $nomem:ident $readonly:ident $preserves_flags:ident
+     $noreturn:ident $nostack:ident $att_syntax:ident $options:ident) => {
+        unsafe {
+            asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+            //~^ ERROR asm outputs are not allowed with the `noreturn` option
+            const x, sym x,
+            $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+            //~^ ERROR the `nomem` and `readonly` options are mutually exclusive
+            //~| ERROR the `pure` and `noreturn` options are mutually exclusive
+        }
+    };
+}
+
+fn main() {
+    m!(in out lateout inout inlateout const sym
+       pure nomem readonly preserves_flags
+       noreturn nostack att_syntax options);
+}
diff --git a/src/test/ui/asm/x86_64/interpolated-idents.stderr b/src/test/ui/asm/x86_64/interpolated-idents.stderr
new file mode 100644 (file)
index 0000000..5de8d20
--- /dev/null
@@ -0,0 +1,51 @@
+error: the `nomem` and `readonly` options are mutually exclusive
+  --> $DIR/interpolated-idents.rs:13:13
+   |
+LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | /     m!(in out lateout inout inlateout const sym
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |____________________________________________- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: the `pure` and `noreturn` options are mutually exclusive
+  --> $DIR/interpolated-idents.rs:13:13
+   |
+LL |               $options($pure, $nomem, $readonly, $preserves_flags, $noreturn, $nostack, $att_syntax));
+   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL | /     m!(in out lateout inout inlateout const sym
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |____________________________________________- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm outputs are not allowed with the `noreturn` option
+  --> $DIR/interpolated-idents.rs:10:32
+   |
+LL |               asm!("", $in(x) x, $out(x) x, $lateout(x) x, $inout(x) x, $inlateout(x) x,
+   |                                  ^^^^^^^^^  ^^^^^^^^^^^^^  ^^^^^^^^^^^  ^^^^^^^^^^^^^^^
+...
+LL |       m!(in out lateout inout inlateout const sym
+   |  _____-
+   | |_____|
+   | |_____|
+   | |_____|
+   | |
+LL | |        pure nomem readonly preserves_flags
+LL | |        noreturn nostack att_syntax options);
+   | |                                            -
+   | |____________________________________________|
+   | |____________________________________________in this macro invocation
+   | |____________________________________________in this macro invocation
+   | |____________________________________________in this macro invocation
+   |                                              in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/asm/x86_64/issue-82869.rs b/src/test/ui/asm/x86_64/issue-82869.rs
new file mode 100644 (file)
index 0000000..a8e688c
--- /dev/null
@@ -0,0 +1,23 @@
+// only-x86_64
+// Make sure rustc doesn't ICE on asm! for a foreign architecture.
+
+#![feature(asm)]
+#![crate_type = "rlib"]
+
+pub unsafe fn aarch64(a: f64, b: f64) -> f64 {
+    let c;
+    asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+        || {};
+        b
+    });
+    //~^^^^ invalid register class
+    //~^^^^^ invalid register class
+    //~^^^^^^ invalid register
+    c
+}
+
+pub unsafe fn x86(a: f64, b: f64) -> f64 {
+    let c;
+    asm!("addsd {}, {}, xmm0", out(xmm_reg) c, in(xmm_reg) a, in("xmm0") b);
+    c
+}
diff --git a/src/test/ui/asm/x86_64/issue-82869.stderr b/src/test/ui/asm/x86_64/issue-82869.stderr
new file mode 100644 (file)
index 0000000..d05714e
--- /dev/null
@@ -0,0 +1,24 @@
+error: invalid register class `vreg`: unknown register class
+  --> $DIR/issue-82869.rs:9:32
+   |
+LL |     asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+   |                                ^^^^^^^^^^^
+
+error: invalid register class `vreg`: unknown register class
+  --> $DIR/issue-82869.rs:9:45
+   |
+LL |     asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+   |                                             ^^^^^^^^^^
+
+error: invalid register `d0`: unknown register
+  --> $DIR/issue-82869.rs:9:57
+   |
+LL |       asm!("add {:d}, {:d}, d0", out(vreg) c, in(vreg) a, in("d0") {
+   |  _________________________________________________________^
+LL | |         || {};
+LL | |         b
+LL | |     });
+   | |_____^
+
+error: aborting due to 3 previous errors
+
diff --git a/src/test/ui/asm/x86_64/parse-error.rs b/src/test/ui/asm/x86_64/parse-error.rs
new file mode 100644 (file)
index 0000000..fa14c52
--- /dev/null
@@ -0,0 +1,135 @@
+// only-x86_64
+
+#![feature(asm, global_asm)]
+
+fn main() {
+    let mut foo = 0;
+    let mut bar = 0;
+    unsafe {
+        asm!();
+        //~^ ERROR requires at least a template string argument
+        asm!(foo);
+        //~^ ERROR asm template must be a string literal
+        asm!("{}" foo);
+        //~^ ERROR expected token: `,`
+        asm!("{}", foo);
+        //~^ ERROR expected operand, clobber_abi, options, or additional template string
+        asm!("{}", in foo);
+        //~^ ERROR expected `(`, found `foo`
+        asm!("{}", in(reg foo));
+        //~^ ERROR expected `)`, found `foo`
+        asm!("{}", in(reg));
+        //~^ ERROR expected expression, found end of macro arguments
+        asm!("{}", inout(=) foo => bar);
+        //~^ ERROR expected register class or explicit register
+        asm!("{}", inout(reg) foo =>);
+        //~^ ERROR expected expression, found end of macro arguments
+        asm!("{}", in(reg) foo => bar);
+        //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+        asm!("{}", sym foo + bar);
+        //~^ ERROR argument to `sym` must be a path expression
+        asm!("", options(foo));
+        //~^ ERROR expected one of
+        asm!("", options(nomem foo));
+        //~^ ERROR expected one of
+        asm!("", options(nomem, foo));
+        //~^ ERROR expected one of
+        asm!("{}", options(), const foo);
+        //~^ ERROR arguments are not allowed after options
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", clobber_abi(foo));
+        //~^ ERROR expected string literal
+        asm!("", clobber_abi("C" foo));
+        //~^ ERROR expected `)`, found `foo`
+        asm!("", clobber_abi("C", foo));
+        //~^ ERROR expected `)`, found `,`
+        asm!("{}", clobber_abi("C"), const foo);
+        //~^ ERROR arguments are not allowed after clobber_abi
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", options(), clobber_abi("C"));
+        //~^ ERROR clobber_abi is not allowed after options
+        asm!("{}", options(), clobber_abi("C"), const foo);
+        //~^ ERROR clobber_abi is not allowed after options
+        asm!("", clobber_abi("C"), clobber_abi("C"));
+        //~^ ERROR clobber_abi specified multiple times
+        asm!("{a}", a = const foo, a = const bar);
+        //~^ ERROR duplicate argument named `a`
+        //~^^ ERROR argument never used
+        //~^^^ ERROR attempt to use a non-constant value in a constant
+        //~^^^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", a = in("eax") foo);
+        //~^ ERROR explicit register arguments cannot have names
+        asm!("{a}", in("eax") foo, a = const bar);
+        //~^ ERROR named arguments cannot follow explicit register arguments
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("{a}", in("eax") foo, a = const bar);
+        //~^ ERROR named arguments cannot follow explicit register arguments
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("{1}", in("eax") foo, const bar);
+        //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments
+        //~^^ ERROR attempt to use a non-constant value in a constant
+        asm!("", options(), "");
+        //~^ ERROR expected one of
+        asm!("{}", in(reg) foo, "{}", out(reg) foo);
+        //~^ ERROR expected one of
+        asm!(format!("{{{}}}", 0), in(reg) foo);
+        //~^ ERROR asm template must be a string literal
+        asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+        //~^ ERROR asm template must be a string literal
+        asm!("{}", in(reg) _);
+        //~^ ERROR _ cannot be used for input operands
+        asm!("{}", inout(reg) _);
+        //~^ ERROR _ cannot be used for input operands
+        asm!("{}", inlateout(reg) _);
+        //~^ ERROR _ cannot be used for input operands
+    }
+}
+
+const FOO: i32 = 1;
+const BAR: i32 = 2;
+global_asm!();
+//~^ ERROR requires at least a template string argument
+global_asm!(FOO);
+//~^ ERROR asm template must be a string literal
+global_asm!("{}" FOO);
+//~^ ERROR expected token: `,`
+global_asm!("{}", FOO);
+//~^ ERROR expected operand, options, or additional template string
+global_asm!("{}", const);
+//~^ ERROR expected expression, found end of macro arguments
+global_asm!("{}", const(reg) FOO);
+//~^ ERROR expected one of
+global_asm!("", options(FOO));
+//~^ ERROR expected one of
+global_asm!("", options(nomem FOO));
+//~^ ERROR expected one of
+global_asm!("", options(nomem, FOO));
+//~^ ERROR expected one of
+global_asm!("{}", options(), const FOO);
+//~^ ERROR arguments are not allowed after options
+global_asm!("", clobber_abi(FOO));
+//~^ ERROR expected string literal
+global_asm!("", clobber_abi("C" FOO));
+//~^ ERROR expected `)`, found `FOO`
+global_asm!("", clobber_abi("C", FOO));
+//~^ ERROR expected `)`, found `,`
+global_asm!("{}", clobber_abi("C"), const FOO);
+//~^ ERROR arguments are not allowed after clobber_abi
+//~^^ ERROR `clobber_abi` cannot be used with `global_asm!`
+global_asm!("", options(), clobber_abi("C"));
+//~^ ERROR clobber_abi is not allowed after options
+global_asm!("{}", options(), clobber_abi("C"), const FOO);
+//~^ ERROR clobber_abi is not allowed after options
+global_asm!("", clobber_abi("C"), clobber_abi("C"));
+//~^ ERROR clobber_abi specified multiple times
+global_asm!("{a}", a = const FOO, a = const BAR);
+//~^ ERROR duplicate argument named `a`
+//~^^ ERROR argument never used
+global_asm!("", options(), "");
+//~^ ERROR expected one of
+global_asm!("{}", const FOO, "{}", const FOO);
+//~^ ERROR expected one of
+global_asm!(format!("{{{}}}", 0), const FOO);
+//~^ ERROR asm template must be a string literal
+global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
+//~^ ERROR asm template must be a string literal
diff --git a/src/test/ui/asm/x86_64/parse-error.stderr b/src/test/ui/asm/x86_64/parse-error.stderr
new file mode 100644 (file)
index 0000000..78d342c
--- /dev/null
@@ -0,0 +1,462 @@
+error: requires at least a template string argument
+  --> $DIR/parse-error.rs:9:9
+   |
+LL |         asm!();
+   |         ^^^^^^^
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:11:14
+   |
+LL |         asm!(foo);
+   |              ^^^
+
+error: expected token: `,`
+  --> $DIR/parse-error.rs:13:19
+   |
+LL |         asm!("{}" foo);
+   |                   ^^^ expected `,`
+
+error: expected operand, clobber_abi, options, or additional template string
+  --> $DIR/parse-error.rs:15:20
+   |
+LL |         asm!("{}", foo);
+   |                    ^^^ expected operand, clobber_abi, options, or additional template string
+
+error: expected `(`, found `foo`
+  --> $DIR/parse-error.rs:17:23
+   |
+LL |         asm!("{}", in foo);
+   |                       ^^^ expected `(`
+
+error: expected `)`, found `foo`
+  --> $DIR/parse-error.rs:19:27
+   |
+LL |         asm!("{}", in(reg foo));
+   |                           ^^^ expected `)`
+
+error: expected expression, found end of macro arguments
+  --> $DIR/parse-error.rs:21:27
+   |
+LL |         asm!("{}", in(reg));
+   |                           ^ expected expression
+
+error: expected register class or explicit register
+  --> $DIR/parse-error.rs:23:26
+   |
+LL |         asm!("{}", inout(=) foo => bar);
+   |                          ^
+
+error: expected expression, found end of macro arguments
+  --> $DIR/parse-error.rs:25:37
+   |
+LL |         asm!("{}", inout(reg) foo =>);
+   |                                     ^ expected expression
+
+error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>`
+  --> $DIR/parse-error.rs:27:32
+   |
+LL |         asm!("{}", in(reg) foo => bar);
+   |                                ^^ expected one of 7 possible tokens
+
+error: argument to `sym` must be a path expression
+  --> $DIR/parse-error.rs:29:24
+   |
+LL |         asm!("{}", sym foo + bar);
+   |                        ^^^^^^^^^
+
+error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+  --> $DIR/parse-error.rs:31:26
+   |
+LL |         asm!("", options(foo));
+   |                          ^^^ expected one of 9 possible tokens
+
+error: expected one of `)` or `,`, found `foo`
+  --> $DIR/parse-error.rs:33:32
+   |
+LL |         asm!("", options(nomem foo));
+   |                                ^^^ expected one of `)` or `,`
+
+error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, `raw`, or `readonly`, found `foo`
+  --> $DIR/parse-error.rs:35:33
+   |
+LL |         asm!("", options(nomem, foo));
+   |                                 ^^^ expected one of 9 possible tokens
+
+error: arguments are not allowed after options
+  --> $DIR/parse-error.rs:37:31
+   |
+LL |         asm!("{}", options(), const foo);
+   |                    ---------  ^^^^^^^^^ argument
+   |                    |
+   |                    previous options
+
+error: expected string literal
+  --> $DIR/parse-error.rs:40:30
+   |
+LL |         asm!("", clobber_abi(foo));
+   |                              ^^^ not a string literal
+
+error: expected `)`, found `foo`
+  --> $DIR/parse-error.rs:42:34
+   |
+LL |         asm!("", clobber_abi("C" foo));
+   |                                  ^^^ expected `)`
+
+error: expected `)`, found `,`
+  --> $DIR/parse-error.rs:44:33
+   |
+LL |         asm!("", clobber_abi("C", foo));
+   |                                 ^ expected `)`
+
+error: arguments are not allowed after clobber_abi
+  --> $DIR/parse-error.rs:46:38
+   |
+LL |         asm!("{}", clobber_abi("C"), const foo);
+   |                    ----------------  ^^^^^^^^^ argument
+   |                    |
+   |                    clobber_abi
+
+error: clobber_abi is not allowed after options
+  --> $DIR/parse-error.rs:49:29
+   |
+LL |         asm!("", options(), clobber_abi("C"));
+   |                  ---------  ^^^^^^^^^^^^^^^^
+   |                  |
+   |                  options
+
+error: clobber_abi is not allowed after options
+  --> $DIR/parse-error.rs:51:31
+   |
+LL |         asm!("{}", options(), clobber_abi("C"), const foo);
+   |                    ---------  ^^^^^^^^^^^^^^^^
+   |                    |
+   |                    options
+
+error: clobber_abi specified multiple times
+  --> $DIR/parse-error.rs:53:36
+   |
+LL |         asm!("", clobber_abi("C"), clobber_abi("C"));
+   |                  ----------------  ^^^^^^^^^^^^^^^^
+   |                  |
+   |                  clobber_abi previously specified here
+
+error: duplicate argument named `a`
+  --> $DIR/parse-error.rs:55:36
+   |
+LL |         asm!("{a}", a = const foo, a = const bar);
+   |                     -------------  ^^^^^^^^^^^^^ duplicate argument
+   |                     |
+   |                     previously here
+
+error: argument never used
+  --> $DIR/parse-error.rs:55:36
+   |
+LL |         asm!("{a}", a = const foo, a = const bar);
+   |                                    ^^^^^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
+
+error: explicit register arguments cannot have names
+  --> $DIR/parse-error.rs:60:18
+   |
+LL |         asm!("", a = in("eax") foo);
+   |                  ^^^^^^^^^^^^^^^^^
+
+error: named arguments cannot follow explicit register arguments
+  --> $DIR/parse-error.rs:62:36
+   |
+LL |         asm!("{a}", in("eax") foo, a = const bar);
+   |                     -------------  ^^^^^^^^^^^^^ named argument
+   |                     |
+   |                     explicit register argument
+
+error: named arguments cannot follow explicit register arguments
+  --> $DIR/parse-error.rs:65:36
+   |
+LL |         asm!("{a}", in("eax") foo, a = const bar);
+   |                     -------------  ^^^^^^^^^^^^^ named argument
+   |                     |
+   |                     explicit register argument
+
+error: positional arguments cannot follow named arguments or explicit register arguments
+  --> $DIR/parse-error.rs:68:36
+   |
+LL |         asm!("{1}", in("eax") foo, const bar);
+   |                     -------------  ^^^^^^^^^ positional argument
+   |                     |
+   |                     explicit register argument
+
+error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `""`
+  --> $DIR/parse-error.rs:71:29
+   |
+LL |         asm!("", options(), "");
+   |                             ^^ expected one of 9 possible tokens
+
+error: expected one of `clobber_abi`, `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `"{}"`
+  --> $DIR/parse-error.rs:73:33
+   |
+LL |         asm!("{}", in(reg) foo, "{}", out(reg) foo);
+   |                                 ^^^^ expected one of 9 possible tokens
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:75:14
+   |
+LL |         asm!(format!("{{{}}}", 0), in(reg) foo);
+   |              ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:77:21
+   |
+LL |         asm!("{1}", format!("{{{}}}", 0), in(reg) foo, out(reg) bar);
+   |                     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: _ cannot be used for input operands
+  --> $DIR/parse-error.rs:79:28
+   |
+LL |         asm!("{}", in(reg) _);
+   |                            ^
+
+error: _ cannot be used for input operands
+  --> $DIR/parse-error.rs:81:31
+   |
+LL |         asm!("{}", inout(reg) _);
+   |                               ^
+
+error: _ cannot be used for input operands
+  --> $DIR/parse-error.rs:83:35
+   |
+LL |         asm!("{}", inlateout(reg) _);
+   |                                   ^
+
+error: requires at least a template string argument
+  --> $DIR/parse-error.rs:90:1
+   |
+LL | global_asm!();
+   | ^^^^^^^^^^^^^^
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:92:13
+   |
+LL | global_asm!(FOO);
+   |             ^^^
+
+error: expected token: `,`
+  --> $DIR/parse-error.rs:94:18
+   |
+LL | global_asm!("{}" FOO);
+   |                  ^^^ expected `,`
+
+error: expected operand, options, or additional template string
+  --> $DIR/parse-error.rs:96:19
+   |
+LL | global_asm!("{}", FOO);
+   |                   ^^^ expected operand, options, or additional template string
+
+error: expected expression, found end of macro arguments
+  --> $DIR/parse-error.rs:98:24
+   |
+LL | global_asm!("{}", const);
+   |                        ^ expected expression
+
+error: expected one of `,`, `.`, `?`, or an operator, found `FOO`
+  --> $DIR/parse-error.rs:100:30
+   |
+LL | global_asm!("{}", const(reg) FOO);
+   |                              ^^^ expected one of `,`, `.`, `?`, or an operator
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `FOO`
+  --> $DIR/parse-error.rs:102:25
+   |
+LL | global_asm!("", options(FOO));
+   |                         ^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+  --> $DIR/parse-error.rs:104:25
+   |
+LL | global_asm!("", options(nomem FOO));
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: expected one of `)`, `att_syntax`, or `raw`, found `nomem`
+  --> $DIR/parse-error.rs:106:25
+   |
+LL | global_asm!("", options(nomem, FOO));
+   |                         ^^^^^ expected one of `)`, `att_syntax`, or `raw`
+
+error: arguments are not allowed after options
+  --> $DIR/parse-error.rs:108:30
+   |
+LL | global_asm!("{}", options(), const FOO);
+   |                   ---------  ^^^^^^^^^ argument
+   |                   |
+   |                   previous options
+
+error: expected string literal
+  --> $DIR/parse-error.rs:110:29
+   |
+LL | global_asm!("", clobber_abi(FOO));
+   |                             ^^^ not a string literal
+
+error: expected `)`, found `FOO`
+  --> $DIR/parse-error.rs:112:33
+   |
+LL | global_asm!("", clobber_abi("C" FOO));
+   |                                 ^^^ expected `)`
+
+error: expected `)`, found `,`
+  --> $DIR/parse-error.rs:114:32
+   |
+LL | global_asm!("", clobber_abi("C", FOO));
+   |                                ^ expected `)`
+
+error: arguments are not allowed after clobber_abi
+  --> $DIR/parse-error.rs:116:37
+   |
+LL | global_asm!("{}", clobber_abi("C"), const FOO);
+   |                   ----------------  ^^^^^^^^^ argument
+   |                   |
+   |                   clobber_abi
+
+error: `clobber_abi` cannot be used with `global_asm!`
+  --> $DIR/parse-error.rs:116:19
+   |
+LL | global_asm!("{}", clobber_abi("C"), const FOO);
+   |                   ^^^^^^^^^^^^^^^^
+
+error: clobber_abi is not allowed after options
+  --> $DIR/parse-error.rs:119:28
+   |
+LL | global_asm!("", options(), clobber_abi("C"));
+   |                 ---------  ^^^^^^^^^^^^^^^^
+   |                 |
+   |                 options
+
+error: clobber_abi is not allowed after options
+  --> $DIR/parse-error.rs:121:30
+   |
+LL | global_asm!("{}", options(), clobber_abi("C"), const FOO);
+   |                   ---------  ^^^^^^^^^^^^^^^^
+   |                   |
+   |                   options
+
+error: clobber_abi specified multiple times
+  --> $DIR/parse-error.rs:123:35
+   |
+LL | global_asm!("", clobber_abi("C"), clobber_abi("C"));
+   |                 ----------------  ^^^^^^^^^^^^^^^^
+   |                 |
+   |                 clobber_abi previously specified here
+
+error: duplicate argument named `a`
+  --> $DIR/parse-error.rs:125:35
+   |
+LL | global_asm!("{a}", a = const FOO, a = const BAR);
+   |                    -------------  ^^^^^^^^^^^^^ duplicate argument
+   |                    |
+   |                    previously here
+
+error: argument never used
+  --> $DIR/parse-error.rs:125:35
+   |
+LL | global_asm!("{a}", a = const FOO, a = const BAR);
+   |                                   ^^^^^^^^^^^^^ argument never used
+   |
+   = help: if this argument is intentionally unused, consider using it in an asm comment: `"/* {1} */"`
+
+error: expected one of `clobber_abi`, `const`, or `options`, found `""`
+  --> $DIR/parse-error.rs:128:28
+   |
+LL | global_asm!("", options(), "");
+   |                            ^^ expected one of `clobber_abi`, `const`, or `options`
+
+error: expected one of `clobber_abi`, `const`, or `options`, found `"{}"`
+  --> $DIR/parse-error.rs:130:30
+   |
+LL | global_asm!("{}", const FOO, "{}", const FOO);
+   |                              ^^^^ expected one of `clobber_abi`, `const`, or `options`
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:132:13
+   |
+LL | global_asm!(format!("{{{}}}", 0), const FOO);
+   |             ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: asm template must be a string literal
+  --> $DIR/parse-error.rs:134:20
+   |
+LL | global_asm!("{1}", format!("{{{}}}", 0), const FOO, const BAR);
+   |                    ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this error originates in the macro `format` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:37:37
+   |
+LL |     let mut foo = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL |         asm!("{}", options(), const foo);
+   |                                     ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:46:44
+   |
+LL |     let mut foo = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL |         asm!("{}", clobber_abi("C"), const foo);
+   |                                            ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:55:31
+   |
+LL |     let mut foo = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const foo`
+...
+LL |         asm!("{a}", a = const foo, a = const bar);
+   |                               ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:55:46
+   |
+LL |     let mut bar = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{a}", a = const foo, a = const bar);
+   |                                              ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:62:46
+   |
+LL |     let mut bar = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{a}", in("eax") foo, a = const bar);
+   |                                              ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:65:46
+   |
+LL |     let mut bar = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{a}", in("eax") foo, a = const bar);
+   |                                              ^^^ non-constant value
+
+error[E0435]: attempt to use a non-constant value in a constant
+  --> $DIR/parse-error.rs:68:42
+   |
+LL |     let mut bar = 0;
+   |      ---------- help: consider using `const` instead of `let`: `const bar`
+...
+LL |         asm!("{1}", in("eax") foo, const bar);
+   |                                          ^^^ non-constant value
+
+error: aborting due to 66 previous errors
+
+For more information about this error, try `rustc --explain E0435`.
diff --git a/src/test/ui/asm/x86_64/srcloc.rs b/src/test/ui/asm/x86_64/srcloc.rs
new file mode 100644 (file)
index 0000000..ed8cefc
--- /dev/null
@@ -0,0 +1,124 @@
+// min-llvm-version: 10.0.1
+// only-x86_64
+// build-fail
+// compile-flags: -Ccodegen-units=1
+#![feature(asm)]
+
+// Checks that inline asm errors are mapped to the correct line in the source code.
+
+fn main() {
+    unsafe {
+        asm!("invalid_instruction");
+        //~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!("
+            invalid_instruction
+        ");
+        //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(r#"
+            invalid_instruction
+        "#);
+        //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!("
+            mov eax, eax
+            invalid_instruction
+            mov eax, eax
+        ");
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(r#"
+            mov eax, eax
+            invalid_instruction
+            mov eax, eax
+        "#);
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(concat!("invalid", "_", "instruction"));
+        //~^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
+        //~^ WARN: scale factor without index register is ignored
+
+        asm!(
+            "invalid_instruction",
+        );
+        //~^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(
+            "mov eax, eax",
+            "invalid_instruction",
+            "mov eax, eax",
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(
+            "mov eax, eax\n",
+            "invalid_instruction",
+            "mov eax, eax",
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(
+            "mov eax, eax",
+            concat!("invalid", "_", "instruction"),
+            "mov eax, eax",
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        asm!(
+            concat!("mov eax", ", ", "eax"),
+            concat!("invalid", "_", "instruction"),
+            concat!("mov eax", ", ", "eax"),
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction'
+
+        // Make sure template strings get separated
+        asm!(
+            "invalid_instruction1",
+            "invalid_instruction2",
+        );
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+        //~^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2",
+            ),
+        );
+        //~^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+        //~^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2",
+            ),
+            concat!(
+                "invalid", "_", "instruction3", "\n",
+                "invalid", "_", "instruction4",
+            ),
+        );
+        //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+        //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+        //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
+        //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
+
+        asm!(
+            concat!(
+                "invalid", "_", "instruction1", "\n",
+                "invalid", "_", "instruction2", "\n",
+            ),
+            concat!(
+                "invalid", "_", "instruction3", "\n",
+                "invalid", "_", "instruction4", "\n",
+            ),
+        );
+        //~^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction1'
+        //~^^^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction2'
+        //~^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction3'
+        //~^^^^^^^^ ERROR: invalid instruction mnemonic 'invalid_instruction4'
+    }
+}
diff --git a/src/test/ui/asm/x86_64/srcloc.stderr b/src/test/ui/asm/x86_64/srcloc.stderr
new file mode 100644 (file)
index 0000000..b62c894
--- /dev/null
@@ -0,0 +1,290 @@
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:11:15
+   |
+LL |         asm!("invalid_instruction");
+   |               ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:15:13
+   |
+LL |             invalid_instruction
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:13
+   |
+LL |             invalid_instruction
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:20:13
+   |
+LL |             invalid_instruction
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:13
+   |
+LL |             invalid_instruction
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:26:13
+   |
+LL |             invalid_instruction
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:13
+   |
+LL |             invalid_instruction
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:33:13
+   |
+LL |             invalid_instruction
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:13
+   |
+LL |             invalid_instruction
+   |             ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:38:14
+   |
+LL |         asm!(concat!("invalid", "_", "instruction"));
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction
+   |     ^^^^^^^^^^^^^^^^^^^
+
+warning: scale factor without index register is ignored
+  --> $DIR/srcloc.rs:41:15
+   |
+LL |         asm!("movaps %xmm3, (%esi, 2)", options(att_syntax));
+   |               ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:1:23
+   |
+LL |     movaps %xmm3, (%esi, 2)
+   |                          ^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:45:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction
+   |     ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:51:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:58:14
+   |
+LL |             "invalid_instruction",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:65:13
+   |
+LL |             concat!("invalid", "_", "instruction"),
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction'
+  --> $DIR/srcloc.rs:72:13
+   |
+LL |             concat!("invalid", "_", "instruction"),
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction
+   | ^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+  --> $DIR/srcloc.rs:79:14
+   |
+LL |             "invalid_instruction1",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction1
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+  --> $DIR/srcloc.rs:80:14
+   |
+LL |             "invalid_instruction2",
+   |              ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction2
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+  --> $DIR/srcloc.rs:86:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction1
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+  --> $DIR/srcloc.rs:86:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction2
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+  --> $DIR/srcloc.rs:95:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction1
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+  --> $DIR/srcloc.rs:95:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction2
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction3'
+  --> $DIR/srcloc.rs:99:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:4:1
+   |
+LL | invalid_instruction3
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction4'
+  --> $DIR/srcloc.rs:99:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:5:1
+   |
+LL | invalid_instruction4
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction1'
+  --> $DIR/srcloc.rs:110:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:2:2
+   |
+LL |     invalid_instruction1
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction2'
+  --> $DIR/srcloc.rs:110:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:3:1
+   |
+LL | invalid_instruction2
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction3'
+  --> $DIR/srcloc.rs:114:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:5:1
+   |
+LL | invalid_instruction3
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: invalid instruction mnemonic 'invalid_instruction4'
+  --> $DIR/srcloc.rs:114:13
+   |
+LL |             concat!(
+   |             ^
+   |
+note: instantiated into assembly here
+  --> <inline asm>:6:1
+   |
+LL | invalid_instruction4
+   | ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 23 previous errors; 1 warning emitted
+
diff --git a/src/test/ui/asm/x86_64/sym.rs b/src/test/ui/asm/x86_64/sym.rs
new file mode 100644 (file)
index 0000000..634ef01
--- /dev/null
@@ -0,0 +1,80 @@
+// min-llvm-version: 10.0.1
+// only-x86_64
+// only-linux
+// run-pass
+
+#![feature(asm, thread_local)]
+
+extern "C" fn f1() -> i32 {
+    111
+}
+
+// The compiler will generate a shim to hide the caller location parameter.
+#[track_caller]
+fn f2() -> i32 {
+    222
+}
+
+macro_rules! call {
+    ($func:path) => {
+        unsafe {
+            let result: i32;
+            asm!("call {}", sym $func,
+                out("rax") result,
+                out("rcx") _, out("rdx") _, out("rdi") _, out("rsi") _,
+                out("r8") _, out("r9") _, out("r10") _, out("r11") _,
+                out("xmm0") _, out("xmm1") _, out("xmm2") _, out("xmm3") _,
+                out("xmm4") _, out("xmm5") _, out("xmm6") _, out("xmm7") _,
+                out("xmm8") _, out("xmm9") _, out("xmm10") _, out("xmm11") _,
+                out("xmm12") _, out("xmm13") _, out("xmm14") _, out("xmm15") _,
+            );
+            result
+        }
+    }
+}
+
+macro_rules! static_addr {
+    ($s:expr) => {
+        unsafe {
+            let result: *const u32;
+            // LEA performs a RIP-relative address calculation and returns the address
+            asm!("lea {}, [rip + {}]", out(reg) result, sym $s);
+            result
+        }
+    }
+}
+macro_rules! static_tls_addr {
+    ($s:expr) => {
+        unsafe {
+            let result: *const u32;
+            asm!(
+                "
+                    # Load TLS base address
+                    mov {out}, qword ptr fs:[0]
+                    # Calculate the address of sym in the TLS block. The @tpoff
+                    # relocation gives the offset of the symbol from the start
+                    # of the TLS block.
+                    lea {out}, [{out} + {sym}@tpoff]
+                ",
+                out = out(reg) result,
+                sym = sym $s
+            );
+            result
+        }
+    }
+}
+
+static S1: u32 = 111;
+#[thread_local]
+static S2: u32 = 222;
+
+fn main() {
+    assert_eq!(call!(f1), 111);
+    assert_eq!(call!(f2), 222);
+    assert_eq!(static_addr!(S1), &S1 as *const u32);
+    assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
+    std::thread::spawn(|| {
+        assert_eq!(static_addr!(S1), &S1 as *const u32);
+        assert_eq!(static_tls_addr!(S2), &S2 as *const u32);
+    }).join().unwrap();
+}
diff --git a/src/test/ui/asm/x86_64/type-check-2.rs b/src/test/ui/asm/x86_64/type-check-2.rs
new file mode 100644 (file)
index 0000000..2311f86
--- /dev/null
@@ -0,0 +1,80 @@
+// only-x86_64
+
+#![feature(asm, repr_simd, never_type)]
+
+#[repr(simd)]
+struct SimdNonCopy(f32, f32, f32, f32);
+
+fn main() {
+    unsafe {
+        // Inputs must be initialized
+
+        let x: u64;
+        asm!("{}", in(reg) x);
+        //~^ ERROR use of possibly-uninitialized variable: `x`
+        let mut y: u64;
+        asm!("{}", inout(reg) y);
+        //~^ ERROR use of possibly-uninitialized variable: `y`
+        let _ = y;
+
+        // Outputs require mutable places
+
+        let v: Vec<u64> = vec![0, 1, 2];
+        asm!("{}", in(reg) v[0]);
+        asm!("{}", out(reg) v[0]);
+        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+        asm!("{}", inout(reg) v[0]);
+        //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable
+
+        // Sym operands must point to a function or static
+
+        const C: i32 = 0;
+        static S: i32 = 0;
+        asm!("{}", sym S);
+        asm!("{}", sym main);
+        asm!("{}", sym C);
+        //~^ ERROR asm `sym` operand must point to a fn or static
+        asm!("{}", sym x);
+        //~^ ERROR asm `sym` operand must point to a fn or static
+
+        // Register operands must be Copy
+
+        asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
+        //~^ ERROR arguments for inline assembly must be copyable
+
+        // Register operands must be integers, floats, SIMD vectors, pointers or
+        // function pointers.
+
+        asm!("{}", in(reg) 0i64);
+        asm!("{}", in(reg) 0f64);
+        asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps());
+        asm!("{}", in(reg) 0 as *const u8);
+        asm!("{}", in(reg) 0 as *mut u8);
+        asm!("{}", in(reg) main as fn());
+        asm!("{}", in(reg) |x: i32| x);
+        //~^ ERROR cannot use value of type
+        asm!("{}", in(reg) vec![0]);
+        //~^ ERROR cannot use value of type `Vec<i32>` for inline assembly
+        asm!("{}", in(reg) (1, 2, 3));
+        //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly
+        asm!("{}", in(reg) [1, 2, 3]);
+        //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly
+
+        // Register inputs (but not outputs) allow references and function types
+
+        let mut f = main;
+        let mut r = &mut 0;
+        asm!("{}", in(reg) f);
+        asm!("{}", inout(reg) f);
+        //~^ ERROR cannot use value of type `fn() {main}` for inline assembly
+        asm!("{}", in(reg) r);
+        asm!("{}", inout(reg) r);
+        //~^ ERROR cannot use value of type `&mut i32` for inline assembly
+        let _ = (f, r);
+
+        // Type checks ignore never type
+
+        let u: ! = unreachable!();
+        asm!("{}", in(reg) u);
+    }
+}
diff --git a/src/test/ui/asm/x86_64/type-check-2.stderr b/src/test/ui/asm/x86_64/type-check-2.stderr
new file mode 100644 (file)
index 0000000..b82a0b8
--- /dev/null
@@ -0,0 +1,103 @@
+error: arguments for inline assembly must be copyable
+  --> $DIR/type-check-2.rs:42:32
+   |
+LL |         asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0));
+   |                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `SimdNonCopy` does not implement the Copy trait
+
+error: cannot use value of type `[closure@$DIR/type-check-2.rs:54:28: 54:38]` for inline assembly
+  --> $DIR/type-check-2.rs:54:28
+   |
+LL |         asm!("{}", in(reg) |x: i32| x);
+   |                            ^^^^^^^^^^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `Vec<i32>` for inline assembly
+  --> $DIR/type-check-2.rs:56:28
+   |
+LL |         asm!("{}", in(reg) vec![0]);
+   |                            ^^^^^^^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+   = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: cannot use value of type `(i32, i32, i32)` for inline assembly
+  --> $DIR/type-check-2.rs:58:28
+   |
+LL |         asm!("{}", in(reg) (1, 2, 3));
+   |                            ^^^^^^^^^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `[i32; 3]` for inline assembly
+  --> $DIR/type-check-2.rs:60:28
+   |
+LL |         asm!("{}", in(reg) [1, 2, 3]);
+   |                            ^^^^^^^^^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `fn() {main}` for inline assembly
+  --> $DIR/type-check-2.rs:68:31
+   |
+LL |         asm!("{}", inout(reg) f);
+   |                               ^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: cannot use value of type `&mut i32` for inline assembly
+  --> $DIR/type-check-2.rs:71:31
+   |
+LL |         asm!("{}", inout(reg) r);
+   |                               ^
+   |
+   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly
+
+error: asm `sym` operand must point to a fn or static
+  --> $DIR/type-check-2.rs:35:24
+   |
+LL |         asm!("{}", sym C);
+   |                        ^
+
+error: asm `sym` operand must point to a fn or static
+  --> $DIR/type-check-2.rs:37:24
+   |
+LL |         asm!("{}", sym x);
+   |                        ^
+
+error[E0381]: use of possibly-uninitialized variable: `x`
+  --> $DIR/type-check-2.rs:13:28
+   |
+LL |         asm!("{}", in(reg) x);
+   |                            ^ use of possibly-uninitialized `x`
+
+error[E0381]: use of possibly-uninitialized variable: `y`
+  --> $DIR/type-check-2.rs:16:9
+   |
+LL |         asm!("{}", inout(reg) y);
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y`
+
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/type-check-2.rs:24:29
+   |
+LL |         let v: Vec<u64> = vec![0, 1, 2];
+   |             - help: consider changing this to be mutable: `mut v`
+LL |         asm!("{}", in(reg) v[0]);
+LL |         asm!("{}", out(reg) v[0]);
+   |                             ^ cannot borrow as mutable
+
+error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable
+  --> $DIR/type-check-2.rs:26:31
+   |
+LL |         let v: Vec<u64> = vec![0, 1, 2];
+   |             - help: consider changing this to be mutable: `mut v`
+...
+LL |         asm!("{}", inout(reg) v[0]);
+   |                               ^ cannot borrow as mutable
+
+error: aborting due to 13 previous errors
+
+Some errors have detailed explanations: E0381, E0596.
+For more information about an error, try `rustc --explain E0381`.
diff --git a/src/test/ui/asm/x86_64/type-check-3.rs b/src/test/ui/asm/x86_64/type-check-3.rs
new file mode 100644 (file)
index 0000000..c2c1885
--- /dev/null
@@ -0,0 +1,89 @@
+// only-x86_64
+// compile-flags: -C target-feature=+avx512f
+
+#![feature(asm, global_asm)]
+
+use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps};
+
+fn main() {
+    unsafe {
+        // Types must be listed in the register class.
+
+        asm!("{}", in(reg) 0i128);
+        //~^ ERROR type `i128` cannot be used with this register class
+        asm!("{}", in(reg) _mm_setzero_ps());
+        //~^ ERROR type `__m128` cannot be used with this register class
+        asm!("{}", in(reg) _mm256_setzero_ps());
+        //~^ ERROR type `__m256` cannot be used with this register class
+        asm!("{}", in(xmm_reg) 0u8);
+        //~^ ERROR type `u8` cannot be used with this register class
+        asm!("{:e}", in(reg) 0i32);
+        asm!("{}", in(xmm_reg) 0i32);
+        asm!("{:e}", in(reg) 0f32);
+        asm!("{}", in(xmm_reg) 0f32);
+        asm!("{}", in(xmm_reg) _mm_setzero_ps());
+        asm!("{:x}", in(ymm_reg) _mm_setzero_ps());
+        asm!("{}", in(kreg) 0u16);
+        asm!("{}", in(kreg) 0u64);
+        //~^ ERROR `avx512bw` target feature is not enabled
+
+        // Template modifier suggestions for sub-registers
+
+        asm!("{0} {0}", in(reg) 0i16);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{0} {0:x}", in(reg) 0i16);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(reg) 0i32);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(reg) 0i64);
+        asm!("{}", in(ymm_reg) 0i64);
+        //~^ WARN formatting may not be suitable for sub-register argument
+        asm!("{}", in(ymm_reg) _mm256_setzero_ps());
+        asm!("{:l}", in(reg) 0i16);
+        asm!("{:l}", in(reg) 0i32);
+        asm!("{:l}", in(reg) 0i64);
+        asm!("{:x}", in(ymm_reg) 0i64);
+        asm!("{:x}", in(ymm_reg) _mm256_setzero_ps());
+
+        // Suggest different register class for type
+
+        asm!("{}", in(reg) 0i8);
+        //~^ ERROR type `i8` cannot be used with this register class
+        asm!("{}", in(reg_byte) 0i8);
+
+        // Split inout operands must have compatible types
+
+        let mut val_i16: i16;
+        let mut val_f32: f32;
+        let mut val_u32: u32;
+        let mut val_u64: u64;
+        let mut val_ptr: *mut u8;
+        asm!("{:r}", inout(reg) 0u16 => val_i16);
+        asm!("{:r}", inout(reg) 0u32 => val_f32);
+        //~^ ERROR incompatible types for asm inout argument
+        asm!("{:r}", inout(reg) 0u32 => val_ptr);
+        //~^ ERROR incompatible types for asm inout argument
+        asm!("{:r}", inout(reg) main => val_u32);
+        //~^ ERROR incompatible types for asm inout argument
+        asm!("{:r}", inout(reg) 0u64 => val_ptr);
+        asm!("{:r}", inout(reg) main => val_u64);
+    }
+}
+
+// Constants must be... constant
+
+static S: i32 = 1;
+const fn const_foo(x: i32) -> i32 {
+    x
+}
+const fn const_bar<T>(x: T) -> T {
+    x
+}
+global_asm!("{}", const S);
+//~^ ERROR constants cannot refer to statics
+global_asm!("{}", const const_foo(0));
+global_asm!("{}", const const_foo(S));
+//~^ ERROR constants cannot refer to statics
+global_asm!("{}", const const_bar(0));
+global_asm!("{}", const const_bar(S));
+//~^ ERROR constants cannot refer to statics
diff --git a/src/test/ui/asm/x86_64/type-check-3.stderr b/src/test/ui/asm/x86_64/type-check-3.stderr
new file mode 100644 (file)
index 0000000..9f6989c
--- /dev/null
@@ -0,0 +1,143 @@
+error: type `i128` cannot be used with this register class
+  --> $DIR/type-check-3.rs:12:28
+   |
+LL |         asm!("{}", in(reg) 0i128);
+   |                            ^^^^^
+   |
+   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+
+error: type `__m128` cannot be used with this register class
+  --> $DIR/type-check-3.rs:14:28
+   |
+LL |         asm!("{}", in(reg) _mm_setzero_ps());
+   |                            ^^^^^^^^^^^^^^^^
+   |
+   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+
+error: type `__m256` cannot be used with this register class
+  --> $DIR/type-check-3.rs:16:28
+   |
+LL |         asm!("{}", in(reg) _mm256_setzero_ps());
+   |                            ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+
+error: type `u8` cannot be used with this register class
+  --> $DIR/type-check-3.rs:18:32
+   |
+LL |         asm!("{}", in(xmm_reg) 0u8);
+   |                                ^^^
+   |
+   = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2
+
+error: `avx512bw` target feature is not enabled
+  --> $DIR/type-check-3.rs:27:29
+   |
+LL |         asm!("{}", in(kreg) 0u64);
+   |                             ^^^^
+   |
+   = note: this is required to use type `u64` with register class `kreg`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:32:15
+   |
+LL |         asm!("{0} {0}", in(reg) 0i16);
+   |               ^^^ ^^^           ---- for this argument
+   |
+   = note: `#[warn(asm_sub_register)]` on by default
+   = help: use the `x` modifier to have the register formatted as `ax`
+   = help: or use the `r` modifier to keep the default formatting of `rax`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:34:15
+   |
+LL |         asm!("{0} {0:x}", in(reg) 0i16);
+   |               ^^^                 ---- for this argument
+   |
+   = help: use the `x` modifier to have the register formatted as `ax`
+   = help: or use the `r` modifier to keep the default formatting of `rax`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:36:15
+   |
+LL |         asm!("{}", in(reg) 0i32);
+   |               ^^           ---- for this argument
+   |
+   = help: use the `e` modifier to have the register formatted as `eax`
+   = help: or use the `r` modifier to keep the default formatting of `rax`
+
+warning: formatting may not be suitable for sub-register argument
+  --> $DIR/type-check-3.rs:39:15
+   |
+LL |         asm!("{}", in(ymm_reg) 0i64);
+   |               ^^               ---- for this argument
+   |
+   = help: use the `x` modifier to have the register formatted as `xmm0`
+   = help: or use the `y` modifier to keep the default formatting of `ymm0`
+
+error: type `i8` cannot be used with this register class
+  --> $DIR/type-check-3.rs:50:28
+   |
+LL |         asm!("{}", in(reg) 0i8);
+   |                            ^^^
+   |
+   = note: register class `reg` supports these types: i16, i32, i64, f32, f64
+   = help: consider using the `reg_byte` register class instead
+
+error: incompatible types for asm inout argument
+  --> $DIR/type-check-3.rs:62:33
+   |
+LL |         asm!("{:r}", inout(reg) 0u32 => val_f32);
+   |                                 ^^^^    ^^^^^^^ type `f32`
+   |                                 |
+   |                                 type `u32`
+   |
+   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error: incompatible types for asm inout argument
+  --> $DIR/type-check-3.rs:64:33
+   |
+LL |         asm!("{:r}", inout(reg) 0u32 => val_ptr);
+   |                                 ^^^^    ^^^^^^^ type `*mut u8`
+   |                                 |
+   |                                 type `u32`
+   |
+   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error: incompatible types for asm inout argument
+  --> $DIR/type-check-3.rs:66:33
+   |
+LL |         asm!("{:r}", inout(reg) main => val_u32);
+   |                                 ^^^^    ^^^^^^^ type `u32`
+   |                                 |
+   |                                 type `fn()`
+   |
+   = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/type-check-3.rs:82:25
+   |
+LL | global_asm!("{}", const S);
+   |                         ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/type-check-3.rs:85:35
+   |
+LL | global_asm!("{}", const const_foo(S));
+   |                                   ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error[E0013]: constants cannot refer to statics
+  --> $DIR/type-check-3.rs:88:35
+   |
+LL | global_asm!("{}", const const_bar(S));
+   |                                   ^
+   |
+   = help: consider extracting the value of the `static` to a `const`, and referring to that
+
+error: aborting due to 12 previous errors; 4 warnings emitted
+
+For more information about this error, try `rustc --explain E0013`.
index ad5c6aed97c2c3ce7fb57c7215a839fc33b49a32..d854dce382fc47ea1591f9ea353f27092a708b97 100644 (file)
@@ -1,5 +1,5 @@
 // check-pass
-// compile-flags:-Cincremental=tmp/traits-assoc-type-macros
+// incremental
 
 // This test case makes sure that we can compile with incremental compilation
 // enabled when there are macros, traits, inheritance and associated types involved.
index 96ba2ee3b62b8c12ffd2875d792a988e67cfd271..05498ba63e9948305f8a699be193bcc41131e43b 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn pairwise_sub(mut t: Box<dyn DoubleEndedIterator<Item=isize>>) -> isize {
     let mut result = 0;
index e3bd0c2276e48ca2ac120a84844aa81ff52c1d5d..de254b7a1636c904ddf0eb76def308ae37ef186a 100644 (file)
@@ -6,6 +6,11 @@ LL |     foo(());
    |
    = note: expected reference `&'a ()`
               found reference `&()`
+note: the lifetime requirement is introduced here
+  --> $DIR/higher-ranked-projection.rs:15:33
+   |
+LL |     where for<'a> &'a T: Mirror<Image=U>
+   |                                 ^^^^^^^
 
 error: aborting due to previous error
 
index 61c8c8c1594d3b80a6d2a36ffd1409460e7c00c9..2280154c7157ce4dbe3896635d42cb79755774fa 100644 (file)
@@ -1,5 +1,5 @@
 // edition:2018
-// compile-flags:-Cincremental=tmp/issue-72442
+// incremental
 
 use std::fs::File;
 use std::future::Future;
index 5313d1715c4835574c22bcddf63ff88cba76510c..6d6eff4864ee3663cc1c415d4d9304a25932e433 100644 (file)
@@ -1,5 +1,6 @@
 // check-pass
-// compile-flags: -Z query-dep-graph -C incremental=tmp/issue-64964
+// incremental
+// compile-flags: -Z query-dep-graph
 // edition:2018
 
 // Regression test for ICE related to `await`ing in a method + incr. comp. (#64964)
index 77acfcd87cf75cdeaadf131592c211248c1181a2..8f6977cb55f25b06db7444c53432a4be153359ed 100644 (file)
@@ -30,13 +30,13 @@ error: malformed `register_attr` attribute input
   --> $DIR/register-attr-tool-fail.rs:4:1
    |
 LL | #![register_attr]
-   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_attr(attr1, attr2, ...)]`
+   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_attr(attr1, attr2, ...)]`
 
 error: malformed `register_tool` attribute input
   --> $DIR/register-attr-tool-fail.rs:5:1
    |
 LL | #![register_tool]
-   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[register_tool(tool1, tool2, ...)]`
+   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![register_tool(tool1, tool2, ...)]`
 
 error: aborting due to 6 previous errors
 
index f07a2c107ba457be042a38bfdab532329fb1d635..0fadc5c98277e92574c946aa17a2a504d9eea8cc 100644 (file)
@@ -1,23 +1,23 @@
-#![feature(box_syntax)]
-
 struct Clam {
     x: Box<isize>,
     y: Box<isize>,
 }
 
+
+
 struct Fish {
     a: Box<isize>,
 }
 
 fn main() {
-    let a: Clam = Clam{x: box 1, y: box 2};
-    let b: Clam = Clam{x: box 10, y: box 20};
+    let a: Clam = Clam{ x: Box::new(1), y: Box::new(2) };
+    let b: Clam = Clam{ x: Box::new(10), y: Box::new(20) };
     let z: isize = a.x + b.y;
     //~^ ERROR cannot add `Box<isize>` to `Box<isize>`
     println!("{}", z);
     assert_eq!(z, 21);
-    let forty: Fish = Fish{a: box 40};
-    let two: Fish = Fish{a: box 2};
+    let forty: Fish = Fish{ a: Box::new(40) };
+    let two: Fish = Fish{ a: Box::new(2) };
     let answer: isize = forty.a + two.a;
     //~^ ERROR cannot add `Box<isize>` to `Box<isize>`
     println!("{}", answer);
index fadb0784e75257eb35354fe9b7c7885ed67b710b..af747cc76e9a062700280cb4a75107a767277966 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 trait double {
     fn double(self: Box<Self>) -> usize;
@@ -11,6 +10,6 @@ fn double(self: Box<usize>) -> usize { *self * 2 }
 }
 
 pub fn main() {
-    let x: Box<_> = box (box 3usize as Box<dyn double>);
+    let x: Box<_> = Box::new(Box::new(3usize) as Box<dyn double>);
     assert_eq!(x.double(), 6);
 }
index a218f85eba2c6cecf487d049c0735edb581dacbe..88a5140dc752bb8d3fc1cad5ec08d487aba206b3 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 trait double {
     fn double(self) -> usize;
@@ -15,6 +14,6 @@ fn double(self) -> usize { *self * 2 }
 }
 
 pub fn main() {
-    let x: Box<_> = box 3;
+    let x: Box<_> = Box::new(3);
     assert_eq!(x.double(), 6);
 }
index 9fda3b2c09999c0056a3852e4df503e7b441af2b..3657e61d42534a99253362e9bfa559045e057dda 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 trait double {
     fn double(self: Box<Self>) -> usize;
@@ -11,6 +10,6 @@ fn double(self: Box<Box<usize>>) -> usize { **self * 2 }
 }
 
 pub fn main() {
-    let x: Box<Box<Box<Box<Box<_>>>>> = box box box box box 3;
+    let x: Box<Box<Box<Box<Box<_>>>>> = Box::new(Box::new(Box::new(Box::new(Box::new(3)))));
     assert_eq!(x.double(), 6);
 }
index f53dc8d1032bff65db3304b5657e1365960975ff..ed86b31b8bbed626443bbc947368c3296ddb8a18 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 trait double {
     fn double(self: Box<Self>) -> usize;
@@ -11,6 +10,6 @@ fn double(self: Box<usize>) -> usize { *self * 2 }
 }
 
 pub fn main() {
-    let x: Box<Box<_>> = box box 3;
+    let x: Box<Box<_>> = Box::new(Box::new(3));
     assert_eq!(x.double(), 6);
 }
index 262050fa47bec440048b84b9bcbd57c7bbf00df1..5b7965e9553fef2a74bf002d10576cf3c9438541 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 trait double {
     fn double(self: Box<Self>) -> usize;
@@ -11,6 +10,6 @@ fn double(self: Box<usize>) -> usize { *self * 2 }
 }
 
 pub fn main() {
-    let x: Box<_> = box 3;
+    let x: Box<_> = Box::new(3);
     assert_eq!(x.double(), 6);
 }
index 70ef7ce87ede8eb3663fc6627029ff70d2e46264..3bdc248ff0f7f1dea34472e624358c7931a95db7 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 trait Foo {
     fn foo(&self) -> String;
@@ -18,6 +17,6 @@ fn foo(&self) -> String {
 }
 
 pub fn main() {
-    let x: Box<_> = box 3;
+    let x: Box<_> = Box::new(3);
     assert_eq!(x.foo(), "box 3".to_string());
 }
index 5a5f75eea36792da25e2fa28135f729fdaf5941f..c5f38d815593a50f5463a7f6e154ffb0171d4172 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn test_generic<T: Clone, F>(expected: Box<T>, eq: F) where F: FnOnce(Box<T>, Box<T>) -> bool {
     let actual: Box<T> = match true {
@@ -13,7 +12,7 @@ fn test_box() {
     fn compare_box(b1: Box<bool>, b2: Box<bool>) -> bool {
         return *b1 == *b2;
     }
-    test_generic::<bool, _>(box true, compare_box);
+    test_generic::<bool, _>(Box::new(true), compare_box);
 }
 
 pub fn main() { test_box(); }
index 1d236135cdbd7d3cf979bba302325d2976ae774b..8977ca68efa67aaff4c3a358da986e0f07016aae 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn test_generic<T: Clone, F>(expected: T, eq: F) where F: FnOnce(T, T) -> bool {
     let actual: T = match true {
@@ -11,7 +10,7 @@ fn test_generic<T: Clone, F>(expected: T, eq: F) where F: FnOnce(T, T) -> bool {
 
 fn test_vec() {
     fn compare_box(v1: Box<isize>, v2: Box<isize>) -> bool { return v1 == v2; }
-    test_generic::<Box<isize>, _>(box 1, compare_box);
+    test_generic::<Box<isize>, _>(Box::new(1), compare_box);
 }
 
 pub fn main() { test_vec(); }
index a999541207d14f995ee86fe5de84e20f684b985f..eec9e1f8b4ae1c574fe30a39c5a8c3662af92484 100644 (file)
@@ -1,9 +1,8 @@
 // run-pass
-#![feature(box_syntax)]
 
 // Tests for match as expressions resulting in boxed types
 fn test_box() {
-    let res: Box<_> = match true { true => { box 100 }, _ => panic!() };
+    let res: Box<_> = match true { true => { Box::new(100) }, _ => panic!() };
     assert_eq!(*res, 100);
 }
 
index 98dd51811de5b03d5444a0fdfe3b4a479cf1d06d..eb94ee48f9249ccafd531762b3a91b4bb3018044 100644 (file)
@@ -3,8 +3,6 @@
 // Test that we do not leak when the arg pattern must drop part of the
 // argument (in this case, the `y` field).
 
-#![feature(box_syntax)]
-
 struct Foo {
     x: Box<usize>,
     y: Box<usize>,
@@ -16,9 +14,9 @@ fn foo(Foo {x, ..}: Foo) -> *const usize {
 }
 
 pub fn main() {
-    let obj: Box<_> = box 1;
+    let obj: Box<_> = Box::new(1);
     let objptr: *const usize = &*obj;
-    let f = Foo {x: obj, y: box 2};
+    let f = Foo { x: obj, y: Box::new(2) };
     let xptr = foo(f);
     assert_eq!(objptr, xptr);
 }
index f46eeb7a020d8f9ef0464d821d3db2a2fd285de8..2d75c12140bf3befa326985ea4536a8fe2206a35 100644 (file)
@@ -5,7 +5,6 @@
 // pattern.
 
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 fn getaddr(box ref x: Box<usize>) -> *const usize {
     let addr: *const usize = &*x;
@@ -17,11 +16,11 @@ fn checkval(box ref x: Box<usize>) -> usize {
 }
 
 pub fn main() {
-    let obj: Box<_> = box 1;
+    let obj: Box<_> = Box::new(1);
     let objptr: *const usize = &*obj;
     let xptr = getaddr(obj);
     assert_eq!(objptr, xptr);
 
-    let obj = box 22;
+    let obj = Box::new(22);
     assert_eq!(checkval(obj), 22);
 }
index 5bb375d285d38ed258e259763622239f606b464d..b85f4a96a6d50d8c774fea6d8655eb51cfc20df4 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn f() {
-    let a: Box<_> = box 1;
+    let a: Box<_> = Box::new(1);
     let b: &isize = &*a;
     println!("{}", b);
 }
index a7e8109b46ca7d573dbbf920bc7ea27ce1051ae9..74ffe2ecdb3a5eea1ac94afaac0a0e4a13eaa1d4 100644 (file)
@@ -1,16 +1,15 @@
 // run-pass
 #![allow(non_shorthand_field_patterns)]
-#![feature(box_syntax)]
 
 struct Pair { a: Box<isize>, b: Box<isize> }
 
 pub fn main() {
-    let mut x: Box<_> = box Pair {a: box 10, b: box 20};
+    let mut x: Box<_> = Box::new(Pair { a: Box::new(10), b: Box::new(20) });
     let x_internal = &mut *x;
     match *x_internal {
       Pair {a: ref mut a, b: ref mut _b} => {
         assert_eq!(**a, 10);
-        *a = box 30;
+        *a = Box::new(30);
         assert_eq!(**a, 30);
       }
     }
index f5361b118bed85aebab71ece419754014e8c57bd..507478983f68163ab662754b1a4fda0d12fa410d 100644 (file)
@@ -1,9 +1,8 @@
 // run-pass
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 pub fn main() {
-    match box 100 {
+    match Box::new(100) {
       box x => {
         println!("{}", x);
         assert_eq!(x, 100);
index 4b209b20a18aa4e32fcc98d996eae335007c3482..0d750da79e71c042fbb6451d1b399c8d1e9e714d 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 fn foo(x: Option<Box<isize>>, b: bool) -> isize {
     match x {
       None => { 1 }
@@ -12,8 +10,8 @@ fn foo(x: Option<Box<isize>>, b: bool) -> isize {
 }
 
 pub fn main() {
-    foo(Some(box 22), true);
-    foo(Some(box 22), false);
+    foo(Some(Box::new(22)), true);
+    foo(Some(Box::new(22)), false);
     foo(None, true);
     foo(None, false);
 }
index 3e24a1b29c920e66e9ed577bb34b957a524f897c..c628fa49ede4370f64b16257473557180225ada8 100644 (file)
@@ -1,13 +1,13 @@
-#![feature(box_syntax)]
+struct Foo(Box<isize>, isize);
+
+struct Bar(isize, isize);
 
 
 
-struct Foo(Box<isize>, isize);
 
-struct Bar(isize, isize);
 
 fn main() {
-    let x: (Box<_>, _) = (box 1, 2);
+    let x: (Box<_>, _) = (Box::new(1), 2);
     let r = &x.0;
     let y = x; //~ ERROR cannot move out of `x` because it is borrowed
 
@@ -23,7 +23,7 @@ fn main() {
     let b = &mut x.0; //~ ERROR cannot borrow `x.0` as mutable more than once at a time
     a.use_ref();
 
-    let x = Foo(box 1, 2);
+    let x = Foo(Box::new(1), 2);
     let r = &x.0;
     let y = x; //~ ERROR cannot move out of `x` because it is borrowed
     r.use_ref();
index 3abc56153b78a96726fed2b239f0f3b6881ac8ab..b0bb9a0351b4900722ef88a6b881ca66d3090431 100644 (file)
@@ -1,10 +1,10 @@
 // Test that we detect nested calls that could free pointers evaluated
 // for earlier arguments.
 
-#![feature(box_syntax)]
+
 
 fn rewrite(v: &mut Box<usize>) -> usize {
-    *v = box 22;
+    *v = Box::new(22);
     **v
 }
 
@@ -13,7 +13,7 @@ fn add(v: &usize, w: usize) -> usize {
 }
 
 fn implicit() {
-    let mut a: Box<_> = box 1;
+    let mut a: Box<_> = Box::new(1);
 
     // Note the danger here:
     //
@@ -26,7 +26,7 @@ fn implicit() {
 }
 
 fn explicit() {
-    let mut a: Box<_> = box 1;
+    let mut a: Box<_> = Box::new(1);
     add(
         &*a,
         rewrite(&mut a)); //~ ERROR cannot borrow
index fd8df78a5d5a1e4a90b255ba5d5522ec1f11b64b..b2afb6391c1ad53655859f0a710142c0c7289ba0 100644 (file)
@@ -1,10 +1,10 @@
 // Test that we detect nested calls that could free pointers evaluated
 // for earlier arguments.
 
-#![feature(box_syntax)]
+
 
 fn rewrite(v: &mut Box<usize>) -> usize {
-    *v = box 22;
+    *v = Box::new(22);
     **v
 }
 
@@ -13,7 +13,7 @@ fn add(v: &usize, w: Box<usize>) -> usize {
 }
 
 fn implicit() {
-    let mut a: Box<_> = box 1;
+    let mut a: Box<_> = Box::new(1);
 
     // Note the danger here:
     //
@@ -26,7 +26,7 @@ fn implicit() {
 }
 
 fn explicit() {
-    let mut a: Box<_> = box 1;
+    let mut a: Box<_> = Box::new(1);
     add(
         &*a,
         a); //~ ERROR cannot move
index 15c6e8bf210fcec2684fd2e39afc0b4d8b136d3f..24efadc3055117f368fa020dc760ca7416d052e0 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn borrow<F>(x: &isize, f: F) where F: FnOnce(&isize) {
     f(x)
@@ -14,5 +13,5 @@ fn test1(x: &Box<isize>) {
 }
 
 pub fn main() {
-    test1(&box 22);
+    test1(&Box::new(22));
 }
index bc820ee9f9141a7d506748653d0be7d6201e5e2d..6b5544a8a396ba5d9aca5ef46313d04e3b0e5c12 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 struct A;
 
 impl A {
@@ -7,8 +5,10 @@ fn foo(&mut self) {
     }
 }
 
+
+
 pub fn main() {
-    let a: Box<_> = box A;
+    let a: Box<_> = Box::new(A);
     a.foo();
     //~^ ERROR cannot borrow `*a` as mutable, as `a` is not declared as mutable [E0596]
 }
index 7d7e305a31f31ccf3d113e53af7c9ffd3756efa8..76dc01202f6c9266f8b3acd9085fc0e80d7c1410 100644 (file)
@@ -1,7 +1,7 @@
 error[E0596]: cannot borrow `*a` as mutable, as `a` is not declared as mutable
   --> $DIR/borrowck-borrow-immut-deref-of-box-as-mut.rs:12:5
    |
-LL |     let a: Box<_> = box A;
+LL |     let a: Box<_> = Box::new(A);
    |         - help: consider changing this to be mutable: `mut a`
 LL |     a.foo();
    |     ^ cannot borrow as mutable
index a78c66f47cd14c9c3ca73a163a374f013691d11d..1d05845fc6b20d626b5dee1dc515d103cfeffeea 100644 (file)
@@ -1,8 +1,8 @@
-//buggy.rs
+use std::collections::HashMap;
+
+
 
-#![feature(box_syntax)]
 
-use std::collections::HashMap;
 
 fn main() {
     let tmp: Box<_>;
@@ -10,6 +10,6 @@ fn main() {
     buggy_map.insert(42, &*Box::new(1)); //~ ERROR temporary value dropped while borrowed
 
     // but it is ok if we use a temporary
-    tmp = box 2;
+    tmp = Box::new(2);
     buggy_map.insert(43, &*tmp);
 }
index e5591f500380b5c9b1cdbef060f3e09d08e5c7ce..e880f876f91a94a74444433184a987b176ed7ce9 100644 (file)
@@ -3,8 +3,6 @@
 
 // run-pass
 
-#![feature(box_syntax)]
-
 struct A {
     x: Box<isize>,
     y: isize,
@@ -26,97 +24,97 @@ struct D {
 }
 
 fn copy_after_move() {
-    let a: Box<_> = box A { x: box 0, y: 1 };
+    let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
     let _x = a.x;
     let _y = a.y;
 }
 
 fn move_after_move() {
-    let a: Box<_> = box B { x: box 0, y: box 1 };
+    let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
     let _x = a.x;
     let _y = a.y;
 }
 
 fn borrow_after_move() {
-    let a: Box<_> = box A { x: box 0, y: 1 };
+    let a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
     let _x = a.x;
     let _y = &a.y;
 }
 
 fn move_after_borrow() {
-    let a: Box<_> = box B { x: box 0, y: box 1 };
+    let a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
     let _x = &a.x;
     let _y = a.y;
     use_imm(_x);
 }
 fn copy_after_mut_borrow() {
-    let mut a: Box<_> = box A { x: box 0, y: 1 };
+    let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
     let _x = &mut a.x;
     let _y = a.y;
     use_mut(_x);
 }
 fn move_after_mut_borrow() {
-    let mut a: Box<_> = box B { x: box 0, y: box 1 };
+    let mut a: Box<_> = Box::new(B { x: Box::new(0), y: Box::new(1) });
     let _x = &mut a.x;
     let _y = a.y;
     use_mut(_x);
 }
 fn borrow_after_mut_borrow() {
-    let mut a: Box<_> = box A { x: box 0, y: 1 };
+    let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
     let _x = &mut a.x;
     let _y = &a.y;
     use_mut(_x);
 }
 fn mut_borrow_after_borrow() {
-    let mut a: Box<_> = box A { x: box 0, y: 1 };
+    let mut a: Box<_> = Box::new(A { x: Box::new(0), y: 1 });
     let _x = &a.x;
     let _y = &mut a.y;
     use_imm(_x);
 }
 fn copy_after_move_nested() {
-    let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+    let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
     let _x = a.x.x;
     let _y = a.y;
 }
 
 fn move_after_move_nested() {
-    let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
+    let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
     let _x = a.x.x;
     let _y = a.y;
 }
 
 fn borrow_after_move_nested() {
-    let a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+    let a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
     let _x = a.x.x;
     let _y = &a.y;
 }
 
 fn move_after_borrow_nested() {
-    let a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
+    let a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
     let _x = &a.x.x;
     let _y = a.y;
     use_imm(_x);
 }
 fn copy_after_mut_borrow_nested() {
-    let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+    let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
     let _x = &mut a.x.x;
     let _y = a.y;
     use_mut(_x);
 }
 fn move_after_mut_borrow_nested() {
-    let mut a: Box<_> = box D { x: box A { x: box 0, y: 1 }, y: box 2 };
+    let mut a: Box<_> = Box::new(D { x: Box::new(A { x: Box::new(0), y: 1 }), y: Box::new(2) });
     let _x = &mut a.x.x;
     let _y = a.y;
     use_mut(_x);
 }
 fn borrow_after_mut_borrow_nested() {
-    let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+    let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
     let _x = &mut a.x.x;
     let _y = &a.y;
     use_mut(_x);
 }
 fn mut_borrow_after_borrow_nested() {
-    let mut a: Box<_> = box C { x: box A { x: box 0, y: 1 }, y: 2 };
+    let mut a: Box<_> = Box::new(C { x: Box::new(A { x: Box::new(0), y: 1 }), y: 2 });
     let _x = &a.x.x;
     let _y = &mut a.y;
     use_imm(_x);
index 2dc405ffcd4c0a100c0a3ee24a80e9af9456a214..a8225f2faf16613bd034167a8577ae94e97c55ee 100644 (file)
@@ -1,8 +1,6 @@
 // Tests that two closures cannot simultaneously have mutable
 // and immutable access to the variable. Issue #6801.
 
-#![feature(box_syntax)]
-
 fn get(x: &isize) -> isize {
     *x
 }
@@ -11,6 +9,8 @@ fn set(x: &mut isize) {
     *x = 4;
 }
 
+
+
 fn a() {
     let mut x = 3;
     let c1 = || x = 4;
@@ -52,7 +52,7 @@ fn e() {
 }
 
 fn f() {
-    let mut x: Box<_> = box 3;
+    let mut x: Box<_> = Box::new(3);
     let c1 = || get(&*x);
     *x = 5;
     //~^ ERROR cannot assign to `*x` because it is borrowed
@@ -64,7 +64,7 @@ struct Foo {
         f: Box<isize>
     }
 
-    let mut x: Box<_> = box Foo { f: box 3 };
+    let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
     let c1 = || get(&*x.f);
     *x.f = 5;
     //~^ ERROR cannot assign to `*x.f` because it is borrowed
@@ -76,7 +76,7 @@ struct Foo {
         f: Box<isize>
     }
 
-    let mut x: Box<_> = box Foo { f: box 3 };
+    let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
     let c1 = || get(&*x.f);
     let c2 = || *x.f = 5;
     //~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
index 2a1757231db851c814c7e526e861652d23a051f2..63a75cdff42de16773afffefc5495ffc6a50d609 100644 (file)
@@ -2,7 +2,7 @@
 // access to the variable, whether that mutable access be used
 // for direct assignment or for taking mutable ref. Issue #6801.
 
-#![feature(box_syntax)]
+
 
 
 
@@ -48,7 +48,7 @@ struct Foo {
         f: Box<isize>
     }
 
-    let mut x: Box<_> = box Foo { f: box 3 };
+    let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
     let c1 = to_fn_mut(|| set(&mut *x.f));
     let c2 = to_fn_mut(|| set(&mut *x.f));
     //~^ ERROR cannot borrow `x` as mutable more than once
index 5fe51654f3b7977ecf7c8f2024ed676403892d17..cdff8f9e890c61680df148c817f7d9e0743acd30 100644 (file)
@@ -2,7 +2,7 @@
 // access to the variable, whether that mutable access be used
 // for direct assignment or for taking mutable ref. Issue #6801.
 
-#![feature(box_syntax)]
+
 
 fn to_fn_mut<F: FnMut()>(f: F) -> F { f }
 
@@ -44,7 +44,7 @@ struct Foo {
         f: Box<isize>
     }
 
-    let mut x: Box<_> = box Foo { f: box 3 };
+    let mut x: Box<_> = Box::new(Foo { f: Box::new(3) });
     let c1 = to_fn_mut(|| set(&mut *x.f));
     let c2 = to_fn_mut(|| set(&mut *x.f));
     //~^ ERROR cannot borrow `x` as mutable more than once
index e9f65c4ff7df419d14430223b669ee319824b719..be5f1f873df52bfaa6926036a26e9f67e6e8418f 100644 (file)
@@ -2,8 +2,6 @@
 // cannot also be supplied a borrowed version of that
 // variable's contents. Issue #11192.
 
-#![feature(box_syntax)]
-
 struct Foo {
   x: isize
 }
@@ -14,10 +12,12 @@ fn drop(&mut self) {
   }
 }
 
+
+
 fn main() {
-  let mut ptr: Box<_> = box Foo { x: 0 };
+  let mut ptr: Box<_> = Box::new(Foo { x: 0 });
   let mut test = |foo: &Foo| {
-    ptr = box Foo { x: ptr.x + 1 };
+    ptr = Box::new(Foo { x: ptr.x + 1 });
   };
   test(&*ptr); //~ ERROR cannot borrow `*ptr`
 }
index a6dbcf36077a728b704effd7ccff75c735edcb37..30900a3b6d96eadc5989ea4ae6d5e737cf7f3461 100644 (file)
@@ -3,7 +3,7 @@ error[E0502]: cannot borrow `*ptr` as immutable because it is also borrowed as m
    |
 LL |   let mut test = |foo: &Foo| {
    |                  ----------- mutable borrow occurs here
-LL |     ptr = box Foo { x: ptr.x + 1 };
+LL |     ptr = Box::new(Foo { x: ptr.x + 1 });
    |     --- first borrow occurs due to use of `ptr` in closure
 LL |   };
 LL |   test(&*ptr);
index cb1ba90de891e529f0e34740bd5485dc1ff0aedf..dd6708582c1b4b709015ab89d1a2a5db1b89e83f 100644 (file)
@@ -3,89 +3,87 @@
 #![allow(unused_variables)]
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 struct A { a: isize, b: Box<isize> }
 struct B { a: Box<isize>, b: Box<isize> }
 
 fn move_after_copy() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.a);
     drop(x.b);
 }
 
 fn move_after_fu_copy() {
-    let x = A { a: 1, b: box 2 };
-    let _y = A { b: box 3, .. x };
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { b: Box::new(3), .. x };
     drop(x.b);
 }
 
 fn fu_move_after_copy() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.a);
     let _y = A { a: 3, .. x };
 }
 
 fn fu_move_after_fu_copy() {
-    let x = A { a: 1, b: box 2 };
-    let _y = A { b: box 3, .. x };
+    let x = A { a: 1, b: Box::new(2) };
+    let _y = A { b: Box::new(3), .. x };
     let _z = A { a: 4, .. x };
 }
 
 fn copy_after_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.b);
     drop(x.a);
 }
 
 fn copy_after_fu_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let y = A { a: 3, .. x };
     drop(x.a);
 }
 
 fn fu_copy_after_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.b);
-    let _y = A { b: box 3, .. x };
+    let _y = A { b: Box::new(3), .. x };
 }
 
 fn fu_copy_after_fu_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
-    let _z = A { b: box 3, .. x };
+    let _z = A { b: Box::new(3), .. x };
 }
 
 fn borrow_after_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.b);
     let p = &x.a;
     drop(*p);
 }
 
 fn borrow_after_fu_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
     let p = &x.a;
     drop(*p);
 }
 
 fn move_after_borrow() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let p = &x.a;
     drop(x.b);
     drop(*p);
 }
 
 fn fu_move_after_borrow() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let p = &x.a;
     let _y = A { a: 3, .. x };
     drop(*p);
 }
 
 fn mut_borrow_after_mut_borrow() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let p = &mut x.a;
     let q = &mut x.b;
     drop(*p);
@@ -93,134 +91,134 @@ fn mut_borrow_after_mut_borrow() {
 }
 
 fn move_after_move() {
-    let x = B { a: box 1, b: box 2 };
+    let x = B { a: Box::new(1), b: Box::new(2) };
     drop(x.a);
     drop(x.b);
 }
 
 fn move_after_fu_move() {
-    let x = B { a: box 1, b: box 2 };
-    let y = B { a: box 3, .. x };
+    let x = B { a: Box::new(1), b: Box::new(2) };
+    let y = B { a: Box::new(3), .. x };
     drop(x.a);
 }
 
 fn fu_move_after_move() {
-    let x = B { a: box 1, b: box 2 };
+    let x = B { a: Box::new(1), b: Box::new(2) };
     drop(x.a);
-    let z = B { a: box 3, .. x };
+    let z = B { a: Box::new(3), .. x };
     drop(z.b);
 }
 
 fn fu_move_after_fu_move() {
-    let x = B { a: box 1, b: box 2 };
-    let _y = B { b: box 3, .. x };
-    let _z = B { a: box 4, .. x };
+    let x = B { a: Box::new(1), b: Box::new(2) };
+    let _y = B { b: Box::new(3), .. x };
+    let _z = B { a: Box::new(4), .. x };
 }
 
 fn copy_after_assign_after_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     drop(x.b);
-    x = A { a: 3, b: box 4 };
+    x = A { a: 3, b: Box::new(4) };
     drop(*x.b);
 }
 
 fn copy_after_assign_after_fu_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
-    x = A { a: 3, b: box 4 };
+    x = A { a: 3, b: Box::new(4) };
     drop(*x.b);
 }
 
 fn copy_after_field_assign_after_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     drop(x.b);
-    x.b = box 3;
+    x.b = Box::new(3);
     drop(*x.b);
 }
 
 fn copy_after_field_assign_after_fu_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
-    x.b = box 3;
+    x.b = Box::new(3);
     drop(*x.b);
 }
 
 fn borrow_after_assign_after_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     drop(x.b);
-    x = A { a: 3, b: box 4 };
+    x = A { a: 3, b: Box::new(4) };
     let p = &x.b;
     drop(**p);
 }
 
 fn borrow_after_assign_after_fu_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
-    x = A { a: 3, b: box 4 };
+    x = A { a: 3, b: Box::new(4) };
     let p = &x.b;
     drop(**p);
 }
 
 fn borrow_after_field_assign_after_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     drop(x.b);
-    x.b = box 3;
+    x.b = Box::new(3);
     let p = &x.b;
     drop(**p);
 }
 
 fn borrow_after_field_assign_after_fu_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
-    x.b = box 3;
+    x.b = Box::new(3);
     let p = &x.b;
     drop(**p);
 }
 
 fn move_after_assign_after_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let _y = x.b;
-    x = A { a: 3, b: box 4 };
+    x = A { a: 3, b: Box::new(4) };
     drop(x.b);
 }
 
 fn move_after_assign_after_fu_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
-    x = A { a: 3, b: box 4 };
+    x = A { a: 3, b: Box::new(4) };
     drop(x.b);
 }
 
 fn move_after_field_assign_after_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     drop(x.b);
-    x.b = box 3;
+    x.b = Box::new(3);
     drop(x.b);
 }
 
 fn move_after_field_assign_after_fu_move() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
-    x.b = box 3;
+    x.b = Box::new(3);
     drop(x.b);
 }
 
 fn copy_after_assign_after_uninit() {
     let mut x: A;
-    x = A { a: 1, b: box 2 };
+    x = A { a: 1, b: Box::new(2) };
     drop(x.a);
 }
 
 fn borrow_after_assign_after_uninit() {
     let mut x: A;
-    x = A { a: 1, b: box 2 };
+    x = A { a: 1, b: Box::new(2) };
     let p = &x.a;
     drop(*p);
 }
 
 fn move_after_assign_after_uninit() {
     let mut x: A;
-    x = A { a: 1, b: box 2 };
+    x = A { a: 1, b: Box::new(2) };
     drop(x.b);
 }
 
index ab607c2acbd4b15b595bd222f9db68edf6439cda..50edfb6ba2db16bff9620e6f5fcba6006798d6e1 100644 (file)
@@ -1,49 +1,49 @@
-#![feature(box_syntax)]
-
 struct A { a: isize, b: Box<isize> }
 
+
+
 fn deref_after_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.b);
     drop(*x.b); //~ ERROR use of moved value: `x.b`
 }
 
 fn deref_after_fu_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let y = A { a: 3, .. x };
     drop(*x.b); //~ ERROR use of moved value: `x.b`
 }
 
 fn borrow_after_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.b);
     let p = &x.b; //~ ERROR borrow of moved value: `x.b`
     drop(**p);
 }
 
 fn borrow_after_fu_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
     let p = &x.b; //~ ERROR borrow of moved value: `x.b`
     drop(**p);
 }
 
 fn move_after_borrow() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let p = &x.b;
     drop(x.b); //~ ERROR cannot move out of `x.b` because it is borrowed
     drop(**p);
 }
 
 fn fu_move_after_borrow() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let p = &x.b;
     let _y = A { a: 3, .. x }; //~ ERROR cannot move out of `x.b` because it is borrowed
     drop(**p);
 }
 
 fn mut_borrow_after_mut_borrow() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let p = &mut x.a;
     let q = &mut x.a; //~ ERROR cannot borrow `x.a` as mutable more than once at a time
     drop(*p);
@@ -51,25 +51,25 @@ fn mut_borrow_after_mut_borrow() {
 }
 
 fn move_after_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.b);
     drop(x.b);  //~ ERROR use of moved value: `x.b`
 }
 
 fn move_after_fu_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
     drop(x.b);  //~ ERROR use of moved value: `x.b`
 }
 
 fn fu_move_after_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     drop(x.b);
     let _z = A { a: 3, .. x };  //~ ERROR use of moved value: `x.b`
 }
 
 fn fu_move_after_fu_move() {
-    let x = A { a: 1, b: box 2 };
+    let x = A { a: 1, b: Box::new(2) };
     let _y = A { a: 3, .. x };
     let _z = A { a: 4, .. x };  //~ ERROR use of moved value: `x.b`
 }
@@ -91,7 +91,7 @@ fn borrow_after_field_assign_after_uninit() {
 
 fn move_after_field_assign_after_uninit() {
     let mut x: A;
-    x.b = box 1; //~ ERROR assign to part of possibly-uninitialized variable: `x`
+    x.b = Box::new(1); //~ ERROR assign to part of possibly-uninitialized variable: `x`
     drop(x.b);
 }
 
index f1601336fca9b5e2b49a1d0898e3c9d455243033..bb4d2f06016b9ecc5e3126fe662a79617d9892b3 100644 (file)
@@ -123,7 +123,7 @@ LL |     x.a = 1;
 error[E0381]: assign to part of possibly-uninitialized variable: `x`
   --> $DIR/borrowck-field-sensitivity.rs:94:5
    |
-LL |     x.b = box 1;
+LL |     x.b = Box::new(1);
    |     ^^^ use of possibly-uninitialized `x`
 
 error: aborting due to 14 previous errors
index de75368578d9fda69f54330165d48f576440626c..389b8a43c0551391d9c8a8c74cee0e5d5b64317c 100644 (file)
@@ -1,6 +1,6 @@
 // Issue #16205.
 
-#![feature(box_syntax)]
+
 
 struct Foo {
     a: [Box<isize>; 3],
@@ -13,12 +13,12 @@ fn main() {
     }
 
     let f = Foo {
-        a: [box 3, box 4, box 5],
+        a: [Box::new(3), Box::new(4), Box::new(5)],
     };
     for &a in &f.a {  //~ ERROR cannot move out
     }
 
-    let x: Option<Box<_>> = Some(box 1);
+    let x: Option<Box<_>> = Some(Box::new(1));
     for &a in x.iter() {    //~ ERROR cannot move out
     }
 }
index e8c9019264fe7343e658960ae9a2156f28aeffc9..003533a51844d4ad87b3d4920e6b28e70eeed294 100644 (file)
@@ -4,14 +4,14 @@
 // Also includes tests of the errors reported when the Box in question
 // is immutable (#14270).
 
-#![feature(box_syntax)]
+
 
 struct A { a: isize }
 struct B<'a> { a: Box<&'a mut isize> }
 
 fn indirect_write_to_imm_box() {
     let mut x: isize = 1;
-    let y: Box<_> = box &mut x;
+    let y: Box<_> = Box::new(&mut x);
     let p = &y;
     ***p = 2; //~ ERROR cannot assign to `***p`
     drop(p);
@@ -19,7 +19,7 @@ fn indirect_write_to_imm_box() {
 
 fn borrow_in_var_from_var() {
     let mut x: isize = 1;
-    let mut y: Box<_> = box &mut x;
+    let mut y: Box<_> = Box::new(&mut x);
     let p = &y;
     let q = &***p;
     **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
@@ -29,7 +29,7 @@ fn borrow_in_var_from_var() {
 
 fn borrow_in_var_from_var_via_imm_box() {
     let mut x: isize = 1;
-    let y: Box<_> = box &mut x;
+    let y: Box<_> = Box::new(&mut x);
     let p = &y;
     let q = &***p;
     **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
@@ -39,7 +39,7 @@ fn borrow_in_var_from_var_via_imm_box() {
 
 fn borrow_in_var_from_field() {
     let mut x = A { a: 1 };
-    let mut y: Box<_> = box &mut x.a;
+    let mut y: Box<_> = Box::new(&mut x.a);
     let p = &y;
     let q = &***p;
     **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
@@ -49,7 +49,7 @@ fn borrow_in_var_from_field() {
 
 fn borrow_in_var_from_field_via_imm_box() {
     let mut x = A { a: 1 };
-    let y: Box<_> = box &mut x.a;
+    let y: Box<_> = Box::new(&mut x.a);
     let p = &y;
     let q = &***p;
     **y = 2; //~ ERROR cannot assign to `**y` because it is borrowed
@@ -59,7 +59,7 @@ fn borrow_in_var_from_field_via_imm_box() {
 
 fn borrow_in_field_from_var() {
     let mut x: isize = 1;
-    let mut y = B { a: box &mut x };
+    let mut y = B { a: Box::new(&mut x) };
     let p = &y.a;
     let q = &***p;
     **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
@@ -69,7 +69,7 @@ fn borrow_in_field_from_var() {
 
 fn borrow_in_field_from_var_via_imm_box() {
     let mut x: isize = 1;
-    let y = B { a: box &mut x };
+    let y = B { a: Box::new(&mut x) };
     let p = &y.a;
     let q = &***p;
     **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
@@ -79,7 +79,7 @@ fn borrow_in_field_from_var_via_imm_box() {
 
 fn borrow_in_field_from_field() {
     let mut x = A { a: 1 };
-    let mut y = B { a: box &mut x.a };
+    let mut y = B { a: Box::new(&mut x.a) };
     let p = &y.a;
     let q = &***p;
     **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
@@ -89,7 +89,7 @@ fn borrow_in_field_from_field() {
 
 fn borrow_in_field_from_field_via_imm_box() {
     let mut x = A { a: 1 };
-    let y = B { a: box &mut x.a };
+    let y = B { a: Box::new(&mut x.a) };
     let p = &y.a;
     let q = &***p;
     **y.a = 2; //~ ERROR cannot assign to `**y.a` because it is borrowed
index c38293740edaa4c6b385c9c30023c8089149cd32..0fb2267b982ea6fb9505d1b47e2fc1270a932d60 100644 (file)
@@ -1,9 +1,9 @@
-#![feature(box_syntax)]
-
+trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
+impl<T> Fake for T { }
 
 
 fn main() {
-    let x: Option<Box<_>> = Some(box 1);
+    let x: Option<Box<_>> = Some(Box::new(1));
     match x {
       Some(ref _y) => {
         let _a = x; //~ ERROR cannot move
@@ -12,6 +12,3 @@ fn main() {
       _ => {}
     }
 }
-
-trait Fake { fn use_mut(&mut self) { } fn use_ref(&self) { }  }
-impl<T> Fake for T { }
index cea561104874499b20da10389b83aeb78b4b119d..7dbac02154a6e29bddf4ad389f38a403b7bf25b8 100644 (file)
@@ -1,7 +1,7 @@
-#![feature(box_syntax)]
-
 fn main() {
-    let x: Option<Box<_>> = Some(box 1);
+
+    let x: Option<Box<_>> = Some(Box::new(1));
+
     match x {
       Some(ref y) => {
         let _b = *y; //~ ERROR cannot move out
index 1150346f752faa006071e119a620a6114c8c1d0f..19a0dd0c6b17b7e3426c48f03ab6762c26a3da9b 100644 (file)
@@ -4,7 +4,7 @@
 // either genuine or would require more advanced changes.  The latter
 // cases are noted.
 
-#![feature(box_syntax)]
+
 
 fn borrow(_v: &isize) {}
 fn borrow_mut(_v: &mut isize) {}
@@ -13,15 +13,15 @@ fn for_func<F>(_f: F) where F: FnOnce() -> bool { panic!() }
 fn produce<T>() -> T { panic!(); }
 
 fn inc(v: &mut Box<isize>) {
-    *v = box (**v + 1);
+    *v = Box::new(**v + 1);
 }
 
 fn pre_freeze_cond() {
     // In this instance, the freeze is conditional and starts before
     // the mut borrow.
 
-    let u = box 0;
-    let mut v: Box<_> = box 3;
+    let u = Box::new(0);
+    let mut v: Box<_> = Box::new(3);
     let mut _w = &u;
     if cond() {
         _w = &v;
@@ -34,8 +34,8 @@ fn pre_freeze_else() {
     // In this instance, the freeze and mut borrow are on separate sides
     // of the if.
 
-    let u = box 0;
-    let mut v: Box<_> = box 3;
+    let u = Box::new(0);
+    let mut v: Box<_> = Box::new(3);
     let mut _w = &u;
     if cond() {
         _w = &v;
index b650df91ca23cfadce567474a31518b79d17c86f..548ffbd515e98836fe2bf8b2c22b92674078a14d 100644 (file)
@@ -1,18 +1,18 @@
-#![feature(box_syntax)]
-
 fn borrow(_v: &isize) {}
 fn borrow_mut(_v: &mut isize) {}
 fn cond() -> bool { panic!() }
 fn produce<T>() -> T { panic!(); }
 
+
 fn inc(v: &mut Box<isize>) {
-    *v = box (**v + 1);
+    *v = Box::new(**v + 1);
 }
 
+
 fn loop_overarching_alias_mut() {
     // In this instance, the borrow ends on the line before the loop
 
-    let mut v: Box<_> = box 3;
+    let mut v: Box<_> = Box::new(3);
     let mut x = &mut v;
     **x += 1;
     loop {
@@ -23,18 +23,18 @@ fn loop_overarching_alias_mut() {
 fn block_overarching_alias_mut() {
     // In this instance, the borrow encompasses the entire closure call.
 
-    let mut v: Box<_> = box 3;
+    let mut v: Box<_> = Box::new(3);
     let mut x = &mut v;
     for _ in 0..3 {
         borrow(&*v); //~ ERROR cannot borrow
     }
-    *x = box 5;
+    *x = Box::new(5);
 }
 fn loop_aliased_mut() {
     // In this instance, the borrow ends right after each assignment to _x
 
-    let mut v: Box<_> = box 3;
-    let mut w: Box<_> = box 4;
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
     let mut _x = &w;
     loop {
         borrow_mut(&mut *v); // OK
@@ -45,8 +45,8 @@ fn loop_aliased_mut() {
 fn while_aliased_mut() {
     // In this instance, the borrow ends right after each assignment to _x
 
-    let mut v: Box<_> = box 3;
-    let mut w: Box<_> = box 4;
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
     let mut _x = &w;
     while cond() {
         borrow_mut(&mut *v); // OK
@@ -58,8 +58,8 @@ fn while_aliased_mut() {
 fn loop_aliased_mut_break() {
     // In this instance, the borrow ends right after each assignment to _x
 
-    let mut v: Box<_> = box 3;
-    let mut w: Box<_> = box 4;
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
     let mut _x = &w;
     loop {
         borrow_mut(&mut *v);
@@ -72,8 +72,8 @@ fn loop_aliased_mut_break() {
 fn while_aliased_mut_break() {
     // In this instance, the borrow ends right after each assignment to _x
 
-    let mut v: Box<_> = box 3;
-    let mut w: Box<_> = box 4;
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
     let mut _x = &w;
     while cond() {
         borrow_mut(&mut *v);
@@ -84,8 +84,8 @@ fn while_aliased_mut_break() {
 }
 
 fn while_aliased_mut_cond(cond: bool, cond2: bool) {
-    let mut v: Box<_> = box 3;
-    let mut w: Box<_> = box 4;
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
     let mut x = &mut w;
     while cond {
         **x += 1;
index f02c357f48b4c919ade516158e3da2318801c600..df7c86b85623e76f5d02c0c0b73575ad459b0057 100644 (file)
@@ -7,7 +7,7 @@ LL |     for _ in 0..3 {
 LL |         borrow(&*v);
    |                ^^^ immutable borrow occurs here
 LL |     }
-LL |     *x = box 5;
+LL |     *x = Box::new(5);
    |     -- mutable borrow later used here
 
 error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
index 0eb62ede5d65a5ca4f18a3ae4bcfb79a43aa7a98..564c57044a37e015cddeec14d365cfa7b5700f44 100644 (file)
@@ -4,7 +4,7 @@
 // either genuine or would require more advanced changes.  The latter
 // cases are noted.
 
-#![feature(box_syntax)]
+
 
 fn borrow(_v: &isize) {}
 fn borrow_mut(_v: &mut isize) {}
@@ -13,13 +13,13 @@ fn for_func<F>(_f: F) where F: FnOnce() -> bool { panic!() }
 fn produce<T>() -> T { panic!(); }
 
 fn inc(v: &mut Box<isize>) {
-    *v = box (**v + 1);
+    *v = Box::new(**v + 1);
 }
 
 fn pre_freeze() {
     // In this instance, the freeze starts before the mut borrow.
 
-    let mut v: Box<_> = box 3;
+    let mut v: Box<_> = Box::new(3);
     let _w = &v;
     borrow_mut(&mut *v); //~ ERROR cannot borrow
     _w.use_ref();
@@ -28,7 +28,7 @@ fn pre_freeze() {
 fn post_freeze() {
     // In this instance, the const alias starts after the borrow.
 
-    let mut v: Box<_> = box 3;
+    let mut v: Box<_> = Box::new(3);
     borrow_mut(&mut *v);
     let _w = &v;
 }
index 9fa46563fdf801ab8788e76452d6d464ec23f982..e536d404099273ede42310aef0bc6c0b3992cbad 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 use std::thread;
 
 
@@ -8,8 +6,10 @@ fn borrow<F>(v: &isize, f: F) where F: FnOnce(&isize) {
     f(v);
 }
 
+
+
 fn box_imm() {
-    let v: Box<_> = box 3;
+    let v: Box<_> = Box::new(3);
     let w = &v;
     thread::spawn(move|| {
     //~^ ERROR cannot move out of `v` because it is borrowed
@@ -19,7 +19,7 @@ fn box_imm() {
 }
 
 fn box_imm_explicit() {
-    let v: Box<_> = box 3;
+    let v: Box<_> = Box::new(3);
     let w = &v;
     thread::spawn(move|| {
     //~^ ERROR cannot move
index bde73219f70ede7df3ae5e2a3882c6f0be916de8..f3f443721b5ec69e749ef444233998bb1d36b398 100644 (file)
@@ -1,12 +1,12 @@
-#![feature(box_syntax)]
+fn take(_v: Box<isize>) {
+}
+
 
 
 
-fn take(_v: Box<isize>) {
-}
 
 fn box_imm() {
-    let v = box 3;
+    let v = Box::new(3);
     let w = &v;
     take(v); //~ ERROR cannot move out of `v` because it is borrowed
     w.use_ref();
index da30bfa29bbf7ad336a130d9b1d928c2a67928e0..33d6af303102af3d267926cb3fe4d9b6596eac86 100644 (file)
@@ -1,14 +1,14 @@
-#![feature(box_syntax)]
-
 fn borrow<F>(v: &isize, f: F) where F: FnOnce(&isize) {
     f(v);
 }
 
+
+
 fn box_imm() {
-    let mut v: Box<_> = box 3;
+    let mut v: Box<_> = Box::new(3);
     borrow(&*v,
            |w| { //~ ERROR cannot borrow `v` as mutable
-            v = box 4;
+            v = Box::new(4);
             assert_eq!(*v, 3);
             assert_eq!(*w, 4);
         })
index 1d1522a15b1ed0ae19464da611137f6a3741e918..fa5308c2903906179b4f1be41b1b5abe0fc441f1 100644 (file)
@@ -7,7 +7,7 @@ LL |     borrow(&*v,
    |     immutable borrow later used by call
 LL |            |w| {
    |            ^^^ mutable borrow occurs here
-LL |             v = box 4;
+LL |             v = Box::new(4);
    |             - second borrow occurs due to use of `v` in closure
 
 error: aborting due to previous error
index 1baa94edfbe58b2cb164e53f339002b90d457dc7..b8f1650fcdc599bf5d4524f552c5d57cfbc4d245 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
+
 
 use std::ops::Add;
 
@@ -12,12 +12,12 @@ impl Add for Foo {
     fn add(self, f: Foo) -> Foo {
         let Foo(box i) = self;
         let Foo(box j) = f;
-        Foo(box (i + j))
+        Foo(Box::new(i + j))
     }
 }
 
 fn main() {
-    let x = Foo(box 3);
+    let x = Foo(Box::new(3));
     let _y = {x} + x.clone(); // the `{x}` forces a move to occur
     //~^ ERROR borrow of moved value: `x`
 }
index 095ae7f56b22e5643219552e332d6538596c2a4c..cd288065b74f7df96b14e5c6bb09e037bdb7f3b0 100644 (file)
@@ -1,7 +1,7 @@
 error[E0382]: borrow of moved value: `x`
   --> $DIR/borrowck-loan-in-overloaded-op.rs:21:20
    |
-LL |     let x = Foo(box 3);
+LL |     let x = Foo(Box::new(3));
    |         - move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
 LL |     let _y = {x} + x.clone(); // the `{x}` forces a move to occur
    |               -    ^ value borrowed here after move
index 628e49f574cf2f5b92f71eaaee010f9b29459ad2..4e969f6ed83d30935dd74dfd89801a0b5ed8f17b 100644 (file)
@@ -6,9 +6,7 @@
 // Check that we do not ICE when compiling this
 // macro, which reuses the expression `$id`
 
-
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 struct Foo {
   a: isize
@@ -23,7 +21,7 @@ fn elaborate_stm(&mut self, s: Box<Bar>) -> Box<Bar> {
     macro_rules! declare {
       ($id:expr, $rest:expr) => ({
         self.check_id($id);
-        box Bar::Bar2($id, $rest)
+        Box::new(Bar::Bar2($id, $rest))
       })
     }
     match s {
index 98e4b881893cbb4e93e1ef339890cf44b76ccf48..e7a48ebf6ca9b0cd001dc50f2e84740e24e43b27 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let bar: Box<_> = box 3;
+    let bar: Box<_> = Box::new(3);
     let h = || -> isize { *bar };
     assert_eq!(h(), 3);
 }
index a825ed5e89acd8087a3c0c9510733f834611e8fe..f26edef17f34963fd7fed5f2638d4ad323dfd407 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax,unboxed_closures)]
+#![feature(unboxed_closures)]
 
 fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
 fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 
 pub fn main() {
-    let bar: Box<_> = box 3;
+    let bar: Box<_> = Box::new(3);
     let _g = to_fn_mut(|| {
         let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of
     });
index 05489cf18e7fc9a5b2ebc352536a4b1d7a46f8ea..257ec3fbb7fa237266afbbf31f219c92eea359e4 100644 (file)
@@ -1,7 +1,7 @@
 error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure
   --> $DIR/borrowck-move-by-capture.rs:9:29
    |
-LL |       let bar: Box<_> = box 3;
+LL |       let bar: Box<_> = Box::new(3);
    |           --- captured outer variable
 LL |       let _g = to_fn_mut(|| {
    |  ________________________-
index 7ef59f50c0332c856247b5df47e13d1ca73f1492..ef38cbb63a5e3455cb31328eaa43ba5eb3ee5af2 100644 (file)
@@ -1,14 +1,14 @@
-#![feature(box_syntax)]
-
 enum Foo {
     Foo1(Box<u32>, Box<u32>),
     Foo2(Box<u32>),
     Foo3,
 }
 
+
+
 fn blah() {
-    let f = &Foo::Foo1(box 1, box 2);
-    match *f {             //~ ERROR cannot move out of
+    let f = &Foo::Foo1(Box::new(1), Box::new(2));
+    match *f { //~ ERROR cannot move out of
         Foo::Foo1(num1,
                   num2) => (),
         Foo::Foo2(num) => (),
@@ -42,8 +42,8 @@ struct A {
 fn free<T>(_: T) {}
 
 fn blah2() {
-    let a = &A { a: box 1 };
-    match a.a {           //~ ERROR cannot move out of
+    let a = &A { a: Box::new(1) };
+    match a.a { //~ ERROR cannot move out of
         n => {
             free(n)
         }
index e058c80651679f3e22f245c54d0fa370f4af5954..71405f7a7329d1c080b24e64e27bcaa4ddc4dd2d 100644 (file)
@@ -3,10 +3,10 @@
 
 
 
-#![feature(box_syntax)]
+
 
 fn main() {
-    let a: Box<Box<_>> = box box 2;
+    let a: Box<Box<_>> = Box::new(Box::new(2));
     let b = &a;
 
     let z = *a; //~ ERROR: cannot move out of `*a` because it is borrowed
index 233d0a733e316c9564fdfff57383fa65364df1ad..72e7b5a716273a4afaab55700ac192c357955d52 100644 (file)
@@ -1,11 +1,11 @@
-#![feature(box_syntax)]
-
 fn call_f<F:FnOnce() -> isize>(f: F) -> isize {
     f()
 }
 
+
+
 fn main() {
-    let t: Box<_> = box 3;
+    let t: Box<_> = Box::new(3);
 
     call_f(move|| { *t + 1 });
     call_f(move|| { *t + 1 }); //~ ERROR use of moved value
index 1ac4999e6e11d8d78144fbfa8f79eb2ddca652b9..edd597fe30bd291371523b69e5c8e9a0e534fe1e 100644 (file)
@@ -1,7 +1,7 @@
 error[E0382]: use of moved value: `t`
   --> $DIR/borrowck-move-moved-value-into-closure.rs:11:12
    |
-LL |     let t: Box<_> = box 3;
+LL |     let t: Box<_> = Box::new(3);
    |         - move occurs because `t` has type `Box<isize>`, which does not implement the `Copy` trait
 LL | 
 LL |     call_f(move|| { *t + 1 });
index 4185632c4e2919e05f60d18e0115d3fad3319a6d..38abd19322215207241335a1a8431f8277d89606 100644 (file)
@@ -1,7 +1,7 @@
 // Tests that the borrow checker checks all components of a path when moving
 // out.
 
-#![feature(box_syntax)]
+
 
 struct S {
   x : Box<isize>
@@ -10,7 +10,7 @@ struct S {
 fn f<T>(_: T) {}
 
 fn main() {
-  let a : S = S { x : box 1 };
+  let a : S = S { x : Box::new(1) };
   let pb = &a;
   let S { x: ax } = a;  //~ ERROR cannot move out
   f(pb);
index 9f09f8442c04469397af294522f9539d683cddce..57b3819ac5113641589134e7e750477e2a14a615 100644 (file)
@@ -1,13 +1,13 @@
-#![feature(box_syntax)]
-
 use std::thread;
 
+
 fn borrow<T>(_: &T) { }
 
+
 fn different_vars_after_borrows() {
-    let x1: Box<_> = box 1;
+    let x1: Box<_> = Box::new(1);
     let p1 = &x1;
-    let x2: Box<_> = box 2;
+    let x2: Box<_> = Box::new(2);
     let p2 = &x2;
     thread::spawn(move|| {
         //~^ ERROR cannot move out of `x1` because it is borrowed
@@ -20,9 +20,9 @@ fn different_vars_after_borrows() {
 }
 
 fn different_vars_after_moves() {
-    let x1: Box<_> = box 1;
+    let x1: Box<_> = Box::new(1);
     drop(x1);
-    let x2: Box<_> = box 2;
+    let x2: Box<_> = Box::new(2);
     drop(x2);
     thread::spawn(move|| {
         //~^ ERROR use of moved value: `x1`
@@ -33,7 +33,7 @@ fn different_vars_after_moves() {
 }
 
 fn same_var_after_borrow() {
-    let x: Box<_> = box 1;
+    let x: Box<_> = Box::new(1);
     let p = &x;
     thread::spawn(move|| {
         //~^ ERROR cannot move out of `x` because it is borrowed
@@ -44,7 +44,7 @@ fn same_var_after_borrow() {
 }
 
 fn same_var_after_move() {
-    let x: Box<_> = box 1;
+    let x: Box<_> = Box::new(1);
     drop(x);
     thread::spawn(move|| {
         //~^ ERROR use of moved value: `x`
index e159878619a0bd35b4a9cf4a22226611bc7dbe7e..86d2955e2364f4a3a832c0defb288bcf90bc677b 100644 (file)
@@ -30,7 +30,7 @@ LL |     borrow(&*p2);
 error[E0382]: use of moved value: `x1`
   --> $DIR/borrowck-multiple-captures.rs:27:19
    |
-LL |     let x1: Box<_> = box 1;
+LL |     let x1: Box<_> = Box::new(1);
    |         -- move occurs because `x1` has type `Box<i32>`, which does not implement the `Copy` trait
 LL |     drop(x1);
    |          -- value moved here
@@ -44,7 +44,7 @@ LL |         drop(x1);
 error[E0382]: use of moved value: `x2`
   --> $DIR/borrowck-multiple-captures.rs:27:19
    |
-LL |     let x2: Box<_> = box 2;
+LL |     let x2: Box<_> = Box::new(2);
    |         -- move occurs because `x2` has type `Box<i32>`, which does not implement the `Copy` trait
 LL |     drop(x2);
    |          -- value moved here
@@ -91,7 +91,7 @@ LL |         drop(x);
 error[E0382]: use of moved value: `x`
   --> $DIR/borrowck-multiple-captures.rs:49:19
    |
-LL |     let x: Box<_> = box 1;
+LL |     let x: Box<_> = Box::new(1);
    |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
 LL |     drop(x);
    |          - value moved here
index 80b3484e0fb23477d127326d44a298c918041a7d..255b4995b640db8368ef046cf3700b1ee5c1f19f 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 use std::mem::swap;
 
@@ -20,7 +19,7 @@ fn iter_ints<F>(x: &Ints, mut f: F) -> bool where F: FnMut(&isize) -> bool {
 }
 
 pub fn main() {
-    let mut ints: Box<_> = box Ints {sum: box 0, values: Vec::new()};
+    let mut ints: Box<_> = Box::new(Ints {sum: Box::new(0), values: Vec::new()});
     add_int(&mut *ints, 22);
     add_int(&mut *ints, 44);
 
index 4c1ff98ce6ec26e6bb71706818d257281ff894b9..f035049d82d8db4fb2bbfb664aaf9b47d689b38d 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 struct Node_ {
     a: Box<Cycle>
 }
@@ -8,8 +6,10 @@ enum Cycle {
     Node(Node_),
     Empty,
 }
+
 fn main() {
-    let mut x: Box<_> = box Cycle::Node(Node_ {a: box Cycle::Empty});
+    let mut x: Box<_> = Box::new(Cycle::Node(Node_ {a: Box::new(Cycle::Empty)}));
+
     // Create a cycle!
     match *x {
       Cycle::Node(ref mut y) => {
index ddf6354c97341550025050317f3855ac04804de6..344d75cc58f02f9801b3364d3458759cc4aff436 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 use std::ops::Index;
 
 struct MyVec<T> {
@@ -14,8 +12,10 @@ fn index(&self, i: usize) -> &T {
     }
 }
 
+
+
 fn main() {
-    let v = MyVec::<Box<_>> { data: vec![box 1, box 2, box 3] };
+    let v = MyVec::<Box<_>> { data: vec![Box::new(1), Box::new(2), Box::new(3)] };
     let good = &v[0]; // Shouldn't fail here
     let bad = v[0];
     //~^ ERROR cannot move out of index of `MyVec<Box<i32>>`
index f62880788edb748f6a50ae2c458c4062c6eb061d..25d3e0b548646bd49815f5d05335457da4bad299 100644 (file)
@@ -1,17 +1,17 @@
-#![feature(box_syntax)]
+fn borrow(_v: &isize) {}
+
 
 
 
-fn borrow(_v: &isize) {}
 
 fn local() {
-    let mut v: Box<_> = box 3;
+    let mut v: Box<_> = Box::new(3);
     borrow(&*v);
 }
 
 fn local_rec() {
     struct F { f: Box<isize> }
-    let mut v = F {f: box 3};
+    let mut v = F {f: Box::new(3)};
     borrow(&*v.f);
 }
 
@@ -19,35 +19,35 @@ fn local_recs() {
     struct F { f: G }
     struct G { g: H }
     struct H { h: Box<isize> }
-    let mut v = F {f: G {g: H {h: box 3}}};
+    let mut v = F {f: G {g: H {h: Box::new(3)}}};
     borrow(&*v.f.g.h);
 }
 
 fn aliased_imm() {
-    let mut v: Box<_> = box 3;
+    let mut v: Box<_> = Box::new(3);
     let w = &v;
     borrow(&*v);
     w.use_ref();
 }
 
 fn aliased_mut() {
-    let mut v: Box<_> = box 3;
+    let mut v: Box<_> = Box::new(3);
     let w = &mut v;
     borrow(&*v); //~ ERROR cannot borrow `*v`
     w.use_mut();
 }
 
 fn aliased_other() {
-    let mut v: Box<_> = box 3;
-    let mut w: Box<_> = box 4;
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
     let x = &mut w;
     borrow(&*v);
     x.use_mut();
 }
 
 fn aliased_other_reassign() {
-    let mut v: Box<_> = box 3;
-    let mut w: Box<_> = box 4;
+    let mut v: Box<_> = Box::new(3);
+    let mut w: Box<_> = Box::new(4);
     let mut x = &mut w;
     x = &mut v;
     borrow(&*v); //~ ERROR cannot borrow `*v`
index bcd1d3ccd8acb754bfd4c50415a3be8a29e87a5e..1cf763f66fd2022f0de9355dbb350cd85b384af9 100644 (file)
@@ -1,41 +1,39 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 struct A { a: isize, b: Box<isize> }
 
 fn field_copy_after_field_borrow() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let p = &mut x.b;
     drop(x.a);
     **p = 3;
 }
 
 fn fu_field_copy_after_field_borrow() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let p = &mut x.b;
-    let y = A { b: box 3, .. x };
+    let y = A { b: Box::new(3), .. x };
     drop(y);
     **p = 4;
 }
 
 fn field_deref_after_field_borrow() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let p = &mut x.a;
     drop(*x.b);
     *p = 3;
 }
 
 fn field_move_after_field_borrow() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let p = &mut x.a;
     drop(x.b);
     *p = 3;
 }
 
 fn fu_field_move_after_field_borrow() {
-    let mut x = A { a: 1, b: box 2 };
+    let mut x = A { a: 1, b: Box::new(2) };
     let p = &mut x.a;
     let y = A { a: 3, .. x };
     drop(y);
index 95b165d6ef22fe5cb0482db7f966252ecfe0a351..94f88395ff9e2b92c8205a164c5ef23fc136f85f 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax)]
-
 #[derive(Copy, Clone)]
 struct A { a: isize, b: isize }
 
 struct B { a: isize, b: Box<isize> }
 
+
+
 fn var_copy_after_var_borrow() {
     let mut x: isize = 1;
     let p = &mut x;
@@ -50,21 +50,21 @@ fn fu_field_copy_after_field_borrow() {
 }
 
 fn var_deref_after_var_borrow() {
-    let mut x: Box<isize> = box 1;
+    let mut x: Box<isize> = Box::new(1);
     let p = &mut x;
     drop(*x); //~ ERROR cannot use `*x` because it was mutably borrowed
     **p = 2;
 }
 
 fn field_deref_after_var_borrow() {
-    let mut x = B { a: 1, b: box 2 };
+    let mut x = B { a: 1, b: Box::new(2) };
     let p = &mut x;
     drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed
     p.a = 3;
 }
 
 fn field_deref_after_field_borrow() {
-    let mut x = B { a: 1, b: box 2 };
+    let mut x = B { a: 1, b: Box::new(2) };
     let p = &mut x.b;
     drop(*x.b); //~ ERROR cannot use `*x.b` because it was mutably borrowed
     **p = 3;
index 67b6c12ba803a230a09266750e53ec004f8b2698..8a9296c597828adb834b6cb0bebe93f6cfbb464f 100644 (file)
@@ -1,12 +1,12 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
+
 
 fn a() {
-    let mut vec = [box 1, box 2, box 3];
+    let mut vec = [Box::new(1), Box::new(2), Box::new(3)];
     match vec {
         [box ref _a, _, _] => {
         //~^ NOTE borrow of `vec[_]` occurs here
-            vec[0] = box 4; //~ ERROR cannot assign
+            vec[0] = Box::new(4); //~ ERROR cannot assign
             //~^ NOTE assignment to borrowed `vec[_]` occurs here
             _a.use_ref();
             //~^ NOTE borrow later used here
@@ -15,12 +15,12 @@ fn a() {
 }
 
 fn b() {
-    let mut vec = vec![box 1, box 2, box 3];
+    let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
         &mut [ref _b @ ..] => {
         //~^ borrow of `vec[_]` occurs here
-            vec[0] = box 4; //~ ERROR cannot assign
+            vec[0] = Box::new(4); //~ ERROR cannot assign
             //~^ NOTE assignment to borrowed `vec[_]` occurs here
             _b.use_ref();
             //~^ NOTE borrow later used here
@@ -29,7 +29,7 @@ fn b() {
 }
 
 fn c() {
-    let mut vec = vec![box 1, box 2, box 3];
+    let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
         //~^ ERROR cannot move out
@@ -50,7 +50,7 @@ fn c() {
 }
 
 fn d() {
-    let mut vec = vec![box 1, box 2, box 3];
+    let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
         //~^ ERROR cannot move out
@@ -69,7 +69,7 @@ fn d() {
 }
 
 fn e() {
-    let mut vec = vec![box 1, box 2, box 3];
+    let mut vec = vec![Box::new(1), Box::new(2), Box::new(3)];
     let vec: &mut [Box<isize>] = &mut vec;
     match vec {
         //~^ ERROR cannot move out
index 36f8f5c9ad73970c810d74edd4079dfb1c6f084b..41c9b3be28164d2dbbce6736e7b073b42a113882 100644 (file)
@@ -4,7 +4,7 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed
 LL |         [box ref _a, _, _] => {
    |              ------ borrow of `vec[_]` occurs here
 LL |
-LL |             vec[0] = box 4;
+LL |             vec[0] = Box::new(4);
    |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
 LL |
 LL |             _a.use_ref();
@@ -16,7 +16,7 @@ error[E0506]: cannot assign to `vec[_]` because it is borrowed
 LL |         &mut [ref _b @ ..] => {
    |               ----------- borrow of `vec[_]` occurs here
 LL |
-LL |             vec[0] = box 4;
+LL |             vec[0] = Box::new(4);
    |             ^^^^^^ assignment to borrowed `vec[_]` occurs here
 LL |
 LL |             _b.use_ref();
index 6a0b4ed17b96294866da32d19b3cc142f78e88fa..85e0a840a1961102b60de1617da6073a0850ea5c 100644 (file)
@@ -5,7 +5,7 @@
 // Issue 4691: Ensure that functional-struct-updates operates
 // correctly and moves rather than copy when appropriate.
 
-#![feature(box_syntax, core)]
+#![feature(core)]
 
 struct ncint { v: isize }
 fn ncint(v: isize) -> ncint { ncint { v: v } }
@@ -17,7 +17,7 @@ fn new(x:isize,y:isize) -> NoFoo { NoFoo { copied: x, nocopy: ncint(y) } }
 
 struct MoveFoo { copied: isize, moved: Box<isize>, }
 impl MoveFoo {
-    fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: box y } }
+    fn new(x:isize,y:isize) -> MoveFoo { MoveFoo { copied: x, moved: Box::new(y) } }
 }
 
 struct DropNoFoo { inner: NoFoo }
@@ -53,8 +53,8 @@ fn test0() {
 
     // Case 2: Owned
     let f = DropMoveFoo::new(5, 6);
-    let b = DropMoveFoo { inner: MoveFoo { moved: box 7, ..f.inner }};
-    let c = DropMoveFoo { inner: MoveFoo { moved: box 8, ..f.inner }};
+    let b = DropMoveFoo { inner: MoveFoo { moved: Box::new(7), ..f.inner }};
+    let c = DropMoveFoo { inner: MoveFoo { moved: Box::new(8), ..f.inner }};
     assert_eq!(f.inner.copied,    5);
     assert_eq!(*f.inner.moved,    6);
 
@@ -69,7 +69,7 @@ fn test1() {
     // copying move-by-default fields from `f`, so it moves:
     let f = MoveFoo::new(11, 12);
 
-    let b = MoveFoo {moved: box 13, ..f};
+    let b = MoveFoo {moved: Box::new(13), ..f};
     let c = MoveFoo {copied: 14, ..f};
     assert_eq!(b.copied,    11);
     assert_eq!(*b.moved,    13);
index 7e9ff68548225edf9bcd28f809296e964ba97df1..4f560b065f1b55fb7053c9126dd88b89158f0ae0 100644 (file)
@@ -1,14 +1,12 @@
 // check-pass
 
-#![feature(box_syntax)]
-
 struct Foo { a: isize, b: isize }
 
 fn main() {
-    let mut x: Box<_> = box Foo { a: 1, b: 2 };
+    let mut x: Box<_> = Box::new(Foo { a: 1, b: 2 });
     let (a, b) = (&mut x.a, &mut x.b);
 
-    let mut foo: Box<_> = box Foo { a: 1, b: 2 };
+    let mut foo: Box<_> = Box::new(Foo { a: 1, b: 2 });
     let (c, d) = (&mut foo.a, &foo.b);
 
     // We explicitly use the references created above to illustrate that the
index 781d5c14abe9cbfb32ee976ebb4da40e20ef2410..a0a561ab2d21ed9293205383120f151b1b845cfc 100644 (file)
@@ -1,12 +1,10 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 fn foo(x: &mut Box<u8>) {
-    *x = box 5;
+    *x = Box::new(5);
 }
 
 pub fn main() {
-    foo(&mut box 4);
+    foo(&mut Box::new(4));
 }
index bb4c3fac93806e8303d9301609558cb083dfd653..345d6efd2d90ada0f1893a39d027d9033d32d9fb 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 trait Noisy {
   fn speak(&self);
 }
@@ -48,7 +46,9 @@ fn cat(in_x : usize, in_y : isize, in_name: String) -> Cat {
     }
 }
 
+
+
 fn main() {
-  let nyan: Box<dyn Noisy> = box cat(0, 2, "nyan".to_string()) as Box<dyn Noisy>;
+  let nyan: Box<dyn Noisy> = Box::new(cat(0, 2, "nyan".to_string())) as Box<dyn Noisy>;
   nyan.eat(); //~ ERROR no method named `eat` found
 }
index 915842f3e85f243ba03ee8d6c5604a8b5f42b785..38c717089c46bf1712a8dbea4ee2ef4b0fae9344 100644 (file)
@@ -7,7 +7,7 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax, os)]
+#![feature(os)]
 
 use std::os;
 
@@ -15,7 +15,7 @@ struct Test { x: isize }
 
 impl Test {
     fn get_x(&self) -> Option<Box<isize>> {
-        Some(box self.x)
+        Some(Box::new(self.x))
     }
 }
 
index c5dd87c0f5a1fb712de242c120c997ab00e82559..b80f95b79f91d2966ca82abebd03046008f9816a 100644 (file)
@@ -7,7 +7,6 @@
 // lifetime rules.
 
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 use std::ops::Drop;
 
@@ -106,8 +105,8 @@ pub fn main() {
     end_of_block!(AddFlags { bits: ref _x }, AddFlags(1));
     end_of_block!(&AddFlags { bits }, &AddFlags(1));
     end_of_block!((_, ref _y), (AddFlags(1), 22));
-    end_of_block!(box ref _x, box AddFlags(1));
-    end_of_block!(box _x, box AddFlags(1));
+    end_of_block!(box ref _x, std::boxed::Box::new(AddFlags(1)));
+    end_of_block!(box _x, std::boxed::Box::new(AddFlags(1)));
     end_of_block!(_, { { check_flags(0); &AddFlags(1) } });
     end_of_block!(_, &((Box { f: AddFlags(1) }).f));
     end_of_block!(_, &(([AddFlags(1)])[0]));
index 62f8b81385aa3b2d1b77449742217d365682abaf..eadbe44a8e9dee767d2dd0c67def8eac1038aed8 100644 (file)
@@ -21,8 +21,6 @@
 
 // ignore-emscripten no threads support
 
-#![feature(box_syntax)]
-
 use std::thread;
 
 enum Conzabble {
@@ -40,7 +38,7 @@ fn get_bar(x: usize) -> Vec<usize> { vec![x * 2] }
 pub fn fails() {
     let x = 2;
     let mut y: Vec<Box<_>> = Vec::new();
-    y.push(box Conzabble::Bickwick(do_it(&get_bar(x))));
+    y.push(Box::new(Conzabble::Bickwick(do_it(&get_bar(x)))));
 }
 
 pub fn main() {
index 1ef2971926796d6023207765746b753884014ff4..9fc661b14777ea6eb4708a37d7d1b05e6ccacf29 100644 (file)
@@ -3,8 +3,6 @@
 #![allow(unused_must_use)]
 // ignore-emscripten no threads support
 
-#![feature(box_syntax)]
-
 use std::thread;
 
 struct Pair {
@@ -13,7 +11,7 @@ struct Pair {
 }
 
 pub fn main() {
-    let z: Box<_> = box Pair { a : 10, b : 12};
+    let z: Box<_> = Box::new(Pair { a : 10, b : 12});
 
     thread::spawn(move|| {
         assert_eq!(z.a, 10);
index 4d6edf4ecb0f330522ce374a08209a48c3a10210..429b21e8b8b99b73da84f9840146249a1d702e28 100644 (file)
@@ -5,8 +5,6 @@
 // storing closure data (as we used to do), the u64 would
 // overwrite the u16.
 
-#![feature(box_syntax)]
-
 struct Pair<A,B> {
     a: A, b: B
 }
@@ -27,10 +25,10 @@ fn f(&self) -> (A, u16) {
 }
 
 fn f<A:Clone + 'static>(a: A, b: u16) -> Box<dyn Invokable<A>+'static> {
-    box Invoker {
+    Box::new(Invoker {
         a: a,
         b: b,
-    } as Box<dyn Invokable<A>+'static>
+    }) as Box<dyn Invokable<A>+'static>
 }
 
 pub fn main() {
index 6a8c9664051dfc0e4c9681cbe695e63738adc6c1..5ff7b1242db702666dbcf91cf3c6b1adf17f241a 100644 (file)
@@ -1,10 +1,10 @@
 // edition:2021
 
+
+
 // Tests that two closures cannot simultaneously have mutable
 // and immutable access to the variable. Issue #6801.
 
-#![feature(box_syntax)]
-
 #[derive(Debug)]
 struct Point {
     x: i32,
index beebb118399f3920f0b04fbc154be73ae751108a..b0fc5120f08f219783461c3e3e44316ed4323b28 100644 (file)
@@ -4,6 +4,14 @@
 
 use std::thread;
 
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 /* Test Send Trait Migration */
 struct SendPointer(*mut i32);
 unsafe impl Send for SendPointer {}
@@ -42,19 +50,19 @@ fn test_sync_trait() {
 }
 
 /* Test Clone Trait Migration */
-struct S(String);
+struct S(Foo);
 struct T(i32);
 
 struct U(S, T);
 
 impl Clone for U {
     fn clone(&self) -> Self {
-        U(S(String::from("Hello World")), T(0))
+        U(S(Foo(0)), T(0))
     }
 }
 
 fn test_clone_trait() {
-    let f = U(S(String::from("Hello World")), T(0));
+    let f = U(S(Foo(0)), T(0));
     let c = || {
         let _ = &f;
         //~^ ERROR: `Clone` trait implementation for closure and drop order
index 812ecae262f77b8b2ee74d99024aec6fc021fa2f..2bcf9a795edbd8f9fa093efe8b216d76725d777f 100644 (file)
@@ -4,6 +4,14 @@
 
 use std::thread;
 
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 /* Test Send Trait Migration */
 struct SendPointer(*mut i32);
 unsafe impl Send for SendPointer {}
@@ -42,19 +50,19 @@ fn test_sync_trait() {
 }
 
 /* Test Clone Trait Migration */
-struct S(String);
+struct S(Foo);
 struct T(i32);
 
 struct U(S, T);
 
 impl Clone for U {
     fn clone(&self) -> Self {
-        U(S(String::from("Hello World")), T(0))
+        U(S(Foo(0)), T(0))
     }
 }
 
 fn test_clone_trait() {
-    let f = U(S(String::from("Hello World")), T(0));
+    let f = U(S(Foo(0)), T(0));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure and drop order
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
index 98396abb6ff66d6f11cd3c5a3d3a331e01709899..8d2d3553d4040f2fdbb6027cbe71d5fb5c3fd700 100644 (file)
@@ -1,5 +1,5 @@
 error: changes to closure capture in Rust 2021 will affect `Send` trait implementation for closure
-  --> $DIR/auto_traits.rs:14:19
+  --> $DIR/auto_traits.rs:22:19
    |
 LL |     thread::spawn(move || unsafe {
    |                   ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Send` as `fptr` implements `Send`, but in Rust 2021, this closure will no longer implement `Send` as `fptr.0` does not implement `Send`
@@ -24,7 +24,7 @@ LL |         *fptr.0 = 20;
  ...
 
 error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
-  --> $DIR/auto_traits.rs:34:19
+  --> $DIR/auto_traits.rs:42:19
    |
 LL |     thread::spawn(move || unsafe {
    |                   ^^^^^^^^^^^^^^ in Rust 2018, this closure implements `Sync`, `Send` as `fptr` implements `Sync`, `Send`, but in Rust 2021, this closure will no longer implement `Sync`, `Send` as `fptr.0.0` does not implement `Sync`, `Send`
@@ -44,7 +44,7 @@ LL |         *fptr.0.0 = 20;
  ...
 
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/auto_traits.rs:58:13
+  --> $DIR/auto_traits.rs:66:13
    |
 LL |     let c = || {
    |             ^^ in Rust 2018, this closure implements `Clone` as `f` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f.1` does not implement `Clone`
index f91454aa2111e044ee11a99f84582a8b02e267de..9a6db588c8bf50f8b9138af373678202242ea632 100644 (file)
@@ -3,6 +3,14 @@
 // check-pass
 #![warn(rust_2021_compatibility)]
 
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 macro_rules! m {
     (@ $body:expr) => {{
         let f = || $body;
@@ -15,11 +23,11 @@ macro_rules! m {
 }
 
 fn main() {
-    let a = (1.to_string(), 2.to_string());
+    let a = (Foo(0), Foo(1));
     m!({
         let _ = &a;
         //~^ HELP: add a dummy
         let x = a.0;
-        println!("{}", x);
+        println!("{:?}", x);
     });
 }
index 5a1026d04331912d4d998eea56b7bacfd7da06a9..08cc24b4b3fe8f173c066d9a2d481e0c7fe463ff 100644 (file)
@@ -3,6 +3,14 @@
 // check-pass
 #![warn(rust_2021_compatibility)]
 
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 macro_rules! m {
     (@ $body:expr) => {{
         let f = || $body;
@@ -15,10 +23,10 @@ macro_rules! m {
 }
 
 fn main() {
-    let a = (1.to_string(), 2.to_string());
+    let a = (Foo(0), Foo(1));
     m!({
         //~^ HELP: add a dummy
         let x = a.0;
-        println!("{}", x);
+        println!("{:?}", x);
     });
 }
index e6e5598f6d2a1beee09d78c72271ab1c511f074b..a2a9da5f87ced2f9ed3f24fe9ee3cfc45670c485 100644 (file)
@@ -1,5 +1,5 @@
 warning: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/closure-body-macro-fragment.rs:8:17
+  --> $DIR/closure-body-macro-fragment.rs:16:17
    |
 LL |           let f = || $body;
    |  _________________^
@@ -15,7 +15,7 @@ LL | /     m!({
 LL | |
 LL | |         let x = a.0;
    | |                 --- in Rust 2018, this closure captures all of `a`, but in Rust 2021, it will only capture `a.0`
-LL | |         println!("{}", x);
+LL | |         println!("{:?}", x);
 LL | |     });
    | |_______- in this macro invocation
    |
index c82bc369f430181f594aa0a38f2356b521dfcd2d..2652bf5988e6543472052504c1183f753641be80 100644 (file)
+// run-pass
 // run-rustfix
 
 #![deny(rust_2021_incompatible_closure_captures)]
-//~^ NOTE: the lint level is defined here
+#![allow(unused)]
 
 // Test cases for types that implement an insignificant drop (stlib defined)
 
-// `t` needs Drop because one of its elements needs drop,
-// therefore precise capture might affect drop ordering
-fn test1_all_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let t2 = (String::new(), String::new());
+macro_rules! test_insig_dtor_for_type {
+    ($t: ty, $disambiguator: ident) => {
+        mod $disambiguator {
+            use std::collections::*;
+            use std::rc::Rc;
+            use std::sync::Mutex;
 
-    let c = || {
-        let _ = (&t, &t1, &t2);
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+            fn test_for_type(t: $t) {
+                let tup = (Mutex::new(0), t);
 
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _t1 = t1.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-        let _t2 = t2.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+                let _c = || tup.0;
+            }
+        }
     };
-
-    c();
 }
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
-
-// String implements drop and therefore should be migrated.
-// But in this test cases, `t2` is completely captured and when it is dropped won't be affected
-fn test2_only_precise_paths_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let t2 = (String::new(), String::new());
-
-    let c = || {
-        let _ = (&t, &t1);
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _t1 = t1.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-        let _t2 = t2;
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-
-// If a variable would've not been captured by value then it would've not been
-// dropped with the closure and therefore doesn't need migration.
-fn test3_only_by_value_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let c = || {
-        let _ = &t;
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        println!("{}", t1.1);
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-// Copy types get copied into the closure instead of move. Therefore we don't need to
-// migrate then as their drop order isn't tied to the closure.
-fn test4_only_non_copy_types_need_migration() {
-    let t = (String::new(), String::new());
-
-    // `t1` is Copy because all of its elements are Copy
-    let t1 = (0i32, 0i32);
-
-    let c = || {
-        let _ = &t;
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _t1 = t1.0;
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-fn test5_only_drop_types_need_migration() {
-    struct S(i32, i32);
 
-    let t = (String::new(), String::new());
-
-    // `s` doesn't implement Drop or any elements within it, and doesn't need migration
-    let s = S(0i32, 0i32);
-
-    let c = || {
-        let _ = &t;
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _s = s.0;
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-// Since we are using a move closure here, both `t` and `t1` get moved
-// even though they are being used by ref inside the closure.
-fn test6_move_closures_non_copy_types_might_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let c = move || {
-        let _ = (&t1, &t);
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured
-        println!("{} {}", t1.1, t.1);
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
-        //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
-
-// Test migration analysis in case of Drop + Non Drop aggregates.
-// Note we need migration here only because the non-copy (because Drop type) is captured,
-// otherwise we won't need to, since we can get away with just by ref capture in that case.
-fn test7_drop_non_drop_aggregate_need_migration() {
-    let t = (String::new(), String::new(), 0i32);
-
-    let c = || {
-        let _ = &t;
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-fn main() {
-    test1_all_need_migration();
-    test2_only_precise_paths_need_migration();
-    test3_only_by_value_need_migration();
-    test4_only_non_copy_types_need_migration();
-    test5_only_drop_types_need_migration();
-    test6_move_closures_non_copy_types_might_need_migration();
-    test7_drop_non_drop_aggregate_need_migration();
-}
+test_insig_dtor_for_type!(i32, prim_i32);
+test_insig_dtor_for_type!(Vec<i32>, vec_i32);
+test_insig_dtor_for_type!(String, string);
+test_insig_dtor_for_type!(Vec<String>, vec_string);
+test_insig_dtor_for_type!(HashMap<String, String>, hash_map);
+test_insig_dtor_for_type!(BTreeMap<String, i32>, btree_map);
+test_insig_dtor_for_type!(LinkedList<String>, linked_list);
+test_insig_dtor_for_type!(Rc<i32>, rc_i32);
+test_insig_dtor_for_type!(Rc<String>, rc_string);
+test_insig_dtor_for_type!(std::vec::IntoIter<String>, vec_into_iter);
+test_insig_dtor_for_type!(btree_map::IntoIter<String, String>, btree_map_into_iter);
+test_insig_dtor_for_type!(std::array::IntoIter<String, 5>, array_into_iter);
+
+fn main() {}
index 57ab15ae8f2439041e440060209a480df4cd4457..2652bf5988e6543472052504c1183f753641be80 100644 (file)
+// run-pass
 // run-rustfix
 
 #![deny(rust_2021_incompatible_closure_captures)]
-//~^ NOTE: the lint level is defined here
+#![allow(unused)]
 
 // Test cases for types that implement an insignificant drop (stlib defined)
 
-// `t` needs Drop because one of its elements needs drop,
-// therefore precise capture might affect drop ordering
-fn test1_all_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let t2 = (String::new(), String::new());
+macro_rules! test_insig_dtor_for_type {
+    ($t: ty, $disambiguator: ident) => {
+        mod $disambiguator {
+            use std::collections::*;
+            use std::rc::Rc;
+            use std::sync::Mutex;
 
-    let c = || {
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
+            fn test_for_type(t: $t) {
+                let tup = (Mutex::new(0), t);
 
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _t1 = t1.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-        let _t2 = t2.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
+                let _c = || tup.0;
+            }
+        }
     };
-
-    c();
 }
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
-
-// String implements drop and therefore should be migrated.
-// But in this test cases, `t2` is completely captured and when it is dropped won't be affected
-fn test2_only_precise_paths_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let t2 = (String::new(), String::new());
-
-    let c = || {
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t`, `t1` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _t1 = t1.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-        let _t2 = t2;
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-
-// If a variable would've not been captured by value then it would've not been
-// dropped with the closure and therefore doesn't need migration.
-fn test3_only_by_value_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let c = || {
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        println!("{}", t1.1);
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-// Copy types get copied into the closure instead of move. Therefore we don't need to
-// migrate then as their drop order isn't tied to the closure.
-fn test4_only_non_copy_types_need_migration() {
-    let t = (String::new(), String::new());
-
-    // `t1` is Copy because all of its elements are Copy
-    let t1 = (0i32, 0i32);
-
-    let c = || {
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _t1 = t1.0;
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-fn test5_only_drop_types_need_migration() {
-    struct S(i32, i32);
 
-    let t = (String::new(), String::new());
-
-    // `s` doesn't implement Drop or any elements within it, and doesn't need migration
-    let s = S(0i32, 0i32);
-
-    let c = || {
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-        let _s = s.0;
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-// Since we are using a move closure here, both `t` and `t1` get moved
-// even though they are being used by ref inside the closure.
-fn test6_move_closures_non_copy_types_might_need_migration() {
-    let t = (String::new(), String::new());
-    let t1 = (String::new(), String::new());
-    let c = move || {
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t1`, `t` to be fully captured
-        println!("{} {}", t1.1, t.1);
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
-        //~| NOTE: in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
-//~| in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
-
-// Test migration analysis in case of Drop + Non Drop aggregates.
-// Note we need migration here only because the non-copy (because Drop type) is captured,
-// otherwise we won't need to, since we can get away with just by ref capture in that case.
-fn test7_drop_non_drop_aggregate_need_migration() {
-    let t = (String::new(), String::new(), 0i32);
-
-    let c = || {
-        //~^ ERROR: drop order
-        //~| NOTE: for more information, see
-        //~| HELP: add a dummy let to cause `t` to be fully captured
-        let _t = t.0;
-        //~^ NOTE: in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-    };
-
-    c();
-}
-//~^ in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-
-fn main() {
-    test1_all_need_migration();
-    test2_only_precise_paths_need_migration();
-    test3_only_by_value_need_migration();
-    test4_only_non_copy_types_need_migration();
-    test5_only_drop_types_need_migration();
-    test6_move_closures_non_copy_types_might_need_migration();
-    test7_drop_non_drop_aggregate_need_migration();
-}
+test_insig_dtor_for_type!(i32, prim_i32);
+test_insig_dtor_for_type!(Vec<i32>, vec_i32);
+test_insig_dtor_for_type!(String, string);
+test_insig_dtor_for_type!(Vec<String>, vec_string);
+test_insig_dtor_for_type!(HashMap<String, String>, hash_map);
+test_insig_dtor_for_type!(BTreeMap<String, i32>, btree_map);
+test_insig_dtor_for_type!(LinkedList<String>, linked_list);
+test_insig_dtor_for_type!(Rc<i32>, rc_i32);
+test_insig_dtor_for_type!(Rc<String>, rc_string);
+test_insig_dtor_for_type!(std::vec::IntoIter<String>, vec_into_iter);
+test_insig_dtor_for_type!(btree_map::IntoIter<String, String>, btree_map_into_iter);
+test_insig_dtor_for_type!(std::array::IntoIter<String, 5>, array_into_iter);
+
+fn main() {}
diff --git a/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr b/src/test/ui/closures/2229_closure_analysis/migrations/insignificant_drop.stderr
deleted file mode 100644 (file)
index 7989a8f..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop.rs:15:13
-   |
-LL |     let c = || {
-   |             ^^
-...
-LL |         let _t = t.0;
-   |                  --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-LL |
-LL |         let _t1 = t1.0;
-   |                   ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-LL |
-LL |         let _t2 = t2.0;
-   |                   ---- in Rust 2018, this closure captures all of `t2`, but in Rust 2021, it will only capture `t2.0`
-...
-LL | }
-   | -
-   | |
-   | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-   | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-   | in Rust 2018, `t2` is dropped here, but in Rust 2021, only `t2.0` will be dropped here as part of the closure
-   |
-note: the lint level is defined here
-  --> $DIR/insignificant_drop.rs:3:9
-   |
-LL | #![deny(rust_2021_incompatible_closure_captures)]
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t`, `t1`, `t2` to be fully captured
-   |
-LL ~     let c = || {
-LL +         let _ = (&t, &t1, &t2);
-   |
-
-error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop.rs:41:13
-   |
-LL |     let c = || {
-   |             ^^
-...
-LL |         let _t = t.0;
-   |                  --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-LL |
-LL |         let _t1 = t1.0;
-   |                   ---- in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.0`
-...
-LL | }
-   | -
-   | |
-   | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-   | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.0` will be dropped here as part of the closure
-   |
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t`, `t1` to be fully captured
-   |
-LL ~     let c = || {
-LL +         let _ = (&t, &t1);
-   |
-
-error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop.rs:62:13
-   |
-LL |     let c = || {
-   |             ^^
-...
-LL |         let _t = t.0;
-   |                  --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-...
-LL | }
-   | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-   |
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t` to be fully captured
-   |
-LL ~     let c = || {
-LL +         let _ = &t;
-   |
-
-error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop.rs:83:13
-   |
-LL |     let c = || {
-   |             ^^
-...
-LL |         let _t = t.0;
-   |                  --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-...
-LL | }
-   | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-   |
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t` to be fully captured
-   |
-LL ~     let c = || {
-LL +         let _ = &t;
-   |
-
-error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop.rs:104:13
-   |
-LL |     let c = || {
-   |             ^^
-...
-LL |         let _t = t.0;
-   |                  --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-...
-LL | }
-   | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-   |
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t` to be fully captured
-   |
-LL ~     let c = || {
-LL +         let _ = &t;
-   |
-
-error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop.rs:122:13
-   |
-LL |     let c = move || {
-   |             ^^^^^^^
-...
-LL |         println!("{} {}", t1.1, t.1);
-   |                           ----  --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.1`
-   |                           |
-   |                           in Rust 2018, this closure captures all of `t1`, but in Rust 2021, it will only capture `t1.1`
-...
-LL | }
-   | -
-   | |
-   | in Rust 2018, `t1` is dropped here, but in Rust 2021, only `t1.1` will be dropped here as part of the closure
-   | in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.1` will be dropped here as part of the closure
-   |
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t1`, `t` to be fully captured
-   |
-LL ~     let c = move || {
-LL +         let _ = (&t1, &t);
-   |
-
-error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop.rs:142:13
-   |
-LL |     let c = || {
-   |             ^^
-...
-LL |         let _t = t.0;
-   |                  --- in Rust 2018, this closure captures all of `t`, but in Rust 2021, it will only capture `t.0`
-...
-LL | }
-   | - in Rust 2018, `t` is dropped here, but in Rust 2021, only `t.0` will be dropped here as part of the closure
-   |
-   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
-help: add a dummy let to cause `t` to be fully captured
-   |
-LL ~     let c = || {
-LL +         let _ = &t;
-   |
-
-error: aborting due to 7 previous errors
-
index e672d9266fcd19dba7135009d4e73e3111528304..d985e3bb9ec74131ff59a13d678b0bbdfdf9ea12 100644 (file)
@@ -5,13 +5,15 @@
 #![feature(rustc_attrs)]
 #![allow(unused)]
 
+use std::sync::Mutex;
+
+    #[rustc_insignificant_dtor]
 struct InsignificantDropPoint {
     x: i32,
-    y: i32,
+    y: Mutex<i32>,
 }
 
 impl Drop for InsignificantDropPoint {
-    #[rustc_insignificant_dtor]
     fn drop(&mut self) {}
 }
 
@@ -21,15 +23,15 @@ impl Drop for SigDrop {
     fn drop(&mut self) {}
 }
 
+#[rustc_insignificant_dtor]
 struct GenericStruct<T>(T, T);
 
-struct Wrapper<T>(GenericStruct<T>, i32);
-
 impl<T> Drop for GenericStruct<T> {
-    #[rustc_insignificant_dtor]
     fn drop(&mut self) {}
 }
 
+struct Wrapper<T>(GenericStruct<T>, i32);
+
 // `SigDrop` implements drop and therefore needs to be migrated.
 fn significant_drop_needs_migration() {
     let t = (SigDrop {}, SigDrop {});
index 45850ec5f36dce9f68e8ee665e29456bea5a641e..f95d34eeb299aaf68d60392aae52bf0cac006226 100644 (file)
@@ -5,13 +5,15 @@
 #![feature(rustc_attrs)]
 #![allow(unused)]
 
+use std::sync::Mutex;
+
+    #[rustc_insignificant_dtor]
 struct InsignificantDropPoint {
     x: i32,
-    y: i32,
+    y: Mutex<i32>,
 }
 
 impl Drop for InsignificantDropPoint {
-    #[rustc_insignificant_dtor]
     fn drop(&mut self) {}
 }
 
@@ -21,15 +23,15 @@ impl Drop for SigDrop {
     fn drop(&mut self) {}
 }
 
+#[rustc_insignificant_dtor]
 struct GenericStruct<T>(T, T);
 
-struct Wrapper<T>(GenericStruct<T>, i32);
-
 impl<T> Drop for GenericStruct<T> {
-    #[rustc_insignificant_dtor]
     fn drop(&mut self) {}
 }
 
+struct Wrapper<T>(GenericStruct<T>, i32);
+
 // `SigDrop` implements drop and therefore needs to be migrated.
 fn significant_drop_needs_migration() {
     let t = (SigDrop {}, SigDrop {});
index 961834aca194d4b2daef9f515bae695f76a66fc7..832a81711b13775a1f6f516b708ad1ba24b6a77d 100644 (file)
@@ -1,5 +1,5 @@
 error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop_attr_migrations.rs:37:13
+  --> $DIR/insignificant_drop_attr_migrations.rs:39:13
    |
 LL |     let c = || {
    |             ^^
@@ -23,7 +23,7 @@ LL +         let _ = &t;
    |
 
 error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/insignificant_drop_attr_migrations.rs:57:13
+  --> $DIR/insignificant_drop_attr_migrations.rs:59:13
    |
 LL |     let c = move || {
    |             ^^^^^^^
index a527bf42e574a7b8ce1ccf6140980854ba9e8210..3f184a67fbac93b728fac5ccce07a6a4500cf71f 100644 (file)
@@ -3,6 +3,7 @@
 #![deny(rust_2021_incompatible_closure_captures)]
 #![feature(rustc_attrs)]
 #![allow(unused)]
+#[rustc_insignificant_dtor]
 
 struct InsignificantDropPoint {
     x: i32,
@@ -10,7 +11,6 @@ struct InsignificantDropPoint {
 }
 
 impl Drop for InsignificantDropPoint {
-    #[rustc_insignificant_dtor]
     fn drop(&mut self) {}
 }
 
index b9dd8a20b093f782ebb7c5962a331371bb7e1599..31fe494dc795a900620a2ac511adf7963e342b36 100644 (file)
@@ -5,8 +5,17 @@
 #![deny(rust_2021_incompatible_closure_captures)]
 //~^ NOTE: the lint level is defined here
 
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 fn main() {
-    let a = ("hey".to_string(), "123".to_string());
+    let a = (Foo(0), Foo(1));
     let _ = || { let _ = &a; dbg!(a.0) };
     //~^ ERROR: drop order
     //~| NOTE: will only capture `a.0`
index f7ccdb754b85821acbcad57dc77948346dc1af44..0f0c497492290b60fd769e64328d98d686c77970 100644 (file)
@@ -5,8 +5,17 @@
 #![deny(rust_2021_incompatible_closure_captures)]
 //~^ NOTE: the lint level is defined here
 
+
+#[derive(Debug)]
+struct Foo(i32);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
 fn main() {
-    let a = ("hey".to_string(), "123".to_string());
+    let a = (Foo(0), Foo(1));
     let _ = || dbg!(a.0);
     //~^ ERROR: drop order
     //~| NOTE: will only capture `a.0`
index d1f959dfc520e2fe8f5f5e2965c2ff4670f26c1a..5046a4bcbb4b37fa009b59c965cc11eb93ecbc36 100644 (file)
@@ -1,5 +1,5 @@
 error: changes to closure capture in Rust 2021 will affect drop order
-  --> $DIR/macro.rs:10:13
+  --> $DIR/macro.rs:19:13
    |
 LL |     let _ = || dbg!(a.0);
    |             ^^^^^^^^---^
index ef90257474a9f78eb9da9e65d5b1823fa8ff5ead..11218eff1337f7f63e779df6b9ec5a7a40fdc429 100644 (file)
@@ -4,7 +4,22 @@
 
 use std::thread;
 
-struct S(String);
+#[derive(Debug)]
+struct Foo(String);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
+impl Foo {
+    fn from(s: &str) -> Self {
+        Self(String::from(s))
+    }
+}
+
+
+struct S(Foo);
 
 #[derive(Clone)]
 struct T(i32);
@@ -13,13 +28,13 @@ struct U(S, T);
 
 impl Clone for U {
     fn clone(&self) -> Self {
-        U(S(String::from("Hello World")), T(0))
+        U(S(Foo::from("Hello World")), T(0))
     }
 }
 
 fn test_multi_issues() {
-    let f1 = U(S(String::from("foo")), T(0));
-    let f2 = U(S(String::from("bar")), T(0));
+    let f1 = U(S(Foo::from("foo")), T(0));
+    let f2 = U(S(Foo::from("bar")), T(0));
     let c = || {
         let _ = (&f1, &f2);
         //~^ ERROR: `Clone` trait implementation for closure and drop order
@@ -39,7 +54,7 @@ fn test_multi_issues() {
 //~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
 
 fn test_capturing_all_disjoint_fields_individually() {
-    let f1 = U(S(String::from("foo")), T(0));
+    let f1 = U(S(Foo::from("foo")), T(0));
     let c = || {
         let _ = &f1;
         //~^ ERROR: `Clone` trait implementation for closure
@@ -60,12 +75,12 @@ struct U1(S, T, S);
 
 impl Clone for U1 {
     fn clone(&self) -> Self {
-        U1(S(String::from("foo")), T(0), S(String::from("bar")))
+        U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")))
     }
 }
 
 fn test_capturing_several_disjoint_fields_individually_1() {
-    let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+    let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         let _ = &f1;
         //~^ ERROR: `Clone` trait implementation for closure
@@ -85,7 +100,7 @@ fn test_capturing_several_disjoint_fields_individually_1() {
 }
 
 fn test_capturing_several_disjoint_fields_individually_2() {
-    let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+    let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         let _ = &f1;
         //~^ ERROR: `Clone` trait implementation for closure and drop order
index b9644c18d28e28465ee5a40e3de4eefa1318c0f8..02f2faa2e8741615266e5f91687be7713335d207 100644 (file)
@@ -4,7 +4,22 @@
 
 use std::thread;
 
-struct S(String);
+#[derive(Debug)]
+struct Foo(String);
+impl Drop for Foo {
+    fn drop(&mut self) {
+        println!("{:?} dropped", self.0);
+    }
+}
+
+impl Foo {
+    fn from(s: &str) -> Self {
+        Self(String::from(s))
+    }
+}
+
+
+struct S(Foo);
 
 #[derive(Clone)]
 struct T(i32);
 
 impl Clone for U {
     fn clone(&self) -> Self {
-        U(S(String::from("Hello World")), T(0))
+        U(S(Foo::from("Hello World")), T(0))
     }
 }
 
 fn test_multi_issues() {
-    let f1 = U(S(String::from("foo")), T(0));
-    let f2 = U(S(String::from("bar")), T(0));
+    let f1 = U(S(Foo::from("foo")), T(0));
+    let f2 = U(S(Foo::from("bar")), T(0));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure and drop order
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -38,7 +53,7 @@ fn test_multi_issues() {
 //~^ NOTE: in Rust 2018, `f2` is dropped here, but in Rust 2021, only `f2.1` will be dropped here as part of the closure
 
 fn test_capturing_all_disjoint_fields_individually() {
-    let f1 = U(S(String::from("foo")), T(0));
+    let f1 = U(S(Foo::from("foo")), T(0));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -58,12 +73,12 @@ fn test_capturing_all_disjoint_fields_individually() {
 
 impl Clone for U1 {
     fn clone(&self) -> Self {
-        U1(S(String::from("foo")), T(0), S(String::from("bar")))
+        U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")))
     }
 }
 
 fn test_capturing_several_disjoint_fields_individually_1() {
-    let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+    let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -82,7 +97,7 @@ fn test_capturing_several_disjoint_fields_individually_1() {
 }
 
 fn test_capturing_several_disjoint_fields_individually_2() {
-    let f1 = U1(S(String::from("foo")), T(0), S(String::from("bar")));
+    let f1 = U1(S(Foo::from("foo")), T(0), S(Foo::from("bar")));
     let c = || {
         //~^ ERROR: `Clone` trait implementation for closure and drop order
         //~| NOTE: in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
index 8bee950c13eca0273b93632434119816ad03661c..d425db5aa998c69394a674441809eef0581660b3 100644 (file)
@@ -1,5 +1,5 @@
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/multi_diagnostics.rs:23:13
+  --> $DIR/multi_diagnostics.rs:38:13
    |
 LL |     let c = || {
    |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -26,7 +26,7 @@ LL +         let _ = (&f1, &f2);
    |
 
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:42:13
+  --> $DIR/multi_diagnostics.rs:57:13
    |
 LL |     let c = || {
    |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -42,7 +42,7 @@ LL +         let _ = &f1;
    |
 
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:67:13
+  --> $DIR/multi_diagnostics.rs:82:13
    |
 LL |     let c = || {
    |             ^^
@@ -64,7 +64,7 @@ LL +         let _ = &f1;
    |
 
 error: changes to closure capture in Rust 2021 will affect `Clone` trait implementation for closure and drop order
-  --> $DIR/multi_diagnostics.rs:86:13
+  --> $DIR/multi_diagnostics.rs:101:13
    |
 LL |     let c = || {
    |             ^^ in Rust 2018, this closure implements `Clone` as `f1` implements `Clone`, but in Rust 2021, this closure will no longer implement `Clone` as `f1.0` does not implement `Clone`
@@ -89,7 +89,7 @@ LL +         let _ = &f1;
    |
 
 error: changes to closure capture in Rust 2021 will affect `Sync`, `Send` trait implementation for closure
-  --> $DIR/multi_diagnostics.rs:119:19
+  --> $DIR/multi_diagnostics.rs:134:19
    |
 LL |     thread::spawn(move || unsafe {
    |                   ^^^^^^^^^^^^^^
index aca0b2a96ac56bc2b6a6cc5fdb2ec0b73a474222..63e4000e833eb584424d8d52fec54b0f638d0906 100644 (file)
@@ -165,7 +165,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() {
 fn test8_drop_order_and_blocks() {
     {
         let tuple =
-          (String::from("foo"), String::from("bar"));
+          (Foo(0), Foo(1));
         {
             let c = || {
                 let _ = &tuple;
@@ -184,7 +184,7 @@ fn test8_drop_order_and_blocks() {
 
 fn test9_drop_order_and_nested_closures() {
     let tuple =
-        (String::from("foo"), String::from("bar"));
+        (Foo(0), Foo(1));
     let b = || {
         let c = || {
             let _ = &tuple;
@@ -202,6 +202,19 @@ fn test9_drop_order_and_nested_closures() {
     b();
 }
 
+// Test that we migrate if drop order of Vec<T> would be affected if T is a significant drop type
+fn test10_vec_of_significant_drop_type() {
+
+        let tup = (Foo(0), vec![Foo(3)]);
+
+        let _c = || { let _ = &tup; tup.0 };
+            //~^ ERROR: drop order
+            //~| NOTE: for more information, see
+            //~| HELP: add a dummy let to cause `tup` to be fully captured
+            //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+}
+//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+
 fn main() {
     test1_all_need_migration();
     test2_only_precise_paths_need_migration();
@@ -212,4 +225,5 @@ fn main() {
     test7_move_closures_non_copy_types_might_need_migration();
     test8_drop_order_and_blocks();
     test9_drop_order_and_nested_closures();
+    test10_vec_of_significant_drop_type();
 }
index fd4134a7704793daacf70bf73b243ee027b0a782..9d9c54298cf112ccb9c838a934fe33320380fa46 100644 (file)
@@ -158,7 +158,7 @@ fn test7_move_closures_non_copy_types_might_need_migration() {
 fn test8_drop_order_and_blocks() {
     {
         let tuple =
-          (String::from("foo"), String::from("bar"));
+          (Foo(0), Foo(1));
         {
             let c = || {
                 //~^ ERROR: drop order
@@ -176,7 +176,7 @@ fn test8_drop_order_and_blocks() {
 
 fn test9_drop_order_and_nested_closures() {
     let tuple =
-        (String::from("foo"), String::from("bar"));
+        (Foo(0), Foo(1));
     let b = || {
         let c = || {
             //~^ ERROR: drop order
@@ -193,6 +193,19 @@ fn test9_drop_order_and_nested_closures() {
     b();
 }
 
+// Test that we migrate if drop order of Vec<T> would be affected if T is a significant drop type
+fn test10_vec_of_significant_drop_type() {
+
+        let tup = (Foo(0), vec![Foo(3)]);
+
+        let _c = || tup.0;
+            //~^ ERROR: drop order
+            //~| NOTE: for more information, see
+            //~| HELP: add a dummy let to cause `tup` to be fully captured
+            //~| NOTE: in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+}
+//~^ NOTE: in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+
 fn main() {
     test1_all_need_migration();
     test2_only_precise_paths_need_migration();
@@ -203,4 +216,5 @@ fn main() {
     test7_move_closures_non_copy_types_might_need_migration();
     test8_drop_order_and_blocks();
     test9_drop_order_and_nested_closures();
+    test10_vec_of_significant_drop_type();
 }
index e9170eba3f17665f3855d65e8c389f1c5516996e..fa1f83c37823f5e55f356904f81201cbef636ea6 100644 (file)
@@ -195,5 +195,22 @@ LL ~         let c = || {
 LL +             let _ = &tuple;
    |
 
-error: aborting due to 9 previous errors
+error: changes to closure capture in Rust 2021 will affect drop order
+  --> $DIR/significant_drop.rs:201:18
+   |
+LL |         let _c = || tup.0;
+   |                  ^^^-----
+   |                     |
+   |                     in Rust 2018, this closure captures all of `tup`, but in Rust 2021, it will only capture `tup.0`
+...
+LL | }
+   | - in Rust 2018, `tup` is dropped here, but in Rust 2021, only `tup.0` will be dropped here as part of the closure
+   |
+   = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/disjoint-capture-in-closures.html>
+help: add a dummy let to cause `tup` to be fully captured
+   |
+LL |         let _c = || { let _ = &tup; tup.0 };
+   |                     +++++++++++++++       +
+
+error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.rs
new file mode 100644 (file)
index 0000000..2f8cddc
--- /dev/null
@@ -0,0 +1,101 @@
+// edition:2021
+
+// Tests that in cases where we individually capture all the fields of a type,
+// we still drop them in the order they would have been dropped in the 2018 edition.
+
+// NOTE: It is *critical* that the order of the min capture NOTES in the stderr output
+//       does *not* change!
+
+#![feature(rustc_attrs)]
+
+#[derive(Debug)]
+struct HasDrop;
+impl Drop for HasDrop {
+    fn drop(&mut self) {
+        println!("dropped");
+    }
+}
+
+fn test_one() {
+    let a = (HasDrop, HasDrop);
+    let b = (HasDrop, HasDrop);
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+        //~^ ERROR: Min Capture analysis includes:
+        //~| ERROR
+        println!("{:?}", a.0);
+        //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow
+        //~| NOTE
+        println!("{:?}", a.1);
+        //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow
+        //~| NOTE
+
+        println!("{:?}", b.0);
+        //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow
+        //~| NOTE
+        println!("{:?}", b.1);
+        //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow
+        //~| NOTE
+    };
+}
+
+fn test_two() {
+    let a = (HasDrop, HasDrop);
+    let b = (HasDrop, HasDrop);
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+        //~^ ERROR: Min Capture analysis includes:
+        //~| ERROR
+        println!("{:?}", a.1);
+        //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow
+        //~| NOTE
+        println!("{:?}", a.0);
+        //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow
+        //~| NOTE
+
+        println!("{:?}", b.1);
+        //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow
+        //~| NOTE
+        println!("{:?}", b.0);
+        //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow
+        //~| NOTE
+    };
+}
+
+fn test_three() {
+    let a = (HasDrop, HasDrop);
+    let b = (HasDrop, HasDrop);
+
+    let c = #[rustc_capture_analysis]
+    //~^ ERROR: attributes on expressions are experimental
+    //~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
+    || {
+        //~^ ERROR: Min Capture analysis includes:
+        //~| ERROR
+        println!("{:?}", b.1);
+        //~^ NOTE: Min Capture b[(1, 0)] -> ImmBorrow
+        //~| NOTE
+        println!("{:?}", a.1);
+        //~^ NOTE: Min Capture a[(1, 0)] -> ImmBorrow
+        //~| NOTE
+        println!("{:?}", a.0);
+        //~^ NOTE: Min Capture a[(0, 0)] -> ImmBorrow
+        //~| NOTE
+
+        println!("{:?}", b.0);
+        //~^ NOTE: Min Capture b[(0, 0)] -> ImmBorrow
+        //~| NOTE
+    };
+}
+
+fn main() {
+    test_one();
+    test_two();
+    test_three();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order.stderr
new file mode 100644 (file)
index 0000000..2d1dc87
--- /dev/null
@@ -0,0 +1,228 @@
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/preserve_field_drop_order.rs:23:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/preserve_field_drop_order.rs:49:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/preserve_field_drop_order.rs:75:13
+   |
+LL |     let c = #[rustc_capture_analysis]
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+
+error: First Pass analysis includes:
+  --> $DIR/preserve_field_drop_order.rs:26:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{:?}", a.0);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing a[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:29:26
+   |
+LL |         println!("{:?}", a.0);
+   |                          ^^^
+note: Capturing a[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:32:26
+   |
+LL |         println!("{:?}", a.1);
+   |                          ^^^
+note: Capturing b[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:36:26
+   |
+LL |         println!("{:?}", b.0);
+   |                          ^^^
+note: Capturing b[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:39:26
+   |
+LL |         println!("{:?}", b.1);
+   |                          ^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/preserve_field_drop_order.rs:26:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{:?}", a.0);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture a[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:29:26
+   |
+LL |         println!("{:?}", a.0);
+   |                          ^^^
+note: Min Capture a[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:32:26
+   |
+LL |         println!("{:?}", a.1);
+   |                          ^^^
+note: Min Capture b[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:36:26
+   |
+LL |         println!("{:?}", b.0);
+   |                          ^^^
+note: Min Capture b[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:39:26
+   |
+LL |         println!("{:?}", b.1);
+   |                          ^^^
+
+error: First Pass analysis includes:
+  --> $DIR/preserve_field_drop_order.rs:52:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{:?}", a.1);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing a[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:55:26
+   |
+LL |         println!("{:?}", a.1);
+   |                          ^^^
+note: Capturing a[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:58:26
+   |
+LL |         println!("{:?}", a.0);
+   |                          ^^^
+note: Capturing b[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:62:26
+   |
+LL |         println!("{:?}", b.1);
+   |                          ^^^
+note: Capturing b[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:65:26
+   |
+LL |         println!("{:?}", b.0);
+   |                          ^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/preserve_field_drop_order.rs:52:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{:?}", a.1);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture a[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:58:26
+   |
+LL |         println!("{:?}", a.0);
+   |                          ^^^
+note: Min Capture a[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:55:26
+   |
+LL |         println!("{:?}", a.1);
+   |                          ^^^
+note: Min Capture b[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:65:26
+   |
+LL |         println!("{:?}", b.0);
+   |                          ^^^
+note: Min Capture b[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:62:26
+   |
+LL |         println!("{:?}", b.1);
+   |                          ^^^
+
+error: First Pass analysis includes:
+  --> $DIR/preserve_field_drop_order.rs:78:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{:?}", b.1);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Capturing b[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:81:26
+   |
+LL |         println!("{:?}", b.1);
+   |                          ^^^
+note: Capturing a[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:84:26
+   |
+LL |         println!("{:?}", a.1);
+   |                          ^^^
+note: Capturing a[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:87:26
+   |
+LL |         println!("{:?}", a.0);
+   |                          ^^^
+note: Capturing b[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:91:26
+   |
+LL |         println!("{:?}", b.0);
+   |                          ^^^
+
+error: Min Capture analysis includes:
+  --> $DIR/preserve_field_drop_order.rs:78:5
+   |
+LL | /     || {
+LL | |
+LL | |
+LL | |         println!("{:?}", b.1);
+...  |
+LL | |
+LL | |     };
+   | |_____^
+   |
+note: Min Capture b[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:91:26
+   |
+LL |         println!("{:?}", b.0);
+   |                          ^^^
+note: Min Capture b[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:81:26
+   |
+LL |         println!("{:?}", b.1);
+   |                          ^^^
+note: Min Capture a[(0, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:87:26
+   |
+LL |         println!("{:?}", a.0);
+   |                          ^^^
+note: Min Capture a[(1, 0)] -> ImmBorrow
+  --> $DIR/preserve_field_drop_order.rs:84:26
+   |
+LL |         println!("{:?}", a.1);
+   |                          ^^^
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.rs
new file mode 100644 (file)
index 0000000..1cae776
--- /dev/null
@@ -0,0 +1,58 @@
+// run-pass
+// check-run-results
+// revisions: twenty_eighteen twenty_twentyone
+// [twenty_eighteen]compile-flags: --edition 2018
+// [twenty_twentyone]compile-flags: --edition 2021
+
+#[derive(Debug)]
+struct Dropable(&'static str);
+
+impl Drop for Dropable {
+    fn drop(&mut self) {
+        println!("Dropping {}", self.0)
+    }
+}
+
+#[derive(Debug)]
+struct A {
+    x: Dropable,
+    y: Dropable,
+}
+
+#[derive(Debug)]
+struct B {
+    c: A,
+    d: A,
+}
+
+#[derive(Debug)]
+struct R<'a> {
+    c: &'a A,
+    d: &'a A,
+}
+
+fn main() {
+    let a = A { x: Dropable("x"), y: Dropable("y") };
+
+    let c = move || println!("{:?} {:?}", a.y, a.x);
+
+    c();
+
+    let b = B {
+        c: A { x: Dropable("b.c.x"), y: Dropable("b.c.y") },
+        d: A { x: Dropable("b.d.x"), y: Dropable("b.d.y") },
+    };
+
+    let d = move || println!("{:?} {:?} {:?} {:?}", b.d.y, b.d.x, b.c.y, b.c.x);
+
+    d();
+
+        let r = R {
+        c: &A { x: Dropable("r.c.x"), y: Dropable("r.c.y") },
+        d: &A { x: Dropable("r.d.x"), y: Dropable("r.d.y") },
+    };
+
+    let e = move || println!("{:?} {:?} {:?} {:?}", r.d.y, r.d.x, r.c.y, r.c.x);
+
+    e();
+}
diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_eighteen.run.stdout
new file mode 100644 (file)
index 0000000..557d047
--- /dev/null
@@ -0,0 +1,13 @@
+Dropable("y") Dropable("x")
+Dropable("b.d.y") Dropable("b.d.x") Dropable("b.c.y") Dropable("b.c.x")
+Dropable("r.d.y") Dropable("r.d.x") Dropable("r.c.y") Dropable("r.c.x")
+Dropping r.d.x
+Dropping r.d.y
+Dropping r.c.x
+Dropping r.c.y
+Dropping b.c.x
+Dropping b.c.y
+Dropping b.d.x
+Dropping b.d.y
+Dropping x
+Dropping y
diff --git a/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout b/src/test/ui/closures/2229_closure_analysis/preserve_field_drop_order2.twenty_twentyone.run.stdout
new file mode 100644 (file)
index 0000000..557d047
--- /dev/null
@@ -0,0 +1,13 @@
+Dropable("y") Dropable("x")
+Dropable("b.d.y") Dropable("b.d.x") Dropable("b.c.y") Dropable("b.c.x")
+Dropable("r.d.y") Dropable("r.d.x") Dropable("r.c.y") Dropable("r.c.x")
+Dropping r.d.x
+Dropping r.d.y
+Dropping r.c.x
+Dropping r.c.y
+Dropping b.c.x
+Dropping b.c.y
+Dropping b.d.x
+Dropping b.d.y
+Dropping x
+Dropping y
index d486fdf73aba8d795a1dde8c4ff37ad921efed26..eeb8fe82346c2245dd103e96c0d5aaaacd3fedcc 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(unused_braces)]
-#![feature(box_syntax)]
 
 use std::cell::RefCell;
 use std::fmt::Debug;
index 1f0b7f7e78a69dc17766139d0b3dee7df4ccc99d..32796c67229a7eb0892163503d37679d889e9002 100644 (file)
@@ -9,5 +9,5 @@ fn main() {}
 static TEST_BAD: &mut i32 = {
     &mut *(box 0)
     //~^ ERROR could not evaluate static initializer
-    //~| NOTE heap allocations
+    //~| NOTE calling non-const function `alloc::alloc::exchange_malloc`
 };
index 66ea9d5924dfb6157740e1aa7386534e36226f48..05d9858dc09f0a938351136a19bb1cab9d5fde8e 100644 (file)
@@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer
   --> $DIR/box.rs:10:11
    |
 LL |     &mut *(box 0)
-   |           ^^^^^^^ "heap allocations via `box` keyword" needs an rfc before being allowed inside constants
+   |           ^^^^^^^ calling non-const function `alloc::alloc::exchange_malloc`
 
 warning: skipping const checks
    |
index eefcf7738ada779adf96a0d414c88ce9bb978433..55e05cfb203b9c806abf38c654178f7c2b2e9a3e 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 // This is a regression test that the metadata for the
 // name_pool::methods impl in the other crate is reachable from this
 // crate.
@@ -14,7 +12,7 @@
 pub fn main() {
     use crate_method_reexport_grrrrrrr2::rust::add;
     use crate_method_reexport_grrrrrrr2::rust::cx;
-    let x: Box<_> = box ();
+    let x: Box<_> = Box::new(());
     x.cx();
     let y = ();
     y.add("hi".to_string());
index 379ed076611f4990d7c40e8658c0e4594c772b2a..23d76ef3656e1454427e594e27608876b24c80d8 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 use std::cell::RefCell;
 
 pub struct Entry<A,B> {
@@ -37,7 +35,7 @@ pub fn new_int_alist<B:'static>() -> alist<isize, B> {
     fn eq_int(a: isize, b: isize) -> bool { a == b }
     return alist {
         eq_fn: eq_int,
-        data: box RefCell::new(Vec::new()),
+        data: Box::new(RefCell::new(Vec::new())),
     };
 }
 
@@ -47,6 +45,6 @@ pub fn new_int_alist_2<B:'static>() -> alist<isize, B> {
     fn eq_int(a: isize, b: isize) -> bool { a == b }
     return alist {
         eq_fn: eq_int,
-        data: box RefCell::new(Vec::new()),
+        data: Box::new(RefCell::new(Vec::new())),
     };
 }
index 605a166ffa3564d12c73790ad4ff795022bc03eb..fee6b5d03a9e562ae74825fa1e62c2b41b57d003 100644 (file)
@@ -1,13 +1,11 @@
 // run-pass
 // aux-build:cci_borrow_lib.rs
 
-#![feature(box_syntax)]
-
 extern crate cci_borrow_lib;
 use cci_borrow_lib::foo;
 
 pub fn main() {
-    let p: Box<_> = box 22;
+    let p: Box<_> = Box::new(22);
     let r = foo(&*p);
     println!("r={}", r);
     assert_eq!(r, 22);
index a0ee3ad31e6976f2899f146405ee5ba5454f69d8..978c1994800c901b413b0c1457440ada4965f4af 100644 (file)
@@ -1,7 +1,8 @@
 // Test that when a trait impl changes, fns whose body uses that trait
 // must also be recompiled.
 
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-assoc-type-codegen
+// incremental
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(warnings)]
index 4e659648e9edce5a2d07fdbad3287b57c4b5b8f9..cdc268cff992e0fb94f52f19e01872c2e15bd253 100644 (file)
@@ -1,5 +1,5 @@
 error: OK
-  --> $DIR/dep-graph-assoc-type-codegen.rs:28:5
+  --> $DIR/dep-graph-assoc-type-codegen.rs:29:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index c95ea53650b479b78abbc6dd1344366089d43178..4a3a8bb6bf9394808448c13964ba49141364737f 100644 (file)
@@ -1,7 +1,8 @@
 // Test that immediate callers have to change when callee changes, but
 // not callers' callers.
 
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-caller-callee
+// incremental
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index 3d968aa3ea68a79676bc993b6995eebe459228b7..4d06dc7f3ed37250ca205691b0489f0fd4a491b1 100644 (file)
@@ -1,11 +1,11 @@
 error: OK
-  --> $DIR/dep-graph-caller-callee.rs:20:5
+  --> $DIR/dep-graph-caller-callee.rs:21:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `x` to `typeck`
-  --> $DIR/dep-graph-caller-callee.rs:31:5
+  --> $DIR/dep-graph-caller-callee.rs:32:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 50a670b87723826eacd976d93747d085f243f894..fcf9f6387102f64c2012b080b2882ef4f313a3b6 100644 (file)
@@ -1,7 +1,8 @@
 // Test cases where a changing struct appears in the signature of fns
 // and methods.
 
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-struct-signature
+// incremental
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index b81aeabab7ff1b0dc483f4211acfc2fb12c01a5b..60bfbe94a8a8b7055ad4ad41e64842e2a50e63cb 100644 (file)
 error: no path from `WillChange` to `type_of`
-  --> $DIR/dep-graph-struct-signature.rs:27:5
+  --> $DIR/dep-graph-struct-signature.rs:28:5
    |
 LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `associated_item`
-  --> $DIR/dep-graph-struct-signature.rs:28:5
+  --> $DIR/dep-graph-struct-signature.rs:29:5
    |
 LL |     #[rustc_then_this_would_need(associated_item)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `trait_def`
-  --> $DIR/dep-graph-struct-signature.rs:29:5
+  --> $DIR/dep-graph-struct-signature.rs:30:5
    |
 LL |     #[rustc_then_this_would_need(trait_def)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:31:9
+  --> $DIR/dep-graph-struct-signature.rs:32:9
    |
 LL |         #[rustc_then_this_would_need(fn_sig)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:35:5
+  --> $DIR/dep-graph-struct-signature.rs:36:5
    |
 LL |     #[rustc_then_this_would_need(fn_sig)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:36:5
+  --> $DIR/dep-graph-struct-signature.rs:37:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:39:5
+  --> $DIR/dep-graph-struct-signature.rs:40:5
    |
 LL |     #[rustc_then_this_would_need(fn_sig)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:40:5
+  --> $DIR/dep-graph-struct-signature.rs:41:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:45:5
+  --> $DIR/dep-graph-struct-signature.rs:46:5
    |
 LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:47:9
+  --> $DIR/dep-graph-struct-signature.rs:48:9
    |
 LL |         #[rustc_then_this_would_need(fn_sig)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:48:9
+  --> $DIR/dep-graph-struct-signature.rs:49:9
    |
 LL |         #[rustc_then_this_would_need(typeck)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:52:5
+  --> $DIR/dep-graph-struct-signature.rs:53:5
    |
 LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:54:9
+  --> $DIR/dep-graph-struct-signature.rs:55:9
    |
 LL |         #[rustc_then_this_would_need(fn_sig)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:55:9
+  --> $DIR/dep-graph-struct-signature.rs:56:9
    |
 LL |         #[rustc_then_this_would_need(typeck)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:60:9
+  --> $DIR/dep-graph-struct-signature.rs:61:9
    |
 LL |         #[rustc_then_this_would_need(type_of)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-struct-signature.rs:62:9
+  --> $DIR/dep-graph-struct-signature.rs:63:9
    |
 LL |         #[rustc_then_this_would_need(type_of)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `type_of`
-  --> $DIR/dep-graph-struct-signature.rs:67:5
+  --> $DIR/dep-graph-struct-signature.rs:68:5
    |
 LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `type_of`
-  --> $DIR/dep-graph-struct-signature.rs:74:5
+  --> $DIR/dep-graph-struct-signature.rs:75:5
    |
 LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `fn_sig`
-  --> $DIR/dep-graph-struct-signature.rs:76:9
+  --> $DIR/dep-graph-struct-signature.rs:77:9
    |
 LL |         #[rustc_then_this_would_need(fn_sig)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `fn_sig`
-  --> $DIR/dep-graph-struct-signature.rs:80:5
+  --> $DIR/dep-graph-struct-signature.rs:81:5
    |
 LL |     #[rustc_then_this_would_need(fn_sig)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `fn_sig`
-  --> $DIR/dep-graph-struct-signature.rs:83:5
+  --> $DIR/dep-graph-struct-signature.rs:84:5
    |
 LL |     #[rustc_then_this_would_need(fn_sig)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `WillChange` to `typeck`
-  --> $DIR/dep-graph-struct-signature.rs:84:5
+  --> $DIR/dep-graph-struct-signature.rs:85:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index c0a6617316b8dc9994c991cc5a9e52175262a32a..5da8df57064643a9472fe0177307ab1ad8f7b17d 100644 (file)
@@ -1,7 +1,8 @@
 // Test that adding an impl to a trait `Foo` DOES affect functions
 // that only use `Bar` if they have methods in common.
 
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits-same-method
+// incremental
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index ae3d725e1c051a091220df9413487aa5de8d4a85..6f56cbc8dd7ae55d450a42782eb2054c964c0e98 100644 (file)
@@ -1,11 +1,11 @@
 error: OK
-  --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:32:5
+  --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:33:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `x::<impl Foo for u32>` to `typeck`
-  --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:41:5
+  --> $DIR/dep-graph-trait-impl-two-traits-same-method.rs:42:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 56e9762ddb26c1740b55ee185748175e31b97d7c..0331e75b2fe8d6c060d1792508d77cf07033fb6e 100644 (file)
@@ -1,7 +1,8 @@
 // Test that adding an impl to a trait `Foo` does not affect functions
 // that only use `Bar`, so long as they do not have methods in common.
 
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl-two-traits
+// incremental
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(warnings)]
index 4823927477fe08e19ef499997d0498d65dc838ed..08f382cc024c7377830943c77a04ebd0fbb65e83 100644 (file)
@@ -1,11 +1,11 @@
 error: no path from `x::<impl Foo for char>` to `typeck`
-  --> $DIR/dep-graph-trait-impl-two-traits.rs:31:5
+  --> $DIR/dep-graph-trait-impl-two-traits.rs:32:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `x::<impl Foo for char>` to `typeck`
-  --> $DIR/dep-graph-trait-impl-two-traits.rs:40:5
+  --> $DIR/dep-graph-trait-impl-two-traits.rs:41:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 3bbe3e745ca691c7ad266f3946996b82a4ca642a..19002965b93721a6ece38d222e74c19436df86ce 100644 (file)
@@ -1,7 +1,8 @@
 // Test that when a trait impl changes, fns whose body uses that trait
 // must also be recompiled.
 
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-trait-impl
+// incremental
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(warnings)]
index f8ead80894276400d1de6be0b3c8d8f79a30177c..bfee6d5c87b3452572e1979a6abc5863180426aa 100644 (file)
@@ -1,29 +1,29 @@
 error: OK
-  --> $DIR/dep-graph-trait-impl.rs:27:5
+  --> $DIR/dep-graph-trait-impl.rs:28:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-trait-impl.rs:32:5
+  --> $DIR/dep-graph-trait-impl.rs:33:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-trait-impl.rs:37:5
+  --> $DIR/dep-graph-trait-impl.rs:38:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-trait-impl.rs:42:5
+  --> $DIR/dep-graph-trait-impl.rs:43:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `x::<impl Foo for char>` to `typeck`
-  --> $DIR/dep-graph-trait-impl.rs:55:5
+  --> $DIR/dep-graph-trait-impl.rs:56:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 5c5e24693a4f563039c99a0edc55f840fc613203..0e1b3db192518df08b25fd35267f2ae2037a0f13 100644 (file)
@@ -1,6 +1,7 @@
 // Test that changing what a `type` points to does not go unnoticed.
 
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-type-alias
+// incremental
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index e698ce8f628b4e898947fcd7db2a4fee01120dda..c59cf8014c3d1dfe69a5b9117c2d211b1ac96e63 100644 (file)
@@ -1,71 +1,71 @@
 error: no path from `TypeAlias` to `type_of`
-  --> $DIR/dep-graph-type-alias.rs:17:1
+  --> $DIR/dep-graph-type-alias.rs:18:1
    |
 LL | #[rustc_then_this_would_need(type_of)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:19:5
+  --> $DIR/dep-graph-type-alias.rs:20:5
    |
 LL |     #[rustc_then_this_would_need(type_of)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `TypeAlias` to `type_of`
-  --> $DIR/dep-graph-type-alias.rs:24:1
+  --> $DIR/dep-graph-type-alias.rs:25:1
    |
 LL | #[rustc_then_this_would_need(type_of)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:27:9
+  --> $DIR/dep-graph-type-alias.rs:28:9
    |
 LL |         #[rustc_then_this_would_need(type_of)]
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `TypeAlias` to `type_of`
-  --> $DIR/dep-graph-type-alias.rs:33:1
+  --> $DIR/dep-graph-type-alias.rs:34:1
    |
 LL | #[rustc_then_this_would_need(type_of)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:35:5
+  --> $DIR/dep-graph-type-alias.rs:36:5
    |
 LL |     #[rustc_then_this_would_need(fn_sig)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: no path from `TypeAlias` to `type_of`
-  --> $DIR/dep-graph-type-alias.rs:41:1
+  --> $DIR/dep-graph-type-alias.rs:42:1
    |
 LL | #[rustc_then_this_would_need(type_of)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:43:5
+  --> $DIR/dep-graph-type-alias.rs:44:5
    |
 LL |     #[rustc_then_this_would_need(fn_sig)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:44:5
+  --> $DIR/dep-graph-type-alias.rs:45:5
    |
 LL |     #[rustc_then_this_would_need(typeck)]
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:48:1
+  --> $DIR/dep-graph-type-alias.rs:49:1
    |
 LL | #[rustc_then_this_would_need(type_of)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:51:1
+  --> $DIR/dep-graph-type-alias.rs:52:1
    |
 LL | #[rustc_then_this_would_need(fn_sig)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: OK
-  --> $DIR/dep-graph-type-alias.rs:52:1
+  --> $DIR/dep-graph-type-alias.rs:53:1
    |
 LL | #[rustc_then_this_would_need(typeck)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 4f1612759559d95bb5e53a3712af6a378545323c..008434696d63ddfc7102070ba97c9c14e7edf58e 100644 (file)
@@ -1,7 +1,8 @@
 // Test that changing what a `type` points to does not go unnoticed
 // by the variance analysis.
 
-// compile-flags: -Z query-dep-graph -C incremental=tmp/dep-graph-variance-alias
+// incremental
+// compile-flags: -Z query-dep-graph
 
 #![feature(rustc_attrs)]
 #![allow(dead_code)]
index 2422cb9bb2f52ed93695bd62f1a8f2c388299e30..554ff455a2073580156b905e8ed63021bd50bdbf 100644 (file)
@@ -1,5 +1,5 @@
 error: OK
-  --> $DIR/dep-graph-variance-alias.rs:18:1
+  --> $DIR/dep-graph-variance-alias.rs:19:1
    |
 LL | #[rustc_then_this_would_need(variances_of)]
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index cad4ede06a56175050055610cde6d60d52858039..0d4e08ad95476995f98ae0433d3bdbd8df6875c1 100644 (file)
@@ -1,9 +1,7 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    let x: Box<isize> = box 10;
+    let x: Box<isize> = Box::new(10);
     let _y: isize = *x;
 }
index 2538b5533a6d69f57ee3218bdad585c269468994..1d0554ad0477fe28db53563b08749dfeb00693a0 100644 (file)
@@ -2,10 +2,8 @@ error[E0277]: the trait bound `C: Copy` is not satisfied
   --> $DIR/deriving-copyclone.rs:31:13
    |
 LL |     is_copy(B { a: 1, b: C });
-   |     ------- ^^^^^^^^^^^^^^^^
-   |     |       |
-   |     |       expected an implementor of trait `Copy`
-   |     |       help: consider borrowing here: `&B { a: 1, b: C }`
+   |     ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy`
+   |     |
    |     required by a bound introduced by this call
    |
 note: required because of the requirements on the impl of `Copy` for `B<C>`
@@ -19,15 +17,17 @@ note: required by a bound in `is_copy`
 LL | fn is_copy<T: Copy>(_: T) {}
    |               ^^^^ required by this bound in `is_copy`
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing here
+   |
+LL |     is_copy(&B { a: 1, b: C });
+   |             +
 
 error[E0277]: the trait bound `C: Clone` is not satisfied
   --> $DIR/deriving-copyclone.rs:32:14
    |
 LL |     is_clone(B { a: 1, b: C });
-   |     -------- ^^^^^^^^^^^^^^^^
-   |     |        |
-   |     |        expected an implementor of trait `Clone`
-   |     |        help: consider borrowing here: `&B { a: 1, b: C }`
+   |     -------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone`
+   |     |
    |     required by a bound introduced by this call
    |
 note: required because of the requirements on the impl of `Clone` for `B<C>`
@@ -41,15 +41,17 @@ note: required by a bound in `is_clone`
 LL | fn is_clone<T: Clone>(_: T) {}
    |                ^^^^^ required by this bound in `is_clone`
    = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing here
+   |
+LL |     is_clone(&B { a: 1, b: C });
+   |              +
 
 error[E0277]: the trait bound `D: Copy` is not satisfied
   --> $DIR/deriving-copyclone.rs:35:13
    |
 LL |     is_copy(B { a: 1, b: D });
-   |     ------- ^^^^^^^^^^^^^^^^
-   |     |       |
-   |     |       expected an implementor of trait `Copy`
-   |     |       help: consider borrowing here: `&B { a: 1, b: D }`
+   |     ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Copy`
+   |     |
    |     required by a bound introduced by this call
    |
 note: required because of the requirements on the impl of `Copy` for `B<D>`
@@ -63,6 +65,10 @@ note: required by a bound in `is_copy`
 LL | fn is_copy<T: Copy>(_: T) {}
    |               ^^^^ required by this bound in `is_copy`
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider borrowing here
+   |
+LL |     is_copy(&B { a: 1, b: D });
+   |             +
 
 error: aborting due to 3 previous errors
 
index 237dbfaa0567468910aed5842d2999e74545b4e4..b71e1149613886771665ac017219370b8cec8cbb 100644 (file)
@@ -1,6 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
-
 use std::default::Default;
 
 #[derive(Default)]
index fdc9bbab7306773b2a91190989c4c3092c336adc..50b64aeebf0efadb3904a9b10e10b250d580c7c3 100644 (file)
@@ -2,11 +2,11 @@
 // reference work properly.
 
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 trait T { fn foo(&self) {} }
 impl T for isize {}
 
+
 fn main() {
     // For an expression of the form:
     //
@@ -25,7 +25,7 @@ fn main() {
     // n == m
     let &x = &1isize as &dyn T;      //~ ERROR type `&dyn T` cannot be dereferenced
     let &&x = &(&1isize as &dyn T);  //~ ERROR type `&dyn T` cannot be dereferenced
-    let box x = box 1isize as Box<dyn T>;
+    let box x = Box::new(1isize) as Box<dyn T>;
     //~^ ERROR type `Box<dyn T>` cannot be dereferenced
 
     // n > m
@@ -37,7 +37,7 @@ fn main() {
     //~^ ERROR mismatched types
     //~| expected trait object `dyn T`
     //~| found reference `&_`
-    let box box x = box 1isize as Box<dyn T>;
+    let box box x = Box::new(1isize) as Box<dyn T>;
     //~^ ERROR mismatched types
     //~| expected trait object `dyn T`
     //~| found struct `Box<_>`
index fb43ca760b8c0b898767444cc3352948028c871e..302917ca02e00ef79f122e47e3d0b86d599820b3 100644 (file)
@@ -13,7 +13,7 @@ LL |     let &&x = &(&1isize as &dyn T);
 error[E0033]: type `Box<dyn T>` cannot be dereferenced
   --> $DIR/destructure-trait-ref.rs:28:9
    |
-LL |     let box x = box 1isize as Box<dyn T>;
+LL |     let box x = Box::new(1isize) as Box<dyn T>;
    |         ^^^^^ type `Box<dyn T>` cannot be dereferenced
 
 error[E0308]: mismatched types
@@ -43,8 +43,8 @@ LL |     let &&&x = &(&1isize as &dyn T);
 error[E0308]: mismatched types
   --> $DIR/destructure-trait-ref.rs:40:13
    |
-LL |     let box box x = box 1isize as Box<dyn T>;
-   |             ^^^^^   ------------------------ this expression has type `Box<dyn T>`
+LL |     let box box x = Box::new(1isize) as Box<dyn T>;
+   |             ^^^^^   ------------------------------ this expression has type `Box<dyn T>`
    |             |
    |             expected trait object `dyn T`, found struct `Box`
    |
index 1747bf029aa334672d86863ea962e0cf845b9991..ef3a90a53a6a0241b85c0afdeab2dfbfabf44fa7 100644 (file)
@@ -2,11 +2,9 @@
 // pretty-expanded FIXME #23616
 #![allow(non_camel_case_types)]
 
-#![feature(box_syntax)]
-
 enum t { foo(Box<isize>), }
 
 pub fn main() {
-    let tt = t::foo(box 10);
+    let tt = t::foo(Box::new(10));
     match tt { t::foo(_z) => { } }
 }
index 1bc3b4c157ca8d596e9353cb905d427a5f165756..377027a4fc5f2895cd611b9658d24082cca9493e 100644 (file)
@@ -5,8 +5,6 @@
 // Test that destructor on a struct runs successfully after the struct
 // is boxed and converted to an object.
 
-#![feature(box_syntax)]
-
 static mut value: usize = 0;
 
 struct Cat {
@@ -29,7 +27,7 @@ fn drop(&mut self) {
 
 pub fn main() {
     {
-        let x = box Cat {name: 22};
+        let x = Box::new(Cat {name: 22});
         let nyan: Box<dyn Dummy> = x as Box<dyn Dummy>;
     }
     unsafe {
index aec46575f97fc438fe688ffa3e3f0d8e8098fda0..4ab8f733ad75a419981c8a3318a7a4040bdef065 100644 (file)
@@ -4,8 +4,6 @@
 #![allow(unused_variables)]
 // ignore-emscripten no threads support
 
-#![feature(box_syntax)]
-
 use std::thread;
 use std::sync::mpsc::{channel, Sender};
 
@@ -57,7 +55,7 @@ pub fn main() {
 
     let (sender, receiver) = channel();
     {
-        let v = Foo::NestedVariant(box 42, SendOnDrop { sender: sender.clone() }, sender);
+        let v = Foo::NestedVariant(Box::new(42), SendOnDrop { sender: sender.clone() }, sender);
     }
     assert_eq!(receiver.recv().unwrap(), Message::DestructorRan);
     assert_eq!(receiver.recv().unwrap(), Message::Dropped);
@@ -74,10 +72,10 @@ pub fn main() {
     let (sender, receiver) = channel();
     let t = {
         thread::spawn(move|| {
-            let mut v = Foo::NestedVariant(box 42, SendOnDrop {
+            let mut v = Foo::NestedVariant(Box::new(42), SendOnDrop {
                 sender: sender.clone()
             }, sender.clone());
-            v = Foo::NestedVariant(box 42,
+            v = Foo::NestedVariant(Box::new(42),
                                    SendOnDrop { sender: sender.clone() },
                                    sender.clone());
             v = Foo::SimpleVariant(sender.clone());
index 70bcc3de07d29b279962e8d60e3f32d8b2c3288e..c1e45215ad8c4b78a66ed6cce9af9482ebabe587 100644 (file)
@@ -2,7 +2,6 @@
 #![allow(type_alias_bounds)]
 
 #![allow(unused_features)]
-#![feature(box_syntax)]
 #![feature(unsized_tuple_coercion)]
 
 type Fat<T: ?Sized> = (isize, &'static str, T);
index f70a45a1b357456ec7cc4a8522c85cc58f37f707..604ac511290100700875ac32840cd93803d88eb7 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(type_alias_bounds)]
 
-#![feature(box_syntax)]
 #![feature(unsized_tuple_coercion)]
 
 type Fat<T: ?Sized> = (isize, &'static str, T);
@@ -109,7 +108,7 @@ pub fn main() {
     assert_eq!((*f2)[1], 2);
 
     // Nested Box.
-    let f1 : Box<Fat<[isize; 3]>> = box (5, "some str", [1, 2, 3]);
+    let f1 : Box<Fat<[isize; 3]>> = Box::new((5, "some str", [1, 2, 3]));
     foo(&*f1);
     let f2 : Box<Fat<[isize]>> = f1;
     foo(&*f2);
index d081cb2be7ee39820bb146a6c5eab90f85a38ada..14603a2c71fc4e6e47d9d93ac5cf9b4de6952411 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(unused_braces)]
-#![feature(box_syntax)]
 
 fn test_generic<T, F>(expected: Box<T>, eq: F) where T: Clone, F: FnOnce(Box<T>, Box<T>) -> bool {
     let actual: Box<T> = { expected.clone() };
@@ -13,7 +12,7 @@ fn compare_box(b1: Box<bool>, b2: Box<bool>) -> bool {
         println!("{}", *b2);
         return *b1 == *b2;
     }
-    test_generic::<bool, _>(box true, compare_box);
+    test_generic::<bool, _>(Box::new(true), compare_box);
 }
 
 pub fn main() { test_box(); }
index 9362eb86fc30976dd713c7a408d70c05469bce09..7879c144b10923aa9bbf9c1d474afdf76784ee50 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(unused_braces)]
-#![feature(box_syntax)]
 
 fn test_generic<T, F>(expected: T, eq: F) where T: Clone, F: FnOnce(T, T) -> bool {
     let actual: T = { expected.clone() };
@@ -9,7 +8,7 @@ fn test_generic<T, F>(expected: T, eq: F) where T: Clone, F: FnOnce(T, T) -> boo
 
 fn test_vec() {
     fn compare_vec(v1: Box<isize>, v2: Box<isize>) -> bool { return v1 == v2; }
-    test_generic::<Box<isize>, _>(box 1, compare_vec);
+    test_generic::<Box<isize>, _>(Box::new(1), compare_vec);
 }
 
 pub fn main() { test_vec(); }
index eff3fd3a15152a78e55d7d38d381d9c037de1ec1..5fa11ad1283b9d7fcb1060e19c3f743c04590249 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
 #![allow(unused_braces)]
-#![feature(box_syntax)]
 
-pub fn main() { let x: Box<_> = { box 100 }; assert_eq!(*x, 100); }
+pub fn main() { let x: Box<_> = { Box::new(100) }; assert_eq!(*x, 100); }
index 509d069d40fecd73c38ff369e61adfcc80fbdb60..86232683549b602463f200038968229346827a86 100644 (file)
@@ -1,10 +1,8 @@
 // run-pass
 
-#![feature(box_syntax)]
-
 // Tests for if as expressions returning boxed types
 fn test_box() {
-    let rs: Box<_> = if true { box 100 } else { box 101 };
+    let rs: Box<_> = if true { Box::new(100) } else { Box::new(101) };
     assert_eq!(*rs, 100);
 }
 
index 0c389e1dc57a960403003316ead1dd6a71685c8e..636ac7107e62a6eeafdd08735546a2b159051df3 100644 (file)
@@ -1,17 +1,17 @@
-#![feature(box_syntax)]
-
 fn needs_fn<F>(x: F) where F: Fn(isize) -> isize {}
 
+
+
 fn main() {
-    let _: () = (box |_: isize| {}) as Box<dyn FnOnce(isize)>;
+    let _: () = Box::new(|_: isize| {}) as Box<dyn FnOnce(isize)>;
     //~^ ERROR mismatched types
     //~| expected unit type `()`
     //~| found struct `Box<dyn FnOnce(isize)>`
-    let _: () = (box |_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
+    let _: () = Box::new(|_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
     //~^ ERROR mismatched types
     //~| expected unit type `()`
     //~| found struct `Box<dyn Fn(isize, isize)>`
-    let _: () = (box || -> isize { unimplemented!() }) as Box<dyn FnMut() -> isize>;
+    let _: () = Box::new(|| -> isize { unimplemented!() }) as Box<dyn FnMut() -> isize>;
     //~^ ERROR mismatched types
     //~| expected unit type `()`
     //~| found struct `Box<dyn FnMut() -> isize>`
index f9fb3a0ef267dbfbd50bfe9f30ecb29ad43c4848..ea88e401bed8737e755b53c36a7abc6fdb9ba499 100644 (file)
@@ -1,8 +1,8 @@
 error[E0308]: mismatched types
   --> $DIR/fn-trait-formatting.rs:6:17
    |
-LL |     let _: () = (box |_: isize| {}) as Box<dyn FnOnce(isize)>;
-   |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
+LL |     let _: () = Box::new(|_: isize| {}) as Box<dyn FnOnce(isize)>;
+   |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
    |            |
    |            expected due to this
    |
@@ -12,8 +12,8 @@ LL |     let _: () = (box |_: isize| {}) as Box<dyn FnOnce(isize)>;
 error[E0308]: mismatched types
   --> $DIR/fn-trait-formatting.rs:10:17
    |
-LL |     let _: () = (box |_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
-   |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
+LL |     let _: () = Box::new(|_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
+   |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
    |            |
    |            expected due to this
    |
@@ -23,8 +23,8 @@ LL |     let _: () = (box |_: isize, isize| {}) as Box<dyn Fn(isize, isize)>;
 error[E0308]: mismatched types
   --> $DIR/fn-trait-formatting.rs:14:17
    |
-LL |     let _: () = (box || -> isize { unimplemented!() }) as Box<dyn FnMut() -> isize>;
-   |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
+LL |     let _: () = Box::new(|| -> isize { unimplemented!() }) as Box<dyn FnMut() -> isize>;
+   |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box`
    |            |
    |            expected due to this
    |
@@ -41,7 +41,7 @@ LL |     needs_fn(1);
    |
    = help: the trait `Fn<(isize,)>` is not implemented for `{integer}`
 note: required by a bound in `needs_fn`
-  --> $DIR/fn-trait-formatting.rs:3:31
+  --> $DIR/fn-trait-formatting.rs:1:31
    |
 LL | fn needs_fn<F>(x: F) where F: Fn(isize) -> isize {}
    |                               ^^^^^^^^^^^^^^^^^^ required by this bound in `needs_fn`
index 6fecb4e76da3222f7a5e9e97e8b4ec052bad3056..afc77355ab00a4b072060829a525f189c7ecc5c7 100644 (file)
@@ -2,8 +2,6 @@
 // This test verifies that temporaries created for `while`'s and `if`
 // conditions are dropped after the condition is evaluated.
 
-#![feature(box_syntax)]
-
 struct Temporary;
 
 static mut DROPPED: isize = 0;
@@ -18,7 +16,7 @@ impl Temporary {
     fn do_stuff(&self) -> bool {true}
 }
 
-fn borrow() -> Box<Temporary> { box Temporary }
+fn borrow() -> Box<Temporary> { Box::new(Temporary) }
 
 
 pub fn main() {
index 79e59f76311fd1d8391ce17c903b9e8063bdbd4b..a8ec9391523c7e1b2c2143e4052507dd2543e789 100644 (file)
@@ -20,13 +20,13 @@ error: malformed `feature` attribute input
   --> $DIR/gated-bad-feature.rs:5:1
    |
 LL | #![feature]
-   | ^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]`
+   | ^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name1, ...)]`
 
 error: malformed `feature` attribute input
   --> $DIR/gated-bad-feature.rs:6:1
    |
 LL | #![feature = "foo"]
-   | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[feature(name1, name1, ...)]`
+   | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![feature(name1, name1, ...)]`
 
 error: aborting due to 5 previous errors
 
index 25bc6afc550b3a08e9ae3cbc115b2f81d5c13792..b5144c607a8808463b6c9465c76fb5dd2b7c9979 100644 (file)
@@ -6,6 +6,11 @@ LL |     test(gen);
    |
    = note: expected type `for<'a> Generator<&'a mut bool>`
               found type `Generator<&mut bool>`
+note: the lifetime requirement is introduced here
+  --> $DIR/resume-arg-late-bound.rs:8:17
+   |
+LL | fn test(a: impl for<'a> Generator<&'a mut bool>) {}
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
index 76a184d8d256a878735d127d6de53b540ed24814..fc138398634d5182977f167e7b1c96bdc19e39a4 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn id<T:Send>(t: T) -> T { return t; }
 
 pub fn main() {
-    let expected: Box<_> = box 100;
+    let expected: Box<_> = Box::new(100);
     let actual = id::<Box<isize>>(expected.clone());
     println!("{}", *actual);
     assert_eq!(*expected, *actual);
index 9b3e1ee02a2af6508fc3924afb1f9a9ad2b7cff9..10d87f9f43d0dbffc4e4418e97b828d2dce14f9a 100644 (file)
@@ -1,9 +1,8 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct Recbox<T> {x: Box<T>}
 
-fn reclift<T>(t: T) -> Recbox<T> { return Recbox {x: box t}; }
+fn reclift<T>(t: T) -> Recbox<T> { return Recbox { x: Box::new(t) }; }
 
 pub fn main() {
     let foo: isize = 17;
index 6cda1c3dc15e1f3c98edbe2ec92505848a2aa079..7e246bce9a10c86b75f8d273966c53e91bad52f0 100644 (file)
@@ -1,6 +1,8 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn f<T>(x: Box<T>) -> Box<T> { return x; }
 
-pub fn main() { let x = f(box 3); println!("{}", *x); }
+pub fn main() {
+    let x = f(Box::new(3));
+    println!("{}", *x);
+}
index 870ff980ec64d0ac897d9b475c6896a3816e6881..851424a11b5c141c31014ad91499928511091fc4 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 trait Foo<T> {
     fn get(&self) -> T;
@@ -16,7 +15,7 @@ fn get(&self) -> isize {
 }
 
 pub fn main() {
-    let x = box S { x: 1 };
+    let x = Box::new(S { x: 1 });
     let y = x as Box<dyn Foo<isize>>;
     assert_eq!(y.get(), 1);
 }
index e1875f0abbe61130080964d1c4c1fa0db03c6783..74f5b701d98a54153ff5e1b95c2ed308b0c5490a 100644 (file)
@@ -1,13 +1,12 @@
 // run-pass
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 enum list<T> { cons(Box<T>, Box<list<T>>), nil, }
 
 pub fn main() {
     let _a: list<isize> =
-        list::cons::<isize>(box 10,
-        box list::cons::<isize>(box 12,
-        box list::cons::<isize>(box 13,
-        box list::nil::<isize>)));
+        list::cons::<isize>(Box::new(10),
+        Box::new(list::cons::<isize>(Box::new(12),
+        Box::new(list::cons::<isize>(Box::new(13),
+        Box::new(list::nil::<isize>))))));
 }
index 74ef4eeba8ab70ca4dc9a0a45e663d5f1099faf5..67f2ccdde34a1c4bd3c4b0bbde8ed0bb0d002ca7 100644 (file)
@@ -5,11 +5,10 @@
 // pretty-expanded FIXME #23616
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 
 enum option<T> { some(Box<T>), none, }
 
 pub fn main() {
-    let mut a: option<isize> = option::some::<isize>(box 10);
+    let mut a: option<isize> = option::some::<isize>(Box::new(10));
     a = option::none::<isize>;
 }
index d36504c75dd9c6e73f46be86659534a8b5cc05bd..2f34712ecfbf375edf11b4b62ea495028997584b 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 struct Triple<T> { x: T, y: T, z: T }
 
-fn box_it<T>(x: Triple<T>) -> Box<Triple<T>> { return box x; }
+fn box_it<T>(x: Triple<T>) -> Box<Triple<T>> { return Box::new(x); }
 
 pub fn main() {
     let x: Box<Triple<isize>> = box_it::<isize>(Triple{x: 1, y: 2, z: 3});
index 6d6908ef7f63e00249f324209363e72f8aeea90b..ca26252832bcd5b7a7b48209bdee54b40697650a 100644 (file)
@@ -1,6 +1,6 @@
 // error-pattern: reached the recursion limit while auto-dereferencing
 
-#![feature(box_syntax)]
+
 
 use std::ops::Deref;
 
@@ -17,7 +17,7 @@ fn deref(&self) -> &Foo {
 pub fn main() {
     let mut x;
     loop {
-        x = box x;
+        x = Box::new(x);
         x.foo;
         x.bar();
     }
index cbefbf83be0a24da6a88ef87fc33a20e637c1d38..1f26ba30000b43f4619a7f61d7fc6f1b73a8af0d 100644 (file)
@@ -1,13 +1,10 @@
 error[E0308]: mismatched types
   --> $DIR/infinite-autoderef.rs:20:13
    |
-LL |         x = box x;
-   |             ^^^^^ cyclic type of infinite size
-   |
-help: try using a conversion method
-   |
-LL |         x = (box x).to_string();
-   |             +     +++++++++++++
+LL |         x = Box::new(x);
+   |             ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
+   |             |
+   |             cyclic type of infinite size
 
 error[E0055]: reached the recursion limit while auto-dereferencing `Foo`
   --> $DIR/infinite-autoderef.rs:25:5
index ed0c600c1d2e75e4044fd53665f04708487ae5db..7f416262dcb8cb253b4cef2641170fcdc020f495 100644 (file)
@@ -2,7 +2,6 @@
 
 #![allow(non_camel_case_types)]
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 use std::cell::Cell;
 
@@ -58,7 +57,7 @@ fn test_tup() {
 fn test_unique() {
     let i = &Cell::new(0);
     {
-        let _a: Box<_> = box r(i);
+        let _a: Box<_> = Box::new(r(i));
     }
     assert_eq!(i.get(), 1);
 }
@@ -66,9 +65,9 @@ fn test_unique() {
 fn test_unique_rec() {
     let i = &Cell::new(0);
     {
-        let _a: Box<_> = box BoxR {
+        let _a: Box<_> = Box::new(BoxR {
             x: r(i)
-        };
+        });
     }
     assert_eq!(i.get(), 1);
 }
index 608cf3dee5230565fe54ae0c38a221f0a15bef83..c6e48e8b5afbabe46dac3c4666ff3195f0cc419f 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 #![feature(intrinsics)]
 
 mod rusti {
@@ -34,7 +33,7 @@ mod rusti {
 
 pub fn main() {
     unsafe {
-        let mut x: Box<_> = box 1;
+        let mut x: Box<_> = Box::new(1);
 
         assert_eq!(rusti::atomic_load(&*x), 1);
         *x = 5;
diff --git a/src/test/ui/invalid/invalid-crate-type-macro.rs b/src/test/ui/invalid/invalid-crate-type-macro.rs
new file mode 100644 (file)
index 0000000..9ba5e79
--- /dev/null
@@ -0,0 +1,7 @@
+#![crate_type = foo!()] //~ ERROR malformed `crate_type` attribute
+
+macro_rules! foo {
+    () => {"rlib"};
+}
+
+fn main() {}
diff --git a/src/test/ui/invalid/invalid-crate-type-macro.stderr b/src/test/ui/invalid/invalid-crate-type-macro.stderr
new file mode 100644 (file)
index 0000000..c196d42
--- /dev/null
@@ -0,0 +1,8 @@
+error: malformed `crate_type` attribute input
+  --> $DIR/invalid-crate-type-macro.rs:1:1
+   |
+LL | #![crate_type = foo!()]
+   | ^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
+
+error: aborting due to previous error
+
index 92bed231586f9eacde055fbffa681c9e49d9dbe8..4072a2fa1624a1ebac5b71982fbab5f7a00f6709 100644 (file)
@@ -2,7 +2,7 @@ error: malformed `crate_type` attribute input
   --> $DIR/invalid_crate_type_syntax.rs:2:1
    |
 LL | #![crate_type(lib)]
-   | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]`
+   | ^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
 
 error: aborting due to previous error
 
index ce3ab6b599864ded9ba9cf5b66316137b0af37da..5a67aead75a73d44f9de286329e756c0d393b76f 100644 (file)
@@ -2,10 +2,7 @@ error[E0277]: the size for values of type `dyn Iterator<Item = &'a mut u8>` cann
   --> $DIR/issue-20605.rs:2:17
    |
 LL |     for item in *things { *item = 0 }
-   |                 ^^^^^^^
-   |                 |
-   |                 expected an implementor of trait `IntoIterator`
-   |                 help: consider mutably borrowing here: `&mut *things`
+   |                 ^^^^^^^ expected an implementor of trait `IntoIterator`
    |
    = note: the trait bound `dyn Iterator<Item = &'a mut u8>: IntoIterator` is not satisfied
    = note: required because of the requirements on the impl of `IntoIterator` for `dyn Iterator<Item = &'a mut u8>`
@@ -14,6 +11,10 @@ note: required by `into_iter`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider mutably borrowing here
+   |
+LL |     for item in &mut *things { *item = 0 }
+   |                 ++++
 
 error: aborting due to previous error
 
index c08f776dbf20a9bb97f7230e4f2e536c0faa25c8..8b0771985dc3fe53cc50dadb2911156ff65cc307 100644 (file)
@@ -1,15 +1,15 @@
-#![feature(box_syntax)]
-
 trait Foo {
 }
 
+
+
 impl<T:Copy> Foo for T {
 }
 
 fn take_param<T:Foo>(foo: &T) { }
 
 fn main() {
-    let x: Box<_> = box 3;
+    let x: Box<_> = Box::new(3);
     take_param(&x);
     //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied
 }
index 4d4d191b6aaee0283d52f099871f3fb148bbea42..5622d65cb175bb1001a27fc9f5c75afd7492170e 100644 (file)
@@ -1,7 +1,7 @@
 // Issue #14061: tests the interaction between generic implementation
 // parameter bounds and trait objects.
 
-#![feature(box_syntax)]
+
 
 use std::marker;
 
@@ -34,7 +34,7 @@ fn foo<'a>() {
 }
 
 fn foo2<'a>() {
-    let t: Box<S<String>> = box S(marker::PhantomData);
+    let t: Box<S<String>> = Box::new(S(marker::PhantomData));
     let a = t as Box<dyn Gettable<String>>;
     //~^ ERROR : Copy` is not satisfied
 }
@@ -42,7 +42,7 @@ fn foo2<'a>() {
 fn foo3<'a>() {
     struct Foo; // does not impl Copy
 
-    let t: Box<S<Foo>> = box S(marker::PhantomData);
+    let t: Box<S<Foo>> = Box::new(S(marker::PhantomData));
     let a: Box<dyn Gettable<Foo>> = t;
     //~^ ERROR : Copy` is not satisfied
 }
index aad693e5b193708149bf63f1d1aa968e5634c134..87d47556bdd2561ad9033507c8b5e2c88b90a7a9 100644 (file)
@@ -3,7 +3,7 @@
 // revisions: curr object_safe_for_dispatch
 
 #![cfg_attr(object_safe_for_dispatch, feature(object_safe_for_dispatch))]
-#![feature(box_syntax)]
+
 
 use std::any::Any;
 
@@ -17,13 +17,13 @@ impl<T:Copy> Foo for T {
 fn take_param<T:Foo>(foo: &T) { }
 
 fn a() {
-    let x: Box<_> = box 3;
+    let x: Box<_> = Box::new(3);
     take_param(&x); //[curr]~ ERROR E0277
     //[object_safe_for_dispatch]~^ ERROR E0277
 }
 
 fn b() {
-    let x: Box<_> = box 3;
+    let x: Box<_> = Box::new(3);
     let y = &x;
     let z = &x as &dyn Foo;
     //[curr]~^ ERROR E0038
diff --git a/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.rs
new file mode 100644 (file)
index 0000000..52bd813
--- /dev/null
@@ -0,0 +1,27 @@
+// Make sure that an error is reported if the `call` function of the
+// `fn`/`fn_mut` lang item is grossly ill-formed.
+
+#![feature(lang_items)]
+#![feature(no_core)]
+#![no_core]
+
+#[lang = "fn"]
+trait MyFn<T> {
+    const call: i32 = 42;
+    //~^ ERROR: `call` trait item in `fn` lang item must be a function
+}
+
+#[lang = "fn_mut"]
+trait MyFnMut<T> {
+    fn call(i: i32, j: i32) -> i32 { i + j }
+    //~^ ERROR: first argument of `call` in `fn_mut` lang item must be a reference
+}
+
+fn main() {
+    let a = || 42;
+    a();
+
+    let mut i = 0;
+    let mut b = || { i += 1; };
+    b();
+}
diff --git a/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr b/src/test/ui/lang-items/fn-fn_mut-call-ill-formed.stderr
new file mode 100644 (file)
index 0000000..82bdae2
--- /dev/null
@@ -0,0 +1,14 @@
+error: `call` trait item in `fn` lang item must be a function
+  --> $DIR/fn-fn_mut-call-ill-formed.rs:10:5
+   |
+LL |     const call: i32 = 42;
+   |     ^^^^^^^^^^^^^^^^^^^^^
+
+error: first argument of `call` in `fn_mut` lang item must be a reference
+  --> $DIR/fn-fn_mut-call-ill-formed.rs:16:16
+   |
+LL |     fn call(i: i32, j: i32) -> i32 { i + j }
+   |                ^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/lang-items/issue-83471.rs b/src/test/ui/lang-items/issue-83471.rs
new file mode 100644 (file)
index 0000000..b32aa03
--- /dev/null
@@ -0,0 +1,23 @@
+// Regression test for the ICE reported in issue #83471.
+
+#![crate_type="lib"]
+#![feature(no_core)]
+#![no_core]
+
+#[lang = "sized"]
+//~^ ERROR: language items are subject to change [E0658]
+trait Sized {}
+
+#[lang = "fn"]
+//~^ ERROR: language items are subject to change [E0658]
+//~| ERROR: `fn` language item must be applied to a trait with 1 generic argument
+trait Fn {
+    fn call(export_name);
+    //~^ ERROR: expected type
+    //~| WARNING: anonymous parameters are deprecated
+    //~| WARNING: this is accepted in the current edition
+}
+fn call_through_fn_trait() {
+    a()
+    //~^ ERROR: cannot find function
+}
diff --git a/src/test/ui/lang-items/issue-83471.stderr b/src/test/ui/lang-items/issue-83471.stderr
new file mode 100644 (file)
index 0000000..c6130bb
--- /dev/null
@@ -0,0 +1,51 @@
+error[E0573]: expected type, found built-in attribute `export_name`
+  --> $DIR/issue-83471.rs:15:13
+   |
+LL |     fn call(export_name);
+   |             ^^^^^^^^^^^ not a type
+
+error[E0425]: cannot find function `a` in this scope
+  --> $DIR/issue-83471.rs:21:5
+   |
+LL |     a()
+   |     ^ not found in this scope
+
+error[E0658]: language items are subject to change
+  --> $DIR/issue-83471.rs:7:1
+   |
+LL | #[lang = "sized"]
+   | ^^^^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(lang_items)]` to the crate attributes to enable
+
+error[E0658]: language items are subject to change
+  --> $DIR/issue-83471.rs:11:1
+   |
+LL | #[lang = "fn"]
+   | ^^^^^^^^^^^^^^
+   |
+   = help: add `#![feature(lang_items)]` to the crate attributes to enable
+
+warning: anonymous parameters are deprecated and will be removed in the next edition.
+  --> $DIR/issue-83471.rs:15:13
+   |
+LL |     fn call(export_name);
+   |             ^^^^^^^^^^^ help: try naming the parameter or explicitly ignoring it: `_: export_name`
+   |
+   = note: `#[warn(anonymous_parameters)]` on by default
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
+   = note: for more information, see issue #41686 <https://github.com/rust-lang/rust/issues/41686>
+
+error[E0718]: `fn` language item must be applied to a trait with 1 generic argument
+  --> $DIR/issue-83471.rs:11:1
+   |
+LL | #[lang = "fn"]
+   | ^^^^^^^^^^^^^^
+...
+LL | trait Fn {
+   |         - this trait has 0 generic arguments
+
+error: aborting due to 5 previous errors; 1 warning emitted
+
+Some errors have detailed explanations: E0425, E0573, E0658, E0718.
+For more information about an error, try `rustc --explain E0425`.
index af2308777939e125dca53b3d03ce3658fd76eb7a..1055fe7995ba629e5686933fd5c51f2128f26d1c 100644 (file)
@@ -3,13 +3,11 @@
 #![allow(dead_code)]
 // Make sure #1399 stays fixed
 
-#![feature(box_syntax)]
-
 struct A { a: Box<isize> }
 
 pub fn main() {
     fn invoke<F>(f: F) where F: FnOnce() { f(); }
-    let k: Box<_> = box 22;
+    let k: Box<_> = 22.into();
     let _u = A {a: k.clone()};
     invoke(|| println!("{}", k.clone()) )
 }
index 752081b78f27568f11d3a501e4d8c9068255bb21..322f726156d0c6e91e23f938c41c1ec6e91c4f21 100644 (file)
@@ -1,8 +1,9 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 fn leaky<T>(_t: T) { }
 
-pub fn main() { let x = box 10; leaky::<Box<isize>>(x); }
+pub fn main() {
+    let x = Box::new(10);
+    leaky::<Box<isize>>(x);
+}
index 907b43d6762e98e51a36463b5a110ec222920a89..04d9b64d64fdda70639588a0c4760b03087bd5e2 100644 (file)
@@ -38,6 +38,11 @@ note: this closure does not fulfill the lifetime requirements
    |
 LL |     take_foo(|a| a);
    |              ^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-79187-2.rs:5:21
+   |
+LL | fn take_foo(_: impl Foo) {}
+   |                     ^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-79187-2.rs:9:5
@@ -47,6 +52,11 @@ LL |     take_foo(|a: &i32| a);
    |
    = note: expected reference `&i32`
               found reference `&i32`
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-79187-2.rs:5:21
+   |
+LL | fn take_foo(_: impl Foo) {}
+   |                     ^^^
 
 error[E0308]: mismatched types
   --> $DIR/issue-79187-2.rs:10:5
@@ -56,6 +66,11 @@ LL |     take_foo(|a: &i32| -> &i32 { a });
    |
    = note: expected reference `&i32`
               found reference `&i32`
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-79187-2.rs:5:21
+   |
+LL | fn take_foo(_: impl Foo) {}
+   |                     ^^^
 
 error: aborting due to 6 previous errors
 
index 725b132e83a12b0aaeb5596bfc2cba9c9b1b36ec..3a993e88d8a92577a605ef0a811ae9e22e16ac63 100644 (file)
@@ -11,6 +11,11 @@ note: this closure does not fulfill the lifetime requirements
    |
 LL |     let f = |_| ();
    |             ^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/issue-79187.rs:1:18
+   |
+LL | fn thing(x: impl FnOnce(&u32)) {}
+   |                  ^^^^^^^^^^^^
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/issue-79187.rs:5:5
index 5a1294f948f1c3c13e7aa984982f7b7b1d6b7841..5509226cb1cdd83c5c8eebcc6cae3673e52a9e53 100644 (file)
@@ -14,6 +14,11 @@ LL |     f(data, identity)
    |
    = note: expected type `for<'r> Fn<(&'r T,)>`
               found type `Fn<(&T,)>`
+note: the lifetime requirement is introduced here
+  --> $DIR/issue_74400.rs:8:34
+   |
+LL | fn f<T, S>(data: &[T], key: impl Fn(&T) -> S) {
+   |                                  ^^^^^^^^^^^
 
 error: implementation of `FnOnce` is not general enough
   --> $DIR/issue_74400.rs:12:5
diff --git a/src/test/ui/lint/known-tool-in-submodule/root.rs b/src/test/ui/lint/known-tool-in-submodule/root.rs
new file mode 100644 (file)
index 0000000..80806dc
--- /dev/null
@@ -0,0 +1,10 @@
+// check-pass
+
+#![feature(register_tool)]
+#![register_tool(tool)]
+
+mod submodule;
+
+fn main() {
+    submodule::foo();
+}
diff --git a/src/test/ui/lint/known-tool-in-submodule/submodule.rs b/src/test/ui/lint/known-tool-in-submodule/submodule.rs
new file mode 100644 (file)
index 0000000..bb25e10
--- /dev/null
@@ -0,0 +1,4 @@
+// ignore-test: not a test
+
+#[allow(tool::lint)]
+pub fn foo() {}
index b3a41a786c1f0961e10dfffc057ea276da0dab49..91b4e509b269efd791789ebcfd645c8dd48b15da 100644 (file)
@@ -14,7 +14,7 @@ error: malformed `deny` attribute input
   --> $DIR/lint-malformed.rs:1:1
    |
 LL | #![deny = "foo"]
-   | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
+   | ^^^^^^^^^^^^^^^^ help: must be of the form: `#![deny(lint1, lint2, ..., /*opt*/ reason = "...")]`
 
 error[E0452]: malformed lint attribute input
   --> $DIR/lint-malformed.rs:2:10
index 7ef18c28c1ab783311f3e3d7f8c7fca8c54b422d..af47d5c072005b814f25907957830f45cdfe1f33 100644 (file)
@@ -1,12 +1,12 @@
 #![allow(dead_code)]
 #![forbid(box_pointers)]
-#![feature(box_syntax)]
+
 
 struct Foo {
     x: Box<isize> //~ ERROR type uses owned
 }
 
 fn main() {
-    let _x : Foo = Foo {x : box 10};
+    let _x: Foo = Foo { x : Box::new(10) };
     //~^ ERROR type uses owned
 }
index 40310f9387455a16338f5437944a3706dee281c7..5ba3969707571acd7dda91698d0a938af5539ce2 100644 (file)
@@ -13,8 +13,8 @@ LL | #![forbid(box_pointers)]
 error: type uses owned (Box type) pointers: Box<isize>
   --> $DIR/lint-owned-heap-memory.rs:10:29
    |
-LL |     let _x : Foo = Foo {x : box 10};
-   |                             ^^^^^^
+LL |     let _x: Foo = Foo { x : Box::new(10) };
+   |                             ^^^^^^^^^^^^
 
 error: aborting due to 2 previous errors
 
index 0ad014e3361b785d85c0d88a6d8c74efcfe9f7ad..4822a9b2c7ff825ec90ea435514fc9f1d25c2cd2 100644 (file)
@@ -1,7 +1,7 @@
 // check-pass
 
-#![feature(box_syntax)]
 #![feature(box_patterns)]
+
 #![warn(unused)] // UI tests pass `-A unused` (#43896)
 
 struct SoulHistory {
@@ -67,7 +67,7 @@ fn main() {
     };
 
     // Boxed struct
-    match box bag {
+    match Box::new(bag) {
         box Large::Suit { case } => {} //~ WARNING unused variable: `case`
     };
 
index 2ac5733b4199b5ec835b9efeb9c287a68ee315fc..cb83d4103dcedd375bd7d3ab2e38f7775d67a9b5 100644 (file)
@@ -3,8 +3,8 @@
 #![allow(non_camel_case_types)]
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 enum list { cons(isize, Box<list>), nil, }
 
-pub fn main() { list::cons(10, box list::cons(11, box list::cons(12, box list::nil))); }
+pub fn main() {
+    list::cons(10, Box::new(list::cons(11, Box::new(list::cons(12, Box::new(list::nil))))));
+}
index 98d12f5747aaeb9f11372a38796fc7b18bac2184..1bc2ea6b9fef6914ef9fb827a028adf0bbceaf8d 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax)]
-
 fn take(_x: Box<isize>) {}
 
+
 fn main() {
 
-    let x: Box<isize> = box 25;
+    let x: Box<isize> = Box::new(25);
+
     loop {
         take(x); //~ ERROR use of moved value: `x`
     }
index 5ea5c40f2ac97b68d64a46732ff044ec535f6394..7c0e916eddcaa12e55d76996032d737c662b0c80 100644 (file)
@@ -1,9 +1,9 @@
 error[E0382]: use of moved value: `x`
   --> $DIR/liveness-move-call-arg.rs:9:14
    |
-LL |     let x: Box<isize> = box 25;
+LL |     let x: Box<isize> = Box::new(25);
    |         - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
-LL |     loop {
+...
 LL |         take(x);
    |              ^ value moved here, in previous iteration of loop
 
index eb3288a28e2bccb9ac918d049cfa6c786a449141..064be14d6d28cd13cf7177f7e3d48bc88802aa80 100644 (file)
@@ -1,8 +1,8 @@
-#![feature(box_syntax)]
-
 fn main() {
-    let y: Box<isize> = box 42;
+
+    let y: Box<isize> = 42.into();
     let mut x: Box<isize>;
+
     loop {
         println!("{}", y);
         loop {
index 66b6373e450553470e075d56bee8d60b9f359a15..832d4f8fa030f9fae223c2db1c27565e8e40d861 100644 (file)
@@ -1,7 +1,7 @@
 error[E0382]: use of moved value: `y`
   --> $DIR/liveness-move-in-loop.rs:11:25
    |
-LL |     let y: Box<isize> = box 42;
+LL |     let y: Box<isize> = 42.into();
    |         - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait
 ...
 LL |                     x = y;
index 9f3ebf1362b823fc736e10d3999584a826e2a5dd..7c0cd282c97e007303ad0002563b2563de0f6444 100644 (file)
@@ -1,8 +1,8 @@
-#![feature(box_syntax)]
-
 fn main() {
-    let y: Box<isize> = box 42;
+
+    let y: Box<isize> = 42.into();
     let mut x: Box<isize>;
+
     loop {
         println!("{}", y); //~ ERROR borrow of moved value: `y`
         while true { while true { while true { x = y; x.clone(); } } }
index 92e0f372521580cdc942362446c547472c2f1290..6a8f239bd09a8a073862e455e3e15d7631167d78 100644 (file)
@@ -21,7 +21,7 @@ LL |         while true { while true { while true { x = y; x.clone(); } } }
 error[E0382]: borrow of moved value: `y`
   --> $DIR/liveness-move-in-while.rs:7:24
    |
-LL |     let y: Box<isize> = box 42;
+LL |     let y: Box<isize> = 42.into();
    |         - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait
 ...
 LL |         println!("{}", y);
index 5263e293603cdb9ca2395041ef5f82fea631e2d2..46102ca1eb11ebe3d58282e0a63cb881080d1956 100644 (file)
@@ -1,8 +1,8 @@
-#![feature(box_syntax)]
-
 fn main() {
-    let x: Box<_> = box 5;
+
+    let x: Box<_> = 5.into();
     let y = x;
+
     println!("{}", *x); //~ ERROR borrow of moved value: `x`
     y.clone();
 }
index 3977a3f4136d28b21f4cafd0672c4eb4d42506f8..292ce013dcc7622aaaa2cce9a285009cbe79b702 100644 (file)
@@ -1,10 +1,11 @@
 error[E0382]: borrow of moved value: `x`
   --> $DIR/liveness-use-after-move.rs:6:20
    |
-LL |     let x: Box<_> = box 5;
+LL |     let x: Box<_> = 5.into();
    |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
 LL |     let y = x;
    |             - value moved here
+LL | 
 LL |     println!("{}", *x);
    |                    ^^ value borrowed here after move
 
diff --git a/src/test/ui/macros/bang-after-name.fixed b/src/test/ui/macros/bang-after-name.fixed
new file mode 100644 (file)
index 0000000..c107ddd
--- /dev/null
@@ -0,0 +1,8 @@
+// run-rustfix
+#[allow(unused_macros)]
+
+macro_rules! foo { //~ ERROR macro names aren't followed by a `!`
+    () => {};
+}
+
+fn main() {}
diff --git a/src/test/ui/macros/bang-after-name.rs b/src/test/ui/macros/bang-after-name.rs
new file mode 100644 (file)
index 0000000..7654d8c
--- /dev/null
@@ -0,0 +1,8 @@
+// run-rustfix
+#[allow(unused_macros)]
+
+macro_rules! foo! { //~ ERROR macro names aren't followed by a `!`
+    () => {};
+}
+
+fn main() {}
diff --git a/src/test/ui/macros/bang-after-name.stderr b/src/test/ui/macros/bang-after-name.stderr
new file mode 100644 (file)
index 0000000..f609c49
--- /dev/null
@@ -0,0 +1,8 @@
+error: macro names aren't followed by a `!`
+  --> $DIR/bang-after-name.rs:4:17
+   |
+LL | macro_rules! foo! {
+   |                 ^ help: remove the `!`
+
+error: aborting due to previous error
+
index 98744434d4f8c916aadfd9d4838ccfda4580091b..505f6b6f140baa8e9e3578997c9b1076254f756d 100644 (file)
@@ -2,7 +2,7 @@ error: malformed `plugin` attribute input
   --> $DIR/malformed-plugin-1.rs:2:1
    |
 LL | #![plugin]
-   | ^^^^^^^^^^ help: must be of the form: `#[plugin(name)]`
+   | ^^^^^^^^^^ help: must be of the form: `#![plugin(name)]`
 
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/malformed-plugin-1.rs:2:1
index 9bf0bf9345c6cccd911fc39dd934b395ba0885f5..52bbd82a3892b15f2c5b07656bf6c078af09bf31 100644 (file)
@@ -2,7 +2,7 @@ error: malformed `plugin` attribute input
   --> $DIR/malformed-plugin-2.rs:2:1
    |
 LL | #![plugin="bleh"]
-   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#[plugin(name)]`
+   | ^^^^^^^^^^^^^^^^^ help: must be of the form: `#![plugin(name)]`
 
 warning: use of deprecated attribute `plugin`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675
   --> $DIR/malformed-plugin-2.rs:2:1
index 89b57087507c8466a9fc6e5af98d8b0bcafd374d..dc33b961800ea8bf75bc8ecef9780493ab95a9da 100644 (file)
@@ -1,7 +1,7 @@
-#![feature(box_syntax)]
-
 use std::collections::HashMap;
 
+
+
 trait Map<K, V>
 {
     fn get(&self, k: K) -> V { panic!() }
@@ -12,7 +12,7 @@ impl<K, V> Map<K, V> for HashMap<K, V> {}
 // Test that trait types printed in error msgs include the type arguments.
 
 fn main() {
-    let x: Box<HashMap<isize, isize>> = box HashMap::new();
+    let x: Box<HashMap<isize, isize>> = HashMap::new().into();
     let x: Box<dyn Map<isize, isize>> = x;
     let y: Box<dyn Map<usize, isize>> = Box::new(x);
     //~^ ERROR `Box<dyn Map<isize, isize>>: Map<usize, isize>` is not satisfied
index 8258fdd9ab93a8eaaa432329c5a6c01fb3233cd3..f89019fe5859f91d3ec691309de635bfcd7fa1cf 100644 (file)
@@ -1,7 +1,5 @@
 #![crate_type = "lib"]
 
-#![feature(box_syntax)]
-
 static mut COUNT: u64 = 1;
 
 pub fn get_count() -> u64 { unsafe { COUNT } }
@@ -19,8 +17,8 @@ pub fn foo(self, x: &Foo) {
         Foo::baz(self);
         Foo::baz(*x);
 
-        Foo::qux(box self);
-        Foo::qux(box *x);
+        Foo::qux(Box::new(self));
+        Foo::qux(Box::new(*x));
     }
 
     pub fn bar(&self) {
index 94a4a016c3eca390fd67cfa8fe6d32571f075d77..96725456291ea0916608aeb7e008ef6d1ce4600a 100644 (file)
@@ -1,7 +1,5 @@
 #![crate_type = "lib"]
 
-#![feature(box_syntax)]
-
 static mut COUNT: u64 = 1;
 
 pub fn get_count() -> u64 { unsafe { COUNT } }
@@ -15,11 +13,11 @@ pub fn run_trait(self) {
         // Test internal call.
         Bar::foo1(&self);
         Bar::foo2(self);
-        Bar::foo3(box self);
+        Bar::foo3(Box::new(self));
 
         Bar::bar1(&self);
         Bar::bar2(self);
-        Bar::bar3(box self);
+        Bar::bar3(Box::new(self));
     }
 }
 
index 9e38ff7de34247c48cfbd38049d69c062f2765ee..79b70a17ca1870d1cebd4a903c5681a85c650e48 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // Test method calls with self as an argument (cross-crate)
 
-#![feature(box_syntax)]
-
 // aux-build:method_self_arg1.rs
 extern crate method_self_arg1;
 use method_self_arg1::Foo;
@@ -12,7 +10,7 @@ fn main() {
     // Test external call.
     Foo::bar(&x);
     Foo::baz(x);
-    Foo::qux(box x);
+    Foo::qux(Box::new(x));
 
     x.foo(&x);
 
index 8e70399d047cd3719affa21a68de96fa27cee871..16487b54f174f550262dbadbdf1137310e61e9d8 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // Test method calls with self as an argument (cross-crate)
 
-#![feature(box_syntax)]
-
 // aux-build:method_self_arg2.rs
 extern crate method_self_arg2;
 use method_self_arg2::{Foo, Bar};
@@ -12,11 +10,11 @@ fn main() {
     // Test external call.
     Bar::foo1(&x);
     Bar::foo2(x);
-    Bar::foo3(box x);
+    Bar::foo3(Box::new(x));
 
     Bar::bar1(&x);
     Bar::bar2(x);
-    Bar::bar3(box x);
+    Bar::bar3(Box::new(x));
 
     x.run_trait();
 
index 227b1eab25de296239a84db4b7251e2acf92b6c5..ffa7a552b25a3678e056b091f3e6be176de4dc49 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // Test method calls with self as an argument
 
-#![feature(box_syntax)]
-
 static mut COUNT: u64 = 1;
 
 #[derive(Copy, Clone)]
@@ -44,11 +42,11 @@ fn baz(self) {
         // Test internal call.
         Bar::foo1(&self);
         Bar::foo2(self);
-        Bar::foo3(box self);
+        Bar::foo3(Box::new(self));
 
         Bar::bar1(&self);
         Bar::bar2(self);
-        Bar::bar3(box self);
+        Bar::bar3(Box::new(self));
     }
 }
 
@@ -57,11 +55,11 @@ fn main() {
     // Test external call.
     Bar::foo1(&x);
     Bar::foo2(x);
-    Bar::foo3(box x);
+    Bar::foo3(Box::new(x));
 
     Bar::bar1(&x);
     Bar::bar2(x);
-    Bar::bar3(box x);
+    Bar::bar3(Box::new(x));
 
     x.baz();
 
index 2d25b0dbad1967a745e98ce4961bb44caf3f0232..f738fa19c852a0df39d3adb87cd81b061f3d75ab 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // Test method calls with self as an argument
 
-#![feature(box_syntax)]
-
 static mut COUNT: usize = 1;
 
 #[derive(Copy, Clone)]
@@ -18,8 +16,8 @@ fn foo(self, x: &Foo) {
         Foo::baz(self);
         Foo::baz(*x);
 
-        Foo::qux(box self);
-        Foo::qux(box *x);
+        Foo::qux(Box::new(self));
+        Foo::qux(Box::new(*x));
     }
 
     fn bar(&self) {
@@ -40,7 +38,7 @@ fn main() {
     // Test external call.
     Foo::bar(&x);
     Foo::baz(x);
-    Foo::qux(box x);
+    Foo::qux(Box::new(x));
 
     x.foo(&x);
 
index 8af3dcf5c3db01b3c2b40db9db4e5083afd47182..fc5766da9714b807881ef5a1836eba390dc7bbc6 100644 (file)
@@ -10,8 +10,6 @@
 // codegen the call as `Foo::foo(&x)` and let the specific impl get
 // chosen later.
 
-#![feature(box_syntax)]
-
 trait Foo {
     fn foo(&self) -> isize;
 }
@@ -37,7 +35,7 @@ fn call_foo_copy() -> isize {
 fn call_foo_other() -> isize {
     let mut x: Vec<_> = Vec::new();
     let y = x.foo();
-    let z: Box<i32> = box 0;
+    let z: Box<i32> = Box::new(0);
     x.push(z);
     y
 }
index f29126e6afc76c7430e0896533fcf2510ab7516d..bd36fab92886dd600a168db9c7186504b286165b 100644 (file)
@@ -20,6 +20,11 @@ note: this closure does not fulfill the lifetime requirements
    |
 LL |     baz(|_| ());
    |         ^^^^^^
+note: the lifetime requirement is introduced here
+  --> $DIR/closure-mismatch.rs:5:11
+   |
+LL | fn baz<T: Foo>(_: T) {}
+   |           ^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/modules/path-invalid-form.rs b/src/test/ui/modules/path-invalid-form.rs
new file mode 100644 (file)
index 0000000..713ef4a
--- /dev/null
@@ -0,0 +1,4 @@
+#[path = 123]  //~ ERROR malformed `path` attribute
+mod foo;
+
+fn main() {}
diff --git a/src/test/ui/modules/path-invalid-form.stderr b/src/test/ui/modules/path-invalid-form.stderr
new file mode 100644 (file)
index 0000000..7e8aa44
--- /dev/null
@@ -0,0 +1,8 @@
+error: malformed `path` attribute input
+  --> $DIR/path-invalid-form.rs:1:1
+   |
+LL | #[path = 123]
+   | ^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/modules/path-macro.rs b/src/test/ui/modules/path-macro.rs
new file mode 100644 (file)
index 0000000..ce2d1e2
--- /dev/null
@@ -0,0 +1,8 @@
+macro_rules! foo {
+    () => {"bar.rs"};
+}
+
+#[path = foo!()] //~ ERROR malformed `path` attribute
+mod abc;
+
+fn main() {}
diff --git a/src/test/ui/modules/path-macro.stderr b/src/test/ui/modules/path-macro.stderr
new file mode 100644 (file)
index 0000000..9a2e01e
--- /dev/null
@@ -0,0 +1,8 @@
+error: malformed `path` attribute input
+  --> $DIR/path-macro.rs:5:1
+   |
+LL | #[path = foo!()]
+   | ^^^^^^^^^^^^^^^^ help: must be of the form: `#[path = "file"]`
+
+error: aborting due to previous error
+
index 7d3987f65608715ce3147fdbf44295120869b968..f98d075d18bba9204103aff0e7a5e1b66a083d8d 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(unused_mut)]
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 #[derive(Clone)]
 struct Triple {
@@ -13,12 +12,12 @@ struct Triple {
 fn test(x: bool, foo: Box<Triple>) -> isize {
     let bar = foo;
     let mut y: Box<Triple>;
-    if x { y = bar; } else { y = box Triple{x: 4, y: 5, z: 6}; }
+    if x { y = bar; } else { y = Box::new(Triple{x: 4, y: 5, z: 6}); }
     return y.y;
 }
 
 pub fn main() {
-    let x: Box<_> = box Triple{x: 1, y: 2, z: 3};
+    let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3});
     assert_eq!(test(true, x.clone()), 2);
     assert_eq!(test(true, x.clone()), 2);
     assert_eq!(test(true, x.clone()), 2);
index 910a88c102f0fe37f06a2f3d1d6dee08bdb949eb..8fda3c1c86c6039d2b768f37a6f747e82840aa72 100644 (file)
@@ -1,11 +1,10 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 struct X { x: isize, y: isize, z: isize }
 
 pub fn main() {
-    let x: Box<_> = box X{x: 1, y: 2, z: 3};
+    let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3});
     let y = x;
     assert_eq!(y.y, 2);
 }
index 4ad53e96e50f2d1cd9596a54efc525fdc061312d..5e010087465d9e1902eab6cd2d0133ceeccd104c 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 struct X { x: isize, y: isize, z: isize }
 
-pub fn main() { let x: Box<_> = box X {x: 1, y: 2, z: 3}; let y = x; assert_eq!(y.y, 2); }
+pub fn main() { let x: Box<_> = Box::new(X {x: 1, y: 2, z: 3}); let y = x; assert_eq!(y.y, 2); }
index d23a852433f4f9b478312061d6a78d16a9eacc5c..8e5df2c3ff9fd6e93a155707545df7e77608f091 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 #![allow(unused_mut)]
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 #[derive(Clone)]
 struct Triple {
@@ -13,12 +12,12 @@ struct Triple {
 fn test(x: bool, foo: Box<Triple>) -> isize {
     let bar = foo;
     let mut y: Box<Triple>;
-    if x { y = bar; } else { y = box Triple {x: 4, y: 5, z: 6}; }
+    if x { y = bar; } else { y = Box::new(Triple {x: 4, y: 5, z: 6}); }
     return y.y;
 }
 
 pub fn main() {
-    let x: Box<_> = box Triple{x: 1, y: 2, z: 3};
+    let x: Box<_> = Box::new(Triple{x: 1, y: 2, z: 3});
     for _ in 0_usize..10000_usize {
         assert_eq!(test(true, x.clone()), 2);
     }
index 1787caadb7ab0d68ba3c405f0b2e3bc29765593d..24aec7ea62c8b59635d85078ee3d18653309efbb 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 struct Triple {a: isize, b: isize, c: isize}
 
@@ -13,7 +12,7 @@ fn test(foo: Box<Triple>) -> Box<Triple> {
 }
 
 pub fn main() {
-    let x = box Triple{a: 1, b: 2, c: 3};
+    let x = Box::new(Triple{a: 1, b: 2, c: 3});
     let y = test(x);
     assert_eq!(y.c, 3);
 }
index c87c605df7730301edb975436e3eab0d98586044..63aa031a66e60137c09412eb85d38af3a37372a8 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 struct Triple { a: isize, b: isize, c: isize }
 
@@ -13,7 +12,7 @@ fn test(foo: Box<Triple>) -> Box<Triple> {
 }
 
 pub fn main() {
-    let x = box Triple{a: 1, b: 2, c: 3};
+    let x = Box::new(Triple{ a: 1, b: 2, c: 3 });
     let y = test(x);
     assert_eq!(y.c, 3);
 }
index fcfd5e14765f57e50e9f0211a4cc03fbd8bd7660..9622c83750d3ed1b12deea187869ade8eaddfb7b 100644 (file)
@@ -1,13 +1,12 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn test(foo: Box<Vec<isize>> ) { assert_eq!((*foo)[0], 10); }
 
 pub fn main() {
-    let x = box vec![10];
+    let x = Box::new(vec![10]);
     // Test forgetting a local by move-in
     test(x);
 
     // Test forgetting a temporary by move-in.
-    test(box vec![10]);
+    test(Box::new(vec![10]));
 }
index 4cd1f6fe8105e0765f7314287b819ebae794537b..77ee06e192e73c17fc00915b211a850e9830a257 100644 (file)
@@ -1,13 +1,12 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn test(foo: Box<Vec<isize>>) { assert_eq!((*foo)[0], 10); }
 
 pub fn main() {
-    let x = box vec![10];
+    let x = Box::new(vec![10]);
     // Test forgetting a local by move-in
     test(x);
 
     // Test forgetting a temporary by move-in.
-    test(box vec![10]);
+    test(Box::new(vec![10]));
 }
index da436b89f538e511d0a6339f33594c201e6ce21e..b96ef8e19eb51a4fcf3d12413779267ab03fb587 100644 (file)
@@ -8,10 +8,10 @@
 // that assumption did not hold, at least not in the long run (namely,
 // overlapping patterns were turned into warnings rather than errors).
 
-#![feature(box_syntax)]
+
 
 fn main() {
-    let x: Box<_> = box 1;
+    let x: Box<_> = Box::new(1);
 
     let v = (1, 2);
 
index 5fc8a5499326e68e4e76bc148c788862b40aaf4b..2048fefefa31b69855cdbc0df73befa07709c375 100644 (file)
@@ -1,7 +1,7 @@
 error[E0382]: use of moved value: `x`
   --> $DIR/move-guard-same-consts.rs:20:24
    |
-LL |     let x: Box<_> = box 1;
+LL |     let x: Box<_> = Box::new(1);
    |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
 ...
 LL |         (1, 2) if take(x) => (),
index 9c50782e6406cf5109180d7f66e1ca59b88194a9..36e39fea6af3b7ef308efb23dc829c89ce2edaca 100644 (file)
@@ -1,7 +1,7 @@
-#![feature(box_syntax)]
-
 pub fn main() {
-    let x: Box<_> = box 1;
+
+
+    let x: Box<_> = Box::new(1);
 
     let v = (1, 2);
 
index d894209f51764f78af592da8ffc78ce2ec621abf..5e9aa66b90daebd6e4fc9d343e640ef009aa194f 100644 (file)
@@ -1,7 +1,7 @@
 error[E0382]: use of moved value: `x`
   --> $DIR/move-in-guard-1.rs:10:24
    |
-LL |     let x: Box<_> = box 1;
+LL |     let x: Box<_> = Box::new(1);
    |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
 ...
 LL |         (1, _) if take(x) => (),
index f478625a83b3efc28ca0b89b55bdfc24d778089b..085b7ec6e0ccc14d5110c46bd13f014c3e275dc7 100644 (file)
@@ -1,7 +1,5 @@
-#![feature(box_syntax)]
-
 pub fn main() {
-    let x: Box<_> = box 1;
+    let x: Box<_> = Box::new(1);
 
     let v = (1, 2);
 
index a067d43389378258d5435d6e858a90a1dc0a935e..ea350926b1519f77a1264274880d4dda57509274 100644 (file)
@@ -1,7 +1,7 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/move-in-guard-2.rs:10:24
+  --> $DIR/move-in-guard-2.rs:8:24
    |
-LL |     let x: Box<_> = box 1;
+LL |     let x: Box<_> = Box::new(1);
    |         - move occurs because `x` has type `Box<i32>`, which does not implement the `Copy` trait
 ...
 LL |         (_, 2) if take(x) => (),
index e5a505bb88d328bef7de2ffc33b6dbc343b17b25..66912fa4d099809b8c9901f7906f6c5552b6822e 100644 (file)
@@ -1,13 +1,13 @@
-#![feature(box_syntax)]
-
 struct Foo(Box<isize>);
 
+
+
 fn main() {
-    let x: (Box<_>,) = (box 1,);
+    let x: (Box<_>,) = (Box::new(1),);
     let y = x.0;
     let z = x.0; //~ ERROR use of moved value: `x.0`
 
-    let x = Foo(box 1);
+    let x = Foo(Box::new(1));
     let y = x.0;
     let z = x.0; //~ ERROR use of moved value: `x.0`
 }
index 085e249c0fb073d6bb180fcad3ab2eba648009d8..eca33167f454ae6ea9ee7777c1c45a6815a86a0f 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
+
 
 struct S {
     x: Box<E>
@@ -16,7 +16,7 @@ fn f<G>(s: &S, g: G) where G: FnOnce(&S) {
 }
 
 fn main() {
-    let s = S { x: box E::Bar(box 42) };
+    let s = S { x: Box::new(E::Bar(Box::new(42))) };
     loop {
         f(&s, |hellothere| {
             match hellothere.x { //~ ERROR cannot move out
index 52a5103865123ee44050b604fef98485eb820ef6..76b7aab542de8313d351541b229dbe5b127311c5 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax, unboxed_closures)]
+#![feature(unboxed_closures)]
 
 fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
 
 fn test(_x: Box<usize>) {}
 
 fn main() {
-    let i = box 3;
+    let i = Box::new(3);
     let _f = to_fn(|| test(i)); //~ ERROR cannot move out
 }
index e12af2d45274315fcdef2ad9bfed6f3d1e4f2784..ce930eee2e919a8d336317f87d15aa2b7fc86c53 100644 (file)
@@ -1,7 +1,7 @@
 error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure
   --> $DIR/moves-based-on-type-move-out-of-closure-env-issue-1965.rs:9:28
    |
-LL |     let i = box 3;
+LL |     let i = Box::new(3);
    |         - captured outer variable
 LL |     let _f = to_fn(|| test(i));
    |                    --------^-
index 828d90cd7ac7f4b48c4e2212c388e0e0a920cd0e..2e67d8f8a69131676f12d6c84b356d0111a613af 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax)]
-
 fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
-    box (x, x)
+
+
+    Box::new((x, x))
     //~^ use of moved value: `x` [E0382]
 }
 
 fn main() {
-    dup(box 3);
+    dup(Box::new(3));
 }
index a52c023e202930b3e8e61b2b1d6163e59141103a..eef8ce61fa9d8aef6b354c247696b3daa9c471fe 100644 (file)
@@ -1,12 +1,13 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/moves-based-on-type-tuple.rs:4:13
+  --> $DIR/moves-based-on-type-tuple.rs:4:18
    |
 LL | fn dup(x: Box<isize>) -> Box<(Box<isize>,Box<isize>)> {
    |        - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
-LL |     box (x, x)
-   |          -  ^ value used here after move
-   |          |
-   |          value moved here
+...
+LL |     Box::new((x, x))
+   |               -  ^ value used here after move
+   |               |
+   |               value moved here
 
 error: aborting due to previous error
 
index e620e5de92320fe89928f9b0dee340c145a5dd99..72957c49fc8ae9f7e0e1fb858acc20fb9ff27f74 100644 (file)
@@ -1,7 +1,7 @@
-#![feature(box_syntax)]
-
 type Noncopyable = Box<isize>;
 
+
+
 struct Foo {
     copied: isize,
     moved: Box<isize>,
@@ -10,8 +10,8 @@ struct Foo {
 
 fn test0(f: Foo, g: Noncopyable, h: Noncopyable) {
     // just copy implicitly copyable fields from `f`, no moves:
-    let _b = Foo {moved: box 1, noncopyable: g, ..f};
-    let _c = Foo {moved: box 2, noncopyable: h, ..f};
+    let _b = Foo {moved: Box::new(1), noncopyable: g, ..f};
+    let _c = Foo {moved: Box::new(2), noncopyable: h, ..f};
 }
 
 fn test1(f: Foo, g: Noncopyable, h: Noncopyable) {
index 620d00edbbce3609e767c103098ad62e2d5b8439..1e682fc4b66c41ec3c8602627e5746a715192a93 100644 (file)
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(box_syntax)]
-
 fn f(mut y: Box<isize>) {
     *y = 5;
     assert_eq!(*y, 5);
@@ -9,13 +7,13 @@ fn f(mut y: Box<isize>) {
 
 fn g() {
     let frob = |mut q: Box<isize>| { *q = 2; assert_eq!(*q, 2); };
-    let w = box 37;
+    let w = Box::new(37);
     frob(w);
 
 }
 
 pub fn main() {
-    let z = box 17;
+    let z = Box::new(17);
     f(z);
     g();
 }
index 63e49c292eac705ee1267b86813aeebd11350c27..080faab73261925d810a1b1ede3cd465c07538ad 100644 (file)
@@ -1,8 +1,8 @@
-#![feature(box_syntax)]
-
 fn f(_: &mut isize) {}
 
 fn main() {
-    let mut x: Box<_> = box 3;
+
+    let mut x: Box<_> = Box::new(3);
+
     f(x)    //~ ERROR mismatched types
 }
index 418cf554b49be7f75d09622fd4985ede64b801ae..c56e1dd46254ff59ee64d0bf94fbb67f0e8134e1 100644 (file)
@@ -5,7 +5,6 @@
  * http://creativecommons.org/publicdomain/zero/1.0/ */
 
 #![allow(dead_code, unused_variables)]
-#![feature(box_syntax)]
 
 // Tests that the new `box` syntax works with unique pointers.
 
@@ -17,12 +16,12 @@ struct Structure {
 }
 
 pub fn main() {
-    let y: Box<isize> = box 2;
-    let b: Box<isize> = box (1 + 2);
-    let c = box (3 + 4);
+    let y: Box<isize> = Box::new(2);
+    let b: Box<isize> = Box::new(1 + 2);
+    let c = Box::new(3 + 4);
 
-    let s: Box<Structure> = box Structure {
+    let s: Box<Structure> = Box::new(Structure {
         x: 3,
         y: 4,
-    };
+    });
 }
index d11f0d045a7e422e7b874613d4dfd3a05354c0c2..96a3b197f461cf59a76fc9869e89cecd4a275e6d 100644 (file)
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(box_syntax)]
-
 fn f(x: Box<isize>) {
     let y: &isize = &*x;
     println!("{}", *x);
@@ -27,6 +25,6 @@ fn g(x: Box<dyn Trait>) {
 }
 
 fn main() {
-    f(box 1234);
-    g(box Struct as Box<dyn Trait>);
+    f(Box::new(1234));
+    g(Box::new(Struct) as Box<dyn Trait>);
 }
index a7be365bde4bdf78c9c4da1d8b0d9a45b25e4454..f6bbb2d14b003afb80e9f1d0225663f9bbe1be9a 100644 (file)
@@ -1,16 +1,16 @@
-#![feature(box_syntax)]
-
 trait Foo { fn get(&self); }
 
 impl<A> Foo for A {
     fn get(&self) { }
 }
 
+
+
 fn main() {
     let _ = {
         let tmp0 = 3;
         let tmp1 = &tmp0;
-        box tmp1 as Box<dyn Foo + '_>
+        Box::new(tmp1) as Box<dyn Foo + '_>
     };
     //~^^^ ERROR `tmp0` does not live long enough
 }
index b71893de7f8bdca925bcf391dac445e1908dd97a..5cedea6e66520a5e022ce895232324b31bb79272 100644 (file)
@@ -3,8 +3,8 @@ error[E0597]: `tmp0` does not live long enough
    |
 LL |         let tmp1 = &tmp0;
    |                    ^^^^^ borrowed value does not live long enough
-LL |         box tmp1 as Box<dyn Foo + '_>
-   |         ----------------------------- borrow later captured here by trait object
+LL |         Box::new(tmp1) as Box<dyn Foo + '_>
+   |         ----------------------------------- borrow later captured here by trait object
 LL |     };
    |     - `tmp0` dropped here while still borrowed
 
index f34df4e2dd143f66758a82124e847f2bc6f3623c..93da7c3e0ddd65ca368fa9a4c65cd88ffaff5bca 100644 (file)
@@ -2,7 +2,7 @@ error: malformed `crate_type` attribute input
   --> $DIR/no_crate_type.rs:2:1
    |
 LL | #![crate_type]
-   | ^^^^^^^^^^^^^^ help: must be of the form: `#[crate_type = "bin|lib|..."]`
+   | ^^^^^^^^^^^^^^ help: must be of the form: `#![crate_type = "bin|lib|..."]`
 
 error: aborting due to previous error
 
index 568c3e144be2c302cabef8446cd0f166954bad0a..f9edba6743499dddcfe13e4ea0e8b5095cf3a2bf 100644 (file)
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(box_syntax)]
-
 // Iota-reduction is a rule in the Calculus of (Co-)Inductive Constructions,
 // which "says that a destructor applied to an object built from a constructor
 // behaves as expected".  -- https://coq.inria.fr/doc/language/core/conversion.html#iota-reduction
@@ -64,7 +62,7 @@ macro_rules! check_type {
 
 pub fn main() {
     check_type!(&17, &isize);
-    check_type!(box 18, Box<isize>);
+    check_type!(Box::new(18), Box<isize>);
     check_type!("foo".to_string(), String);
     check_type!(vec![20, 22], Vec<isize>);
     check_type!(main, fn(), |pthing| {
index 9b88d8ea7bcd9444b5a5ecfffe2f26d00f9a6c3f..fce1341fc74154c7105cdd86407232660fef973b 100644 (file)
@@ -3,9 +3,6 @@
 // closed over do not contain managed values, and thus the boxes do
 // not have headers.
 
-#![feature(box_syntax)]
-
-
 trait FooTrait {
     fn foo(&self) -> usize;
 }
@@ -22,9 +19,9 @@ fn foo(&self) -> usize {
 
 pub fn main() {
     let foos: Vec<Box<dyn FooTrait>> = vec![
-        box BarStruct{ x: 0 } as Box<dyn FooTrait>,
-        box BarStruct{ x: 1 } as Box<dyn FooTrait>,
-        box BarStruct{ x: 2 } as Box<dyn FooTrait>
+        Box::new(BarStruct{ x: 0 }) as Box<dyn FooTrait>,
+        Box::new(BarStruct{ x: 1 }) as Box<dyn FooTrait>,
+        Box::new(BarStruct{ x: 2 }) as Box<dyn FooTrait>,
     ];
 
     for i in 0..foos.len() {
index 4b7b68f22176f6576f3f5097dabe5baa80364c74..15677a5185c2f1a2776c3f84b6be7b9d496189de 100644 (file)
@@ -3,8 +3,6 @@
 // closed over contain managed values. This implies that the boxes
 // will have headers that must be skipped over.
 
-#![feature(box_syntax)]
-
 trait FooTrait {
     fn foo(self: Box<Self>) -> usize;
 }
@@ -20,6 +18,6 @@ fn foo(self: Box<BarStruct>) -> usize {
 }
 
 pub fn main() {
-    let foo = box BarStruct{ x: 22 } as Box<dyn FooTrait>;
+    let foo = Box::new(BarStruct{ x: 22 }) as Box<dyn FooTrait>;
     assert_eq!(22, foo.foo());
 }
index 213fd2619cee7d9979d460215f734c23a95fc51e..f36682a3dd82132b577ccfece5b28e9e7147c694 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax)]
-
 fn main() {
+
     let f;
     let g;
+
     g = f;
-    f = box g;
+    f = Box::new(g);
     //~^  ERROR mismatched types
     //~| cyclic type of infinite size
 }
index c004043307899f11a6e7e6bde1bbd5b2ea4cf3ec..dcbfc81b4d51928f25c43cf3f06c4dd1434002fc 100644 (file)
@@ -1,13 +1,10 @@
 error[E0308]: mismatched types
   --> $DIR/occurs-check-2.rs:7:9
    |
-LL |     f = box g;
-   |         ^^^^^ cyclic type of infinite size
-   |
-help: try using a conversion method
-   |
-LL |     f = (box g).to_string();
-   |         +     +++++++++++++
+LL |     f = Box::new(g);
+   |         ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
+   |         |
+   |         cyclic type of infinite size
 
 error: aborting due to previous error
 
index 5f2c2362d24cd81c9230d47ae274eff901133b9d..aec52d839766ad3e42ec040a30a6cf4e0572bae7 100644 (file)
@@ -1,8 +1,8 @@
-#![feature(box_syntax)]
-
 fn main() {
+
     let f;
-    f = box f;
+
+    f = Box::new(f);
     //~^ ERROR mismatched types
     //~| cyclic type of infinite size
 }
index 452163e2fa5ee44fd9a0b71c66e32244373707fe..3e1ef2e719ad570a6d2f497a8293873cbc7f050a 100644 (file)
@@ -1,13 +1,10 @@
 error[E0308]: mismatched types
   --> $DIR/occurs-check.rs:5:9
    |
-LL |     f = box f;
-   |         ^^^^^ cyclic type of infinite size
-   |
-help: try using a conversion method
-   |
-LL |     f = (box f).to_string();
-   |         +     +++++++++++++
+LL |     f = Box::new(f);
+   |         ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
+   |         |
+   |         cyclic type of infinite size
 
 error: aborting due to previous error
 
index af4caf75669967d0b8cda24859f4e1560be69e53..7c20a2b2f94e8d3fc223c5bb2ef15fa841da5f9a 100644 (file)
@@ -7,22 +7,21 @@
 
 #![allow(dead_assignment)]
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 
 struct A { a: isize, b: isize }
 struct Abox { a: Box<isize>, b: Box<isize> }
 
 fn ret_int_i() -> isize { 10 }
 
-fn ret_ext_i() -> Box<isize> { box 10 }
+fn ret_ext_i() -> Box<isize> { Box::new(10) }
 
 fn ret_int_rec() -> A { A {a: 10, b: 10} }
 
-fn ret_ext_rec() -> Box<A> { box A {a: 10, b: 10} }
+fn ret_ext_rec() -> Box<A> { Box::new(A {a: 10, b: 10}) }
 
-fn ret_ext_mem() -> Abox { Abox {a: box 10, b: box 10} }
+fn ret_ext_mem() -> Abox { Abox {a: Box::new(10), b: Box::new(10) } }
 
-fn ret_ext_ext_mem() -> Box<Abox> { box Abox{a: box 10, b: box 10} }
+fn ret_ext_ext_mem() -> Box<Abox> { Box::new(Abox{a: Box::new(10), b: Box::new(10) }) }
 
 pub fn main() {
     let mut int_i: isize;
index e850633e34fee1e674c04fda455181ed2ee81fda..cae3ec906211e86b60cf0b4a3d1cafb1f2ff4ccb 100644 (file)
@@ -2,8 +2,6 @@
 #![allow(unused_variables)]
 #![allow(stable_features)]
 
-#![feature(box_syntax, core)]
-
 use std::cell::RefCell;
 use std::rc::Rc;
 
@@ -14,7 +12,7 @@ struct Point {
 }
 
 pub fn main() {
-    let box_5: Box<_> = box 5_usize;
+    let box_5: Box<_> = Box::new(5_usize);
     let point = Rc::new(Point {x: 2, y: 4});
     assert_eq!(point.x, 2);
     assert_eq!(point.y, 4);
index 6996ee32933c088ac8581b6e6d5e86932e2ff60b..41f9efa8c1619348d4203c63645756b696b79617 100644 (file)
@@ -3,8 +3,6 @@
 
 // Test overloaded indexing combined with autoderef.
 
-#![feature(box_syntax, core)]
-
 use std::ops::{Index, IndexMut};
 
 struct Foo {
@@ -47,10 +45,10 @@ fn get_from_ref(&self) -> isize { *self }
 }
 
 fn main() {
-    let mut f: Box<_> = box Foo {
+    let mut f: Box<_> = Box::new(Foo {
         x: 1,
         y: 2,
-    };
+    });
 
     assert_eq!(f[1], 2);
 
index 322054caf116140b92e2b4d54a8be8e103f522d9..7636025c25b8324c5c7345c760590fef141aff2f 100644 (file)
@@ -2,12 +2,10 @@
 // error-pattern:meep
 // ignore-emscripten no processes
 
-#![feature(box_syntax)]
-
 fn f(_a: isize, _b: isize, _c: Box<isize>) {
     panic!("moop");
 }
 
 fn main() {
-    f(1, panic!("meep"), box 42);
+    f(1, panic!("meep"), Box::new(42));
 }
index 08acc6e8078f9b8df2b804ee4a30e019f34f186f..c7df5365474e950970670ed9230f716ec5dba435 100644 (file)
@@ -2,9 +2,8 @@
 // error-pattern:panicked at 'Box<dyn Any>'
 // ignore-emscripten no processes
 
-#![feature(box_syntax)]
 #![allow(non_fmt_panics)]
 
 fn main() {
-    panic!(box 413 as Box<dyn std::any::Any + Send>);
+    panic!(Box::new(413) as Box<dyn std::any::Any + Send>);
 }
index 33c30d731087795996a48735fd23b3dfcb18c113..61819cabdf178514905a96e47a0525a298835d83 100644 (file)
@@ -1,10 +1,9 @@
 // build-pass (FIXME(62277): could be check-pass?)
 
-#![feature(box_syntax)]
 #![allow(bare_trait_objects)]
 
 use std::fmt::Debug;
 
 fn main() {
-    let x: Box<Debug+> = box 3 as Box<Debug+>; // Trailing `+` is OK
+    let x: Box<Debug+> = Box::new(3) as Box<Debug+>; // Trailing `+` is OK
 }
index 8b391cd95d7f78c1fb4d348a6d71a119e6ae7b14..3cb92a54029dc03cdea9190fd3762f139f767f25 100644 (file)
@@ -1,9 +1,9 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 #![allow(dead_code)]
 #![allow(unused_variables)]
 #![deny(unreachable_patterns)]
 
+
 enum IntList {
     Cons(isize, Box<IntList>),
     Nil
@@ -12,9 +12,9 @@ enum IntList {
 fn tail(source_list: &IntList) -> IntList {
     match source_list {
         &IntList::Cons(val, box ref next_list) => tail(next_list),
-        &IntList::Cons(val, box IntList::Nil)  => IntList::Cons(val, box IntList::Nil),
-//~^ ERROR unreachable pattern
-        _                          => panic!()
+        &IntList::Cons(val, box IntList::Nil)  => IntList::Cons(val, Box::new(IntList::Nil)),
+        //~^ ERROR unreachable pattern
+        _ => panic!(),
     }
 }
 
index 4d162eb77e725879e71ea638d717474ee730f0c3..7f15c4703a31c2238ef4a9da649bc6411b75ff09 100644 (file)
@@ -1,11 +1,11 @@
 error: unreachable pattern
   --> $DIR/issue-12116.rs:15:9
    |
-LL |         &IntList::Cons(val, box IntList::Nil)  => IntList::Cons(val, box IntList::Nil),
+LL |         &IntList::Cons(val, box IntList::Nil)  => IntList::Cons(val, Box::new(IntList::Nil)),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: the lint level is defined here
-  --> $DIR/issue-12116.rs:5:9
+  --> $DIR/issue-12116.rs:4:9
    |
 LL | #![deny(unreachable_patterns)]
    |         ^^^^^^^^^^^^^^^^^^^^
index e33359beccdefb5d437d6e8894b9696968676163..6215a23980d6d32a75f5f362b738bb039a3a51de 100644 (file)
@@ -1,5 +1,4 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 struct HTMLImageData {
     image: Option<String>
@@ -23,8 +22,9 @@ struct NodeData {
 
 fn main() {
     let mut id = HTMLImageData { image: None };
-    let ed = ElementData { kind: box ElementKind::HTMLImageElement(id) };
-    let n = NodeData {kind : box NodeKind::Element(ed)};
+    let ed = ElementData { kind: Box::new(ElementKind::HTMLImageElement(id)) };
+    let n = NodeData { kind: Box::new(NodeKind::Element(ed)) };
+
     // n.b. span could be better
     match n.kind {
         box NodeKind::Element(ed) => match ed.kind { //~ ERROR non-exhaustive patterns
diff --git a/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs b/src/test/ui/proc-macro/attribute-after-derive-feature-gate.rs
deleted file mode 100644 (file)
index f0fec67..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-// gate-test-macro_attributes_in_derive_output
-// aux-build: test-macros.rs
-
-#![feature(proc_macro_hygiene)]
-#![feature(stmt_expr_attributes)]
-
-#[macro_use]
-extern crate test_macros;
-
-#[derive(Empty)]
-#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable
-struct S1 {
-    field: [u8; 10],
-}
-
-#[derive(Empty)]
-#[empty_helper]
-#[empty_attr] //~ ERROR macro attributes in `#[derive]` output are unstable
-struct S2 {
-    field: [u8; 10],
-}
-
-#[derive(Empty)]
-struct S3 {
-    field: [u8; #[identity_attr] 10], //~ ERROR macro attributes in `#[derive]` output are unstable
-}
-
-#[derive(Empty)]
-struct S4 {
-    field: [u8; {
-        #[derive(Empty)] // OK, not gated
-        struct Inner;
-        10
-    }]
-}
-
-fn main() {}
diff --git a/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr b/src/test/ui/proc-macro/attribute-after-derive-feature-gate.stderr
deleted file mode 100644 (file)
index 74cace6..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-error[E0658]: macro attributes in `#[derive]` output are unstable
-  --> $DIR/attribute-after-derive-feature-gate.rs:11:3
-   |
-LL | #[empty_attr]
-   |   ^^^^^^^^^^
-   |
-   = note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
-   = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
-
-error[E0658]: macro attributes in `#[derive]` output are unstable
-  --> $DIR/attribute-after-derive-feature-gate.rs:18:3
-   |
-LL | #[empty_attr]
-   |   ^^^^^^^^^^
-   |
-   = note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
-   = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
-
-error[E0658]: macro attributes in `#[derive]` output are unstable
-  --> $DIR/attribute-after-derive-feature-gate.rs:25:19
-   |
-LL |     field: [u8; #[identity_attr] 10],
-   |                   ^^^^^^^^^^^^^
-   |
-   = note: see issue #81119 <https://github.com/rust-lang/rust/issues/81119> for more information
-   = help: add `#![feature(macro_attributes_in_derive_output)]` to the crate attributes to enable
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0658`.
index ac3f28b6ef3ea119e50cfce971341cf175e6399a..0f0f27bff97be8b89ac4e7841950a6837c709e75 100644 (file)
@@ -5,8 +5,6 @@
 // compile-flags: -Z span-debug
 // aux-build: test-macros.rs
 
-#![feature(macro_attributes_in_derive_output)]
-
 #![no_std] // Don't load unnecessary hygiene information from std
 extern crate std;
 
index 4c48e41ff338b38c62b93a9fb5660c20a97e90a9..c5b84b0367c8fbdf1c5c501a2811a574e1a54988 100644 (file)
@@ -3,35 +3,35 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/attribute-after-derive.rs:17:1: 17:2 (#0),
+        span: $DIR/attribute-after-derive.rs:15:1: 15:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "derive",
-                span: $DIR/attribute-after-derive.rs:17:3: 17:9 (#0),
+                span: $DIR/attribute-after-derive.rs:15:3: 15:9 (#0),
             },
             Group {
                 delimiter: Parenthesis,
                 stream: TokenStream [
                     Ident {
                         ident: "Print",
-                        span: $DIR/attribute-after-derive.rs:17:10: 17:15 (#0),
+                        span: $DIR/attribute-after-derive.rs:15:10: 15:15 (#0),
                     },
                 ],
-                span: $DIR/attribute-after-derive.rs:17:9: 17:16 (#0),
+                span: $DIR/attribute-after-derive.rs:15:9: 15:16 (#0),
             },
         ],
-        span: $DIR/attribute-after-derive.rs:17:2: 17:17 (#0),
+        span: $DIR/attribute-after-derive.rs:15:2: 15:17 (#0),
     },
     Ident {
         ident: "struct",
-        span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0),
+        span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0),
     },
     Ident {
         ident: "AttributeDerive",
-        span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0),
+        span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0),
     },
     Group {
         delimiter: Brace,
@@ -39,64 +39,64 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [
             Punct {
                 ch: '#',
                 spacing: Alone,
-                span: $DIR/attribute-after-derive.rs:19:5: 19:6 (#0),
+                span: $DIR/attribute-after-derive.rs:17:5: 17:6 (#0),
             },
             Group {
                 delimiter: Bracket,
                 stream: TokenStream [
                     Ident {
                         ident: "cfg",
-                        span: $DIR/attribute-after-derive.rs:19:7: 19:10 (#0),
+                        span: $DIR/attribute-after-derive.rs:17:7: 17:10 (#0),
                     },
                     Group {
                         delimiter: Parenthesis,
                         stream: TokenStream [
                             Ident {
                                 ident: "FALSE",
-                                span: $DIR/attribute-after-derive.rs:19:11: 19:16 (#0),
+                                span: $DIR/attribute-after-derive.rs:17:11: 17:16 (#0),
                             },
                         ],
-                        span: $DIR/attribute-after-derive.rs:19:10: 19:17 (#0),
+                        span: $DIR/attribute-after-derive.rs:17:10: 17:17 (#0),
                     },
                 ],
-                span: $DIR/attribute-after-derive.rs:19:6: 19:18 (#0),
+                span: $DIR/attribute-after-derive.rs:17:6: 17:18 (#0),
             },
             Ident {
                 ident: "field",
-                span: $DIR/attribute-after-derive.rs:20:5: 20:10 (#0),
+                span: $DIR/attribute-after-derive.rs:18:5: 18:10 (#0),
             },
             Punct {
                 ch: ':',
                 spacing: Alone,
-                span: $DIR/attribute-after-derive.rs:20:10: 20:11 (#0),
+                span: $DIR/attribute-after-derive.rs:18:10: 18:11 (#0),
             },
             Ident {
                 ident: "u8",
-                span: $DIR/attribute-after-derive.rs:20:12: 20:14 (#0),
+                span: $DIR/attribute-after-derive.rs:18:12: 18:14 (#0),
             },
             Punct {
                 ch: ',',
                 spacing: Alone,
-                span: $DIR/attribute-after-derive.rs:20:14: 20:15 (#0),
+                span: $DIR/attribute-after-derive.rs:18:14: 18:15 (#0),
             },
         ],
-        span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0),
+        span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): struct AttributeDerive { }
 PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/attribute-after-derive.rs:18:1: 18:7 (#0),
+        span: $DIR/attribute-after-derive.rs:16:1: 16:7 (#0),
     },
     Ident {
         ident: "AttributeDerive",
-        span: $DIR/attribute-after-derive.rs:18:8: 18:23 (#0),
+        span: $DIR/attribute-after-derive.rs:16:8: 16:23 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/attribute-after-derive.rs:18:24: 21:2 (#0),
+        span: $DIR/attribute-after-derive.rs:16:24: 19:2 (#0),
     },
 ]
 PRINT-DERIVE INPUT (DISPLAY): #[print_attr] struct DeriveAttribute { }
@@ -104,45 +104,89 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [
     Punct {
         ch: '#',
         spacing: Alone,
-        span: $DIR/attribute-after-derive.rs:24:1: 24:2 (#0),
+        span: $DIR/attribute-after-derive.rs:22:1: 22:2 (#0),
     },
     Group {
         delimiter: Bracket,
         stream: TokenStream [
             Ident {
                 ident: "print_attr",
-                span: $DIR/attribute-after-derive.rs:24:3: 24:13 (#0),
+                span: $DIR/attribute-after-derive.rs:22:3: 22:13 (#0),
             },
         ],
-        span: $DIR/attribute-after-derive.rs:24:2: 24:14 (#0),
+        span: $DIR/attribute-after-derive.rs:22:2: 22:14 (#0),
     },
     Ident {
         ident: "struct",
-        span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0),
+        span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0),
     },
     Ident {
         ident: "DeriveAttribute",
-        span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0),
+        span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0),
     },
     Group {
         delimiter: Brace,
         stream: TokenStream [],
-        span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
+        span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0),
     },
 ]
-PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { }
+PRINT-ATTR INPUT (DISPLAY): struct DeriveAttribute { #[cfg(FALSE)] field : u8, }
 PRINT-ATTR INPUT (DEBUG): TokenStream [
     Ident {
         ident: "struct",
-        span: $DIR/attribute-after-derive.rs:25:1: 25:7 (#0),
+        span: $DIR/attribute-after-derive.rs:23:1: 23:7 (#0),
     },
     Ident {
         ident: "DeriveAttribute",
-        span: $DIR/attribute-after-derive.rs:25:8: 25:23 (#0),
+        span: $DIR/attribute-after-derive.rs:23:8: 23:23 (#0),
     },
     Group {
         delimiter: Brace,
-        stream: TokenStream [],
-        span: $DIR/attribute-after-derive.rs:25:24: 28:2 (#0),
+        stream: TokenStream [
+            Punct {
+                ch: '#',
+                spacing: Alone,
+                span: $DIR/attribute-after-derive.rs:24:5: 24:6 (#0),
+            },
+            Group {
+                delimiter: Bracket,
+                stream: TokenStream [
+                    Ident {
+                        ident: "cfg",
+                        span: $DIR/attribute-after-derive.rs:24:7: 24:10 (#0),
+                    },
+                    Group {
+                        delimiter: Parenthesis,
+                        stream: TokenStream [
+                            Ident {
+                                ident: "FALSE",
+                                span: $DIR/attribute-after-derive.rs:24:11: 24:16 (#0),
+                            },
+                        ],
+                        span: $DIR/attribute-after-derive.rs:24:10: 24:17 (#0),
+                    },
+                ],
+                span: $DIR/attribute-after-derive.rs:24:6: 24:18 (#0),
+            },
+            Ident {
+                ident: "field",
+                span: $DIR/attribute-after-derive.rs:25:5: 25:10 (#0),
+            },
+            Punct {
+                ch: ':',
+                spacing: Alone,
+                span: $DIR/attribute-after-derive.rs:25:10: 25:11 (#0),
+            },
+            Ident {
+                ident: "u8",
+                span: $DIR/attribute-after-derive.rs:25:12: 25:14 (#0),
+            },
+            Punct {
+                ch: ',',
+                spacing: Alone,
+                span: $DIR/attribute-after-derive.rs:25:14: 25:15 (#0),
+            },
+        ],
+        span: $DIR/attribute-after-derive.rs:23:24: 26:2 (#0),
     },
 ]
index 2ff6f935a03c15c11554801aadf9deb37a9550db..2f2ece75ebeeb0c7cead9f59b4e96559cbc7a045 100644 (file)
@@ -5,8 +5,6 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 fn sums_to(v: Vec<isize> , sum: isize) -> bool {
     let mut i = 0;
     let mut sum0 = 0;
@@ -19,7 +17,7 @@ fn sums_to(v: Vec<isize> , sum: isize) -> bool {
 
 fn sums_to_using_uniq(v: Vec<isize> , sum: isize) -> bool {
     let mut i = 0;
-    let mut sum0: Box<_> = box 0;
+    let mut sum0: Box<_> = 0.into();
     while i < v.len() {
         *sum0 += v[i];
         i += 1;
@@ -41,7 +39,7 @@ struct F<T> { f: T }
 
 fn sums_to_using_uniq_rec(v: Vec<isize> , sum: isize) -> bool {
     let mut i = 0;
-    let mut sum0 = F::<Box<_>> {f: box 0};
+    let mut sum0 = F::<Box<_>> {f: 0.into() };
     while i < v.len() {
         *sum0.f += v[i];
         i += 1;
index 37113bc0a050bf95393e0edcba22f3e56a3a761e..7f32b8b91a6f0c6a7f20295ffe65f99c6fd6c9ab 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
 
 #![allow(non_camel_case_types)]
-#![feature(box_syntax)]
 
 trait get {
     fn get(self) -> isize;
@@ -17,7 +16,7 @@ fn get(self) -> isize {
 }
 
 pub fn main() {
-    let x: Box<_> = box 6;
+    let x: Box<_> = 6.into();
     let y = x.get();
     println!("y={}", y);
     assert_eq!(y, 6);
index 243fed0c8ce528bad27edd4df0883ac44830c3a2..6049321337c75379051186e3889edf3f87d16b4d 100644 (file)
@@ -1,5 +1,5 @@
-#![feature(box_syntax)]
 #![allow(unused_variables)]
+
 #![deny(unreachable_code)]
 
 fn main() {
index 64c3896851669fc52f65503267f7d4d5794b70f0..3277bf0d52b201babb349bb9e39c6548ae8478e3 100644 (file)
@@ -1,5 +1,5 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
+
 #![allow(dead_code)]
 #![deny(unreachable_patterns)]
 
diff --git a/src/test/ui/recursion_limit/invalid_digit_type.rs b/src/test/ui/recursion_limit/invalid_digit_type.rs
new file mode 100644 (file)
index 0000000..e408109
--- /dev/null
@@ -0,0 +1,3 @@
+#![recursion_limit = 123] //~ ERROR malformed `recursion_limit` attribute
+
+fn main() {}
diff --git a/src/test/ui/recursion_limit/invalid_digit_type.stderr b/src/test/ui/recursion_limit/invalid_digit_type.stderr
new file mode 100644 (file)
index 0000000..6d1409b
--- /dev/null
@@ -0,0 +1,8 @@
+error: malformed `recursion_limit` attribute input
+  --> $DIR/invalid_digit_type.rs:1:1
+   |
+LL | #![recursion_limit = 123]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/recursion_limit/invalid_macro.rs b/src/test/ui/recursion_limit/invalid_macro.rs
new file mode 100644 (file)
index 0000000..7db67a8
--- /dev/null
@@ -0,0 +1,7 @@
+#![recursion_limit = foo!()] //~ ERROR malformed `recursion_limit` attribute
+
+macro_rules! foo {
+    () => {"128"};
+}
+
+fn main() {}
diff --git a/src/test/ui/recursion_limit/invalid_macro.stderr b/src/test/ui/recursion_limit/invalid_macro.stderr
new file mode 100644 (file)
index 0000000..0189e99
--- /dev/null
@@ -0,0 +1,8 @@
+error: malformed `recursion_limit` attribute input
+  --> $DIR/invalid_macro.rs:1:1
+   |
+LL | #![recursion_limit = foo!()]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#![recursion_limit = "N"]`
+
+error: aborting due to previous error
+
index 0ade359923a0e6c6449d8d4385e61f1c7ccb1186..d8f2abb0c3c217039f9aed0cae44081f6ae9cfd8 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax)]
-
 trait X {
     fn get_i(&self) -> isize;
 }
 
 
+
+
 struct B {
     i: isize
 }
@@ -24,7 +24,7 @@ fn make_a<'a>(p: &'a dyn X) -> A<'a> {
 }
 
 fn make_make_a<'a>() -> A<'a> {
-    let b: Box<B> = box B {i:1};
+    let b: Box<B> = Box::new(B { i: 1 });
     let bb: &B = &*b;
     make_a(bb)  //~ ERROR cannot return value referencing local data `*b`
 }
index 355e8c914551c26952f41e3352b7349f3e5676bf..152abe109bca49913e799d2d38324c561d047ac1 100644 (file)
@@ -1,12 +1,11 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn foo(x: &usize) -> usize {
     *x
 }
 
 pub fn main() {
-    let p: Box<_> = box 22;
+    let p: Box<_> = Box::new(22);
     let r = foo(&*p);
     println!("r={}", r);
     assert_eq!(r, 22);
index 3bf049c151137a974c51c8c907b7761efe4a6046..adc6b1939da7f7e297a3c9f570668b5f8527644b 100644 (file)
@@ -1,12 +1,11 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn foo(x: &usize) -> usize {
     *x
 }
 
 pub fn main() {
-    let p: Box<_> = box 3;
+    let p: Box<_> = Box::new(3);
     let r = foo(&*p);
     assert_eq!(r, 3);
 }
index 0cbdc828c507fa5ecdcf9111ad0e1d6b28381317..428477e24899a8437733de8f6b04924a8e41e4ae 100644 (file)
@@ -1,7 +1,7 @@
-#![feature(box_syntax)]
-
 trait X {}
 
+
+
 trait Iter {
     type Item: X;
 
@@ -18,7 +18,7 @@ fn bad1<T: Iter>(v: T) -> Box<dyn X + 'static>
 fn bad2<T: Iter>(v: T) -> Box<dyn X + 'static>
     where Box<T::Item> : X
 {
-    let item: Box<_> = box v.into_item();
+    let item: Box<_> = Box::new(v.into_item());
     Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough
 }
 
@@ -31,7 +31,7 @@ fn bad3<'a, T: Iter>(v: T) -> Box<dyn X + 'a>
 fn bad4<'a, T: Iter>(v: T) -> Box<dyn X + 'a>
     where Box<T::Item> : X
 {
-    let item: Box<_> = box v.into_item();
+    let item: Box<_> = Box::new(v.into_item());
     Box::new(item) //~ ERROR associated type `<T as Iter>::Item` may not live long enough
 }
 
index 5518c6a94b1d0bf546795d1fb5320ad2cdc5d7f6..2dc33d5671ff0597d14d9aa7fce9ff2a87a63ae2 100644 (file)
@@ -1,7 +1,7 @@
-#![feature(box_syntax)]
 #![allow(warnings)]
 
 trait A<T> { }
+
 struct B<'a, T:'a>(&'a (A<T>+'a));
 
 trait X { }
@@ -9,7 +9,7 @@ trait X { }
 impl<'a, T> X for B<'a, T> {}
 
 fn f<'a, T:'static, U>(v: Box<A<T>+'static>) -> Box<X+'static> {
-    box B(&*v) as Box<X> //~ ERROR cannot return value referencing local data `*v`
+    Box::new(B(&*v)) as Box<X> //~ ERROR cannot return value referencing local data `*v`
 }
 
 fn main() {}
index 8e119c4f5355fc8bbc1331db9d1fec8d3e92f6c2..5bfaeb295c352d1b771b202ae8ef44e302988cef 100644 (file)
@@ -1,10 +1,10 @@
 error[E0515]: cannot return value referencing local data `*v`
   --> $DIR/regions-close-object-into-object-1.rs:12:5
    |
-LL |     box B(&*v) as Box<X>
-   |     ^^^^^^---^^^^^^^^^^^
-   |     |     |
-   |     |     `*v` is borrowed here
+LL |     Box::new(B(&*v)) as Box<X>
+   |     ^^^^^^^^^^^---^^^^^^^^^^^^
+   |     |          |
+   |     |          `*v` is borrowed here
    |     returns a value referencing data owned by the current function
 
 error: aborting due to previous error
index 882faf4ece316a34fc1dd781d153d99f2a5d08ee..410fab962f7208155c26a8f01becedd2c594c261 100644 (file)
@@ -1,20 +1,20 @@
 error: lifetime may not live long enough
-  --> $DIR/regions-close-object-into-object-2.rs:10:5
+  --> $DIR/regions-close-object-into-object-2.rs:9:5
    |
 LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
    |      -- lifetime `'a` defined here
-LL |     box B(&*v) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
    |
    = help: consider replacing `'a` with `'static`
 
 error[E0515]: cannot return value referencing local data `*v`
-  --> $DIR/regions-close-object-into-object-2.rs:10:5
+  --> $DIR/regions-close-object-into-object-2.rs:9:5
    |
-LL |     box B(&*v) as Box<dyn X>
-   |     ^^^^^^---^^^^^^^^^^^^^^^
-   |     |     |
-   |     |     `*v` is borrowed here
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
+   |     |          |
+   |     |          `*v` is borrowed here
    |     returns a value referencing data owned by the current function
 
 error: aborting due to 2 previous errors
index 7144ab5a24c51443ec36b8dffda63669e12317a0..9c41174e24d8db96cc84b0c58fc2a99948fe3f86 100644 (file)
@@ -1,13 +1,12 @@
-#![feature(box_syntax)]
-
 trait A<T> { }
+
 struct B<'a, T:'a>(&'a (dyn A<T> + 'a));
 
 trait X { }
 impl<'a, T> X for B<'a, T> {}
 
 fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
-    box B(&*v) as Box<dyn X> //~ ERROR E0759
+    Box::new(B(&*v)) as Box<dyn X> //~ ERROR E0759
 }
 
 fn main() { }
index 78d2371cf53b29f2ebb14535c88872e0bc57ed65..9a7df8c0188b193f6027a3a71a911dd88b450195 100644 (file)
@@ -1,10 +1,10 @@
 error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-close-object-into-object-2.rs:10:11
+  --> $DIR/regions-close-object-into-object-2.rs:9:16
    |
 LL | fn g<'a, T: 'static>(v: Box<dyn A<T> + 'a>) -> Box<dyn X + 'static> {
    |                         ------------------ this data with lifetime `'a`...
-LL |     box B(&*v) as Box<dyn X>
-   |           ^^^ ...is captured here, requiring it to live as long as `'static`
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...is captured here, requiring it to live as long as `'static`
    |
 help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
    |
index 6f6b3a170027db2b0c996b1a7e772a0bb9970724..78d93b0ece5b656612590cc769beafbf8694d8f2 100644 (file)
@@ -1,14 +1,14 @@
-#![feature(box_syntax)]
 #![allow(warnings)]
 
 trait A<T> { }
+
 struct B<'a, T:'a>(&'a (A<T>+'a));
 
 trait X { }
 impl<'a, T> X for B<'a, T> {}
 
 fn h<'a, T, U:'static>(v: Box<A<U>+'static>) -> Box<X+'static> {
-    box B(&*v) as Box<X> //~ ERROR cannot return value referencing local data `*v`
+    Box::new(B(&*v)) as Box<X> //~ ERROR cannot return value referencing local data `*v`
 }
 
 fn main() {}
index 9ea13638f5cad3506d382532a64fcab4905dd5e7..9f92c40e1e18d1d7f11e3cb07b363bee55198842 100644 (file)
@@ -1,10 +1,10 @@
 error[E0515]: cannot return value referencing local data `*v`
   --> $DIR/regions-close-object-into-object-3.rs:11:5
    |
-LL |     box B(&*v) as Box<X>
-   |     ^^^^^^---^^^^^^^^^^^
-   |     |     |
-   |     |     `*v` is borrowed here
+LL |     Box::new(B(&*v)) as Box<X>
+   |     ^^^^^^^^^^^---^^^^^^^^^^^^
+   |     |          |
+   |     |          `*v` is borrowed here
    |     returns a value referencing data owned by the current function
 
 error: aborting due to previous error
index 93ac17810dae2015fd6fc92fa598524e722badf7..e2cd864ea020e63cd5540d134b0dce51ca759fd9 100644 (file)
@@ -1,39 +1,55 @@
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/regions-close-object-into-object-4.rs:10:5
+  --> $DIR/regions-close-object-into-object-4.rs:9:5
    |
-LL |     box B(&*v) as Box<dyn X>
-   |     ^^^^^^^^^^
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `U: 'static`...
+
+error[E0310]: the parameter type `U` may not live long enough
+  --> $DIR/regions-close-object-into-object-4.rs:9:5
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `U: 'static`...
+
+error[E0310]: the parameter type `U` may not live long enough
+  --> $DIR/regions-close-object-into-object-4.rs:9:5
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `U: 'static`...
 
 error: lifetime may not live long enough
-  --> $DIR/regions-close-object-into-object-4.rs:10:5
+  --> $DIR/regions-close-object-into-object-4.rs:9:5
    |
 LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
    |      -- lifetime `'a` defined here
-LL |     box B(&*v) as Box<dyn X>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
    |
    = help: consider replacing `'a` with `'static`
 
 error[E0515]: cannot return value referencing local data `*v`
-  --> $DIR/regions-close-object-into-object-4.rs:10:5
+  --> $DIR/regions-close-object-into-object-4.rs:9:5
    |
-LL |     box B(&*v) as Box<dyn X>
-   |     ^^^^^^---^^^^^^^^^^^^^^^
-   |     |     |
-   |     |     `*v` is borrowed here
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
+   |     |          |
+   |     |          `*v` is borrowed here
    |     returns a value referencing data owned by the current function
 
 error[E0310]: the parameter type `U` may not live long enough
-  --> $DIR/regions-close-object-into-object-4.rs:10:9
+  --> $DIR/regions-close-object-into-object-4.rs:9:14
    |
-LL |     box B(&*v) as Box<dyn X>
-   |         ^^^^^^
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |              ^^^^^^
    |
    = help: consider adding an explicit lifetime bound `U: 'static`...
 
-error: aborting due to 4 previous errors
+error: aborting due to 6 previous errors
 
 Some errors have detailed explanations: E0310, E0515.
 For more information about an error, try `rustc --explain E0310`.
index 4c087f264f92b964010c16521d98fd6a97f92889..2a06a2b7c0513630af945507700c46592af52a26 100644 (file)
@@ -1,13 +1,12 @@
-#![feature(box_syntax)]
-
 trait A<T> { }
+
 struct B<'a, T:'a>(&'a (dyn A<T> + 'a));
 
 trait X { }
 impl<'a, T> X for B<'a, T> {}
 
 fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
-    box B(&*v) as Box<dyn X> //~ ERROR E0759
+    Box::new(B(&*v)) as Box<dyn X> //~ ERROR E0759
 }
 
 fn main() {}
index 8c94b44f20037c84df4b0b89c14d08beddf7f84b..a7a9b16b0801379c4dcb0bb40675ca230bb9b9ca 100644 (file)
@@ -1,10 +1,10 @@
 error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement
-  --> $DIR/regions-close-object-into-object-4.rs:10:11
+  --> $DIR/regions-close-object-into-object-4.rs:9:16
    |
 LL | fn i<'a, T, U>(v: Box<dyn A<U>+'a>) -> Box<dyn X + 'static> {
    |                   ---------------- this data with lifetime `'a`...
-LL |     box B(&*v) as Box<dyn X>
-   |           ^^^ ...is captured here, requiring it to live as long as `'static`
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...is captured here, requiring it to live as long as `'static`
    |
 help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v`
    |
index 08ba1b17b56636a176e08492ca9f0b51213ef13c..7486e73e66ab31122bda6f9b0af5301668a2cc94 100644 (file)
@@ -1,29 +1,45 @@
 error[E0310]: the parameter type `T` may not live long enough
   --> $DIR/regions-close-object-into-object-5.rs:17:5
    |
-LL |     box B(&*v) as Box<X>
-   |     ^^^^^^^^^^
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:17:5
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^
+   |
+   = help: consider adding an explicit lifetime bound `T: 'static`...
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:17:5
+   |
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
 
 error[E0515]: cannot return value referencing local data `*v`
   --> $DIR/regions-close-object-into-object-5.rs:17:5
    |
-LL |     box B(&*v) as Box<X>
-   |     ^^^^^^---^^^^^^^^^^^
-   |     |     |
-   |     |     `*v` is borrowed here
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^---^^^^^^^^^^^^^^^^
+   |     |          |
+   |     |          `*v` is borrowed here
    |     returns a value referencing data owned by the current function
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:9
+  --> $DIR/regions-close-object-into-object-5.rs:17:14
    |
-LL |     box B(&*v) as Box<X>
-   |         ^^^^^^
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |              ^^^^^^
    |
    = help: consider adding an explicit lifetime bound `T: 'static`...
 
-error: aborting due to 3 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0310, E0515.
 For more information about an error, try `rustc --explain E0310`.
index ff35b9ada45cd379dd66bc40e5e806ce62f5e22d..5471c375b4990ddf903a171fb21679825955e69e 100644 (file)
@@ -1,6 +1,6 @@
-#![feature(box_syntax)]
 #![allow(warnings)]
 
+
 trait A<T>
 {
     fn get(&self) -> T { panic!() }
@@ -14,13 +14,14 @@ impl<'a, T> X for B<'a, T> {}
 
 fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
     // oh dear!
-    box B(&*v) as Box<X>
+    Box::new(B(&*v)) as Box<dyn X>
     //~^ ERROR the parameter type `T` may not live long enough
     //~| ERROR the parameter type `T` may not live long enough
     //~| ERROR the parameter type `T` may not live long enough
     //~| ERROR the parameter type `T` may not live long enough
     //~| ERROR the parameter type `T` may not live long enough
     //~| ERROR the parameter type `T` may not live long enough
+    //~| ERROR the parameter type `T` may not live long enough
 }
 
 fn main() {}
index 5b692cdcc0ecc77ebc6444265cb2730e7b9c092a..83f8d20b9e1deaae136e32c6a2bdafef7b92c06b 100644 (file)
@@ -4,26 +4,41 @@ error[E0310]: the parameter type `T` may not live long enough
 LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
-LL |     box B(&*v) as Box<X>
-   |     ^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+   |
+note: ...that is required by this bound
+  --> $DIR/regions-close-object-into-object-5.rs:9:17
+   |
+LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
+   |                 ^^
+
+error[E0310]: the parameter type `T` may not live long enough
+  --> $DIR/regions-close-object-into-object-5.rs:17:5
+   |
+LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
+   |          - help: consider adding an explicit lifetime bound...: `T: 'static`
+LL |     // oh dear!
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |     ^^^^^^^^^^^^^^^^ ...so that the type `B<'_, T>` will meet its required lifetime bounds
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:9
+  --> $DIR/regions-close-object-into-object-5.rs:17:14
    |
 LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
-LL |     box B(&*v) as Box<X>
-   |         ^ ...so that the type `T` will meet its required lifetime bounds
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |              ^ ...so that the type `T` will meet its required lifetime bounds
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:9
+  --> $DIR/regions-close-object-into-object-5.rs:17:14
    |
 LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
-LL |     box B(&*v) as Box<X>
-   |         ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |              ^^^^^^ ...so that the type `T` will meet its required lifetime bounds...
    |
 note: ...that is required by this bound
   --> $DIR/regions-close-object-into-object-5.rs:9:17
@@ -32,32 +47,32 @@ LL | struct B<'a, T: 'a>(&'a (A<T> + 'a));
    |                 ^^
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:11
+  --> $DIR/regions-close-object-into-object-5.rs:17:16
    |
 LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
-LL |     box B(&*v) as Box<X>
-   |           ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...so that the reference type `&dyn A<T>` does not outlive the data it points at
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:11
+  --> $DIR/regions-close-object-into-object-5.rs:17:16
    |
 LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
-LL |     box B(&*v) as Box<X>
-   |           ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
 
 error[E0310]: the parameter type `T` may not live long enough
-  --> $DIR/regions-close-object-into-object-5.rs:17:11
+  --> $DIR/regions-close-object-into-object-5.rs:17:16
    |
 LL | fn f<'a, T, U>(v: Box<A<T> + 'static>) -> Box<X + 'static> {
    |          - help: consider adding an explicit lifetime bound...: `T: 'static`
 LL |     // oh dear!
-LL |     box B(&*v) as Box<X>
-   |           ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
+LL |     Box::new(B(&*v)) as Box<dyn X>
+   |                ^^^ ...so that the type `(dyn A<T> + 'static)` is not borrowed for too long
 
-error: aborting due to 6 previous errors
+error: aborting due to 7 previous errors
 
 For more information about this error, try `rustc --explain E0310`.
index 3101d815881b17fcd6442581dcefd58cd99acd00..b576ae87011377d25a1a6f8c53a1554ef63fdc81 100644 (file)
@@ -1,16 +1,16 @@
 error[E0310]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:12:5
    |
-LL |     box v as Box<dyn SomeTrait + 'static>
-   |     ^^^^^
+LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
+   |     ^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `A: 'static`...
 
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:21:5
    |
-LL |     box v as Box<dyn SomeTrait + 'b>
-   |     ^^^^^
+LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
+   |     ^^^^^^^^^^^
    |
    = help: consider adding an explicit lifetime bound `A: 'b`...
 
index 6e708a5f70fbd828edd106b96fed18ea85042e00..52d18c5d7a6fa1f113d5fedc7b27197265fbe488 100644 (file)
@@ -1,24 +1,24 @@
-#![feature(box_syntax)]
-
 // Test for what happens when a type parameter `A` is closed over into
 // an object. This should yield errors unless `A` (and the object)
 // both have suitable bounds.
 
+
 trait SomeTrait {
     fn get(&self) -> isize;
 }
 
+
 fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
-    box v as Box<dyn SomeTrait + 'static>
+    Box::new(v) as Box<dyn SomeTrait + 'static>
     //~^ ERROR the parameter type `A` may not live long enough
 }
 
 fn make_object2<'a, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'a> {
-    box v as Box<dyn SomeTrait + 'a>
+    Box::new(v) as Box<dyn SomeTrait + 'a>
 }
 
 fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
-    box v as Box<dyn SomeTrait + 'b>
+    Box::new(v) as Box<dyn SomeTrait + 'b>
     //~^ ERROR the parameter type `A` may not live long enough
 }
 
index 50274b066df60039130b9ba55bd0272b0de0f885..063c3b19a19cccc5bb96ea39e08196eb838a6295 100644 (file)
@@ -3,16 +3,16 @@ error[E0310]: the parameter type `A` may not live long enough
    |
 LL | fn make_object1<A: SomeTrait>(v: A) -> Box<dyn SomeTrait + 'static> {
    |                 -- help: consider adding an explicit lifetime bound...: `A: 'static +`
-LL |     box v as Box<dyn SomeTrait + 'static>
-   |     ^^^^^ ...so that the type `A` will meet its required lifetime bounds
+LL |     Box::new(v) as Box<dyn SomeTrait + 'static>
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
 
 error[E0309]: the parameter type `A` may not live long enough
   --> $DIR/regions-close-over-type-parameter-1.rs:21:5
    |
 LL | fn make_object3<'a, 'b, A: SomeTrait + 'a>(v: A) -> Box<dyn SomeTrait + 'b> {
    |                         -- help: consider adding an explicit lifetime bound...: `A: 'b +`
-LL |     box v as Box<dyn SomeTrait + 'b>
-   |     ^^^^^ ...so that the type `A` will meet its required lifetime bounds
+LL |     Box::new(v) as Box<dyn SomeTrait + 'b>
+   |     ^^^^^^^^^^^ ...so that the type `A` will meet its required lifetime bounds
 
 error: aborting due to 2 previous errors
 
index 2fb9dcc4e9ec77c3c9b5f59c79b59aeaaeee8ab3..c2bd3bbf823d2b6f206a88cb492f7ab77762dc2b 100644 (file)
@@ -6,8 +6,8 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait +
    |                    |
    |                    lifetime `'a` defined here
 LL |     // A outlives 'a AND 'b...but not 'c.
-LL |     box v as Box<dyn SomeTrait + 'a>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c`
+LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'c`
    |
    = help: consider adding the following bound: `'a: 'c`
 
index 26643e08985be6107d873e27a0c481a4d390cbba..fc7696e7e03201e3e9b8fdcaaef36dc1ffc9f056 100644 (file)
@@ -1,23 +1,23 @@
-#![feature(box_syntax)]
-
 // Various tests where we over type parameters with multiple lifetime
 // bounds.
 
+
 trait SomeTrait { fn get(&self) -> isize; }
 
+
 fn make_object_good1<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'a> {
     // A outlives 'a AND 'b...
-    box v as Box<dyn SomeTrait + 'a> // ...hence this type is safe.
+    Box::new(v) as Box<dyn SomeTrait + 'a> // ...hence this type is safe.
 }
 
 fn make_object_good2<'a,'b,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'b> {
     // A outlives 'a AND 'b...
-    box v as Box<dyn SomeTrait + 'b> // ...hence this type is safe.
+    Box::new(v) as Box<dyn SomeTrait + 'b> // ...hence this type is safe.
 }
 
 fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait + 'c> {
     // A outlives 'a AND 'b...but not 'c.
-    box v as Box<dyn SomeTrait + 'a> //~ ERROR cannot infer an appropriate lifetime
+    Box::new(v) as Box<dyn SomeTrait + 'a> //~ ERROR cannot infer an appropriate lifetime
 }
 
 fn main() {
index bf29c76a0f0a8bcee9ea263faeb1c70a23224ec0..0cb0b24f108b0c07392e2028ffb792d3c60a8b30 100644 (file)
@@ -1,8 +1,8 @@
 error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
    |
-LL |     box v as Box<dyn SomeTrait + 'a>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
 note: first, the lifetime cannot outlive the lifetime `'a` as defined on the function body at 18:20...
   --> $DIR/regions-close-over-type-parameter-multiple.rs:18:20
@@ -12,8 +12,8 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait +
 note: ...so that the declared lifetime parameter bounds are satisfied
   --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
    |
-LL |     box v as Box<dyn SomeTrait + 'a>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 note: but, the lifetime must be valid for the lifetime `'c` as defined on the function body at 18:26...
   --> $DIR/regions-close-over-type-parameter-multiple.rs:18:26
    |
@@ -22,8 +22,8 @@ LL | fn make_object_bad<'a,'b,'c,A:SomeTrait+'a+'b>(v: A) -> Box<dyn SomeTrait +
 note: ...so that the types are compatible
   --> $DIR/regions-close-over-type-parameter-multiple.rs:20:5
    |
-LL |     box v as Box<dyn SomeTrait + 'a>
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |     Box::new(v) as Box<dyn SomeTrait + 'a>
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: expected `Box<(dyn SomeTrait + 'c)>`
               found `Box<dyn SomeTrait>`
 
index 4b47ed8c6aeb7120ed4c56888112208bafa0d365..48aad9481bbead1072a0786f2519670856924fbe 100644 (file)
@@ -2,8 +2,6 @@
 // A test where we (successfully) close over a reference into
 // an object.
 
-#![feature(box_syntax)]
-
 trait SomeTrait { fn get(&self) -> isize; }
 
 impl<'a> SomeTrait for &'a isize {
@@ -13,7 +11,7 @@ fn get(&self) -> isize {
 }
 
 fn make_object<'a,A:SomeTrait+'a>(v: A) -> Box<dyn SomeTrait+'a> {
-    box v as Box<dyn SomeTrait+'a>
+    Box::new(v) as Box<dyn SomeTrait+'a>
 }
 
 fn main() {
index 0a7e6625c735392e8d5b1ee5d78bb634bbbacb8a..a6cb56e3156d445209b39d98425bd27ac0faadb9 100644 (file)
@@ -3,7 +3,6 @@
 // Issue #3148.
 
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 struct A {
     value: B
@@ -81,7 +80,7 @@ pub fn main() {
                          v2: [23, 24, 25],
                          v3: vec![26, 27, 28],
                          v4: C { f: 29 },
-                         v5: box C { f: 30 },
+                         v5: Box::new(C { f: 30 }),
                          v6: Some(C { f: 31 })}};
 
     let p = get_v1(&a);
index 276a64b8e9a7bb537ddf85549d93d2815f706a64..a28bd14ba88f6ca949e79912591923f6adf0789c 100644 (file)
@@ -2,8 +2,6 @@
 // Tests that you can use an early-bound lifetime parameter as
 // on of the generic parameters in a trait.
 
-#![feature(box_syntax)]
-
 trait Trait<'a> {
     fn long(&'a self) -> isize;
     fn short<'b>(&'b self) -> isize;
@@ -72,7 +70,7 @@ fn short<'b>(&'b self) -> isize {
 
 impl<'t> MakerTrait for Box<dyn Trait<'t>+'static> {
     fn mk() -> Box<dyn Trait<'t>+'static> {
-        let tup: Box<(isize, isize)> = box (4,5);
+        let tup: Box<(isize, isize)> = Box::new((4,5));
         tup as Box<dyn Trait>
     }
 }
index fd4690463e6667a6d8682807a9d63f9882e0ebfb..65f4c1b6a64877265ed987f2a8a67607a9a5e0fe 100644 (file)
@@ -1,10 +1,8 @@
 // run-pass
-#![feature(box_syntax)]
-
 fn foo(x: &usize) -> &usize { x }
 fn bar(x: &usize) -> usize { *x }
 
 pub fn main() {
-    let p: Box<_> = box 3;
+    let p: Box<_> = Box::new(3);
     assert_eq!(bar(foo(&*p)), 3);
 }
index f0ecc5de5456786169385ffa06ecc36cb2db0e59..dca26742dacc598cbb3e03472dbdc61e5d60733b 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn borrow<T>(x: &T) -> &T {x}
 
 pub fn main() {
-    let x: Box<_> = box 3;
+    let x: Box<_> = Box::new(3);
     loop {
         let y = borrow(&*x);
         assert_eq!(*x, *y);
index 453973d9c58c34c4b8bb568654e42b6d4fd26aa4..b4a050bf1ede08af06e7666a382a95d6ec9bf54d 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 struct Point {x: isize, y: isize}
 
@@ -9,7 +8,7 @@ fn x_coord(p: &Point) -> &isize {
 }
 
 pub fn main() {
-    let p: Box<_> = box Point {x: 3, y: 4};
+    let p: Box<_> = Box::new(Point {x: 3, y: 4});
     let xc = x_coord(&*p);
     assert_eq!(*xc, 3);
 }
index c8106f32c65c257f68071d359c1484d6276d83b4..3852a14d9f98e8a113f98225cca04ca4f7628ac4 100644 (file)
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
     fn explicit() {
         fn test<F>(_x: Option<Box<F>>) where F: FnMut(Box<dyn for<'a> FnMut(&'a isize)>) {}
-        test(Some(box |_f: Box<dyn for<'a> FnMut(&'a isize)>| {}));
+        test(Some(Box::new(|_f: Box<dyn for<'a> FnMut(&'a isize)>| {})));
     }
 
     // The code below is shorthand for the code above (and more likely
     // to represent what one encounters in practice).
     fn implicit() {
         fn test<F>(_x: Option<Box<F>>) where F: FnMut(Box<dyn        FnMut(&   isize)>) {}
-        test(Some(box |_f: Box<dyn        FnMut(&   isize)>| {}));
+        test(Some(Box::new(|_f: Box<dyn        FnMut(&   isize)>| {})));
     }
 
     explicit();
index d1cbd279b65a52432f1a74e8bd492ca7912c6826..3df529c9f0dae8909d60e14eda1579abdab6edb4 100644 (file)
@@ -1,11 +1,11 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
+
 
 fn arg_item(box ref x: Box<isize>) -> &'static isize {
     x //~ ERROR cannot return value referencing function parameter
 }
 
-fn with<R, F>(f: F) -> R where F: FnOnce(Box<isize>) -> R { f(box 3) }
+fn with<R, F>(f: F) -> R where F: FnOnce(Box<isize>) -> R { f(Box::new(3)) }
 
 fn arg_closure() -> &'static isize {
     with(|box ref x| x) //~ ERROR cannot return value referencing function parameter
index aec05161c1afbca2d57e7fdf7c7836db6136b889..b1bdb813ac6aad8215a2262c4dafc1ec681b6fae 100644 (file)
@@ -9,8 +9,6 @@
 // changes were caught. However, those uses in the compiler could
 // easily get changed or refactored away in the future.
 
-#![feature(box_syntax)]
-
 struct Ctxt<'tcx> {
     x: &'tcx Vec<isize>
 }
index 9169d457d40514dda3334cfa23f844923d76d17c..94ffb85c9c9c5d214a2f3b7df49da18e2be0fde5 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 // Issue #12470.
 
 trait X {
@@ -31,9 +29,11 @@ fn make_a(p: &dyn X) -> A {
 }
 
 fn make_make_a<'a>() -> A<'a> {
-    let b: Box<B> = box B {
+
+    let b: Box<B> = Box::new(B {
         i: 1,
-    };
+    });
+
     let bb: &B = &*b;
     make_a(bb) //~ ERROR cannot return value referencing local data `*b`
 }
diff --git a/src/test/ui/resolve/suggest-path-for-tuple-struct.rs b/src/test/ui/resolve/suggest-path-for-tuple-struct.rs
new file mode 100644 (file)
index 0000000..c8bc3e7
--- /dev/null
@@ -0,0 +1,26 @@
+mod module {
+    pub struct SomeTupleStruct(u8);
+    pub struct SomeRegularStruct {
+        foo: u8
+    }
+
+    impl SomeTupleStruct {
+        pub fn new() -> Self {
+            Self(0)
+        }
+    }
+    impl SomeRegularStruct {
+        pub fn new() -> Self {
+            Self { foo: 0 }
+        }
+    }
+}
+
+use module::{SomeTupleStruct, SomeRegularStruct};
+
+fn main() {
+    let _ = SomeTupleStruct.new();
+    //~^ ERROR expected value, found struct `SomeTupleStruct`
+    let _ = SomeRegularStruct.new();
+    //~^ ERROR expected value, found struct `SomeRegularStruct`
+}
diff --git a/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr b/src/test/ui/resolve/suggest-path-for-tuple-struct.stderr
new file mode 100644 (file)
index 0000000..957045c
--- /dev/null
@@ -0,0 +1,19 @@
+error[E0423]: expected value, found struct `SomeTupleStruct`
+  --> $DIR/suggest-path-for-tuple-struct.rs:22:13
+   |
+LL |     let _ = SomeTupleStruct.new();
+   |             ^^^^^^^^^^^^^^^----
+   |             |
+   |             help: use the path separator to refer to an item: `SomeTupleStruct::new`
+
+error[E0423]: expected value, found struct `SomeRegularStruct`
+  --> $DIR/suggest-path-for-tuple-struct.rs:24:13
+   |
+LL |     let _ = SomeRegularStruct.new();
+   |             ^^^^^^^^^^^^^^^^^----
+   |             |
+   |             help: use the path separator to refer to an item: `SomeRegularStruct::new`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0423`.
index b3be41599a54534134980f9aea93d0bb9e546847..0d1cded36b62d7b5e4dc058bb8e88cb072d03b3d 100644 (file)
@@ -1,11 +1,11 @@
 // run-pass
 #![allow(unreachable_patterns)]
-#![feature(box_syntax, box_patterns)]
+#![feature(box_patterns)]
 
 struct Foo{}
 
 pub fn main() {
-    let b = box Foo{};
+    let b = Box::new(Foo{});
     let box f = &b;
     let _: &Foo = f;
 
index 03f72a5513c20b294ca8b3ec2af35732612c5cba..8f6bed3b0cd6e01ba7b5f0e8c1b0ed2050a3f546 100644 (file)
@@ -1,6 +1,5 @@
 // run-pass
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 #[derive(Copy, Clone)]
 struct LM { resize_at: usize, size: usize }
@@ -24,6 +23,6 @@ pub fn len(&mut self) -> usize {
 }
 
 pub fn main() {
-    let mut m: Box<_> = box linear_map::<(),()>();
+    let mut m: Box<_> = Box::new(linear_map::<(),()>());
     assert_eq!(m.len(), 0);
 }
index 0050bc7124d7183da5136ceb4b99d802b8e52700..250ea12e57c81f2345d773a42621aa733d9b5dfc 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 trait Foo {
     fn f(self: Box<Self>);
@@ -16,7 +15,7 @@ fn f(self: Box<S>) {
 }
 
 pub fn main() {
-    let x = box S { x: 3 };
+    let x = Box::new(S { x: 3 });
     let y = x as Box<dyn Foo>;
     y.f();
 }
index 6d19d33b6fee9bed347f6b25c55eb7ab8c95c607..873c3621a3bce35dfa4563db8b91894296c6a077 100644 (file)
@@ -3,8 +3,6 @@
 #![allow(non_camel_case_types)]
 #![allow(non_upper_case_globals)]
 
-#![feature(box_syntax)]
-
 static tau: f64 = 2.0*3.14159265358979323;
 
 struct Point {x: f64, y: f64}
@@ -64,7 +62,7 @@ pub fn spam(self) -> isize { self.x.a }
 impl Nus for thing { fn f(&self) {} }
 
 pub fn main() {
-    let y: Box<_> = box thing(A {a: 10});
+    let y: Box<_> = Box::new(thing(A {a: 10}));
     assert_eq!(y.clone().bar(), 10);
     assert_eq!(y.quux(), 10);
 
index 23d513e3fac075b5671cd23be996c936b859ac21..7eed3f056a25f10fb5d320478daea6bb62474711 100644 (file)
@@ -5,8 +5,6 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 struct Foo;
 
 // Test uses on inherent impl.
@@ -57,14 +55,14 @@ fn bar(_x: Self, _y: &Self, _z: Box<Self>, _: Self::SuperQux) -> Self {
         let _: Self::SuperQux = true;
         let _: <Self as SuperBar>::SuperQux = true;
 
-        box Baz { f: 42 }
+        Box::new(Baz { f: 42 })
     }
 }
 
 fn main() {
-    let _: Foo = Foo::foo(Foo, &Foo, box Foo);
-    let _: Box<Baz<isize>> = Bar::bar(box Baz { f: 42 },
-                                      &box Baz { f: 42 },
-                                      box box Baz { f: 42 },
+    let _: Foo = Foo::foo(Foo, &Foo, Box::new(Foo));
+    let _: Box<Baz<isize>> = Bar::bar(Box::new(Baz { f: 42 }),
+                                      &Box::new(Baz { f: 42 }),
+                                      Box::new(Box::new(Baz { f: 42 })),
                                       true);
 }
index 82c5f58f0208fa6520782e9f877f90a03ceac5d1..45e122c8d77a0eca273f9a1ec2030e10e9da342b 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct X {
     a: isize
@@ -30,7 +29,7 @@ pub fn main() {
     let new_x = x.change();
     assert_eq!(new_x.a, 55);
 
-    let x: Box<_> = box new_x;
+    let x: Box<_> = Box::new(new_x);
     let new_x = x.change_again();
     assert_eq!(new_x.a, 45);
 }
index 88e8614683227117abbb41dac3d7d69e87dc998b..9595ebf9601fb89e335b9233e0cb215f3236742d 100644 (file)
@@ -2,13 +2,12 @@
 // Ensure assigning an owned or managed variable to itself works. In particular,
 // that we do not glue_drop before we glue_take (#3290).
 
-#![feature(box_syntax)]
 #![allow(dead_code)]
 
 use std::rc::Rc;
 
 pub fn main() {
-   let mut x: Box<_> = box 3;
+   let mut x: Box<_> = Box::new(3);
    x = x;
    assert_eq!(*x, 3);
 
index 0aaaa7d47c3c1eef0bcf8066e2e08218136a495b..d83af14d354fbe8d7dd79d30bb9ab5018efcd8d0 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 #![allow(dead_code)]
 
 #[derive(Copy, Clone)]
@@ -37,13 +36,13 @@ fn baz(self: Bar<T>, x: isize) -> isize {
 }
 
 fn main() {
-    let foo: Box<_> = box Foo {
+    let foo: Box<_> = Box::new(Foo {
         f: 1,
-    };
+    });
     println!("{} {} {}", foo.foo(2), foo.bar(2), foo.baz(2));
-    let bar: Box<_> = box Bar {
+    let bar: Box<_> = Box::new(Bar {
         f: 1,
-    };
+    });
     println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2));
     let bar: Box<Bar<isize>> = bar;
     println!("{} {} {}", bar.foo(2), bar.bar(2), bar.baz(2));
index 695f06ecddafb40887d20784a038737768b34e46..71e57d8c1fa1b50471bb621acf9b07b5ae3a0b25 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct X {
     a: isize
@@ -17,7 +16,7 @@ fn change(mut self: Box<X>) -> Box<X> {
 }
 
 pub fn main() {
-    let x: Box<_> = box X { a: 32 };
+    let x: Box<_> = Box::new(X { a: 32 });
     let new_x = x.change();
     assert_eq!(new_x.a, 55);
 }
index e74620f8900c08922d1bb81abc0ff2788e913d69..66fd68a9f236216f3a0e0f001a6d50afbf5b7fdb 100644 (file)
@@ -1,9 +1,9 @@
 // Test that shadowed lifetimes generate an error.
 
-#![feature(box_syntax)]
 
 struct Foo<T>(T);
 
+
 impl<T> Foo<T> {
     fn shadow_in_method<T>(&self) {}
     //~^ ERROR the name `T` is already used
index c461f825d99a481c30546bb0ca1d3f735c32faad..7920ae0b26ccaf6587a26c22ff5c286cf42cd2d4 100644 (file)
@@ -1,8 +1,8 @@
-#![feature(box_syntax)]
-
 fn test(_x: &mut String) {}
+
 fn test2(_x: &mut i32) {}
 
+
 fn main() {
     let x: usize = String::new();
     //~^ ERROR E0308
@@ -14,7 +14,7 @@ fn main() {
     test2(&y);
     //~^ ERROR E0308
     let f;
-    f = box f;
+    f = Box::new(f);
     //~^ ERROR E0308
 
     let s = &mut String::new();
index 2487684c1dd7f62f74c3b1cf4074e5ef8fe9816d..74caae8645c1d01e70d24307132e147ed9d459a9 100644 (file)
@@ -37,13 +37,10 @@ LL |     test2(&y);
 error[E0308]: mismatched types
   --> $DIR/coerce-suggestions.rs:17:9
    |
-LL |     f = box f;
-   |         ^^^^^ cyclic type of infinite size
-   |
-help: try using a conversion method
-   |
-LL |     f = (box f).to_string();
-   |         +     +++++++++++++
+LL |     f = Box::new(f);
+   |         ^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
+   |         |
+   |         cyclic type of infinite size
 
 error[E0308]: mismatched types
   --> $DIR/coerce-suggestions.rs:21:9
index 0f6472b05f7aae7a228983c17c5ebf6bed70db45..d9c08fbdd0f15e2521ad5967f3b3a9abbd9c77b1 100644 (file)
@@ -1,10 +1,10 @@
-#![feature(box_syntax, unboxed_closures)]
+#![feature(unboxed_closures)]
 
 fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 
 fn main() {
     let r = {
-        let x: Box<_> = box 42;
+        let x: Box<_> = Box::new(42);
         let f = to_fn_once(move|| &x); //~ ERROR cannot return reference to local data `x`
         f()
     };
index e34f84683bbc7777b994f55dc7f737c7e87dfeb1..16b4cc2586273f98f1fc0c8a67ecf4996b7cc052 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 fn id<T>(x: T) -> T { x }
 
 trait Foo { }
@@ -7,10 +5,12 @@ trait Foo { }
 impl<'a> Foo for &'a isize { }
 
 fn main() {
+
     let blah;
+
     {
         let ss: &isize = &id(1);
         //~^ ERROR temporary value dropped while borrowed
-        blah = box ss as Box<dyn Foo>;
+        blah = Box::new(ss) as Box<dyn Foo>;
     }
 }
index 29083154b899130abb98560220adf58b22f1ab2e..aca3972cb6c55dc5a127d3c73dc4f2f52d10ef76 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 // Test for what happens when a type parameter `A` is closed over into
 // an object. This should yield errors unless `A` (and the object)
 // both have suitable bounds.
@@ -7,14 +5,16 @@
 trait Foo { fn get(&self); }
 
 impl<A> Foo for A {
-    fn get(&self) { }
+    fn get(&self) {
+    }
 }
 
 fn repeater3<'a,A:'a>(v: A) -> Box<dyn Foo + 'a> {
-    box v as Box<dyn Foo+'a>
+    Box::new(v) as Box<dyn Foo+'a>
 }
 
 fn main() {
+
     // Error results because the type of is inferred to be
     // ~Repeat<&'blk isize> where blk is the lifetime of the block below.
 
index f133133b3365038fbafbd29a56a45544aa05473e..d70706e5764f636bd48ab1e9ea68cf9269f9276d 100644 (file)
@@ -1,12 +1,12 @@
-#![feature(box_syntax)]
-
 fn id<T>(x: T) -> T { x }
 
 fn f<T:'static>(_: T) {}
 
 fn main() {
-    let x: Box<_> = box 3;
+
+    let x: Box<_> = Box::new(3);
     f(x);
+
     let x = &id(3); //~ ERROR temporary value dropped while borrowed
     f(x);
 }
index bf1ba8a643fea8f89950724a933b5d34598552da..f870096fdd44a798411b1a8f6aee5898848f1a12 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // aux-build:cci_class_cast.rs
 
-#![feature(box_syntax)]
-
 extern crate cci_class_cast;
 
 use std::string::ToString;
@@ -15,6 +13,6 @@ fn print_out(thing: Box<dyn ToString>, expected: String) {
 }
 
 pub fn main() {
-  let nyan: Box<dyn ToString> = box cat(0, 2, "nyan".to_string()) as Box<dyn ToString>;
+  let nyan: Box<dyn ToString> = Box::new(cat(0, 2, "nyan".to_string())) as Box<dyn ToString>;
   print_out(nyan, "nyan".to_string());
 }
index 947690b51f422ab70ec1bfb46dd4eb83adbb1321..3d6da1cc280243d2208be1338bcf636345fb0689 100644 (file)
@@ -2,8 +2,6 @@
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
 
-#![feature(box_syntax)]
-
 use std::fmt;
 
 struct cat {
@@ -60,6 +58,6 @@ fn print_out(thing: Box<dyn ToString>, expected: String) {
 }
 
 pub fn main() {
-  let nyan: Box<dyn ToString> = box cat(0, 2, "nyan".to_string()) as Box<dyn ToString>;
+  let nyan: Box<dyn ToString> = Box::new(cat(0, 2, "nyan".to_string())) as Box<dyn ToString>;
   print_out(nyan, "nyan".to_string());
 }
index 77419e1132dc9ce0fd2fe1681c0d5c6feb0e0652..53892a4e0aeb46418848d9ef82f24e4d4a124fbe 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 /*!
  * This is a regression test for a bug in LLVM, fixed in upstream r179587,
@@ -9,7 +8,7 @@
 
 enum List<X> { Nil, Cons(X, Box<List<X>>) }
 pub fn main() {
-    match List::Cons(10, box List::Nil) {
+    match List::Cons(10, Box::new(List::Nil)) {
         List::Cons(10, _) => {}
         List::Nil => {}
         _ => panic!()
index 71779ecb7299f1f14bd0a2cc609a6dc73127bdc0..001af27b2484e9415844e8a628579f54c5fb4e47 100644 (file)
@@ -22,10 +22,8 @@ error[E0277]: the trait bound `S: Trait` is not satisfied
   --> $DIR/imm-ref-trait-object-literal.rs:13:7
    |
 LL |   foo(s);
-   |   --- ^
-   |   |   |
-   |   |   expected an implementor of trait `Trait`
-   |   |   help: consider mutably borrowing here: `&mut s`
+   |   --- ^ expected an implementor of trait `Trait`
+   |   |
    |   required by a bound introduced by this call
    |
 note: required by a bound in `foo`
@@ -33,6 +31,10 @@ note: required by a bound in `foo`
    |
 LL | fn foo<X: Trait>(_: X) {}
    |           ^^^^^ required by this bound in `foo`
+help: consider mutably borrowing here
+   |
+LL |   foo(&mut s);
+   |       ++++
 
 error: aborting due to 2 previous errors
 
index 93251b2c8dbfc62d91d8102b74300dec54412d43..29ba39cbe109c5ecf84f32459c8b4d60e493ffbc 100644 (file)
@@ -2,14 +2,16 @@ error[E0277]: expected a `FnMut<(char,)>` closure, found `String`
   --> $DIR/issue-62843.rs:4:32
    |
 LL |     println!("{:?}", line.find(pattern));
-   |                           ---- ^^^^^^^
-   |                           |    |
-   |                           |    expected an implementor of trait `Pattern<'_>`
-   |                           |    help: consider borrowing here: `&pattern`
+   |                           ---- ^^^^^^^ expected an implementor of trait `Pattern<'_>`
+   |                           |
    |                           required by a bound introduced by this call
    |
    = note: the trait bound `String: Pattern<'_>` is not satisfied
    = note: required because of the requirements on the impl of `Pattern<'_>` for `String`
+help: consider borrowing here
+   |
+LL |     println!("{:?}", line.find(&pattern));
+   |                                +
 
 error: aborting due to previous error
 
index 0448f0719589dceeceac3c3b383d90cf9eee1bf5..c54be7f5dff0d9497668de34e60c7a8d062cf45c 100644 (file)
@@ -1,5 +1,5 @@
 // edition:2018
-// compile-flags: -Cincremental=tmp/issue-72766
+// incremental
 
 pub struct SadGirl;
 
index c1a7a2e101d62476c8951efb94d3cd1d9201bf71..2c54ea6724505f9217ec07e9aebe5423c8c5b826 100644 (file)
@@ -2,10 +2,8 @@ error[E0277]: the trait bound `i32: Tr` is not satisfied
   --> $DIR/issue-84973-2.rs:11:9
    |
 LL |     foo(a);
-   |     --- ^
-   |     |   |
-   |     |   expected an implementor of trait `Tr`
-   |     |   help: consider mutably borrowing here: `&mut a`
+   |     --- ^ expected an implementor of trait `Tr`
+   |     |
    |     required by a bound introduced by this call
    |
 note: required by a bound in `foo`
@@ -13,6 +11,10 @@ note: required by a bound in `foo`
    |
 LL | fn foo<T: Tr>(i: T) {}
    |           ^^ required by this bound in `foo`
+help: consider mutably borrowing here
+   |
+LL |     foo(&mut a);
+   |         ++++
 
 error: aborting due to previous error
 
index 14b32d8515cd78c82029d5559b79dc693cac2cf9..1f33374eb29dbf9c050c88e5fa4babd9c4a61a92 100644 (file)
@@ -16,10 +16,8 @@ error[E0277]: the trait bound `f32: Tr` is not satisfied
   --> $DIR/issue-84973-negative.rs:11:9
    |
 LL |     bar(b);
-   |     --- ^
-   |     |   |
-   |     |   expected an implementor of trait `Tr`
-   |     |   help: consider borrowing here: `&b`
+   |     --- ^ expected an implementor of trait `Tr`
+   |     |
    |     required by a bound introduced by this call
    |
 note: required by a bound in `bar`
@@ -27,6 +25,10 @@ note: required by a bound in `bar`
    |
 LL | fn bar<T: Tr>(t: T) {}
    |           ^^ required by this bound in `bar`
+help: consider borrowing here
+   |
+LL |     bar(&b);
+   |         +
 
 error: aborting due to 2 previous errors
 
index 169d0cccb43efe05e0c3df6e8f4e75d19489a961..16a28c73aa7247db0184c755bfb8ab880f9359d1 100644 (file)
@@ -2,10 +2,8 @@ error[E0277]: the trait bound `Fancy: SomeTrait` is not satisfied
   --> $DIR/issue-84973.rs:6:24
    |
 LL |     let o = Other::new(f);
-   |             ---------- ^
-   |             |          |
-   |             |          expected an implementor of trait `SomeTrait`
-   |             |          help: consider borrowing here: `&f`
+   |             ---------- ^ expected an implementor of trait `SomeTrait`
+   |             |
    |             required by a bound introduced by this call
    |
 note: required by `Other::<'a, G>::new`
@@ -13,6 +11,10 @@ note: required by `Other::<'a, G>::new`
    |
 LL |     pub fn new(g: G) -> Self {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+   |
+LL |     let o = Other::new(&f);
+   |                        +
 
 error: aborting due to previous error
 
index 018f62e783daf4bcc995691ee0071d0b77d407fd..0275fd475d8c6a1f5363b5ba7a807884a90c6fa2 100644 (file)
@@ -2,10 +2,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation
   --> $DIR/slice-issue-87994.rs:3:12
    |
 LL |   for _ in v[1..] {
-   |            ^^^^^^
-   |            |
-   |            expected an implementor of trait `IntoIterator`
-   |            help: consider borrowing here: `&v[1..]`
+   |            ^^^^^^ expected an implementor of trait `IntoIterator`
    |
    = note: the trait bound `[i32]: IntoIterator` is not satisfied
    = note: required because of the requirements on the impl of `IntoIterator` for `[i32]`
@@ -14,15 +11,18 @@ note: required by `into_iter`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+   |
+LL |   for _ in &v[1..] {
+   |            +
+LL |   for _ in &mut v[1..] {
+   |            ++++
 
 error[E0277]: `[i32]` is not an iterator
   --> $DIR/slice-issue-87994.rs:3:12
    |
 LL |   for _ in v[1..] {
-   |            ^^^^^^
-   |            |
-   |            expected an implementor of trait `IntoIterator`
-   |            help: consider borrowing here: `&v[1..]`
+   |            ^^^^^^ expected an implementor of trait `IntoIterator`
    |
    = note: the trait bound `[i32]: IntoIterator` is not satisfied
    = note: required because of the requirements on the impl of `IntoIterator` for `[i32]`
@@ -31,15 +31,18 @@ note: required by `into_iter`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+   |
+LL |   for _ in &v[1..] {
+   |            +
+LL |   for _ in &mut v[1..] {
+   |            ++++
 
 error[E0277]: the size for values of type `[K]` cannot be known at compilation time
   --> $DIR/slice-issue-87994.rs:11:13
    |
 LL |   for i2 in v2[1..] {
-   |             ^^^^^^^
-   |             |
-   |             expected an implementor of trait `IntoIterator`
-   |             help: consider borrowing here: `&v2[1..]`
+   |             ^^^^^^^ expected an implementor of trait `IntoIterator`
    |
    = note: the trait bound `[K]: IntoIterator` is not satisfied
    = note: required because of the requirements on the impl of `IntoIterator` for `[K]`
@@ -48,15 +51,18 @@ note: required by `into_iter`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+   |
+LL |   for i2 in &v2[1..] {
+   |             +
+LL |   for i2 in &mut v2[1..] {
+   |             ++++
 
 error[E0277]: `[K]` is not an iterator
   --> $DIR/slice-issue-87994.rs:11:13
    |
 LL |   for i2 in v2[1..] {
-   |             ^^^^^^^
-   |             |
-   |             expected an implementor of trait `IntoIterator`
-   |             help: consider borrowing here: `&v2[1..]`
+   |             ^^^^^^^ expected an implementor of trait `IntoIterator`
    |
    = note: the trait bound `[K]: IntoIterator` is not satisfied
    = note: required because of the requirements on the impl of `IntoIterator` for `[K]`
@@ -65,6 +71,12 @@ note: required by `into_iter`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: consider borrowing here
+   |
+LL |   for i2 in &v2[1..] {
+   |             +
+LL |   for i2 in &mut v2[1..] {
+   |             ++++
 
 error: aborting due to 4 previous errors
 
diff --git a/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.rs
new file mode 100644 (file)
index 0000000..a62669d
--- /dev/null
@@ -0,0 +1,23 @@
+trait Trait {}
+
+struct A;
+struct B;
+struct C;
+
+impl Trait for &A {}
+impl Trait for &mut A {}
+
+impl Trait for &B {}
+
+impl Trait for &mut C {}
+
+fn foo<X: Trait>(_: X) {}
+
+fn main() {
+    let a = A;
+    let b = B;
+    let c = C;
+    foo(a); //~ ERROR the trait bound `A: Trait` is not satisfied
+    foo(b); //~ ERROR the trait bound `B: Trait` is not satisfied
+    foo(c); //~ ERROR the trait bound `C: Trait` is not satisfied
+}
diff --git a/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr b/src/test/ui/suggestions/suggest-imm-mut-trait-implementations.stderr
new file mode 100644 (file)
index 0000000..6583cab
--- /dev/null
@@ -0,0 +1,59 @@
+error[E0277]: the trait bound `A: Trait` is not satisfied
+  --> $DIR/suggest-imm-mut-trait-implementations.rs:20:9
+   |
+LL |     foo(a);
+   |     --- ^ expected an implementor of trait `Trait`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11
+   |
+LL | fn foo<X: Trait>(_: X) {}
+   |           ^^^^^ required by this bound in `foo`
+help: consider borrowing here
+   |
+LL |     foo(&a);
+   |         +
+LL |     foo(&mut a);
+   |         ++++
+
+error[E0277]: the trait bound `B: Trait` is not satisfied
+  --> $DIR/suggest-imm-mut-trait-implementations.rs:21:9
+   |
+LL |     foo(b);
+   |     --- ^ expected an implementor of trait `Trait`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11
+   |
+LL | fn foo<X: Trait>(_: X) {}
+   |           ^^^^^ required by this bound in `foo`
+help: consider borrowing here
+   |
+LL |     foo(&b);
+   |         +
+
+error[E0277]: the trait bound `C: Trait` is not satisfied
+  --> $DIR/suggest-imm-mut-trait-implementations.rs:22:9
+   |
+LL |     foo(c);
+   |     --- ^ expected an implementor of trait `Trait`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `foo`
+  --> $DIR/suggest-imm-mut-trait-implementations.rs:14:11
+   |
+LL | fn foo<X: Trait>(_: X) {}
+   |           ^^^^^ required by this bound in `foo`
+help: consider mutably borrowing here
+   |
+LL |     foo(&mut c);
+   |         ++++
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
index 8c40b2a5f11d6420cea7a920cec9121bba3acdbb..1e598b9e709718cd3164434bded57c604e5d1e55 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // ignore-emscripten no threads support
 
-#![feature(box_syntax)]
-
 use std::thread;
 
 pub fn main() { test05(); }
@@ -12,7 +10,7 @@ fn test05_start<F:FnOnce(isize)>(f: F) {
 }
 
 fn test05() {
-    let three: Box<_> = box 3;
+    let three: Box<_> = Box::new(3);
     let fn_to_send = move|n:isize| {
         println!("{}", *three + n); // will copy x into the closure
         assert_eq!(*three, 3);
index 458f5653885e99a4b7bd7f9e596064193d3be12f..a63903778026a42029a723fe7259e7118b9b7657 100644 (file)
@@ -2,15 +2,13 @@
 #![allow(unused_must_use)]
 // ignore-emscripten no threads support
 
-#![feature(box_syntax)]
-
 use std::thread;
 use std::sync::mpsc::channel;
 
 pub fn main() {
     let (tx, rx) = channel::<usize>();
 
-    let x: Box<isize> = box 1;
+    let x: Box<isize> = Box::new(1);
     let x_in_parent = &(*x) as *const isize as usize;
 
     let t = thread::spawn(move || {
index 941f66c056104081da515f7994f1553eb62abd85..a1492c0b98237bcbc50c02d7052517cf780d5eec 100644 (file)
@@ -5,8 +5,6 @@
 
 // ignore-emscripten no threads support
 
-#![feature(box_syntax)]
-
 use std::sync::Arc;
 use std::sync::mpsc::channel;
 use std::thread;
@@ -67,10 +65,11 @@ pub fn main() {
         swim_speed: 998,
         name: "alec_guinness".to_string(),
     };
-    let arc = Arc::new(vec![box catte  as Box<dyn Pet+Sync+Send>,
-                            box dogge1 as Box<dyn Pet+Sync+Send>,
-                            box fishe  as Box<dyn Pet+Sync+Send>,
-                            box dogge2 as Box<dyn Pet+Sync+Send>]);
+    let arc = Arc::new(vec![
+        Box::new(catte)  as Box<dyn Pet+Sync+Send>,
+        Box::new(dogge1) as Box<dyn Pet+Sync+Send>,
+        Box::new(fishe)  as Box<dyn Pet+Sync+Send>,
+        Box::new(dogge2) as Box<dyn Pet+Sync+Send>]);
     let (tx1, rx1) = channel();
     let arc1 = arc.clone();
     let t1 = thread::spawn(move|| { check_legs(arc1); tx1.send(()); });
index cba33af1f1aca1f9b8221b5bdd8c912c630c8ce6..e62742bac5c74a42be062055b33cffd58253b0bf 100644 (file)
@@ -2,7 +2,6 @@
 #![allow(dead_code)]
 #![allow(unused_mut)]
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 
 use std::io::{self, Write};
 
index a9c194486fecb93e2ebdb0cdc8d590951998f231..dd882dce6663573b2525580c161a17f20255bd0d 100644 (file)
@@ -3,7 +3,6 @@
 // blanket impl for T:Copy coexists with an impl for Box<T>, because
 // Box does not impl Copy.
 
-#![feature(box_syntax)]
 
 trait Get {
     fn get(&self) -> Self;
@@ -20,7 +19,7 @@ fn get(&self) -> T { self.copy() }
 }
 
 impl Get for Box<i32> {
-    fn get(&self) -> Box<i32> { box get_it(&**self) }
+    fn get(&self) -> Box<i32> { Box::new(get_it(&**self)) }
 }
 
 fn get_it<T:Get>(t: &T) -> T {
index 8859fbe6afb7b4ef01c5a3595d30828d8fe61866..07d92f8f8a0164e9674c9e1bd334ff19949c8428 100644 (file)
@@ -1,7 +1,5 @@
 // run-pass
 
-#![feature(box_syntax)]
-
 use std::collections::HashMap;
 
 trait Graph<Node, Edge> {
@@ -19,6 +17,6 @@ fn g(&self, _e: isize) {
 }
 
 pub fn main() {
-    let g : Box<HashMap<isize,isize>> = box HashMap::new();
+    let g : Box<HashMap<isize,isize>> = Box::new(HashMap::new());
     let _g2 : Box<dyn Graph<isize,isize>> = g as Box<dyn Graph<isize,isize>>;
 }
index 23b91f924b553055f6562153a2904bdd66224b63..8adb06ba3d04e0da04775b2e84c544f46077b678 100644 (file)
@@ -2,8 +2,6 @@
 #![allow(non_snake_case)]
 #![allow(non_camel_case_types)]
 
-#![feature(box_syntax)]
-
 trait repeat<A> { fn get(&self) -> A; }
 
 impl<A:Clone + 'static> repeat<A> for Box<A> {
@@ -13,11 +11,11 @@ fn get(&self) -> A {
 }
 
 fn repeater<A:Clone + 'static>(v: Box<A>) -> Box<dyn repeat<A>+'static> {
-    box v as Box<dyn repeat<A>+'static> // No
+    Box::new(v) as Box<dyn repeat<A>+'static> // No
 }
 
 pub fn main() {
     let x = 3;
-    let y = repeater(box x);
+    let y = repeater(Box::new(x));
     assert_eq!(x, y.get());
 }
index 790e2a81c3a8c0efcdd5ffa6b76b301b866b29b0..8059a8ca71e43b0697eda08692317a7f2c6564f2 100644 (file)
@@ -61,10 +61,8 @@ error[E0277]: `dummy2::TestType` cannot be sent between threads safely
   --> $DIR/negated-auto-traits-error.rs:48:13
    |
 LL |     is_send(Box::new(TestType));
-   |     ------- ^^^^^^^^^^^^^^^^^^
-   |     |       |
-   |     |       expected an implementor of trait `Send`
-   |     |       help: consider borrowing here: `&Box::new(TestType)`
+   |     ------- ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Send`
+   |     |
    |     required by a bound introduced by this call
    |
    = note: the trait bound `dummy2::TestType: Send` is not satisfied
@@ -75,6 +73,10 @@ note: required by a bound in `is_send`
    |
 LL | fn is_send<T: Send>(_: T) {}
    |               ^^^^ required by this bound in `is_send`
+help: consider borrowing here
+   |
+LL |     is_send(&Box::new(TestType));
+   |             +
 
 error[E0277]: `dummy3::TestType` cannot be sent between threads safely
   --> $DIR/negated-auto-traits-error.rs:56:13
@@ -102,10 +104,8 @@ error[E0277]: `main::TestType` cannot be sent between threads safely
   --> $DIR/negated-auto-traits-error.rs:66:13
    |
 LL |     is_sync(Outer2(TestType));
-   |     ------- ^^^^^^^^^^^^^^^^
-   |     |       |
-   |     |       expected an implementor of trait `Sync`
-   |     |       help: consider borrowing here: `&Outer2(TestType)`
+   |     ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Sync`
+   |     |
    |     required by a bound introduced by this call
    |
    = note: the trait bound `main::TestType: Sync` is not satisfied
@@ -119,6 +119,12 @@ note: required by a bound in `is_sync`
    |
 LL | fn is_sync<T: Sync>(_: T) {}
    |               ^^^^ required by this bound in `is_sync`
+help: consider borrowing here
+   |
+LL |     is_sync(&Outer2(TestType));
+   |             +
+LL |     is_sync(&mut Outer2(TestType));
+   |             ++++
 
 error: aborting due to 7 previous errors
 
index b92a2ab7b4bc2414ab9aaab2517088df6652b372..86a2094eee098578e4562e83dd2a1de2aeac7196 100644 (file)
@@ -4,8 +4,6 @@
 // Testing creating two vtables with the same self type, but different
 // traits.
 
-#![feature(box_syntax)]
-
 use std::any::Any;
 
 trait Wrap {
@@ -27,7 +25,7 @@ fn is<T:Any>(x: &dyn Any) -> bool {
 }
 
 fn main() {
-    let x = box 22isize as Box<dyn Wrap>;
+    let x = Box::new(22isize) as Box<dyn Wrap>;
     println!("x={}", x.get());
     let y = x.wrap();
 }
index c18754302b75b279af7165e3398a87cfdb5ac3ea..e5a96af3810de4121ee202554f81721b9b0dd5ca 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // test for #8664
 
-#![feature(box_syntax)]
-
 use std::marker;
 
 pub trait Trait2<A> {
@@ -38,6 +36,6 @@ fn method(&self, _x: Type<(u8,V)>) -> isize { 0 }
 }
 
 pub fn main() {
-    let a = box () as Box<dyn Trait<u8, u8>>;
+    let a = Box::new(()) as Box<dyn Trait<u8, u8>>;
     assert_eq!(a.method(Type::Constant((1, 2))), 0);
 }
index 183c779607c9510a09c1e948ea9811443e65b2cf..342928e882a556e0e9a8958041284e945a14ee6a 100644 (file)
@@ -1,6 +1,6 @@
-#![feature(box_syntax)]
-
 #[allow(non_camel_case_types)]
+
+
 trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
 impl bar for i32 { fn dup(&self) -> i32 { *self } fn blah<X>(&self) {} }
 impl bar for u32 { fn dup(&self) -> u32 { *self } fn blah<X>(&self) {} }
@@ -10,7 +10,8 @@ fn main() {
     //~^ ERROR this associated function takes 0 generic arguments but 1
     10.blah::<i32, i32>();
     //~^ ERROR this associated function takes 1 generic argument but 2
-    (box 10 as Box<dyn bar>).dup();
+    (Box::new(10) as Box<dyn bar>).dup();
     //~^ ERROR E0038
     //~| ERROR E0038
+    //~| ERROR E0038
 }
index d943b48fd0082115045e051a5f884cf56b545fe3..77ea4e4e974ebf06c36175f8cd48d50821840f0c 100644 (file)
@@ -27,10 +27,27 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    |                                       ^^^^ -
 
 error[E0038]: the trait `bar` cannot be made into an object
-  --> $DIR/test-2.rs:13:16
+  --> $DIR/test-2.rs:13:22
    |
-LL |     (box 10 as Box<dyn bar>).dup();
-   |                ^^^^^^^^^^^^ `bar` cannot be made into an object
+LL |     (Box::new(10) as Box<dyn bar>).dup();
+   |                      ^^^^^^^^^^^^ `bar` cannot be made into an object
+   |
+note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
+  --> $DIR/test-2.rs:4:30
+   |
+LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
+   |       ---                    ^^^^     ^^^^ ...because method `blah` has generic type parameters
+   |       |                      |
+   |       |                      ...because method `dup` references the `Self` type in its return type
+   |       this trait cannot be made into an object...
+   = help: consider moving `dup` to another trait
+   = help: consider moving `blah` to another trait
+
+error[E0038]: the trait `bar` cannot be made into an object
+  --> $DIR/test-2.rs:13:5
+   |
+LL |     (Box::new(10) as Box<dyn bar>).dup();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `bar` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/test-2.rs:4:30
@@ -46,8 +63,8 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
 error[E0038]: the trait `bar` cannot be made into an object
   --> $DIR/test-2.rs:13:6
    |
-LL |     (box 10 as Box<dyn bar>).dup();
-   |      ^^^^^^ `bar` cannot be made into an object
+LL |     (Box::new(10) as Box<dyn bar>).dup();
+   |      ^^^^^^^^^^^^ `bar` cannot be made into an object
    |
 note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
   --> $DIR/test-2.rs:4:30
@@ -62,7 +79,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); }
    = note: required because of the requirements on the impl of `CoerceUnsized<Box<dyn bar>>` for `Box<{integer}>`
    = note: required by cast to type `Box<dyn bar>`
 
-error: aborting due to 4 previous errors
+error: aborting due to 5 previous errors
 
 Some errors have detailed explanations: E0038, E0107.
 For more information about an error, try `rustc --explain E0038`.
index 277d9eabe4fb2ce7737c333e2da5c1e565854462..6d88002540c1ac43c355241244183a1ec04834fa 100644 (file)
@@ -1,5 +1,5 @@
 // run-pass
-#![feature(box_syntax, trait_upcasting)]
+#![feature(trait_upcasting)]
 #![allow(incomplete_features)]
 
 struct Test {
@@ -8,6 +8,6 @@ struct Test {
 
 fn main() {
     let closure: Box<dyn Fn() + 'static> = Box::new(|| ());
-    let mut test = box Test { func: closure };
+    let mut test = Box::new(Test { func: closure });
     (test.func)();
 }
index 4b42fddaf5c88d7e66dbc66fa5eba3025a131ec2..3d87a089fca3a35299198ae32fc2a12b14654f9f 100644 (file)
@@ -4,8 +4,6 @@
 #![allow(dead_code)]
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 fn p_foo<T>(_pinned: T) { }
 fn s_foo<T>(_shared: T) { }
 fn u_foo<T:Send>(_unique: T) { }
@@ -27,13 +25,13 @@ fn r(i:isize) -> r {
 pub fn main() {
     p_foo(r(10));
 
-    p_foo::<Box<_>>(box r(10));
-    p_foo::<Box<_>>(box 10);
+    p_foo::<Box<_>>(Box::new(r(10)));
+    p_foo::<Box<_>>(Box::new(10));
     p_foo(10);
 
-    s_foo::<Box<_>>(box 10);
+    s_foo::<Box<_>>(Box::new(10));
     s_foo(10);
 
-    u_foo::<Box<_>>(box 10);
+    u_foo::<Box<_>>(Box::new(10));
     u_foo(10);
 }
index 282d51a93df894b19fbc794408d22d1a98ad51b7..f982ad6a0ddc33da33d46d035fe368c166165021 100644 (file)
@@ -3,7 +3,6 @@
 #![allow(non_camel_case_types)]
 #![allow(non_snake_case)]
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 // Example from lkuper's intern talk, August 2012 -- now with static
 // methods!
@@ -59,11 +58,11 @@ pub fn main() {
     assert!(Equal::isEq(&leaf(cyan), &leaf(cyan)));
     assert!(!Equal::isEq(&leaf(cyan), &leaf(yellow)));
 
-    assert!(Equal::isEq(&branch(box leaf(magenta), box leaf(cyan)),
-                &branch(box leaf(magenta), box leaf(cyan))));
+    assert!(Equal::isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))),
+                &branch(Box::new(leaf(magenta)), Box::new(leaf(cyan)))));
 
-    assert!(!Equal::isEq(&branch(box leaf(magenta), box leaf(cyan)),
-                 &branch(box leaf(magenta), box leaf(magenta))));
+    assert!(!Equal::isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan))),
+                 &branch(Box::new(leaf(magenta)), Box::new(leaf(magenta)))));
 
     println!("Assertions all succeeded!");
 }
index 8d1d22eb823004a242156a539fc76af16ec7a931..4400301e61ed7c3797ea306c08a837b22b50b3d0 100644 (file)
@@ -3,7 +3,6 @@
 #![allow(non_camel_case_types)]
 #![allow(non_snake_case)]
 #![allow(dead_code)]
-#![feature(box_syntax)]
 
 // Example from lkuper's intern talk, August 2012.
 use Color::{cyan, magenta, yellow, black};
@@ -55,11 +54,11 @@ pub fn main() {
     assert!(leaf(cyan).isEq(&leaf(cyan)));
     assert!(!leaf(cyan).isEq(&leaf(yellow)));
 
-    assert!(branch(box leaf(magenta), box leaf(cyan))
-        .isEq(&branch(box leaf(magenta), box leaf(cyan))));
+    assert!(branch(Box::new(leaf(magenta)), Box::new(leaf(cyan)))
+        .isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(cyan)))));
 
-    assert!(!branch(box leaf(magenta), box leaf(cyan))
-        .isEq(&branch(box leaf(magenta), box leaf(magenta))));
+    assert!(!branch(Box::new(leaf(magenta)), Box::new(leaf(cyan)))
+        .isEq(&branch(Box::new(leaf(magenta)), Box::new(leaf(magenta)))));
 
     println!("Assertions all succeeded!");
 }
index e836d33976a93114f8ec18331f17922e461d5169..cb1fac0bae6ae1798f231ba382ce76eb254d58f6 100644 (file)
@@ -1,9 +1,9 @@
-#![feature(box_syntax)]
-
 struct Foo {
     f: isize,
 }
 
+
+
 impl Foo {
     fn foo(self: isize, x: isize) -> isize {
         //~^ ERROR invalid `self` parameter type
@@ -48,12 +48,12 @@ fn dummy3(self: &&Bar<T>) {}
 }
 
 fn main() {
-    let foo = box Foo {
+    let foo = Box::new(Foo {
         f: 1,
-    };
+    });
     println!("{}", foo.foo(2));
-    let bar = box Bar {
+    let bar = Box::new(Bar {
         f: 1,
-    };
+    });
     println!("{} {}", bar.foo(2), bar.bar(2));
 }
index b2596e49aa78eecc8ea2e91f8a93e3e6d8a12aab..3f550fd04259f583b43de4d6068b623c61c223fa 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
-#![feature(box_syntax)]
 
 use std::ops::FnMut;
 
  fn make_adder(x: i32) -> Box<dyn FnMut(i32)->i32+'static> {
-    (box move |y: i32| -> i32 { x + y }) as
+    Box::new(move |y: i32| -> i32 { x + y }) as
         Box<dyn FnMut(i32)->i32+'static>
 }
 
index 58c726d2185c4d3d13ec6cfb6813933a17295877..f1573b6adf0ce0952577be747a15ef8ebdfaa3b5 100644 (file)
@@ -1,8 +1,8 @@
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 #![feature(never_type)]
 #![feature(exhaustive_patterns)]
 
+
 #![deny(unreachable_patterns)]
 
 mod foo {
index d243b8f34dbcf045c558dca39341be0bb84d88f7..2c40dfc7a4b257bad296477b99662c271447e1bd 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 trait Foo {
     fn f(&self);
 }
@@ -18,8 +16,10 @@ fn f(&self) {
     }
 }
 
+
+
 fn main() {
-    let x = box Bar { x: 10 };
+    let x = Box::new(Bar { x: 10 });
     let y: Box<dyn Foo> = x as Box<dyn Foo>;
     let _z = y.clone(); //~ ERROR the method
 }
index 194698102377e117d4c898eed448984c560151ad..b742973ce327d856d309a56819a3e5ec1ab28e15 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let mut i: Box<_> = box 1;
+    let mut i: Box<_> = Box::new(1);
     // Should be a copy
     let mut j;
     j = i.clone();
index 32068e79df49cf8939bb3ac3e95e3720680e70f0..e7685b589ca8ee770e6bd7a9e075e513a7bdf44c 100644 (file)
@@ -1,11 +1,9 @@
 // run-pass
 #![allow(unused_assignments)]
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    let i: Box<_> = box 1;
-    let mut j: Box<_> = box 2;
+    let i: Box<_> = Box::new(1);
+    let mut j: Box<_> = Box::new(2);
     // Should drop the previous value of j
     j = i;
     assert_eq!(*j, 1);
index 2d62ce59ad01257903878ca6dc9e4a895d5b63ae..d4932d8333ab7d3c4a9365208e8777182ca73124 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn f<T>(t: T) -> T {
     let t1 = t;
@@ -7,6 +6,6 @@ fn f<T>(t: T) -> T {
 }
 
 pub fn main() {
-    let t = f::<Box<_>>(box 100);
-    assert_eq!(t, box 100);
+    let t = f::<Box<_>>(Box::new(100));
+    assert_eq!(t, Box::new(100));
 }
index 5a88df071a0b97e088ae91f24cea3b6843109599..d598744f145b2a08bbc9b4d4d527dd7b82b62fa7 100644 (file)
@@ -1,9 +1,8 @@
 // run-pass
 #![allow(unused_mut)]
-#![feature(box_syntax)]
 
 pub fn main() {
     let mut i: Box<_>;
-    i = box 1;
+    i = Box::new(1);
     assert_eq!(*i, 1);
 }
index 0360646f1330e0973406b3ed8825c7701e069e56..64147e11f1c0c90a82336791eeaf38822c18767d 100644 (file)
@@ -1,11 +1,10 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct J { j: isize }
 
 pub fn main() {
-    let i: Box<_> = box J {
+    let i: Box<_> = Box::new(J {
         j: 100
-    };
+    });
     assert_eq!(i.j, 100);
 }
index 5a3d17a84efc2f232de6fe7432b4a07d0b9831a0..ea6598a7f6b351518f14366724a0c48f016f6b2e 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let i: Box<_> = box vec![100];
+    let i: Box<_> = Box::new(vec![100]);
     assert_eq!((*i)[0], 100);
 }
index 7bbc61d25ac780665a8db9ce4503eb26ab296f83..ee05dd5a31d5b5b268f2b014dff5b264e942aa49 100644 (file)
@@ -1,12 +1,11 @@
 // run-pass
 #![allow(unused_allocation)]
-#![feature(box_syntax)]
 
 pub fn main() {
-    let i: Box<_> = box 100;
-    assert_eq!(i, box 100);
-    assert!(i < box 101);
-    assert!(i <= box 100);
-    assert!(i > box 99);
-    assert!(i >= box 99);
+    let i: Box<_> = Box::new(100);
+    assert_eq!(i, Box::new(100));
+    assert!(i < Box::new(101));
+    assert!(i <= Box::new(100));
+    assert!(i > Box::new(99));
+    assert!(i >= Box::new(99));
 }
index f24b3a8645f297eb31bce7645cb204590e8d8e6d..6c31ae99b8eefa492ad0db8482c88c3c2daad373 100644 (file)
@@ -4,12 +4,10 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
     enum t { t1(isize), t2(isize), }
 
-    let _x: Box<_> = box t::t1(10);
+    let _x: Box<_> = Box::new(t::t1(10));
 
     /*alt *x {
       t1(a) {
@@ -19,9 +17,9 @@ enum t { t1(isize), t2(isize), }
     }*/
 
     /*alt x {
-      box t1(a) {
+      Box::new(t1(a) {
         assert_eq!(a, 10);
-      }
+      })
       _ { panic!(); }
     }*/
 }
index 3df0f7d55fd5849a40c7d78c8bb45a900c962220..c566e79620a95f0f6beb4e9a590d5d39de5ac827 100644 (file)
@@ -2,10 +2,8 @@
 #![allow(dead_code)]
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    let _: Box<_> = box 100;
+    let _: Box<_> = Box::new(100);
 }
 
 fn vec() {
index 6ae95949e84da428a2c040ad9b185dab2dab8bae..5b9576fcc7a5b65c57badca295471b7c89eeea7d 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let mut i: Box<_> = box 1;
+    let mut i: Box<_> = Box::new(1);
     // Should be a copy
     let mut j = i.clone();
     *i = 2;
index 2c7b9d6054f44f7f1911d01af800c734bb3b1762..1d70860c7cec0b213ca04cd74dc0671a25595f78 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let i: Box<_> = box 1;
+    let i: Box<_> = Box::new(1);
     let j = i;
     assert_eq!(*j, 1);
 }
index 4a5ee56ea92828644d699e722c9a4856bef014bd..21187510ff0c5942719eddceda66a1cd0fab20d2 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let i: Box<_> = box 100;
+    let i: Box<_> = Box::new(100);
     let j = i;
     assert_eq!(*j, 100);
 }
index 0c6af0f7f97af2130b557ccd4b7b5157594ad960..33a1e9932b5d1beb07eef6cdbcd2fcfc56f67e00 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let i: Box<_> = box 100;
+    let i: Box<_> = Box::new(100);
     assert_eq!(*i, 100);
 }
index 9b9f95dfbcae608076fafd39f11f21c501dcc7b5..7207ac962953ebc53ac3764c4348dc76dcc11917 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 struct Foo { a: isize, b: isize }
 
 pub fn main() {
-    let box Foo{a, b} = box Foo{a: 100, b: 200};
+    let box Foo{ a, b } = Box::new(Foo { a: 100, b: 200 });
     assert_eq!(a + b, 300);
 }
index 0b7bda83b3fa18a68882a0b80919b7e1d36a0eae..2324f1e1a652f5c66100c462c578c2347a4a0d9a 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    let _x: Box<_> = box vec![0,0,0,0,0];
+    let _x: Box<_> = Box::new(vec![0,0,0,0,0]);
 }
index ff33839e57ee27c757005d567bbb53222675696f..6d42df218fbfd03cde2deec15d7458e1065443b8 100644 (file)
@@ -1,11 +1,10 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn f(i: Box<isize>) {
     assert_eq!(*i, 100);
 }
 
 pub fn main() {
-    let i = box 100;
+    let i = Box::new(100);
     f(i);
 }
index e8bb35e4eb0cf99698db036785de56dc446305cf..01510200b11b793d48d717c63cfb008fc9d57775 100644 (file)
@@ -1,12 +1,11 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn f(i: &mut Box<isize>) {
-    *i = box 200;
+    *i = Box::new(200);
 }
 
 pub fn main() {
-    let mut i = box 100;
+    let mut i = Box::new(100);
     f(&mut i);
     assert_eq!(*i, 200);
 }
index 75f2a767f59baef301da208e69cc322525ab4845..b4f3bc4b294bace6a97a54305c61e2595858011b 100644 (file)
@@ -1,12 +1,11 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn f(i: Box<isize>) {
     assert_eq!(*i, 100);
 }
 
 pub fn main() {
-    f(box 100);
-    let i = box 100;
+    f(Box::new(100));
+    let i = Box::new(100);
     f(i);
 }
index cd44cfa983661433a2bb0e0d8c1c8ba7981c0f2e..773a9bce1adb04e010d9eb8214283cb3b54365f1 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
-#![feature(box_syntax)]
 
 fn f() -> Box<isize> {
-    box 100
+    Box::new(100)
 }
 
 pub fn main() {
-    assert_eq!(f(), box 100);
+    assert_eq!(f(), Box::new(100));
 }
index 8d97ebe659097ba32e3fff0c96d46fa0626e1b0f..6daa06fb12de6407c1f6376962ef25a7103e9214 100644 (file)
@@ -2,12 +2,10 @@
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
 
-#![feature(box_syntax)]
-
 fn test1() {
     enum bar { u(Box<isize>), w(isize), }
 
-    let x = bar::u(box 10);
+    let x = bar::u(Box::new(10));
     assert!(match x {
       bar::u(a) => {
         println!("{}", a);
index 8907a8b20a7aefd3619042fa7c32c1b621381982..ce52d15ef1acb7ee7bf1e10cb0ea14b5fceafa57 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let mut a: Vec<Box<_>> = vec![box 10];
+    let mut a: Vec<Box<_>> = vec![Box::new(10)];
     let b = a.clone();
 
     assert_eq!(*a[0], 10);
index 528ea4fb870e85717a226b55d693b98db2f9521b..1e8d05e3d269f9f10ae58c7be2193658a980eaaa 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let vect : Vec<Box<_>> = vec![box 100];
-    assert_eq!(vect[0], box 100);
+    let vect : Vec<Box<_>> = vec![Box::new(100)];
+    assert_eq!(vect[0], Box::new(100));
 }
index c8a150522fd2e3884f5ef54867f3b273beb72ca7..d19605046e1bc349e49fa67283ef00f17fcc3af3 100644 (file)
@@ -1,8 +1,6 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    let _i: Box<_> = box 100;
+    let _i: Box<_> = Box::new(100);
 }
index f369a1e2a190d3e1184d81923812e8404f241332..f02d0b50764ae9f0b9c061ebaeab0b3f2b87c903 100644 (file)
@@ -1,5 +1,4 @@
 // run-pass
-#![feature(box_syntax)]
 
 use std::cmp::PartialEq;
 use std::fmt::Debug;
@@ -14,11 +13,11 @@ fn g<T:Send + PartialEq>(i: T, j: T) {
         assert!(i != j);
     }
 
-    let i: Box<_> = box 100;
-    let j: Box<_> = box 100;
+    let i: Box<_> = Box::new(100);
+    let j: Box<_> = Box::new(100);
     f(i, j);
-    let i: Box<_> = box 100;
-    let j: Box<_> = box 101;
+    let i: Box<_> = Box::new(100);
+    let j: Box<_> = Box::new(101);
     g(i, j);
 }
 
@@ -32,11 +31,11 @@ fn g<T:PartialEq>(i: T, j: T) {
         assert!(i != j);
     }
 
-    let i: Box<_> = box 100;
-    let j: Box<_> = box 100;
+    let i: Box<_> = Box::new(100);
+    let j: Box<_> = Box::new(100);
     f(i, j);
-    let i: Box<_> = box 100;
-    let j: Box<_> = box 101;
+    let i: Box<_> = Box::new(100);
+    let j: Box<_> = Box::new(101);
     g(i, j);
 }
 
@@ -50,11 +49,11 @@ fn g<T:PartialEq>(i: T, j: T) {
         assert!(i != j);
     }
 
-    let i: Box<_> = box 100;
-    let j: Box<_> = box 100;
+    let i: Box<_> = Box::new(100);
+    let j: Box<_> = Box::new(100);
     f(i, j);
-    let i: Box<_> = box 100;
-    let j: Box<_> = box 101;
+    let i: Box<_> = Box::new(100);
+    let j: Box<_> = Box::new(101);
     g(i, j);
 }
 
index 279777177061d5b1f32b8108383b8b6ffefc4c0e..0715d16628f87cb991ecf52cb0bde7c03258d1cf 100644 (file)
@@ -1,7 +1,6 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let i: Box<_> = box 100;
+    let i: Box<_> = Box::new(100);
     println!("{}", i);
 }
index e1ea58b39ef50007984e14308154c58f3b527fb6..c0f5d8f90532dfcbc6b9a383b80179d5738cb09d 100644 (file)
@@ -1,11 +1,10 @@
 // run-pass
 
 #![allow(unused_variables)]
-#![feature(box_syntax)]
 
 pub fn main() {
-    let i: Box<_> = box 100;
-    let j: Box<_> = box 200;
+    let i: Box<_> = Box::new(100);
+    let j: Box<_> = Box::new(200);
     let j = i;
     assert_eq!(*j, 100);
 }
index 4f5de50b722f92229eb929f396a72e487bc20c5e..103af8e1f1e02bd4f481f872a60577473277743e 100644 (file)
@@ -1,9 +1,8 @@
 // run-pass
 #![allow(unused_mut)]
-#![feature(box_syntax)]
 
 pub fn main() {
     let mut i: Box<_>;
-    i = box 100;
+    i = Box::new(100);
     assert_eq!(*i, 100);
 }
index 0f6bff1432b3fd39d0c6a64eeeb250830dadeda1..40a2718e4e5f68ed2335b907b980b1427e15bdc2 100644 (file)
@@ -1,9 +1,8 @@
 // run-pass
 #![allow(unused_mut)]
-#![feature(box_syntax)]
 
 pub fn main() {
-    let i: Box<_> = box 100;
+    let i: Box<_> = Box::new(100);
     let mut j;
     j = i;
     assert_eq!(*j, 100);
index 176cf33d4889c0c499ad1197f2292efe74f94f5b..0367c08099a8326b61123ae4b6d1f151529ac765 100644 (file)
@@ -1,8 +1,7 @@
 // run-pass
-#![feature(box_syntax)]
 
 pub fn main() {
-    let mut i: Box<_> = box 0;
+    let mut i: Box<_> = Box::new(0);
     *i = 1;
     assert_eq!(*i, 1);
 }
index 84e8cdb32b84e588a03ed474451900fa53f1acb3..bb35a9b2d73e2cd55ac0e0a3e88e24419590b64a 100644 (file)
@@ -4,8 +4,6 @@
 
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub trait EventLoop { fn foo(&self) {} }
 
 pub struct UvEventLoop {
@@ -15,6 +13,6 @@ pub struct UvEventLoop {
 impl EventLoop for UvEventLoop { }
 
 pub fn main() {
-    let loop_: Box<dyn EventLoop> = box UvEventLoop { uvio: 0 } as Box<dyn EventLoop>;
+    let loop_: Box<dyn EventLoop> = Box::new(UvEventLoop { uvio: 0 }) as Box<dyn EventLoop>;
     let _loop2_ = loop_;
 }
index c18e029b252cbb468887e217e6b752e44b4f56fc..9c73fd2204c382ed6f9c8b8c58f6adf8df66e0f0 100644 (file)
@@ -4,15 +4,15 @@
 #![allow(non_shorthand_field_patterns)]
 
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 struct Foo {a: isize, b: usize}
 
 enum bar { u(Box<Foo>), w(isize), }
 
 pub fn main() {
-    assert!(match bar::u(box Foo{a: 10, b: 40}) {
-              bar::u(box Foo{a: a, b: b}) => { a + (b as isize) }
-              _ => { 66 }
-            } == 50);
+    let v = match bar::u(Box::new(Foo{ a: 10, b: 40 })) {
+        bar::u(box Foo{ a: a, b: b }) => { a + (b as isize) }
+        _ => { 66 }
+    };
+    assert_eq!(v, 50);
 }
index e17b5a3ddb450996fc335267cdf220d800abf7cf..2e81f898d0c98e04b619f6deb2e8350917d2b501 100644 (file)
@@ -2,16 +2,15 @@
 #![allow(dead_code)]
 #![allow(non_camel_case_types)]
 
-#![feature(box_syntax)]
-
 enum bar { u(Box<isize>), w(isize), }
 
 pub fn main() {
-    assert!(match bar::u(box 10) {
-      bar::u(a) => {
-        println!("{}", a);
-        *a
-      }
-      _ => { 66 }
-    } == 10);
+    let v = match bar::u(10.into()) {
+        bar::u(a) => {
+            println!("{}", a);
+            *a
+        }
+        _ => { 66 }
+    };
+    assert_eq!(v, 10);
 }
index b32195ac274217b1a2cb5efb1ec57415613a4f8e..c2474d0e77214dca8b16898dd7c39343a4ae51aa 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
 
 #![feature(box_patterns)]
-#![feature(box_syntax)]
 
 fn simple() {
-    match box true {
+    match Box::new(true) {
       box true => { }
       _ => { panic!(); }
     }
index c8bddd246a8051aa6b2d0c120fad89a459cd631f..9f8ad9bb050430542106a076aa97abdf4c51fcee 100644 (file)
@@ -1,10 +1,9 @@
 // run-pass
-#![feature(box_syntax)]
 
 struct X { x: isize }
 
 pub fn main() {
-    let x: Box<_> = box X {x: 1};
+    let x: Box<_> = Box::new(X {x: 1});
     let bar = x;
     assert_eq!(bar.x, 1);
 }
index 22f0e6c3a49b03aa93d21e3bd38ada5da4d44207..23ddd2cdca25d0f333943ad8a3279e5427eef0f8 100644 (file)
@@ -2,13 +2,11 @@
 #![allow(unused_must_use)]
 // ignore-emscripten no threads support
 
-#![feature(box_syntax)]
-
 use std::sync::mpsc::{channel, Sender};
 use std::thread;
 
 fn child(tx: &Sender<Box<usize>>, i: usize) {
-    tx.send(box i).unwrap();
+    tx.send(Box::new(i)).unwrap();
 }
 
 pub fn main() {
index a5c7561b9ae3cf652f43954916ae928adb8e4f83..431cc2be5d20e3d458af8403b7539d7453f40245 100644 (file)
@@ -1,11 +1,10 @@
 // run-pass
-#![feature(box_syntax)]
 
 use std::sync::mpsc::channel;
 
 pub fn main() {
     let (tx, rx) = channel::<Box<_>>();
-    tx.send(box 100).unwrap();
+    tx.send(Box::new(100)).unwrap();
     let v = rx.recv().unwrap();
-    assert_eq!(v, box 100);
+    assert_eq!(v, Box::new(100));
 }
index 33a6b3b3ed046ae86c482b2b3eeb782c22c907b5..4f33ff9a8a35e7fdb1a2364a3908e4dbd115f2d5 100644 (file)
@@ -1,12 +1,11 @@
 // run-pass
-#![feature(box_syntax)]
 
 use std::mem::swap;
 
 pub fn main() {
-    let mut i: Box<_> = box 100;
-    let mut j: Box<_> = box 200;
+    let mut i: Box<_> = Box::new(100);
+    let mut j: Box<_> = Box::new(200);
     swap(&mut i, &mut j);
-    assert_eq!(i, box 200);
-    assert_eq!(j, box 100);
+    assert_eq!(i, Box::new(200));
+    assert_eq!(j, Box::new(100));
 }
index be4406399fd0f7ba8ebefa0441bc16954d4f3286..bbeb00d5fed60c423cb0fc371710193f6f97d31c 100644 (file)
@@ -4,7 +4,6 @@
 #![allow(dead_code)]
 #![allow(unused_variables)]
 #![allow(unused_imports)]
-#![feature(box_syntax)]
 
 // Test sized-ness checking in substitution.
 
@@ -36,7 +35,7 @@ trait T2 {
 struct S;
 impl T2 for S {
     fn f() -> Box<S> {
-        box S
+        Box::new(S)
     }
 }
 fn f5<X: ?Sized+T2>(x: &X) {
@@ -51,7 +50,7 @@ trait T3 {
 }
 impl T3 for S {
     fn f() -> Box<S> {
-        box S
+        Box::new(S)
     }
 }
 fn f7<X: ?Sized+T3>(x: &X) {
index c5c5ed26c7384b263dcf857a844f6c118194b9d9..4d5e89575bef6b50d14cafacc22ab9f643b4fbed 100644 (file)
@@ -2,7 +2,7 @@
 // Test structs with always-unsized fields.
 
 #![allow(warnings)]
-#![feature(box_syntax, unsize, ptr_metadata)]
+#![feature(unsize, ptr_metadata)]
 
 use std::mem;
 use std::ptr;
@@ -58,7 +58,7 @@ struct Foo_<T> {
             f: [T; 3],
         }
 
-        let data: Box<Foo_<i32>> = box Foo_ { f: [1, 2, 3] };
+        let data: Box<Foo_<i32>> = Box::new(Foo_ { f: [1, 2, 3] });
         let x: &Foo<i32> = mem::transmute(slice::from_raw_parts(&*data, 3));
         assert_eq!(x.f.len(), 3);
         assert_eq!(x.f[0], 1);
@@ -69,7 +69,7 @@ struct Baz_ {
         }
 
         let data: Box<_> =
-            box Baz_ { f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] };
+            Box::new(Baz_ { f1: 42, f2: ['a' as u8, 'b' as u8, 'c' as u8, 'd' as u8, 'e' as u8] });
         let x: &Baz = mem::transmute(slice::from_raw_parts(&*data, 5));
         assert_eq!(x.f1, 42);
         let chs: Vec<char> = x.f2.chars().collect();
@@ -84,9 +84,9 @@ struct Qux_ {
             f: St,
         }
 
-        let obj: Box<St> = box St { f: 42 };
+        let obj: Box<St> = Box::new(St { f: 42 });
         let obj: &Tr = &*obj;
-        let data: Box<_> = box Qux_ { f: St { f: 234 } };
+        let data: Box<_> = Box::new(Qux_ { f: St { f: 234 } });
         let x: &Qux = &*ptr::from_raw_parts::<Qux>((&*data as *const _).cast(), ptr::metadata(obj));
         assert_eq!(x.f.foo(), 234);
     }
index e9d4684736ebfecc8d209cfba2ffce585e012158..efaf10da4a99fa2b9fb12263700eeb809b794080 100644 (file)
@@ -1,10 +1,8 @@
 // run-pass
 // pretty-expanded FIXME #23616
 
-#![feature(box_syntax)]
-
 pub fn main() {
-    let _x: Box<_> = box 1;
+    let _x: Box<_> = Box::new(1);
     let lam_move = || {};
     lam_move();
 }
index 37aee22f85dbb3eefb0aad3dce970dd20a46d52c..697434d47ebb217c4cceb0d9d14e0e851bd1b5fe 100644 (file)
@@ -6,10 +6,8 @@
 // pretty-expanded FIXME #23616
 
 #![allow(path_statements)]
-#![feature(box_syntax)]
 
-pub fn main()
-{
-    let y: Box<_> = box 1;
+pub fn main() {
+    let y: Box<_> = Box::new(1);
     y;
 }
index ea3089e747fb539caddfd9b9d1d8868a91353112..7ca53b664ac6cb2057071a047f5fc11093814df8 100644 (file)
@@ -1,12 +1,10 @@
 // run-pass
 // ignore-emscripten no threads support
 
-#![feature(box_syntax)]
-
 use std::thread;
 
 fn f() {
-    let _a: Box<_> = box 0;
+    let _a: Box<_> = Box::new(0);
     panic!();
 }
 
index 76487ef1c14093d604ebe1ba72d7727e7e410ec1..47fbb5bf1c362c4e453b0bf5bc7bbb8586c4ca8b 100644 (file)
@@ -1,5 +1,3 @@
-#![feature(box_syntax)]
-
 use std::fmt;
 
 struct Number {
@@ -22,9 +20,11 @@ fn push(&mut self, n: Box<dyn ToString + 'static>) {
 }
 
 fn main() {
-    let n: Box<_> = box Number { n: 42 };
-    let mut l: Box<_> = box List { list: Vec::new() };
+
+    let n: Box<_> = Number { n: 42 }.into();
+    let mut l: Box<_> = List { list: Vec::new() }.into();
     l.push(n);
+
     let x = n.to_string();
     //~^ ERROR: borrow of moved value: `n`
 }
index b3266562d14b69e1961bda28cafe96cfd85d193f..539ea94a70de54effe3977b6390ba96ae1da869f 100644 (file)
@@ -1,11 +1,12 @@
 error[E0382]: borrow of moved value: `n`
   --> $DIR/use-after-move-implicity-coerced-object.rs:28:13
    |
-LL |     let n: Box<_> = box Number { n: 42 };
+LL |     let n: Box<_> = Number { n: 42 }.into();
    |         - move occurs because `n` has type `Box<Number>`, which does not implement the `Copy` trait
-LL |     let mut l: Box<_> = box List { list: Vec::new() };
+LL |     let mut l: Box<_> = List { list: Vec::new() }.into();
 LL |     l.push(n);
    |            - value moved here
+LL | 
 LL |     let x = n.to_string();
    |             ^ value borrowed here after move
 
index a6f6c45573d0ac80c83875887118535275bfc077..f7a3c0ecce5ba49dc3bd80d03e089959c523d029 100644 (file)
@@ -1,9 +1,9 @@
-#![feature(box_syntax)]
-
 struct S {
     x: Box<isize>,
 }
 
+
+
 impl S {
     pub fn foo(self) -> isize {
         self.bar();
@@ -14,6 +14,6 @@ pub fn bar(self) {}
 }
 
 fn main() {
-    let x = S { x: box 1 };
+    let x = S { x: 1.into() };
     println!("{}", x.foo());
 }
index bb398e5698a8018797877601ccd9596c4f9564f5..2b4b480df0acf81e2b77c2c2ff396c0fa92b782e 100644 (file)
@@ -1,5 +1,5 @@
 // Regression test for #87549.
-// compile-flags: -C incremental=tmp/wf/hir-wf-check-erase-regions
+// incremental
 
 pub struct Table<T, const N: usize>([Option<T>; N]);
 
index 1ba241d37761675150a31b80e2e30cc4dc76023e..6bbac6d9a24688598775794ba0f94a991eb1c27c 100644 (file)
@@ -92,7 +92,7 @@ fn check_fn(
                         // be sure we have `self` parameter in this function
                         if let AssocItemKind::Fn { has_self: true } = trait_item.kind {
                             trait_self_ty =
-                                Some(TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()).self_ty());
+                                Some(TraitRef::identity(cx.tcx, trait_item.id.def_id.to_def_id()).self_ty().skip_binder());
                         }
                     }
                 }
index e89b2d295b92345f4f1173e0e19911c559cc3bca..8a699f13f2ed267328eeca69fed865048b05225c 100644 (file)
 declare_clippy_lint! {
     /// ### What it does
     /// Checks for use of `.iter().nth()` (and the related
-    /// `.iter_mut().nth()`) on standard library types with O(1) element access.
+    /// `.iter_mut().nth()`) on standard library types with *O*(1) element access.
     ///
     /// ### Why is this bad?
     /// `.get()` and `.get_mut()` are more efficient and more
@@ -2061,7 +2061,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
             then {
                 let first_arg_span = first_arg_ty.span;
                 let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty);
-                let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty();
+                let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
                 wrong_self_convention::check(
                     cx,
                     &item.ident.name.as_str(),
@@ -2078,7 +2078,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>
             if item.ident.name == sym::new;
             if let TraitItemKind::Fn(_, _) = item.kind;
             let ret_ty = return_ty(cx, item.hir_id());
-            let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty();
+            let self_ty = TraitRef::identity(cx.tcx, item.def_id.to_def_id()).self_ty().skip_binder();
             if !contains_ty(cx.tcx, ret_ty, self_ty);
 
             then {
index e9a9895cb746f39a6abece6de0aa7df4aa26ca92..e2f2e2008bb2604543f1ba4814b0d92538d89fc1 100644 (file)
@@ -194,6 +194,7 @@ fn check_rvalue(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, def_id: DefId, rvalue: &Rv
         },
         Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => Ok(()),
         Rvalue::NullaryOp(NullOp::Box, _) => Err((span, "heap allocations are not allowed in const fn".into())),
+        Rvalue::ShallowInitBox(_, _) => Ok(()),
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
index 99b0a3454e89ccaed91b758a80c9155d3ed18828..cd0a56d08d8bc6c72d7d5b38db0093f672047652 100644 (file)
@@ -459,3 +459,9 @@ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<
 pub fn output_base_name(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf {
     output_base_dir(config, testpaths, revision).join(testpaths.file.file_stem().unwrap())
 }
+
+/// Absolute path to the directory to use for incremental compilation. Example:
+///   /path/to/build/host-triple/test/ui/relative/testname.mode/testname.inc
+pub fn incremental_dir(config: &Config, testpaths: &TestPaths) -> PathBuf {
+    output_base_name(config, testpaths, None).with_extension("inc")
+}
index 28089e85b55b493dbb3610e91f3f52ab9d930dfe..efd85502799595ab12fc6e31528a3a5510996b88 100644 (file)
@@ -113,6 +113,21 @@ pub struct TestProps {
     // testing harness and used when generating compilation
     // arguments. (In particular, it propagates to the aux-builds.)
     pub incremental_dir: Option<PathBuf>,
+    // If `true`, this test will use incremental compilation.
+    //
+    // This can be set manually with the `incremental` header, or implicitly
+    // by being a part of an incremental mode test. Using the `incremental`
+    // header should be avoided if possible; using an incremental mode test is
+    // preferred. Incremental mode tests support multiple passes, which can
+    // verify that the incremental cache can be loaded properly after being
+    // created. Just setting the header will only verify the behavior with
+    // creating an incremental cache, but doesn't check that it is created
+    // correctly.
+    //
+    // Compiletest will create the incremental directory, and ensure it is
+    // empty before the test starts. Incremental mode tests will reuse the
+    // incremental directory between passes in the same test.
+    pub incremental: bool,
     // How far should the test proceed while still passing.
     pass_mode: Option<PassMode>,
     // Ignore `--pass` overrides from the command line for this test.
@@ -163,6 +178,7 @@ pub fn new() -> Self {
             pretty_compare_only: false,
             forbid_output: vec![],
             incremental_dir: None,
+            incremental: false,
             pass_mode: None,
             fail_mode: None,
             ignore_pass: false,
@@ -350,6 +366,10 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
                 if !self.stderr_per_bitwidth {
                     self.stderr_per_bitwidth = config.parse_stderr_per_bitwidth(ln);
                 }
+
+                if !self.incremental {
+                    self.incremental = config.parse_incremental(ln);
+                }
             });
         }
 
@@ -360,6 +380,10 @@ fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
             self.failure_status = 101;
         }
 
+        if config.mode == Mode::Incremental {
+            self.incremental = true;
+        }
+
         for key in &["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
             if let Ok(val) = env::var(key) {
                 if self.exec_env.iter().find(|&&(ref x, _)| x == key).is_none() {
@@ -731,6 +755,10 @@ fn parse_rustfix_only_machine_applicable(&self, line: &str) -> bool {
     fn parse_edition(&self, line: &str) -> Option<String> {
         self.parse_name_value_directive(line, "edition")
     }
+
+    fn parse_incremental(&self, line: &str) -> bool {
+        self.parse_name_directive(line, "incremental")
+    }
 }
 
 fn expand_variables(mut value: String, config: &Config) -> String {
index 51a4d74109a639181ee8d1087a7f7e631947728d..2a4bb9eb88b306c666172e0d5b101bd5aba36207 100644 (file)
@@ -1,7 +1,7 @@
 // ignore-tidy-filelength
 
 use crate::common::{expected_output_path, UI_EXTENSIONS, UI_FIXED, UI_STDERR, UI_STDOUT};
-use crate::common::{output_base_dir, output_base_name, output_testname_unique};
+use crate::common::{incremental_dir, output_base_dir, output_base_name, output_testname_unique};
 use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJson, Ui};
 use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc};
 use crate::common::{CompareMode, FailMode, PassMode};
@@ -229,18 +229,24 @@ pub fn run(config: Config, testpaths: &TestPaths, revision: Option<&str>) {
         print!("\n\n");
     }
     debug!("running {:?}", testpaths.file.display());
-    let props = TestProps::from_file(&testpaths.file, revision, &config);
+    let mut props = TestProps::from_file(&testpaths.file, revision, &config);
+    if props.incremental {
+        props.incremental_dir = Some(incremental_dir(&config, testpaths));
+    }
 
     let cx = TestCx { config: &config, props: &props, testpaths, revision };
     create_dir_all(&cx.output_base_dir()).unwrap();
+    if props.incremental {
+        cx.init_incremental_test();
+    }
 
     if config.mode == Incremental {
         // Incremental tests are special because they cannot be run in
         // parallel.
         assert!(!props.revisions.is_empty(), "Incremental tests require revisions.");
-        cx.init_incremental_test();
         for revision in &props.revisions {
-            let revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config);
+            let mut revision_props = TestProps::from_file(&testpaths.file, Some(revision), &config);
+            revision_props.incremental_dir = props.incremental_dir.clone();
             let rev_cx = TestCx {
                 config: &config,
                 props: &revision_props,
@@ -2937,7 +2943,7 @@ fn init_incremental_test(&self) {
         // incremental workproduct directory.  Delete any old
         // incremental work products that may be there from prior
         // runs.
-        let incremental_dir = self.incremental_dir();
+        let incremental_dir = self.props.incremental_dir.as_ref().unwrap();
         if incremental_dir.exists() {
             // Canonicalizing the path will convert it to the //?/ format
             // on Windows, which enables paths longer than 260 character
@@ -2947,7 +2953,7 @@ fn init_incremental_test(&self) {
         fs::create_dir_all(&incremental_dir).unwrap();
 
         if self.config.verbose {
-            print!("init_incremental_test: incremental_dir={}", incremental_dir.display());
+            println!("init_incremental_test: incremental_dir={}", incremental_dir.display());
         }
     }
 
@@ -2974,46 +2980,30 @@ fn run_incremental_test(&self) {
         let revision = self.revision.expect("incremental tests require a list of revisions");
 
         // Incremental workproduct directory should have already been created.
-        let incremental_dir = self.incremental_dir();
+        let incremental_dir = self.props.incremental_dir.as_ref().unwrap();
         assert!(incremental_dir.exists(), "init_incremental_test failed to create incremental dir");
 
-        // Add an extra flag pointing at the incremental directory.
-        let mut revision_props = self.props.clone();
-        revision_props.incremental_dir = Some(incremental_dir);
-
-        let revision_cx = TestCx {
-            config: self.config,
-            props: &revision_props,
-            testpaths: self.testpaths,
-            revision: self.revision,
-        };
-
         if self.config.verbose {
-            print!("revision={:?} revision_props={:#?}", revision, revision_props);
+            print!("revision={:?} props={:#?}", revision, self.props);
         }
 
         if revision.starts_with("rpass") {
-            if revision_cx.props.should_ice {
-                revision_cx.fatal("can only use should-ice in cfail tests");
+            if self.props.should_ice {
+                self.fatal("can only use should-ice in cfail tests");
             }
-            revision_cx.run_rpass_test();
+            self.run_rpass_test();
         } else if revision.starts_with("rfail") {
-            if revision_cx.props.should_ice {
-                revision_cx.fatal("can only use should-ice in cfail tests");
+            if self.props.should_ice {
+                self.fatal("can only use should-ice in cfail tests");
             }
-            revision_cx.run_rfail_test();
+            self.run_rfail_test();
         } else if revision.starts_with("cfail") {
-            revision_cx.run_cfail_test();
+            self.run_cfail_test();
         } else {
-            revision_cx.fatal("revision name must begin with rpass, rfail, or cfail");
+            self.fatal("revision name must begin with rpass, rfail, or cfail");
         }
     }
 
-    /// Directory where incremental work products are stored.
-    fn incremental_dir(&self) -> PathBuf {
-        self.output_base_name().with_extension("inc")
-    }
-
     fn run_rmake_test(&self) {
         let cwd = env::current_dir().unwrap();
         let src_root = self.config.src_base.parent().unwrap().parent().unwrap().parent().unwrap();
index 35809e599266c8111e6758f84307b1371838ea69..a20ea3235ed46348fc07ac468a1c94c9c84b689f 100644 (file)
@@ -57,6 +57,7 @@ fn filter_dirs(path: &Path) -> bool {
     let skip = [
         "tidy-test-file",
         "compiler/rustc_codegen_cranelift",
+        "compiler/rustc_codegen_gcc",
         "src/llvm-project",
         "library/backtrace",
         "library/stdarch",