aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog54
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/ada/gcc-interface/decl.cc8
-rw-r--r--gcc/ada/gen_il-gen-gen_nodes.adb2
-rw-r--r--gcc/ada/gnatvsn.adb7
-rw-r--r--gcc/ada/sem_ch12.adb31
-rw-r--r--gcc/c-family/ChangeLog5
-rw-r--r--gcc/c/ChangeLog16
-rw-r--r--gcc/c/c-decl.cc4
-rw-r--r--gcc/c/c-typeck.cc20
-rw-r--r--gcc/cobol/ChangeLog55
-rw-r--r--gcc/cobol/gcobolspec.cc38
-rw-r--r--gcc/cobol/util.cc19
-rw-r--r--gcc/config.in6
-rw-r--r--gcc/config/aarch64/aarch64-arches.def2
-rw-r--r--gcc/config/avr/avr-passes.cc54
-rw-r--r--gcc/config/i386/sse.md6
-rw-r--r--gcc/config/loongarch/loongarch.h32
-rwxr-xr-xgcc/configure2
-rw-r--r--gcc/configure.ac2
-rw-r--r--gcc/cp/ChangeLog29
-rw-r--r--gcc/cp/cp-gimplify.cc74
-rw-r--r--gcc/cp/decl2.cc22
-rw-r--r--gcc/cp/mangle.cc13
-rw-r--r--gcc/cp/pt.cc11
-rw-r--r--gcc/cp/typeck.cc20
-rw-r--r--gcc/d/ChangeLog8
-rw-r--r--gcc/diagnostic-format-sarif.cc2
-rw-r--r--gcc/diagnostic.cc57
-rw-r--r--gcc/diagnostic.h23
-rw-r--r--gcc/doc/invoke.texi2
-rw-r--r--gcc/fortran/ChangeLog7
-rw-r--r--gcc/fortran/resolve.cc21
-rw-r--r--gcc/fortran/trans-array.cc4
-rw-r--r--gcc/gcc-urlifier.cc7
-rw-r--r--gcc/gcc-urlifier.h7
-rw-r--r--gcc/gcc.cc2
-rw-r--r--gcc/ira-costs.cc15
-rw-r--r--gcc/po/fr.po1278
-rw-r--r--gcc/rust/ChangeLog62
-rw-r--r--gcc/rust/Make-lang.in7
-rw-r--r--gcc/rust/ast/rust-ast-builder-type.cc164
-rw-r--r--gcc/rust/ast/rust-ast-builder-type.h57
-rw-r--r--gcc/rust/ast/rust-ast-builder.cc201
-rw-r--r--gcc/rust/ast/rust-ast-builder.h17
-rw-r--r--gcc/rust/ast/rust-ast-collector.cc14
-rw-r--r--gcc/rust/ast/rust-ast-collector.h2
-rw-r--r--gcc/rust/ast/rust-ast-full-decls.h4
-rw-r--r--gcc/rust/ast/rust-ast-visitor.cc52
-rw-r--r--gcc/rust/ast/rust-ast-visitor.h6
-rw-r--r--gcc/rust/ast/rust-ast.cc4
-rw-r--r--gcc/rust/ast/rust-ast.h27
-rw-r--r--gcc/rust/ast/rust-expr.h196
-rw-r--r--gcc/rust/ast/rust-item.h2
-rw-r--r--gcc/rust/ast/rust-path.cc28
-rw-r--r--gcc/rust/ast/rust-path.h274
-rw-r--r--gcc/rust/ast/rust-pattern.h2
-rw-r--r--gcc/rust/ast/rust-type.h10
-rw-r--r--gcc/rust/backend/rust-compile-asm.cc146
-rw-r--r--gcc/rust/backend/rust-compile-asm.h63
-rw-r--r--gcc/rust/backend/rust-compile-block.h2
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc119
-rw-r--r--gcc/rust/backend/rust-compile-expr.h1
-rw-r--r--gcc/rust/backend/rust-compile-item.cc19
-rw-r--r--gcc/rust/backend/rust-compile.cc128
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/.cargo/config.toml5
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.lock39
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs11
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs19
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json1
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md40
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml29
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE201
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT23
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md44
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md26
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs115
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs62
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs180
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs567
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs13
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs195
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs661
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json1
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md324
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml139
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE201
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT25
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/README.md130
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs27
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs123
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs94
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs143
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs265
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs514
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs1394
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs1878
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs367
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs397
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml1
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json1
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml29
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md6
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs129
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs16
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs495
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs284
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs170
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs156
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs614
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs299
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json1
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md40
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml25
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE201
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT23
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md38
-rw-r--r--gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs148
-rw-r--r--gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h21
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc157
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h1
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h125
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h79
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc273
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h259
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder.h41
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-dump.cc75
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-dump.h4
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h165
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-free-region.h38
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-place.h152
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir.h79
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc129
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h14
-rw-r--r--gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc4
-rw-r--r--gcc/rust/checks/errors/privacy/rust-privacy-reporter.h1
-rw-r--r--gcc/rust/checks/errors/rust-const-checker.cc16
-rw-r--r--gcc/rust/checks/errors/rust-feature-gate.cc27
-rw-r--r--gcc/rust/checks/errors/rust-feature-gate.h139
-rw-r--r--gcc/rust/checks/errors/rust-feature.cc43
-rw-r--r--gcc/rust/checks/errors/rust-feature.h14
-rw-r--r--gcc/rust/checks/errors/rust-hir-pattern-analysis.cc1568
-rw-r--r--gcc/rust/checks/errors/rust-hir-pattern-analysis.h526
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.cc18
-rw-r--r--gcc/rust/checks/lints/rust-lint-marklive.cc31
-rw-r--r--gcc/rust/expand/rust-cfg-strip.cc26
-rw-r--r--gcc/rust/expand/rust-cfg-strip.h2
-rw-r--r--gcc/rust/expand/rust-derive-clone.cc88
-rw-r--r--gcc/rust/expand/rust-derive-clone.h5
-rw-r--r--gcc/rust/expand/rust-derive-copy.cc87
-rw-r--r--gcc/rust/expand/rust-derive-copy.h4
-rw-r--r--gcc/rust/expand/rust-derive.h2
-rw-r--r--gcc/rust/expand/rust-expand-visitor.h2
-rw-r--r--gcc/rust/expand/rust-macro-builtins-asm.cc207
-rw-r--r--gcc/rust/expand/rust-macro-builtins-asm.h13
-rw-r--r--gcc/rust/expand/rust-macro-builtins-helpers.cc7
-rw-r--r--gcc/rust/expand/rust-macro-builtins-helpers.h3
-rw-r--r--gcc/rust/expand/rust-macro-builtins-include.cc54
-rw-r--r--gcc/rust/expand/rust-macro-expand.cc7
-rw-r--r--gcc/rust/hir/rust-ast-lower-base.cc6
-rw-r--r--gcc/rust/hir/rust-ast-lower-base.h2
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.cc124
-rw-r--r--gcc/rust/hir/rust-ast-lower-item.cc9
-rw-r--r--gcc/rust/hir/rust-ast-lower-type.cc25
-rw-r--r--gcc/rust/hir/rust-hir-dump.cc5
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h277
-rw-r--r--gcc/rust/hir/tree/rust-hir-full-decls.h3
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h26
-rw-r--r--gcc/rust/hir/tree/rust-hir-visitor.h1
-rw-r--r--gcc/rust/hir/tree/rust-hir.cc64
-rw-r--r--gcc/rust/hir/tree/rust-hir.h28
-rw-r--r--gcc/rust/lex/rust-lex.cc9
-rw-r--r--gcc/rust/lex/rust-lex.h9
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.cc9
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.h2
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.cc74
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h4
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-pattern.cc3
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.cc17
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h4
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc5
-rw-r--r--gcc/rust/resolve/rust-default-resolver.cc550
-rw-r--r--gcc/rust/resolve/rust-default-resolver.h124
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.cc123
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.h148
-rw-r--r--gcc/rust/resolve/rust-finalize-imports-2.0.cc224
-rw-r--r--gcc/rust/resolve/rust-finalize-imports-2.0.h110
-rw-r--r--gcc/rust/resolve/rust-forever-stack.h31
-rw-r--r--gcc/rust/resolve/rust-forever-stack.hxx115
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.cc92
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.h3
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.cc20
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.h6
-rw-r--r--gcc/rust/resolve/rust-name-resolver.cc9
-rw-r--r--gcc/rust/resolve/rust-name-resolver.h7
-rw-r--r--gcc/rust/resolve/rust-rib.cc107
-rw-r--r--gcc/rust/resolve/rust-rib.h32
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc367
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h134
-rw-r--r--gcc/rust/rust-session-manager.cc24
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.cc27
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-enumitem.cc80
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.cc83
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h1
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.cc23
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.cc65
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.h3
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-pattern.cc205
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.h5
-rw-r--r--gcc/rust/typecheck/rust-tyty-variance-analysis-private.h11
-rw-r--r--gcc/rust/typecheck/rust-tyty-variance-analysis.cc8
-rw-r--r--gcc/rust/typecheck/rust-tyty-variance-analysis.h7
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc2
-rw-r--r--gcc/rust/util/optional.h86
-rw-r--r--gcc/rust/util/rust-attribute-values.h1
-rw-r--r--gcc/rust/util/rust-attributes.cc3
-rw-r--r--gcc/rust/util/rust-canonical-path.h4
-rw-r--r--gcc/testsuite/ChangeLog105
-rw-r--r--gcc/testsuite/g++.dg/abi/mangle-new1.C10
-rw-r--r--gcc/testsuite/g++.dg/conversion/ptrmem10.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/alias-decl-variadic3.C22
-rw-r--r--gcc/testsuite/g++.dg/template/linkage7.C17
-rw-r--r--gcc/testsuite/g++.target/i386/pr118068.C17
-rw-r--r--gcc/testsuite/gcc.dg/Wfatal-bad-attr-pr119366.c8
-rw-r--r--gcc/testsuite/gcc.dg/Wfree-nonheap-object-7.c6
-rw-r--r--gcc/testsuite/gcc.dg/pr0
-rw-r--r--gcc/testsuite/gcc.dg/pr118061.c8
-rw-r--r--gcc/testsuite/gcc.dg/pr118765.c7
-rw-r--r--gcc/testsuite/gcc.dg/pr119350-1.c14
-rw-r--r--gcc/testsuite/gcc.dg/pr119350-2.c14
-rw-r--r--gcc/testsuite/gcc.dg/pr119350-3.c14
-rw-r--r--gcc/testsuite/gcc.dg/vect/bb-slp-41.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_128.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa10.c6
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa11.c5
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa8.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa9.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_22.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_26.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_43.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_44.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_56.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-early-break_6.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/apx-ndd-tls-1b.c7
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512vlbw-pr119357.c14
-rw-r--r--gcc/testsuite/gcc.target/loongarch/regname-float-abi.c14
-rw-r--r--gcc/testsuite/gcc.target/s390/vector/vcond-shift.c12
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c2
-rw-r--r--gcc/testsuite/gfortran.dg/allocate_assumed_charlen_5.f9017
-rw-r--r--gcc/testsuite/gfortran.dg/associate_74.f9047
-rw-r--r--gcc/testsuite/gfortran.dg/bounds_check_27.f9045
-rw-r--r--gcc/testsuite/gfortran.dg/deferred_character_18.f903
-rw-r--r--gcc/testsuite/gnat.dg/generic_inst14.adb20
-rw-r--r--gcc/testsuite/gnat.dg/generic_inst14_pkg-child.ads27
-rw-r--r--gcc/testsuite/gnat.dg/generic_inst14_pkg.ads16
-rw-r--r--gcc/testsuite/rust/borrowck/reference.rs96
-rw-r--r--gcc/testsuite/rust/borrowck/return_ref_to_local.rs15
-rw-r--r--gcc/testsuite/rust/borrowck/subset.rs29
-rw-r--r--gcc/testsuite/rust/borrowck/test_move.rs26
-rw-r--r--gcc/testsuite/rust/borrowck/test_move_conditional.rs45
-rw-r--r--gcc/testsuite/rust/borrowck/tmp.rs95
-rw-r--r--gcc/testsuite/rust/borrowck/use_while_mut.rs21
-rw-r--r--gcc/testsuite/rust/borrowck/use_while_mut_fr.rs19
-rw-r--r--gcc/testsuite/rust/borrowck/well_formed_function_inputs.rs21
-rw-r--r--gcc/testsuite/rust/compile/assume.rs2
-rw-r--r--gcc/testsuite/rust/compile/auto_trait.rs1
-rw-r--r--gcc/testsuite/rust/compile/auto_trait_super_trait.rs1
-rw-r--r--gcc/testsuite/rust/compile/box_syntax_feature_gate.rs2
-rw-r--r--gcc/testsuite/rust/compile/builtin_macro_include_bytes.rs15
-rw-r--r--gcc/testsuite/rust/compile/builtin_macro_include_str.rs16
-rw-r--r--gcc/testsuite/rust/compile/exhaustiveness1.rs53
-rw-r--r--gcc/testsuite/rust/compile/exhaustiveness2.rs28
-rw-r--r--gcc/testsuite/rust/compile/exhaustiveness3.rs55
-rw-r--r--gcc/testsuite/rust/compile/functions_without_body.rs1
-rw-r--r--gcc/testsuite/rust/compile/generic_auto_trait.rs1
-rw-r--r--gcc/testsuite/rust/compile/inline_asm_compile_nop.rs12
-rw-r--r--gcc/testsuite/rust/compile/inline_asm_illegal_operands.rs6
-rw-r--r--gcc/testsuite/rust/compile/inline_asm_parse_operand.rs20
-rw-r--r--gcc/testsuite/rust/compile/inline_asm_parse_output_operand.rs18
-rw-r--r--gcc/testsuite/rust/compile/inline_asm_typecheck.rs20
-rw-r--r--gcc/testsuite/rust/compile/issue-1901.rs2
-rw-r--r--gcc/testsuite/rust/compile/issue-1981.rs2
-rw-r--r--gcc/testsuite/rust/compile/issue-2203.rs3
-rw-r--r--gcc/testsuite/rust/compile/issue-2324-1.rs19
-rw-r--r--gcc/testsuite/rust/compile/issue-2324-2.rs19
-rw-r--r--gcc/testsuite/rust/compile/issue-2499.rs11
-rw-r--r--gcc/testsuite/rust/compile/issue-2951.rs13
-rw-r--r--gcc/testsuite/rust/compile/issue-3030.rs16
-rw-r--r--gcc/testsuite/rust/compile/issue-3035.rs25
-rw-r--r--gcc/testsuite/rust/compile/issue-3036.rs14
-rw-r--r--gcc/testsuite/rust/compile/issue-3045-1.rs21
-rw-r--r--gcc/testsuite/rust/compile/issue-3045-2.rs20
-rw-r--r--gcc/testsuite/rust/compile/issue-3082.rs9
-rw-r--r--gcc/testsuite/rust/compile/issue-3139-1.rs45
-rw-r--r--gcc/testsuite/rust/compile/issue-3139-2.rs57
-rw-r--r--gcc/testsuite/rust/compile/issue-3139-3.rs32
-rw-r--r--gcc/testsuite/rust/compile/issue-3141.rs62
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/builtin_macro.exp35
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/compile_error.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_compile_error.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/concat.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_concat.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/eager1.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_eager1.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/eager2.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_eager2.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/eager3.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_eager3.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/env.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_env.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include1.rs14
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include2.rs11
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include3.rs19
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include4.rs15
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs23
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include_bytes_location_info.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_include_bytes_location_info.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include_rs1
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include_rs21
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include_str.rs24
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/include_str_location_info.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_include_str_location_info.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/invalid_utf8 (renamed from gcc/testsuite/rust/compile/invalid_utf8)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/not_found.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_not_found.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/builtin/recurse2.rs (renamed from gcc/testsuite/rust/compile/builtin_macro_recurse2.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-delim.rs (renamed from gcc/testsuite/rust/compile/macro-delim.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue1053-2.rs (renamed from gcc/testsuite/rust/compile/macro-issue1053-2.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue1053.rs (renamed from gcc/testsuite/rust/compile/macro-issue1053.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue1224.rs (renamed from gcc/testsuite/rust/compile/macro-issue1224.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs (renamed from gcc/testsuite/rust/compile/macro-issue1233.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue1395-2.rs (renamed from gcc/testsuite/rust/compile/macro-issue1395-2.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue1395.rs (renamed from gcc/testsuite/rust/compile/macro-issue1395.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue1400-2.rs (renamed from gcc/testsuite/rust/compile/macro-issue1400-2.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue1400.rs (renamed from gcc/testsuite/rust/compile/macro-issue1400.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2092.rs (renamed from gcc/testsuite/rust/compile/macro-issue2092.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2192.rs (renamed from gcc/testsuite/rust/compile/macro-issue2192.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2194.rs (renamed from gcc/testsuite/rust/compile/macro-issue2194.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2229.rs (renamed from gcc/testsuite/rust/compile/macro-issue2229.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2264.rs (renamed from gcc/testsuite/rust/compile/macro-issue2264.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2268.rs (renamed from gcc/testsuite/rust/compile/macro-issue2268.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2273.rs (renamed from gcc/testsuite/rust/compile/macro-issue2273.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2653.rs (renamed from gcc/testsuite/rust/compile/macro-issue2653.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs27
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro1.rs (renamed from gcc/testsuite/rust/compile/macro1.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro10.rs (renamed from gcc/testsuite/rust/compile/macro10.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro11.rs (renamed from gcc/testsuite/rust/compile/macro11.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro12.rs (renamed from gcc/testsuite/rust/compile/macro12.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro13.rs (renamed from gcc/testsuite/rust/compile/macro13.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro14.rs (renamed from gcc/testsuite/rust/compile/macro14.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro15.rs (renamed from gcc/testsuite/rust/compile/macro15.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro16.rs (renamed from gcc/testsuite/rust/compile/macro16.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro17.rs (renamed from gcc/testsuite/rust/compile/macro17.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro18.rs (renamed from gcc/testsuite/rust/compile/macro18.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro19.rs (renamed from gcc/testsuite/rust/compile/macro19.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro2.rs (renamed from gcc/testsuite/rust/compile/macro2.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro20.rs (renamed from gcc/testsuite/rust/compile/macro20.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro21.rs (renamed from gcc/testsuite/rust/compile/macro21.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro22.rs (renamed from gcc/testsuite/rust/compile/macro22.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro23.rs (renamed from gcc/testsuite/rust/compile/macro23.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro25.rs (renamed from gcc/testsuite/rust/compile/macro25.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro26.rs (renamed from gcc/testsuite/rust/compile/macro26.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro27.rs (renamed from gcc/testsuite/rust/compile/macro27.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro28.rs (renamed from gcc/testsuite/rust/compile/macro28.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro29.rs (renamed from gcc/testsuite/rust/compile/macro29.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro3.rs (renamed from gcc/testsuite/rust/compile/macro3.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro30.rs (renamed from gcc/testsuite/rust/compile/macro30.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro31.rs (renamed from gcc/testsuite/rust/compile/macro31.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro32.rs (renamed from gcc/testsuite/rust/compile/macro32.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro33.rs (renamed from gcc/testsuite/rust/compile/macro33.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro34.rs (renamed from gcc/testsuite/rust/compile/macro34.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro35.rs (renamed from gcc/testsuite/rust/compile/macro35.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro36.rs (renamed from gcc/testsuite/rust/compile/macro36.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro37.rs (renamed from gcc/testsuite/rust/compile/macro37.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro38.rs (renamed from gcc/testsuite/rust/compile/macro38.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro39.rs (renamed from gcc/testsuite/rust/compile/macro39.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro4.rs (renamed from gcc/testsuite/rust/compile/macro4.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro40.rs (renamed from gcc/testsuite/rust/compile/macro40.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro41.rs (renamed from gcc/testsuite/rust/compile/macro41.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro42.rs (renamed from gcc/testsuite/rust/compile/macro42.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro43.rs (renamed from gcc/testsuite/rust/compile/macro43.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro44.rs (renamed from gcc/testsuite/rust/compile/macro44.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro45.rs (renamed from gcc/testsuite/rust/compile/macro45.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro46.rs (renamed from gcc/testsuite/rust/compile/macro46.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro47.rs (renamed from gcc/testsuite/rust/compile/macro47.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro48.rs (renamed from gcc/testsuite/rust/compile/macro48.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro49.rs (renamed from gcc/testsuite/rust/compile/macro49.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro5.rs (renamed from gcc/testsuite/rust/compile/macro5.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro50.rs (renamed from gcc/testsuite/rust/compile/macro50.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro51.rs (renamed from gcc/testsuite/rust/compile/macro51.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro52.rs (renamed from gcc/testsuite/rust/compile/macro52.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro53.rs (renamed from gcc/testsuite/rust/compile/macro53.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro54.rs (renamed from gcc/testsuite/rust/compile/macro54.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro55.rs (renamed from gcc/testsuite/rust/compile/macro55.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro56.rs (renamed from gcc/testsuite/rust/compile/macro56.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro57.rs (renamed from gcc/testsuite/rust/compile/macro57.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro6.rs (renamed from gcc/testsuite/rust/compile/macro6.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro7.rs (renamed from gcc/testsuite/rust/compile/macro7.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro8.rs (renamed from gcc/testsuite/rust/compile/macro8.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro9.rs (renamed from gcc/testsuite/rust/compile/macro9.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro_call_statement.rs (renamed from gcc/testsuite/rust/compile/macro_call_statement.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro_export_1.rs (renamed from gcc/testsuite/rust/compile/macro_export_1.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro_return.rs (renamed from gcc/testsuite/rust/compile/macro_return.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro_rules_macro_rules.rs (renamed from gcc/testsuite/rust/compile/macro_rules_macro_rules.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro_use1.rs (renamed from gcc/testsuite/rust/compile/macro_use1.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/mbe_macro.exp35
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/attribute_crate_type.rs (renamed from gcc/testsuite/rust/compile/proc_macro_attribute_crate_type.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/attribute_non_function.rs (renamed from gcc/testsuite/rust/compile/proc_macro_attribute_non_function.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/attribute_non_root_function.rs (renamed from gcc/testsuite/rust/compile/proc_macro_attribute_non_root_function.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/attribute_non_root_method.rs (renamed from gcc/testsuite/rust/compile/proc_macro_attribute_non_root_method.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/attribute_non_root_module.rs (renamed from gcc/testsuite/rust/compile/proc_macro_attribute_non_root_module.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/attribute_private.rs (renamed from gcc/testsuite/rust/compile/proc_macro_attribute_private.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/crate_type.rs (renamed from gcc/testsuite/rust/compile/proc_macro_crate_type.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/derive_crate_type.rs (renamed from gcc/testsuite/rust/compile/proc_macro_derive_crate_type.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/derive_malformed.rs (renamed from gcc/testsuite/rust/compile/proc_macro_derive_malformed.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/derive_non_function.rs (renamed from gcc/testsuite/rust/compile/proc_macro_derive_non_function.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/derive_non_root_function.rs (renamed from gcc/testsuite/rust/compile/proc_macro_derive_non_root_function.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/derive_non_root_module.rs (renamed from gcc/testsuite/rust/compile/proc_macro_derive_non_root_module.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/derive_private.rs (renamed from gcc/testsuite/rust/compile/proc_macro_derive_private.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/non_function.rs (renamed from gcc/testsuite/rust/compile/proc_macro_non_function.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/non_root_function.rs (renamed from gcc/testsuite/rust/compile/proc_macro_non_root_function.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/non_root_method.rs (renamed from gcc/testsuite/rust/compile/proc_macro_non_root_method.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/non_root_module.rs (renamed from gcc/testsuite/rust/compile/proc_macro_non_root_module.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/non_root_trait_method.rs (renamed from gcc/testsuite/rust/compile/proc_macro_derive_non_root_method.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/private.rs (renamed from gcc/testsuite/rust/compile/proc_macro_private.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/proc_macro.exp35
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/pub_function.rs (renamed from gcc/testsuite/rust/compile/proc_macro_pub_function.rs)0
-rw-r--r--gcc/testsuite/rust/compile/macros/proc/pub_module.rs (renamed from gcc/testsuite/rust/compile/proc_macro_pub_module.rs)0
-rw-r--r--gcc/testsuite/rust/compile/match8.rs19
-rw-r--r--gcc/testsuite/rust/compile/match9.rs30
-rw-r--r--gcc/testsuite/rust/compile/nonexistent-field.rs14
-rw-r--r--gcc/testsuite/rust/compile/nr2/compile.exp136
-rw-r--r--gcc/testsuite/rust/compile/nr2/exclude237
-rw-r--r--gcc/testsuite/rust/compile/prelude_import.rs12
-rw-r--r--gcc/testsuite/rust/compile/sizeof-stray-infer-var-bug.rs2
-rw-r--r--gcc/testsuite/rust/compile/torture/intrinsics-8.rs2
-rw-r--r--gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs2
-rw-r--r--gcc/testsuite/rust/compile/torture/transmute1.rs2
-rw-r--r--gcc/testsuite/rust/compile/torture/uninit-intrinsic-1.rs2
-rw-r--r--gcc/testsuite/rust/compile/trait13.rs47
-rw-r--r--gcc/testsuite/rust/compile/trait14.rs51
-rw-r--r--gcc/testsuite/rust/compile/v0-mangle1.rs2
-rw-r--r--gcc/testsuite/rust/compile/xfail/name_resolution21.rs (renamed from gcc/testsuite/rust/compile/name_resolution21.rs)3
-rw-r--r--gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs49
-rw-r--r--gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs11
-rw-r--r--gcc/testsuite/rust/execute/torture/inline_asm_mov_x_5_ARM.rs36
-rw-r--r--gcc/testsuite/rust/execute/torture/inline_asm_mov_x_5_x86_64.rs35
-rw-r--r--gcc/testsuite/rust/execute/torture/issue-1436.rs3
-rw-r--r--gcc/testsuite/rust/execute/torture/issue-2583.rs2
-rw-r--r--gcc/testsuite/rust/execute/torture/trait14.rs47
-rw-r--r--gcc/testsuite/rust/execute/torture/trait15.rs56
-rw-r--r--gcc/testsuite/rust/execute/torture/trait16.rs52
-rw-r--r--gcc/testsuite/rust/execute/torture/trait17.rs54
-rw-r--r--gcc/testsuite/rust/execute/torture/trait18.rs56
-rw-r--r--gcc/testsuite/rust/rustc/README.md4
-rw-r--r--gcc/testsuite/rust/rustc/rustc.exp35
-rw-r--r--gcc/toplev.cc2
448 files changed, 21979 insertions, 3333 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 736c5f8..0f50aff 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,57 @@
+2025-03-18 Georg-Johann Lay <avr@gjlay.de>
+
+ PR target/119355
+ * config/avr/avr-passes.cc (memento_t::apply): Only
+ read values[p.arg] when it is actually used.
+
+2025-03-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR cobol/119301
+ * config.in: Regenerate.
+ * configure: Regenerate.
+ * configure.ac: Add check for get_current_dir_name.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/116545
+ * doc/extend.texi (musttail statement attribute): Document
+ that musttail GNU attribute can be used as well.
+
+2025-03-18 Michael Matz <matz@suse.de>
+
+ * config/rs6000/rs6000.opt.urls: Regenerate.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ * doc/sourcebuild.texi (dg-output-file): Document.
+
+2025-03-18 Andrew Pinski <quic_apinski@quicinc.com>
+
+ * gimple-ssa-sccopy.cc (scc_copy_prop::replace_scc_by_value): Dump
+ what is being replaced with what.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/119307
+ * lra.cc (lra_rtx_hash): Handle SUBREG.
+
+2025-03-18 Richard Biener <rguenther@suse.de>
+
+ PR debug/101533
+ * dwarf2out.cc (gen_type_die_with_usage): When we have
+ output the typedef already do nothing for a typedef variant.
+ Do not set TREE_ASM_WRITTEN on the type.
+
+2025-03-18 Jeff Law <jlaw@ventanamicro.com>
+
+ * config/riscv/riscv.md (equality shifted-arith splitter): Do not
+ create op AND -1 as it won't be cleaned up post-reload.
+
+2025-03-18 Andrew Pinski <quic_apinski@quicinc.com>
+
+ * configure: Regenerate.
+ * configure.ac: s/gcc_cv_ld64_macosx_version_min/gcc_cv_ld64_macos_version_min/.
+
2025-03-17 Jeff Law <jlaw@ventanamicro.com>
* config/riscv/bitmanip.md (*<or_optab>i<mode>_extrabit): Reject cases
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index c0dd068..22523f5 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20250318
+20250319
diff --git a/gcc/ada/gcc-interface/decl.cc b/gcc/ada/gcc-interface/decl.cc
index 1854c58..1694b4e 100644
--- a/gcc/ada/gcc-interface/decl.cc
+++ b/gcc/ada/gcc-interface/decl.cc
@@ -3651,6 +3651,14 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
TYPE_PACKED (gnu_type) = TYPE_PACKED (gnu_base_type);
TYPE_REVERSE_STORAGE_ORDER (gnu_type)
= Reverse_Storage_Order (gnat_entity);
+
+ /* Do the same for subtypes as for the base type, since pointers
+ to them may symmetrically also point to the latter. */
+ prepend_one_attribute
+ (&attr_list, ATTR_MACHINE_ATTRIBUTE,
+ get_identifier ("may_alias"), NULL_TREE,
+ gnat_entity);
+
process_attributes (&gnu_type, &attr_list, true, gnat_entity);
/* Set the size, alignment and alias set of the type to match
diff --git a/gcc/ada/gen_il-gen-gen_nodes.adb b/gcc/ada/gen_il-gen-gen_nodes.adb
index 1f5dc6d..eb03536 100644
--- a/gcc/ada/gen_il-gen-gen_nodes.adb
+++ b/gcc/ada/gen_il-gen-gen_nodes.adb
@@ -1309,7 +1309,7 @@ begin -- Gen_IL.Gen.Gen_Nodes
Cc (N_Formal_Modular_Type_Definition, Node_Kind);
Cc (N_Formal_Ordinary_Fixed_Point_Definition, Node_Kind);
- Cc (N_Formal_Package_Declaration, Node_Kind,
+ Cc (N_Formal_Package_Declaration, N_Declaration,
(Sy (Defining_Identifier, Node_Id),
Sy (Name, Node_Id, Default_Empty),
Sy (Generic_Associations, List_Id, Default_No_List),
diff --git a/gcc/ada/gnatvsn.adb b/gcc/ada/gnatvsn.adb
index 5b7b4fb..58f8a1a 100644
--- a/gcc/ada/gnatvsn.adb
+++ b/gcc/ada/gnatvsn.adb
@@ -41,10 +41,11 @@ package body Gnatvsn is
function Gnat_Free_Software return String is
begin
return
- "This is free software; see the source for copying conditions." &
+ "This is free software; see the source for copying conditions. " &
+ "There is NO" &
ASCII.LF &
- "There is NO warranty; not even for MERCHANTABILITY or FITNESS" &
- " FOR A PARTICULAR PURPOSE.";
+ "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR " &
+ "PURPOSE.";
end Gnat_Free_Software;
type char_array is array (Natural range <>) of aliased Character;
diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb
index dad8c73..5768e28e 100644
--- a/gcc/ada/sem_ch12.adb
+++ b/gcc/ada/sem_ch12.adb
@@ -11551,6 +11551,7 @@ package body Sem_Ch12 is
function Get_Formal_Entity (N : Node_Id) return Entity_Id is
Kind : constant Node_Kind := Nkind (Original_Node (N));
+
begin
case Kind is
when N_Formal_Object_Declaration =>
@@ -11565,9 +11566,6 @@ package body Sem_Ch12 is
when N_Formal_Package_Declaration =>
return Defining_Identifier (Original_Node (N));
- when N_Generic_Package_Declaration =>
- return Defining_Identifier (Original_Node (N));
-
-- All other declarations are introduced by semantic analysis and
-- have no match in the actual.
@@ -11806,6 +11804,26 @@ package body Sem_Ch12 is
end if;
Next_Non_Pragma (Formal_Node);
+
+ -- If the actual of the local package created for the formal
+ -- is itself an instantiated formal package, then it could
+ -- have given rise to additional declarations, see the code
+ -- dealing with conformance checking below.
+
+ if Nkind (Actual_Of_Formal) = N_Package_Renaming_Declaration
+ and then Requires_Conformance_Checking
+ (Declaration_Node
+ (Associated_Formal_Package
+ (Defining_Entity (Actual_Of_Formal))))
+ then
+ Next (Actual_Of_Formal);
+ pragma Assert
+ (Nkind (Actual_Of_Formal) = N_Package_Declaration);
+ Next (Actual_Of_Formal);
+ pragma Assert
+ (Nkind (Actual_Of_Formal) = N_Package_Instantiation);
+ end if;
+
Next (Actual_Of_Formal);
-- A formal subprogram may be overloaded, so advance in
@@ -11861,10 +11879,15 @@ package body Sem_Ch12 is
-- checking, because it contains formal declarations for those
-- defaulted parameters, and those should not reach the back-end.
+ -- This processing needs to be synchronized with the pattern matching
+ -- done in the main loop of the above block that starts with the test
+ -- on Requires_Conformance_Checking.
+
if Requires_Conformance_Checking (Formal) then
declare
I_Pack : constant Entity_Id := Make_Temporary (Loc, 'P');
- I_Nam : Node_Id;
+ I_Nam : Node_Id;
+
begin
Set_Is_Internal (I_Pack);
Mutate_Ekind (I_Pack, E_Package);
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 3db9088..01ce574 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,8 @@
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/116545
+ * c-attribs.cc (c_common_clang_attributes): Add musttail.
+
2025-03-14 Jakub Jelinek <jakub@redhat.com>
PR target/119120
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 54775d4..c2528f6 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,19 @@
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/119311
+ * c-parser.cc (c_parser_if_body): Pass result of c_parser_all_labels
+ as last argument to c_parser_statement_after_labels.
+ (c_parser_else_body): Likewise.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/116545
+ * c-parser.cc (c_parser_declaration_or_fndef): Parse
+ __attribute__((musttail)) return.
+ (c_parser_handle_musttail): Diagnose attribute arguments.
+ (c_parser_statement_after_labels): Parse
+ __attribute__((musttail)) return.
+
2025-03-11 Jakub Jelinek <jakub@redhat.com>
PR c/117178
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 0dcbae9..1ae5208 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9846,7 +9846,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
&& TREE_CODE (vistype) == TREE_CODE (t)
&& !C_TYPE_BEING_DEFINED (vistype))
{
- TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (t);
+ TYPE_STUB_DECL (t) = TYPE_STUB_DECL (vistype);
if (c_type_variably_modified_p (t))
{
error ("redefinition of struct or union %qT with variably "
@@ -10321,7 +10321,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
&& TREE_CODE (vistype) == TREE_CODE (enumtype)
&& !C_TYPE_BEING_DEFINED (vistype))
{
- TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (enumtype);
+ TYPE_STUB_DECL (enumtype) = TYPE_STUB_DECL (vistype);
if (!comptypes_same_p (enumtype, vistype))
error("conflicting redefinition of enum %qT", enumtype);
}
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 11fa98d..71782bc 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1933,6 +1933,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
ft2 = DECL_BIT_FIELD_TYPE (s2);
}
+ if (TREE_CODE (ft1) == ERROR_MARK || TREE_CODE (ft2) == ERROR_MARK)
+ return false;
+
data->anon_field = !DECL_NAME (s1);
data->pointedto = false;
@@ -10274,24 +10277,29 @@ pop_init_level (location_t loc, int implicit,
&& !TYPE_MAX_VALUE (TYPE_DOMAIN (constructor_type)))
{
/* Silently discard empty initializations. The parser will
- already have pedwarned for empty brackets. */
+ already have pedwarned for empty brackets for C17 and earlier. */
if (integer_zerop (constructor_unfilled_index))
constructor_type = NULL_TREE;
- else
+ if (constructor_type || flag_isoc23)
{
- gcc_assert (!TYPE_SIZE (constructor_type));
+ gcc_assert (!constructor_type || !TYPE_SIZE (constructor_type));
- if (constructor_depth > 2)
+ if (constructor_depth <= 2)
+ pedwarn_init (loc, OPT_Wpedantic,
+ "initialization of a flexible array member");
+ else if (constructor_type)
error_init (loc, "initialization of flexible array member "
"in a nested context");
else
pedwarn_init (loc, OPT_Wpedantic,
- "initialization of a flexible array member");
+ "initialization of flexible array member "
+ "in a nested context");
/* We have already issued an error message for the existence
of a flexible array member not at the end of the structure.
Discard the initializer so that we do not die later. */
- if (DECL_CHAIN (constructor_fields) != NULL_TREE
+ if (constructor_type
+ && DECL_CHAIN (constructor_fields) != NULL_TREE
&& (!p->type || TREE_CODE (p->type) != UNION_TYPE))
constructor_type = NULL_TREE;
}
diff --git a/gcc/cobol/ChangeLog b/gcc/cobol/ChangeLog
index 9dfda4c..be421d2 100644
--- a/gcc/cobol/ChangeLog
+++ b/gcc/cobol/ChangeLog
@@ -1,3 +1,58 @@
+2025-03-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ * gcobolspec.cc (append_rpath): Remove.
+ (lang_specific_driver): Remove hard-wired rpath and library
+ names.
+
+2025-03-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ PR cobol/119301
+ * util.cc: Check for the availability of get_current_dir_name
+ snf fall back to getcwd() if it is not present on the host.
+
+2025-03-18 Richard Biener <rguenther@suse.de>
+
+ * gengen.cc (gg_finalize_function): Dump to TDI_original.
+
+2025-03-18 Bob Dubner <rdubner@symas.com>
+
+ * cdf.y: Make compatible with C++14.
+ * copybook.h: Likewise.
+ * dts.h: Likewise.
+ * except.cc: Likewise.
+ * genapi.cc: Likewise.
+ * genutil.cc: Likewise.
+ * genutil.h: Likewise.
+ * lexio.cc: Likewise.
+ * parse.y: Likewise.
+ * parse_ante.h: Likewise.
+ * show_parse.h: Likewise.
+ * symbols.cc: Likewise.
+ * symbols.h: Likewise.
+ * util.cc: Likewise.
+
+2025-03-18 Matthias Klose <doko@ubuntu.com>
+
+ * Make-lang.in (GCOBC_TARGET_INSTALL_NAME, gcobol-cross): New.
+ (cobol.all.cross): Depend on gcobol-cross.
+ (cobol.install-common): Adjust install for the cross build.
+ (cobol.uninstall): Use *_INSTALL_NAME for uninstall.
+
+2025-03-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ * util.cc (cbl_field_t::report_invalid_initial_value): Avoid
+ auto here and specify const char *.
+
+2025-03-18 Jose E. Marchesi <jose.marchesi@oracle.com>
+
+ * cdf-copy.cc (copybook_elem_t::open_file): Use ldirname rather
+ than dirname.
+
+2025-03-18 Iain Sandoe <iain@sandoe.co.uk>
+
+ * parse.y: Remove c++ header includes appearing after
+ system.h.
+
2025-03-17 Bob Dubner <rdubner@symas.com>
PR cobol/119213
diff --git a/gcc/cobol/gcobolspec.cc b/gcc/cobol/gcobolspec.cc
index 5bd6853..4ae8e2c 100644
--- a/gcc/cobol/gcobolspec.cc
+++ b/gcc/cobol/gcobolspec.cc
@@ -141,21 +141,6 @@ append_rdynamic()
}
static void
-append_rpath()
- {
-#ifdef EXEC_LIB
- // Handing append_option() something on the stack Just Doesn't Work
- if( strlen(EXEC_LIB) )
- {
- static char ach[256];
- snprintf(ach, sizeof(ach), "-rpath=%s", EXEC_LIB);
- append_option (OPT_Wl_, ach, 1);
- }
-#endif
- return;
- }
-
-static void
append_allow_multiple_definition()
{
append_option (OPT_Wl_, "--allow-multiple-definition", 1);
@@ -250,9 +235,6 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
int index_libgcobol_a = 0;
- // This is for the -Wl,-rpath=<EXEC_LIB>
- bool need_rpath = true;
-
bool no_files_error = true;
#ifdef NOISY
@@ -339,16 +321,6 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
{
need_allow_multiple_definition = false;
}
- if( strstr(decoded_options[i].orig_option_with_args_text, "-rpath") )
- {
- // The caller is doing something with -rpath. Assume they know what
- // they are doing
-
- // On second thought, always install our rpath. It goes at the end,
- // so if the user specifies and rpath that they prefer, it'll get
- // taken first.
- need_rpath = true;
- }
break;
case OPT_nostdlib:
@@ -616,12 +588,9 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
if( need_libgcobol )
{
-#ifdef EXEC_LIB
- append_option(OPT_L, EXEC_LIB, 1);
-#endif
add_arg_lib(COBOL_LIBRARY, static_libgcobol);
}
- if( need_libmath )
+ if( need_libmath)
{
add_arg_lib(MATH_LIBRARY, static_in_general);
}
@@ -649,11 +618,6 @@ lang_specific_driver (struct cl_decoded_option **in_decoded_options,
append_allow_multiple_definition();
}
- if( need_rpath && (n_infiles || n_outfiles) )
- {
- append_rpath();
- }
-
if( prior_main )
{
char ach[] = "\"-main\" without a source file";
diff --git a/gcc/cobol/util.cc b/gcc/cobol/util.cc
index 62ecd98..101a0a0 100644
--- a/gcc/cobol/util.cc
+++ b/gcc/cobol/util.cc
@@ -72,6 +72,25 @@ extern int yyparse(void);
extern int demonstration_administrator(int N);
+#if !defined (HAVE_GET_CURRENT_DIR_NAME)
+/* Posix platforms might not have get_current_dir_name but should have
+ getcwd() and PATH_MAX. */
+#if __has_include (<limits.h>)
+# include <limits.h>
+#endif
+/* The Hurd doesn't define PATH_MAX. */
+#if !defined (PATH_MAX) && defined(__GNU__)
+# define PATH_MAX 4096
+#endif
+static inline char *
+get_current_dir_name ()
+{
+ /* Use libiberty's allocator here. */
+ char *buf = (char *) xmalloc (PATH_MAX);
+ return getcwd (buf, PATH_MAX);
+}
+#endif
+
const char *
symbol_type_str( enum symbol_type_t type )
{
diff --git a/gcc/config.in b/gcc/config.in
index 0b46faa..bc60d36 100644
--- a/gcc/config.in
+++ b/gcc/config.in
@@ -1624,6 +1624,12 @@
#endif
+/* Define to 1 if you have the `get_current_dir_name' function. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GET_CURRENT_DIR_NAME
+#endif
+
+
/* Define to 1 if using GNU as. */
#ifndef USED_FOR_TARGET
#undef HAVE_GNU_AS
diff --git a/gcc/config/aarch64/aarch64-arches.def b/gcc/config/aarch64/aarch64-arches.def
index 34a792d..bf56fe9 100644
--- a/gcc/config/aarch64/aarch64-arches.def
+++ b/gcc/config/aarch64/aarch64-arches.def
@@ -45,7 +45,7 @@ AARCH64_ARCH("armv9-a", generic_armv9_a, V9A , 9, (V8_5A, SVE2))
AARCH64_ARCH("armv9.1-a", generic_armv9_a, V9_1A, 9, (V8_6A, V9A))
AARCH64_ARCH("armv9.2-a", generic_armv9_a, V9_2A, 9, (V8_7A, V9_1A))
AARCH64_ARCH("armv9.3-a", generic_armv9_a, V9_3A, 9, (V8_8A, V9_2A))
-AARCH64_ARCH("armv9.4-a", generic_armv9_a, V9_4A, 9, (V8_9A, V9_3A))
+AARCH64_ARCH("armv9.4-a", generic_armv9_a, V9_4A, 9, (V8_9A, V9_3A, SVE2p1))
AARCH64_ARCH("armv9.5-a", generic_armv9_a, V9_5A, 9, (V9_4A, CPA, FAMINMAX, LUT))
#undef AARCH64_ARCH
diff --git a/gcc/config/avr/avr-passes.cc b/gcc/config/avr/avr-passes.cc
index e32c467..184619a 100644
--- a/gcc/config/avr/avr-passes.cc
+++ b/gcc/config/avr/avr-passes.cc
@@ -2205,9 +2205,6 @@ memento_t::apply (const ply_t &p)
}
else if (p.size == 1)
{
- int x = values[p.regno];
- int y = values[p.arg];
-
switch (p.code)
{
default:
@@ -2234,29 +2231,42 @@ memento_t::apply (const ply_t &p)
gcc_unreachable ();
break;
-#define DO_ARITH(n_args, code, expr) \
+#define DO_ARITH1(code, expr) \
+ case code: \
+ gcc_assert (knows (p.regno)); \
+ { \
+ const int x = values[p.regno]; \
+ set_value (p.regno, expr); \
+ } \
+ break
+
+#define DO_ARITH2(code, expr) \
case code: \
gcc_assert (knows (p.regno)); \
- if (n_args == 2) \
- gcc_assert (knows (p.arg)); \
- set_value (p.regno, expr); \
+ gcc_assert (knows (p.arg)); \
+ { \
+ const int x = values[p.regno]; \
+ const int y = values[p.arg]; \
+ set_value (p.regno, expr); \
+ } \
break
- DO_ARITH (1, NEG, -x);
- DO_ARITH (1, NOT, ~x);
- DO_ARITH (1, PRE_INC, x + 1);
- DO_ARITH (1, PRE_DEC, x - 1);
- DO_ARITH (1, ROTATE, (x << 4) | (x >> 4));
- DO_ARITH (1, ASHIFT, x << 1);
- DO_ARITH (1, LSHIFTRT, x >> 1);
- DO_ARITH (1, ASHIFTRT, (x >> 1) | (x & 0x80));
-
- DO_ARITH (2, AND, x & y);
- DO_ARITH (2, IOR, x | y);
- DO_ARITH (2, XOR, x ^ y);
- DO_ARITH (2, PLUS, x + y);
- DO_ARITH (2, MINUS, x - y);
-#undef DO_ARITH
+ DO_ARITH1 (NEG, -x);
+ DO_ARITH1 (NOT, ~x);
+ DO_ARITH1 (PRE_INC, x + 1);
+ DO_ARITH1 (PRE_DEC, x - 1);
+ DO_ARITH1 (ROTATE, (x << 4) | (x >> 4));
+ DO_ARITH1 (ASHIFT, x << 1);
+ DO_ARITH1 (LSHIFTRT, x >> 1);
+ DO_ARITH1 (ASHIFTRT, (x >> 1) | (x & 0x80));
+
+ DO_ARITH2 (AND, x & y);
+ DO_ARITH2 (IOR, x | y);
+ DO_ARITH2 (XOR, x ^ y);
+ DO_ARITH2 (PLUS, x + y);
+ DO_ARITH2 (MINUS, x - y);
+#undef DO_ARITH1
+#undef DO_ARITH2
}
} // size == 1
else
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index 7b39103..70c2cf3 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -22414,7 +22414,8 @@
[(set (reg:CCZ FLAGS_REG)
(unspec:CCZ [(match_dup 0)
(match_dup 0)]
- UNSPEC_PTEST))])
+ UNSPEC_PTEST))]
+ "operands[0] = force_reg (<MODE>mode, operands[0]);")
(define_insn_and_split "*pmovsk_mask_cmp_<mode>_avx512"
[(set (reg:CCZ FLAGS_REG)
@@ -22455,7 +22456,8 @@
[(set (reg:CCZ FLAGS_REG)
(unspec:CCZ [(match_dup 0)
(match_dup 0)]
- UNSPEC_PTEST))])
+ UNSPEC_PTEST))]
+ "operands[0] = force_reg (<MODE>mode, operands[0]);")
(define_expand "sse2_maskmovdqu"
[(set (match_operand:V16QI 0 "memory_operand")
diff --git a/gcc/config/loongarch/loongarch.h b/gcc/config/loongarch/loongarch.h
index 42a38a4..d897763 100644
--- a/gcc/config/loongarch/loongarch.h
+++ b/gcc/config/loongarch/loongarch.h
@@ -941,6 +941,38 @@ typedef struct {
{ "s6", 29 + GP_REG_FIRST }, \
{ "s7", 30 + GP_REG_FIRST }, \
{ "s8", 31 + GP_REG_FIRST }, \
+ { "fa0", 0 + FP_REG_FIRST }, \
+ { "fa1", 1 + FP_REG_FIRST }, \
+ { "fa2", 2 + FP_REG_FIRST }, \
+ { "fa3", 3 + FP_REG_FIRST }, \
+ { "fa4", 4 + FP_REG_FIRST }, \
+ { "fa5", 5 + FP_REG_FIRST }, \
+ { "fa6", 6 + FP_REG_FIRST }, \
+ { "fa7", 7 + FP_REG_FIRST }, \
+ { "ft0", 8 + FP_REG_FIRST }, \
+ { "ft1", 9 + FP_REG_FIRST }, \
+ { "ft2", 10 + FP_REG_FIRST }, \
+ { "ft3", 11 + FP_REG_FIRST }, \
+ { "ft4", 12 + FP_REG_FIRST }, \
+ { "ft5", 13 + FP_REG_FIRST }, \
+ { "ft6", 14 + FP_REG_FIRST }, \
+ { "ft7", 15 + FP_REG_FIRST }, \
+ { "ft8", 16 + FP_REG_FIRST }, \
+ { "ft9", 17 + FP_REG_FIRST }, \
+ { "ft10", 18 + FP_REG_FIRST }, \
+ { "ft11", 19 + FP_REG_FIRST }, \
+ { "ft12", 20 + FP_REG_FIRST }, \
+ { "ft13", 21 + FP_REG_FIRST }, \
+ { "ft14", 22 + FP_REG_FIRST }, \
+ { "ft15", 23 + FP_REG_FIRST }, \
+ { "fs0", 24 + FP_REG_FIRST }, \
+ { "fs1", 25 + FP_REG_FIRST }, \
+ { "fs2", 26 + FP_REG_FIRST }, \
+ { "fs3", 27 + FP_REG_FIRST }, \
+ { "fs4", 28 + FP_REG_FIRST }, \
+ { "fs5", 29 + FP_REG_FIRST }, \
+ { "fs6", 30 + FP_REG_FIRST }, \
+ { "fs7", 31 + FP_REG_FIRST }, \
{ "v0", 4 + GP_REG_FIRST }, \
{ "v1", 5 + GP_REG_FIRST }, \
{ "vr0", 0 + FP_REG_FIRST }, \
diff --git a/gcc/configure b/gcc/configure
index 0ef47a9..ae1d349 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -10640,7 +10640,7 @@ for ac_func in times clock kill getrlimit setrlimit atoq \
popen sysconf strsignal getrusage nl_langinfo \
gettimeofday mbstowcs wcswidth mmap posix_fallocate setlocale \
clearerr_unlocked feof_unlocked ferror_unlocked fflush_unlocked fgetc_unlocked fgets_unlocked fileno_unlocked fprintf_unlocked fputc_unlocked fputs_unlocked fread_unlocked fwrite_unlocked getchar_unlocked getc_unlocked putchar_unlocked putc_unlocked madvise mallinfo mallinfo2 fstatat getauxval \
- clock_gettime munmap msync
+ clock_gettime munmap msync get_current_dir_name
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 4ac419a..8ef11e3 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -1574,7 +1574,7 @@ AC_CHECK_FUNCS(times clock kill getrlimit setrlimit atoq \
popen sysconf strsignal getrusage nl_langinfo \
gettimeofday mbstowcs wcswidth mmap posix_fallocate setlocale \
gcc_UNLOCKED_FUNCS madvise mallinfo mallinfo2 fstatat getauxval \
- clock_gettime munmap msync)
+ clock_gettime munmap msync get_current_dir_name)
# At least for glibc, clock_gettime is in librt. But don't pull that
# in if it still doesn't give us the function we want.
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 612e57d..d59d242 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,32 @@
+2025-03-18 Marek Polacek <polacek@redhat.com>
+
+ PR c++/119344
+ * typeck.cc (cp_build_binary_op): Use cp_save_expr instead of save_expr.
+
+2025-03-18 Jason Merrill <jason@redhat.com>
+
+ PR c++/119194
+ * decl2.cc (min_vis_expr_r) [ADDR_EXPR]: New case.
+
+2025-03-18 Marek Polacek <polacek@redhat.com>
+
+ PR c++/118104
+ * pt.cc (use_pack_expansion_extra_args_p): Remove an assert.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/116545
+ * parser.cc (cp_parser_statement): Call cp_parser_attributes_opt
+ rather than cp_parser_std_attribute_spec_seq.
+ (cp_parser_jump_statement): Diagnose gnu::musttail attributes
+ with no arguments.
+
+2025-03-18 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/119233
+ * pt.cc (mark_template_arguments_used): Also handle member
+ function pointers.
+
2025-03-14 Jakub Jelinek <jakub@redhat.com>
PR target/119120
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 04e4308..550cea29 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -519,7 +519,7 @@ cp_fold_immediate (tree *tp, mce_value manifestly_const_eval,
cp_fold_data data (flags);
int save_errorcount = errorcount;
- tree r = cp_walk_tree_without_duplicates (tp, cp_fold_immediate_r, &data);
+ tree r = cp_walk_tree (tp, cp_fold_immediate_r, &data, NULL);
if (errorcount > save_errorcount)
return integer_one_node;
return r;
@@ -1204,7 +1204,8 @@ cp_build_init_expr_for_ctor (tree call, tree init)
return init;
}
-/* A subroutine of cp_fold_r to handle immediate functions. */
+/* A walk_tree callback for cp_fold_function and cp_fully_fold_init to handle
+ immediate functions. */
static tree
cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_)
@@ -1250,7 +1251,19 @@ cp_fold_immediate_r (tree *stmt_p, int *walk_subtrees, void *data_)
if (!ADDR_EXPR_DENOTES_CALL_P (stmt))
decl = TREE_OPERAND (stmt, 0);
break;
+ case IF_STMT:
+ if (IF_STMT_CONSTEVAL_P (stmt))
+ {
+ if (!data->pset.add (stmt))
+ cp_walk_tree (&ELSE_CLAUSE (stmt), cp_fold_immediate_r, data_,
+ NULL);
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+ /* FALLTHRU */
default:
+ if (data->pset.add (stmt))
+ *walk_subtrees = 0;
return NULL_TREE;
}
@@ -1370,45 +1383,8 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
tree stmt = *stmt_p;
enum tree_code code = TREE_CODE (stmt);
- if (cxx_dialect >= cxx20)
- {
- /* Unfortunately we must handle code like
- false ? bar () : 42
- where we have to check bar too. The cp_fold call below could
- fold the ?: into a constant before we've checked it. */
- if (code == COND_EXPR)
- {
- auto then_fn = cp_fold_r, else_fn = cp_fold_r;
- /* See if we can figure out if either of the branches is dead. If it
- is, we don't need to do everything that cp_fold_r does. */
- cp_walk_tree (&TREE_OPERAND (stmt, 0), cp_fold_r, data, nullptr);
- if (integer_zerop (TREE_OPERAND (stmt, 0)))
- then_fn = cp_fold_immediate_r;
- else if (integer_nonzerop (TREE_OPERAND (stmt, 0)))
- else_fn = cp_fold_immediate_r;
-
- if (TREE_OPERAND (stmt, 1))
- cp_walk_tree (&TREE_OPERAND (stmt, 1), then_fn, data,
- nullptr);
- if (TREE_OPERAND (stmt, 2))
- cp_walk_tree (&TREE_OPERAND (stmt, 2), else_fn, data,
- nullptr);
- *walk_subtrees = 0;
- /* Don't return yet, still need the cp_fold below. */
- }
- else
- cp_fold_immediate_r (stmt_p, walk_subtrees, data);
- }
-
*stmt_p = stmt = cp_fold (*stmt_p, data->flags);
- /* For certain trees, like +foo(), the cp_fold above will remove the +,
- and the subsequent tree walk would go straight down to the CALL_EXPR's
- operands, meaning that cp_fold_immediate_r would never see the
- CALL_EXPR. Ew :(. */
- if (TREE_CODE (stmt) == CALL_EXPR && code != CALL_EXPR)
- cp_fold_immediate_r (stmt_p, walk_subtrees, data);
-
if (data->pset.add (stmt))
{
/* Don't walk subtrees of stmts we've already walked once, otherwise
@@ -1537,6 +1513,16 @@ cp_fold_function (tree fndecl)
been constant-evaluated already if possible, so we can safely
pass ff_mce_false. */
cp_fold_data data (ff_genericize | ff_mce_false);
+ /* Do cp_fold_immediate_r in separate whole IL walk instead of during
+ cp_fold_r, as otherwise expressions using results of immediate functions
+ might not be folded as cp_fold is called on those before cp_fold_r is
+ called on their argument. */
+ if (cxx_dialect >= cxx20)
+ {
+ cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_immediate_r,
+ &data, NULL);
+ data.pset.empty ();
+ }
cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_fold_r, &data, NULL);
/* This is merely an optimization: if FNDECL has no i-e expressions,
@@ -1717,6 +1703,11 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
case RETURN_EXPR:
if (TREE_OPERAND (stmt, 0))
{
+ if (error_operand_p (TREE_OPERAND (stmt, 0))
+ && warn_return_type)
+ /* Suppress -Wreturn-type for this function. */
+ suppress_warning (current_function_decl, OPT_Wreturn_type);
+
if (is_invisiref_parm (TREE_OPERAND (stmt, 0)))
/* Don't dereference an invisiref RESULT_DECL inside a
RETURN_EXPR. */
@@ -2922,6 +2913,11 @@ cp_fully_fold_init (tree x)
return x;
x = cp_fully_fold (x, mce_false);
cp_fold_data data (ff_mce_false);
+ if (cxx_dialect >= cxx20)
+ {
+ cp_walk_tree (&x, cp_fold_immediate_r, &data, NULL);
+ data.pset.empty ();
+ }
cp_walk_tree (&x, cp_fold_r, &data, NULL);
return x;
}
diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc
index 4a9fb1c..a3149f2 100644
--- a/gcc/cp/decl2.cc
+++ b/gcc/cp/decl2.cc
@@ -2843,16 +2843,28 @@ min_vis_expr_r (tree *tp, int */*walk_subtrees*/, void *data)
tpvis = type_visibility (TREE_TYPE (t));
break;
+ case ADDR_EXPR:
+ t = TREE_OPERAND (t, 0);
+ if (VAR_P (t))
+ /* If a variable has its address taken, the lvalue-rvalue conversion is
+ not applied, so skip that case. */
+ goto addressable;
+ break;
+
case VAR_DECL:
case FUNCTION_DECL:
if (decl_constant_var_p (t))
/* The ODR allows definitions in different TUs to refer to distinct
constant variables with internal or no linkage, so such a reference
- shouldn't affect visibility (PR110323). FIXME but only if the
- lvalue-rvalue conversion is applied. We still want to restrict
- visibility according to the type of the declaration however. */
- tpvis = type_visibility (TREE_TYPE (t));
- else if (! TREE_PUBLIC (t))
+ shouldn't affect visibility if the lvalue-rvalue conversion is
+ applied (PR110323). We still want to restrict visibility according
+ to the type of the declaration however. */
+ {
+ tpvis = type_visibility (TREE_TYPE (t));
+ break;
+ }
+ addressable:
+ if (! TREE_PUBLIC (t))
tpvis = VISIBILITY_ANON;
else
tpvis = DECL_VISIBILITY (t);
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index df61f2d..9ca5cf6 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -3642,10 +3642,15 @@ write_expression (tree expr)
if (nelts)
{
- tree domain;
++processing_template_decl;
- domain = compute_array_index_type (NULL_TREE, nelts,
- tf_warning_or_error);
+ /* Avoid compute_array_index_type complaints about
+ non-constant nelts. */
+ tree max = cp_build_binary_op (input_location, MINUS_EXPR,
+ fold_convert (sizetype, nelts),
+ size_one_node,
+ tf_warning_or_error);
+ max = maybe_constant_value (max);
+ tree domain = build_index_type (max);
type = build_cplus_array_type (type, domain);
--processing_template_decl;
}
@@ -4242,6 +4247,8 @@ write_array_type (const tree type)
}
else
{
+ gcc_checking_assert (TREE_CODE (max) == MINUS_EXPR
+ && integer_onep (TREE_OPERAND (max, 1)));
max = TREE_OPERAND (max, 0);
write_expression (max);
}
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 50eda18..538ff22 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -13180,7 +13180,16 @@ use_pack_expansion_extra_args_p (tree t,
if (has_expansion_arg && has_non_expansion_arg)
{
- gcc_checking_assert (false);
+ /* We can get here with:
+
+ template <class... Ts> struct X {
+ template <class... Us> using Y = Z<void(Ts, Us)...>;
+ };
+ template <class A, class... P>
+ using foo = X<int, int>::Y<A, P...>;
+
+ where we compare int and A and then the second int and P...,
+ whose expansion-ness doesn't match, but that's OK. */
return true;
}
}
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 4b382b9..c8e4441 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -5480,7 +5480,7 @@ cp_build_binary_op (const op_location_t &location,
case stv_firstarg:
{
op0 = convert (TREE_TYPE (type1), op0);
- op0 = save_expr (op0);
+ op0 = cp_save_expr (op0);
op0 = build_vector_from_val (type1, op0);
orig_type0 = type0 = TREE_TYPE (op0);
code0 = TREE_CODE (type0);
@@ -5490,7 +5490,7 @@ cp_build_binary_op (const op_location_t &location,
case stv_secondarg:
{
op1 = convert (TREE_TYPE (type0), op1);
- op1 = save_expr (op1);
+ op1 = cp_save_expr (op1);
op1 = build_vector_from_val (type0, op1);
orig_type1 = type1 = TREE_TYPE (op1);
code1 = TREE_CODE (type1);
@@ -6019,9 +6019,9 @@ cp_build_binary_op (const op_location_t &location,
return error_mark_node;
if (TREE_SIDE_EFFECTS (op0))
- op0 = save_expr (op0);
+ op0 = cp_save_expr (op0);
if (TREE_SIDE_EFFECTS (op1))
- op1 = save_expr (op1);
+ op1 = cp_save_expr (op1);
pfn0 = pfn_from_ptrmemfunc (op0);
pfn0 = cp_fully_fold (pfn0);
@@ -6262,8 +6262,8 @@ cp_build_binary_op (const op_location_t &location,
&& !processing_template_decl
&& sanitize_flags_p (SANITIZE_POINTER_COMPARE))
{
- op0 = save_expr (op0);
- op1 = save_expr (op1);
+ op0 = cp_save_expr (op0);
+ op1 = cp_save_expr (op1);
tree tt = builtin_decl_explicit (BUILT_IN_ASAN_POINTER_COMPARE);
instrument_expr = build_call_expr_loc (location, tt, 2, op0, op1);
@@ -6523,14 +6523,14 @@ cp_build_binary_op (const op_location_t &location,
return error_mark_node;
if (first_complex)
{
- op0 = save_expr (op0);
+ op0 = cp_save_expr (op0);
real = cp_build_unary_op (REALPART_EXPR, op0, true, complain);
imag = cp_build_unary_op (IMAGPART_EXPR, op0, true, complain);
switch (code)
{
case MULT_EXPR:
case TRUNC_DIV_EXPR:
- op1 = save_expr (op1);
+ op1 = cp_save_expr (op1);
imag = build2 (resultcode, real_type, imag, op1);
/* Fall through. */
case PLUS_EXPR:
@@ -6543,13 +6543,13 @@ cp_build_binary_op (const op_location_t &location,
}
else
{
- op1 = save_expr (op1);
+ op1 = cp_save_expr (op1);
real = cp_build_unary_op (REALPART_EXPR, op1, true, complain);
imag = cp_build_unary_op (IMAGPART_EXPR, op1, true, complain);
switch (code)
{
case MULT_EXPR:
- op0 = save_expr (op0);
+ op0 = cp_save_expr (op0);
imag = build2 (resultcode, real_type, op0, imag);
/* Fall through. */
case PLUS_EXPR:
diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog
index 0724c0d..cfa41f2 100644
--- a/gcc/d/ChangeLog
+++ b/gcc/d/ChangeLog
@@ -1,3 +1,11 @@
+2025-03-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd fde0f8c40a.
+
+2025-03-18 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd 51be8bb729.
+
2025-03-16 Iain Buclaw <ibuclaw@gdcproject.org>
* dmd/MERGE: Merge upstream dmd 603225372b.
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index 554992b..8dbc91e 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -4365,7 +4365,7 @@ test_message_with_embedded_link (enum sarif_version version)
};
test_sarif_diagnostic_context dc ("test.c", version);
- dc.set_urlifier (::make_unique<test_urlifier> ());
+ dc.push_owned_urlifier (::make_unique<test_urlifier> ());
rich_location richloc (line_table, UNKNOWN_LOCATION);
dc.report (DK_ERROR, richloc, nullptr, 0,
"foo %<-foption%> %<unrecognized%> bar");
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index c2f6714..82d7f94 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -254,7 +254,7 @@ diagnostic_context::initialize (int n_opts)
m_text_callbacks.m_start_span = default_diagnostic_start_span_fn;
m_text_callbacks.m_end_diagnostic = default_diagnostic_text_finalizer;
m_option_mgr = nullptr;
- m_urlifier = nullptr;
+ m_urlifier_stack = new auto_vec<urlifier_stack_node> ();
m_last_location = UNKNOWN_LOCATION;
m_client_aux_data = nullptr;
m_lock = 0;
@@ -424,8 +424,13 @@ diagnostic_context::finish ()
delete m_option_mgr;
m_option_mgr = nullptr;
- delete m_urlifier;
- m_urlifier = nullptr;
+ if (m_urlifier_stack)
+ {
+ while (!m_urlifier_stack->is_empty ())
+ pop_urlifier ();
+ delete m_urlifier_stack;
+ m_urlifier_stack = nullptr;
+ }
freeargv (m_original_argv);
m_original_argv = nullptr;
@@ -549,13 +554,43 @@ set_option_manager (std::unique_ptr<diagnostic_option_manager> mgr,
}
void
-diagnostic_context::set_urlifier (std::unique_ptr<urlifier> urlifier)
+diagnostic_context::push_owned_urlifier (std::unique_ptr<urlifier> ptr)
{
- delete m_urlifier;
- /* Ideally the field would be a std::unique_ptr here. */
- m_urlifier = urlifier.release ();
+ gcc_assert (m_urlifier_stack);
+ const urlifier_stack_node node = { ptr.release (), true };
+ m_urlifier_stack->safe_push (node);
}
+void
+diagnostic_context::push_borrowed_urlifier (const urlifier &loan)
+{
+ gcc_assert (m_urlifier_stack);
+ const urlifier_stack_node node = { const_cast <urlifier *> (&loan), false };
+ m_urlifier_stack->safe_push (node);
+}
+
+void
+diagnostic_context::pop_urlifier ()
+{
+ gcc_assert (m_urlifier_stack);
+ gcc_assert (m_urlifier_stack->length () > 0);
+
+ const urlifier_stack_node node = m_urlifier_stack->pop ();
+ if (node.m_owned)
+ delete node.m_urlifier;
+}
+
+const urlifier *
+diagnostic_context::get_urlifier () const
+{
+ if (!m_urlifier_stack)
+ return nullptr;
+ if (m_urlifier_stack->is_empty ())
+ return nullptr;
+ return m_urlifier_stack->last ().m_urlifier;
+}
+
+
/* Set PP as the reference printer for this context.
Refresh all output sinks. */
@@ -605,14 +640,6 @@ diagnostic_context::set_prefixing_rule (diagnostic_prefixing_rule_t rule)
pp_prefixing_rule (sink->get_printer ()) = rule;
}
-/* Set the urlifier without deleting the existing one. */
-
-void
-diagnostic_context::override_urlifier (urlifier *urlifier)
-{
- m_urlifier = urlifier;
-}
-
void
diagnostic_context::create_edit_context ()
{
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 202760b..62bffd2 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -609,8 +609,11 @@ public:
void set_output_format (std::unique_ptr<diagnostic_output_format> output_format);
void set_text_art_charset (enum diagnostic_text_art_charset charset);
void set_client_data_hooks (std::unique_ptr<diagnostic_client_data_hooks> hooks);
- void set_urlifier (std::unique_ptr<urlifier>);
- void override_urlifier (urlifier *);
+
+ void push_owned_urlifier (std::unique_ptr<urlifier>);
+ void push_borrowed_urlifier (const urlifier &);
+ void pop_urlifier ();
+
void create_edit_context ();
void set_warning_as_error_requested (bool val)
{
@@ -667,7 +670,8 @@ public:
{
return m_client_data_hooks;
}
- urlifier *get_urlifier () const { return m_urlifier; }
+
+ const urlifier *get_urlifier () const;
text_art::theme *get_diagram_theme () const { return m_diagrams.m_theme; }
@@ -888,11 +892,16 @@ private:
diagnostic_option_manager *m_option_mgr;
unsigned m_lang_mask;
- /* An optional hook for adding URLs to quoted text strings in
+ /* A stack of optional hooks for adding URLs to quoted text strings in
diagnostics. Only used for the main diagnostic message.
- Owned by the context; this would be a std::unique_ptr if
- diagnostic_context had a proper ctor. */
- urlifier *m_urlifier;
+ Typically a single one owner by the context, but can be temporarily
+ overridden by a borrowed urlifier (e.g. on-stack). */
+ struct urlifier_stack_node
+ {
+ urlifier *m_urlifier;
+ bool m_owned;
+ };
+ auto_vec<urlifier_stack_node> *m_urlifier_stack;
public:
/* Auxiliary data for client. */
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7bef9bb..1819bcd 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -21708,7 +21708,7 @@ and the features that they enable by default:
@item @samp{armv9.1-a} @tab Armv9.1-A @tab @samp{armv9-a}, @samp{+bf16}, @samp{+i8mm}
@item @samp{armv9.2-a} @tab Armv9.2-A @tab @samp{armv9.1-a}, @samp{+wfxt}, @samp{+xs}
@item @samp{armv9.3-a} @tab Armv9.3-A @tab @samp{armv9.2-a}, @samp{+mops}
-@item @samp{armv9.4-a} @tab Armv9.4-A @tab @samp{armv9.3-a}
+@item @samp{armv9.4-a} @tab Armv9.4-A @tab @samp{armv9.3-a}, @samp{+sve2p1}
@item @samp{armv9.5-a} @tab Armv9.4-A @tab @samp{armv9.4-a}, @samp{cpa}, @samp{+faminmax}, @samp{+lut}
@item @samp{armv8-r} @tab Armv8-R @tab @samp{armv8-r}
@end multitable
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 9e5f939..a61e6f5 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,10 @@
+2025-03-18 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/119338
+ * resolve.cc (resolve_allocate_expr): Check F2003:C626: Type-spec
+ in ALLOCATE of an assumed-length character dummy argument shall be
+ an asterisk.
+
2025-03-16 Harald Anlauf <anlauf@gmx.de>
PR fortran/60560
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index d64edff..b9c469a 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -7351,8 +7351,9 @@ resolve_compcall (gfc_expr* e, const char **name)
/* Check that's really a FUNCTION. */
if (!e->value.compcall.tbp->function)
{
- gfc_error ("%qs at %L should be a FUNCTION",
- e->value.compcall.name, &e->where);
+ if (e->symtree && e->symtree->n.sym->resolve_symbol_called)
+ gfc_error ("%qs at %L should be a FUNCTION", e->value.compcall.name,
+ &e->where);
return false;
}
@@ -8987,6 +8988,22 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code, bool *array_alloc_wo_spec)
goto failure;
}
+ /* F2003:C626 (R623) A type-param-value in a type-spec shall be an asterisk
+ if and only if each allocate-object is a dummy argument for which the
+ corresponding type parameter is assumed. */
+ if (code->ext.alloc.ts.type == BT_CHARACTER
+ && code->ext.alloc.ts.u.cl->length != NULL
+ && e->ts.type == BT_CHARACTER && !e->ts.deferred
+ && e->ts.u.cl->length == NULL
+ && e->symtree->n.sym->attr.dummy)
+ {
+ gfc_error ("The type parameter in ALLOCATE statement with type-spec "
+ "shall be an asterisk as allocate object %qs at %L is a "
+ "dummy argument with assumed type parameter",
+ sym->name, &e->where);
+ goto failure;
+ }
+
/* Check F08:C632. */
if (code->ext.alloc.ts.type == BT_CHARACTER && !e->ts.deferred
&& !UNLIMITED_POLY (e))
diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index 8ab290b..e9eacf2 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -11236,9 +11236,7 @@ gfc_is_reallocatable_lhs (gfc_expr *expr)
return true;
/* All that can be left are allocatable components. */
- if ((sym->ts.type != BT_DERIVED
- && sym->ts.type != BT_CLASS)
- || !sym->ts.u.derived->attr.alloc_comp)
+ if (sym->ts.type != BT_DERIVED && sym->ts.type != BT_CLASS)
return false;
/* Find a component ref followed by an array reference. */
diff --git a/gcc/gcc-urlifier.cc b/gcc/gcc-urlifier.cc
index 49611b7..a409458 100644
--- a/gcc/gcc-urlifier.cc
+++ b/gcc/gcc-urlifier.cc
@@ -220,15 +220,14 @@ make_gcc_urlifier (unsigned int lang_mask)
/* class auto_override_urlifier. */
-auto_override_urlifier::auto_override_urlifier (urlifier *new_urlifier)
-: m_old_urlifier (global_dc->get_urlifier ())
+auto_override_urlifier::auto_override_urlifier (const urlifier &new_urlifier)
{
- global_dc->override_urlifier (new_urlifier);
+ global_dc->push_borrowed_urlifier (new_urlifier);
}
auto_override_urlifier::~auto_override_urlifier ()
{
- global_dc->override_urlifier (m_old_urlifier);
+ global_dc->pop_urlifier ();
}
#if CHECKING_P
diff --git a/gcc/gcc-urlifier.h b/gcc/gcc-urlifier.h
index 5ffbbf7..eefed49 100644
--- a/gcc/gcc-urlifier.h
+++ b/gcc/gcc-urlifier.h
@@ -33,11 +33,8 @@ extern char *make_doc_url (const char *doc_url_suffix);
class auto_override_urlifier
{
public:
- auto_override_urlifier (urlifier *new_urlifier);
+ auto_override_urlifier (const urlifier &new_urlifier);
~auto_override_urlifier ();
-
-protected:
- urlifier * const m_old_urlifier;
};
/* Subclass of urlifier that attempts to add URLs to quoted strings
@@ -71,7 +68,7 @@ class auto_urlify_attributes
{
public:
auto_urlify_attributes ()
- : m_override (&m_urlifier)
+ : m_override (m_urlifier)
{
}
diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 04b3736..c7b2aa6 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -8356,7 +8356,7 @@ driver::global_initializations ()
diagnostic_initialize (global_dc, 0);
diagnostic_color_init (global_dc);
diagnostic_urls_init (global_dc);
- global_dc->set_urlifier (make_gcc_urlifier (0));
+ global_dc->push_owned_urlifier (make_gcc_urlifier (0));
#ifdef GCC_DRIVER_HOST_INITIALIZATION
/* Perform host dependent initialization when needed. */
diff --git a/gcc/ira-costs.cc b/gcc/ira-costs.cc
index 70cba94..faf706c 100644
--- a/gcc/ira-costs.cc
+++ b/gcc/ira-costs.cc
@@ -1926,12 +1926,15 @@ calculate_equiv_gains (void)
|| !bitmap_bit_p (&equiv_pseudos, regno))
continue;
- rtx_insn_list *x;
- for (x = ira_reg_equiv[regno].init_insns; x != NULL; x = x->next ())
- if (insn == x->insn ())
- break;
- if (x != NULL)
- continue; /* skip equiv init insn */
+ if (ira_reg_equiv[regno].invariant != NULL)
+ {
+ rtx_insn_list *x = ira_reg_equiv[regno].init_insns;
+ for (; x != NULL; x = x->next ())
+ if (insn == x->insn ())
+ break;
+ if (x != NULL)
+ continue; /* skip equiv init insn for invariant */
+ }
rtx subst = ira_reg_equiv[regno].memory;
diff --git a/gcc/po/fr.po b/gcc/po/fr.po
index 350d4b6..8eda238 100644
--- a/gcc/po/fr.po
+++ b/gcc/po/fr.po
@@ -97,10 +97,10 @@
#
msgid ""
msgstr ""
-"Project-Id-Version: gcc-15-b20250216\n"
+"Project-Id-Version: gcc-15.1-b20250316\n"
"Report-Msgid-Bugs-To: https://gcc.gnu.org/bugs/\n"
"POT-Creation-Date: 2025-03-14 22:06+0000\n"
-"PO-Revision-Date: 2025-03-09 17:24+0100\n"
+"PO-Revision-Date: 2025-03-19 19:39+0100\n"
"Last-Translator: Frédéric Marchal <fmarchal@perso.be>\n"
"Language-Team: French <traduc@traduc.org>\n"
"Language: fr\n"
@@ -662,10 +662,9 @@ msgid "Warn about possibly incorrect subscripts in do loops."
msgstr "Avertir à propos d'indices probablement incorrects dans les boucles « do »."
#: fortran/lang.opt:246
-#, fuzzy, no-c-format
-#| msgid "Warn in case profiles in -fprofile-use do not match."
+#, no-c-format
msgid "Warn when arguments of external procedures do not match."
-msgstr "Avertir si les profiles définis par -fprofile-use ne correspondent pas."
+msgstr "Avertir si les arguments des procédures externes ne correspondent pas."
#: fortran/lang.opt:254
#, no-c-format
@@ -1080,7 +1079,7 @@ msgstr "-finline-arg-packing\tRéaliser le compactage de l'argument en ligne."
#: fortran/lang.opt:691
#, no-c-format
msgid "Enable generation of inline code instead of calls to functions from the library to implement intrinsics."
-msgstr ""
+msgstr "Activer la génération de code en ligne au lieu d'appels à des fonctions depuis la bibliothèque pour implémenter les intrinsèques."
#: fortran/lang.opt:712
#, no-c-format
@@ -1200,7 +1199,7 @@ msgstr "Copier les sections de tableaux dans un bloc contigu lors de l'entrée d
#: fortran/lang.opt:824
#, no-c-format
msgid "Experimental unsigned numbers."
-msgstr ""
+msgstr "Nombres non signés expérimentaux."
#: fortran/lang.opt:828
#, no-c-format
@@ -2785,7 +2784,7 @@ msgstr "Avertir à propos d'espaces de fin sur les lignes excepté quand dans de
#: c-family/c.opt:1522
#, no-c-format
msgid "Warn about trailing whitespace on lines except when in raw string literals. Equivalent to Wtrailing-whitespace=blanks when enabled or Wtrailing-whitespace=none when disabled."
-msgstr ""
+msgstr "Avertir à propos d'espaces à la fin sur les lignes sauf dans les littéraux de chaînes bruts. Équivalent à Wtrailing-whitespace=blanks lorsque activé ou Wtrailing-whitespace=none si désactivé."
#: c-family/c.opt:1526
#, no-c-format
@@ -2820,7 +2819,7 @@ msgstr "Avertir à propos de constantes flottantes sans suffixe."
#: c-family/c.opt:1554
#, no-c-format
msgid "Warn about character arrays initialized as unterminated character sequences with a string literal."
-msgstr ""
+msgstr "Avertir à propos de tableaux de caractères initialisés avec des séquences de caractères indéterminées dans un littéral de chaîne."
#: c-family/c.opt:1570
#, no-c-format
@@ -2957,7 +2956,7 @@ msgstr "Reconnaître le mot clef « asm »."
#: c-family/c.opt:1703
#, no-c-format
msgid "Assume C++ replaceable global operators new, new[], delete, delete[] don't read or write visible global state."
-msgstr ""
+msgstr "Supposer que les opérateurs globaux remplaçables du C++ new, new[], delete, delete[] ne lisent ni n'écrivent des états globaux visibles."
#: c-family/c.opt:1711
#, no-c-format
@@ -3427,7 +3426,7 @@ msgstr "Traiter les valeurs de retour connues de sprintf comme des constantes."
#: c-family/c.opt:2285
#, no-c-format
msgid "Enable lifetime extension of range based for temporaries."
-msgstr ""
+msgstr "Activer l'extension de la durée de vie de temporaires basés sur une plage."
#: c-family/c.opt:2289
#, no-c-format
@@ -3447,7 +3446,7 @@ msgstr "Générer l'information pour les types de descripteurs lors de l'exécut
#: c-family/c.opt:2301
#, no-c-format
msgid "Look for the main source file on the include path."
-msgstr ""
+msgstr "Chercher le fichier source principal dans le chemin d'inclusion."
#: c-family/c.opt:2308 ada/gcc-interface/lang.opt:81
#, no-c-format
@@ -3883,76 +3882,72 @@ msgstr "Ne pas prédéfinir les macros spécifiques au système et à GCC."
#: cobol/lang.opt:43
#, no-c-format
msgid "Accept COBOL constructs used by non-ISO compilers"
-msgstr ""
+msgstr "Accepter les constructions COBOL utilisées par les compilateurs non ISO"
#: cobol/lang.opt:62
-#, fuzzy, no-c-format
-#| msgid "%<-fhandle-exceptions%> has been renamed %<-fexceptions%> (and is now on by default)"
+#, no-c-format
msgid "-fcobol-exceptions=<n>\tEnable some exceptions by default"
-msgstr "%<-fhandle-exceptions%> a été renommé en %<-fexceptions%> (et est maintenant utilisé par défaut)"
+msgstr "-fcobol-exceptions=<n>\tActiver quelques exceptions par défaut"
#: cobol/lang.opt:66
#, no-c-format
msgid "Define alternative implicit copybook filename extension"
-msgstr ""
+msgstr "Définir une extension alternative et implicite pour le nom de fichier copybook"
#: cobol/lang.opt:70
#, no-c-format
msgid "Set Working-Storage data items to the supplied value"
-msgstr ""
+msgstr "Définir les éléments de données Working-Storage à la valeur fournie"
#: cobol/lang.opt:74
-#, fuzzy, no-c-format
-#| msgid "Enable backend debugging."
+#, no-c-format
msgid "Enable Cobol lex debugging"
-msgstr "Activer le débogage par un backend."
+msgstr "Activer le débogage lex du Cobol"
#: cobol/lang.opt:90
#, no-c-format
msgid "-findicator-column=<n>\tColumn after which Region A begins"
-msgstr ""
+msgstr "-findicator-column=<n>\tColonne après laquelle la Région A commence"
#: cobol/lang.opt:94
#, no-c-format
msgid "-finternal-ebcdic\tInternal processing is in EBCDIC Code Page 1140"
-msgstr ""
+msgstr "-finternal-ebcdic\tLe traitement interne est en EBCDIC Code de Page 1140"
#: cobol/lang.opt:102
#, no-c-format
msgid "Enable/disable static linkage for CALL literals"
-msgstr ""
+msgstr "Activer/désactiver l'édition de liens statique pour les CALL littéraux"
#: cobol/lang.opt:106
-#, fuzzy, no-c-format
-#| msgid "Enable backend debugging."
+#, no-c-format
msgid "Enable Cobol parser debugging"
-msgstr "Activer le débogage par un backend."
+msgstr "Activer le débogage de l'analyseur Cobol"
#: cobol/lang.opt:110
-#, fuzzy, no-c-format
-#| msgid "Enable backend debugging."
+#, no-c-format
msgid "Enable Cobol yacc debugging"
-msgstr "Activer le débogage par un backend."
+msgstr "Activer le débogage yacc du Cobol"
#: cobol/lang.opt:114
#, no-c-format
msgid "preprocess <source_filter> before compiling"
-msgstr ""
+msgstr "prétraiter <filtre_source> avant la compilation"
#: cobol/lang.opt:134
#, no-c-format
msgid "-main\tThe first program-id in the next source file is called by a generated main() entry point"
-msgstr ""
+msgstr "-main\tLe premier ID de programme dans le fichier source suivant est appelé par le point d'entrée main() généré"
#: cobol/lang.opt:138
#, no-c-format
msgid "-main=<source_file> source_file/PROGRAM-ID is called by the generated main()"
-msgstr ""
+msgstr "-main=<fichier_source> fichier_source/ID-PROGRAMME est appelé par le main() généré"
#: cobol/lang.opt:142
#, no-c-format
msgid "-nomain\tNo main() function is created from COBOL source files"
-msgstr ""
+msgstr "-nomain\tAucune fonction main() est créé depuis les fichiers source COBOL"
#: ada/gcc-interface/lang.opt:61
#, no-c-format
@@ -4222,7 +4217,7 @@ msgstr "Désactiver l'accès aux objets en mémoire partagée."
#: d/lang.opt:405
#, no-c-format
msgid "Enable safety checks on all functions by default."
-msgstr ""
+msgstr "Activer les vérifications de sécurité dans toutes les fonctions par défaut."
#: d/lang.opt:409
#, no-c-format
@@ -4457,32 +4452,32 @@ msgstr "activer le pistage du débogage interne pour quad,token,line,all (commut
#: m2/lang.opt:139
#, no-c-format
msgid "dump Modula-2 internal intemediate representation specified by: all,quad,decl,gimple"
-msgstr ""
+msgstr "vidanger la représentation intermédiaire interne Modula-2 spécifiée par : all,quad,dcl,gimple"
#: m2/lang.opt:143
#, no-c-format
msgid "dump Modula-2 decls to the filename stem specified"
-msgstr ""
+msgstr "vidanger les déclarations Modula-2 vers la racine de nom de fichier spécifiée"
#: m2/lang.opt:147
#, no-c-format
msgid "dump Modula-2 gimple to the filename stem specified"
-msgstr ""
+msgstr "vidanger le gimple Modula-2 vers la racine de nom de fichier spécifiée"
#: m2/lang.opt:151
#, no-c-format
msgid "dump Modula-2 quads to the filename stem specified"
-msgstr ""
+msgstr "vidanger les quads Modula-2 vers la racine de nom de fichier spécifiée"
#: m2/lang.opt:155
#, no-c-format
msgid "filter the language dump using a comma separated list of procedures and modules"
-msgstr ""
+msgstr "filtrer le vidangage du langage en utilisant une liste de procédures et de modules séparés par des virgules"
#: m2/lang.opt:159
#, no-c-format
msgid "override the default 64 bit definition of SYSTEM.COFF_T with the argument specified"
-msgstr ""
+msgstr "écraser la définition 64 bits par défaut de SYSTEM.COFF_T avec l'argument spécifié"
#: m2/lang.opt:163
#, no-c-format
@@ -5762,7 +5757,7 @@ msgstr "-unexported_symbols_list <fichier>\tNe pas exporter les symboles globaux
#: config/darwin.opt:392
#, no-c-format
msgid "-weak_framework <framework>\tMake a weak link to the specified framework."
-msgstr ""
+msgstr "-weak_framework <framework>\tÉtablir un lien faible vers le framework spécifié."
#: config/darwin.opt:396
#, no-c-format
@@ -6053,7 +6048,7 @@ msgstr "Utiliser des décalages sur 32 bits dans les tables de sauts au lieu de
#: config/m68k/m68k.opt:151 config/avr/avr.opt:23
#, no-c-format
msgid "Usa LRA for reload instead of the old reload framework. This option is experimental, and it may be removed in future versions of the compiler."
-msgstr ""
+msgstr "Utiliser un LRA pour recharger au lieu de l'ancien rechargement du framework. Cette option est expérimentale et elle peut être retirée dans les futures versions de ce compilateur."
#: config/m68k/m68k.opt:156
#, no-c-format
@@ -6343,7 +6338,7 @@ msgstr "-param=vsetvl-strategy=<chaîne>\tDéfini le niveau d'optimisation de la
#: config/riscv/riscv.opt:627
#, no-c-format
msgid "-param=riscv-two-source-permutes Enable permutes with two source vectors."
-msgstr ""
+msgstr "-param=riscv-two-source-permutes Activer les permutations avec deux vecteurs source."
#: config/riscv/riscv.opt:631 config/i386/i386.opt:496
#, no-c-format
@@ -6685,7 +6680,7 @@ msgstr "Le nombre d'itérations Newton pour calculer la réciproque du type doub
#: config/aarch64/aarch64.opt:359
#, no-c-format
msgid "--param=aarch64-autovec-preference=[default|asimd-only|sve-only|prefer-asimd|prefer-sve] Force an ISA selection strategy for auto-vectorization."
-msgstr ""
+msgstr "--param=aarch64-autovec-preference=[default|asimd-only|sve-only|prefer-asimd|prefer-sve] Forcer une stratégie de sélection ISA pour l'auto vectorisation."
#: config/aarch64/aarch64.opt:385
#, no-c-format
@@ -8821,7 +8816,7 @@ msgstr "Optimisation. Utiliser des sous-routines pour les prologue et épilogue
#: config/avr/avr.opt:31
#, no-c-format
msgid "Use a startup code with a compact vector table."
-msgstr ""
+msgstr "Utiliser un code de démarrage avec une table de vecteurs compacte."
#: config/avr/avr.opt:35
#, no-c-format
@@ -8841,7 +8836,7 @@ msgstr "Cette option est utilisée en interne. Définir le nombre de segments de
#: config/avr/avr.opt:47
#, no-c-format
msgid "Call main and exit (default)."
-msgstr ""
+msgstr "Appeler main et terminer (défaut)."
#: config/avr/avr.opt:51
#, no-c-format
@@ -8856,7 +8851,7 @@ msgstr "Cette option est utilisée en interne. Activer le support et l'utilisati
#: config/avr/avr.opt:66
#, no-c-format
msgid "This option is on per default in order to work around PR118012."
-msgstr ""
+msgstr "Cette option est active par défaut pour contourner PR118012."
#: config/avr/avr.opt:70
#, no-c-format
@@ -8906,7 +8901,7 @@ msgstr "Optimisation. Accumuler les arguments sortants d'une fonction et acquér
#: config/avr/avr.opt:112
#, no-c-format
msgid "Optimization. Split shifts of 4-byte values into a byte shift and a residual bit shift."
-msgstr ""
+msgstr "Optimisation. Scinder les décalages de valeurs de 4 octets en un décalage d'octet et un décalage des bits résiduels."
#: config/avr/avr.opt:116
#, no-c-format
@@ -8961,12 +8956,12 @@ msgstr "Autoriser l'utilisation d'une troncature au lieu d'un arrondi vers le ba
#: config/avr/avr.opt:157
#, no-c-format
msgid "Optimization. Run a post-reload pass that tweaks move instructions."
-msgstr ""
+msgstr "Optimisation. Exécuter une étape après le rechargement pour ajuster les instructions de déplacement."
#: config/avr/avr.opt:161
#, no-c-format
msgid "-mfuse-move=<0,23>\tOptimization. Run a post-reload pass that tweaks move instructions."
-msgstr ""
+msgstr "-mfuse-move=<0,23>\tOptimisation. Exécuter une étape après le rechargement pour ajuster les instructions de déplacement."
#: config/avr/avr.opt:165
#, no-c-format
@@ -10653,7 +10648,7 @@ msgstr "-mbranch-cost=COÛT\tDéfinir le coût des branchements à, approximativ
#: config/loongarch/loongarch.opt:190
#, no-c-format
msgid "-maddr-reg-reg-cost=COST Set the cost of ADDRESS_REG_REG to the value calculated by COST."
-msgstr ""
+msgstr "-maddr-reg-reg-cost=COÛT Définir le coût de ADDRESS_REG_REG à la valeur calculée par COÛT."
#: config/loongarch/loongarch.opt:194 config/mips/mips.opt:83
#, no-c-format
@@ -10718,7 +10713,7 @@ msgstr "Utilisé pour limiter le facteur de dépliage qui indique combien de foi
#: config/loongarch/loongarch.opt:319
#, no-c-format
msgid "Annotate table jump instruction (jr {reg}) to correlate it with the jump table."
-msgstr ""
+msgstr "Annoter les instructions de saut de table (jr {reg}) pour les corréler avec la table de saut."
#: config/loongarch/loongarch.opt:323
#, no-c-format
@@ -14075,12 +14070,12 @@ msgstr "-fdiagnostics-format=[text|sarif-stderr|sarif-file|json|json-stderr|json
#: common.opt:1452
#, no-c-format
msgid "Add output format."
-msgstr ""
+msgstr "Ajouter le format de sortie."
#: common.opt:1456
#, no-c-format
msgid "Set output format."
-msgstr ""
+msgstr "Définir le format de sortie."
#: common.opt:1460
#, no-c-format
@@ -14115,7 +14110,7 @@ msgstr "Imprimer toute règle associée avec les messages de diagnostiques."
#: common.opt:1527
#, no-c-format
msgid "Use color within diagnostic messages to highlight pertinent information."
-msgstr ""
+msgstr "Utiliser une couleur dans les messages de diagnostique pour mettre les informations pertinentes en évidence."
#: common.opt:1531
#, no-c-format
@@ -14321,7 +14316,7 @@ msgstr "Exécuter le mouvement de stockage après l'élimination des sous-expres
#: common.opt:1771
#, no-c-format
msgid "Try to avoid store forwarding."
-msgstr ""
+msgstr "Essayer d'éviter le renvoi du stockage"
#: common.opt:1775
#, no-c-format
@@ -14356,7 +14351,7 @@ msgstr "Activer la sortie de chargements adjacents hors d'une boucle pour encour
#: common.opt:1823
#, no-c-format
msgid "Run two instruction combination passes late in the pass pipeline; one before register allocation and one after."
-msgstr ""
+msgstr "Exécuter deux étapes de combinaison d'instructions tard dans l'étape du pipeline ; une avant l'allocation des registres et une autre après."
#: common.opt:1828
#, no-c-format
@@ -14706,12 +14701,12 @@ msgstr "Les optimisations durant l'édition de liens sont faites avec un nombre
#: common.opt:2247
#, no-c-format
msgid "Enable incremental LTO, with its cache in given directory."
-msgstr ""
+msgstr "Activer le LTO incrémental avec sa cache dans le répertoire donné."
#: common.opt:2251
#, no-c-format
msgid "Number of cache entries in incremental LTO after which to prune old entries."
-msgstr ""
+msgstr "Nombre d'entrées dans la cache dans LTO incrémental après lequel éliminer les anciennes entrées."
#: common.opt:2276
#, no-c-format
@@ -14746,7 +14741,7 @@ msgstr "-fmax-errors=<nombre>\tNombre maximum d'erreurs à rapporter."
#: common.opt:2305
#, no-c-format
msgid "Allow removal of malloc and free pairs when allocated block is unused."
-msgstr ""
+msgstr "Autoriser le retrait des paires malloc et free quand le bloc alloué n'est pas utilisé."
#: common.opt:2312
#, no-c-format
@@ -14873,7 +14868,7 @@ msgstr "Écrire un fichier FICHSRC.opt-record.json détaillant quelles optimisat
#: common.opt:2441
#, no-c-format
msgid "Detect loops calculating CRC and replace with faster implementation. If the target supports CRC instruction and the CRC loop uses the same polynomial as the one used in the CRC instruction, directly replace with the corresponding CRC instruction. Otherwise, if the target supports carry-less-multiplication instruction, generate CRC using it. If neither case applies, generate table-based CRC."
-msgstr ""
+msgstr "Détecter les boucles qui calculent un CRC et les remplacer par une implémentation plus rapide. Si la cible supporte l'instruction CRC et que la boucle CRC utilise le même polynôme que l'instruction CRC, la remplacer directement avec l'instruction CRC correspondante. Sinon, si la cible supporte l'instruction carry-less-multiplication, générer le CRC en l'utilisant. Si aucun des cas est possible, générer un CRC basé sur une table."
#: common.opt:2455
#, no-c-format
@@ -15904,7 +15899,7 @@ msgstr "Vider les registres utilisés dans l'appel lors du retour de fonction."
#: common.opt:3549
#, no-c-format
msgid "-fzero-init-padding-bits=[standard|unions|all]\tZero padding bits in initializers."
-msgstr ""
+msgstr "-fzero-init-padding-bits=[standard|unions|all]\tCompléter les bits avec des zéros dans les initialiseurs."
#: common.opt:3565
#, no-c-format
@@ -15944,7 +15939,7 @@ msgstr "Générer les informations de débogage BTF au niveau par défaut."
#: common.opt:3611
#, no-c-format
msgid "Generate pruned BTF when emitting BTF info."
-msgstr ""
+msgstr "Générer du BTF élagué lors de l'émission d'infos BTF"
#: common.opt:3615
#, no-c-format
@@ -16119,7 +16114,7 @@ msgstr "Faire sauvegarder les registres par l'appelant au travers des appels si
#: common.opt:3957
#, no-c-format
msgid "Perform dead code elimination on zero and sign extensions with special dataflow analysis."
-msgstr ""
+msgstr "Éliminer le code mort sur des zéros et des extensions de signe avec une analyse du flux de données spéciale."
#: params.opt:27
#, no-c-format
@@ -16179,7 +16174,7 @@ msgstr "Autoriser la détection par ASan des bogues d'utilisation après retour.
#: params.opt:71
#, no-c-format
msgid "Whether the scheduling description is mostly a cycle-accurate model of the target processor and is likely to be spill aggressively to fill any pipeline bubbles."
-msgstr ""
+msgstr "Est-ce que la description de l'ordonnancement est principalement un modèle fidèle du cycle du processeur cible et va probablement déborder agressivement pour remplir toute bulle du pipeline."
#: params.opt:75
#, no-c-format
@@ -17170,7 +17165,7 @@ msgstr "Le nombre maximum de relations que l'oracle enregistrera dans un bloc de
#: params.opt:945
#, no-c-format
msgid "Work bound when discovering transitive relations from existing relations."
-msgstr ""
+msgstr "Travail lié lors de la découverte de relations transitives depuis les relations existantes."
#: params.opt:949
#, no-c-format
@@ -19909,7 +19904,7 @@ msgstr "les opérandes de %T/%t doivent être reg + const_int:"
#: config/avr/avr.cc:2762
#, c-format
msgid "bad I/O address 0x%s outside of valid range [0x%x, 0x%x] for %%i operand"
-msgstr ""
+msgstr "mauvaise adresse E/S 0x%s en dehors de la plage valide [0x%x, 0x%x] pour l'opérande %%i"
#: config/avr/avr.cc:2788
#, c-format
@@ -21326,10 +21321,9 @@ msgid "expected label"
msgstr "étiquette attendue"
#: cobol/gcobolspec.cc:680
-#, fuzzy, c-format
-#| msgid "Driving:"
+#, c-format
msgid "Driving: (%ld)\n"
-msgstr "Pilotage:"
+msgstr "Pilotage: (%ld)\n"
#: cp/call.cc:4225
#, c-format
@@ -21759,6 +21753,12 @@ msgid ""
"\n"
" Use another -std option to compile. */\n"
msgstr ""
+"\n"
+"\n"
+"/* AVERTISSEMENT : À cause d'arguments différents à une procédure\n"
+" externe, ce fichier d'en-tête n'est pas compatible avec -std=c23.\n"
+"\n"
+" Utilisez une autre option -std pour compiler. */\n"
#: fortran/error.cc:324
msgid "Prohibited in Fortran 2023:"
@@ -21802,7 +21802,7 @@ msgstr "Fonctionnalité supprimée :"
#: fortran/error.cc:348
msgid "Unsigned:"
-msgstr ""
+msgstr "Non signé :"
#: fortran/expr.cc:3856
msgid "array assignment"
@@ -22785,7 +22785,7 @@ msgstr "Vous avez cassé GCC Rust. C'est une fonctionnalité.\n"
#: data-streamer.h:233
#, gcc-internal-format
msgid "degree of %<poly_int%> exceeds %<NUM_POLY_INT_COEFFS%> (%d)"
-msgstr ""
+msgstr "le degré de %<poly_int%> dépasse %<NUM_POLY_INT_COEFFS%> (%d)"
#: lto-streamer.h:1039
#, gcc-internal-format, gfc-internal-format
@@ -23052,38 +23052,34 @@ msgid "%<-mrelax%> is only supported for RTP PIC"
msgstr "%<-mrelax%> est uniquement supporté pour le PIC RTP"
#: cobol/parse_ante.h:1718
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "old declaration %q#D"
+#, gcc-internal-format, gfc-internal-format
msgid "Global declarative %s for %s"
-msgstr "ancienne déclaration %q#D"
+msgstr "Déclarative globale %s pour %s"
#: cobol/parse_ante.h:2447 cobol/genapi.cc:5829
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d: invalid symbol_type_t %d"
-msgstr ""
+msgstr "%s:%d: symbol_type_t %d invalide"
#: cobol/parse_ante.h:2789
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d: no symbol '%s' found"
-msgstr ""
+msgstr "%s:%d: aucun symbole « %s » trouvé"
#: cobol/parse_util.h:351
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "Intrinsic function %qs (%d) not recognized"
+#, gcc-internal-format, gfc-internal-format
msgid "%s: intrinsic function %s not found"
-msgstr "Fonction intrinsèque %qs (%d) non reconnue"
+msgstr "%s: fonction intrinsèque %s pas trouvée"
#: cobol/parse_util.h:383
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "invalid cast to function type %qT"
+#, gcc-internal-format, gfc-internal-format
msgid "%s: invalid function descr type '%c'"
-msgstr "transtypage invalide vers le type fonction %qT"
+msgstr "%s: type de descripteur de fonction « %c » invalide"
#: cobol/scan_ante.h:38
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "close: %s"
+#, gcc-internal-format, gfc-internal-format
msgid "scan.o: %s"
-msgstr "fermeture: %s"
+msgstr "scan.o: %s"
#. A general purpose syntax error.
#: fortran/gfortran.h:3557 fortran/io.cc:3727 fortran/io.cc:4413
@@ -23265,10 +23261,9 @@ msgid "unrecognized scalar storage order value %qs"
msgstr "ordre de stockage des scalaires %qs non reconnu"
#: cobol/lang.opt:46
-#, fuzzy, gcc-internal-format
-#| msgid "Unrecognized MCU name %qs."
+#, gcc-internal-format
msgid "Unrecognized COBOL dialect name: %qs"
-msgstr "Nom de MCU %qs non reconnu."
+msgstr "Nom de dialecte COBOL non reconnu : %qs "
#: d/lang.opt:201
#, gcc-internal-format
@@ -23326,10 +23321,9 @@ msgid "missing device or architecture after %qs"
msgstr "périphérique ou architecture manquant après %qs"
#: config/s390/s390.opt:139
-#, fuzzy, gcc-internal-format
-#| msgid "%<-mcpu=%> is deprecated; use %<-mtune=%> or %<-march=%> instead"
+#, gcc-internal-format
msgid "%<-mesa%> is deprecated and support for ESA/390 will be removed; use %<-mzarch%> instead"
-msgstr "%<-mcpu=%> est déprécié; utilisez plutôt %<-mtune=%> ou %<-march=%>"
+msgstr "%<-mesa%> est déprécié et le support pour ESA/390 sera retiré ; utilisez plutôt %<-mzarch%>"
#: config/rs6000/rs6000.opt:308
#, gcc-internal-format
@@ -28196,7 +28190,7 @@ msgstr "avec %<ancestor%>, seules les clauses %<device%>, %<firstprivate%>, %<pr
#: gimplify.cc:13974
#, gcc-internal-format
msgid "allocator with access trait set to %<thread%> results in undefined behavior for %qs directive"
-msgstr ""
+msgstr "l'allocateur avec un trait d'accès défini à %<thread%> résulte en un comportement indéfini pour la directive %qs"
#: gimplify.cc:14015
#, gcc-internal-format
@@ -28552,10 +28546,9 @@ msgid "a type with different precision is defined in another translation unit"
msgstr "un type avec une précision différente est défini dans une autre unité de traduction"
#: ipa-devirt.cc:1273
-#, fuzzy, gcc-internal-format
-#| msgid "a type with different number of methods is defined in another translation unit"
+#, gcc-internal-format
msgid "a vector type with different number of elements is defined in another translation unit"
-msgstr "un type avec un nombre différent de méthodes est défini dans une autre unité de traduction"
+msgstr "un type vectoriel avec un nombre différent d'éléments est défini dans une autre unité de traduction"
#: ipa-devirt.cc:1280
#, gcc-internal-format
@@ -29194,7 +29187,7 @@ msgstr "le code d'arbre %qs n'est pas supporté dans les flux LTO"
#: lto-streamer-out.cc:2554
#, gcc-internal-format
msgid "LTO streaming of toplevel extended %<asm%> unimplemented"
-msgstr ""
+msgstr "le streaming LTO d'un %<asm%> étendu au plus haut niveau n'est pas implémenté"
#: lto-streamer.cc:129
#, gcc-internal-format, gfc-internal-format
@@ -29309,7 +29302,7 @@ msgstr "utilisation de la compilation série de %d tâches LTRANS"
#: lto-wrapper.cc:2054
#, gcc-internal-format
msgid "using ltrans cache without file locking support, do not use in parallel"
-msgstr ""
+msgstr "utilisation de la cache ltrans sans support pour le verrouillage de fichier, ne pas utiliser en parallèle"
#: lto-wrapper.cc:2315 config/gcn/mkoffload.cc:954
#, gcc-internal-format
@@ -32979,12 +32972,12 @@ msgstr "la fonction intégrée spécifique à la cible n'est pas disponible"
#: tree-streamer-in.cc:726
#, gcc-internal-format
msgid "degree of %<poly_int%> exceeds %<NUM_POLY_INT_COEFFS%>"
-msgstr ""
+msgstr "le degré de %<poly_int%> dépasse %<NUM_POLY_INT_COEFFS%>"
#: tree-switch-conversion.cc:2354
#, gcc-internal-format
msgid "Using faster switch lowering algorithms. Number of switch cases (%d) exceeds %<--param=switch-lower-slow-alg-max-cases=%d%> limit."
-msgstr ""
+msgstr "Utilisation d'algorithmes rapides de diminution des branchements. Le nombre de cas du branchement (%d) dépasse la limite %<--param=switch-lower-slow-alg-max-cases=%d%>."
#: tree-vect-generic.cc:308 tree-vect-generic.cc:437 tree-vect-generic.cc:1938
#, gcc-internal-format
@@ -33019,7 +33012,7 @@ msgstr "la vectorisation n'a pas eu lieu pour une boucle simd"
#: tree-vrp.cc:1341
#, gcc-internal-format
msgid "using fast VRP algorithm; %d basic blocks exceeds %<--param=vrp-block-limit=%d%> limit"
-msgstr ""
+msgstr "utilisation de l'algorithme VRP rapide ; %d blocs de base dépasse la limite %<--param=vrp-block-limit=%d%>"
#: tree.cc:2329
#, gcc-internal-format
@@ -33695,7 +33688,7 @@ msgstr "disposition de pile compacte"
#: c-family/c-attribs.cc:714 c-family/c-attribs.cc:719
#, gcc-internal-format
msgid "cannot tail-call: return value must be a call"
-msgstr ""
+msgstr "impossible d'appeler à la fin : la valeur de retour doit être un appel"
#: c-family/c-attribs.cc:752 d/d-attribs.cc:1195
#, gcc-internal-format
@@ -36215,7 +36208,7 @@ msgstr "la variable %qD utilisée dans l'expression d'incrément est liée dans
#: c-family/c-omp.cc:1977
#, gcc-internal-format
msgid "imperfectly nested loop using generated loops"
-msgstr ""
+msgstr "boucle imparfaitement imbriquée en utilisant des boucles générées"
#: c-family/c-omp.cc:2561
#, gcc-internal-format
@@ -39371,7 +39364,7 @@ msgstr "le pragma ou l'attribut %<target(\"%s\")%> est mal composé"
#: config/aarch64/aarch64.cc:20092
#, gcc-internal-format
msgid "Function Multi Versioning support is experimental, and the behavior is likely to change"
-msgstr ""
+msgstr "le support du versionnage multi-fonctions est expérimental et le comportement changera vraisemblablement"
#: config/aarch64/aarch64.cc:20101 config/riscv/riscv-target-attr.cc:497
#, gcc-internal-format
@@ -40376,16 +40369,14 @@ msgid "%<asm%> flags not supported in thumb1 mode"
msgstr "fanions %<asm%> non supportés en mode thumb1"
#: config/avr/avr-c.cc:59
-#, fuzzy, gcc-internal-format
-#| msgid "built-in function %qE not supported for MIPS16"
+#, gcc-internal-format
msgid "built-in function is only supported for GNU-C"
-msgstr "la fonction interne %qE n'est pas supportée pour un MIPS16"
+msgstr "la fonction interne est uniquement supportée pour GNU-C"
#: config/avr/avr-c.cc:70
-#, fuzzy, gcc-internal-format
-#| msgid "address spaces are not supported for reduced Tiny devices"
+#, gcc-internal-format
msgid "built-in function for named address-space is not supported for reduced Tiny devices"
-msgstr "les espaces d'adresses ne sont pas supportés pour les périphériques Tiny réduits"
+msgstr "la fonction interne pour l'espace d'adresse nommé n'est pas supportée pour les périphériques Tiny réduits"
#: config/avr/avr-c.cc:101 config/avr/avr-c.cc:226
#, gcc-internal-format
@@ -40469,7 +40460,7 @@ msgstr "la fonction avec l'attribut %qs ne peut pas avoir d'argument"
#: config/avr/avr.cc:982
#, gcc-internal-format
msgid "method %qs has an implicit %<this%> argument"
-msgstr ""
+msgstr "la méthode %qs a un argument %<this%> implicite"
#: config/avr/avr.cc:986 config/riscv/riscv.cc:11243
#, gcc-internal-format
@@ -41125,7 +41116,7 @@ msgstr "suppression du fichier %qs : %m"
#: config/gcn/mkoffload.cc:785
#, gcc-internal-format
msgid "%<-foffload-abi-host-opts%> not specified"
-msgstr ""
+msgstr "%<-foffload-abi-host-opts%> pas spécifié"
#. else
#: config/gcn/mkoffload.cc:810
@@ -41146,7 +41137,7 @@ msgstr "l'argument valide pour %<-march=%> est : %qs"
#: config/gcn/mkoffload.cc:923
#, gcc-internal-format
msgid "GCC was built without library support for %<-march=%s%>; consider compiling for the associated generic architecture %<-march=%s%> instead"
-msgstr ""
+msgstr "GCC a été compilé sans support pour les bibliothèques pour %<-march=%s%> ; envisagez plutôt de compiler pour l'architecture générique associée %<-march=%s%>"
#: config/gcn/mkoffload.cc:958
#, gcc-internal-format
@@ -41226,7 +41217,7 @@ msgstr "%<-mn%> n'est pas supporté sur les cibles linux"
#: config/i386/driver-i386.cc:659
#, gcc-internal-format
msgid "Xeon Phi ISA support has been removed since GCC 15, use GCC 14 for the Xeon Phi ISAs or %<-march=broadwell%> for all the other ISAs supported on this machine."
-msgstr ""
+msgstr "le support de l'ISA Xeon Phi a été enlevé depuis GCC 15, utilisez GCC 14 pour les ISA Xeon Phy ou %<-march=broadwell%> pour toutes les autres ISA supportées sur cette machine."
#: config/i386/host-cygwin.cc:64
#, gcc-internal-format
@@ -41733,10 +41724,9 @@ msgid "%<-mno-avx512XXX%> cannot disable AVX10 instructions when AVX10 is availa
msgstr "%<-mno-avx512XXX%> ne sait pas désactiver les instructions AVX10 quand AVX10 est disponible"
#: config/i386/i386-options.cc:2734
-#, fuzzy, gcc-internal-format
-#| msgid "%<-mno-avx10.1, -mno-avx10.1-256, -mno-avx10.1-512%> cannot disable AVX512 instructions when %<-mavx512XXX%>"
+#, gcc-internal-format
msgid "%<-mno-avx10.1-256, -mno-avx10.1-512%> cannot disable AVX512 instructions when %<-mavx512XXX%>"
-msgstr "%<-mno-avx10.1, -mno-avx10.1-256, -mno-avx10.1-512%> ne sait pas désactiver les instructions AVX512 quand %<-mavx512XXX%>"
+msgstr "%<-mno-avx10.1-256, -mno-avx10.1-512%> ne sait pas désactiver les instructions AVX512 quand %<-mavx512XXX%>"
#: config/i386/i386-options.cc:2780
#, gcc-internal-format
@@ -43380,7 +43370,7 @@ msgstr "la variable d'environnement COLLECT_GCC_OPTIONS doit être définie"
#: config/nvptx/mkoffload.cc:613
#, gcc-internal-format
msgid "%<-foffload-abi-host-opts%> not specified."
-msgstr ""
+msgstr "%<-foffload-abi-host-opts%> n'est pas spécifié."
#: config/nvptx/mkoffload.cc:644
#, gcc-internal-format
@@ -43544,16 +43534,14 @@ msgid "junk at end of %<#pragma CTABLE_ENTRY%>"
msgstr "rebut à la fin de %<#pragma CTABLE_ENTRY%>"
#: config/pru/pru-pragma.cc:61
-#, fuzzy, gcc-internal-format
-#| msgid "%<CTABLE_ENTRY%> index %"
+#, gcc-internal-format
msgid "%<CTABLE_ENTRY%> index %wd is not valid"
-msgstr "%<CTABLE_ENTRY%> index %"
+msgstr "%<CTABLE_ENTRY%> index %wd n'est pas valide"
#: config/pru/pru-pragma.cc:63
-#, fuzzy, gcc-internal-format
-#| msgid "redefinition of %<CTABLE_ENTRY %"
+#, gcc-internal-format
msgid "redefinition of %<CTABLE_ENTRY %wd%>"
-msgstr "redéfinition de %<CTABLE_ENTRY%"
+msgstr "redéfinition de %<CTABLE_ENTRY %wd%>"
#: config/pru/pru-pragma.cc:67
#, gcc-internal-format
@@ -43616,16 +43604,14 @@ msgid "unknown %<#pragma riscv intrinsic%> option %qs"
msgstr "option %qs inconnue pour %<#pragma riscv intrinsic%>"
#: config/riscv/riscv-target-attr.cc:105
-#, fuzzy, gcc-internal-format
-#| msgid "unexpected arch for %<target()%> attribute: must start with + or rv"
+#, gcc-internal-format
msgid "unexpected arch for %<target()%> attribute: must start with rv64 but found %qs"
-msgstr "architecture inattendue pour l'attribut %<target()%> : doit commencer par + ou rv"
+msgstr "architecture inattendue pour l'attribut %<target()%> : doit commencer par rv64 mais %qs est trouvé"
#: config/riscv/riscv-target-attr.cc:112
-#, fuzzy, gcc-internal-format
-#| msgid "unexpected arch for %<target()%> attribute: must start with + or rv"
+#, gcc-internal-format
msgid "unexpected arch for %<target()%> attribute: must start with rv32 but found %qs"
-msgstr "architecture inattendue pour l'attribut %<target()%> : doit commencer par + ou rv"
+msgstr "architecture inattendue pour l'attribut %<target()%> : doit commencer par rv32 mais %qs est trouvé"
#: config/riscv/riscv-target-attr.cc:145
#, gcc-internal-format
@@ -46727,12 +46713,12 @@ msgstr "une union vide a une taille 0 en C et une taille 1 en C++"
#: c/c-decl.cc:9475
#, gcc-internal-format
msgid "argument %qE to the %<counted_by%> attribute is not a field declaration in the same structure as %qD"
-msgstr ""
+msgstr "l'argument %qE de l'attribut %<counted_by%> n'est pas une déclaration de champ dans la même structure que %qD"
#: c/c-decl.cc:9491
#, gcc-internal-format
msgid "argument %qE to the %<counted_by%> attribute is not a field declaration with an integer type"
-msgstr ""
+msgstr "l'argument %qE de l'attribut %<counted_by%> n'est pas une déclaration de champ avec un type entier"
#: c/c-decl.cc:9549
#, gcc-internal-format
@@ -47664,10 +47650,9 @@ msgid "empty enum is invalid"
msgstr "un enum vide est invalide"
#: c/c-parser.cc:3849
-#, fuzzy, gcc-internal-format
-#| msgid "cannot use mode %qs for enumerated types"
+#, gcc-internal-format
msgid "cannot use keyword %qs as enumeration constant"
-msgstr "impossible d'utiliser le mode %qs pour des types énumérés"
+msgstr "impossible d'utiliser le mot-clé %qs comme constante d'une énumération"
#. Otherwise, a more generic error message.
#: c/c-parser.cc:3861 c/c-parser.cc:5093 c/c-parser.cc:5951 c/c-parser.cc:5968
@@ -47776,16 +47761,14 @@ msgid "expected identifier or %<(%>"
msgstr "identificateur ou %<(%> attendu"
#: c/c-parser.cc:4986
-#, fuzzy, gcc-internal-format
-#| msgid "%<static%> may not be used when defining (as opposed to declaring) a static data member"
+#, gcc-internal-format
msgid "%<static%> may not be used with an unspecified variable length array size"
-msgstr "%<static%> ne peut pas être utilisé lors de la définition (contrairement à la déclaration) d'un membre de donnée statique"
+msgstr "%<static%> ne peut pas être utilisé avec une taille de tableau de longueur variable non spécifiée"
#: c/c-parser.cc:4994
-#, fuzzy, gcc-internal-format
-#| msgid "%<this%> may not be used in this context"
+#, gcc-internal-format
msgid "%<static%> may not be used without an array size"
-msgstr "%<this%> ne peut pas être utilisé dans ce contexte"
+msgstr "%<static%> ne peut pas être utilisé sans une taille de tableau"
#: c/c-parser.cc:5154
#, gcc-internal-format
@@ -47873,10 +47856,9 @@ msgid "inner loops must be perfectly nested with %<reduction%> %<inscan%> clause
msgstr "les boucles internes doivent être parfaitement imbriquées avec la clause %<reduction%> %<inscan%>"
#: c/c-parser.cc:7001
-#, fuzzy, gcc-internal-format
-#| msgid "inner loops must be perfectly nested in %<#pragma acc loop%>"
+#, gcc-internal-format
msgid "inner loops must be perfectly nested in %<pragma omp tile%>"
-msgstr "les boucles internes doivent être parfaitement imbriquées dans %<#pragma acc loop%>"
+msgstr "les boucles internes doivent être parfaitement imbriquées dans %<#pragma omp tile%>"
#: c/c-parser.cc:7057 c/c-parser.cc:7212 cp/parser.cc:12617 cp/parser.cc:12767
#: cp/parser.cc:50767
@@ -47982,16 +47964,14 @@ msgid "only attribute %<fallthrough%> or %<assume%> can be applied to a null sta
msgstr "seul l'attribut %<fallthrough%> ou %<assume%> peut être appliqué à une instruction nulle"
#: c/c-parser.cc:8391
-#, fuzzy, gcc-internal-format
-#| msgid "ISO C does not support decimal floating-point before C23"
+#, gcc-internal-format
msgid "ISO C does not support if declarations before C2Y"
-msgstr "le C ISO ne supporte pas les virgules flottantes décimales avant C23"
+msgstr "le C ISO ne supporte pas les déclarations « if » avant C2Y"
#: c/c-parser.cc:8413
-#, fuzzy, gcc-internal-format
-#| msgid "rank mismatch with controlling expression of parent if-statement"
+#, gcc-internal-format
msgid "declaration in the controlling expression must have an initializer"
-msgstr "désaccord de rang avec l'expression de contrôle de l'instruction « if » parente"
+msgstr "la déclaration dans l'expression contrôlante doit avoir un initiliseur"
#: c/c-parser.cc:8430 cp/parser.cc:5462 cp/parser.cc:16399
#, gcc-internal-format
@@ -48147,22 +48127,19 @@ msgid "ISO C90 does not support %<_Generic%>"
msgstr "le C90 ISO ne supporte pas %<_Generic%>"
#: c/c-parser.cc:11006
-#, fuzzy, gcc-internal-format
-#| msgid "ISO C does not support specifying %<enum%> underlying types before C23"
+#, gcc-internal-format
msgid "ISO C does not support use of type name as %<_Generic%> controlling operand before C2Y"
-msgstr "le C ISO ne supporte pas de spécifier les types sous-jacents de %<enum%> avant C23"
+msgstr "le C ISO ne supporte pas l'utilisation du nom d'un type comme %<_Generic%> dans un opérande contrôlant avant C2Y"
#: c/c-parser.cc:11077
-#, fuzzy, gcc-internal-format
-#| msgid "ISO C does not support %<auto%> type deduction before C23"
+#, gcc-internal-format
msgid "ISO C does not support %<_Generic%> association with function type before C2Y"
-msgstr "le C ISO ne supporte pas la déduction de type avec %<auto%> avant C23"
+msgstr "le C ISO ne supporte pas l'association de %<_Generic%> au type fonction avant C2Y"
#: c/c-parser.cc:11081
-#, fuzzy, gcc-internal-format
-#| msgid "%<_Generic%> association has incomplete type"
+#, gcc-internal-format
msgid "ISO C does not support %<_Generic%> association with incomplete type before C2Y"
-msgstr "l'association %<_Generic%> a un type incomplet"
+msgstr "le C ISO ne supporte pas l'association de %<_Generic%> a un type incomplet avant C2Y"
#: c/c-parser.cc:11086
#, gcc-internal-format
@@ -48252,15 +48229,14 @@ msgid "ISO C forbids braced-groups within expressions"
msgstr "le C ISO interdit les groupes entre accolades à l'intérieur d'expressions"
#: c/c-parser.cc:11619
-#, fuzzy, gcc-internal-format
-#| msgid "second parameter of %<va_start%> not last named argument"
+#, gcc-internal-format
msgid "optional second parameter of %<va_start%> not last named argument"
-msgstr "le deuxième paramètre de %<va_start%> n'est pas le dernier argument nommé"
+msgstr "le deuxième paramètre optionnel de %<va_start%> n'est pas le dernier argument nommé"
#: c/c-parser.cc:11658
#, gcc-internal-format
msgid "%<va_start%> macro used with additional arguments other than identifier of the last named argument"
-msgstr ""
+msgstr "la macro %<va_start%> est utilisée avec des arguments supplémentaires autres que l'identificateur du dernier argument nommé"
#: c/c-parser.cc:11803
#, gcc-internal-format
@@ -48388,16 +48364,14 @@ msgid "%<__builtin_complex%> operands of different types"
msgstr "opérandes de %<__builtin_complex%> de types différents"
#: c/c-parser.cc:12522
-#, fuzzy, gcc-internal-format
-#| msgid "wrong number of arguments to %<__builtin_launder%>"
+#, gcc-internal-format
msgid "wrong number of arguments to %<__builtin_counted_by_ref%>"
-msgstr "mauvais nombre d'arguments pour %<__builtin_launder%>"
+msgstr "mauvais nombre d'arguments pour %<__builtin_counted_by_ref%>"
#: c/c-parser.cc:12533
-#, fuzzy, gcc-internal-format
-#| msgid "the align argument to %<__builtin_coro_promise%> must be a constant"
+#, gcc-internal-format
msgid "the argument to %<__builtin_counted_by_ref%> must be an array"
-msgstr "l'argument d'alignement de %<__builtin_core_promise%> doit être une constante"
+msgstr "l'argument de %<__builtin_counted_by_ref%> doit être un tableau"
#: c/c-parser.cc:12584 c/c-parser.cc:12613 cp/parser.cc:8032
#, gcc-internal-format
@@ -48430,16 +48404,14 @@ msgid "argument 1 in call to function %qs has signed type"
msgstr "l'argument 1 dans l'appel à la fonction %qs est un type signé"
#: c/c-parser.cc:12821
-#, fuzzy, gcc-internal-format
-#| msgid "argument 1 in call to function %qs has signed type"
+#, gcc-internal-format
msgid "argument 1 in call to function %qs has %<char%> type"
-msgstr "l'argument 1 dans l'appel à la fonction %qs est un type signé"
+msgstr "l'argument 1 dans l'appel à la fonction %qs a le type %<char%>"
#: c/c-parser.cc:12895
-#, fuzzy, gcc-internal-format
-#| msgid "left rotate count is negative"
+#, gcc-internal-format
msgid "rotate count is negative"
-msgstr "le compteur de rotations vers la gauche est négatif"
+msgstr "le compteur de rotations est négatif"
#: c/c-parser.cc:13187 cp/parser.cc:6380
#, gcc-internal-format
@@ -49027,10 +48999,9 @@ msgid "expected %<host%>, %<nohost%> or %<any%>"
msgstr "%<host%>, %<nohost%> ou %<any%> attendu"
#: c/c-parser.cc:20354 cp/semantics.cc:9664 cp/semantics.cc:9682
-#, fuzzy, gcc-internal-format
-#| msgid "ordered argument needs positive constant integer expression"
+#, gcc-internal-format
msgid "%<partial%> argument needs positive constant integer expression"
-msgstr "les arguments ordonnés ont besoin d'une expression entière constante positive"
+msgstr "l'argument de %<partial%> a besoin d'une expression entière constante positive"
#: c/c-parser.cc:20455 cp/semantics.cc:8836
#, gcc-internal-format
@@ -49039,83 +49010,72 @@ msgstr "le gestionnaire d'événement de la clause %<detach%> a le type %qT plut
#: c/c-parser.cc:20523 c/c-parser.cc:20617 cp/parser.cc:42802
#: cp/parser.cc:42914
-#, fuzzy, gcc-internal-format
-#| msgid "wide string literal in %<asm%>"
+#, gcc-internal-format
msgid "string literal must not contain %<\\0%>"
-msgstr "littéral de chaîne de caractères larges dans %<asm%>"
+msgstr "le littéral de chaîne de caractères ne peut pas contenir %<\\0%>"
#: c/c-parser.cc:20532 c/c-parser.cc:20653 cp/parser.cc:42809
#: cp/parser.cc:42949
-#, fuzzy, gcc-internal-format
-#| msgid "undefined identifier `%s`"
+#, gcc-internal-format
msgid "unknown foreign runtime identifier %qs"
-msgstr "identificateur « %s » non défini"
+msgstr "identificateur d'exécution étranger %qs inconnu"
#: c/c-parser.cc:20547 c/c-parser.cc:20676 cp/parser.cc:42824
#: cp/parser.cc:42971
-#, fuzzy, gcc-internal-format
-#| msgid "Expected register or constant integer."
+#, gcc-internal-format
msgid "expected string literal or constant integer expression"
-msgstr "Registre ou constante entière attendus."
+msgstr "littéral de chaîne ou expression entière constante attendu"
#: c/c-parser.cc:20555 c/c-parser.cc:20684 cp/parser.cc:42832
#: cp/parser.cc:42979 cp/semantics.cc:7512
#, gcc-internal-format
msgid "unknown foreign runtime identifier %qwd"
-msgstr ""
+msgstr "identificateur d'exécution étranger %qwd inconnu"
#: c/c-parser.cc:20593 cp/parser.cc:42891
-#, fuzzy, gcc-internal-format
-#| msgid "expected %<none%> or %<present%>"
+#, gcc-internal-format
msgid "expected %<fr%> or %<attr%> preference selector"
-msgstr "%<none%> ou %<present%> attendu"
+msgstr "sélecteur de préférence %<fr%> ou %<attr%> attendu"
#: c/c-parser.cc:20601 cp/parser.cc:42899
-#, fuzzy, gcc-internal-format
-#| msgid "duplicated %<if%> condition"
+#, gcc-internal-format
msgid "duplicated %<fr%> preference selector"
-msgstr "condition %<if%> dupliquée"
+msgstr "sélecteur de préférence %<fr%> dupliquée"
#: c/c-parser.cc:20627 cp/parser.cc:42923
-#, fuzzy, gcc-internal-format
-#| msgid "%<-march=%s%>: %s must separate with %<_%>"
+#, gcc-internal-format
msgid "%<attr%> string literal must start with %<ompx_%>"
-msgstr "%<-march=%s%> %s doit être séparé par %<_%>"
+msgstr "le littéral de chaîne %<attr%> doit commencer par %<ompx_%>"
#: c/c-parser.cc:20635 cp/parser.cc:42930
#, gcc-internal-format
msgid "%<attr%> string literal must not contain a comma"
-msgstr ""
+msgstr "le littéral de chaîne %<attr%> ne peut pas contenir de virgule"
#: c/c-parser.cc:20647 cp/parser.cc:42942
-#, fuzzy, gcc-internal-format
-#| msgid "expected string literal"
+#, gcc-internal-format
msgid "non-empty string literal expected"
-msgstr "chaîne littérale attendue"
+msgstr "chaîne littérale non vide attendue"
#: c/c-parser.cc:20757 cp/parser.cc:43082
-#, fuzzy, gcc-internal-format
-#| msgid "duplicate %qs modifier"
+#, gcc-internal-format
msgid "duplicate %<targetsync%> modifier"
-msgstr "modificateur %qs dupliqué"
+msgstr "modificateur %<targetsync%> dupliqué"
#: c/c-parser.cc:20764 cp/parser.cc:43089
-#, fuzzy, gcc-internal-format
-#| msgid "duplicate %qs modifier"
+#, gcc-internal-format
msgid "duplicate %<target%> modifier"
-msgstr "modificateur %qs dupliqué"
+msgstr "modificateur %<target%> dupliqué"
#: c/c-parser.cc:20771 cp/parser.cc:43096
-#, fuzzy, gcc-internal-format
-#| msgid "duplicate %qs modifier"
+#, gcc-internal-format
msgid "duplicate %<prefer_type%> modifier"
-msgstr "modificateur %qs dupliqué"
+msgstr "modificateur %<prefer_type%> dupliqué"
#: c/c-parser.cc:20791 cp/parser.cc:43116
-#, fuzzy, gcc-internal-format
-#| msgid "%<map%> clause with map-type modifier other than %<always%>, %<close%> or %<present%>"
+#, gcc-internal-format
msgid "%<init%> clause with modifier other than %<prefer_type%>, %<target%> or %<targetsync%>"
-msgstr "clause %<map%> avec un modificateur de type map autre que %<always%>, %<close%> ou %<present%>"
+msgstr "clause %<init%> avec un modificateur autre que %<prefer_type%>, %<target%> ou %<targetsync%>"
#: c/c-parser.cc:21090 cp/parser.cc:43469
#, gcc-internal-format
@@ -49470,35 +49430,34 @@ msgstr "instruction « for » attendue"
#. provided message with a more confusing one if there was
#. a bad pragma or attribute directive.
#: c/c-parser.cc:23945 cp/parser.cc:46195 cp/parser.cc:46197 cp/parser.cc:46382
-#, fuzzy, gcc-internal-format
-#| msgid "for statement expected"
+#, gcc-internal-format
msgid "loop nest expected"
-msgstr "instruction « for » attendue"
+msgstr "imbrication de boucles inattendue"
#: c/c-parser.cc:23997 cp/parser.cc:46270
#, gcc-internal-format
msgid "attributes other than OpenMP directives are not allowed on %<for%> in loop nest"
-msgstr ""
+msgstr "les attributs autres que les directives OpenMP ne sont pas permises avec les imbrications de boucles %<for%>"
#: c/c-parser.cc:24026 cp/parser.cc:46301
#, gcc-internal-format
msgid "%<unroll%> construct with %<partial%> clause generates just one loop with canonical form but %d loops are needed"
-msgstr ""
+msgstr "la construction %<unroll%> avec la clause %<partial%> génère une seule boucle avec la forme canonique mais %d boucles sont nécessaires"
#: c/c-parser.cc:24037 cp/parser.cc:46312
#, gcc-internal-format
msgid "generated loop of %<unroll%> construct without %<partial%> clause does not have canonical form"
-msgstr ""
+msgstr "la boucle générée par la construction %<unroll%> avec la clause %<partial%> n'a pas la forme canonique"
#: c/c-parser.cc:24060 cp/parser.cc:46338
#, gcc-internal-format
msgid "%<tile%> construct generates %d loops with canonical form but %d loops are needed"
-msgstr ""
+msgstr "la construction %<tile%> génère %d boucles avec la forme canonique mais %d boucles sont nécessaires"
#: c/c-parser.cc:24071 cp/parser.cc:46349
#, gcc-internal-format
msgid "expected %<for%> loop or OpenMP loop transformation construct"
-msgstr ""
+msgstr "boucle %<for%> ou construction de transformation de boucle OpenMP attendue"
#: c/c-parser.cc:24159 cp/semantics.cc:11469 cp/semantics.cc:11562
#, gcc-internal-format
@@ -49532,22 +49491,19 @@ msgid "expected %<for%> after %qs"
msgstr "%<for%> attendu après %qs"
#: c/c-parser.cc:25352 c/c-parser.cc:25360
-#, fuzzy, gcc-internal-format
-#| msgid "expected function name"
+#, gcc-internal-format
msgid "expected a function name"
msgstr "nom de fonction attendu"
#: c/c-parser.cc:25373 cp/parser.cc:50211
-#, fuzzy, gcc-internal-format
-#| msgid "expected function name"
+#, gcc-internal-format
msgid "expected target-function call"
-msgstr "nom de fonction attendu"
+msgstr "appel de fonction cible attendu"
#: c/c-parser.cc:25443
-#, fuzzy, gcc-internal-format
-#| msgid "%<#pragma omp declare %s%> must be followed by function declaration or definition"
+#, gcc-internal-format
msgid "%<#pragma omp dispatch%> must be followed by a function call with optional assignment"
-msgstr "%<#pragma omp declare %s%> doit être suivi d'une déclaration ou une définition de fonction"
+msgstr "%<#pragma omp dispatch%> doit être suivi d'un appel de fonction avec une assignation optionnelle"
#: c/c-parser.cc:25630 cp/parser.cc:48075
#, gcc-internal-format
@@ -49640,10 +49596,9 @@ msgid "expected identifier or string literal"
msgstr "identificateur ou chaîne littérale attendus"
#: c/c-parser.cc:26753 cp/parser.cc:49835 cp/pt.cc:18215
-#, fuzzy, gcc-internal-format
-#| msgid "property must be constant integer expression"
+#, gcc-internal-format
msgid "property must be integer expression"
-msgstr "la propriété doit être une expression entière constante"
+msgstr "la propriété doit être une expression entière"
#: c/c-parser.cc:26766 cp/parser.cc:49846
#, gcc-internal-format
@@ -49661,16 +49616,14 @@ msgid "expected context selector set name"
msgstr "nom de l'ensemble du sélecteur de contexte attendu"
#: c/c-parser.cc:26958 cp/parser.cc:50429
-#, fuzzy, gcc-internal-format
-#| msgid "expected %<at%>, %<severity%> or %<message%> clause"
+#, gcc-internal-format
msgid "expected %<match%>, %<adjust_args%> or %<append_args%> clause"
-msgstr "clause %<at%>, %<severity%> ou %<message%> attendue"
+msgstr "clause %<match%>, %<adjust_args%> ou %<append_args%> attendue"
#: c/c-parser.cc:26974 cp/parser.cc:50442
-#, fuzzy, gcc-internal-format
-#| msgid "too many %<if%> clauses"
+#, gcc-internal-format
msgid "too many %<match%> clauses"
-msgstr "trop de clauses %<if%>"
+msgstr "trop de clauses %<match%>"
#: c/c-parser.cc:26985
#, gcc-internal-format
@@ -49683,52 +49636,44 @@ msgid "variant %qD is a built-in"
msgstr "le variant %qD est interne"
#: c/c-parser.cc:27046 cp/parser.cc:50504
-#, fuzzy, gcc-internal-format
-#| msgid "%qs clause at %L specified more than once"
+#, gcc-internal-format
msgid "%qD is specified more than once"
-msgstr "La clause %qs à %L est spécifiée plus d'une fois"
+msgstr "%qD est spécifié plus d'une fois"
#: c/c-parser.cc:27053
-#, fuzzy, gcc-internal-format
-#| msgid "%qD is not a pointer variable"
+#, gcc-internal-format
msgid "%qD is not of pointer type"
-msgstr "%qD n'est pas une variable pointeur"
+msgstr "%qD n'est pas un type pointeur"
#: c/c-parser.cc:27073 cp/parser.cc:50537
-#, fuzzy, gcc-internal-format
-#| msgid "expected %<ancestor%> or %<device_num%>"
+#, gcc-internal-format
msgid "expected %<nothing%> or %<need_device_ptr%>"
-msgstr "%<ancestor%> ou %<device_num%> attendu"
+msgstr "%<nothing%> ou %<need_device_ptr%> attendu"
#: c/c-parser.cc:27076
-#, fuzzy, gcc-internal-format
-#| msgid "%qs is not valid for %qs"
+#, gcc-internal-format
msgid "%<need_device_addr%> is not valid for C"
-msgstr "%qs n'est pas valide pour %qs"
+msgstr "%<need_device_addr%> n'est pas valide pour le C"
#: c/c-parser.cc:27083 cp/parser.cc:50544
-#, fuzzy, gcc-internal-format
-#| msgid "expected %<ancestor%> or %<device_num%>"
+#, gcc-internal-format
msgid "expected %<nothing%> or %<need_device_ptr%> followed by %<:%>"
-msgstr "%<ancestor%> ou %<device_num%> attendu"
+msgstr "%<nothing%> ou %<need_device_ptr%> suivi par %<:%> attendu"
#: c/c-parser.cc:27103 cp/parser.cc:50561
-#, fuzzy, gcc-internal-format
-#| msgid "expected %<point%>"
+#, gcc-internal-format
msgid "expected %<interop%>"
-msgstr "%<point%> attendu"
+msgstr "%<interop%> attendu"
#: c/c-parser.cc:27197 cp/decl.cc:8601
-#, fuzzy, gcc-internal-format
-#| msgid "argument %d of %qE must be a pointer type"
+#, gcc-internal-format
msgid "argument %d of %qD must be of %<omp_interop_t%>"
-msgstr "l'argument %d de %qE doit être un type pointeur"
+msgstr "l'argument %d de %qD doit être du type %<omp_interop_t%>"
#: c/c-parser.cc:27199 cp/decl.cc:8498 cp/decl.cc:8604
-#, fuzzy, gcc-internal-format
-#| msgid "%<setter%> specified here"
+#, gcc-internal-format
msgid "%<append_args%> specified here"
-msgstr "%<setter%> spécifié ici"
+msgstr "%<append_args%> spécifié ici"
#: c/c-parser.cc:27245 cp/decl.cc:8610
#, gcc-internal-format
@@ -49736,15 +49681,14 @@ msgid "variant %qD and base %qD have incompatible types"
msgstr "le variant %qD et la base %qD ont des types incompatibles"
#: c/c-parser.cc:27270 cp/parser.cc:50625
-#, fuzzy, gcc-internal-format
-#| msgid "%qs clause requires %qs clause"
+#, gcc-internal-format
msgid "an %qs clause requires a %<match%> clause"
-msgstr "la clause %qs requiert la clause %qs"
+msgstr "une clause %qs requiert la clause %<match%>"
#: c/c-parser.cc:27283
#, gcc-internal-format
msgid "an %qs clause can only be specified if the %<dispatch%> selector of the %<construct%> selector set appears in the %<match%> clause"
-msgstr ""
+msgstr "une clause %qs peut uniquement être spécifiée si le sélecteur %<dispatch%> du sélecteur %<construct%> apparaît dans la clause %<match%>"
#: c/c-parser.cc:27326
#, gcc-internal-format
@@ -49870,10 +49814,9 @@ msgid "expected %<acq_rel%>, %<acquire%>, %<relaxed%>, %<release%> or %<seq_cst%
msgstr "%<acq_rel%>, %<acquire%>, %<relaxed%>, %<release%> ou %<seq_cst%> attendu"
#: c/c-parser.cc:28277 cp/parser.cc:52313
-#, fuzzy, gcc-internal-format
-#| msgid "expected %<unified_address%>, %<unified_shared_memory%>, %<dynamic_allocators%>, %<reverse_offload%> or %<atomic_default_mem_order%> clause"
+#, gcc-internal-format
msgid "expected %<unified_address%>, %<unified_shared_memory%>, %<self_maps%>, %<dynamic_allocators%>, %<reverse_offload%> or %<atomic_default_mem_order%> clause"
-msgstr "clause %<unified_address%>, %<unified_shared_memory%>, %<dynamic_allocators%>, %<reverse_offload%> ou %<atomic_default_mem_order%> attendue"
+msgstr "clause %<unified_address%>, %<unified_shared_memory%>, %<self_maps%>, %<dynamic_allocators%>, %<reverse_offload%> ou %<atomic_default_mem_order%> attendue"
#: c/c-parser.cc:28296 cp/parser.cc:52332
#, gcc-internal-format
@@ -49906,16 +49849,14 @@ msgid "variable sized type %qT in %<reduction%> clause"
msgstr "type %qT de taille variable dans la clause %<reduction%>"
#: c/c-parser.cc:28474 cp/parser.cc:48878
-#, fuzzy, gcc-internal-format
-#| msgid "expected %<else%>"
+#, gcc-internal-format
msgid "expected %<sizes%>"
-msgstr "%<else%> attendu"
+msgstr "%<sizes%> attendu"
#: c/c-parser.cc:28503 cp/semantics.cc:9566 cp/semantics.cc:9583
-#, fuzzy, gcc-internal-format
-#| msgid "%<tile%> argument needs positive integral constant"
+#, gcc-internal-format
msgid "%<sizes%> argument needs positive integral constant"
-msgstr "l'argument %<tile%> a besoin d'une constante entière positive"
+msgstr "l'argument %<sizes%> a besoin d'une constante entière positive"
#: c/c-parser.cc:28619 cp/parser.cc:52424
#, gcc-internal-format
@@ -49954,10 +49895,9 @@ msgid "expected directive name"
msgstr "nom de directive attendu"
#: c/c-parser.cc:28859 cp/parser.cc:50083
-#, fuzzy, gcc-internal-format
-#| msgid "Invalid %qs directive at %L in %s clause: declarative, informational and meta directives not permitted"
+#, gcc-internal-format
msgid "invalid OpenMP directive name in %qs clause argument: declarative, informational, and meta directives not permitted"
-msgstr "Directive %qs invalide à %L dans la clause %s : directives déclarative, informationnelle et meta non permises"
+msgstr "nom de directive OpenMP invalide dans l'argument de la clause %qs : déclarative, informationnelle et meta directives non permises"
#: c/c-parser.cc:28867 cp/parser.cc:50091
#, gcc-internal-format
@@ -49985,38 +49925,34 @@ msgid "expected assumption clause"
msgstr "clause de présomption attendue"
#: c/c-parser.cc:29050 cp/parser.cc:51385
-#, fuzzy, gcc-internal-format
-#| msgid "expected %<depend%>, %<destroy%> or %<update%> clause"
+#, gcc-internal-format
msgid "expected %<when%>, %<otherwise%>, or %<default%> clause"
-msgstr "clause %<depend%>, %<destroy%> ou %<update%> attendue"
+msgstr "clause %<when%>, %<otherwise%> ou %<default%> attendue"
#: c/c-parser.cc:29064 cp/parser.cc:51400
-#, fuzzy, gcc-internal-format
-#| msgid "too many %<defaultmap%> clauses with %qs category"
+#, gcc-internal-format
msgid "too many %<otherwise%> or %<default%> clauses in %<metadirective%>"
-msgstr "trop de clauses %<defaultmap%> avec la catégorie %qs"
+msgstr "trop de clauses %<otherwise%> ou %<default%> dans %<metadirective%>"
#: c/c-parser.cc:29073 cp/parser.cc:51410
-#, fuzzy, gcc-internal-format
-#| msgid "properties for %<simd%> selector may not be specified in %<metadirective%>"
+#, gcc-internal-format
msgid "%<otherwise%> or %<default%> clause must appear last in %<metadirective%>"
-msgstr "les propriétés pour le sélecteur %<simd%> ne peuvent pas être spécifiées dans %<metadirective%>"
+msgstr "la clause %<otherwise%> ou %<default%> doit apparaître en dernier dans %<metadirective%>"
#: c/c-parser.cc:29163 cp/parser.cc:51501
-#, fuzzy, gcc-internal-format
-#| msgid "Unknown directive at %L"
+#, gcc-internal-format
msgid "unknown directive name"
-msgstr "Directive inconnue à %L"
+msgstr "nom de directive inconnu"
#: c/c-parser.cc:29178 cp/parser.cc:51521
#, gcc-internal-format
msgid "metadirectives cannot be used as variants of a %<metadirective%>"
-msgstr ""
+msgstr "les métadirectives ne peuvent pas être utilisées comme variantes de %<metadirective%>"
#: c/c-parser.cc:29184 cp/parser.cc:51527
#, gcc-internal-format
msgid "declarative directive variants of a %<metadirective%> are not supported"
-msgstr ""
+msgstr "les variantes de directives déclaratives d'une %<metadirective%> ne sont pas supportées"
#: c/c-parser.cc:29509 cp/semantics.cc:10338
#, gcc-internal-format
@@ -50095,10 +50031,9 @@ msgid "%qT and %qT are in disjoint named address spaces"
msgstr "%qT et %qT sont dans des espaces d'adresses nommés disjoints"
#: c/c-typeck.cc:571
-#, fuzzy, gcc-internal-format
-#| msgid "%qs attribute only applies to variadic functions"
+#, gcc-internal-format
msgid "%qs attribute can only be applied to variadic functions"
-msgstr "l'attribut %qs s’applique seulement aux fonctions variadiques"
+msgstr "l'attribut %qs peut uniquement être appliqué aux fonctions variadiques"
#: c/c-typeck.cc:938 c/c-typeck.cc:961
#, gcc-internal-format
@@ -50319,16 +50254,14 @@ msgid "passing argument %d of %qE as signed due to prototype"
msgstr "passage de l'argument %d de %qE comme signé à cause du prototype"
#: c/c-typeck.cc:4304
-#, fuzzy, gcc-internal-format
-#| msgid "too many arguments to method %qE"
+#, gcc-internal-format
msgid "too many arguments to method %qE; expected %i, have %i"
-msgstr "trop d'arguments pour la fonction %qE"
+msgstr "trop d'arguments pour la méthode %qE ; %i attendus, %i obtenus"
#: c/c-typeck.cc:4308
-#, fuzzy, gcc-internal-format
-#| msgid "too many arguments to built-in function %qE expecting %d"
+#, gcc-internal-format
msgid "too many arguments to function %qE; expected %i, have %i"
-msgstr "trop d'arguments pour la fonction interne %qE %d attendus"
+msgstr "trop d'arguments pour la fonction %qE ; %i attendus, %i obtenus"
#: c/c-typeck.cc:4318
#, gcc-internal-format
@@ -50338,13 +50271,12 @@ msgstr "trop d'arguments pour la fonction interne %qE %d attendus"
#: c/c-typeck.cc:4330
#, gcc-internal-format
msgid "ISO C23 does not allow arguments for method %qE declared without parameters"
-msgstr ""
+msgstr "le C23 ISO n'autorise pas que les arguments pour la méthode %qE soient déclarés sans paramètres"
#: c/c-typeck.cc:4335
-#, fuzzy, gcc-internal-format
-#| msgid "in a call to function %qD declared with attribute %qs"
+#, gcc-internal-format
msgid "ISO C23 does not allow arguments for function %qE declared without parameters"
-msgstr "dans un appel à la fonction %qD déclarée avec l'attribut %qs"
+msgstr "le C23 ISO n'autorise pas que les arguments de la fonction %qE soient déclarés sans paramètres"
#: c/c-typeck.cc:4411
#, gcc-internal-format
@@ -50352,16 +50284,14 @@ msgid "implicit conversion from %qT to %qT when passing argument to function"
msgstr "conversion implicite de %qT en %qT lors du passage de l'argument à la fonction"
#: c/c-typeck.cc:4492
-#, fuzzy, gcc-internal-format
-#| msgid "too few arguments to built-in function %qE expecting %u"
+#, gcc-internal-format
msgid "too few arguments to function %qE; expected at least %i, have %i"
-msgstr "trop peu d'arguments pour la fonction interne %qE %u attendus"
+msgstr "trop peu d'arguments pour la fonction %qE ; %i attendus au moins, %i obtenus"
#: c/c-typeck.cc:4493
-#, fuzzy, gcc-internal-format
-#| msgid "too few arguments to built-in function %qE expecting %u"
+#, gcc-internal-format
msgid "too few arguments to function %qE; expected %i, have %i"
-msgstr "trop peu d'arguments pour la fonction interne %qE %u attendus"
+msgstr "trop peu d'arguments pour la fonction %qE ; %i attendus, %i obtenus"
#: c/c-typeck.cc:4507
#, gcc-internal-format
@@ -50460,10 +50390,9 @@ msgid "decrement of a boolean expression"
msgstr "décrémentation d'une expression booléenne"
#: c/c-typeck.cc:5458
-#, fuzzy, gcc-internal-format
-#| msgid "ISO C does not support %<++%> and %<--%> on complex types"
+#, gcc-internal-format
msgid "ISO C does not support %<++%> and %<--%> on complex types before C2Y"
-msgstr "le C ISO ne permet pas %<++%> ni %<--%> sur les types complexes"
+msgstr "le C ISO ne permet pas %<++%> ni %<--%> sur les types complexes avant C2Y"
#: c/c-typeck.cc:5485 c/c-typeck.cc:5519
#, gcc-internal-format
@@ -50749,10 +50678,8 @@ msgid "array initialized from parenthesized string constant"
msgstr "tableau initialisé depuis une constante chaîne entre parenthèses"
#: c/c-typeck.cc:7617
-#, fuzzy
-#| msgid "expected %qT but argument is of type %qT"
msgid "expected %e but argument is of type %e"
-msgstr "%qT attendu mais l'argument est de type %qT"
+msgstr "%e attendu mais l'argument est de type %e"
#: c/c-typeck.cc:7651
#, gcc-internal-format
@@ -50770,10 +50697,8 @@ msgid "built-in %qD declared here"
msgstr "la fonction interne %qD est déclarée ici"
#: c/c-typeck.cc:7716 c/c-typeck.cc:8624
-#, fuzzy
-#| msgid " declared here"
msgid "%e declared here"
-msgstr " déclaré ici"
+msgstr "%e déclaré ici"
#: c/c-typeck.cc:7909
#, gcc-internal-format
@@ -50963,40 +50888,28 @@ msgid "passing argument %d of %qE from incompatible pointer type"
msgstr "passage de l'argument %d de %qE depuis un type pointeur incompatible"
#: c/c-typeck.cc:8566
-#, fuzzy
-#| msgid "assignment to %qT from pointer to %qD with incompatible type %qT"
msgid "assignment to %e from pointer to %qD with incompatible type %e"
-msgstr "affectation à %qT depuis un pointeur vers %qD avec le type incompatible %qT"
+msgstr "affectation à %e depuis un pointeur vers %qD avec le type incompatible %e"
#: c/c-typeck.cc:8572
-#, fuzzy
-#| msgid "assignment to %qT from incompatible pointer type %qT"
msgid "assignment to %e from incompatible pointer type %e"
-msgstr "affectation à %qT depuis le type pointeur %qT qui est incompatible"
+msgstr "affectation à %e depuis le type pointeur %e qui est incompatible"
#: c/c-typeck.cc:8581
-#, fuzzy
-#| msgid "initialization of %qT from pointer to %qD with incompatible type %qT"
msgid "initialization of %e from pointer to %qD with incompatible type %e"
-msgstr "initialisation de %qT depuis un pointeur vers %qD avec le type incompatible %qT"
+msgstr "initialisation de %e depuis un pointeur vers %qD avec le type incompatible %e"
#: c/c-typeck.cc:8587
-#, fuzzy
-#| msgid "initialization of %qT from incompatible pointer type %qT"
msgid "initialization of %e from incompatible pointer type %e"
-msgstr "initialisation de %qT depuis le type pointeur %qT qui est incompatible"
+msgstr "initialisation de %e depuis le type pointeur %e qui est incompatible"
#: c/c-typeck.cc:8595
-#, fuzzy
-#| msgid "returning pointer to %qD of type %qT from a function with incompatible type %qT"
msgid "returning pointer to %qD of type %e from a function with incompatible type %e"
-msgstr "retour d'un pointeur vers %qD de type %qT depuis une fonction avec le type incompatible %qT"
+msgstr "retour d'un pointeur vers %qD de type %e depuis une fonction avec le type incompatible %e"
#: c/c-typeck.cc:8601
-#, fuzzy
-#| msgid "returning %qT from a function with incompatible return type %qT"
msgid "returning %e from a function with incompatible return type %e"
-msgstr "retour de %qT depuis une fonction avec le type de retour %qT qui est incompatible"
+msgstr "retour de %e depuis une fonction avec le type de retour %e qui est incompatible"
#: c/c-typeck.cc:8677
#, gcc-internal-format
@@ -51104,21 +51017,19 @@ msgid "cannot initialize array of %qT from a string literal with type array of %
msgstr "impossible d'initialiser un tableau de %qT depuis une chaîne de caractères littérale avec un tableau de type %qT"
#: c/c-typeck.cc:9380
-#, fuzzy, gcc-internal-format
-#| msgid "initializer-string for %qT is too long"
+#, gcc-internal-format
msgid "initializer-string for array of %qT is too long (%wu chars into %wu available)"
-msgstr "la chaîne d'initialisation pour %qT est trop longue"
+msgstr "la chaîne d'initialisation pour le tableau de %qT est trop longue (%wu caractères dans %wu disponibles)"
#: c/c-typeck.cc:9385
-#, fuzzy, gcc-internal-format
-#| msgid "initializer-string for %qT is too long"
+#, gcc-internal-format
msgid "initializer-string for array of %qT is too long for C++ (%wu chars into %wu available)"
-msgstr "la chaîne d'initialisation pour %qT est trop longue"
+msgstr "la chaîne d'initialisation pour le tableau de %qT est trop longue pour C++ (%wu caractères dans %wu disponibles)"
#: c/c-typeck.cc:9392
#, gcc-internal-format
msgid "initializer-string for array of %qT truncates NUL terminator but destination lacks %qs attribute (%wu chars into %wu available)"
-msgstr ""
+msgstr "la chaîne d'initialisation pour le tableau de %qT tronque le NUL de fin mais la destination n'a pas l'attribut %qs (%wu caractères dans %wu disponibles)"
#: c/c-typeck.cc:9404
#, gcc-internal-format
@@ -51152,10 +51063,9 @@ msgid "initializer element is not a constant expression"
msgstr "un élément de l'initialisation n'est pas une expression constante"
#: c/c-typeck.cc:9560 cp/typeck2.cc:1340
-#, fuzzy, gcc-internal-format
-#| msgid "conversion from %qT to %qT changes value from %qE to %qE"
+#, gcc-internal-format
msgid "conversion from %qT to %qT changes value from %qd to %qd"
-msgstr "la conversion depuis %qT vers %qT change la valeur de %qE en %qE"
+msgstr "la conversion depuis %qT vers %qT change la valeur de %qd en %qd"
#: c/c-typeck.cc:9602 c/c-typeck.cc:11447
#, gcc-internal-format
@@ -51302,46 +51212,40 @@ msgstr "trop d'éléments dans l'initialisation d'un scalaire"
#: c/c-typeck.cc:12521 c/c-typeck.cc:12597 cp/semantics.cc:2346
#: cp/semantics.cc:2455
-#, fuzzy, gcc-internal-format
-#| msgid "ISO C does not allow extra %<;%> outside of a function"
+#, gcc-internal-format
msgid "constraint allows registers outside of a function"
-msgstr "le C ISO n'autorise pas de %<;%> supplémentaire en dehors d'une fonction"
+msgstr "la contrainte n'autorise pas des registres en dehors d'une fonction"
#: c/c-typeck.cc:12533 cp/semantics.cc:2358
-#, fuzzy, gcc-internal-format
-#| msgid "ISO C does not allow extra %<;%> outside of a function"
+#, gcc-internal-format
msgid "side-effects in output operand outside of a function"
-msgstr "le C ISO n'autorise pas de %<;%> supplémentaire en dehors d'une fonction"
+msgstr "effets de bord dans l'opérande de sortie en dehors d'une fonction"
#: c/c-typeck.cc:12544 cp/semantics.cc:2374
-#, fuzzy, gcc-internal-format
-#| msgid "output operand %d must use %<&%> constraint"
+#, gcc-internal-format
msgid "output operand outside of a function is not constant"
-msgstr "l'opérande de sortie %d doit utiliser la contrainte %<&%>"
+msgstr "l'opérande de sortie en dehors d'une fonction n'est pas une constante"
#: c/c-typeck.cc:12552 c/c-typeck.cc:12642 cp/semantics.cc:2385
#: cp/semantics.cc:2518
-#, fuzzy, gcc-internal-format
-#| msgid "%<_Cilk_spawn%> may only be used inside a function"
+#, gcc-internal-format
msgid "%<-%> modifier used inside of a function"
-msgstr "%<_Cilk_spawn%> ne peut être utilisé qu'à l'intérieur d'une fonction"
+msgstr "le modificateur %<-%> est utilisé à l'intérieur d'une fonction"
#: c/c-typeck.cc:12610 cp/semantics.cc:2468
#, gcc-internal-format
msgid "%<:%> constraint operand is not address of a function or non-automatic variable"
-msgstr ""
+msgstr "l'opérande de contrainte %<:%> n'est pas une adresse d'une fonction ou une variable non automatique"
#: c/c-typeck.cc:12623 cp/semantics.cc:2481
-#, fuzzy, gcc-internal-format
-#| msgid "ISO C does not allow extra %<;%> outside of a function"
+#, gcc-internal-format
msgid "side-effects in input operand outside of a function"
-msgstr "le C ISO n'autorise pas de %<;%> supplémentaire en dehors d'une fonction"
+msgstr "effets secondaires dans l'opérande d'entrée en dehors d'une fonction"
#: c/c-typeck.cc:12634 cp/semantics.cc:2496 cp/semantics.cc:2510
-#, fuzzy, gcc-internal-format
-#| msgid "%qD is not defined outside of function scope"
+#, gcc-internal-format
msgid "input operand outside of a function is not constant"
-msgstr "%qD n'est pas défini à l'extérieur de la portée de la fonction"
+msgstr "l'opérande d'entrée en dehors d'une fonction n'est pas une constante"
#: c/c-typeck.cc:12686
#, gcc-internal-format
@@ -51754,10 +51658,9 @@ msgid "variable length element type in array %<reduction%> clause"
msgstr "type d'élément de longueur variable dans la table de la clause %<reduction%>"
#: c/c-typeck.cc:16335 c/c-typeck.cc:17249 cp/semantics.cc:9941
-#, fuzzy, gcc-internal-format
-#| msgid "%<nowait%> clause must not be used together with %<copyprivate%>"
+#, gcc-internal-format
msgid "%<nowait%> clause must not be used together with %<copyprivate%> clause"
-msgstr "la clause %<nowait%> ne doit pas être utilisée avec %<copyprivate%>"
+msgstr "la clause %<nowait%> ne doit pas être utilisée avec la clause %<copyprivate%>"
#: c/c-typeck.cc:16347 cp/semantics.cc:10009
#, gcc-internal-format
@@ -51957,10 +51860,9 @@ msgid "%qs variable is neither a pointer nor an array"
msgstr "la variable %qs n'est ni un pointeur ni un tableau"
#: c/c-typeck.cc:17262 c/c-typeck.cc:17367 cp/semantics.cc:9892
-#, fuzzy, gcc-internal-format
-#| msgid "%<order%> clause must not be used together with %<ordered%>"
+#, gcc-internal-format
msgid "%<order%> clause must not be used together with %<ordered%> clause"
-msgstr "la clause %<order%> ne doit pas être utilisée avec %<ordered%>"
+msgstr "la clause %<order%> ne doit pas être utilisée avec la clause %<ordered%>"
#: c/c-typeck.cc:17282 cp/semantics.cc:8815
#, gcc-internal-format
@@ -51973,22 +51875,19 @@ msgid "%<inbranch%> clause is incompatible with %<notinbranch%>"
msgstr "la clause %<inbranch%> est incompatible avec %<notinbranch%>"
#: c/c-typeck.cc:17438 cp/semantics.cc:9704
-#, fuzzy, gcc-internal-format
-#| msgid "%qD appears more than once in motion clauses"
+#, gcc-internal-format
msgid "%qD appears more than once in action clauses"
-msgstr "%qD apparaît plus d'une fois dans les clauses de mouvement"
+msgstr "%qD apparaît plus d'une fois dans les clauses d'action"
#: c/c-typeck.cc:17449 cp/semantics.cc:9718
-#, fuzzy, gcc-internal-format
-#| msgid "defaulted %qD must be %<const%>"
+#, gcc-internal-format
msgid "%qD must be of %<omp_interop_t%>"
-msgstr "%qD par défaut doit être %<const%>"
+msgstr "%qD par défaut doit être du type %<omp_interop_t%>"
#: c/c-typeck.cc:17458 cp/semantics.cc:9727
-#, fuzzy, gcc-internal-format
-#| msgid "%q#D is not const"
+#, gcc-internal-format
msgid "%qD shall not be const"
-msgstr "%q#D n'est pas const"
+msgstr "%qD ne doit pas être const"
# le premier %qs est un mot non traduit tel que « private », « shared » ou « threadprivate ».
#: c/c-typeck.cc:17507 cp/semantics.cc:10080
@@ -52028,16 +51927,14 @@ msgid "%<nogroup%> clause must not be used together with %<reduction%> clause"
msgstr "la clause %<nogroup%> ne doit pas être utilisée avec la clause %<reduction%>"
#: c/c-typeck.cc:17686 cp/semantics.cc:9874
-#, fuzzy, gcc-internal-format
-#| msgid "%<nogroup%> clause must not be used together with %<reduction%> clause"
+#, gcc-internal-format
msgid "%<grainsize%> clause must not be used together with %<num_tasks%> clause"
-msgstr "la clause %<nogroup%> ne doit pas être utilisée avec la clause %<reduction%>"
+msgstr "la clause %<grainsize%> ne doit pas être utilisée avec la clause %<num_tasks%>"
#: c/c-typeck.cc:17694 cp/semantics.cc:9930
-#, fuzzy, gcc-internal-format
-#| msgid "%<nogroup%> clause must not be used together with %<reduction%> clause"
+#, gcc-internal-format
msgid "%<full%> clause must not be used together with %<partial%> clause"
-msgstr "la clause %<nogroup%> ne doit pas être utilisée avec la clause %<reduction%>"
+msgstr "la clause %<full%> ne doit pas être utilisée avec la clause %<partial%>"
#: c/c-typeck.cc:17704 cp/semantics.cc:9903
#, gcc-internal-format
@@ -52052,13 +51949,12 @@ msgstr "l'identificateur de l'événement d'une clause %<detach%> ne devrait pas
#: c/c-typeck.cc:17740 cp/semantics.cc:10176
#, gcc-internal-format
msgid "%<depend%> clause requires action clauses with %<targetsync%> interop-type"
-msgstr ""
+msgstr "la clause %<depend%> requiert les clauses d'action avec le type interop %<targetsync%>"
#: c/c-typeck.cc:17744 cp/semantics.cc:10180
-#, fuzzy, gcc-internal-format
-#| msgid "too many %<if%> clauses with %qs modifier"
+#, gcc-internal-format
msgid "%<init%> clause lacks the %<targetsync%> modifier"
-msgstr "trop de %<if%> avec le modificateur %qs"
+msgstr "la clause %<init%> n'a pas le modificateur %<targetsync%>"
#: c/c-typeck.cc:17916
#, gcc-internal-format
@@ -52293,356 +52189,343 @@ msgstr "étiquette de « case » attendue"
#: cobol/cdf-copy.cc:110
msgid "REPLACING %zu characters exceeds system capacity'%s'"
-msgstr ""
+msgstr "REPLACING %zu caractères dépasse la capacité du système « %s »"
#: cobol/cobol1.cc:276
#, gcc-internal-format
msgid "COBOL requires a 64-bit configuration"
-msgstr ""
+msgstr "COBOL requiert une configuration 64 bits"
#: cobol/cobol1.cc:327
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "Creating '%s'\n"
+#, gcc-internal-format, gfc-internal-format
msgid "exception '%s'"
-msgstr "Création de « %s »\n"
+msgstr "exception « %s »"
#: cobol/cobol1.cc:413
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "could not close response file %s"
+#, gcc-internal-format, gfc-internal-format
msgid "could not execute preprocessor %s"
-msgstr "n'a pu fermer le fichier de réponse %s"
+msgstr "n'a pu exécuter le préprocesseur %s"
#: cobol/cobol1.cc:418
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "could not find specs file %s\n"
+#, gcc-internal-format, gfc-internal-format
msgid "could not include %s"
-msgstr "impossible de trouver le fichier des specs %s\n"
+msgstr "impossible d'inclure %s"
#. This isn't right. All OPT_main should be replaced
#: cobol/cobol1.cc:424
#, gcc-internal-format
msgid "We should never see a non-equal dash-main in cobol1.c"
-msgstr ""
+msgstr "Nous ne devrions jamais voir un dash-main non égal dans cobol1.c"
#: cobol/except.cc:54
msgid "no such exception: 0x%04x"
-msgstr ""
+msgstr "pas de telle exception : 0x%04x"
#: cobol/genapi.cc:332
#, gcc-internal-format
msgid "Probable cause: it was referenced without being defined."
-msgstr ""
+msgstr "Cause probable : il a été référencé sans avoir été défini."
#: cobol/genapi.cc:571
#, gcc-internal-format
msgid "Nice try, but you can't fire me. I quit!"
-msgstr ""
+msgstr "Bien essayé mais vous ne pouvez pas me virer. Je pars !"
#: cobol/genapi.cc:1484
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "%qE does not have a mappable type in %qs clause"
+#, gcc-internal-format, gfc-internal-format
msgid "%s(): Knows not the variable type %s for %s"
-msgstr "%qE n'a pas un type pour lequel une correspondance peut être établie (mappable type) dans la clause %qs"
+msgstr "%s(): Le type de la variable %s est inconnu pour %s"
#: cobol/genapi.cc:2171
#, gcc-internal-format, gfc-internal-format
msgid "I don't know how to MOVE an alphabetical string to %s(%s) \n"
-msgstr ""
+msgstr "Je ne sais pas comment déplacer une chaîne alphabétique vers %s(%s)\n"
#: cobol/genapi.cc:2239
#, gcc-internal-format, gfc-internal-format
msgid "%s(): field->type %s must be literal or alphanumeric"
-msgstr ""
+msgstr "%s(): champ->type %s doit être littéral ou alphanumérique"
#: cobol/genapi.cc:5773
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "invalid receiver type %qs"
+#, gcc-internal-format, gfc-internal-format
msgid "%s(): Invalid field type %s:"
-msgstr "type du receveur %qs invalide"
+msgstr "%s(): Champ de type invalide %s :"
#: cobol/genapi.cc:6987 cobol/genapi.cc:6993 cobol/genapi.cc:6999
#, gcc-internal-format, gfc-internal-format
msgid "parser_logop() was called with variable %s on line %d, which is not a FldConditional\n"
-msgstr ""
+msgstr "parser_logop() a été appelé avec la variable %s à la ligne %d qui n'est pas un FldConditional\n"
#: cobol/genapi.cc:7106 cobol/genapi.cc:7170
#, gcc-internal-format, gfc-internal-format
msgid "parser_relop() was called with variable %s, which is not a FldConditional\n"
-msgstr ""
+msgstr "parser_relop() a été appelé avec la variable %s qui n'est pas un FldConditional\n"
#: cobol/genapi.cc:7216
#, gcc-internal-format, gfc-internal-format
msgid "parser_if() was called with variable %s, which is not a FldConditional\n"
-msgstr ""
+msgstr "parser_if() a été appelé avec la variable %s qui n'est pas un FldConditional\n"
#: cobol/genapi.cc:7469
#, gcc-internal-format, gfc-internal-format
msgid "###### candidate %s has unimplemented CVT_type %d(%s)\n"
-msgstr ""
+msgstr "###### le candidat %s a le type CVT_type %d(%s) non implémenté\n"
#: cobol/genapi.cc:7480
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "unknown evrp mode %qs"
+#, gcc-internal-format, gfc-internal-format
msgid "###### unknown setop_t code %d\n"
-msgstr "mode evrp %qs inconnu"
+msgstr "###### code setop_t %d inconnu\n"
#: cobol/genapi.cc:7676
msgid "%s:%d: %zu exceeds MAXIMUM_UNTILS of %d, line %d"
-msgstr ""
+msgstr "%s:%d: %zu dépasse MAXIMUM_UNTILS de %d, ligne %d"
#: cobol/genapi.cc:8682
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d: ignoring subscripts"
-msgstr ""
+msgstr "%s:%d: indices ignorés"
#: cobol/genapi.cc:8900 cobol/genapi.cc:9360
#, gcc-internal-format, gfc-internal-format
msgid "%s(): called with NULL *file"
-msgstr ""
+msgstr "%s(): appelé avec NULL *fichier"
#: cobol/genapi.cc:9025
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d file %s access mode is 'file_inaccessible_e' in %s"
-msgstr ""
+msgstr "%s:%d le mode d'accès du fichier %s est « file_inaccessible_e » dans %s"
#: cobol/genapi.cc:9098
#, gcc-internal-format
msgid "parser_file_open called with NULL *file"
-msgstr ""
+msgstr "parser_file_open appelé avec NULL *fichier"
#: cobol/genapi.cc:9103
#, gcc-internal-format, gfc-internal-format
msgid "parser_file_open for %s called with NULL var_decl_node"
-msgstr ""
+msgstr "parser_file_open pour %s appelé avec NULL var_decl_node"
#: cobol/genapi.cc:9108
#, gcc-internal-format, gfc-internal-format
msgid "EXTEND can only be used where %s is ACCESS MODE SEQUENTIAL"
-msgstr ""
+msgstr "EXTEND peut uniquement être utilisé où %s est ACCESS MODE SEQUENTIAL"
#: cobol/genapi.cc:9176
#, gcc-internal-format
msgid "parser_file_close called with NULL *file"
-msgstr ""
+msgstr "parser_file_close appelé avec NULL *fichier"
#: cobol/genapi.cc:9181
#, gcc-internal-format, gfc-internal-format
msgid "parser_file_close for %s called with NULL file->var_decl_node"
-msgstr ""
+msgstr "parser_file_close pour %s est appelé avec NULL fichier->var_decl_node"
#: cobol/genapi.cc:9234
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d file %s 'where' is zero in %s"
-msgstr ""
+msgstr "%s:%d pour le fichier %s, « where » est zéro dans %s"
#: cobol/genapi.cc:9244
#, gcc-internal-format
msgid "parser_file_read called with NULL *file"
-msgstr ""
+msgstr "parser_file_read appelé avec NULL *fichier"
#: cobol/genapi.cc:9249
#, gcc-internal-format, gfc-internal-format
msgid "parser_file_read for %s called with NULL file->var_decl_node"
-msgstr ""
+msgstr "parser_file_read pour %s est appelé avec NULL fichier->var_decl_node"
#: cobol/genapi.cc:9254
#, gcc-internal-format
msgid "parser_file_read called with NULL *field"
-msgstr ""
+msgstr "parser_file_read appelé avec NULL *champ"
#: cobol/genapi.cc:9259
#, gcc-internal-format, gfc-internal-format
msgid "parser_file_read for %s called with NULL field->var_decl_node"
-msgstr ""
+msgstr "parser_file_read pour %s est appelé avec NULL champ->var_decl_node"
#: cobol/genapi.cc:9264
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d file %s is RELATIVE/SEQUENTIAL, but 'where' >= 0"
-msgstr ""
+msgstr "%s:%d le fichier %s est RELATIVE/SEQUENTIAL, mais le « where » >= 0"
#: cobol/genapi.cc:9273
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d file %s is RELATIVE/RANDOM, but 'where' < 0"
-msgstr ""
+msgstr "%s:%d le fichier %s est RELATIVE/RANDOM mais le « where » < 0"
#: cobol/genapi.cc:9316
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d file %s 'sequentially' is %d in %s"
-msgstr ""
+msgstr "%s:%d le fichier %s a « sequentially » à %d dans %s"
#: cobol/genapi.cc:9365
#, gcc-internal-format, gfc-internal-format
msgid "%s(): for %s called with NULL file->var_decl_node"
-msgstr ""
+msgstr "%s(): pour %s appelé avec NULL fichier->var_decl_node"
#: cobol/genapi.cc:9371
#, gcc-internal-format, gfc-internal-format
msgid "%s(): called with NULL *field"
-msgstr ""
+msgstr "%s(): appelé avec NULL *champ"
#: cobol/genapi.cc:9376
#, gcc-internal-format, gfc-internal-format
msgid "%s(): for %s called with NULL field->var_decl_node"
-msgstr ""
+msgstr "%s(): pour %s appelé avec NULL champ->var_decl_node"
#: cobol/genapi.cc:9511
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d file %s is INDEXED/SEQUENTIAL, but 'sequentially' is false"
-msgstr ""
+msgstr "%s:%d le fichier %s est INDEXED/SEQUENTIAL mais « sequentially » est faux"
#: cobol/genapi.cc:11163
#, gcc-internal-format, gfc-internal-format
msgid "%s(): asked to sort %s, but it's not a table"
-msgstr ""
+msgstr "%s(): le tri de %s a été demandé mais ce n'est pas une table"
#. Having both or neither violates SORT syntax
#: cobol/genapi.cc:11291
#, gcc-internal-format, gfc-internal-format
msgid "%s(): syntax error -- both (or neither) USING and input-proc are specified"
-msgstr ""
+msgstr "%s(): erreur de syntaxe -- les deux (ou aucun) USING et une procédure d'entrée sont spécifiés"
#: cobol/genapi.cc:11420
#, gcc-internal-format, gfc-internal-format
msgid "%s(): syntax error -- both (or neither) GIVING and output-proc are specified"
-msgstr ""
+msgstr "%s(): erreur de syntaxe -- les deux (ou aucun) GIVING et une procédure de sortie sont spécifiés"
#: cobol/genapi.cc:11826
#, gcc-internal-format, gfc-internal-format
msgid "%s(): syntax error -- both (or neither) files and output-proc are specified"
-msgstr ""
+msgstr "%s(): erreur de syntaxe -- les deux (ou aucun) fichiers et une procédure de sortie sont spécifiés"
#: cobol/genapi.cc:12227
#, gcc-internal-format
msgid "CALL USING BY CONTENT <temporary> would require REPOSITORY PROTOTYPES."
-msgstr ""
+msgstr "CALL USING BY CONTENT <temporary> requiert REPOSITORY PROTOTYPES."
#: cobol/genapi.cc:12478
#, gcc-internal-format, gfc-internal-format
msgid "%s(): What in the name of Nero's fiddle are we doing here?"
-msgstr ""
+msgstr "%s(): Qu'est-ce que nous bricolons ici ?"
#: cobol/genapi.cc:13993
#, gcc-internal-format, gfc-internal-format
msgid "In parser_move(%s to %s), the move of FldLiteralN to %s hasn't been implemented"
-msgstr ""
+msgstr "In parser_move(%s to %s), le déplacement de FldLiteralN vers %s n'a pas été implémenté"
#: cobol/genapi.cc:14229
#, gcc-internal-format, gfc-internal-format
msgid "In mh_dest_is_float(%s to %s), the move of %s to %s hasn't been implemented"
-msgstr ""
+msgstr "Dans mh_dest_is_float(%s to %s), le déplacement de %s vers %s n'a pas été implémenté"
#: cobol/genapi.cc:16323
#, gcc-internal-format, gfc-internal-format
msgid "LEVEL 01 (%s) OCCURS has insufficient data.memsize"
-msgstr ""
+msgstr "LEVEL 01 (%s) OCCURS a un paramètre data.memsize insuffisant"
#: cobol/genapi.cc:16395
#, gcc-internal-format
msgid "parser_symbol_add() was called with a NULL new_var\n"
-msgstr ""
+msgstr "parser_symbol_add() a été appelé avec un nouvelle_var NULL\n"
#: cobol/genapi.cc:16423
msgid "%s(): %2.2d %s is a table, but it improperly has a capacity of zero"
-msgstr ""
+msgstr "%s(): %2.2d %s est une table mais elle a une capacité inopportunément à zéro"
#: cobol/genapi.cc:16463
#, gcc-internal-format, gfc-internal-format
msgid "parser_symbol_add(): %s is its own ancestor"
-msgstr ""
+msgstr "parser_symbol_add(): %s est son propre ancêtre"
#: cobol/genapi.cc:16469
msgid "parser_symbol_add(): %2.2d %s has null ancestor"
-msgstr ""
+msgstr "parser_symbol_add(): %2.2d %s a un ancêtre null"
#: cobol/genapi.cc:16477
#, gcc-internal-format, gfc-internal-format
msgid "parser_symbol_add( %s ) improperly has a non-null var_decl_node\n"
-msgstr ""
+msgstr "parser_symbol_add( %s ) a un var_decl_node inopportunément non null\n"
#: cobol/genapi.cc:16682
msgid "%s(): %2.2d %s<%s> improperly has a data.capacity of zero"
-msgstr ""
+msgstr "%s(): %2.2d %s<%s> a une data.capacité inopportunément à zéro"
#: cobol/gengen.cc:363
#, gcc-internal-format
msgid "The given type is not NULL, and that's just not fair"
-msgstr ""
+msgstr "Le type donné n'est pas NULL et ce n'est pas sympa"
#: cobol/gengen.cc:372
#, gcc-internal-format
msgid "The given type is not a DECL or a TYPE"
-msgstr ""
+msgstr "Le type donné n'est pas un DECL ou un TYPE"
#: cobol/gengen.cc:412
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "unknown lam type %qs"
+#, gcc-internal-format, gfc-internal-format
msgid "Unknown type %d"
-msgstr "type lam %qs inconnu"
+msgstr "Type %d inconnu"
#: cobol/gengen.cc:2931
#, gcc-internal-format
msgid "Residual context count!"
-msgstr ""
+msgstr "Décompte de contextes résiduels !"
#: cobol/genmath.cc:1394
#, gcc-internal-format, gfc-internal-format
msgid "parser_op() doesn't know how to evaluate \"%s = %s %c %s\"\n"
-msgstr ""
+msgstr "parser_op() ne sait pas comment évaluer \"%s = %s %c %s\"\n"
#: cobol/genutil.cc:324 cobol/genutil.cc:603
-#, fuzzy, gcc-internal-format
-#| msgid "too many input files"
+#, gcc-internal-format
msgid "Too many subscripts"
-msgstr "trop de fichiers d'entrée"
+msgstr "Trop d'indices"
#: cobol/lexio.cc:1485
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "%s signal terminated program %s"
+#, gcc-internal-format, gfc-internal-format
msgid "%s pid %d terminated by %s"
-msgstr "le signal %s a terminé le programme %s"
+msgstr "%s pid %d terminé par %s"
#: cobol/lexio.cc:1490
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "%s returned %d exit status"
+#, gcc-internal-format, gfc-internal-format
msgid "%s exited with status %d"
-msgstr "%s a retourné %d comme valeur de sortie"
+msgstr "%s s'est terminé avec le statut %d"
#: cobol/symbols.cc:530
msgid "%s:%d: LblNone '%s' has parent #%zu"
-msgstr ""
+msgstr "%s:%d: LblNone « %s » a le parent #%zu"
#: cobol/symbols.cc:2040
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "%qs value must be positive"
+#, gcc-internal-format, gfc-internal-format
msgid "%s: key must be field"
-msgstr "la valeur de %qs doit être positive"
+msgstr "%s: la clé doit être un champ"
#: cobol/symbols.cc:3837 cobol/symbols.cc:3960 cobol/symbols.cc:3997
#, gcc-internal-format, gfc-internal-format
msgid "%s:%d: could not add '%s'"
-msgstr ""
+msgstr "%s:%d: impossible d'ajouter « %s »"
#: cobol/util.cc:1085
#, gcc-internal-format, gfc-internal-format
msgid "logic error: MOVE %s %s invalid type:"
-msgstr ""
+msgstr "erreur de logique : MOVE %s %s type invalide :"
#: cobol/util.cc:1695
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "%s: %s: %s"
+#, gcc-internal-format, gfc-internal-format
msgid "%s: regcomp: %s"
-msgstr "%s: %s: %s"
+msgstr "%s: regcomp: %s"
#: cobol/util.cc:1805
#, gcc-internal-format, gfc-internal-format
msgid "logic error: missing inode for %s"
-msgstr ""
+msgstr "erreur de logique : inœud manquant pour %s"
#: cobol/util.cc:2143
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid "collect: recompiling %s\n"
+#, gcc-internal-format, gfc-internal-format
msgid "failed compiling %s"
-msgstr "collect: recompilation de %s\n"
+msgstr "échec de la compilation %s"
#: cp/call.cc:2106
#, gcc-internal-format
@@ -52656,47 +52539,36 @@ msgid "passing %qT as %<this%> argument discards qualifiers"
msgstr "le passage de %qT comme argument %<this%> abandonne les qualificatifs"
#: cp/call.cc:3961
-#, fuzzy
-#| msgid " no known conversion for implicit %<this%> parameter from %qH to %qI"
msgid "no known conversion for implicit %<this%> parameter from %qH to %qI"
-msgstr " pas de conversion connue de %qH vers %qI pour le paramètre implicite %<this%>"
+msgstr "pas de conversion connue pour le paramètre %<this%> implicite pour convertir de %qH vers %qI"
#: cp/call.cc:3968
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid " conversion of argument %d would be ill-formed:"
+#, gcc-internal-format, gfc-internal-format
msgid "conversion of argument %d would be ill-formed:"
-msgstr " la conversion de l'argument %d serait mal formée:"
+msgstr "la conversion de l'argument %d serait mal formée:"
#. Conversion of conversion function return value failed.
#: cp/call.cc:3976
-#, fuzzy
-#| msgid " no known conversion from %qH to %qI"
msgid "no known conversion from %qH to %qI"
-msgstr " pas de conversion connue pour convertir %qH en %qI"
+msgstr "pas de conversion connue pour convertir %qH en %qI"
#: cp/call.cc:3982
-#, fuzzy
-#| msgid " no known conversion for argument %d from %qH to %qI"
msgid "no known conversion for argument %d from %qH to %qI"
-msgstr " pas de conversion connue pour convertir l'argument %d depuis %qH vers %qI"
+msgstr "pas de conversion connue pour convertir l'argument %d depuis %qH vers %qI"
#: cp/call.cc:3996
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid " candidate expects at least %d argument, %d provided"
-#| msgid_plural " candidate expects at least %d arguments, %d provided"
+#, gcc-internal-format, gfc-internal-format
msgid "candidate expects at least %d argument, %d provided"
msgid_plural "candidate expects at least %d arguments, %d provided"
-msgstr[0] " le candidat attend au moins %d argument, %d fourni(s)"
-msgstr[1] " le candidat attend au moins %d arguments, %d fourni(s)"
+msgstr[0] "le candidat attend au moins %d argument, %d fourni(s)"
+msgstr[1] "le candidat attend au moins %d arguments, %d fourni(s)"
#: cp/call.cc:4001
-#, fuzzy, gcc-internal-format, gfc-internal-format
-#| msgid " candidate expects %d argument, %d provided"
-#| msgid_plural " candidate expects %d arguments, %d provided"
+#, gcc-internal-format, gfc-internal-format
msgid "candidate expects %d argument, %d provided"
msgid_plural "candidate expects %d arguments, %d provided"
-msgstr[0] " le candidat attend %d argument, %d fourni(s)"
-msgstr[1] " le candidat attend %d arguments, %d fourni(s)"
+msgstr[0] "le candidat attend %d argument, %d fourni(s)"
+msgstr[1] "le candidat attend %d arguments, %d fourni(s)"
#: cp/call.cc:4029
#, gcc-internal-format
@@ -52749,54 +52621,47 @@ msgid "%s%#qD"
msgstr "%s%#qD"
#: cp/call.cc:4058
-#, fuzzy, gcc-internal-format
-#| msgid " inherited here"
+#, gcc-internal-format
msgid "inherited here"
-msgstr " hérité ici"
+msgstr "hérité ici"
#: cp/call.cc:4080
-#, fuzzy, gcc-internal-format
-#| msgid " return type %qT of explicit conversion function cannot be converted to %qT with a qualification conversion"
+#, gcc-internal-format
msgid "return type %qT of explicit conversion function cannot be converted to %qT with a qualification conversion"
-msgstr " le type de retour %qT de la fonction de conversion explicite ne peut pas être converti en %qT avec une conversion qualifiée"
+msgstr "le type de retour %qT de la fonction de conversion explicite ne peut pas être converti en %qT avec une conversion qualifiée"
#: cp/call.cc:4086
-#, fuzzy, gcc-internal-format
-#| msgid " conversion from return type %qT of template conversion function specialization to %qT is not an exact match"
+#, gcc-internal-format
msgid "conversion from return type %qT of template conversion function specialization to %qT is not an exact match"
-msgstr " la conversion depuis le type de retour %qT de la spécialisation de la fonction de conversion du patron vers %qT n'est pas une correspondance exacte"
+msgstr "la conversion depuis le type de retour %qT de la spécialisation de la fonction de conversion du patron vers %qT n'est pas une correspondance exacte"
#: cp/call.cc:4097
-#, fuzzy, gcc-internal-format
-#| msgid " substitution of deduced template arguments resulted in errors seen above"
+#, gcc-internal-format
msgid "substitution of deduced template arguments resulted in errors seen above"
-msgstr " la substitution des arguments du patron déduit a provoqué les erreurs vues plus haut"
+msgstr "la substitution des arguments du patron déduit a provoqué les erreurs vues plus haut"
#. Re-run template unification with diagnostics.
#: cp/call.cc:4102
-#, fuzzy, gcc-internal-format
-#| msgid " template argument deduction/substitution failed:"
+#, gcc-internal-format
msgid "template argument deduction/substitution failed:"
-msgstr " la déduction/substitution de l'argument du patron a échoué:"
+msgstr "la déduction/substitution de l'argument du patron a échoué:"
#: cp/call.cc:4119
-#, fuzzy, gcc-internal-format
-#| msgid " a constructor taking a single argument of its own class type is invalid"
+#, gcc-internal-format
msgid "a constructor taking a single argument of its own class type is invalid"
-msgstr " un constructeur acceptant un unique argument de son propre type de classe est invalide"
+msgstr "un constructeur acceptant un unique argument de son propre type de classe est invalide"
#: cp/call.cc:4129
-#, fuzzy, gcc-internal-format
-#| msgid " an inherited constructor is not a candidate for initialization from an expression of the same or derived type"
+#, gcc-internal-format
msgid "an inherited constructor is not a candidate for initialization from an expression of the same or derived type"
-msgstr " un constructeur hérité n'est pas un candidat pour une initialisation depuis une expression du même type ou d'un type dérivé"
+msgstr "un constructeur hérité n'est pas un candidat pour une initialisation depuis une expression du même type ou d'un type dérivé"
#: cp/call.cc:4209
#, gcc-internal-format, gfc-internal-format
msgid "there is %i candidate"
msgid_plural "there are %i candidates"
-msgstr[0] ""
-msgstr[1] ""
+msgstr[0] "il y a %i candidat"
+msgstr[1] "il y a %i candidats"
#: cp/call.cc:4220
#, gcc-internal-format
@@ -52877,10 +52742,8 @@ msgid " (operand type is %qT)"
msgstr " (le type de l'opérande est %qT)"
#: cp/call.cc:5606
-#, fuzzy
-#| msgid " (operand types are %qT and %qT)"
msgid " (operand types are %e and %e)"
-msgstr " (les types des opérandes sont %qT et %qT)"
+msgstr " (les types des opérandes sont %e et %e)"
#: cp/call.cc:5621
#, gcc-internal-format
@@ -53136,10 +52999,9 @@ msgid "converting %<false%> to pointer type %qT"
msgstr "conversion de %<false%> vers le type pointeur %qT"
#: cp/call.cc:8547
-#, fuzzy, gcc-internal-format
-#| msgid " initializing argument %P of %qD"
+#, gcc-internal-format
msgid "initializing argument %P of %qD"
-msgstr " initialisation de l'argument %P de %qD"
+msgstr "initialisation de l'argument %P de %qD"
#: cp/call.cc:8569
#, gcc-internal-format
@@ -53182,10 +53044,8 @@ msgid "in C++11 and above a default constructor can be explicit"
msgstr "en C++11 et au delà, un constructeur par défaut peut être explicite"
#: cp/call.cc:8953
-#, fuzzy
-#| msgid "narrowing conversion of %qE from %qH to %qI"
msgid "narrowing conversion of %qd from %qH to %qI"
-msgstr "conversion réductrice de %qE depuis %qH vers %qI"
+msgstr "conversion réductrice de %qd depuis %qH vers %qI"
#: cp/call.cc:9104
#, gcc-internal-format
@@ -53558,10 +53418,9 @@ msgid "possibly dangling reference to a temporary"
msgstr "est peut-être une référence ballante vers un temporaire"
#: cp/call.cc:14722
-#, fuzzy, gcc-internal-format
-#| msgid "unnamed temporary defined here"
+#, gcc-internal-format
msgid "%qT temporary created here"
-msgstr "le temporaire non nommé est défini ici"
+msgstr "le temporaire %qT est créé ici"
#: cp/call.cc:15101
#, gcc-internal-format
@@ -54022,10 +53881,9 @@ msgid "flexible array member %qD not at end of %q#T"
msgstr "le membre tableau flexible %qD n'est pas à la fin de %q#T"
#: cp/class.cc:7704
-#, fuzzy, gcc-internal-format
-#| msgid "flexible array member %qD in an otherwise empty %q#T"
+#, gcc-internal-format
msgid "flexible array member %qD in an otherwise empty %q#T is a GCC extension"
-msgstr "membre tableau flexible %qD dans %q#T par ailleurs vide"
+msgstr "membre tableau flexible %qD dans %q#T par ailleurs vide est une extension de GCC"
#: cp/class.cc:7727
#, gcc-internal-format
@@ -54139,10 +53997,9 @@ msgid "the type %qT of %<constexpr%> variable %qD is not literal"
msgstr "le type %qT de la variable %<constexpr%> %qD n'est pas littéral"
#: cp/constexpr.cc:123
-#, fuzzy, gcc-internal-format
-#| msgid "variable %qD of non-literal type %qT in %<constexpr%> function only available with %<-std=c++2b%> or %<-std=gnu++2b%>"
+#, gcc-internal-format
msgid "variable %qD of non-literal type %qT in %<constexpr%> function only available with %<-std=c++23%> or %<-std=gnu++23%>"
-msgstr "la variable %qD du type non littéral %qT dans une fonction %<constexpr%> uniquement disponible avec %<-std=c++2b%> ou %<-std=gnu++2b%>"
+msgstr "la variable %qD du type non littéral %qT dans une fonction %<constexpr%> uniquement disponible avec %<-std=c++23%> ou %<-std=gnu++23%>"
#: cp/constexpr.cc:136
#, gcc-internal-format
@@ -54204,7 +54061,7 @@ msgstr "le corps de la fonction %<constexpr%> %qD n'est pas une unique instructi
#: cp/constexpr.cc:1069
#, gcc-internal-format
msgid "%<-fimplicit-constexpr%> only affects %<inline%> functions"
-msgstr ""
+msgstr "%<-fimplicit-constexpr%> affecte uniquement les fonctions %<inline%>"
#: cp/constexpr.cc:1085
#, gcc-internal-format
@@ -54316,10 +54173,9 @@ msgid "expression %qE does not designate a %<constexpr%> function"
msgstr "l'expression %qE ne désigne pas une fonction %<constexpr%>"
#: cp/constexpr.cc:2940
-#, fuzzy, gcc-internal-format
-#| msgid "'o' operand is not constant"
+#, gcc-internal-format
msgid "cannot allocate array: size not constant"
-msgstr "l'opérande « o » n'est pas une constante"
+msgstr "impossible d'allouer le tableau : la taille n'est pas constante"
#: cp/constexpr.cc:2981
#, gcc-internal-format
@@ -54808,10 +54664,9 @@ msgid "constant evaluation returns address of immediate function %qD"
msgstr "l'évaluation constante retourne l'adresse de la fonction immédiate %qD"
#: cp/constexpr.cc:9289
-#, fuzzy, gcc-internal-format
-#| msgid "%qs is not a constant expression because %qT contains a pointer type"
+#, gcc-internal-format
msgid "%qE is not a constant expression because it initializes a %qT rather than %qT"
-msgstr "%qs n'est pas une expression constante car %qT contient un type pointeur"
+msgstr "%qE n'est pas une expression constante car il initialise un %qT plutôt qu'un %qT"
#: cp/constexpr.cc:9910 rust/backend/rust-constexpr.cc:5667
#, gcc-internal-format
@@ -54899,10 +54754,9 @@ msgid "non-constant array initialization"
msgstr "initialisation d'un tableau non constant"
#: cp/constexpr.cc:10965
-#, fuzzy, gcc-internal-format
-#| msgid "label definition in %<constexpr%> function only available with %<-std=c++2b%> or %<-std=gnu++2b%>"
+#, gcc-internal-format
msgid "label definition in %<constexpr%> function only available with %<-std=c++23%> or %<-std=gnu++23%>"
-msgstr "la définition d'une étiquette dans une fonction %<constexpr%> est uniquement disponible avec %<-std=c++2b%> ou %<-std=gnu++2b%>"
+msgstr "la définition d'une étiquette dans une fonction %<constexpr%> est uniquement disponible avec %<-std=c++23%> ou %<-std=gnu++23%>"
#: cp/constexpr.cc:11001 rust/backend/rust-constexpr.cc:6438
#, gcc-internal-format, gfc-internal-format
@@ -55107,10 +54961,9 @@ msgid " %qT is not a class"
msgstr " %qT n'est pas une classe"
#: cp/constraint.cc:3090
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not an object type"
+#, gcc-internal-format
msgid " %qT is not a const type"
-msgstr " %qT n'est pas un type objet"
+msgstr " %qT n'est pas un type constant"
#: cp/constraint.cc:3094
#, gcc-internal-format
@@ -55148,16 +55001,14 @@ msgid " %qT is not a function"
msgstr " %qT n'est pas une fonction"
#: cp/constraint.cc:3115
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not trivially copyable"
+#, gcc-internal-format
msgid " %qT is not invocable"
-msgstr " %qT n'est pas trivialement copiable"
+msgstr " %qT ne peut pas être invoqué"
#: cp/constraint.cc:3117
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not assignable from %qT"
+#, gcc-internal-format
msgid " %qT is not invocable by %qE"
-msgstr " %qT n'est pas assignable depuis %qT"
+msgstr " %qT ne peut pas être invoqué par %qE"
#: cp/constraint.cc:3120
#, gcc-internal-format
@@ -55200,16 +55051,14 @@ msgid " %qT is not nothrow convertible from %qE"
msgstr " %qT ne peut pas être converti avec %<nothrow%> à partir de %qE"
#: cp/constraint.cc:3148
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not nothrow copy assignable"
+#, gcc-internal-format
msgid " %qT is not nothrow invocable"
-msgstr " %qT n'est pas assignable par copie avec nothrow"
+msgstr " %qT ne peut pas être invoqué avec nothrow"
#: cp/constraint.cc:3150
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not nothrow assignable from %qT"
+#, gcc-internal-format
msgid " %qT is not nothrow invocable by %qE"
-msgstr " %qT n'est pas assignable avec nothrow depuis %qT"
+msgstr " %qT ne peut pas être invoqué avec nothrow par %qE"
#: cp/constraint.cc:3153
#, gcc-internal-format
@@ -55227,10 +55076,9 @@ msgid " %qT is not a POD type"
msgstr " %qT n'est pas un type simple (aussi appelé POD : Plain Old Data)"
#: cp/constraint.cc:3163
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not a member pointer"
+#, gcc-internal-format
msgid " %qT is not a pointer"
-msgstr " %qT n'est pas un pointeur membre"
+msgstr " %qT n'est pas un pointeur"
#: cp/constraint.cc:3166
#, gcc-internal-format
@@ -55278,10 +55126,9 @@ msgid " %qT is not trivially copyable"
msgstr " %qT n'est pas trivialement copiable"
#: cp/constraint.cc:3196
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not a bounded array"
+#, gcc-internal-format
msgid " %qT is not an unbounded array"
-msgstr " %qT n'est pas un tableau borné"
+msgstr " %qT n'est pas un tableau non borné"
#: cp/constraint.cc:3199
#, gcc-internal-format
@@ -55289,22 +55136,19 @@ msgid " %qT is not a union"
msgstr " %qT est une union"
#: cp/constraint.cc:3202
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not a base of %qT"
+#, gcc-internal-format
msgid " %qT is not a virtual base of %qT"
-msgstr " %qT n'est pas une base de %qT"
+msgstr " %qT n'est pas une base virtuelle de %qT"
#: cp/constraint.cc:3205
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not a literal type"
+#, gcc-internal-format
msgid " %qT is not a volatile type"
-msgstr " %qT n'est pas un type littéral"
+msgstr " %qT n'est pas un type volatile"
#: cp/constraint.cc:3208
-#, fuzzy, gcc-internal-format
-#| msgid " %qT is not an array"
+#, gcc-internal-format
msgid " %qT cannot yield a rank"
-msgstr " %qT n'est pas un tableau"
+msgstr " %qT ne peut pas rendre un rang"
#: cp/constraint.cc:3211
#, gcc-internal-format
@@ -55523,35 +55367,30 @@ msgid "coroutines require a handle class template; cannot find %<%E::%E%>"
msgstr "les coroutines requièrent un identificateur de patron de classe ; impossible de trouver %<%E::%E%>"
#: cp/coroutines.cc:534
-#, fuzzy, gcc-internal-format
-#| msgid "%qD must be a non-member function"
+#, gcc-internal-format
msgid "%qE must be a non-overloaded method"
-msgstr "%qD doit être une fonction non membre"
+msgstr "%qE doit être une méthode non surchargée"
#: cp/coroutines.cc:547
-#, fuzzy, gcc-internal-format
-#| msgid "%qD must have no arguments"
+#, gcc-internal-format
msgid "%qE must take no arguments"
-msgstr "%qD ne doit avoir aucun argument"
+msgstr "%qE ne doit prendre aucun argument"
# le premier %qs est un mot non traduit tel que « private », « shared » ou « threadprivate ».
#: cp/coroutines.cc:554 cp/coroutines.cc:599
-#, fuzzy, gcc-internal-format
-#| msgid "%qE is predetermined %qs for %qs"
+#, gcc-internal-format
msgid "%qE must return %qT, not %qT"
-msgstr "%qE est prédéterminé %qs pour %qs"
+msgstr "%qE doit retourner %qT, pas %qT"
#: cp/coroutines.cc:581
-#, fuzzy, gcc-internal-format
-#| msgid "%qD must be a non-static member function"
+#, gcc-internal-format
msgid "%qE must be a non-overloaded static function"
-msgstr "%qD doit être une fonction membre non statique"
+msgstr "%qE doit être une fonction statique non surchargée"
#: cp/coroutines.cc:592
-#, fuzzy, gcc-internal-format
-#| msgid "%qT is not a base of %qT"
+#, gcc-internal-format
msgid "%qE must take a single %qT"
-msgstr "%qT n'est pas une base de %qT"
+msgstr "%qE doit prendre un seul %qT"
#: cp/coroutines.cc:621
#, gcc-internal-format
@@ -55702,15 +55541,14 @@ msgid "%qE is provided by %qT but %<std::nothrow%> cannot be found"
msgstr "%qE est fourni par %qT mais %<std::nothrow%> n'est pas trouvé"
#: cp/coroutines.cc:4840
-#, fuzzy, gcc-internal-format
-#| msgid "%qE is provided by %qT but is not usable with the function signature %qD"
+#, gcc-internal-format
msgid "%qE is provided by %qT but is not usable with the function %qD"
-msgstr "%qE est fourni par %qT mais il n'est pas utilisable avec la fonction ayant la signature %qD"
+msgstr "%qE est fourni par %qT mais il n'est pas utilisable avec la fonction %qD"
#: cp/coroutines.cc:5146
#, gcc-internal-format
msgid "no viable conversion from %<void%> provided by %<get_return_object%> to return type %qT"
-msgstr ""
+msgstr "aucune conversion viable de %<void%> est fournie par %<get_return_object%> pour retourner le type %qT"
#: cp/cp-gimplify.cc:197
#, gcc-internal-format
@@ -55868,10 +55706,9 @@ msgid "conversion from %qH to non-scalar type %qI requested"
msgstr "conversion de %qH vers le type non scalaire %qI demandée"
#: cp/cvt.cc:1089
-#, fuzzy, gcc-internal-format
-#| msgid "ignoring return value of %qD, declared with attribute %<nodiscard%>: %E"
+#, gcc-internal-format
msgid "ignoring return value of %qD, declared with attribute %<nodiscard%>: %qs"
-msgstr "la valeur de retour de %qD est ignorée alors qu'elle est déclarée avec l'attribut %<nodiscard%> : %E"
+msgstr "la valeur de retour de %qD est ignorée alors qu'elle est déclarée avec l'attribut %<nodiscard%> : %qs"
#: cp/cvt.cc:1091
#, gcc-internal-format
@@ -55879,10 +55716,9 @@ msgid "ignoring return value of %qD, declared with attribute %<nodiscard%>%s"
msgstr "la valeur de retour de %qD est ignorée alors qu'elle est déclarée avec l'attribut %<nodiscard%>%s"
#: cp/cvt.cc:1108
-#, fuzzy, gcc-internal-format
-#| msgid "ignoring returned value of type %qT, declared with attribute %<nodiscard%>%s"
+#, gcc-internal-format
msgid "ignoring returned value of type %qT, declared with attribute %<nodiscard%>: %qs"
-msgstr "la valeur de retour de type %qT est ignorée alors qu'elle est déclarée avec l'attribut %<nodiscard%>%s"
+msgstr "la valeur de retour de type %qT est ignorée alors qu'elle est déclarée avec l'attribut %<nodiscard%> : %qs"
#: cp/cvt.cc:1110
#, gcc-internal-format
@@ -56170,10 +56006,9 @@ msgid "with"
msgstr "avec"
#: cp/decl.cc:733
-#, fuzzy, gcc-internal-format
-#| msgid "existing declaration %#qD"
+#, gcc-internal-format
msgid "unused using-declaration %qD"
-msgstr "déclaration %#qD existante"
+msgstr "déclaration using %qD inutilisée"
#: cp/decl.cc:737
#, gcc-internal-format
@@ -56911,16 +56746,14 @@ msgid "block-scope extern declaration %q#D must not be attached to a named modul
msgstr "la déclaration externe avec la portée bloc %q#D ne doit pas être attachée à un module nommé"
#: cp/decl.cc:6205
-#, fuzzy, gcc-internal-format
-#| msgid "%qD defined %<thread_local%> in %qs function only available with %<-std=c++2b%> or %<-std=gnu++2b%>"
+#, gcc-internal-format
msgid "%qD defined %<thread_local%> in %qs function only available with %<-std=c++23%> or %<-std=gnu++23%>"
-msgstr "%qD défini %<thread_local%> dans la fonction %qs est uniquement disponible avec %<-std=c++2b%> ou %<-std=gnu++2b%>"
+msgstr "%qD défini %<thread_local%> dans la fonction %qs est uniquement disponible avec %<-std=c++23%> ou %<-std=gnu++23%>"
#: cp/decl.cc:6211
-#, fuzzy, gcc-internal-format
-#| msgid "%qD defined %<static%> in %qs function only available with %<-std=c++2b%> or %<-std=gnu++2b%>"
+#, gcc-internal-format
msgid "%qD defined %<static%> in %qs function only available with %<-std=c++23%> or %<-std=gnu++23%>"
-msgstr "%qD défini %<static%> dans la fonction %qs est uniquement disponible avec %<-std=c++2b%> ou %<-std=gnu++2b%>"
+msgstr "%qD défini %<static%> dans la fonction %qs est uniquement disponible avec %<-std=c++23%> ou %<-std=gnu++23%>"
#: cp/decl.cc:6277
#, gcc-internal-format
@@ -57154,10 +56987,9 @@ msgid "reference %qD is initialized with itself"
msgstr "la référence %qD est initialisée avec elle-même"
#: cp/decl.cc:8495
-#, fuzzy, gcc-internal-format
-#| msgid "argument %d of %qE must be a pointer type"
+#, gcc-internal-format
msgid "argument %d of %qE must be of %<omp_interop_t%>"
-msgstr "l'argument %d de %qE doit être un type pointeur"
+msgstr "l'argument %d de %qE doit être un type %<omp_interop_t%>"
#: cp/decl.cc:8663
#, gcc-internal-format
@@ -57222,10 +57054,9 @@ msgstr "le type déduit %qT pour %qD est incomplet"
#. [basic.start.main]/3: A program that defines main as deleted
#. is ill-formed.
#: cp/decl.cc:8941
-#, fuzzy, gcc-internal-format
-#| msgid "%qD cannot be defaulted"
+#, gcc-internal-format
msgid "%<::main%> cannot be deleted"
-msgstr "%qD ne peut pas être imposé par défaut"
+msgstr "%<::main%> ne peut pas être supprimé"
#: cp/decl.cc:9095
#, gcc-internal-format
@@ -57248,10 +57079,9 @@ msgid "cannot decompose lambda closure type %qT"
msgstr "impossible de décomposer le type de fermeture lambda %qT"
#: cp/decl.cc:9579
-#, fuzzy, gcc-internal-format
-#| msgid " declared here"
+#, gcc-internal-format
msgid "lambda declared here"
-msgstr " déclaré ici"
+msgstr "lambda déclarée ici"
#: cp/decl.cc:9595
#, gcc-internal-format
@@ -57269,10 +57099,9 @@ msgid "cannot decompose inaccessible member %qD of %qT"
msgstr "impossible de décomposer le membre inaccessible %qD de %qT"
#: cp/decl.cc:9629
-#, fuzzy, gcc-internal-format
-#| msgid "no base class for %s"
+#, gcc-internal-format
msgid "in base class of %qT"
-msgstr "pas de classe de base pour %s"
+msgstr "dans la classe de base de %qT"
#: cp/decl.cc:9636
#, gcc-internal-format
@@ -57290,10 +57119,9 @@ msgid "structured binding refers to incomplete type %qT"
msgstr "la liaison structurée fait référence au type incomplet %qT"
#: cp/decl.cc:9899
-#, fuzzy, gcc-internal-format
-#| msgid "invalid initializer for structured binding declaration"
+#, gcc-internal-format
msgid "array initializer for structured binding declaration in condition"
-msgstr "initialisation invalide pour la déclaration de liaison structurée"
+msgstr "initialiseur de tableau pour une déclaration de liaison structurée dans une condition"
#: cp/decl.cc:9905
#, gcc-internal-format
@@ -57482,10 +57310,9 @@ msgid "static member function %q#D declared with type qualifiers"
msgstr "la fonction membre statique %q#D est déclarée avec des qualificatifs de type"
#: cp/decl.cc:11070
-#, fuzzy, gcc-internal-format
-#| msgid "named return values are no longer supported"
+#, gcc-internal-format
msgid "function concepts are no longer supported"
-msgstr "les valeurs nommées à retourner ne sont plus supportées"
+msgstr "les concepts de fonctions ne sont plus supportés"
#: cp/decl.cc:11108
#, gcc-internal-format
@@ -57549,16 +57376,14 @@ msgid "cannot declare %<::main%> to be static"
msgstr "ne peut déclarer %<::main%> comme étant static"
#: cp/decl.cc:11293
-#, fuzzy, gcc-internal-format
-#| msgid "cannot declare %<::main%> to be static"
+#, gcc-internal-format
msgid "cannot declare %<::main%> with a linkage specification"
-msgstr "ne peut déclarer %<::main%> comme étant static"
+msgstr "ne peut déclarer %<::main%> avec une spécification de liaison"
#: cp/decl.cc:11296
-#, fuzzy, gcc-internal-format
-#| msgid "cannot declare %<::main%> to be a template"
+#, gcc-internal-format
msgid "cannot attach %<::main%> to a named module"
-msgstr "ne peut déclarer %<::main%> comme étant un patron"
+msgstr "ne peut attacher %<::main%> à un module nommé"
#: cp/decl.cc:11355
#, gcc-internal-format
@@ -57678,7 +57503,7 @@ msgstr "ne peut déclarer %<::main%> comme variable globale"
#: cp/decl.cc:11800
#, gcc-internal-format
msgid "an entity named %<main%> cannot be declared with C language linkage"
-msgstr ""
+msgstr "un %<main%> nommé vide ne peut pas être déclaré avec la liaison du langage C"
#: cp/decl.cc:11809
#, gcc-internal-format
@@ -57691,10 +57516,9 @@ msgid "concept must be defined at namespace scope"
msgstr "le concept doit être défini au niveau de l'espace de noms"
#: cp/decl.cc:11815
-#, fuzzy, gcc-internal-format
-#| msgid "named return values are no longer supported"
+#, gcc-internal-format
msgid "variable concepts are no longer supported"
-msgstr "les valeurs nommées à retourner ne sont plus supportées"
+msgstr "les concepts de variables ne sont plus supportés"
#: cp/decl.cc:11936
#, gcc-internal-format
@@ -57927,10 +57751,8 @@ msgid "%<decltype(auto)%> cannot be cv-qualified"
msgstr "%<decltype(auto)%> ne peut pas être qualifié avec CV"
#: cp/decl.cc:12678
-#, fuzzy
-#| msgid "%<signed%> and %<unsigned%> specified together"
msgid "%e and %e specified together"
-msgstr "%<signed%> et %<unsigned%> spécifiés ensemble"
+msgstr "%e et %e spécifiés ensemble"
#: cp/decl.cc:12890
#, gcc-internal-format
@@ -58244,16 +58066,14 @@ msgid "invalid use of %<decltype(auto)%>"
msgstr "utilisation invalide de %<decltype(auto)%>"
#: cp/decl.cc:14044
-#, fuzzy, gcc-internal-format
-#| msgid "%qs function with trailing return type has %qT as its type rather than plain %<auto%>"
+#, gcc-internal-format
msgid "%qs function with trailing return type has constrained %<auto%> type specifier rather than plain %<auto%>"
-msgstr "la fonction %qs avec un type de retour à la fin a %qT comme étant son type au lieu d'un simple %<auto%>"
+msgstr "la fonction %qs avec un type de retour à la fin a le spécificateur de type %<auto%> contraint au lieu d'un simple %<auto%>"
#: cp/decl.cc:14050
-#, fuzzy, gcc-internal-format
-#| msgid "invalid use of constructor as a template"
+#, gcc-internal-format
msgid "invalid use of constrained %<auto%> type"
-msgstr "utilisation invalide du constructeur comme patron"
+msgstr "utilisation invalide du type %<auto%> contraint"
#: cp/decl.cc:14062
#, gcc-internal-format
@@ -59645,10 +59465,9 @@ msgid "converting lambda that uses %<...%> to function pointer"
msgstr "conversion d'une fonction lambda qui utilise %<...%> en pointeur de fonction"
#: cp/decl2.cc:6317
-#, fuzzy, gcc-internal-format
-#| msgid "use of deleted function %qD"
+#, gcc-internal-format
msgid "use of deleted function %qD: %s"
-msgstr "utilisation de la fonction supprimée %qD"
+msgstr "utilisation de la fonction supprimée %qD : %s"
#: cp/decl2.cc:6321
#, gcc-internal-format
@@ -60288,10 +60107,9 @@ msgid "new cannot be applied to a function type"
msgstr "« new » ne peut être appliqué à un type de fonction"
#: cp/init.cc:4159
-#, fuzzy, gcc-internal-format
-#| msgid "parameter %u has incomplete type"
+#, gcc-internal-format
msgid "operator %<delete []%> used on incomplete type"
-msgstr "le paramètre %u a un type incomplet"
+msgstr "opérateur %<delete []%> utilisé sur un type incomplet"
#: cp/init.cc:4174
#, gcc-internal-format
@@ -60314,10 +60132,9 @@ msgid "unknown array size in delete"
msgstr "taille du tableau inconnue dans delete"
#: cp/init.cc:5263
-#, fuzzy, gcc-internal-format
-#| msgid "return type is an incomplete type"
+#, gcc-internal-format
msgid "operator %<delete%> used on incomplete type"
-msgstr "le type du retour est un type incomplet"
+msgstr "opérateur %<delete%> utilisé sur un type incomplet"
#: cp/init.cc:5278
#, gcc-internal-format
@@ -60370,10 +60187,9 @@ msgid "capture by copy of incomplete type %qT"
msgstr "capture par copie du type incomplet %qT"
#: cp/lambda.cc:632
-#, fuzzy, gcc-internal-format
-#| msgid "unused structured binding declaration"
+#, gcc-internal-format
msgid "captured structured bindings are a C++20 extension"
-msgstr "déclaration de liaison structurée inutilisée"
+msgstr "les liaisons structurées capturées sont une extension du C++20"
#: cp/lambda.cc:699
#, gcc-internal-format
@@ -60396,16 +60212,14 @@ msgid "%<this%> was not captured for this lambda function"
msgstr "%<this%> n'a pas été capturé pour cette fonction lambda"
#: cp/lambda.cc:1575
-#, fuzzy, gcc-internal-format
-#| msgid "the calling convention for %qT changes in %<-fabi-version=13%> (GCC 8.2)"
+#, gcc-internal-format
msgid "the mangled name of %qT changed in %<-fabi-version=20%> (GCC 15.1)"
-msgstr "la convention d'appel pour %qT change avec %<-fabi-version=13%> (GCC 8.2)"
+msgstr "le nom décoré de %qT a changé avec %<-fabi-version=20%> (GCC 15.1)"
#: cp/lambda.cc:1579
-#, fuzzy, gcc-internal-format
-#| msgid "the calling convention for %qT changes in %<-fabi-version=13%> (GCC 8.2)"
+#, gcc-internal-format
msgid "the mangled name of %qT changes in %<-fabi-version=20%> (GCC 15.1)"
-msgstr "la convention d'appel pour %qT change avec %<-fabi-version=13%> (GCC 8.2)"
+msgstr "le nom décoré de %qT change avec %<-fabi-version=20%> (GCC 15.1)"
#: cp/lex.cc:643
#, gcc-internal-format
@@ -60646,22 +60460,19 @@ msgid "synthesized method %qD first required here"
msgstr "la méthode synthétisée %qD est requise ici pour la première fois"
#: cp/method.cc:1989
-#, fuzzy, gcc-internal-format
-#| msgid "(a pointer to member can only be formed with %<&%E%>)"
+#, gcc-internal-format
msgid "pointer to data member type %qT can only be invoked with one argument"
-msgstr "(un pointeur vers un membre peut seulement être formé avec %<&%E%>)"
+msgstr "le pointeur vers le membre de données de type %qT peut uniquement être invoqué avec un argument"
#: cp/method.cc:1996
-#, fuzzy, gcc-internal-format
-#| msgid " member function type %qT is not a valid template argument"
+#, gcc-internal-format
msgid "pointer to member function type %qT must be invoked with at least one argument"
-msgstr " le type fonction membre %qT n'est pas un argument de patron valable"
+msgstr "le pointeur vers la fonction membre de type %qT doit être invoqué avec au moins un argument"
#: cp/method.cc:2016
-#, fuzzy, gcc-internal-format
-#| msgid "the type of a pointer to explicit object member function is a regular pointer to function type"
+#, gcc-internal-format
msgid "first argument type %qT of a pointer to member must be a class type or a pointer to a class type"
-msgstr "le type d'un pointeur vers une fonction membre d'objet explicite est un pointeur régulier vers un type de fonction"
+msgstr "le premier argument du type %qT d'un pointeur vers un membre doit être un type de classe ou un pointeur vers un type de classe"
#: cp/method.cc:2524
#, gcc-internal-format
@@ -60734,26 +60545,24 @@ msgid "%q#F is implicitly deleted because its exception-specification does not m
msgstr "%q#F est implicitement supprimé car sa spécification d'exception ne correspond pas à la spécification d'exception implicite %qX"
#: cp/method.cc:3573
-#, fuzzy, gcc-internal-format
-#| msgid "%q#F is implicitly deleted because its exception-specification does not match the implicit exception-specification %qX"
+#, gcc-internal-format
msgid "explicitly defaulted copy constructor is implicitly deleted because its declared type does not match the type of an implicit copy constructor"
-msgstr "%q#F est implicitement supprimé car sa spécification d'exception ne correspond pas à la spécification d'exception implicite %qX"
+msgstr "le constructeur par copie explicitement par défaut est supprimé implicitement car son type déclaré ne correspond pas au type d'un constructeur par copie implicite"
#: cp/method.cc:3578
-#, fuzzy, gcc-internal-format
-#| msgid "%q#F is implicitly deleted because its exception-specification does not match the implicit exception-specification %qX"
+#, gcc-internal-format
msgid "explicitly defaulted move constructor is implicitly deleted because its declared type does not match the type of an implicit move constructor"
-msgstr "%q#F est implicitement supprimé car sa spécification d'exception ne correspond pas à la spécification d'exception implicite %qX"
+msgstr "le constructeur par déplacement explicitement par défaut est supprimé implicitement car son type déclaré ne correspond pas au type d'un constructeur par déplacement implicite"
#: cp/method.cc:3583
#, gcc-internal-format
msgid "explicitly defaulted copy assignment operator is implicitly deleted because its declared type does not match the type of an implicit copy assignment operator"
-msgstr ""
+msgstr "l'opérateur d'affectation par copie explicitement par défaut est supprimé implicitement car son type déclaré ne correspond pas au type d'un opérateur d'affectation par copie implicite"
#: cp/method.cc:3588
#, gcc-internal-format
msgid "explicitly defaulted move assignment operator is implicitly deleted because its declared type does not match the type of an implicit move assignment operator"
-msgstr ""
+msgstr "l'opérateur d'affectation par déplacement explicitement par défaut est supprimé implicitement car son type déclaré ne correspond pas au type d'un opérateur d'affectation par déplacement implicite"
#: cp/method.cc:3597
#, gcc-internal-format
@@ -60824,22 +60633,19 @@ msgid "existing declaration %#qD"
msgstr "déclaration %#qD existante"
#: cp/module.cc:12186
-#, fuzzy, gcc-internal-format
-#| msgid "no default argument for %qD"
+#, gcc-internal-format
msgid "conflicting default argument for %#qD"
-msgstr "pas d'argument par défaut pour %qD"
+msgstr "argument par défaut conflictuel pour %#qD"
#: cp/module.cc:12188 cp/module.cc:12215
-#, fuzzy, gcc-internal-format
-#| msgid "built-in %qD declared here"
+#, gcc-internal-format
msgid "existing default declared here"
-msgstr "la fonction interne %qD est déclarée ici"
+msgstr "celui par défaut existant est déclarée ici"
#: cp/module.cc:12212
-#, fuzzy, gcc-internal-format
-#| msgid "default argument missing for parameter %P of %q#D"
+#, gcc-internal-format
msgid "conflicting default argument for parameter %P of %#qD"
-msgstr "argument par défaut manquant pour le paramètre %P de %q#D"
+msgstr "argument par défaut conflictuel pour le paramètre %P de %q#D"
#: cp/module.cc:13265
#, gcc-internal-format
@@ -60872,84 +60678,74 @@ msgid "enumeration range differs"
msgstr "la plage d'énumération diffère"
#: cp/module.cc:13504
-#, fuzzy, gcc-internal-format
-#| msgid "specialization of alias template %qD"
+#, gcc-internal-format
msgid "%qD is an alias of TU-local type %qT"
-msgstr "spécialisation du patron d'alias %qD"
+msgstr "%qD est un alias pour le type local TU %qT"
#: cp/module.cc:13522
-#, fuzzy, gcc-internal-format
-#| msgid "specialization of alias template %qD"
+#, gcc-internal-format
msgid "%qD is a specialization of TU-local template %qD"
-msgstr "spécialisation du patron d'alias %qD"
+msgstr "%qD est une spécialisation du patron local TU %qD"
#: cp/module.cc:13546
-#, fuzzy, gcc-internal-format
-#| msgid "%q#D declared here with internal linkage"
+#, gcc-internal-format
msgid "%qD declared with internal linkage"
-msgstr "%q#D déclaré ici avec un lien externe"
+msgstr "%qD est déclaré avec une liaison interne"
#: cp/module.cc:13564
-#, fuzzy, gcc-internal-format
-#| msgid "%qD may not be declared within a namespace"
+#, gcc-internal-format
msgid "%qD has no linkage and is declared in an anonymous namespace"
-msgstr "%qD ne peut pas être déclaré dans un espace de noms"
+msgstr "%qD n'a pas de liaison et est déclaré dans un espace de nom anonyme"
#: cp/module.cc:13576
-#, fuzzy, gcc-internal-format
-#| msgid "%qD has not been declared within %qD"
+#, gcc-internal-format
msgid "%qD has no linkage and is declared within TU-local entity %qT"
-msgstr "%qD n'a pas été déclaré dans %qD"
+msgstr "%qD n'a pas de liaison et est déclaré dans l'entité locale TU %qT"
#: cp/module.cc:13587
-#, fuzzy, gcc-internal-format
-#| msgid "%qD has not been declared within %qD"
+#, gcc-internal-format
msgid "%qD has no linkage and is declared within TU-local entity %qD"
-msgstr "%qD n'a pas été déclaré dans %qD"
+msgstr "%qD n'a pas de liaison et est déclaré avec l'entité locale TU %qD"
#: cp/module.cc:13619
#, gcc-internal-format
msgid "%qT has no name and cannot be differentiated from similar lambdas in other TUs"
-msgstr ""
+msgstr "%qT n'a pas de nom et ne peut pas être différencié des lambda similaires dans d'autres TU"
#: cp/module.cc:13628
#, gcc-internal-format
msgid "%qT has no name and is not defined within a class, function, or initializer"
-msgstr ""
+msgstr "%qT n'a pas de nom et n'est pas défini dans une classe, fonction ou initialiseur"
#: cp/module.cc:13664
-#, fuzzy, gcc-internal-format
-#| msgid "%qD used without template arguments"
+#, gcc-internal-format
msgid "%qD has TU-local template argument %qD"
-msgstr "%qD utilisé sans arguments du patron"
+msgstr "%qD a l'argument de patron local TU %qD"
#: cp/module.cc:13676
-#, fuzzy, gcc-internal-format
-#| msgid "%qE is not a valid template argument for type %qT"
+#, gcc-internal-format
msgid "%qD has TU-local template argument %qT"
-msgstr "%qE n'est pas un argument de patron valide pour le type %qT"
+msgstr "%qD a l'argument de patron local TU %qT"
#: cp/module.cc:13728
-#, fuzzy, gcc-internal-format
-#| msgid "%qD called on unallocated object %qD"
+#, gcc-internal-format
msgid "%qD refers to TU-local object %qD"
-msgstr "%qD appelé sur l'objet %qD non alloué"
+msgstr "%qD fait référence à l'objet local TU %qD"
#: cp/module.cc:13730
-#, fuzzy, gcc-internal-format
-#| msgid "%qD does not refer to a function"
+#, gcc-internal-format
msgid "%qD refers to TU-local function %qD"
-msgstr "%qD ne fait pas référence à une fonction"
+msgstr "%qD fait référence à la fonction locale TU %qD"
#: cp/module.cc:14852
#, gcc-internal-format
msgid "%qD exposes TU-local entity %qD"
-msgstr ""
+msgstr "%qD expose l'entité locale TU %qD"
#: cp/module.cc:14863
#, gcc-internal-format
msgid "%qD is declared %<constexpr%> and is initialized to a TU-local value"
-msgstr ""
+msgstr "%qD est déclaré %<constexpr%> et est initialisé à une valeur locale TU"
#: cp/module.cc:14901
#, gcc-internal-format
@@ -84748,7 +84544,7 @@ msgstr ""
#: fortran/trans-openmp.cc:8909
#, gcc-internal-format
msgid "the %qs clause can only be specified if the %<dispatch%> selector of the construct selector set appears in the %<match%> clause at %L"
-msgstr ""
+msgstr "la clause %qs peut uniquement être spécifiée si le sélecteur %<dispatch%> de l'ensemble du sélecteur du constructeur apparaît dans la clause %<match%> à %L"
#: fortran/trans-openmp.cc:9010 fortran/trans-openmp.cc:9049
#, fuzzy, gcc-internal-format, gfc-internal-format
diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog
index d6f94f5..ba6430a 100644
--- a/gcc/rust/ChangeLog
+++ b/gcc/rust/ChangeLog
@@ -1,3 +1,65 @@
+2025-03-18 Marc Poulhiès <dkm@kataplop.net>
+
+ PR rust/119333
+ * Make-lang.in: Force offline mode for cargo
+
+2025-03-18 Arthur Cohen <arthur.cohen@embecosm.com>
+
+ * checks/errors/borrowck/ffi-polonius/.cargo/config.toml: New file, force vendored deps.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/README.md: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs:
+ New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs:
+ New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs:
+ New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs:
+ New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md: New file.
+ * checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs: New file.
+
2025-03-17 Muhammad Mahad <mahadtxt@gmail.com>
* typecheck/rust-hir-type-check-type.cc (TypeCheckType::visit):
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index efa6309..b1777e3 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -92,6 +92,7 @@ GRS_OBJS = \
rust/rust-cfg-strip.o \
rust/rust-expand-visitor.o \
rust/rust-ast-builder.o \
+ rust/rust-ast-builder-type.o \
rust/rust-derive.o \
rust/rust-derive-clone.o \
rust/rust-derive-copy.o \
@@ -131,6 +132,7 @@ GRS_OBJS = \
rust/rust-default-resolver.o \
rust/rust-toplevel-name-resolver-2.0.o \
rust/rust-early-name-resolver-2.0.o \
+ rust/rust-finalize-imports-2.0.o \
rust/rust-late-name-resolver-2.0.o \
rust/rust-immutable-name-resolution-context.o \
rust/rust-early-name-resolver.o \
@@ -171,6 +173,7 @@ GRS_OBJS = \
rust/rust-borrow-checker.o \
rust/rust-borrow-checker-diagnostics.o\
rust/rust-bir-builder-expr-stmt.o \
+ rust/rust-bir-builder-pattern.o \
rust/rust-bir-dump.o \
rust/rust-polonius.o\
rust/rust-hir-dot-operator.o \
@@ -188,6 +191,7 @@ GRS_OBJS = \
rust/rust-readonly-check.o \
rust/rust-hir-type-check-path.o \
rust/rust-unsafe-checker.o \
+ rust/rust-hir-pattern-analysis.o \
rust/rust-compile-intrinsic.o \
rust/rust-compile-pattern.o \
rust/rust-compile-fnparam.o \
@@ -196,6 +200,7 @@ GRS_OBJS = \
rust/rust-compile-item.o \
rust/rust-compile-implitem.o \
rust/rust-compile-stmt.o \
+ rust/rust-compile-asm.o \
rust/rust-compile-expr.o \
rust/rust-compile-type.o \
rust/rust-compile-block.o \
@@ -503,5 +508,5 @@ rust/%.o: rust/metadata/%.cc
rust/libffi_polonius.a: \
rust/checks/errors/borrowck/ffi-polonius/Cargo.toml \
$(wildcard $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/src/*)
- cargo build --manifest-path $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/Cargo.toml --release --target-dir rust/ffi-polonius
+ cd $(srcdir)/rust/checks/errors/borrowck/ffi-polonius/ && cargo build --offline --release --target-dir $(objdir)/rust/ffi-polonius
cp rust/ffi-polonius/release/libffi_polonius.a rust/libffi_polonius.a
diff --git a/gcc/rust/ast/rust-ast-builder-type.cc b/gcc/rust/ast/rust-ast-builder-type.cc
new file mode 100644
index 0000000..e76d0de
--- /dev/null
+++ b/gcc/rust/ast/rust-ast-builder-type.cc
@@ -0,0 +1,164 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-builder-type.h"
+#include "rust-ast-builder.h"
+#include "rust-ast-full.h"
+#include "rust-common.h"
+#include "rust-make-unique.h"
+
+namespace Rust {
+namespace AST {
+
+ASTTypeBuilder::ASTTypeBuilder () : translated (nullptr) {}
+
+Type *
+ASTTypeBuilder::build (Type &type)
+{
+ ASTTypeBuilder builder;
+ type.accept_vis (builder);
+ rust_assert (builder.translated != nullptr);
+ return builder.translated;
+}
+
+void
+ASTTypeBuilder::visit (BareFunctionType &fntype)
+{
+ /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (TupleType &tuple)
+{
+ std::vector<std::unique_ptr<Type> > elems;
+ for (auto &elem : tuple.get_elems ())
+ {
+ Type *t = ASTTypeBuilder::build (*elem.get ());
+ std::unique_ptr<Type> ty (t);
+ elems.push_back (std::move (ty));
+ }
+ translated = new TupleType (std::move (elems), tuple.get_locus ());
+}
+
+void
+ASTTypeBuilder::visit (TypePath &path)
+{
+ std::vector<std::unique_ptr<TypePathSegment> > segments;
+ for (auto &seg : path.get_segments ())
+ {
+ switch (seg->get_type ())
+ {
+ case TypePathSegment::REG: {
+ const TypePathSegment &segment
+ = (const TypePathSegment &) (*seg.get ());
+ TypePathSegment *s
+ = new TypePathSegment (segment.get_ident_segment (),
+ segment.get_separating_scope_resolution (),
+ segment.get_locus ());
+ std::unique_ptr<TypePathSegment> sg (s);
+ segments.push_back (std::move (sg));
+ }
+ break;
+
+ case TypePathSegment::GENERIC: {
+ TypePathSegmentGeneric &generic
+ = (TypePathSegmentGeneric &) (*seg.get ());
+
+ GenericArgs args
+ = Builder::new_generic_args (generic.get_generic_args ());
+ TypePathSegmentGeneric *s
+ = new TypePathSegmentGeneric (generic.get_ident_segment (), false,
+ std::move (args),
+ generic.get_locus ());
+ std::unique_ptr<TypePathSegment> sg (s);
+ segments.push_back (std::move (sg));
+ }
+ break;
+
+ case TypePathSegment::FUNCTION: {
+ rust_unreachable ();
+ // TODO
+ // const TypePathSegmentFunction &fn
+ // = (const TypePathSegmentFunction &) (*seg.get ());
+ }
+ break;
+ }
+ }
+
+ translated = new TypePath (std::move (segments), path.get_locus (),
+ path.has_opening_scope_resolution_op ());
+}
+
+void
+ASTTypeBuilder::visit (QualifiedPathInType &path)
+{
+ /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (ArrayType &type)
+{
+ /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (ReferenceType &type)
+{
+ /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (RawPointerType &type)
+{
+ /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (SliceType &type)
+{
+ Type *t = ASTTypeBuilder::build (type.get_elem_type ());
+ std::unique_ptr<Type> ty (t);
+ translated = new SliceType (std::move (ty), type.get_locus ());
+}
+
+void
+ASTTypeBuilder::visit (InferredType &type)
+{
+ translated = new InferredType (type.get_locus ());
+}
+
+void
+ASTTypeBuilder::visit (NeverType &type)
+{
+ translated = new NeverType (type.get_locus ());
+}
+
+void
+ASTTypeBuilder::visit (TraitObjectTypeOneBound &type)
+{
+ /* TODO */
+}
+
+void
+ASTTypeBuilder::visit (TraitObjectType &type)
+{
+ /* TODO */
+}
+
+} // namespace AST
+} // namespace Rust
diff --git a/gcc/rust/ast/rust-ast-builder-type.h b/gcc/rust/ast/rust-ast-builder-type.h
new file mode 100644
index 0000000..b67ae3b
--- /dev/null
+++ b/gcc/rust/ast/rust-ast-builder-type.h
@@ -0,0 +1,57 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_BUILDER_TYPE
+#define RUST_AST_BUILDER_TYPE
+
+#include "rust-ast-visitor.h"
+
+namespace Rust {
+namespace AST {
+
+class ASTTypeBuilder : public DefaultASTVisitor
+{
+protected:
+ using DefaultASTVisitor::visit;
+
+public:
+ static Type *build (Type &type);
+
+ void visit (BareFunctionType &fntype) override;
+ void visit (TupleType &tuple) override;
+ void visit (TypePath &path) override;
+ void visit (QualifiedPathInType &path) override;
+ void visit (ArrayType &type) override;
+ void visit (ReferenceType &type) override;
+ void visit (RawPointerType &type) override;
+ void visit (SliceType &type) override;
+ void visit (InferredType &type) override;
+ void visit (NeverType &type) override;
+ void visit (TraitObjectTypeOneBound &type) override;
+ void visit (TraitObjectType &type) override;
+
+private:
+ ASTTypeBuilder ();
+
+ Type *translated;
+};
+
+} // namespace AST
+} // namespace Rust
+
+#endif // RUST_AST_BUILDER_TYPE
diff --git a/gcc/rust/ast/rust-ast-builder.cc b/gcc/rust/ast/rust-ast-builder.cc
index 4679aa7..529c686 100644
--- a/gcc/rust/ast/rust-ast-builder.cc
+++ b/gcc/rust/ast/rust-ast-builder.cc
@@ -17,8 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-ast-builder.h"
-#include "rust-ast-full-decls.h"
-#include "rust-ast-full.h"
+#include "rust-ast-builder-type.h"
#include "rust-common.h"
#include "rust-expr.h"
#include "rust-token.h"
@@ -83,6 +82,13 @@ Builder::type_path_segment (std::string seg) const
new TypePathSegment (seg, false, loc));
}
+std::unique_ptr<TypePathSegment>
+Builder::generic_type_path_segment (std::string seg, GenericArgs args) const
+{
+ return std::unique_ptr<TypePathSegment> (
+ new TypePathSegmentGeneric (PathIdentSegment (seg, loc), false, args, loc));
+}
+
std::unique_ptr<Type>
Builder::single_type_path (std::string type) const
{
@@ -92,6 +98,15 @@ Builder::single_type_path (std::string type) const
return std::unique_ptr<Type> (new TypePath (std::move (segments), loc));
}
+std::unique_ptr<Type>
+Builder::single_generic_type_path (std::string type, GenericArgs args) const
+{
+ auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
+ segments.emplace_back (generic_type_path_segment (type, args));
+
+ return std::unique_ptr<Type> (new TypePath (std::move (segments), loc));
+}
+
PathInExpression
Builder::path_in_expression (std::vector<std::string> &&segments) const
{
@@ -174,5 +189,187 @@ Builder::wildcard () const
return std::unique_ptr<Pattern> (new WildcardPattern (loc));
}
+std::unique_ptr<Type>
+Builder::new_type (Type &type)
+{
+ Type *t = ASTTypeBuilder::build (type);
+ return std::unique_ptr<Type> (t);
+}
+
+std::unique_ptr<GenericParam>
+Builder::new_lifetime_param (LifetimeParam &param)
+{
+ Lifetime l = new_lifetime (param.get_lifetime ());
+ std::vector<Lifetime> lifetime_bounds;
+ for (auto b : param.get_lifetime_bounds ())
+ {
+ Lifetime bl = new_lifetime (b);
+ lifetime_bounds.push_back (bl);
+ }
+
+ auto p = new LifetimeParam (l, std::move (lifetime_bounds),
+ param.get_outer_attrs (), param.get_locus ());
+ return std::unique_ptr<GenericParam> (p);
+}
+
+std::unique_ptr<GenericParam>
+Builder::new_type_param (TypeParam &param)
+{
+ location_t locus = param.get_locus ();
+ AST::AttrVec outer_attrs = param.get_outer_attrs ();
+ Identifier type_representation = param.get_type_representation ();
+ std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds;
+ std::unique_ptr<Type> type = nullptr;
+
+ if (param.has_type ())
+ type = new_type (param.get_type ());
+
+ for (const auto &b : param.get_type_param_bounds ())
+ {
+ switch (b->get_bound_type ())
+ {
+ case TypeParamBound::TypeParamBoundType::TRAIT: {
+ const TraitBound &tb = (const TraitBound &) *b.get ();
+ const TypePath &path = tb.get_type_path ();
+
+ std::vector<LifetimeParam> for_lifetimes;
+ for (const auto &lifetime : tb.get_for_lifetimes ())
+ {
+ std::vector<Lifetime> lifetime_bounds;
+ for (const auto &b : lifetime.get_lifetime_bounds ())
+ {
+ Lifetime bl = new_lifetime (b);
+ lifetime_bounds.push_back (std::move (bl));
+ }
+
+ Lifetime nl = new_lifetime (lifetime.get_lifetime ());
+ LifetimeParam p (std::move (nl), std::move (lifetime_bounds),
+ {}, lifetime.get_locus ());
+ for_lifetimes.push_back (std::move (p));
+ }
+
+ std::vector<std::unique_ptr<TypePathSegment>> segments;
+ for (auto &seg : path.get_segments ())
+ {
+ switch (seg->get_type ())
+ {
+ case TypePathSegment::REG: {
+ const TypePathSegment &segment
+ = (const TypePathSegment &) (*seg.get ());
+ TypePathSegment *s = new TypePathSegment (
+ segment.get_ident_segment (),
+ segment.get_separating_scope_resolution (),
+ segment.get_locus ());
+ std::unique_ptr<TypePathSegment> sg (s);
+ segments.push_back (std::move (sg));
+ }
+ break;
+
+ case TypePathSegment::GENERIC: {
+ TypePathSegmentGeneric &generic
+ = (TypePathSegmentGeneric &) (*seg.get ());
+
+ GenericArgs args
+ = new_generic_args (generic.get_generic_args ());
+ TypePathSegmentGeneric *s = new TypePathSegmentGeneric (
+ generic.get_ident_segment (), false, std::move (args),
+ generic.get_locus ());
+ std::unique_ptr<TypePathSegment> sg (s);
+ segments.push_back (std::move (sg));
+ }
+ break;
+
+ case TypePathSegment::FUNCTION: {
+ rust_unreachable ();
+ // TODO
+ // const TypePathSegmentFunction &fn
+ // = (const TypePathSegmentFunction &) (*seg.get ());
+ }
+ break;
+ }
+ }
+
+ TypePath p (std::move (segments), path.get_locus (),
+ path.has_opening_scope_resolution_op ());
+
+ TraitBound *b = new TraitBound (std::move (p), tb.get_locus (),
+ tb.is_in_parens (),
+ tb.has_opening_question_mark (),
+ std::move (for_lifetimes));
+ std::unique_ptr<TypeParamBound> bound (b);
+ type_param_bounds.push_back (std::move (bound));
+ }
+ break;
+
+ case TypeParamBound::TypeParamBoundType::LIFETIME: {
+ const Lifetime &l = (const Lifetime &) *b.get ();
+
+ auto bl = new Lifetime (l.get_lifetime_type (),
+ l.get_lifetime_name (), l.get_locus ());
+ std::unique_ptr<TypeParamBound> bound (bl);
+ type_param_bounds.push_back (std::move (bound));
+ }
+ break;
+ }
+ }
+
+ auto type_param
+ = new TypeParam (type_representation, locus, std::move (type_param_bounds),
+ std::move (type), std::move (outer_attrs));
+
+ return std::unique_ptr<GenericParam> (type_param);
+}
+
+Lifetime
+Builder::new_lifetime (const Lifetime &lifetime)
+{
+ return Lifetime (lifetime.get_lifetime_type (), lifetime.get_lifetime_name (),
+ lifetime.get_locus ());
+}
+
+GenericArgs
+Builder::new_generic_args (GenericArgs &args)
+{
+ std::vector<Lifetime> lifetime_args;
+ std::vector<GenericArg> generic_args;
+ std::vector<GenericArgsBinding> binding_args;
+ location_t locus = args.get_locus ();
+
+ for (const auto &lifetime : args.get_lifetime_args ())
+ {
+ Lifetime l = new_lifetime (lifetime);
+ lifetime_args.push_back (std::move (l));
+ }
+
+ for (auto &binding : args.get_binding_args ())
+ {
+ Type &t = *binding.get_type_ptr ().get ();
+ std::unique_ptr<Type> ty = new_type (t);
+ GenericArgsBinding b (binding.get_identifier (), std::move (ty),
+ binding.get_locus ());
+ binding_args.push_back (std::move (b));
+ }
+
+ for (auto &arg : args.get_generic_args ())
+ {
+ switch (arg.get_kind ())
+ {
+ case GenericArg::Kind::Type: {
+ std::unique_ptr<Type> ty = new_type (arg.get_type ());
+ GenericArg arg = GenericArg::create_type (std::move (ty));
+ }
+ break;
+
+ default:
+ // FIXME
+ rust_unreachable ();
+ break;
+ }
+ }
+
+ return GenericArgs (std::move (lifetime_args), std::move (generic_args),
+ std::move (binding_args), locus);
+}
+
} // namespace AST
} // namespace Rust
diff --git a/gcc/rust/ast/rust-ast-builder.h b/gcc/rust/ast/rust-ast-builder.h
index aed71e7..bad79d0 100644
--- a/gcc/rust/ast/rust-ast-builder.h
+++ b/gcc/rust/ast/rust-ast-builder.h
@@ -82,10 +82,16 @@ public:
/* And similarly for type path segments */
std::unique_ptr<TypePathSegment> type_path_segment (std::string seg) const;
+ std::unique_ptr<TypePathSegment>
+ generic_type_path_segment (std::string seg, GenericArgs args) const;
+
/* Create a Type from a single string - the most basic kind of type in our AST
*/
std::unique_ptr<Type> single_type_path (std::string type) const;
+ std::unique_ptr<Type> single_generic_type_path (std::string type,
+ GenericArgs args) const;
+
/**
* Create a path in expression from multiple segments (`Clone::clone`). You
* do not need to separate the segments using `::`, you can simply provide a
@@ -116,6 +122,17 @@ public:
/* Create a wildcard pattern (`_`) */
std::unique_ptr<Pattern> wildcard () const;
+ static std::unique_ptr<Type> new_type (Type &type);
+
+ static std::unique_ptr<GenericParam>
+ new_lifetime_param (LifetimeParam &param);
+
+ static std::unique_ptr<GenericParam> new_type_param (TypeParam &param);
+
+ static Lifetime new_lifetime (const Lifetime &lifetime);
+
+ static GenericArgs new_generic_args (GenericArgs &args);
+
private:
/**
* Location of the generated AST nodes
diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc
index 6980fef..2022668 100644
--- a/gcc/rust/ast/rust-ast-collector.cc
+++ b/gcc/rust/ast/rust-ast-collector.cc
@@ -21,6 +21,7 @@
#include "rust-expr.h"
#include "rust-item.h"
#include "rust-keyword-values.h"
+#include "rust-system.h"
#include "rust-token.h"
namespace Rust {
@@ -561,6 +562,19 @@ TokenCollector::visit (PathInExpression &path)
}
void
+TokenCollector::visit (RegularPath &path)
+{
+ // FIXME: We probably want to have a proper implementation here, and call this
+ // function from things like the PathInExpression visitor
+}
+
+void
+TokenCollector::visit (LangItemPath &path)
+{
+ // TODO: Implement proper token collection for lang item paths
+}
+
+void
TokenCollector::visit (TypePathSegment &segment)
{
// Syntax:
diff --git a/gcc/rust/ast/rust-ast-collector.h b/gcc/rust/ast/rust-ast-collector.h
index b2dc41b..32a5bd3 100644
--- a/gcc/rust/ast/rust-ast-collector.h
+++ b/gcc/rust/ast/rust-ast-collector.h
@@ -234,6 +234,8 @@ public:
void visit (PathExprSegment &segment);
void visit (PathIdentSegment &segment);
void visit (PathInExpression &path);
+ void visit (RegularPath &path);
+ void visit (LangItemPath &path);
void visit (TypePathSegment &segment);
void visit (TypePathSegmentGeneric &segment);
void visit (TypePathSegmentFunction &segment);
diff --git a/gcc/rust/ast/rust-ast-full-decls.h b/gcc/rust/ast/rust-ast-full-decls.h
index d2ba876..80d217e 100644
--- a/gcc/rust/ast/rust-ast-full-decls.h
+++ b/gcc/rust/ast/rust-ast-full-decls.h
@@ -61,7 +61,7 @@ class PathIdentSegment;
struct GenericArgsBinding;
struct GenericArgs;
class PathExprSegment;
-class PathPattern;
+class Path;
class PathInExpression;
class TypePathSegment;
class TypePathSegmentGeneric;
@@ -148,7 +148,7 @@ class AsyncBlockExpr;
enum class InlineAsmOption;
struct AnonConst;
struct InlineAsmRegOrRegClass;
-struct InlineAsmOperand;
+class InlineAsmOperand;
struct InlineAsmPlaceHolder;
struct InlineAsmTemplatePiece;
struct TupleClobber;
diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc
index 866357b..8f53e52 100644
--- a/gcc/rust/ast/rust-ast-visitor.cc
+++ b/gcc/rust/ast/rust-ast-visitor.cc
@@ -86,6 +86,17 @@ DefaultASTVisitor::visit (AST::ConstGenericParam &const_param)
}
void
+DefaultASTVisitor::visit (AST::RegularPath &path)
+{
+ for (auto &segment : path.get_segments ())
+ visit (segment);
+}
+
+void
+DefaultASTVisitor::visit (AST::LangItemPath &path)
+{}
+
+void
DefaultASTVisitor::visit (AST::PathInExpression &path)
{
visit_outer_attrs (path);
@@ -664,7 +675,46 @@ DefaultASTVisitor::visit (AST::AsyncBlockExpr &expr)
void
DefaultASTVisitor::visit (AST::InlineAsm &expr)
-{}
+{
+ visit_outer_attrs (expr);
+ using RegisterType = AST::InlineAsmOperand::RegisterType;
+ for (auto &operand : expr.get_operands ())
+ {
+ switch (operand.get_register_type ())
+ {
+ case RegisterType::In: {
+ visit (operand.get_in ().expr);
+ break;
+ }
+ case RegisterType::Out: {
+ visit (operand.get_out ().expr);
+ break;
+ }
+ case RegisterType::InOut: {
+ visit (operand.get_in_out ().expr);
+ break;
+ }
+ case RegisterType::SplitInOut: {
+ auto split = operand.get_split_in_out ();
+ visit (split.in_expr);
+ visit (split.out_expr);
+ break;
+ }
+ case RegisterType::Const: {
+ visit (operand.get_const ().anon_const.expr);
+ break;
+ }
+ case RegisterType::Sym: {
+ visit (operand.get_sym ().expr);
+ break;
+ }
+ case RegisterType::Label: {
+ visit (operand.get_label ().expr);
+ break;
+ }
+ }
+ }
+}
void
DefaultASTVisitor::visit (AST::TypeParam &param)
diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h
index 2f56d89..50b9301 100644
--- a/gcc/rust/ast/rust-ast-visitor.h
+++ b/gcc/rust/ast/rust-ast-visitor.h
@@ -24,6 +24,7 @@
#include "rust-ast-full-decls.h"
#include "rust-ast.h"
#include "rust-item.h"
+#include "rust-path.h"
#include "rust-system.h"
namespace Rust {
@@ -58,6 +59,8 @@ public:
// virtual void visit(TraitImplItem& trait_impl_item) = 0;
// rust-path.h
+ virtual void visit (RegularPath &path) = 0;
+ virtual void visit (LangItemPath &path) = 0;
virtual void visit (PathInExpression &path) = 0;
virtual void visit (TypePathSegment &segment) = 0;
virtual void visit (TypePathSegmentGeneric &segment) = 0;
@@ -241,7 +244,6 @@ class DefaultASTVisitor : public ASTVisitor
public:
virtual void visit (AST::Crate &crate);
-protected:
virtual void visit (AST::Token &tok) override;
virtual void visit (AST::DelimTokenTree &delim_tok_tree) override;
virtual void visit (AST::AttrInputMetaItemContainer &input) override;
@@ -249,6 +251,8 @@ protected:
virtual void visit (AST::Lifetime &lifetime) override;
virtual void visit (AST::LifetimeParam &lifetime_param) override;
virtual void visit (AST::ConstGenericParam &const_param) override;
+ virtual void visit (AST::RegularPath &path) override;
+ virtual void visit (AST::LangItemPath &path) override;
virtual void visit (AST::PathInExpression &path) override;
virtual void visit (AST::TypePathSegment &segment) override;
virtual void visit (AST::TypePathSegmentGeneric &segment) override;
diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc
index bf7d31d..1d52352 100644
--- a/gcc/rust/ast/rust-ast.cc
+++ b/gcc/rust/ast/rust-ast.cc
@@ -311,7 +311,8 @@ Attribute::get_traits_to_derive ()
// Copy constructor must deep copy attr_input as unique pointer
Attribute::Attribute (Attribute const &other)
- : path (other.path), locus (other.locus)
+ : path (other.path), locus (other.locus),
+ inner_attribute (other.inner_attribute)
{
// guard to protect from null pointer dereference
if (other.attr_input != nullptr)
@@ -324,6 +325,7 @@ Attribute::operator= (Attribute const &other)
{
path = other.path;
locus = other.locus;
+ inner_attribute = other.inner_attribute;
// guard to protect from null pointer dereference
if (other.attr_input != nullptr)
attr_input = other.attr_input->clone_attr_input ();
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index 4f40eff..42ad011 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -1477,6 +1477,12 @@ protected:
class TypeParamBound : public Visitable
{
public:
+ enum TypeParamBoundType
+ {
+ TRAIT,
+ LIFETIME
+ };
+
virtual ~TypeParamBound () {}
// Unique pointer custom clone function
@@ -1491,6 +1497,8 @@ public:
virtual location_t get_locus () const = 0;
+ virtual TypeParamBoundType get_bound_type () const = 0;
+
protected:
// Clone function implementation as pure virtual method
virtual TypeParamBound *clone_type_param_bound_impl () const = 0;
@@ -1546,12 +1554,17 @@ public:
void accept_vis (ASTVisitor &vis) override;
- LifetimeType get_lifetime_type () { return lifetime_type; }
+ LifetimeType get_lifetime_type () const { return lifetime_type; }
location_t get_locus () const override final { return locus; }
std::string get_lifetime_name () const { return lifetime_name; }
+ TypeParamBoundType get_bound_type () const override
+ {
+ return TypeParamBound::TypeParamBoundType::LIFETIME;
+ }
+
protected:
/* Use covariance to implement clone function as returning this object
* rather than base */
@@ -1587,7 +1600,7 @@ public:
virtual Kind get_kind () const = 0;
- NodeId get_node_id () { return node_id; }
+ NodeId get_node_id () const { return node_id; }
protected:
GenericParam () : node_id (Analysis::Mappings::get ().get_next_node_id ()) {}
@@ -1619,6 +1632,11 @@ public:
std::vector<Lifetime> &get_lifetime_bounds () { return lifetime_bounds; }
+ const std::vector<Lifetime> &get_lifetime_bounds () const
+ {
+ return lifetime_bounds;
+ }
+
// Returns whether the lifetime param has an outer attribute.
bool has_outer_attribute () const { return !outer_attrs.empty (); }
@@ -2048,11 +2066,6 @@ public:
}
};
-// Base path expression AST node - abstract
-class PathExpr : public ExprWithoutBlock
-{
-};
-
} // namespace AST
} // namespace Rust
diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index 9477bf0..438d3d3 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -4768,9 +4768,10 @@ struct InlineAsmRegOrRegClass
location_t locus;
};
-struct InlineAsmOperand
+class InlineAsmOperand
{
- enum RegisterType
+public:
+ enum class RegisterType
{
In,
Out,
@@ -4781,8 +4782,24 @@ struct InlineAsmOperand
Label,
};
- struct In
+ class Register
+ {
+ public:
+ Register () {}
+ virtual ~Register () = default;
+
+ std::unique_ptr<Register> clone () const
+ {
+ return std::unique_ptr<Register> (clone_impl ());
+ }
+
+ protected:
+ virtual Register *clone_impl () const = 0;
+ };
+
+ class In : public Register
{
+ public:
tl::optional<InlineAsmRegOrRegClass> reg;
std::unique_ptr<Expr> expr;
@@ -4807,10 +4824,14 @@ struct InlineAsmOperand
return *this;
}
+
+ private:
+ In *clone_impl () const { return new In (*this); }
};
- struct Out
+ class Out : public Register
{
+ public:
tl::optional<InlineAsmRegOrRegClass> reg;
bool late;
std::unique_ptr<Expr> expr; // can be null
@@ -4836,10 +4857,14 @@ struct InlineAsmOperand
expr = other.expr->clone_expr ();
return *this;
}
+
+ private:
+ Out *clone_impl () const { return new Out (*this); }
};
- struct InOut
+ class InOut : public Register
{
+ public:
tl::optional<InlineAsmRegOrRegClass> reg;
bool late;
std::unique_ptr<Expr> expr; // this can't be null
@@ -4866,10 +4891,14 @@ struct InlineAsmOperand
return *this;
}
+
+ private:
+ InOut *clone_impl () const { return new InOut (*this); }
};
- struct SplitInOut
+ class SplitInOut : public Register
{
+ public:
tl::optional<InlineAsmRegOrRegClass> reg;
bool late;
std::unique_ptr<Expr> in_expr;
@@ -4901,15 +4930,23 @@ struct InlineAsmOperand
return *this;
}
+
+ private:
+ SplitInOut *clone_impl () const { return new SplitInOut (*this); }
};
- struct Const
+ class Const : public Register
{
+ public:
AnonConst anon_const;
+
+ private:
+ Const *clone_impl () const { return new Const (*this); }
};
- struct Sym
+ class Sym : public Register
{
+ public:
std::unique_ptr<Expr> expr;
Sym (std::unique_ptr<Expr> expr) : expr (std::move (expr))
@@ -4926,10 +4963,14 @@ struct InlineAsmOperand
expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
return *this;
}
+
+ private:
+ Sym *clone_impl () const { return new Sym (*this); }
};
- struct Label
+ class Label : public Register
{
+ public:
std::string label_name;
std::unique_ptr<Expr> expr;
@@ -4950,76 +4991,127 @@ struct InlineAsmOperand
expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
return *this;
}
- };
- RegisterType register_type;
-
- tl::optional<struct In> in;
- tl::optional<struct Out> out;
- tl::optional<struct InOut> in_out;
- tl::optional<struct SplitInOut> split_in_out;
- tl::optional<struct Const> cnst;
- tl::optional<struct Sym> sym;
- tl::optional<struct Label> label;
+ private:
+ Label *clone_impl () const { return new Label (*this); }
+ };
- InlineAsmOperand () {}
InlineAsmOperand (const InlineAsmOperand &other)
- : in (other.in), out (other.out), in_out (other.in_out),
- split_in_out (other.split_in_out), cnst (other.cnst), sym (other.sym)
+ : register_type (other.register_type), locus (other.locus),
+ reg (other.reg->clone ())
{}
- void set_in (const tl::optional<struct In> &reg)
- {
- this->register_type = In;
+ InlineAsmOperand (const In &reg, location_t locus)
+ : register_type (RegisterType::In), locus (locus), reg (new In (reg))
+ {}
+ InlineAsmOperand (const Out &reg, location_t locus)
+ : register_type (RegisterType::Out), locus (locus), reg (new Out (reg))
+ {}
+ InlineAsmOperand (const InOut &reg, location_t locus)
+ : register_type (RegisterType::InOut), locus (locus), reg (new InOut (reg))
+ {}
+ InlineAsmOperand (const SplitInOut &reg, location_t locus)
+ : register_type (RegisterType::SplitInOut), locus (locus),
+ reg (new SplitInOut (reg))
+ {}
+ InlineAsmOperand (const Const &reg, location_t locus)
+ : register_type (RegisterType::Const), locus (locus), reg (new Const (reg))
+ {}
+ InlineAsmOperand (const Sym &reg, location_t locus)
+ : register_type (RegisterType::Sym), locus (locus), reg (new Sym (reg))
+ {}
+ InlineAsmOperand (const Label &reg, location_t locus)
+ : register_type (RegisterType::Label), locus (locus), reg (new Label (reg))
+ {}
- if (reg.has_value ())
- this->in = reg.value ();
- }
+ location_t get_locus () const { return locus; }
+ RegisterType get_register_type () const { return register_type; }
- void set_out (const tl::optional<struct Out> &reg)
+ // Potentially fail immediately if you don't use get_register_type() to
+ // inspect the RegisterType first before calling the following functions Check
+ // first
+ In &get_in ()
+ {
+ rust_assert (register_type == RegisterType::In);
+ return static_cast<In &> (*reg);
+ }
+ const In &get_in () const
{
- this->register_type = Out;
+ rust_assert (register_type == RegisterType::In);
+ return static_cast<const In &> (*reg);
+ }
- if (reg.has_value ())
- this->out = reg.value ();
+ Out &get_out ()
+ {
+ rust_assert (register_type == RegisterType::Out);
+ return static_cast<Out &> (*reg);
+ }
+ const Out &get_out () const
+ {
+ rust_assert (register_type == RegisterType::Out);
+ return static_cast<const Out &> (*reg);
}
- void set_in_out (const tl::optional<struct InOut> &reg)
+ InOut &get_in_out ()
+ {
+ rust_assert (register_type == RegisterType::InOut);
+ return static_cast<InOut &> (*reg);
+ }
+ const InOut &get_in_out () const
{
- this->register_type = InOut;
- if (reg.has_value ())
- this->in_out = reg.value ();
+ rust_assert (register_type == RegisterType::InOut);
+ return static_cast<const InOut &> (*reg);
}
- void set_split_in_out (const tl::optional<struct SplitInOut> &reg)
+ SplitInOut &get_split_in_out ()
{
- this->register_type = SplitInOut;
- if (reg.has_value ())
- this->split_in_out = reg.value ();
+ rust_assert (register_type == RegisterType::SplitInOut);
+ return static_cast<SplitInOut &> (*reg);
+ }
+ const SplitInOut &get_split_in_out () const
+ {
+ rust_assert (register_type == RegisterType::SplitInOut);
+ return static_cast<const SplitInOut &> (*reg);
}
- void set_cnst (const tl::optional<struct Const> &reg)
+ Const &get_const ()
+ {
+ rust_assert (register_type == RegisterType::Const);
+ return static_cast<Const &> (*reg);
+ }
+ const Const &get_const () const
{
- this->register_type = Const;
- if (reg.has_value ())
- this->cnst = reg.value ();
+ rust_assert (register_type == RegisterType::Const);
+ return static_cast<Const &> (*reg);
}
- void set_sym (const tl::optional<struct Sym> &reg)
+ Sym &get_sym ()
+ {
+ rust_assert (register_type == RegisterType::Sym);
+ return static_cast<Sym &> (*reg);
+ }
+ const Sym &get_sym () const
{
- this->register_type = Sym;
- if (reg.has_value ())
- this->sym = reg.value ();
+ rust_assert (register_type == RegisterType::Sym);
+ return static_cast<const Sym &> (*reg);
}
- void set_label (const tl::optional<struct Label> &reg)
+ Label &get_label ()
{
- this->register_type = Label;
- if (reg.has_value ())
- this->label = reg.value ();
+ rust_assert (register_type == RegisterType::Label);
+ return static_cast<Label &> (*reg);
}
+ const Label &get_label () const
+ {
+ rust_assert (register_type == RegisterType::Label);
+ return static_cast<const Label &> (*reg);
+ }
+
+private:
+ RegisterType register_type;
location_t locus;
+ std::unique_ptr<Register> reg;
};
struct InlineAsmPlaceHolder
diff --git a/gcc/rust/ast/rust-item.h b/gcc/rust/ast/rust-item.h
index bd9113f..2ae7c44 100644
--- a/gcc/rust/ast/rust-item.h
+++ b/gcc/rust/ast/rust-item.h
@@ -1213,7 +1213,7 @@ public:
std::string as_string () const override;
- NewBindType get_new_bind_type () { return bind_type; }
+ NewBindType get_new_bind_type () const { return bind_type; }
void accept_vis (ASTVisitor &vis) override;
diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc
index 3aaf263..06c98cd 100644
--- a/gcc/rust/ast/rust-path.cc
+++ b/gcc/rust/ast/rust-path.cc
@@ -17,6 +17,7 @@ You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
+#include "rust-path.h"
#include "rust-system.h"
#include "rust-ast-full.h"
#include "rust-diagnostics.h"
@@ -135,7 +136,7 @@ PathExprSegment::as_string () const
}
std::string
-PathPattern::as_string () const
+RegularPath::as_string () const
{
std::string str;
@@ -148,8 +149,15 @@ PathPattern::as_string () const
return str;
}
+std::string
+LangItemPath::as_string () const
+{
+ // FIXME: Handle #[lang] paths
+ rust_unreachable ();
+}
+
SimplePath
-PathPattern::convert_to_simple_path (bool with_opening_scope_resolution) const
+RegularPath::convert_to_simple_path (bool with_opening_scope_resolution) const
{
if (!has_segments ())
return SimplePath::create_empty ();
@@ -184,6 +192,18 @@ PathPattern::convert_to_simple_path (bool with_opening_scope_resolution) const
}
void
+RegularPath::accept_vis (ASTVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
+LangItemPath::accept_vis (ASTVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
PathInExpression::accept_vis (ASTVisitor &vis)
{
vis.visit (*this);
@@ -197,7 +217,7 @@ PathInExpression::as_string () const
if (has_opening_scope_resolution)
str = "::";
- return str + PathPattern::as_string ();
+ return str + path->as_string ();
}
std::string
@@ -297,7 +317,7 @@ TypePathFunction::as_string () const
std::string
QualifiedPathInExpression::as_string () const
{
- return path_type.as_string () + "::" + PathPattern::as_string ();
+ return path_type.as_string () + "::" + path->as_string ();
}
std::string
diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h
index b20f31c..98fde5a 100644
--- a/gcc/rust/ast/rust-path.h
+++ b/gcc/rust/ast/rust-path.h
@@ -22,6 +22,9 @@
* for virtually all AST-related functionality. */
#include "rust-ast.h"
+#include "rust-hir-map.h"
+#include "rust-mapping-common.h"
+#include "rust-system.h"
#include "system.h"
namespace Rust {
@@ -476,15 +479,23 @@ public:
std::string as_string () const;
- // TODO: is this better? Or is a "vis_pattern" better?
std::vector<GenericArg> &get_generic_args () { return generic_args; }
- // TODO: is this better? Or is a "vis_pattern" better?
std::vector<GenericArgsBinding> &get_binding_args () { return binding_args; }
+ const std::vector<GenericArgsBinding> &get_binding_args () const
+ {
+ return binding_args;
+ }
+
std::vector<Lifetime> &get_lifetime_args () { return lifetime_args; };
- location_t get_locus () { return locus; }
+ const std::vector<Lifetime> &get_lifetime_args () const
+ {
+ return lifetime_args;
+ };
+
+ location_t get_locus () const { return locus; }
};
/* A segment of a path in expression, including an identifier aspect and maybe
@@ -565,51 +576,114 @@ public:
// AST node representing a pattern that involves a "path" - abstract base
// class
-class PathPattern : public Pattern
+class Path : public Pattern
{
- std::vector<PathExprSegment> segments;
+public:
+ enum class Kind
+ {
+ LangItem,
+ Regular,
+ };
+
+ virtual Kind get_path_kind () const = 0;
+
+ Pattern::Kind get_pattern_kind () override final
+ {
+ return Pattern::Kind::Path;
+ }
+
+ location_t get_locus () const override final { return locus; }
+ NodeId get_node_id () const override final { return node_id; }
+
+ std::unique_ptr<Path> clone_path ()
+ {
+ return std::unique_ptr<Path> (clone_path_impl ());
+ }
+
+ Pattern *clone_pattern_impl () const override final
+ {
+ return clone_path_impl ();
+ }
protected:
- PathPattern (std::vector<PathExprSegment> segments)
- : segments (std::move (segments))
+ location_t locus;
+ NodeId node_id;
+
+ Path (location_t locus, NodeId node_id) : locus (locus), node_id (node_id) {}
+
+ virtual Path *clone_path_impl () const = 0;
+};
+
+class RegularPath : public Path
+{
+ std::vector<PathExprSegment> segments;
+
+public:
+ explicit RegularPath (std::vector<PathExprSegment> &&segments,
+ location_t locus, NodeId node_id)
+ : Path (locus, node_id), segments (std::move (segments))
{}
+ std::string as_string () const override;
+
// Returns whether path has segments.
bool has_segments () const { return !segments.empty (); }
+ std::vector<PathExprSegment> &get_segments () { return segments; }
+
+ const std::vector<PathExprSegment> &get_segments () const { return segments; }
+
+ /* Returns whether the path is a single segment (excluding qualified path
+ * initial as segment). */
+ bool is_single_segment () const { return segments.size () == 1; }
+
/* Converts path segments to their equivalent SimplePath segments if
* possible, and creates a SimplePath from them. */
SimplePath convert_to_simple_path (bool with_opening_scope_resolution) const;
- // Removes all segments of the path.
- void remove_all_segments ()
+ Path::Kind get_path_kind () const override { return Path::Kind::Regular; }
+
+ void accept_vis (ASTVisitor &vis) override;
+
+ Path *clone_path_impl () const override
{
- segments.clear ();
- segments.shrink_to_fit ();
+ return new RegularPath (std::vector<PathExprSegment> (segments), locus,
+ node_id);
}
+};
-public:
- /* Returns whether the path is a single segment (excluding qualified path
- * initial as segment). */
- bool is_single_segment () const { return segments.size () == 1; }
+class LangItemPath : public Path
+{
+ NodeId lang_item;
+ // TODO: Add LangItemKind or w/ever here as well
- std::string as_string () const override;
+ // TODO: This constructor is wrong
+ explicit LangItemPath (NodeId lang_item, location_t locus)
+ : Path (locus, lang_item), lang_item (lang_item)
+ {}
- // TODO: this seems kinda dodgy
- std::vector<PathExprSegment> &get_segments () { return segments; }
- const std::vector<PathExprSegment> &get_segments () const { return segments; }
+ Path::Kind get_path_kind () const override { return Path::Kind::LangItem; }
- Pattern::Kind get_pattern_kind () override { return Pattern::Kind::Path; }
+ void accept_vis (ASTVisitor &vis) override;
+
+ Path *clone_path_impl () const override
+ {
+ return new LangItemPath (lang_item, locus);
+ }
+
+ std::string as_string () const override;
};
/* AST node representing a path-in-expression pattern (path that allows
* generic arguments) */
-class PathInExpression : public PathPattern, public PathExpr
+class PathInExpression : public Pattern, public ExprWithoutBlock
{
std::vector<Attribute> outer_attrs;
bool has_opening_scope_resolution;
location_t locus;
NodeId _node_id;
+ std::unique_ptr<Path> path;
+ bool marked_for_strip;
public:
std::string as_string () const override;
@@ -618,12 +692,34 @@ public:
PathInExpression (std::vector<PathExprSegment> path_segments,
std::vector<Attribute> outer_attrs, location_t locus,
bool has_opening_scope_resolution = false)
- : PathPattern (std::move (path_segments)),
- outer_attrs (std::move (outer_attrs)),
+ : outer_attrs (std::move (outer_attrs)),
has_opening_scope_resolution (has_opening_scope_resolution),
- locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ())
+ locus (locus), _node_id (Analysis::Mappings::get ().get_next_node_id ()),
+ path (Rust::make_unique<RegularPath> (std::move (path_segments), locus,
+ _node_id)),
+ marked_for_strip (false)
{}
+ PathInExpression (const PathInExpression &other)
+ : outer_attrs (other.outer_attrs),
+ has_opening_scope_resolution (other.has_opening_scope_resolution),
+ locus (other.locus), _node_id (other._node_id),
+ path (other.path->clone_path ()),
+ marked_for_strip (other.marked_for_strip)
+ {}
+
+ PathInExpression &operator= (const PathInExpression &other)
+ {
+ outer_attrs = other.outer_attrs;
+ has_opening_scope_resolution = other.has_opening_scope_resolution;
+ locus = other.locus;
+ _node_id = other._node_id;
+ path = other.path->clone_path ();
+ marked_for_strip = other.marked_for_strip;
+
+ return *this;
+ }
+
// Creates an error state path in expression.
static PathInExpression create_error ()
{
@@ -631,28 +727,34 @@ public:
}
// Returns whether path in expression is in an error state.
- bool is_error () const { return !has_segments (); }
+ bool is_error () const
+ {
+ // FIXME: Cleanup
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return !static_cast<RegularPath &> (*path).has_segments ();
+
+ return false;
+ }
/* Converts PathInExpression to SimplePath if possible (i.e. no generic
* arguments). Otherwise returns an empty SimplePath. */
SimplePath as_simple_path () const
{
- /* delegate to parent class as can't access segments. however,
- * QualifiedPathInExpression conversion to simple path wouldn't make
- * sense, so the method in the parent class should be protected, not
- * public. Have to pass in opening scope resolution as parent class has no
- * access to it.
- */
- return convert_to_simple_path (has_opening_scope_resolution);
+ // FIXME: Cleanup
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).convert_to_simple_path (
+ has_opening_scope_resolution);
+ else
+ // FIXME: lang item to simple path?
+ rust_unreachable ();
}
location_t get_locus () const override final { return locus; }
void accept_vis (ASTVisitor &vis) override;
- // Invalid if path is empty (error state), so base stripping on that.
- void mark_for_strip () override { remove_all_segments (); }
- bool is_marked_for_strip () const override { return is_error (); }
+ void mark_for_strip () override { marked_for_strip = true; }
+ bool is_marked_for_strip () const override { return marked_for_strip; }
bool opening_scope_resolution () const
{
@@ -671,13 +773,61 @@ public:
NodeId get_pattern_node_id () const { return get_node_id (); }
- PathExprSegment &get_final_segment () { return get_segments ().back (); }
+ PathExprSegment &get_final_segment ()
+ {
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).get_segments ().back ();
+
+ // lang item segment?
+ rust_unreachable ();
+ }
+
const PathExprSegment &get_final_segment () const
{
- return get_segments ().back ();
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).get_segments ().back ();
+
+ // lang item segment?
+ rust_unreachable ();
+ }
+
+ const std::vector<PathExprSegment> &get_segments () const
+ {
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).get_segments ();
+
+ rust_unreachable ();
+ }
+
+ std::vector<PathExprSegment> &get_segments ()
+ {
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).get_segments ();
+
+ rust_unreachable ();
+ }
+
+ bool is_single_segment () const
+ {
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).get_segments ().size () == 1;
+
+ return false;
}
+ Pattern::Kind get_pattern_kind () override { return Pattern::Kind::Path; }
+
protected:
+ PathInExpression (std::vector<Attribute> &&outer_attrs,
+ bool has_opening_scope_resolution, location_t locus,
+ NodeId node_id, std::unique_ptr<Path> &&path,
+ bool marked_for_strip)
+ : outer_attrs (std::move (outer_attrs)),
+ has_opening_scope_resolution (has_opening_scope_resolution),
+ locus (locus), _node_id (node_id), path (std::move (path)),
+ marked_for_strip (marked_for_strip)
+ {}
+
/* Use covariance to implement clone function as returning this object
* rather than base */
PathInExpression *clone_pattern_impl () const final override
@@ -1226,12 +1376,12 @@ public:
/* AST node representing a qualified path-in-expression pattern (path that
* allows specifying trait functions) */
-class QualifiedPathInExpression : public PathPattern, public PathExpr
+class QualifiedPathInExpression : public Pattern, public ExprWithoutBlock
{
std::vector<Attribute> outer_attrs;
QualifiedPathType path_type;
- location_t locus;
- NodeId _node_id;
+
+ std::unique_ptr<Path> path;
public:
std::string as_string () const override;
@@ -1240,10 +1390,16 @@ public:
std::vector<PathExprSegment> path_segments,
std::vector<Attribute> outer_attrs,
location_t locus)
- : PathPattern (std::move (path_segments)),
- outer_attrs (std::move (outer_attrs)),
- path_type (std::move (qual_path_type)), locus (locus),
- _node_id (Analysis::Mappings::get ().get_next_node_id ())
+ : outer_attrs (std::move (outer_attrs)),
+ path_type (std::move (qual_path_type)),
+ path (Rust::make_unique<RegularPath> (
+ std::move (path_segments), locus,
+ Analysis::Mappings::get ().get_next_node_id ()))
+ {}
+
+ QualifiedPathInExpression (const QualifiedPathInExpression &other)
+ : outer_attrs (other.outer_attrs), path_type (other.path_type),
+ path (other.path->clone_path ())
{}
/* TODO: maybe make a shortcut constructor that has QualifiedPathType
@@ -1259,7 +1415,9 @@ public:
{}, UNDEF_LOCATION);
}
- location_t get_locus () const override final { return locus; }
+ Pattern::Kind get_pattern_kind () override { return Pattern::Kind::Path; }
+
+ location_t get_locus () const override final { return path->get_locus (); }
void accept_vis (ASTVisitor &vis) override;
@@ -1285,7 +1443,31 @@ public:
outer_attrs = std::move (new_attrs);
}
- NodeId get_node_id () const override { return _node_id; }
+ NodeId get_node_id () const override { return path->get_node_id (); }
+
+ const std::vector<PathExprSegment> &get_segments () const
+ {
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).get_segments ();
+
+ rust_unreachable ();
+ }
+
+ std::vector<PathExprSegment> &get_segments ()
+ {
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).get_segments ();
+
+ rust_unreachable ();
+ }
+
+ bool is_single_segment () const
+ {
+ if (path->get_path_kind () == Path::Kind::Regular)
+ return static_cast<RegularPath &> (*path).get_segments ().size () == 1;
+
+ return false;
+ }
protected:
/* Use covariance to implement clone function as returning this object
diff --git a/gcc/rust/ast/rust-pattern.h b/gcc/rust/ast/rust-pattern.h
index 383a5ee..69dbd98 100644
--- a/gcc/rust/ast/rust-pattern.h
+++ b/gcc/rust/ast/rust-pattern.h
@@ -1657,7 +1657,7 @@ protected:
};
// Moved definition to rust-path.h
-class PathPattern;
+class Path;
// Forward decls for paths (defined in rust-path.h)
class PathInExpression;
diff --git a/gcc/rust/ast/rust-type.h b/gcc/rust/ast/rust-type.h
index cf830f6..20e0232 100644
--- a/gcc/rust/ast/rust-type.h
+++ b/gcc/rust/ast/rust-type.h
@@ -48,6 +48,11 @@ public:
std::vector<LifetimeParam> &get_for_lifetimes () { return for_lifetimes; }
+ const std::vector<LifetimeParam> &get_for_lifetimes () const
+ {
+ return for_lifetimes;
+ }
+
TraitBound (TypePath type_path, location_t locus, bool in_parens = false,
bool opening_question_mark = false,
std::vector<LifetimeParam> for_lifetimes
@@ -81,6 +86,11 @@ public:
bool is_in_parens () const { return in_parens; }
bool has_opening_question_mark () const { return opening_question_mark; }
+ TypeParamBoundType get_bound_type () const override
+ {
+ return TypeParamBound::TypeParamBoundType::TRAIT;
+ }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc
new file mode 100644
index 0000000..e85d08d
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-asm.cc
@@ -0,0 +1,146 @@
+#include "rust-compile-asm.h"
+#include "rust-compile-expr.h"
+namespace Rust {
+namespace Compile {
+
+CompileAsm::CompileAsm (Context *ctx)
+ : HIRCompileBase (ctx), translated (error_mark_node)
+{}
+tree
+CompileAsm::tree_codegen_asm (HIR::InlineAsm &expr)
+{
+ auto asm_expr
+ = asm_build_stmt (expr.get_locus (), {asm_construct_string_tree (expr),
+ asm_construct_outputs (expr),
+ asm_construct_inputs (expr),
+ asm_construct_clobber_tree (expr),
+ asm_construct_label_tree (expr)});
+
+ ASM_BASIC_P (asm_expr) = expr.is_simple_asm ();
+ ASM_VOLATILE_P (asm_expr) = false;
+ ASM_INLINE_P (asm_expr) = expr.is_inline_asm ();
+ /*Backend::debug (asm_expr);*/
+ return asm_expr;
+}
+
+tree
+CompileAsm::asm_build_stmt (
+ location_t loc,
+ const std::array<tree, CompileAsm::ASM_TREE_ARRAY_LENGTH> &trees)
+{
+ // Prototype functiion for building an ASM_EXPR tree.
+ tree ret;
+ bool side_effects;
+
+ ret = make_node (ASM_EXPR);
+ TREE_TYPE (ret) = void_type_node;
+ SET_EXPR_LOCATION (ret, loc);
+
+ /* TREE_SIDE_EFFECTS will already be set for statements with
+ implicit side effects. Here we make sure it is set for other
+ expressions by checking whether the parameters have side
+ effects. */
+
+ // This is here because of c-typeck.cc's code
+ // I'm not sure what kind of effects it has
+ side_effects = false;
+ for (size_t i = 0; i < trees.size (); i++)
+ {
+ tree t = trees[i];
+ if (t && !TYPE_P (t))
+ side_effects |= TREE_SIDE_EFFECTS (t);
+ TREE_OPERAND (ret, i) = t;
+ }
+
+ TREE_SIDE_EFFECTS (ret) |= side_effects;
+
+ return ret;
+}
+
+tree
+CompileAsm::asm_construct_string_tree (HIR::InlineAsm &expr)
+{
+ // To construct an ASM_EXPR tree, we need to build a STRING_CST tree.
+ //
+ // We do this by concatenating all the template strings in the InlineAsm
+ // into one big std::string seperated by tabs and newlines. (For easier
+ // debugging and reading)
+ std::stringstream ss;
+ for (const auto &template_str : expr.template_strs)
+ ss << template_str.symbol << "\n";
+
+ std::string result = ss.str ();
+ return Backend::string_constant_expression (result);
+}
+
+tree
+CompileAsm::asm_construct_outputs (HIR::InlineAsm &expr)
+{
+ // TODO: Do i need to do this?
+
+ tree head = NULL_TREE;
+ for (auto &output : expr.get_operands ())
+ {
+ if (output.get_register_type ()
+ == AST::InlineAsmOperand::RegisterType::Out)
+ {
+ auto out = output.get_out ();
+
+ tree out_tree = CompileExpr::Compile (out.expr.get (), this->ctx);
+ // expects a tree list
+ // TODO: This assumes that the output is a register
+ std::string expr_name = "=r";
+ auto name = build_string (expr_name.size () + 1, expr_name.c_str ());
+ head
+ = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name),
+ out_tree));
+
+ /*Backend::debug (head);*/
+ /*head = chainon (head, out_tree);*/
+ }
+ }
+ return head;
+}
+
+tree
+CompileAsm::asm_construct_inputs (HIR::InlineAsm &expr)
+{
+ // TODO: Do i need to do this?
+ tree head = NULL_TREE;
+ for (auto &input : expr.get_operands ())
+ {
+ if (input.get_register_type () == AST::InlineAsmOperand::RegisterType::In)
+ {
+ auto in = input.get_in ();
+
+ tree in_tree = CompileExpr::Compile (in.expr.get (), this->ctx);
+ // expects a tree list
+ // TODO: This assumes that the input is a register
+ std::string expr_name = "r";
+ auto name = build_string (expr_name.size () + 1, expr_name.c_str ());
+ head
+ = chainon (head, build_tree_list (build_tree_list (NULL_TREE, name),
+ in_tree));
+
+ /*head = chainon (head, out_tree);*/
+ }
+ }
+ return head;
+}
+
+tree
+CompileAsm::asm_construct_clobber_tree (HIR::InlineAsm &expr)
+{
+ // TODO: Do i need to do this?
+ return NULL_TREE;
+}
+
+tree
+CompileAsm::asm_construct_label_tree (HIR::InlineAsm &expr)
+{
+ // TODO: Do i need to do this?
+ return NULL_TREE;
+}
+
+} // namespace Compile
+} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-asm.h b/gcc/rust/backend/rust-compile-asm.h
new file mode 100644
index 0000000..402d950
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-asm.h
@@ -0,0 +1,63 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_COMPILE_ASM
+#define RUST_COMPILE_ASM
+
+#include "rust-compile-base.h"
+#include "rust-hir-visitor.h"
+
+namespace Rust {
+namespace Compile {
+
+class CompileAsm : private HIRCompileBase
+{
+private:
+ tree translated;
+
+ // RELEVANT MEMBER FUNCTIONS
+
+ // The limit is 5 because it stands for the 5 things that the C version of
+ // build_asm_expr accepts: string, output, input, clobber and label.
+ // The function signature is
+ //
+ // tree
+ // build_asm_expr (location_t loc, tree string, tree outputs, tree inputs,
+ // tree clobbers, tree labels, bool simple, bool is_inline)
+ static const int ASM_TREE_ARRAY_LENGTH = 5;
+ tree asm_build_stmt (location_t,
+ const std::array<tree, ASM_TREE_ARRAY_LENGTH> &);
+
+ tree asm_construct_string_tree (HIR::InlineAsm &);
+ tree asm_construct_outputs (HIR::InlineAsm &);
+ tree asm_construct_inputs (HIR::InlineAsm &);
+ tree asm_construct_clobber_tree (HIR::InlineAsm &);
+ tree asm_construct_label_tree (HIR::InlineAsm &);
+
+public:
+ // WE WILL OPEN THIS UP WHEN WE WANT TO ADD A DEDICATED PASS OF HIR'S ASM
+ // translation.
+ // static tree Compile (HIR::Expr *expr, Context *ctx);
+
+ CompileAsm (Context *ctx);
+
+ tree tree_codegen_asm (HIR::InlineAsm &);
+};
+} // namespace Compile
+} // namespace Rust
+#endif // RUST_COMPILE_ASM
diff --git a/gcc/rust/backend/rust-compile-block.h b/gcc/rust/backend/rust-compile-block.h
index b315c77..d226b4b 100644
--- a/gcc/rust/backend/rust-compile-block.h
+++ b/gcc/rust/backend/rust-compile-block.h
@@ -101,6 +101,7 @@ public:
void visit (HIR::MatchExpr &) override {}
void visit (HIR::AwaitExpr &) override {}
void visit (HIR::AsyncBlockExpr &) override {}
+ void visit (HIR::InlineAsm &) override {}
private:
CompileConditionalBlocks (Context *ctx, Bvariable *result)
@@ -184,6 +185,7 @@ public:
void visit (HIR::MatchExpr &) override {}
void visit (HIR::AwaitExpr &) override {}
void visit (HIR::AsyncBlockExpr &) override {}
+ void visit (HIR::InlineAsm &) override {}
private:
CompileExprWithBlock (Context *ctx, Bvariable *result)
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index e2fa6dd..7251cc8 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -25,7 +25,7 @@
#include "rust-constexpr.h"
#include "rust-compile-type.h"
#include "rust-gcc.h"
-
+#include "rust-compile-asm.h"
#include "fold-const.h"
#include "realmpfr.h"
#include "convert.h"
@@ -235,7 +235,25 @@ void
CompileExpr::visit (HIR::NegationExpr &expr)
{
auto op = expr.get_expr_type ();
- auto negated_expr = CompileExpr::Compile (expr.get_expr ().get (), ctx);
+
+ const auto literal_expr = expr.get_expr ().get ();
+
+ // If it's a negated integer/float literal, we can return early
+ if (op == NegationOperator::NEGATE
+ && literal_expr->get_expression_type () == HIR::Expr::ExprType::Lit)
+ {
+ auto new_literal_expr = static_cast<HIR::LiteralExpr *> (literal_expr);
+ auto lit_type = new_literal_expr->get_lit_type ();
+ if (lit_type == HIR::Literal::LitType::INT
+ || lit_type == HIR::Literal::LitType::FLOAT)
+ {
+ new_literal_expr->set_negative ();
+ translated = CompileExpr::Compile (literal_expr, ctx);
+ return;
+ }
+ }
+
+ auto negated_expr = CompileExpr::Compile (literal_expr, ctx);
auto location = expr.get_locus ();
// this might be an operator overload situation lets check
@@ -319,6 +337,16 @@ CompileExpr::visit (HIR::IfExpr &expr)
}
void
+CompileExpr::visit (HIR::InlineAsm &expr)
+{
+ CompileAsm asm_codegen (ctx);
+ ctx->add_statement (asm_codegen.tree_codegen_asm (expr));
+ // translated = build_asm_expr (0, NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE,
+ // NULL_TREE, true, true);
+ // CompileAsm::asm_build_expr (expr);
+}
+
+void
CompileExpr::visit (HIR::IfExprConseqElse &expr)
{
TyTy::BaseType *if_type = nullptr;
@@ -725,8 +753,24 @@ CompileExpr::visit (HIR::BreakExpr &expr)
if (expr.has_label ())
{
NodeId resolved_node_id = UNKNOWN_NODEID;
- if (!ctx->get_resolver ()->lookup_resolved_label (
- expr.get_label ().get_mappings ().get_nodeid (), &resolved_node_id))
+ if (flag_name_resolution_2_0)
+ {
+ auto &nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ if (auto id
+ = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ()))
+ resolved_node_id = *id;
+ }
+ else
+ {
+ NodeId tmp = UNKNOWN_NODEID;
+ if (ctx->get_resolver ()->lookup_resolved_label (
+ expr.get_label ().get_mappings ().get_nodeid (), &tmp))
+ resolved_node_id = tmp;
+ }
+
+ if (resolved_node_id == UNKNOWN_NODEID)
{
rust_error_at (
expr.get_label ().get_locus (),
@@ -771,8 +815,25 @@ CompileExpr::visit (HIR::ContinueExpr &expr)
if (expr.has_label ())
{
NodeId resolved_node_id = UNKNOWN_NODEID;
- if (!ctx->get_resolver ()->lookup_resolved_label (
- expr.get_label ().get_mappings ().get_nodeid (), &resolved_node_id))
+ if (flag_name_resolution_2_0)
+ {
+ auto &nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ if (auto id
+ = nr_ctx.lookup (expr.get_label ().get_mappings ().get_nodeid ()))
+ resolved_node_id = *id;
+ }
+ else
+ {
+ NodeId tmp = UNKNOWN_NODEID;
+
+ if (ctx->get_resolver ()->lookup_resolved_label (
+ expr.get_label ().get_mappings ().get_nodeid (), &tmp))
+ resolved_node_id = tmp;
+ }
+
+ if (resolved_node_id == UNKNOWN_NODEID)
{
rust_error_at (
expr.get_label ().get_locus (),
@@ -1496,6 +1557,10 @@ CompileExpr::compile_integer_literal (const HIR::LiteralExpr &expr,
mpz_init (type_max);
get_type_static_bounds (type, type_min, type_max);
+ if (expr.is_negative ())
+ {
+ mpz_neg (ival, ival);
+ }
if (mpz_cmp (ival, type_min) < 0 || mpz_cmp (ival, type_max) > 0)
{
rust_error_at (expr.get_locus (),
@@ -1520,6 +1585,8 @@ CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr,
rust_assert (expr.get_lit_type () == HIR::Literal::FLOAT);
const auto literal_value = expr.get_literal ();
+ tree type = TyTyResolveCompile::compile (ctx, tyty);
+
mpfr_t fval;
if (mpfr_init_set_str (fval, literal_value.as_string ().c_str (), 10,
MPFR_RNDN)
@@ -1529,12 +1596,44 @@ CompileExpr::compile_float_literal (const HIR::LiteralExpr &expr,
return error_mark_node;
}
- tree type = TyTyResolveCompile::compile (ctx, tyty);
-
// taken from:
// see go/gofrontend/expressions.cc:check_float_type
- mpfr_exp_t exp = mpfr_get_exp (fval);
- bool real_value_overflow = exp > TYPE_PRECISION (type);
+ bool real_value_overflow;
+
+ if (mpfr_regular_p (fval) != 0)
+ {
+ mpfr_exp_t exp = mpfr_get_exp (fval);
+ mpfr_exp_t min_exp;
+ mpfr_exp_t max_exp;
+
+ /*
+ * By convention, the radix point of the significand is just before the
+ * first digit (which is always 1 due to normalization), like in the C
+ * language, but unlike in IEEE 754 (thus, for a given number, the
+ * exponent values in MPFR and in IEEE 754 differ by 1).
+ */
+ switch (TYPE_PRECISION (type))
+ {
+ case 32:
+ min_exp = -128 + 1;
+ max_exp = 127 + 1;
+ break;
+ case 64:
+ min_exp = -1024 + 1;
+ max_exp = 1023 + 1;
+ break;
+ default:
+ rust_error_at (expr.get_locus (),
+ "precision of type %<%s%> not supported",
+ tyty->get_name ().c_str ());
+ return error_mark_node;
+ }
+ real_value_overflow = exp < min_exp || exp > max_exp;
+ }
+ else
+ {
+ real_value_overflow = false;
+ }
REAL_VALUE_TYPE r1;
real_from_mpfr (&r1, fval, type, GMP_RNDN);
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index b257da5..ef907d1 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -68,6 +68,7 @@ public:
void visit (HIR::RangeFullExpr &expr) override;
void visit (HIR::RangeFromToInclExpr &expr) override;
void visit (HIR::ClosureExpr &expr) override;
+ void visit (HIR::InlineAsm &expr) override;
// TODO
void visit (HIR::ErrorPropagationExpr &) override {}
diff --git a/gcc/rust/backend/rust-compile-item.cc b/gcc/rust/backend/rust-compile-item.cc
index c0cac68..0878716 100644
--- a/gcc/rust/backend/rust-compile-item.cc
+++ b/gcc/rust/backend/rust-compile-item.cc
@@ -42,8 +42,23 @@ CompileItem::visit (HIR::StaticItem &var)
tree type = TyTyResolveCompile::compile (ctx, resolved_type);
- auto canonical_path = ctx->get_mappings ().lookup_canonical_path (
- var.get_mappings ().get_nodeid ());
+ tl::optional<Resolver::CanonicalPath> canonical_path;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ canonical_path
+ = nr_ctx.values.to_canonical_path (var.get_mappings ().get_nodeid ());
+ }
+ else
+ {
+ canonical_path = ctx->get_mappings ().lookup_canonical_path (
+ var.get_mappings ().get_nodeid ());
+ }
+
+ rust_assert (canonical_path.has_value ());
HIR::Expr *const_value_expr = var.get_expr ().get ();
ctx->push_const_context ();
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index 20190c3..7e0a9b6 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -241,100 +241,84 @@ HIRCompileBase::compute_address_for_trait_item (
&receiver_bounds,
const TyTy::BaseType *receiver, const TyTy::BaseType *root, location_t locus)
{
- // There are two cases here one where its an item which has an implementation
- // within a trait-impl-block. Then there is the case where there is a default
- // implementation for this within the trait.
- //
- // The awkward part here is that this might be a generic trait and we need to
- // figure out the correct monomorphized type for this so we can resolve the
- // address of the function , this is stored as part of the
- // type-bound-predicate
- //
- // Algo:
- // check if there is an impl-item for this trait-item-ref first
- // else assert that the trait-item-ref has an implementation
- //
- // FIXME this does not support super traits
-
TyTy::TypeBoundPredicateItem predicate_item
= predicate->lookup_associated_item (ref->get_identifier ());
rust_assert (!predicate_item.is_error ());
- // this is the expected end type
+ // This is the expected end type
TyTy::BaseType *trait_item_type = predicate_item.get_tyty_for_receiver (root);
rust_assert (trait_item_type->get_kind () == TyTy::TypeKind::FNDEF);
TyTy::FnType *trait_item_fntype
= static_cast<TyTy::FnType *> (trait_item_type);
- // find impl-block for this trait-item-ref
- HIR::ImplBlock *associated_impl_block = nullptr;
- const Resolver::TraitReference *predicate_trait_ref = predicate->get ();
+ // Loop through the list of trait references and impls that we satisfy.
+ // We are looking for one that has an implementation for "ref", a trait
+ // item.
for (auto &item : receiver_bounds)
{
- Resolver::TraitReference *trait_ref = item.first;
HIR::ImplBlock *impl_block = item.second;
- if (predicate_trait_ref->is_equal (*trait_ref))
+ rust_assert (impl_block != nullptr);
+
+ // Lookup type for potentially associated impl.
+ std::unique_ptr<HIR::Type> &self_type_path = impl_block->get_type ();
+
+ // Checks for empty impl blocks, triggered by Sized trait.
+ if (self_type_path == nullptr)
+ continue;
+
+ // Convert HIR::Type to TyTy::BaseType
+ TyTy::BaseType *self = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_type (
+ self_type_path->get_mappings ().get_hirid (), &self);
+
+ rust_assert (ok);
+
+ // Look through the relevant bounds on our type, and find which one our
+ // impl block satisfies
+ TyTy::TypeBoundPredicate *self_bound = nullptr;
+ for (auto &bound : self->get_specified_bounds ())
{
- associated_impl_block = impl_block;
- break;
+ const Resolver::TraitReference *bound_ref = bound.get ();
+ const Resolver::TraitReference *specified_ref = predicate->get ();
+ // If this impl is for one of our types or supertypes
+ if (specified_ref->satisfies_bound (*bound_ref))
+ {
+ self_bound = &bound;
+ break;
+ }
}
- }
- // FIXME this probably should just return error_mark_node but this helps
- // debug for now since we are wrongly returning early on type-resolution
- // failures, until we take advantage of more error types and error_mark_node
- rust_assert (associated_impl_block != nullptr);
-
- // lookup self for the associated impl
- std::unique_ptr<HIR::Type> &self_type_path
- = associated_impl_block->get_type ();
- TyTy::BaseType *self = nullptr;
- bool ok = ctx->get_tyctx ()->lookup_type (
- self_type_path->get_mappings ().get_hirid (), &self);
- rust_assert (ok);
-
- // lookup the predicate item from the self
- TyTy::TypeBoundPredicate *self_bound = nullptr;
- for (auto &bound : self->get_specified_bounds ())
- {
- const Resolver::TraitReference *bound_ref = bound.get ();
- const Resolver::TraitReference *specified_ref = predicate->get ();
- if (bound_ref->is_equal (*specified_ref))
+ // This impl block doesn't help us
+ if (self_bound == nullptr)
+ continue;
+
+ // Find the specific function in the impl block that matches "ref".
+ // This is the one we want to compute the address for.
+ HIR::Function *associated_function = nullptr;
+ for (auto &impl_item : impl_block->get_impl_items ())
{
- self_bound = &bound;
- break;
+ bool is_function = impl_item->get_impl_item_type ()
+ == HIR::ImplItem::ImplItemType::FUNCTION;
+ if (!is_function)
+ continue;
+
+ HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ());
+ bool found_associated_item
+ = fn->get_function_name ().as_string ().compare (
+ ref->get_identifier ())
+ == 0;
+ if (found_associated_item)
+ associated_function = fn;
}
- }
- rust_assert (self_bound != nullptr);
-
- // lookup the associated item from the associated impl block
- TyTy::TypeBoundPredicateItem associated_self_item
- = self_bound->lookup_associated_item (ref->get_identifier ());
- rust_assert (!associated_self_item.is_error ());
- // Lookup the impl-block for the associated impl_item if it exists
- HIR::Function *associated_function = nullptr;
- for (auto &impl_item : associated_impl_block->get_impl_items ())
- {
- bool is_function = impl_item->get_impl_item_type ()
- == HIR::ImplItem::ImplItemType::FUNCTION;
- if (!is_function)
+ // This impl block satisfies the bound, but doesn't contain the relevant
+ // function. This could happen because of supertraits.
+ if (associated_function == nullptr)
continue;
- HIR::Function *fn = static_cast<HIR::Function *> (impl_item.get ());
- bool found_associated_item
- = fn->get_function_name ().as_string ().compare (ref->get_identifier ())
- == 0;
- if (found_associated_item)
- associated_function = fn;
- }
-
- // we found an impl_item for this
- if (associated_function != nullptr)
- {
// lookup the associated type for this item
TyTy::BaseType *lookup = nullptr;
- bool ok = ctx->get_tyctx ()->lookup_type (
+ ok = ctx->get_tyctx ()->lookup_type (
associated_function->get_mappings ().get_hirid (), &lookup);
rust_assert (ok);
rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/.cargo/config.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/.cargo/config.toml
new file mode 100644
index 0000000..0236928
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/.cargo/config.toml
@@ -0,0 +1,5 @@
+[source.crates-io]
+replace-with = "vendored-sources"
+
+[source.vendored-sources]
+directory = "vendor"
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.lock b/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.lock
new file mode 100644
index 0000000..f7cbd41
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/Cargo.lock
@@ -0,0 +1,39 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "datafrog"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
+
+[[package]]
+name = "ffi-polonius"
+version = "0.1.0"
+dependencies = [
+ "polonius-engine",
+]
+
+[[package]]
+name = "log"
+version = "0.4.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "polonius-engine"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4e8e505342045d397d0b6674dcb82d6faf5cf40484d30eeb88fc82ef14e903f"
+dependencies = [
+ "datafrog",
+ "log",
+ "rustc-hash",
+]
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs
index 0cb85078..7377e3a 100644
--- a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/gccrs_ffi.rs
@@ -30,11 +30,16 @@
// ```
include!("gccrs_ffi_generated.rs");
+use std::marker::{PhantomData, PhantomPinned};
+
use crate::GccrsAtom;
-// Using opqaue types
-extern "C" {
- pub type FFIVector;
+// We define an opaque C type per the nomicon's recommendation:
+// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
+#[repr(C)]
+pub struct FFIVector {
+ _empty: [u8; 0],
+ marker: PhantomData<(*mut u8, PhantomPinned)>,
}
impl<T1, T2> Into<(GccrsAtom, GccrsAtom)> for Pair<T1, T2>
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs
index 782a63f..b21dee3 100644
--- a/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/src/lib.rs
@@ -16,8 +16,6 @@
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
-#![feature(extern_types)]
-
mod gccrs_ffi;
use gccrs_ffi::FFIVector;
@@ -107,9 +105,24 @@ impl From<gccrs_ffi::FactsView> for AllFacts<GccrsFacts> {
fn print_point(point: GccrsAtom) {
let val: usize = point.into();
+ // Point is a 32 bit unsigned integer
+ // 16 15 1
+ // xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx x
+ // ^~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~ ^
+ // | | |
+ // basic_block | start/mid
+ // statement
+ // the left most 16 bits store the basic block number
+ // the right most bit, represents the start/mid status
+ // the remaining 15 bits between these two represent the statement
let mid = val % 2 == 1;
let bb = val >> 16;
- let stmt = (val >> 1) & ((1 << 15) - 1);
+ // firstly we can get rid of right most bit by performing left shift once
+ let hide_left_most_bit = val >> 1;
+ // now we only need the 15 bits on the right
+ // we can mask the remaining bits by performing bitwise AND with fifteen
+ // 1's which in hexadecimal is 0x7FFF
+ let stmt = hide_left_most_bit & 0x7FFF;
eprint!("{}(bb{}[{}])", if mid { "Mid" } else { "Start" }, bb, stmt);
}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json
new file mode 100644
index 0000000..80aa32c
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CODE_OF_CONDUCT.md":"edca092fde496419a9f1ba640048aa0270b62dfea576cd3175f0b53e3c230470","Cargo.toml":"c3a8ecf831d7985fafcb8e523fd2d1bf875297e1a11b750a28222793a42e0d4c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"60c181bf865b494df30968378509453719163f57a84f31a244fe69e62c342c5b","RELEASES.md":"a49128d725075bb614da3d53ea2aa2ab080bcb83ce46fc57655f6f6ecc9e2b74","examples/borrow_check.rs":"256857ed6609be8d1f3c8cf041ff8a1c0a884e8540f3156d2f3a2a2a9f73a05d","examples/graspan1.rs":"7d93ba71ff08a3667fea696d0a94e2c91e7514c304f2be8b088465cee17537fe","src/join.rs":"04eb29a02a1fd3ecf27d35a9eaabeec686bbfabdeafe13ad9ac98a622acb0f19","src/lib.rs":"7c95a63c237f48f986abd63ddfa4ed296bb5d280d245295d025fdf2f9744c2f3","src/map.rs":"93f1c7273fb67beb62a4b02201a6502bcaabf1e079aa7201a88d8e0aea6123e9","src/test.rs":"1eee5db2817a781cf8bf16744338b896252e400c150ae23ad87ce8c623acee69","src/treefrog.rs":"fe84a2bd2e36f1a48cb6b7e77a74addf218cfc881e9f6d4e7ceff4d8d97aa380"},"package":"a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"} \ No newline at end of file
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..d70b2b5
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/CODE_OF_CONDUCT.md
@@ -0,0 +1,40 @@
+# The Rust Code of Conduct
+
+A version of this document [can be found online](https://www.rust-lang.org/conduct.html).
+
+## Conduct
+
+**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org)
+
+* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
+* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
+* Please be kind and courteous. There's no need to be mean or rude.
+* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
+* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
+* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
+* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
+* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
+
+## Moderation
+
+
+These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team].
+
+1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
+2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
+3. Moderators will first respond to such remarks with a warning.
+4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
+5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
+6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
+7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
+8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
+
+In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
+
+And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
+
+The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
+
+*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
+
+[mod_team]: https://www.rust-lang.org/team.html#Moderation-team
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml
new file mode 100644
index 0000000..71bccdd
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/Cargo.toml
@@ -0,0 +1,29 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g. crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "datafrog"
+version = "2.0.1"
+authors = ["Frank McSherry <fmcsherry@me.com>", "The Rust Project Developers", "Datafrog Developers"]
+description = "Lightweight Datalog engine intended to be embedded in other Rust programs"
+readme = "README.md"
+keywords = ["datalog", "analysis"]
+license = "Apache-2.0/MIT"
+repository = "https://github.com/rust-lang-nursery/datafrog"
+[dev-dependencies.proptest]
+version = "0.8.7"
+[badges.is-it-maintained-issue-resolution]
+repository = "https://github.com/rust-lang-nursery/datafrog"
+
+[badges.is-it-maintained-open-issues]
+repository = "https://github.com/rust-lang-nursery/datafrog"
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ 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
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/LICENSE-MIT
@@ -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/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md
new file mode 100644
index 0000000..9483584
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/README.md
@@ -0,0 +1,44 @@
+# datafrog
+
+Datafrog is a lightweight Datalog engine intended to be embedded in other Rust programs.
+
+Datafrog has no runtime, and relies on you to build and repeatedly apply the update rules.
+It tries to help you do this correctly. As an example, here is how you might write a reachability
+query using Datafrog (minus the part where we populate the `nodes` and `edges` initial relations).
+
+```rust
+extern crate datafrog;
+use datafrog::Iteration;
+
+fn main() {
+
+ // Create a new iteration context, ...
+ let mut iteration = Iteration::new();
+
+ // .. some variables, ..
+ let nodes_var = iteration.variable::<(u32,u32)>("nodes");
+ let edges_var = iteration.variable::<(u32,u32)>("edges");
+
+ // .. load them with some initial values, ..
+ nodes_var.insert(nodes.into());
+ edges_var.insert(edges.into());
+
+ // .. and then start iterating rules!
+ while iteration.changed() {
+ // nodes(a,c) <- nodes(a,b), edges(b,c)
+ nodes_var.from_join(&nodes_var, &edges_var, |_b, &a, &c| (c,a));
+ }
+
+ // extract the final results.
+ let reachable: Vec<(u32,u32)> = variable.complete();
+}
+```
+
+If you'd like to read more about how it works, check out [this blog post](https://github.com/frankmcsherry/blog/blob/master/posts/2018-05-19.md).
+
+## Authorship
+
+Datafrog was initially developed by [Frank McSherry][fmc] and was
+later transferred to the rust-lang-nursery organization. Thanks Frank!
+
+[fmc]: https://github.com/frankmcsherry
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md
new file mode 100644
index 0000000..7d666f6
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/RELEASES.md
@@ -0,0 +1,26 @@
+# 2.0.1
+
+- Work around a rustdoc ICE (#24)
+
+# 2.0.0
+
+- Breaking changes:
+ - leapjoin now takes a tuple of leapers, and not a `&mut` slice:
+ - `from_leapjoin(&input, &mut [&mut foo.extend_with(...), ..], ..)` becomes
+ `from_leapjoin(&input, (foo.extend_with(...), ..), ..)`
+ - if there is only one leaper, no tuple is needed
+ - `Relation::from` now requires a vector, not an iterator; use
+ `Relation::from_iter` instead
+- Changed the API to permit using `Relation` and `Variable` more interchangeably,
+ and added a number of operations to construct relations directly, like `Relation::from_join`
+- Extended leapfrog triejoin with new operations (`PrefixFilter` and `ValueFilter`)
+
+# 1.0.0
+
+- Added leapfrog triejoin (#11).
+- Have badges and repo links now!
+- Minor performance improvements (#13).
+
+# 0.1.0
+
+- Initial release.
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs
new file mode 100644
index 0000000..8f2197a
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/borrow_check.rs
@@ -0,0 +1,115 @@
+extern crate datafrog;
+use datafrog::Iteration;
+
+type Region = u32;
+type Borrow = u32;
+type Point = u32;
+
+fn main() {
+ let subset = {
+ // Create a new iteration context, ...
+ let mut iteration1 = Iteration::new();
+
+ // .. some variables, ..
+ let subset = iteration1.variable::<(Region, Region, Point)>("subset");
+
+ // different indices for `subset`.
+ let subset_r1p = iteration1.variable::<((Region, Point), Region)>("subset_r1p");
+ let subset_r2p = iteration1.variable::<((Region, Point), Region)>("subset_r2p");
+ let subset_p = iteration1.variable::<(Point, (Region, Region))>("subset_p");
+
+ // temporaries as we perform a multi-way join.
+ let subset_1 = iteration1.variable::<((Region, Point), Region)>("subset_1");
+ let subset_2 = iteration1.variable::<((Region, Point), Region)>("subset_2");
+
+ let region_live_at = iteration1.variable::<((Region, Point), ())>("region_live_at");
+ let cfg_edge_p = iteration1.variable::<(Point, Point)>("cfg_edge_p");
+
+ // load initial facts.
+ subset.insert(Vec::new().into());
+ region_live_at.insert(Vec::new().into());
+ cfg_edge_p.insert(Vec::new().into());
+
+ // .. and then start iterating rules!
+ while iteration1.changed() {
+ // remap fields to re-index by keys.
+ subset_r1p.from_map(&subset, |&(r1, r2, p)| ((r1, p), r2));
+ subset_r2p.from_map(&subset, |&(r1, r2, p)| ((r2, p), r1));
+ subset_p.from_map(&subset, |&(r1, r2, p)| (p, (r1, r2)));
+
+ // R0: subset(R1, R2, P) :- outlives(R1, R2, P).
+ // Already loaded; outlives is static.
+
+ // R1: subset(R1, R3, P) :-
+ // subset(R1, R2, P),
+ // subset(R2, R3, P).
+ subset.from_join(&subset_r2p, &subset_r1p, |&(_r2, p), &r1, &r3| (r1, r3, p));
+
+ // R2: subset(R1, R2, Q) :-
+ // subset(R1, R2, P),
+ // cfg_edge(P, Q),
+ // region_live_at(R1, Q),
+ // region_live_at(R2, Q).
+
+ subset_1.from_join(&subset_p, &cfg_edge_p, |&_p, &(r1, r2), &q| ((r1, q), r2));
+ subset_2.from_join(&subset_1, &region_live_at, |&(r1, q), &r2, &()| {
+ ((r2, q), r1)
+ });
+ subset.from_join(&subset_2, &region_live_at, |&(r2, q), &r1, &()| (r1, r2, q));
+ }
+
+ subset_r1p.complete()
+ };
+
+ let _requires = {
+ // Create a new iteration context, ...
+ let mut iteration2 = Iteration::new();
+
+ // .. some variables, ..
+ let requires = iteration2.variable::<(Region, Borrow, Point)>("requires");
+ requires.insert(Vec::new().into());
+
+ let requires_rp = iteration2.variable::<((Region, Point), Borrow)>("requires_rp");
+ let requires_bp = iteration2.variable::<((Borrow, Point), Region)>("requires_bp");
+
+ let requires_1 = iteration2.variable::<(Point, (Borrow, Region))>("requires_1");
+ let requires_2 = iteration2.variable::<((Region, Point), Borrow)>("requires_2");
+
+ let subset_r1p = iteration2.variable::<((Region, Point), Region)>("subset_r1p");
+ subset_r1p.insert(subset);
+
+ let killed = Vec::new().into();
+ let region_live_at = iteration2.variable::<((Region, Point), ())>("region_live_at");
+ let cfg_edge_p = iteration2.variable::<(Point, Point)>("cfg_edge_p");
+
+ // .. and then start iterating rules!
+ while iteration2.changed() {
+ requires_rp.from_map(&requires, |&(r, b, p)| ((r, p), b));
+ requires_bp.from_map(&requires, |&(r, b, p)| ((b, p), r));
+
+ // requires(R, B, P) :- borrow_region(R, B, P).
+ // Already loaded; borrow_region is static.
+
+ // requires(R2, B, P) :-
+ // requires(R1, B, P),
+ // subset(R1, R2, P).
+ requires.from_join(&requires_rp, &subset_r1p, |&(_r1, p), &b, &r2| (r2, b, p));
+
+ // requires(R, B, Q) :-
+ // requires(R, B, P),
+ // !killed(B, P),
+ // cfg_edge(P, Q),
+ // (region_live_at(R, Q); universal_region(R)).
+
+ requires_1.from_antijoin(&requires_bp, &killed, |&(b, p), &r| (p, (b, r)));
+ requires_2.from_join(&requires_1, &cfg_edge_p, |&_p, &(b, r), &q| ((r, q), b));
+ requires.from_join(&requires_2, &region_live_at, |&(r, q), &b, &()| (r, b, q));
+ }
+
+ requires.complete()
+ };
+
+ // borrow_live_at(B, P) :- requires(R, B, P), region_live_at(R, P)
+
+ // borrow_live_at(B, P) :- requires(R, B, P), universal_region(R).
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs
new file mode 100644
index 0000000..31225b1
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/examples/graspan1.rs
@@ -0,0 +1,62 @@
+extern crate datafrog;
+use datafrog::Iteration;
+
+fn main() {
+ let timer = ::std::time::Instant::now();
+
+ // Make space for input data.
+ let mut nodes = Vec::new();
+ let mut edges = Vec::new();
+
+ // Read input data from a handy file.
+ use std::fs::File;
+ use std::io::{BufRead, BufReader};
+
+ let filename = std::env::args().nth(1).unwrap();
+ let file = BufReader::new(File::open(filename).unwrap());
+ for readline in file.lines() {
+ let line = readline.expect("read error");
+ if !line.is_empty() && !line.starts_with('#') {
+ let mut elts = line[..].split_whitespace();
+ let src: u32 = elts.next().unwrap().parse().expect("malformed src");
+ let dst: u32 = elts.next().unwrap().parse().expect("malformed dst");
+ let typ: &str = elts.next().unwrap();
+ match typ {
+ "n" => {
+ nodes.push((dst, src));
+ }
+ "e" => {
+ edges.push((src, dst));
+ }
+ unk => panic!("unknown type: {}", unk),
+ }
+ }
+ }
+
+ println!("{:?}\tData loaded", timer.elapsed());
+
+ // Create a new iteration context, ...
+ let mut iteration = Iteration::new();
+
+ // .. some variables, ..
+ let variable1 = iteration.variable::<(u32, u32)>("nodes");
+ let variable2 = iteration.variable::<(u32, u32)>("edges");
+
+ // .. load them with some initial values, ..
+ variable1.insert(nodes.into());
+ variable2.insert(edges.into());
+
+ // .. and then start iterating rules!
+ while iteration.changed() {
+ // N(a,c) <- N(a,b), E(b,c)
+ variable1.from_join(&variable1, &variable2, |_b, &a, &c| (c, a));
+ }
+
+ let reachable = variable1.complete();
+
+ println!(
+ "{:?}\tComputation complete (nodes_final: {})",
+ timer.elapsed(),
+ reachable.len()
+ );
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs
new file mode 100644
index 0000000..94270af
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/join.rs
@@ -0,0 +1,180 @@
+//! Join functionality.
+
+use super::{Relation, Variable};
+use std::cell::Ref;
+use std::ops::Deref;
+
+/// Implements `join`. Note that `input1` must be a variable, but
+/// `input2` can be either a variable or a relation. This is necessary
+/// because relations have no "recent" tuples, so the fn would be a
+/// guaranteed no-op if both arguments were relations. See also
+/// `join_into_relation`.
+pub(crate) fn join_into<'me, Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>(
+ input1: &Variable<(Key, Val1)>,
+ input2: impl JoinInput<'me, (Key, Val2)>,
+ output: &Variable<Result>,
+ mut logic: impl FnMut(&Key, &Val1, &Val2) -> Result,
+) {
+ let mut results = Vec::new();
+
+ let recent1 = input1.recent();
+ let recent2 = input2.recent();
+
+ {
+ // scoped to let `closure` drop borrow of `results`.
+
+ let mut closure = |k: &Key, v1: &Val1, v2: &Val2| results.push(logic(k, v1, v2));
+
+ for batch2 in input2.stable().iter() {
+ join_helper(&recent1, &batch2, &mut closure);
+ }
+
+ for batch1 in input1.stable().iter() {
+ join_helper(&batch1, &recent2, &mut closure);
+ }
+
+ join_helper(&recent1, &recent2, &mut closure);
+ }
+
+ output.insert(Relation::from_vec(results));
+}
+
+/// Join, but for two relations.
+pub(crate) fn join_into_relation<'me, Key: Ord, Val1: Ord, Val2: Ord, Result: Ord>(
+ input1: &Relation<(Key, Val1)>,
+ input2: &Relation<(Key, Val2)>,
+ mut logic: impl FnMut(&Key, &Val1, &Val2) -> Result,
+) -> Relation<Result> {
+ let mut results = Vec::new();
+
+ join_helper(&input1.elements, &input2.elements, |k, v1, v2| {
+ results.push(logic(k, v1, v2));
+ });
+
+ Relation::from_vec(results)
+}
+
+/// Moves all recent tuples from `input1` that are not present in `input2` into `output`.
+pub(crate) fn antijoin<'me, Key: Ord, Val: Ord, Result: Ord>(
+ input1: impl JoinInput<'me, (Key, Val)>,
+ input2: &Relation<Key>,
+ mut logic: impl FnMut(&Key, &Val) -> Result,
+) -> Relation<Result> {
+ let mut tuples2 = &input2[..];
+
+ let results = input1
+ .recent()
+ .iter()
+ .filter(|(ref key, _)| {
+ tuples2 = gallop(tuples2, |k| k < key);
+ tuples2.first() != Some(key)
+ })
+ .map(|(ref key, ref val)| logic(key, val))
+ .collect::<Vec<_>>();
+
+ Relation::from_vec(results)
+}
+
+fn join_helper<K: Ord, V1, V2>(
+ mut slice1: &[(K, V1)],
+ mut slice2: &[(K, V2)],
+ mut result: impl FnMut(&K, &V1, &V2),
+) {
+ while !slice1.is_empty() && !slice2.is_empty() {
+ use std::cmp::Ordering;
+
+ // If the keys match produce tuples, else advance the smaller key until they might.
+ match slice1[0].0.cmp(&slice2[0].0) {
+ Ordering::Less => {
+ slice1 = gallop(slice1, |x| x.0 < slice2[0].0);
+ }
+ Ordering::Equal => {
+ // Determine the number of matching keys in each slice.
+ let count1 = slice1.iter().take_while(|x| x.0 == slice1[0].0).count();
+ let count2 = slice2.iter().take_while(|x| x.0 == slice2[0].0).count();
+
+ // Produce results from the cross-product of matches.
+ for index1 in 0..count1 {
+ for s2 in slice2[..count2].iter() {
+ result(&slice1[0].0, &slice1[index1].1, &s2.1);
+ }
+ }
+
+ // Advance slices past this key.
+ slice1 = &slice1[count1..];
+ slice2 = &slice2[count2..];
+ }
+ Ordering::Greater => {
+ slice2 = gallop(slice2, |x| x.0 < slice1[0].0);
+ }
+ }
+ }
+}
+
+pub(crate) fn gallop<T>(mut slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> &[T] {
+ // if empty slice, or already >= element, return
+ if !slice.is_empty() && cmp(&slice[0]) {
+ let mut step = 1;
+ while step < slice.len() && cmp(&slice[step]) {
+ slice = &slice[step..];
+ step <<= 1;
+ }
+
+ step >>= 1;
+ while step > 0 {
+ if step < slice.len() && cmp(&slice[step]) {
+ slice = &slice[step..];
+ }
+ step >>= 1;
+ }
+
+ slice = &slice[1..]; // advance one, as we always stayed < value
+ }
+
+ slice
+}
+
+/// An input that can be used with `from_join`; either a `Variable` or a `Relation`.
+pub trait JoinInput<'me, Tuple: Ord>: Copy {
+ /// If we are on iteration N of the loop, these are the tuples
+ /// added on iteration N-1. (For a `Relation`, this is always an
+ /// empty slice.)
+ type RecentTuples: Deref<Target = [Tuple]>;
+
+ /// If we are on iteration N of the loop, these are the tuples
+ /// added on iteration N - 2 or before. (For a `Relation`, this is
+ /// just `self`.)
+ type StableTuples: Deref<Target = [Relation<Tuple>]>;
+
+ /// Get the set of recent tuples.
+ fn recent(self) -> Self::RecentTuples;
+
+ /// Get the set of stable tuples.
+ fn stable(self) -> Self::StableTuples;
+}
+
+impl<'me, Tuple: Ord> JoinInput<'me, Tuple> for &'me Variable<Tuple> {
+ type RecentTuples = Ref<'me, [Tuple]>;
+ type StableTuples = Ref<'me, [Relation<Tuple>]>;
+
+ fn recent(self) -> Self::RecentTuples {
+ Ref::map(self.recent.borrow(), |r| &r.elements[..])
+ }
+
+ fn stable(self) -> Self::StableTuples {
+ Ref::map(self.stable.borrow(), |v| &v[..])
+ }
+}
+
+impl<'me, Tuple: Ord> JoinInput<'me, Tuple> for &'me Relation<Tuple> {
+ type RecentTuples = &'me [Tuple];
+ type StableTuples = &'me [Relation<Tuple>];
+
+ fn recent(self) -> Self::RecentTuples {
+ &[]
+ }
+
+ fn stable(self) -> Self::StableTuples {
+ std::slice::from_ref(self)
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs
new file mode 100644
index 0000000..d2f9323
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/lib.rs
@@ -0,0 +1,567 @@
+//! A lightweight Datalog engine in Rust
+//!
+//! The intended design is that one has static `Relation` types that are sets
+//! of tuples, and `Variable` types that represent monotonically increasing
+//! sets of tuples.
+//!
+//! The types are mostly wrappers around `Vec<Tuple>` indicating sorted-ness,
+//! and the intent is that this code can be dropped in the middle of an otherwise
+//! normal Rust program, run to completion, and then the results extracted as
+//! vectors again.
+
+#![forbid(missing_docs)]
+
+use std::cell::RefCell;
+use std::cmp::Ordering;
+use std::iter::FromIterator;
+use std::rc::Rc;
+
+mod join;
+mod map;
+mod test;
+mod treefrog;
+pub use crate::join::JoinInput;
+pub use crate::treefrog::{
+ extend_anti::ExtendAnti,
+ extend_with::ExtendWith,
+ filter_anti::FilterAnti,
+ filter_with::FilterWith,
+ filters::{PrefixFilter, ValueFilter},
+ Leaper, Leapers, RelationLeaper,
+};
+
+/// A static, ordered list of key-value pairs.
+///
+/// A relation represents a fixed set of key-value pairs. In many places in a
+/// Datalog computation we want to be sure that certain relations are not able
+/// to vary (for example, in antijoins).
+#[derive(Clone)]
+pub struct Relation<Tuple: Ord> {
+ /// Sorted list of distinct tuples.
+ pub elements: Vec<Tuple>,
+}
+
+impl<Tuple: Ord> Relation<Tuple> {
+ /// Merges two relations into their union.
+ pub fn merge(self, other: Self) -> Self {
+ let Relation {
+ elements: mut elements1,
+ } = self;
+ let Relation {
+ elements: mut elements2,
+ } = other;
+
+ // If one of the element lists is zero-length, we don't need to do any work
+ if elements1.is_empty() {
+ return Relation {
+ elements: elements2,
+ };
+ }
+
+ if elements2.is_empty() {
+ return Relation {
+ elements: elements1,
+ };
+ }
+
+ // Make sure that elements1 starts with the lower element
+ // Will not panic since both collections must have at least 1 element at this point
+ if elements1[0] > elements2[0] {
+ std::mem::swap(&mut elements1, &mut elements2);
+ }
+
+ // Fast path for when all the new elements are after the exiting ones
+ if elements1[elements1.len() - 1] < elements2[0] {
+ elements1.extend(elements2.into_iter());
+ // println!("fast path");
+ return Relation {
+ elements: elements1,
+ };
+ }
+
+ let mut elements = Vec::with_capacity(elements1.len() + elements2.len());
+ let mut elements1 = elements1.drain(..);
+ let mut elements2 = elements2.drain(..).peekable();
+
+ elements.push(elements1.next().unwrap());
+ if elements.first() == elements2.peek() {
+ elements2.next();
+ }
+
+ for elem in elements1 {
+ while elements2.peek().map(|x| x.cmp(&elem)) == Some(Ordering::Less) {
+ elements.push(elements2.next().unwrap());
+ }
+ if elements2.peek().map(|x| x.cmp(&elem)) == Some(Ordering::Equal) {
+ elements2.next();
+ }
+ elements.push(elem);
+ }
+
+ // Finish draining second list
+ elements.extend(elements2);
+
+ Relation { elements }
+ }
+
+ /// Creates a `Relation` from the elements of the `iterator`.
+ ///
+ /// Same as the `from_iter` method from `std::iter::FromIterator` trait.
+ pub fn from_iter<I>(iterator: I) -> Self
+ where
+ I: IntoIterator<Item = Tuple>,
+ {
+ iterator.into_iter().collect()
+ }
+
+ /// Creates a `Relation` using the `leapjoin` logic;
+ /// see [`Variable::from_leapjoin`]
+ pub fn from_leapjoin<'leap, SourceTuple: Ord, Val: Ord + 'leap>(
+ source: &Relation<SourceTuple>,
+ leapers: impl Leapers<'leap, SourceTuple, Val>,
+ logic: impl FnMut(&SourceTuple, &Val) -> Tuple,
+ ) -> Self {
+ treefrog::leapjoin(&source.elements, leapers, logic)
+ }
+
+ /// Creates a `Relation` by joining the values from `input1` and
+ /// `input2` and then applying `logic`. Like
+ /// [`Variable::from_join`] except for use where the inputs are
+ /// not varying across iterations.
+ pub fn from_join<Key: Ord, Val1: Ord, Val2: Ord>(
+ input1: &Relation<(Key, Val1)>,
+ input2: &Relation<(Key, Val2)>,
+ logic: impl FnMut(&Key, &Val1, &Val2) -> Tuple,
+ ) -> Self {
+ join::join_into_relation(input1, input2, logic)
+ }
+
+ /// Creates a `Relation` by removing all values from `input1` that
+ /// share a key with `input2`, and then transforming the resulting
+ /// tuples with the `logic` closure. Like
+ /// [`Variable::from_antijoin`] except for use where the inputs
+ /// are not varying across iterations.
+ pub fn from_antijoin<Key: Ord, Val1: Ord>(
+ input1: &Relation<(Key, Val1)>,
+ input2: &Relation<Key>,
+ logic: impl FnMut(&Key, &Val1) -> Tuple,
+ ) -> Self {
+ join::antijoin(input1, input2, logic)
+ }
+
+ /// Construct a new relation by mapping another one. Equivalent to
+ /// creating an iterator but perhaps more convenient. Analogous to
+ /// `Variable::from_map`.
+ pub fn from_map<T2: Ord>(input: &Relation<T2>, logic: impl FnMut(&T2) -> Tuple) -> Self {
+ input.iter().map(logic).collect()
+ }
+
+ /// Creates a `Relation` from a vector of tuples.
+ pub fn from_vec(mut elements: Vec<Tuple>) -> Self {
+ elements.sort();
+ elements.dedup();
+ Relation { elements }
+ }
+}
+
+impl<Tuple: Ord> From<Vec<Tuple>> for Relation<Tuple> {
+ fn from(iterator: Vec<Tuple>) -> Self {
+ Self::from_vec(iterator)
+ }
+}
+
+impl<Tuple: Ord> FromIterator<Tuple> for Relation<Tuple> {
+ fn from_iter<I>(iterator: I) -> Self
+ where
+ I: IntoIterator<Item = Tuple>,
+ {
+ Relation::from_vec(iterator.into_iter().collect())
+ }
+}
+
+impl<'tuple, Tuple: 'tuple + Copy + Ord> FromIterator<&'tuple Tuple> for Relation<Tuple> {
+ fn from_iter<I>(iterator: I) -> Self
+ where
+ I: IntoIterator<Item = &'tuple Tuple>,
+ {
+ Relation::from_vec(iterator.into_iter().cloned().collect())
+ }
+}
+
+impl<Tuple: Ord> std::ops::Deref for Relation<Tuple> {
+ type Target = [Tuple];
+ fn deref(&self) -> &Self::Target {
+ &self.elements[..]
+ }
+}
+
+/// An iterative context for recursive evaluation.
+///
+/// An `Iteration` tracks monotonic variables, and monitors their progress.
+/// It can inform the user if they have ceased changing, at which point the
+/// computation should be done.
+pub struct Iteration {
+ variables: Vec<Box<dyn VariableTrait>>,
+}
+
+impl Iteration {
+ /// Create a new iterative context.
+ pub fn new() -> Self {
+ Iteration {
+ variables: Vec::new(),
+ }
+ }
+ /// Reports whether any of the monitored variables have changed since
+ /// the most recent call.
+ pub fn changed(&mut self) -> bool {
+ let mut result = false;
+ for variable in self.variables.iter_mut() {
+ if variable.changed() {
+ result = true;
+ }
+ }
+ result
+ }
+ /// Creates a new named variable associated with the iterative context.
+ pub fn variable<Tuple: Ord + 'static>(&mut self, name: &str) -> Variable<Tuple> {
+ let variable = Variable::new(name);
+ self.variables.push(Box::new(variable.clone()));
+ variable
+ }
+ /// Creates a new named variable associated with the iterative context.
+ ///
+ /// This variable will not be maintained distinctly, and may advertise tuples as
+ /// recent multiple times (perhaps unboundedly many times).
+ pub fn variable_indistinct<Tuple: Ord + 'static>(&mut self, name: &str) -> Variable<Tuple> {
+ let mut variable = Variable::new(name);
+ variable.distinct = false;
+ self.variables.push(Box::new(variable.clone()));
+ variable
+ }
+}
+
+/// A type that can report on whether it has changed.
+trait VariableTrait {
+ /// Reports whether the variable has changed since it was last asked.
+ fn changed(&mut self) -> bool;
+}
+
+/// An monotonically increasing set of `Tuple`s.
+///
+/// There are three stages in the lifecycle of a tuple:
+///
+/// 1. A tuple is added to `self.to_add`, but is not yet visible externally.
+/// 2. Newly added tuples are then promoted to `self.recent` for one iteration.
+/// 3. After one iteration, recent tuples are moved to `self.tuples` for posterity.
+///
+/// Each time `self.changed()` is called, the `recent` relation is folded into `tuples`,
+/// and the `to_add` relations are merged, potentially deduplicated against `tuples`, and
+/// then made `recent`. This way, across calls to `changed()` all added tuples are in
+/// `recent` at least once and eventually all are in `tuples`.
+///
+/// A `Variable` may optionally be instructed not to de-duplicate its tuples, for reasons
+/// of performance. Such a variable cannot be relied on to terminate iterative computation,
+/// and it is important that any cycle of derivations have at least one de-duplicating
+/// variable on it.
+pub struct Variable<Tuple: Ord> {
+ /// Should the variable be maintained distinctly.
+ distinct: bool,
+ /// A useful name for the variable.
+ name: String,
+ /// A list of relations whose union are the accepted tuples.
+ pub stable: Rc<RefCell<Vec<Relation<Tuple>>>>,
+ /// A list of recent tuples, still to be processed.
+ pub recent: Rc<RefCell<Relation<Tuple>>>,
+ /// A list of future tuples, to be introduced.
+ to_add: Rc<RefCell<Vec<Relation<Tuple>>>>,
+}
+
+// Operator implementations.
+impl<Tuple: Ord> Variable<Tuple> {
+ /// Adds tuples that result from joining `input1` and `input2` --
+ /// each of the inputs must be a set of (Key, Value) tuples. Both
+ /// `input1` and `input2` must have the same type of key (`K`) but
+ /// they can have distinct value types (`V1` and `V2`
+ /// respectively). The `logic` closure will be invoked for each
+ /// key that appears in both inputs; it is also given the two
+ /// values, and from those it should construct the resulting
+ /// value.
+ ///
+ /// Note that `input1` must be a variable, but `input2` can be a
+ /// relation or a variable. Therefore, you cannot join two
+ /// relations with this method. This is not because the result
+ /// would be wrong, but because it would be inefficient: the
+ /// result from such a join cannot vary across iterations (as
+ /// relations are fixed), so you should prefer to invoke `insert`
+ /// on a relation created by `Relation::from_join` instead.
+ ///
+ /// # Examples
+ ///
+ /// This example starts a collection with the pairs (x, x+1) and (x+1, x) for x in 0 .. 10.
+ /// It then adds pairs (y, z) for which (x, y) and (x, z) are present. Because the initial
+ /// pairs are symmetric, this should result in all pairs (x, y) for x and y in 0 .. 11.
+ ///
+ /// ```
+ /// use datafrog::{Iteration, Relation};
+ ///
+ /// let mut iteration = Iteration::new();
+ /// let variable = iteration.variable::<(usize, usize)>("source");
+ /// variable.extend((0 .. 10).map(|x| (x, x + 1)));
+ /// variable.extend((0 .. 10).map(|x| (x + 1, x)));
+ ///
+ /// while iteration.changed() {
+ /// variable.from_join(&variable, &variable, |&key, &val1, &val2| (val1, val2));
+ /// }
+ ///
+ /// let result = variable.complete();
+ /// assert_eq!(result.len(), 121);
+ /// ```
+ pub fn from_join<'me, K: Ord, V1: Ord, V2: Ord>(
+ &self,
+ input1: &'me Variable<(K, V1)>,
+ input2: impl JoinInput<'me, (K, V2)>,
+ logic: impl FnMut(&K, &V1, &V2) -> Tuple,
+ ) {
+ join::join_into(input1, input2, self, logic)
+ }
+
+ /// Adds tuples from `input1` whose key is not present in `input2`.
+ ///
+ /// Note that `input1` must be a variable: if you have a relation
+ /// instead, you can use `Relation::from_antijoin` and then
+ /// `Variable::insert`. Note that the result will not vary during
+ /// the iteration.
+ ///
+ /// # Examples
+ ///
+ /// This example starts a collection with the pairs (x, x+1) for x in 0 .. 10. It then
+ /// adds any pairs (x+1,x) for which x is not a multiple of three. That excludes four
+ /// pairs (for 0, 3, 6, and 9) which should leave us with 16 total pairs.
+ ///
+ /// ```
+ /// use datafrog::{Iteration, Relation};
+ ///
+ /// let mut iteration = Iteration::new();
+ /// let variable = iteration.variable::<(usize, usize)>("source");
+ /// variable.extend((0 .. 10).map(|x| (x, x + 1)));
+ ///
+ /// let relation: Relation<_> = (0 .. 10).filter(|x| x % 3 == 0).collect();
+ ///
+ /// while iteration.changed() {
+ /// variable.from_antijoin(&variable, &relation, |&key, &val| (val, key));
+ /// }
+ ///
+ /// let result = variable.complete();
+ /// assert_eq!(result.len(), 16);
+ /// ```
+ pub fn from_antijoin<K: Ord, V: Ord>(
+ &self,
+ input1: &Variable<(K, V)>,
+ input2: &Relation<K>,
+ logic: impl FnMut(&K, &V) -> Tuple,
+ ) {
+ self.insert(join::antijoin(input1, input2, logic))
+ }
+
+ /// Adds tuples that result from mapping `input`.
+ ///
+ /// # Examples
+ ///
+ /// This example starts a collection with the pairs (x, x) for x in 0 .. 10. It then
+ /// repeatedly adds any pairs (x, z) for (x, y) in the collection, where z is the Collatz
+ /// step for y: it is y/2 if y is even, and 3*y + 1 if y is odd. This produces all of the
+ /// pairs (x, y) where x visits y as part of its Collatz journey.
+ ///
+ /// ```
+ /// use datafrog::{Iteration, Relation};
+ ///
+ /// let mut iteration = Iteration::new();
+ /// let variable = iteration.variable::<(usize, usize)>("source");
+ /// variable.extend((0 .. 10).map(|x| (x, x)));
+ ///
+ /// while iteration.changed() {
+ /// variable.from_map(&variable, |&(key, val)|
+ /// if val % 2 == 0 {
+ /// (key, val/2)
+ /// }
+ /// else {
+ /// (key, 3*val + 1)
+ /// });
+ /// }
+ ///
+ /// let result = variable.complete();
+ /// assert_eq!(result.len(), 74);
+ /// ```
+ pub fn from_map<T2: Ord>(&self, input: &Variable<T2>, logic: impl FnMut(&T2) -> Tuple) {
+ map::map_into(input, self, logic)
+ }
+
+ /// Adds tuples that result from combining `source` with the
+ /// relations given in `leapers`. This operation is very flexible
+ /// and can be used to do a combination of joins and anti-joins.
+ /// The main limitation is that the things being combined must
+ /// consist of one dynamic variable (`source`) and then several
+ /// fixed relations (`leapers`).
+ ///
+ /// The idea is as follows:
+ ///
+ /// - You will be inserting new tuples that result from joining (and anti-joining)
+ /// some dynamic variable `source` of source tuples (`SourceTuple`)
+ /// with some set of values (of type `Val`).
+ /// - You provide these values by combining `source` with a set of leapers
+ /// `leapers`, each of which is derived from a fixed relation. The `leapers`
+ /// should be either a single leaper (of suitable type) or else a tuple of leapers.
+ /// You can create a leaper in one of two ways:
+ /// - Extension: In this case, you have a relation of type `(K, Val)` for some
+ /// type `K`. You provide a closure that maps from `SourceTuple` to the key
+ /// `K`. If you use `relation.extend_with`, then any `Val` values the
+ /// relation provides will be added to the set of values; if you use
+ /// `extend_anti`, then the `Val` values will be removed.
+ /// - Filtering: In this case, you have a relation of type `K` for some
+ /// type `K` and you provide a closure that maps from `SourceTuple` to
+ /// the key `K`. Filters don't provide values but they remove source
+ /// tuples.
+ /// - Finally, you get a callback `logic` that accepts each `(SourceTuple, Val)`
+ /// that was successfully joined (and not filtered) and which maps to the
+ /// type of this variable.
+ pub fn from_leapjoin<'leap, SourceTuple: Ord, Val: Ord + 'leap>(
+ &self,
+ source: &Variable<SourceTuple>,
+ leapers: impl Leapers<'leap, SourceTuple, Val>,
+ logic: impl FnMut(&SourceTuple, &Val) -> Tuple,
+ ) {
+ self.insert(treefrog::leapjoin(&source.recent.borrow(), leapers, logic));
+ }
+}
+
+impl<Tuple: Ord> Clone for Variable<Tuple> {
+ fn clone(&self) -> Self {
+ Variable {
+ distinct: self.distinct,
+ name: self.name.clone(),
+ stable: self.stable.clone(),
+ recent: self.recent.clone(),
+ to_add: self.to_add.clone(),
+ }
+ }
+}
+
+impl<Tuple: Ord> Variable<Tuple> {
+ fn new(name: &str) -> Self {
+ Variable {
+ distinct: true,
+ name: name.to_string(),
+ stable: Rc::new(RefCell::new(Vec::new())),
+ recent: Rc::new(RefCell::new(Vec::new().into())),
+ to_add: Rc::new(RefCell::new(Vec::new())),
+ }
+ }
+
+ /// Inserts a relation into the variable.
+ ///
+ /// This is most commonly used to load initial values into a variable.
+ /// it is not obvious that it should be commonly used otherwise, but
+ /// it should not be harmful.
+ pub fn insert(&self, relation: Relation<Tuple>) {
+ if !relation.is_empty() {
+ self.to_add.borrow_mut().push(relation);
+ }
+ }
+
+ /// Extend the variable with values from the iterator.
+ ///
+ /// This is most commonly used to load initial values into a variable.
+ /// it is not obvious that it should be commonly used otherwise, but
+ /// it should not be harmful.
+ pub fn extend<T>(&self, iterator: impl IntoIterator<Item = T>)
+ where
+ Relation<Tuple>: FromIterator<T>,
+ {
+ self.insert(iterator.into_iter().collect());
+ }
+
+ /// Consumes the variable and returns a relation.
+ ///
+ /// This method removes the ability for the variable to develop, and
+ /// flattens all internal tuples down to one relation. The method
+ /// asserts that iteration has completed, in that `self.recent` and
+ /// `self.to_add` should both be empty.
+ pub fn complete(self) -> Relation<Tuple> {
+ assert!(self.recent.borrow().is_empty());
+ assert!(self.to_add.borrow().is_empty());
+ let mut result: Relation<Tuple> = Vec::new().into();
+ while let Some(batch) = self.stable.borrow_mut().pop() {
+ result = result.merge(batch);
+ }
+ result
+ }
+}
+
+impl<Tuple: Ord> VariableTrait for Variable<Tuple> {
+ fn changed(&mut self) -> bool {
+ // 1. Merge self.recent into self.stable.
+ if !self.recent.borrow().is_empty() {
+ let mut recent =
+ ::std::mem::replace(&mut (*self.recent.borrow_mut()), Vec::new().into());
+ while self
+ .stable
+ .borrow()
+ .last()
+ .map(|x| x.len() <= 2 * recent.len())
+ == Some(true)
+ {
+ let last = self.stable.borrow_mut().pop().unwrap();
+ recent = recent.merge(last);
+ }
+ self.stable.borrow_mut().push(recent);
+ }
+
+ // 2. Move self.to_add into self.recent.
+ let to_add = self.to_add.borrow_mut().pop();
+ if let Some(mut to_add) = to_add {
+ while let Some(to_add_more) = self.to_add.borrow_mut().pop() {
+ to_add = to_add.merge(to_add_more);
+ }
+ // 2b. Restrict `to_add` to tuples not in `self.stable`.
+ if self.distinct {
+ for batch in self.stable.borrow().iter() {
+ let mut slice = &batch[..];
+ // Only gallop if the slice is relatively large.
+ if slice.len() > 4 * to_add.elements.len() {
+ to_add.elements.retain(|x| {
+ slice = join::gallop(slice, |y| y < x);
+ slice.is_empty() || &slice[0] != x
+ });
+ } else {
+ to_add.elements.retain(|x| {
+ while !slice.is_empty() && &slice[0] < x {
+ slice = &slice[1..];
+ }
+ slice.is_empty() || &slice[0] != x
+ });
+ }
+ }
+ }
+ *self.recent.borrow_mut() = to_add;
+ }
+
+ // let mut total = 0;
+ // for tuple in self.stable.borrow().iter() {
+ // total += tuple.len();
+ // }
+
+ // println!("Variable\t{}\t{}\t{}", self.name, total, self.recent.borrow().len());
+
+ !self.recent.borrow().is_empty()
+ }
+}
+
+// impl<Tuple: Ord> Drop for Variable<Tuple> {
+// fn drop(&mut self) {
+// let mut total = 0;
+// for batch in self.stable.borrow().iter() {
+// total += batch.len();
+// }
+// println!("FINAL: {:?}\t{:?}", self.name, total);
+// }
+// }
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs
new file mode 100644
index 0000000..1a8c101
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/map.rs
@@ -0,0 +1,13 @@
+//! Map functionality.
+
+use super::{Relation, Variable};
+
+pub(crate) fn map_into<T1: Ord, T2: Ord>(
+ input: &Variable<T1>,
+ output: &Variable<T2>,
+ logic: impl FnMut(&T1) -> T2,
+) {
+ let results: Vec<T2> = input.recent.borrow().iter().map(logic).collect();
+
+ output.insert(Relation::from_vec(results));
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs
new file mode 100644
index 0000000..9d5af35
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/test.rs
@@ -0,0 +1,195 @@
+#![cfg(test)]
+
+use crate::Iteration;
+use crate::Relation;
+use crate::RelationLeaper;
+use proptest::prelude::*;
+use proptest::{proptest, proptest_helper};
+
+fn inputs() -> impl Strategy<Value = Vec<(u32, u32)>> {
+ prop::collection::vec((0_u32..100, 0_u32..100), 1..500)
+}
+
+/// The original way to use datafrog -- computes reachable nodes from a set of edges
+fn reachable_with_var_join(edges: &[(u32, u32)]) -> Relation<(u32, u32)> {
+ let edges: Relation<_> = edges.iter().collect();
+ let mut iteration = Iteration::new();
+
+ let edges_by_successor = iteration.variable::<(u32, u32)>("edges_invert");
+ edges_by_successor.extend(edges.iter().map(|&(n1, n2)| (n2, n1)));
+
+ let reachable = iteration.variable::<(u32, u32)>("reachable");
+ reachable.insert(edges);
+
+ while iteration.changed() {
+ // reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3).
+ reachable.from_join(&reachable, &edges_by_successor, |&_, &n3, &n1| (n1, n3));
+ }
+
+ reachable.complete()
+}
+
+/// Like `reachable`, but using a relation as an input to `from_join`
+fn reachable_with_relation_join(edges: &[(u32, u32)]) -> Relation<(u32, u32)> {
+ let edges: Relation<_> = edges.iter().collect();
+ let mut iteration = Iteration::new();
+
+ // NB. Changed from `reachable_with_var_join`:
+ let edges_by_successor: Relation<_> = edges.iter().map(|&(n1, n2)| (n2, n1)).collect();
+
+ let reachable = iteration.variable::<(u32, u32)>("reachable");
+ reachable.insert(edges);
+
+ while iteration.changed() {
+ // reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3).
+ reachable.from_join(&reachable, &edges_by_successor, |&_, &n3, &n1| (n1, n3));
+ }
+
+ reachable.complete()
+}
+
+fn reachable_with_leapfrog(edges: &[(u32, u32)]) -> Relation<(u32, u32)> {
+ let edges: Relation<_> = edges.iter().collect();
+ let mut iteration = Iteration::new();
+
+ let edges_by_successor: Relation<_> = edges.iter().map(|&(n1, n2)| (n2, n1)).collect();
+
+ let reachable = iteration.variable::<(u32, u32)>("reachable");
+ reachable.insert(edges);
+
+ while iteration.changed() {
+ // reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3).
+ reachable.from_leapjoin(
+ &reachable,
+ edges_by_successor.extend_with(|&(n2, _)| n2),
+ |&(_, n3), &n1| (n1, n3),
+ );
+ }
+
+ reachable.complete()
+}
+
+/// Computes a join where the values are summed -- uses iteration
+/// variables (the original datafrog technique).
+fn sum_join_via_var(
+ input1_slice: &[(u32, u32)],
+ input2_slice: &[(u32, u32)],
+) -> Relation<(u32, u32)> {
+ let mut iteration = Iteration::new();
+
+ let input1 = iteration.variable::<(u32, u32)>("input1");
+ input1.extend(input1_slice);
+
+ let input2 = iteration.variable::<(u32, u32)>("input1");
+ input2.extend(input2_slice);
+
+ let output = iteration.variable::<(u32, u32)>("output");
+
+ while iteration.changed() {
+ // output(K1, V1 * 100 + V2) :- input1(K1, V1), input2(K1, V2).
+ output.from_join(&input1, &input2, |&k1, &v1, &v2| (k1, v1 * 100 + v2));
+ }
+
+ output.complete()
+}
+
+/// Computes a join where the values are summed -- uses iteration
+/// variables (the original datafrog technique).
+fn sum_join_via_relation(
+ input1_slice: &[(u32, u32)],
+ input2_slice: &[(u32, u32)],
+) -> Relation<(u32, u32)> {
+ let input1: Relation<_> = input1_slice.iter().collect();
+ let input2: Relation<_> = input2_slice.iter().collect();
+ Relation::from_join(&input1, &input2, |&k1, &v1, &v2| (k1, v1 * 100 + v2))
+}
+
+proptest! {
+ #[test]
+ fn reachable_leapfrog_vs_var_join(edges in inputs()) {
+ let reachable1 = reachable_with_var_join(&edges);
+ let reachable2 = reachable_with_leapfrog(&edges);
+ assert_eq!(reachable1.elements, reachable2.elements);
+ }
+
+ #[test]
+ fn reachable_rel_join_vs_var_join(edges in inputs()) {
+ let reachable1 = reachable_with_var_join(&edges);
+ let reachable2 = reachable_with_relation_join(&edges);
+ assert_eq!(reachable1.elements, reachable2.elements);
+ }
+
+ #[test]
+ fn sum_join_from_var_vs_rel((set1, set2) in (inputs(), inputs())) {
+ let output1 = sum_join_via_var(&set1, &set2);
+ let output2 = sum_join_via_relation(&set1, &set2);
+ assert_eq!(output1.elements, output2.elements);
+ }
+
+ /// Test the behavior of `filter_anti` used on its own in a
+ /// leapjoin -- effectively it becomes an "intersection"
+ /// operation.
+ #[test]
+ fn filter_with_on_its_own((set1, set2) in (inputs(), inputs())) {
+ let input1: Relation<(u32, u32)> = set1.iter().collect();
+ let input2: Relation<(u32, u32)> = set2.iter().collect();
+ let intersection1 = Relation::from_leapjoin(
+ &input1,
+ input2.filter_with(|&tuple| tuple),
+ |&tuple, &()| tuple,
+ );
+
+ let intersection2: Relation<(u32, u32)> = input1.elements.iter()
+ .filter(|t| input2.elements.binary_search(&t).is_ok())
+ .collect();
+
+ assert_eq!(intersection1.elements, intersection2.elements);
+ }
+
+ /// Test the behavior of `filter_anti` used on its own in a
+ /// leapjoin -- effectively it becomes a "set minus" operation.
+ #[test]
+ fn filter_anti_on_its_own((set1, set2) in (inputs(), inputs())) {
+ let input1: Relation<(u32, u32)> = set1.iter().collect();
+ let input2: Relation<(u32, u32)> = set2.iter().collect();
+
+ let difference1 = Relation::from_leapjoin(
+ &input1,
+ input2.filter_anti(|&tuple| tuple),
+ |&tuple, &()| tuple,
+ );
+
+ let difference2: Relation<(u32, u32)> = input1.elements.iter()
+ .filter(|t| input2.elements.binary_search(&t).is_err())
+ .collect();
+
+ assert_eq!(difference1.elements, difference2.elements);
+ }
+}
+
+/// Test that `from_leapjoin` matches against the tuples from an
+/// `extend` that precedes first iteration.
+///
+/// This was always true, but wasn't immediately obvious to me until I
+/// re-read the code more carefully. -nikomatsakis
+#[test]
+fn leapjoin_from_extend() {
+ let doubles: Relation<(u32, u32)> = (0..10).map(|i| (i, i * 2)).collect();
+
+ let mut iteration = Iteration::new();
+
+ let variable = iteration.variable::<(u32, u32)>("variable");
+ variable.extend(Some((2, 2)));
+
+ while iteration.changed() {
+ variable.from_leapjoin(
+ &variable,
+ doubles.extend_with(|&(i, _)| i),
+ |&(i, _), &j| (i, j),
+ );
+ }
+
+ let variable = variable.complete();
+
+ assert_eq!(variable.elements, vec![(2, 2), (2, 4)]);
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs
new file mode 100644
index 0000000..2ad238f
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/datafrog/src/treefrog.rs
@@ -0,0 +1,661 @@
+//! Join functionality.
+
+use super::Relation;
+
+/// Performs treefrog leapjoin using a list of leapers.
+pub(crate) fn leapjoin<'leap, Tuple: Ord, Val: Ord + 'leap, Result: Ord>(
+ source: &[Tuple],
+ mut leapers: impl Leapers<'leap, Tuple, Val>,
+ mut logic: impl FnMut(&Tuple, &Val) -> Result,
+) -> Relation<Result> {
+ let mut result = Vec::new(); // temp output storage.
+ let mut values = Vec::new(); // temp value storage.
+
+ for tuple in source {
+ // Determine which leaper would propose the fewest values.
+ let mut min_index = usize::max_value();
+ let mut min_count = usize::max_value();
+ leapers.for_each_count(tuple, |index, count| {
+ if min_count > count {
+ min_count = count;
+ min_index = index;
+ }
+ });
+
+ // We had best have at least one relation restricting values.
+ assert!(min_count < usize::max_value());
+
+ // If there are values to propose:
+ if min_count > 0 {
+ // Push the values that `min_index` "proposes" into `values`.
+ leapers.propose(tuple, min_index, &mut values);
+
+ // Give other leapers a chance to remove values from
+ // anti-joins or filters.
+ leapers.intersect(tuple, min_index, &mut values);
+
+ // Push remaining items into result.
+ for val in values.drain(..) {
+ result.push(logic(tuple, val));
+ }
+ }
+ }
+
+ Relation::from_vec(result)
+}
+
+/// Implemented for a tuple of leapers
+pub trait Leapers<'leap, Tuple, Val> {
+ /// Internal method:
+ fn for_each_count(&mut self, tuple: &Tuple, op: impl FnMut(usize, usize));
+
+ /// Internal method:
+ fn propose(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>);
+
+ /// Internal method:
+ fn intersect(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>);
+}
+
+macro_rules! tuple_leapers {
+ ($($Ty:ident)*) => {
+ #[allow(unused_assignments, non_snake_case)]
+ impl<'leap, Tuple, Val, $($Ty),*> Leapers<'leap, Tuple, Val> for ($($Ty,)*)
+ where
+ $($Ty: Leaper<'leap, Tuple, Val>,)*
+ {
+ fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) {
+ let ($($Ty,)*) = self;
+ let mut index = 0;
+ $(
+ let count = $Ty.count(tuple);
+ op(index, count);
+ index += 1;
+ )*
+ }
+
+ fn propose(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>) {
+ let ($($Ty,)*) = self;
+ let mut index = 0;
+ $(
+ if min_index == index {
+ return $Ty.propose(tuple, values);
+ }
+ index += 1;
+ )*
+ panic!("no match found for min_index={}", min_index);
+ }
+
+ fn intersect(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>) {
+ let ($($Ty,)*) = self;
+ let mut index = 0;
+ $(
+ if min_index != index {
+ $Ty.intersect(tuple, values);
+ }
+ index += 1;
+ )*
+ }
+ }
+ }
+}
+
+tuple_leapers!(A B);
+tuple_leapers!(A B C);
+tuple_leapers!(A B C D);
+tuple_leapers!(A B C D E);
+tuple_leapers!(A B C D E F);
+tuple_leapers!(A B C D E F G);
+
+/// Methods to support treefrog leapjoin.
+pub trait Leaper<'leap, Tuple, Val> {
+ /// Estimates the number of proposed values.
+ fn count(&mut self, prefix: &Tuple) -> usize;
+ /// Populates `values` with proposed values.
+ fn propose(&mut self, prefix: &Tuple, values: &mut Vec<&'leap Val>);
+ /// Restricts `values` to proposed values.
+ fn intersect(&mut self, prefix: &Tuple, values: &mut Vec<&'leap Val>);
+}
+
+pub(crate) mod filters {
+ use super::Leaper;
+ use super::Leapers;
+
+ /// A treefrog leaper that tests each of the tuples from the main
+ /// input (the "prefix"). Use like `PrefixFilter::from(|tuple|
+ /// ...)`; if the closure returns true, then the tuple is
+ /// retained, else it will be ignored. This leaper can be used in
+ /// isolation in which case it just acts like a filter on the
+ /// input (the "proposed value" will be `()` type).
+ pub struct PrefixFilter<Tuple, Func: Fn(&Tuple) -> bool> {
+ phantom: ::std::marker::PhantomData<Tuple>,
+ predicate: Func,
+ }
+
+ impl<'leap, Tuple, Func> PrefixFilter<Tuple, Func>
+ where
+ Func: Fn(&Tuple) -> bool,
+ {
+ /// Creates a new filter based on the prefix
+ pub fn from(predicate: Func) -> Self {
+ PrefixFilter {
+ phantom: ::std::marker::PhantomData,
+ predicate,
+ }
+ }
+ }
+
+ impl<'leap, Tuple, Val, Func> Leaper<'leap, Tuple, Val> for PrefixFilter<Tuple, Func>
+ where
+ Func: Fn(&Tuple) -> bool,
+ {
+ /// Estimates the number of proposed values.
+ fn count(&mut self, prefix: &Tuple) -> usize {
+ if (self.predicate)(prefix) {
+ usize::max_value()
+ } else {
+ 0
+ }
+ }
+ /// Populates `values` with proposed values.
+ fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val>) {
+ panic!("PrefixFilter::propose(): variable apparently unbound");
+ }
+ /// Restricts `values` to proposed values.
+ fn intersect(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val>) {
+ // We can only be here if we returned max_value() above.
+ }
+ }
+
+ impl<'leap, Tuple, Func> Leapers<'leap, Tuple, ()> for PrefixFilter<Tuple, Func>
+ where
+ Func: Fn(&Tuple) -> bool,
+ {
+ fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) {
+ if <Self as Leaper<'_, Tuple, ()>>::count(self, tuple) == 0 {
+ op(0, 0)
+ } else {
+ // we will "propose" the `()` value if the predicate applies
+ op(0, 1)
+ }
+ }
+
+ fn propose(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) {
+ assert_eq!(min_index, 0);
+ values.push(&());
+ }
+
+ fn intersect(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) {
+ assert_eq!(min_index, 0);
+ assert_eq!(values.len(), 1);
+ }
+ }
+
+ /// A treefrog leaper based on a predicate of prefix and value.
+ /// Use like `ValueFilter::from(|tuple, value| ...)`. The closure
+ /// should return true if `value` ought to be retained. The
+ /// `value` will be a value proposed elsewhere by an `extend_with`
+ /// leaper.
+ ///
+ /// This leaper cannot be used in isolation, it must be combined
+ /// with other leapers.
+ pub struct ValueFilter<Tuple, Val, Func: Fn(&Tuple, &Val) -> bool> {
+ phantom: ::std::marker::PhantomData<(Tuple, Val)>,
+ predicate: Func,
+ }
+
+ impl<'leap, Tuple, Val, Func> ValueFilter<Tuple, Val, Func>
+ where
+ Func: Fn(&Tuple, &Val) -> bool,
+ {
+ /// Creates a new filter based on the prefix
+ pub fn from(predicate: Func) -> Self {
+ ValueFilter {
+ phantom: ::std::marker::PhantomData,
+ predicate,
+ }
+ }
+ }
+
+ impl<'leap, Tuple, Val, Func> Leaper<'leap, Tuple, Val> for ValueFilter<Tuple, Val, Func>
+ where
+ Func: Fn(&Tuple, &Val) -> bool,
+ {
+ /// Estimates the number of proposed values.
+ fn count(&mut self, _prefix: &Tuple) -> usize {
+ usize::max_value()
+ }
+ /// Populates `values` with proposed values.
+ fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val>) {
+ panic!("PrefixFilter::propose(): variable apparently unbound");
+ }
+ /// Restricts `values` to proposed values.
+ fn intersect(&mut self, prefix: &Tuple, values: &mut Vec<&'leap Val>) {
+ values.retain(|val| (self.predicate)(prefix, val));
+ }
+ }
+
+}
+
+/// Extension method for relations.
+pub trait RelationLeaper<Key: Ord, Val: Ord> {
+ /// Extend with `Val` using the elements of the relation.
+ fn extend_with<'leap, Tuple: Ord, Func: Fn(&Tuple) -> Key>(
+ &'leap self,
+ key_func: Func,
+ ) -> extend_with::ExtendWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: 'leap,
+ Val: 'leap;
+ /// Extend with `Val` using the complement of the relation.
+ fn extend_anti<'leap, Tuple: Ord, Func: Fn(&Tuple) -> Key>(
+ &'leap self,
+ key_func: Func,
+ ) -> extend_anti::ExtendAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: 'leap,
+ Val: 'leap;
+ /// Extend with any value if tuple is present in relation.
+ fn filter_with<'leap, Tuple: Ord, Func: Fn(&Tuple) -> (Key, Val)>(
+ &'leap self,
+ key_func: Func,
+ ) -> filter_with::FilterWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: 'leap,
+ Val: 'leap;
+ /// Extend with any value if tuple is absent from relation.
+ fn filter_anti<'leap, Tuple: Ord, Func: Fn(&Tuple) -> (Key, Val)>(
+ &'leap self,
+ key_func: Func,
+ ) -> filter_anti::FilterAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: 'leap,
+ Val: 'leap;
+}
+
+impl<Key: Ord, Val: Ord> RelationLeaper<Key, Val> for Relation<(Key, Val)> {
+ fn extend_with<'leap, Tuple: Ord, Func: Fn(&Tuple) -> Key>(
+ &'leap self,
+ key_func: Func,
+ ) -> extend_with::ExtendWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: 'leap,
+ Val: 'leap,
+ {
+ extend_with::ExtendWith::from(self, key_func)
+ }
+ fn extend_anti<'leap, Tuple: Ord, Func: Fn(&Tuple) -> Key>(
+ &'leap self,
+ key_func: Func,
+ ) -> extend_anti::ExtendAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: 'leap,
+ Val: 'leap,
+ {
+ extend_anti::ExtendAnti::from(self, key_func)
+ }
+ fn filter_with<'leap, Tuple: Ord, Func: Fn(&Tuple) -> (Key, Val)>(
+ &'leap self,
+ key_func: Func,
+ ) -> filter_with::FilterWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: 'leap,
+ Val: 'leap,
+ {
+ filter_with::FilterWith::from(self, key_func)
+ }
+ fn filter_anti<'leap, Tuple: Ord, Func: Fn(&Tuple) -> (Key, Val)>(
+ &'leap self,
+ key_func: Func,
+ ) -> filter_anti::FilterAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: 'leap,
+ Val: 'leap,
+ {
+ filter_anti::FilterAnti::from(self, key_func)
+ }
+}
+
+pub(crate) mod extend_with {
+ use super::{binary_search, Leaper, Leapers, Relation};
+ use crate::join::gallop;
+
+ /// Wraps a Relation<Tuple> as a leaper.
+ pub struct ExtendWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> Key,
+ {
+ relation: &'leap Relation<(Key, Val)>,
+ start: usize,
+ end: usize,
+ key_func: Func,
+ phantom: ::std::marker::PhantomData<Tuple>,
+ }
+
+ impl<'leap, Key, Val, Tuple, Func> ExtendWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> Key,
+ {
+ /// Constructs a ExtendWith from a relation and key and value function.
+ pub fn from(relation: &'leap Relation<(Key, Val)>, key_func: Func) -> Self {
+ ExtendWith {
+ relation,
+ start: 0,
+ end: 0,
+ key_func,
+ phantom: ::std::marker::PhantomData,
+ }
+ }
+ }
+
+ impl<'leap, Key, Val, Tuple, Func> Leaper<'leap, Tuple, Val>
+ for ExtendWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> Key,
+ {
+ fn count(&mut self, prefix: &Tuple) -> usize {
+ let key = (self.key_func)(prefix);
+ self.start = binary_search(&self.relation[..], |x| &x.0 < &key);
+ let slice1 = &self.relation[self.start..];
+ let slice2 = gallop(slice1, |x| &x.0 <= &key);
+ self.end = self.relation.len() - slice2.len();
+ slice1.len() - slice2.len()
+ }
+ fn propose(&mut self, _prefix: &Tuple, values: &mut Vec<&'leap Val>) {
+ let slice = &self.relation[self.start..self.end];
+ values.extend(slice.iter().map(|&(_, ref val)| val));
+ }
+ fn intersect(&mut self, _prefix: &Tuple, values: &mut Vec<&'leap Val>) {
+ let mut slice = &self.relation[self.start..self.end];
+ values.retain(|v| {
+ slice = gallop(slice, |kv| &kv.1 < v);
+ slice.get(0).map(|kv| &kv.1) == Some(v)
+ });
+ }
+ }
+
+ impl<'leap, Key, Val, Tuple, Func> Leapers<'leap, Tuple, Val>
+ for ExtendWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> Key,
+ {
+ fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) {
+ op(0, self.count(tuple))
+ }
+
+ fn propose(&mut self, tuple: &Tuple, min_index: usize, values: &mut Vec<&'leap Val>) {
+ assert_eq!(min_index, 0);
+ Leaper::propose(self, tuple, values);
+ }
+
+ fn intersect(&mut self, _: &Tuple, min_index: usize, _: &mut Vec<&'leap Val>) {
+ assert_eq!(min_index, 0);
+ }
+ }
+}
+
+pub(crate) mod extend_anti {
+ use super::{binary_search, Leaper, Relation};
+ use crate::join::gallop;
+
+ /// Wraps a Relation<Tuple> as a leaper.
+ pub struct ExtendAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> Key,
+ {
+ relation: &'leap Relation<(Key, Val)>,
+ key_func: Func,
+ phantom: ::std::marker::PhantomData<Tuple>,
+ }
+
+ impl<'leap, Key, Val, Tuple, Func> ExtendAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> Key,
+ {
+ /// Constructs a ExtendAnti from a relation and key and value function.
+ pub fn from(relation: &'leap Relation<(Key, Val)>, key_func: Func) -> Self {
+ ExtendAnti {
+ relation,
+ key_func,
+ phantom: ::std::marker::PhantomData,
+ }
+ }
+ }
+
+ impl<'leap, Key: Ord, Val: Ord + 'leap, Tuple: Ord, Func> Leaper<'leap, Tuple, Val>
+ for ExtendAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> Key,
+ {
+ fn count(&mut self, _prefix: &Tuple) -> usize {
+ usize::max_value()
+ }
+ fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val>) {
+ panic!("ExtendAnti::propose(): variable apparently unbound.");
+ }
+ fn intersect(&mut self, prefix: &Tuple, values: &mut Vec<&'leap Val>) {
+ let key = (self.key_func)(prefix);
+ let start = binary_search(&self.relation[..], |x| &x.0 < &key);
+ let slice1 = &self.relation[start..];
+ let slice2 = gallop(slice1, |x| &x.0 <= &key);
+ let mut slice = &slice1[..(slice1.len() - slice2.len())];
+ if !slice.is_empty() {
+ values.retain(|v| {
+ slice = gallop(slice, |kv| &kv.1 < v);
+ slice.get(0).map(|kv| &kv.1) != Some(v)
+ });
+ }
+ }
+ }
+}
+
+pub(crate) mod filter_with {
+
+ use super::{Leaper, Leapers, Relation};
+
+ /// Wraps a Relation<Tuple> as a leaper.
+ pub struct FilterWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> (Key, Val),
+ {
+ relation: &'leap Relation<(Key, Val)>,
+ key_func: Func,
+ phantom: ::std::marker::PhantomData<Tuple>,
+ }
+
+ impl<'leap, Key, Val, Tuple, Func> FilterWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> (Key, Val),
+ {
+ /// Constructs a FilterWith from a relation and key and value function.
+ pub fn from(relation: &'leap Relation<(Key, Val)>, key_func: Func) -> Self {
+ FilterWith {
+ relation,
+ key_func,
+ phantom: ::std::marker::PhantomData,
+ }
+ }
+ }
+
+ impl<'leap, Key, Val, Val2, Tuple, Func> Leaper<'leap, Tuple, Val2>
+ for FilterWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> (Key, Val),
+ {
+ fn count(&mut self, prefix: &Tuple) -> usize {
+ let key_val = (self.key_func)(prefix);
+ if self.relation.binary_search(&key_val).is_ok() {
+ usize::max_value()
+ } else {
+ 0
+ }
+ }
+ fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val2>) {
+ panic!("FilterWith::propose(): variable apparently unbound.");
+ }
+ fn intersect(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val2>) {
+ // Only here because we didn't return zero above, right?
+ }
+ }
+
+ impl<'leap, Key, Val, Tuple, Func> Leapers<'leap, Tuple, ()>
+ for FilterWith<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> (Key, Val),
+ {
+ fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) {
+ if <Self as Leaper<Tuple, ()>>::count(self, tuple) == 0 {
+ op(0, 0)
+ } else {
+ op(0, 1)
+ }
+ }
+
+ fn propose(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) {
+ assert_eq!(min_index, 0);
+ values.push(&());
+ }
+
+ fn intersect(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) {
+ assert_eq!(min_index, 0);
+ assert_eq!(values.len(), 1);
+ }
+ }
+}
+
+pub(crate) mod filter_anti {
+
+ use super::{Leaper, Leapers, Relation};
+
+ /// Wraps a Relation<Tuple> as a leaper.
+ pub struct FilterAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> (Key, Val),
+ {
+ relation: &'leap Relation<(Key, Val)>,
+ key_func: Func,
+ phantom: ::std::marker::PhantomData<Tuple>,
+ }
+
+ impl<'leap, Key, Val, Tuple, Func> FilterAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> (Key, Val),
+ {
+ /// Constructs a FilterAnti from a relation and key and value function.
+ pub fn from(relation: &'leap Relation<(Key, Val)>, key_func: Func) -> Self {
+ FilterAnti {
+ relation,
+ key_func,
+ phantom: ::std::marker::PhantomData,
+ }
+ }
+ }
+
+ impl<'leap, Key: Ord, Val: Ord + 'leap, Val2, Tuple: Ord, Func> Leaper<'leap, Tuple, Val2>
+ for FilterAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> (Key, Val),
+ {
+ fn count(&mut self, prefix: &Tuple) -> usize {
+ let key_val = (self.key_func)(prefix);
+ if self.relation.binary_search(&key_val).is_ok() {
+ 0
+ } else {
+ usize::max_value()
+ }
+ }
+ fn propose(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val2>) {
+ panic!("FilterAnti::propose(): variable apparently unbound.");
+ }
+ fn intersect(&mut self, _prefix: &Tuple, _values: &mut Vec<&'leap Val2>) {
+ // Only here because we didn't return zero above, right?
+ }
+ }
+
+ impl<'leap, Key, Val, Tuple, Func> Leapers<'leap, Tuple, ()>
+ for FilterAnti<'leap, Key, Val, Tuple, Func>
+ where
+ Key: Ord + 'leap,
+ Val: Ord + 'leap,
+ Tuple: Ord,
+ Func: Fn(&Tuple) -> (Key, Val),
+ {
+ fn for_each_count(&mut self, tuple: &Tuple, mut op: impl FnMut(usize, usize)) {
+ if <Self as Leaper<Tuple, ()>>::count(self, tuple) == 0 {
+ op(0, 0)
+ } else {
+ op(0, 1)
+ }
+ }
+
+ fn propose(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) {
+ // We only get here if `tuple` is *not* a member of `self.relation`
+ assert_eq!(min_index, 0);
+ values.push(&());
+ }
+
+ fn intersect(&mut self, _: &Tuple, min_index: usize, values: &mut Vec<&'leap ()>) {
+ // We only get here if `tuple` is not a member of `self.relation`
+ assert_eq!(min_index, 0);
+ assert_eq!(values.len(), 1);
+ }
+ }
+}
+
+fn binary_search<T>(slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> usize {
+ // we maintain the invariant that `lo` many elements of `slice` satisfy `cmp`.
+ // `hi` is maintained at the first element we know does not satisfy `cmp`.
+
+ let mut hi = slice.len();
+ let mut lo = 0;
+ while lo < hi {
+ let mid = lo + (hi - lo) / 2;
+ if cmp(&slice[mid]) {
+ lo = mid + 1;
+ } else {
+ hi = mid;
+ }
+ }
+ lo
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json
new file mode 100644
index 0000000..42ea021
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CHANGELOG.md":"df7d7ea4256611dd5e3bf160e39bb3f8b665c6805ae47fdbf28acf9f77245ffd","Cargo.toml":"2161251dd0dfbea680a9d5fd762973e343fc5215794681c5ffd641faab9a4e4c","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"a23bbe55ac94081711c081a63df10d324a8a26f4b836952cb3c45c9318a03152","benches/value.rs":"b613ff353d3cf0ef8cb98e4ca461ea929b8ba553fe299f2eb2942d77a5b1b6a0","src/__private_api.rs":"da677f1e29e3cb135c971247031bc0eb20324294ab5c1c74c5118f87e45518ae","src/kv/error.rs":"6dae12424164c33b93915f5e70bd6d99d616c969c8bfb543806721dd9b423981","src/kv/key.rs":"9439e91c3ab3f9574a6a11a0347c7b63fdf1652384a6b28411136e4373de2970","src/kv/mod.rs":"3521a5bcfd7f92dcfac6c3c948020d686fee696596c566333a27edbbcc8a4ea8","src/kv/source.rs":"73fbc180c824072d86f1f41f8c59c014db1d8988a86be38a9128d67d6aab06a5","src/kv/value.rs":"0aade52b8e3523a17d6114f8b664793862032a94ea1ee2a4f12a20dd729b92d4","src/lib.rs":"55c32130cd8b99cde2ea962a403cdade52d20e80088357ba2784ee53b2eb9a2c","src/macros.rs":"dfb98017d5f205fec632069ab857a18661d6d563cf5162eeef64d367cc3ad7f5","src/serde.rs":"35f520f62fdba0216ccee33e5b66ad8f81dee3af5b65b824f1816180c9350df5","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"} \ No newline at end of file
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md
new file mode 100644
index 0000000..2c89834
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/CHANGELOG.md
@@ -0,0 +1,324 @@
+# Change Log
+
+## [Unreleased]
+
+## [0.4.22] - 2024-06-27
+
+## What's Changed
+* Add some clarifications to the library docs by @KodrAus in https://github.com/rust-lang/log/pull/620
+* Add links to `colog` crate by @chrivers in https://github.com/rust-lang/log/pull/621
+* adding line_number test + updating some testing infrastructure by @DIvkov575 in https://github.com/rust-lang/log/pull/619
+* Clarify the actual set of functions that can race in _racy variants by @KodrAus in https://github.com/rust-lang/log/pull/623
+* Replace deprecated std::sync::atomic::spin_loop_hint() by @Catamantaloedis in https://github.com/rust-lang/log/pull/625
+* Check usage of max_level features by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/627
+* Remove unneeded import by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/628
+* Loosen orderings for logger initialization in https://github.com/rust-lang/log/pull/632. Originally by @pwoolcoc in https://github.com/rust-lang/log/pull/599
+* Use Location::caller() for file and line info in https://github.com/rust-lang/log/pull/633. Originally by @Cassy343 in https://github.com/rust-lang/log/pull/520
+
+## New Contributors
+* @chrivers made their first contribution in https://github.com/rust-lang/log/pull/621
+* @DIvkov575 made their first contribution in https://github.com/rust-lang/log/pull/619
+* @Catamantaloedis made their first contribution in https://github.com/rust-lang/log/pull/625
+
+**Full Changelog**: https://github.com/rust-lang/log/compare/0.4.21...0.4.22
+
+## [0.4.21] - 2024-02-27
+
+## What's Changed
+* Minor clippy nits by @nyurik in https://github.com/rust-lang/log/pull/578
+* Simplify Display impl by @nyurik in https://github.com/rust-lang/log/pull/579
+* Set all crates to 2021 edition by @nyurik in https://github.com/rust-lang/log/pull/580
+* Various changes based on review by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/583
+* Fix typo in file_static() method doc by @dimo414 in https://github.com/rust-lang/log/pull/590
+* Specialize empty key value pairs by @EFanZh in https://github.com/rust-lang/log/pull/576
+* Fix incorrect lifetime in Value::to_str() by @peterjoel in https://github.com/rust-lang/log/pull/587
+* Remove some API of the key-value feature by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/585
+* Add logcontrol-log and log-reload by @swsnr in https://github.com/rust-lang/log/pull/595
+* Add Serialization section to kv::Value docs by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/593
+* Rename Value::to_str to to_cow_str by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/592
+* Clarify documentation and simplify initialization of `STATIC_MAX_LEVEL` by @ptosi in https://github.com/rust-lang/log/pull/594
+* Update docs to 2021 edition, test by @nyurik in https://github.com/rust-lang/log/pull/577
+* Add "alterable_logger" link to README.md by @brummer-simon in https://github.com/rust-lang/log/pull/589
+* Normalize line ending by @EFanZh in https://github.com/rust-lang/log/pull/602
+* Remove `ok_or` in favor of `Option::ok_or` by @AngelicosPhosphoros in https://github.com/rust-lang/log/pull/607
+* Use `Acquire` ordering for initialization check by @AngelicosPhosphoros in https://github.com/rust-lang/log/pull/610
+* Get structured logging API ready for stabilization by @KodrAus in https://github.com/rust-lang/log/pull/613
+
+## New Contributors
+* @nyurik made their first contribution in https://github.com/rust-lang/log/pull/578
+* @dimo414 made their first contribution in https://github.com/rust-lang/log/pull/590
+* @peterjoel made their first contribution in https://github.com/rust-lang/log/pull/587
+* @ptosi made their first contribution in https://github.com/rust-lang/log/pull/594
+* @brummer-simon made their first contribution in https://github.com/rust-lang/log/pull/589
+* @AngelicosPhosphoros made their first contribution in https://github.com/rust-lang/log/pull/607
+
+## [0.4.20] - 2023-07-11
+
+* Remove rustversion dev-dependency by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/568
+* Remove `local_inner_macros` usage by @EFanZh in https://github.com/rust-lang/log/pull/570
+
+## [0.4.19] - 2023-06-10
+
+* Use target_has_atomic instead of the old atomic_cas cfg by @GuillaumeGomez in https://github.com/rust-lang/log/pull/555
+* Put MSRV into Cargo.toml by @est31 in https://github.com/rust-lang/log/pull/557
+
+## [0.4.18] - 2023-05-28
+
+* fix markdown links (again) by @hellow554 in https://github.com/rust-lang/log/pull/513
+* add cargo doc to workflow by @hellow554 in https://github.com/rust-lang/log/pull/515
+* Apply Clippy lints by @hellow554 in https://github.com/rust-lang/log/pull/516
+* Replace ad-hoc eq_ignore_ascii_case with slice::eq_ignore_ascii_case by @glandium in https://github.com/rust-lang/log/pull/519
+* fix up windows targets by @KodrAus in https://github.com/rust-lang/log/pull/528
+* typo fix by @jiangying000 in https://github.com/rust-lang/log/pull/529
+* Remove dependency on cfg_if by @EriKWDev in https://github.com/rust-lang/log/pull/536
+* GitHub Workflows security hardening by @sashashura in https://github.com/rust-lang/log/pull/538
+* Fix build status badge by @atouchet in https://github.com/rust-lang/log/pull/539
+* Add call_logger to the documentation by @a1ecbr0wn in https://github.com/rust-lang/log/pull/547
+* Use stable internals for key-value API by @KodrAus in https://github.com/rust-lang/log/pull/550
+* Change wording of list of implementations by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/553
+* Add std-logger to list of implementations by @Thomasdezeeuw in https://github.com/rust-lang/log/pull/554
+* Add `set_max_level_racy` and gate `set_max_level` by @djkoloski in https://github.com/rust-lang/log/pull/544
+* [doc] src/lib.rs : prefix an unused variable with an underscore by @OccupyMars2025 in https://github.com/rust-lang/log/pull/561
+* [doc] src/macros.rs : correct grammar errors of an example in lib documentation by @OccupyMars2025 in https://github.com/rust-lang/log/pull/562
+
+## [0.4.17] - 2022-04-29
+
+* Update `kv_unstable` internal dependencies.
+
+## [0.4.16] - 2022-03-22
+
+* Fix a conflict with unqualified `Option` use in macros.
+
+## [0.4.15] - 2022-02-23
+
+* Silence a warning about the deprecated `spin_loop_hint`.
+* Relax ordering in the atomic `set_max_level` call.
+* Add thumbv4t-none-eabi to targets that don't support atomics
+* Allow levels to be iterated over.
+* Implement `Log` on some common wrapper types.
+* Improvements to test coverage.
+* Improvements to documentation.
+* Add key-value support to the `log!` macros.
+* Tighten `kv_unstable` internal dependencies so they don't bump past their current alpha.
+* Add a simple visit API to `kv_unstable`.
+* Support `NonZero*` integers as values in structured logging
+* Support static strings as keys in structured logging
+
+## [0.4.14] - 2021-01-27
+
+* Remove the `__private_api_log_lit` special case.
+* Fixed incorrect combination of `kv_unstable` and `std` features causing compile failures.
+* Remove unstable `Value::to_*` conversions that were incorrectly using `as`.
+* Rename unstable `Value::to_error` to `Value::to_borrowed_error`.
+
+## [0.4.13] - 2021-01-11
+
+* This is the same as `0.4.11`, except with a `kv_unstable_std` feature added to aid migrating current dependents to `0.4.14` (which was originally going to be `0.4.13` until it was decided to create a patch from `0.4.11` to minimize disruption).
+
+## [0.4.12] - 2020-12-24
+
+### New
+
+* Support platforms without atomics by racing instead of failing to compile
+* Implement `Log` for `Box<T: Log>`
+* Update `cfg-if` to `1.0`
+* Internal reworks of the structured logging API. Removed the `Fill` API
+and added `source::as_map` and `source::as_list` to easily serialize a `Source`
+as either a map of `{key: value, ..}` or as a list of `[(key, value), ..]`.
+
+### Fixed
+
+* Fixed deserialization of `LevelFilter` to use their `u64` index variants
+
+## [0.4.11] - 2020-07-09
+
+### New
+
+* Support coercing structured values into concrete types.
+* Reference the `win_dbg_logger` in the readme.
+
+### Fixed
+
+* Updates a few deprecated items used internally.
+* Fixed issues in docs and expands sections.
+* Show the correct build badge in the readme.
+* Fix up a possible inference breakage with structured value errors.
+* Respect formatting flags in structured value formatting.
+
+## [0.4.10] - 2019-12-16 (yanked)
+
+### Fixed
+
+* Fixed the `log!` macros so they work in expression context (this regressed in `0.4.9`, which has been yanked).
+
+## [0.4.9] - 2019-12-12 (yanked)
+
+### Minimum Supported Rust Version
+
+This release bumps the minimum compiler version to `1.31.0`. This was mainly needed for `cfg-if`,
+but between `1.16.0` and `1.31.0` there are a lot of language and library improvements we now
+take advantage of.
+
+### New
+
+* Unstable support for capturing key-value pairs in a record using the `log!` macros
+
+### Improved
+
+* Better documentation for max level filters.
+* Internal updates to line up with bumped MSRV
+
+## [0.4.8] - 2019-07-28
+
+### New
+
+* Support attempting to get `Record` fields as static strings.
+
+## [0.4.7] - 2019-07-06
+
+### New
+
+* Support for embedded environments with thread-unsafe initialization.
+* Initial unstable support for capturing structured data under the `kv_unstable`
+feature gate. This new API doesn't affect existing users and may change in future
+patches (so those changes may not appear in the changelog until it stabilizes).
+
+### Improved
+
+* Docs for using `log` with the 2018 edition.
+* Error messages for macros missing arguments.
+
+## [0.4.6] - 2018-10-27
+
+### Improved
+
+* Support 2018-style macro import for the `log_enabled!` macro.
+
+## [0.4.5] - 2018-09-03
+
+### Improved
+
+* Make `log`'s internal helper macros less likely to conflict with user-defined
+ macros.
+
+## [0.4.4] - 2018-08-17
+
+### Improved
+
+* Support 2018-style imports of the log macros.
+
+## [0.4.3] - 2018-06-29
+
+### Improved
+
+* More code generation improvements.
+
+## [0.4.2] - 2018-06-05
+
+### Improved
+
+* Log invocations now generate less code.
+
+### Fixed
+
+* Example Logger implementations now properly set the max log level.
+
+## [0.4.1] - 2017-12-30
+
+### Fixed
+
+* Some doc links were fixed.
+
+## [0.4.0] - 2017-12-24
+
+The changes in this release include cleanup of some obscure functionality and a more robust public
+API designed to support bridges to other logging systems, and provide more flexibility to new
+features in the future.
+
+### Compatibility
+
+Vast portions of the Rust ecosystem use the 0.3.x release series of log, and we don't want to force
+the community to go through the pain of upgrading every crate to 0.4.x at the exact same time. Along
+with 0.4.0, we've published a new 0.3.9 release which acts as a "shim" over 0.4.0. This will allow
+crates using either version to coexist without losing messages from one side or the other.
+
+There is one caveat - a log message generated by a crate using 0.4.x but consumed by a logging
+implementation using 0.3.x will not have a file name or module path. Applications affected by this
+can upgrade their logging implementations to one using 0.4.x to avoid losing this information. The
+other direction does not lose any information, fortunately!
+
+**TL;DR** Libraries should feel comfortable upgrading to 0.4.0 without treating that as a breaking
+change. Applications may need to update their logging implementation (e.g. env-logger) to a newer
+version using log 0.4.x to avoid losing module and file information.
+
+### New
+
+* The crate is now `no_std` by default.
+* `Level` and `LevelFilter` now implement `Serialize` and `Deserialize` when the `serde` feature is
+ enabled.
+* The `Record` and `Metadata` types can now be constructed by third-party code via a builder API.
+* The `logger` free function returns a reference to the logger implementation. This, along with the
+ ability to construct `Record`s, makes it possible to bridge from another logging framework to
+ this one without digging into the private internals of the crate. The standard `error!` `warn!`,
+ etc, macros now exclusively use the public API of the crate rather than "secret" internal APIs.
+* `Log::flush` has been added to allow crates to tell the logging implementation to ensure that all
+ "in flight" log events have been persisted. This can be used, for example, just before an
+ application exits to ensure that asynchronous log sinks finish their work.
+
+### Removed
+
+* The `shutdown` and `shutdown_raw` functions have been removed. Supporting shutdown significantly
+ complicated the implementation and imposed a performance cost on each logging operation.
+* The `log_panics` function and its associated `nightly` Cargo feature have been removed. Use the
+ [log-panics](https://crates.io/crates/log-panics) instead.
+
+### Changed
+
+* The `Log` prefix has been removed from type names. For example, `LogLevelFilter` is now
+ `LevelFilter`, and `LogRecord` is now `Record`.
+* The `MaxLogLevelFilter` object has been removed in favor of a `set_max_level` free function.
+* The `set_logger` free functions have been restructured. The logger is now directly passed to the
+ functions rather than a closure which returns the logger. `set_logger` now takes a `&'static
+ Log` and is usable in `no_std` contexts in place of the old `set_logger_raw`. `set_boxed_logger`
+ is a convenience function which takes a `Box<Log>` but otherwise acts like `set_logger`. It
+ requires the `std` feature.
+* The `file` and `module_path` values in `Record` no longer have the `'static` lifetime to support
+ integration with other logging frameworks that don't provide a `'static` lifetime for the
+ equivalent values.
+* The `file`, `line`, and `module_path` values in `Record` are now `Option`s to support integration
+ with other logging frameworks that don't provide those values.
+
+### In the Future
+
+* We're looking to add support for *structured* logging - the inclusion of extra key-value pairs of
+ information in a log event in addition to the normal string message. This should be able to be
+ added in a backwards compatible manner to the 0.4.x series when the design is worked out.
+
+## Older
+
+Look at the [release tags] for information about older releases.
+
+[Unreleased]: https://github.com/rust-lang-nursery/log/compare/0.4.21...HEAD
+[0.4.21]: https://github.com/rust-lang/log/compare/0.4.20...0.4.21
+[0.4.20]: https://github.com/rust-lang-nursery/log/compare/0.4.19...0.4.20
+[0.4.19]: https://github.com/rust-lang-nursery/log/compare/0.4.18...0.4.19
+[0.4.18]: https://github.com/rust-lang-nursery/log/compare/0.4.17...0.4.18
+[0.4.17]: https://github.com/rust-lang-nursery/log/compare/0.4.16...0.4.17
+[0.4.16]: https://github.com/rust-lang-nursery/log/compare/0.4.15...0.4.16
+[0.4.15]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.15
+[0.4.14]: https://github.com/rust-lang-nursery/log/compare/0.4.13...0.4.14
+[0.4.13]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.13
+[0.4.12]: https://github.com/rust-lang-nursery/log/compare/0.4.11...0.4.12
+[0.4.11]: https://github.com/rust-lang-nursery/log/compare/0.4.10...0.4.11
+[0.4.10]: https://github.com/rust-lang-nursery/log/compare/0.4.9...0.4.10
+[0.4.9]: https://github.com/rust-lang-nursery/log/compare/0.4.8...0.4.9
+[0.4.8]: https://github.com/rust-lang-nursery/log/compare/0.4.7...0.4.8
+[0.4.7]: https://github.com/rust-lang-nursery/log/compare/0.4.6...0.4.7
+[0.4.6]: https://github.com/rust-lang-nursery/log/compare/0.4.5...0.4.6
+[0.4.5]: https://github.com/rust-lang-nursery/log/compare/0.4.4...0.4.5
+[0.4.4]: https://github.com/rust-lang-nursery/log/compare/0.4.3...0.4.4
+[0.4.3]: https://github.com/rust-lang-nursery/log/compare/0.4.2...0.4.3
+[0.4.2]: https://github.com/rust-lang-nursery/log/compare/0.4.1...0.4.2
+[0.4.1]: https://github.com/rust-lang-nursery/log/compare/0.4.0...0.4.1
+[0.4.0]: https://github.com/rust-lang-nursery/log/compare/0.3.8...0.4.0
+[release tags]: https://github.com/rust-lang-nursery/log/releases
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml
new file mode 100644
index 0000000..313a005
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/Cargo.toml
@@ -0,0 +1,139 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies.
+#
+# If you are reading this file be aware that the original Cargo.toml
+# will likely look very different (and much more reasonable).
+# See Cargo.toml.orig for the original contents.
+
+[package]
+edition = "2021"
+rust-version = "1.60.0"
+name = "log"
+version = "0.4.22"
+authors = ["The Rust Project Developers"]
+exclude = ["rfcs/**/*"]
+description = """
+A lightweight logging facade for Rust
+"""
+documentation = "https://docs.rs/log"
+readme = "README.md"
+keywords = ["logging"]
+categories = ["development-tools::debugging"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/rust-lang/log"
+
+[package.metadata.docs.rs]
+features = [
+ "std",
+ "serde",
+ "kv_std",
+ "kv_sval",
+ "kv_serde",
+]
+
+[[test]]
+name = "integration"
+path = "tests/integration.rs"
+harness = false
+
+[[test]]
+name = "macros"
+path = "tests/macros.rs"
+harness = true
+
+[dependencies.serde]
+version = "1.0"
+optional = true
+default-features = false
+
+[dependencies.sval]
+version = "2.1"
+optional = true
+default-features = false
+
+[dependencies.sval_ref]
+version = "2.1"
+optional = true
+default-features = false
+
+[dependencies.value-bag]
+version = "1.7"
+features = ["inline-i128"]
+optional = true
+default-features = false
+
+[dev-dependencies.proc-macro2]
+version = "1.0.63"
+default-features = false
+
+[dev-dependencies.serde]
+version = "1.0"
+features = ["derive"]
+
+[dev-dependencies.serde_json]
+version = "1.0"
+
+[dev-dependencies.serde_test]
+version = "1.0"
+
+[dev-dependencies.sval]
+version = "2.1"
+
+[dev-dependencies.sval_derive]
+version = "2.1"
+
+[dev-dependencies.value-bag]
+version = "1.7"
+features = ["test"]
+
+[features]
+kv = []
+kv_serde = [
+ "kv_std",
+ "value-bag/serde",
+ "serde",
+]
+kv_std = [
+ "std",
+ "kv",
+ "value-bag/error",
+]
+kv_sval = [
+ "kv",
+ "value-bag/sval",
+ "sval",
+ "sval_ref",
+]
+kv_unstable = [
+ "kv",
+ "value-bag",
+]
+kv_unstable_serde = [
+ "kv_serde",
+ "kv_unstable_std",
+]
+kv_unstable_std = [
+ "kv_std",
+ "kv_unstable",
+]
+kv_unstable_sval = [
+ "kv_sval",
+ "kv_unstable",
+]
+max_level_debug = []
+max_level_error = []
+max_level_info = []
+max_level_off = []
+max_level_trace = []
+max_level_warn = []
+release_max_level_debug = []
+release_max_level_error = []
+release_max_level_info = []
+release_max_level_off = []
+release_max_level_trace = []
+release_max_level_warn = []
+std = []
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ 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
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT
new file mode 100644
index 0000000..39d4bdb
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/LICENSE-MIT
@@ -0,0 +1,25 @@
+Copyright (c) 2014 The Rust Project Developers
+
+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/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/README.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/README.md
new file mode 100644
index 0000000..d4a08b1
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/README.md
@@ -0,0 +1,130 @@
+log
+===
+
+A Rust library providing a lightweight logging *facade*.
+
+[![Build status](https://img.shields.io/github/actions/workflow/status/rust-lang/log/main.yml?branch=master)](https://github.com/rust-lang/log/actions)
+[![Latest version](https://img.shields.io/crates/v/log.svg)](https://crates.io/crates/log)
+[![Documentation](https://docs.rs/log/badge.svg)](https://docs.rs/log)
+![License](https://img.shields.io/crates/l/log.svg)
+
+* [`log` documentation](https://docs.rs/log)
+
+A logging facade provides a single logging API that abstracts over the actual
+logging implementation. Libraries can use the logging API provided by this
+crate, and the consumer of those libraries can choose the logging
+implementation that is most suitable for its use case.
+
+
+## Minimum supported `rustc`
+
+`1.60.0+`
+
+This version is explicitly tested in CI and may be bumped in any release as needed. Maintaining compatibility with older compilers is a priority though, so the bar for bumping the minimum supported version is set very high. Any changes to the supported minimum version will be called out in the release notes.
+
+## Usage
+
+### In libraries
+
+Libraries should link only to the `log` crate, and use the provided macros to
+log whatever information will be useful to downstream consumers:
+
+```toml
+[dependencies]
+log = "0.4"
+```
+
+```rust
+use log::{info, trace, warn};
+
+pub fn shave_the_yak(yak: &mut Yak) {
+ trace!("Commencing yak shaving");
+
+ loop {
+ match find_a_razor() {
+ Ok(razor) => {
+ info!("Razor located: {razor}");
+ yak.shave(razor);
+ break;
+ }
+ Err(err) => {
+ warn!("Unable to locate a razor: {err}, retrying");
+ }
+ }
+ }
+}
+```
+
+### In executables
+
+In order to produce log output, executables have to use a logger implementation compatible with the facade.
+There are many available implementations to choose from, here are some options:
+
+* Simple minimal loggers:
+ * [`env_logger`](https://docs.rs/env_logger/*/env_logger/)
+ * [`colog`](https://docs.rs/colog/*/colog/)
+ * [`simple_logger`](https://docs.rs/simple_logger/*/simple_logger/)
+ * [`simplelog`](https://docs.rs/simplelog/*/simplelog/)
+ * [`pretty_env_logger`](https://docs.rs/pretty_env_logger/*/pretty_env_logger/)
+ * [`stderrlog`](https://docs.rs/stderrlog/*/stderrlog/)
+ * [`flexi_logger`](https://docs.rs/flexi_logger/*/flexi_logger/)
+ * [`call_logger`](https://docs.rs/call_logger/*/call_logger/)
+ * [`std-logger`](https://docs.rs/std-logger/*/std_logger/)
+ * [`structured-logger`](https://docs.rs/structured-logger/latest/structured_logger/)
+* Complex configurable frameworks:
+ * [`log4rs`](https://docs.rs/log4rs/*/log4rs/)
+ * [`fern`](https://docs.rs/fern/*/fern/)
+* Adaptors for other facilities:
+ * [`syslog`](https://docs.rs/syslog/*/syslog/)
+ * [`systemd-journal-logger`](https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/)
+ * [`slog-stdlog`](https://docs.rs/slog-stdlog/*/slog_stdlog/)
+ * [`android_log`](https://docs.rs/android_log/*/android_log/)
+ * [`win_dbg_logger`](https://docs.rs/win_dbg_logger/*/win_dbg_logger/)
+ * [`db_logger`](https://docs.rs/db_logger/*/db_logger/)
+ * [`log-to-defmt`](https://docs.rs/log-to-defmt/*/log_to_defmt/)
+ * [`logcontrol-log`](https://docs.rs/logcontrol-log/*/logcontrol_log/)
+* For WebAssembly binaries:
+ * [`console_log`](https://docs.rs/console_log/*/console_log/)
+* For dynamic libraries:
+ * You may need to construct [an FFI-safe wrapper over `log`](https://github.com/rust-lang/log/issues/421) to initialize in your libraries.
+* Utilities:
+ * [`log_err`](https://docs.rs/log_err/*/log_err/)
+ * [`log-reload`](https://docs.rs/log-reload/*/log_reload/)
+ * [`alterable_logger`](https://docs.rs/alterable_logger/*/alterable_logger)
+
+Executables should choose a logger implementation and initialize it early in the
+runtime of the program. Logger implementations will typically include a
+function to do this. Any log messages generated before the logger is
+initialized will be ignored.
+
+The executable itself may use the `log` crate to log as well.
+
+## Structured logging
+
+If you enable the `kv` feature, you can associate structured data with your log records:
+
+```rust
+use log::{info, trace, warn};
+
+pub fn shave_the_yak(yak: &mut Yak) {
+ // `yak:serde` will capture `yak` using its `serde::Serialize` impl
+ //
+ // You could also use `:?` for `Debug`, or `:%` for `Display`. For a
+ // full list, see the `log` crate documentation
+ trace!(target = "yak_events", yak:serde; "Commencing yak shaving");
+
+ loop {
+ match find_a_razor() {
+ Ok(razor) => {
+ info!(razor; "Razor located");
+ yak.shave(razor);
+ break;
+ }
+ Err(e) => {
+ // `e:err` will capture `e` using its `std::error::Error` impl
+ warn!(e:err; "Unable to locate a razor, retrying");
+ }
+ }
+ }
+}
+```
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs
new file mode 100644
index 0000000..3d0f18b
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/benches/value.rs
@@ -0,0 +1,27 @@
+#![cfg(feature = "kv")]
+#![feature(test)]
+
+use log::kv::Value;
+
+#[bench]
+fn u8_to_value(b: &mut test::Bencher) {
+ b.iter(|| Value::from(1u8));
+}
+
+#[bench]
+fn u8_to_value_debug(b: &mut test::Bencher) {
+ b.iter(|| Value::from_debug(&1u8));
+}
+
+#[bench]
+fn str_to_value_debug(b: &mut test::Bencher) {
+ b.iter(|| Value::from_debug(&"a string"));
+}
+
+#[bench]
+fn custom_to_value_debug(b: &mut test::Bencher) {
+ #[derive(Debug)]
+ struct A;
+
+ b.iter(|| Value::from_debug(&A));
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs
new file mode 100644
index 0000000..11bc2fc
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/__private_api.rs
@@ -0,0 +1,123 @@
+//! WARNING: this is not part of the crate's public API and is subject to change at any time
+
+use self::sealed::KVs;
+use crate::{Level, Metadata, Record};
+use std::fmt::Arguments;
+use std::panic::Location;
+pub use std::{format_args, module_path, stringify};
+
+#[cfg(not(feature = "kv"))]
+pub type Value<'a> = &'a str;
+
+mod sealed {
+ /// Types for the `kv` argument.
+ pub trait KVs<'a> {
+ fn into_kvs(self) -> Option<&'a [(&'a str, super::Value<'a>)]>;
+ }
+}
+
+// Types for the `kv` argument.
+
+impl<'a> KVs<'a> for &'a [(&'a str, Value<'a>)] {
+ #[inline]
+ fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> {
+ Some(self)
+ }
+}
+
+impl<'a> KVs<'a> for () {
+ #[inline]
+ fn into_kvs(self) -> Option<&'a [(&'a str, Value<'a>)]> {
+ None
+ }
+}
+
+// Log implementation.
+
+fn log_impl(
+ args: Arguments,
+ level: Level,
+ &(target, module_path, loc): &(&str, &'static str, &'static Location),
+ kvs: Option<&[(&str, Value)]>,
+) {
+ #[cfg(not(feature = "kv"))]
+ if kvs.is_some() {
+ panic!("key-value support is experimental and must be enabled using the `kv` feature")
+ }
+
+ let mut builder = Record::builder();
+
+ builder
+ .args(args)
+ .level(level)
+ .target(target)
+ .module_path_static(Some(module_path))
+ .file_static(Some(loc.file()))
+ .line(Some(loc.line()));
+
+ #[cfg(feature = "kv")]
+ builder.key_values(&kvs);
+
+ crate::logger().log(&builder.build());
+}
+
+pub fn log<'a, K>(
+ args: Arguments,
+ level: Level,
+ target_module_path_and_loc: &(&str, &'static str, &'static Location),
+ kvs: K,
+) where
+ K: KVs<'a>,
+{
+ log_impl(args, level, target_module_path_and_loc, kvs.into_kvs())
+}
+
+pub fn enabled(level: Level, target: &str) -> bool {
+ crate::logger().enabled(&Metadata::builder().level(level).target(target).build())
+}
+
+#[track_caller]
+pub fn loc() -> &'static Location<'static> {
+ Location::caller()
+}
+
+#[cfg(feature = "kv")]
+mod kv_support {
+ use crate::kv;
+
+ pub type Value<'a> = kv::Value<'a>;
+
+ // NOTE: Many functions here accept a double reference &&V
+ // This is so V itself can be ?Sized, while still letting us
+ // erase it to some dyn Trait (because &T is sized)
+
+ pub fn capture_to_value<'a, V: kv::ToValue + ?Sized>(v: &'a &'a V) -> Value<'a> {
+ v.to_value()
+ }
+
+ pub fn capture_debug<'a, V: core::fmt::Debug + ?Sized>(v: &'a &'a V) -> Value<'a> {
+ Value::from_debug(v)
+ }
+
+ pub fn capture_display<'a, V: core::fmt::Display + ?Sized>(v: &'a &'a V) -> Value<'a> {
+ Value::from_display(v)
+ }
+
+ #[cfg(feature = "kv_std")]
+ pub fn capture_error<'a>(v: &'a (dyn std::error::Error + 'static)) -> Value<'a> {
+ Value::from_dyn_error(v)
+ }
+
+ #[cfg(feature = "kv_sval")]
+ pub fn capture_sval<'a, V: sval::Value + ?Sized>(v: &'a &'a V) -> Value<'a> {
+ Value::from_sval(v)
+ }
+
+ #[cfg(feature = "kv_serde")]
+ pub fn capture_serde<'a, V: serde::Serialize + ?Sized>(v: &'a &'a V) -> Value<'a> {
+ Value::from_serde(v)
+ }
+}
+
+#[cfg(feature = "kv")]
+pub use self::kv_support::*;
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs
new file mode 100644
index 0000000..7efa5af
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/error.rs
@@ -0,0 +1,94 @@
+use std::fmt;
+
+/// An error encountered while working with structured data.
+#[derive(Debug)]
+pub struct Error {
+ inner: Inner,
+}
+
+#[derive(Debug)]
+enum Inner {
+ #[cfg(feature = "std")]
+ Boxed(std_support::BoxedError),
+ Msg(&'static str),
+ #[cfg(feature = "value-bag")]
+ Value(crate::kv::value::inner::Error),
+ Fmt,
+}
+
+impl Error {
+ /// Create an error from a message.
+ pub fn msg(msg: &'static str) -> Self {
+ Error {
+ inner: Inner::Msg(msg),
+ }
+ }
+
+ // Not public so we don't leak the `crate::kv::value::inner` API
+ #[cfg(feature = "value-bag")]
+ pub(super) fn from_value(err: crate::kv::value::inner::Error) -> Self {
+ Error {
+ inner: Inner::Value(err),
+ }
+ }
+
+ // Not public so we don't leak the `crate::kv::value::inner` API
+ #[cfg(feature = "value-bag")]
+ pub(super) fn into_value(self) -> crate::kv::value::inner::Error {
+ match self.inner {
+ Inner::Value(err) => err,
+ #[cfg(feature = "kv_std")]
+ _ => crate::kv::value::inner::Error::boxed(self),
+ #[cfg(not(feature = "kv_std"))]
+ _ => crate::kv::value::inner::Error::msg("error inspecting a value"),
+ }
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ use self::Inner::*;
+ match &self.inner {
+ #[cfg(feature = "std")]
+ Boxed(err) => err.fmt(f),
+ #[cfg(feature = "value-bag")]
+ Value(err) => err.fmt(f),
+ Msg(msg) => msg.fmt(f),
+ Fmt => fmt::Error.fmt(f),
+ }
+ }
+}
+
+impl From<fmt::Error> for Error {
+ fn from(_: fmt::Error) -> Self {
+ Error { inner: Inner::Fmt }
+ }
+}
+
+#[cfg(feature = "std")]
+mod std_support {
+ use super::*;
+ use std::{error, io};
+
+ pub(super) type BoxedError = Box<dyn error::Error + Send + Sync>;
+
+ impl Error {
+ /// Create an error from a standard error type.
+ pub fn boxed<E>(err: E) -> Self
+ where
+ E: Into<BoxedError>,
+ {
+ Error {
+ inner: Inner::Boxed(err.into()),
+ }
+ }
+ }
+
+ impl error::Error for Error {}
+
+ impl From<io::Error> for Error {
+ fn from(err: io::Error) -> Self {
+ Error::boxed(err)
+ }
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs
new file mode 100644
index 0000000..9a64b95
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/key.rs
@@ -0,0 +1,143 @@
+//! Structured keys.
+
+use std::borrow::Borrow;
+use std::fmt;
+
+/// A type that can be converted into a [`Key`](struct.Key.html).
+pub trait ToKey {
+ /// Perform the conversion.
+ fn to_key(&self) -> Key;
+}
+
+impl<'a, T> ToKey for &'a T
+where
+ T: ToKey + ?Sized,
+{
+ fn to_key(&self) -> Key {
+ (**self).to_key()
+ }
+}
+
+impl<'k> ToKey for Key<'k> {
+ fn to_key(&self) -> Key {
+ Key { key: self.key }
+ }
+}
+
+impl ToKey for str {
+ fn to_key(&self) -> Key {
+ Key::from_str(self)
+ }
+}
+
+/// A key in a key-value.
+// These impls must only be based on the as_str() representation of the key
+// If a new field (such as an optional index) is added to the key they must not affect comparison
+#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Key<'k> {
+ key: &'k str,
+}
+
+impl<'k> Key<'k> {
+ /// Get a key from a borrowed string.
+ pub fn from_str(key: &'k str) -> Self {
+ Key { key }
+ }
+
+ /// Get a borrowed string from this key.
+ pub fn as_str(&self) -> &str {
+ self.key
+ }
+}
+
+impl<'k> fmt::Display for Key<'k> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ self.key.fmt(f)
+ }
+}
+
+impl<'k> AsRef<str> for Key<'k> {
+ fn as_ref(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl<'k> Borrow<str> for Key<'k> {
+ fn borrow(&self) -> &str {
+ self.as_str()
+ }
+}
+
+impl<'k> From<&'k str> for Key<'k> {
+ fn from(s: &'k str) -> Self {
+ Key::from_str(s)
+ }
+}
+
+#[cfg(feature = "std")]
+mod std_support {
+ use super::*;
+
+ use std::borrow::Cow;
+
+ impl ToKey for String {
+ fn to_key(&self) -> Key {
+ Key::from_str(self)
+ }
+ }
+
+ impl<'a> ToKey for Cow<'a, str> {
+ fn to_key(&self) -> Key {
+ Key::from_str(self)
+ }
+ }
+}
+
+#[cfg(feature = "kv_sval")]
+mod sval_support {
+ use super::*;
+
+ use sval::Value;
+ use sval_ref::ValueRef;
+
+ impl<'a> Value for Key<'a> {
+ fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(
+ &'sval self,
+ stream: &mut S,
+ ) -> sval::Result {
+ self.key.stream(stream)
+ }
+ }
+
+ impl<'a> ValueRef<'a> for Key<'a> {
+ fn stream_ref<S: sval::Stream<'a> + ?Sized>(&self, stream: &mut S) -> sval::Result {
+ self.key.stream(stream)
+ }
+ }
+}
+
+#[cfg(feature = "kv_serde")]
+mod serde_support {
+ use super::*;
+
+ use serde::{Serialize, Serializer};
+
+ impl<'a> Serialize for Key<'a> {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ self.key.serialize(serializer)
+ }
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn key_from_string() {
+ assert_eq!("a key", Key::from_str("a key").as_str());
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs
new file mode 100644
index 0000000..1ccb825
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/mod.rs
@@ -0,0 +1,265 @@
+//! Structured logging.
+//!
+//! Add the `kv` feature to your `Cargo.toml` to enable
+//! this module:
+//!
+//! ```toml
+//! [dependencies.log]
+//! features = ["kv"]
+//! ```
+//!
+//! # Structured logging in `log`
+//!
+//! Structured logging enhances traditional text-based log records with user-defined
+//! attributes. Structured logs can be analyzed using a variety of data processing
+//! techniques, without needing to find and parse attributes from unstructured text first.
+//!
+//! In `log`, user-defined attributes are part of a [`Source`] on the log record.
+//! Each attribute is a key-value; a pair of [`Key`] and [`Value`]. Keys are strings
+//! and values are a datum of any type that can be formatted or serialized. Simple types
+//! like strings, booleans, and numbers are supported, as well as arbitrarily complex
+//! structures involving nested objects and sequences.
+//!
+//! ## Adding key-values to log records
+//!
+//! Key-values appear before the message format in the `log!` macros:
+//!
+//! ```
+//! # use log::info;
+//! info!(a = 1; "Something of interest");
+//! ```
+//!
+//! Key-values support the same shorthand identifer syntax as `format_args`:
+//!
+//! ```
+//! # use log::info;
+//! let a = 1;
+//!
+//! info!(a; "Something of interest");
+//! ```
+//!
+//! Values are capturing using the [`ToValue`] trait by default. To capture a value
+//! using a different trait implementation, use a modifier after its key. Here's how
+//! the same example can capture `a` using its `Debug` implementation instead:
+//!
+//! ```
+//! # use log::info;
+//! info!(a:? = 1; "Something of interest");
+//! ```
+//!
+//! The following capturing modifiers are supported:
+//!
+//! - `:?` will capture the value using `Debug`.
+//! - `:debug` will capture the value using `Debug`.
+//! - `:%` will capture the value using `Display`.
+//! - `:display` will capture the value using `Display`.
+//! - `:err` will capture the value using `std::error::Error` (requires the `kv_std` feature).
+//! - `:sval` will capture the value using `sval::Value` (requires the `kv_sval` feature).
+//! - `:serde` will capture the value using `serde::Serialize` (requires the `kv_serde` feature).
+//!
+//! ## Working with key-values on log records
+//!
+//! Use the [`Record::key_values`](../struct.Record.html#method.key_values) method to access key-values.
+//!
+//! Individual values can be pulled from the source by their key:
+//!
+//! ```
+//! # fn main() -> Result<(), log::kv::Error> {
+//! use log::kv::{Source, Key, Value};
+//! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
+//!
+//! // info!(a = 1; "Something of interest");
+//!
+//! let a: Value = record.key_values().get(Key::from("a")).unwrap();
+//! assert_eq!(1, a.to_i64().unwrap());
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! All key-values can also be enumerated using a [`VisitSource`]:
+//!
+//! ```
+//! # fn main() -> Result<(), log::kv::Error> {
+//! use std::collections::BTreeMap;
+//!
+//! use log::kv::{self, Source, Key, Value, VisitSource};
+//!
+//! struct Collect<'kvs>(BTreeMap<Key<'kvs>, Value<'kvs>>);
+//!
+//! impl<'kvs> VisitSource<'kvs> for Collect<'kvs> {
+//! fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> {
+//! self.0.insert(key, value);
+//!
+//! Ok(())
+//! }
+//! }
+//!
+//! let mut visitor = Collect(BTreeMap::new());
+//!
+//! # let record = log::Record::builder().key_values(&[("a", 1), ("b", 2), ("c", 3)]).build();
+//! // info!(a = 1, b = 2, c = 3; "Something of interest");
+//!
+//! record.key_values().visit(&mut visitor)?;
+//!
+//! let collected = visitor.0;
+//!
+//! assert_eq!(
+//! vec!["a", "b", "c"],
+//! collected
+//! .keys()
+//! .map(|k| k.as_str())
+//! .collect::<Vec<_>>(),
+//! );
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! [`Value`]s have methods for conversions to common types:
+//!
+//! ```
+//! # fn main() -> Result<(), log::kv::Error> {
+//! use log::kv::{Source, Key};
+//! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
+//!
+//! // info!(a = 1; "Something of interest");
+//!
+//! let a = record.key_values().get(Key::from("a")).unwrap();
+//!
+//! assert_eq!(1, a.to_i64().unwrap());
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! Values also have their own [`VisitValue`] type. Value visitors are a lightweight
+//! API for working with primitives types:
+//!
+//! ```
+//! # fn main() -> Result<(), log::kv::Error> {
+//! use log::kv::{self, Source, Key, VisitValue};
+//! # let record = log::Record::builder().key_values(&[("a", 1)]).build();
+//!
+//! struct IsNumeric(bool);
+//!
+//! impl<'kvs> VisitValue<'kvs> for IsNumeric {
+//! fn visit_any(&mut self, _value: kv::Value) -> Result<(), kv::Error> {
+//! self.0 = false;
+//! Ok(())
+//! }
+//!
+//! fn visit_u64(&mut self, _value: u64) -> Result<(), kv::Error> {
+//! self.0 = true;
+//! Ok(())
+//! }
+//!
+//! fn visit_i64(&mut self, _value: i64) -> Result<(), kv::Error> {
+//! self.0 = true;
+//! Ok(())
+//! }
+//!
+//! fn visit_u128(&mut self, _value: u128) -> Result<(), kv::Error> {
+//! self.0 = true;
+//! Ok(())
+//! }
+//!
+//! fn visit_i128(&mut self, _value: i128) -> Result<(), kv::Error> {
+//! self.0 = true;
+//! Ok(())
+//! }
+//!
+//! fn visit_f64(&mut self, _value: f64) -> Result<(), kv::Error> {
+//! self.0 = true;
+//! Ok(())
+//! }
+//! }
+//!
+//! // info!(a = 1; "Something of interest");
+//!
+//! let a = record.key_values().get(Key::from("a")).unwrap();
+//!
+//! let mut visitor = IsNumeric(false);
+//!
+//! a.visit(&mut visitor)?;
+//!
+//! let is_numeric = visitor.0;
+//!
+//! assert!(is_numeric);
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! To serialize a value to a format like JSON, you can also use either `serde` or `sval`:
+//!
+//! ```
+//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
+//! # #[cfg(feature = "serde")]
+//! # {
+//! # use log::kv::Key;
+//! #[derive(serde::Serialize)]
+//! struct Data {
+//! a: i32, b: bool,
+//! c: &'static str,
+//! }
+//!
+//! let data = Data { a: 1, b: true, c: "Some data" };
+//!
+//! # let source = [("a", log::kv::Value::from_serde(&data))];
+//! # let record = log::Record::builder().key_values(&source).build();
+//! // info!(a = data; "Something of interest");
+//!
+//! let a = record.key_values().get(Key::from("a")).unwrap();
+//!
+//! assert_eq!("{\"a\":1,\"b\":true,\"c\":\"Some data\"}", serde_json::to_string(&a)?);
+//! # }
+//! # Ok(())
+//! # }
+//! ```
+//!
+//! The choice of serialization framework depends on the needs of the consumer.
+//! If you're in a no-std environment, you can use `sval`. In other cases, you can use `serde`.
+//! Log producers and log consumers don't need to agree on the serialization framework.
+//! A value can be captured using its `serde::Serialize` implementation and still be serialized
+//! through `sval` without losing any structure or data.
+//!
+//! Values can also always be formatted using the standard `Debug` and `Display`
+//! traits:
+//!
+//! ```
+//! # use log::kv::Key;
+//! # #[derive(Debug)]
+//! struct Data {
+//! a: i32,
+//! b: bool,
+//! c: &'static str,
+//! }
+//!
+//! let data = Data { a: 1, b: true, c: "Some data" };
+//!
+//! # let source = [("a", log::kv::Value::from_debug(&data))];
+//! # let record = log::Record::builder().key_values(&source).build();
+//! // info!(a = data; "Something of interest");
+//!
+//! let a = record.key_values().get(Key::from("a")).unwrap();
+//!
+//! assert_eq!("Data { a: 1, b: true, c: \"Some data\" }", format!("{a:?}"));
+//! ```
+
+mod error;
+mod key;
+
+#[cfg(not(feature = "kv_unstable"))]
+mod source;
+#[cfg(not(feature = "kv_unstable"))]
+mod value;
+
+pub use self::error::Error;
+pub use self::key::{Key, ToKey};
+pub use self::source::{Source, VisitSource};
+pub use self::value::{ToValue, Value, VisitValue};
+
+#[cfg(feature = "kv_unstable")]
+pub mod source;
+#[cfg(feature = "kv_unstable")]
+pub mod value;
+
+#[cfg(feature = "kv_unstable")]
+pub use self::source::Visitor;
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs
new file mode 100644
index 0000000..f463e6d
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/source.rs
@@ -0,0 +1,514 @@
+//! Sources for key-values.
+//!
+//! This module defines the [`Source`] type and supporting APIs for
+//! working with collections of key-values.
+
+use crate::kv::{Error, Key, ToKey, ToValue, Value};
+use std::fmt;
+
+/// A source of key-values.
+///
+/// The source may be a single pair, a set of pairs, or a filter over a set of pairs.
+/// Use the [`VisitSource`](trait.VisitSource.html) trait to inspect the structured data
+/// in a source.
+///
+/// A source is like an iterator over its key-values, except with a push-based API
+/// instead of a pull-based one.
+///
+/// # Examples
+///
+/// Enumerating the key-values in a source:
+///
+/// ```
+/// # fn main() -> Result<(), log::kv::Error> {
+/// use log::kv::{self, Source, Key, Value, VisitSource};
+///
+/// // A `VisitSource` that prints all key-values
+/// // VisitSources are fed the key-value pairs of each key-values
+/// struct Printer;
+///
+/// impl<'kvs> VisitSource<'kvs> for Printer {
+/// fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), kv::Error> {
+/// println!("{key}: {value}");
+///
+/// Ok(())
+/// }
+/// }
+///
+/// // A source with 3 key-values
+/// // Common collection types implement the `Source` trait
+/// let source = &[
+/// ("a", 1),
+/// ("b", 2),
+/// ("c", 3),
+/// ];
+///
+/// // Pass an instance of the `VisitSource` to a `Source` to visit it
+/// source.visit(&mut Printer)?;
+/// # Ok(())
+/// # }
+/// ```
+pub trait Source {
+ /// Visit key-values.
+ ///
+ /// A source doesn't have to guarantee any ordering or uniqueness of key-values.
+ /// If the given visitor returns an error then the source may early-return with it,
+ /// even if there are more key-values.
+ ///
+ /// # Implementation notes
+ ///
+ /// A source should yield the same key-values to a subsequent visitor unless
+ /// that visitor itself fails.
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error>;
+
+ /// Get the value for a given key.
+ ///
+ /// If the key appears multiple times in the source then which key is returned
+ /// is implementation specific.
+ ///
+ /// # Implementation notes
+ ///
+ /// A source that can provide a more efficient implementation of this method
+ /// should override it.
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ get_default(self, key)
+ }
+
+ /// Count the number of key-values that can be visited.
+ ///
+ /// # Implementation notes
+ ///
+ /// A source that knows the number of key-values upfront may provide a more
+ /// efficient implementation.
+ ///
+ /// A subsequent call to `visit` should yield the same number of key-values.
+ fn count(&self) -> usize {
+ count_default(self)
+ }
+}
+
+/// The default implementation of `Source::get`
+fn get_default<'v>(source: &'v (impl Source + ?Sized), key: Key) -> Option<Value<'v>> {
+ struct Get<'k, 'v> {
+ key: Key<'k>,
+ found: Option<Value<'v>>,
+ }
+
+ impl<'k, 'kvs> VisitSource<'kvs> for Get<'k, 'kvs> {
+ fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {
+ if self.key == key {
+ self.found = Some(value);
+ }
+
+ Ok(())
+ }
+ }
+
+ let mut get = Get { key, found: None };
+
+ let _ = source.visit(&mut get);
+ get.found
+}
+
+/// The default implementation of `Source::count`.
+fn count_default(source: impl Source) -> usize {
+ struct Count(usize);
+
+ impl<'kvs> VisitSource<'kvs> for Count {
+ fn visit_pair(&mut self, _: Key<'kvs>, _: Value<'kvs>) -> Result<(), Error> {
+ self.0 += 1;
+
+ Ok(())
+ }
+ }
+
+ let mut count = Count(0);
+ let _ = source.visit(&mut count);
+ count.0
+}
+
+impl<'a, T> Source for &'a T
+where
+ T: Source + ?Sized,
+{
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ Source::visit(&**self, visitor)
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ Source::get(&**self, key)
+ }
+
+ fn count(&self) -> usize {
+ Source::count(&**self)
+ }
+}
+
+impl<K, V> Source for (K, V)
+where
+ K: ToKey,
+ V: ToValue,
+{
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ visitor.visit_pair(self.0.to_key(), self.1.to_value())
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ if self.0.to_key() == key {
+ Some(self.1.to_value())
+ } else {
+ None
+ }
+ }
+
+ fn count(&self) -> usize {
+ 1
+ }
+}
+
+impl<S> Source for [S]
+where
+ S: Source,
+{
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ for source in self {
+ source.visit(visitor)?;
+ }
+
+ Ok(())
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ for source in self {
+ if let Some(found) = source.get(key.clone()) {
+ return Some(found);
+ }
+ }
+
+ None
+ }
+
+ fn count(&self) -> usize {
+ self.iter().map(Source::count).sum()
+ }
+}
+
+impl<const N: usize, S> Source for [S; N]
+where
+ S: Source,
+{
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ Source::visit(self as &[_], visitor)
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ Source::get(self as &[_], key)
+ }
+
+ fn count(&self) -> usize {
+ Source::count(self as &[_])
+ }
+}
+
+impl<S> Source for Option<S>
+where
+ S: Source,
+{
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ if let Some(source) = self {
+ source.visit(visitor)?;
+ }
+
+ Ok(())
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ self.as_ref().and_then(|s| s.get(key))
+ }
+
+ fn count(&self) -> usize {
+ self.as_ref().map_or(0, Source::count)
+ }
+}
+
+/// A visitor for the key-value pairs in a [`Source`](trait.Source.html).
+pub trait VisitSource<'kvs> {
+ /// Visit a key-value pair.
+ fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error>;
+}
+
+impl<'a, 'kvs, T> VisitSource<'kvs> for &'a mut T
+where
+ T: VisitSource<'kvs> + ?Sized,
+{
+ fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {
+ (**self).visit_pair(key, value)
+ }
+}
+
+impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugMap<'a, 'b> {
+ fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {
+ self.entry(&key, &value);
+ Ok(())
+ }
+}
+
+impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugList<'a, 'b> {
+ fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {
+ self.entry(&(key, value));
+ Ok(())
+ }
+}
+
+impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugSet<'a, 'b> {
+ fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {
+ self.entry(&(key, value));
+ Ok(())
+ }
+}
+
+impl<'a, 'b: 'a, 'kvs> VisitSource<'kvs> for fmt::DebugTuple<'a, 'b> {
+ fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {
+ self.field(&key);
+ self.field(&value);
+ Ok(())
+ }
+}
+
+#[cfg(feature = "std")]
+mod std_support {
+ use super::*;
+ use std::borrow::Borrow;
+ use std::collections::{BTreeMap, HashMap};
+ use std::hash::{BuildHasher, Hash};
+ use std::rc::Rc;
+ use std::sync::Arc;
+
+ impl<S> Source for Box<S>
+ where
+ S: Source + ?Sized,
+ {
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ Source::visit(&**self, visitor)
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ Source::get(&**self, key)
+ }
+
+ fn count(&self) -> usize {
+ Source::count(&**self)
+ }
+ }
+
+ impl<S> Source for Arc<S>
+ where
+ S: Source + ?Sized,
+ {
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ Source::visit(&**self, visitor)
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ Source::get(&**self, key)
+ }
+
+ fn count(&self) -> usize {
+ Source::count(&**self)
+ }
+ }
+
+ impl<S> Source for Rc<S>
+ where
+ S: Source + ?Sized,
+ {
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ Source::visit(&**self, visitor)
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ Source::get(&**self, key)
+ }
+
+ fn count(&self) -> usize {
+ Source::count(&**self)
+ }
+ }
+
+ impl<S> Source for Vec<S>
+ where
+ S: Source,
+ {
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ Source::visit(&**self, visitor)
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ Source::get(&**self, key)
+ }
+
+ fn count(&self) -> usize {
+ Source::count(&**self)
+ }
+ }
+
+ impl<'kvs, V> VisitSource<'kvs> for Box<V>
+ where
+ V: VisitSource<'kvs> + ?Sized,
+ {
+ fn visit_pair(&mut self, key: Key<'kvs>, value: Value<'kvs>) -> Result<(), Error> {
+ (**self).visit_pair(key, value)
+ }
+ }
+
+ impl<K, V, S> Source for HashMap<K, V, S>
+ where
+ K: ToKey + Borrow<str> + Eq + Hash,
+ V: ToValue,
+ S: BuildHasher,
+ {
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ for (key, value) in self {
+ visitor.visit_pair(key.to_key(), value.to_value())?;
+ }
+ Ok(())
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ HashMap::get(self, key.as_str()).map(|v| v.to_value())
+ }
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+ }
+
+ impl<K, V> Source for BTreeMap<K, V>
+ where
+ K: ToKey + Borrow<str> + Ord,
+ V: ToValue,
+ {
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ for (key, value) in self {
+ visitor.visit_pair(key.to_key(), value.to_value())?;
+ }
+ Ok(())
+ }
+
+ fn get(&self, key: Key) -> Option<Value<'_>> {
+ BTreeMap::get(self, key.as_str()).map(|v| v.to_value())
+ }
+
+ fn count(&self) -> usize {
+ self.len()
+ }
+ }
+
+ #[cfg(test)]
+ mod tests {
+ use crate::kv::value;
+
+ use super::*;
+
+ #[test]
+ fn count() {
+ assert_eq!(1, Source::count(&Box::new(("a", 1))));
+ assert_eq!(2, Source::count(&vec![("a", 1), ("b", 2)]));
+ }
+
+ #[test]
+ fn get() {
+ let source = vec![("a", 1), ("b", 2), ("a", 1)];
+ assert_eq!(
+ value::inner::Token::I64(1),
+ Source::get(&source, Key::from_str("a")).unwrap().to_token()
+ );
+
+ let source = Box::new(None::<(&str, i32)>);
+ assert!(Source::get(&source, Key::from_str("a")).is_none());
+ }
+
+ #[test]
+ fn hash_map() {
+ let mut map = HashMap::new();
+ map.insert("a", 1);
+ map.insert("b", 2);
+
+ assert_eq!(2, Source::count(&map));
+ assert_eq!(
+ value::inner::Token::I64(1),
+ Source::get(&map, Key::from_str("a")).unwrap().to_token()
+ );
+ }
+
+ #[test]
+ fn btree_map() {
+ let mut map = BTreeMap::new();
+ map.insert("a", 1);
+ map.insert("b", 2);
+
+ assert_eq!(2, Source::count(&map));
+ assert_eq!(
+ value::inner::Token::I64(1),
+ Source::get(&map, Key::from_str("a")).unwrap().to_token()
+ );
+ }
+ }
+}
+
+// NOTE: Deprecated; but aliases can't carry this attribute
+#[cfg(feature = "kv_unstable")]
+pub use VisitSource as Visitor;
+
+#[cfg(test)]
+mod tests {
+ use crate::kv::value;
+
+ use super::*;
+
+ #[test]
+ fn source_is_object_safe() {
+ fn _check(_: &dyn Source) {}
+ }
+
+ #[test]
+ fn visitor_is_object_safe() {
+ fn _check(_: &dyn VisitSource) {}
+ }
+
+ #[test]
+ fn count() {
+ struct OnePair {
+ key: &'static str,
+ value: i32,
+ }
+
+ impl Source for OnePair {
+ fn visit<'kvs>(&'kvs self, visitor: &mut dyn VisitSource<'kvs>) -> Result<(), Error> {
+ visitor.visit_pair(self.key.to_key(), self.value.to_value())
+ }
+ }
+
+ assert_eq!(1, Source::count(&("a", 1)));
+ assert_eq!(2, Source::count(&[("a", 1), ("b", 2)] as &[_]));
+ assert_eq!(0, Source::count(&None::<(&str, i32)>));
+ assert_eq!(1, Source::count(&OnePair { key: "a", value: 1 }));
+ }
+
+ #[test]
+ fn get() {
+ let source = &[("a", 1), ("b", 2), ("a", 1)] as &[_];
+ assert_eq!(
+ value::inner::Token::I64(1),
+ Source::get(source, Key::from_str("a")).unwrap().to_token()
+ );
+ assert_eq!(
+ value::inner::Token::I64(2),
+ Source::get(source, Key::from_str("b")).unwrap().to_token()
+ );
+ assert!(Source::get(&source, Key::from_str("c")).is_none());
+
+ let source = None::<(&str, i32)>;
+ assert!(Source::get(&source, Key::from_str("a")).is_none());
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs
new file mode 100644
index 0000000..1511dd0
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/kv/value.rs
@@ -0,0 +1,1394 @@
+//! Structured values.
+//!
+//! This module defines the [`Value`] type and supporting APIs for
+//! capturing and serializing them.
+
+use std::fmt;
+
+pub use crate::kv::Error;
+
+/// A type that can be converted into a [`Value`](struct.Value.html).
+pub trait ToValue {
+ /// Perform the conversion.
+ fn to_value(&self) -> Value;
+}
+
+impl<'a, T> ToValue for &'a T
+where
+ T: ToValue + ?Sized,
+{
+ fn to_value(&self) -> Value {
+ (**self).to_value()
+ }
+}
+
+impl<'v> ToValue for Value<'v> {
+ fn to_value(&self) -> Value {
+ Value {
+ inner: self.inner.clone(),
+ }
+ }
+}
+
+/// A value in a key-value.
+///
+/// Values are an anonymous bag containing some structured datum.
+///
+/// # Capturing values
+///
+/// There are a few ways to capture a value:
+///
+/// - Using the `Value::from_*` methods.
+/// - Using the `ToValue` trait.
+/// - Using the standard `From` trait.
+///
+/// ## Using the `Value::from_*` methods
+///
+/// `Value` offers a few constructor methods that capture values of different kinds.
+///
+/// ```
+/// use log::kv::Value;
+///
+/// let value = Value::from_debug(&42i32);
+///
+/// assert_eq!(None, value.to_i64());
+/// ```
+///
+/// ## Using the `ToValue` trait
+///
+/// The `ToValue` trait can be used to capture values generically.
+/// It's the bound used by `Source`.
+///
+/// ```
+/// # use log::kv::ToValue;
+/// let value = 42i32.to_value();
+///
+/// assert_eq!(Some(42), value.to_i64());
+/// ```
+///
+/// ## Using the standard `From` trait
+///
+/// Standard types that implement `ToValue` also implement `From`.
+///
+/// ```
+/// use log::kv::Value;
+///
+/// let value = Value::from(42i32);
+///
+/// assert_eq!(Some(42), value.to_i64());
+/// ```
+///
+/// # Data model
+///
+/// Values can hold one of a number of types:
+///
+/// - **Null:** The absence of any other meaningful value. Note that
+/// `Some(Value::null())` is not the same as `None`. The former is
+/// `null` while the latter is `undefined`. This is important to be
+/// able to tell the difference between a key-value that was logged,
+/// but its value was empty (`Some(Value::null())`) and a key-value
+/// that was never logged at all (`None`).
+/// - **Strings:** `str`, `char`.
+/// - **Booleans:** `bool`.
+/// - **Integers:** `u8`-`u128`, `i8`-`i128`, `NonZero*`.
+/// - **Floating point numbers:** `f32`-`f64`.
+/// - **Errors:** `dyn (Error + 'static)`.
+/// - **`serde`:** Any type in `serde`'s data model.
+/// - **`sval`:** Any type in `sval`'s data model.
+///
+/// # Serialization
+///
+/// Values provide a number of ways to be serialized.
+///
+/// For basic types the [`Value::visit`] method can be used to extract the
+/// underlying typed value. However this is limited in the amount of types
+/// supported (see the [`VisitValue`] trait methods).
+///
+/// For more complex types one of the following traits can be used:
+/// * `sval::Value`, requires the `kv_sval` feature.
+/// * `serde::Serialize`, requires the `kv_serde` feature.
+///
+/// You don't need a visitor to serialize values through `serde` or `sval`.
+///
+/// A value can always be serialized using any supported framework, regardless
+/// of how it was captured. If, for example, a value was captured using its
+/// `Display` implementation, it will serialize through `serde` as a string. If it was
+/// captured as a struct using `serde`, it will also serialize as a struct
+/// through `sval`, or can be formatted using a `Debug`-compatible representation.
+pub struct Value<'v> {
+ inner: inner::Inner<'v>,
+}
+
+impl<'v> Value<'v> {
+ /// Get a value from a type implementing `ToValue`.
+ pub fn from_any<T>(value: &'v T) -> Self
+ where
+ T: ToValue,
+ {
+ value.to_value()
+ }
+
+ /// Get a value from a type implementing `std::fmt::Debug`.
+ pub fn from_debug<T>(value: &'v T) -> Self
+ where
+ T: fmt::Debug,
+ {
+ Value {
+ inner: inner::Inner::from_debug(value),
+ }
+ }
+
+ /// Get a value from a type implementing `std::fmt::Display`.
+ pub fn from_display<T>(value: &'v T) -> Self
+ where
+ T: fmt::Display,
+ {
+ Value {
+ inner: inner::Inner::from_display(value),
+ }
+ }
+
+ /// Get a value from a type implementing `serde::Serialize`.
+ #[cfg(feature = "kv_serde")]
+ pub fn from_serde<T>(value: &'v T) -> Self
+ where
+ T: serde::Serialize,
+ {
+ Value {
+ inner: inner::Inner::from_serde1(value),
+ }
+ }
+
+ /// Get a value from a type implementing `sval::Value`.
+ #[cfg(feature = "kv_sval")]
+ pub fn from_sval<T>(value: &'v T) -> Self
+ where
+ T: sval::Value,
+ {
+ Value {
+ inner: inner::Inner::from_sval2(value),
+ }
+ }
+
+ /// Get a value from a dynamic `std::fmt::Debug`.
+ pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self {
+ Value {
+ inner: inner::Inner::from_dyn_debug(value),
+ }
+ }
+
+ /// Get a value from a dynamic `std::fmt::Display`.
+ pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self {
+ Value {
+ inner: inner::Inner::from_dyn_display(value),
+ }
+ }
+
+ /// Get a value from a dynamic error.
+ #[cfg(feature = "kv_std")]
+ pub fn from_dyn_error(err: &'v (dyn std::error::Error + 'static)) -> Self {
+ Value {
+ inner: inner::Inner::from_dyn_error(err),
+ }
+ }
+
+ /// Get a `null` value.
+ pub fn null() -> Self {
+ Value {
+ inner: inner::Inner::empty(),
+ }
+ }
+
+ /// Get a value from an internal primitive.
+ fn from_inner<T>(value: T) -> Self
+ where
+ T: Into<inner::Inner<'v>>,
+ {
+ Value {
+ inner: value.into(),
+ }
+ }
+
+ /// Inspect this value using a simple visitor.
+ ///
+ /// When the `kv_serde` or `kv_sval` features are enabled, you can also
+ /// serialize a value using its `Serialize` or `Value` implementation.
+ pub fn visit(&self, visitor: impl VisitValue<'v>) -> Result<(), Error> {
+ inner::visit(&self.inner, visitor)
+ }
+}
+
+impl<'v> fmt::Debug for Value<'v> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, f)
+ }
+}
+
+impl<'v> fmt::Display for Value<'v> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&self.inner, f)
+ }
+}
+
+#[cfg(feature = "kv_serde")]
+impl<'v> serde::Serialize for Value<'v> {
+ fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ self.inner.serialize(s)
+ }
+}
+
+#[cfg(feature = "kv_sval")]
+impl<'v> sval::Value for Value<'v> {
+ fn stream<'sval, S: sval::Stream<'sval> + ?Sized>(&'sval self, stream: &mut S) -> sval::Result {
+ sval::Value::stream(&self.inner, stream)
+ }
+}
+
+#[cfg(feature = "kv_sval")]
+impl<'v> sval_ref::ValueRef<'v> for Value<'v> {
+ fn stream_ref<S: sval::Stream<'v> + ?Sized>(&self, stream: &mut S) -> sval::Result {
+ sval_ref::ValueRef::stream_ref(&self.inner, stream)
+ }
+}
+
+impl ToValue for str {
+ fn to_value(&self) -> Value {
+ Value::from(self)
+ }
+}
+
+impl<'v> From<&'v str> for Value<'v> {
+ fn from(value: &'v str) -> Self {
+ Value::from_inner(value)
+ }
+}
+
+impl ToValue for () {
+ fn to_value(&self) -> Value {
+ Value::from_inner(())
+ }
+}
+
+impl<T> ToValue for Option<T>
+where
+ T: ToValue,
+{
+ fn to_value(&self) -> Value {
+ match *self {
+ Some(ref value) => value.to_value(),
+ None => Value::from_inner(()),
+ }
+ }
+}
+
+macro_rules! impl_to_value_primitive {
+ ($($into_ty:ty,)*) => {
+ $(
+ impl ToValue for $into_ty {
+ fn to_value(&self) -> Value {
+ Value::from(*self)
+ }
+ }
+
+ impl<'v> From<$into_ty> for Value<'v> {
+ fn from(value: $into_ty) -> Self {
+ Value::from_inner(value)
+ }
+ }
+
+ impl<'v> From<&'v $into_ty> for Value<'v> {
+ fn from(value: &'v $into_ty) -> Self {
+ Value::from_inner(*value)
+ }
+ }
+ )*
+ };
+}
+
+macro_rules! impl_to_value_nonzero_primitive {
+ ($($into_ty:ident,)*) => {
+ $(
+ impl ToValue for std::num::$into_ty {
+ fn to_value(&self) -> Value {
+ Value::from(self.get())
+ }
+ }
+
+ impl<'v> From<std::num::$into_ty> for Value<'v> {
+ fn from(value: std::num::$into_ty) -> Self {
+ Value::from(value.get())
+ }
+ }
+
+ impl<'v> From<&'v std::num::$into_ty> for Value<'v> {
+ fn from(value: &'v std::num::$into_ty) -> Self {
+ Value::from(value.get())
+ }
+ }
+ )*
+ };
+}
+
+macro_rules! impl_value_to_primitive {
+ ($(#[doc = $doc:tt] $into_name:ident -> $into_ty:ty,)*) => {
+ impl<'v> Value<'v> {
+ $(
+ #[doc = $doc]
+ pub fn $into_name(&self) -> Option<$into_ty> {
+ self.inner.$into_name()
+ }
+ )*
+ }
+ }
+}
+
+impl_to_value_primitive![
+ usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64, char, bool,
+];
+
+#[rustfmt::skip]
+impl_to_value_nonzero_primitive![
+ NonZeroUsize, NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128,
+ NonZeroIsize, NonZeroI8, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI128,
+];
+
+impl_value_to_primitive![
+ #[doc = "Try convert this value into a `u64`."]
+ to_u64 -> u64,
+ #[doc = "Try convert this value into a `i64`."]
+ to_i64 -> i64,
+ #[doc = "Try convert this value into a `u128`."]
+ to_u128 -> u128,
+ #[doc = "Try convert this value into a `i128`."]
+ to_i128 -> i128,
+ #[doc = "Try convert this value into a `f64`."]
+ to_f64 -> f64,
+ #[doc = "Try convert this value into a `char`."]
+ to_char -> char,
+ #[doc = "Try convert this value into a `bool`."]
+ to_bool -> bool,
+];
+
+impl<'v> Value<'v> {
+ /// Try convert this value into an error.
+ #[cfg(feature = "kv_std")]
+ pub fn to_borrowed_error(&self) -> Option<&(dyn std::error::Error + 'static)> {
+ self.inner.to_borrowed_error()
+ }
+
+ /// Try convert this value into a borrowed string.
+ pub fn to_borrowed_str(&self) -> Option<&str> {
+ self.inner.to_borrowed_str()
+ }
+}
+
+#[cfg(feature = "kv_std")]
+mod std_support {
+ use std::borrow::Cow;
+ use std::rc::Rc;
+ use std::sync::Arc;
+
+ use super::*;
+
+ impl<T> ToValue for Box<T>
+ where
+ T: ToValue + ?Sized,
+ {
+ fn to_value(&self) -> Value {
+ (**self).to_value()
+ }
+ }
+
+ impl<T> ToValue for Arc<T>
+ where
+ T: ToValue + ?Sized,
+ {
+ fn to_value(&self) -> Value {
+ (**self).to_value()
+ }
+ }
+
+ impl<T> ToValue for Rc<T>
+ where
+ T: ToValue + ?Sized,
+ {
+ fn to_value(&self) -> Value {
+ (**self).to_value()
+ }
+ }
+
+ impl ToValue for String {
+ fn to_value(&self) -> Value {
+ Value::from(&**self)
+ }
+ }
+
+ impl<'v> ToValue for Cow<'v, str> {
+ fn to_value(&self) -> Value {
+ Value::from(&**self)
+ }
+ }
+
+ impl<'v> Value<'v> {
+ /// Try convert this value into a string.
+ pub fn to_cow_str(&self) -> Option<Cow<'v, str>> {
+ self.inner.to_str()
+ }
+ }
+
+ impl<'v> From<&'v String> for Value<'v> {
+ fn from(v: &'v String) -> Self {
+ Value::from(&**v)
+ }
+ }
+}
+
+/// A visitor for a [`Value`].
+///
+/// Also see [`Value`'s documentation on seralization]. Value visitors are a simple alternative
+/// to a more fully-featured serialization framework like `serde` or `sval`. A value visitor
+/// can differentiate primitive types through methods like [`VisitValue::visit_bool`] and
+/// [`VisitValue::visit_str`], but more complex types like maps and sequences
+/// will fallthrough to [`VisitValue::visit_any`].
+///
+/// If you're trying to serialize a value to a format like JSON, you can use either `serde`
+/// or `sval` directly with the value. You don't need a visitor.
+///
+/// [`Value`'s documentation on seralization]: Value#serialization
+pub trait VisitValue<'v> {
+ /// Visit a `Value`.
+ ///
+ /// This is the only required method on `VisitValue` and acts as a fallback for any
+ /// more specific methods that aren't overridden.
+ /// The `Value` may be formatted using its `fmt::Debug` or `fmt::Display` implementation,
+ /// or serialized using its `sval::Value` or `serde::Serialize` implementation.
+ fn visit_any(&mut self, value: Value) -> Result<(), Error>;
+
+ /// Visit an empty value.
+ fn visit_null(&mut self) -> Result<(), Error> {
+ self.visit_any(Value::null())
+ }
+
+ /// Visit an unsigned integer.
+ fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
+ self.visit_any(value.into())
+ }
+
+ /// Visit a signed integer.
+ fn visit_i64(&mut self, value: i64) -> Result<(), Error> {
+ self.visit_any(value.into())
+ }
+
+ /// Visit a big unsigned integer.
+ fn visit_u128(&mut self, value: u128) -> Result<(), Error> {
+ self.visit_any((value).into())
+ }
+
+ /// Visit a big signed integer.
+ fn visit_i128(&mut self, value: i128) -> Result<(), Error> {
+ self.visit_any((value).into())
+ }
+
+ /// Visit a floating point.
+ fn visit_f64(&mut self, value: f64) -> Result<(), Error> {
+ self.visit_any(value.into())
+ }
+
+ /// Visit a boolean.
+ fn visit_bool(&mut self, value: bool) -> Result<(), Error> {
+ self.visit_any(value.into())
+ }
+
+ /// Visit a string.
+ fn visit_str(&mut self, value: &str) -> Result<(), Error> {
+ self.visit_any(value.into())
+ }
+
+ /// Visit a string.
+ fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
+ self.visit_str(value)
+ }
+
+ /// Visit a Unicode character.
+ fn visit_char(&mut self, value: char) -> Result<(), Error> {
+ let mut b = [0; 4];
+ self.visit_str(&*value.encode_utf8(&mut b))
+ }
+
+ /// Visit an error.
+ #[cfg(feature = "kv_std")]
+ fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> {
+ self.visit_any(Value::from_dyn_error(err))
+ }
+
+ /// Visit an error.
+ #[cfg(feature = "kv_std")]
+ fn visit_borrowed_error(
+ &mut self,
+ err: &'v (dyn std::error::Error + 'static),
+ ) -> Result<(), Error> {
+ self.visit_any(Value::from_dyn_error(err))
+ }
+}
+
+impl<'a, 'v, T: ?Sized> VisitValue<'v> for &'a mut T
+where
+ T: VisitValue<'v>,
+{
+ fn visit_any(&mut self, value: Value) -> Result<(), Error> {
+ (**self).visit_any(value)
+ }
+
+ fn visit_null(&mut self) -> Result<(), Error> {
+ (**self).visit_null()
+ }
+
+ fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
+ (**self).visit_u64(value)
+ }
+
+ fn visit_i64(&mut self, value: i64) -> Result<(), Error> {
+ (**self).visit_i64(value)
+ }
+
+ fn visit_u128(&mut self, value: u128) -> Result<(), Error> {
+ (**self).visit_u128(value)
+ }
+
+ fn visit_i128(&mut self, value: i128) -> Result<(), Error> {
+ (**self).visit_i128(value)
+ }
+
+ fn visit_f64(&mut self, value: f64) -> Result<(), Error> {
+ (**self).visit_f64(value)
+ }
+
+ fn visit_bool(&mut self, value: bool) -> Result<(), Error> {
+ (**self).visit_bool(value)
+ }
+
+ fn visit_str(&mut self, value: &str) -> Result<(), Error> {
+ (**self).visit_str(value)
+ }
+
+ fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
+ (**self).visit_borrowed_str(value)
+ }
+
+ fn visit_char(&mut self, value: char) -> Result<(), Error> {
+ (**self).visit_char(value)
+ }
+
+ #[cfg(feature = "kv_std")]
+ fn visit_error(&mut self, err: &(dyn std::error::Error + 'static)) -> Result<(), Error> {
+ (**self).visit_error(err)
+ }
+
+ #[cfg(feature = "kv_std")]
+ fn visit_borrowed_error(
+ &mut self,
+ err: &'v (dyn std::error::Error + 'static),
+ ) -> Result<(), Error> {
+ (**self).visit_borrowed_error(err)
+ }
+}
+
+#[cfg(feature = "value-bag")]
+pub(in crate::kv) mod inner {
+ /**
+ An implementation of `Value` based on a library called `value_bag`.
+
+ `value_bag` was written specifically for use in `log`'s value, but was split out when it outgrew
+ the codebase here. It's a general-purpose type-erasure library that handles mapping between
+ more fully-featured serialization frameworks.
+ */
+ use super::*;
+
+ pub use value_bag::ValueBag as Inner;
+
+ pub use value_bag::Error;
+
+ #[cfg(test)]
+ pub use value_bag::test::TestToken as Token;
+
+ pub fn visit<'v>(
+ inner: &Inner<'v>,
+ visitor: impl VisitValue<'v>,
+ ) -> Result<(), crate::kv::Error> {
+ struct InnerVisitValue<V>(V);
+
+ impl<'v, V> value_bag::visit::Visit<'v> for InnerVisitValue<V>
+ where
+ V: VisitValue<'v>,
+ {
+ fn visit_any(&mut self, value: value_bag::ValueBag) -> Result<(), Error> {
+ self.0
+ .visit_any(Value { inner: value })
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_empty(&mut self) -> Result<(), Error> {
+ self.0.visit_null().map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
+ self.0
+ .visit_u64(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_i64(&mut self, value: i64) -> Result<(), Error> {
+ self.0
+ .visit_i64(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_u128(&mut self, value: u128) -> Result<(), Error> {
+ self.0
+ .visit_u128(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_i128(&mut self, value: i128) -> Result<(), Error> {
+ self.0
+ .visit_i128(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_f64(&mut self, value: f64) -> Result<(), Error> {
+ self.0
+ .visit_f64(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_bool(&mut self, value: bool) -> Result<(), Error> {
+ self.0
+ .visit_bool(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_str(&mut self, value: &str) -> Result<(), Error> {
+ self.0
+ .visit_str(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
+ self.0
+ .visit_borrowed_str(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ fn visit_char(&mut self, value: char) -> Result<(), Error> {
+ self.0
+ .visit_char(value)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ #[cfg(feature = "kv_std")]
+ fn visit_error(
+ &mut self,
+ err: &(dyn std::error::Error + 'static),
+ ) -> Result<(), Error> {
+ self.0
+ .visit_error(err)
+ .map_err(crate::kv::Error::into_value)
+ }
+
+ #[cfg(feature = "kv_std")]
+ fn visit_borrowed_error(
+ &mut self,
+ err: &'v (dyn std::error::Error + 'static),
+ ) -> Result<(), Error> {
+ self.0
+ .visit_borrowed_error(err)
+ .map_err(crate::kv::Error::into_value)
+ }
+ }
+
+ inner
+ .visit(&mut InnerVisitValue(visitor))
+ .map_err(crate::kv::Error::from_value)
+ }
+}
+
+#[cfg(not(feature = "value-bag"))]
+pub(in crate::kv) mod inner {
+ /**
+ This is a dependency-free implementation of `Value` when there's no serialization frameworks involved.
+ In these simple cases a more fully featured solution like `value_bag` isn't needed, so we avoid pulling it in.
+
+ There are a few things here that need to remain consistent with the `value_bag`-based implementation:
+
+ 1. Conversions should always produce the same results. If a conversion here returns `Some`, then
+ the same `value_bag`-based conversion must also. Of particular note here are floats to ints; they're
+ based on the standard library's `TryInto` conversions, which need to be convert to `i32` or `u32`,
+ and then to `f64`.
+ 2. VisitValues should always be called in the same way. If a particular type of value calls `visit_i64`,
+ then the same `value_bag`-based visitor must also.
+ */
+ use super::*;
+
+ #[derive(Clone)]
+ pub enum Inner<'v> {
+ None,
+ Bool(bool),
+ Str(&'v str),
+ Char(char),
+ I64(i64),
+ U64(u64),
+ F64(f64),
+ I128(i128),
+ U128(u128),
+ Debug(&'v dyn fmt::Debug),
+ Display(&'v dyn fmt::Display),
+ }
+
+ impl<'v> From<()> for Inner<'v> {
+ fn from(_: ()) -> Self {
+ Inner::None
+ }
+ }
+
+ impl<'v> From<bool> for Inner<'v> {
+ fn from(v: bool) -> Self {
+ Inner::Bool(v)
+ }
+ }
+
+ impl<'v> From<char> for Inner<'v> {
+ fn from(v: char) -> Self {
+ Inner::Char(v)
+ }
+ }
+
+ impl<'v> From<f32> for Inner<'v> {
+ fn from(v: f32) -> Self {
+ Inner::F64(v as f64)
+ }
+ }
+
+ impl<'v> From<f64> for Inner<'v> {
+ fn from(v: f64) -> Self {
+ Inner::F64(v)
+ }
+ }
+
+ impl<'v> From<i8> for Inner<'v> {
+ fn from(v: i8) -> Self {
+ Inner::I64(v as i64)
+ }
+ }
+
+ impl<'v> From<i16> for Inner<'v> {
+ fn from(v: i16) -> Self {
+ Inner::I64(v as i64)
+ }
+ }
+
+ impl<'v> From<i32> for Inner<'v> {
+ fn from(v: i32) -> Self {
+ Inner::I64(v as i64)
+ }
+ }
+
+ impl<'v> From<i64> for Inner<'v> {
+ fn from(v: i64) -> Self {
+ Inner::I64(v as i64)
+ }
+ }
+
+ impl<'v> From<isize> for Inner<'v> {
+ fn from(v: isize) -> Self {
+ Inner::I64(v as i64)
+ }
+ }
+
+ impl<'v> From<u8> for Inner<'v> {
+ fn from(v: u8) -> Self {
+ Inner::U64(v as u64)
+ }
+ }
+
+ impl<'v> From<u16> for Inner<'v> {
+ fn from(v: u16) -> Self {
+ Inner::U64(v as u64)
+ }
+ }
+
+ impl<'v> From<u32> for Inner<'v> {
+ fn from(v: u32) -> Self {
+ Inner::U64(v as u64)
+ }
+ }
+
+ impl<'v> From<u64> for Inner<'v> {
+ fn from(v: u64) -> Self {
+ Inner::U64(v as u64)
+ }
+ }
+
+ impl<'v> From<usize> for Inner<'v> {
+ fn from(v: usize) -> Self {
+ Inner::U64(v as u64)
+ }
+ }
+
+ impl<'v> From<i128> for Inner<'v> {
+ fn from(v: i128) -> Self {
+ Inner::I128(v)
+ }
+ }
+
+ impl<'v> From<u128> for Inner<'v> {
+ fn from(v: u128) -> Self {
+ Inner::U128(v)
+ }
+ }
+
+ impl<'v> From<&'v str> for Inner<'v> {
+ fn from(v: &'v str) -> Self {
+ Inner::Str(v)
+ }
+ }
+
+ impl<'v> fmt::Debug for Inner<'v> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Inner::None => fmt::Debug::fmt(&None::<()>, f),
+ Inner::Bool(v) => fmt::Debug::fmt(v, f),
+ Inner::Str(v) => fmt::Debug::fmt(v, f),
+ Inner::Char(v) => fmt::Debug::fmt(v, f),
+ Inner::I64(v) => fmt::Debug::fmt(v, f),
+ Inner::U64(v) => fmt::Debug::fmt(v, f),
+ Inner::F64(v) => fmt::Debug::fmt(v, f),
+ Inner::I128(v) => fmt::Debug::fmt(v, f),
+ Inner::U128(v) => fmt::Debug::fmt(v, f),
+ Inner::Debug(v) => fmt::Debug::fmt(v, f),
+ Inner::Display(v) => fmt::Display::fmt(v, f),
+ }
+ }
+ }
+
+ impl<'v> fmt::Display for Inner<'v> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Inner::None => fmt::Debug::fmt(&None::<()>, f),
+ Inner::Bool(v) => fmt::Display::fmt(v, f),
+ Inner::Str(v) => fmt::Display::fmt(v, f),
+ Inner::Char(v) => fmt::Display::fmt(v, f),
+ Inner::I64(v) => fmt::Display::fmt(v, f),
+ Inner::U64(v) => fmt::Display::fmt(v, f),
+ Inner::F64(v) => fmt::Display::fmt(v, f),
+ Inner::I128(v) => fmt::Display::fmt(v, f),
+ Inner::U128(v) => fmt::Display::fmt(v, f),
+ Inner::Debug(v) => fmt::Debug::fmt(v, f),
+ Inner::Display(v) => fmt::Display::fmt(v, f),
+ }
+ }
+ }
+
+ impl<'v> Inner<'v> {
+ pub fn from_debug<T: fmt::Debug>(value: &'v T) -> Self {
+ Inner::Debug(value)
+ }
+
+ pub fn from_display<T: fmt::Display>(value: &'v T) -> Self {
+ Inner::Display(value)
+ }
+
+ pub fn from_dyn_debug(value: &'v dyn fmt::Debug) -> Self {
+ Inner::Debug(value)
+ }
+
+ pub fn from_dyn_display(value: &'v dyn fmt::Display) -> Self {
+ Inner::Display(value)
+ }
+
+ pub fn empty() -> Self {
+ Inner::None
+ }
+
+ pub fn to_bool(&self) -> Option<bool> {
+ match self {
+ Inner::Bool(v) => Some(*v),
+ _ => None,
+ }
+ }
+
+ pub fn to_char(&self) -> Option<char> {
+ match self {
+ Inner::Char(v) => Some(*v),
+ _ => None,
+ }
+ }
+
+ pub fn to_f64(&self) -> Option<f64> {
+ match self {
+ Inner::F64(v) => Some(*v),
+ Inner::I64(v) => {
+ let v: i32 = (*v).try_into().ok()?;
+ v.try_into().ok()
+ }
+ Inner::U64(v) => {
+ let v: u32 = (*v).try_into().ok()?;
+ v.try_into().ok()
+ }
+ Inner::I128(v) => {
+ let v: i32 = (*v).try_into().ok()?;
+ v.try_into().ok()
+ }
+ Inner::U128(v) => {
+ let v: u32 = (*v).try_into().ok()?;
+ v.try_into().ok()
+ }
+ _ => None,
+ }
+ }
+
+ pub fn to_i64(&self) -> Option<i64> {
+ match self {
+ Inner::I64(v) => Some(*v),
+ Inner::U64(v) => (*v).try_into().ok(),
+ Inner::I128(v) => (*v).try_into().ok(),
+ Inner::U128(v) => (*v).try_into().ok(),
+ _ => None,
+ }
+ }
+
+ pub fn to_u64(&self) -> Option<u64> {
+ match self {
+ Inner::U64(v) => Some(*v),
+ Inner::I64(v) => (*v).try_into().ok(),
+ Inner::I128(v) => (*v).try_into().ok(),
+ Inner::U128(v) => (*v).try_into().ok(),
+ _ => None,
+ }
+ }
+
+ pub fn to_u128(&self) -> Option<u128> {
+ match self {
+ Inner::U128(v) => Some(*v),
+ Inner::I64(v) => (*v).try_into().ok(),
+ Inner::U64(v) => (*v).try_into().ok(),
+ Inner::I128(v) => (*v).try_into().ok(),
+ _ => None,
+ }
+ }
+
+ pub fn to_i128(&self) -> Option<i128> {
+ match self {
+ Inner::I128(v) => Some(*v),
+ Inner::I64(v) => (*v).try_into().ok(),
+ Inner::U64(v) => (*v).try_into().ok(),
+ Inner::U128(v) => (*v).try_into().ok(),
+ _ => None,
+ }
+ }
+
+ pub fn to_borrowed_str(&self) -> Option<&'v str> {
+ match self {
+ Inner::Str(v) => Some(v),
+ _ => None,
+ }
+ }
+
+ #[cfg(test)]
+ pub fn to_test_token(&self) -> Token {
+ match self {
+ Inner::None => Token::None,
+ Inner::Bool(v) => Token::Bool(*v),
+ Inner::Str(v) => Token::Str(*v),
+ Inner::Char(v) => Token::Char(*v),
+ Inner::I64(v) => Token::I64(*v),
+ Inner::U64(v) => Token::U64(*v),
+ Inner::F64(v) => Token::F64(*v),
+ Inner::I128(_) => unimplemented!(),
+ Inner::U128(_) => unimplemented!(),
+ Inner::Debug(_) => unimplemented!(),
+ Inner::Display(_) => unimplemented!(),
+ }
+ }
+ }
+
+ #[cfg(test)]
+ #[derive(Debug, PartialEq)]
+ pub enum Token<'v> {
+ None,
+ Bool(bool),
+ Char(char),
+ Str(&'v str),
+ F64(f64),
+ I64(i64),
+ U64(u64),
+ }
+
+ pub fn visit<'v>(
+ inner: &Inner<'v>,
+ mut visitor: impl VisitValue<'v>,
+ ) -> Result<(), crate::kv::Error> {
+ match inner {
+ Inner::None => visitor.visit_null(),
+ Inner::Bool(v) => visitor.visit_bool(*v),
+ Inner::Str(v) => visitor.visit_borrowed_str(*v),
+ Inner::Char(v) => visitor.visit_char(*v),
+ Inner::I64(v) => visitor.visit_i64(*v),
+ Inner::U64(v) => visitor.visit_u64(*v),
+ Inner::F64(v) => visitor.visit_f64(*v),
+ Inner::I128(v) => visitor.visit_i128(*v),
+ Inner::U128(v) => visitor.visit_u128(*v),
+ Inner::Debug(v) => visitor.visit_any(Value::from_dyn_debug(*v)),
+ Inner::Display(v) => visitor.visit_any(Value::from_dyn_display(*v)),
+ }
+ }
+}
+
+impl<'v> Value<'v> {
+ /// Get a value from a type implementing `std::fmt::Debug`.
+ #[cfg(feature = "kv_unstable")]
+ #[deprecated(note = "use `from_debug` instead")]
+ pub fn capture_debug<T>(value: &'v T) -> Self
+ where
+ T: fmt::Debug + 'static,
+ {
+ Value::from_debug(value)
+ }
+
+ /// Get a value from a type implementing `std::fmt::Display`.
+ #[cfg(feature = "kv_unstable")]
+ #[deprecated(note = "use `from_display` instead")]
+ pub fn capture_display<T>(value: &'v T) -> Self
+ where
+ T: fmt::Display + 'static,
+ {
+ Value::from_display(value)
+ }
+
+ /// Get a value from an error.
+ #[cfg(feature = "kv_unstable_std")]
+ #[deprecated(note = "use `from_dyn_error` instead")]
+ pub fn capture_error<T>(err: &'v T) -> Self
+ where
+ T: std::error::Error + 'static,
+ {
+ Value::from_dyn_error(err)
+ }
+
+ /// Get a value from a type implementing `serde::Serialize`.
+ #[cfg(feature = "kv_unstable_serde")]
+ #[deprecated(note = "use `from_serde` instead")]
+ pub fn capture_serde<T>(value: &'v T) -> Self
+ where
+ T: serde::Serialize + 'static,
+ {
+ Value::from_serde(value)
+ }
+
+ /// Get a value from a type implementing `sval::Value`.
+ #[cfg(feature = "kv_unstable_sval")]
+ #[deprecated(note = "use `from_sval` instead")]
+ pub fn capture_sval<T>(value: &'v T) -> Self
+ where
+ T: sval::Value + 'static,
+ {
+ Value::from_sval(value)
+ }
+
+ /// Check whether this value can be downcast to `T`.
+ #[cfg(feature = "kv_unstable")]
+ #[deprecated(
+ note = "downcasting has been removed; log an issue at https://github.com/rust-lang/log/issues if this is something you rely on"
+ )]
+ pub fn is<T: 'static>(&self) -> bool {
+ false
+ }
+
+ /// Try downcast this value to `T`.
+ #[cfg(feature = "kv_unstable")]
+ #[deprecated(
+ note = "downcasting has been removed; log an issue at https://github.com/rust-lang/log/issues if this is something you rely on"
+ )]
+ pub fn downcast_ref<T: 'static>(&self) -> Option<&T> {
+ None
+ }
+}
+
+// NOTE: Deprecated; but aliases can't carry this attribute
+#[cfg(feature = "kv_unstable")]
+pub use VisitValue as Visit;
+
+/// Get a value from a type implementing `std::fmt::Debug`.
+#[cfg(feature = "kv_unstable")]
+#[deprecated(note = "use the `key:? = value` macro syntax instead")]
+#[macro_export]
+macro_rules! as_debug {
+ ($capture:expr) => {
+ $crate::kv::Value::from_debug(&$capture)
+ };
+}
+
+/// Get a value from a type implementing `std::fmt::Display`.
+#[cfg(feature = "kv_unstable")]
+#[deprecated(note = "use the `key:% = value` macro syntax instead")]
+#[macro_export]
+macro_rules! as_display {
+ ($capture:expr) => {
+ $crate::kv::Value::from_display(&$capture)
+ };
+}
+
+/// Get a value from an error.
+#[cfg(feature = "kv_unstable_std")]
+#[deprecated(note = "use the `key:err = value` macro syntax instead")]
+#[macro_export]
+macro_rules! as_error {
+ ($capture:expr) => {
+ $crate::kv::Value::from_dyn_error(&$capture)
+ };
+}
+
+#[cfg(feature = "kv_unstable_serde")]
+#[deprecated(note = "use the `key:serde = value` macro syntax instead")]
+/// Get a value from a type implementing `serde::Serialize`.
+#[macro_export]
+macro_rules! as_serde {
+ ($capture:expr) => {
+ $crate::kv::Value::from_serde(&$capture)
+ };
+}
+
+/// Get a value from a type implementing `sval::Value`.
+#[cfg(feature = "kv_unstable_sval")]
+#[deprecated(note = "use the `key:sval = value` macro syntax instead")]
+#[macro_export]
+macro_rules! as_sval {
+ ($capture:expr) => {
+ $crate::kv::Value::from_sval(&$capture)
+ };
+}
+
+#[cfg(test)]
+pub(crate) mod tests {
+ use super::*;
+
+ impl<'v> Value<'v> {
+ pub(crate) fn to_token(&self) -> inner::Token {
+ self.inner.to_test_token()
+ }
+ }
+
+ fn unsigned() -> impl Iterator<Item = Value<'static>> {
+ vec![
+ Value::from(8u8),
+ Value::from(16u16),
+ Value::from(32u32),
+ Value::from(64u64),
+ Value::from(1usize),
+ Value::from(std::num::NonZeroU8::new(8).unwrap()),
+ Value::from(std::num::NonZeroU16::new(16).unwrap()),
+ Value::from(std::num::NonZeroU32::new(32).unwrap()),
+ Value::from(std::num::NonZeroU64::new(64).unwrap()),
+ Value::from(std::num::NonZeroUsize::new(1).unwrap()),
+ ]
+ .into_iter()
+ }
+
+ fn signed() -> impl Iterator<Item = Value<'static>> {
+ vec![
+ Value::from(-8i8),
+ Value::from(-16i16),
+ Value::from(-32i32),
+ Value::from(-64i64),
+ Value::from(-1isize),
+ Value::from(std::num::NonZeroI8::new(-8).unwrap()),
+ Value::from(std::num::NonZeroI16::new(-16).unwrap()),
+ Value::from(std::num::NonZeroI32::new(-32).unwrap()),
+ Value::from(std::num::NonZeroI64::new(-64).unwrap()),
+ Value::from(std::num::NonZeroIsize::new(-1).unwrap()),
+ ]
+ .into_iter()
+ }
+
+ fn float() -> impl Iterator<Item = Value<'static>> {
+ vec![Value::from(32.32f32), Value::from(64.64f64)].into_iter()
+ }
+
+ fn bool() -> impl Iterator<Item = Value<'static>> {
+ vec![Value::from(true), Value::from(false)].into_iter()
+ }
+
+ fn str() -> impl Iterator<Item = Value<'static>> {
+ vec![Value::from("a string"), Value::from("a loong string")].into_iter()
+ }
+
+ fn char() -> impl Iterator<Item = Value<'static>> {
+ vec![Value::from('a'), Value::from('â›°')].into_iter()
+ }
+
+ #[test]
+ fn test_to_value_display() {
+ assert_eq!(42u64.to_value().to_string(), "42");
+ assert_eq!(42i64.to_value().to_string(), "42");
+ assert_eq!(42.01f64.to_value().to_string(), "42.01");
+ assert_eq!(true.to_value().to_string(), "true");
+ assert_eq!('a'.to_value().to_string(), "a");
+ assert_eq!("a loong string".to_value().to_string(), "a loong string");
+ assert_eq!(Some(true).to_value().to_string(), "true");
+ assert_eq!(().to_value().to_string(), "None");
+ assert_eq!(None::<bool>.to_value().to_string(), "None");
+ }
+
+ #[test]
+ fn test_to_value_structured() {
+ assert_eq!(42u64.to_value().to_token(), inner::Token::U64(42));
+ assert_eq!(42i64.to_value().to_token(), inner::Token::I64(42));
+ assert_eq!(42.01f64.to_value().to_token(), inner::Token::F64(42.01));
+ assert_eq!(true.to_value().to_token(), inner::Token::Bool(true));
+ assert_eq!('a'.to_value().to_token(), inner::Token::Char('a'));
+ assert_eq!(
+ "a loong string".to_value().to_token(),
+ inner::Token::Str("a loong string".into())
+ );
+ assert_eq!(Some(true).to_value().to_token(), inner::Token::Bool(true));
+ assert_eq!(().to_value().to_token(), inner::Token::None);
+ assert_eq!(None::<bool>.to_value().to_token(), inner::Token::None);
+ }
+
+ #[test]
+ fn test_to_number() {
+ for v in unsigned() {
+ assert!(v.to_u64().is_some());
+ assert!(v.to_i64().is_some());
+ }
+
+ for v in signed() {
+ assert!(v.to_i64().is_some());
+ }
+
+ for v in unsigned().chain(signed()).chain(float()) {
+ assert!(v.to_f64().is_some());
+ }
+
+ for v in bool().chain(str()).chain(char()) {
+ assert!(v.to_u64().is_none());
+ assert!(v.to_i64().is_none());
+ assert!(v.to_f64().is_none());
+ }
+ }
+
+ #[test]
+ fn test_to_float() {
+ // Only integers from i32::MIN..=u32::MAX can be converted into floats
+ assert!(Value::from(i32::MIN).to_f64().is_some());
+ assert!(Value::from(u32::MAX).to_f64().is_some());
+
+ assert!(Value::from((i32::MIN as i64) - 1).to_f64().is_none());
+ assert!(Value::from((u32::MAX as u64) + 1).to_f64().is_none());
+ }
+
+ #[test]
+ fn test_to_cow_str() {
+ for v in str() {
+ assert!(v.to_borrowed_str().is_some());
+
+ #[cfg(feature = "kv_std")]
+ assert!(v.to_cow_str().is_some());
+ }
+
+ let short_lived = String::from("short lived");
+ let v = Value::from(&*short_lived);
+
+ assert!(v.to_borrowed_str().is_some());
+
+ #[cfg(feature = "kv_std")]
+ assert!(v.to_cow_str().is_some());
+
+ for v in unsigned().chain(signed()).chain(float()).chain(bool()) {
+ assert!(v.to_borrowed_str().is_none());
+
+ #[cfg(feature = "kv_std")]
+ assert!(v.to_cow_str().is_none());
+ }
+ }
+
+ #[test]
+ fn test_to_bool() {
+ for v in bool() {
+ assert!(v.to_bool().is_some());
+ }
+
+ for v in unsigned()
+ .chain(signed())
+ .chain(float())
+ .chain(str())
+ .chain(char())
+ {
+ assert!(v.to_bool().is_none());
+ }
+ }
+
+ #[test]
+ fn test_to_char() {
+ for v in char() {
+ assert!(v.to_char().is_some());
+ }
+
+ for v in unsigned()
+ .chain(signed())
+ .chain(float())
+ .chain(str())
+ .chain(bool())
+ {
+ assert!(v.to_char().is_none());
+ }
+ }
+
+ #[test]
+ fn test_visit_integer() {
+ struct Extract(Option<u64>);
+
+ impl<'v> VisitValue<'v> for Extract {
+ fn visit_any(&mut self, value: Value) -> Result<(), Error> {
+ unimplemented!("unexpected value: {value:?}")
+ }
+
+ fn visit_u64(&mut self, value: u64) -> Result<(), Error> {
+ self.0 = Some(value);
+
+ Ok(())
+ }
+ }
+
+ let mut extract = Extract(None);
+ Value::from(42u64).visit(&mut extract).unwrap();
+
+ assert_eq!(Some(42), extract.0);
+ }
+
+ #[test]
+ fn test_visit_borrowed_str() {
+ struct Extract<'v>(Option<&'v str>);
+
+ impl<'v> VisitValue<'v> for Extract<'v> {
+ fn visit_any(&mut self, value: Value) -> Result<(), Error> {
+ unimplemented!("unexpected value: {value:?}")
+ }
+
+ fn visit_borrowed_str(&mut self, value: &'v str) -> Result<(), Error> {
+ self.0 = Some(value);
+
+ Ok(())
+ }
+ }
+
+ let mut extract = Extract(None);
+
+ let short_lived = String::from("A short-lived string");
+ Value::from(&*short_lived).visit(&mut extract).unwrap();
+
+ assert_eq!(Some("A short-lived string"), extract.0);
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs
new file mode 100644
index 0000000..6b43a9a
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/lib.rs
@@ -0,0 +1,1878 @@
+// 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.
+
+//! A lightweight logging facade.
+//!
+//! The `log` crate provides a single logging API that abstracts over the
+//! actual logging implementation. Libraries can use the logging API provided
+//! by this crate, and the consumer of those libraries can choose the logging
+//! implementation that is most suitable for its use case.
+//!
+//! If no logging implementation is selected, the facade falls back to a "noop"
+//! implementation that ignores all log messages. The overhead in this case
+//! is very small - just an integer load, comparison and jump.
+//!
+//! A log request consists of a _target_, a _level_, and a _body_. A target is a
+//! string which defaults to the module path of the location of the log request,
+//! though that default may be overridden. Logger implementations typically use
+//! the target to filter requests based on some user configuration.
+//!
+//! # Usage
+//!
+//! The basic use of the log crate is through the five logging macros: [`error!`],
+//! [`warn!`], [`info!`], [`debug!`] and [`trace!`]
+//! where `error!` represents the highest-priority log messages
+//! and `trace!` the lowest. The log messages are filtered by configuring
+//! the log level to exclude messages with a lower priority.
+//! Each of these macros accept format strings similarly to [`println!`].
+//!
+//!
+//! [`error!`]: ./macro.error.html
+//! [`warn!`]: ./macro.warn.html
+//! [`info!`]: ./macro.info.html
+//! [`debug!`]: ./macro.debug.html
+//! [`trace!`]: ./macro.trace.html
+//! [`println!`]: https://doc.rust-lang.org/stable/std/macro.println.html
+//!
+//! Avoid writing expressions with side-effects in log statements. They may not be evaluated.
+//!
+//! ## In libraries
+//!
+//! Libraries should link only to the `log` crate, and use the provided
+//! macros to log whatever information will be useful to downstream consumers.
+//!
+//! ### Examples
+//!
+//! ```
+//! # #[derive(Debug)] pub struct Yak(String);
+//! # impl Yak { fn shave(&mut self, _: u32) {} }
+//! # fn find_a_razor() -> Result<u32, u32> { Ok(1) }
+//! use log::{info, warn};
+//!
+//! pub fn shave_the_yak(yak: &mut Yak) {
+//! info!(target: "yak_events", "Commencing yak shaving for {yak:?}");
+//!
+//! loop {
+//! match find_a_razor() {
+//! Ok(razor) => {
+//! info!("Razor located: {razor}");
+//! yak.shave(razor);
+//! break;
+//! }
+//! Err(err) => {
+//! warn!("Unable to locate a razor: {err}, retrying");
+//! }
+//! }
+//! }
+//! }
+//! # fn main() {}
+//! ```
+//!
+//! ## In executables
+//!
+//! Executables should choose a logging implementation and initialize it early in the
+//! runtime of the program. Logging implementations will typically include a
+//! function to do this. Any log messages generated before
+//! the implementation is initialized will be ignored.
+//!
+//! The executable itself may use the `log` crate to log as well.
+//!
+//! ### Warning
+//!
+//! The logging system may only be initialized once.
+//!
+//! ## Structured logging
+//!
+//! If you enable the `kv` feature you can associate structured values
+//! with your log records. If we take the example from before, we can include
+//! some additional context besides what's in the formatted message:
+//!
+//! ```
+//! # use serde::Serialize;
+//! # #[derive(Debug, Serialize)] pub struct Yak(String);
+//! # impl Yak { fn shave(&mut self, _: u32) {} }
+//! # fn find_a_razor() -> Result<u32, std::io::Error> { Ok(1) }
+//! # #[cfg(feature = "kv_serde")]
+//! # fn main() {
+//! use log::{info, warn};
+//!
+//! pub fn shave_the_yak(yak: &mut Yak) {
+//! info!(target: "yak_events", yak:serde; "Commencing yak shaving");
+//!
+//! loop {
+//! match find_a_razor() {
+//! Ok(razor) => {
+//! info!(razor; "Razor located");
+//! yak.shave(razor);
+//! break;
+//! }
+//! Err(e) => {
+//! warn!(e:err; "Unable to locate a razor, retrying");
+//! }
+//! }
+//! }
+//! }
+//! # }
+//! # #[cfg(not(feature = "kv_serde"))]
+//! # fn main() {}
+//! ```
+//!
+//! See the [`kv`] module documentation for more details.
+//!
+//! # Available logging implementations
+//!
+//! In order to produce log output executables have to use
+//! a logger implementation compatible with the facade.
+//! There are many available implementations to choose from,
+//! here are some of the most popular ones:
+//!
+//! * Simple minimal loggers:
+//! * [env_logger]
+//! * [colog]
+//! * [simple_logger]
+//! * [simplelog]
+//! * [pretty_env_logger]
+//! * [stderrlog]
+//! * [flexi_logger]
+//! * [call_logger]
+//! * [structured-logger]
+//! * Complex configurable frameworks:
+//! * [log4rs]
+//! * [fern]
+//! * Adaptors for other facilities:
+//! * [syslog]
+//! * [slog-stdlog]
+//! * [systemd-journal-logger]
+//! * [android_log]
+//! * [win_dbg_logger]
+//! * [db_logger]
+//! * [log-to-defmt]
+//! * [logcontrol-log]
+//! * For WebAssembly binaries:
+//! * [console_log]
+//! * For dynamic libraries:
+//! * You may need to construct an FFI-safe wrapper over `log` to initialize in your libraries
+//! * Utilities:
+//! * [log_err]
+//! * [log-reload]
+//!
+//! # Implementing a Logger
+//!
+//! Loggers implement the [`Log`] trait. Here's a very basic example that simply
+//! logs all messages at the [`Error`][level_link], [`Warn`][level_link] or
+//! [`Info`][level_link] levels to stdout:
+//!
+//! ```
+//! use log::{Record, Level, Metadata};
+//!
+//! struct SimpleLogger;
+//!
+//! impl log::Log for SimpleLogger {
+//! fn enabled(&self, metadata: &Metadata) -> bool {
+//! metadata.level() <= Level::Info
+//! }
+//!
+//! fn log(&self, record: &Record) {
+//! if self.enabled(record.metadata()) {
+//! println!("{} - {}", record.level(), record.args());
+//! }
+//! }
+//!
+//! fn flush(&self) {}
+//! }
+//!
+//! # fn main() {}
+//! ```
+//!
+//! Loggers are installed by calling the [`set_logger`] function. The maximum
+//! log level also needs to be adjusted via the [`set_max_level`] function. The
+//! logging facade uses this as an optimization to improve performance of log
+//! messages at levels that are disabled. It's important to set it, as it
+//! defaults to [`Off`][filter_link], so no log messages will ever be captured!
+//! In the case of our example logger, we'll want to set the maximum log level
+//! to [`Info`][filter_link], since we ignore any [`Debug`][level_link] or
+//! [`Trace`][level_link] level log messages. A logging implementation should
+//! provide a function that wraps a call to [`set_logger`] and
+//! [`set_max_level`], handling initialization of the logger:
+//!
+//! ```
+//! # use log::{Level, Metadata};
+//! # struct SimpleLogger;
+//! # impl log::Log for SimpleLogger {
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn log(&self, _: &log::Record) {}
+//! # fn flush(&self) {}
+//! # }
+//! # fn main() {}
+//! use log::{SetLoggerError, LevelFilter};
+//!
+//! static LOGGER: SimpleLogger = SimpleLogger;
+//!
+//! pub fn init() -> Result<(), SetLoggerError> {
+//! log::set_logger(&LOGGER)
+//! .map(|()| log::set_max_level(LevelFilter::Info))
+//! }
+//! ```
+//!
+//! Implementations that adjust their configurations at runtime should take care
+//! to adjust the maximum log level as well.
+//!
+//! # Use with `std`
+//!
+//! `set_logger` requires you to provide a `&'static Log`, which can be hard to
+//! obtain if your logger depends on some runtime configuration. The
+//! `set_boxed_logger` function is available with the `std` Cargo feature. It is
+//! identical to `set_logger` except that it takes a `Box<Log>` rather than a
+//! `&'static Log`:
+//!
+//! ```
+//! # use log::{Level, LevelFilter, Log, SetLoggerError, Metadata};
+//! # struct SimpleLogger;
+//! # impl log::Log for SimpleLogger {
+//! # fn enabled(&self, _: &Metadata) -> bool { false }
+//! # fn log(&self, _: &log::Record) {}
+//! # fn flush(&self) {}
+//! # }
+//! # fn main() {}
+//! # #[cfg(feature = "std")]
+//! pub fn init() -> Result<(), SetLoggerError> {
+//! log::set_boxed_logger(Box::new(SimpleLogger))
+//! .map(|()| log::set_max_level(LevelFilter::Info))
+//! }
+//! ```
+//!
+//! # Compile time filters
+//!
+//! Log levels can be statically disabled at compile time by enabling one of these Cargo features:
+//!
+//! * `max_level_off`
+//! * `max_level_error`
+//! * `max_level_warn`
+//! * `max_level_info`
+//! * `max_level_debug`
+//! * `max_level_trace`
+//!
+//! Log invocations at disabled levels will be skipped and will not even be present in the
+//! resulting binary. These features control the value of the `STATIC_MAX_LEVEL` constant. The
+//! logging macros check this value before logging a message. By default, no levels are disabled.
+//!
+//! It is possible to override this level for release builds only with the following features:
+//!
+//! * `release_max_level_off`
+//! * `release_max_level_error`
+//! * `release_max_level_warn`
+//! * `release_max_level_info`
+//! * `release_max_level_debug`
+//! * `release_max_level_trace`
+//!
+//! Libraries should avoid using the max level features because they're global and can't be changed
+//! once they're set.
+//!
+//! For example, a crate can disable trace level logs in debug builds and trace, debug, and info
+//! level logs in release builds with the following configuration:
+//!
+//! ```toml
+//! [dependencies]
+//! log = { version = "0.4", features = ["max_level_debug", "release_max_level_warn"] }
+//! ```
+//! # Crate Feature Flags
+//!
+//! The following crate feature flags are available in addition to the filters. They are
+//! configured in your `Cargo.toml`.
+//!
+//! * `std` allows use of `std` crate instead of the default `core`. Enables using `std::error` and
+//! `set_boxed_logger` functionality.
+//! * `serde` enables support for serialization and deserialization of `Level` and `LevelFilter`.
+//!
+//! ```toml
+//! [dependencies]
+//! log = { version = "0.4", features = ["std", "serde"] }
+//! ```
+//!
+//! # Version compatibility
+//!
+//! The 0.3 and 0.4 versions of the `log` crate are almost entirely compatible. Log messages
+//! made using `log` 0.3 will forward transparently to a logger implementation using `log` 0.4. Log
+//! messages made using `log` 0.4 will forward to a logger implementation using `log` 0.3, but the
+//! module path and file name information associated with the message will unfortunately be lost.
+//!
+//! [`Log`]: trait.Log.html
+//! [level_link]: enum.Level.html
+//! [filter_link]: enum.LevelFilter.html
+//! [`set_logger`]: fn.set_logger.html
+//! [`set_max_level`]: fn.set_max_level.html
+//! [`try_set_logger_raw`]: fn.try_set_logger_raw.html
+//! [`shutdown_logger_raw`]: fn.shutdown_logger_raw.html
+//! [env_logger]: https://docs.rs/env_logger/*/env_logger/
+//! [colog]: https://docs.rs/colog/*/colog/
+//! [simple_logger]: https://github.com/borntyping/rust-simple_logger
+//! [simplelog]: https://github.com/drakulix/simplelog.rs
+//! [pretty_env_logger]: https://docs.rs/pretty_env_logger/*/pretty_env_logger/
+//! [stderrlog]: https://docs.rs/stderrlog/*/stderrlog/
+//! [flexi_logger]: https://docs.rs/flexi_logger/*/flexi_logger/
+//! [call_logger]: https://docs.rs/call_logger/*/call_logger/
+//! [syslog]: https://docs.rs/syslog/*/syslog/
+//! [slog-stdlog]: https://docs.rs/slog-stdlog/*/slog_stdlog/
+//! [log4rs]: https://docs.rs/log4rs/*/log4rs/
+//! [fern]: https://docs.rs/fern/*/fern/
+//! [systemd-journal-logger]: https://docs.rs/systemd-journal-logger/*/systemd_journal_logger/
+//! [android_log]: https://docs.rs/android_log/*/android_log/
+//! [win_dbg_logger]: https://docs.rs/win_dbg_logger/*/win_dbg_logger/
+//! [db_logger]: https://docs.rs/db_logger/*/db_logger/
+//! [log-to-defmt]: https://docs.rs/log-to-defmt/*/log_to_defmt/
+//! [console_log]: https://docs.rs/console_log/*/console_log/
+//! [structured-logger]: https://docs.rs/structured-logger/latest/structured_logger/
+//! [logcontrol-log]: https://docs.rs/logcontrol-log/*/logcontrol_log/
+//! [log_err]: https://docs.rs/log_err/*/log_err/
+//! [log-reload]: https://docs.rs/log-reload/*/log_reload/
+
+#![doc(
+ html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
+ html_favicon_url = "https://www.rust-lang.org/favicon.ico",
+ html_root_url = "https://docs.rs/log/0.4.22"
+)]
+#![warn(missing_docs)]
+#![deny(missing_debug_implementations, unconditional_recursion)]
+#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
+
+#[cfg(any(
+ all(feature = "max_level_off", feature = "max_level_error"),
+ all(feature = "max_level_off", feature = "max_level_warn"),
+ all(feature = "max_level_off", feature = "max_level_info"),
+ all(feature = "max_level_off", feature = "max_level_debug"),
+ all(feature = "max_level_off", feature = "max_level_trace"),
+ all(feature = "max_level_error", feature = "max_level_warn"),
+ all(feature = "max_level_error", feature = "max_level_info"),
+ all(feature = "max_level_error", feature = "max_level_debug"),
+ all(feature = "max_level_error", feature = "max_level_trace"),
+ all(feature = "max_level_warn", feature = "max_level_info"),
+ all(feature = "max_level_warn", feature = "max_level_debug"),
+ all(feature = "max_level_warn", feature = "max_level_trace"),
+ all(feature = "max_level_info", feature = "max_level_debug"),
+ all(feature = "max_level_info", feature = "max_level_trace"),
+ all(feature = "max_level_debug", feature = "max_level_trace"),
+))]
+compile_error!("multiple max_level_* features set");
+
+#[rustfmt::skip]
+#[cfg(any(
+ all(feature = "release_max_level_off", feature = "release_max_level_error"),
+ all(feature = "release_max_level_off", feature = "release_max_level_warn"),
+ all(feature = "release_max_level_off", feature = "release_max_level_info"),
+ all(feature = "release_max_level_off", feature = "release_max_level_debug"),
+ all(feature = "release_max_level_off", feature = "release_max_level_trace"),
+ all(feature = "release_max_level_error", feature = "release_max_level_warn"),
+ all(feature = "release_max_level_error", feature = "release_max_level_info"),
+ all(feature = "release_max_level_error", feature = "release_max_level_debug"),
+ all(feature = "release_max_level_error", feature = "release_max_level_trace"),
+ all(feature = "release_max_level_warn", feature = "release_max_level_info"),
+ all(feature = "release_max_level_warn", feature = "release_max_level_debug"),
+ all(feature = "release_max_level_warn", feature = "release_max_level_trace"),
+ all(feature = "release_max_level_info", feature = "release_max_level_debug"),
+ all(feature = "release_max_level_info", feature = "release_max_level_trace"),
+ all(feature = "release_max_level_debug", feature = "release_max_level_trace"),
+))]
+compile_error!("multiple release_max_level_* features set");
+
+#[cfg(all(not(feature = "std"), not(test)))]
+extern crate core as std;
+
+use std::cfg;
+#[cfg(feature = "std")]
+use std::error;
+use std::str::FromStr;
+use std::{cmp, fmt, mem};
+
+#[macro_use]
+mod macros;
+mod serde;
+
+#[cfg(feature = "kv")]
+pub mod kv;
+
+#[cfg(target_has_atomic = "ptr")]
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+#[cfg(not(target_has_atomic = "ptr"))]
+use std::cell::Cell;
+#[cfg(not(target_has_atomic = "ptr"))]
+use std::sync::atomic::Ordering;
+
+#[cfg(not(target_has_atomic = "ptr"))]
+struct AtomicUsize {
+ v: Cell<usize>,
+}
+
+#[cfg(not(target_has_atomic = "ptr"))]
+impl AtomicUsize {
+ const fn new(v: usize) -> AtomicUsize {
+ AtomicUsize { v: Cell::new(v) }
+ }
+
+ fn load(&self, _order: Ordering) -> usize {
+ self.v.get()
+ }
+
+ fn store(&self, val: usize, _order: Ordering) {
+ self.v.set(val)
+ }
+
+ #[cfg(target_has_atomic = "ptr")]
+ fn compare_exchange(
+ &self,
+ current: usize,
+ new: usize,
+ _success: Ordering,
+ _failure: Ordering,
+ ) -> Result<usize, usize> {
+ let prev = self.v.get();
+ if current == prev {
+ self.v.set(new);
+ }
+ Ok(prev)
+ }
+}
+
+// Any platform without atomics is unlikely to have multiple cores, so
+// writing via Cell will not be a race condition.
+#[cfg(not(target_has_atomic = "ptr"))]
+unsafe impl Sync for AtomicUsize {}
+
+// The LOGGER static holds a pointer to the global logger. It is protected by
+// the STATE static which determines whether LOGGER has been initialized yet.
+static mut LOGGER: &dyn Log = &NopLogger;
+
+static STATE: AtomicUsize = AtomicUsize::new(0);
+
+// There are three different states that we care about: the logger's
+// uninitialized, the logger's initializing (set_logger's been called but
+// LOGGER hasn't actually been set yet), or the logger's active.
+const UNINITIALIZED: usize = 0;
+const INITIALIZING: usize = 1;
+const INITIALIZED: usize = 2;
+
+static MAX_LOG_LEVEL_FILTER: AtomicUsize = AtomicUsize::new(0);
+
+static LOG_LEVEL_NAMES: [&str; 6] = ["OFF", "ERROR", "WARN", "INFO", "DEBUG", "TRACE"];
+
+static SET_LOGGER_ERROR: &str = "attempted to set a logger after the logging system \
+ was already initialized";
+static LEVEL_PARSE_ERROR: &str =
+ "attempted to convert a string that doesn't match an existing log level";
+
+/// An enum representing the available verbosity levels of the logger.
+///
+/// Typical usage includes: checking if a certain `Level` is enabled with
+/// [`log_enabled!`](macro.log_enabled.html), specifying the `Level` of
+/// [`log!`](macro.log.html), and comparing a `Level` directly to a
+/// [`LevelFilter`](enum.LevelFilter.html).
+#[repr(usize)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Level {
+ /// The "error" level.
+ ///
+ /// Designates very serious errors.
+ // This way these line up with the discriminants for LevelFilter below
+ // This works because Rust treats field-less enums the same way as C does:
+ // https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-field-less-enumerations
+ Error = 1,
+ /// The "warn" level.
+ ///
+ /// Designates hazardous situations.
+ Warn,
+ /// The "info" level.
+ ///
+ /// Designates useful information.
+ Info,
+ /// The "debug" level.
+ ///
+ /// Designates lower priority information.
+ Debug,
+ /// The "trace" level.
+ ///
+ /// Designates very low priority, often extremely verbose, information.
+ Trace,
+}
+
+impl PartialEq<LevelFilter> for Level {
+ #[inline]
+ fn eq(&self, other: &LevelFilter) -> bool {
+ *self as usize == *other as usize
+ }
+}
+
+impl PartialOrd<LevelFilter> for Level {
+ #[inline]
+ fn partial_cmp(&self, other: &LevelFilter) -> Option<cmp::Ordering> {
+ Some((*self as usize).cmp(&(*other as usize)))
+ }
+}
+
+impl FromStr for Level {
+ type Err = ParseLevelError;
+ fn from_str(level: &str) -> Result<Level, Self::Err> {
+ LOG_LEVEL_NAMES
+ .iter()
+ .position(|&name| name.eq_ignore_ascii_case(level))
+ .into_iter()
+ .filter(|&idx| idx != 0)
+ .map(|idx| Level::from_usize(idx).unwrap())
+ .next()
+ .ok_or(ParseLevelError(()))
+ }
+}
+
+impl fmt::Display for Level {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.pad(self.as_str())
+ }
+}
+
+impl Level {
+ fn from_usize(u: usize) -> Option<Level> {
+ match u {
+ 1 => Some(Level::Error),
+ 2 => Some(Level::Warn),
+ 3 => Some(Level::Info),
+ 4 => Some(Level::Debug),
+ 5 => Some(Level::Trace),
+ _ => None,
+ }
+ }
+
+ /// Returns the most verbose logging level.
+ #[inline]
+ pub fn max() -> Level {
+ Level::Trace
+ }
+
+ /// Converts the `Level` to the equivalent `LevelFilter`.
+ #[inline]
+ pub fn to_level_filter(&self) -> LevelFilter {
+ LevelFilter::from_usize(*self as usize).unwrap()
+ }
+
+ /// Returns the string representation of the `Level`.
+ ///
+ /// This returns the same string as the `fmt::Display` implementation.
+ pub fn as_str(&self) -> &'static str {
+ LOG_LEVEL_NAMES[*self as usize]
+ }
+
+ /// Iterate through all supported logging levels.
+ ///
+ /// The order of iteration is from more severe to less severe log messages.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use log::Level;
+ ///
+ /// let mut levels = Level::iter();
+ ///
+ /// assert_eq!(Some(Level::Error), levels.next());
+ /// assert_eq!(Some(Level::Trace), levels.last());
+ /// ```
+ pub fn iter() -> impl Iterator<Item = Self> {
+ (1..6).map(|i| Self::from_usize(i).unwrap())
+ }
+}
+
+/// An enum representing the available verbosity level filters of the logger.
+///
+/// A `LevelFilter` may be compared directly to a [`Level`]. Use this type
+/// to get and set the maximum log level with [`max_level()`] and [`set_max_level`].
+///
+/// [`Level`]: enum.Level.html
+/// [`max_level()`]: fn.max_level.html
+/// [`set_max_level`]: fn.set_max_level.html
+#[repr(usize)]
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum LevelFilter {
+ /// A level lower than all log levels.
+ Off,
+ /// Corresponds to the `Error` log level.
+ Error,
+ /// Corresponds to the `Warn` log level.
+ Warn,
+ /// Corresponds to the `Info` log level.
+ Info,
+ /// Corresponds to the `Debug` log level.
+ Debug,
+ /// Corresponds to the `Trace` log level.
+ Trace,
+}
+
+impl PartialEq<Level> for LevelFilter {
+ #[inline]
+ fn eq(&self, other: &Level) -> bool {
+ other.eq(self)
+ }
+}
+
+impl PartialOrd<Level> for LevelFilter {
+ #[inline]
+ fn partial_cmp(&self, other: &Level) -> Option<cmp::Ordering> {
+ Some((*self as usize).cmp(&(*other as usize)))
+ }
+}
+
+impl FromStr for LevelFilter {
+ type Err = ParseLevelError;
+ fn from_str(level: &str) -> Result<LevelFilter, Self::Err> {
+ LOG_LEVEL_NAMES
+ .iter()
+ .position(|&name| name.eq_ignore_ascii_case(level))
+ .map(|p| LevelFilter::from_usize(p).unwrap())
+ .ok_or(ParseLevelError(()))
+ }
+}
+
+impl fmt::Display for LevelFilter {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.pad(self.as_str())
+ }
+}
+
+impl LevelFilter {
+ fn from_usize(u: usize) -> Option<LevelFilter> {
+ match u {
+ 0 => Some(LevelFilter::Off),
+ 1 => Some(LevelFilter::Error),
+ 2 => Some(LevelFilter::Warn),
+ 3 => Some(LevelFilter::Info),
+ 4 => Some(LevelFilter::Debug),
+ 5 => Some(LevelFilter::Trace),
+ _ => None,
+ }
+ }
+
+ /// Returns the most verbose logging level filter.
+ #[inline]
+ pub fn max() -> LevelFilter {
+ LevelFilter::Trace
+ }
+
+ /// Converts `self` to the equivalent `Level`.
+ ///
+ /// Returns `None` if `self` is `LevelFilter::Off`.
+ #[inline]
+ pub fn to_level(&self) -> Option<Level> {
+ Level::from_usize(*self as usize)
+ }
+
+ /// Returns the string representation of the `LevelFilter`.
+ ///
+ /// This returns the same string as the `fmt::Display` implementation.
+ pub fn as_str(&self) -> &'static str {
+ LOG_LEVEL_NAMES[*self as usize]
+ }
+
+ /// Iterate through all supported filtering levels.
+ ///
+ /// The order of iteration is from less to more verbose filtering.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use log::LevelFilter;
+ ///
+ /// let mut levels = LevelFilter::iter();
+ ///
+ /// assert_eq!(Some(LevelFilter::Off), levels.next());
+ /// assert_eq!(Some(LevelFilter::Trace), levels.last());
+ /// ```
+ pub fn iter() -> impl Iterator<Item = Self> {
+ (0..6).map(|i| Self::from_usize(i).unwrap())
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+enum MaybeStaticStr<'a> {
+ Static(&'static str),
+ Borrowed(&'a str),
+}
+
+impl<'a> MaybeStaticStr<'a> {
+ #[inline]
+ fn get(&self) -> &'a str {
+ match *self {
+ MaybeStaticStr::Static(s) => s,
+ MaybeStaticStr::Borrowed(s) => s,
+ }
+ }
+}
+
+/// The "payload" of a log message.
+///
+/// # Use
+///
+/// `Record` structures are passed as parameters to the [`log`][method.log]
+/// method of the [`Log`] trait. Logger implementors manipulate these
+/// structures in order to display log messages. `Record`s are automatically
+/// created by the [`log!`] macro and so are not seen by log users.
+///
+/// Note that the [`level()`] and [`target()`] accessors are equivalent to
+/// `self.metadata().level()` and `self.metadata().target()` respectively.
+/// These methods are provided as a convenience for users of this structure.
+///
+/// # Example
+///
+/// The following example shows a simple logger that displays the level,
+/// module path, and message of any `Record` that is passed to it.
+///
+/// ```
+/// struct SimpleLogger;
+///
+/// impl log::Log for SimpleLogger {
+/// fn enabled(&self, _metadata: &log::Metadata) -> bool {
+/// true
+/// }
+///
+/// fn log(&self, record: &log::Record) {
+/// if !self.enabled(record.metadata()) {
+/// return;
+/// }
+///
+/// println!("{}:{} -- {}",
+/// record.level(),
+/// record.target(),
+/// record.args());
+/// }
+/// fn flush(&self) {}
+/// }
+/// ```
+///
+/// [method.log]: trait.Log.html#tymethod.log
+/// [`Log`]: trait.Log.html
+/// [`log!`]: macro.log.html
+/// [`level()`]: struct.Record.html#method.level
+/// [`target()`]: struct.Record.html#method.target
+#[derive(Clone, Debug)]
+pub struct Record<'a> {
+ metadata: Metadata<'a>,
+ args: fmt::Arguments<'a>,
+ module_path: Option<MaybeStaticStr<'a>>,
+ file: Option<MaybeStaticStr<'a>>,
+ line: Option<u32>,
+ #[cfg(feature = "kv")]
+ key_values: KeyValues<'a>,
+}
+
+// This wrapper type is only needed so we can
+// `#[derive(Debug)]` on `Record`. It also
+// provides a useful `Debug` implementation for
+// the underlying `Source`.
+#[cfg(feature = "kv")]
+#[derive(Clone)]
+struct KeyValues<'a>(&'a dyn kv::Source);
+
+#[cfg(feature = "kv")]
+impl<'a> fmt::Debug for KeyValues<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut visitor = f.debug_map();
+ self.0.visit(&mut visitor).map_err(|_| fmt::Error)?;
+ visitor.finish()
+ }
+}
+
+impl<'a> Record<'a> {
+ /// Returns a new builder.
+ #[inline]
+ pub fn builder() -> RecordBuilder<'a> {
+ RecordBuilder::new()
+ }
+
+ /// The message body.
+ #[inline]
+ pub fn args(&self) -> &fmt::Arguments<'a> {
+ &self.args
+ }
+
+ /// Metadata about the log directive.
+ #[inline]
+ pub fn metadata(&self) -> &Metadata<'a> {
+ &self.metadata
+ }
+
+ /// The verbosity level of the message.
+ #[inline]
+ pub fn level(&self) -> Level {
+ self.metadata.level()
+ }
+
+ /// The name of the target of the directive.
+ #[inline]
+ pub fn target(&self) -> &'a str {
+ self.metadata.target()
+ }
+
+ /// The module path of the message.
+ #[inline]
+ pub fn module_path(&self) -> Option<&'a str> {
+ self.module_path.map(|s| s.get())
+ }
+
+ /// The module path of the message, if it is a `'static` string.
+ #[inline]
+ pub fn module_path_static(&self) -> Option<&'static str> {
+ match self.module_path {
+ Some(MaybeStaticStr::Static(s)) => Some(s),
+ _ => None,
+ }
+ }
+
+ /// The source file containing the message.
+ #[inline]
+ pub fn file(&self) -> Option<&'a str> {
+ self.file.map(|s| s.get())
+ }
+
+ /// The source file containing the message, if it is a `'static` string.
+ #[inline]
+ pub fn file_static(&self) -> Option<&'static str> {
+ match self.file {
+ Some(MaybeStaticStr::Static(s)) => Some(s),
+ _ => None,
+ }
+ }
+
+ /// The line containing the message.
+ #[inline]
+ pub fn line(&self) -> Option<u32> {
+ self.line
+ }
+
+ /// The structured key-value pairs associated with the message.
+ #[cfg(feature = "kv")]
+ #[inline]
+ pub fn key_values(&self) -> &dyn kv::Source {
+ self.key_values.0
+ }
+
+ /// Create a new [`RecordBuilder`](struct.RecordBuilder.html) based on this record.
+ #[cfg(feature = "kv")]
+ #[inline]
+ pub fn to_builder(&self) -> RecordBuilder {
+ RecordBuilder {
+ record: Record {
+ metadata: Metadata {
+ level: self.metadata.level,
+ target: self.metadata.target,
+ },
+ args: self.args,
+ module_path: self.module_path,
+ file: self.file,
+ line: self.line,
+ key_values: self.key_values.clone(),
+ },
+ }
+ }
+}
+
+/// Builder for [`Record`](struct.Record.html).
+///
+/// Typically should only be used by log library creators or for testing and "shim loggers".
+/// The `RecordBuilder` can set the different parameters of `Record` object, and returns
+/// the created object when `build` is called.
+///
+/// # Examples
+///
+/// ```
+/// use log::{Level, Record};
+///
+/// let record = Record::builder()
+/// .args(format_args!("Error!"))
+/// .level(Level::Error)
+/// .target("myApp")
+/// .file(Some("server.rs"))
+/// .line(Some(144))
+/// .module_path(Some("server"))
+/// .build();
+/// ```
+///
+/// Alternatively, use [`MetadataBuilder`](struct.MetadataBuilder.html):
+///
+/// ```
+/// use log::{Record, Level, MetadataBuilder};
+///
+/// let error_metadata = MetadataBuilder::new()
+/// .target("myApp")
+/// .level(Level::Error)
+/// .build();
+///
+/// let record = Record::builder()
+/// .metadata(error_metadata)
+/// .args(format_args!("Error!"))
+/// .line(Some(433))
+/// .file(Some("app.rs"))
+/// .module_path(Some("server"))
+/// .build();
+/// ```
+#[derive(Debug)]
+pub struct RecordBuilder<'a> {
+ record: Record<'a>,
+}
+
+impl<'a> RecordBuilder<'a> {
+ /// Construct new `RecordBuilder`.
+ ///
+ /// The default options are:
+ ///
+ /// - `args`: [`format_args!("")`]
+ /// - `metadata`: [`Metadata::builder().build()`]
+ /// - `module_path`: `None`
+ /// - `file`: `None`
+ /// - `line`: `None`
+ ///
+ /// [`format_args!("")`]: https://doc.rust-lang.org/std/macro.format_args.html
+ /// [`Metadata::builder().build()`]: struct.MetadataBuilder.html#method.build
+ #[inline]
+ pub fn new() -> RecordBuilder<'a> {
+ RecordBuilder {
+ record: Record {
+ args: format_args!(""),
+ metadata: Metadata::builder().build(),
+ module_path: None,
+ file: None,
+ line: None,
+ #[cfg(feature = "kv")]
+ key_values: KeyValues(&None::<(kv::Key, kv::Value)>),
+ },
+ }
+ }
+
+ /// Set [`args`](struct.Record.html#method.args).
+ #[inline]
+ pub fn args(&mut self, args: fmt::Arguments<'a>) -> &mut RecordBuilder<'a> {
+ self.record.args = args;
+ self
+ }
+
+ /// Set [`metadata`](struct.Record.html#method.metadata). Construct a `Metadata` object with [`MetadataBuilder`](struct.MetadataBuilder.html).
+ #[inline]
+ pub fn metadata(&mut self, metadata: Metadata<'a>) -> &mut RecordBuilder<'a> {
+ self.record.metadata = metadata;
+ self
+ }
+
+ /// Set [`Metadata::level`](struct.Metadata.html#method.level).
+ #[inline]
+ pub fn level(&mut self, level: Level) -> &mut RecordBuilder<'a> {
+ self.record.metadata.level = level;
+ self
+ }
+
+ /// Set [`Metadata::target`](struct.Metadata.html#method.target)
+ #[inline]
+ pub fn target(&mut self, target: &'a str) -> &mut RecordBuilder<'a> {
+ self.record.metadata.target = target;
+ self
+ }
+
+ /// Set [`module_path`](struct.Record.html#method.module_path)
+ #[inline]
+ pub fn module_path(&mut self, path: Option<&'a str>) -> &mut RecordBuilder<'a> {
+ self.record.module_path = path.map(MaybeStaticStr::Borrowed);
+ self
+ }
+
+ /// Set [`module_path`](struct.Record.html#method.module_path) to a `'static` string
+ #[inline]
+ pub fn module_path_static(&mut self, path: Option<&'static str>) -> &mut RecordBuilder<'a> {
+ self.record.module_path = path.map(MaybeStaticStr::Static);
+ self
+ }
+
+ /// Set [`file`](struct.Record.html#method.file)
+ #[inline]
+ pub fn file(&mut self, file: Option<&'a str>) -> &mut RecordBuilder<'a> {
+ self.record.file = file.map(MaybeStaticStr::Borrowed);
+ self
+ }
+
+ /// Set [`file`](struct.Record.html#method.file) to a `'static` string.
+ #[inline]
+ pub fn file_static(&mut self, file: Option<&'static str>) -> &mut RecordBuilder<'a> {
+ self.record.file = file.map(MaybeStaticStr::Static);
+ self
+ }
+
+ /// Set [`line`](struct.Record.html#method.line)
+ #[inline]
+ pub fn line(&mut self, line: Option<u32>) -> &mut RecordBuilder<'a> {
+ self.record.line = line;
+ self
+ }
+
+ /// Set [`key_values`](struct.Record.html#method.key_values)
+ #[cfg(feature = "kv")]
+ #[inline]
+ pub fn key_values(&mut self, kvs: &'a dyn kv::Source) -> &mut RecordBuilder<'a> {
+ self.record.key_values = KeyValues(kvs);
+ self
+ }
+
+ /// Invoke the builder and return a `Record`
+ #[inline]
+ pub fn build(&self) -> Record<'a> {
+ self.record.clone()
+ }
+}
+
+impl<'a> Default for RecordBuilder<'a> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// Metadata about a log message.
+///
+/// # Use
+///
+/// `Metadata` structs are created when users of the library use
+/// logging macros.
+///
+/// They are consumed by implementations of the `Log` trait in the
+/// `enabled` method.
+///
+/// `Record`s use `Metadata` to determine the log message's severity
+/// and target.
+///
+/// Users should use the `log_enabled!` macro in their code to avoid
+/// constructing expensive log messages.
+///
+/// # Examples
+///
+/// ```
+/// use log::{Record, Level, Metadata};
+///
+/// struct MyLogger;
+///
+/// impl log::Log for MyLogger {
+/// fn enabled(&self, metadata: &Metadata) -> bool {
+/// metadata.level() <= Level::Info
+/// }
+///
+/// fn log(&self, record: &Record) {
+/// if self.enabled(record.metadata()) {
+/// println!("{} - {}", record.level(), record.args());
+/// }
+/// }
+/// fn flush(&self) {}
+/// }
+///
+/// # fn main(){}
+/// ```
+#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+pub struct Metadata<'a> {
+ level: Level,
+ target: &'a str,
+}
+
+impl<'a> Metadata<'a> {
+ /// Returns a new builder.
+ #[inline]
+ pub fn builder() -> MetadataBuilder<'a> {
+ MetadataBuilder::new()
+ }
+
+ /// The verbosity level of the message.
+ #[inline]
+ pub fn level(&self) -> Level {
+ self.level
+ }
+
+ /// The name of the target of the directive.
+ #[inline]
+ pub fn target(&self) -> &'a str {
+ self.target
+ }
+}
+
+/// Builder for [`Metadata`](struct.Metadata.html).
+///
+/// Typically should only be used by log library creators or for testing and "shim loggers".
+/// The `MetadataBuilder` can set the different parameters of a `Metadata` object, and returns
+/// the created object when `build` is called.
+///
+/// # Example
+///
+/// ```
+/// let target = "myApp";
+/// use log::{Level, MetadataBuilder};
+/// let metadata = MetadataBuilder::new()
+/// .level(Level::Debug)
+/// .target(target)
+/// .build();
+/// ```
+#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+pub struct MetadataBuilder<'a> {
+ metadata: Metadata<'a>,
+}
+
+impl<'a> MetadataBuilder<'a> {
+ /// Construct a new `MetadataBuilder`.
+ ///
+ /// The default options are:
+ ///
+ /// - `level`: `Level::Info`
+ /// - `target`: `""`
+ #[inline]
+ pub fn new() -> MetadataBuilder<'a> {
+ MetadataBuilder {
+ metadata: Metadata {
+ level: Level::Info,
+ target: "",
+ },
+ }
+ }
+
+ /// Setter for [`level`](struct.Metadata.html#method.level).
+ #[inline]
+ pub fn level(&mut self, arg: Level) -> &mut MetadataBuilder<'a> {
+ self.metadata.level = arg;
+ self
+ }
+
+ /// Setter for [`target`](struct.Metadata.html#method.target).
+ #[inline]
+ pub fn target(&mut self, target: &'a str) -> &mut MetadataBuilder<'a> {
+ self.metadata.target = target;
+ self
+ }
+
+ /// Returns a `Metadata` object.
+ #[inline]
+ pub fn build(&self) -> Metadata<'a> {
+ self.metadata.clone()
+ }
+}
+
+impl<'a> Default for MetadataBuilder<'a> {
+ fn default() -> Self {
+ Self::new()
+ }
+}
+
+/// A trait encapsulating the operations required of a logger.
+pub trait Log: Sync + Send {
+ /// Determines if a log message with the specified metadata would be
+ /// logged.
+ ///
+ /// This is used by the `log_enabled!` macro to allow callers to avoid
+ /// expensive computation of log message arguments if the message would be
+ /// discarded anyway.
+ ///
+ /// # For implementors
+ ///
+ /// This method isn't called automatically by the `log!` macros.
+ /// It's up to an implementation of the `Log` trait to call `enabled` in its own
+ /// `log` method implementation to guarantee that filtering is applied.
+ fn enabled(&self, metadata: &Metadata) -> bool;
+
+ /// Logs the `Record`.
+ ///
+ /// # For implementors
+ ///
+ /// Note that `enabled` is *not* necessarily called before this method.
+ /// Implementations of `log` should perform all necessary filtering
+ /// internally.
+ fn log(&self, record: &Record);
+
+ /// Flushes any buffered records.
+ ///
+ /// # For implementors
+ ///
+ /// This method isn't called automatically by the `log!` macros.
+ /// It can be called manually on shut-down to ensure any in-flight records are flushed.
+ fn flush(&self);
+}
+
+// Just used as a dummy initial value for LOGGER
+struct NopLogger;
+
+impl Log for NopLogger {
+ fn enabled(&self, _: &Metadata) -> bool {
+ false
+ }
+
+ fn log(&self, _: &Record) {}
+ fn flush(&self) {}
+}
+
+impl<T> Log for &'_ T
+where
+ T: ?Sized + Log,
+{
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ (**self).enabled(metadata)
+ }
+
+ fn log(&self, record: &Record) {
+ (**self).log(record);
+ }
+ fn flush(&self) {
+ (**self).flush();
+ }
+}
+
+#[cfg(feature = "std")]
+impl<T> Log for std::boxed::Box<T>
+where
+ T: ?Sized + Log,
+{
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ self.as_ref().enabled(metadata)
+ }
+
+ fn log(&self, record: &Record) {
+ self.as_ref().log(record);
+ }
+ fn flush(&self) {
+ self.as_ref().flush();
+ }
+}
+
+#[cfg(feature = "std")]
+impl<T> Log for std::sync::Arc<T>
+where
+ T: ?Sized + Log,
+{
+ fn enabled(&self, metadata: &Metadata) -> bool {
+ self.as_ref().enabled(metadata)
+ }
+
+ fn log(&self, record: &Record) {
+ self.as_ref().log(record);
+ }
+ fn flush(&self) {
+ self.as_ref().flush();
+ }
+}
+
+/// Sets the global maximum log level.
+///
+/// Generally, this should only be called by the active logging implementation.
+///
+/// Note that `Trace` is the maximum level, because it provides the maximum amount of detail in the emitted logs.
+#[inline]
+#[cfg(target_has_atomic = "ptr")]
+pub fn set_max_level(level: LevelFilter) {
+ MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed);
+}
+
+/// A thread-unsafe version of [`set_max_level`].
+///
+/// This function is available on all platforms, even those that do not have
+/// support for atomics that is needed by [`set_max_level`].
+///
+/// In almost all cases, [`set_max_level`] should be preferred.
+///
+/// # Safety
+///
+/// This function is only safe to call when it cannot race with any other
+/// calls to `set_max_level` or `set_max_level_racy`.
+///
+/// This can be upheld by (for example) making sure that **there are no other
+/// threads**, and (on embedded) that **interrupts are disabled**.
+///
+/// It is safe to use all other logging functions while this function runs
+/// (including all logging macros).
+///
+/// [`set_max_level`]: fn.set_max_level.html
+#[inline]
+pub unsafe fn set_max_level_racy(level: LevelFilter) {
+ // `MAX_LOG_LEVEL_FILTER` uses a `Cell` as the underlying primitive when a
+ // platform doesn't support `target_has_atomic = "ptr"`, so even though this looks the same
+ // as `set_max_level` it may have different safety properties.
+ MAX_LOG_LEVEL_FILTER.store(level as usize, Ordering::Relaxed);
+}
+
+/// Returns the current maximum log level.
+///
+/// The [`log!`], [`error!`], [`warn!`], [`info!`], [`debug!`], and [`trace!`] macros check
+/// this value and discard any message logged at a higher level. The maximum
+/// log level is set by the [`set_max_level`] function.
+///
+/// [`log!`]: macro.log.html
+/// [`error!`]: macro.error.html
+/// [`warn!`]: macro.warn.html
+/// [`info!`]: macro.info.html
+/// [`debug!`]: macro.debug.html
+/// [`trace!`]: macro.trace.html
+/// [`set_max_level`]: fn.set_max_level.html
+#[inline(always)]
+pub fn max_level() -> LevelFilter {
+ // Since `LevelFilter` is `repr(usize)`,
+ // this transmute is sound if and only if `MAX_LOG_LEVEL_FILTER`
+ // is set to a usize that is a valid discriminant for `LevelFilter`.
+ // Since `MAX_LOG_LEVEL_FILTER` is private, the only time it's set
+ // is by `set_max_level` above, i.e. by casting a `LevelFilter` to `usize`.
+ // So any usize stored in `MAX_LOG_LEVEL_FILTER` is a valid discriminant.
+ unsafe { mem::transmute(MAX_LOG_LEVEL_FILTER.load(Ordering::Relaxed)) }
+}
+
+/// Sets the global logger to a `Box<Log>`.
+///
+/// This is a simple convenience wrapper over `set_logger`, which takes a
+/// `Box<Log>` rather than a `&'static Log`. See the documentation for
+/// [`set_logger`] for more details.
+///
+/// Requires the `std` feature.
+///
+/// # Errors
+///
+/// An error is returned if a logger has already been set.
+///
+/// [`set_logger`]: fn.set_logger.html
+#[cfg(all(feature = "std", target_has_atomic = "ptr"))]
+pub fn set_boxed_logger(logger: Box<dyn Log>) -> Result<(), SetLoggerError> {
+ set_logger_inner(|| Box::leak(logger))
+}
+
+/// Sets the global logger to a `&'static Log`.
+///
+/// This function may only be called once in the lifetime of a program. Any log
+/// events that occur before the call to `set_logger` completes will be ignored.
+///
+/// This function does not typically need to be called manually. Logger
+/// implementations should provide an initialization method that installs the
+/// logger internally.
+///
+/// # Availability
+///
+/// This method is available even when the `std` feature is disabled. However,
+/// it is currently unavailable on `thumbv6` targets, which lack support for
+/// some atomic operations which are used by this function. Even on those
+/// targets, [`set_logger_racy`] will be available.
+///
+/// # Errors
+///
+/// An error is returned if a logger has already been set.
+///
+/// # Examples
+///
+/// ```
+/// use log::{error, info, warn, Record, Level, Metadata, LevelFilter};
+///
+/// static MY_LOGGER: MyLogger = MyLogger;
+///
+/// struct MyLogger;
+///
+/// impl log::Log for MyLogger {
+/// fn enabled(&self, metadata: &Metadata) -> bool {
+/// metadata.level() <= Level::Info
+/// }
+///
+/// fn log(&self, record: &Record) {
+/// if self.enabled(record.metadata()) {
+/// println!("{} - {}", record.level(), record.args());
+/// }
+/// }
+/// fn flush(&self) {}
+/// }
+///
+/// # fn main(){
+/// log::set_logger(&MY_LOGGER).unwrap();
+/// log::set_max_level(LevelFilter::Info);
+///
+/// info!("hello log");
+/// warn!("warning");
+/// error!("oops");
+/// # }
+/// ```
+///
+/// [`set_logger_racy`]: fn.set_logger_racy.html
+#[cfg(target_has_atomic = "ptr")]
+pub fn set_logger(logger: &'static dyn Log) -> Result<(), SetLoggerError> {
+ set_logger_inner(|| logger)
+}
+
+#[cfg(target_has_atomic = "ptr")]
+fn set_logger_inner<F>(make_logger: F) -> Result<(), SetLoggerError>
+where
+ F: FnOnce() -> &'static dyn Log,
+{
+ match STATE.compare_exchange(
+ UNINITIALIZED,
+ INITIALIZING,
+ Ordering::Acquire,
+ Ordering::Relaxed,
+ ) {
+ Ok(UNINITIALIZED) => {
+ unsafe {
+ LOGGER = make_logger();
+ }
+ STATE.store(INITIALIZED, Ordering::Release);
+ Ok(())
+ }
+ Err(INITIALIZING) => {
+ while STATE.load(Ordering::Relaxed) == INITIALIZING {
+ std::hint::spin_loop();
+ }
+ Err(SetLoggerError(()))
+ }
+ _ => Err(SetLoggerError(())),
+ }
+}
+
+/// A thread-unsafe version of [`set_logger`].
+///
+/// This function is available on all platforms, even those that do not have
+/// support for atomics that is needed by [`set_logger`].
+///
+/// In almost all cases, [`set_logger`] should be preferred.
+///
+/// # Safety
+///
+/// This function is only safe to call when it cannot race with any other
+/// calls to `set_logger` or `set_logger_racy`.
+///
+/// This can be upheld by (for example) making sure that **there are no other
+/// threads**, and (on embedded) that **interrupts are disabled**.
+///
+/// It is safe to use other logging functions while this function runs
+/// (including all logging macros).
+///
+/// [`set_logger`]: fn.set_logger.html
+pub unsafe fn set_logger_racy(logger: &'static dyn Log) -> Result<(), SetLoggerError> {
+ match STATE.load(Ordering::Acquire) {
+ UNINITIALIZED => {
+ LOGGER = logger;
+ STATE.store(INITIALIZED, Ordering::Release);
+ Ok(())
+ }
+ INITIALIZING => {
+ // This is just plain UB, since we were racing another initialization function
+ unreachable!("set_logger_racy must not be used with other initialization functions")
+ }
+ _ => Err(SetLoggerError(())),
+ }
+}
+
+/// The type returned by [`set_logger`] if [`set_logger`] has already been called.
+///
+/// [`set_logger`]: fn.set_logger.html
+#[allow(missing_copy_implementations)]
+#[derive(Debug)]
+pub struct SetLoggerError(());
+
+impl fmt::Display for SetLoggerError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.write_str(SET_LOGGER_ERROR)
+ }
+}
+
+// The Error trait is not available in libcore
+#[cfg(feature = "std")]
+impl error::Error for SetLoggerError {}
+
+/// The type returned by [`from_str`] when the string doesn't match any of the log levels.
+///
+/// [`from_str`]: https://doc.rust-lang.org/std/str/trait.FromStr.html#tymethod.from_str
+#[allow(missing_copy_implementations)]
+#[derive(Debug, PartialEq, Eq)]
+pub struct ParseLevelError(());
+
+impl fmt::Display for ParseLevelError {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt.write_str(LEVEL_PARSE_ERROR)
+ }
+}
+
+// The Error trait is not available in libcore
+#[cfg(feature = "std")]
+impl error::Error for ParseLevelError {}
+
+/// Returns a reference to the logger.
+///
+/// If a logger has not been set, a no-op implementation is returned.
+pub fn logger() -> &'static dyn Log {
+ // Acquire memory ordering guarantees that current thread would see any
+ // memory writes that happened before store of the value
+ // into `STATE` with memory ordering `Release` or stronger.
+ //
+ // Since the value `INITIALIZED` is written only after `LOGGER` was
+ // initialized, observing it after `Acquire` load here makes both
+ // write to the `LOGGER` static and initialization of the logger
+ // internal state synchronized with current thread.
+ if STATE.load(Ordering::Acquire) != INITIALIZED {
+ static NOP: NopLogger = NopLogger;
+ &NOP
+ } else {
+ unsafe { LOGGER }
+ }
+}
+
+// WARNING: this is not part of the crate's public API and is subject to change at any time
+#[doc(hidden)]
+pub mod __private_api;
+
+/// The statically resolved maximum log level.
+///
+/// See the crate level documentation for information on how to configure this.
+///
+/// This value is checked by the log macros, but not by the `Log`ger returned by
+/// the [`logger`] function. Code that manually calls functions on that value
+/// should compare the level against this value.
+///
+/// [`logger`]: fn.logger.html
+pub const STATIC_MAX_LEVEL: LevelFilter = match cfg!(debug_assertions) {
+ false if cfg!(feature = "release_max_level_off") => LevelFilter::Off,
+ false if cfg!(feature = "release_max_level_error") => LevelFilter::Error,
+ false if cfg!(feature = "release_max_level_warn") => LevelFilter::Warn,
+ false if cfg!(feature = "release_max_level_info") => LevelFilter::Info,
+ false if cfg!(feature = "release_max_level_debug") => LevelFilter::Debug,
+ false if cfg!(feature = "release_max_level_trace") => LevelFilter::Trace,
+ _ if cfg!(feature = "max_level_off") => LevelFilter::Off,
+ _ if cfg!(feature = "max_level_error") => LevelFilter::Error,
+ _ if cfg!(feature = "max_level_warn") => LevelFilter::Warn,
+ _ if cfg!(feature = "max_level_info") => LevelFilter::Info,
+ _ if cfg!(feature = "max_level_debug") => LevelFilter::Debug,
+ _ => LevelFilter::Trace,
+};
+
+#[cfg(test)]
+mod tests {
+ use super::{Level, LevelFilter, ParseLevelError, STATIC_MAX_LEVEL};
+
+ #[test]
+ fn test_levelfilter_from_str() {
+ let tests = [
+ ("off", Ok(LevelFilter::Off)),
+ ("error", Ok(LevelFilter::Error)),
+ ("warn", Ok(LevelFilter::Warn)),
+ ("info", Ok(LevelFilter::Info)),
+ ("debug", Ok(LevelFilter::Debug)),
+ ("trace", Ok(LevelFilter::Trace)),
+ ("OFF", Ok(LevelFilter::Off)),
+ ("ERROR", Ok(LevelFilter::Error)),
+ ("WARN", Ok(LevelFilter::Warn)),
+ ("INFO", Ok(LevelFilter::Info)),
+ ("DEBUG", Ok(LevelFilter::Debug)),
+ ("TRACE", Ok(LevelFilter::Trace)),
+ ("asdf", Err(ParseLevelError(()))),
+ ];
+ for &(s, ref expected) in &tests {
+ assert_eq!(expected, &s.parse());
+ }
+ }
+
+ #[test]
+ fn test_level_from_str() {
+ let tests = [
+ ("OFF", Err(ParseLevelError(()))),
+ ("error", Ok(Level::Error)),
+ ("warn", Ok(Level::Warn)),
+ ("info", Ok(Level::Info)),
+ ("debug", Ok(Level::Debug)),
+ ("trace", Ok(Level::Trace)),
+ ("ERROR", Ok(Level::Error)),
+ ("WARN", Ok(Level::Warn)),
+ ("INFO", Ok(Level::Info)),
+ ("DEBUG", Ok(Level::Debug)),
+ ("TRACE", Ok(Level::Trace)),
+ ("asdf", Err(ParseLevelError(()))),
+ ];
+ for &(s, ref expected) in &tests {
+ assert_eq!(expected, &s.parse());
+ }
+ }
+
+ #[test]
+ fn test_level_as_str() {
+ let tests = &[
+ (Level::Error, "ERROR"),
+ (Level::Warn, "WARN"),
+ (Level::Info, "INFO"),
+ (Level::Debug, "DEBUG"),
+ (Level::Trace, "TRACE"),
+ ];
+ for (input, expected) in tests {
+ assert_eq!(*expected, input.as_str());
+ }
+ }
+
+ #[test]
+ fn test_level_show() {
+ assert_eq!("INFO", Level::Info.to_string());
+ assert_eq!("ERROR", Level::Error.to_string());
+ }
+
+ #[test]
+ fn test_levelfilter_show() {
+ assert_eq!("OFF", LevelFilter::Off.to_string());
+ assert_eq!("ERROR", LevelFilter::Error.to_string());
+ }
+
+ #[test]
+ fn test_cross_cmp() {
+ assert!(Level::Debug > LevelFilter::Error);
+ assert!(LevelFilter::Warn < Level::Trace);
+ assert!(LevelFilter::Off < Level::Error);
+ }
+
+ #[test]
+ fn test_cross_eq() {
+ assert!(Level::Error == LevelFilter::Error);
+ assert!(LevelFilter::Off != Level::Error);
+ assert!(Level::Trace == LevelFilter::Trace);
+ }
+
+ #[test]
+ fn test_to_level() {
+ assert_eq!(Some(Level::Error), LevelFilter::Error.to_level());
+ assert_eq!(None, LevelFilter::Off.to_level());
+ assert_eq!(Some(Level::Debug), LevelFilter::Debug.to_level());
+ }
+
+ #[test]
+ fn test_to_level_filter() {
+ assert_eq!(LevelFilter::Error, Level::Error.to_level_filter());
+ assert_eq!(LevelFilter::Trace, Level::Trace.to_level_filter());
+ }
+
+ #[test]
+ fn test_level_filter_as_str() {
+ let tests = &[
+ (LevelFilter::Off, "OFF"),
+ (LevelFilter::Error, "ERROR"),
+ (LevelFilter::Warn, "WARN"),
+ (LevelFilter::Info, "INFO"),
+ (LevelFilter::Debug, "DEBUG"),
+ (LevelFilter::Trace, "TRACE"),
+ ];
+ for (input, expected) in tests {
+ assert_eq!(*expected, input.as_str());
+ }
+ }
+
+ #[test]
+ #[cfg_attr(not(debug_assertions), ignore)]
+ fn test_static_max_level_debug() {
+ if cfg!(feature = "max_level_off") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off);
+ } else if cfg!(feature = "max_level_error") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error);
+ } else if cfg!(feature = "max_level_warn") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn);
+ } else if cfg!(feature = "max_level_info") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info);
+ } else if cfg!(feature = "max_level_debug") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug);
+ } else {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace);
+ }
+ }
+
+ #[test]
+ #[cfg_attr(debug_assertions, ignore)]
+ fn test_static_max_level_release() {
+ if cfg!(feature = "release_max_level_off") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off);
+ } else if cfg!(feature = "release_max_level_error") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error);
+ } else if cfg!(feature = "release_max_level_warn") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn);
+ } else if cfg!(feature = "release_max_level_info") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info);
+ } else if cfg!(feature = "release_max_level_debug") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug);
+ } else if cfg!(feature = "release_max_level_trace") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace);
+ } else if cfg!(feature = "max_level_off") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Off);
+ } else if cfg!(feature = "max_level_error") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Error);
+ } else if cfg!(feature = "max_level_warn") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Warn);
+ } else if cfg!(feature = "max_level_info") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Info);
+ } else if cfg!(feature = "max_level_debug") {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Debug);
+ } else {
+ assert_eq!(STATIC_MAX_LEVEL, LevelFilter::Trace);
+ }
+ }
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn test_error_trait() {
+ use super::SetLoggerError;
+ let e = SetLoggerError(());
+ assert_eq!(
+ &e.to_string(),
+ "attempted to set a logger after the logging system \
+ was already initialized"
+ );
+ }
+
+ #[test]
+ fn test_metadata_builder() {
+ use super::MetadataBuilder;
+ let target = "myApp";
+ let metadata_test = MetadataBuilder::new()
+ .level(Level::Debug)
+ .target(target)
+ .build();
+ assert_eq!(metadata_test.level(), Level::Debug);
+ assert_eq!(metadata_test.target(), "myApp");
+ }
+
+ #[test]
+ fn test_metadata_convenience_builder() {
+ use super::Metadata;
+ let target = "myApp";
+ let metadata_test = Metadata::builder()
+ .level(Level::Debug)
+ .target(target)
+ .build();
+ assert_eq!(metadata_test.level(), Level::Debug);
+ assert_eq!(metadata_test.target(), "myApp");
+ }
+
+ #[test]
+ fn test_record_builder() {
+ use super::{MetadataBuilder, RecordBuilder};
+ let target = "myApp";
+ let metadata = MetadataBuilder::new().target(target).build();
+ let fmt_args = format_args!("hello");
+ let record_test = RecordBuilder::new()
+ .args(fmt_args)
+ .metadata(metadata)
+ .module_path(Some("foo"))
+ .file(Some("bar"))
+ .line(Some(30))
+ .build();
+ assert_eq!(record_test.metadata().target(), "myApp");
+ assert_eq!(record_test.module_path(), Some("foo"));
+ assert_eq!(record_test.file(), Some("bar"));
+ assert_eq!(record_test.line(), Some(30));
+ }
+
+ #[test]
+ fn test_record_convenience_builder() {
+ use super::{Metadata, Record};
+ let target = "myApp";
+ let metadata = Metadata::builder().target(target).build();
+ let fmt_args = format_args!("hello");
+ let record_test = Record::builder()
+ .args(fmt_args)
+ .metadata(metadata)
+ .module_path(Some("foo"))
+ .file(Some("bar"))
+ .line(Some(30))
+ .build();
+ assert_eq!(record_test.target(), "myApp");
+ assert_eq!(record_test.module_path(), Some("foo"));
+ assert_eq!(record_test.file(), Some("bar"));
+ assert_eq!(record_test.line(), Some(30));
+ }
+
+ #[test]
+ fn test_record_complete_builder() {
+ use super::{Level, Record};
+ let target = "myApp";
+ let record_test = Record::builder()
+ .module_path(Some("foo"))
+ .file(Some("bar"))
+ .line(Some(30))
+ .target(target)
+ .level(Level::Error)
+ .build();
+ assert_eq!(record_test.target(), "myApp");
+ assert_eq!(record_test.level(), Level::Error);
+ assert_eq!(record_test.module_path(), Some("foo"));
+ assert_eq!(record_test.file(), Some("bar"));
+ assert_eq!(record_test.line(), Some(30));
+ }
+
+ #[test]
+ #[cfg(feature = "kv")]
+ fn test_record_key_values_builder() {
+ use super::Record;
+ use crate::kv::{self, VisitSource};
+
+ struct TestVisitSource {
+ seen_pairs: usize,
+ }
+
+ impl<'kvs> VisitSource<'kvs> for TestVisitSource {
+ fn visit_pair(
+ &mut self,
+ _: kv::Key<'kvs>,
+ _: kv::Value<'kvs>,
+ ) -> Result<(), kv::Error> {
+ self.seen_pairs += 1;
+ Ok(())
+ }
+ }
+
+ let kvs: &[(&str, i32)] = &[("a", 1), ("b", 2)];
+ let record_test = Record::builder().key_values(&kvs).build();
+
+ let mut visitor = TestVisitSource { seen_pairs: 0 };
+
+ record_test.key_values().visit(&mut visitor).unwrap();
+
+ assert_eq!(2, visitor.seen_pairs);
+ }
+
+ #[test]
+ #[cfg(feature = "kv")]
+ fn test_record_key_values_get_coerce() {
+ use super::Record;
+
+ let kvs: &[(&str, &str)] = &[("a", "1"), ("b", "2")];
+ let record = Record::builder().key_values(&kvs).build();
+
+ assert_eq!(
+ "2",
+ record
+ .key_values()
+ .get("b".into())
+ .expect("missing key")
+ .to_borrowed_str()
+ .expect("invalid value")
+ );
+ }
+
+ // Test that the `impl Log for Foo` blocks work
+ // This test mostly operates on a type level, so failures will be compile errors
+ #[test]
+ fn test_foreign_impl() {
+ use super::Log;
+ #[cfg(feature = "std")]
+ use std::sync::Arc;
+
+ fn assert_is_log<T: Log + ?Sized>() {}
+
+ assert_is_log::<&dyn Log>();
+
+ #[cfg(feature = "std")]
+ assert_is_log::<Box<dyn Log>>();
+
+ #[cfg(feature = "std")]
+ assert_is_log::<Arc<dyn Log>>();
+
+ // Assert these statements for all T: Log + ?Sized
+ #[allow(unused)]
+ fn forall<T: Log + ?Sized>() {
+ #[cfg(feature = "std")]
+ assert_is_log::<Box<T>>();
+
+ assert_is_log::<&T>();
+
+ #[cfg(feature = "std")]
+ assert_is_log::<Arc<T>>();
+ }
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs
new file mode 100644
index 0000000..87693f2
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/macros.rs
@@ -0,0 +1,367 @@
+// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+/// The standard logging macro.
+///
+/// This macro will generically log with the specified `Level` and `format!`
+/// based argument list.
+///
+/// # Examples
+///
+/// ```
+/// use log::{log, Level};
+///
+/// # fn main() {
+/// let data = (42, "Forty-two");
+/// let private_data = "private";
+///
+/// log!(Level::Error, "Received errors: {}, {}", data.0, data.1);
+/// log!(target: "app_events", Level::Warn, "App warning: {}, {}, {}",
+/// data.0, data.1, private_data);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! log {
+ // log!(target: "my_target", Level::Info, key1:? = 42, key2 = true; "a {} event", "log");
+ (target: $target:expr, $lvl:expr, $($key:tt $(:$capture:tt)? $(= $value:expr)?),+; $($arg:tt)+) => ({
+ let lvl = $lvl;
+ if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
+ $crate::__private_api::log::<&_>(
+ $crate::__private_api::format_args!($($arg)+),
+ lvl,
+ &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()),
+ &[$(($crate::__log_key!($key), $crate::__log_value!($key $(:$capture)* = $($value)*))),+]
+ );
+ }
+ });
+
+ // log!(target: "my_target", Level::Info, "a {} event", "log");
+ (target: $target:expr, $lvl:expr, $($arg:tt)+) => ({
+ let lvl = $lvl;
+ if lvl <= $crate::STATIC_MAX_LEVEL && lvl <= $crate::max_level() {
+ $crate::__private_api::log(
+ $crate::__private_api::format_args!($($arg)+),
+ lvl,
+ &($target, $crate::__private_api::module_path!(), $crate::__private_api::loc()),
+ (),
+ );
+ }
+ });
+
+ // log!(Level::Info, "a log event")
+ ($lvl:expr, $($arg:tt)+) => ($crate::log!(target: $crate::__private_api::module_path!(), $lvl, $($arg)+));
+}
+
+/// Logs a message at the error level.
+///
+/// # Examples
+///
+/// ```
+/// use log::error;
+///
+/// # fn main() {
+/// let (err_info, port) = ("No connection", 22);
+///
+/// error!("Error: {err_info} on port {port}");
+/// error!(target: "app_events", "App Error: {err_info}, Port: {port}");
+/// # }
+/// ```
+#[macro_export]
+macro_rules! error {
+ // error!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
+ // error!(target: "my_target", "a {} event", "log")
+ (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Error, $($arg)+));
+
+ // error!("a {} event", "log")
+ ($($arg:tt)+) => ($crate::log!($crate::Level::Error, $($arg)+))
+}
+
+/// Logs a message at the warn level.
+///
+/// # Examples
+///
+/// ```
+/// use log::warn;
+///
+/// # fn main() {
+/// let warn_description = "Invalid Input";
+///
+/// warn!("Warning! {warn_description}!");
+/// warn!(target: "input_events", "App received warning: {warn_description}");
+/// # }
+/// ```
+#[macro_export]
+macro_rules! warn {
+ // warn!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
+ // warn!(target: "my_target", "a {} event", "log")
+ (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Warn, $($arg)+));
+
+ // warn!("a {} event", "log")
+ ($($arg:tt)+) => ($crate::log!($crate::Level::Warn, $($arg)+))
+}
+
+/// Logs a message at the info level.
+///
+/// # Examples
+///
+/// ```
+/// use log::info;
+///
+/// # fn main() {
+/// # struct Connection { port: u32, speed: f32 }
+/// let conn_info = Connection { port: 40, speed: 3.20 };
+///
+/// info!("Connected to port {} at {} Mb/s", conn_info.port, conn_info.speed);
+/// info!(target: "connection_events", "Successful connection, port: {}, speed: {}",
+/// conn_info.port, conn_info.speed);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! info {
+ // info!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
+ // info!(target: "my_target", "a {} event", "log")
+ (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Info, $($arg)+));
+
+ // info!("a {} event", "log")
+ ($($arg:tt)+) => ($crate::log!($crate::Level::Info, $($arg)+))
+}
+
+/// Logs a message at the debug level.
+///
+/// # Examples
+///
+/// ```
+/// use log::debug;
+///
+/// # fn main() {
+/// # struct Position { x: f32, y: f32 }
+/// let pos = Position { x: 3.234, y: -1.223 };
+///
+/// debug!("New position: x: {}, y: {}", pos.x, pos.y);
+/// debug!(target: "app_events", "New position: x: {}, y: {}", pos.x, pos.y);
+/// # }
+/// ```
+#[macro_export]
+macro_rules! debug {
+ // debug!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
+ // debug!(target: "my_target", "a {} event", "log")
+ (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Debug, $($arg)+));
+
+ // debug!("a {} event", "log")
+ ($($arg:tt)+) => ($crate::log!($crate::Level::Debug, $($arg)+))
+}
+
+/// Logs a message at the trace level.
+///
+/// # Examples
+///
+/// ```
+/// use log::trace;
+///
+/// # fn main() {
+/// # struct Position { x: f32, y: f32 }
+/// let pos = Position { x: 3.234, y: -1.223 };
+///
+/// trace!("Position is: x: {}, y: {}", pos.x, pos.y);
+/// trace!(target: "app_events", "x is {} and y is {}",
+/// if pos.x >= 0.0 { "positive" } else { "negative" },
+/// if pos.y >= 0.0 { "positive" } else { "negative" });
+/// # }
+/// ```
+#[macro_export]
+macro_rules! trace {
+ // trace!(target: "my_target", key1 = 42, key2 = true; "a {} event", "log")
+ // trace!(target: "my_target", "a {} event", "log")
+ (target: $target:expr, $($arg:tt)+) => ($crate::log!(target: $target, $crate::Level::Trace, $($arg)+));
+
+ // trace!("a {} event", "log")
+ ($($arg:tt)+) => ($crate::log!($crate::Level::Trace, $($arg)+))
+}
+
+/// Determines if a message logged at the specified level in that module will
+/// be logged.
+///
+/// This can be used to avoid expensive computation of log message arguments if
+/// the message would be ignored anyway.
+///
+/// # Examples
+///
+/// ```
+/// use log::Level::Debug;
+/// use log::{debug, log_enabled};
+///
+/// # fn foo() {
+/// if log_enabled!(Debug) {
+/// let data = expensive_call();
+/// debug!("expensive debug data: {} {}", data.x, data.y);
+/// }
+/// if log_enabled!(target: "Global", Debug) {
+/// let data = expensive_call();
+/// debug!(target: "Global", "expensive debug data: {} {}", data.x, data.y);
+/// }
+/// # }
+/// # struct Data { x: u32, y: u32 }
+/// # fn expensive_call() -> Data { Data { x: 0, y: 0 } }
+/// # fn main() {}
+/// ```
+#[macro_export]
+macro_rules! log_enabled {
+ (target: $target:expr, $lvl:expr) => {{
+ let lvl = $lvl;
+ lvl <= $crate::STATIC_MAX_LEVEL
+ && lvl <= $crate::max_level()
+ && $crate::__private_api::enabled(lvl, $target)
+ }};
+ ($lvl:expr) => {
+ $crate::log_enabled!(target: $crate::__private_api::module_path!(), $lvl)
+ };
+}
+
+// These macros use a pattern of #[cfg]s to produce nicer error
+// messages when log features aren't available
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(feature = "kv")]
+macro_rules! __log_key {
+ // key1 = 42
+ ($($args:ident)*) => {
+ $crate::__private_api::stringify!($($args)*)
+ };
+ // "key1" = 42
+ ($($args:expr)*) => {
+ $($args)*
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(not(feature = "kv"))]
+macro_rules! __log_key {
+ ($($args:tt)*) => {
+ compile_error!("key value support requires the `kv` feature of `log`")
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(feature = "kv")]
+macro_rules! __log_value {
+ // Entrypoint
+ ($key:tt = $args:expr) => {
+ $crate::__log_value!(($args):value)
+ };
+ ($key:tt :$capture:tt = $args:expr) => {
+ $crate::__log_value!(($args):$capture)
+ };
+ ($key:ident =) => {
+ $crate::__log_value!(($key):value)
+ };
+ ($key:ident :$capture:tt =) => {
+ $crate::__log_value!(($key):$capture)
+ };
+ // ToValue
+ (($args:expr):value) => {
+ $crate::__private_api::capture_to_value(&&$args)
+ };
+ // Debug
+ (($args:expr):?) => {
+ $crate::__private_api::capture_debug(&&$args)
+ };
+ (($args:expr):debug) => {
+ $crate::__private_api::capture_debug(&&$args)
+ };
+ // Display
+ (($args:expr):%) => {
+ $crate::__private_api::capture_display(&&$args)
+ };
+ (($args:expr):display) => {
+ $crate::__private_api::capture_display(&&$args)
+ };
+ //Error
+ (($args:expr):err) => {
+ $crate::__log_value_error!($args)
+ };
+ // sval::Value
+ (($args:expr):sval) => {
+ $crate::__log_value_sval!($args)
+ };
+ // serde::Serialize
+ (($args:expr):serde) => {
+ $crate::__log_value_serde!($args)
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(not(feature = "kv"))]
+macro_rules! __log_value {
+ ($($args:tt)*) => {
+ compile_error!("key value support requires the `kv` feature of `log`")
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(feature = "kv_sval")]
+macro_rules! __log_value_sval {
+ ($args:expr) => {
+ $crate::__private_api::capture_sval(&&$args)
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(not(feature = "kv_sval"))]
+macro_rules! __log_value_sval {
+ ($args:expr) => {
+ compile_error!("capturing values as `sval::Value` requites the `kv_sval` feature of `log`")
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(feature = "kv_serde")]
+macro_rules! __log_value_serde {
+ ($args:expr) => {
+ $crate::__private_api::capture_serde(&&$args)
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(not(feature = "kv_serde"))]
+macro_rules! __log_value_serde {
+ ($args:expr) => {
+ compile_error!(
+ "capturing values as `serde::Serialize` requites the `kv_serde` feature of `log`"
+ )
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(feature = "kv_std")]
+macro_rules! __log_value_error {
+ ($args:expr) => {
+ $crate::__private_api::capture_error(&$args)
+ };
+}
+
+#[doc(hidden)]
+#[macro_export]
+#[cfg(not(feature = "kv_std"))]
+macro_rules! __log_value_error {
+ ($args:expr) => {
+ compile_error!(
+ "capturing values as `std::error::Error` requites the `kv_std` feature of `log`"
+ )
+ };
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs
new file mode 100644
index 0000000..63bef7f
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/src/serde.rs
@@ -0,0 +1,397 @@
+#![cfg(feature = "serde")]
+
+use serde::de::{
+ Deserialize, DeserializeSeed, Deserializer, EnumAccess, Error, Unexpected, VariantAccess,
+ Visitor,
+};
+use serde::ser::{Serialize, Serializer};
+
+use crate::{Level, LevelFilter, LOG_LEVEL_NAMES};
+
+use std::fmt;
+use std::str::{self, FromStr};
+
+// The Deserialize impls are handwritten to be case insensitive using FromStr.
+
+impl Serialize for Level {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match *self {
+ Level::Error => serializer.serialize_unit_variant("Level", 0, "ERROR"),
+ Level::Warn => serializer.serialize_unit_variant("Level", 1, "WARN"),
+ Level::Info => serializer.serialize_unit_variant("Level", 2, "INFO"),
+ Level::Debug => serializer.serialize_unit_variant("Level", 3, "DEBUG"),
+ Level::Trace => serializer.serialize_unit_variant("Level", 4, "TRACE"),
+ }
+ }
+}
+
+impl<'de> Deserialize<'de> for Level {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct LevelIdentifier;
+
+ impl<'de> Visitor<'de> for LevelIdentifier {
+ type Value = Level;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("log level")
+ }
+
+ fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ let variant = LOG_LEVEL_NAMES[1..]
+ .get(v as usize)
+ .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?;
+
+ self.visit_str(variant)
+ }
+
+ fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ // Case insensitive.
+ FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES[1..]))
+ }
+
+ fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ let variant = str::from_utf8(value)
+ .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?;
+
+ self.visit_str(variant)
+ }
+ }
+
+ impl<'de> DeserializeSeed<'de> for LevelIdentifier {
+ type Value = Level;
+
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_identifier(LevelIdentifier)
+ }
+ }
+
+ struct LevelEnum;
+
+ impl<'de> Visitor<'de> for LevelEnum {
+ type Value = Level;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("log level")
+ }
+
+ fn visit_enum<A>(self, value: A) -> Result<Self::Value, A::Error>
+ where
+ A: EnumAccess<'de>,
+ {
+ let (level, variant) = value.variant_seed(LevelIdentifier)?;
+ // Every variant is a unit variant.
+ variant.unit_variant()?;
+ Ok(level)
+ }
+ }
+
+ deserializer.deserialize_enum("Level", &LOG_LEVEL_NAMES[1..], LevelEnum)
+ }
+}
+
+impl Serialize for LevelFilter {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: Serializer,
+ {
+ match *self {
+ LevelFilter::Off => serializer.serialize_unit_variant("LevelFilter", 0, "OFF"),
+ LevelFilter::Error => serializer.serialize_unit_variant("LevelFilter", 1, "ERROR"),
+ LevelFilter::Warn => serializer.serialize_unit_variant("LevelFilter", 2, "WARN"),
+ LevelFilter::Info => serializer.serialize_unit_variant("LevelFilter", 3, "INFO"),
+ LevelFilter::Debug => serializer.serialize_unit_variant("LevelFilter", 4, "DEBUG"),
+ LevelFilter::Trace => serializer.serialize_unit_variant("LevelFilter", 5, "TRACE"),
+ }
+ }
+}
+
+impl<'de> Deserialize<'de> for LevelFilter {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ struct LevelFilterIdentifier;
+
+ impl<'de> Visitor<'de> for LevelFilterIdentifier {
+ type Value = LevelFilter;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("log level filter")
+ }
+
+ fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ let variant = LOG_LEVEL_NAMES
+ .get(v as usize)
+ .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v), &self))?;
+
+ self.visit_str(variant)
+ }
+
+ fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ // Case insensitive.
+ FromStr::from_str(s).map_err(|_| Error::unknown_variant(s, &LOG_LEVEL_NAMES))
+ }
+
+ fn visit_bytes<E>(self, value: &[u8]) -> Result<Self::Value, E>
+ where
+ E: Error,
+ {
+ let variant = str::from_utf8(value)
+ .map_err(|_| Error::invalid_value(Unexpected::Bytes(value), &self))?;
+
+ self.visit_str(variant)
+ }
+ }
+
+ impl<'de> DeserializeSeed<'de> for LevelFilterIdentifier {
+ type Value = LevelFilter;
+
+ fn deserialize<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ deserializer.deserialize_identifier(LevelFilterIdentifier)
+ }
+ }
+
+ struct LevelFilterEnum;
+
+ impl<'de> Visitor<'de> for LevelFilterEnum {
+ type Value = LevelFilter;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ formatter.write_str("log level filter")
+ }
+
+ fn visit_enum<A>(self, value: A) -> Result<Self::Value, A::Error>
+ where
+ A: EnumAccess<'de>,
+ {
+ let (level_filter, variant) = value.variant_seed(LevelFilterIdentifier)?;
+ // Every variant is a unit variant.
+ variant.unit_variant()?;
+ Ok(level_filter)
+ }
+ }
+
+ deserializer.deserialize_enum("LevelFilter", &LOG_LEVEL_NAMES, LevelFilterEnum)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::{Level, LevelFilter};
+ use serde_test::{assert_de_tokens, assert_de_tokens_error, assert_tokens, Token};
+
+ fn level_token(variant: &'static str) -> Token {
+ Token::UnitVariant {
+ name: "Level",
+ variant,
+ }
+ }
+
+ fn level_bytes_tokens(variant: &'static [u8]) -> [Token; 3] {
+ [
+ Token::Enum { name: "Level" },
+ Token::Bytes(variant),
+ Token::Unit,
+ ]
+ }
+
+ fn level_variant_tokens(variant: u32) -> [Token; 3] {
+ [
+ Token::Enum { name: "Level" },
+ Token::U32(variant),
+ Token::Unit,
+ ]
+ }
+
+ fn level_filter_token(variant: &'static str) -> Token {
+ Token::UnitVariant {
+ name: "LevelFilter",
+ variant,
+ }
+ }
+
+ fn level_filter_bytes_tokens(variant: &'static [u8]) -> [Token; 3] {
+ [
+ Token::Enum {
+ name: "LevelFilter",
+ },
+ Token::Bytes(variant),
+ Token::Unit,
+ ]
+ }
+
+ fn level_filter_variant_tokens(variant: u32) -> [Token; 3] {
+ [
+ Token::Enum {
+ name: "LevelFilter",
+ },
+ Token::U32(variant),
+ Token::Unit,
+ ]
+ }
+
+ #[test]
+ fn test_level_ser_de() {
+ let cases = &[
+ (Level::Error, [level_token("ERROR")]),
+ (Level::Warn, [level_token("WARN")]),
+ (Level::Info, [level_token("INFO")]),
+ (Level::Debug, [level_token("DEBUG")]),
+ (Level::Trace, [level_token("TRACE")]),
+ ];
+
+ for (s, expected) in cases {
+ assert_tokens(s, expected);
+ }
+ }
+
+ #[test]
+ fn test_level_case_insensitive() {
+ let cases = &[
+ (Level::Error, [level_token("error")]),
+ (Level::Warn, [level_token("warn")]),
+ (Level::Info, [level_token("info")]),
+ (Level::Debug, [level_token("debug")]),
+ (Level::Trace, [level_token("trace")]),
+ ];
+
+ for (s, expected) in cases {
+ assert_de_tokens(s, expected);
+ }
+ }
+
+ #[test]
+ fn test_level_de_bytes() {
+ let cases = &[
+ (Level::Error, level_bytes_tokens(b"ERROR")),
+ (Level::Warn, level_bytes_tokens(b"WARN")),
+ (Level::Info, level_bytes_tokens(b"INFO")),
+ (Level::Debug, level_bytes_tokens(b"DEBUG")),
+ (Level::Trace, level_bytes_tokens(b"TRACE")),
+ ];
+
+ for (value, tokens) in cases {
+ assert_de_tokens(value, tokens);
+ }
+ }
+
+ #[test]
+ fn test_level_de_variant_index() {
+ let cases = &[
+ (Level::Error, level_variant_tokens(0)),
+ (Level::Warn, level_variant_tokens(1)),
+ (Level::Info, level_variant_tokens(2)),
+ (Level::Debug, level_variant_tokens(3)),
+ (Level::Trace, level_variant_tokens(4)),
+ ];
+
+ for (value, tokens) in cases {
+ assert_de_tokens(value, tokens);
+ }
+ }
+
+ #[test]
+ fn test_level_de_error() {
+ let msg = "unknown variant `errorx`, expected one of \
+ `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`";
+ assert_de_tokens_error::<Level>(&[level_token("errorx")], msg);
+ }
+
+ #[test]
+ fn test_level_filter_ser_de() {
+ let cases = &[
+ (LevelFilter::Off, [level_filter_token("OFF")]),
+ (LevelFilter::Error, [level_filter_token("ERROR")]),
+ (LevelFilter::Warn, [level_filter_token("WARN")]),
+ (LevelFilter::Info, [level_filter_token("INFO")]),
+ (LevelFilter::Debug, [level_filter_token("DEBUG")]),
+ (LevelFilter::Trace, [level_filter_token("TRACE")]),
+ ];
+
+ for (s, expected) in cases {
+ assert_tokens(s, expected);
+ }
+ }
+
+ #[test]
+ fn test_level_filter_case_insensitive() {
+ let cases = &[
+ (LevelFilter::Off, [level_filter_token("off")]),
+ (LevelFilter::Error, [level_filter_token("error")]),
+ (LevelFilter::Warn, [level_filter_token("warn")]),
+ (LevelFilter::Info, [level_filter_token("info")]),
+ (LevelFilter::Debug, [level_filter_token("debug")]),
+ (LevelFilter::Trace, [level_filter_token("trace")]),
+ ];
+
+ for (s, expected) in cases {
+ assert_de_tokens(s, expected);
+ }
+ }
+
+ #[test]
+ fn test_level_filter_de_bytes() {
+ let cases = &[
+ (LevelFilter::Off, level_filter_bytes_tokens(b"OFF")),
+ (LevelFilter::Error, level_filter_bytes_tokens(b"ERROR")),
+ (LevelFilter::Warn, level_filter_bytes_tokens(b"WARN")),
+ (LevelFilter::Info, level_filter_bytes_tokens(b"INFO")),
+ (LevelFilter::Debug, level_filter_bytes_tokens(b"DEBUG")),
+ (LevelFilter::Trace, level_filter_bytes_tokens(b"TRACE")),
+ ];
+
+ for (value, tokens) in cases {
+ assert_de_tokens(value, tokens);
+ }
+ }
+
+ #[test]
+ fn test_level_filter_de_variant_index() {
+ let cases = &[
+ (LevelFilter::Off, level_filter_variant_tokens(0)),
+ (LevelFilter::Error, level_filter_variant_tokens(1)),
+ (LevelFilter::Warn, level_filter_variant_tokens(2)),
+ (LevelFilter::Info, level_filter_variant_tokens(3)),
+ (LevelFilter::Debug, level_filter_variant_tokens(4)),
+ (LevelFilter::Trace, level_filter_variant_tokens(5)),
+ ];
+
+ for (value, tokens) in cases {
+ assert_de_tokens(value, tokens);
+ }
+ }
+
+ #[test]
+ fn test_level_filter_de_error() {
+ let msg = "unknown variant `errorx`, expected one of \
+ `OFF`, `ERROR`, `WARN`, `INFO`, `DEBUG`, `TRACE`";
+ assert_de_tokens_error::<LevelFilter>(&[level_filter_token("errorx")], msg);
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml
new file mode 100644
index 0000000..fa0824a
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/log/triagebot.toml
@@ -0,0 +1 @@
+[assign]
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json
new file mode 100644
index 0000000..bcbce9e
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"d4ff1d54f23cde7d35174635e8db5e6aee0d61b846d2fccbf0d28146246b3a28","README.md":"fc6752d50a57acbf3d65581c0d2f3d0da8c5fef5735a12857660c9e9687751d0","src/facts.rs":"9fad471b6ba5f63b8a1367002fee2b27fc3b3b893680eca390bc2616718f8915","src/lib.rs":"19ef0fd2d054b3a48c11ff4007734b7940ca739d3a9d5083d3a03b4d982cdb99","src/output/datafrog_opt.rs":"c75fa04ed1cc1a5b59f9405ce959af5950d37ae57876cc9510adc7c013b25af5","src/output/initialization.rs":"b9665c1397ff5e1cc1a93e9645bec0bed672ea9822c4dd32fc545ecbd3f80258","src/output/liveness.rs":"b68c9edd17feebff7d0b006caaf8197b5c30320b1a8cdcbe653bd7218954dd4f","src/output/location_insensitive.rs":"eb7c495ec38768104b8877de66341aaca210cdad824cae948f3fd7cf4ba858d0","src/output/mod.rs":"968f8547954a4444f59f3c056a9b742aa59ede3a90bb9b6fe08ba506fcc6bce5","src/output/naive.rs":"b345c2beb8a2f79bc482d131954bea4f23e53a3ce8270f64b8e940f0de376730"},"package":"c4e8e505342045d397d0b6674dcb82d6faf5cf40484d30eeb88fc82ef14e903f"} \ No newline at end of file
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml
new file mode 100644
index 0000000..e3a8f74
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/Cargo.toml
@@ -0,0 +1,29 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "polonius-engine"
+version = "0.13.0"
+authors = ["The Rust Project Developers", "Polonius Developers"]
+description = "Core definition for the Rust borrow checker"
+readme = "README.md"
+keywords = ["compiler", "borrowck", "datalog"]
+license = "Apache-2.0/MIT"
+repository = "https://github.com/rust-lang-nursery/polonius"
+[dependencies.datafrog]
+version = "2.0.0"
+
+[dependencies.log]
+version = "0.4"
+
+[dependencies.rustc-hash]
+version = "1.0.0"
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md
new file mode 100644
index 0000000..d88295e
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/README.md
@@ -0,0 +1,6 @@
+This is a core library that models the borrow check. It implements the
+analysis [described in this blogpost][post]. This library is intended
+for use both by rustc and by the polonius crate, which is a distinct
+front-end intended for testing, profiling, etc.
+
+[post]: http://smallcultfollowing.com/babysteps/blog/2018/04/27/an-alias-based-formulation-of-the-borrow-checker/
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs
new file mode 100644
index 0000000..442ba18
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/facts.rs
@@ -0,0 +1,129 @@
+use std::fmt::Debug;
+use std::hash::Hash;
+
+/// The "facts" which are the basis of the NLL borrow analysis.
+#[derive(Clone, Debug)]
+pub struct AllFacts<T: FactTypes> {
+ /// `loan_issued_at(origin, loan, point)` indicates that the `loan` was "issued"
+ /// at the given `point`, creating a reference with the `origin`.
+ /// Effectively, `origin` may refer to data from `loan` starting at `point` (this is usually
+ /// the point *after* a borrow rvalue).
+ pub loan_issued_at: Vec<(T::Origin, T::Loan, T::Point)>,
+
+ /// `universal_region(origin)` -- this is a "free region" within fn body
+ pub universal_region: Vec<T::Origin>,
+
+ /// `cfg_edge(point1, point2)` for each edge `point1 -> point2` in the control flow
+ pub cfg_edge: Vec<(T::Point, T::Point)>,
+
+ /// `loan_killed_at(loan, point)` when some prefix of the path borrowed at `loan`
+ /// is assigned at `point`.
+ /// Indicates that the path borrowed by the `loan` has changed in some way that the loan no
+ /// longer needs to be tracked. (In particular, mutations to the path that was borrowed
+ /// no longer invalidate the loan)
+ pub loan_killed_at: Vec<(T::Loan, T::Point)>,
+
+ /// `subset_base(origin1, origin2, point)` when we require `origin1@point: origin2@point`.
+ /// Indicates that `origin1 <= origin2` -- i.e., the set of loans in `origin1` are a subset
+ /// of those in `origin2`.
+ pub subset_base: Vec<(T::Origin, T::Origin, T::Point)>,
+
+ /// `loan_invalidated_at(point, loan)` indicates that the `loan` is invalidated by some action
+ /// taking place at `point`; if any origin that references this loan is live, this is an error.
+ pub loan_invalidated_at: Vec<(T::Point, T::Loan)>,
+
+ /// `var_used_at(var, point)` when the variable `var` is used for anything
+ /// but a drop at `point`
+ pub var_used_at: Vec<(T::Variable, T::Point)>,
+
+ /// `var_defined_at(var, point)` when the variable `var` is overwritten at `point`
+ pub var_defined_at: Vec<(T::Variable, T::Point)>,
+
+ /// `var_dropped_at(var, point)` when the variable `var` is used in a drop at `point`
+ pub var_dropped_at: Vec<(T::Variable, T::Point)>,
+
+ /// `use_of_var_derefs_origin(variable, origin)`: References with the given
+ /// `origin` may be dereferenced when the `variable` is used.
+ ///
+ /// In rustc, we generate this whenever the type of the variable includes the
+ /// given origin.
+ pub use_of_var_derefs_origin: Vec<(T::Variable, T::Origin)>,
+
+ /// `drop_of_var_derefs_origin(var, origin)` when the type of `var` includes
+ /// the `origin` and uses it when dropping
+ pub drop_of_var_derefs_origin: Vec<(T::Variable, T::Origin)>,
+
+ /// `child_path(child, parent)` when the path `child` is the direct child of
+ /// `parent`, e.g. `child_path(x.y, x)`, but not `child_path(x.y.z, x)`.
+ pub child_path: Vec<(T::Path, T::Path)>,
+
+ /// `path_is_var(path, var)` the root path `path` starting in variable `var`.
+ pub path_is_var: Vec<(T::Path, T::Variable)>,
+
+ /// `path_assigned_at_base(path, point)` when the `path` was initialized at point
+ /// `point`. This fact is only emitted for a prefix `path`, and not for the
+ /// implicit initialization of all of `path`'s children. E.g. a statement like
+ /// `x.y = 3` at `point` would give the fact `path_assigned_at_base(x.y, point)` (but
+ /// neither `path_assigned_at_base(x.y.z, point)` nor `path_assigned_at_base(x, point)`).
+ pub path_assigned_at_base: Vec<(T::Path, T::Point)>,
+
+ /// `path_moved_at_base(path, point)` when the `path` was moved at `point`. The
+ /// same logic is applied as for `path_assigned_at_base` above.
+ pub path_moved_at_base: Vec<(T::Path, T::Point)>,
+
+ /// `path_accessed_at_base(path, point)` when the `path` was accessed at point
+ /// `point`. The same logic as for `path_assigned_at_base` and `path_moved_at_base` applies.
+ pub path_accessed_at_base: Vec<(T::Path, T::Point)>,
+
+ /// These reflect the `'a: 'b` relations that are either declared by the user on function
+ /// declarations or which are inferred via implied bounds.
+ /// For example: `fn foo<'a, 'b: 'a, 'c>(x: &'c &'a u32)` would have two entries:
+ /// - one for the user-supplied subset `'b: 'a`
+ /// - and one for the `'a: 'c` implied bound from the `x` parameter,
+ /// (note that the transitive relation `'b: 'c` is not necessarily included
+ /// explicitly, but rather inferred by polonius).
+ pub known_placeholder_subset: Vec<(T::Origin, T::Origin)>,
+
+ /// `placeholder(origin, loan)` describes a placeholder `origin`, with its associated
+ /// placeholder `loan`.
+ pub placeholder: Vec<(T::Origin, T::Loan)>,
+}
+
+impl<T: FactTypes> Default for AllFacts<T> {
+ fn default() -> Self {
+ AllFacts {
+ loan_issued_at: Vec::default(),
+ universal_region: Vec::default(),
+ cfg_edge: Vec::default(),
+ loan_killed_at: Vec::default(),
+ subset_base: Vec::default(),
+ loan_invalidated_at: Vec::default(),
+ var_used_at: Vec::default(),
+ var_defined_at: Vec::default(),
+ var_dropped_at: Vec::default(),
+ use_of_var_derefs_origin: Vec::default(),
+ drop_of_var_derefs_origin: Vec::default(),
+ child_path: Vec::default(),
+ path_is_var: Vec::default(),
+ path_assigned_at_base: Vec::default(),
+ path_moved_at_base: Vec::default(),
+ path_accessed_at_base: Vec::default(),
+ known_placeholder_subset: Vec::default(),
+ placeholder: Vec::default(),
+ }
+ }
+}
+
+pub trait Atom:
+ From<usize> + Into<usize> + Copy + Clone + Debug + Eq + Ord + Hash + 'static
+{
+ fn index(self) -> usize;
+}
+
+pub trait FactTypes: Copy + Clone + Debug {
+ type Origin: Atom;
+ type Loan: Atom;
+ type Point: Atom;
+ type Variable: Atom;
+ type Path: Atom;
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs
new file mode 100644
index 0000000..0926be8
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/lib.rs
@@ -0,0 +1,16 @@
+/// Contains the core of the Polonius borrow checking engine.
+/// Input is fed in via AllFacts, and outputs are returned via Output
+extern crate datafrog;
+#[macro_use]
+extern crate log;
+extern crate rustc_hash;
+
+mod facts;
+mod output;
+
+// Reexports of facts
+pub use facts::AllFacts;
+pub use facts::Atom;
+pub use facts::FactTypes;
+pub use output::Algorithm;
+pub use output::Output;
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs
new file mode 100644
index 0000000..da9c343
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/datafrog_opt.rs
@@ -0,0 +1,495 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+use datafrog::{Iteration, Relation, RelationLeaper};
+use std::time::Instant;
+
+use crate::facts::FactTypes;
+use crate::output::{Context, Output};
+
+pub(super) fn compute<T: FactTypes>(
+ ctx: &Context<'_, T>,
+ result: &mut Output<T>,
+) -> (
+ Relation<(T::Loan, T::Point)>,
+ Relation<(T::Origin, T::Origin, T::Point)>,
+) {
+ let timer = Instant::now();
+
+ let (errors, subset_errors) = {
+ // Static inputs
+ let origin_live_on_entry_rel = &ctx.origin_live_on_entry;
+ let cfg_edge_rel = &ctx.cfg_edge;
+ let loan_killed_at = &ctx.loan_killed_at;
+ let known_placeholder_subset = &ctx.known_placeholder_subset;
+ let placeholder_origin = &ctx.placeholder_origin;
+
+ // Create a new iteration context, ...
+ let mut iteration = Iteration::new();
+
+ // `loan_invalidated_at` facts, stored ready for joins
+ let loan_invalidated_at =
+ iteration.variable::<((T::Loan, T::Point), ())>("loan_invalidated_at");
+
+ // we need `origin_live_on_entry` in both variable and relation forms,
+ // (respectively, for join and antijoin).
+ let origin_live_on_entry_var =
+ iteration.variable::<((T::Origin, T::Point), ())>("origin_live_on_entry");
+
+ // `loan_issued_at` input but organized for join
+ let loan_issued_at_op =
+ iteration.variable::<((T::Origin, T::Point), T::Loan)>("loan_issued_at_op");
+
+ // .decl subset(origin1, origin2, point)
+ //
+ // Indicates that `origin1: origin2` at `point`.
+ let subset_o1p = iteration.variable::<((T::Origin, T::Point), T::Origin)>("subset_o1p");
+
+ // .decl origin_contains_loan_on_entry(origin, loan, point)
+ //
+ // At `point`, things with `origin` may depend on data from `loan`.
+ let origin_contains_loan_on_entry_op = iteration
+ .variable::<((T::Origin, T::Point), T::Loan)>("origin_contains_loan_on_entry_op");
+
+ // .decl loan_live_at(loan, point)
+ //
+ // True if the restrictions of the `loan` need to be enforced at `point`.
+ let loan_live_at = iteration.variable::<((T::Loan, T::Point), ())>("loan_live_at");
+
+ // .decl live_to_dying_regions(origin1, origin2, point1, point2)
+ //
+ // The origins `origin1` and `origin2` are "live to dead"
+ // on the edge `point1 -> point2` if:
+ //
+ // - In `point1`, `origin1` <= `origin2`
+ // - In `point2`, `origin1` is live but `origin2` is dead.
+ //
+ // In that case, `point2` would like to add all the
+ // live things reachable from `origin2` to `origin1`.
+ //
+ let live_to_dying_regions_o2pq = iteration
+ .variable::<((T::Origin, T::Point, T::Point), T::Origin)>("live_to_dying_regions_o2pq");
+
+ // .decl dying_region_requires((origin, point1, point2), loan)
+ //
+ // The `origin` requires `loan`, but the `origin` goes dead
+ // along the edge `point1 -> point2`.
+ let dying_region_requires = iteration
+ .variable::<((T::Origin, T::Point, T::Point), T::Loan)>("dying_region_requires");
+
+ // .decl dying_can_reach_origins(origin, point1, point2)
+ //
+ // Contains dead origins where we are interested
+ // in computing the transitive closure of things they
+ // can reach.
+ //
+ // FIXME: this relation was named before renaming the `regions` atoms to `origins`, and
+ // will need to be renamed to change "_origins" to "_ascendants", "_roots", etc.
+ let dying_can_reach_origins =
+ iteration.variable::<((T::Origin, T::Point), T::Point)>("dying_can_reach_origins");
+
+ // .decl dying_can_reach(origin1, origin2, point1, point2)
+ //
+ // Indicates that `origin1`, which is dead
+ // in `point2`, can reach `origin2` in `point1`.
+ //
+ // This is effectively the transitive subset
+ // relation, but we try to limit it to origins
+ // that are dying on the edge `point1 -> point2`.
+ let dying_can_reach_o2q =
+ iteration.variable::<((T::Origin, T::Point), (T::Origin, T::Point))>("dying_can_reach");
+ let dying_can_reach_1 = iteration.variable_indistinct("dying_can_reach_1");
+
+ // .decl dying_can_reach_live(origin1, origin2, point1, point2)
+ //
+ // Indicates that, along the edge `point1 -> point2`, the dead (in `point2`)
+ // `origin1` can reach the live (in `point2`) `origin2` via a subset
+ // relation. This is a subset of the full `dying_can_reach`
+ // relation where we filter down to those cases where `origin2` is
+ // live in `point2`.
+ let dying_can_reach_live = iteration
+ .variable::<((T::Origin, T::Point, T::Point), T::Origin)>("dying_can_reach_live");
+
+ // .decl dead_borrow_region_can_reach_root((origin, point), loan)
+ //
+ // Indicates a "borrow region" `origin` at `point` which is not live on
+ // entry to `point`.
+ let dead_borrow_region_can_reach_root = iteration
+ .variable::<((T::Origin, T::Point), T::Loan)>("dead_borrow_region_can_reach_root");
+
+ // .decl dead_borrow_region_can_reach_dead((origin2, point), loan)
+ let dead_borrow_region_can_reach_dead = iteration
+ .variable::<((T::Origin, T::Point), T::Loan)>("dead_borrow_region_can_reach_dead");
+ let dead_borrow_region_can_reach_dead_1 =
+ iteration.variable_indistinct("dead_borrow_region_can_reach_dead_1");
+
+ // .decl errors(loan, point)
+ let errors = iteration.variable("errors");
+ let subset_errors = iteration.variable::<(T::Origin, T::Origin, T::Point)>("subset_errors");
+
+ let subset_placeholder =
+ iteration.variable::<(T::Origin, T::Origin, T::Point)>("subset_placeholder");
+ let subset_placeholder_o2p = iteration.variable_indistinct("subset_placeholder_o2p");
+
+ // Make "variable" versions of the relations, needed for joins.
+ loan_issued_at_op.extend(
+ ctx.loan_issued_at
+ .iter()
+ .map(|&(origin, loan, point)| ((origin, point), loan)),
+ );
+ loan_invalidated_at.extend(
+ ctx.loan_invalidated_at
+ .iter()
+ .map(|&(loan, point)| ((loan, point), ())),
+ );
+ origin_live_on_entry_var.extend(
+ origin_live_on_entry_rel
+ .iter()
+ .map(|&(origin, point)| ((origin, point), ())),
+ );
+
+ // subset(origin1, origin2, point) :-
+ // subset_base(origin1, origin2, point).
+ subset_o1p.extend(
+ ctx.subset_base
+ .iter()
+ .map(|&(origin1, origin2, point)| ((origin1, point), origin2)),
+ );
+
+ // origin_contains_loan_on_entry(origin, loan, point) :-
+ // loan_issued_at(origin, loan, point).
+ origin_contains_loan_on_entry_op.extend(
+ ctx.loan_issued_at
+ .iter()
+ .map(|&(origin, loan, point)| ((origin, point), loan)),
+ );
+
+ // .. and then start iterating rules!
+ while iteration.changed() {
+ // Cleanup step: remove symmetries
+ // - remove origins which are `subset`s of themselves
+ //
+ // FIXME: investigate whether is there a better way to do that without complicating
+ // the rules too much, because it would also require temporary variables and
+ // impact performance. Until then, the big reduction in tuples improves performance
+ // a lot, even if we're potentially adding a small number of tuples
+ // per round just to remove them in the next round.
+ subset_o1p
+ .recent
+ .borrow_mut()
+ .elements
+ .retain(|&((origin1, _), origin2)| origin1 != origin2);
+
+ subset_placeholder
+ .recent
+ .borrow_mut()
+ .elements
+ .retain(|&(origin1, origin2, _)| origin1 != origin2);
+ subset_placeholder_o2p.from_map(&subset_placeholder, |&(origin1, origin2, point)| {
+ ((origin2, point), origin1)
+ });
+
+ // live_to_dying_regions(origin1, origin2, point1, point2) :-
+ // subset(origin1, origin2, point1),
+ // cfg_edge(point1, point2),
+ // origin_live_on_entry(origin1, point2),
+ // !origin_live_on_entry(origin2, point2).
+ live_to_dying_regions_o2pq.from_leapjoin(
+ &subset_o1p,
+ (
+ cfg_edge_rel.extend_with(|&((_, point1), _)| point1),
+ origin_live_on_entry_rel.extend_with(|&((origin1, _), _)| origin1),
+ origin_live_on_entry_rel.extend_anti(|&((_, _), origin2)| origin2),
+ ),
+ |&((origin1, point1), origin2), &point2| ((origin2, point1, point2), origin1),
+ );
+
+ // dying_region_requires((origin, point1, point2), loan) :-
+ // origin_contains_loan_on_entry(origin, loan, point1),
+ // !loan_killed_at(loan, point1),
+ // cfg_edge(point1, point2),
+ // !origin_live_on_entry(origin, point2).
+ dying_region_requires.from_leapjoin(
+ &origin_contains_loan_on_entry_op,
+ (
+ loan_killed_at.filter_anti(|&((_, point1), loan)| (loan, point1)),
+ cfg_edge_rel.extend_with(|&((_, point1), _)| point1),
+ origin_live_on_entry_rel.extend_anti(|&((origin, _), _)| origin),
+ ),
+ |&((origin, point1), loan), &point2| ((origin, point1, point2), loan),
+ );
+
+ // dying_can_reach_origins(origin2, point1, point2) :-
+ // live_to_dying_regions(_, origin2, point1, point2).
+ dying_can_reach_origins.from_map(
+ &live_to_dying_regions_o2pq,
+ |&((origin2, point1, point2), _origin1)| ((origin2, point1), point2),
+ );
+
+ // dying_can_reach_origins(origin, point1, point2) :-
+ // dying_region_requires(origin, point1, point2, _loan).
+ dying_can_reach_origins.from_map(
+ &dying_region_requires,
+ |&((origin, point1, point2), _loan)| ((origin, point1), point2),
+ );
+
+ // dying_can_reach(origin1, origin2, point1, point2) :-
+ // dying_can_reach_origins(origin1, point1, point2),
+ // subset(origin1, origin2, point1).
+ dying_can_reach_o2q.from_join(
+ &dying_can_reach_origins,
+ &subset_o1p,
+ |&(origin1, point1), &point2, &origin2| ((origin2, point2), (origin1, point1)),
+ );
+
+ // dying_can_reach(origin1, origin3, point1, point2) :-
+ // dying_can_reach(origin1, origin2, point1, point2),
+ // !origin_live_on_entry(origin2, point2),
+ // subset(origin2, origin3, point1).
+ //
+ // This is the "transitive closure" rule, but
+ // note that we only apply it with the
+ // "intermediate" `origin2` is dead at `point2`.
+ dying_can_reach_1.from_antijoin(
+ &dying_can_reach_o2q,
+ &origin_live_on_entry_rel,
+ |&(origin2, point2), &(origin1, point1)| ((origin2, point1), (origin1, point2)),
+ );
+ dying_can_reach_o2q.from_join(
+ &dying_can_reach_1,
+ &subset_o1p,
+ |&(_origin2, point1), &(origin1, point2), &origin3| {
+ ((origin3, point2), (origin1, point1))
+ },
+ );
+
+ // dying_can_reach_live(origin1, origin2, point1, point2) :-
+ // dying_can_reach(origin1, origin2, point1, point2),
+ // origin_live_on_entry(origin2, point2).
+ dying_can_reach_live.from_join(
+ &dying_can_reach_o2q,
+ &origin_live_on_entry_var,
+ |&(origin2, point2), &(origin1, point1), _| ((origin1, point1, point2), origin2),
+ );
+
+ // subset(origin1, origin2, point2) :-
+ // subset(origin1, origin2, point1),
+ // cfg_edge(point1, point2),
+ // origin_live_on_entry(origin1, point2),
+ // origin_live_on_entry(origin2, point2).
+ //
+ // Carry `origin1 <= origin2` from `point1` into `point2` if both `origin1` and
+ // `origin2` are live in `point2`.
+ subset_o1p.from_leapjoin(
+ &subset_o1p,
+ (
+ cfg_edge_rel.extend_with(|&((_, point1), _)| point1),
+ origin_live_on_entry_rel.extend_with(|&((origin1, _), _)| origin1),
+ origin_live_on_entry_rel.extend_with(|&((_, _), origin2)| origin2),
+ ),
+ |&((origin1, _point1), origin2), &point2| ((origin1, point2), origin2),
+ );
+
+ // subset(origin1, origin3, point2) :-
+ // live_to_dying_regions(origin1, origin2, point1, point2),
+ // dying_can_reach_live(origin2, origin3, point1, point2).
+ subset_o1p.from_join(
+ &live_to_dying_regions_o2pq,
+ &dying_can_reach_live,
+ |&(_origin2, _point1, point2), &origin1, &origin3| ((origin1, point2), origin3),
+ );
+
+ // origin_contains_loan_on_entry(origin2, loan, point2) :-
+ // dying_region_requires(origin1, loan, point1, point2),
+ // dying_can_reach_live(origin1, origin2, point1, point2).
+ //
+ // Communicate a `origin1 contains loan` relation across
+ // an edge `point1 -> point2` where `origin1` is dead in `point2`; in
+ // that case, for each origin `origin2` live in `point2`
+ // where `origin1 <= origin2` in `point1`, we add `origin2 contains loan`
+ // to `point2`.
+ origin_contains_loan_on_entry_op.from_join(
+ &dying_region_requires,
+ &dying_can_reach_live,
+ |&(_origin1, _point1, point2), &loan, &origin2| ((origin2, point2), loan),
+ );
+
+ // origin_contains_loan_on_entry(origin, loan, point2) :-
+ // origin_contains_loan_on_entry(origin, loan, point1),
+ // !loan_killed_at(loan, point1),
+ // cfg_edge(point1, point2),
+ // origin_live_on_entry(origin, point2).
+ origin_contains_loan_on_entry_op.from_leapjoin(
+ &origin_contains_loan_on_entry_op,
+ (
+ loan_killed_at.filter_anti(|&((_, point1), loan)| (loan, point1)),
+ cfg_edge_rel.extend_with(|&((_, point1), _)| point1),
+ origin_live_on_entry_rel.extend_with(|&((origin, _), _)| origin),
+ ),
+ |&((origin, _), loan), &point2| ((origin, point2), loan),
+ );
+
+ // dead_borrow_region_can_reach_root((origin, point), loan) :-
+ // loan_issued_at(origin, loan, point),
+ // !origin_live_on_entry(origin, point).
+ dead_borrow_region_can_reach_root.from_antijoin(
+ &loan_issued_at_op,
+ &origin_live_on_entry_rel,
+ |&(origin, point), &loan| ((origin, point), loan),
+ );
+
+ // dead_borrow_region_can_reach_dead((origin, point), loan) :-
+ // dead_borrow_region_can_reach_root((origin, point), loan).
+ dead_borrow_region_can_reach_dead
+ .from_map(&dead_borrow_region_can_reach_root, |&tuple| tuple);
+
+ // dead_borrow_region_can_reach_dead((origin2, point), loan) :-
+ // dead_borrow_region_can_reach_dead(origin1, loan, point),
+ // subset(origin1, origin2, point),
+ // !origin_live_on_entry(origin2, point).
+ dead_borrow_region_can_reach_dead_1.from_join(
+ &dead_borrow_region_can_reach_dead,
+ &subset_o1p,
+ |&(_origin1, point), &loan, &origin2| ((origin2, point), loan),
+ );
+ dead_borrow_region_can_reach_dead.from_antijoin(
+ &dead_borrow_region_can_reach_dead_1,
+ &origin_live_on_entry_rel,
+ |&(origin2, point), &loan| ((origin2, point), loan),
+ );
+
+ // loan_live_at(loan, point) :-
+ // origin_contains_loan_on_entry(origin, loan, point),
+ // origin_live_on_entry(origin, point).
+ loan_live_at.from_join(
+ &origin_contains_loan_on_entry_op,
+ &origin_live_on_entry_var,
+ |&(_origin, point), &loan, _| ((loan, point), ()),
+ );
+
+ // loan_live_at(loan, point) :-
+ // dead_borrow_region_can_reach_dead(origin1, loan, point),
+ // subset(origin1, origin2, point),
+ // origin_live_on_entry(origin2, point).
+ //
+ // NB: the datafrog code below uses
+ // `dead_borrow_region_can_reach_dead_1`, which is equal
+ // to `dead_borrow_region_can_reach_dead` and `subset`
+ // joined together.
+ loan_live_at.from_join(
+ &dead_borrow_region_can_reach_dead_1,
+ &origin_live_on_entry_var,
+ |&(_origin2, point), &loan, _| ((loan, point), ()),
+ );
+
+ // errors(loan, point) :-
+ // loan_invalidated_at(loan, point),
+ // loan_live_at(loan, point).
+ errors.from_join(
+ &loan_invalidated_at,
+ &loan_live_at,
+ |&(loan, point), _, _| (loan, point),
+ );
+
+ // subset_placeholder(Origin1, Origin2, Point) :-
+ // subset(Origin1, Origin2, Point),
+ // placeholder_origin(Origin1).
+ subset_placeholder.from_leapjoin(
+ &subset_o1p,
+ (
+ placeholder_origin.extend_with(|&((origin1, _point), _origin2)| origin1),
+ // remove symmetries:
+ datafrog::ValueFilter::from(|&((origin1, _point), origin2), _| {
+ origin1 != origin2
+ }),
+ ),
+ |&((origin1, point), origin2), _| (origin1, origin2, point),
+ );
+
+ // We compute the transitive closure of the placeholder origins, so we
+ // maintain the invariant from the rule above that `Origin1` is a placeholder origin.
+ //
+ // subset_placeholder(Origin1, Origin3, Point) :-
+ // subset_placeholder(Origin1, Origin2, Point),
+ // subset(Origin2, Origin3, Point).
+ subset_placeholder.from_join(
+ &subset_placeholder_o2p,
+ &subset_o1p,
+ |&(_origin2, point), &origin1, &origin3| (origin1, origin3, point),
+ );
+
+ // subset_error(Origin1, Origin2, Point) :-
+ // subset_placeholder(Origin1, Origin2, Point),
+ // placeholder_origin(Origin2),
+ // !known_placeholder_subset(Origin1, Origin2).
+ subset_errors.from_leapjoin(
+ &subset_placeholder,
+ (
+ placeholder_origin.extend_with(|&(_origin1, origin2, _point)| origin2),
+ known_placeholder_subset
+ .filter_anti(|&(origin1, origin2, _point)| (origin1, origin2)),
+ // remove symmetries:
+ datafrog::ValueFilter::from(|&(origin1, origin2, _point), _| {
+ origin1 != origin2
+ }),
+ ),
+ |&(origin1, origin2, point), _| (origin1, origin2, point),
+ );
+ }
+
+ if result.dump_enabled {
+ let subset_o1p = subset_o1p.complete();
+ assert!(
+ subset_o1p
+ .iter()
+ .filter(|&((origin1, _), origin2)| origin1 == origin2)
+ .count()
+ == 0,
+ "unwanted subset symmetries"
+ );
+ for &((origin1, location), origin2) in subset_o1p.iter() {
+ result
+ .subset
+ .entry(location)
+ .or_default()
+ .entry(origin1)
+ .or_default()
+ .insert(origin2);
+ }
+
+ let origin_contains_loan_on_entry_op = origin_contains_loan_on_entry_op.complete();
+ for &((origin, location), loan) in origin_contains_loan_on_entry_op.iter() {
+ result
+ .origin_contains_loan_at
+ .entry(location)
+ .or_default()
+ .entry(origin)
+ .or_default()
+ .insert(loan);
+ }
+
+ let loan_live_at = loan_live_at.complete();
+ for &((loan, location), _) in loan_live_at.iter() {
+ result.loan_live_at.entry(location).or_default().push(loan);
+ }
+ }
+
+ (errors.complete(), subset_errors.complete())
+ };
+
+ info!(
+ "analysis done: {} `errors` tuples, {} `subset_errors` tuples, {:?}",
+ errors.len(),
+ subset_errors.len(),
+ timer.elapsed()
+ );
+
+ (errors, subset_errors)
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs
new file mode 100644
index 0000000..30409d9
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/initialization.rs
@@ -0,0 +1,284 @@
+use std::time::Instant;
+
+use crate::facts::FactTypes;
+use crate::output::{InitializationContext, Output};
+
+use datafrog::{Iteration, Relation, RelationLeaper};
+
+// This represents the output of an intermediate elaboration step (step 1).
+struct TransitivePaths<T: FactTypes> {
+ path_moved_at: Relation<(T::Path, T::Point)>,
+ path_assigned_at: Relation<(T::Path, T::Point)>,
+ path_accessed_at: Relation<(T::Path, T::Point)>,
+ path_begins_with_var: Relation<(T::Path, T::Variable)>,
+}
+
+struct InitializationStatus<T: FactTypes> {
+ var_maybe_partly_initialized_on_exit: Relation<(T::Variable, T::Point)>,
+ move_error: Relation<(T::Path, T::Point)>,
+}
+
+pub(super) struct InitializationResult<T: FactTypes>(
+ pub(super) Relation<(T::Variable, T::Point)>,
+ pub(super) Relation<(T::Path, T::Point)>,
+);
+
+// Step 1: compute transitive closures of path operations. This would elaborate,
+// for example, an access to x into an access to x.f, x.f.0, etc. We do this for:
+// - access to a path
+// - initialization of a path
+// - moves of a path
+// FIXME: transitive rooting in a variable (path_begins_with_var)
+// Note that this step may not be entirely necessary!
+fn compute_transitive_paths<T: FactTypes>(
+ child_path: Vec<(T::Path, T::Path)>,
+ path_assigned_at_base: Vec<(T::Path, T::Point)>,
+ path_moved_at_base: Vec<(T::Path, T::Point)>,
+ path_accessed_at_base: Vec<(T::Path, T::Point)>,
+ path_is_var: Vec<(T::Path, T::Variable)>,
+) -> TransitivePaths<T> {
+ let mut iteration = Iteration::new();
+ let child_path: Relation<(T::Path, T::Path)> = child_path.into();
+
+ let ancestor_path = iteration.variable::<(T::Path, T::Path)>("ancestor");
+
+ // These are the actual targets:
+ let path_moved_at = iteration.variable::<(T::Path, T::Point)>("path_moved_at");
+ let path_assigned_at = iteration.variable::<(T::Path, T::Point)>("path_initialized_at");
+ let path_accessed_at = iteration.variable::<(T::Path, T::Point)>("path_accessed_at");
+ let path_begins_with_var = iteration.variable::<(T::Path, T::Variable)>("path_begins_with_var");
+
+ // ancestor_path(Parent, Child) :- child_path(Child, Parent).
+ ancestor_path.extend(child_path.iter().map(|&(child, parent)| (parent, child)));
+
+ // path_moved_at(Path, Point) :- path_moved_at_base(Path, Point).
+ path_moved_at.insert(path_moved_at_base.into());
+
+ // path_assigned_at(Path, Point) :- path_assigned_at_base(Path, Point).
+ path_assigned_at.insert(path_assigned_at_base.into());
+
+ // path_accessed_at(Path, Point) :- path_accessed_at_base(Path, Point).
+ path_accessed_at.insert(path_accessed_at_base.into());
+
+ // path_begins_with_var(Path, Var) :- path_is_var(Path, Var).
+ path_begins_with_var.insert(path_is_var.into());
+
+ while iteration.changed() {
+ // ancestor_path(Grandparent, Child) :-
+ // ancestor_path(Parent, Child),
+ // child_path(Parent, Grandparent).
+ ancestor_path.from_join(
+ &ancestor_path,
+ &child_path,
+ |&_parent, &child, &grandparent| (grandparent, child),
+ );
+
+ // moving a path moves its children
+ // path_moved_at(Child, Point) :-
+ // path_moved_at(Parent, Point),
+ // ancestor_path(Parent, Child).
+ path_moved_at.from_join(&path_moved_at, &ancestor_path, |&_parent, &p, &child| {
+ (child, p)
+ });
+
+ // initialising x at p initialises all x:s children
+ // path_assigned_at(Child, point) :-
+ // path_assigned_at(Parent, point),
+ // ancestor_path(Parent, Child).
+ path_assigned_at.from_join(&path_assigned_at, &ancestor_path, |&_parent, &p, &child| {
+ (child, p)
+ });
+
+ // accessing x at p accesses all x:s children at p (actually,
+ // accesses should be maximally precise and this shouldn't happen?)
+ // path_accessed_at(Child, point) :-
+ // path_accessed_at(Parent, point),
+ // ancestor_path(Parent, Child).
+ path_accessed_at.from_join(&path_accessed_at, &ancestor_path, |&_parent, &p, &child| {
+ (child, p)
+ });
+
+ // path_begins_with_var(Child, Var) :-
+ // path_begins_with_var(Parent, Var)
+ // ancestor_path(Parent, Child).
+ path_begins_with_var.from_join(
+ &path_begins_with_var,
+ &ancestor_path,
+ |&_parent, &var, &child| (child, var),
+ );
+ }
+
+ TransitivePaths {
+ path_assigned_at: path_assigned_at.complete(),
+ path_moved_at: path_moved_at.complete(),
+ path_accessed_at: path_accessed_at.complete(),
+ path_begins_with_var: path_begins_with_var.complete(),
+ }
+}
+
+// Step 2: Compute path initialization and deinitialization across the CFG.
+fn compute_move_errors<T: FactTypes>(
+ ctx: TransitivePaths<T>,
+ cfg_edge: &Relation<(T::Point, T::Point)>,
+ output: &mut Output<T>,
+) -> InitializationStatus<T> {
+ let mut iteration = Iteration::new();
+ // Variables
+
+ // var_maybe_partly_initialized_on_exit(var, point): Upon leaving `point`,
+ // `var` is partially initialized for some path through the CFG, that is
+ // there has been an initialization of var, and var has not been moved in
+ // all paths through the CFG.
+ let var_maybe_partly_initialized_on_exit =
+ iteration.variable::<(T::Variable, T::Point)>("var_maybe_partly_initialized_on_exit");
+
+ // path_maybe_initialized_on_exit(path, point): Upon leaving `point`, the
+ // move path `path` is initialized for some path through the CFG.
+ let path_maybe_initialized_on_exit =
+ iteration.variable::<(T::Path, T::Point)>("path_maybe_initialized_on_exit");
+
+ // path_maybe_uninitialized_on_exit(Path, Point): There exists at least one
+ // path through the CFG to Point such that `Path` has been moved out by the
+ // time we arrive at `Point` without it being re-initialized for sure.
+ let path_maybe_uninitialized_on_exit =
+ iteration.variable::<(T::Path, T::Point)>("path_maybe_uninitialized_on_exit");
+
+ // move_error(Path, Point): There is an access to `Path` at `Point`, but
+ // `Path` is potentially moved (or never initialised).
+ let move_error = iteration.variable::<(T::Path, T::Point)>("move_error");
+
+ // Initial propagation of static relations
+
+ // path_maybe_initialized_on_exit(path, point) :- path_assigned_at(path, point).
+ path_maybe_initialized_on_exit.insert(ctx.path_assigned_at.clone());
+
+ // path_maybe_uninitialized_on_exit(path, point) :- path_moved_at(path, point).
+ path_maybe_uninitialized_on_exit.insert(ctx.path_moved_at.clone());
+
+ while iteration.changed() {
+ // path_maybe_initialized_on_exit(path, point2) :-
+ // path_maybe_initialized_on_exit(path, point1),
+ // cfg_edge(point1, point2),
+ // !path_moved_at(path, point2).
+ path_maybe_initialized_on_exit.from_leapjoin(
+ &path_maybe_initialized_on_exit,
+ (
+ cfg_edge.extend_with(|&(_path, point1)| point1),
+ ctx.path_moved_at.extend_anti(|&(path, _point1)| path),
+ ),
+ |&(path, _point1), &point2| (path, point2),
+ );
+
+ // path_maybe_uninitialized_on_exit(path, point2) :-
+ // path_maybe_uninitialized_on_exit(path, point1),
+ // cfg_edge(point1, point2)
+ // !path_assigned_at(path, point2).
+ path_maybe_uninitialized_on_exit.from_leapjoin(
+ &path_maybe_uninitialized_on_exit,
+ (
+ cfg_edge.extend_with(|&(_path, point1)| point1),
+ ctx.path_assigned_at.extend_anti(|&(path, _point1)| path),
+ ),
+ |&(path, _point1), &point2| (path, point2),
+ );
+
+ // var_maybe_partly_initialized_on_exit(var, point) :-
+ // path_maybe_initialized_on_exit(path, point).
+ // path_begins_with_var(path, var).
+ var_maybe_partly_initialized_on_exit.from_leapjoin(
+ &path_maybe_initialized_on_exit,
+ ctx.path_begins_with_var.extend_with(|&(path, _point)| path),
+ |&(_path, point), &var| (var, point),
+ );
+
+ // move_error(Path, TargetNode) :-
+ // path_maybe_uninitialized_on_exit(Path, SourceNode),
+ // cfg_edge(SourceNode, TargetNode),
+ // path_accessed_at(Path, TargetNode).
+ move_error.from_leapjoin(
+ &path_maybe_uninitialized_on_exit,
+ (
+ cfg_edge.extend_with(|&(_path, source_node)| source_node),
+ ctx.path_accessed_at
+ .extend_with(|&(path, _source_node)| path),
+ ),
+ |&(path, _source_node), &target_node| (path, target_node),
+ );
+ }
+
+ if output.dump_enabled {
+ for &(path, location) in path_maybe_initialized_on_exit.complete().iter() {
+ output
+ .path_maybe_initialized_on_exit
+ .entry(location)
+ .or_default()
+ .push(path);
+ }
+
+ for &(path, location) in path_maybe_uninitialized_on_exit.complete().iter() {
+ output
+ .path_maybe_uninitialized_on_exit
+ .entry(location)
+ .or_default()
+ .push(path);
+ }
+ }
+
+ InitializationStatus {
+ var_maybe_partly_initialized_on_exit: var_maybe_partly_initialized_on_exit.complete(),
+ move_error: move_error.complete(),
+ }
+}
+
+// Compute two things:
+//
+// - an over-approximation of the initialization of variables. This is used in
+// the origin_live_on_entry computations to determine when a drop may happen; a
+// definitely moved variable would not be actually dropped.
+// - move errors.
+//
+// The process is split into two stages:
+//
+// 1. Compute the transitive closure of path accesses. That is, accessing `f.a`
+// would access `f.a.b`, etc.
+// 2. Use this to compute both paths that may be initialized and paths that may
+// have been deinitialized, which in turn can be used to find move errors (an
+// access to a path that may be deinitialized).
+pub(super) fn compute<T: FactTypes>(
+ ctx: InitializationContext<T>,
+ cfg_edge: &Relation<(T::Point, T::Point)>,
+ output: &mut Output<T>,
+) -> InitializationResult<T> {
+ let timer = Instant::now();
+
+ let transitive_paths = compute_transitive_paths::<T>(
+ ctx.child_path,
+ ctx.path_assigned_at_base,
+ ctx.path_moved_at_base,
+ ctx.path_accessed_at_base,
+ ctx.path_is_var,
+ );
+ info!("initialization phase 1 completed: {:?}", timer.elapsed());
+
+ let InitializationStatus {
+ var_maybe_partly_initialized_on_exit,
+ move_error,
+ } = compute_move_errors::<T>(transitive_paths, cfg_edge, output);
+ info!(
+ "initialization phase 2: {} move errors in {:?}",
+ move_error.elements.len(),
+ timer.elapsed()
+ );
+
+ if output.dump_enabled {
+ for &(var, location) in var_maybe_partly_initialized_on_exit.iter() {
+ output
+ .var_maybe_partly_initialized_on_exit
+ .entry(location)
+ .or_default()
+ .push(var);
+ }
+ }
+
+ InitializationResult(var_maybe_partly_initialized_on_exit, move_error)
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs
new file mode 100644
index 0000000..1b4b4ce
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/liveness.rs
@@ -0,0 +1,170 @@
+// Copyright 2019 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.
+
+//! An implementation of the origin liveness calculation logic
+
+use std::collections::BTreeSet;
+use std::time::Instant;
+
+use crate::facts::FactTypes;
+use crate::output::{LivenessContext, Output};
+
+use datafrog::{Iteration, Relation, RelationLeaper};
+
+pub(super) fn compute_live_origins<T: FactTypes>(
+ ctx: LivenessContext<T>,
+ cfg_edge: &Relation<(T::Point, T::Point)>,
+ var_maybe_partly_initialized_on_exit: Relation<(T::Variable, T::Point)>,
+ output: &mut Output<T>,
+) -> Vec<(T::Origin, T::Point)> {
+ let timer = Instant::now();
+ let mut iteration = Iteration::new();
+
+ // Relations
+ let var_defined_at: Relation<(T::Variable, T::Point)> = ctx.var_defined_at.into();
+ let cfg_edge_reverse: Relation<(T::Point, T::Point)> = cfg_edge
+ .iter()
+ .map(|&(point1, point2)| (point2, point1))
+ .collect();
+ let use_of_var_derefs_origin: Relation<(T::Variable, T::Origin)> =
+ ctx.use_of_var_derefs_origin.into();
+ let drop_of_var_derefs_origin: Relation<(T::Variable, T::Origin)> =
+ ctx.drop_of_var_derefs_origin.into();
+ let var_dropped_at: Relation<((T::Variable, T::Point), ())> = ctx
+ .var_dropped_at
+ .into_iter()
+ .map(|(var, point)| ((var, point), ()))
+ .collect();
+
+ // Variables
+
+ // `var_live_on_entry`: variable `var` is live upon entry at `point`
+ let var_live_on_entry = iteration.variable::<(T::Variable, T::Point)>("var_live_on_entry");
+ // `var_drop_live_on_entry`: variable `var` is drop-live (will be used for a drop) upon entry in `point`
+ let var_drop_live_on_entry =
+ iteration.variable::<(T::Variable, T::Point)>("var_drop_live_on_entry");
+
+ // This is what we are actually calculating:
+ let origin_live_on_entry = iteration.variable::<(T::Origin, T::Point)>("origin_live_on_entry");
+
+ // This propagates the relation `var_live_on_entry(var, point) :- var_used_at(var, point)`:
+ var_live_on_entry.insert(ctx.var_used_at.into());
+
+ // var_maybe_partly_initialized_on_entry(var, point2) :-
+ // var_maybe_partly_initialized_on_exit(var, point1),
+ // cfg_edge(point1, point2).
+ let var_maybe_partly_initialized_on_entry = Relation::from_leapjoin(
+ &var_maybe_partly_initialized_on_exit,
+ cfg_edge.extend_with(|&(_var, point1)| point1),
+ |&(var, _point1), &point2| ((var, point2), ()),
+ );
+
+ // var_drop_live_on_entry(var, point) :-
+ // var_dropped_at(var, point),
+ // var_maybe_partly_initialized_on_entry(var, point).
+ var_drop_live_on_entry.insert(Relation::from_join(
+ &var_dropped_at,
+ &var_maybe_partly_initialized_on_entry,
+ |&(var, point), _, _| (var, point),
+ ));
+
+ while iteration.changed() {
+ // origin_live_on_entry(origin, point) :-
+ // var_drop_live_on_entry(var, point),
+ // drop_of_var_derefs_origin(var, origin).
+ origin_live_on_entry.from_join(
+ &var_drop_live_on_entry,
+ &drop_of_var_derefs_origin,
+ |_var, &point, &origin| (origin, point),
+ );
+
+ // origin_live_on_entry(origin, point) :-
+ // var_live_on_entry(var, point),
+ // use_of_var_derefs_origin(var, origin).
+ origin_live_on_entry.from_join(
+ &var_live_on_entry,
+ &use_of_var_derefs_origin,
+ |_var, &point, &origin| (origin, point),
+ );
+
+ // var_live_on_entry(var, point1) :-
+ // var_live_on_entry(var, point2),
+ // cfg_edge(point1, point2),
+ // !var_defined(var, point1).
+ var_live_on_entry.from_leapjoin(
+ &var_live_on_entry,
+ (
+ var_defined_at.extend_anti(|&(var, _point2)| var),
+ cfg_edge_reverse.extend_with(|&(_var, point2)| point2),
+ ),
+ |&(var, _point2), &point1| (var, point1),
+ );
+
+ // var_drop_live_on_entry(Var, SourceNode) :-
+ // var_drop_live_on_entry(Var, TargetNode),
+ // cfg_edge(SourceNode, TargetNode),
+ // !var_defined_at(Var, SourceNode),
+ // var_maybe_partly_initialized_on_exit(Var, SourceNode).
+ var_drop_live_on_entry.from_leapjoin(
+ &var_drop_live_on_entry,
+ (
+ var_defined_at.extend_anti(|&(var, _target_node)| var),
+ cfg_edge_reverse.extend_with(|&(_var, target_node)| target_node),
+ var_maybe_partly_initialized_on_exit.extend_with(|&(var, _target_node)| var),
+ ),
+ |&(var, _targetnode), &source_node| (var, source_node),
+ );
+ }
+
+ let origin_live_on_entry = origin_live_on_entry.complete();
+
+ info!(
+ "compute_live_origins() completed: {} tuples, {:?}",
+ origin_live_on_entry.len(),
+ timer.elapsed(),
+ );
+
+ if output.dump_enabled {
+ let var_drop_live_on_entry = var_drop_live_on_entry.complete();
+ for &(var, location) in var_drop_live_on_entry.iter() {
+ output
+ .var_drop_live_on_entry
+ .entry(location)
+ .or_default()
+ .push(var);
+ }
+
+ let var_live_on_entry = var_live_on_entry.complete();
+ for &(var, location) in var_live_on_entry.iter() {
+ output
+ .var_live_on_entry
+ .entry(location)
+ .or_default()
+ .push(var);
+ }
+ }
+
+ origin_live_on_entry.elements
+}
+
+pub(super) fn make_universal_regions_live<T: FactTypes>(
+ origin_live_on_entry: &mut Vec<(T::Origin, T::Point)>,
+ cfg_node: &BTreeSet<T::Point>,
+ universal_regions: &[T::Origin],
+) {
+ debug!("make_universal_regions_live()");
+
+ origin_live_on_entry.reserve(universal_regions.len() * cfg_node.len());
+ for &origin in universal_regions.iter() {
+ for &point in cfg_node.iter() {
+ origin_live_on_entry.push((origin, point));
+ }
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs
new file mode 100644
index 0000000..83ce277
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/location_insensitive.rs
@@ -0,0 +1,156 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+use datafrog::{Iteration, Relation, RelationLeaper};
+use std::time::Instant;
+
+use crate::facts::FactTypes;
+use crate::output::{Context, Output};
+
+pub(super) fn compute<T: FactTypes>(
+ ctx: &Context<'_, T>,
+ result: &mut Output<T>,
+) -> (
+ Relation<(T::Loan, T::Point)>,
+ Relation<(T::Origin, T::Origin)>,
+) {
+ let timer = Instant::now();
+
+ let (potential_errors, potential_subset_errors) = {
+ // Static inputs
+ let origin_live_on_entry = &ctx.origin_live_on_entry;
+ let loan_invalidated_at = &ctx.loan_invalidated_at;
+ let placeholder_origin = &ctx.placeholder_origin;
+ let placeholder_loan = &ctx.placeholder_loan;
+ let known_contains = &ctx.known_contains;
+
+ // subset(Origin1, Origin2) :-
+ // subset_base(Origin1, Origin2, _).
+ let subset = Relation::from_iter(
+ ctx.subset_base
+ .iter()
+ .map(|&(origin1, origin2, _point)| (origin1, origin2)),
+ );
+
+ // Create a new iteration context, ...
+ let mut iteration = Iteration::new();
+
+ // .. some variables, ..
+ let origin_contains_loan_on_entry =
+ iteration.variable::<(T::Origin, T::Loan)>("origin_contains_loan_on_entry");
+
+ let potential_errors = iteration.variable::<(T::Loan, T::Point)>("potential_errors");
+ let potential_subset_errors =
+ iteration.variable::<(T::Origin, T::Origin)>("potential_subset_errors");
+
+ // load initial facts.
+
+ // origin_contains_loan_on_entry(Origin, Loan) :-
+ // loan_issued_at(Origin, Loan, _).
+ origin_contains_loan_on_entry.extend(
+ ctx.loan_issued_at
+ .iter()
+ .map(|&(origin, loan, _point)| (origin, loan)),
+ );
+
+ // origin_contains_loan_on_entry(Origin, Loan) :-
+ // placeholder_loan(Origin, Loan).
+ origin_contains_loan_on_entry.extend(
+ placeholder_loan
+ .iter()
+ .map(|&(loan, origin)| (origin, loan)),
+ );
+
+ // .. and then start iterating rules!
+ while iteration.changed() {
+ // origin_contains_loan_on_entry(Origin2, Loan) :-
+ // origin_contains_loan_on_entry(Origin1, Loan),
+ // subset(Origin1, Origin2).
+ //
+ // Note: Since `subset` is effectively a static input, this join can be ported to
+ // a leapjoin. Doing so, however, was 7% slower on `clap`.
+ origin_contains_loan_on_entry.from_join(
+ &origin_contains_loan_on_entry,
+ &subset,
+ |&_origin1, &loan, &origin2| (origin2, loan),
+ );
+
+ // loan_live_at(Loan, Point) :-
+ // origin_contains_loan_on_entry(Origin, Loan),
+ // origin_live_on_entry(Origin, Point)
+ //
+ // potential_errors(Loan, Point) :-
+ // loan_invalidated_at(Loan, Point),
+ // loan_live_at(Loan, Point).
+ //
+ // Note: we don't need to materialize `loan_live_at` here
+ // so we can inline it in the `potential_errors` relation.
+ //
+ potential_errors.from_leapjoin(
+ &origin_contains_loan_on_entry,
+ (
+ origin_live_on_entry.extend_with(|&(origin, _loan)| origin),
+ loan_invalidated_at.extend_with(|&(_origin, loan)| loan),
+ ),
+ |&(_origin, loan), &point| (loan, point),
+ );
+
+ // potential_subset_errors(Origin1, Origin2) :-
+ // placeholder(Origin1, Loan1),
+ // placeholder(Origin2, _),
+ // origin_contains_loan_on_entry(Origin2, Loan1),
+ // !known_contains(Origin2, Loan1).
+ potential_subset_errors.from_leapjoin(
+ &origin_contains_loan_on_entry,
+ (
+ known_contains.filter_anti(|&(origin2, loan1)| (origin2, loan1)),
+ placeholder_origin.filter_with(|&(origin2, _loan1)| (origin2, ())),
+ placeholder_loan.extend_with(|&(_origin2, loan1)| loan1),
+ // remove symmetries:
+ datafrog::ValueFilter::from(|&(origin2, _loan1), &origin1| origin2 != origin1),
+ ),
+ |&(origin2, _loan1), &origin1| (origin1, origin2),
+ );
+ }
+
+ if result.dump_enabled {
+ for &(origin1, origin2) in subset.iter() {
+ result
+ .subset_anywhere
+ .entry(origin1)
+ .or_default()
+ .insert(origin2);
+ }
+
+ let origin_contains_loan_on_entry = origin_contains_loan_on_entry.complete();
+ for &(origin, loan) in origin_contains_loan_on_entry.iter() {
+ result
+ .origin_contains_loan_anywhere
+ .entry(origin)
+ .or_default()
+ .insert(loan);
+ }
+ }
+
+ (
+ potential_errors.complete(),
+ potential_subset_errors.complete(),
+ )
+ };
+
+ info!(
+ "analysis done: {} `potential_errors` tuples, {} `potential_subset_errors` tuples, {:?}",
+ potential_errors.len(),
+ potential_subset_errors.len(),
+ timer.elapsed()
+ );
+
+ (potential_errors, potential_subset_errors)
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs
new file mode 100644
index 0000000..b840e4b
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/mod.rs
@@ -0,0 +1,614 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+use datafrog::Relation;
+use rustc_hash::{FxHashMap, FxHashSet};
+use std::borrow::Cow;
+use std::collections::{BTreeMap, BTreeSet};
+
+use crate::facts::{AllFacts, Atom, FactTypes};
+
+mod datafrog_opt;
+mod initialization;
+mod liveness;
+mod location_insensitive;
+mod naive;
+
+#[derive(Debug, Clone, Copy)]
+pub enum Algorithm {
+ /// Simple rules, but slower to execute
+ Naive,
+
+ /// Optimized variant of the rules
+ DatafrogOpt,
+
+ /// Fast to compute, but imprecise: there can be false-positives
+ /// but no false-negatives. Tailored for quick "early return" situations.
+ LocationInsensitive,
+
+ /// Compares the `Naive` and `DatafrogOpt` variants to ensure they indeed
+ /// compute the same errors.
+ Compare,
+
+ /// Combination of the fast `LocationInsensitive` pre-pass, followed by
+ /// the more expensive `DatafrogOpt` variant.
+ Hybrid,
+}
+
+impl Algorithm {
+ /// Optimized variants that ought to be equivalent to "naive"
+ pub const OPTIMIZED: &'static [Algorithm] = &[Algorithm::DatafrogOpt];
+
+ pub fn variants() -> [&'static str; 5] {
+ [
+ "Naive",
+ "DatafrogOpt",
+ "LocationInsensitive",
+ "Compare",
+ "Hybrid",
+ ]
+ }
+}
+
+impl ::std::str::FromStr for Algorithm {
+ type Err = String;
+ fn from_str(s: &str) -> Result<Self, Self::Err> {
+ match s.to_lowercase().as_ref() {
+ "naive" => Ok(Algorithm::Naive),
+ "datafrogopt" => Ok(Algorithm::DatafrogOpt),
+ "locationinsensitive" => Ok(Algorithm::LocationInsensitive),
+ "compare" => Ok(Algorithm::Compare),
+ "hybrid" => Ok(Algorithm::Hybrid),
+ _ => Err(String::from(
+ "valid values: Naive, DatafrogOpt, LocationInsensitive, Compare, Hybrid",
+ )),
+ }
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Output<T: FactTypes> {
+ pub errors: FxHashMap<T::Point, Vec<T::Loan>>,
+ pub subset_errors: FxHashMap<T::Point, BTreeSet<(T::Origin, T::Origin)>>,
+ pub move_errors: FxHashMap<T::Point, Vec<T::Path>>,
+
+ pub dump_enabled: bool,
+
+ // these are just for debugging
+ pub loan_live_at: FxHashMap<T::Point, Vec<T::Loan>>,
+ pub origin_contains_loan_at: FxHashMap<T::Point, BTreeMap<T::Origin, BTreeSet<T::Loan>>>,
+ pub origin_contains_loan_anywhere: FxHashMap<T::Origin, BTreeSet<T::Loan>>,
+ pub origin_live_on_entry: FxHashMap<T::Point, Vec<T::Origin>>,
+ pub loan_invalidated_at: FxHashMap<T::Point, Vec<T::Loan>>,
+ pub subset: FxHashMap<T::Point, BTreeMap<T::Origin, BTreeSet<T::Origin>>>,
+ pub subset_anywhere: FxHashMap<T::Origin, BTreeSet<T::Origin>>,
+ pub var_live_on_entry: FxHashMap<T::Point, Vec<T::Variable>>,
+ pub var_drop_live_on_entry: FxHashMap<T::Point, Vec<T::Variable>>,
+ pub path_maybe_initialized_on_exit: FxHashMap<T::Point, Vec<T::Path>>,
+ pub path_maybe_uninitialized_on_exit: FxHashMap<T::Point, Vec<T::Path>>,
+ pub known_contains: FxHashMap<T::Origin, BTreeSet<T::Loan>>,
+ pub var_maybe_partly_initialized_on_exit: FxHashMap<T::Point, Vec<T::Variable>>,
+}
+
+/// Subset of `AllFacts` dedicated to initialization
+struct InitializationContext<T: FactTypes> {
+ child_path: Vec<(T::Path, T::Path)>,
+ path_is_var: Vec<(T::Path, T::Variable)>,
+ path_assigned_at_base: Vec<(T::Path, T::Point)>,
+ path_moved_at_base: Vec<(T::Path, T::Point)>,
+ path_accessed_at_base: Vec<(T::Path, T::Point)>,
+}
+
+/// Subset of `AllFacts` dedicated to liveness
+struct LivenessContext<T: FactTypes> {
+ var_used_at: Vec<(T::Variable, T::Point)>,
+ var_defined_at: Vec<(T::Variable, T::Point)>,
+ var_dropped_at: Vec<(T::Variable, T::Point)>,
+ use_of_var_derefs_origin: Vec<(T::Variable, T::Origin)>,
+ drop_of_var_derefs_origin: Vec<(T::Variable, T::Origin)>,
+}
+
+/// Subset of `AllFacts` dedicated to borrow checking, and data ready to use by the variants
+struct Context<'ctx, T: FactTypes> {
+ // `Relation`s used as static inputs, by all variants
+ origin_live_on_entry: Relation<(T::Origin, T::Point)>,
+ loan_invalidated_at: Relation<(T::Loan, T::Point)>,
+
+ // static inputs used via `Variable`s, by all variants
+ subset_base: &'ctx Vec<(T::Origin, T::Origin, T::Point)>,
+ loan_issued_at: &'ctx Vec<(T::Origin, T::Loan, T::Point)>,
+
+ // static inputs used by variants other than `LocationInsensitive`
+ loan_killed_at: Relation<(T::Loan, T::Point)>,
+ known_contains: Relation<(T::Origin, T::Loan)>,
+ placeholder_origin: Relation<(T::Origin, ())>,
+ placeholder_loan: Relation<(T::Loan, T::Origin)>,
+
+ // The `known_placeholder_subset` relation in the facts does not necessarily contain all the
+ // transitive subsets. The transitive closure is always needed, so this version here is fully
+ // closed over.
+ known_placeholder_subset: Relation<(T::Origin, T::Origin)>,
+
+ // while this static input is unused by `LocationInsensitive`, it's depended on by
+ // initialization and liveness, so already computed by the time we get to borrowcking.
+ cfg_edge: Relation<(T::Point, T::Point)>,
+
+ // Partial results possibly used by other variants as input. Not currently used yet.
+ #[allow(dead_code)]
+ potential_errors: Option<FxHashSet<T::Loan>>,
+ #[allow(dead_code)]
+ potential_subset_errors: Option<Relation<(T::Origin, T::Origin)>>,
+}
+
+impl<T: FactTypes> Output<T> {
+ /// All variants require the same initial preparations, done in multiple
+ /// successive steps:
+ /// - compute initialization data
+ /// - compute liveness
+ /// - prepare static inputs as shared `Relation`s
+ /// - in cases where `LocationInsensitive` variant is ran as a filtering pre-pass,
+ /// partial results can also be stored in the context, so that the following
+ /// variant can use it to prune its own input data
+ pub fn compute(all_facts: &AllFacts<T>, algorithm: Algorithm, dump_enabled: bool) -> Self {
+ let mut result = Output::new(dump_enabled);
+
+ // TODO: remove all the cloning thereafter, but that needs to be done in concert with rustc
+
+ let cfg_edge = all_facts.cfg_edge.clone().into();
+
+ // 1) Initialization
+ let initialization_ctx = InitializationContext {
+ child_path: all_facts.child_path.clone(),
+ path_is_var: all_facts.path_is_var.clone(),
+ path_assigned_at_base: all_facts.path_assigned_at_base.clone(),
+ path_moved_at_base: all_facts.path_moved_at_base.clone(),
+ path_accessed_at_base: all_facts.path_accessed_at_base.clone(),
+ };
+
+ let initialization::InitializationResult::<T>(
+ var_maybe_partly_initialized_on_exit,
+ move_errors,
+ ) = initialization::compute(initialization_ctx, &cfg_edge, &mut result);
+
+ // FIXME: move errors should prevent the computation from continuing: we can't compute
+ // liveness and analyze loans accurately when there are move errors, and should early
+ // return here.
+ for &(path, location) in move_errors.iter() {
+ result.move_errors.entry(location).or_default().push(path);
+ }
+
+ // 2) Liveness
+ let liveness_ctx = LivenessContext {
+ var_used_at: all_facts.var_used_at.clone(),
+ var_defined_at: all_facts.var_defined_at.clone(),
+ var_dropped_at: all_facts.var_dropped_at.clone(),
+ use_of_var_derefs_origin: all_facts.use_of_var_derefs_origin.clone(),
+ drop_of_var_derefs_origin: all_facts.drop_of_var_derefs_origin.clone(),
+ };
+
+ let mut origin_live_on_entry = liveness::compute_live_origins(
+ liveness_ctx,
+ &cfg_edge,
+ var_maybe_partly_initialized_on_exit,
+ &mut result,
+ );
+
+ let cfg_node = cfg_edge
+ .iter()
+ .map(|&(point1, _)| point1)
+ .chain(cfg_edge.iter().map(|&(_, point2)| point2))
+ .collect();
+
+ liveness::make_universal_regions_live::<T>(
+ &mut origin_live_on_entry,
+ &cfg_node,
+ &all_facts.universal_region,
+ );
+
+ // 3) Borrow checking
+
+ // Prepare data as datafrog relations, ready to join.
+ //
+ // Note: if rustc and polonius had more interaction, we could also delay or avoid
+ // generating some of the facts that are now always present here. For example,
+ // the `LocationInsensitive` variant doesn't use the `loan_killed_at` relation, so we could
+ // technically delay computing and passing it from rustc, when using this or the `Hybrid`
+ // variants, to after the pre-pass has made sure we actually need to compute the full
+ // analysis. If these facts happened to be recorded in separate MIR walks, we might also
+ // avoid generating those facts.
+
+ let origin_live_on_entry = origin_live_on_entry.into();
+
+ // TODO: also flip the order of this relation's arguments in rustc
+ // from `loan_invalidated_at(point, loan)` to `loan_invalidated_at(loan, point)`.
+ // to avoid this allocation.
+ let loan_invalidated_at = Relation::from_iter(
+ all_facts
+ .loan_invalidated_at
+ .iter()
+ .map(|&(point, loan)| (loan, point)),
+ );
+
+ let loan_killed_at = all_facts.loan_killed_at.clone().into();
+
+ // `known_placeholder_subset` is a list of all the `'a: 'b` subset relations the user gave:
+ // it's not required to be transitive. `known_contains` is its transitive closure: a list
+ // of all the known placeholder loans that each of these placeholder origins contains.
+ // Given the `known_placeholder_subset`s `'a: 'b` and `'b: 'c`: in the `known_contains`
+ // relation, `'a` will also contain `'c`'s placeholder loan.
+ let known_placeholder_subset = all_facts.known_placeholder_subset.clone().into();
+ let known_contains =
+ Output::<T>::compute_known_contains(&known_placeholder_subset, &all_facts.placeholder);
+
+ // Fully close over the `known_placeholder_subset` relation.
+ let known_placeholder_subset =
+ Output::<T>::compute_known_placeholder_subset(&known_placeholder_subset);
+
+ let placeholder_origin: Relation<_> = Relation::from_iter(
+ all_facts
+ .universal_region
+ .iter()
+ .map(|&origin| (origin, ())),
+ );
+
+ let placeholder_loan = Relation::from_iter(
+ all_facts
+ .placeholder
+ .iter()
+ .map(|&(origin, loan)| (loan, origin)),
+ );
+
+ // Ask the variants to compute errors in their own way
+ let mut ctx = Context {
+ origin_live_on_entry,
+ loan_invalidated_at,
+ cfg_edge,
+ subset_base: &all_facts.subset_base,
+ loan_issued_at: &all_facts.loan_issued_at,
+ loan_killed_at,
+ known_contains,
+ known_placeholder_subset,
+ placeholder_origin,
+ placeholder_loan,
+ potential_errors: None,
+ potential_subset_errors: None,
+ };
+
+ let (errors, subset_errors) = match algorithm {
+ Algorithm::LocationInsensitive => {
+ let (potential_errors, potential_subset_errors) =
+ location_insensitive::compute(&ctx, &mut result);
+
+ // Note: the error location is meaningless for a location-insensitive
+ // subset error analysis. This is acceptable here as this variant is not one
+ // which should be used directly besides debugging, the `Hybrid` variant will
+ // take advantage of its result.
+ let potential_subset_errors: Relation<(T::Origin, T::Origin, T::Point)> =
+ Relation::from_iter(
+ potential_subset_errors
+ .into_iter()
+ .map(|&(origin1, origin2)| (origin1, origin2, 0.into())),
+ );
+
+ (potential_errors, potential_subset_errors)
+ }
+ Algorithm::Naive => naive::compute(&ctx, &mut result),
+ Algorithm::DatafrogOpt => datafrog_opt::compute(&ctx, &mut result),
+ Algorithm::Hybrid => {
+ // Execute the fast `LocationInsensitive` computation as a pre-pass:
+ // if it finds no possible errors, we don't need to do the more complex
+ // computations as they won't find errors either, and we can return early.
+ let (potential_errors, potential_subset_errors) =
+ location_insensitive::compute(&ctx, &mut result);
+
+ if potential_errors.is_empty() && potential_subset_errors.is_empty() {
+ // There are no loan errors, nor subset errors, we can early return
+ // empty errors lists and avoid doing the heavy analysis.
+ (potential_errors, Vec::new().into())
+ } else {
+ // Record these potential errors as they can be used to limit the next
+ // variant's work to only these loans.
+ ctx.potential_errors =
+ Some(potential_errors.iter().map(|&(loan, _)| loan).collect());
+ ctx.potential_subset_errors = Some(potential_subset_errors);
+
+ datafrog_opt::compute(&ctx, &mut result)
+ }
+ }
+ Algorithm::Compare => {
+ // Ensure the `Naive` and `DatafrogOpt` errors are the same
+ let (naive_errors, naive_subset_errors) = naive::compute(&ctx, &mut result);
+ let (opt_errors, _) = datafrog_opt::compute(&ctx, &mut result);
+
+ // TODO: compare illegal subset relations errors as well here ?
+
+ let mut naive_errors_by_point = FxHashMap::default();
+ for &(loan, point) in naive_errors.iter() {
+ naive_errors_by_point
+ .entry(point)
+ .or_insert_with(Vec::new)
+ .push(loan);
+ }
+
+ let mut opt_errors_by_point = FxHashMap::default();
+ for &(loan, point) in opt_errors.iter() {
+ opt_errors_by_point
+ .entry(point)
+ .or_insert_with(Vec::new)
+ .push(loan);
+ }
+
+ if compare_errors(&naive_errors_by_point, &opt_errors_by_point) {
+ panic!(concat!(
+ "The errors reported by the naive algorithm differ from ",
+ "the errors reported by the optimized algorithm. ",
+ "See the error log for details."
+ ));
+ } else {
+ debug!("Naive and optimized algorithms reported the same errors.");
+ }
+
+ (naive_errors, naive_subset_errors)
+ }
+ };
+
+ // Record illegal access errors
+ for &(loan, location) in errors.iter() {
+ result.errors.entry(location).or_default().push(loan);
+ }
+
+ // Record illegal subset errors
+ for &(origin1, origin2, location) in subset_errors.iter() {
+ result
+ .subset_errors
+ .entry(location)
+ .or_default()
+ .insert((origin1, origin2));
+ }
+
+ // Record more debugging info when asked to do so
+ if dump_enabled {
+ for &(origin, location) in ctx.origin_live_on_entry.iter() {
+ result
+ .origin_live_on_entry
+ .entry(location)
+ .or_default()
+ .push(origin);
+ }
+
+ for &(origin, loan) in ctx.known_contains.iter() {
+ result
+ .known_contains
+ .entry(origin)
+ .or_default()
+ .insert(loan);
+ }
+ }
+
+ result
+ }
+
+ /// Computes the transitive closure of the `known_placeholder_subset` relation, so that we have
+ /// the full list of placeholder loans contained by the placeholder origins.
+ fn compute_known_contains(
+ known_placeholder_subset: &Relation<(T::Origin, T::Origin)>,
+ placeholder: &[(T::Origin, T::Loan)],
+ ) -> Relation<(T::Origin, T::Loan)> {
+ let mut iteration = datafrog::Iteration::new();
+ let known_contains = iteration.variable("known_contains");
+
+ // known_contains(Origin1, Loan1) :-
+ // placeholder(Origin1, Loan1).
+ known_contains.extend(placeholder.iter());
+
+ while iteration.changed() {
+ // known_contains(Origin2, Loan1) :-
+ // known_contains(Origin1, Loan1),
+ // known_placeholder_subset(Origin1, Origin2).
+ known_contains.from_join(
+ &known_contains,
+ known_placeholder_subset,
+ |&_origin1, &loan1, &origin2| (origin2, loan1),
+ );
+ }
+
+ known_contains.complete()
+ }
+
+ /// Computes the transitive closure of the `known_placeholder_subset` relation.
+ fn compute_known_placeholder_subset(
+ known_placeholder_subset_base: &Relation<(T::Origin, T::Origin)>,
+ ) -> Relation<(T::Origin, T::Origin)> {
+ use datafrog::{Iteration, RelationLeaper};
+ let mut iteration = Iteration::new();
+
+ let known_placeholder_subset = iteration.variable("known_placeholder_subset");
+
+ // known_placeholder_subset(Origin1, Origin2) :-
+ // known_placeholder_subset_base(Origin1, Origin2).
+ known_placeholder_subset.extend(known_placeholder_subset_base.iter());
+
+ while iteration.changed() {
+ // known_placeholder_subset(Origin1, Origin3) :-
+ // known_placeholder_subset(Origin1, Origin2),
+ // known_placeholder_subset_base(Origin2, Origin3).
+ known_placeholder_subset.from_leapjoin(
+ &known_placeholder_subset,
+ known_placeholder_subset_base.extend_with(|&(_origin1, origin2)| origin2),
+ |&(origin1, _origin2), &origin3| (origin1, origin3),
+ );
+ }
+
+ known_placeholder_subset.complete()
+ }
+
+ fn new(dump_enabled: bool) -> Self {
+ Output {
+ errors: FxHashMap::default(),
+ subset_errors: FxHashMap::default(),
+ dump_enabled,
+ loan_live_at: FxHashMap::default(),
+ origin_contains_loan_at: FxHashMap::default(),
+ origin_contains_loan_anywhere: FxHashMap::default(),
+ origin_live_on_entry: FxHashMap::default(),
+ loan_invalidated_at: FxHashMap::default(),
+ move_errors: FxHashMap::default(),
+ subset: FxHashMap::default(),
+ subset_anywhere: FxHashMap::default(),
+ var_live_on_entry: FxHashMap::default(),
+ var_drop_live_on_entry: FxHashMap::default(),
+ path_maybe_initialized_on_exit: FxHashMap::default(),
+ path_maybe_uninitialized_on_exit: FxHashMap::default(),
+ var_maybe_partly_initialized_on_exit: FxHashMap::default(),
+ known_contains: FxHashMap::default(),
+ }
+ }
+
+ pub fn errors_at(&self, location: T::Point) -> &[T::Loan] {
+ match self.errors.get(&location) {
+ Some(v) => v,
+ None => &[],
+ }
+ }
+
+ pub fn loans_in_scope_at(&self, location: T::Point) -> &[T::Loan] {
+ match self.loan_live_at.get(&location) {
+ Some(p) => p,
+ None => &[],
+ }
+ }
+
+ pub fn origin_contains_loan_at(
+ &self,
+ location: T::Point,
+ ) -> Cow<'_, BTreeMap<T::Origin, BTreeSet<T::Loan>>> {
+ assert!(self.dump_enabled);
+ match self.origin_contains_loan_at.get(&location) {
+ Some(map) => Cow::Borrowed(map),
+ None => Cow::Owned(BTreeMap::default()),
+ }
+ }
+
+ pub fn origins_live_at(&self, location: T::Point) -> &[T::Origin] {
+ assert!(self.dump_enabled);
+ match self.origin_live_on_entry.get(&location) {
+ Some(v) => v,
+ None => &[],
+ }
+ }
+
+ pub fn subsets_at(
+ &self,
+ location: T::Point,
+ ) -> Cow<'_, BTreeMap<T::Origin, BTreeSet<T::Origin>>> {
+ assert!(self.dump_enabled);
+ match self.subset.get(&location) {
+ Some(v) => Cow::Borrowed(v),
+ None => Cow::Owned(BTreeMap::default()),
+ }
+ }
+}
+
+/// Compares errors reported by Naive implementation with the errors
+/// reported by the optimized implementation.
+fn compare_errors<Loan: Atom, Point: Atom>(
+ all_naive_errors: &FxHashMap<Point, Vec<Loan>>,
+ all_opt_errors: &FxHashMap<Point, Vec<Loan>>,
+) -> bool {
+ let points = all_naive_errors.keys().chain(all_opt_errors.keys());
+
+ let mut differ = false;
+ for point in points {
+ let mut naive_errors = all_naive_errors.get(&point).cloned().unwrap_or_default();
+ naive_errors.sort();
+
+ let mut opt_errors = all_opt_errors.get(&point).cloned().unwrap_or_default();
+ opt_errors.sort();
+
+ for err in naive_errors.iter() {
+ if !opt_errors.contains(err) {
+ error!(
+ "Error {0:?} at {1:?} reported by naive, but not opt.",
+ err, point
+ );
+ differ = true;
+ }
+ }
+
+ for err in opt_errors.iter() {
+ if !naive_errors.contains(err) {
+ error!(
+ "Error {0:?} at {1:?} reported by opt, but not naive.",
+ err, point
+ );
+ differ = true;
+ }
+ }
+ }
+
+ differ
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ impl Atom for usize {
+ fn index(self) -> usize {
+ self
+ }
+ }
+
+ fn compare(
+ errors1: &FxHashMap<usize, Vec<usize>>,
+ errors2: &FxHashMap<usize, Vec<usize>>,
+ ) -> bool {
+ let diff1 = compare_errors(errors1, errors2);
+ let diff2 = compare_errors(errors2, errors1);
+ assert_eq!(diff1, diff2);
+ diff1
+ }
+
+ #[test]
+ fn test_compare_errors() {
+ let empty = FxHashMap::default();
+ assert_eq!(false, compare(&empty, &empty));
+ let mut empty_vec = FxHashMap::default();
+ empty_vec.insert(1, vec![]);
+ empty_vec.insert(2, vec![]);
+ assert_eq!(false, compare(&empty, &empty_vec));
+
+ let mut singleton1 = FxHashMap::default();
+ singleton1.insert(1, vec![10]);
+ assert_eq!(false, compare(&singleton1, &singleton1));
+ let mut singleton2 = FxHashMap::default();
+ singleton2.insert(1, vec![11]);
+ assert_eq!(false, compare(&singleton2, &singleton2));
+ let mut singleton3 = FxHashMap::default();
+ singleton3.insert(2, vec![10]);
+ assert_eq!(false, compare(&singleton3, &singleton3));
+
+ assert_eq!(true, compare(&singleton1, &singleton2));
+ assert_eq!(true, compare(&singleton2, &singleton3));
+ assert_eq!(true, compare(&singleton1, &singleton3));
+
+ assert_eq!(true, compare(&empty, &singleton1));
+ assert_eq!(true, compare(&empty, &singleton2));
+ assert_eq!(true, compare(&empty, &singleton3));
+
+ let mut errors1 = FxHashMap::default();
+ errors1.insert(1, vec![11]);
+ errors1.insert(2, vec![10]);
+ assert_eq!(false, compare(&errors1, &errors1));
+ assert_eq!(true, compare(&errors1, &singleton1));
+ assert_eq!(true, compare(&errors1, &singleton2));
+ assert_eq!(true, compare(&errors1, &singleton3));
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs
new file mode 100644
index 0000000..aa42048
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/polonius-engine/src/output/naive.rs
@@ -0,0 +1,299 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <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.
+
+//! A version of the Naive datalog analysis using Datafrog.
+
+use datafrog::{Iteration, Relation, RelationLeaper};
+use std::time::Instant;
+
+use crate::facts::FactTypes;
+use crate::output::{Context, Output};
+
+pub(super) fn compute<T: FactTypes>(
+ ctx: &Context<'_, T>,
+ result: &mut Output<T>,
+) -> (
+ Relation<(T::Loan, T::Point)>,
+ Relation<(T::Origin, T::Origin, T::Point)>,
+) {
+ let timer = Instant::now();
+
+ let (errors, subset_errors) = {
+ // Static inputs
+ let origin_live_on_entry_rel = &ctx.origin_live_on_entry;
+ let cfg_edge = &ctx.cfg_edge;
+ let loan_killed_at = &ctx.loan_killed_at;
+ let known_placeholder_subset = &ctx.known_placeholder_subset;
+ let placeholder_origin = &ctx.placeholder_origin;
+
+ // Create a new iteration context, ...
+ let mut iteration = Iteration::new();
+
+ // .. some variables, ..
+ let subset = iteration.variable::<(T::Origin, T::Origin, T::Point)>("subset");
+ let origin_contains_loan_on_entry =
+ iteration.variable::<(T::Origin, T::Loan, T::Point)>("origin_contains_loan_on_entry");
+ let loan_live_at = iteration.variable::<((T::Loan, T::Point), ())>("loan_live_at");
+
+ // `loan_invalidated_at` facts, stored ready for joins
+ let loan_invalidated_at = Relation::from_iter(
+ ctx.loan_invalidated_at
+ .iter()
+ .map(|&(loan, point)| ((loan, point), ())),
+ );
+
+ // different indices for `subset`.
+ let subset_o1p = iteration.variable_indistinct("subset_o1p");
+ let subset_o2p = iteration.variable_indistinct("subset_o2p");
+
+ // different index for `origin_contains_loan_on_entry`.
+ let origin_contains_loan_on_entry_op =
+ iteration.variable_indistinct("origin_contains_loan_on_entry_op");
+
+ // Unfortunately, we need `origin_live_on_entry` in both variable and relation forms:
+ // We need:
+ // - `origin_live_on_entry` as a Relation for the leapjoins in rules 3 & 6
+ // - `origin_live_on_entry` as a Variable for the join in rule 7
+ //
+ // The leapjoins use `origin_live_on_entry` as `(Origin, Point)` tuples, while the join uses
+ // it as a `((O, P), ())` tuple to filter the `((Origin, Point), Loan)` tuples from
+ // `origin_contains_loan_on_entry_op`.
+ //
+ // The regular join in rule 7 could be turned into a `filter_with` leaper but that would
+ // result in a leapjoin with no `extend_*` leapers: a leapjoin that is not well-formed.
+ // Doing the filtering via an `extend_with` leaper would be extremely inefficient.
+ //
+ // Until there's an API in datafrog to handle this use-case better, we do a slightly less
+ // inefficient thing of copying the whole static input into a Variable to use a regular
+ // join, even though the liveness information can be quite heavy (around 1M tuples
+ // on `clap`).
+ // This is the Naive variant so this is not a big problem, but needs an
+ // explanation.
+ let origin_live_on_entry_var =
+ iteration.variable::<((T::Origin, T::Point), ())>("origin_live_on_entry");
+ origin_live_on_entry_var.extend(
+ origin_live_on_entry_rel
+ .iter()
+ .map(|&(origin, point)| ((origin, point), ())),
+ );
+
+ // output relations: illegal accesses errors, and illegal subset relations errors
+ let errors = iteration.variable("errors");
+ let subset_errors = iteration.variable::<(T::Origin, T::Origin, T::Point)>("subset_errors");
+
+ // load initial facts:
+
+ // Rule 1: the initial subsets are the non-transitive `subset_base` static input.
+ //
+ // subset(Origin1, Origin2, Point) :-
+ // subset_base(Origin1, Origin2, Point).
+ subset.extend(ctx.subset_base.iter());
+
+ // Rule 4: the issuing origins are the ones initially containing loans.
+ //
+ // origin_contains_loan_on_entry(Origin, Loan, Point) :-
+ // loan_issued_at(Origin, Loan, Point).
+ origin_contains_loan_on_entry.extend(ctx.loan_issued_at.iter());
+
+ // .. and then start iterating rules!
+ while iteration.changed() {
+ // Cleanup step: remove symmetries
+ // - remove origins which are `subset`s of themselves
+ //
+ // FIXME: investigate whether is there a better way to do that without complicating
+ // the rules too much, because it would also require temporary variables and
+ // impact performance. Until then, the big reduction in tuples improves performance
+ // a lot, even if we're potentially adding a small number of tuples
+ // per round just to remove them in the next round.
+ subset
+ .recent
+ .borrow_mut()
+ .elements
+ .retain(|&(origin1, origin2, _)| origin1 != origin2);
+
+ // Remap fields to re-index by keys, to prepare the data needed by the rules below.
+ subset_o1p.from_map(&subset, |&(origin1, origin2, point)| {
+ ((origin1, point), origin2)
+ });
+ subset_o2p.from_map(&subset, |&(origin1, origin2, point)| {
+ ((origin2, point), origin1)
+ });
+
+ origin_contains_loan_on_entry_op
+ .from_map(&origin_contains_loan_on_entry, |&(origin, loan, point)| {
+ ((origin, point), loan)
+ });
+
+ // Rule 1: done above, as part of the static input facts setup.
+
+ // Rule 2: compute the subset transitive closure, at a given point.
+ //
+ // subset(Origin1, Origin3, Point) :-
+ // subset(Origin1, Origin2, Point),
+ // subset(Origin2, Origin3, Point).
+ subset.from_join(
+ &subset_o2p,
+ &subset_o1p,
+ |&(_origin2, point), &origin1, &origin3| (origin1, origin3, point),
+ );
+
+ // Rule 3: propagate subsets along the CFG, according to liveness.
+ //
+ // subset(Origin1, Origin2, Point2) :-
+ // subset(Origin1, Origin2, Point1),
+ // cfg_edge(Point1, Point2),
+ // origin_live_on_entry(Origin1, Point2),
+ // origin_live_on_entry(Origin2, Point2).
+ subset.from_leapjoin(
+ &subset,
+ (
+ cfg_edge.extend_with(|&(_origin1, _origin2, point1)| point1),
+ origin_live_on_entry_rel.extend_with(|&(origin1, _origin2, _point1)| origin1),
+ origin_live_on_entry_rel.extend_with(|&(_origin1, origin2, _point1)| origin2),
+ ),
+ |&(origin1, origin2, _point1), &point2| (origin1, origin2, point2),
+ );
+
+ // Rule 4: done above as part of the static input facts setup.
+
+ // Rule 5: propagate loans within origins, at a given point, according to subsets.
+ //
+ // origin_contains_loan_on_entry(Origin2, Loan, Point) :-
+ // origin_contains_loan_on_entry(Origin1, Loan, Point),
+ // subset(Origin1, Origin2, Point).
+ origin_contains_loan_on_entry.from_join(
+ &origin_contains_loan_on_entry_op,
+ &subset_o1p,
+ |&(_origin1, point), &loan, &origin2| (origin2, loan, point),
+ );
+
+ // Rule 6: propagate loans along the CFG, according to liveness.
+ //
+ // origin_contains_loan_on_entry(Origin, Loan, Point2) :-
+ // origin_contains_loan_on_entry(Origin, Loan, Point1),
+ // !loan_killed_at(Loan, Point1),
+ // cfg_edge(Point1, Point2),
+ // origin_live_on_entry(Origin, Point2).
+ origin_contains_loan_on_entry.from_leapjoin(
+ &origin_contains_loan_on_entry,
+ (
+ loan_killed_at.filter_anti(|&(_origin, loan, point1)| (loan, point1)),
+ cfg_edge.extend_with(|&(_origin, _loan, point1)| point1),
+ origin_live_on_entry_rel.extend_with(|&(origin, _loan, _point1)| origin),
+ ),
+ |&(origin, loan, _point1), &point2| (origin, loan, point2),
+ );
+
+ // Rule 7: compute whether a loan is live at a given point, i.e. whether it is
+ // contained in a live origin at this point.
+ //
+ // loan_live_at(Loan, Point) :-
+ // origin_contains_loan_on_entry(Origin, Loan, Point),
+ // origin_live_on_entry(Origin, Point).
+ loan_live_at.from_join(
+ &origin_contains_loan_on_entry_op,
+ &origin_live_on_entry_var,
+ |&(_origin, point), &loan, _| ((loan, point), ()),
+ );
+
+ // Rule 8: compute illegal access errors, i.e. an invalidation of a live loan.
+ //
+ // Here again, this join acts as a pure filter and could be a more efficient leapjoin.
+ // However, similarly to the `origin_live_on_entry` example described above, the
+ // leapjoin with a single `filter_with` leaper would currently not be well-formed.
+ // We don't explictly need to materialize `loan_live_at` either, and that doesn't
+ // change the well-formedness situation, so we still materialize it (since that also
+ // helps in testing).
+ //
+ // errors(Loan, Point) :-
+ // loan_invalidated_at(Loan, Point),
+ // loan_live_at(Loan, Point).
+ errors.from_join(
+ &loan_live_at,
+ &loan_invalidated_at,
+ |&(loan, point), _, _| (loan, point),
+ );
+
+ // Rule 9: compute illegal subset relations errors, i.e. the undeclared subsets
+ // between two placeholder origins.
+ // Here as well, WF-ness prevents this join from being a filter-only leapjoin. It
+ // doesn't matter much, as `placeholder_origin` is single-value relation.
+ //
+ // subset_error(Origin1, Origin2, Point) :-
+ // subset(Origin1, Origin2, Point),
+ // placeholder_origin(Origin1),
+ // placeholder_origin(Origin2),
+ // !known_placeholder_subset(Origin1, Origin2).
+ subset_errors.from_leapjoin(
+ &subset,
+ (
+ placeholder_origin.extend_with(|&(origin1, _origin2, _point)| origin1),
+ placeholder_origin.extend_with(|&(_origin1, origin2, _point)| origin2),
+ known_placeholder_subset
+ .filter_anti(|&(origin1, origin2, _point)| (origin1, origin2)),
+ // remove symmetries:
+ datafrog::ValueFilter::from(|&(origin1, origin2, _point), _| {
+ origin1 != origin2
+ }),
+ ),
+ |&(origin1, origin2, point), _| (origin1, origin2, point),
+ );
+ }
+
+ // Handle verbose output data
+ if result.dump_enabled {
+ let subset = subset.complete();
+ assert!(
+ subset
+ .iter()
+ .filter(|&(origin1, origin2, _)| origin1 == origin2)
+ .count()
+ == 0,
+ "unwanted subset symmetries"
+ );
+ for &(origin1, origin2, location) in subset.iter() {
+ result
+ .subset
+ .entry(location)
+ .or_default()
+ .entry(origin1)
+ .or_default()
+ .insert(origin2);
+ }
+
+ let origin_contains_loan_on_entry = origin_contains_loan_on_entry.complete();
+ for &(origin, loan, location) in origin_contains_loan_on_entry.iter() {
+ result
+ .origin_contains_loan_at
+ .entry(location)
+ .or_default()
+ .entry(origin)
+ .or_default()
+ .insert(loan);
+ }
+
+ let loan_live_at = loan_live_at.complete();
+ for &((loan, location), _) in loan_live_at.iter() {
+ result.loan_live_at.entry(location).or_default().push(loan);
+ }
+ }
+
+ (errors.complete(), subset_errors.complete())
+ };
+
+ info!(
+ "analysis done: {} `errors` tuples, {} `subset_errors` tuples, {:?}",
+ errors.len(),
+ subset_errors.len(),
+ timer.elapsed()
+ );
+
+ (errors, subset_errors)
+}
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json
new file mode 100644
index 0000000..544af9f
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"CODE_OF_CONDUCT.md":"edca092fde496419a9f1ba640048aa0270b62dfea576cd3175f0b53e3c230470","Cargo.toml":"647814b27b6fc4fbef1df70d796b53b723e776b68467372044e4182763007379","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"cac8197ac869d64a6efc26cab883a269392ae6db51f7453bca722f8f31d67c7c","src/lib.rs":"ddecafb5db609d0d8eebd19e4d98dc865e7e9282a4183421f9bd765c01a231c0"},"package":"08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"} \ No newline at end of file
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..d70b2b5
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/CODE_OF_CONDUCT.md
@@ -0,0 +1,40 @@
+# The Rust Code of Conduct
+
+A version of this document [can be found online](https://www.rust-lang.org/conduct.html).
+
+## Conduct
+
+**Contact**: [rust-mods@rust-lang.org](mailto:rust-mods@rust-lang.org)
+
+* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
+* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
+* Please be kind and courteous. There's no need to be mean or rude.
+* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
+* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
+* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
+* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
+* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
+
+## Moderation
+
+
+These are the policies for upholding our community's standards of conduct. If you feel that a thread needs moderation, please contact the [Rust moderation team][mod_team].
+
+1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
+2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
+3. Moderators will first respond to such remarks with a warning.
+4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
+5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
+6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
+7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
+8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
+
+In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
+
+And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
+
+The enforcement policies listed above apply to all official Rust venues; including official IRC channels (#rust, #rust-internals, #rust-tools, #rust-libs, #rustc, #rust-beginners, #rust-docs, #rust-community, #rust-lang, and #cargo); GitHub repositories under rust-lang, rust-lang-nursery, and rust-lang-deprecated; and all forums under rust-lang.org (users.rust-lang.org, internals.rust-lang.org). For other projects adopting the Rust Code of Conduct, please contact the maintainers of those projects for enforcement. If you wish to use this code of conduct for your own project, consider explicitly mentioning your moderation policy or making a copy with your own moderation policy so as to avoid confusion.
+
+*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
+
+[mod_team]: https://www.rust-lang.org/team.html#Moderation-team
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml
new file mode 100644
index 0000000..47330b7
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/Cargo.toml
@@ -0,0 +1,25 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+name = "rustc-hash"
+version = "1.1.0"
+authors = ["The Rust Project Developers"]
+description = "speed, non-cryptographic hash used in rustc"
+readme = "README.md"
+keywords = ["hash", "fxhash", "rustc"]
+license = "Apache-2.0/MIT"
+repository = "https://github.com/rust-lang-nursery/rustc-hash"
+
+[features]
+default = ["std"]
+std = []
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE
new file mode 100644
index 0000000..16fe87b
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-APACHE
@@ -0,0 +1,201 @@
+ 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
+
+APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/LICENSE-MIT
@@ -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/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md
new file mode 100644
index 0000000..e33057a
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/README.md
@@ -0,0 +1,38 @@
+# rustc-hash
+
+[![crates.io](https://img.shields.io/crates/v/rustc-hash.svg)](https://crates.io/crates/rustc-hash)
+[![Documentation](https://docs.rs/rustc-hash/badge.svg)](https://docs.rs/rustc-hash)
+
+A speedy hash algorithm used within rustc. The hashmap in liballoc by
+default uses SipHash which isn't quite as speedy as we want. In the
+compiler we're not really worried about DOS attempts, so we use a fast
+non-cryptographic hash.
+
+This is the same as the algorithm used by Firefox -- which is a
+homespun one not based on any widely-known algorithm -- though
+modified to produce 64-bit hash values instead of 32-bit hash
+values. It consistently out-performs an FNV-based hash within rustc
+itself -- the collision rate is similar or slightly worse than FNV,
+but the speed of the hash function itself is much higher because it
+works on up to 8 bytes at a time.
+
+## Usage
+
+```rust
+use rustc_hash::FxHashMap;
+
+let mut map: FxHashMap<u32, u32> = FxHashMap::default();
+map.insert(22, 44);
+```
+
+### `no_std`
+
+This crate can be used as a `no_std` crate by disabling the `std`
+feature, which is on by default, as follows:
+
+```toml
+rustc-hash = { version = "1.0", default-features = false }
+```
+
+In this configuration, `FxHasher` is the only export, and the
+`FxHashMap`/`FxHashSet` type aliases are omitted.
diff --git a/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs
new file mode 100644
index 0000000..ee9ad31
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/ffi-polonius/vendor/rustc-hash/src/lib.rs
@@ -0,0 +1,148 @@
+// 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.
+
+//! Fast, non-cryptographic hash used by rustc and Firefox.
+//!
+//! # Example
+//!
+//! ```rust
+//! # #[cfg(feature = "std")]
+//! # fn main() {
+//! use rustc_hash::FxHashMap;
+//! let mut map: FxHashMap<u32, u32> = FxHashMap::default();
+//! map.insert(22, 44);
+//! # }
+//! # #[cfg(not(feature = "std"))]
+//! # fn main() { }
+//! ```
+
+#![no_std]
+
+#[cfg(feature = "std")]
+extern crate std;
+
+use core::convert::TryInto;
+use core::default::Default;
+#[cfg(feature = "std")]
+use core::hash::BuildHasherDefault;
+use core::hash::Hasher;
+use core::mem::size_of;
+use core::ops::BitXor;
+#[cfg(feature = "std")]
+use std::collections::{HashMap, HashSet};
+
+/// Type alias for a hashmap using the `fx` hash algorithm.
+#[cfg(feature = "std")]
+pub type FxHashMap<K, V> = HashMap<K, V, BuildHasherDefault<FxHasher>>;
+
+/// Type alias for a hashmap using the `fx` hash algorithm.
+#[cfg(feature = "std")]
+pub type FxHashSet<V> = HashSet<V, BuildHasherDefault<FxHasher>>;
+
+/// A speedy hash algorithm for use within rustc. The hashmap in liballoc
+/// by default uses SipHash which isn't quite as speedy as we want. In the
+/// compiler we're not really worried about DOS attempts, so we use a fast
+/// non-cryptographic hash.
+///
+/// This is the same as the algorithm used by Firefox -- which is a homespun
+/// one not based on any widely-known algorithm -- though modified to produce
+/// 64-bit hash values instead of 32-bit hash values. It consistently
+/// out-performs an FNV-based hash within rustc itself -- the collision rate is
+/// similar or slightly worse than FNV, but the speed of the hash function
+/// itself is much higher because it works on up to 8 bytes at a time.
+pub struct FxHasher {
+ hash: usize,
+}
+
+#[cfg(target_pointer_width = "32")]
+const K: usize = 0x9e3779b9;
+#[cfg(target_pointer_width = "64")]
+const K: usize = 0x517cc1b727220a95;
+
+impl Default for FxHasher {
+ #[inline]
+ fn default() -> FxHasher {
+ FxHasher { hash: 0 }
+ }
+}
+
+impl FxHasher {
+ #[inline]
+ fn add_to_hash(&mut self, i: usize) {
+ self.hash = self.hash.rotate_left(5).bitxor(i).wrapping_mul(K);
+ }
+}
+
+impl Hasher for FxHasher {
+ #[inline]
+ fn write(&mut self, mut bytes: &[u8]) {
+ #[cfg(target_pointer_width = "32")]
+ let read_usize = |bytes: &[u8]| u32::from_ne_bytes(bytes[..4].try_into().unwrap());
+ #[cfg(target_pointer_width = "64")]
+ let read_usize = |bytes: &[u8]| u64::from_ne_bytes(bytes[..8].try_into().unwrap());
+
+ let mut hash = FxHasher { hash: self.hash };
+ assert!(size_of::<usize>() <= 8);
+ while bytes.len() >= size_of::<usize>() {
+ hash.add_to_hash(read_usize(bytes) as usize);
+ bytes = &bytes[size_of::<usize>()..];
+ }
+ if (size_of::<usize>() > 4) && (bytes.len() >= 4) {
+ hash.add_to_hash(u32::from_ne_bytes(bytes[..4].try_into().unwrap()) as usize);
+ bytes = &bytes[4..];
+ }
+ if (size_of::<usize>() > 2) && bytes.len() >= 2 {
+ hash.add_to_hash(u16::from_ne_bytes(bytes[..2].try_into().unwrap()) as usize);
+ bytes = &bytes[2..];
+ }
+ if (size_of::<usize>() > 1) && bytes.len() >= 1 {
+ hash.add_to_hash(bytes[0] as usize);
+ }
+ self.hash = hash.hash;
+ }
+
+ #[inline]
+ fn write_u8(&mut self, i: u8) {
+ self.add_to_hash(i as usize);
+ }
+
+ #[inline]
+ fn write_u16(&mut self, i: u16) {
+ self.add_to_hash(i as usize);
+ }
+
+ #[inline]
+ fn write_u32(&mut self, i: u32) {
+ self.add_to_hash(i as usize);
+ }
+
+ #[cfg(target_pointer_width = "32")]
+ #[inline]
+ fn write_u64(&mut self, i: u64) {
+ self.add_to_hash(i as usize);
+ self.add_to_hash((i >> 32) as usize);
+ }
+
+ #[cfg(target_pointer_width = "64")]
+ #[inline]
+ fn write_u64(&mut self, i: u64) {
+ self.add_to_hash(i as usize);
+ }
+
+ #[inline]
+ fn write_usize(&mut self, i: usize) {
+ self.add_to_hash(i);
+ }
+
+ #[inline]
+ fn finish(&self) -> u64 {
+ self.hash as u64
+ }
+}
diff --git a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h
index b013a93..0ce2142 100644
--- a/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h
+++ b/gcc/rust/checks/errors/borrowck/polonius/rust-polonius.h
@@ -35,7 +35,7 @@ struct FullPoint
bool mid;
/** Expands a compressed `Point` into its components.
- * See `Point` docs for encoding details.
+ * See `Point` docs for encoding details in ./rust-polonius-ffi.h
*/
explicit FullPoint (Point point)
: bb (extract_bb (point)), stmt (extract_stmt (point)),
@@ -45,7 +45,24 @@ struct FullPoint
static uint32_t extract_bb (Point point) { return point >> 16; }
static uint32_t extract_stmt (Point point)
{
- return (point & ~(1 << 16)) >> 1;
+ // Point is a 32 bit unsigned integer
+ // 16 15 1
+ // xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxx x
+ // ^~~~~~~~~~~~~~~~ ^~~~~~~~~~~~~~~ ^
+ // | | |
+ // basic_block | start/mid
+ // statement
+ // the left most 16 bits store the basic block number
+ // the right most bit, represents the start/mid status
+ // the remaining 15 bits between these two represent the statement number
+ // which we need to extract in this fucntion
+ //
+ // firstly we can get rid of right most bit by performing left shift once
+ auto hide_left_most_bit = point >> 1;
+ // now we only need the 15 bits on the right
+ // we can mask the remaining bits by performing bitwise AND with fifteen
+ // 1's which in hexadecimal is 0x7FFF
+ return hide_left_most_bit & 0x7FFF;
}
static bool extract_mid (Point point) { return point & 1; }
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
index acfcdd8..1713bf6 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc
@@ -21,6 +21,7 @@
#include "rust-bir-builder-lazyboolexpr.h"
#include "rust-bir-builder-pattern.h"
#include "rust-bir-builder-struct.h"
+#include "rust-hir-expr.h"
namespace Rust {
namespace BIR {
@@ -44,7 +45,8 @@ ExprStmtBuilder::setup_loop (HIR::BaseLoopExpr &expr)
BasicBlockId break_bb = new_bb ();
// We are still outside the loop block;
- ScopeId continue_scope = ctx.place_db.get_current_scope_id () + 1;
+ ScopeId continue_scope
+ = ctx.place_db.get_current_scope_id ().next_scope_id ();
ctx.loop_and_label_stack.emplace_back (true, label, label_var, break_bb,
continue_bb, continue_scope);
@@ -80,14 +82,21 @@ ExprStmtBuilder::visit (HIR::ClosureExpr &expr)
{
auto closure_ty = lookup_type (expr)->as<TyTy::ClosureType> ();
std::vector<PlaceId> captures;
+ std::vector<location_t> capture_locations;
for (auto &capture : closure_ty->get_captures ())
{
captures.push_back (ctx.place_db.lookup_variable (capture));
+ auto location = Analysis::Mappings::get ()
+ .lookup_ast_item (capture)
+ .value ()
+ ->get_locus ();
+ capture_locations.push_back (location);
}
- move_all (captures);
+ move_all (captures, capture_locations);
// Note: Not a coercion site for captures.
- return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr));
+ return_expr (new InitializerExpr (std::move (captures)), lookup_type (expr),
+ expr.get_locus ());
}
void
@@ -96,23 +105,31 @@ ExprStmtBuilder::visit (HIR::StructExprStructFields &fields)
auto *p_adt_type = lookup_type (fields)->as<TyTy::ADTType> ();
auto struct_ty = p_adt_type->get_variants ().at (0);
auto init_values = StructBuilder (ctx, struct_ty).build (fields);
- move_all (init_values);
+ // collect fields locations
+ std::vector<location_t> field_locations;
+ for (auto &field : fields.get_fields ())
+ {
+ field_locations.push_back (field->get_locus ());
+ }
+ move_all (init_values, field_locations);
return_expr (new InitializerExpr (std::move (init_values)),
- lookup_type (fields));
+ lookup_type (fields), fields.get_locus ());
}
void
ExprStmtBuilder::visit (HIR::StructExprStruct &expr)
{
// There is no way to modify empty struct, which makes them constant.
- return_place (ctx.place_db.get_constant (lookup_type (expr)));
+ return_place (ctx.place_db.get_constant (lookup_type (expr)),
+ expr.get_locus ());
}
void
ExprStmtBuilder::visit (HIR::LiteralExpr &expr)
{
// Different literal values of the same type are not distinguished in BIR.
- return_place (ctx.place_db.get_constant (lookup_type (expr)));
+ return_place (ctx.place_db.get_constant (lookup_type (expr)),
+ expr.get_locus ());
}
void
@@ -122,12 +139,12 @@ ExprStmtBuilder::visit (HIR::BorrowExpr &expr)
if (ctx.place_db[operand].is_constant ())
{
// Cannot borrow a constant, must create a temporary copy.
- push_tmp_assignment (operand);
+ push_tmp_assignment (operand, expr.get_locus ());
operand = translated;
}
// BorrowExpr cannot be annotated with lifetime.
- return_borrowed (operand, lookup_type (expr));
+ return_borrowed (operand, lookup_type (expr), expr.get_locus ());
}
void
@@ -135,7 +152,8 @@ ExprStmtBuilder::visit (HIR::DereferenceExpr &expr)
{
auto operand = visit_expr (*expr.get_expr ());
return_place (ctx.place_db.lookup_or_add_path (Place::DEREF,
- lookup_type (expr), operand));
+ lookup_type (expr), operand),
+ expr.get_locus ());
}
void
@@ -149,7 +167,8 @@ void
ExprStmtBuilder::visit (HIR::NegationExpr &expr)
{
PlaceId operand = visit_expr (*expr.get_expr ());
- return_expr (new Operator<1> ({move_place (operand)}), lookup_type (expr));
+ return_expr (new Operator<1> ({move_place (operand, expr.get_locus ())}),
+ lookup_type (expr), expr.get_locus ());
}
void
@@ -157,8 +176,10 @@ ExprStmtBuilder::visit (HIR::ArithmeticOrLogicalExpr &expr)
{
PlaceId lhs = visit_expr (*expr.get_lhs ());
PlaceId rhs = visit_expr (*expr.get_rhs ());
- return_expr (new Operator<2> ({move_place (lhs), move_place (rhs)}),
- lookup_type (expr));
+ return_expr (new Operator<2> (
+ {move_place (lhs, expr.get_lhs ()->get_locus ()),
+ move_place (rhs, expr.get_rhs ()->get_locus ())}),
+ lookup_type (expr), expr.get_locus ());
}
void
@@ -166,8 +187,10 @@ ExprStmtBuilder::visit (HIR::ComparisonExpr &expr)
{
PlaceId lhs = visit_expr (*expr.get_lhs ());
PlaceId rhs = visit_expr (*expr.get_rhs ());
- return_expr (new Operator<2> ({move_place (lhs), move_place (rhs)}),
- lookup_type (expr));
+ return_expr (new Operator<2> (
+ {move_place (lhs, expr.get_lhs ()->get_locus ()),
+ move_place (rhs, expr.get_rhs ()->get_locus ())}),
+ lookup_type (expr), expr.get_locus ());
}
void
@@ -175,14 +198,16 @@ ExprStmtBuilder::visit (HIR::LazyBooleanExpr &expr)
{
return_place (LazyBooleanExprBuilder (ctx, take_or_create_return_place (
lookup_type (expr)))
- .build (expr));
+ .build (expr),
+ expr.get_locus ());
}
void
ExprStmtBuilder::visit (HIR::TypeCastExpr &expr)
{
auto operand = visit_expr (*expr.get_expr ());
- return_expr (new Operator<1> ({operand}), lookup_type (expr));
+ return_expr (new Operator<1> ({operand}), lookup_type (expr),
+ expr.get_locus ());
}
void
@@ -190,7 +215,7 @@ ExprStmtBuilder::visit (HIR::AssignmentExpr &expr)
{
auto lhs = visit_expr (*expr.get_lhs ());
auto rhs = visit_expr (*expr.get_rhs ());
- push_assignment (lhs, rhs);
+ push_assignment (lhs, rhs, expr.get_locus ());
translated = INVALID_PLACE;
}
@@ -199,13 +224,13 @@ ExprStmtBuilder::visit (HIR::CompoundAssignmentExpr &expr)
{
auto lhs = visit_expr (*expr.get_lhs ());
auto rhs = visit_expr (*expr.get_rhs ());
- push_assignment (lhs, new Operator<2> ({lhs, rhs}));
+ push_assignment (lhs, new Operator<2> ({lhs, rhs}), expr.get_locus ());
}
void
ExprStmtBuilder::visit (HIR::GroupedExpr &expr)
{
- return_place (visit_expr (*expr.get_expr_in_parens ()));
+ return_place (visit_expr (*expr.get_expr_in_parens ()), expr.get_locus ());
}
void
@@ -217,15 +242,22 @@ ExprStmtBuilder::visit (HIR::ArrayExpr &expr)
case HIR::ArrayElems::VALUES: {
auto &elem_vals = (static_cast<HIR::ArrayElemsValues &> (*elems));
auto init_values = visit_list (elem_vals.get_values ());
- move_all (init_values);
+ // collect locations
+ std::vector<location_t> value_locations;
+ for (auto &value : elem_vals.get_values ())
+ {
+ value_locations.push_back (value->get_locus ());
+ }
+ move_all (init_values, value_locations);
return_expr (new InitializerExpr (std::move (init_values)),
- lookup_type (expr));
+ lookup_type (expr), expr.get_locus ());
break;
}
case HIR::ArrayElems::COPIED: {
auto &elem_copied = (static_cast<HIR::ArrayElemsCopied &> (*elems));
auto init = visit_expr (*elem_copied.get_elem_to_copy ());
- return_expr (new InitializerExpr ({init}), lookup_type (expr));
+ return_expr (new InitializerExpr ({init}), lookup_type (expr),
+ expr.get_locus ());
break;
}
}
@@ -238,8 +270,9 @@ ExprStmtBuilder::visit (HIR::ArrayIndexExpr &expr)
auto rhs = visit_expr (*expr.get_index_expr ());
// The index is not tracked in BIR.
std::ignore = rhs;
- return_place (
- ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (expr), lhs));
+ return_place (ctx.place_db.lookup_or_add_path (Place::INDEX,
+ lookup_type (expr), lhs),
+ expr.get_locus ());
}
void
@@ -247,7 +280,7 @@ ExprStmtBuilder::visit (HIR::TupleExpr &expr)
{
std::vector<PlaceId> init_values = visit_list (expr.get_tuple_elems ());
return_expr (new InitializerExpr (std::move (init_values)),
- lookup_type (expr));
+ lookup_type (expr), expr.get_locus ());
}
void
@@ -256,7 +289,8 @@ ExprStmtBuilder::visit (HIR::TupleIndexExpr &expr)
auto tuple = visit_expr (*expr.get_tuple_expr ());
return_place (ctx.place_db.lookup_or_add_path (Place::FIELD,
lookup_type (expr), tuple,
- expr.get_tuple_index ()));
+ expr.get_tuple_index ()),
+ expr.get_locus ());
}
void
@@ -273,13 +307,23 @@ ExprStmtBuilder::visit (HIR::CallExpr &expr)
coercion_site (arguments[i], fn_type->get_param_type_at (i));
}
- move_all (arguments);
+ // collect parameter locations
+ std::vector<location_t> parameter_locations;
+ for (auto &parameter : expr.get_arguments ())
+ {
+ parameter_locations.push_back (parameter->get_locus ());
+ }
+ move_all (arguments, parameter_locations);
return_expr (new CallExpr (fn, std::move (arguments)), lookup_type (expr),
- true);
+ expr.get_locus (), true);
}
void
+ExprStmtBuilder::visit (HIR::InlineAsm &expr)
+{}
+
+void
ExprStmtBuilder::visit (HIR::MethodCallExpr &expr)
{}
@@ -302,7 +346,8 @@ ExprStmtBuilder::visit (HIR::FieldAccessExpr &expr)
return_place (ctx.place_db.lookup_or_add_path (Place::FIELD,
field_ty->get_field_type (),
- receiver, field_index));
+ receiver, field_index),
+ expr.get_locus ());
}
void
@@ -338,7 +383,8 @@ ExprStmtBuilder::visit (HIR::BlockExpr &block)
if (block.has_expr () && !unreachable)
{
push_assignment (block_ctx.label_var,
- visit_expr (*block.get_final_expr ()));
+ visit_expr (*block.get_final_expr ()),
+ block.get_start_locus ());
}
if (!ctx.get_current_bb ().is_terminated ())
{
@@ -347,13 +393,14 @@ ExprStmtBuilder::visit (HIR::BlockExpr &block)
ctx.current_bb = block_ctx.break_bb;
ctx.loop_and_label_stack.pop_back ();
- return_place (block_ctx.label_var);
+ return_place (block_ctx.label_var, block.get_start_locus ());
}
else if (block.has_expr () && !unreachable)
{
return_place (visit_expr (*block.get_final_expr (),
take_or_create_return_place (
- lookup_type (*block.get_final_expr ()))));
+ lookup_type (*block.get_final_expr ()))),
+ block.get_start_locus ());
}
if (!unreachable)
@@ -368,7 +415,7 @@ ExprStmtBuilder::visit (HIR::ContinueExpr &cont)
LoopAndLabelCtx info = cont.has_label () ? get_label_ctx (cont.get_label ())
: get_unnamed_loop_ctx ();
start_new_consecutive_bb ();
- unwind_until (info.continue_bb);
+ unwind_until (info.continue_scope);
push_goto (info.continue_bb);
// No code allowed after continue. Handled in BlockExpr.
}
@@ -379,7 +426,8 @@ ExprStmtBuilder::visit (HIR::BreakExpr &brk)
LoopAndLabelCtx info = brk.has_label () ? get_label_ctx (brk.get_label ())
: get_unnamed_loop_ctx ();
if (brk.has_break_expr ())
- push_assignment (info.label_var, visit_expr (*brk.get_expr ()));
+ push_assignment (info.label_var, visit_expr (*brk.get_expr ()),
+ brk.get_locus ());
start_new_consecutive_bb ();
unwind_until (ctx.place_db.get_scope (info.continue_scope).parent);
@@ -392,27 +440,30 @@ ExprStmtBuilder::visit (HIR::RangeFromToExpr &range)
{
auto from = visit_expr (*range.get_from_expr ());
auto to = visit_expr (*range.get_to_expr ());
- return_expr (new InitializerExpr ({from, to}), lookup_type (range));
+ return_expr (new InitializerExpr ({from, to}), lookup_type (range),
+ range.get_locus ());
}
void
ExprStmtBuilder::visit (HIR::RangeFromExpr &expr)
{
auto from = visit_expr (*expr.get_from_expr ());
- return_expr (new InitializerExpr ({from}), lookup_type (expr));
+ return_expr (new InitializerExpr ({from}), lookup_type (expr),
+ expr.get_locus ());
}
void
ExprStmtBuilder::visit (HIR::RangeToExpr &expr)
{
auto to = visit_expr (*expr.get_to_expr ());
- return_expr (new InitializerExpr ({to}), lookup_type (expr));
+ return_expr (new InitializerExpr ({to}), lookup_type (expr),
+ expr.get_locus ());
}
void
ExprStmtBuilder::visit (HIR::RangeFullExpr &expr)
{
- return_expr (new InitializerExpr ({}), lookup_type (expr));
+ return_expr (new InitializerExpr ({}), lookup_type (expr), expr.get_locus ());
}
void
@@ -420,14 +471,16 @@ ExprStmtBuilder::visit (HIR::RangeFromToInclExpr &expr)
{
auto from = visit_expr (*expr.get_from_expr ());
auto to = visit_expr (*expr.get_to_expr ());
- return_expr (new InitializerExpr ({from, to}), lookup_type (expr));
+ return_expr (new InitializerExpr ({from, to}), lookup_type (expr),
+ expr.get_locus ());
}
void
ExprStmtBuilder::visit (HIR::RangeToInclExpr &expr)
{
auto to = visit_expr (*expr.get_to_expr ());
- return_expr (new InitializerExpr ({to}), lookup_type (expr));
+ return_expr (new InitializerExpr ({to}), lookup_type (expr),
+ expr.get_locus ());
}
void
@@ -436,10 +489,12 @@ ExprStmtBuilder::visit (HIR::ReturnExpr &ret)
if (ret.has_return_expr ())
{
push_assignment (RETURN_VALUE_PLACE,
- move_place (visit_expr (*ret.get_expr ())));
+ move_place (visit_expr (*ret.get_expr ()),
+ ret.get_expr ()->get_locus ()),
+ ret.get_expr ()->get_locus ());
}
unwind_until (ROOT_SCOPE);
- ctx.get_current_bb ().statements.emplace_back (Statement::Kind::RETURN);
+ push_return (ret.get_locus ());
translated = INVALID_PLACE;
}
@@ -468,7 +523,7 @@ ExprStmtBuilder::visit (HIR::WhileLoopExpr &expr)
auto cond_val = visit_expr (*expr.get_predicate_expr ());
auto body_bb = new_bb ();
- push_switch (cond_val, {body_bb, loop.break_bb});
+ push_switch (cond_val, expr.get_locus (), {body_bb, loop.break_bb});
ctx.current_bb = body_bb;
std::ignore = visit_expr (*expr.get_loop_block ());
@@ -492,7 +547,7 @@ ExprStmtBuilder::visit (HIR::IfExpr &expr)
if (expr.get_if_block ()->statements.empty ())
return;
- push_switch (visit_expr (*expr.get_if_condition ()));
+ push_switch (visit_expr (*expr.get_if_condition ()), expr.get_locus ());
BasicBlockId if_block = ctx.current_bb;
ctx.current_bb = new_bb ();
@@ -518,7 +573,9 @@ ExprStmtBuilder::visit (HIR::IfExpr &expr)
void
ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr)
{
- push_switch (move_place (visit_expr (*expr.get_if_condition ())));
+ push_switch (move_place (visit_expr (*expr.get_if_condition ()),
+ expr.get_if_condition ()->get_locus ()),
+ expr.get_locus ());
BasicBlockId if_end_bb = ctx.current_bb;
PlaceId result = take_or_create_return_place (lookup_type (expr));
@@ -539,7 +596,7 @@ ExprStmtBuilder::visit (HIR::IfExprConseqElse &expr)
ctx.current_bb = new_bb ();
BasicBlockId final_start_bb = ctx.current_bb;
- return_place (result);
+ return_place (result, expr.get_locus ());
// Jumps are added at the end to match rustc MIR order for easier comparison.
add_jump (if_end_bb, then_start_bb);
@@ -627,7 +684,7 @@ ExprStmtBuilder::visit (HIR::QualifiedPathInExpression &expr)
{
// Note: Type is only stored for the expr, not the segment.
PlaceId result = resolve_variable_or_fn (expr, lookup_type (expr));
- return_place (result);
+ return_place (result, expr.get_locus ());
}
void
@@ -635,7 +692,7 @@ ExprStmtBuilder::visit (HIR::PathInExpression &expr)
{
// Note: Type is only stored for the expr, not the segment.
PlaceId result = resolve_variable_or_fn (expr, lookup_type (expr));
- return_place (result);
+ return_place (result, expr.get_locus ());
}
void
@@ -677,7 +734,7 @@ ExprStmtBuilder::visit (HIR::ExprStmt &stmt)
// We must read the value for current liveness and we must not store it into
// the same place.
if (result != INVALID_PLACE)
- push_tmp_assignment (result);
+ push_tmp_assignment (result, stmt.get_locus ());
}
} // namespace BIR
} // namespace Rust
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
index 3a58611..574f0f3 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.h
@@ -99,6 +99,7 @@ protected: // Expr
void visit (HIR::WhileLetLoopExpr &expr) override;
void visit (HIR::IfExpr &expr) override;
void visit (HIR::IfExprConseqElse &expr) override;
+ void visit (HIR::InlineAsm &expr) override;
void visit (HIR::IfLetExpr &expr) override;
void visit (HIR::IfLetExprConseqElse &expr) override;
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h
index f47c41f..4df0e14 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-internal.h
@@ -76,8 +76,8 @@ struct BuilderContext
Resolver::Resolver &resolver;
// BIR output
- std::vector<BasicBlock> basic_blocks;
- size_t current_bb = 0;
+ BasicBlocks basic_blocks;
+ BasicBlockId current_bb = ENTRY_BASIC_BLOCK;
/**
* Allocation and lookup of places (variables, temporaries, paths, and
@@ -156,7 +156,7 @@ protected:
auto place_id = ctx.place_db.add_variable (nodeid, ty);
- if (ctx.place_db.get_current_scope_id () != 0)
+ if (ctx.place_db.get_current_scope_id () != INVALID_SCOPE)
push_storage_live (place_id);
if (user_type_annotation)
@@ -170,7 +170,7 @@ protected:
void pop_scope ()
{
auto &scope = ctx.place_db.get_current_scope ();
- if (ctx.place_db.get_current_scope_id () != 0)
+ if (ctx.place_db.get_current_scope_id () != INVALID_SCOPE)
{
std::for_each (scope.locals.rbegin (), scope.locals.rend (),
[&] (PlaceId place) { push_storage_dead (place); });
@@ -206,7 +206,7 @@ protected:
FreeRegions bind_regions (std::vector<TyTy::Region> regions,
FreeRegions parent_free_regions)
{
- std::vector<FreeRegion> free_regions;
+ FreeRegions free_regions;
for (auto &region : regions)
{
if (region.is_early_bound ())
@@ -215,7 +215,7 @@ protected:
}
else if (region.is_static ())
{
- free_regions.push_back (0);
+ free_regions.push_back (STATIC_FREE_REGION);
}
else if (region.is_anonymous ())
{
@@ -231,87 +231,95 @@ protected:
rust_unreachable ();
}
}
- // This is necesarry because of clash of current gcc and gcc4.8.
- FreeRegions free_regions_final{std::move (free_regions)};
- return free_regions_final;
+ return free_regions;
}
protected: // Helpers to add BIR statements
- void push_assignment (PlaceId lhs, AbstractExpr *rhs)
+ void push_assignment (PlaceId lhs, AbstractExpr *rhs, location_t location)
{
- ctx.get_current_bb ().statements.emplace_back (lhs, rhs);
+ ctx.get_current_bb ().statements.push_back (
+ Statement::make_assignment (lhs, rhs, location));
translated = lhs;
}
- void push_assignment (PlaceId lhs, PlaceId rhs)
+ void push_assignment (PlaceId lhs, PlaceId rhs, location_t location)
{
- push_assignment (lhs, new Assignment (rhs));
+ push_assignment (lhs, new Assignment (rhs), location);
}
- void push_tmp_assignment (AbstractExpr *rhs, TyTy::BaseType *tyty)
+ void push_tmp_assignment (AbstractExpr *rhs, TyTy::BaseType *tyty,
+ location_t location)
{
PlaceId tmp = ctx.place_db.add_temporary (tyty);
push_storage_live (tmp);
- push_assignment (tmp, rhs);
+ push_assignment (tmp, rhs, location);
}
- void push_tmp_assignment (PlaceId rhs)
+ void push_tmp_assignment (PlaceId rhs, location_t location)
{
- push_tmp_assignment (new Assignment (rhs), ctx.place_db[rhs].tyty);
+ push_tmp_assignment (new Assignment (rhs), ctx.place_db[rhs].tyty,
+ location);
}
- void push_switch (PlaceId switch_val,
+ void push_switch (PlaceId switch_val, location_t location,
std::initializer_list<BasicBlockId> destinations = {})
{
- auto copy = move_place (switch_val);
- ctx.get_current_bb ().statements.emplace_back (Statement::Kind::SWITCH,
- copy);
+ auto copy = move_place (switch_val, location);
+ ctx.get_current_bb ().statements.push_back (Statement::make_switch (copy));
ctx.get_current_bb ().successors.insert (
ctx.get_current_bb ().successors.end (), destinations);
}
void push_goto (BasicBlockId bb)
{
- ctx.get_current_bb ().statements.emplace_back (Statement::Kind::GOTO);
+ ctx.get_current_bb ().statements.push_back (Statement::make_goto ());
if (bb != INVALID_BB) // INVALID_BB means the goto will be resolved later.
ctx.get_current_bb ().successors.push_back (bb);
}
void push_storage_live (PlaceId place)
{
- ctx.get_current_bb ().statements.emplace_back (
- Statement::Kind::STORAGE_LIVE, place);
+ ctx.get_current_bb ().statements.push_back (
+ Statement::make_storage_live (place));
}
void push_storage_dead (PlaceId place)
{
- ctx.get_current_bb ().statements.emplace_back (
- Statement::Kind::STORAGE_DEAD, place);
+ ctx.get_current_bb ().statements.push_back (
+ Statement::make_storage_dead (place));
}
void push_user_type_ascription (PlaceId place, TyTy::BaseType *ty)
{
- ctx.get_current_bb ().statements.emplace_back (
- Statement::Kind::USER_TYPE_ASCRIPTION, place, ty);
+ ctx.get_current_bb ().statements.push_back (
+ Statement::make_user_type_ascription (place, ty));
}
void push_fake_read (PlaceId place)
{
- ctx.get_current_bb ().statements.emplace_back (Statement::Kind::FAKE_READ,
- place);
+ ctx.get_current_bb ().statements.push_back (
+ Statement::make_fake_read (place));
}
- PlaceId borrow_place (PlaceId place_id, TyTy::BaseType *ty)
+ void push_return (location_t location)
+ {
+ ctx.get_current_bb ().statements.push_back (
+ Statement::make_return (location));
+ }
+
+ PlaceId borrow_place (PlaceId place_id, TyTy::BaseType *ty,
+ location_t location)
{
auto mutability = ty->as<const TyTy::ReferenceType> ()->mutability ();
- auto loan = ctx.place_db.add_loan ({mutability, place_id});
- push_tmp_assignment (new BorrowExpr (place_id, loan,
- ctx.place_db.get_next_free_region ()),
- ty);
+ auto loan = ctx.place_db.add_loan ({mutability, place_id, location});
+ push_tmp_assignment (
+ new BorrowExpr (place_id, loan,
+ ctx.place_db.get_next_free_region ().value),
+ ty, location);
return translated;
}
- PlaceId move_place (PlaceId arg)
+ PlaceId move_place (PlaceId arg, location_t location)
{
auto &place = ctx.place_db[arg];
@@ -319,34 +327,38 @@ protected: // Helpers to add BIR statements
return arg;
if (place.tyty->is<TyTy::ReferenceType> ())
- return reborrow_place (arg);
+ return reborrow_place (arg, location);
if (place.is_rvalue ())
return arg;
- push_tmp_assignment (arg);
+ push_tmp_assignment (arg, location);
return translated;
}
- PlaceId reborrow_place (PlaceId arg)
+ PlaceId reborrow_place (PlaceId arg, location_t location)
{
auto ty = ctx.place_db[arg].tyty->as<TyTy::ReferenceType> ();
return borrow_place (ctx.place_db.lookup_or_add_path (Place::DEREF,
ty->get_base (), arg),
- ty);
+ ty, location);
}
- template <typename T> void move_all (T &args)
+ template <typename T>
+ void move_all (T &args, std::vector<location_t> locations)
{
- std::transform (args.begin (), args.end (), args.begin (),
- [this] (PlaceId arg) { return move_place (arg); });
+ rust_assert (args.size () == locations.size ());
+ std::transform (args.begin (), args.end (), locations.begin (),
+ args.begin (), [this] (PlaceId arg, location_t location) {
+ return move_place (arg, location);
+ });
}
protected: // CFG helpers
BasicBlockId new_bb ()
{
ctx.basic_blocks.emplace_back ();
- return ctx.basic_blocks.size () - 1;
+ return {ctx.basic_blocks.size () - 1};
}
BasicBlockId start_new_consecutive_bb ()
@@ -477,12 +489,15 @@ protected: // Implicit conversions.
{
if (ctx.place_db[translated].tyty->get_kind () != TyTy::REF)
{
+ // FIXME: not sure how to fetch correct location for this
+ // this function is unused yet, so can ignore for now
auto ty = ctx.place_db[translated].tyty;
translated
= borrow_place (translated,
new TyTy::ReferenceType (ty->get_ref (),
TyTy::TyVar (ty->get_ref ()),
- Mutability::Imm));
+ Mutability::Imm),
+ UNKNOWN_LOCATION);
}
}
};
@@ -531,16 +546,16 @@ protected:
* @param can_panic mark that expression can panic to insert jump to
* cleanup.
*/
- void return_expr (AbstractExpr *expr, TyTy::BaseType *ty,
+ void return_expr (AbstractExpr *expr, TyTy::BaseType *ty, location_t location,
bool can_panic = false)
{
if (expr_return_place != INVALID_PLACE)
{
- push_assignment (expr_return_place, expr);
+ push_assignment (expr_return_place, expr, location);
}
else
{
- push_tmp_assignment (expr, ty);
+ push_tmp_assignment (expr, ty, location);
}
if (can_panic)
@@ -556,12 +571,12 @@ protected:
}
/** Mark place to be a result of processed subexpression. */
- void return_place (PlaceId place, bool can_panic = false)
+ void return_place (PlaceId place, location_t location, bool can_panic = false)
{
if (expr_return_place != INVALID_PLACE)
{
// Return place is already allocated, no need to defer assignment.
- push_assignment (expr_return_place, place);
+ push_assignment (expr_return_place, place, location);
}
else
{
@@ -585,14 +600,16 @@ protected:
translated = ctx.place_db.get_constant (lookup_type (expr));
}
- PlaceId return_borrowed (PlaceId place_id, TyTy::BaseType *ty)
+ PlaceId return_borrowed (PlaceId place_id, TyTy::BaseType *ty,
+ location_t location)
{
// TODO: deduplicate with borrow_place
auto loan = ctx.place_db.add_loan (
- {ty->as<const TyTy::ReferenceType> ()->mutability (), place_id});
+ {ty->as<const TyTy::ReferenceType> ()->mutability (), place_id,
+ location});
return_expr (new BorrowExpr (place_id, loan,
- ctx.place_db.get_next_free_region ()),
- ty);
+ ctx.place_db.get_next_free_region ().value),
+ ty, location);
return translated;
}
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
index 11134c2..f499532 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
@@ -37,7 +37,8 @@ class LazyBooleanExprBuilder : public AbstractExprBuilder
public:
explicit LazyBooleanExprBuilder (BuilderContext &ctx,
PlaceId expr_return_place = INVALID_PLACE)
- : AbstractExprBuilder (ctx, expr_return_place), short_circuit_bb (0)
+ : AbstractExprBuilder (ctx, expr_return_place),
+ short_circuit_bb (ENTRY_BASIC_BLOCK)
{}
PlaceId build (HIR::LazyBooleanExpr &expr)
@@ -45,13 +46,14 @@ public:
PlaceId return_place = take_or_create_return_place (lookup_type (expr));
short_circuit_bb = new_bb ();
- push_assignment (return_place, visit_expr (expr));
+ push_assignment (return_place, visit_expr (expr), expr.get_locus ());
auto final_bb = new_bb ();
push_goto (final_bb);
ctx.current_bb = short_circuit_bb;
push_assignment (return_place,
- ctx.place_db.get_constant (lookup_type (expr)));
+ ctx.place_db.get_constant (lookup_type (expr)),
+ expr.get_locus ());
push_goto (final_bb);
ctx.current_bb = final_bb;
@@ -62,10 +64,11 @@ protected:
void visit (HIR::LazyBooleanExpr &expr) override
{
auto lhs = visit_expr (*expr.get_lhs ());
- push_switch (move_place (lhs), {short_circuit_bb});
+ push_switch (move_place (lhs, expr.get_lhs ()->get_locus ()),
+ expr.get_locus (), {short_circuit_bb});
start_new_consecutive_bb ();
- return_place (visit_expr (*expr.get_rhs ()));
+ return_place (visit_expr (*expr.get_rhs ()), expr.get_locus ());
}
void visit (HIR::GroupedExpr &expr) override
{
@@ -76,15 +79,15 @@ protected:
public:
void visit (HIR::QualifiedPathInExpression &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::PathInExpression &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::ClosureExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::StructExprStructFields &fields) override
{
@@ -96,121 +99,123 @@ public:
}
void visit (HIR::LiteralExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::BorrowExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::DereferenceExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::ErrorPropagationExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::NegationExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::ArithmeticOrLogicalExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::ComparisonExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::TypeCastExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::AssignmentExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::CompoundAssignmentExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::ArrayExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::ArrayIndexExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::TupleExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::TupleIndexExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::CallExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::MethodCallExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::FieldAccessExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::BlockExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::UnsafeBlockExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::LoopExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::WhileLoopExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::WhileLetLoopExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::IfExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::IfExprConseqElse &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::IfLetExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::IfLetExprConseqElse &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::MatchExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::AwaitExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
void visit (HIR::AsyncBlockExpr &expr) override
{
- return_place (ExprStmtBuilder (ctx).build (expr));
+ return_place (ExprStmtBuilder (ctx).build (expr), expr.get_locus ());
}
+ void visit (HIR::InlineAsm &expr) override {}
+
protected: // Illegal at this position.
void visit (HIR::StructExprFieldIdentifier &field) override
{
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
new file mode 100644
index 0000000..723ff73
--- /dev/null
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
@@ -0,0 +1,273 @@
+#include "rust-bir-builder-pattern.h"
+
+namespace Rust {
+namespace BIR {
+
+void
+PatternBindingBuilder::visit_identifier (const Analysis::NodeMapping &node,
+ bool is_ref, location_t location,
+ bool is_mut)
+{
+ if (is_ref)
+ {
+ translated = declare_variable (
+ node,
+ new TyTy::ReferenceType (node.get_hirid (),
+ TyTy::TyVar (node.get_hirid ()),
+ (is_mut) ? Mutability::Mut : Mutability::Imm));
+ }
+ else
+ {
+ translated = declare_variable (node);
+ }
+
+ if (init.has_value ())
+ {
+ push_assignment (translated, init.value (), location);
+ }
+}
+
+void
+PatternBindingBuilder::visit (HIR::IdentifierPattern &pattern)
+{
+ // Top-level identifiers are resolved directly to avoid useless temporary
+ // (for cleaner BIR).
+ visit_identifier (pattern.get_mappings (), pattern.get_is_ref (),
+ pattern.get_locus (), pattern.is_mut ());
+}
+
+void
+PatternBindingBuilder::visit (HIR::ReferencePattern &pattern)
+{
+ SavedState saved (this);
+
+ init = init.map ([&] (PlaceId id) {
+ return ctx.place_db.lookup_or_add_path (Place::DEREF, lookup_type (pattern),
+ id);
+ });
+
+ type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
+ return ty->as<TyTy::ReferenceType> ()->get_base ();
+ });
+
+ pattern.get_referenced_pattern ()->accept_vis (*this);
+}
+
+void
+PatternBindingBuilder::visit (HIR::SlicePattern &pattern)
+{
+ SavedState saved (this);
+
+ // All indexes are supposed to point to the same place for borrow-checking.
+ // init = ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type
+ // (pattern), saved.init);
+ init = init.map ([&] (PlaceId id) {
+ return ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type (pattern),
+ id);
+ });
+
+ type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
+ return ty->as<TyTy::SliceType> ()->get_element_type ();
+ });
+
+ // Regions are unchnaged.
+
+ for (auto &item : pattern.get_items ())
+ {
+ item->accept_vis (*this);
+ }
+}
+
+void
+PatternBindingBuilder::visit (HIR::AltPattern &pattern)
+{
+ rust_sorry_at (pattern.get_locus (),
+ "borrow-checking of alt patterns is not yet implemented");
+}
+
+void
+PatternBindingBuilder::visit (HIR::StructPattern &pattern)
+{
+ SavedState saved (this);
+
+ auto tyty = ctx.place_db[init.value ()].tyty;
+ rust_assert (tyty->get_kind () == TyTy::ADT);
+ auto adt_ty = static_cast<TyTy::ADTType *> (tyty);
+ rust_assert (adt_ty->is_struct_struct ());
+ auto struct_ty = adt_ty->get_variants ().at (0);
+
+ for (auto &field :
+ pattern.get_struct_pattern_elems ().get_struct_pattern_fields ())
+ {
+ switch (field->get_item_type ())
+ {
+ case HIR::StructPatternField::TUPLE_PAT: {
+ auto tuple
+ = static_cast<HIR::StructPatternFieldTuplePat *> (field.get ());
+
+ init = init.map ([&] (PlaceId id) {
+ return ctx.place_db.lookup_or_add_path (
+ Place::FIELD, lookup_type (*tuple->get_tuple_pattern ()), id,
+ tuple->get_index ());
+ });
+
+ type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
+ return ty->as<TyTy::ADTType> ()
+ ->get_variants ()
+ .at (0)
+ ->get_fields ()
+ .at (tuple->get_index ())
+ ->get_field_type ();
+ });
+
+ tuple->get_tuple_pattern ()->accept_vis (*this);
+ break;
+ }
+ case HIR::StructPatternField::IDENT_PAT: {
+ auto ident_field
+ = static_cast<HIR::StructPatternFieldIdentPat *> (field.get ());
+ TyTy::StructFieldType *field_ty = nullptr;
+ size_t field_index = 0;
+ auto ok = struct_ty->lookup_field (
+ ident_field->get_identifier ().as_string (), &field_ty,
+ &field_index);
+ rust_assert (ok);
+ init = ctx.place_db.lookup_or_add_path (Place::FIELD,
+ field_ty->get_field_type (),
+ saved.init.value (),
+ field_index);
+ ident_field->get_pattern ()->accept_vis (*this);
+ break;
+ }
+ case HIR::StructPatternField::IDENT: {
+ auto ident_field
+ = static_cast<HIR::StructPatternFieldIdent *> (field.get ());
+ TyTy::StructFieldType *field_ty = nullptr;
+ size_t field_index = 0;
+ auto ok = struct_ty->lookup_field (
+ ident_field->get_identifier ().as_string (), &field_ty,
+ &field_index);
+ rust_assert (ok);
+ init = ctx.place_db.lookup_or_add_path (Place::FIELD,
+ field_ty->get_field_type (),
+ saved.init.value (),
+ field_index);
+ visit_identifier (ident_field->get_mappings (),
+ ident_field->get_has_ref (),
+ ident_field->get_locus (),
+ ident_field->is_mut ());
+ break;
+ }
+ }
+ }
+}
+
+void
+PatternBindingBuilder::visit_tuple_fields (
+ std::vector<std::unique_ptr<HIR::Pattern>> &fields, SavedState &saved,
+ size_t &index)
+{
+ for (auto &item : fields)
+ {
+ auto type = lookup_type (*item);
+
+ init = init.map ([&] (PlaceId id) {
+ return ctx.place_db.lookup_or_add_path (Place::FIELD, type, id, index);
+ });
+
+ type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
+ return ty->as<TyTy::TupleType> ()->get_fields ().at (index).get_tyty ();
+ });
+
+ regions = regions.map ([&] (FreeRegions regs) {
+ return bind_regions (Resolver::TypeCheckContext::get ()
+ ->get_variance_analysis_ctx ()
+ .query_type_regions (type),
+ regs);
+ });
+
+ item->accept_vis (*this);
+ index++;
+ }
+}
+
+void
+PatternBindingBuilder::visit (HIR::TuplePattern &pattern)
+{
+ SavedState saved (this);
+
+ size_t index = 0;
+ switch (pattern.get_items ()->get_item_type ())
+ {
+ case HIR::TuplePatternItems::MULTIPLE: {
+ auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
+ *pattern.get_items ());
+ visit_tuple_fields (items.get_patterns (), saved, index);
+ break;
+ }
+ case HIR::TuplePatternItems::RANGED: {
+ auto &items
+ = static_cast<HIR::TuplePatternItemsRanged &> (*pattern.get_items ());
+
+ auto tyty = ctx.place_db[init.value ()].tyty;
+ rust_assert (tyty->get_kind () == TyTy::TUPLE);
+
+ auto skipped = (static_cast<TyTy::TupleType *> (tyty))->num_fields ()
+ - items.get_lower_patterns ().size ()
+ - items.get_upper_patterns ().size ();
+
+ visit_tuple_fields (items.get_lower_patterns (), saved, index);
+ index += skipped;
+ visit_tuple_fields (items.get_upper_patterns (), saved, index);
+ break;
+ }
+ }
+ init = saved.init;
+}
+
+void
+PatternBindingBuilder::visit (HIR::TupleStructPattern &pattern)
+{
+ SavedState saved (this);
+
+ type_annotation = tl::nullopt;
+
+ auto type = lookup_type (pattern);
+
+ regions = regions.map ([&] (FreeRegions regs) {
+ return bind_regions (Resolver::TypeCheckContext::get ()
+ ->get_variance_analysis_ctx ()
+ .query_type_regions (type),
+ regs);
+ });
+
+ size_t index = 0;
+ switch (pattern.get_items ()->get_item_type ())
+ {
+ case HIR::TupleStructItems::RANGED: {
+ auto &items
+ = static_cast<HIR::TupleStructItemsRange &> (*pattern.get_items ());
+
+ rust_assert (type->get_kind () == TyTy::ADT);
+ auto adt_ty = static_cast<TyTy::ADTType *> (type);
+ rust_assert (adt_ty->is_tuple_struct ());
+
+ auto skipped = adt_ty->get_variants ().at (0)->get_fields ().size ()
+ - items.get_lower_patterns ().size ()
+ - items.get_upper_patterns ().size ();
+
+ visit_tuple_fields (items.get_lower_patterns (), saved, index);
+ index += skipped;
+ visit_tuple_fields (items.get_upper_patterns (), saved, index);
+ break;
+ }
+ case HIR::TupleStructItems::MULTIPLE: {
+ auto &items
+ = static_cast<HIR::TupleStructItemsNoRange &> (*pattern.get_items ());
+ visit_tuple_fields (items.get_patterns (), saved, index);
+ break;
+ }
+ }
+}
+} // namespace BIR
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h
index f704f77..5d4b85a 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.h
@@ -65,265 +65,24 @@ public:
void go (HIR::Pattern &pattern) { pattern.accept_vis (*this); }
void visit_identifier (const Analysis::NodeMapping &node, bool is_ref,
- bool is_mut = false)
- {
- if (is_ref)
- {
- translated = declare_variable (
- node, new TyTy::ReferenceType (node.get_hirid (),
- TyTy::TyVar (node.get_hirid ()),
- (is_mut) ? Mutability::Mut
- : Mutability::Imm));
- }
- else
- {
- translated = declare_variable (node);
- }
-
- if (init.has_value ())
- {
- push_assignment (translated, init.value ());
- }
- }
-
- void visit (HIR::IdentifierPattern &pattern) override
- {
- // Top-level identifiers are resolved directly to avoid useless temporary
- // (for cleaner BIR).
- visit_identifier (pattern.get_mappings (), pattern.get_is_ref (),
- pattern.is_mut ());
- }
-
- void visit (HIR::ReferencePattern &pattern) override
- {
- SavedState saved (this);
-
- init = init.map ([&] (PlaceId id) {
- return ctx.place_db.lookup_or_add_path (Place::DEREF,
- lookup_type (pattern), id);
- });
-
- type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
- return ty->as<TyTy::ReferenceType> ()->get_base ();
- });
-
- pattern.get_referenced_pattern ()->accept_vis (*this);
- }
-
- void visit (HIR::SlicePattern &pattern) override
- {
- SavedState saved (this);
-
- // All indexes are supposed to point to the same place for borrow-checking.
- // init = ctx.place_db.lookup_or_add_path (Place::INDEX, lookup_type
- // (pattern), saved.init);
- init = init.map ([&] (PlaceId id) {
- return ctx.place_db.lookup_or_add_path (Place::INDEX,
- lookup_type (pattern), id);
- });
-
- type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
- return ty->as<TyTy::SliceType> ()->get_element_type ();
- });
-
- // Regions are unchnaged.
-
- for (auto &item : pattern.get_items ())
- {
- item->accept_vis (*this);
- }
- }
-
- void visit (HIR::AltPattern &pattern) override
- {
- rust_sorry_at (pattern.get_locus (),
- "borrow-checking of alt patterns is not yet implemented");
- }
-
- void visit (HIR::StructPattern &pattern) override
- {
- SavedState saved (this);
+ location_t location, bool is_mut = false);
- auto tyty = ctx.place_db[init.value ()].tyty;
- rust_assert (tyty->get_kind () == TyTy::ADT);
- auto adt_ty = static_cast<TyTy::ADTType *> (tyty);
- rust_assert (adt_ty->is_struct_struct ());
- auto struct_ty = adt_ty->get_variants ().at (0);
+ void visit (HIR::IdentifierPattern &pattern) override;
- for (auto &field :
- pattern.get_struct_pattern_elems ().get_struct_pattern_fields ())
- {
- switch (field->get_item_type ())
- {
- case HIR::StructPatternField::TUPLE_PAT: {
- auto tuple
- = static_cast<HIR::StructPatternFieldTuplePat *> (field.get ());
+ void visit (HIR::ReferencePattern &pattern) override;
- init = init.map ([&] (PlaceId id) {
- return ctx.place_db.lookup_or_add_path (
- Place::FIELD, lookup_type (*tuple->get_tuple_pattern ()), id,
- tuple->get_index ());
- });
+ void visit (HIR::SlicePattern &pattern) override;
- type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
- return ty->as<TyTy::ADTType> ()
- ->get_variants ()
- .at (0)
- ->get_fields ()
- .at (tuple->get_index ())
- ->get_field_type ();
- });
+ void visit (HIR::AltPattern &pattern) override;
- tuple->get_tuple_pattern ()->accept_vis (*this);
- break;
- }
- case HIR::StructPatternField::IDENT_PAT: {
- auto ident_field
- = static_cast<HIR::StructPatternFieldIdentPat *> (field.get ());
- TyTy::StructFieldType *field_ty = nullptr;
- size_t field_index = 0;
- auto ok = struct_ty->lookup_field (
- ident_field->get_identifier ().as_string (), &field_ty,
- &field_index);
- rust_assert (ok);
- init
- = ctx.place_db.lookup_or_add_path (Place::FIELD,
- field_ty->get_field_type (),
- saved.init.value (),
- field_index);
- ident_field->get_pattern ()->accept_vis (*this);
- break;
- }
- case HIR::StructPatternField::IDENT: {
- auto ident_field
- = static_cast<HIR::StructPatternFieldIdent *> (field.get ());
- TyTy::StructFieldType *field_ty = nullptr;
- size_t field_index = 0;
- auto ok = struct_ty->lookup_field (
- ident_field->get_identifier ().as_string (), &field_ty,
- &field_index);
- rust_assert (ok);
- init
- = ctx.place_db.lookup_or_add_path (Place::FIELD,
- field_ty->get_field_type (),
- saved.init.value (),
- field_index);
- visit_identifier (ident_field->get_mappings (),
- ident_field->get_has_ref (),
- ident_field->is_mut ());
- break;
- }
- }
- }
- }
+ void visit (HIR::StructPattern &pattern) override;
void visit_tuple_fields (std::vector<std::unique_ptr<HIR::Pattern>> &fields,
- SavedState &saved, size_t &index)
- {
- for (auto &item : fields)
- {
- auto type = lookup_type (*item);
-
- init = init.map ([&] (PlaceId id) {
- return ctx.place_db.lookup_or_add_path (Place::FIELD, type, id,
- index);
- });
-
- type_annotation = type_annotation.map ([&] (TyTy::BaseType *ty) {
- return ty->as<TyTy::TupleType> ()
- ->get_fields ()
- .at (index)
- .get_tyty ();
- });
-
- regions = regions.map ([&] (FreeRegions regs) {
- return bind_regions (Resolver::TypeCheckContext::get ()
- ->get_variance_analysis_ctx ()
- .query_type_regions (type),
- regs);
- });
-
- item->accept_vis (*this);
- index++;
- }
- }
-
- void visit (HIR::TuplePattern &pattern) override
- {
- SavedState saved (this);
-
- size_t index = 0;
- switch (pattern.get_items ()->get_item_type ())
- {
- case HIR::TuplePatternItems::MULTIPLE: {
- auto &items = static_cast<HIR::TuplePatternItemsMultiple &> (
- *pattern.get_items ());
- visit_tuple_fields (items.get_patterns (), saved, index);
- break;
- }
- case HIR::TuplePatternItems::RANGED: {
- auto &items = static_cast<HIR::TuplePatternItemsRanged &> (
- *pattern.get_items ());
-
- auto tyty = ctx.place_db[init.value ()].tyty;
- rust_assert (tyty->get_kind () == TyTy::TUPLE);
-
- auto skipped = (static_cast<TyTy::TupleType *> (tyty))->num_fields ()
- - items.get_lower_patterns ().size ()
- - items.get_upper_patterns ().size ();
-
- visit_tuple_fields (items.get_lower_patterns (), saved, index);
- index += skipped;
- visit_tuple_fields (items.get_upper_patterns (), saved, index);
- break;
- }
- }
- init = saved.init;
- }
-
- void visit (HIR::TupleStructPattern &pattern) override
- {
- SavedState saved (this);
-
- type_annotation = tl::nullopt;
-
- auto type = lookup_type (pattern);
-
- regions = regions.map ([&] (FreeRegions regs) {
- return bind_regions (Resolver::TypeCheckContext::get ()
- ->get_variance_analysis_ctx ()
- .query_type_regions (type),
- regs);
- });
-
- size_t index = 0;
- switch (pattern.get_items ()->get_item_type ())
- {
- case HIR::TupleStructItems::RANGED: {
- auto &items
- = static_cast<HIR::TupleStructItemsRange &> (*pattern.get_items ());
-
- rust_assert (type->get_kind () == TyTy::ADT);
- auto adt_ty = static_cast<TyTy::ADTType *> (type);
- rust_assert (adt_ty->is_tuple_struct ());
+ SavedState &saved, size_t &index);
- auto skipped = adt_ty->get_variants ().at (0)->get_fields ().size ()
- - items.get_lower_patterns ().size ()
- - items.get_upper_patterns ().size ();
+ void visit (HIR::TuplePattern &pattern) override;
- visit_tuple_fields (items.get_lower_patterns (), saved, index);
- index += skipped;
- visit_tuple_fields (items.get_upper_patterns (), saved, index);
- break;
- }
- case HIR::TupleStructItems::MULTIPLE: {
- auto &items = static_cast<HIR::TupleStructItemsNoRange &> (
- *pattern.get_items ());
- visit_tuple_fields (items.get_patterns (), saved, index);
- break;
- }
- }
- }
+ void visit (HIR::TupleStructPattern &pattern) override;
void visit (HIR::WildcardPattern &pattern) override {}
// Unused for binding.
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h
index bafa22b4..63d3262 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder.h
@@ -50,6 +50,8 @@ public:
handle_param (param);
handle_body (*function.get_definition ());
+ auto region_hir_map
+ = map_region_to_hir (function.get_generic_params (), ctx.fn_free_regions);
return Function{
std::move (ctx.place_db),
@@ -57,6 +59,7 @@ public:
std::move (ctx.basic_blocks),
std::move (ctx.fn_free_regions),
std::move (universal_region_bounds),
+ std::move (region_hir_map),
function.get_locus (),
};
}
@@ -65,15 +68,15 @@ private:
/** Instantiate `num_lifetime_params` free regions. */
void handle_lifetime_params (size_t num_lifetime_params)
{
- std::vector<FreeRegion> function_free_regions;
+ FreeRegions regions;
for (size_t i = 0; i < num_lifetime_params; i++)
{
- function_free_regions.push_back (ctx.place_db.get_next_free_region ());
+ regions.push_back (ctx.place_db.get_next_free_region ());
}
rust_debug ("\tctx.fn_free_region={%s}",
ctx.fn_free_regions.to_string ().c_str ());
- ctx.fn_free_regions.set_from (std::move (function_free_regions));
+ ctx.fn_free_regions = regions;
}
void handle_lifetime_param_constraints (
@@ -91,8 +94,8 @@ private:
ctx.fn_free_regions[bound.second.get_index ()]);
auto last_bound = universal_region_bounds.back ();
- rust_debug ("\t\t %lu: %lu", (unsigned long) last_bound.first,
- (unsigned long) last_bound.second);
+ rust_debug ("\t\t %lu: %lu", (unsigned long) last_bound.first.value,
+ (unsigned long) last_bound.second.value);
}
// TODO: handle type_region constraints
@@ -152,11 +155,35 @@ private:
{
push_assignment (RETURN_VALUE_PLACE,
ctx.place_db.get_constant (
- ctx.place_db[RETURN_VALUE_PLACE].tyty));
+ ctx.place_db[RETURN_VALUE_PLACE].tyty),
+ body.get_end_locus ());
}
- ctx.get_current_bb ().statements.emplace_back (Statement::Kind::RETURN);
+ auto return_location = body.has_expr ()
+ ? body.get_final_expr ()->get_locus ()
+ : body.get_end_locus ();
+ push_return (return_location);
}
}
+
+ // Maps named lifetime parameters to their respective HIR node
+ const std::unordered_map<Polonius::Origin, HIR::LifetimeParam *>
+ map_region_to_hir (
+ const std::vector<std::unique_ptr<HIR::GenericParam>> &generic_params,
+ const FreeRegions &regions)
+ {
+ std::unordered_map<Polonius::Origin, HIR::LifetimeParam *> result;
+ size_t region_index = 0;
+ for (auto &generic_param : generic_params)
+ {
+ if (generic_param->get_kind ()
+ == HIR::GenericParam::GenericKind::LIFETIME)
+ {
+ result[regions[region_index++].value]
+ = static_cast<HIR::LifetimeParam *> (generic_param.get ());
+ }
+ }
+ return result;
+ }
};
} // namespace BIR
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc
index a35f47b..3864b81 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-dump.cc
@@ -53,21 +53,25 @@ renumber_places (const Function &func, std::vector<PlaceId> &place_map)
{
// Renumbering places to avoid gaps in the place id space.
// This is needed to match MIR's shape.
- size_t next_out_id = 0;
+ PlaceId next_out_id = INVALID_PLACE;
- for (size_t in_id = FIRST_VARIABLE_PLACE; in_id < func.place_db.size ();
- ++in_id)
+ for (PlaceId in_id = FIRST_VARIABLE_PLACE;
+ in_id.value < func.place_db.size (); ++in_id.value)
{
const Place &place = func.place_db[in_id];
if (place.kind == Place::VARIABLE || place.kind == Place::TEMPORARY)
- place_map[in_id] = next_out_id++;
+ {
+ place_map[in_id.value] = next_out_id;
+ ++next_out_id.value;
+ }
+
else
- place_map[in_id] = INVALID_PLACE;
+ place_map[in_id.value] = INVALID_PLACE;
}
}
void
-simplify_cfg (Function &func, std::vector<BasicBlockId> &bb_fold_map)
+simplify_cfg (Function &func, IndexVec<BasicBlockId, BasicBlockId> &bb_fold_map)
{
// The BIR builder can generate many useless basic blocks, which contain only
// a goto.
@@ -78,7 +82,7 @@ simplify_cfg (Function &func, std::vector<BasicBlockId> &bb_fold_map)
{
stabilized = true;
// BB0 cannot be folded as it is an entry block.
- for (size_t i = 1; i < func.basic_blocks.size (); ++i)
+ for (BasicBlockId i = {1}; i.value < func.basic_blocks.size (); ++i.value)
{
const BasicBlock &bb = func.basic_blocks[bb_fold_map[i]];
if (bb.statements.empty () && bb.is_goto_terminated ())
@@ -93,7 +97,11 @@ simplify_cfg (Function &func, std::vector<BasicBlockId> &bb_fold_map)
rust_inform (UNKNOWN_LOCATION,
"Continuing with an unfolded CFG.");
// Reverting the fold map to the original state.
- std::iota (bb_fold_map.begin (), bb_fold_map.end (), 0);
+ for (BasicBlockId i = ENTRY_BASIC_BLOCK;
+ i.value < bb_fold_map.size (); ++i.value)
+ {
+ bb_fold_map[i] = i;
+ }
stabilized = true;
break;
}
@@ -108,9 +116,15 @@ void
Dump::go (bool enable_simplify_cfg)
{
// To avoid mutation of the BIR, we use indirection through bb_fold_map.
- std::iota (bb_fold_map.begin (), bb_fold_map.end (), 0);
-
- std::iota (place_map.begin (), place_map.end (), 0);
+ for (BasicBlockId i = ENTRY_BASIC_BLOCK; i.value < bb_fold_map.size ();
+ ++i.value)
+ {
+ bb_fold_map[i] = i;
+ }
+ for (PlaceId i = INVALID_PLACE; i.value < place_map.size (); ++i.value)
+ {
+ place_map[i] = i;
+ }
if (enable_simplify_cfg)
simplify_cfg (func, bb_fold_map);
@@ -119,18 +133,18 @@ Dump::go (bool enable_simplify_cfg)
stream << "fn " << name << "(";
print_comma_separated (stream, func.arguments, [this] (PlaceId place_id) {
- stream << "_" << place_map[place_id] << ": "
+ stream << "_" << place_map[place_id].value << ": "
<< get_tyty_name (func.place_db[place_id].tyty);
});
stream << ") -> " << get_tyty_name (func.place_db[RETURN_VALUE_PLACE].tyty);
stream << " {\n";
// Print locals declaration.
- visit_scope (0);
+ visit_scope (ROOT_SCOPE);
// Print BBs.
- for (statement_bb = 0; statement_bb < func.basic_blocks.size ();
- ++statement_bb)
+ for (statement_bb = ENTRY_BASIC_BLOCK;
+ statement_bb.value < func.basic_blocks.size (); ++statement_bb.value)
{
if (bb_fold_map[statement_bb] != statement_bb)
continue; // This BB was folded.
@@ -143,7 +157,8 @@ Dump::go (bool enable_simplify_cfg)
BasicBlock &bb = func.basic_blocks[statement_bb];
stream << "\n";
- stream << indentation << "bb" << bb_fold_map[statement_bb] << ": {\n";
+ stream << indentation << "bb" << bb_fold_map[statement_bb].value
+ << ": {\n";
size_t i = 0;
for (auto &stmt : bb.statements)
{
@@ -153,7 +168,8 @@ Dump::go (bool enable_simplify_cfg)
}
if (!bb_terminated)
stream << indentation << indentation << "goto -> bb"
- << bb_fold_map[bb.successors.at (0)] << ";\t\t" << i++ << "\n";
+ << bb_fold_map[bb.successors.at (0)].value << ";\t\t" << i++
+ << "\n";
stream << indentation << "}\n";
}
@@ -178,7 +194,7 @@ Dump::visit (const Statement &stmt)
stream << ") -> [";
print_comma_separated (stream, func.basic_blocks[statement_bb].successors,
[this] (BasicBlockId succ) {
- stream << "bb" << bb_fold_map[succ];
+ stream << "bb" << bb_fold_map[succ].value;
});
stream << "]";
bb_terminated = true;
@@ -188,8 +204,9 @@ Dump::visit (const Statement &stmt)
bb_terminated = true;
break;
case Statement::Kind::GOTO:
- stream << "goto -> bb"
- << bb_fold_map[func.basic_blocks[statement_bb].successors.at (0)];
+ stream
+ << "goto -> bb"
+ << bb_fold_map[func.basic_blocks[statement_bb].successors.at (0)].value;
bb_terminated = true;
break;
case Statement::Kind::STORAGE_DEAD:
@@ -228,7 +245,7 @@ Dump::visit_place (PlaceId place_id)
{
case Place::TEMPORARY:
case Place::VARIABLE:
- stream << "_" << place_map[place_id];
+ stream << "_" << place_map[place_id].value;
break;
case Place::DEREF:
stream << "(";
@@ -272,7 +289,7 @@ Dump::visit (const BorrowExpr &expr)
{
stream << "&"
<< "'?" << expr.get_origin () << " ";
- if (func.place_db.get_loans ()[expr.get_loan ()].mutability
+ if (func.place_db.get_loan (expr.get_loan_id ()).mutability
== Mutability::Mut)
stream << "mut ";
visit_place (expr.get_place ());
@@ -311,7 +328,7 @@ Dump::visit (const CallExpr &expr)
stream << ") -> [";
print_comma_separated (stream, func.basic_blocks[statement_bb].successors,
[this] (BasicBlockId succ) {
- stream << "bb" << bb_fold_map[succ];
+ stream << "bb" << bb_fold_map[succ].value;
});
stream << "]";
bb_terminated = true;
@@ -359,13 +376,13 @@ Dump::visit_scope (ScopeId id, size_t depth)
if (scope.locals.empty () && scope.children.empty ())
return;
- if (id > 1)
- indent (depth) << "scope " << id - 1 << " {\n";
+ if (id.value > 1)
+ indent (depth) << "scope " << id.value - 1 << " {\n";
for (auto &local : scope.locals)
{
indent (depth + 1) << "let _";
- stream << place_map[local] << ": "
+ stream << place_map[local].value << ": "
<< get_tyty_name (func.place_db[local].tyty);
stream << ";\t";
@@ -373,14 +390,14 @@ Dump::visit_scope (ScopeId id, size_t depth)
print_comma_separated (stream,
func.place_db[local].regions.get_regions (),
[this] (FreeRegion region_id) {
- stream << "'?" << region_id;
+ stream << "'?" << region_id.value;
});
stream << "]\n";
}
for (auto &child : scope.children)
- visit_scope (child, (id >= 1) ? depth + 1 : depth);
+ visit_scope (child, (id.value >= 1) ? depth + 1 : depth);
- if (id > 1)
+ if (id.value > 1)
indent (depth) << "}\n";
}
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-dump.h b/gcc/rust/checks/errors/borrowck/rust-bir-dump.h
index e88681f..1bf3f2d 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-dump.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-dump.h
@@ -34,8 +34,8 @@ class Dump : public Visitor
Function &func;
const std::string &name;
- std::vector<BasicBlockId> bb_fold_map;
- std::vector<PlaceId> place_map;
+ IndexVec<BasicBlockId, BasicBlockId> bb_fold_map;
+ IndexVec<PlaceId, PlaceId> place_map;
PlaceId statement_place = INVALID_PLACE;
BasicBlockId statement_bb = INVALID_BB;
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h
index 9999bdd..1332ecf 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-fact-collector.h
@@ -40,14 +40,14 @@ class FactCollector : public Visitor
// Read-only context.
const PlaceDB &place_db;
- const std::vector<BasicBlock> &basic_blocks;
+ const BasicBlocks &basic_blocks;
const PlaceId first_local;
const location_t location;
Resolver::TypeCheckContext &tyctx;
// Collector state.
- BasicBlockId current_bb = 0;
+ BasicBlockId current_bb = ENTRY_BASIC_BLOCK;
uint32_t current_stmt = 0;
PlaceId lhs = INVALID_PLACE;
@@ -65,11 +65,11 @@ class FactCollector : public Visitor
FreeRegions make_fresh_regions (size_t size)
{
- std::vector<FreeRegion> free_regions;
+ FreeRegions free_regions;
for (size_t i = 0; i < size; i++)
free_regions.push_back (region_binder.get_next_free_region ());
- return FreeRegions (std::move (free_regions));
+ return free_regions;
}
public:
@@ -88,8 +88,9 @@ public:
protected: // Constructor and destructor.
explicit FactCollector (Function &func)
: place_db (func.place_db), basic_blocks (func.basic_blocks),
- first_local (func.arguments.empty () ? FIRST_VARIABLE_PLACE
- : *func.arguments.rbegin () + 1),
+ first_local (func.arguments.empty ()
+ ? FIRST_VARIABLE_PLACE
+ : PlaceId{func.arguments.rbegin ()->value + 1}),
location (func.location), tyctx (*Resolver::TypeCheckContext::get ()),
next_fresh_region (place_db.peek_next_free_region ())
{}
@@ -106,19 +107,21 @@ protected: // Main collection entry points (for different categories).
for (auto &region : universal_regions)
{
- facts.universal_region.emplace_back (region);
- facts.placeholder.emplace_back (region, next_loan++);
- facts.known_placeholder_subset.emplace_back (0, region);
+ facts.universal_region.emplace_back (region.value);
+ facts.placeholder.emplace_back (region.value, next_loan++);
+ facts.known_placeholder_subset.emplace_back (0, region.value);
}
// Copy already collected subset facts, that are universally valid.
for (auto &bound : universal_region_bounds)
- facts.known_placeholder_subset.emplace_back (bound.first, bound.second);
+ facts.known_placeholder_subset.emplace_back (bound.first.value,
+ bound.second.value);
}
void visit_places (const std::vector<PlaceId> &args)
{
- for (PlaceId place_id = 0; place_id < place_db.size (); ++place_id)
+ for (PlaceId place_id = INVALID_PLACE; place_id.value < place_db.size ();
+ ++place_id.value)
{
auto &place = place_db[place_id];
@@ -126,24 +129,28 @@ protected: // Main collection entry points (for different categories).
{
case Place::VARIABLE:
case Place::TEMPORARY:
- facts.path_is_var.emplace_back (place_id, place_id);
+ facts.path_is_var.emplace_back (place_id.value, place_id.value);
for (auto &region : place.regions)
- facts.use_of_var_derefs_origin.emplace_back (place_id, region);
+ facts.use_of_var_derefs_origin.emplace_back (place_id.value,
+ region.value);
// TODO: drop_of_var_derefs_origin
break;
case Place::FIELD:
sanizite_field (place_id);
- facts.child_path.emplace_back (place_id, place.path.parent);
+ facts.child_path.emplace_back (place_id.value,
+ place.path.parent.value);
break;
case Place::INDEX:
push_subset_all (place.tyty, place.regions,
place_db[place.path.parent].regions);
- facts.child_path.emplace_back (place_id, place.path.parent);
+ facts.child_path.emplace_back (place_id.value,
+ place.path.parent.value);
break;
case Place::DEREF:
sanitize_deref (place_id);
- facts.child_path.emplace_back (place_id, place.path.parent);
+ facts.child_path.emplace_back (place_id.value,
+ place.path.parent.value);
break;
case Place::CONSTANT:
case Place::INVALID:
@@ -151,15 +158,18 @@ protected: // Main collection entry points (for different categories).
}
}
- for (PlaceId arg = FIRST_VARIABLE_PLACE + 1; arg < first_local; ++arg)
+ for (PlaceId arg = PlaceId{FIRST_VARIABLE_PLACE.value + 1};
+ arg < first_local; ++arg.value)
facts.path_assigned_at_base.emplace_back (
- arg, get_point (0, 0, PointPosition::START));
+ arg.value, get_point (ENTRY_BASIC_BLOCK, 0, PointPosition::START));
- for (PlaceId place = first_local; place < place_db.size (); ++place)
+ for (PlaceId place = first_local; place.value < place_db.size ();
+ ++place.value)
{
if (place_db[place].is_var ())
facts.path_moved_at_base.emplace_back (
- place, get_point (0, 0, PointPosition::START));
+ place.value,
+ get_point (ENTRY_BASIC_BLOCK, 0, PointPosition::START));
}
}
@@ -170,11 +180,12 @@ protected: // Main collection entry points (for different categories).
rust_debug ("\tSanitize deref of %s", base.tyty->as_string ().c_str ());
- std::vector<Polonius::Origin> regions;
- regions.insert (regions.end (), base.regions.begin () + 1,
- base.regions.end ());
- FreeRegions r (std::move (regions));
- push_subset_all (place.tyty, r, place.regions);
+ FreeRegions regions;
+ for (auto it = base.regions.begin () + 1; it != base.regions.end (); ++it)
+ {
+ regions.push_back (*it);
+ }
+ push_subset_all (place.tyty, regions, place.regions);
}
void sanizite_field (PlaceId place_id)
{
@@ -191,15 +202,15 @@ protected: // Main collection entry points (for different categories).
.query_field_regions (base.tyty->as<TyTy::ADTType> (), 0,
place.variable_or_field_index,
base.regions); // FIXME
- FreeRegions f (std::move (r));
- push_subset_all (place.tyty, f, place.regions);
+ push_subset_all (place.tyty, r, place.regions);
}
void visit_statemensts ()
{
rust_debug ("visit_statemensts");
- for (current_bb = 0; current_bb < basic_blocks.size (); ++current_bb)
+ for (current_bb = ENTRY_BASIC_BLOCK;
+ current_bb.value < basic_blocks.size (); ++current_bb.value)
{
auto &bb = basic_blocks[current_bb];
for (current_stmt = 0; current_stmt < bb.statements.size ();
@@ -213,7 +224,7 @@ protected: // Main collection entry points (for different categories).
visit (bb.statements[current_stmt]);
}
}
- current_bb = 0;
+ current_bb = ENTRY_BASIC_BLOCK;
current_stmt = 0;
}
@@ -242,9 +253,9 @@ protected: // Main collection entry points (for different categories).
break;
}
case Statement::Kind::STORAGE_DEAD: {
- facts.path_moved_at_base.emplace_back (stmt.get_place (),
+ facts.path_moved_at_base.emplace_back (stmt.get_place ().value,
get_current_point_mid ());
- facts.var_defined_at.emplace_back (stmt.get_place (),
+ facts.var_defined_at.emplace_back (stmt.get_place ().value,
get_current_point_mid ());
break;
}
@@ -293,9 +304,10 @@ protected: // Main collection entry points (for different categories).
void visit (const BorrowExpr &expr) override
{
- rust_debug ("\t_%u = BorrowExpr(_%u)", lhs - 1, expr.get_place () - 1);
+ rust_debug ("\t_%u = BorrowExpr(_%u)", lhs.value - 1,
+ expr.get_place ().value - 1);
- auto loan = place_db.get_loans ()[expr.get_loan ()];
+ auto loan = place_db.get_loan (expr.get_loan_id ());
auto &base_place = place_db[expr.get_place ()];
auto &ref_place = place_db[lhs];
@@ -314,24 +326,24 @@ protected: // Main collection entry points (for different categories).
->is_mutable ())
rust_error_at (location,
"Cannot reborrow immutable borrow as mutable");
- issue_loan (expr.get_origin (), expr.get_loan ());
+ issue_loan (expr.get_origin (), expr.get_loan_id ());
}
- push_subset (main_loan_place.regions[0], expr.get_origin ());
+ push_subset (main_loan_place.regions[0], {expr.get_origin ()});
}
else
{
- issue_loan (expr.get_origin (), expr.get_loan ());
+ issue_loan (expr.get_origin (), expr.get_loan_id ());
}
- auto loan_regions = base_place.regions.prepend (expr.get_origin ());
+ auto loan_regions = base_place.regions.prepend ({expr.get_origin ()});
push_subset (ref_place.tyty, loan_regions, ref_place.regions);
}
void visit (const Assignment &expr) override
{
- rust_debug ("\t_%u = Assignment(_%u) at %u:%u", lhs - 1,
- expr.get_rhs () - 1, current_bb, current_stmt);
+ rust_debug ("\t_%u = Assignment(_%u) at %u:%u", lhs.value - 1,
+ expr.get_rhs ().value - 1, current_bb.value, current_stmt);
issue_read_move (expr.get_rhs ());
push_place_subset (lhs, expr.get_rhs ());
@@ -339,7 +351,8 @@ protected: // Main collection entry points (for different categories).
void visit (const CallExpr &expr) override
{
- rust_debug ("\t_%u = CallExpr(_%u)", lhs - 1, expr.get_callable () - 1);
+ rust_debug ("\t_%u = CallExpr(_%u)", lhs.value - 1,
+ expr.get_callable ().value - 1);
auto &return_place = place_db[lhs];
auto &callable_place = place_db[expr.get_callable ()];
@@ -387,7 +400,7 @@ protected: // Statement visitor helpers
get_point (BasicBlockId bb, uint32_t stmt, PointPosition pos)
{
Polonius::Point point = 0;
- point |= (bb << 16);
+ point |= (bb.value << 16);
point |= (stmt << 1);
point |= (static_cast<uint8_t> (pos) & 1);
return point;
@@ -434,14 +447,14 @@ protected: // Generic BIR operations.
return;
if (place_id != RETURN_VALUE_PLACE)
- facts.path_accessed_at_base.emplace_back (place_id,
+ facts.path_accessed_at_base.emplace_back (place_id.value,
get_current_point_mid ());
if (place.is_var ())
- facts.var_used_at.emplace_back (place_id, get_current_point_mid ());
+ facts.var_used_at.emplace_back (place_id.value, get_current_point_mid ());
else if (place.is_path ())
{
- facts.var_used_at.emplace_back (place_db.get_var (place_id),
+ facts.var_used_at.emplace_back (place_db.get_var (place_id).value,
get_current_point_mid ());
}
}
@@ -468,11 +481,12 @@ protected: // Generic BIR operations.
rust_assert (place.is_lvalue () || place.is_rvalue ());
if (place.is_var ())
- facts.var_defined_at.emplace_back (place_id, get_current_point_mid ());
+ facts.var_defined_at.emplace_back (place_id.value,
+ get_current_point_mid ());
if (!is_init)
{
- facts.path_assigned_at_base.emplace_back (place_id,
+ facts.path_assigned_at_base.emplace_back (place_id.value,
get_current_point_mid ());
check_write_for_conflict (place_id);
kill_borrows_for_place (place_id);
@@ -484,9 +498,11 @@ protected: // Generic BIR operations.
if (!place_db[place_id].should_be_moved ())
return;
- facts.path_moved_at_base.emplace_back (
- place_id, initial ? get_point (0, 0, PointPosition::START)
- : get_current_point_mid ());
+ facts.path_moved_at_base.emplace_back (place_id.value,
+ initial
+ ? get_point (ENTRY_BASIC_BLOCK, 0,
+ PointPosition::START)
+ : get_current_point_mid ());
check_move_behind_reference (place_id);
@@ -499,24 +515,25 @@ protected: // Generic BIR operations.
void issue_loan (Polonius::Origin origin, LoanId loan_id)
{
- facts.loan_issued_at.emplace_back (origin, loan_id,
+ facts.loan_issued_at.emplace_back (origin, loan_id.value,
get_current_point_mid ());
- check_for_borrow_conficts (place_db.get_loans ()[loan_id].place, loan_id,
- place_db.get_loans ()[loan_id].mutability);
+ check_for_borrow_conficts (place_db.get_loan (loan_id).place, loan_id,
+ place_db.get_loan (loan_id).mutability);
}
void issue_locals_dealloc ()
{
- for (LoanId loan_id = 0; loan_id < place_db.get_loans ().size (); ++loan_id)
+ for (LoanId loan_id = {0}; loan_id.value < place_db.get_loans ().size ();
+ ++loan_id.value)
{
- auto &loan = place_db.get_loans ()[loan_id];
+ auto &loan = place_db.get_loan (loan_id);
auto loaned_var_id = place_db.get_var (loan.place);
if (place_db[loaned_var_id].tyty->is<TyTy::ReferenceType> ())
continue;
if (loaned_var_id >= first_local)
facts.loan_invalidated_at.emplace_back (get_current_point_start (),
- loan_id);
+ loan_id.value);
}
}
@@ -534,20 +551,20 @@ protected: // Generic BIR operations.
place_db.for_each_path_segment (place_id, [&] (PlaceId id) {
for (auto loan : place_db[id].borrowed_by)
{
- if (place_db.get_loans ()[loan].mutability == Mutability::Mut)
+ if (place_db.get_loan (loan).mutability == Mutability::Mut)
{
facts.loan_invalidated_at.emplace_back (
- get_current_point_start (), loan);
+ get_current_point_start (), loan.value);
}
}
});
place_db.for_each_path_from_root (place_id, [&] (PlaceId id) {
for (auto loan : place_db[id].borrowed_by)
{
- if (place_db.get_loans ()[loan].mutability == Mutability::Mut)
+ if (place_db.get_loan (loan).mutability == Mutability::Mut)
{
facts.loan_invalidated_at.emplace_back (
- get_current_point_start (), loan);
+ get_current_point_start (), loan.value);
}
}
});
@@ -558,12 +575,12 @@ protected: // Generic BIR operations.
place_db.for_each_path_segment (place_id, [&] (PlaceId id) {
for (auto loan : place_db[id].borrowed_by)
facts.loan_invalidated_at.emplace_back (get_current_point_start (),
- loan);
+ loan.value);
});
place_db.for_each_path_from_root (place_id, [&] (PlaceId id) {
for (auto loan : place_db[id].borrowed_by)
facts.loan_invalidated_at.emplace_back (get_current_point_start (),
- loan);
+ loan.value);
});
}
@@ -574,12 +591,11 @@ protected: // Generic BIR operations.
for (auto other_loan : place_db[id].borrowed_by)
{
if (mutability == Mutability::Imm
- && place_db.get_loans ()[other_loan].mutability
- == Mutability::Imm)
+ && place_db.get_loan (other_loan).mutability == Mutability::Imm)
continue;
else
facts.loan_invalidated_at.emplace_back (get_current_point_start (),
- other_loan);
+ other_loan.value);
}
});
@@ -587,12 +603,11 @@ protected: // Generic BIR operations.
for (auto other_loan : place_db[id].borrowed_by)
{
if (mutability == Mutability::Imm
- && place_db.get_loans ()[other_loan].mutability
- == Mutability::Imm)
+ && place_db.get_loan (other_loan).mutability == Mutability::Imm)
continue;
else
facts.loan_invalidated_at.emplace_back (get_current_point_start (),
- other_loan);
+ other_loan.value);
}
});
}
@@ -614,26 +629,28 @@ protected: // Generic BIR operations.
{
// TODO: this is more complicated, see
// compiler/rustc_borrowck/src/constraint_generation.rs:176
- facts.loan_killed_at.emplace_back (loan, get_current_point_mid ());
+ facts.loan_killed_at.emplace_back (loan.value,
+ get_current_point_mid ());
}
}
protected: // Subset helpers.
void push_subset (FreeRegion lhs, FreeRegion rhs)
{
- rust_debug ("\t\tpush_subset: '?%lu: '?%lu", (unsigned long) lhs,
- (unsigned long) rhs);
+ rust_debug ("\t\tpush_subset: '?%lu: '?%lu", (unsigned long) lhs.value,
+ (unsigned long) rhs.value);
- facts.subset_base.emplace_back (lhs, rhs, get_current_point_mid ());
+ facts.subset_base.emplace_back (lhs.value, rhs.value,
+ get_current_point_mid ());
}
void push_subset_all (FreeRegion lhs, FreeRegion rhs)
{
- rust_debug ("\t\tpush_subset_all: '?%lu: '?%lu", (unsigned long) lhs,
- (unsigned long) rhs);
+ rust_debug ("\t\tpush_subset_all: '?%lu: '?%lu", (unsigned long) lhs.value,
+ (unsigned long) rhs.value);
for (auto point : cfg_points_all)
- facts.subset_base.emplace_back (lhs, rhs, point);
+ facts.subset_base.emplace_back (lhs.value, rhs.value, point);
}
void push_subset (Variance variance, FreeRegion lhs, FreeRegion rhs)
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-free-region.h b/gcc/rust/checks/errors/borrowck/rust-bir-free-region.h
index c09e888..cb459f8 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-free-region.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-free-region.h
@@ -24,7 +24,19 @@
namespace Rust {
-using FreeRegion = size_t;
+struct FreeRegion
+{
+ size_t value;
+ // some overloads for comparision
+ bool operator== (const FreeRegion &rhs) const { return value == rhs.value; }
+ bool operator!= (const FreeRegion &rhs) const { return !(operator== (rhs)); }
+ bool operator< (const FreeRegion &rhs) const { return value < rhs.value; }
+ bool operator> (const FreeRegion &rhs) const { return value > rhs.value; }
+ bool operator<= (const FreeRegion &rhs) const { return !(operator> (rhs)); }
+ bool operator>= (const FreeRegion &rhs) const { return !(operator< (rhs)); }
+};
+
+static constexpr FreeRegion STATIC_FREE_REGION = {0};
class FreeRegions
{
@@ -38,14 +50,6 @@ public:
FreeRegion &operator[] (size_t i) { return regions.at (i); }
const FreeRegion &operator[] (size_t i) const { return regions.at (i); }
const std::vector<FreeRegion> &get_regions () const { return regions; }
- void set_from (std::vector<Rust::Polonius::Origin> &&regions)
- {
- this->regions.clear ();
- for (auto &region : regions)
- {
- this->regions.push_back ({region});
- }
- }
WARN_UNUSED_RESULT FreeRegions prepend (FreeRegion region) const
{
@@ -54,6 +58,9 @@ public:
return FreeRegions (std::move (new_regions));
}
+ void push_back (FreeRegion region) { regions.push_back (region); }
+
+ FreeRegions () {}
FreeRegions (std::vector<FreeRegion> &&regions) : regions (regions) {}
WARN_UNUSED_RESULT std::string to_string () const
@@ -61,7 +68,7 @@ public:
std::stringstream result;
for (auto &region : regions)
{
- result << region;
+ result << region.value;
result << ", ";
}
// Remove the last ", " from the string.
@@ -83,19 +90,20 @@ public:
WARN_UNUSED_RESULT FreeRegion get_next_free_region () const
{
- return next_free_region++;
+ ++next_free_region.value;
+ return {next_free_region.value - 1};
}
FreeRegions bind_regions (std::vector<TyTy::Region> regions,
FreeRegions parent_free_regions)
{
- std::vector<FreeRegion> free_regions;
+ FreeRegions free_regions;
for (auto &region : regions)
{
if (region.is_early_bound ())
free_regions.push_back (parent_free_regions[region.get_index ()]);
else if (region.is_static ())
- free_regions.push_back (0);
+ free_regions.push_back (STATIC_FREE_REGION);
else if (region.is_anonymous ())
free_regions.push_back (get_next_free_region ());
else if (region.is_named ())
@@ -106,9 +114,7 @@ public:
rust_unreachable ();
}
}
- // This is necesarry because of clash of current gcc and gcc4.8.
- FreeRegions free_regions_final{std::move (free_regions)};
- return free_regions_final;
+ return free_regions;
}
};
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-place.h b/gcc/rust/checks/errors/borrowck/rust-bir-place.h
index 8c38e8e..a1621b7 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-place.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-place.h
@@ -32,14 +32,36 @@ namespace Rust {
namespace BIR {
/** A unique identifier for a place in the BIR. */
-using PlaceId = uint32_t;
+struct PlaceId
+{
+ uint32_t value;
+ // some overloads for comparision
+ bool operator== (const PlaceId &rhs) const { return value == rhs.value; }
+ bool operator!= (const PlaceId &rhs) const { return !(operator== (rhs)); }
+ bool operator< (const PlaceId &rhs) const { return value < rhs.value; }
+ bool operator> (const PlaceId &rhs) const { return value > rhs.value; }
+ bool operator<= (const PlaceId &rhs) const { return !(operator> (rhs)); }
+ bool operator>= (const PlaceId &rhs) const { return !(operator< (rhs)); }
+};
-static constexpr PlaceId INVALID_PLACE = 0;
-static constexpr PlaceId RETURN_VALUE_PLACE = 1;
+static constexpr PlaceId INVALID_PLACE = {0};
+static constexpr PlaceId RETURN_VALUE_PLACE = {1};
static constexpr PlaceId FIRST_VARIABLE_PLACE = RETURN_VALUE_PLACE;
using Variance = TyTy::VarianceAnalysis::Variance;
-using LoanId = uint32_t;
+
+/** A unique identifier for a loan in the BIR. */
+struct LoanId
+{
+ uint32_t value;
+ // some overloads for comparision
+ bool operator== (const LoanId &rhs) const { return value == rhs.value; }
+ bool operator!= (const LoanId &rhs) const { return !(operator== (rhs)); }
+ bool operator< (const LoanId &rhs) const { return value < rhs.value; }
+ bool operator> (const LoanId &rhs) const { return value > rhs.value; }
+ bool operator<= (const LoanId &rhs) const { return !(operator> (rhs)); }
+ bool operator>= (const LoanId &rhs) const { return !(operator< (rhs)); }
+};
/**
* Representation of lvalues and constants in BIR.
@@ -143,13 +165,25 @@ public:
}
};
-using ScopeId = uint32_t;
+struct ScopeId
+{
+ uint32_t value;
+ ScopeId next_scope_id () const { return {value + 1}; }
+ // some overloads for comparision
+ bool operator== (const ScopeId &rhs) const { return value == rhs.value; }
+ bool operator!= (const ScopeId &rhs) const { return !(operator== (rhs)); }
+ bool operator< (const ScopeId &rhs) const { return value < rhs.value; }
+ bool operator> (const ScopeId &rhs) const { return value > rhs.value; }
+ bool operator<= (const ScopeId &rhs) const { return !(operator> (rhs)); }
+ bool operator>= (const ScopeId &rhs) const { return !(operator< (rhs)); }
+};
-static constexpr ScopeId INVALID_SCOPE = std::numeric_limits<ScopeId>::max ();
+static constexpr ScopeId INVALID_SCOPE
+ = {std::numeric_limits<uint32_t>::max ()};
/** Arguments and return value are in the root scope. */
-static constexpr ScopeId ROOT_SCOPE = 0;
+static constexpr ScopeId ROOT_SCOPE = {0};
/** Top-level local variables are in the top-level scope. */
-static constexpr ScopeId TOP_LEVEL_SCOPE = 1;
+static constexpr ScopeId TOP_LEVEL_SCOPE = {1};
struct Scope
{
@@ -162,21 +196,51 @@ struct Loan
{
Mutability mutability;
PlaceId place;
+ location_t location;
+};
+
+// I is the index type, T is the contained type
+template <typename I, typename T> class IndexVec
+{
+ std::vector<T> internal_vector;
+
+public:
+ IndexVec () = default;
+ IndexVec (size_t size) { internal_vector.reserve (size); }
+
+ T &at (I pid) { return internal_vector[pid.value]; }
+ const T &at (I pid) const { return internal_vector[pid.value]; }
+ T &operator[] (I pid) { return internal_vector[pid.value]; }
+ const T &operator[] (I pid) const { return internal_vector[pid.value]; }
+
+ void push_back (T &&param) { internal_vector.push_back (std::move (param)); }
+ template <typename... Args> void emplace_back (Args &&... args)
+ {
+ internal_vector.emplace_back (std::forward<Args> (args)...);
+ }
+
+ size_t size () const { return internal_vector.size (); }
+
+ std::vector<T> &get_vector () { return internal_vector; }
};
+using Scopes = IndexVec<ScopeId, Scope>;
+using Loans = IndexVec<LoanId, Loan>;
+using Places = IndexVec<PlaceId, Place>;
+
/** Allocated places and keeps track of paths. */
class PlaceDB
{
private:
// Possible optimizations: separate variables to speedup lookup.
- std::vector<Place> places;
+ Places places;
std::unordered_map<TyTy::BaseType *, PlaceId> constants_lookup;
- std::vector<Scope> scopes;
- ScopeId current_scope = 0;
+ Scopes scopes;
+ ScopeId current_scope = ROOT_SCOPE;
- std::vector<Loan> loans;
+ Loans loans;
- Polonius::Origin next_free_region = 1;
+ FreeRegion next_free_region = {1};
public:
PlaceDB ()
@@ -190,22 +254,24 @@ public:
Place &operator[] (PlaceId id) { return places.at (id); }
const Place &operator[] (PlaceId id) const { return places.at (id); }
- decltype (places)::const_iterator begin () const { return places.begin (); }
- decltype (places)::const_iterator end () const { return places.end (); }
-
size_t size () const { return places.size (); }
- const std::vector<Loan> &get_loans () const { return loans; }
+ const Loans &get_loans () const { return loans; }
+ const Loan &get_loan (LoanId loan_id) const { return loans.at (loan_id); }
ScopeId get_current_scope_id () const { return current_scope; }
- const std::vector<Scope> &get_scopes () const { return scopes; }
+ const Scopes &get_scopes () const { return scopes; }
const Scope &get_current_scope () const { return scopes[current_scope]; }
const Scope &get_scope (ScopeId id) const { return scopes[id]; }
- FreeRegion get_next_free_region () { return next_free_region++; }
+ FreeRegion get_next_free_region ()
+ {
+ ++next_free_region.value;
+ return {next_free_region.value - 1};
+ }
FreeRegion peek_next_free_region () const { return next_free_region; }
@@ -213,7 +279,7 @@ public:
ScopeId push_new_scope ()
{
- ScopeId new_scope = scopes.size ();
+ ScopeId new_scope = {scopes.size ()};
scopes.emplace_back ();
scopes[new_scope].parent = current_scope;
scopes[current_scope].children.push_back (new_scope);
@@ -227,12 +293,12 @@ public:
return current_scope;
}
- PlaceId add_place (Place &&place, PlaceId last_sibling = 0)
+ PlaceId add_place (Place &&place, PlaceId last_sibling = INVALID_PLACE)
{
places.emplace_back (std::forward<Place &&> (place));
- PlaceId new_place = places.size () - 1;
+ PlaceId new_place = {places.size () - 1};
Place &new_place_ref = places[new_place]; // Intentional shadowing.
- if (last_sibling == 0)
+ if (last_sibling == INVALID_PLACE)
places[new_place_ref.path.parent].path.first_child = new_place;
else
places[last_sibling].path.next_sibling = new_place;
@@ -244,29 +310,33 @@ public:
auto variances = Resolver::TypeCheckContext::get ()
->get_variance_analysis_ctx ()
.query_type_variances (new_place_ref.tyty);
- std::vector<Polonius::Origin> regions;
- for (size_t i = 0; i < variances.size (); i++)
- regions.push_back (next_free_region++);
+ FreeRegions regions;
+ for (size_t i = 0; i < variances.size (); ++i)
+ {
+ regions.push_back (next_free_region);
+ ++next_free_region.value;
+ }
- new_place_ref.regions.set_from (std::move (regions));
+ new_place_ref.regions = regions;
return new_place;
}
PlaceId add_variable (NodeId id, TyTy::BaseType *tyty)
{
- return add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty}, 0);
+ return add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty},
+ INVALID_PLACE);
}
WARN_UNUSED_RESULT PlaceId lookup_or_add_path (Place::Kind kind,
TyTy::BaseType *tyty,
PlaceId parent, size_t id = 0)
{
- PlaceId current = 0;
- if (parent < places.size ())
+ PlaceId current = INVALID_PLACE;
+ if (parent.value < places.size ())
{
current = places[parent].path.first_child;
- while (current != 0)
+ while (current != INVALID_PLACE)
{
if (places[current].kind == kind
&& places[current].variable_or_field_index == id)
@@ -277,14 +347,16 @@ public:
current = places[current].path.next_sibling;
}
}
- return add_place ({kind, (uint32_t) id, Place::Path{parent, 0, 0},
+ return add_place ({kind, (uint32_t) id,
+ Place::Path{parent, INVALID_PLACE, INVALID_PLACE},
is_type_copy (tyty), tyty},
current);
}
PlaceId add_temporary (TyTy::BaseType *tyty)
{
- return add_place ({Place::TEMPORARY, 0, {}, is_type_copy (tyty), tyty}, 0);
+ return add_place ({Place::TEMPORARY, 0, {}, is_type_copy (tyty), tyty},
+ INVALID_PLACE);
}
PlaceId get_constant (TyTy::BaseType *tyty)
@@ -299,22 +371,22 @@ public:
{
PlaceId current = FIRST_VARIABLE_PLACE;
- while (current != places.size ())
+ while (current.value != places.size ())
{
if (places[current].kind == Place::VARIABLE
&& places[current].variable_or_field_index == id)
return current;
- current++;
+ ++current.value;
}
return INVALID_PLACE;
}
LoanId add_loan (Loan &&loan)
{
- LoanId id = loans.size ();
+ LoanId id = {loans.size ()};
loans.push_back (std::forward<Loan &&> (loan));
- PlaceId borrowed_place = loans.rbegin ()->place;
- places[loans.rbegin ()->place].borrowed_by.push_back (id);
+ PlaceId borrowed_place = loans.get_vector ().rbegin ()->place;
+ places[loans.get_vector ().rbegin ()->place].borrowed_by.push_back (id);
if (places[borrowed_place].kind == Place::DEREF)
{
places[places[borrowed_place].path.parent].borrowed_by.push_back (id);
@@ -337,7 +409,7 @@ public:
void set_next_free_region (Polonius::Origin next_free_region)
{
- this->next_free_region = next_free_region;
+ this->next_free_region.value = next_free_region;
}
PlaceId lookup_or_add_variable (NodeId id, TyTy::BaseType *tyty)
@@ -347,7 +419,7 @@ public:
return lookup;
add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty});
- return places.size () - 1;
+ return {places.size () - 1};
};
template <typename FN> void for_each_path_from_root (PlaceId var, FN fn) const
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir.h b/gcc/rust/checks/errors/borrowck/rust-bir.h
index ed190a0..e90e508 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir.h
@@ -30,11 +30,11 @@ namespace Rust {
namespace BIR {
struct BasicBlock;
+struct BasicBlockId;
+using BasicBlocks = IndexVec<BasicBlockId, BasicBlock>;
class Statement;
class AbstractExpr;
-using LoanId = uint32_t;
-
/**
* Top-level entity of the Borrow-checker IR (BIR).
* It represents a single function (method, closure, etc.), which is the
@@ -44,9 +44,10 @@ struct Function
{
PlaceDB place_db;
std::vector<PlaceId> arguments;
- std::vector<BasicBlock> basic_blocks;
+ BasicBlocks basic_blocks;
FreeRegions universal_regions;
std::vector<std::pair<FreeRegion, FreeRegion>> universal_region_bounds;
+ std::unordered_map<Polonius::Origin, HIR::LifetimeParam *> region_hir_map;
location_t location;
};
@@ -77,19 +78,50 @@ private:
// otherwise: <unused>
std::unique_ptr<AbstractExpr> expr;
TyTy::BaseType *type;
+ // stores location of the actual expression from source code
+ // currently only available when kind is ASSIGNMENT | RETURN
+ // FIXME: Add location for other statement kinds
+ location_t location;
public:
- Statement (PlaceId lhs, AbstractExpr *rhs)
- : kind (Kind::ASSIGNMENT), place (lhs), expr (rhs)
- {}
-
- explicit Statement (Kind kind, PlaceId place = INVALID_PLACE,
- AbstractExpr *expr = nullptr)
- : kind (kind), place (place), expr (expr)
- {}
+ static Statement make_assignment (PlaceId place, AbstractExpr *rhs,
+ location_t location)
+ {
+ return Statement (Kind::ASSIGNMENT, place, rhs, nullptr, location);
+ }
+ static Statement make_switch (PlaceId place)
+ {
+ return Statement (Kind::SWITCH, place);
+ }
+ static Statement make_return (location_t location)
+ {
+ return Statement (Kind::RETURN, INVALID_PLACE, nullptr, nullptr, location);
+ }
+ static Statement make_goto () { return Statement (Kind::GOTO); }
+ static Statement make_storage_dead (PlaceId place)
+ {
+ return Statement (Kind::STORAGE_DEAD, place);
+ }
+ static Statement make_storage_live (PlaceId place)
+ {
+ return Statement (Kind::STORAGE_LIVE, place);
+ }
+ static Statement make_user_type_ascription (PlaceId place,
+ TyTy::BaseType *type)
+ {
+ return Statement (Kind::USER_TYPE_ASCRIPTION, place, nullptr, type);
+ }
+ static Statement make_fake_read (PlaceId place)
+ {
+ return Statement (Kind::FAKE_READ, place);
+ }
- explicit Statement (Kind kind, PlaceId place, TyTy::BaseType *type)
- : kind (kind), place (place), type (type)
+private:
+ // compelete constructor, used by make_* functions
+ Statement (Kind kind, PlaceId place = INVALID_PLACE,
+ AbstractExpr *rhs = nullptr, TyTy::BaseType *type = nullptr,
+ location_t location = UNKNOWN_LOCATION)
+ : kind (kind), place (place), expr (rhs), type (type), location (location)
{}
public:
@@ -97,13 +129,28 @@ public:
WARN_UNUSED_RESULT PlaceId get_place () const { return place; }
WARN_UNUSED_RESULT AbstractExpr &get_expr () const { return *expr; }
WARN_UNUSED_RESULT TyTy::BaseType *get_type () const { return type; }
+ WARN_UNUSED_RESULT location_t get_location () const { return location; }
};
/** Unique identifier for a basic block in the BIR. */
-using BasicBlockId = uint32_t;
+struct BasicBlockId
+{
+ uint32_t value;
+ // some overloads for comparision
+ bool operator== (const BasicBlockId &rhs) const { return value == rhs.value; }
+ bool operator!= (const BasicBlockId &rhs) const
+ {
+ return !(operator== (rhs));
+ }
+ bool operator< (const BasicBlockId &rhs) const { return value < rhs.value; }
+ bool operator> (const BasicBlockId &rhs) const { return value > rhs.value; }
+ bool operator<= (const BasicBlockId &rhs) const { return !(operator> (rhs)); }
+ bool operator>= (const BasicBlockId &rhs) const { return !(operator< (rhs)); }
+};
static constexpr BasicBlockId INVALID_BB
- = std::numeric_limits<BasicBlockId>::max ();
+ = {std::numeric_limits<uint32_t>::max ()};
+static constexpr BasicBlockId ENTRY_BASIC_BLOCK = {0};
struct BasicBlock
{
@@ -192,7 +239,7 @@ public:
loan (loan_id), origin (lifetime)
{}
WARN_UNUSED_RESULT PlaceId get_place () const { return place; }
- WARN_UNUSED_RESULT LoanId get_loan () const { return loan; }
+ WARN_UNUSED_RESULT LoanId get_loan_id () const { return loan; }
WARN_UNUSED_RESULT Polonius::Origin get_origin () const { return origin; }
};
diff --git a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc
index a8eaa80..6c67706 100644
--- a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.cc
@@ -17,6 +17,8 @@
// <http://www.gnu.org/licenses/>.
#include "rust-borrow-checker-diagnostics.h"
+#include "polonius/rust-polonius-ffi.h"
+#include "rust-diagnostics.h"
namespace Rust {
namespace BIR {
@@ -32,35 +34,136 @@ BorrowCheckerDiagnostics::report_errors ()
void
BorrowCheckerDiagnostics::report_move_errors ()
{
- if (!move_errors.empty ())
+ for (const auto &pair : move_errors)
{
- rust_error_at (hir_function->get_locus (),
- "Found move errors in function %s",
- hir_function->get_function_name ().as_string ().c_str ());
+ auto error_location = get_statement (pair.first).get_location ();
+
+ // in future, we can use the assigned at location to hint the
+ // user to implement copy trait for the type
+ /*
+ for (auto it : facts.path_assigned_at_base)
+ {
+ if (pair.second[0] == it.first)
+ {
+ auto point_assigned_at = it.second;
+ auto assigned_at_location
+ = get_statement (point_assigned_at).get_location ();
+ }
+ }
+ */
+
+ std::vector<LabelLocationPair> labels{
+ {"moved value used here", error_location}};
+ // add labels to all the moves for the given path
+ for (auto it : facts.path_moved_at_base)
+ {
+ if (pair.second[0] == it.first)
+ {
+ auto point_moved_at = it.second;
+ // don't label the move location where the error occured
+ if (pair.first != point_moved_at)
+ {
+ auto move_at_location
+ = get_statement (point_moved_at).get_location ();
+ labels.push_back ({"value moved here", move_at_location});
+ }
+ }
+ }
+ multi_label_error ("use of moved value", error_location, labels);
}
}
void
BorrowCheckerDiagnostics::report_loan_errors ()
{
- if (!loan_errors.empty ())
+ for (const auto &pair : loan_errors)
{
- rust_error_at (hir_function->get_locus (),
- "Found loan errors in function %s",
- hir_function->get_function_name ().as_string ().c_str ());
+ auto error_location = get_statement (pair.first).get_location ();
+ for (const auto &loan : pair.second)
+ {
+ auto loan_struct = get_loan (loan);
+ multi_label_error ("use of borrowed value", error_location,
+ {{"borrow occurs here", loan_struct.location},
+ {"borrowed value used here", error_location}});
+ }
}
}
void
BorrowCheckerDiagnostics::report_subset_errors ()
{
- if (!subset_errors.empty ())
+ // remove duplicates in subset_errors
+ //
+ // Polonius may output subset errors for same 2 origins at multiple points
+ // so to avoid duplicating the errors, we can remove the elements in subset
+ // errors with same origin pair
+ std::vector<std::pair<size_t, std::pair<size_t, size_t>>>
+ deduplicated_subset_errors;
+
+ for (auto pair : subset_errors)
+ {
+ auto it = std::find_if (
+ deduplicated_subset_errors.begin (), deduplicated_subset_errors.end (),
+ [&pair] (std::pair<size_t, std::pair<size_t, size_t>> element) {
+ return element.second == pair.second;
+ });
+ if (it == deduplicated_subset_errors.end ())
+ {
+ deduplicated_subset_errors.push_back (pair);
+ }
+ }
+ for (const auto &error : deduplicated_subset_errors)
+ {
+ auto first_lifetime_location
+ = get_lifetime_param (error.second.first)->get_locus ();
+ auto second_lifetime_location
+ = get_lifetime_param (error.second.second)->get_locus ();
+ multi_label_error (
+ "subset error, some lifetime constraints need to be added",
+ bir_function.location,
+ {{"lifetime defined here", first_lifetime_location},
+ {"lifetime defined here", second_lifetime_location},
+ {"subset error occurs in this function", bir_function.location}});
+ }
+}
+
+const BIR::Statement &
+BorrowCheckerDiagnostics::get_statement (Polonius::Point point)
+{
+ auto statement_index = Polonius::FullPoint::extract_stmt (point);
+ auto bb_index = Polonius::FullPoint::extract_bb (point);
+ // assert that the extracted indexes are valid
+ rust_assert (bb_index < bir_function.basic_blocks.size ());
+ rust_assert (statement_index
+ < bir_function.basic_blocks[{bb_index}].statements.size ());
+ return bir_function.basic_blocks[{bb_index}].statements[statement_index];
+}
+
+const BIR::Loan &
+BorrowCheckerDiagnostics::get_loan (Polonius::Loan loan)
+{
+ return bir_function.place_db.get_loans ()[{loan}];
+}
+
+const HIR::LifetimeParam *
+BorrowCheckerDiagnostics::get_lifetime_param (Polonius::Origin origin)
+
+{
+ return bir_function.region_hir_map.at (origin);
+}
+
+void
+BorrowCheckerDiagnostics::multi_label_error (
+ const char *error_message, location_t error_location,
+ std::vector<LabelLocationPair> location_label_pairs)
+{
+ rich_location r{line_table, error_location};
+ for (auto &label_location : location_label_pairs)
{
- rust_error_at (hir_function->get_locus (),
- "Found subset errors in function %s. Some lifetime "
- "constraints need to be added.",
- hir_function->get_function_name ().as_string ().c_str ());
+ r.add_range (label_location.location, SHOW_RANGE_WITHOUT_CARET,
+ &label_location.label);
}
+ rust_error_at (r, "%s", error_message);
}
} // namespace BIR
diff --git a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h
index 90d5ed8..9ab0591 100644
--- a/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h
+++ b/gcc/rust/checks/errors/borrowck/rust-borrow-checker-diagnostics.h
@@ -22,6 +22,7 @@
#include "polonius/rust-polonius.h"
#include "rust-bir.h"
#include "rust-hir-item.h"
+#include "text-range-label.h"
namespace Rust {
namespace BIR {
@@ -62,6 +63,19 @@ private:
void report_move_errors ();
void report_loan_errors ();
void report_subset_errors ();
+
+ const BIR::Statement &get_statement (Polonius::Point point);
+ const BIR::Loan &get_loan (Polonius::Loan loan);
+ const HIR::LifetimeParam *get_lifetime_param (Polonius::Origin origin);
+
+ struct LabelLocationPair
+ {
+ text_range_label label;
+ location_t location;
+ };
+ static void
+ multi_label_error (const char *error_message, location_t error_location,
+ std::vector<LabelLocationPair> location_label_pairs);
};
} // namespace BIR
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
index d16d6ed..01d8ea5 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
@@ -284,6 +284,10 @@ PrivacyReporter::visit (HIR::TypePathSegmentFunction &)
}
void
+PrivacyReporter::visit (HIR::InlineAsm &)
+{}
+
+void
PrivacyReporter::visit (HIR::TypePath &path)
{
check_for_privacy_violation (path.get_mappings ().get_nodeid (),
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
index 6f2937c..c4f94ab 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
@@ -126,6 +126,7 @@ types
virtual void visit (HIR::MatchExpr &expr);
virtual void visit (HIR::AwaitExpr &expr);
virtual void visit (HIR::AsyncBlockExpr &expr);
+ virtual void visit (HIR::InlineAsm &expr);
virtual void visit (HIR::EnumItemTuple &);
virtual void visit (HIR::EnumItemStruct &);
diff --git a/gcc/rust/checks/errors/rust-const-checker.cc b/gcc/rust/checks/errors/rust-const-checker.cc
index 2beee21..84c09dd 100644
--- a/gcc/rust/checks/errors/rust-const-checker.cc
+++ b/gcc/rust/checks/errors/rust-const-checker.cc
@@ -22,6 +22,10 @@
#include "rust-hir-stmt.h"
#include "rust-hir-item.h"
#include "rust-system.h"
+#include "rust-immutable-name-resolution-context.h"
+
+// for flag_name_resolution_2_0
+#include "options.h"
namespace Rust {
namespace HIR {
@@ -354,8 +358,18 @@ ConstChecker::visit (CallExpr &expr)
NodeId ast_node_id = expr.get_fnexpr ()->get_mappings ().get_nodeid ();
NodeId ref_node_id;
+ if (flag_name_resolution_2_0)
+ {
+ auto &nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ if (auto id = nr_ctx.lookup (ast_node_id))
+ ref_node_id = *id;
+ else
+ return;
+ }
// We don't care about types here
- if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
+ else if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
return;
if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id))
diff --git a/gcc/rust/checks/errors/rust-feature-gate.cc b/gcc/rust/checks/errors/rust-feature-gate.cc
index 580afc9..f3daa61 100644
--- a/gcc/rust/checks/errors/rust-feature-gate.cc
+++ b/gcc/rust/checks/errors/rust-feature-gate.cc
@@ -21,6 +21,7 @@
#include "rust-attribute-values.h"
#include "rust-ast-visitor.h"
#include "rust-feature.h"
+#include "rust-ast-full.h"
namespace Rust {
@@ -75,16 +76,17 @@ FeatureGate::gate (Feature::Name name, location_t loc,
if (!valid_features.count (name))
{
auto feature = Feature::create (name);
- auto issue = feature.issue ();
- if (issue > 0)
+ if (auto issue = feature.issue ())
{
+ auto issue_number = issue.value ();
const char *fmt_str
= "%s. see issue %u "
"<https://github.com/rust-lang/rust/issues/%u> for more "
"information. add `#![feature(%s)]` to the crate attributes to "
"enable.";
rust_error_at (loc, ErrorCode::E0658, fmt_str, error_msg.c_str (),
- issue, issue, feature.as_string ().c_str ());
+ issue_number, issue_number,
+ feature.as_string ().c_str ());
}
else
{
@@ -169,7 +171,16 @@ FeatureGate::visit (AST::TraitImpl &impl)
"negative_impls are not yet implemented");
AST::DefaultASTVisitor::visit (impl);
-};
+}
+
+void
+FeatureGate::visit (AST::Trait &trait)
+{
+ if (trait.is_auto ())
+ gate (Feature::Name::AUTO_TRAITS, trait.get_locus (),
+ "auto traits are experimental and possibly buggy");
+ AST::DefaultASTVisitor::visit (trait);
+}
void
FeatureGate::visit (AST::BoxExpr &expr)
@@ -217,4 +228,12 @@ FeatureGate::visit (AST::RangePattern &pattern)
"exclusive range pattern syntax is experimental");
}
+void
+FeatureGate::visit (AST::UseTreeGlob &use)
+{
+ // At the moment, UseTrees do not have outer attributes, but they should. we
+ // need to eventually gate `#[prelude_import]` on use-trees based on the
+ // #[feature(prelude_import)]
+}
+
} // namespace Rust
diff --git a/gcc/rust/checks/errors/rust-feature-gate.h b/gcc/rust/checks/errors/rust-feature-gate.h
index 31c2ed6..f1011e5 100644
--- a/gcc/rust/checks/errors/rust-feature-gate.h
+++ b/gcc/rust/checks/errors/rust-feature-gate.h
@@ -20,7 +20,6 @@
#define RUST_FEATURE_GATE_H
#include "rust-ast-visitor.h"
-#include "rust-ast-full.h"
#include "rust-feature.h"
namespace Rust {
@@ -35,153 +34,19 @@ public:
void check (AST::Crate &crate);
void visit (AST::Crate &crate) override;
- void visit (AST::Token &tok) override {}
- void visit (AST::DelimTokenTree &delim_tok_tree) override {}
- void visit (AST::AttrInputMetaItemContainer &input) override {}
- void visit (AST::IdentifierExpr &ident_expr) override {}
- void visit (AST::Lifetime &lifetime) override {}
void visit (AST::LifetimeParam &lifetime_param) override;
void visit (AST::ConstGenericParam &const_param) override;
- void visit (AST::PathInExpression &path) override {}
- void visit (AST::TypePathSegment &segment) override {}
- void visit (AST::TypePathSegmentGeneric &segment) override {}
- void visit (AST::TypePathSegmentFunction &segment) override {}
- void visit (AST::TypePath &path) override {}
- void visit (AST::QualifiedPathInExpression &path) override {}
- void visit (AST::QualifiedPathInType &path) override {}
- void visit (AST::LiteralExpr &expr) override {}
- void visit (AST::AttrInputLiteral &attr_input) override {}
- void visit (AST::AttrInputMacro &attr_input) override {}
- void visit (AST::MetaItemLitExpr &meta_item) override {}
- void visit (AST::MetaItemPathLit &meta_item) override {}
void visit (AST::BorrowExpr &expr) override;
- void visit (AST::DereferenceExpr &expr) override {}
- void visit (AST::ErrorPropagationExpr &expr) override {}
- void visit (AST::NegationExpr &expr) override {}
- void visit (AST::ArithmeticOrLogicalExpr &expr) override {}
- void visit (AST::ComparisonExpr &expr) override {}
- void visit (AST::LazyBooleanExpr &expr) override {}
- void visit (AST::TypeCastExpr &expr) override {}
- void visit (AST::AssignmentExpr &expr) override {}
- void visit (AST::CompoundAssignmentExpr &expr) override {}
- void visit (AST::GroupedExpr &expr) override {}
- void visit (AST::ArrayElemsValues &elems) override {}
- void visit (AST::ArrayElemsCopied &elems) override {}
- void visit (AST::ArrayExpr &expr) override {}
- void visit (AST::ArrayIndexExpr &expr) override {}
- void visit (AST::TupleExpr &expr) override {}
- void visit (AST::TupleIndexExpr &expr) override {}
- void visit (AST::StructExprStruct &expr) override {}
- void visit (AST::StructExprFieldIdentifier &field) override {}
- void visit (AST::StructExprFieldIdentifierValue &field) override {}
- void visit (AST::StructExprFieldIndexValue &field) override {}
- void visit (AST::StructExprStructFields &expr) override {}
- void visit (AST::StructExprStructBase &expr) override {}
- void visit (AST::CallExpr &expr) override {}
- void visit (AST::MethodCallExpr &expr) override {}
- void visit (AST::FieldAccessExpr &expr) override {}
- void visit (AST::ClosureExprInner &expr) override {}
- void visit (AST::ClosureExprInnerTyped &expr) override {}
- void visit (AST::ContinueExpr &expr) override {}
- void visit (AST::BreakExpr &expr) override {}
- void visit (AST::RangeFromToExpr &expr) override {}
- void visit (AST::RangeFromExpr &expr) override {}
- void visit (AST::RangeToExpr &expr) override {}
- void visit (AST::RangeFullExpr &expr) override {}
- void visit (AST::RangeFromToInclExpr &expr) override {}
- void visit (AST::RangeToInclExpr &expr) override {}
- void visit (AST::ReturnExpr &expr) override {}
void visit (AST::BoxExpr &expr) override;
- void visit (AST::UnsafeBlockExpr &expr) override {}
- void visit (AST::LoopExpr &expr) override {}
- void visit (AST::WhileLoopExpr &expr) override {}
- void visit (AST::WhileLetLoopExpr &expr) override {}
- void visit (AST::ForLoopExpr &expr) override {}
- void visit (AST::IfExpr &expr) override {}
- void visit (AST::IfExprConseqElse &expr) override {}
- void visit (AST::IfLetExprConseqElse &expr) override {}
- void visit (AST::AwaitExpr &expr) override {}
- void visit (AST::AsyncBlockExpr &expr) override {}
void visit (AST::TypeParam &param) override;
- void visit (AST::LifetimeWhereClauseItem &item) override {}
- void visit (AST::TypeBoundWhereClauseItem &item) override {}
- void visit (AST::Module &module) override {}
- void visit (AST::ExternCrate &crate) override {}
- void visit (AST::UseTreeGlob &use_tree) override {}
- void visit (AST::UseTreeList &use_tree) override {}
- void visit (AST::UseTreeRebind &use_tree) override {}
- void visit (AST::UseDeclaration &use_decl) override {}
+ void visit (AST::UseTreeGlob &use_tree) override;
void visit (AST::Function &function) override;
- void visit (AST::TypeAlias &type_alias) override {}
- void visit (AST::StructStruct &struct_item) override {}
- void visit (AST::TupleStruct &tuple_struct) override {}
- void visit (AST::EnumItem &item) override {}
- void visit (AST::EnumItemTuple &item) override {}
- void visit (AST::EnumItemStruct &item) override {}
- void visit (AST::EnumItemDiscriminant &item) override {}
- void visit (AST::Enum &enum_item) override {}
- void visit (AST::Union &union_item) override {}
- void visit (AST::ConstantItem &const_item) override {}
- void visit (AST::StaticItem &static_item) override {}
- void visit (AST::TraitItemConst &item) override {}
- void visit (AST::TraitItemType &item) override {}
void visit (AST::TraitImpl &impl) override;
- void visit (AST::Trait &trait) override {}
+ void visit (AST::Trait &trait) override;
void visit (AST::ExternalTypeItem &item) override;
- void visit (AST::ExternalStaticItem &item) override {}
void visit (AST::ExternBlock &block) override;
- void visit (AST::MacroMatchFragment &match) override {}
- void visit (AST::MacroMatchRepetition &match) override {}
- void visit (AST::MacroMatcher &matcher) override {}
void visit (AST::MacroRulesDefinition &rules_def) override;
- void visit (AST::MacroInvocation &macro_invoc) override {}
- void visit (AST::MetaItemPath &meta_item) override {}
- void visit (AST::MetaItemSeq &meta_item) override {}
- void visit (AST::MetaWord &meta_item) override {}
- void visit (AST::MetaNameValueStr &meta_item) override {}
- void visit (AST::MetaListPaths &meta_item) override {}
- void visit (AST::MetaListNameValueStr &meta_item) override {}
- void visit (AST::LiteralPattern &pattern) override {}
- void visit (AST::IdentifierPattern &pattern) override {}
- void visit (AST::WildcardPattern &pattern) override {}
- void visit (AST::RestPattern &pattern) override {}
- void visit (AST::RangePatternBoundLiteral &bound) override {}
- void visit (AST::RangePatternBoundPath &bound) override {}
- void visit (AST::RangePatternBoundQualPath &bound) override {}
void visit (AST::RangePattern &pattern) override;
- void visit (AST::ReferencePattern &pattern) override {}
- void visit (AST::StructPatternFieldTuplePat &field) override {}
- void visit (AST::StructPatternFieldIdentPat &field) override {}
- void visit (AST::StructPatternFieldIdent &field) override {}
- void visit (AST::StructPattern &pattern) override {}
- void visit (AST::TupleStructItemsNoRange &tuple_items) override {}
- void visit (AST::TupleStructItemsRange &tuple_items) override {}
- void visit (AST::TupleStructPattern &pattern) override {}
- void visit (AST::TuplePatternItemsMultiple &tuple_items) override {}
- void visit (AST::TuplePatternItemsRanged &tuple_items) override {}
- void visit (AST::TuplePattern &pattern) override {}
- void visit (AST::GroupedPattern &pattern) override {}
- void visit (AST::SlicePattern &pattern) override {}
- void visit (AST::AltPattern &pattern) override {}
- void visit (AST::EmptyStmt &stmt) override {}
- void visit (AST::ExprStmt &stmt) override {}
- void visit (AST::TraitBound &bound) override {}
- void visit (AST::ImplTraitType &type) override {}
- void visit (AST::TraitObjectType &type) override {}
- void visit (AST::ParenthesisedType &type) override {}
- void visit (AST::ImplTraitTypeOneBound &type) override {}
- void visit (AST::TraitObjectTypeOneBound &type) override {}
- void visit (AST::TupleType &type) override {}
- void visit (AST::NeverType &type) override {}
- void visit (AST::RawPointerType &type) override {}
- void visit (AST::ReferenceType &type) override {}
- void visit (AST::ArrayType &type) override {}
- void visit (AST::SliceType &type) override {}
- void visit (AST::InferredType &type) override {}
- void visit (AST::BareFunctionType &type) override {}
- void visit (AST::FunctionParam &param) override {}
- void visit (AST::VariadicParam &param) override {}
- void visit (AST::SelfParam &param) override {}
private:
void gate (Feature::Name name, location_t loc, const std::string &error_msg);
diff --git a/gcc/rust/checks/errors/rust-feature.cc b/gcc/rust/checks/errors/rust-feature.cc
index 917e3b2..25af46c 100644
--- a/gcc/rust/checks/errors/rust-feature.cc
+++ b/gcc/rust/checks/errors/rust-feature.cc
@@ -17,47 +17,47 @@
// <http://www.gnu.org/licenses/>.
#include "rust-feature.h"
-#include "rust-session-manager.h"
namespace Rust {
Feature
-Feature::create (Feature::Name name)
+Feature::create (Feature::Name f)
{
- switch (name)
+ switch (f)
{
case Feature::Name::ASSOCIATED_TYPE_BOUNDS:
return Feature (Feature::Name::ASSOCIATED_TYPE_BOUNDS,
Feature::State::ACCEPTED, "associated_type_bounds",
- "1.34.0", 52662, tl::nullopt, "");
+ "1.34.0", 52662);
case Feature::Name::INTRINSICS:
- return Feature (Feature::Name::INTRINSICS, Feature::State::ACCEPTED,
- "intrinsics", "1.0.0", 0, tl::nullopt, "");
+ return Feature (f, Feature::State::ACCEPTED, "intrinsics", "1.0.0");
case Feature::Name::RUSTC_ATTRS:
- return Feature (Feature::Name::RUSTC_ATTRS, Feature::State::ACCEPTED,
- "rustc_attrs", "1.0.0", 0, tl::nullopt, "");
+ return Feature (f, Feature::State::ACCEPTED, "rustc_attrs", "1.0.0");
case Feature::Name::DECL_MACRO:
- return Feature (Feature::Name::DECL_MACRO, Feature::State::ACCEPTED,
- "decl_macro", "1.0.0", 0, tl::nullopt, "");
+ return Feature (f, Feature::State::ACCEPTED, "decl_macro", "1.0.0",
+ 39412);
case Feature::Name::EXTERN_TYPES:
- return Feature (Feature::Name::EXTERN_TYPES, Feature::State::ACTIVE,
- "extern_types", "1.23.0", 43467, tl::nullopt, "");
+ return Feature (f, Feature::State::ACTIVE, "extern_types", "1.23.0",
+ 43467);
case Feature::Name::NEGATIVE_IMPLS:
- return Feature (Feature::Name::NEGATIVE_IMPLS, Feature::State::ACTIVE,
- "negative_impls", "1.0.0", 68318, tl::nullopt, "");
+ return Feature (f, Feature::State::ACTIVE, "negative_impls", "1.0.0",
+ 68318);
case Feature::Name::BOX_SYNTAX:
- return Feature (Feature::Name::BOX_SYNTAX, Feature::State::ACTIVE,
- "box_syntax", "1.0.0", 49733, tl::nullopt, "");
+ return Feature (f, Feature::State::ACTIVE, "box_syntax", "1.0.0", 49733);
case Feature::Name::DROPCK_EYEPATCH:
- return Feature (Feature::Name::DROPCK_EYEPATCH, Feature::State::ACTIVE,
- "dropck_eyepatch", "1.10.0", 34761, tl::nullopt, "");
+ return Feature (f, Feature::State::ACTIVE, "dropck_eyepatch", "1.10.0",
+ 34761);
case Feature::Name::RAW_REF_OP:
- return Feature (Feature::Name::RAW_REF_OP, Feature::State::ACTIVE,
- "raw_ref_op", "1.41.0", 64490, tl::nullopt, "");
+ return Feature (f, Feature::State::ACTIVE, "raw_ref_op", "1.41.0", 64490);
case Feature::Name::EXCLUSIVE_RANGE_PATTERN:
return Feature (Feature::Name::EXCLUSIVE_RANGE_PATTERN,
Feature::State::ACTIVE, "exclusive_range_pattern",
- "1.11.0", 37854, tl::nullopt, "");
+ "1.11.0", 37854);
+ case Feature::Name::PRELUDE_IMPORT:
+ return Feature (f, Feature::State::ACTIVE, "prelude_import", "1.0.0");
+ case Feature::Name::AUTO_TRAITS:
+ return Feature (f, Feature::State::ACTIVE, "optin_builtin_traits",
+ "1.0.0", 13231);
default:
rust_unreachable ();
}
@@ -79,6 +79,7 @@ const std::map<std::string, Feature::Name> Feature::name_hash_map = {
{"dropck_eyepatch", Feature::Name::DROPCK_EYEPATCH},
{"raw_ref_op", Feature::Name::RAW_REF_OP},
{"exclusive_range_pattern", Feature::Name::EXCLUSIVE_RANGE_PATTERN},
+ {"prelude_import", Feature::Name::PRELUDE_IMPORT},
}; // namespace Rust
tl::optional<Feature::Name>
diff --git a/gcc/rust/checks/errors/rust-feature.h b/gcc/rust/checks/errors/rust-feature.h
index 698aac2..e2082c5 100644
--- a/gcc/rust/checks/errors/rust-feature.h
+++ b/gcc/rust/checks/errors/rust-feature.h
@@ -50,22 +50,24 @@ public:
DROPCK_EYEPATCH,
RAW_REF_OP,
EXCLUSIVE_RANGE_PATTERN,
+ PRELUDE_IMPORT,
};
const std::string &as_string () { return m_name_str; }
Name name () { return m_name; }
const std::string &description () { return m_description; }
State state () { return m_state; }
- unsigned issue () { return m_issue; }
+ tl::optional<unsigned> issue () { return m_issue; }
static tl::optional<Name> as_name (const std::string &name);
static Feature create (Name name);
private:
Feature (Name name, State state, const char *name_str,
- const char *rustc_since, unsigned issue_number,
- const tl::optional<CompileOptions::Edition> &edition,
- const char *description)
+ const char *rustc_since,
+ tl::optional<unsigned> issue_number = tl::nullopt,
+ const tl::optional<CompileOptions::Edition> &edition = tl::nullopt,
+ const char *description = "")
: m_state (state), m_name (name), m_name_str (name_str),
m_rustc_since (rustc_since), m_issue (issue_number), edition (edition),
m_description (description)
@@ -75,9 +77,9 @@ private:
Name m_name;
std::string m_name_str;
std::string m_rustc_since;
- unsigned m_issue;
+ tl::optional<unsigned> m_issue;
tl::optional<CompileOptions::Edition> edition;
- std::string m_description;
+ std::string m_description; // TODO: Switch to optional?
static const std::map<std::string, Name> name_hash_map;
};
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
new file mode 100644
index 0000000..f46f429
--- /dev/null
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
@@ -0,0 +1,1568 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-system.h"
+#include "rust-hir-pattern-analysis.h"
+#include "rust-diagnostics.h"
+#include "rust-hir-full-decls.h"
+#include "rust-hir-path.h"
+#include "rust-hir-pattern.h"
+#include "rust-hir.h"
+#include "rust-mapping-common.h"
+#include "rust-system.h"
+#include "rust-tyty.h"
+#include "rust-immutable-name-resolution-context.h"
+
+// for flag_name_resolution_2_0
+#include "options.h"
+
+namespace Rust {
+namespace Analysis {
+
+PatternChecker::PatternChecker ()
+ : tyctx (*Resolver::TypeCheckContext::get ()),
+ resolver (*Resolver::Resolver::get ()),
+ mappings (Analysis::Mappings::get ())
+{}
+
+void
+PatternChecker::go (HIR::Crate &crate)
+{
+ rust_debug ("started pattern check");
+ for (auto &item : crate.get_items ())
+ item->accept_vis (*this);
+ rust_debug ("finished pattern check");
+}
+
+void
+PatternChecker::visit (Lifetime &)
+{}
+
+void
+PatternChecker::visit (LifetimeParam &)
+{}
+
+void
+PatternChecker::visit (PathInExpression &path)
+{}
+
+void
+PatternChecker::visit (TypePathSegment &)
+{}
+
+void
+PatternChecker::visit (TypePathSegmentGeneric &)
+{}
+
+void
+PatternChecker::visit (TypePathSegmentFunction &)
+{}
+
+void
+PatternChecker::visit (TypePath &)
+{}
+
+void
+PatternChecker::visit (QualifiedPathInExpression &)
+{}
+
+void
+PatternChecker::visit (QualifiedPathInType &)
+{}
+
+void
+PatternChecker::visit (LiteralExpr &)
+{}
+
+void
+PatternChecker::visit (BorrowExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (DereferenceExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ErrorPropagationExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (NegationExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ArithmeticOrLogicalExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ComparisonExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (LazyBooleanExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (TypeCastExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (AssignmentExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (CompoundAssignmentExpr &expr)
+{
+ expr.get_lhs ()->accept_vis (*this);
+ expr.get_rhs ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (GroupedExpr &expr)
+{
+ expr.get_expr_in_parens ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ArrayElemsValues &elems)
+{
+ for (auto &elem : elems.get_values ())
+ elem->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ArrayElemsCopied &elems)
+{
+ elems.get_elem_to_copy ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ArrayExpr &expr)
+{
+ expr.get_internal_elements ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ArrayIndexExpr &expr)
+{
+ expr.get_array_expr ()->accept_vis (*this);
+ expr.get_index_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (TupleExpr &expr)
+{
+ for (auto &elem : expr.get_tuple_elems ())
+ elem->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (TupleIndexExpr &expr)
+{
+ expr.get_tuple_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (StructExprStruct &)
+{}
+
+void
+PatternChecker::visit (StructExprFieldIdentifier &)
+{}
+
+void
+PatternChecker::visit (StructExprFieldIdentifierValue &field)
+{
+ field.get_value ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (StructExprFieldIndexValue &field)
+{
+ field.get_value ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (StructExprStructFields &expr)
+{
+ for (auto &field : expr.get_fields ())
+ field->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (StructExprStructBase &)
+{}
+
+void
+PatternChecker::visit (CallExpr &expr)
+{
+ if (!expr.get_fnexpr ())
+ return;
+
+ NodeId ast_node_id = expr.get_fnexpr ()->get_mappings ().get_nodeid ();
+ NodeId ref_node_id;
+ if (flag_name_resolution_2_0)
+ {
+ auto &nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ if (auto id = nr_ctx.lookup (ast_node_id))
+ ref_node_id = *id;
+ else
+ return;
+ }
+ else if (!resolver.lookup_resolved_name (ast_node_id, &ref_node_id))
+ return;
+
+ if (auto definition_id = mappings.lookup_node_to_hir (ref_node_id))
+ {
+ if (expr.has_params ())
+ for (auto &arg : expr.get_arguments ())
+ arg->accept_vis (*this);
+ }
+ else
+ {
+ rust_unreachable ();
+ }
+}
+
+void
+PatternChecker::visit (MethodCallExpr &expr)
+{
+ expr.get_receiver ()->accept_vis (*this);
+
+ for (auto &arg : expr.get_arguments ())
+ arg->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (FieldAccessExpr &expr)
+{
+ expr.get_receiver_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ClosureExpr &expr)
+{
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (BlockExpr &expr)
+{
+ for (auto &stmt : expr.get_statements ())
+ stmt->accept_vis (*this);
+
+ if (expr.has_expr ())
+ expr.get_final_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ContinueExpr &)
+{}
+
+void
+PatternChecker::visit (BreakExpr &expr)
+{
+ if (expr.has_break_expr ())
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (RangeFromToExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (RangeFromExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (RangeToExpr &expr)
+{
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (RangeFullExpr &)
+{}
+
+void
+PatternChecker::visit (RangeFromToInclExpr &expr)
+{
+ expr.get_from_expr ()->accept_vis (*this);
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (RangeToInclExpr &expr)
+{
+ expr.get_to_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ReturnExpr &expr)
+{
+ if (expr.has_return_expr ())
+ expr.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (UnsafeBlockExpr &expr)
+{
+ expr.get_block_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (LoopExpr &expr)
+{
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (WhileLoopExpr &expr)
+{
+ expr.get_predicate_expr ()->accept_vis (*this);
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (WhileLetLoopExpr &expr)
+{
+ expr.get_cond ()->accept_vis (*this);
+ expr.get_loop_block ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (IfExpr &expr)
+{
+ expr.get_if_condition ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (IfExprConseqElse &expr)
+{
+ expr.get_if_condition ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+ expr.get_else_block ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (IfLetExpr &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (IfLetExprConseqElse &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+ expr.get_if_block ()->accept_vis (*this);
+
+ expr.get_else_block ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (MatchExpr &expr)
+{
+ expr.get_scrutinee_expr ()->accept_vis (*this);
+
+ for (auto &match_arm : expr.get_match_cases ())
+ match_arm.get_expr ()->accept_vis (*this);
+
+ // match expressions are only an entrypoint
+ TyTy::BaseType *scrutinee_ty;
+ bool ok = tyctx.lookup_type (
+ expr.get_scrutinee_expr ()->get_mappings ().get_hirid (), &scrutinee_ty);
+ rust_assert (ok);
+
+ check_match_usefulness (&tyctx, scrutinee_ty, expr);
+}
+
+void
+PatternChecker::visit (AwaitExpr &)
+{
+ // TODO: Visit expression
+}
+
+void
+PatternChecker::visit (AsyncBlockExpr &)
+{
+ // TODO: Visit block expression
+}
+
+void
+PatternChecker::visit (InlineAsm &expr)
+{}
+
+void
+PatternChecker::visit (TypeParam &)
+{}
+
+void
+PatternChecker::visit (ConstGenericParam &)
+{}
+
+void
+PatternChecker::visit (LifetimeWhereClauseItem &)
+{}
+
+void
+PatternChecker::visit (TypeBoundWhereClauseItem &)
+{}
+
+void
+PatternChecker::visit (Module &module)
+{
+ for (auto &item : module.get_items ())
+ item->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ExternCrate &)
+{}
+
+void
+PatternChecker::visit (UseTreeGlob &)
+{}
+
+void
+PatternChecker::visit (UseTreeList &)
+{}
+
+void
+PatternChecker::visit (UseTreeRebind &)
+{}
+
+void
+PatternChecker::visit (UseDeclaration &)
+{}
+
+void
+PatternChecker::visit (Function &function)
+{
+ function.get_definition ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (TypeAlias &)
+{}
+
+void
+PatternChecker::visit (StructStruct &)
+{}
+
+void
+PatternChecker::visit (TupleStruct &)
+{}
+
+void
+PatternChecker::visit (EnumItem &)
+{}
+
+void
+PatternChecker::visit (EnumItemTuple &)
+{}
+
+void
+PatternChecker::visit (EnumItemStruct &)
+{}
+
+void
+PatternChecker::visit (EnumItemDiscriminant &)
+{}
+
+void
+PatternChecker::visit (Enum &)
+{}
+
+void
+PatternChecker::visit (Union &)
+{}
+
+void
+PatternChecker::visit (ConstantItem &const_item)
+{
+ const_item.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (StaticItem &static_item)
+{
+ static_item.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (TraitItemFunc &item)
+{
+ if (item.has_block_defined ())
+ item.get_block_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (TraitItemConst &item)
+{
+ if (item.has_expr ())
+ item.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (TraitItemType &)
+{}
+
+void
+PatternChecker::visit (Trait &trait)
+{
+ for (auto &item : trait.get_trait_items ())
+ item->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ImplBlock &impl)
+{
+ for (auto &item : impl.get_impl_items ())
+ item->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ExternalStaticItem &)
+{}
+
+void
+PatternChecker::visit (ExternalFunctionItem &)
+{}
+
+void
+PatternChecker::visit (ExternalTypeItem &)
+{}
+
+void
+PatternChecker::visit (ExternBlock &block)
+{
+ // FIXME: Do we need to do this?
+ for (auto &item : block.get_extern_items ())
+ item->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (LiteralPattern &)
+{}
+
+void
+PatternChecker::visit (IdentifierPattern &)
+{}
+
+void
+PatternChecker::visit (WildcardPattern &)
+{}
+
+void
+PatternChecker::visit (RangePatternBoundLiteral &)
+{}
+
+void
+PatternChecker::visit (RangePatternBoundPath &)
+{}
+
+void
+PatternChecker::visit (RangePatternBoundQualPath &)
+{}
+
+void
+PatternChecker::visit (RangePattern &)
+{}
+
+void
+PatternChecker::visit (ReferencePattern &)
+{}
+
+void
+PatternChecker::visit (StructPatternFieldTuplePat &)
+{}
+
+void
+PatternChecker::visit (StructPatternFieldIdentPat &)
+{}
+
+void
+PatternChecker::visit (StructPatternFieldIdent &)
+{}
+
+void
+PatternChecker::visit (StructPattern &)
+{}
+
+void
+PatternChecker::visit (TupleStructItemsNoRange &)
+{}
+
+void
+PatternChecker::visit (TupleStructItemsRange &)
+{}
+
+void
+PatternChecker::visit (TupleStructPattern &)
+{}
+
+void
+PatternChecker::visit (TuplePatternItemsMultiple &)
+{}
+
+void
+PatternChecker::visit (TuplePatternItemsRanged &)
+{}
+
+void
+PatternChecker::visit (TuplePattern &)
+{}
+
+void
+PatternChecker::visit (SlicePattern &)
+{}
+
+void
+PatternChecker::visit (AltPattern &)
+{}
+
+void
+PatternChecker::visit (EmptyStmt &)
+{}
+
+void
+PatternChecker::visit (LetStmt &stmt)
+{
+ if (stmt.has_init_expr ())
+ stmt.get_init_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (ExprStmt &stmt)
+{
+ stmt.get_expr ()->accept_vis (*this);
+}
+
+void
+PatternChecker::visit (TraitBound &)
+{}
+
+void
+PatternChecker::visit (ImplTraitType &)
+{}
+
+void
+PatternChecker::visit (TraitObjectType &)
+{}
+
+void
+PatternChecker::visit (ParenthesisedType &)
+{}
+
+void
+PatternChecker::visit (ImplTraitTypeOneBound &)
+{}
+
+void
+PatternChecker::visit (TupleType &)
+{}
+
+void
+PatternChecker::visit (NeverType &)
+{}
+
+void
+PatternChecker::visit (RawPointerType &)
+{}
+
+void
+PatternChecker::visit (ReferenceType &)
+{}
+
+void
+PatternChecker::visit (ArrayType &)
+{}
+
+void
+PatternChecker::visit (SliceType &)
+{}
+
+void
+PatternChecker::visit (InferredType &)
+{}
+
+void
+PatternChecker::visit (BareFunctionType &)
+{}
+
+bool
+Constructor::is_covered_by (const Constructor &o) const
+{
+ if (o.kind == ConstructorKind::WILDCARD)
+ return true;
+
+ switch (kind)
+ {
+ case ConstructorKind::VARIANT: {
+ rust_assert (kind == ConstructorKind::VARIANT);
+ return variant_idx == o.variant_idx;
+ }
+ break;
+ case ConstructorKind::INT_RANGE: {
+ rust_assert (kind == ConstructorKind::INT_RANGE);
+ return int_range.lo >= o.int_range.lo && int_range.hi <= o.int_range.hi;
+ }
+ break;
+ case ConstructorKind::WILDCARD: {
+ // TODO: wildcard is covered by a variant of enum with a single
+ // variant
+ return false;
+ }
+ break;
+ case ConstructorKind::STRUCT: {
+ // Struct pattern is always covered by a other struct constructor.
+ return true;
+ }
+ break;
+ // TODO: support references
+ case ConstructorKind::REFERENCE:
+ default:
+ rust_unreachable ();
+ }
+}
+
+bool
+Constructor::operator< (const Constructor &o) const
+{
+ if (kind != o.kind)
+ return kind < o.kind;
+
+ switch (kind)
+ {
+ case ConstructorKind::VARIANT:
+ return variant_idx < o.variant_idx;
+ case ConstructorKind::INT_RANGE:
+ return int_range.lo < o.int_range.lo
+ || (int_range.lo == o.int_range.lo
+ && int_range.hi < o.int_range.hi);
+ case ConstructorKind::STRUCT:
+ case ConstructorKind::WILDCARD:
+ case ConstructorKind::REFERENCE:
+ return false;
+ default:
+ rust_unreachable ();
+ }
+}
+
+std::string
+Constructor::to_string () const
+{
+ switch (kind)
+ {
+ case ConstructorKind::STRUCT:
+ return "STRUCT";
+ case ConstructorKind::VARIANT:
+ return "VARIANT(" + std::to_string (variant_idx) + ")";
+ case ConstructorKind::INT_RANGE:
+ return "RANGE" + std::to_string (int_range.lo) + ".."
+ + std::to_string (int_range.hi);
+ case ConstructorKind::WILDCARD:
+ return "_";
+ case ConstructorKind::REFERENCE:
+ return "REF";
+ default:
+ rust_unreachable ();
+ }
+}
+
+std::vector<DeconstructedPat>
+DeconstructedPat::specialize (const Constructor &other_ctor,
+ int other_ctor_arity) const
+{
+ rust_assert (other_ctor.is_covered_by (ctor));
+ if (ctor.is_wildcard ())
+ return std::vector<DeconstructedPat> (
+ other_ctor_arity,
+ DeconstructedPat (Constructor::make_wildcard (), locus));
+
+ return fields;
+}
+
+std::string
+DeconstructedPat::to_string () const
+{
+ std::string s = ctor.to_string () + "[";
+ for (auto &f : fields)
+ s += f.to_string () + ", ";
+
+ s += "](arity=" + std::to_string (arity) + ")";
+ return s;
+}
+
+bool
+PatOrWild::is_covered_by (const Constructor &c) const
+{
+ if (pat.has_value ())
+ return pat.value ().get_ctor ().is_covered_by (c);
+ else
+ return true;
+}
+
+std::vector<PatOrWild>
+PatOrWild::specialize (const Constructor &other_ctor,
+ int other_ctor_arity) const
+{
+ if (pat.has_value ())
+ {
+ auto v = pat.value ().specialize (other_ctor, other_ctor_arity);
+ std::vector<PatOrWild> ret;
+ for (auto &pat : v)
+ ret.push_back (PatOrWild::make_pattern (pat));
+
+ return ret;
+ }
+ else
+ {
+ return std::vector<PatOrWild> (other_ctor_arity,
+ PatOrWild::make_wildcard ());
+ }
+}
+
+std::string
+PatOrWild::to_string () const
+{
+ if (pat.has_value ())
+ return pat.value ().to_string ();
+ else
+ return "Wild";
+}
+
+void
+PatStack::pop_head_constructor (const Constructor &other_ctor,
+ int other_ctor_arity)
+{
+ rust_assert (!pats.empty ());
+ rust_assert (other_ctor.is_covered_by (head ().ctor ()));
+
+ PatOrWild &hd = head ();
+ auto v = hd.specialize (other_ctor, other_ctor_arity);
+ {
+ std::string s = "[";
+ for (auto &pat : v)
+ s += pat.to_string () + ", ";
+ s += "]";
+
+ rust_debug ("specialize %s with %s to %s", hd.to_string ().c_str (),
+ other_ctor.to_string ().c_str (), s.c_str ());
+ }
+ pop_head ();
+ for (auto &pat : v)
+ pats.push_back (pat);
+}
+
+std::string
+MatrixRow::to_string () const
+{
+ std::string s;
+ for (const PatOrWild &pat : pats.get_subpatterns ())
+ s += pat.to_string () + ", ";
+ return s;
+}
+
+std::vector<PlaceInfo>
+PlaceInfo::specialize (const Constructor &c) const
+{
+ switch (c.get_kind ())
+ {
+ case Constructor::ConstructorKind::WILDCARD:
+ case Constructor::ConstructorKind::INT_RANGE: {
+ return {};
+ }
+ break;
+ case Constructor::ConstructorKind::STRUCT:
+ case Constructor::ConstructorKind::VARIANT: {
+ rust_assert (ty->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty);
+ switch (adt->get_adt_kind ())
+ {
+ case TyTy::ADTType::ADTKind::ENUM:
+ case TyTy::ADTType::ADTKind::STRUCT_STRUCT:
+ case TyTy::ADTType::ADTKind::TUPLE_STRUCT: {
+ TyTy::VariantDef *variant
+ = adt->get_variants ().at (c.get_variant_index ());
+ if (variant->get_variant_type ()
+ == TyTy::VariantDef::VariantType::NUM)
+ return {};
+
+ std::vector<PlaceInfo> new_place_infos;
+ for (auto &field : variant->get_fields ())
+ new_place_infos.push_back (field->get_field_type ());
+
+ return new_place_infos;
+ }
+ break;
+ case TyTy::ADTType::ADTKind::UNION: {
+ // TODO: support unions
+ rust_unreachable ();
+ }
+ }
+ }
+ break;
+ default: {
+ rust_unreachable ();
+ }
+ break;
+ }
+
+ rust_unreachable ();
+}
+
+Matrix
+Matrix::specialize (const Constructor &ctor) const
+{
+ auto subfields_place_info = place_infos.at (0).specialize (ctor);
+
+ std::vector<MatrixRow> new_rows;
+ for (const MatrixRow &row : rows)
+ {
+ PatStack pats = row.get_pats_clone ();
+ const PatOrWild &hd = pats.head ();
+ if (ctor.is_covered_by (hd.ctor ()))
+ {
+ pats.pop_head_constructor (ctor, subfields_place_info.size ());
+ new_rows.push_back (MatrixRow (pats, row.is_under_guard ()));
+ }
+ }
+
+ if (place_infos.empty ())
+ return Matrix (new_rows, {});
+
+ // push subfields of the first fields after specialization
+ std::vector<PlaceInfo> new_place_infos = subfields_place_info;
+ // add place infos for the rest of the fields
+ for (size_t i = 1; i < place_infos.size (); i++)
+ new_place_infos.push_back (place_infos.at (i));
+
+ return Matrix (new_rows, new_place_infos);
+}
+
+std::string
+Matrix::to_string () const
+{
+ std::string s = "[\n";
+ for (const MatrixRow &row : rows)
+ s += "row: " + row.to_string () + "\n";
+
+ s += "](place_infos=[";
+ for (const PlaceInfo &place_info : place_infos)
+ s += place_info.get_type ()->as_string () + ", ";
+
+ s += "])";
+ return s;
+}
+
+std::string
+WitnessPat::to_string () const
+{
+ switch (ctor.get_kind ())
+ {
+ case Constructor::ConstructorKind::STRUCT: {
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty);
+ TyTy::VariantDef *variant
+ = adt->get_variants ().at (ctor.get_variant_index ());
+ std::string buf;
+ buf += adt->get_identifier ();
+
+ buf += " {";
+ if (!fields.empty ())
+ buf += " ";
+
+ for (size_t i = 0; i < fields.size (); i++)
+ {
+ buf += variant->get_fields ().at (i)->get_name () + ": ";
+ buf += fields.at (i).to_string ();
+ if (i < fields.size () - 1)
+ buf += ", ";
+ }
+ if (!fields.empty ())
+ buf += " ";
+
+ buf += "}";
+ return buf;
+ }
+ break;
+ case Constructor::ConstructorKind::VARIANT: {
+ std::string buf;
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty);
+ buf += adt->get_identifier ();
+ TyTy::VariantDef *variant
+ = adt->get_variants ().at (ctor.get_variant_index ());
+ buf += "::" + variant->get_identifier ();
+
+ switch (variant->get_variant_type ())
+ {
+ case TyTy::VariantDef::VariantType::NUM: {
+ return buf;
+ }
+ break;
+ case TyTy::VariantDef::VariantType::TUPLE: {
+ buf += "(";
+ for (size_t i = 0; i < fields.size (); i++)
+ {
+ buf += fields.at (i).to_string ();
+ if (i < fields.size () - 1)
+ buf += ", ";
+ }
+ buf += ")";
+ return buf;
+ }
+ break;
+ case TyTy::VariantDef::VariantType::STRUCT: {
+ buf += " {";
+ if (!fields.empty ())
+ buf += " ";
+
+ for (size_t i = 0; i < fields.size (); i++)
+ {
+ buf += variant->get_fields ().at (i)->get_name () + ": ";
+ buf += fields.at (i).to_string ();
+ if (i < fields.size () - 1)
+ buf += ", ";
+ }
+
+ if (!fields.empty ())
+ buf += " ";
+
+ buf += "}";
+ }
+ break;
+ default: {
+ rust_unreachable ();
+ }
+ break;
+ }
+ return buf;
+ }
+ break;
+ case Constructor::ConstructorKind::INT_RANGE: {
+ // TODO: implement
+ rust_unreachable ();
+ }
+ break;
+ case Constructor::ConstructorKind::WILDCARD: {
+ return "_";
+ }
+ break;
+ case Constructor::ConstructorKind::REFERENCE: {
+ // TODO: implement
+ rust_unreachable ();
+ }
+ break;
+ default: {
+ rust_unreachable ();
+ }
+ break;
+ }
+ rust_unreachable ();
+}
+
+void
+WitnessMatrix::apply_constructor (const Constructor &ctor,
+ const std::set<Constructor> &missings,
+ TyTy::BaseType *ty)
+{
+ int arity = 0;
+ // TODO: only support struct and variant ctor for now.
+ switch (ctor.get_kind ())
+ {
+ case Constructor::ConstructorKind::WILDCARD: {
+ arity = 0;
+ }
+ break;
+ case Constructor::ConstructorKind::STRUCT:
+ case Constructor::ConstructorKind::VARIANT: {
+ if (ty->get_kind () == TyTy::TypeKind::ADT)
+ {
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty);
+ TyTy::VariantDef *variant
+ = adt->get_variants ().at (ctor.get_variant_index ());
+ if (variant->get_variant_type () == TyTy::VariantDef::NUM)
+ arity = 0;
+ else
+ arity = variant->get_fields ().size ();
+ }
+ }
+ break;
+ default: {
+ rust_unreachable ();
+ }
+ }
+
+ std::string buf;
+ for (auto &stack : patstacks)
+ {
+ buf += "[";
+ for (auto &pat : stack)
+ buf += pat.to_string () + ", ";
+
+ buf += "]\n";
+ }
+ rust_debug ("witness pats:\n%s", buf.c_str ());
+
+ for (auto &stack : patstacks)
+ {
+ std::vector<WitnessPat> subfield;
+ for (int i = 0; i < arity; i++)
+ {
+ if (stack.empty ())
+ subfield.push_back (WitnessPat::make_wildcard (ty));
+ else
+ {
+ subfield.push_back (stack.back ());
+ stack.pop_back ();
+ }
+ }
+
+ stack.push_back (WitnessPat (ctor, subfield, ty));
+ }
+}
+
+void
+WitnessMatrix::extend (const WitnessMatrix &other)
+{
+ patstacks.insert (patstacks.end (), other.patstacks.begin (),
+ other.patstacks.end ());
+}
+
+// forward declarations
+static DeconstructedPat
+lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern *pattern,
+ TyTy::BaseType *scrutinee_ty);
+
+static DeconstructedPat
+lower_tuple_pattern (Resolver::TypeCheckContext *ctx,
+ HIR::TupleStructPattern *pattern,
+ TyTy::VariantDef *variant, Constructor &ctor)
+{
+ int arity = variant->get_fields ().size ();
+ HIR::TupleStructItems *elems = pattern->get_items ().get ();
+
+ std::vector<DeconstructedPat> fields;
+ switch (elems->get_item_type ())
+ {
+ case HIR::TupleStructItems::ItemType::MULTIPLE: {
+ HIR::TupleStructItemsNoRange *multiple
+ = static_cast<HIR::TupleStructItemsNoRange *> (elems);
+
+ rust_assert (variant->get_fields ().size ()
+ == multiple->get_patterns ().size ());
+ for (size_t i = 0; i < multiple->get_patterns ().size (); i++)
+ {
+ fields.push_back (
+ lower_pattern (ctx, multiple->get_patterns ().at (i).get (),
+ variant->get_fields ().at (i)->get_field_type ()));
+ }
+ return DeconstructedPat (ctor, arity, fields, pattern->get_locus ());
+ }
+ break;
+ case HIR::TupleStructItems::ItemType::RANGED: {
+ // TODO: ranged tuple struct items
+ rust_unreachable ();
+ }
+ break;
+ default: {
+ rust_unreachable ();
+ }
+ }
+}
+
+static DeconstructedPat
+lower_struct_pattern (Resolver::TypeCheckContext *ctx,
+ HIR::StructPattern *pattern, TyTy::VariantDef *variant,
+ Constructor ctor)
+{
+ int arity = variant->get_fields ().size ();
+
+ // Initialize all field patterns to wildcard.
+ std::vector<DeconstructedPat> fields
+ = std::vector<DeconstructedPat> (arity, DeconstructedPat::make_wildcard (
+ pattern->get_locus ()));
+
+ std::map<std::string, int> field_map;
+ for (int i = 0; i < arity; i++)
+ {
+ auto &f = variant->get_fields ().at (i);
+ field_map[f->get_name ()] = i;
+ }
+
+ // Fill in the fields with the present patterns.
+ HIR::StructPatternElements elems = pattern->get_struct_pattern_elems ();
+ for (auto &elem : elems.get_struct_pattern_fields ())
+ {
+ switch (elem->get_item_type ())
+ {
+ case HIR::StructPatternField::ItemType::IDENT: {
+ HIR::StructPatternFieldIdent *ident
+ = static_cast<HIR::StructPatternFieldIdent *> (elem.get ());
+ int field_idx
+ = field_map.at (ident->get_identifier ().as_string ());
+ fields.at (field_idx)
+ = DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::StructPatternField::ItemType::IDENT_PAT: {
+ HIR::StructPatternFieldIdentPat *ident_pat
+ = static_cast<HIR::StructPatternFieldIdentPat *> (elem.get ());
+ int field_idx
+ = field_map.at (ident_pat->get_identifier ().as_string ());
+ fields.at (field_idx) = lower_pattern (
+ ctx, ident_pat->get_pattern ().get (),
+ variant->get_fields ().at (field_idx)->get_field_type ());
+ }
+ break;
+ case HIR::StructPatternField::ItemType::TUPLE_PAT: {
+ // TODO: tuple: pat
+ rust_unreachable ();
+ }
+ break;
+ default: {
+ rust_unreachable ();
+ }
+ }
+ }
+
+ return DeconstructedPat{ctor, arity, fields, pattern->get_locus ()};
+};
+
+static DeconstructedPat
+lower_pattern (Resolver::TypeCheckContext *ctx, HIR::Pattern *pattern,
+ TyTy::BaseType *scrutinee_ty)
+{
+ HIR::Pattern::PatternType pat_type = pattern->get_pattern_type ();
+ switch (pat_type)
+ {
+ case HIR::Pattern::PatternType::WILDCARD:
+ case HIR::Pattern::PatternType::IDENTIFIER: {
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::Pattern::PatternType::PATH: {
+ // TODO: support constants, associated constants, enum variants and
+ // structs
+ // https://doc.rust-lang.org/reference/patterns.html#path-patterns
+ // unimplemented. Treat this pattern as wildcard for now.
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::Pattern::PatternType::REFERENCE: {
+ // TODO: unimplemented. Treat this pattern as wildcard for now.
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::Pattern::PatternType::STRUCT:
+ case HIR::Pattern::PatternType::TUPLE_STRUCT: {
+ HirId path_id = UNKNOWN_HIRID;
+ if (pat_type == HIR::Pattern::PatternType::STRUCT)
+ {
+ HIR::StructPattern *struct_pattern
+ = static_cast<HIR::StructPattern *> (pattern);
+ path_id = struct_pattern->get_path ().get_mappings ().get_hirid ();
+ }
+ else
+ {
+ HIR::TupleStructPattern *tuple_pattern
+ = static_cast<HIR::TupleStructPattern *> (pattern);
+ path_id = tuple_pattern->get_path ().get_mappings ().get_hirid ();
+ }
+
+ rust_assert (scrutinee_ty->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_ty);
+
+ Constructor ctor = Constructor::make_struct ();
+ TyTy::VariantDef *variant;
+ if (adt->is_struct_struct () || adt->is_tuple_struct ())
+ variant = adt->get_variants ().at (0);
+ else if (adt->is_enum ())
+ {
+ HirId variant_id = UNKNOWN_HIRID;
+ bool ok = ctx->lookup_variant_definition (path_id, &variant_id);
+ rust_assert (ok);
+
+ int variant_idx;
+ ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_idx);
+ rust_assert (ok);
+
+ ctor = Constructor::make_variant (variant_idx);
+ }
+ else
+ {
+ rust_unreachable ();
+ }
+ rust_assert (variant->get_variant_type ()
+ == TyTy::VariantDef::VariantType::TUPLE
+ || variant->get_variant_type ()
+ == TyTy::VariantDef::VariantType::STRUCT);
+
+ if (pat_type == HIR::Pattern::PatternType::STRUCT)
+ {
+ HIR::StructPattern *struct_pattern
+ = static_cast<HIR::StructPattern *> (pattern);
+ return lower_struct_pattern (ctx, struct_pattern, variant, ctor);
+ }
+ else
+ {
+ HIR::TupleStructPattern *tuple_pattern
+ = static_cast<HIR::TupleStructPattern *> (pattern);
+ return lower_tuple_pattern (ctx, tuple_pattern, variant, ctor);
+ }
+ }
+ break;
+ case HIR::Pattern::PatternType::TUPLE: {
+ // TODO: unimplemented. Treat this pattern as wildcard for now.
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::Pattern::PatternType::SLICE: {
+ // TODO: unimplemented. Treat this pattern as wildcard for now.
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::Pattern::PatternType::ALT: {
+ // TODO: unimplemented. Treat this pattern as wildcard for now.
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::Pattern::PatternType::LITERAL: {
+ // TODO: unimplemented. Treat this pattern as wildcard for now.
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::Pattern::PatternType::RANGE: {
+ // TODO: unimplemented. Treat this pattern as wildcard for now.
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ case HIR::Pattern::PatternType::GROUPED: {
+ // TODO: unimplemented. Treat this pattern as wildcard for now.
+ return DeconstructedPat::make_wildcard (pattern->get_locus ());
+ }
+ break;
+ default: {
+ rust_unreachable ();
+ }
+ }
+}
+
+static MatchArm
+lower_arm (Resolver::TypeCheckContext *ctx, HIR::MatchCase &arm,
+ TyTy::BaseType *scrutinee_ty)
+{
+ rust_assert (arm.get_arm ().get_patterns ().size () > 0);
+
+ DeconstructedPat pat
+ = lower_pattern (ctx, arm.get_arm ().get_patterns ().at (0).get (),
+ scrutinee_ty);
+ return MatchArm (pat, arm.get_arm ().has_match_arm_guard ());
+}
+
+std::pair<std::set<Constructor>, std::set<Constructor>>
+split_constructors (std::vector<Constructor> &ctors, PlaceInfo &place_info)
+{
+ bool all_wildcard = true;
+ for (auto &ctor : ctors)
+ {
+ if (!ctor.is_wildcard ())
+ all_wildcard = false;
+ }
+
+ // first pass for the case that all patterns are wildcard
+ if (all_wildcard)
+ return std::make_pair (std::set<Constructor> (
+ {Constructor::make_wildcard ()}),
+ std::set<Constructor> ());
+
+ // TODO: only support enums and structs for now.
+ TyTy::BaseType *ty = place_info.get_type ();
+ rust_assert (ty->get_kind () == TyTy::TypeKind::ADT);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (ty);
+ rust_assert (adt->is_enum () || adt->is_struct_struct ()
+ || adt->is_tuple_struct ());
+
+ std::set<Constructor> universe;
+ if (adt->is_enum ())
+ {
+ for (size_t i = 0; i < adt->get_variants ().size (); i++)
+ universe.insert (Constructor::make_variant (i));
+ }
+ else if (adt->is_struct_struct () || adt->is_tuple_struct ())
+ {
+ universe.insert (Constructor::make_struct ());
+ }
+
+ std::set<Constructor> present;
+ for (auto &ctor : ctors)
+ {
+ if (ctor.is_wildcard ())
+ return std::make_pair (universe, std::set<Constructor> ());
+ else
+ present.insert (ctor);
+ }
+
+ std::set<Constructor> missing;
+ std::set_difference (universe.begin (), universe.end (), present.begin (),
+ present.end (), std::inserter (missing, missing.end ()));
+ return std::make_pair (universe, missing);
+}
+
+// The core of the algorithm. It computes the usefulness and exhaustiveness of a
+// given matrix recursively.
+// TODO: calculate usefulness
+static WitnessMatrix
+compute_exhaustiveness_and_usefulness (Resolver::TypeCheckContext *ctx,
+ Matrix &matrix)
+{
+ rust_debug ("call compute_exhaustiveness_and_usefulness");
+ rust_debug ("matrix: %s", matrix.to_string ().c_str ());
+
+ if (matrix.get_rows ().empty ())
+ {
+ // no rows left. This means a non-exhaustive pattern.
+ rust_debug ("non-exhaustive subpattern found");
+ return WitnessMatrix::make_unit ();
+ }
+
+ // Base case: there are no columns in matrix.
+ if (matrix.get_place_infos ().empty ())
+ return WitnessMatrix::make_empty ();
+
+ std::vector<Constructor> heads;
+ for (auto head : matrix.heads ())
+ heads.push_back (head.ctor ());
+
+ // TODO: not sure missing ctors need to be calculated
+ auto ctors_and_missings
+ = split_constructors (heads, matrix.get_place_infos ().at (0));
+ std::set<Constructor> ctors = ctors_and_missings.first;
+ std::set<Constructor> missings = ctors_and_missings.second;
+
+ WitnessMatrix ret = WitnessMatrix::make_empty ();
+ for (auto &ctor : ctors)
+ {
+ rust_debug ("specialize with %s", ctor.to_string ().c_str ());
+ // TODO: Instead of creating new matrix, we can change the original matrix
+ // and use it for sub-pattern matching. It will significantly reduce
+ // memory usage.
+ Matrix spec_matrix = matrix.specialize (ctor);
+
+ WitnessMatrix witness
+ = compute_exhaustiveness_and_usefulness (ctx, spec_matrix);
+
+ TyTy::BaseType *ty = matrix.get_place_infos ().at (0).get_type ();
+ witness.apply_constructor (ctor, missings, ty);
+ ret.extend (witness);
+ }
+
+ return ret;
+}
+
+static void
+emit_exhaustiveness_error (Resolver::TypeCheckContext *ctx,
+ HIR::MatchExpr &expr, WitnessMatrix &witness)
+{
+ TyTy::BaseType *scrutinee_ty;
+ bool ok = ctx->lookup_type (
+ expr.get_scrutinee_expr ()->get_mappings ().get_hirid (), &scrutinee_ty);
+ rust_assert (ok);
+
+ if (!witness.empty ())
+ {
+ std::stringstream buf;
+ for (size_t i = 0; i < witness.get_stacks ().size (); i++)
+ {
+ auto &stack = witness.get_stacks ().at (i);
+ WitnessPat w = WitnessPat::make_wildcard (scrutinee_ty);
+ if (!stack.empty ())
+ w = stack.at (0);
+
+ rust_debug ("Witness[%d]: %s", (int) i, w.to_string ().c_str ());
+ buf << "'" << w.to_string () << "'";
+ if (i != witness.get_stacks ().size () - 1)
+ buf << " and ";
+ }
+ rust_error_at (expr.get_scrutinee_expr ()->get_locus (),
+ "non-exhaustive patterns: %s not covered",
+ buf.str ().c_str ());
+ }
+ else
+ {
+ rust_debug ("no witness found");
+ }
+}
+
+// Entry point for computing match usefulness and check exhaustiveness
+void
+check_match_usefulness (Resolver::TypeCheckContext *ctx,
+ TyTy::BaseType *scrutinee_ty, HIR::MatchExpr &expr)
+{
+ // Lower the arms to a more convenient representation.
+ std::vector<MatrixRow> rows;
+ for (auto &arm : expr.get_match_cases ())
+ {
+ PatStack pats;
+ MatchArm lowered = lower_arm (ctx, arm, scrutinee_ty);
+ PatOrWild pat = PatOrWild::make_pattern (lowered.get_pat ());
+ pats.push (pat);
+ rows.push_back (MatrixRow (pats, lowered.has_guard ()));
+ }
+
+ std::vector<PlaceInfo> place_infos = {{PlaceInfo (scrutinee_ty)}};
+ Matrix matrix{rows, place_infos};
+
+ WitnessMatrix witness = compute_exhaustiveness_and_usefulness (ctx, matrix);
+
+ emit_exhaustiveness_error (ctx, expr, witness);
+}
+
+} // namespace Analysis
+} // namespace Rust
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
new file mode 100644
index 0000000..1af02ba
--- /dev/null
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
@@ -0,0 +1,526 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_HIR_PATTERN_ANALYSIS_H
+#define RUST_HIR_PATTERN_ANALYSIS_H
+
+#include "rust-system.h"
+#include "rust-hir-expr.h"
+#include "rust-hir-type-check.h"
+#include "rust-system.h"
+#include "rust-tyty.h"
+#include "optional.h"
+#include "rust-hir-visitor.h"
+#include "rust-name-resolver.h"
+
+namespace Rust {
+namespace Analysis {
+
+using namespace HIR;
+
+void
+check_match_usefulness (Resolver::TypeCheckContext *ctx,
+ TyTy::BaseType *scrutinee_ty, HIR::MatchExpr &expr);
+
+class PatternChecker : public HIR::HIRFullVisitor
+{
+public:
+ PatternChecker ();
+
+ void go (HIR::Crate &crate);
+
+private:
+ Resolver::TypeCheckContext &tyctx;
+ Resolver::Resolver &resolver;
+ Analysis::Mappings &mappings;
+
+ virtual void visit (Lifetime &lifetime) override;
+ virtual void visit (LifetimeParam &lifetime_param) override;
+ virtual void visit (PathInExpression &path) override;
+ virtual void visit (TypePathSegment &segment) override;
+ virtual void visit (TypePathSegmentGeneric &segment) override;
+ virtual void visit (TypePathSegmentFunction &segment) override;
+ virtual void visit (TypePath &path) override;
+ virtual void visit (QualifiedPathInExpression &path) override;
+ virtual void visit (QualifiedPathInType &path) override;
+ virtual void visit (LiteralExpr &expr) override;
+ virtual void visit (BorrowExpr &expr) override;
+ virtual void visit (DereferenceExpr &expr) override;
+ virtual void visit (ErrorPropagationExpr &expr) override;
+ virtual void visit (NegationExpr &expr) override;
+ virtual void visit (ArithmeticOrLogicalExpr &expr) override;
+ virtual void visit (ComparisonExpr &expr) override;
+ virtual void visit (LazyBooleanExpr &expr) override;
+ virtual void visit (TypeCastExpr &expr) override;
+ virtual void visit (AssignmentExpr &expr) override;
+ virtual void visit (CompoundAssignmentExpr &expr) override;
+ virtual void visit (GroupedExpr &expr) override;
+ virtual void visit (ArrayElemsValues &elems) override;
+ virtual void visit (ArrayElemsCopied &elems) override;
+ virtual void visit (ArrayExpr &expr) override;
+ virtual void visit (ArrayIndexExpr &expr) override;
+ virtual void visit (TupleExpr &expr) override;
+ virtual void visit (TupleIndexExpr &expr) override;
+ virtual void visit (StructExprStruct &expr) override;
+ virtual void visit (StructExprFieldIdentifier &field) override;
+ virtual void visit (StructExprFieldIdentifierValue &field) override;
+ virtual void visit (StructExprFieldIndexValue &field) override;
+ virtual void visit (StructExprStructFields &expr) override;
+ virtual void visit (StructExprStructBase &expr) override;
+ virtual void visit (CallExpr &expr) override;
+ virtual void visit (MethodCallExpr &expr) override;
+ virtual void visit (FieldAccessExpr &expr) override;
+ virtual void visit (BlockExpr &expr) override;
+ virtual void visit (ClosureExpr &expr) override;
+ virtual void visit (ContinueExpr &expr) override;
+ virtual void visit (BreakExpr &expr) override;
+ virtual void visit (RangeFromToExpr &expr) override;
+ virtual void visit (RangeFromExpr &expr) override;
+ virtual void visit (RangeToExpr &expr) override;
+ virtual void visit (RangeFullExpr &expr) override;
+ virtual void visit (RangeFromToInclExpr &expr) override;
+ virtual void visit (RangeToInclExpr &expr) override;
+ virtual void visit (ReturnExpr &expr) override;
+ virtual void visit (UnsafeBlockExpr &expr) override;
+ virtual void visit (LoopExpr &expr) override;
+ virtual void visit (WhileLoopExpr &expr) override;
+ virtual void visit (WhileLetLoopExpr &expr) override;
+ virtual void visit (IfExpr &expr) override;
+ virtual void visit (IfExprConseqElse &expr) override;
+ virtual void visit (IfLetExpr &expr) override;
+ virtual void visit (IfLetExprConseqElse &expr) override;
+ virtual void visit (HIR::MatchExpr &expr) override;
+ virtual void visit (AwaitExpr &expr) override;
+ virtual void visit (AsyncBlockExpr &expr) override;
+ virtual void visit (InlineAsm &expr) override;
+ virtual void visit (TypeParam &param) override;
+ virtual void visit (ConstGenericParam &param) override;
+ virtual void visit (LifetimeWhereClauseItem &item) override;
+ virtual void visit (TypeBoundWhereClauseItem &item) override;
+ virtual void visit (Module &module) override;
+ virtual void visit (ExternCrate &crate) override;
+ virtual void visit (UseTreeGlob &use_tree) override;
+ virtual void visit (UseTreeList &use_tree) override;
+ virtual void visit (UseTreeRebind &use_tree) override;
+ virtual void visit (UseDeclaration &use_decl) override;
+ virtual void visit (Function &function) override;
+ virtual void visit (TypeAlias &type_alias) override;
+ virtual void visit (StructStruct &struct_item) override;
+ virtual void visit (TupleStruct &tuple_struct) override;
+ virtual void visit (EnumItem &item) override;
+ virtual void visit (EnumItemTuple &item) override;
+ virtual void visit (EnumItemStruct &item) override;
+ virtual void visit (EnumItemDiscriminant &item) override;
+ virtual void visit (Enum &enum_item) override;
+ virtual void visit (Union &union_item) override;
+ virtual void visit (ConstantItem &const_item) override;
+ virtual void visit (StaticItem &static_item) override;
+ virtual void visit (TraitItemFunc &item) override;
+ virtual void visit (TraitItemConst &item) override;
+ virtual void visit (TraitItemType &item) override;
+ virtual void visit (Trait &trait) override;
+ virtual void visit (ImplBlock &impl) override;
+ virtual void visit (ExternalStaticItem &item) override;
+ virtual void visit (ExternalFunctionItem &item) override;
+ virtual void visit (ExternalTypeItem &item) override;
+ virtual void visit (ExternBlock &block) override;
+ virtual void visit (LiteralPattern &pattern) override;
+ virtual void visit (IdentifierPattern &pattern) override;
+ virtual void visit (WildcardPattern &pattern) override;
+ virtual void visit (RangePatternBoundLiteral &bound) override;
+ virtual void visit (RangePatternBoundPath &bound) override;
+ virtual void visit (RangePatternBoundQualPath &bound) override;
+ virtual void visit (RangePattern &pattern) override;
+ virtual void visit (ReferencePattern &pattern) override;
+ virtual void visit (StructPatternFieldTuplePat &field) override;
+ virtual void visit (StructPatternFieldIdentPat &field) override;
+ virtual void visit (StructPatternFieldIdent &field) override;
+ virtual void visit (StructPattern &pattern) override;
+ virtual void visit (TupleStructItemsNoRange &tuple_items) override;
+ virtual void visit (TupleStructItemsRange &tuple_items) override;
+ virtual void visit (TupleStructPattern &pattern) override;
+ virtual void visit (TuplePatternItemsMultiple &tuple_items) override;
+ virtual void visit (TuplePatternItemsRanged &tuple_items) override;
+ virtual void visit (TuplePattern &pattern) override;
+ virtual void visit (SlicePattern &pattern) override;
+ virtual void visit (AltPattern &pattern) override;
+ virtual void visit (EmptyStmt &stmt) override;
+ virtual void visit (LetStmt &stmt) override;
+ virtual void visit (ExprStmt &stmt) override;
+ virtual void visit (TraitBound &bound) override;
+ virtual void visit (ImplTraitType &type) override;
+ virtual void visit (TraitObjectType &type) override;
+ virtual void visit (ParenthesisedType &type) override;
+ virtual void visit (ImplTraitTypeOneBound &type) override;
+ virtual void visit (TupleType &type) override;
+ virtual void visit (NeverType &type) override;
+ virtual void visit (RawPointerType &type) override;
+ virtual void visit (ReferenceType &type) override;
+ virtual void visit (ArrayType &type) override;
+ virtual void visit (SliceType &type) override;
+ virtual void visit (InferredType &type) override;
+ virtual void visit (BareFunctionType &type) override;
+};
+
+struct IntRange
+{
+ int64_t lo;
+ int64_t hi;
+};
+
+class Constructor
+{
+public:
+ enum class ConstructorKind
+ {
+ // tuple or struct
+ STRUCT,
+ // enum variant
+ VARIANT,
+ // integers
+ INT_RANGE,
+ // user-provided wildcard
+ WILDCARD,
+ // references
+ REFERENCE,
+ };
+
+ static Constructor make_wildcard ()
+ {
+ return Constructor (ConstructorKind::WILDCARD);
+ }
+
+ static Constructor make_reference ()
+ {
+ return Constructor (ConstructorKind::REFERENCE);
+ }
+
+ static Constructor make_struct ()
+ {
+ Constructor c (ConstructorKind::STRUCT);
+ c.variant_idx = 0;
+ return c;
+ }
+
+ static Constructor make_variant (int variant_idx)
+ {
+ Constructor c (ConstructorKind::VARIANT);
+ c.variant_idx = variant_idx;
+ return c;
+ }
+
+ ConstructorKind get_kind () const { return kind; }
+
+ int get_variant_index () const
+ {
+ rust_assert (kind == ConstructorKind::VARIANT
+ || kind == ConstructorKind::STRUCT);
+ return variant_idx;
+ }
+
+ bool is_covered_by (const Constructor &o) const;
+
+ bool is_wildcard () const { return kind == ConstructorKind::WILDCARD; }
+
+ // Requrired by std::set<T>
+ bool operator< (const Constructor &o) const;
+
+ std::string to_string () const;
+
+private:
+ Constructor (ConstructorKind kind) : kind (kind), variant_idx (0) {}
+ ConstructorKind kind;
+
+ union
+ {
+ // for enum variants, the variant index (always 0 for structs)
+ int variant_idx;
+
+ // for integer ranges, the range
+ IntRange int_range;
+ };
+};
+
+class DeconstructedPat
+{
+public:
+ DeconstructedPat (Constructor ctor, int arity,
+ std::vector<DeconstructedPat> fields, location_t locus)
+ : ctor (ctor), arity (arity), fields (fields)
+ {}
+
+ static DeconstructedPat make_wildcard (location_t locus)
+ {
+ return DeconstructedPat (Constructor::make_wildcard (), locus);
+ }
+
+ static DeconstructedPat make_reference (location_t locus)
+ {
+ return DeconstructedPat (Constructor::make_reference (), locus);
+ }
+
+ const Constructor &get_ctor () const { return ctor; }
+
+ int get_arity () const { return arity; }
+
+ std::vector<DeconstructedPat> specialize (const Constructor &other_ctor,
+ int other_ctor_arity) const;
+
+ std::string to_string () const;
+
+private:
+ DeconstructedPat (Constructor ctor, location_t locus)
+ : ctor (ctor), arity (0), locus (locus)
+ {}
+
+ Constructor ctor;
+ int arity;
+ std::vector<DeconstructedPat> fields;
+ location_t locus;
+};
+
+class PatOrWild
+{
+public:
+ static PatOrWild make_pattern (DeconstructedPat pat)
+ {
+ return PatOrWild (pat);
+ }
+
+ static PatOrWild make_wildcard () { return PatOrWild ({}); }
+
+ bool is_wildcard () const
+ {
+ return !(pat.has_value () && !pat.value ().get_ctor ().is_wildcard ());
+ }
+
+ bool is_covered_by (const Constructor &c) const;
+
+ // Returns the pattern if it is not a wildcard.
+ const tl::optional<DeconstructedPat> &get_pat () const
+ {
+ rust_assert (pat.has_value ());
+ return pat;
+ }
+
+ Constructor ctor () const
+ {
+ if (pat.has_value ())
+ return pat.value ().get_ctor ();
+ else
+ return Constructor::make_wildcard ();
+ }
+
+ std::vector<PatOrWild> specialize (const Constructor &other_ctor,
+ int other_ctor_arity) const;
+
+ std::string to_string () const;
+
+private:
+ PatOrWild (tl::optional<DeconstructedPat> pat) : pat (pat) {}
+
+ tl::optional<DeconstructedPat> pat;
+};
+
+class PatStack
+{
+public:
+ PatStack () : relevant (false) {}
+
+ void push (PatOrWild pat) { pats.push_back (pat); }
+
+ bool empty () const { return pats.empty (); }
+
+ PatOrWild &head ()
+ {
+ rust_assert (!pats.empty ());
+ return pats.front ();
+ }
+
+ const PatOrWild &head () const
+ {
+ rust_assert (!pats.empty ());
+ return pats.front ();
+ }
+
+ // Only called if the head is a constructor which is convered by o.
+ void pop_head_constructor (const Constructor &other_ctor,
+ int other_ctor_arity);
+
+ const std::deque<PatOrWild> &get_subpatterns () const { return pats; }
+
+private:
+ void pop_head () { pats.pop_front (); }
+
+ std::deque<PatOrWild> pats;
+ bool relevant;
+};
+
+class MatrixRow
+{
+public:
+ MatrixRow (PatStack pats, bool is_under_guard_)
+ : pats (pats), is_under_guard_ (is_under_guard_)
+ // useful (false),
+ // head_is_branch (false),
+ {}
+
+ PatStack &get_pats () { return pats; }
+
+ PatStack get_pats_clone () const { return pats; }
+
+ const PatOrWild &head () const { return pats.head (); }
+ PatOrWild &head () { return pats.head (); }
+
+ bool is_under_guard () const { return is_under_guard_; }
+
+ std::string to_string () const;
+
+private:
+ PatStack pats;
+ bool is_under_guard_;
+ // TODO: manage usefulness
+};
+
+class PlaceInfo
+{
+public:
+ PlaceInfo (TyTy::BaseType *ty) : ty (ty) {}
+
+ TyTy::BaseType *get_type () const { return ty; }
+
+ std::vector<PlaceInfo> specialize (const Constructor &c) const;
+
+private:
+ TyTy::BaseType *ty;
+};
+
+class Matrix
+{
+public:
+ Matrix (std::vector<MatrixRow> rows, std::vector<PlaceInfo> place_infos)
+ : rows (rows), place_infos (place_infos)
+ {}
+
+ Matrix () {}
+
+ std::vector<MatrixRow> &get_rows () { return rows; }
+
+ void push_row (const MatrixRow &row) { rows.push_back (row); }
+
+ std::vector<PlaceInfo> &get_place_infos () { return place_infos; }
+
+ std::vector<PatOrWild> heads () const
+ {
+ std::vector<PatOrWild> ret;
+ for (const MatrixRow &row : rows)
+ ret.push_back (row.head ());
+
+ return ret;
+ }
+
+ Matrix specialize (const Constructor &ctor) const;
+
+ std::string to_string () const;
+
+private:
+ std::vector<MatrixRow> rows;
+ std::vector<PlaceInfo> place_infos;
+};
+
+class MatchArm
+{
+public:
+ MatchArm (DeconstructedPat pat, bool has_guard_)
+ : pat (pat), has_guard_ (has_guard_)
+ {}
+
+ DeconstructedPat get_pat () const { return pat; }
+
+ bool has_guard () const { return has_guard_; }
+
+private:
+ DeconstructedPat pat;
+ bool has_guard_;
+};
+
+class WitnessPat
+{
+public:
+ WitnessPat (Constructor ctor, std::vector<WitnessPat> fields,
+ TyTy::BaseType *ty)
+ : ctor (ctor), fields (fields), ty (ty)
+ {}
+
+ static WitnessPat make_wildcard (TyTy::BaseType *ty)
+ {
+ return WitnessPat (Constructor::make_wildcard (), {}, ty);
+ }
+
+ const Constructor &get_ctor () const { return ctor; }
+
+ const std::vector<WitnessPat> &get_fields () const { return fields; }
+
+ TyTy::BaseType *get_type () const { return ty; }
+
+ std::string to_string () const;
+
+private:
+ Constructor ctor;
+ std::vector<WitnessPat> fields;
+ TyTy::BaseType *ty;
+};
+
+class WitnessMatrix
+{
+public:
+ // Create an empty witness matrix.
+ static WitnessMatrix make_empty () { return WitnessMatrix ({}); }
+
+ // Create a unit witness matrix, a new single witness.
+ static WitnessMatrix make_unit ()
+ {
+ return WitnessMatrix ({std::vector<WitnessPat> ()});
+ }
+
+ bool empty () const { return patstacks.empty (); }
+
+ const std::vector<std::vector<WitnessPat>> &get_stacks () const
+ {
+ return patstacks;
+ }
+
+ // Reverses specialization.
+ void apply_constructor (const Constructor &ctor,
+ const std::set<Constructor> &missings,
+ TyTy::BaseType *ty);
+
+ void extend (const WitnessMatrix &other);
+
+private:
+ WitnessMatrix (std::vector<std::vector<WitnessPat>> patstacks)
+ : patstacks (patstacks)
+ {}
+
+ std::vector<std::vector<WitnessPat>> patstacks;
+};
+
+} // namespace Analysis
+} // namespace Rust
+
+#endif
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc
index c6ed922..4c8db3a 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.cc
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc
@@ -784,7 +784,23 @@ UnsafeChecker::visit (Trait &trait)
void
UnsafeChecker::visit (ImplBlock &impl)
{
- // FIXME: Handle unsafe impls
+ bool safe = !impl.is_unsafe ();
+ // Check for unsafe-only attributes on generics and lifetimes
+ if (safe)
+ for (auto &parm : impl.get_generic_params ())
+ {
+ for (auto o_attr : parm->get_outer_attrs ())
+ {
+ rust_assert (!o_attr.is_inner_attribute ());
+
+ Rust::AST::SimplePath path = o_attr.get_path ();
+ if (path == Values::Attributes::MAY_DANGLE)
+ rust_error_at (
+ o_attr.get_locus (), ErrorCode::E0569,
+ "use of %<may_dangle%> is unsafe and requires unsafe impl");
+ }
+ }
+
for (auto &item : impl.get_impl_items ())
item->accept_vis (*this);
}
diff --git a/gcc/rust/checks/lints/rust-lint-marklive.cc b/gcc/rust/checks/lints/rust-lint-marklive.cc
index 24df933..ca26a66 100644
--- a/gcc/rust/checks/lints/rust-lint-marklive.cc
+++ b/gcc/rust/checks/lints/rust-lint-marklive.cc
@@ -155,7 +155,17 @@ MarkLive::visit_path_segment (HIR::PathExprSegment seg)
//
// We should mark them alive all and ignoring other kind of segments.
// If the segment we dont care then just return false is fine
- if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
+ if (flag_name_resolution_2_0)
+ {
+ auto &nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ if (auto id = nr_ctx.lookup (ast_node_id))
+ ref_node_id = *id;
+ else
+ return false;
+ }
+ else if (!resolver->lookup_resolved_name (ast_node_id, &ref_node_id))
{
if (!resolver->lookup_resolved_type (ast_node_id, &ref_node_id))
return false;
@@ -232,9 +242,22 @@ MarkLive::visit (HIR::TupleIndexExpr &expr)
void
MarkLive::visit (HIR::TypeAlias &alias)
{
- NodeId ast_node_id;
- resolver->lookup_resolved_type (
- alias.get_type_aliased ()->get_mappings ().get_nodeid (), &ast_node_id);
+ NodeId ast_node_id = UNKNOWN_NODEID;
+ if (flag_name_resolution_2_0)
+ {
+ auto &nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ if (auto id = nr_ctx.lookup (
+ alias.get_type_aliased ()->get_mappings ().get_nodeid ()))
+ ast_node_id = *id;
+ }
+ else
+ {
+ resolver->lookup_resolved_type (
+ alias.get_type_aliased ()->get_mappings ().get_nodeid (), &ast_node_id);
+ }
+
if (auto hid = mappings.lookup_node_to_hir (ast_node_id))
mark_hir_id (*hid);
else
diff --git a/gcc/rust/expand/rust-cfg-strip.cc b/gcc/rust/expand/rust-cfg-strip.cc
index 8abc5cb..4e6a8ac 100644
--- a/gcc/rust/expand/rust-cfg-strip.cc
+++ b/gcc/rust/expand/rust-cfg-strip.cc
@@ -195,6 +195,26 @@ CfgStrip::maybe_strip_struct_fields (std::vector<AST::StructField> &fields)
}
void
+CfgStrip::maybe_strip_struct_expr_fields (
+ std::vector<std::unique_ptr<AST::StructExprField>> &fields)
+{
+ for (auto it = fields.begin (); it != fields.end ();)
+ {
+ auto &field = *it;
+
+ auto &field_attrs = field->get_outer_attrs ();
+ expand_cfg_attrs (field_attrs);
+ if (fails_cfg_with_expand (field_attrs))
+ {
+ it = fields.erase (it);
+ continue;
+ }
+
+ ++it;
+ }
+}
+
+void
CfgStrip::maybe_strip_tuple_fields (std::vector<AST::TupleField> &fields)
{
for (auto it = fields.begin (); it != fields.end ();)
@@ -962,6 +982,8 @@ CfgStrip::visit (AST::StructExprStructFields &expr)
"cannot strip expression in this position - outer "
"attributes not allowed");
}
+
+ maybe_strip_struct_expr_fields (expr.get_fields ());
}
void
@@ -1852,6 +1874,10 @@ CfgStrip::visit (AST::StructStruct &struct_item)
}
AST::DefaultASTVisitor::visit (struct_item);
+
+ /* strip struct fields if required - this is presumably
+ * allowed by spec */
+ maybe_strip_struct_fields (struct_item.get_fields ());
}
void
CfgStrip::visit (AST::TupleStruct &tuple_struct)
diff --git a/gcc/rust/expand/rust-cfg-strip.h b/gcc/rust/expand/rust-cfg-strip.h
index 773bfde..4900ae8 100644
--- a/gcc/rust/expand/rust-cfg-strip.h
+++ b/gcc/rust/expand/rust-cfg-strip.h
@@ -36,6 +36,8 @@ public:
void go (AST::Crate &crate);
void maybe_strip_struct_fields (std::vector<AST::StructField> &fields);
+ void maybe_strip_struct_expr_fields (
+ std::vector<std::unique_ptr<AST::StructExprField>> &fields);
void maybe_strip_tuple_fields (std::vector<AST::TupleField> &fields);
void maybe_strip_function_params (
std::vector<std::unique_ptr<AST::Param>> &params);
diff --git a/gcc/rust/expand/rust-derive-clone.cc b/gcc/rust/expand/rust-derive-clone.cc
index 2f2554d..18436be 100644
--- a/gcc/rust/expand/rust-derive-clone.cc
+++ b/gcc/rust/expand/rust-derive-clone.cc
@@ -73,8 +73,9 @@ DeriveClone::clone_fn (std::unique_ptr<Expr> &&clone_expr)
*
*/
std::unique_ptr<Item>
-DeriveClone::clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn,
- std::string name)
+DeriveClone::clone_impl (
+ std::unique_ptr<AssociatedItem> &&clone_fn, std::string name,
+ const std::vector<std::unique_ptr<GenericParam>> &type_generics)
{
// should that be `$crate::core::clone::Clone` instead?
auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
@@ -84,10 +85,79 @@ DeriveClone::clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn,
auto trait_items = std::vector<std::unique_ptr<AssociatedItem>> ();
trait_items.emplace_back (std::move (clone_fn));
+ // we need to build up the generics for this impl block which will be just a
+ // clone of the types specified ones
+ //
+ // for example:
+ //
+ // #[derive(Clone)]
+ // struct Be<T: Clone> { ... }
+ //
+ // we need to generate the impl block:
+ //
+ // impl<T: Clone> Clone for Be<T>
+
+ std::vector<Lifetime> lifetime_args;
+ std::vector<GenericArg> generic_args;
+ std::vector<std::unique_ptr<GenericParam>> impl_generics;
+ for (const auto &generic : type_generics)
+ {
+ switch (generic->get_kind ())
+ {
+ case GenericParam::Kind::Lifetime: {
+ LifetimeParam &lifetime_param = (LifetimeParam &) *generic.get ();
+
+ Lifetime l = builder.new_lifetime (lifetime_param.get_lifetime ());
+ lifetime_args.push_back (std::move (l));
+
+ auto impl_lifetime_param
+ = builder.new_lifetime_param (lifetime_param);
+ impl_generics.push_back (std::move (impl_lifetime_param));
+ }
+ break;
+
+ case GenericParam::Kind::Type: {
+ TypeParam &type_param = (TypeParam &) *generic.get ();
+
+ std::unique_ptr<Type> associated_type = builder.single_type_path (
+ type_param.get_type_representation ().as_string ());
+
+ GenericArg type_arg
+ = GenericArg::create_type (std::move (associated_type));
+ generic_args.push_back (std::move (type_arg));
+
+ auto impl_type_param = builder.new_type_param (type_param);
+ impl_generics.push_back (std::move (impl_type_param));
+ }
+ break;
+
+ case GenericParam::Kind::Const: {
+ rust_unreachable ();
+
+ // TODO
+ // const ConstGenericParam *const_param
+ // = (const ConstGenericParam *) generic.get ();
+ // std::unique_ptr<Expr> const_expr = nullptr;
+
+ // GenericArg type_arg
+ // = GenericArg::create_const (std::move (const_expr));
+ // generic_args.push_back (std::move (type_arg));
+ }
+ break;
+ }
+ }
+
+ GenericArgs generic_args_for_self (lifetime_args, generic_args,
+ {} /*binding args*/, loc);
+ std::unique_ptr<Type> self_type_path
+ = impl_generics.empty ()
+ ? builder.single_type_path (name)
+ : builder.single_generic_type_path (name, generic_args_for_self);
+
return std::unique_ptr<Item> (
new TraitImpl (clone, /* unsafe */ false,
/* exclam */ false, std::move (trait_items),
- /* generics */ {}, builder.single_type_path (name),
+ std::move (impl_generics), std::move (self_type_path),
WhereClause::create_empty (), Visibility::create_private (),
{}, {}, loc));
}
@@ -122,7 +192,8 @@ DeriveClone::visit_tuple (TupleStruct &item)
auto constructor = builder.call (std::move (path), std::move (cloned_fields));
expanded = clone_impl (clone_fn (std::move (constructor)),
- item.get_identifier ().as_string ());
+ item.get_identifier ().as_string (),
+ item.get_generic_params ());
}
void
@@ -133,7 +204,8 @@ DeriveClone::visit_struct (StructStruct &item)
auto unit_ctor
= builder.struct_expr_struct (item.get_struct_name ().as_string ());
expanded = clone_impl (clone_fn (std::move (unit_ctor)),
- item.get_struct_name ().as_string ());
+ item.get_struct_name ().as_string (),
+ item.get_generic_params ());
return;
}
@@ -151,7 +223,8 @@ DeriveClone::visit_struct (StructStruct &item)
auto ctor = builder.struct_expr (item.get_struct_name ().as_string (),
std::move (cloned_fields));
expanded = clone_impl (clone_fn (std::move (ctor)),
- item.get_struct_name ().as_string ());
+ item.get_struct_name ().as_string (),
+ item.get_generic_params ());
}
void
@@ -187,7 +260,8 @@ DeriveClone::visit_union (Union &item)
auto block = builder.block (std::move (stmts), std::move (tail_expr));
expanded = clone_impl (clone_fn (std::move (block)),
- item.get_identifier ().as_string ());
+ item.get_identifier ().as_string (),
+ item.get_generic_params ());
}
} // namespace AST
diff --git a/gcc/rust/expand/rust-derive-clone.h b/gcc/rust/expand/rust-derive-clone.h
index ab64829..4a43b2a 100644
--- a/gcc/rust/expand/rust-derive-clone.h
+++ b/gcc/rust/expand/rust-derive-clone.h
@@ -59,8 +59,9 @@ private:
* }
*
*/
- std::unique_ptr<Item> clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn,
- std::string name);
+ std::unique_ptr<Item>
+ clone_impl (std::unique_ptr<AssociatedItem> &&clone_fn, std::string name,
+ const std::vector<std::unique_ptr<GenericParam>> &type_generics);
virtual void visit_struct (StructStruct &item);
virtual void visit_tuple (TupleStruct &item);
diff --git a/gcc/rust/expand/rust-derive-copy.cc b/gcc/rust/expand/rust-derive-copy.cc
index a1c8ed0..1de7290 100644
--- a/gcc/rust/expand/rust-derive-copy.cc
+++ b/gcc/rust/expand/rust-derive-copy.cc
@@ -37,17 +37,88 @@ DeriveCopy::go (Item &item)
}
std::unique_ptr<Item>
-DeriveCopy::copy_impl (std::string name)
+DeriveCopy::copy_impl (
+ std::string name,
+ const std::vector<std::unique_ptr<GenericParam>> &type_generics)
{
// `$crate::core::marker::Copy` instead
auto segments = std::vector<std::unique_ptr<TypePathSegment>> ();
segments.emplace_back (builder.type_path_segment ("Copy"));
auto copy = TypePath (std::move (segments), loc);
+ // we need to build up the generics for this impl block which will be just a
+ // clone of the types specified ones
+ //
+ // for example:
+ //
+ // #[derive(Copy)]
+ // struct Be<T: Copy> { ... }
+ //
+ // we need to generate the impl block:
+ //
+ // impl<T: Copy> Clone for Be<T>
+
+ std::vector<Lifetime> lifetime_args;
+ std::vector<GenericArg> generic_args;
+ std::vector<std::unique_ptr<GenericParam>> impl_generics;
+ for (const auto &generic : type_generics)
+ {
+ switch (generic->get_kind ())
+ {
+ case GenericParam::Kind::Lifetime: {
+ LifetimeParam &lifetime_param = (LifetimeParam &) *generic.get ();
+
+ Lifetime l = builder.new_lifetime (lifetime_param.get_lifetime ());
+ lifetime_args.push_back (std::move (l));
+
+ auto impl_lifetime_param
+ = builder.new_lifetime_param (lifetime_param);
+ impl_generics.push_back (std::move (impl_lifetime_param));
+ }
+ break;
+
+ case GenericParam::Kind::Type: {
+ TypeParam &type_param = (TypeParam &) *generic.get ();
+
+ std::unique_ptr<Type> associated_type = builder.single_type_path (
+ type_param.get_type_representation ().as_string ());
+
+ GenericArg type_arg
+ = GenericArg::create_type (std::move (associated_type));
+ generic_args.push_back (std::move (type_arg));
+
+ auto impl_type_param = builder.new_type_param (type_param);
+ impl_generics.push_back (std::move (impl_type_param));
+ }
+ break;
+
+ case GenericParam::Kind::Const: {
+ rust_unreachable ();
+
+ // TODO
+ // const ConstGenericParam *const_param
+ // = (const ConstGenericParam *) generic.get ();
+ // std::unique_ptr<Expr> const_expr = nullptr;
+
+ // GenericArg type_arg
+ // = GenericArg::create_const (std::move (const_expr));
+ // generic_args.push_back (std::move (type_arg));
+ }
+ break;
+ }
+ }
+
+ GenericArgs generic_args_for_self (lifetime_args, generic_args,
+ {} /*binding args*/, loc);
+ std::unique_ptr<Type> self_type_path
+ = impl_generics.empty ()
+ ? builder.single_type_path (name)
+ : builder.single_generic_type_path (name, generic_args_for_self);
+
return std::unique_ptr<Item> (
new TraitImpl (copy, /* unsafe */ false,
/* exclam */ false, /* trait items */ {},
- /* generics */ {}, builder.single_type_path (name),
+ std::move (impl_generics), std::move (self_type_path),
WhereClause::create_empty (), Visibility::create_private (),
{}, {}, loc));
}
@@ -55,25 +126,29 @@ DeriveCopy::copy_impl (std::string name)
void
DeriveCopy::visit_struct (StructStruct &item)
{
- expanded = copy_impl (item.get_struct_name ().as_string ());
+ expanded = copy_impl (item.get_struct_name ().as_string (),
+ item.get_generic_params ());
}
void
DeriveCopy::visit_tuple (TupleStruct &item)
{
- expanded = copy_impl (item.get_struct_name ().as_string ());
+ expanded = copy_impl (item.get_struct_name ().as_string (),
+ item.get_generic_params ());
}
void
DeriveCopy::visit_enum (Enum &item)
{
- expanded = copy_impl (item.get_identifier ().as_string ());
+ expanded = copy_impl (item.get_identifier ().as_string (),
+ item.get_generic_params ());
}
void
DeriveCopy::visit_union (Union &item)
{
- expanded = copy_impl (item.get_identifier ().as_string ());
+ expanded = copy_impl (item.get_identifier ().as_string (),
+ item.get_generic_params ());
}
} // namespace AST
diff --git a/gcc/rust/expand/rust-derive-copy.h b/gcc/rust/expand/rust-derive-copy.h
index 98decc0..71972eb 100644
--- a/gcc/rust/expand/rust-derive-copy.h
+++ b/gcc/rust/expand/rust-derive-copy.h
@@ -40,7 +40,9 @@ private:
*
* impl Copy for <type> {}
*/
- std::unique_ptr<Item> copy_impl (std::string name);
+ std::unique_ptr<Item>
+ copy_impl (std::string name,
+ const std::vector<std::unique_ptr<GenericParam>> &type_generics);
virtual void visit_struct (StructStruct &item);
virtual void visit_tuple (TupleStruct &item);
diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h
index 1924432..967064c 100644
--- a/gcc/rust/expand/rust-derive.h
+++ b/gcc/rust/expand/rust-derive.h
@@ -81,6 +81,8 @@ private:
virtual void visit (Lifetime &lifetime) override final{};
virtual void visit (LifetimeParam &lifetime_param) override final{};
virtual void visit (ConstGenericParam &const_param) override final{};
+ virtual void visit (RegularPath &path) override final{};
+ virtual void visit (LangItemPath &path) override final{};
virtual void visit (PathInExpression &path) override final{};
virtual void visit (TypePathSegment &segment) override final{};
virtual void visit (TypePathSegmentGeneric &segment) override final{};
diff --git a/gcc/rust/expand/rust-expand-visitor.h b/gcc/rust/expand/rust-expand-visitor.h
index aca6c93..5fc1011e 100644
--- a/gcc/rust/expand/rust-expand-visitor.h
+++ b/gcc/rust/expand/rust-expand-visitor.h
@@ -140,7 +140,7 @@ public:
it = values.erase (it);
for (auto &node : final_fragment.get_nodes ())
{
- auto new_node = extractor (node);
+ U new_node = extractor (node);
if (new_node != nullptr)
{
it = values.insert (it, std::move (new_node));
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc b/gcc/rust/expand/rust-macro-builtins-asm.cc
index 214265d..5ed24d6 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.cc
+++ b/gcc/rust/expand/rust-macro-builtins-asm.cc
@@ -21,6 +21,7 @@
#include "rust-macro-builtins-asm.h"
#include "rust-ast-fragment.h"
#include "rust-ast.h"
+#include "rust-fmt.h"
#include "rust-stmt.h"
namespace Rust {
@@ -38,6 +39,20 @@ std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{
std::set<std::string> potentially_nonpromoted_keywords
= {"in", "out", "lateout", "inout", "inlateout", "const", "sym", "label"};
+
+std::string
+strip_double_quotes (const std::string &str)
+{
+ // Helper function strips the beginning and ending double quotes from a
+ // string.
+ std::string result = str;
+
+ rust_assert (result.size () >= 3);
+ result.erase (0, 1);
+ result.erase (result.size () - 1, 1);
+ return result;
+}
+
tl::expected<InlineAsmContext, InlineAsmParseError>
parse_clobber_abi (InlineAsmContext inline_asm_ctx)
{
@@ -193,7 +208,6 @@ parse_reg_operand (InlineAsmContext inline_asm_ctx)
// None
// };
auto &parser = inline_asm_ctx.parser;
- AST::InlineAsmOperand reg_operand;
auto token = parser.peek_current_token ();
auto iden_token = parser.peek_current_token ();
@@ -227,20 +241,30 @@ parse_reg_operand (InlineAsmContext inline_asm_ctx)
// Loop over and execute the parsing functions, if the parser successfullly
// parses or if the parser fails to parse while it has committed to a token,
// we propogate the result.
+ int count = 0;
+ tl::expected<InlineAsmContext, InlineAsmParseError> parsing_operand (
+ inline_asm_ctx);
for (auto &parse_func : parse_funcs)
{
- auto parsing_operand
- = tl::expected<InlineAsmContext, InlineAsmParseError> (inline_asm_ctx);
- parsing_operand.map (parse_func);
+ count++;
+ auto result = parsing_operand.and_then (parse_func);
// Per rust's asm.rs's structure
// After we've parse successfully, we break out and do a local validation
// of named, positional & explicit register operands
- if (parsing_operand.has_value ())
- break;
- if (parsing_operand.error () == COMMITTED)
- return parsing_operand;
+ if (result.has_value ())
+ {
+ inline_asm_ctx = *result;
+ break;
+ }
+ else if (result.error () == COMMITTED)
+ {
+ if (parse_func == parse_reg_operand_unexpected)
+ return inline_asm_ctx;
+ else
+ return result;
+ }
}
auto &inline_asm = inline_asm_ctx.inline_asm;
@@ -289,8 +313,8 @@ parse_reg_operand_in (InlineAsmContext inline_asm_ctx)
{
// For the keyword IN, currently we count it as a seperate keyword called
// Rust::IN search for #define RS_TOKEN_LIST in code base.
- AST::InlineAsmOperand reg_operand;
auto &parser = inline_asm_ctx.parser;
+ location_t locus = parser.peek_current_token ()->get_locus ();
if (!inline_asm_ctx.is_global_asm () && parser.skip_token (IN))
{
auto reg = parse_reg (inline_asm_ctx);
@@ -303,13 +327,12 @@ parse_reg_operand_in (InlineAsmContext inline_asm_ctx)
return tl::unexpected<InlineAsmParseError> (COMMITTED);
}
- auto expr = parse_format_string (inline_asm_ctx);
+ auto expr = parser.parse_expr ();
// TODO: When we've succesfully parse an expr, remember to clone_expr()
// instead of nullptr
- // struct AST::InlineAsmOperand::In in (reg, nullptr);
- // reg_operand.set_in (in);
- // inline_asm_ctx.inline_asm.operands.push_back (reg_operand);
+ struct AST::InlineAsmOperand::In in (reg, std::move (expr));
+ inline_asm_ctx.inline_asm.operands.emplace_back (in, locus);
return inline_asm_ctx;
}
return tl::unexpected<InlineAsmParseError> (NONCOMMITED);
@@ -319,18 +342,22 @@ tl::expected<InlineAsmContext, InlineAsmParseError>
parse_reg_operand_out (InlineAsmContext inline_asm_ctx)
{
auto &parser = inline_asm_ctx.parser;
- AST::InlineAsmOperand reg_operand;
+ location_t locus = parser.peek_current_token ()->get_locus ();
if (!inline_asm_ctx.is_global_asm () && check_identifier (parser, "out"))
{
auto reg = parse_reg (inline_asm_ctx);
+ std::unique_ptr<AST::Expr> expr = parser.parse_expr ();
- auto expr = parse_format_string (inline_asm_ctx);
+ rust_assert (expr != nullptr);
+
+ /*auto expr_ptr =
+ std::make_unique<AST::Expr>(AST::LiteralExpr(Literal))*/
// TODO: When we've succesfully parse an expr, remember to clone_expr()
// instead of nullptr
- // struct AST::InlineAsmOperand::Out out (reg, false, nullptr);
- // reg_operand.set_out (out);
- // inline_asm_ctx.inline_asm.operands.push_back (reg_operand);
+ struct AST::InlineAsmOperand::Out out (reg, false, std::move (expr));
+
+ inline_asm_ctx.inline_asm.operands.emplace_back (out, locus);
return inline_asm_ctx;
}
@@ -360,7 +387,6 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
auto &parser = inline_asm_ctx.parser;
auto token = parser.peek_current_token ();
- AST::InlineAsmOperand reg_operand;
if (!inline_asm_ctx.is_global_asm () && check_identifier (parser, "inout"))
{
auto reg = parse_reg (inline_asm_ctx);
@@ -378,7 +404,9 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
// TODO: Is error propogation our top priority, the ? in rust's asm.rs is
// doing a lot of work.
// TODO: Not sure how to use parse_expr
- auto expr = parse_format_string (inline_asm_ctx);
+ if (!check_identifier (parser, ""))
+ rust_unreachable ();
+ // auto expr = parse_format_string (inline_asm_ctx);
std::unique_ptr<AST::Expr> out_expr;
@@ -386,9 +414,9 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
{
if (!parser.skip_token (UNDERSCORE))
{
- auto result = parse_format_string (inline_asm_ctx);
+ // auto result = parse_format_string (inline_asm_ctx);
- if (!result.has_value ())
+ if (!check_identifier (parser, ""))
rust_unreachable ();
// out_expr = parser.parse_expr();
}
@@ -399,8 +427,8 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
// expr, out_expr, late: false }
// struct AST::InlineAsmOperand::SplitInOut split_in_out (reg,
// false, nullptr,
- // nullptr); reg_operand.set_split_in_out (split_in_out);
- // inline_asm_ctx.inline_asm.operands.push_back (reg_operand);
+ // nullptr);
+ // inline_asm_ctx.inline_asm.operands.push_back (split_in_out);
return inline_asm_ctx;
}
@@ -410,8 +438,8 @@ parse_reg_operand_inout (InlineAsmContext inline_asm_ctx)
// RUST VERSION: ast::InlineAsmOperand::InOut { reg, expr, late: false
// }
// struct AST::InlineAsmOperand::InOut inout (reg, false,
- // nullptr); reg_operand.set_in_out (inout);
- // inline_asm_ctx.inline_asm.operands.push_back (reg_operand);
+ // nullptr);
+ // inline_asm_ctx.inline_asm.operands.push_back (inout);
return inline_asm_ctx;
}
}
@@ -423,12 +451,10 @@ tl::expected<InlineAsmContext, InlineAsmParseError>
parse_reg_operand_const (InlineAsmContext inline_asm_ctx)
{
auto &parser = inline_asm_ctx.parser;
- AST::InlineAsmOperand reg_operand;
if (parser.peek_current_token ()->get_id () == CONST)
{
// TODO: Please handle const with parse_expr instead.
auto anon_const = parse_format_string (inline_asm_ctx);
- reg_operand.set_cnst (tl::nullopt);
rust_unreachable ();
return tl::unexpected<InlineAsmParseError> (COMMITTED);
}
@@ -457,9 +483,9 @@ parse_reg_operand_unexpected (InlineAsmContext inline_asm_ctx)
// TODO: It is weird that we can't seem to match any identifier,
// something must be wrong. consult compiler code in asm.rs or rust online
// compiler.
- rust_unreachable ();
+ // rust_unreachable ();
- rust_error_at (token->get_locus (), "ERROR RIGHT HERE");
+ // rust_error_at (token->get_locus (), "ERROR RIGHT HERE");
return tl::unexpected<InlineAsmParseError> (COMMITTED);
}
@@ -551,9 +577,7 @@ parse_options (InlineAsmContext &inline_asm_ctx)
// Parse comma as optional
if (parser.skip_token (COMMA))
- {
- continue;
- }
+ continue;
else
{
rust_unreachable ();
@@ -678,7 +702,9 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx)
if (check_identifier (parser, "clobber_abi"))
{
auto expected = parse_clobber_abi (inline_asm_ctx);
- if (expected || expected.error () == COMMITTED)
+ if (expected.has_value ())
+ continue;
+ else if (expected.error () == COMMITTED)
return expected;
// The error type is definitely non-committed (we have checked above),
@@ -688,7 +714,9 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx)
if (check_identifier (parser, "options"))
{
auto expected = parse_options (inline_asm_ctx);
- if (expected || expected.error () == COMMITTED)
+ if (expected.has_value ())
+ continue;
+ else if (expected.error () == COMMITTED)
return expected;
// The error type is definitely non-committed (we have checked above),
@@ -699,7 +727,9 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx)
// only other logical choice is reg_operand
auto expected = parse_reg_operand (inline_asm_ctx);
- if (expected || expected.error () == COMMITTED)
+ if (expected.has_value ())
+ continue;
+ else if (expected.error () == COMMITTED)
return expected;
// Since parse_reg_operand is the last thing we've considered,
@@ -718,6 +748,74 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx)
return tl::expected<InlineAsmContext, InlineAsmParseError> (inline_asm_ctx);
}
+tl::expected<InlineAsmContext, InlineAsmParseError>
+expand_inline_asm_strings (InlineAsmContext inline_asm_ctx)
+{
+ auto &inline_asm = inline_asm_ctx.inline_asm;
+
+ auto str_vec = inline_asm.get_template_strs ();
+
+ decltype (str_vec) resulting_template_vec;
+ for (auto &template_str : str_vec)
+ {
+ /*std::cout << template_str.symbol << std::endl;*/
+
+ auto pieces = Fmt::Pieces::collect (template_str.symbol, false,
+ Fmt::ffi::ParseMode::InlineAsm);
+ auto pieces_vec = pieces.get_pieces ();
+
+ std::string transformed_template_str = "";
+ for (size_t i = 0; i < pieces_vec.size (); i++)
+ {
+ auto piece = pieces_vec[i];
+ if (piece.tag == Fmt::ffi::Piece::Tag::String)
+ {
+ transformed_template_str += piece.string._0.to_string ();
+ }
+ else if (piece.tag == Fmt::ffi::Piece::Tag::NextArgument)
+ {
+ /* std::cout << " " << i << ": "*/
+ /*<< piece.next_argument._0.to_string () << std::endl;*/
+
+ auto next_argument = piece.next_argument._0;
+ switch (piece.next_argument._0.position.tag)
+ {
+ case Fmt::ffi::Position::Tag::ArgumentImplicitlyIs: {
+ auto idx = next_argument.position.argument_implicitly_is._0;
+ /*auto trait = next_argument.format;*/
+ /*auto arg = arguments.at (idx);*/
+
+ /* // FIXME(Arthur): This API sucks*/
+ /* rust_assert (arg.get_kind ().kind*/
+ /*== AST::FormatArgumentKind::Kind::Normal);*/
+ /**/
+ /* args.push_back ({arg.get_expr ().clone_expr (),
+ * trait});*/
+
+ transformed_template_str += "%" + std::to_string (idx);
+ // std::cout << "argument implicitly is: " << idx <<
+ // std::endl; std::cout << "transformed template str is:"
+ // << transformed_template_str << std::endl;
+ /*std::cout << "trait: " << trait.to_string () <<
+ * std::endl;*/
+ /*std::cout << "arg: " << arg.to_string () << std::endl;*/
+ }
+ break;
+ case Fmt::ffi::Position::Tag::ArgumentIs:
+ case Fmt::ffi::Position::Tag::ArgumentNamed:
+ rust_sorry_at (inline_asm.get_locus (),
+ "unhandled argument position specifier");
+ break;
+ }
+ }
+ }
+ template_str.symbol = transformed_template_str;
+ }
+
+ inline_asm.template_strs = str_vec;
+ return inline_asm_ctx;
+}
+
tl::optional<AST::Fragment>
parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
AST::InvocKind semicolon, AST::AsmKind is_global_asm)
@@ -726,7 +824,8 @@ parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
// We first parse all formatted strings. If we fail, then we return
// tl::nullopt
- // We then parse the asm arguments. If we fail, then we return tl::nullopt
+ // We then parse the asm arguments. If we fail, then we return
+ // tl::nullopt
// We then validate. If we fail, then we return tl::nullopt
@@ -741,21 +840,22 @@ parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
auto resulting_context = parse_format_strings (inline_asm_ctx)
.and_then (parse_asm_arg)
- .and_then (validate);
-
- // TODO: I'm putting the validation here because the rust reference put it
- // here Per Arthur's advice we would actually do the validation in a different
- // stage. and visit on the InlineAsm AST instead of it's context.
- auto is_valid = (bool) resulting_context;
+ .and_then (validate)
+ .and_then (expand_inline_asm_strings);
- if (is_valid)
+ // TODO: I'm putting the validation here because the rust reference put
+ // it here Per Arthur's advice we would actually do the validation in a
+ // different stage. and visit on the InlineAsm AST instead of it's
+ // context.
+ if (resulting_context)
{
- auto node = inline_asm_ctx.inline_asm.clone_expr_without_block ();
+ auto node = (*resulting_context).inline_asm.clone_expr_without_block ();
std::vector<AST::SingleASTNode> single_vec = {};
- // If the macro invocation has a semicolon (`asm!("...");`), then we need
- // to make it a statement. This way, it will be expanded properly.
+ // If the macro invocation has a semicolon (`asm!("...");`), then we
+ // need to make it a statement. This way, it will be expanded
+ // properly.
if (semicolon == AST::InvocKind::Semicoloned)
single_vec.emplace_back (AST::SingleASTNode (
Rust::make_unique<AST::ExprStmt> (std::move (node), invoc_locus,
@@ -778,7 +878,8 @@ parse_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
tl::expected<InlineAsmContext, InlineAsmParseError>
parse_format_strings (InlineAsmContext inline_asm_ctx)
{
- // Parse the first ever formatted string, success or not, will skip 1 token
+ // Parse the first ever formatted string, success or not, will skip 1
+ // token
auto &parser = inline_asm_ctx.parser;
auto last_token_id = inline_asm_ctx.last_token_id;
auto fm_string = parse_format_string (inline_asm_ctx);
@@ -794,7 +895,8 @@ parse_format_strings (InlineAsmContext inline_asm_ctx)
else
{
auto template_str
- = AST::TupleTemplateStr (token->get_locus (), fm_string.value ());
+ = AST::TupleTemplateStr (token->get_locus (),
+ strip_double_quotes (fm_string.value ()));
inline_asm.template_strs.push_back (template_str);
}
@@ -806,8 +908,8 @@ parse_format_strings (InlineAsmContext inline_asm_ctx)
{
break;
}
- // Ok after the comma is good, we better be parsing correctly everything
- // in here, which is formatted string in ABNF
+ // Ok after the comma is good, we better be parsing correctly
+ // everything in here, which is formatted string in ABNF
inline_asm_ctx.consumed_comma_without_formatted_string = false;
token = parser.peek_current_token ();
@@ -820,7 +922,8 @@ parse_format_strings (InlineAsmContext inline_asm_ctx)
else
{
auto template_str
- = AST::TupleTemplateStr (token->get_locus (), fm_string.value ());
+ = AST::TupleTemplateStr (token->get_locus (),
+ strip_double_quotes (fm_string.value ()));
inline_asm.template_strs.push_back (template_str);
}
}
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.h b/gcc/rust/expand/rust-macro-builtins-asm.h
index 6997770..8081dae 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.h
+++ b/gcc/rust/expand/rust-macro-builtins-asm.h
@@ -65,6 +65,14 @@ public:
// {
// }
+ InlineAsmContext &operator= (const InlineAsmContext &inline_asm_ctx)
+ {
+ allow_templates = inline_asm_ctx.allow_templates;
+ is_explicit = inline_asm_ctx.is_explicit;
+ consumed_comma_without_formatted_string = false;
+ last_token_id = inline_asm_ctx.last_token_id;
+ return *this;
+ }
bool is_global_asm () { return inline_asm.is_global_asm; }
@@ -75,6 +83,9 @@ public:
this->allow_templates = allow_templates;
}
};
+WARN_UNUSED_RESULT
+tl::expected<InlineAsmContext, InlineAsmParseError>
+expand_inline_asm_strings (InlineAsmContext inline_asm_ctx);
// Expected calls
WARN_UNUSED_RESULT
@@ -161,4 +172,4 @@ tl::optional<std::string>
parse_label (Parser<MacroInvocLexer> &parser, TokenId last_token_id,
InlineAsmContext &inline_asm_ctx);
-} // namespace Rust \ No newline at end of file
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.cc b/gcc/rust/expand/rust-macro-builtins-helpers.cc
index d44efcc..55d113c 100644
--- a/gcc/rust/expand/rust-macro-builtins-helpers.cc
+++ b/gcc/rust/expand/rust-macro-builtins-helpers.cc
@@ -174,7 +174,8 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser,
std::unique_ptr<AST::Expr>
parse_single_string_literal (BuiltinMacro kind,
AST::DelimTokenTree &invoc_token_tree,
- location_t invoc_locus, MacroExpander *expander)
+ location_t invoc_locus, MacroExpander *expander,
+ bool is_semicoloned)
{
MacroInvocLexer lex (invoc_token_tree.to_token_stream ());
Parser<MacroInvocLexer> parser (lex);
@@ -221,7 +222,7 @@ parse_single_string_literal (BuiltinMacro kind,
AST::MacroInvocData (AST::SimplePath ({AST::SimplePathSegment (
path_str, invoc_locus)}),
std::move (invoc_token_tree)),
- {}, invoc_locus, std::move (pending_invocations));
+ {}, invoc_locus, std::move (pending_invocations), is_semicoloned);
}
else
{
@@ -281,4 +282,4 @@ load_file_bytes (location_t invoc_locus, const char *filename)
return buf;
}
-} // namespace Rust \ No newline at end of file
+} // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-builtins-helpers.h b/gcc/rust/expand/rust-macro-builtins-helpers.h
index bf058df..ee5cae7 100644
--- a/gcc/rust/expand/rust-macro-builtins-helpers.h
+++ b/gcc/rust/expand/rust-macro-builtins-helpers.h
@@ -74,7 +74,8 @@ try_expand_many_expr (Parser<MacroInvocLexer> &parser,
std::unique_ptr<AST::Expr>
parse_single_string_literal (BuiltinMacro kind,
AST::DelimTokenTree &invoc_token_tree,
- location_t invoc_locus, MacroExpander *expander);
+ location_t invoc_locus, MacroExpander *expander,
+ bool is_semicoloned = false);
// Treat PATH as a path relative to the source file currently being
// compiled, and return the absolute path for it.
diff --git a/gcc/rust/expand/rust-macro-builtins-include.cc b/gcc/rust/expand/rust-macro-builtins-include.cc
index cf3f93d..4719b0e 100644
--- a/gcc/rust/expand/rust-macro-builtins-include.cc
+++ b/gcc/rust/expand/rust-macro-builtins-include.cc
@@ -40,7 +40,12 @@ MacroBuiltin::include_bytes_handler (location_t invoc_locus,
if (lit_expr == nullptr)
return AST::Fragment::create_error ();
- rust_assert (lit_expr->is_literal ());
+ if (!lit_expr->is_literal ())
+ {
+ auto token_tree = invoc.get_delim_tok_tree ();
+ return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))},
+ token_tree.to_token_stream ());
+ }
std::string target_filename
= source_relative_path (lit_expr->as_string (), invoc_locus);
@@ -188,16 +193,36 @@ MacroBuiltin::include_handler (location_t invoc_locus,
AST::MacroInvocData &invoc,
AST::InvocKind semicolon)
{
+ bool is_semicoloned = semicolon == AST::InvocKind::Semicoloned;
/* Get target filename from the macro invocation, which is treated as a path
relative to the include!-ing file (currently being compiled). */
- auto lit_expr
+ std::unique_ptr<AST::Expr> lit_expr
= parse_single_string_literal (BuiltinMacro::Include,
invoc.get_delim_tok_tree (), invoc_locus,
- invoc.get_expander ());
+ invoc.get_expander (), is_semicoloned);
if (lit_expr == nullptr)
return AST::Fragment::create_error ();
- rust_assert (lit_expr->is_literal ());
+ if (!lit_expr->is_literal ())
+ {
+ // We have to expand an inner macro eagerly
+ auto token_tree = invoc.get_delim_tok_tree ();
+
+ // parse_single_string_literal returned an AST::MacroInvocation, which
+ // can either be an AST::Item or AST::Expr. Depending on the context the
+ // original macro was invoked in, we will set AST::Item or AST::Expr
+ // appropriately.
+ if (is_semicoloned)
+ {
+ std::unique_ptr<AST::Item> lit_item = std::unique_ptr<AST::Item> (
+ static_cast<AST::MacroInvocation *> (lit_expr.release ()));
+ return AST::Fragment ({AST::SingleASTNode (std::move (lit_item))},
+ token_tree.to_token_stream ());
+ }
+ else
+ return AST::Fragment ({AST::SingleASTNode (std::move (lit_expr))},
+ token_tree.to_token_stream ());
+ }
std::string filename
= source_relative_path (lit_expr->as_string (), invoc_locus);
@@ -218,8 +243,14 @@ MacroBuiltin::include_handler (location_t invoc_locus,
Lexer lex (target_filename, std::move (target_file), linemap);
Parser<Lexer> parser (lex);
+ std::unique_ptr<AST::Expr> parsed_expr = nullptr;
+ std::vector<std::unique_ptr<AST::Item>> parsed_items{};
+
+ if (is_semicoloned)
+ parsed_items = parser.parse_items ();
+ else
+ parsed_expr = parser.parse_expr ();
- auto parsed_items = parser.parse_items ();
bool has_error = !parser.get_errors ().empty ();
for (const auto &error : parser.get_errors ())
@@ -233,17 +264,22 @@ MacroBuiltin::include_handler (location_t invoc_locus,
}
std::vector<AST::SingleASTNode> nodes{};
- for (auto &item : parsed_items)
+ if (is_semicoloned)
+ for (auto &item : parsed_items)
+ {
+ AST::SingleASTNode node (std::move (item));
+ nodes.push_back (node);
+ }
+ else
{
- AST::SingleASTNode node (std::move (item));
+ AST::SingleASTNode node (std::move (parsed_expr));
nodes.push_back (node);
}
-
// FIXME: This returns an empty vector of tokens and works fine, but is that
// the expected behavior? `include` macros are a bit harder to reason about
// since they include tokens. Furthermore, our lexer has no easy way to return
// a slice of tokens like the MacroInvocLexer. So it gets even harder to
- // extrac tokens from here. For now, let's keep it that way and see if it
+ // extract tokens from here. For now, let's keep it that way and see if it
// eventually breaks, but I don't expect it to cause many issues since the
// list of tokens is only used when a macro invocation mixes eager
// macro invocations and already expanded tokens. Think
diff --git a/gcc/rust/expand/rust-macro-expand.cc b/gcc/rust/expand/rust-macro-expand.cc
index 4d9cade..e86bfcb 100644
--- a/gcc/rust/expand/rust-macro-expand.cc
+++ b/gcc/rust/expand/rust-macro-expand.cc
@@ -250,7 +250,12 @@ MacroExpander::expand_invoc (AST::MacroInvocation &invoc,
}
if (invoc.get_kind () == AST::MacroInvocation::InvocKind::Builtin)
- expand_eager_invocations (invoc);
+ {
+ // Eager expansions are always expressions
+ push_context (ContextType::EXPR);
+ expand_eager_invocations (invoc);
+ pop_context ();
+ }
AST::MacroInvocData &invoc_data = invoc.get_invoc_data ();
diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc
index 906706e..18e6fff 100644
--- a/gcc/rust/hir/rust-ast-lower-base.cc
+++ b/gcc/rust/hir/rust-ast-lower-base.cc
@@ -63,6 +63,12 @@ ASTLoweringBase::visit (AST::ConstGenericParam &)
// rust-path.h
void
+ASTLoweringBase::visit (AST::RegularPath &)
+{}
+void
+ASTLoweringBase::visit (AST::LangItemPath &)
+{}
+void
ASTLoweringBase::visit (AST::PathInExpression &)
{}
void
diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h
index 1bd1343..4cb098b 100644
--- a/gcc/rust/hir/rust-ast-lower-base.h
+++ b/gcc/rust/hir/rust-ast-lower-base.h
@@ -84,6 +84,8 @@ public:
// virtual void visit(TraitImplItem& trait_impl_item);
// rust-path.h
+ virtual void visit (AST::RegularPath &path);
+ virtual void visit (AST::LangItemPath &path);
virtual void visit (AST::PathInExpression &path);
virtual void visit (AST::TypePathSegment &segment);
virtual void visit (AST::TypePathSegmentGeneric &segment);
diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc
index be7ff41..9dd88b4 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.cc
+++ b/gcc/rust/hir/rust-ast-lower-expr.cc
@@ -25,6 +25,7 @@
#include "rust-ast.h"
#include "rust-diagnostics.h"
#include "rust-system.h"
+#include "tree/rust-hir-expr.h"
namespace Rust {
namespace HIR {
@@ -829,6 +830,115 @@ ASTLoweringExpr::visit (AST::ClosureExprInnerTyped &expr)
expr.get_locus ());
}
+HIR::InlineAsmOperand
+translate_operand_in (const AST::InlineAsmOperand &operand)
+{
+ auto in_value = operand.get_in ();
+
+ struct HIR::InlineAsmOperand::In in (
+ in_value.reg,
+ std::unique_ptr<Expr> (ASTLoweringExpr::translate (*in_value.expr.get ())));
+ return in;
+}
+
+HIR::InlineAsmOperand
+translate_operand_out (const AST::InlineAsmOperand &operand)
+{
+ auto out_value = operand.get_out ();
+ struct HIR::InlineAsmOperand::Out out (out_value.reg, out_value.late,
+ std::unique_ptr<Expr> (
+ ASTLoweringExpr::translate (
+ *out_value.expr.get ())));
+ return out;
+}
+HIR::InlineAsmOperand
+translate_operand_inout (const AST::InlineAsmOperand &operand)
+{
+ auto inout_value = operand.get_in_out ();
+ struct HIR::InlineAsmOperand::InOut inout (inout_value.reg, inout_value.late,
+ std::unique_ptr<Expr> (
+ ASTLoweringExpr::translate (
+ *inout_value.expr.get ())));
+ return inout;
+}
+HIR::InlineAsmOperand
+translate_operand_split_in_out (const AST::InlineAsmOperand &operand)
+{
+ auto split_in_out_value = operand.get_split_in_out ();
+ struct HIR::InlineAsmOperand::SplitInOut split_in_out (
+ split_in_out_value.reg, split_in_out_value.late,
+ std::unique_ptr<Expr> (
+ ASTLoweringExpr::translate (*split_in_out_value.in_expr.get ())),
+ std::unique_ptr<Expr> (
+ ASTLoweringExpr::translate (*split_in_out_value.out_expr.get ())));
+ return split_in_out;
+}
+HIR::InlineAsmOperand
+translate_operand_const (const AST::InlineAsmOperand &operand)
+{
+ auto const_value = operand.get_const ();
+ struct HIR::AnonConst anon_const (const_value.anon_const.id,
+ std::unique_ptr<Expr> (
+ ASTLoweringExpr::translate (
+ *const_value.anon_const.expr.get ())));
+ struct HIR::InlineAsmOperand::Const cnst
+ {
+ anon_const
+ };
+ return cnst;
+}
+
+HIR::InlineAsmOperand
+translate_operand_sym (const AST::InlineAsmOperand &operand)
+{
+ auto sym_value = operand.get_sym ();
+ struct HIR::InlineAsmOperand::Sym sym (std::unique_ptr<Expr> (
+ ASTLoweringExpr::translate (*sym_value.expr.get ())));
+ return sym;
+}
+HIR::InlineAsmOperand
+translate_operand_label (const AST::InlineAsmOperand &operand)
+{
+ auto label_value = operand.get_label ();
+ struct HIR::InlineAsmOperand::Label label (label_value.label_name,
+ std::unique_ptr<Expr> (
+ ASTLoweringExpr::translate (
+ *label_value.expr.get ())));
+ return label;
+}
+HIR::InlineAsmOperand
+from_operand (const AST::InlineAsmOperand &operand)
+{
+ using RegisterType = AST::InlineAsmOperand::RegisterType;
+ auto type = operand.get_register_type ();
+
+ /*In,*/
+ /*Out,*/
+ /*InOut,*/
+ /*SplitInOut,*/
+ /*Const,*/
+ /*Sym,*/
+ /*Label,*/
+ switch (type)
+ {
+ case RegisterType::In:
+ return translate_operand_in (operand);
+ case RegisterType::Out:
+ return translate_operand_out (operand);
+ case RegisterType::InOut:
+ return translate_operand_inout (operand);
+ case RegisterType::SplitInOut:
+ return translate_operand_split_in_out (operand);
+ case RegisterType::Const:
+ return translate_operand_const (operand);
+ case RegisterType::Sym:
+ return translate_operand_sym (operand);
+ case RegisterType::Label:
+ return translate_operand_label (operand);
+ default:
+ rust_unreachable ();
+ }
+}
void
ASTLoweringExpr::visit (AST::InlineAsm &expr)
{
@@ -837,10 +947,22 @@ ASTLoweringExpr::visit (AST::InlineAsm &expr)
mappings.get_next_hir_id (crate_num),
mappings.get_next_localdef_id (crate_num));
+ std::vector<HIR::InlineAsmOperand> hir_operands;
+ const std::vector<AST::InlineAsmOperand> &ast_operands = expr.get_operands ();
+ /*int ast_operands_size = ast_operands.size ();*/
+ for (auto &operand : ast_operands)
+ {
+ hir_operands.push_back (from_operand (operand));
+ }
+ /*int hir_operands_size = hir_operands.size ();*/
+
+ /*rust_debug ("{bdbt} : There are %d ast operands prelowering and %d hir "*/
+ /* "operands after lowering\n",*/
+ /* ast_operands_size, hir_operands_size);*/
translated
= new HIR::InlineAsm (expr.get_locus (), expr.is_global_asm,
expr.get_template_ (), expr.get_template_strs (),
- expr.get_operands (), expr.get_clobber_abi (),
+ hir_operands, expr.get_clobber_abi (),
expr.get_options (), mapping);
}
void
diff --git a/gcc/rust/hir/rust-ast-lower-item.cc b/gcc/rust/hir/rust-ast-lower-item.cc
index 25345ce..171737a 100644
--- a/gcc/rust/hir/rust-ast-lower-item.cc
+++ b/gcc/rust/hir/rust-ast-lower-item.cc
@@ -542,7 +542,7 @@ ASTLoweringItem::visit (AST::InherentImpl &impl_block)
mapping, std::move (impl_items), std::move (generic_params),
std::unique_ptr<HIR::Type> (impl_type), nullptr, where_clause, polarity,
vis, impl_block.get_inner_attrs (), impl_block.get_outer_attrs (),
- impl_block.get_locus ());
+ impl_block.get_locus (), false);
translated = hir_impl_block;
mappings.insert_hir_impl_block (hir_impl_block);
@@ -623,6 +623,7 @@ void
ASTLoweringItem::visit (AST::TraitImpl &impl_block)
{
std::vector<std::unique_ptr<HIR::WhereClauseItem>> where_clause_items;
+ bool unsafe = impl_block.is_unsafe ();
for (auto &item : impl_block.get_where_clause ().get_items ())
{
HIR::WhereClauseItem *i = ASTLowerWhereClauseItem::translate (*item);
@@ -689,14 +690,14 @@ ASTLoweringItem::visit (AST::TraitImpl &impl_block)
}
BoundPolarity polarity = impl_block.is_exclam ()
- ? BoundPolarity::RegularBound
- : BoundPolarity::NegativeBound;
+ ? BoundPolarity::NegativeBound
+ : BoundPolarity::RegularBound;
HIR::ImplBlock *hir_impl_block = new HIR::ImplBlock (
mapping, std::move (impl_items), std::move (generic_params),
std::unique_ptr<HIR::Type> (impl_type),
std::unique_ptr<HIR::TypePath> (trait_ref), where_clause, polarity, vis,
impl_block.get_inner_attrs (), impl_block.get_outer_attrs (),
- impl_block.get_locus ());
+ impl_block.get_locus (), unsafe);
translated = hir_impl_block;
mappings.insert_hir_impl_block (hir_impl_block);
diff --git a/gcc/rust/hir/rust-ast-lower-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc
index f7cb863..7d6ac5d 100644
--- a/gcc/rust/hir/rust-ast-lower-type.cc
+++ b/gcc/rust/hir/rust-ast-lower-type.cc
@@ -17,6 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-ast-lower-type.h"
+#include "rust-attribute-values.h"
namespace Rust {
namespace HIR {
@@ -144,8 +145,15 @@ ASTLowerQualifiedPathInType::visit (AST::QualifiedPathInType &path)
HIR::Type *qual_type
= ASTLoweringType::translate (path.get_qualified_path_type ().get_type ());
- HIR::TypePath *qual_trait = ASTLowerTypePath::translate (
- path.get_qualified_path_type ().get_as_type_path ());
+
+ HIR::TypePath *qual_trait = nullptr;
+ if (!path.get_qualified_path_type ().is_error ())
+ {
+ AST::QualifiedPathType &qualifier = path.get_qualified_path_type ();
+ if (qualifier.has_as_clause ())
+ qual_trait
+ = ASTLowerTypePath::translate (qualifier.get_as_type_path ());
+ }
HIR::QualifiedPathType qual_path_type (
qual_mappings, std::unique_ptr<HIR::Type> (qual_type),
@@ -446,16 +454,17 @@ void
ASTLowerGenericParam::visit (AST::LifetimeParam &param)
{
auto crate_num = mappings.get_current_crate ();
+ AST::Lifetime lifetime = param.get_lifetime ();
Analysis::NodeMapping mapping (crate_num, param.get_node_id (),
mappings.get_next_hir_id (crate_num),
mappings.get_next_localdef_id (crate_num));
- HIR::Lifetime lt (mapping, param.get_lifetime ().get_lifetime_type (),
- param.get_lifetime ().get_lifetime_name (),
- param.get_lifetime ().get_locus ());
+ HIR::Lifetime lt (mapping, lifetime.get_lifetime_type (),
+ lifetime.get_lifetime_name (), lifetime.get_locus ());
translated = new HIR::LifetimeParam (mapping, lt, param.get_locus (),
- std::vector<Lifetime> ());
+ std::vector<Lifetime> (),
+ param.get_outer_attrs ());
}
void
@@ -482,7 +491,6 @@ ASTLowerGenericParam::visit (AST::ConstGenericParam &param)
void
ASTLowerGenericParam::visit (AST::TypeParam &param)
{
- AST::Attribute outer_attr = AST::Attribute::create_empty ();
std::vector<std::unique_ptr<HIR::TypeParamBound>> type_param_bounds;
if (param.has_type_param_bounds ())
{
@@ -506,7 +514,8 @@ ASTLowerGenericParam::visit (AST::TypeParam &param)
translated
= new HIR::TypeParam (mapping, param.get_type_representation (),
param.get_locus (), std::move (type_param_bounds),
- std::unique_ptr<Type> (type), std::move (outer_attr));
+ std::unique_ptr<Type> (type),
+ param.get_outer_attrs ());
}
HIR::TypeParamBound *
diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc
index 4ae9cba..b441377 100644
--- a/gcc/rust/hir/rust-hir-dump.cc
+++ b/gcc/rust/hir/rust-hir-dump.cc
@@ -1270,6 +1270,8 @@ Dump::visit (BlockExpr &e)
begin ("BlockExpr");
do_expr (e);
do_inner_attrs (e);
+ put_field ("tail_reachable", std::to_string (e.is_tail_reachable ()));
+ put_field ("label", e.get_label ().as_string ());
visit_collection ("statements", e.get_statements ());
@@ -1508,7 +1510,8 @@ void
Dump::visit (TypeParam &e)
{
begin ("TypeParam");
- put_field ("outer_attr", e.get_outer_attribute ().as_string ());
+ auto &outer_attrs = e.get_outer_attrs ();
+ do_outer_attrs (outer_attrs);
put_field ("type_representation", e.get_type_representation ().as_string ());
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index ff9fcee..1ee1066 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -93,6 +93,7 @@ class LiteralExpr : public ExprWithoutBlock
{
Literal literal;
location_t locus;
+ bool negative_number = false;
public:
std::string as_string () const override
@@ -132,6 +133,14 @@ public:
ExprType get_expression_type () const override final { return ExprType::Lit; }
+ bool is_negative () const { return negative_number; }
+ void set_negative ()
+ {
+ rust_assert (get_lit_type () == Literal::LitType::INT
+ || get_lit_type () == Literal::LitType::FLOAT);
+ negative_number = true;
+ }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
@@ -3843,28 +3852,259 @@ class InlineAsmRegClass
std::string placeholder;
};
-struct InlineAsmRegOrRegClass
+struct AnonConst
{
- enum Type
+ NodeId id;
+ std::unique_ptr<Expr> expr;
+ AnonConst (NodeId id, std::unique_ptr<Expr> expr)
+ : id (id), expr (std::move (expr))
+ {
+ rust_assert (this->expr != nullptr);
+ }
+ AnonConst (const AnonConst &other)
+ {
+ id = other.id;
+ expr = other.expr->clone_expr ();
+ }
+
+ AnonConst operator= (const AnonConst &other)
+ {
+ id = other.id;
+ expr = other.expr->clone_expr ();
+ return *this;
+ }
+};
+;
+
+class InlineAsmOperand
+{
+public:
+ struct In
{
- Reg, // links to struct Register
- RegClass, // links to struct RegisterClass
+ tl::optional<struct AST::InlineAsmRegOrRegClass> reg;
+ std::unique_ptr<Expr> expr;
+
+ In (const tl::optional<struct AST::InlineAsmRegOrRegClass> &reg,
+ std::unique_ptr<Expr> expr)
+ : reg (reg), expr (std::move (expr))
+ {
+ rust_assert (this->expr != nullptr);
+ }
+
+ In (const struct In &other)
+ {
+ reg = other.reg;
+
+ expr = other.expr->clone_expr ();
+ }
+
+ In operator= (const struct In &other)
+ {
+ reg = other.reg;
+ expr = other.expr->clone_expr ();
+
+ return *this;
+ }
};
- struct Register
+ struct Out
{
- InlineAsmReg Reg;
+ tl::optional<struct AST::InlineAsmRegOrRegClass> reg;
+ bool late;
+ std::unique_ptr<Expr> expr; // can be null
+
+ Out (tl::optional<struct AST::InlineAsmRegOrRegClass> &reg, bool late,
+ std::unique_ptr<Expr> expr)
+ : reg (reg), late (late), expr (std::move (expr))
+ {
+ rust_assert (this->expr != nullptr);
+ }
+
+ Out (const struct Out &other)
+ {
+ reg = other.reg;
+ late = other.late;
+ expr = other.expr->clone_expr ();
+ }
+
+ Out operator= (const struct Out &other)
+ {
+ reg = other.reg;
+ late = other.late;
+ expr = other.expr->clone_expr ();
+ return *this;
+ }
};
- struct RegisterClass
+ struct InOut
{
- InlineAsmRegClass RegClass;
+ tl::optional<struct AST::InlineAsmRegOrRegClass> reg;
+ bool late;
+ std::unique_ptr<Expr> expr; // this can't be null
+
+ InOut (tl::optional<struct AST::InlineAsmRegOrRegClass> &reg, bool late,
+ std::unique_ptr<Expr> expr)
+ : reg (reg), late (late), expr (std::move (expr))
+ {
+ rust_assert (this->expr != nullptr);
+ }
+
+ InOut (const struct InOut &other)
+ {
+ reg = other.reg;
+ late = other.late;
+ expr = other.expr->clone_expr ();
+ }
+
+ InOut operator= (const struct InOut &other)
+ {
+ reg = other.reg;
+ late = other.late;
+ expr = other.expr->clone_expr ();
+
+ return *this;
+ }
+ };
+
+ struct SplitInOut
+ {
+ tl::optional<struct AST::InlineAsmRegOrRegClass> reg;
+ bool late;
+ std::unique_ptr<Expr> in_expr;
+ std::unique_ptr<Expr> out_expr; // could be null
+
+ SplitInOut (tl::optional<struct AST::InlineAsmRegOrRegClass> &reg,
+ bool late, std::unique_ptr<Expr> in_expr,
+ std::unique_ptr<Expr> out_expr)
+ : reg (reg), late (late), in_expr (std::move (in_expr)),
+ out_expr (std::move (out_expr))
+ {
+ rust_assert (this->in_expr != nullptr);
+ rust_assert (this->out_expr != nullptr);
+ }
+
+ SplitInOut (const struct SplitInOut &other)
+ {
+ reg = other.reg;
+ late = other.late;
+ in_expr = other.in_expr->clone_expr ();
+ out_expr = other.out_expr->clone_expr ();
+ }
+
+ SplitInOut operator= (const struct SplitInOut &other)
+ {
+ reg = other.reg;
+ late = other.late;
+ in_expr = other.in_expr->clone_expr ();
+ out_expr = other.out_expr->clone_expr ();
+
+ return *this;
+ }
+ };
+
+ struct Const
+ {
+ AnonConst anon_const;
+ };
+
+ struct Sym
+ {
+ std::unique_ptr<Expr> expr;
+
+ Sym (std::unique_ptr<Expr> expr) : expr (std::move (expr))
+ {
+ rust_assert (this->expr != nullptr);
+ }
+ Sym (const struct Sym &other)
+ {
+ expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
+ }
+
+ Sym operator= (const struct Sym &other)
+ {
+ expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
+ return *this;
+ }
+ };
+
+ struct Label
+ {
+ std::string label_name;
+ std::unique_ptr<Expr> expr;
+
+ Label (tl::optional<std::string> label_name, std::unique_ptr<Expr> expr)
+ : expr (std::move (expr))
+ {
+ rust_assert (this->expr != nullptr);
+ if (label_name.has_value ())
+ this->label_name = label_name.value ();
+ }
+ Label (const struct Label &other)
+ {
+ expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
+ }
+
+ Label operator= (const struct Label &other)
+ {
+ expr = std::unique_ptr<Expr> (other.expr->clone_expr ());
+ return *this;
+ }
};
- Identifier name;
+private:
+ using RegisterType = AST::InlineAsmOperand::RegisterType;
+ AST::InlineAsmOperand::RegisterType register_type;
+
+ tl::optional<struct In> in;
+ tl::optional<struct Out> out;
+ tl::optional<struct InOut> in_out;
+ tl::optional<struct SplitInOut> split_in_out;
+ tl::optional<struct Const> cnst;
+ tl::optional<struct Sym> sym;
+ tl::optional<struct Label> label;
location_t locus;
-};
+public:
+ InlineAsmOperand (const InlineAsmOperand &other)
+ : register_type (other.register_type), in (other.in), out (other.out),
+ in_out (other.in_out), split_in_out (other.split_in_out),
+ cnst (other.cnst), sym (other.sym)
+ {}
+
+ InlineAsmOperand (const struct In &reg)
+ : register_type (RegisterType::In), in (reg)
+ {}
+
+ InlineAsmOperand (const struct Out &reg)
+ : register_type (RegisterType::Out), out (reg)
+ {}
+ InlineAsmOperand (const struct InOut &reg)
+ : register_type (RegisterType::InOut), in_out (reg)
+ {}
+ InlineAsmOperand (const struct SplitInOut &reg)
+ : register_type (RegisterType::SplitInOut), split_in_out (reg)
+ {}
+ InlineAsmOperand (const struct Const &reg)
+ : register_type (RegisterType::Const), cnst (reg)
+ {}
+ InlineAsmOperand (const struct Sym &reg)
+ : register_type (RegisterType::Sym), sym (reg)
+ {}
+ InlineAsmOperand (const struct Label &reg)
+ : register_type (RegisterType::Label), label (reg)
+ {}
+
+ RegisterType get_register_type () const { return register_type; }
+
+ // Potentially unsafe without get_register_type() check
+ struct In get_in () const { return in.value (); }
+ struct Out get_out () const { return out.value (); }
+ struct InOut get_in_out () const { return in_out.value (); }
+ struct SplitInOut get_split_in_out () const { return split_in_out.value (); }
+ struct Const get_const () const { return cnst.value (); }
+ struct Sym get_sym () const { return sym.value (); }
+ struct Label get_label () const { return label.value (); }
+};
// Inline Assembly Node
class InlineAsm : public ExprWithoutBlock
{
@@ -3876,7 +4116,7 @@ public:
std::vector<AST::InlineAsmTemplatePiece> template_;
std::vector<AST::TupleTemplateStr> template_strs;
- std::vector<AST::InlineAsmOperand> operands;
+ std::vector<HIR::InlineAsmOperand> operands;
std::vector<AST::TupleClobber> clobber_abi;
std::set<AST::InlineAsmOption> options;
@@ -3909,16 +4149,27 @@ public:
return template_strs;
}
- std::vector<AST::InlineAsmOperand> get_operands () { return operands; }
+ std::vector<HIR::InlineAsmOperand> get_operands () { return operands; }
std::vector<AST::TupleClobber> get_clobber_abi () { return clobber_abi; }
std::set<AST::InlineAsmOption> get_options () { return options; }
+ bool is_simple_asm ()
+ {
+ // INFO: A simple asm is an asm that does not have any operands
+ return this->operands.size () == 0;
+ }
+
+ bool is_inline_asm ()
+ {
+ // INFO: An inline asm is asm!, which is the opposite of a global_asm()
+ return !this->is_global_asm;
+ }
InlineAsm (location_t locus, bool is_global_asm,
std::vector<AST::InlineAsmTemplatePiece> template_,
std::vector<AST::TupleTemplateStr> template_strs,
- std::vector<AST::InlineAsmOperand> operands,
+ std::vector<HIR::InlineAsmOperand> operands,
std::vector<AST::TupleClobber> clobber_abi,
std::set<AST::InlineAsmOption> options,
Analysis::NodeMapping mappings,
diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h
index efe7c45..64be7bf 100644
--- a/gcc/rust/hir/tree/rust-hir-full-decls.h
+++ b/gcc/rust/hir/tree/rust-hir-full-decls.h
@@ -125,7 +125,8 @@ class AwaitExpr;
class AsyncBlockExpr;
class InlineAsmReg;
class InlineAsmRegClass;
-struct InlineAsmRegOrRegClass;
+struct AnonConst;
+class InlineAsmOperand;
class InlineAsm;
// rust-stmt.h
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index a06513d..1f53e85 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -35,9 +35,7 @@ class TypePath;
// A type generic parameter (as opposed to a lifetime generic parameter)
class TypeParam : public GenericParam
{
- // bool has_outer_attribute;
- // std::unique_ptr<Attribute> outer_attr;
- AST::Attribute outer_attr;
+ AST::AttrVec outer_attrs;
Identifier type_representation;
@@ -59,16 +57,16 @@ public:
bool has_type_param_bounds () const { return !type_param_bounds.empty (); }
// Returns whether the type param has an outer attribute.
- bool has_outer_attribute () const { return !outer_attr.is_empty (); }
- AST::Attribute &get_outer_attribute () { return outer_attr; }
+ bool has_outer_attribute () const override { return outer_attrs.size () > 0; }
+ AST::AttrVec &get_outer_attrs () override { return outer_attrs; }
TypeParam (Analysis::NodeMapping mappings, Identifier type_representation,
location_t locus = UNDEF_LOCATION,
std::vector<std::unique_ptr<TypeParamBound>> type_param_bounds
= std::vector<std::unique_ptr<TypeParamBound>> (),
std::unique_ptr<Type> type = nullptr,
- AST::Attribute outer_attr = AST::Attribute::create_empty ())
- : GenericParam (mappings), outer_attr (std::move (outer_attr)),
+ AST::AttrVec outer_attrs = std::vector<AST::Attribute> ())
+ : GenericParam (mappings), outer_attrs (std::move (outer_attrs)),
type_representation (std::move (type_representation)),
type_param_bounds (std::move (type_param_bounds)),
type (std::move (type)), locus (locus)
@@ -76,7 +74,7 @@ public:
// Copy constructor uses clone
TypeParam (TypeParam const &other)
- : GenericParam (other.mappings), outer_attr (other.outer_attr),
+ : GenericParam (other.mappings), outer_attrs (other.outer_attrs),
type_representation (other.type_representation), locus (other.locus)
{
// guard to prevent null pointer dereference
@@ -92,7 +90,7 @@ public:
TypeParam &operator= (TypeParam const &other)
{
type_representation = other.type_representation;
- outer_attr = other.outer_attr;
+ outer_attrs = other.outer_attrs;
locus = other.locus;
mappings = other.mappings;
@@ -2741,6 +2739,7 @@ class ImplBlock : public VisItem, public WithInnerAttrs
BoundPolarity polarity;
location_t locus;
std::vector<std::unique_ptr<ImplItem>> impl_items;
+ bool unsafe;
public:
ImplBlock (Analysis::NodeMapping mappings,
@@ -2749,20 +2748,20 @@ public:
std::unique_ptr<Type> impl_type,
std::unique_ptr<TypePath> trait_ref, WhereClause where_clause,
BoundPolarity polarity, Visibility vis, AST::AttrVec inner_attrs,
- AST::AttrVec outer_attrs, location_t locus)
+ AST::AttrVec outer_attrs, location_t locus, bool unsafe = false)
: VisItem (std::move (mappings), std::move (vis), std::move (outer_attrs)),
WithInnerAttrs (std::move (inner_attrs)),
generic_params (std::move (generic_params)),
impl_type (std::move (impl_type)), trait_ref (std::move (trait_ref)),
where_clause (std::move (where_clause)), polarity (polarity),
- locus (locus), impl_items (std::move (impl_items))
+ locus (locus), impl_items (std::move (impl_items)), unsafe (unsafe)
{}
ImplBlock (ImplBlock const &other)
: VisItem (other), WithInnerAttrs (other.inner_attrs),
impl_type (other.impl_type->clone_type ()),
where_clause (other.where_clause), polarity (other.polarity),
- locus (other.locus)
+ locus (other.locus), unsafe (other.unsafe)
{
generic_params.reserve (other.generic_params.size ());
for (const auto &e : other.generic_params)
@@ -2781,6 +2780,7 @@ public:
polarity = other.polarity;
inner_attrs = other.inner_attrs;
locus = other.locus;
+ unsafe = other.unsafe;
generic_params.reserve (other.generic_params.size ());
for (const auto &e : other.generic_params)
@@ -2801,6 +2801,8 @@ public:
// Returns whether inherent impl block has inherent impl items.
bool has_impl_items () const { return !impl_items.empty (); }
+ bool is_unsafe () const { return unsafe; }
+
void accept_vis (HIRFullVisitor &vis) override;
void accept_vis (HIRStmtVisitor &vis) override;
void accept_vis (HIRVisItemVisitor &vis) override;
diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h
index 72609f4..e69e951 100644
--- a/gcc/rust/hir/tree/rust-hir-visitor.h
+++ b/gcc/rust/hir/tree/rust-hir-visitor.h
@@ -450,6 +450,7 @@ public:
virtual void visit (IfExprConseqElse &expr) = 0;
virtual void visit (IfLetExpr &expr) = 0;
virtual void visit (IfLetExprConseqElse &expr) = 0;
+ virtual void visit (InlineAsm &expr) = 0;
virtual void visit (MatchExpr &expr) = 0;
virtual void visit (AwaitExpr &expr) = 0;
virtual void visit (AsyncBlockExpr &expr) = 0;
diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc
index ac0a256..f05e506 100644
--- a/gcc/rust/hir/tree/rust-hir.cc
+++ b/gcc/rust/hir/tree/rust-hir.cc
@@ -213,6 +213,44 @@ Module::as_string () const
}
std::string
+Item::item_kind_string (Item::ItemKind kind)
+{
+ switch (kind)
+ {
+ case Item::ItemKind::Static:
+ return "static";
+ case Item::ItemKind::Constant:
+ return "constant";
+ case Item::ItemKind::TypeAlias:
+ return "type alias";
+ case Item::ItemKind::Function:
+ return "function";
+ case Item::ItemKind::UseDeclaration:
+ return "use declaration";
+ case Item::ItemKind::ExternBlock:
+ return "extern block";
+ case Item::ItemKind::ExternCrate:
+ return "extern crate";
+ case Item::ItemKind::Struct:
+ return "struct";
+ case Item::ItemKind::Union:
+ return "union";
+ case Item::ItemKind::Enum:
+ return "enum";
+ case Item::ItemKind::EnumItem:
+ return "enum item";
+ case Item::ItemKind::Trait:
+ return "trait";
+ case Item::ItemKind::Impl:
+ return "impl";
+ case Item::ItemKind::Module:
+ return "module";
+ default:
+ rust_unreachable ();
+ }
+}
+
+std::string
StaticItem::as_string () const
{
std::string str = VisItem::as_string ();
@@ -2017,14 +2055,19 @@ LifetimeParam::as_string () const
{
std::string str ("LifetimeParam: ");
- str += "\n Outer attribute: ";
- if (!has_outer_attribute ())
+ str += "\n Outer attributes: ";
+ if (outer_attrs.empty ())
{
str += "none";
}
else
{
- str += outer_attr.as_string ();
+ /* note that this does not print them with "outer attribute" syntax -
+ * just the body */
+ for (const auto &attr : outer_attrs)
+ {
+ str += "\n " + attr.as_string ();
+ }
}
str += "\n Lifetime: " + lifetime.as_string ();
@@ -2106,14 +2149,19 @@ TypeParam::as_string () const
{
std::string str ("TypeParam: ");
- str += "\n Outer attribute: ";
- if (!has_outer_attribute ())
+ str += "\n Outer attributes: ";
+ if (outer_attrs.empty ())
{
str += "none";
}
else
{
- str += outer_attr.as_string ();
+ /* note that this does not print them with "outer attribute" syntax -
+ * just the body */
+ for (const auto &attr : outer_attrs)
+ {
+ str += "\n " + attr.as_string ();
+ }
}
str += "\n Identifier: " + type_representation.as_string ();
@@ -3785,7 +3833,9 @@ BorrowExpr::accept_vis (HIRFullVisitor &vis)
void
InlineAsm::accept_vis (HIRExpressionVisitor &vis)
-{}
+{
+ vis.visit (*this);
+}
void
InlineAsm::accept_vis (HIRFullVisitor &vis)
diff --git a/gcc/rust/hir/tree/rust-hir.h b/gcc/rust/hir/tree/rust-hir.h
index d7245d4..f8eb22d 100644
--- a/gcc/rust/hir/tree/rust-hir.h
+++ b/gcc/rust/hir/tree/rust-hir.h
@@ -220,6 +220,8 @@ public:
Module,
};
+ static std::string item_kind_string (ItemKind kind);
+
virtual ItemKind get_item_kind () const = 0;
// Unique pointer custom clone function
@@ -617,6 +619,9 @@ public:
CONST,
};
+ virtual AST::AttrVec &get_outer_attrs () = 0;
+ virtual bool has_outer_attribute () const = 0;
+
// Unique pointer custom clone function
std::unique_ptr<GenericParam> clone_generic_param () const
{
@@ -654,9 +659,7 @@ class LifetimeParam : public GenericParam
// LifetimeBounds lifetime_bounds;
std::vector<Lifetime> lifetime_bounds; // inlined LifetimeBounds
- // bool has_outer_attribute;
- // std::unique_ptr<Attribute> outer_attr;
- AST::Attribute outer_attr;
+ AST::AttrVec outer_attrs;
location_t locus;
@@ -669,7 +672,9 @@ public:
std::vector<Lifetime> &get_lifetime_bounds () { return lifetime_bounds; }
// Returns whether the lifetime param has an outer attribute.
- bool has_outer_attribute () const { return !outer_attr.is_empty (); }
+ bool has_outer_attribute () const override { return outer_attrs.size () > 1; }
+
+ AST::AttrVec &get_outer_attrs () { return outer_attrs; }
// Returns whether the lifetime param is in an error state.
bool is_error () const { return lifetime.is_error (); }
@@ -679,11 +684,11 @@ public:
location_t locus = UNDEF_LOCATION,
std::vector<Lifetime> lifetime_bounds
= std::vector<Lifetime> (),
- AST::Attribute outer_attr = AST::Attribute::create_empty ())
+ AST::AttrVec outer_attrs = std::vector<AST::Attribute> ())
: GenericParam (mappings, GenericKind::LIFETIME),
lifetime (std::move (lifetime)),
lifetime_bounds (std::move (lifetime_bounds)),
- outer_attr (std::move (outer_attr)), locus (locus)
+ outer_attrs (std::move (outer_attrs)), locus (locus)
{}
// TODO: remove copy and assignment operator definitions - not required
@@ -692,7 +697,7 @@ public:
LifetimeParam (LifetimeParam const &other)
: GenericParam (other.mappings, GenericKind::LIFETIME),
lifetime (other.lifetime), lifetime_bounds (other.lifetime_bounds),
- outer_attr (other.outer_attr), locus (other.locus)
+ outer_attrs (other.outer_attrs), locus (other.locus)
{}
// Overloaded assignment operator to clone attribute
@@ -700,7 +705,7 @@ public:
{
lifetime = other.lifetime;
lifetime_bounds = other.lifetime_bounds;
- outer_attr = other.outer_attr;
+ outer_attrs = other.outer_attrs;
locus = other.locus;
mappings = other.mappings;
@@ -748,6 +753,10 @@ public:
default_expression = other.default_expression->clone_expr ();
}
+ bool has_outer_attribute () const override { return false; }
+
+ AST::AttrVec &get_outer_attrs () override { return outer_attrs; }
+
std::string as_string () const override final;
void accept_vis (HIRFullVisitor &vis) override final;
@@ -775,6 +784,9 @@ private:
std::string name;
std::unique_ptr<Type> type;
+ /* const params have no outer attrs, should be empty */
+ AST::AttrVec outer_attrs = std::vector<AST::Attribute> ();
+
/* Optional - can be a null pointer if there is no default expression */
std::unique_ptr<Expr> default_expression;
diff --git a/gcc/rust/lex/rust-lex.cc b/gcc/rust/lex/rust-lex.cc
index f4b8861..8490638 100644
--- a/gcc/rust/lex/rust-lex.cc
+++ b/gcc/rust/lex/rust-lex.cc
@@ -589,7 +589,8 @@ Lexer::build_token ()
if (current_char.is_eof ())
{
rust_error_at (
- loc, "unexpected EOF while looking for end of comment");
+ loc, ErrorCode::E0758,
+ "unexpected EOF while looking for end of comment");
break;
}
str += current_char;
@@ -644,7 +645,8 @@ Lexer::build_token ()
if (current_char.is_eof ())
{
rust_error_at (
- loc, "unexpected EOF while looking for end of comment");
+ loc, ErrorCode::E0758,
+ "unexpected EOF while looking for end of comment");
break;
}
@@ -708,7 +710,8 @@ Lexer::build_token ()
if (current_char.is_eof ())
{
rust_error_at (
- loc, "unexpected EOF while looking for end of comment");
+ loc, ErrorCode::E0758,
+ "unexpected EOF while looking for end of comment");
break;
}
diff --git a/gcc/rust/lex/rust-lex.h b/gcc/rust/lex/rust-lex.h
index 8265ca8..10293e0 100644
--- a/gcc/rust/lex/rust-lex.h
+++ b/gcc/rust/lex/rust-lex.h
@@ -115,14 +115,15 @@ private:
// Request new Location for current column in line_table
location_t get_current_location ();
- // Skips the current input char.
+ // Skips the current input character.
void skip_input ();
- // Advances current input char to n + 1 chars ahead of current position.
+ // Advances current input character to n + 1 characters ahead of current
+ // position.
void skip_input (int n);
- // Peeks the current char.
+ // Peeks the current character.
Codepoint peek_input ();
- // Returns char n bytes ahead of current position.
+ // Returns character n characters ahead of current position.
Codepoint peek_input (int n);
// Classifies keyword (i.e. gets id for keyword).
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc
index 69f146c..b23c1eb 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-base.cc
@@ -20,6 +20,7 @@
#include "rust-ast-resolve-expr.h"
#include "rust-ast-resolve-path.h"
#include "rust-item.h"
+#include "rust-path.h"
namespace Rust {
namespace Resolver {
@@ -71,6 +72,14 @@ ResolverBase::visit (AST::ConstGenericParam &)
{}
void
+ResolverBase::visit (AST::RegularPath &)
+{}
+
+void
+ResolverBase::visit (AST::LangItemPath &)
+{}
+
+void
ResolverBase::visit (AST::PathInExpression &)
{}
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h
index 0d497f8..703460a 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.h
+++ b/gcc/rust/resolve/rust-ast-resolve-base.h
@@ -40,6 +40,8 @@ public:
void visit (AST::Lifetime &);
void visit (AST::LifetimeParam &);
void visit (AST::ConstGenericParam &);
+ void visit (AST::RegularPath &);
+ void visit (AST::LangItemPath &);
void visit (AST::PathInExpression &);
void visit (AST::TypePathSegment &);
void visit (AST::TypePathSegmentGeneric &);
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 44ba2a8..7ddf4a9 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -23,6 +23,7 @@
#include "rust-ast-resolve-pattern.h"
#include "rust-ast-resolve-path.h"
#include "diagnostic.h"
+#include "rust-expr.h"
namespace Rust {
namespace Resolver {
@@ -95,6 +96,12 @@ ResolveExpr::visit (AST::MethodCallExpr &expr)
}
void
+ResolveExpr::visit (AST::ErrorPropagationExpr &expr)
+{
+ ResolveExpr::go (expr.get_propagating_expr (), prefix, canonical_prefix);
+}
+
+void
ResolveExpr::visit (AST::AssignmentExpr &expr)
{
ResolveExpr::go (expr.get_left_expr (), prefix, canonical_prefix);
@@ -348,6 +355,60 @@ ResolveExpr::visit (AST::BlockExpr &expr)
}
void
+translate_operand (AST::InlineAsm &expr, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ const auto &operands = expr.get_operands ();
+ using RegisterType = AST::InlineAsmOperand::RegisterType;
+ for (auto &operand : operands)
+ {
+ switch (operand.get_register_type ())
+ {
+ case RegisterType::In: {
+ auto in = operand.get_in ();
+ ResolveExpr::go (*in.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::Out: {
+ auto out = operand.get_out ();
+ ResolveExpr::go (*out.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::InOut: {
+ auto in_out = operand.get_in_out ();
+ ResolveExpr::go (*in_out.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::SplitInOut: {
+ auto split_in_out = operand.get_split_in_out ();
+ ResolveExpr::go (*split_in_out.in_expr, prefix, canonical_prefix);
+ ResolveExpr::go (*split_in_out.out_expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::Const: {
+ auto anon_const = operand.get_const ().anon_const;
+ ResolveExpr::go (*anon_const.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::Sym: {
+ auto sym = operand.get_sym ();
+ ResolveExpr::go (*sym.expr, prefix, canonical_prefix);
+ break;
+ }
+ case RegisterType::Label: {
+ auto label = operand.get_label ();
+ ResolveExpr::go (*label.expr, prefix, canonical_prefix);
+ break;
+ }
+ }
+ }
+}
+void
+ResolveExpr::visit (AST::InlineAsm &expr)
+{
+ translate_operand (expr, prefix, canonical_prefix);
+}
+void
ResolveExpr::visit (AST::UnsafeBlockExpr &expr)
{
expr.get_block_expr ().accept_vis (*this);
@@ -478,12 +539,13 @@ ResolveExpr::visit (AST::BreakExpr &expr)
auto &break_expr = expr.get_break_expr ();
if (break_expr.get_ast_kind () == AST::Kind::IDENTIFIER)
{
- /* This is a break with an expression, and the expression is just a
- single identifier. See if the identifier is either "rust" or
- "gcc", in which case we have "break rust" or "break gcc", and so
- may need to emit our funny error. We cannot yet emit the error
- here though, because the identifier may still be in scope, and
- ICE'ing on valid programs would not be very funny. */
+ /* This is a break with an expression, and the expression is
+ just a single identifier. See if the identifier is either
+ "rust" or "gcc", in which case we have "break rust" or "break
+ gcc", and so may need to emit our funny error. We cannot yet
+ emit the error here though, because the identifier may still
+ be in scope, and ICE'ing on valid programs would not be very
+ funny. */
std::string ident
= static_cast<AST::IdentifierExpr &> (break_expr).as_string ();
if (ident == "rust" || ident == "gcc")
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 75b07b8..562a3bd 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -20,7 +20,9 @@
#define RUST_AST_RESOLVE_EXPR_H
#include "rust-ast-resolve-base.h"
+#include "rust-ast.h"
#include "rust-ast-resolve-pattern.h"
+#include "rust-expr.h"
namespace Rust {
namespace Resolver {
@@ -54,6 +56,7 @@ public:
void visit (AST::IfLetExpr &expr) override;
void visit (AST::IfLetExprConseqElse &expr) override;
void visit (AST::BlockExpr &expr) override;
+ void visit (AST::InlineAsm &expr) override;
void visit (AST::UnsafeBlockExpr &expr) override;
void visit (AST::ArrayElemsValues &elems) override;
void visit (AST::ArrayExpr &expr) override;
@@ -78,6 +81,7 @@ public:
void visit (AST::RangeFromToInclExpr &expr) override;
void visit (AST::ClosureExprInner &expr) override;
void visit (AST::ClosureExprInnerTyped &expr) override;
+ void visit (AST::ErrorPropagationExpr &expr) override;
protected:
void resolve_closure_param (AST::ClosureParam &param,
diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
index 9b383b7..ee84be8 100644
--- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
@@ -330,7 +330,8 @@ PatternDeclaration::check_bindings_consistency (
if (!ident_is_outer_bound && !missing_bindings.count (ident))
missing_bindings.insert ({ident, inner_info});
- else if (outer_bindings_map[ident] != inner_info
+ else if (outer_bindings_map.count (ident)
+ && outer_bindings_map[ident] != inner_info
&& !inconsistent_bindings.count (ident))
inconsistent_bindings.insert ({ident, inner_info});
}
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc
index 934d6ea..ec5e8a7 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-type.cc
@@ -69,7 +69,7 @@ ResolveType::visit (AST::InferredType &)
void
ResolveType::visit (AST::NeverType &)
{
- // FIXME
+ resolved_node = resolver->get_never_type_node_id ();
}
void
@@ -501,6 +501,21 @@ ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &)
rust_unreachable ();
}
+void
+ResolveTypeToCanonicalPath::visit (AST::NeverType &type)
+{
+ result = CanonicalPath::new_seg (type.get_node_id (), "!");
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::TupleType &type)
+{
+ if (!type.is_unit_type ())
+ rust_unreachable ();
+
+ result = CanonicalPath::new_seg (type.get_node_id (), "()");
+}
+
ResolveTypeToCanonicalPath::ResolveTypeToCanonicalPath ()
: ResolverBase (), result (CanonicalPath::create_empty ())
{}
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h
index 0076424..561948e 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.h
+++ b/gcc/rust/resolve/rust-ast-resolve-type.h
@@ -246,6 +246,10 @@ public:
void visit (AST::TraitObjectType &type) override;
+ void visit (AST::NeverType &type) override;
+
+ void visit (AST::TupleType &type) override;
+
private:
ResolveTypeToCanonicalPath ();
diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc
index a467d1e..a093ef7 100644
--- a/gcc/rust/resolve/rust-ast-resolve.cc
+++ b/gcc/rust/resolve/rust-ast-resolve.cc
@@ -63,7 +63,10 @@ NameResolution::go (AST::Crate &crate)
{
// lookup current crate name
CrateNum cnum = mappings.get_current_crate ();
- const auto &crate_name = mappings.get_crate_name (cnum).value ();
+
+ // Clones the crate name instead of references due to gcc's possibly
+ // dangling references warnings
+ const auto crate_name = mappings.get_crate_name (cnum).value ();
// setup the ribs
NodeId scope_node_id = crate.get_node_id ();
diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc
index 6de694f..57b1cc4 100644
--- a/gcc/rust/resolve/rust-default-resolver.cc
+++ b/gcc/rust/resolve/rust-default-resolver.cc
@@ -30,13 +30,7 @@ DefaultResolver::visit (AST::BlockExpr &expr)
// extracting the lambda from the `scoped` call otherwise the code looks like
// a hot turd thanks to our .clang-format
- auto inner_fn = [this, &expr] () {
- for (auto &stmt : expr.get_statements ())
- stmt->accept_vis (*this);
-
- if (expr.has_tail_expr ())
- expr.get_tail_expr ().accept_vis (*this);
- };
+ auto inner_fn = [this, &expr] () { AST::DefaultASTVisitor::visit (expr); };
ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), inner_fn);
}
@@ -44,10 +38,7 @@ DefaultResolver::visit (AST::BlockExpr &expr)
void
DefaultResolver::visit (AST::Module &module)
{
- auto item_fn = [this, &module] () {
- for (auto &item : module.get_items ())
- item->accept_vis (*this);
- };
+ auto item_fn = [this, &module] () { AST::DefaultASTVisitor::visit (module); };
ctx.scoped (Rib::Kind::Module, module.get_node_id (), item_fn,
module.get_name ());
@@ -56,35 +47,8 @@ DefaultResolver::visit (AST::Module &module)
void
DefaultResolver::visit (AST::Function &function)
{
- auto def_fn = [this, &function] () {
- for (auto &p : function.get_function_params ())
- {
- if (p->is_variadic ())
- {
- auto &param = static_cast<AST::VariadicParam &> (*p);
- if (param.has_pattern ())
- param.get_pattern ().accept_vis (*this);
- }
- else if (p->is_self ())
- {
- auto &param = static_cast<AST::SelfParam &> (*p);
- param.get_type ().accept_vis (*this);
- param.get_lifetime ().accept_vis (*this);
- }
- else
- {
- auto &param = static_cast<AST::FunctionParam &> (*p);
- param.get_pattern ().accept_vis (*this);
- param.get_type ().accept_vis (*this);
- }
- }
-
- if (function.has_return_type ())
- visit (function.get_return_type ());
-
- if (function.has_body ())
- function.get_definition ().value ()->accept_vis (*this);
- };
+ auto def_fn
+ = [this, &function] () { AST::DefaultASTVisitor::visit (function); };
ctx.scoped (Rib::Kind::Function, function.get_node_id (), def_fn);
}
@@ -92,20 +56,14 @@ DefaultResolver::visit (AST::Function &function)
void
DefaultResolver::visit (AST::ForLoopExpr &expr)
{
- ctx.scoped (Rib::Kind::Normal, expr.get_node_id (), [this, &expr] () {
- expr.get_pattern ().accept_vis (*this);
- expr.get_iterator_expr ().accept_vis (*this);
- expr.get_loop_block ().accept_vis (*this);
- });
+ ctx.scoped (Rib::Kind::Normal, expr.get_node_id (),
+ [this, &expr] () { AST::DefaultASTVisitor::visit (expr); });
}
void
DefaultResolver::visit (AST::Trait &trait)
{
- auto inner_fn = [this, &trait] () {
- for (auto &item : trait.get_trait_items ())
- item->accept_vis (*this);
- };
+ auto inner_fn = [this, &trait] () { AST::DefaultASTVisitor::visit (trait); };
ctx.scoped (Rib::Kind::TraitOrImpl, trait.get_node_id (), inner_fn,
trait.get_identifier () /* FIXME: Is that valid?*/);
@@ -114,11 +72,7 @@ DefaultResolver::visit (AST::Trait &trait)
void
DefaultResolver::visit (AST::InherentImpl &impl)
{
- auto inner_fn = [this, &impl] () {
- visit (impl.get_type ());
- for (auto &item : impl.get_impl_items ())
- item->accept_vis (*this);
- };
+ auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); };
ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn);
}
@@ -126,10 +80,7 @@ DefaultResolver::visit (AST::InherentImpl &impl)
void
DefaultResolver::visit (AST::TraitImpl &impl)
{
- auto inner_fn = [this, &impl] () {
- for (auto &item : impl.get_impl_items ())
- item->accept_vis (*this);
- };
+ auto inner_fn = [this, &impl] () { AST::DefaultASTVisitor::visit (impl); };
ctx.scoped (Rib::Kind::TraitOrImpl, impl.get_node_id (), inner_fn);
}
@@ -152,40 +103,19 @@ DefaultResolver::visit (AST::Enum &type)
{
// FIXME: Do we need to scope anything by default?
- auto variant_fn = [this, &type] () {
- for (auto &variant : type.get_variants ())
- variant->accept_vis (*this);
- };
+ auto variant_fn = [this, &type] () { AST::DefaultASTVisitor::visit (type); };
ctx.scoped (Rib::Kind::Item /* FIXME: Correct? */, type.get_node_id (),
variant_fn, type.get_identifier ());
}
void
-DefaultResolver::visit (AST::StructExprFieldIdentifierValue &)
-{}
-
-void
-DefaultResolver::visit (AST::StructExprFieldIndexValue &)
-{}
-
-void
DefaultResolver::visit (AST::ClosureExprInner &expr)
{
if (expr.is_marked_for_strip ())
return;
- for (auto &param : expr.get_params ())
- {
- if (param.is_error ())
- continue;
-
- param.get_pattern ().accept_vis (*this);
- if (param.has_type_given ())
- param.get_type ().accept_vis (*this);
- }
-
- expr.get_definition_expr ().accept_vis (*this);
+ AST::DefaultASTVisitor::visit (expr);
}
void
@@ -194,286 +124,16 @@ DefaultResolver::visit (AST::ClosureExprInnerTyped &expr)
if (expr.is_marked_for_strip ())
return;
- for (auto &param : expr.get_params ())
- {
- if (param.is_error ())
- continue;
-
- param.get_pattern ().accept_vis (*this);
- if (param.has_type_given ())
- param.get_type ().accept_vis (*this);
- }
-
- expr.get_definition_block ().accept_vis (*this);
- expr.get_return_type ().accept_vis (*this);
+ AST::DefaultASTVisitor::visit (expr);
}
void
-DefaultResolver::visit (AST::ContinueExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeFromToExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeFromExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeToExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeFromToInclExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::RangeToInclExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::ReturnExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::CallExpr &expr)
-{
- expr.get_function_expr ().accept_vis (*this);
-
- for (auto &param : expr.get_params ())
- param->accept_vis (*this);
-}
-
-void
-DefaultResolver::visit (AST::MethodCallExpr &expr)
-{
- expr.get_receiver_expr ().accept_vis (*this);
-
- if (expr.get_method_name ().has_generic_args ())
- {
- auto &args = expr.get_method_name ().get_generic_args ();
- for (auto &arg : args.get_generic_args ())
- arg.accept_vis (*this);
- for (auto &arg : args.get_binding_args ())
- if (!arg.is_error ())
- arg.get_type ().accept_vis (*this);
- for (auto &arg : args.get_lifetime_args ())
- arg.accept_vis (*this);
- }
-
- for (auto &param : expr.get_params ())
- param->accept_vis (*this);
-}
-
-void
-DefaultResolver::visit (AST::LoopExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::WhileLoopExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::WhileLetLoopExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::IfExpr &expr)
-{
- expr.get_condition_expr ().accept_vis (*this);
- expr.get_if_block ().accept_vis (*this);
-}
-
-void
-DefaultResolver::visit (AST::IfExprConseqElse &expr)
-{
- expr.get_condition_expr ().accept_vis (*this);
- expr.get_if_block ().accept_vis (*this);
- expr.get_else_block ().accept_vis (*this);
-}
-
-void
-DefaultResolver::visit (AST::IfLetExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::IfLetExprConseqElse &)
-{}
-
-void
DefaultResolver::visit (AST::MatchExpr &expr)
{
if (expr.is_marked_for_strip ())
return;
- expr.get_scrutinee_expr ().accept_vis (*this);
- for (auto &arm : expr.get_match_cases ())
- {
- arm.get_expr ().accept_vis (*this);
- for (auto &pat : arm.get_arm ().get_patterns ())
- pat->accept_vis (*this);
- if (arm.get_arm ().has_match_arm_guard ())
- arm.get_arm ().get_guard_expr ().accept_vis (*this);
- }
-}
-
-void
-DefaultResolver::visit (AST::AwaitExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::AsyncBlockExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::DelimTokenTree &)
-{}
-
-void
-DefaultResolver::visit (AST::AttrInputMetaItemContainer &)
-{}
-
-void
-DefaultResolver::visit (AST::IdentifierExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::LifetimeParam &)
-{}
-
-void
-DefaultResolver::visit (AST::ConstGenericParam &)
-{}
-
-void
-DefaultResolver::visit (AST::PathInExpression &expr)
-{
- for (auto &seg : expr.get_segments ())
- if (seg.has_generic_args ())
- {
- auto &args = seg.get_generic_args ();
- for (auto &arg : args.get_generic_args ())
- arg.accept_vis (*this);
- for (auto &arg : args.get_binding_args ())
- if (!arg.is_error ())
- arg.get_type ().accept_vis (*this);
- for (auto &arg : args.get_lifetime_args ())
- arg.accept_vis (*this);
- }
-}
-
-void
-DefaultResolver::visit (AST::TypePathSegmentGeneric &)
-{}
-
-void
-DefaultResolver::visit (AST::TypePathSegmentFunction &)
-{}
-
-void
-DefaultResolver::visit (AST::TypePath &)
-{}
-
-void
-DefaultResolver::visit (AST::QualifiedPathInExpression &)
-{}
-
-void
-DefaultResolver::visit (AST::QualifiedPathInType &)
-{}
-
-void
-DefaultResolver::visit (AST::LiteralExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::AttrInputLiteral &)
-{}
-
-void
-DefaultResolver::visit (AST::AttrInputMacro &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaItemLitExpr &expr)
-{}
-
-void
-DefaultResolver::visit (AST::MetaItemPathLit &)
-{}
-
-void
-DefaultResolver::visit (AST::StructExprStruct &)
-{}
-
-void
-DefaultResolver::visit (AST::StructExprStructFields &)
-{}
-
-void
-DefaultResolver::visit (AST::StructExprStructBase &)
-{}
-
-void
-DefaultResolver::visit (AST::TypeParam &)
-{}
-
-void
-DefaultResolver::visit (AST::LifetimeWhereClauseItem &)
-{}
-
-void
-DefaultResolver::visit (AST::TypeBoundWhereClauseItem &)
-{}
-
-void
-DefaultResolver::visit (AST::ExternCrate &)
-{}
-
-void
-DefaultResolver::visit (AST::UseTreeGlob &)
-{}
-
-void
-DefaultResolver::visit (AST::UseTreeList &)
-{}
-
-void
-DefaultResolver::visit (AST::UseTreeRebind &)
-{}
-
-void
-DefaultResolver::visit (AST::UseDeclaration &)
-{}
-
-void
-DefaultResolver::visit (AST::TypeAlias &)
-{}
-
-void
-DefaultResolver::visit (AST::EnumItem &)
-{}
-
-void
-DefaultResolver::visit (AST::EnumItemTuple &item)
-{
- for (auto &field : item.get_tuple_fields ())
- field.get_field_type ().accept_vis (*this);
-}
-
-void
-DefaultResolver::visit (AST::EnumItemStruct &item)
-{
- for (auto &field : item.get_struct_fields ())
- field.get_field_type ().accept_vis (*this);
-}
-
-void
-DefaultResolver::visit (AST::EnumItemDiscriminant &item)
-{
- if (item.has_expr ())
- item.get_expr ().accept_vis (*this);
+ AST::DefaultASTVisitor::visit (expr);
}
void
@@ -481,10 +141,8 @@ DefaultResolver::visit (AST::ConstantItem &item)
{
if (item.has_expr ())
{
- auto expr_vis = [this, &item] () {
- item.get_expr ().accept_vis (*this);
- visit (item.get_type ());
- };
+ auto expr_vis
+ = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
// FIXME: Why do we need a Rib here?
ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis);
@@ -494,187 +152,11 @@ DefaultResolver::visit (AST::ConstantItem &item)
void
DefaultResolver::visit (AST::StaticItem &item)
{
- auto expr_vis = [this, &item] () { item.get_expr ().accept_vis (*this); };
+ auto expr_vis = [this, &item] () { AST::DefaultASTVisitor::visit (item); };
// FIXME: Why do we need a Rib here?
ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis);
}
-void
-DefaultResolver::visit (AST::TraitItemConst &)
-{}
-
-void
-DefaultResolver::visit (AST::TraitItemType &)
-{}
-
-void
-DefaultResolver::visit (AST::ExternalTypeItem &)
-{}
-
-void
-DefaultResolver::visit (AST::ExternalStaticItem &)
-{}
-
-void
-DefaultResolver::visit (AST::MacroMatchRepetition &)
-{}
-
-void
-DefaultResolver::visit (AST::MacroMatcher &)
-{}
-
-void
-DefaultResolver::visit (AST::MacroRulesDefinition &)
-{}
-
-void
-DefaultResolver::visit (AST::MacroInvocation &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaItemPath &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaItemSeq &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaListPaths &)
-{}
-
-void
-DefaultResolver::visit (AST::MetaListNameValueStr &)
-{}
-
-void
-DefaultResolver::visit (AST::RangePatternBoundPath &)
-{}
-
-void
-DefaultResolver::visit (AST::RangePatternBoundQualPath &)
-{}
-
-void
-DefaultResolver::visit (AST::RangePattern &)
-{}
-
-void
-DefaultResolver::visit (AST::ReferencePattern &)
-{}
-
-void
-DefaultResolver::visit (AST::StructPatternFieldTuplePat &)
-{}
-
-void
-DefaultResolver::visit (AST::StructPatternFieldIdentPat &)
-{}
-
-void
-DefaultResolver::visit (AST::StructPatternFieldIdent &)
-{}
-
-void
-DefaultResolver::visit (AST::StructPattern &)
-{}
-
-void
-DefaultResolver::visit (AST::TupleStructItemsNoRange &)
-{}
-
-void
-DefaultResolver::visit (AST::TupleStructItemsRange &)
-{}
-
-void
-DefaultResolver::visit (AST::TupleStructPattern &)
-{}
-
-void
-DefaultResolver::visit (AST::TuplePatternItemsMultiple &)
-{}
-
-void
-DefaultResolver::visit (AST::TuplePatternItemsRanged &)
-{}
-
-void
-DefaultResolver::visit (AST::TuplePattern &)
-{}
-
-void
-DefaultResolver::visit (AST::GroupedPattern &)
-{}
-
-void
-DefaultResolver::visit (AST::SlicePattern &)
-{}
-
-void
-DefaultResolver::visit (AST::AltPattern &)
-{}
-
-void
-DefaultResolver::visit (AST::EmptyStmt &)
-{}
-
-void
-DefaultResolver::visit (AST::TraitBound &)
-{}
-
-void
-DefaultResolver::visit (AST::ImplTraitType &)
-{}
-
-void
-DefaultResolver::visit (AST::TraitObjectType &)
-{}
-
-void
-DefaultResolver::visit (AST::ParenthesisedType &)
-{}
-
-void
-DefaultResolver::visit (AST::ImplTraitTypeOneBound &)
-{}
-
-void
-DefaultResolver::visit (AST::TraitObjectTypeOneBound &)
-{}
-
-void
-DefaultResolver::visit (AST::TupleType &)
-{}
-
-void
-DefaultResolver::visit (AST::ReferenceType &)
-{}
-
-void
-DefaultResolver::visit (AST::ArrayType &)
-{}
-
-void
-DefaultResolver::visit (AST::SliceType &)
-{}
-
-void
-DefaultResolver::visit (AST::BareFunctionType &)
-{}
-
-void
-DefaultResolver::visit (AST::SelfParam &)
-{}
-
-void
-DefaultResolver::visit (AST::FunctionParam &)
-{}
-
-void
-DefaultResolver::visit (AST::VariadicParam &)
-{}
-
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h
index 6bca8b7..9fcddd1 100644
--- a/gcc/rust/resolve/rust-default-resolver.h
+++ b/gcc/rust/resolve/rust-default-resolver.h
@@ -42,122 +42,26 @@ public:
// First, our lexical scope expressions - these visit their sub nodes, always
// these nodes create new scopes and ribs - they are often used to declare new
// variables, such as a for loop's iterator, or a function's arguments
- void visit (AST::BlockExpr &);
- void visit (AST::Module &);
- void visit (AST::Function &);
- void visit (AST::ForLoopExpr &);
- void visit (AST::Trait &);
- void visit (AST::InherentImpl &);
- void visit (AST::TraitImpl &);
+ void visit (AST::BlockExpr &) override;
+ void visit (AST::Module &) override;
+ void visit (AST::Function &) override;
+ void visit (AST::ForLoopExpr &expr) override;
+ void visit (AST::Trait &) override;
+ void visit (AST::InherentImpl &) override;
+ void visit (AST::TraitImpl &) override;
// type dec nodes, which visit their fields or variants by default
- void visit (AST::StructStruct &);
- void visit (AST::Enum &);
+ void visit (AST::StructStruct &) override;
+ void visit (AST::Enum &) override;
// Visitors that visit their expression node(s)
- void visit (AST::StructExprFieldIdentifierValue &);
- void visit (AST::StructExprFieldIndexValue &);
- void visit (AST::ClosureExprInner &);
- void visit (AST::ClosureExprInnerTyped &);
- void visit (AST::ContinueExpr &);
- void visit (AST::RangeFromToExpr &);
- void visit (AST::RangeFromExpr &);
- void visit (AST::RangeToExpr &);
- void visit (AST::RangeFromToInclExpr &);
- void visit (AST::RangeToInclExpr &);
- void visit (AST::ReturnExpr &);
- void visit (AST::CallExpr &);
- void visit (AST::MethodCallExpr &);
- void visit (AST::LoopExpr &);
- void visit (AST::WhileLoopExpr &);
- void visit (AST::WhileLetLoopExpr &);
- void visit (AST::IfExpr &);
- void visit (AST::IfExprConseqElse &);
- void visit (AST::IfLetExpr &);
- void visit (AST::IfLetExprConseqElse &);
- void visit (AST::MatchExpr &);
- void visit (AST::AwaitExpr &);
- void visit (AST::AsyncBlockExpr &);
+ void visit (AST::ClosureExprInner &) override;
+ void visit (AST::ClosureExprInnerTyped &) override;
+ void visit (AST::MatchExpr &) override;
// Leaf visitors, which do nothing by default
- void visit (AST::DelimTokenTree &);
- void visit (AST::AttrInputMetaItemContainer &);
- void visit (AST::IdentifierExpr &);
- void visit (AST::LifetimeParam &);
- void visit (AST::ConstGenericParam &);
- void visit (AST::PathInExpression &);
- void visit (AST::TypePathSegmentGeneric &);
- void visit (AST::TypePathSegmentFunction &);
- void visit (AST::TypePath &);
- void visit (AST::QualifiedPathInExpression &);
- void visit (AST::QualifiedPathInType &);
- void visit (AST::LiteralExpr &);
- void visit (AST::AttrInputLiteral &);
- void visit (AST::AttrInputMacro &);
- void visit (AST::MetaItemLitExpr &);
- void visit (AST::MetaItemPathLit &);
- void visit (AST::StructExprStruct &);
- void visit (AST::StructExprStructFields &);
- void visit (AST::StructExprStructBase &);
- void visit (AST::TypeParam &);
- void visit (AST::LifetimeWhereClauseItem &);
- void visit (AST::TypeBoundWhereClauseItem &);
- void visit (AST::ExternCrate &);
- void visit (AST::UseTreeGlob &);
- void visit (AST::UseTreeList &);
- void visit (AST::UseTreeRebind &);
- void visit (AST::UseDeclaration &);
- void visit (AST::TypeAlias &);
- void visit (AST::EnumItem &);
- void visit (AST::EnumItemTuple &);
- void visit (AST::EnumItemStruct &);
- void visit (AST::EnumItemDiscriminant &);
- void visit (AST::ConstantItem &);
- void visit (AST::StaticItem &);
- void visit (AST::TraitItemConst &);
- void visit (AST::TraitItemType &);
- void visit (AST::ExternalTypeItem &);
- void visit (AST::ExternalStaticItem &);
- void visit (AST::MacroMatchRepetition &);
- void visit (AST::MacroMatcher &);
- void visit (AST::MacroRulesDefinition &);
- void visit (AST::MacroInvocation &);
- void visit (AST::MetaItemPath &);
- void visit (AST::MetaItemSeq &);
- void visit (AST::MetaListPaths &);
- void visit (AST::MetaListNameValueStr &);
- void visit (AST::RangePatternBoundPath &);
- void visit (AST::RangePatternBoundQualPath &);
- void visit (AST::RangePattern &);
- void visit (AST::ReferencePattern &);
- void visit (AST::StructPatternFieldTuplePat &);
- void visit (AST::StructPatternFieldIdentPat &);
- void visit (AST::StructPatternFieldIdent &);
- void visit (AST::StructPattern &);
- void visit (AST::TupleStructItemsNoRange &);
- void visit (AST::TupleStructItemsRange &);
- void visit (AST::TupleStructPattern &);
- void visit (AST::TuplePatternItemsMultiple &);
- void visit (AST::TuplePatternItemsRanged &);
- void visit (AST::TuplePattern &);
- void visit (AST::GroupedPattern &);
- void visit (AST::SlicePattern &);
- void visit (AST::AltPattern &);
- void visit (AST::EmptyStmt &);
- void visit (AST::TraitBound &);
- void visit (AST::ImplTraitType &);
- void visit (AST::TraitObjectType &);
- void visit (AST::ParenthesisedType &);
- void visit (AST::ImplTraitTypeOneBound &);
- void visit (AST::TraitObjectTypeOneBound &);
- void visit (AST::TupleType &);
- void visit (AST::ReferenceType &);
- void visit (AST::ArrayType &);
- void visit (AST::SliceType &);
- void visit (AST::BareFunctionType &);
- void visit (AST::FunctionParam &);
- void visit (AST::VariadicParam &);
- void visit (AST::SelfParam &);
+ void visit (AST::ConstantItem &) override;
+ void visit (AST::StaticItem &) override;
protected:
DefaultResolver (NameResolutionContext &ctx) : ctx (ctx) {}
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
index 1b21e11..5533048 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -18,13 +18,16 @@
#include "rust-early-name-resolver-2.0.h"
#include "rust-ast-full.h"
+#include "rust-diagnostics.h"
#include "rust-toplevel-name-resolver-2.0.h"
#include "rust-attributes.h"
+#include "rust-finalize-imports-2.0.h"
namespace Rust {
namespace Resolver2_0 {
-Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx) {}
+Early::Early (NameResolutionContext &ctx) : DefaultResolver (ctx), dirty (false)
+{}
void
Early::insert_once (AST::MacroInvocation &invocation, NodeId resolved)
@@ -51,16 +54,116 @@ Early::go (AST::Crate &crate)
auto toplevel = TopLevel (ctx);
toplevel.go (crate);
- textual_scope.push ();
+ // We start with resolving the list of imports that `TopLevel` has built for
+ // us
+ for (auto &&import : toplevel.get_imports_to_resolve ())
+ build_import_mapping (std::move (import));
+
+ // Once this is done, we finalize their resolution
+ FinalizeImports (std::move (import_mappings), toplevel, ctx).go (crate);
- // Then we proceed to the proper "early" name resolution: Import and macro
- // name resolution
+ dirty = toplevel.is_dirty ();
+ // We now proceed with resolving macros, which can be nested in almost any
+ // items
+ textual_scope.push ();
for (auto &item : crate.items)
item->accept_vis (*this);
-
textual_scope.pop ();
}
+bool
+Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob)
+{
+ auto resolved = ctx.types.resolve_path (glob.to_resolve.get_segments ());
+ if (!resolved.has_value ())
+ return false;
+
+ auto result
+ = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ());
+ if (!result)
+ return false;
+
+ // here, we insert the module's NodeId into the import_mappings and will look
+ // up the module proper in `FinalizeImports`
+ // The namespace does not matter here since we are dealing with a glob
+ // TODO: Ugly
+ import_mappings.insert (use_dec_id,
+ ImportPair (std::move (glob),
+ ImportData::Glob (*resolved)));
+
+ return true;
+}
+
+bool
+Early::resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import)
+{
+ auto definitions = resolve_path_in_all_ns (import.to_resolve);
+
+ // if we've found at least one definition, then we're good
+ if (definitions.empty ())
+ return false;
+
+ auto &imports = import_mappings.new_or_access (use_dec_id);
+
+ imports.emplace_back (
+ ImportPair (std::move (import),
+ ImportData::Simple (std::move (definitions))));
+
+ return true;
+}
+
+bool
+Early::resolve_rebind_import (NodeId use_dec_id,
+ TopLevel::ImportKind &&rebind_import)
+{
+ auto definitions = resolve_path_in_all_ns (rebind_import.to_resolve);
+
+ // if we've found at least one definition, then we're good
+ if (definitions.empty ())
+ return false;
+
+ auto &imports = import_mappings.new_or_access (use_dec_id);
+
+ imports.emplace_back (
+ ImportPair (std::move (rebind_import),
+ ImportData::Rebind (std::move (definitions))));
+
+ return true;
+}
+
+void
+Early::build_import_mapping (
+ std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import)
+{
+ auto found = false;
+ auto use_dec_id = use_import.first;
+
+ for (auto &&import : use_import.second)
+ {
+ // We create a copy of the path in case of errors, since the `import` will
+ // be moved into the newly created import mappings
+ auto path = import.to_resolve;
+
+ switch (import.kind)
+ {
+ case TopLevel::ImportKind::Kind::Glob:
+ found = resolve_glob_import (use_dec_id, std::move (import));
+ break;
+ case TopLevel::ImportKind::Kind::Simple:
+ found = resolve_simple_import (use_dec_id, std::move (import));
+ break;
+ case TopLevel::ImportKind::Kind::Rebind:
+ found = resolve_rebind_import (use_dec_id, std::move (import));
+ break;
+ }
+
+ if (!found)
+ collect_error (Error (path.get_final_segment ().get_locus (),
+ ErrorCode::E0433, "unresolved import %qs",
+ path.as_string ().c_str ()));
+ }
+}
+
void
Early::TextualScope::push ()
{
@@ -198,8 +301,9 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs)
if (!definition.has_value ())
{
// FIXME: Change to proper error message
- rust_error_at (trait.get ().get_locus (),
- "could not resolve trait");
+ collect_error (Error (trait.get ().get_locus (),
+ "could not resolve trait %qs",
+ trait.get ().as_string ().c_str ()));
continue;
}
@@ -221,8 +325,9 @@ Early::visit_attributes (std::vector<AST::Attribute> &attrs)
if (!definition.has_value ())
{
// FIXME: Change to proper error message
- rust_error_at (attr.get_locus (),
- "could not resolve attribute macro invocation");
+ collect_error (
+ Error (attr.get_locus (),
+ "could not resolve attribute macro invocation"));
return;
}
auto pm_def = mappings.lookup_attribute_proc_macro_def (
diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
index 590a256..a7ad0f7 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
@@ -24,6 +24,8 @@
#include "rust-ast-visitor.h"
#include "rust-name-resolution-context.h"
#include "rust-default-resolver.h"
+#include "rust-rib.h"
+#include "rust-toplevel-name-resolver-2.0.h"
namespace Rust {
namespace Resolver2_0 {
@@ -32,9 +34,13 @@ class Early : public DefaultResolver
{
using DefaultResolver::visit;
+ bool dirty;
+
public:
Early (NameResolutionContext &ctx);
+ bool is_dirty () { return dirty; }
+
void go (AST::Crate &crate);
const std::vector<Error> &get_macro_resolve_errors () const
@@ -54,6 +60,110 @@ public:
void visit (AST::Function &) override;
void visit (AST::StructStruct &) override;
+ struct ImportData
+ {
+ enum class Kind
+ {
+ Simple,
+ Glob,
+ Rebind
+ } kind;
+
+ static ImportData
+ Simple (std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
+ {
+ return ImportData (Kind::Simple, std::move (definitions));
+ }
+
+ static ImportData
+ Rebind (std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
+ {
+ return ImportData (Kind::Rebind, std::move (definitions));
+ }
+
+ static ImportData Glob (Rib::Definition module)
+ {
+ return ImportData (Kind::Glob, module);
+ }
+
+ Rib::Definition module () const
+ {
+ rust_assert (kind == Kind::Glob);
+ return glob_module;
+ }
+
+ std::vector<std::pair<Rib::Definition, Namespace>> definitions () const
+ {
+ rust_assert (kind != Kind::Glob);
+ return std::move (resolved_definitions);
+ }
+
+ private:
+ ImportData (
+ Kind kind,
+ std::vector<std::pair<Rib::Definition, Namespace>> &&definitions)
+ : kind (kind), resolved_definitions (std::move (definitions))
+ {}
+
+ ImportData (Kind kind, Rib::Definition module)
+ : kind (kind), glob_module (module)
+ {}
+
+ // TODO: Should this be a union?
+
+ // For Simple and Rebind
+ std::vector<std::pair<Rib::Definition, Namespace>> resolved_definitions;
+
+ // For Glob
+ Rib::Definition glob_module;
+ };
+
+ struct ImportPair
+ {
+ TopLevel::ImportKind import_kind;
+ ImportData data;
+
+ explicit ImportPair (TopLevel::ImportKind &&kind, ImportData &&data)
+ : import_kind (std::move (kind)), data (std::move (data))
+ {}
+ };
+
+ class ImportMappings
+ {
+ public:
+ std::vector<ImportPair> &new_or_access (NodeId path_id)
+ {
+ // We insert an empty vector, unless an element was already present for
+ // `use_dec_id` - which is returned in the tuple's first member
+ auto iter = mappings.insert ({{path_id}, {}});
+
+ // We then get that tuple's first member, which will be an iterator to the
+ // existing vec<pair<ImportKind, ImportData>> OR an iterator to our newly
+ // created empty vector (plus its key since this is a hashmap iterator).
+ // we then access the second member of the pair to get access to the
+ // vector directly.
+ return iter.first->second;
+ }
+
+ void insert (NodeId path_id, std::vector<ImportPair> &&pairs)
+ {
+ mappings.insert ({{path_id}, std::move (pairs)});
+ }
+
+ // Same as `insert`, but with just one node
+ void insert (NodeId path_id, ImportPair &&pair)
+ {
+ mappings.insert ({{path_id}, {pair}});
+ }
+
+ std::vector<ImportPair> &get (NodeId use_id) { return mappings[use_id]; }
+
+ private:
+ // Each path can import in multiple namespaces, hence the mapping from one
+ // path to a vector of import pairs
+ std::unordered_map<NodeId, std::vector<ImportPair>> mappings;
+ };
+
private:
void visit_attributes (std::vector<AST::Attribute> &attrs);
@@ -91,6 +201,44 @@ private:
std::vector<std::unordered_map<std::string, NodeId>> scopes;
};
+ // Mappings between an import and the definition it imports
+ ImportMappings import_mappings;
+
+ // FIXME: Documentation
+ // Call this on all the paths of a UseDec - so each flattened path in a
+ // UseTreeList for example
+ // FIXME: Should that return `found`?
+ bool resolve_simple_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
+ bool resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
+ bool resolve_rebind_import (NodeId use_dec_id, TopLevel::ImportKind &&import);
+
+ template <typename P>
+ std::vector<std::pair<Rib::Definition, Namespace>>
+ resolve_path_in_all_ns (const P &path)
+ {
+ const auto &segments = path.get_segments ();
+ std::vector<std::pair<Rib::Definition, Namespace>> resolved;
+
+ // Pair a definition with the namespace it was found in
+ auto pair_with_ns = [&] (Namespace ns) {
+ return [&, ns] (Rib::Definition def) {
+ auto pair = std::make_pair (def, ns);
+ return resolved.emplace_back (std::move (pair));
+ };
+ };
+
+ ctx.values.resolve_path (segments).map (pair_with_ns (Namespace::Values));
+ ctx.types.resolve_path (segments).map (pair_with_ns (Namespace::Types));
+ ctx.macros.resolve_path (segments).map (pair_with_ns (Namespace::Macros));
+
+ return resolved;
+ }
+
+ // Handle an import, resolving it to its definition and adding it to the list
+ // of import mappings
+ void build_import_mapping (
+ std::pair<NodeId, std::vector<TopLevel::ImportKind>> &&use_import);
+
TextualScope textual_scope;
std::vector<Error> macro_resolve_errors;
diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.cc b/gcc/rust/resolve/rust-finalize-imports-2.0.cc
new file mode 100644
index 0000000..71916ae
--- /dev/null
+++ b/gcc/rust/resolve/rust-finalize-imports-2.0.cc
@@ -0,0 +1,224 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-finalize-imports-2.0.h"
+#include "rust-default-resolver.h"
+#include "rust-hir-map.h"
+#include "rust-name-resolution-context.h"
+#include "rust-rib.h"
+#include "rust-toplevel-name-resolver-2.0.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+void
+GlobbingVisitor::go (AST::Module *module)
+{
+ for (auto &i : module->get_items ())
+ visit (i);
+}
+
+void
+GlobbingVisitor::visit (AST::Module &module)
+{
+ if (module.get_visibility ().is_public ())
+ ctx.insert_globbed (module.get_name (), module.get_node_id (),
+ Namespace::Types);
+}
+
+void
+GlobbingVisitor::visit (AST::MacroRulesDefinition &macro)
+{
+ if (macro.get_visibility ().is_public ())
+ ctx.insert_globbed (macro.get_rule_name (), macro.get_node_id (),
+ Namespace::Macros);
+}
+
+void
+GlobbingVisitor::visit (AST::Function &function)
+{
+ if (function.get_visibility ().is_public ())
+ ctx.insert_globbed (function.get_function_name (), function.get_node_id (),
+ Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::StaticItem &static_item)
+{
+ if (static_item.get_visibility ().is_public ())
+ ctx.insert_globbed (static_item.get_identifier (),
+ static_item.get_node_id (), Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::StructStruct &struct_item)
+{
+ if (struct_item.get_visibility ().is_public ())
+ {
+ ctx.insert_globbed (struct_item.get_identifier (),
+ struct_item.get_node_id (), Namespace::Types);
+ if (struct_item.is_unit_struct ())
+ ctx.insert_globbed (struct_item.get_identifier (),
+ struct_item.get_node_id (), Namespace::Values);
+ }
+}
+
+void
+GlobbingVisitor::visit (AST::TupleStruct &tuple_struct)
+{
+ if (tuple_struct.get_visibility ().is_public ())
+ {
+ ctx.insert_globbed (tuple_struct.get_identifier (),
+ tuple_struct.get_node_id (), Namespace::Types);
+
+ ctx.insert_globbed (tuple_struct.get_identifier (),
+ tuple_struct.get_node_id (), Namespace::Values);
+ }
+}
+
+void
+GlobbingVisitor::visit (AST::Enum &enum_item)
+{
+ if (enum_item.get_visibility ().is_public ())
+ ctx.insert_globbed (enum_item.get_identifier (), enum_item.get_node_id (),
+ Namespace::Types);
+}
+
+void
+GlobbingVisitor::visit (AST::Union &union_item)
+{
+ if (union_item.get_visibility ().is_public ())
+ ctx.insert_globbed (union_item.get_identifier (), union_item.get_node_id (),
+ Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::ConstantItem &const_item)
+{
+ if (const_item.get_visibility ().is_public ())
+ ctx.insert_globbed (const_item.get_identifier (), const_item.get_node_id (),
+ Namespace::Values);
+}
+
+void
+GlobbingVisitor::visit (AST::ExternCrate &crate)
+{}
+
+void
+GlobbingVisitor::visit (AST::UseDeclaration &use)
+{
+ // Handle cycles ?
+}
+
+void
+finalize_simple_import (TopLevel &toplevel, const Early::ImportPair &mapping)
+{
+ // FIXME: We probably need to store namespace information
+
+ auto locus = mapping.import_kind.to_resolve.get_locus ();
+ auto data = mapping.data;
+ auto identifier
+ = mapping.import_kind.to_resolve.get_final_segment ().get_segment_name ();
+
+ for (auto &&definition : data.definitions ())
+ toplevel
+ .insert_or_error_out (
+ identifier, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
+}
+
+void
+finalize_glob_import (NameResolutionContext &ctx,
+ const Early::ImportPair &mapping)
+{
+ auto module = Analysis::Mappings::get ().lookup_ast_module (
+ mapping.data.module ().get_node_id ());
+ rust_assert (module);
+
+ GlobbingVisitor glob_visitor (ctx);
+ glob_visitor.go (module.value ());
+}
+
+void
+finalize_rebind_import (TopLevel &toplevel, const Early::ImportPair &mapping)
+{
+ // We can fetch the value here as `resolve_rebind` will only be called on
+ // imports of the right kind
+ auto &path = mapping.import_kind.to_resolve;
+ auto &rebind = mapping.import_kind.rebind.value ();
+ auto data = mapping.data;
+
+ location_t locus = UNKNOWN_LOCATION;
+ std::string declared_name;
+
+ // FIXME: This needs to be done in `FinalizeImports`
+ switch (rebind.get_new_bind_type ())
+ {
+ case AST::UseTreeRebind::NewBindType::IDENTIFIER:
+ declared_name = rebind.get_identifier ().as_string ();
+ locus = rebind.get_identifier ().get_locus ();
+ break;
+ case AST::UseTreeRebind::NewBindType::NONE:
+ declared_name = path.get_final_segment ().as_string ();
+ locus = path.get_final_segment ().get_locus ();
+ break;
+ case AST::UseTreeRebind::NewBindType::WILDCARD:
+ rust_unreachable ();
+ break;
+ }
+
+ for (auto &&definition : data.definitions ())
+ toplevel.insert_or_error_out (
+ declared_name, locus, definition.first.get_node_id (), definition.second /* TODO: This isn't clear - it would be better if it was called .ns or something */);
+}
+
+FinalizeImports::FinalizeImports (Early::ImportMappings &&data,
+ TopLevel &toplevel,
+ NameResolutionContext &ctx)
+ : DefaultResolver (ctx), data (std::move (data)), toplevel (toplevel),
+ ctx (ctx)
+{}
+
+void
+FinalizeImports::go (AST::Crate &crate)
+{
+ for (auto &item : crate.items)
+ item->accept_vis (*this);
+}
+
+void
+FinalizeImports::visit (AST::UseDeclaration &use)
+{
+ auto import_mappings = data.get (use.get_node_id ());
+
+ for (const auto &mapping : import_mappings)
+ switch (mapping.import_kind.kind)
+ {
+ case TopLevel::ImportKind::Kind::Glob:
+ finalize_glob_import (ctx, mapping);
+ break;
+ case TopLevel::ImportKind::Kind::Simple:
+ finalize_simple_import (toplevel, mapping);
+ break;
+ case TopLevel::ImportKind::Kind::Rebind:
+ finalize_rebind_import (toplevel, mapping);
+ break;
+ }
+}
+
+} // namespace Resolver2_0
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-finalize-imports-2.0.h b/gcc/rust/resolve/rust-finalize-imports-2.0.h
new file mode 100644
index 0000000..0fba5a5
--- /dev/null
+++ b/gcc/rust/resolve/rust-finalize-imports-2.0.h
@@ -0,0 +1,110 @@
+// Copyright (C) 2020-2024 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast.h"
+#include "rust-expr.h"
+#include "rust-name-resolution-context.h"
+#include "rust-toplevel-name-resolver-2.0.h"
+#include "rust-early-name-resolver-2.0.h"
+
+namespace Rust {
+namespace Resolver2_0 {
+
+class GlobbingVisitor : public AST::DefaultASTVisitor
+{
+ using AST::DefaultASTVisitor::visit;
+
+public:
+ GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {}
+
+ void go (AST::Module *module);
+ void visit (AST::Module &module) override;
+ void visit (AST::MacroRulesDefinition &macro) override;
+ void visit (AST::Function &function) override;
+ void visit (AST::StaticItem &static_item) override;
+ void visit (AST::StructStruct &struct_item) override;
+ void visit (AST::TupleStruct &tuple_struct) override;
+ void visit (AST::Enum &enum_item) override;
+ void visit (AST::Union &union_item) override;
+ void visit (AST::ConstantItem &const_item) override;
+ void visit (AST::ExternCrate &crate) override;
+ void visit (AST::UseDeclaration &use) override;
+
+private:
+ NameResolutionContext &ctx;
+};
+
+// TODO: Fix documentation
+// How do we do that?
+//
+// We want to resolve in the EarlyNameResolver, but we want to declare in the
+// TopLevel Should the TopLevel declare stubs? How does rustc do it? How to do
+// that for globbing? Should we do globbing afterwards once we've declared all
+// the Uses*?
+//
+// Basically, for each use declare it in a separate map - in the
+// EarlyNameResolver resolve and fix the ForeverStack? Emptying the maps each
+// time?
+//
+// e.g. TopLevel builds a std::vector<NodeId, SimplePath> use_trees_to_resolve;
+// Early goes through and resolves the SimplePath, then replaces the NodeId with
+// the resolved one? Do we even need to do that?
+//
+// rustc just creates an empty definition for the use tree.
+//
+// What about globbing? std::vector<GlobbulesPath> globules;
+// Early goes through and visits the module's path and calls the
+// GlobbingVisitor?
+//
+// the file `imports.rs` goes through and *finalizes* imports. So we can
+// probably add a FinalizeImport pass after the TopLevel and the Early.
+// - TopLevel takes care of declaring these use trees
+// - Early takes care of resolving them to definition points
+// - Finalize takes care of mapping the use's definition point to the actual
+// definition point
+// - We need to work more on that last bit to know exactly what is being
+// inserted, but probably it's going to mutate the ForeverStack - is that okay?
+// - Oh actually maybe no!
+// - TopLevel creates a map of UseTrees with paths to resolve. This should
+// probably be an ImportKind enum or whatever
+// - Early resolves them, creates a map of SimplePath with the associated
+// definition: Map<ImportKind, ImportData>
+// - Finalizes visits all UseTrees and inserts the Definitions found for
+// each ImportKind - easy!
+// - yay!
+
+class FinalizeImports : DefaultResolver
+{
+public:
+ FinalizeImports (Early::ImportMappings &&data, TopLevel &toplevel,
+ NameResolutionContext &ctx);
+
+ void go (AST::Crate &crate);
+
+private:
+ using AST::DefaultASTVisitor::visit;
+
+ void visit (AST::UseDeclaration &) override;
+
+ Early::ImportMappings data;
+ TopLevel &toplevel;
+ NameResolutionContext &ctx;
+};
+
+} // namespace Resolver2_0
+} // namespace Rust
diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h
index a9aca0f..8c5e207 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -453,6 +453,22 @@ public:
NodeId id);
/**
+ * Insert a new glob-originated definition in the innermost `Rib` in this
+ * stack
+ *
+ * @param name The name of the definition
+ * @param id Its NodeId
+ *
+ * @return `DuplicateNameError` if that node was already present in the Rib,
+ * the node's `NodeId` otherwise.
+ *
+ * @aborts if there are no `Rib`s inserted in the current map, this function
+ * aborts the program.
+ */
+ tl::expected<NodeId, DuplicateNameError> insert_globbed (Identifier name,
+ NodeId id);
+
+ /**
* Insert a new definition at the root of this stack
*
* @param name The name of the definition
@@ -497,10 +513,11 @@ public:
tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments);
// FIXME: Documentation
- tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id);
+ tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const;
// FIXME: Documentation
tl::optional<Rib &> to_rib (NodeId rib_id);
+ tl::optional<const Rib &> to_rib (NodeId rib_id) const;
std::string as_debug_string ();
@@ -563,9 +580,12 @@ private:
/* Reverse iterate on `Node`s from the cursor, in an outwards fashion */
void reverse_iter (std::function<KeepGoing (Node &)> lambda);
+ void reverse_iter (std::function<KeepGoing (const Node &)> lambda) const;
/* Reverse iterate on `Node`s from a specified one, in an outwards fashion */
void reverse_iter (Node &start, std::function<KeepGoing (Node &)> lambda);
+ void reverse_iter (const Node &start,
+ std::function<KeepGoing (const Node &)> lambda) const;
Node &cursor ();
const Node &cursor () const;
@@ -601,11 +621,20 @@ private:
Node &first;
std::string second;
};
+ struct ConstDfsResult
+ {
+ const Node &first;
+ std::string second;
+ };
// FIXME: Documentation
tl::optional<DfsResult> dfs (Node &starting_point, NodeId to_find);
+ tl::optional<ConstDfsResult> dfs (const Node &starting_point,
+ NodeId to_find) const;
// FIXME: Documentation
tl::optional<Rib &> dfs_rib (Node &starting_point, NodeId to_find);
+ tl::optional<const Rib &> dfs_rib (const Node &starting_point,
+ NodeId to_find) const;
};
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx
index a7d46ce..5a5a7c7 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -133,6 +133,16 @@ ForeverStack<N>::insert_shadowable (Identifier name, NodeId node)
template <Namespace N>
tl::expected<NodeId, DuplicateNameError>
+ForeverStack<N>::insert_globbed (Identifier name, NodeId node)
+{
+ auto &innermost_rib = peek ();
+
+ return insert_inner (innermost_rib, name.as_string (),
+ Rib::Definition::Globbed (node));
+}
+
+template <Namespace N>
+tl::expected<NodeId, DuplicateNameError>
ForeverStack<N>::insert_at_root (Identifier name, NodeId node)
{
auto &root_rib = root.rib;
@@ -184,6 +194,14 @@ ForeverStack<N>::reverse_iter (std::function<KeepGoing (Node &)> lambda)
template <Namespace N>
void
+ForeverStack<N>::reverse_iter (
+ std::function<KeepGoing (const Node &)> lambda) const
+{
+ return reverse_iter (cursor (), lambda);
+}
+
+template <Namespace N>
+void
ForeverStack<N>::reverse_iter (Node &start,
std::function<KeepGoing (Node &)> lambda)
{
@@ -203,6 +221,26 @@ ForeverStack<N>::reverse_iter (Node &start,
}
template <Namespace N>
+void
+ForeverStack<N>::reverse_iter (
+ const Node &start, std::function<KeepGoing (const Node &)> lambda) const
+{
+ auto *tmp = &start;
+
+ while (true)
+ {
+ auto keep_going = lambda (*tmp);
+ if (keep_going == KeepGoing::No)
+ return;
+
+ if (tmp->is_root ())
+ return;
+
+ tmp = &tmp->parent.value ();
+ }
+}
+
+template <Namespace N>
typename ForeverStack<N>::Node &
ForeverStack<N>::cursor ()
{
@@ -474,9 +512,48 @@ ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
auto values = starting_point.rib.get_values ();
for (auto &kv : values)
- for (auto id : kv.second.ids)
- if (id == to_find)
- return {{starting_point, kv.first}};
+ {
+ for (auto id : kv.second.ids_shadowable)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ for (auto id : kv.second.ids_non_shadowable)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ for (auto id : kv.second.ids_globbed)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ }
+
+ for (auto &child : starting_point.children)
+ {
+ auto candidate = dfs (child.second, to_find);
+
+ if (candidate.has_value ())
+ return candidate;
+ }
+
+ return tl::nullopt;
+}
+
+template <Namespace N>
+tl::optional<typename ForeverStack<N>::ConstDfsResult>
+ForeverStack<N>::dfs (const ForeverStack<N>::Node &starting_point,
+ NodeId to_find) const
+{
+ auto values = starting_point.rib.get_values ();
+
+ for (auto &kv : values)
+ {
+ for (auto id : kv.second.ids_shadowable)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ for (auto id : kv.second.ids_non_shadowable)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ for (auto id : kv.second.ids_globbed)
+ if (id == to_find)
+ return {{starting_point, kv.first}};
+ }
for (auto &child : starting_point.children)
{
@@ -491,20 +568,20 @@ ForeverStack<N>::dfs (ForeverStack<N>::Node &starting_point, NodeId to_find)
template <Namespace N>
tl::optional<Resolver::CanonicalPath>
-ForeverStack<N>::to_canonical_path (NodeId id)
+ForeverStack<N>::to_canonical_path (NodeId id) const
{
// find the id in the current forever stack, starting from the root,
// performing either a BFS or DFS once the Node containing the ID is found, go
// back up to the root (parent().parent().parent()...) accumulate link
// segments reverse them that's your canonical path
- return dfs (root, id).map ([this, id] (DfsResult tuple) {
+ return dfs (root, id).map ([this, id] (ConstDfsResult tuple) {
auto containing_node = tuple.first;
auto name = tuple.second;
auto segments = std::vector<Resolver::CanonicalPath> ();
- reverse_iter (containing_node, [&segments] (Node &current) {
+ reverse_iter (containing_node, [&segments] (const Node &current) {
if (current.is_root ())
return KeepGoing::No;
@@ -564,6 +641,25 @@ ForeverStack<N>::dfs_rib (ForeverStack<N>::Node &starting_point, NodeId to_find)
}
template <Namespace N>
+tl::optional<const Rib &>
+ForeverStack<N>::dfs_rib (const ForeverStack<N>::Node &starting_point,
+ NodeId to_find) const
+{
+ if (starting_point.id == to_find)
+ return starting_point.rib;
+
+ for (auto &child : starting_point.children)
+ {
+ auto candidate = dfs_rib (child.second, to_find);
+
+ if (candidate.has_value ())
+ return candidate;
+ }
+
+ return tl::nullopt;
+}
+
+template <Namespace N>
tl::optional<Rib &>
ForeverStack<N>::to_rib (NodeId rib_id)
{
@@ -571,6 +667,13 @@ ForeverStack<N>::to_rib (NodeId rib_id)
}
template <Namespace N>
+tl::optional<const Rib &>
+ForeverStack<N>::to_rib (NodeId rib_id) const
+{
+ return dfs_rib (root, rib_id);
+}
+
+template <Namespace N>
void
ForeverStack<N>::stream_rib (std::stringstream &stream, const Rib &rib,
const std::string &next,
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
index 9ac0945..43f33df 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -23,6 +23,7 @@
#include "rust-default-resolver.h"
#include "rust-name-resolution-context.h"
#include "rust-path.h"
+#include "rust-system.h"
#include "rust-tyty.h"
#include "rust-hir-type-check.h"
@@ -151,10 +152,10 @@ Late::visit (AST::IdentifierPattern &identifier)
// do we insert in labels or in values
// but values does not allow shadowing... since functions cannot shadow
// do we insert functions in labels as well?
- auto ok
- = ctx.values.insert (identifier.get_ident (), identifier.get_node_id ());
- rust_assert (ok);
+ // We do want to ignore duplicated data because some situations rely on it.
+ std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
+ identifier.get_node_id ());
}
void
@@ -163,16 +164,14 @@ Late::visit (AST::IdentifierExpr &expr)
// TODO: same thing as visit(PathInExpression) here?
tl::optional<Rib::Definition> resolved = tl::nullopt;
- auto label = ctx.labels.get (expr.get_ident ());
- auto value = ctx.values.get (expr.get_ident ());
- if (label)
+ if (auto value = ctx.values.get (expr.get_ident ()))
{
- resolved = label;
+ resolved = value;
}
- else if (value)
+ else if (auto type = ctx.types.get (expr.get_ident ()))
{
- resolved = value;
+ resolved = type;
}
else
{
@@ -200,18 +199,34 @@ Late::visit (AST::PathInExpression &expr)
// in a function item` error here?
// do we emit it in `get<Namespace::Labels>`?
- auto value = ctx.values.resolve_path (expr.get_segments ());
- if (!value.has_value ())
- rust_unreachable (); // Should have been resolved earlier
+ rust_debug ("[ARTHUR]: %s", expr.as_simple_path ().as_string ().c_str ());
+
+ tl::optional<Rib::Definition> resolved = tl::nullopt;
+
+ if (auto value = ctx.values.resolve_path (expr.get_segments ()))
+ {
+ resolved = value;
+ }
+ else if (auto type = ctx.types.resolve_path (expr.get_segments ()))
+ {
+ resolved = type;
+ }
+ else
+ {
+ rust_error_at (expr.get_locus (),
+ "could not resolve path expression: %qs",
+ expr.as_simple_path ().as_string ().c_str ());
+ return;
+ }
- if (value->is_ambiguous ())
+ if (resolved->is_ambiguous ())
{
rust_error_at (expr.get_locus (), ErrorCode::E0659, "%qs is ambiguous",
expr.as_string ().c_str ());
return;
}
ctx.map_usage (Usage (expr.get_node_id ()),
- Definition (value->get_node_id ()));
+ Definition (resolved->get_node_id ()));
}
void
@@ -222,10 +237,21 @@ Late::visit (AST::TypePath &type)
// maybe we can overload `resolve_path<Namespace::Types>` to only do
// typepath-like path resolution? that sounds good
- auto resolved = ctx.types.get (type.get_segments ().back ()->as_string ());
+ auto str = type.get_segments ().back ()->get_ident_segment ().as_string ();
+ auto values = ctx.types.peek ().get_values ();
- ctx.map_usage (Usage (type.get_node_id ()),
- Definition (resolved->get_node_id ()));
+ if (auto resolved = ctx.types.get (str))
+ ctx.map_usage (Usage (type.get_node_id ()),
+ Definition (resolved->get_node_id ()));
+ else
+ rust_unreachable ();
+}
+
+void
+Late::visit (AST::StructStruct &s)
+{
+ auto s_vis = [this, &s] () { AST::DefaultASTVisitor::visit (s); };
+ ctx.scoped (Rib::Kind::Item, s.get_node_id (), s_vis);
}
void
@@ -249,5 +275,37 @@ Late::visit (AST::StructExprStructFields &s)
DefaultResolver::visit (s);
}
+// needed because Late::visit (AST::GenericArg &) is non-virtual
+void
+Late::visit (AST::GenericArgs &args)
+{
+ for (auto &lifetime : args.get_lifetime_args ())
+ visit (lifetime);
+
+ for (auto &generic : args.get_generic_args ())
+ visit (generic);
+
+ for (auto &binding : args.get_binding_args ())
+ visit (binding);
+}
+
+void
+Late::visit (AST::GenericArg &arg)
+{
+ if (arg.get_kind () == AST::GenericArg::Kind::Either)
+ {
+ // prefer type parameter to const parameter on ambiguity
+ auto type = ctx.types.get (arg.get_path ());
+ auto value = ctx.values.get (arg.get_path ());
+
+ if (!type.has_value () && value.has_value ())
+ arg = arg.disambiguate_to_const ();
+ else
+ arg = arg.disambiguate_to_type ();
+ }
+
+ DefaultResolver::visit (arg);
+}
+
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
index b44b2d9..7e33c96 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
@@ -48,6 +48,9 @@ public:
void visit (AST::TypePath &) override;
void visit (AST::StructExprStructBase &) override;
void visit (AST::StructExprStructFields &) override;
+ void visit (AST::StructStruct &) override;
+ void visit (AST::GenericArgs &) override;
+ void visit (AST::GenericArg &);
private:
/* Setup Rust's builtin types (u8, i32, !...) in the resolver */
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc
index d964684..9bfaa09 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -64,6 +64,24 @@ NameResolutionContext::insert_shadowable (Identifier name, NodeId id,
}
}
+tl::expected<NodeId, DuplicateNameError>
+NameResolutionContext::insert_globbed (Identifier name, NodeId id, Namespace ns)
+{
+ switch (ns)
+ {
+ case Namespace::Values:
+ return values.insert_globbed (name, id);
+ case Namespace::Types:
+ return types.insert_globbed (name, id);
+ case Namespace::Macros:
+ return macros.insert_globbed (name, id);
+ case Namespace::Labels:
+ default:
+ // return labels.insert (name, id);
+ rust_unreachable ();
+ }
+}
+
void
NameResolutionContext::map_usage (Usage usage, Definition definition)
{
@@ -74,7 +92,7 @@ NameResolutionContext::map_usage (Usage usage, Definition definition)
}
tl::optional<NodeId>
-NameResolutionContext::lookup (NodeId usage)
+NameResolutionContext::lookup (NodeId usage) const
{
auto it = resolved_nodes.find (Usage (usage));
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h
index 3605392..cd6fa93 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -22,6 +22,7 @@
#include "optional.h"
#include "rust-forever-stack.h"
#include "rust-hir-map.h"
+#include "rust-rib.h"
namespace Rust {
namespace Resolver2_0 {
@@ -174,6 +175,9 @@ public:
tl::expected<NodeId, DuplicateNameError>
insert_shadowable (Identifier name, NodeId id, Namespace ns);
+ tl::expected<NodeId, DuplicateNameError>
+ insert_globbed (Identifier name, NodeId id, Namespace ns);
+
/**
* Run a lambda in a "scoped" context, meaning that a new `Rib` will be pushed
* before executing the lambda and then popped. This is useful for all kinds
@@ -209,7 +213,7 @@ public:
// TODO: Use newtype pattern for Usage and Definition
void map_usage (Usage usage, Definition definition);
- tl::optional<NodeId> lookup (NodeId usage);
+ tl::optional<NodeId> lookup (NodeId usage) const;
private:
/* Map of "usage" nodes which have been resolved to a "definition" node */
diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc
index ee52e5c..21147bd8 100644
--- a/gcc/rust/resolve/rust-name-resolver.cc
+++ b/gcc/rust/resolve/rust-name-resolver.cc
@@ -429,7 +429,10 @@ Resolver::generate_builtins ()
setup_builtin ("isize", isize);
setup_builtin ("char", char_tyty);
setup_builtin ("str", str);
- setup_builtin ("!", never);
+
+ // never type
+ NodeId never_node_id = setup_builtin ("!", never);
+ set_never_type_node_id (never_node_id);
// unit type ()
TyTy::TupleType *unit_tyty
@@ -443,7 +446,7 @@ Resolver::generate_builtins ()
set_unit_type_node_id (unit_type->get_node_id ());
}
-void
+NodeId
Resolver::setup_builtin (const std::string &name, TyTy::BaseType *tyty)
{
AST::PathIdentSegment seg (name, BUILTINS_LOCATION);
@@ -459,6 +462,8 @@ Resolver::setup_builtin (const std::string &name, TyTy::BaseType *tyty)
mappings.insert_canonical_path (
builtin_type->get_node_id (),
CanonicalPath::new_seg (builtin_type->get_node_id (), name));
+
+ return builtin_type->get_node_id ();
}
void
diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h
index c34002e..43b79e5 100644
--- a/gcc/rust/resolve/rust-name-resolver.h
+++ b/gcc/rust/resolve/rust-name-resolver.h
@@ -163,9 +163,13 @@ public:
Scope &get_macro_scope () { return macro_scope; }
NodeId get_global_type_node_id () { return global_type_node_id; }
+
void set_unit_type_node_id (NodeId id) { unit_ty_node_id = id; }
NodeId get_unit_type_node_id () { return unit_ty_node_id; }
+ void set_never_type_node_id (NodeId id) { never_ty_node_id = id; }
+ NodeId get_never_type_node_id () { return never_ty_node_id; }
+
void push_new_module_scope (NodeId module_id)
{
current_module_stack.push_back (module_id);
@@ -208,7 +212,7 @@ private:
Resolver ();
void generate_builtins ();
- void setup_builtin (const std::string &name, TyTy::BaseType *tyty);
+ NodeId setup_builtin (const std::string &name, TyTy::BaseType *tyty);
Analysis::Mappings &mappings;
TypeCheckContext *tyctx;
@@ -222,6 +226,7 @@ private:
NodeId global_type_node_id;
NodeId unit_ty_node_id;
+ NodeId never_ty_node_id;
// map a AST Node to a Rib
std::map<NodeId, Rib *> name_ribs;
diff --git a/gcc/rust/resolve/rust-rib.cc b/gcc/rust/resolve/rust-rib.cc
index 0a8fce3..b0380bb 100644
--- a/gcc/rust/resolve/rust-rib.cc
+++ b/gcc/rust/resolve/rust-rib.cc
@@ -22,26 +22,51 @@
namespace Rust {
namespace Resolver2_0 {
-Rib::Definition::Definition (NodeId id, bool shadowable)
- : ids ({id}), shadowable (shadowable)
-{}
+Rib::Definition::Definition (NodeId id, Mode mode)
+{
+ switch (mode)
+ {
+ case Mode::SHADOWABLE:
+ ids_shadowable.push_back (id);
+ return;
+ case Mode::NON_SHADOWABLE:
+ ids_non_shadowable.push_back (id);
+ return;
+ case Mode::GLOBBED:
+ ids_globbed.push_back (id);
+ return;
+ default:
+ gcc_unreachable ();
+ }
+}
bool
Rib::Definition::is_ambiguous () const
{
- return shadowable && ids.size () > 1;
+ if (!ids_shadowable.empty ())
+ return false;
+ else if (!ids_non_shadowable.empty ())
+ return ids_non_shadowable.size () > 1;
+ else
+ return ids_globbed.size () > 1;
}
std::string
Rib::Definition::to_string () const
{
std::stringstream out;
- out << (shadowable ? "(S)" : "(NS)") << "[";
- std::string sep;
- for (auto id : ids)
+ const char *headers[3] = {"(S)[", "] (NS)[", "] (G)["};
+ const std::vector<NodeId> *id_lists[3]
+ = {&ids_shadowable, &ids_non_shadowable, &ids_globbed};
+ for (int i = 0; i < 3; i++)
{
- out << sep << id;
- sep = ",";
+ out << headers[i];
+ std::string sep;
+ for (auto id : *id_lists[i])
+ {
+ out << sep << id;
+ sep = ",";
+ }
}
out << "]";
return out.str ();
@@ -50,13 +75,19 @@ Rib::Definition::to_string () const
Rib::Definition
Rib::Definition::Shadowable (NodeId id)
{
- return Definition (id, true);
+ return Definition (id, Mode::SHADOWABLE);
}
Rib::Definition
Rib::Definition::NonShadowable (NodeId id)
{
- return Definition (id, false);
+ return Definition (id, Mode::NON_SHADOWABLE);
+}
+
+Rib::Definition
+Rib::Definition::Globbed (NodeId id)
+{
+ return Definition (id, Mode::GLOBBED);
}
DuplicateNameError::DuplicateNameError (std::string name, NodeId existing)
@@ -85,29 +116,53 @@ Rib::insert (std::string name, Definition def)
/* No old value */
values[name] = def;
}
- else if (it->second.shadowable && def.shadowable)
- { /* Both shadowable */
+ else if (it->second.ids_non_shadowable.empty ()
+ || def.ids_non_shadowable.empty ())
+ { /* No non-shadowable conflict */
auto &current = values[name];
- for (auto id : def.ids)
+ for (auto id : def.ids_non_shadowable)
{
- if (std::find (current.ids.cbegin (), current.ids.cend (), id)
- == current.ids.cend ())
- {
- current.ids.push_back (id);
- }
+ if (std::find (current.ids_non_shadowable.cbegin (),
+ current.ids_non_shadowable.cend (), id)
+ == current.ids_non_shadowable.cend ())
+ current.ids_non_shadowable.push_back (id);
+ else
+ // TODO: should this produce an error?
+ return tl::make_unexpected (DuplicateNameError (name, id));
+ }
+ for (auto id : def.ids_shadowable)
+ {
+ if (std::find (current.ids_shadowable.cbegin (),
+ current.ids_shadowable.cend (), id)
+ == current.ids_shadowable.cend ())
+ current.ids_shadowable.push_back (id);
+ else
+ // TODO: should this produce an error?
+ return tl::make_unexpected (DuplicateNameError (name, id));
+ }
+ for (auto id : def.ids_globbed)
+ {
+ if (std::find (current.ids_globbed.cbegin (),
+ current.ids_globbed.cend (), id)
+ == current.ids_globbed.cend ())
+ current.ids_globbed.push_back (id);
+ else
+ // TODO: should this produce an error?
+ return tl::make_unexpected (DuplicateNameError (name, id));
}
}
- else if (it->second.shadowable)
- { /* Only old shadowable : replace value */
- values[name] = def;
- }
- else /* Neither are shadowable */
+ else /* Multiple non-shadowable */
{
return tl::make_unexpected (
- DuplicateNameError (name, it->second.ids.back ()));
+ DuplicateNameError (name, it->second.ids_non_shadowable.back ()));
}
- return def.ids.back ();
+ if (!def.ids_shadowable.empty ())
+ return def.ids_shadowable.back ();
+ else if (!def.ids_non_shadowable.empty ())
+ return def.ids_non_shadowable.back ();
+ rust_assert (!def.ids_globbed.empty ());
+ return def.ids_globbed.back ();
}
tl::optional<Rib::Definition>
diff --git a/gcc/rust/resolve/rust-rib.h b/gcc/rust/resolve/rust-rib.h
index 3228a3c..2eb8de8 100644
--- a/gcc/rust/resolve/rust-rib.h
+++ b/gcc/rust/resolve/rust-rib.h
@@ -113,9 +113,16 @@ public:
public:
static Definition NonShadowable (NodeId id);
static Definition Shadowable (NodeId id);
+ static Definition Globbed (NodeId id);
- std::vector<NodeId> ids;
- bool shadowable;
+ // checked shadowable -> non_shadowable -> globbed
+ // we have shadowable *and* globbed in order to control
+ // resolution priority
+ // we *could* use a single vector with 2 indices here
+ // but it's probably not worth it for now
+ std::vector<NodeId> ids_shadowable;
+ std::vector<NodeId> ids_non_shadowable;
+ std::vector<NodeId> ids_globbed;
Definition () = default;
@@ -124,16 +131,31 @@ public:
bool is_ambiguous () const;
- NodeId get_node_id ()
+ NodeId get_node_id () const
{
+ if (!ids_shadowable.empty ())
+ return ids_shadowable.back ();
+
rust_assert (!is_ambiguous ());
- return ids[0];
+
+ if (!ids_non_shadowable.empty ())
+ return ids_non_shadowable.back ();
+
+ rust_assert (!ids_globbed.empty ());
+ return ids_globbed.back ();
}
std::string to_string () const;
private:
- Definition (NodeId id, bool shadowable);
+ enum class Mode
+ {
+ SHADOWABLE,
+ NON_SHADOWABLE,
+ GLOBBED
+ };
+
+ Definition (NodeId id, Mode mode);
};
enum class Kind
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
index 746b224..a0d8492 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -26,107 +26,8 @@
namespace Rust {
namespace Resolver2_0 {
-void
-GlobbingVisitor::go (AST::Module *module)
-{
- for (auto &i : module->get_items ())
- visit (i);
-}
-
-void
-GlobbingVisitor::visit (AST::Module &module)
-{
- if (module.get_visibility ().is_public ())
- ctx.insert_shadowable (module.get_name (), module.get_node_id (),
- Namespace::Types);
-}
-
-void
-GlobbingVisitor::visit (AST::MacroRulesDefinition &macro)
-{
- if (macro.get_visibility ().is_public ())
- ctx.insert_shadowable (macro.get_rule_name (), macro.get_node_id (),
- Namespace::Macros);
-}
-
-void
-GlobbingVisitor::visit (AST::Function &function)
-{
- if (function.get_visibility ().is_public ())
- ctx.insert_shadowable (function.get_function_name (),
- function.get_node_id (), Namespace::Values);
-}
-
-void
-GlobbingVisitor::visit (AST::StaticItem &static_item)
-{
- if (static_item.get_visibility ().is_public ())
- ctx.insert_shadowable (static_item.get_identifier (),
- static_item.get_node_id (), Namespace::Values);
-}
-
-void
-GlobbingVisitor::visit (AST::StructStruct &struct_item)
-{
- if (struct_item.get_visibility ().is_public ())
- {
- ctx.insert_shadowable (struct_item.get_identifier (),
- struct_item.get_node_id (), Namespace::Types);
- if (struct_item.is_unit_struct ())
- ctx.insert_shadowable (struct_item.get_identifier (),
- struct_item.get_node_id (), Namespace::Values);
- }
-}
-
-void
-GlobbingVisitor::visit (AST::TupleStruct &tuple_struct)
-{
- if (tuple_struct.get_visibility ().is_public ())
- {
- ctx.insert_shadowable (tuple_struct.get_identifier (),
- tuple_struct.get_node_id (), Namespace::Types);
-
- ctx.insert_shadowable (tuple_struct.get_identifier (),
- tuple_struct.get_node_id (), Namespace::Values);
- }
-}
-
-void
-GlobbingVisitor::visit (AST::Enum &enum_item)
-{
- if (enum_item.get_visibility ().is_public ())
- ctx.insert_shadowable (enum_item.get_identifier (),
- enum_item.get_node_id (), Namespace::Types);
-}
-
-void
-GlobbingVisitor::visit (AST::Union &union_item)
-{
- if (union_item.get_visibility ().is_public ())
- ctx.insert_shadowable (union_item.get_identifier (),
- union_item.get_node_id (), Namespace::Values);
-}
-
-void
-GlobbingVisitor::visit (AST::ConstantItem &const_item)
-{
- if (const_item.get_visibility ().is_public ())
- ctx.insert_shadowable (const_item.get_identifier (),
- const_item.get_node_id (), Namespace::Values);
-}
-
-void
-GlobbingVisitor::visit (AST::ExternCrate &crate)
-{}
-
-void
-GlobbingVisitor::visit (AST::UseDeclaration &use)
-{
- // Handle cycles ?
-}
-
TopLevel::TopLevel (NameResolutionContext &resolver)
- : DefaultResolver (resolver)
+ : DefaultResolver (resolver), dirty (false)
{}
template <typename T>
@@ -146,8 +47,9 @@ TopLevel::insert_or_error_out (const Identifier &identifier,
node_locations.emplace (node_id, locus);
auto result = ctx.insert (identifier, node_id, ns);
-
- if (!result && result.error ().existing != node_id)
+ if (result)
+ dirty = true;
+ else if (result.error ().existing != node_id)
{
rich_location rich_loc (line_table, locus);
rich_loc.add_range (node_locations[result.error ().existing]);
@@ -174,6 +76,17 @@ TopLevel::visit (AST::Module &module)
{
insert_or_error_out (module.get_name (), module, Namespace::Types);
+ // Parse the module's items if they haven't been expanded and the file
+ // should be parsed (i.e isn't hidden behind an untrue or impossible cfg
+ // directive
+ // TODO: make sure this is right
+ // TODO: avoid loading items if cfg attributes are present?
+ // might not be needed if this runs after early resolution?
+ // This was copied from the old early resolver method
+ // 'accumulate_escaped_macros'
+ if (module.get_kind () == AST::Module::UNLOADED)
+ module.load_items ();
+
auto sub_visitor = [this, &module] () {
for (auto &item : module.get_items ())
item->accept_vis (*this);
@@ -346,11 +259,30 @@ TopLevel::visit (AST::StaticItem &static_item)
= [this, &static_item] () { static_item.get_expr ().accept_vis (*this); };
ctx.scoped (Rib::Kind::Item, static_item.get_node_id (), sub_vis);
+
+ insert_or_error_out (static_item.get_identifier ().as_string (), static_item,
+ Namespace::Values);
+}
+
+void
+TopLevel::visit (AST::ExternalStaticItem &static_item)
+{
+ insert_or_error_out (static_item.get_identifier ().as_string (), static_item,
+ Namespace::Values);
}
void
TopLevel::visit (AST::StructStruct &struct_item)
{
+ auto generic_vis = [this, &struct_item] () {
+ for (auto &g : struct_item.get_generic_params ())
+ {
+ g->accept_vis (*this);
+ }
+ };
+
+ ctx.scoped (Rib::Kind::Item, struct_item.get_node_id (), generic_vis);
+
insert_or_error_out (struct_item.get_struct_name (), struct_item,
Namespace::Types);
@@ -363,6 +295,24 @@ TopLevel::visit (AST::StructStruct &struct_item)
}
void
+TopLevel::visit (AST::TypeParam &type_param)
+{
+ // Hacky and weird, find a better solution
+ // We should probably not even insert self in the first place ?
+ if (type_param.get_type_representation ().as_string () != "Self")
+ insert_or_error_out (type_param.get_type_representation (), type_param,
+ Namespace::Types);
+}
+
+void
+TopLevel::visit (AST::ConstGenericParam &const_param)
+{
+ insert_or_error_out (const_param.get_name (), const_param, Namespace::Values);
+
+ DefaultResolver::visit (const_param);
+}
+
+void
TopLevel::visit (AST::TupleStruct &tuple_struct)
{
insert_or_error_out (tuple_struct.get_struct_name (), tuple_struct,
@@ -427,181 +377,13 @@ TopLevel::visit (AST::ConstantItem &const_item)
DefaultResolver::visit (const_item);
}
-bool
-TopLevel::handle_use_glob (AST::SimplePath &glob)
-{
- auto resolved = ctx.types.resolve_path (glob.get_segments ());
- if (!resolved.has_value ())
- return false;
-
- auto result
- = Analysis::Mappings::get ().lookup_ast_module (resolved->get_node_id ());
-
- if (!result.has_value ())
- return false;
-
- GlobbingVisitor gvisitor (ctx);
- gvisitor.go (result.value ());
-
- return true;
-}
-
-bool
-TopLevel::handle_use_dec (AST::SimplePath &path)
-{
- auto locus = path.get_final_segment ().get_locus ();
- auto declared_name = path.get_final_segment ().as_string ();
-
- // in what namespace do we perform path resolution? All of them? see which one
- // matches? Error out on ambiguities?
- // so, apparently, for each one that matches, add it to the proper namespace
- // :(
-
- auto found = false;
-
- auto resolve_and_insert
- = [this, &found, &declared_name, locus] (Namespace ns,
- const AST::SimplePath &path) {
- tl::optional<Rib::Definition> resolved = tl::nullopt;
-
- // FIXME: resolve_path needs to return an `expected<NodeId, Error>` so
- // that we can improve it with hints or location or w/ever. and maybe
- // only emit it the first time.
- switch (ns)
- {
- case Namespace::Values:
- resolved = ctx.values.resolve_path (path.get_segments ());
- break;
- case Namespace::Types:
- resolved = ctx.types.resolve_path (path.get_segments ());
- break;
- case Namespace::Macros:
- resolved = ctx.macros.resolve_path (path.get_segments ());
- break;
- case Namespace::Labels:
- // TODO: Is that okay?
- rust_unreachable ();
- }
-
- // FIXME: Ugly
- (void) resolved.map ([this, &found, &declared_name, locus, ns,
- path] (Rib::Definition def) {
- found = true;
-
- // what do we do with the id?
- insert_or_error_out (declared_name, locus, def.get_node_id (), ns);
- auto result = node_forwarding.find (def.get_node_id ());
- if (result != node_forwarding.cend ()
- && result->second != path.get_node_id ())
- rust_error_at (path.get_locus (), "%qs defined multiple times",
- declared_name.c_str ());
- else // No previous thing has inserted this into our scope
- node_forwarding.insert ({def.get_node_id (), path.get_node_id ()});
-
- return def.get_node_id ();
- });
- };
-
- resolve_and_insert (Namespace::Values, path);
- resolve_and_insert (Namespace::Types, path);
- resolve_and_insert (Namespace::Macros, path);
-
- return found;
-}
-
-bool
-TopLevel::handle_rebind (std::pair<AST::SimplePath, AST::UseTreeRebind> &rebind)
+void
+TopLevel::visit (AST::TypeAlias &type_item)
{
- auto &path = rebind.first;
-
- location_t locus = UNKNOWN_LOCATION;
- std::string declared_name;
-
- switch (rebind.second.get_new_bind_type ())
- {
- case AST::UseTreeRebind::NewBindType::IDENTIFIER:
- declared_name = rebind.second.get_identifier ().as_string ();
- locus = rebind.second.get_identifier ().get_locus ();
- break;
- case AST::UseTreeRebind::NewBindType::NONE:
- declared_name = path.get_final_segment ().as_string ();
- locus = path.get_final_segment ().get_locus ();
- break;
- case AST::UseTreeRebind::NewBindType::WILDCARD:
- rust_unreachable ();
- break;
- }
-
- // in what namespace do we perform path resolution? All
- // of them? see which one matches? Error out on
- // ambiguities? so, apparently, for each one that
- // matches, add it to the proper namespace
- // :(
- auto found = false;
-
- auto resolve_and_insert = [this, &found, &declared_name,
- locus] (Namespace ns,
- const AST::SimplePath &path) {
- tl::optional<Rib::Definition> resolved = tl::nullopt;
- tl::optional<Rib::Definition> resolved_bind = tl::nullopt;
-
- std::vector<AST::SimplePathSegment> declaration_v
- = {AST::SimplePathSegment (declared_name, locus)};
- // FIXME: resolve_path needs to return an `expected<NodeId, Error>` so
- // that we can improve it with hints or location or w/ever. and maybe
- // only emit it the first time.
- switch (ns)
- {
- case Namespace::Values:
- resolved = ctx.values.resolve_path (path.get_segments ());
- resolved_bind = ctx.values.resolve_path (declaration_v);
- break;
- case Namespace::Types:
- resolved = ctx.types.resolve_path (path.get_segments ());
- resolved_bind = ctx.types.resolve_path (declaration_v);
- break;
- case Namespace::Macros:
- resolved = ctx.macros.resolve_path (path.get_segments ());
- resolved_bind = ctx.macros.resolve_path (declaration_v);
- break;
- case Namespace::Labels:
- // TODO: Is that okay?
- rust_unreachable ();
- }
-
- resolved.map ([this, &found, &declared_name, locus, ns, path,
- &resolved_bind] (Rib::Definition def) {
- found = true;
-
- insert_or_error_out (declared_name, locus, def.get_node_id (), ns);
- if (resolved_bind.has_value ())
- {
- auto bind_def = resolved_bind.value ();
- // what do we do with the id?
- auto result = node_forwarding.find (bind_def.get_node_id ());
- if (result != node_forwarding.cend ()
- && result->second != path.get_node_id ())
- rust_error_at (path.get_locus (), "%qs defined multiple times",
- declared_name.c_str ());
- }
- else
- {
- // No previous thing has inserted this into our scope
- node_forwarding.insert ({def.get_node_id (), path.get_node_id ()});
- }
- return def.get_node_id ();
- });
- };
-
- // do this for all namespaces (even Labels?)
-
- resolve_and_insert (Namespace::Values, path);
- resolve_and_insert (Namespace::Types, path);
- resolve_and_insert (Namespace::Macros, path);
-
- // TODO: No labels? No, right?
+ insert_or_error_out (type_item.get_new_type_name (), type_item,
+ Namespace::Types);
- return found;
+ DefaultResolver::visit (type_item);
}
static void
@@ -731,6 +513,10 @@ TopLevel::visit (AST::UseDeclaration &use)
auto rebind_path
= std::vector<std::pair<AST::SimplePath, AST::UseTreeRebind>> ();
+ auto &values_rib = ctx.values.peek ();
+ auto &types_rib = ctx.types.peek ();
+ auto &macros_rib = ctx.macros.peek ();
+
// FIXME: How do we handle `use foo::{self}` imports? Some beforehand cleanup?
// How do we handle module imports in general? Should they get added to all
// namespaces?
@@ -738,21 +524,22 @@ TopLevel::visit (AST::UseDeclaration &use)
const auto &tree = use.get_tree ();
flatten (tree.get (), paths, glob_path, rebind_path, this->ctx);
- for (auto &path : paths)
- if (!handle_use_dec (path))
- rust_error_at (path.get_final_segment ().get_locus (), ErrorCode::E0433,
- "unresolved import %qs", path.as_string ().c_str ());
-
- for (auto &glob : glob_path)
- if (!handle_use_glob (glob))
- rust_error_at (glob.get_final_segment ().get_locus (), ErrorCode::E0433,
- "unresolved import %qs", glob.as_string ().c_str ());
-
- for (auto &rebind : rebind_path)
- if (!handle_rebind (rebind))
- rust_error_at (rebind.first.get_final_segment ().get_locus (),
- ErrorCode::E0433, "unresolved import %qs",
- rebind.first.as_string ().c_str ());
+ auto imports = std::vector<ImportKind> ();
+
+ for (auto &&path : paths)
+ imports.emplace_back (
+ ImportKind::Simple (std::move (path), values_rib, types_rib, macros_rib));
+
+ for (auto &&glob : glob_path)
+ imports.emplace_back (
+ ImportKind::Glob (std::move (glob), values_rib, types_rib, macros_rib));
+
+ for (auto &&rebind : rebind_path)
+ imports.emplace_back (
+ ImportKind::Rebind (std::move (rebind.first), std::move (rebind.second),
+ values_rib, types_rib, macros_rib));
+
+ imports_to_resolve.insert ({use.get_node_id (), std::move (imports)});
}
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
index 0950370..7f4e295 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.h
@@ -19,36 +19,16 @@
#ifndef RUST_TOPLEVEL_NAME_RESOLVER_2_0_H
#define RUST_TOPLEVEL_NAME_RESOLVER_2_0_H
+#include "optional.h"
#include "rust-ast-visitor.h"
+#include "rust-ast.h"
+#include "rust-item.h"
#include "rust-name-resolution-context.h"
#include "rust-default-resolver.h"
namespace Rust {
namespace Resolver2_0 {
-class GlobbingVisitor : public AST::DefaultASTVisitor
-{
- using AST::DefaultASTVisitor::visit;
-
-public:
- GlobbingVisitor (NameResolutionContext &ctx) : ctx (ctx) {}
-
- void go (AST::Module *module);
- void visit (AST::Module &module) override;
- void visit (AST::MacroRulesDefinition &macro) override;
- void visit (AST::Function &function) override;
- void visit (AST::StaticItem &static_item) override;
- void visit (AST::StructStruct &struct_item) override;
- void visit (AST::TupleStruct &tuple_struct) override;
- void visit (AST::Enum &enum_item) override;
- void visit (AST::Union &union_item) override;
- void visit (AST::ConstantItem &const_item) override;
- void visit (AST::ExternCrate &crate) override;
- void visit (AST::UseDeclaration &use) override;
-
-private:
- NameResolutionContext &ctx;
-};
/**
* The `TopLevel` visitor takes care of collecting all the definitions in a
* crate, and inserting them into the proper namespaces. These definitions can
@@ -63,7 +43,77 @@ public:
void go (AST::Crate &crate);
-private:
+ bool is_dirty () { return dirty; }
+
+ // Each import will be transformed into an instance of `ImportKind`, a class
+ // representing some of the data we need to resolve in the
+ // `EarlyNameResolver`. Basically, for each `UseTree` that we see in
+ // `TopLevel`, create one of these. `TopLevel` should build a list of these
+ // `ImportKind`s, which `Early` can then resolve to their proper definitions.
+ // Then, a final pass will insert the definitions into the `ForeverStack` -
+ // `FinalizeImports`.
+ //
+ // Using this struct should be very simple - each path within a `UseTree`
+ // becomes one `ImportKind`. The complex case is glob imports, in which case
+ // one glob import will become one `ImportKind` which will later become
+ // multiple definitions thanks to the `GlobbingVisitor`.
+ struct ImportKind
+ {
+ enum class Kind
+ {
+ Glob,
+ Simple,
+ Rebind,
+ } kind;
+
+ static ImportKind Glob (AST::SimplePath &&to_resolve, Rib &values_rib,
+ Rib &types_rib, Rib &macros_rib)
+ {
+ return ImportKind (Kind::Glob, std::move (to_resolve), values_rib,
+ types_rib, macros_rib);
+ }
+
+ static ImportKind Simple (AST::SimplePath &&to_resolve, Rib &values_rib,
+ Rib &types_rib, Rib &macros_rib)
+ {
+ return ImportKind (Kind::Simple, std::move (to_resolve), values_rib,
+ types_rib, macros_rib);
+ }
+
+ static ImportKind Rebind (AST::SimplePath &&to_resolve,
+ AST::UseTreeRebind &&rebind, Rib &values_rib,
+ Rib &types_rib, Rib &macros_rib)
+ {
+ return ImportKind (Kind::Rebind, std::move (to_resolve), values_rib,
+ types_rib, macros_rib, std::move (rebind));
+ }
+
+ // The path for `Early` to resolve.
+ AST::SimplePath to_resolve;
+
+ // The path to rebind an import to - only present if kind is Kind::Rebind
+ tl::optional<AST::UseTreeRebind> rebind;
+
+ Rib &values_rib;
+ Rib &types_rib;
+ Rib &macros_rib;
+
+ private:
+ ImportKind (Kind kind, AST::SimplePath &&to_resolve, Rib &values_rib,
+ Rib &types_rib, Rib &macros_rib,
+ tl::optional<AST::UseTreeRebind> &&rebind = tl::nullopt)
+ : kind (kind), to_resolve (std::move (to_resolve)),
+ rebind (std::move (rebind)), values_rib (values_rib),
+ types_rib (types_rib), macros_rib (macros_rib)
+ {}
+ };
+
+ std::unordered_map<NodeId, std::vector<ImportKind>> &&
+ get_imports_to_resolve ()
+ {
+ return std::move (imports_to_resolve);
+ }
+
/**
* Insert a new definition or error out if a definition with the same name was
* already present in the same namespace in the same scope.
@@ -80,19 +130,29 @@ private:
const location_t &locus, const NodeId &id,
Namespace ns);
+private:
+ // If a new export has been defined whilst visiting the visitor is considered
+ // dirty
+ bool dirty;
+
// FIXME: Do we move these to our mappings?
std::unordered_map<NodeId, location_t> node_locations;
// Store node forwarding for use declaration, the link between a
- // "new" local name and its definition.
+ // definition and its new local name.
std::unordered_map<NodeId, NodeId> node_forwarding;
+ // One of the outputs of the `TopLevel` visitor - the list of imports that
+ // `Early` should take care of resolving
+ std::unordered_map<NodeId, std::vector<ImportKind>> imports_to_resolve;
+
void visit (AST::Module &module) override;
void visit (AST::Trait &trait) override;
void visit (AST::MacroRulesDefinition &macro) override;
void visit (AST::Function &function) override;
void visit (AST::BlockExpr &expr) override;
void visit (AST::StaticItem &static_item) override;
+ void visit (AST::ExternalStaticItem &static_item) override;
void visit (AST::StructStruct &struct_item) override;
void visit (AST::TupleStruct &tuple_struct) override;
void visit (AST::EnumItem &variant) override;
@@ -102,15 +162,10 @@ private:
void visit (AST::Enum &enum_item) override;
void visit (AST::Union &union_item) override;
void visit (AST::ConstantItem &const_item) override;
+ void visit (AST::TypeAlias &type_item) override;
void visit (AST::ExternCrate &crate) override;
-
- // FIXME: Documentation
- // Call this on all the paths of a UseDec - so each flattened path in a
- // UseTreeList for example
- // FIXME: Should that return `found`?
- bool handle_use_dec (AST::SimplePath &path);
- bool handle_use_glob (AST::SimplePath &glob);
- bool handle_rebind (std::pair<AST::SimplePath, AST::UseTreeRebind> &pair);
+ void visit (AST::TypeParam &type_param) override;
+ void visit (AST::ConstGenericParam &const_param) override;
void visit (AST::UseDeclaration &use) override;
};
@@ -118,4 +173,17 @@ private:
} // namespace Resolver2_0
} // namespace Rust
+// For storing Imports as keys in maps
+namespace std {
+template <> struct less<Rust::Resolver2_0::TopLevel::ImportKind>
+{
+ bool operator() (const Rust::Resolver2_0::TopLevel::ImportKind &lhs,
+ const Rust::Resolver2_0::TopLevel::ImportKind &rhs) const
+ {
+ return lhs.to_resolve.as_string () < rhs.to_resolve.as_string ()
+ && lhs.kind < rhs.kind;
+ }
+};
+} // namespace std
+
#endif // !RUST_TOPLEVEL_NAME_RESOLVER_2_0_H
diff --git a/gcc/rust/rust-session-manager.cc b/gcc/rust/rust-session-manager.cc
index 61a76d6..11ff250 100644
--- a/gcc/rust/rust-session-manager.cc
+++ b/gcc/rust/rust-session-manager.cc
@@ -18,6 +18,7 @@
#include "rust-session-manager.h"
#include "rust-diagnostics.h"
+#include "rust-hir-pattern-analysis.h"
#include "rust-immutable-name-resolution-context.h"
#include "rust-unsafe-checker.h"
#include "rust-lex.h"
@@ -476,10 +477,11 @@ Session::compile_crate (const char *filename)
rust_fatal_error (
UNDEF_LOCATION, "%s",
"gccrs is not yet able to compile Rust code "
- "properly. Most of the errors produced will be gccrs' fault and not the "
- "crate you are trying to compile. Because of this, please reports issues "
- "to us directly instead of opening issues on said crate's "
- "repository.\n\nOur github repository: "
+ "properly. Most of the errors produced will be the fault of gccrs and "
+ "not the crate you are trying to compile. Because of this, please report "
+ "errors directly to us instead of opening issues on said crate's "
+ "repository.\n\n"
+ "Our github repository: "
"https://github.com/rust-gcc/gccrs\nOur bugzilla tracker: "
"https://gcc.gnu.org/bugzilla/"
"buglist.cgi?bug_status=__open__&component=rust&product=gcc\n\n"
@@ -671,6 +673,11 @@ Session::compile_crate (const char *filename)
if (saw_errors ())
return;
+ Analysis::PatternChecker ().go (hir);
+
+ if (saw_errors ())
+ return;
+
if (last_step == CompileOptions::CompileStep::Privacy)
return;
@@ -918,21 +925,24 @@ Session::expansion (AST::Crate &crate, Resolver2_0::NameResolutionContext &ctx)
{
CfgStrip ().go (crate);
// Errors might happen during cfg strip pass
- if (saw_errors ())
- break;
+ bool visitor_dirty = false;
if (flag_name_resolution_2_0)
{
Resolver2_0::Early early (ctx);
early.go (crate);
macro_errors = early.get_macro_resolve_errors ();
+ visitor_dirty = early.is_dirty ();
}
else
Resolver::EarlyNameResolver ().go (crate);
+ if (saw_errors ())
+ break;
+
ExpandVisitor (expander).go (crate);
- fixed_point_reached = !expander.has_changed ();
+ fixed_point_reached = !expander.has_changed () && !visitor_dirty;
expander.reset_changed_state ();
iterations++;
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
index 51a6417..ec331cf 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -117,19 +117,26 @@ TraitResolver::resolve_path_to_trait (const HIR::TypePath &path,
return false;
}
- if (auto hid = mappings.lookup_node_to_hir (ref))
+ auto hid = mappings.lookup_node_to_hir (ref);
+ if (!hid)
{
- tl::optional<HIR::Item *> resolved_item
- = mappings.lookup_hir_item (hid.value ());
- rust_assert (resolved_item.has_value ());
- rust_assert (resolved_item.value ()->get_item_kind ()
- == HIR::Item::ItemKind::Trait);
- *resolved = static_cast<HIR::Trait *> (*resolved_item);
+ rust_error_at (path.get_locus (), "Failed to resolve path to hir-id");
+ return false;
+ }
- return true;
+ auto resolved_item = mappings.lookup_hir_item (hid.value ());
+ rust_assert (resolved_item.has_value ());
+ if (resolved_item.value ()->get_item_kind () != HIR::Item::ItemKind::Trait)
+ {
+ rich_location r (line_table, path.get_locus ());
+ r.add_fixit_replace ("not a trait");
+ rust_error_at (r, ErrorCode::E0404, "Expected a trait found %qs",
+ path.as_simple_path ().as_string ().c_str ());
+ return false;
}
- rust_error_at (path.get_locus (), "Failed to resolve path to hir-id");
- return false;
+
+ *resolved = static_cast<HIR::Trait *> (*resolved_item);
+ return true;
}
TraitReference *
diff --git a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
index 72d8791..a9154c6 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-enumitem.cc
@@ -20,6 +20,10 @@
#include "rust-hir-type-check-expr.h"
#include "rust-hir-type-check-enumitem.h"
#include "rust-type-util.h"
+#include "rust-immutable-name-resolution-context.h"
+
+// for flag_name_resolution_2_0
+#include "options.h"
namespace Rust {
namespace Resolver {
@@ -75,8 +79,23 @@ TypeCheckEnumItem::visit (HIR::EnumItem &item)
rust_assert (ok);
context->insert_type (mapping, isize);
- auto canonical_path
- = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ());
+ tl::optional<CanonicalPath> canonical_path;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ canonical_path
+ = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ());
+ }
+ else
+ {
+ canonical_path
+ = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ());
+ }
+
+ rust_assert (canonical_path.has_value ());
RustIdent ident{*canonical_path, item.get_locus ()};
variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
@@ -104,8 +123,23 @@ TypeCheckEnumItem::visit (HIR::EnumItemDiscriminant &item)
TyTy::TyWithLocation (expected_ty),
TyTy::TyWithLocation (capacity_type), item.get_locus ());
- auto canonical_path
- = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ());
+ tl::optional<CanonicalPath> canonical_path;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ canonical_path
+ = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ());
+ }
+ else
+ {
+ canonical_path
+ = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ());
+ }
+
+ rust_assert (canonical_path.has_value ());
RustIdent ident{*canonical_path, item.get_locus ()};
variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
@@ -151,8 +185,23 @@ TypeCheckEnumItem::visit (HIR::EnumItemTuple &item)
rust_assert (ok);
context->insert_type (mapping, isize);
- auto canonical_path
- = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ());
+ tl::optional<CanonicalPath> canonical_path;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ canonical_path
+ = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ());
+ }
+ else
+ {
+ canonical_path
+ = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ());
+ }
+
+ rust_assert (canonical_path.has_value ());
RustIdent ident{*canonical_path, item.get_locus ()};
variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
@@ -197,8 +246,23 @@ TypeCheckEnumItem::visit (HIR::EnumItemStruct &item)
rust_assert (ok);
context->insert_type (mapping, isize);
- auto canonical_path
- = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ());
+ tl::optional<CanonicalPath> canonical_path;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ canonical_path
+ = nr_ctx.types.to_canonical_path (item.get_mappings ().get_nodeid ());
+ }
+ else
+ {
+ canonical_path
+ = mappings.lookup_canonical_path (item.get_mappings ().get_nodeid ());
+ }
+
+ rust_assert (canonical_path.has_value ());
RustIdent ident{*canonical_path, item.get_locus ()};
variant = new TyTy::VariantDef (item.get_mappings ().get_hirid (),
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index 0e897813..ba22eaf 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -85,7 +85,9 @@ TypeCheckExpr::visit (HIR::TupleIndexExpr &expr)
TupleIndex index = expr.get_tuple_index ();
if ((size_t) index >= tuple->num_fields ())
{
- rust_error_at (expr.get_locus (), "unknown field at index %i", index);
+ rust_error_at (expr.get_locus (), ErrorCode::E0609,
+ "no field %qi on type %qs", index,
+ resolved->get_name ().c_str ());
return;
}
@@ -774,6 +776,69 @@ TypeCheckExpr::visit (HIR::RangeToExpr &expr)
}
void
+typecheck_inline_asm_operand (HIR::InlineAsm &expr)
+{
+ const auto &operands = expr.get_operands ();
+ using RegisterType = AST::InlineAsmOperand::RegisterType;
+ for (auto &operand : operands)
+ {
+ switch (operand.get_register_type ())
+ {
+ case RegisterType::In: {
+ auto in = operand.get_in ();
+ TypeCheckExpr::Resolve (in.expr.get ());
+ break;
+ }
+ case RegisterType::Out: {
+ auto out = operand.get_out ();
+ TypeCheckExpr::Resolve (out.expr.get ());
+ break;
+ }
+ case RegisterType::InOut: {
+ auto in_out = operand.get_in_out ();
+ TypeCheckExpr::Resolve (in_out.expr.get ());
+ break;
+ }
+ case RegisterType::SplitInOut: {
+ auto split_in_out = operand.get_split_in_out ();
+ TypeCheckExpr::Resolve (split_in_out.in_expr.get ());
+ TypeCheckExpr::Resolve (split_in_out.out_expr.get ());
+ break;
+ }
+ case RegisterType::Const: {
+ auto anon_const = operand.get_const ().anon_const;
+ TypeCheckExpr::Resolve (anon_const.expr.get ());
+ break;
+ }
+ case RegisterType::Sym: {
+ auto sym = operand.get_sym ();
+ TypeCheckExpr::Resolve (sym.expr.get ());
+ break;
+ }
+ case RegisterType::Label: {
+ auto label = operand.get_label ();
+ TypeCheckExpr::Resolve (label.expr.get ());
+ break;
+ }
+ }
+ }
+}
+void
+TypeCheckExpr::visit (HIR::InlineAsm &expr)
+{
+ typecheck_inline_asm_operand (expr);
+
+ // NOTE: Hoise out if we have noreturn as an option
+ // to return a never type
+ // TODO : new keyword for memory seems sooooo shaky
+ if (expr.options.count (AST::InlineAsmOption::NORETURN) == 1)
+ infered = new TyTy::NeverType (expr.get_mappings ().get_hirid ());
+ else
+ infered
+ = TyTy::TupleType::get_unit_type (expr.get_mappings ().get_hirid ());
+}
+
+void
TypeCheckExpr::visit (HIR::RangeFullExpr &expr)
{
auto lang_item_type = LangItem::Kind::RANGE_FULL;
@@ -1078,7 +1143,8 @@ TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
&lookup, nullptr);
if (!found)
{
- rust_error_at (expr.get_locus (), "unknown field [%s] for type [%s]",
+ rust_error_at (expr.get_locus (), ErrorCode::E0609,
+ "no field %qs on type %qs",
expr.get_field_name ().as_string ().c_str (),
adt->as_string ().c_str ());
return;
@@ -1462,6 +1528,7 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
TyTy::BaseType *scrutinee_tyty
= TypeCheckExpr::Resolve (expr.get_scrutinee_expr ().get ());
+ bool saw_error = false;
std::vector<TyTy::BaseType *> kase_block_tys;
for (auto &kase : expr.get_match_cases ())
{
@@ -1472,7 +1539,10 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
TyTy::BaseType *kase_arm_ty
= TypeCheckPattern::Resolve (pattern.get (), scrutinee_tyty);
if (kase_arm_ty->get_kind () == TyTy ::TypeKind::ERROR)
- return;
+ {
+ saw_error = true;
+ continue;
+ }
TyTy::BaseType *checked_kase = unify_site (
expr.get_mappings ().get_hirid (),
@@ -1481,7 +1551,10 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
TyTy::TyWithLocation (kase_arm_ty, pattern->get_locus ()),
expr.get_locus ());
if (checked_kase->get_kind () == TyTy::TypeKind::ERROR)
- return;
+ {
+ saw_error = true;
+ continue;
+ }
}
// check the kase type
@@ -1489,6 +1562,8 @@ TypeCheckExpr::visit (HIR::MatchExpr &expr)
= TypeCheckExpr::Resolve (kase.get_expr ().get ());
kase_block_tys.push_back (kase_block_ty);
}
+ if (saw_error)
+ return;
if (kase_block_tys.size () == 0)
{
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 45fc330..7192cf4 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -71,6 +71,7 @@ public:
void visit (HIR::RangeFromToInclExpr &expr) override;
void visit (HIR::WhileLoopExpr &expr) override;
void visit (HIR::ClosureExpr &expr) override;
+ void visit (HIR::InlineAsm &expr) override;
// TODO
void visit (HIR::ErrorPropagationExpr &) override {}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
index 58d59d9..0036e9a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.cc
@@ -24,6 +24,10 @@
#include "rust-hir-type-check-pattern.h"
#include "rust-type-util.h"
#include "rust-tyty.h"
+#include "rust-immutable-name-resolution-context.h"
+
+// for flag_name_resolution_2_0
+#include "options.h"
namespace Rust {
namespace Resolver {
@@ -461,8 +465,23 @@ TypeCheckImplItem::visit (HIR::Function &function)
TypeCheckPattern::Resolve (param.get_param_name ().get (), param_tyty);
}
- auto canonical_path
- = mappings.lookup_canonical_path (function.get_mappings ().get_nodeid ());
+ tl::optional<CanonicalPath> canonical_path;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ canonical_path = nr_ctx.values.to_canonical_path (
+ function.get_mappings ().get_nodeid ());
+ }
+ else
+ {
+ canonical_path = mappings.lookup_canonical_path (
+ function.get_mappings ().get_nodeid ());
+ }
+
+ rust_assert (canonical_path.has_value ());
RustIdent ident{*canonical_path, function.get_locus ()};
auto fnType = new TyTy::FnType (
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 68e2069..4ea6852 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -32,6 +32,9 @@
#include "rust-type-util.h"
#include "rust-tyty-variance-analysis.h"
+// for flag_name_resolution_2_0
+#include "options.h"
+
namespace Rust {
namespace Resolver {
@@ -343,8 +346,24 @@ TypeCheckItem::visit (HIR::Enum &enum_decl)
}
// get the path
- auto canonical_path
- = mappings.lookup_canonical_path (enum_decl.get_mappings ().get_nodeid ());
+ tl::optional<CanonicalPath> canonical_path;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ canonical_path = nr_ctx.types.to_canonical_path (
+ enum_decl.get_mappings ().get_nodeid ());
+ }
+ else
+ {
+ canonical_path = mappings.lookup_canonical_path (
+ enum_decl.get_mappings ().get_nodeid ());
+ }
+
+ rust_assert (canonical_path.has_value ());
+
RustIdent ident{*canonical_path, enum_decl.get_locus ()};
// multi variant ADT
@@ -390,8 +409,24 @@ TypeCheckItem::visit (HIR::Union &union_decl)
}
// get the path
- auto canonical_path
- = mappings.lookup_canonical_path (union_decl.get_mappings ().get_nodeid ());
+ tl::optional<CanonicalPath> canonical_path;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ canonical_path = nr_ctx.types.to_canonical_path (
+ union_decl.get_mappings ().get_nodeid ());
+ }
+ else
+ {
+ canonical_path = mappings.lookup_canonical_path (
+ union_decl.get_mappings ().get_nodeid ());
+ }
+
+ rust_assert (canonical_path.has_value ());
+
RustIdent ident{*canonical_path, union_decl.get_locus ()};
// there is only a single variant
@@ -453,6 +488,15 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block)
{
auto binder_pin = context->push_clean_lifetime_resolver (true);
+ TraitReference *trait_reference = &TraitReference::error_node ();
+ if (impl_block.has_trait_ref ())
+ {
+ std::unique_ptr<HIR::TypePath> &ref = impl_block.get_trait_ref ();
+ trait_reference = TraitResolver::Resolve (*ref);
+ if (trait_reference->is_error ())
+ return;
+ }
+
bool failed_flag = false;
auto result = resolve_impl_block_substitutions (impl_block, failed_flag);
if (failed_flag)
@@ -474,7 +518,7 @@ TypeCheckItem::visit (HIR::ImplBlock &impl_block)
}
// validate the impl items
- validate_trait_impl_block (impl_block, self, substitutions);
+ validate_trait_impl_block (trait_reference, impl_block, self, substitutions);
}
TyTy::BaseType *
@@ -698,16 +742,16 @@ TypeCheckItem::resolve_impl_block_substitutions (HIR::ImplBlock &impl_block,
void
TypeCheckItem::validate_trait_impl_block (
- HIR::ImplBlock &impl_block, TyTy::BaseType *self,
+ TraitReference *trait_reference, HIR::ImplBlock &impl_block,
+ TyTy::BaseType *self,
std::vector<TyTy::SubstitutionParamMapping> &substitutions)
{
auto specified_bound = TyTy::TypeBoundPredicate::error ();
- TraitReference *trait_reference = &TraitReference::error_node ();
if (impl_block.has_trait_ref ())
{
std::unique_ptr<HIR::TypePath> &ref = impl_block.get_trait_ref ();
- trait_reference = TraitResolver::Resolve (*ref);
- rust_assert (!trait_reference->is_error ());
+ if (trait_reference->is_error ())
+ return;
// we don't error out here see: gcc/testsuite/rust/compile/traits2.rs
// for example
@@ -734,7 +778,8 @@ TypeCheckItem::validate_trait_impl_block (
bool impl_block_missing_trait_items
= !specified_bound.is_error ()
&& trait_reference->size () != trait_item_refs.size ();
- if (impl_block_missing_trait_items)
+ if (impl_block_missing_trait_items
+ && impl_block.get_polarity () == BoundPolarity::RegularBound)
{
// filter the missing impl_items
std::vector<std::reference_wrapper<const TraitItemReference>>
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.h b/gcc/rust/typecheck/rust-hir-type-check-item.h
index c5b94db..56832e7 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.h
@@ -63,7 +63,8 @@ protected:
bool &failure_flag);
void validate_trait_impl_block (
- HIR::ImplBlock &impl_block, TyTy::BaseType *self,
+ TraitReference *trait_reference, HIR::ImplBlock &impl_block,
+ TyTy::BaseType *self,
std::vector<TyTy::SubstitutionParamMapping> &substitutions);
TyTy::BaseType *resolve_impl_item (HIR::ImplBlock &impl_block,
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
index c469f60..88e4d32f 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -17,8 +17,13 @@
// <http://www.gnu.org/licenses/>.
#include "rust-hir-type-check-pattern.h"
+#include "rust-hir-pattern.h"
#include "rust-hir-type-check-expr.h"
#include "rust-type-util.h"
+#include "rust-immutable-name-resolution-context.h"
+
+// for flag_name_resolution_2_0
+#include "options.h"
namespace Rust {
namespace Resolver {
@@ -43,7 +48,114 @@ TypeCheckPattern::Resolve (HIR::Pattern *pattern, TyTy::BaseType *parent)
void
TypeCheckPattern::visit (HIR::PathInExpression &pattern)
{
- infered = TypeCheckExpr::Resolve (&pattern);
+ // Pattern must be enum variants, sturcts, constants, or associated constansts
+ TyTy::BaseType *pattern_ty = TypeCheckExpr::Resolve (&pattern);
+
+ NodeId ref_node_id = UNKNOWN_NODEID;
+ bool maybe_item = false;
+
+ if (flag_name_resolution_2_0)
+ {
+ auto &nr_ctx
+ = Resolver2_0::ImmutableNameResolutionContext::get ().resolver ();
+
+ if (auto id = nr_ctx.lookup (pattern.get_mappings ().get_nodeid ()))
+ {
+ ref_node_id = *id;
+ maybe_item = true;
+ }
+ }
+ else
+ {
+ maybe_item |= resolver->lookup_resolved_name (
+ pattern.get_mappings ().get_nodeid (), &ref_node_id);
+ maybe_item |= resolver->lookup_resolved_type (
+ pattern.get_mappings ().get_nodeid (), &ref_node_id);
+ }
+
+ bool path_is_const_item = false;
+
+ if (maybe_item)
+ {
+ tl::optional<HirId> definition_id
+ = mappings.lookup_node_to_hir (ref_node_id);
+ rust_assert (definition_id.has_value ());
+ HirId def_id = definition_id.value ();
+
+ tl::optional<HIR::Item *> hir_item = mappings.lookup_hir_item (def_id);
+ // If the path refrerences an item, it must be constants or structs.
+ if (hir_item.has_value ())
+ {
+ HIR::Item *item = hir_item.value ();
+ if (item->get_item_kind () == HIR::Item::ItemKind::Constant)
+ {
+ path_is_const_item = true;
+ }
+ else if (item->get_item_kind () != HIR::Item::ItemKind::Struct)
+ {
+ HIR::Item *item = hir_item.value ();
+ std::string item_kind
+ = HIR::Item::item_kind_string (item->get_item_kind ());
+
+ std::string path_buf;
+ for (size_t i = 0; i < pattern.get_segments ().size (); i++)
+ {
+ HIR::PathExprSegment &seg = pattern.get_segments ().at (i);
+ path_buf += seg.as_string ();
+ if (i != pattern.get_segments ().size () - 1)
+ path_buf += "::";
+ }
+
+ rich_location rich_locus (
+ line_table, pattern.get_final_segment ().get_locus ());
+ rich_locus.add_fixit_replace (
+ "not a unit struct, unit variant or constatnt");
+ rust_error_at (rich_locus, ErrorCode::E0532,
+ "expected unit struct, unit variant or constant, "
+ "found %s %<%s%>",
+ item_kind.c_str (), path_buf.c_str ());
+ return;
+ }
+ }
+ }
+
+ // If the path is a constructor, it must be a unit struct or unit variants.
+ if (!path_is_const_item && pattern_ty->get_kind () == TyTy::TypeKind::ADT)
+ {
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (pattern_ty);
+ rust_assert (adt->get_variants ().size () > 0);
+
+ TyTy::VariantDef *variant = adt->get_variants ().at (0);
+ if (adt->is_enum ())
+ {
+ HirId variant_id = UNKNOWN_HIRID;
+ bool ok = context->lookup_variant_definition (
+ pattern.get_mappings ().get_hirid (), &variant_id);
+ rust_assert (ok);
+
+ ok = adt->lookup_variant_by_id (variant_id, &variant);
+ rust_assert (ok);
+ }
+
+ if (variant->get_variant_type () != TyTy::VariantDef::VariantType::NUM)
+ {
+ std::string variant_type = TyTy::VariantDef::variant_type_string (
+ variant->get_variant_type ());
+
+ rich_location rich_locus (line_table,
+ pattern.get_final_segment ().get_locus ());
+ rich_locus.add_fixit_replace (
+ "not a unit struct, unit variant or constatnt");
+ rust_error_at (rich_locus, ErrorCode::E0532,
+ "expected unit struct, unit variant or constant, "
+ "found %s variant %<%s::%s%>",
+ variant_type.c_str (), adt->get_name ().c_str (),
+ variant->get_identifier ().c_str ());
+ return;
+ }
+
+ infered = pattern_ty;
+ }
}
void
@@ -75,8 +187,8 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
rust_assert (ok);
}
- // error[E0532]: expected tuple struct or tuple variant, found struct variant
- // `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0
+ // error[E0532]: expected tuple struct or tuple variant, found struct
+ // variant `Foo::D`, E0532 by rustc 1.49.0 , E0164 by rustc 1.71.0
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::TUPLE)
{
std::string variant_type
@@ -135,6 +247,7 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
// setup the type on this pattern type
context->insert_type (pattern->get_mappings (), fty);
+ TypeCheckPattern::Resolve (pattern.get (), fty);
}
}
break;
@@ -178,8 +291,8 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
rust_assert (ok);
}
- // error[E0532]: expected tuple struct or tuple variant, found struct variant
- // `Foo::D`
+ // error[E0532]: expected tuple struct or tuple variant, found struct
+ // variant `Foo::D`
if (variant->get_variant_type () != TyTy::VariantDef::VariantType::STRUCT)
{
std::string variant_type
@@ -197,10 +310,6 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
return;
}
- // check the elements
- // error[E0027]: pattern does not mention fields `x`, `y`
- // error[E0026]: variant `Foo::D` does not have a field named `b`
-
std::vector<std::string> named_fields;
auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
@@ -254,31 +363,67 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
}
}
- if (named_fields.size () != variant->num_fields ())
+ // check the elements
+ if (adt->is_union ())
{
- std::map<std::string, bool> missing_names;
+ auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
+ if (struct_pattern_elems.get_struct_pattern_fields ().size () != 1)
+ rust_error_at (pattern.get_locus (),
+ "union patterns should have exactly one field");
- // populate with all fields
- for (auto &field : variant->get_fields ())
- missing_names[field->get_name ()] = true;
-
- // then eliminate with named_fields
- for (auto &named : named_fields)
- missing_names.erase (named);
-
- // then get the list of missing names
- size_t i = 0;
- std::string missing_fields_str;
- for (auto it = missing_names.begin (); it != missing_names.end (); it++)
+ else
{
- bool has_next = (i + 1) < missing_names.size ();
- missing_fields_str += it->first + (has_next ? ", " : "");
- i++;
+ switch (struct_pattern_elems.get_struct_pattern_fields ()
+ .at (0)
+ ->get_item_type ())
+ {
+ case HIR::StructPatternField::ItemType::IDENT:
+ case HIR::StructPatternField::ItemType::IDENT_PAT:
+ break;
+ default: {
+ auto first_elem
+ = struct_pattern_elems.get_struct_pattern_fields ()
+ .at (0)
+ ->as_string ();
+ rust_error_at (pattern.get_locus (),
+ "%qs cannot be used in union patterns",
+ first_elem.c_str ());
+ }
+ }
+ }
+ }
+ else
+ {
+ // Expects enum struct or struct struct.
+ // error[E0027]: pattern does not mention fields `x`, `y`
+ // error[E0026]: variant `Foo::D` does not have a field named `b`
+ if (named_fields.size () != variant->num_fields ())
+ {
+ std::map<std::string, bool> missing_names;
+
+ // populate with all fields
+ for (auto &field : variant->get_fields ())
+ missing_names[field->get_name ()] = true;
+
+ // then eliminate with named_fields
+ for (auto &named : named_fields)
+ missing_names.erase (named);
+
+ // then get the list of missing names
+ size_t i = 0;
+ std::string missing_fields_str;
+ for (auto it = missing_names.begin (); it != missing_names.end ();
+ it++)
+ {
+ bool has_next = (i + 1) < missing_names.size ();
+ missing_fields_str += it->first + (has_next ? ", " : "");
+ i++;
+ }
+
+ rust_error_at (pattern.get_locus (), ErrorCode::E0027,
+ "pattern does not mention fields %s",
+ missing_fields_str.c_str ());
}
-
- rust_error_at (pattern.get_locus (), ErrorCode::E0027,
- "pattern does not mention fields %s",
- missing_fields_str.c_str ());
}
}
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index 3fcb32a..fa49e06 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -349,6 +349,8 @@ private:
/** Only to be used by the guard. */
void pop_binder () { binder_size_stack.pop (); }
+ bool binder_empty () { return binder_size_stack.empty (); }
+
/**
* Switch from resolving a function header to a function body.
*/
@@ -424,7 +426,8 @@ public:
~LifetimeResolverGuard ()
{
rust_assert (!ctx.lifetime_resolver_stack.empty ());
- ctx.lifetime_resolver_stack.top ().pop_binder ();
+ if (!ctx.lifetime_resolver_stack.top ().binder_empty ())
+ ctx.lifetime_resolver_stack.top ().pop_binder ();
if (kind == RESOLVER)
{
ctx.lifetime_resolver_stack.pop ();
diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h b/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h
index 41a0d6f..450e53e 100644
--- a/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h
+++ b/gcc/rust/typecheck/rust-tyty-variance-analysis-private.h
@@ -201,10 +201,9 @@ public: // Module internal API
std::vector<Variance> query_generic_variance (const ADTType &type);
- std::vector<size_t> query_field_regions (const ADTType *parent,
- size_t variant_index,
- size_t field_index,
- const FreeRegions &parent_regions);
+ FreeRegions query_field_regions (const ADTType *parent, size_t variant_index,
+ size_t field_index,
+ const FreeRegions &parent_regions);
std::vector<Region> query_type_regions (BaseType *base);
@@ -309,7 +308,7 @@ class FieldVisitorCtx : public VarianceVisitorCtx<Variance>
public:
using Visitor = VisitorBase<Variance>;
- std::vector<size_t> collect_regions (BaseType &ty);
+ FreeRegions collect_regions (BaseType &ty);
FieldVisitorCtx (GenericTyPerCrateCtx &ctx, const SubstitutionRef &subst,
const FreeRegions &parent_regions)
@@ -332,7 +331,7 @@ public:
private:
GenericTyPerCrateCtx &ctx;
const SubstitutionRef &subst;
- std::vector<size_t> regions;
+ FreeRegions regions;
FreeRegions parent_regions;
std::vector<size_t> type_param_ranges;
};
diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis.cc b/gcc/rust/typecheck/rust-tyty-variance-analysis.cc
index d7116f5..1aba576 100644
--- a/gcc/rust/typecheck/rust-tyty-variance-analysis.cc
+++ b/gcc/rust/typecheck/rust-tyty-variance-analysis.cc
@@ -52,7 +52,7 @@ CrateCtx::query_type_regions (BaseType *type)
return private_ctx->query_type_regions (type);
}
-std::vector<size_t>
+FreeRegions
CrateCtx::query_field_regions (const ADTType *parent, size_t variant_index,
size_t field_index,
const FreeRegions &parent_regions)
@@ -332,7 +332,7 @@ GenericTyPerCrateCtx::query_generic_variance (const ADTType &type)
return result;
}
-std::vector<size_t>
+FreeRegions
GenericTyPerCrateCtx::query_field_regions (const ADTType *parent,
size_t variant_index,
size_t field_index,
@@ -537,7 +537,7 @@ TyVisitorCtx::add_constraints_from_generic_args (HirId ref,
}
}
-std::vector<size_t>
+FreeRegions
FieldVisitorCtx::collect_regions (BaseType &ty)
{
// Segment the regions into ranges for each type parameter. Type parameter
@@ -621,4 +621,4 @@ Term::make_transform (Term lhs, Term rhs)
} // namespace VarianceAnalysis
} // namespace TyTy
-} // namespace Rust \ No newline at end of file
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-tyty-variance-analysis.h b/gcc/rust/typecheck/rust-tyty-variance-analysis.h
index 27e8d8b..9059a2f 100644
--- a/gcc/rust/typecheck/rust-tyty-variance-analysis.h
+++ b/gcc/rust/typecheck/rust-tyty-variance-analysis.h
@@ -33,10 +33,9 @@ public:
/** Get regions mentioned in a type. */
std::vector<Region> query_type_regions (BaseType *type);
- std::vector<size_t> query_field_regions (const ADTType *parent,
- size_t variant_index,
- size_t field_index,
- const FreeRegions &parent_regions);
+ FreeRegions query_field_regions (const ADTType *parent, size_t variant_index,
+ size_t field_index,
+ const FreeRegions &parent_regions);
private:
std::unique_ptr<GenericTyPerCrateCtx> private_ctx;
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index b877c0c..e0a8745 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -3792,7 +3792,7 @@ DynamicObjectType::get_object_items () const
std::vector<
std::pair<const Resolver::TraitItemReference *, const TypeBoundPredicate *>>
items;
- for (auto &bound : get_specified_bounds ())
+ for (const TypeBoundPredicate &bound : get_specified_bounds ())
{
const Resolver::TraitReference *trait = bound.get ();
std::vector<const Resolver::TraitItemReference *> trait_items;
diff --git a/gcc/rust/util/optional.h b/gcc/rust/util/optional.h
index b2011b7..2c59459 100644
--- a/gcc/rust/util/optional.h
+++ b/gcc/rust/util/optional.h
@@ -1249,19 +1249,56 @@ public:
/// Returns a pointer to the stored value
constexpr const T *operator->() const {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
+
return std::addressof(this->m_value);
}
TL_OPTIONAL_11_CONSTEXPR T *operator->() {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
+
return std::addressof(this->m_value);
}
/// Returns the stored value
- TL_OPTIONAL_11_CONSTEXPR T &operator*() & { return this->m_value; }
+ TL_OPTIONAL_11_CONSTEXPR T &operator*() &
+ {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
- constexpr const T &operator*() const & { return this->m_value; }
+ return this->m_value;
+ }
+
+ constexpr const T &operator*() const &
+ {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
+
+ return this->m_value;
+ }
+
+ TL_OPTIONAL_11_CONSTEXPR T &&operator*() &&
+ {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
- TL_OPTIONAL_11_CONSTEXPR T &&operator*() && {
return std::move(this->m_value);
}
@@ -1988,14 +2025,49 @@ public:
void swap(optional &rhs) noexcept { std::swap(m_value, rhs.m_value); }
/// Returns a pointer to the stored value
- constexpr const T *operator->() const noexcept { return m_value; }
+ constexpr const T *operator->() const noexcept
+ {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
+
+ return m_value;
+ }
- TL_OPTIONAL_11_CONSTEXPR T *operator->() noexcept { return m_value; }
+ TL_OPTIONAL_11_CONSTEXPR T *operator->() noexcept
+ {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
+
+ return m_value;
+ }
/// Returns the stored value
- TL_OPTIONAL_11_CONSTEXPR T &operator*() noexcept { return *m_value; }
+ TL_OPTIONAL_11_CONSTEXPR T &operator*() noexcept {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
+
+ return *m_value;
+ }
- constexpr const T &operator*() const noexcept { return *m_value; }
+ constexpr const T &operator*() const noexcept
+ {
+ // constexpr function must only contain a return statement in C++11
+#ifdef TL_OPTIONAL_CXX14
+ // undefined behavior if we don't have a value
+ rust_assert(has_value ());
+#endif
+
+ return *m_value;
+ }
constexpr bool has_value() const noexcept { return m_value != nullptr; }
diff --git a/gcc/rust/util/rust-attribute-values.h b/gcc/rust/util/rust-attribute-values.h
index 9041701..ef01e67 100644
--- a/gcc/rust/util/rust-attribute-values.h
+++ b/gcc/rust/util/rust-attribute-values.h
@@ -56,6 +56,7 @@ public:
static constexpr auto &RUSTC_CONST_STABLE = "rustc_const_stable";
static constexpr auto &RUSTC_CONST_UNSTABLE = "rustc_const_unstable";
static constexpr auto &MAY_DANGLE = "may_dangle";
+ static constexpr auto &PRELUDE_IMPORT = "prelude_import";
};
} // namespace Values
} // namespace Rust
diff --git a/gcc/rust/util/rust-attributes.cc b/gcc/rust/util/rust-attributes.cc
index c9e3764..958f7c3 100644
--- a/gcc/rust/util/rust-attributes.cc
+++ b/gcc/rust/util/rust-attributes.cc
@@ -64,7 +64,8 @@ static const BuiltinAttrDefinition __definitions[]
{Attrs::UNSTABLE, STATIC_ANALYSIS},
// assuming we keep these for static analysis
{Attrs::RUSTC_CONST_STABLE, STATIC_ANALYSIS},
- {Attrs::RUSTC_CONST_UNSTABLE, STATIC_ANALYSIS}};
+ {Attrs::RUSTC_CONST_UNSTABLE, STATIC_ANALYSIS},
+ {Attrs::PRELUDE_IMPORT, NAME_RESOLUTION}};
BuiltinAttributeMappings *
BuiltinAttributeMappings::get ()
diff --git a/gcc/rust/util/rust-canonical-path.h b/gcc/rust/util/rust-canonical-path.h
index af151c2..4d8f954 100644
--- a/gcc/rust/util/rust-canonical-path.h
+++ b/gcc/rust/util/rust-canonical-path.h
@@ -46,7 +46,9 @@ namespace Resolver {
class CanonicalPath
{
public:
- CanonicalPath (const CanonicalPath &other) : segs (other.segs) {}
+ CanonicalPath (const CanonicalPath &other)
+ : segs (other.segs), crate_num (other.crate_num)
+ {}
CanonicalPath &operator= (const CanonicalPath &other)
{
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 81bdfaa..c6ccd46 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,108 @@
+2025-03-18 Marek Polacek <polacek@redhat.com>
+
+ PR c++/119344
+ * g++.dg/conversion/ptrmem10.C: New test.
+
+2025-03-18 Jason Merrill <jason@redhat.com>
+
+ PR c++/119194
+ * g++.dg/template/linkage7.C: New test.
+
+2025-03-18 Marek Polacek <polacek@redhat.com>
+
+ PR c++/118104
+ * g++.dg/cpp0x/alias-decl-variadic3.C: New test.
+
+2025-03-18 Harald Anlauf <anlauf@gmx.de>
+
+ PR fortran/119338
+ * gfortran.dg/deferred_character_18.f90: Adjust testcase.
+ * gfortran.dg/allocate_assumed_charlen_5.f90: New test.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/119311
+ * c-c++-common/musttail14.c: Use * instead of \* in the regexps.
+ * c-c++-common/musttail25.c: New test.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/116545
+ * c-c++-common/attr-fallthrough-2.c: Adjust expected diagnostics
+ for C++.
+ * c-c++-common/musttail15.c: New test.
+ * c-c++-common/musttail16.c: New test.
+ * c-c++-common/musttail17.c: New test.
+ * c-c++-common/musttail18.c: New test.
+ * c-c++-common/musttail19.c: New test.
+ * c-c++-common/musttail20.c: New test.
+ * c-c++-common/musttail21.c: New test.
+ * c-c++-common/musttail22.c: New test.
+ * c-c++-common/musttail23.c: New test.
+ * c-c++-common/musttail24.c: New test.
+ * g++.dg/musttail7.C: New test.
+ * g++.dg/musttail8.C: New test.
+ * g++.dg/musttail12.C: New test.
+ * g++.dg/musttail13.C: New test.
+ * g++.dg/musttail14.C: New test.
+ * g++.dg/ext/pr116545.C: New test.
+
+2025-03-18 Bob Dubner <rdubner@symas.com>
+
+ * cobol.dg/group1/check_88.cob: New testcase.
+ * cobol.dg/group1/comp5.cob: Likewise.
+ * cobol.dg/group1/declarative_1.cob: Likewise.
+ * cobol.dg/group1/display.cob: Likewise.
+ * cobol.dg/group1/display2.cob: Likewise.
+ * cobol.dg/group1/line-sequential.cob: Likewise.
+ * cobol.dg/group1/multiple-compares.cob: Likewise.
+ * cobol.dg/group1/multiply2.cob: Likewise.
+ * cobol.dg/group1/packed.cob: Likewise.
+ * cobol.dg/group1/perform-nested-exit.cob: Likewise.
+ * cobol.dg/group1/pointer1.cob: Likewise.
+ * cobol.dg/group1/simple-arithmetic.cob: Likewise.
+ * cobol.dg/group1/simple-classes.cob: Likewise.
+ * cobol.dg/group1/simple-if.cob: Likewise.
+ * cobol.dg/group1/simple-perform.cob: Likewise.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ * lib/gcc-dg.exp (${tool}-load): If output-file is set, compare
+ combined output against content of the [lindex ${output-file} 1]
+ file.
+ (dg-output-file): New directive.
+ * lib/dg-test-cleanup.exp (cleanup-after-saved-dg-test): Clear
+ output-file variable.
+ * gcc.dg/dg-output-file-1.c: New test.
+ * gcc.dg/dg-output-file-1-lp64.txt: New test.
+ * gcc.dg/dg-output-file-1-ilp32.txt: New test.
+
+2025-03-18 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/119233
+ * g++.dg/template/fn-ptr5.C: New test.
+
+2025-03-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/119307
+ * gcc.target/i386/pr119307.c: New test.
+
+2025-03-18 Richard Biener <rguenther@suse.de>
+
+ PR debug/101533
+ * g++.dg/debug/pr101533.C: New testcase.
+
+2025-03-18 Haochen Jiang <haochen.jiang@intel.com>
+
+ * gcc.target/i386/avx512f-pr103750-1.c: Remove XFAIL.
+ * gcc.target/i386/avx512f-pr103750-2.c: Ditto.
+ * gcc.target/i386/avx512fp16-pr103750-1.c: Ditto.
+ * gcc.target/i386/avx512fp16-pr103750-2.c: Ditto.
+
+2025-03-18 Jeff Law <jlaw@ventanamicro.com>
+
+ * gcc.target/riscv/redundant-andi-2.c: New test.
+
2025-03-17 Jeff Law <jlaw@ventanamicro.com>
* gcc.target/riscv/redundant-andi.c: New test.
diff --git a/gcc/testsuite/g++.dg/abi/mangle-new1.C b/gcc/testsuite/g++.dg/abi/mangle-new1.C
new file mode 100644
index 0000000..bb3ea9b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/mangle-new1.C
@@ -0,0 +1,10 @@
+// PR c++/119316
+// { dg-do compile { target c++11 } }
+
+template <unsigned> struct A { };
+template<typename T>
+auto foo(unsigned n) -> A<sizeof(new T[n])>
+{ return {}; }
+int main() { foo<int>(5); }
+
+// { dg-final { scan-assembler {_Z3fooIiE1AIXszna_Afp__T_EEEj} } }
diff --git a/gcc/testsuite/g++.dg/conversion/ptrmem10.C b/gcc/testsuite/g++.dg/conversion/ptrmem10.C
new file mode 100644
index 0000000..b5fc050
--- /dev/null
+++ b/gcc/testsuite/g++.dg/conversion/ptrmem10.C
@@ -0,0 +1,14 @@
+// PR c++/119344
+// { dg-do compile { target c++11 } }
+
+struct S {
+ void fn();
+};
+typedef void (S::*T)(void);
+template <T Ptr>
+struct s
+{
+ static const bool t = Ptr != T();
+};
+
+int t1 = s<&S::fn>::t;
diff --git a/gcc/testsuite/g++.dg/cpp0x/alias-decl-variadic3.C b/gcc/testsuite/g++.dg/cpp0x/alias-decl-variadic3.C
new file mode 100644
index 0000000..077f033
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alias-decl-variadic3.C
@@ -0,0 +1,22 @@
+// PR c++/118104
+// { dg-do compile { target c++11 } }
+
+template<typename... Zs> struct Z { };
+
+template <class... Ts> struct X {
+ template <class... Us> using W = Z<void(Ts, Us)...>;
+ template <class... Us> using Y = X<void(Ts, Us)...>;
+};
+
+template <class A, class... P>
+using foo = X<int, int>::W<A, P...>;
+
+template <class A, class... P>
+using bar = X<int, int>::Y<A, P...>;
+
+void
+g ()
+{
+ foo<int, int> f;
+ bar<int, int> b;
+}
diff --git a/gcc/testsuite/g++.dg/template/linkage7.C b/gcc/testsuite/g++.dg/template/linkage7.C
new file mode 100644
index 0000000..6686a0e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/linkage7.C
@@ -0,0 +1,17 @@
+// PR c++/119194
+// { dg-do compile { target c++11 } }
+
+template <const int& Str>
+[[gnu::noipa]]
+int get_length() {
+ return Str;
+}
+static constexpr int sssss{ 3};
+int main() {
+ if (get_length<sssss>() != sssss)
+ __builtin_abort();
+ return 0;
+}
+
+// { dg-final { scan-assembler {_Z10get_lengthIL_ZL5sssssEEiv} } }
+// { dg-final { scan-assembler-not {(weak|glob)[^\n]*_Z10get_lengthIL_Z5sssssEEiv} } }
diff --git a/gcc/testsuite/g++.target/i386/pr118068.C b/gcc/testsuite/g++.target/i386/pr118068.C
new file mode 100644
index 0000000..c5cc61f
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/pr118068.C
@@ -0,0 +1,17 @@
+// PR target/118068
+// { dg-do compile { target c++20 } }
+// { dg-options "-O0 -mavx" }
+
+typedef float V __attribute__((vector_size (32)));
+
+consteval unsigned char
+foo (int x)
+{
+ return x;
+}
+
+V
+bar (V x, V y)
+{
+ return __builtin_ia32_blendps256 (x, y, (int) foo (0x23));
+}
diff --git a/gcc/testsuite/gcc.dg/Wfatal-bad-attr-pr119366.c b/gcc/testsuite/gcc.dg/Wfatal-bad-attr-pr119366.c
new file mode 100644
index 0000000..2ca4eed
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wfatal-bad-attr-pr119366.c
@@ -0,0 +1,8 @@
+/* Verify that we don't crash if we bail out with a fatal error
+ while an on-stack attribute_urlifier is active (PR c/119366). */
+/* { dg-options "-Wfatal-errors -Werror=attributes" } */
+void foo() __attribute__((this_does_not_exist)); /* { dg-error "'this_does_not_exist' attribute directive ignored" } */
+
+/* { dg-message "some warnings being treated as errors" "treated as errors" {target "*-*-*"} 0 } */
+/* { dg-message "terminated due to -Wfatal-errors" "terminated" { target *-*-* } 0 } */
+
diff --git a/gcc/testsuite/gcc.dg/Wfree-nonheap-object-7.c b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-7.c
index 52cfbf9..c13b7ca 100644
--- a/gcc/testsuite/gcc.dg/Wfree-nonheap-object-7.c
+++ b/gcc/testsuite/gcc.dg/Wfree-nonheap-object-7.c
@@ -1,9 +1,9 @@
/* { dg-do compile } */
-/* { dg-options "-std=gnu17 -O2 -Wfree-nonheap-object" } */
+/* { dg-options "-O2 -Wfree-nonheap-object" } */
struct local_caches *get_local_caches_lcs;
-void *calloc(long, long);
-void *realloc();
+void *calloc(__SIZE_TYPE__, __SIZE_TYPE__);
+void *realloc(void *, __SIZE_TYPE__);
struct local_caches {
int *t_mem_caches;
diff --git a/gcc/testsuite/gcc.dg/pr b/gcc/testsuite/gcc.dg/pr
deleted file mode 100644
index e69de29..0000000
--- a/gcc/testsuite/gcc.dg/pr
+++ /dev/null
diff --git a/gcc/testsuite/gcc.dg/pr118061.c b/gcc/testsuite/gcc.dg/pr118061.c
new file mode 100644
index 0000000..6efc94d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr118061.c
@@ -0,0 +1,8 @@
+/* { dg-do "compile" } */
+/* { dg-options "-std=gnu23" } */
+
+int main()
+{
+ struct { int x[1++]; } x; /* { dg-error "lvalue required as increment operand" } */
+ struct { int x[1++]; } y; /* { dg-error "lvalue required as increment operand" } */
+}
diff --git a/gcc/testsuite/gcc.dg/pr118765.c b/gcc/testsuite/gcc.dg/pr118765.c
new file mode 100644
index 0000000..12d0259
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr118765.c
@@ -0,0 +1,7 @@
+/* { dg-do "compile" } */
+/* { dg-options "-std=gnu23" } */
+
+typedef struct q { int x; } q_t;
+struct q { int x; };
+typedef struct q { int x; } q_t;
+
diff --git a/gcc/testsuite/gcc.dg/pr119350-1.c b/gcc/testsuite/gcc.dg/pr119350-1.c
new file mode 100644
index 0000000..75ab290
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr119350-1.c
@@ -0,0 +1,14 @@
+/* PR c/119350 */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -pedantic-errors" } */
+
+struct S { int a; int b[]; };
+struct T { struct S c; }; /* { dg-error "invalid use of structure with flexible array member" } */
+struct S d = { 1, {} }; /* { dg-error "initialization of a flexible array member" } */
+struct S e = { 1, { 2 } }; /* { dg-error "initialization of a flexible array member" } */
+struct S f = { .a = 1, .b = {} }; /* { dg-error "initialization of a flexible array member" } */
+struct S g = { .a = 1, .b = { 2 } }; /* { dg-error "initialization of a flexible array member" } */
+struct T h = { { 1, {} } }; /* { dg-error "initialization of flexible array member in a nested context" } */
+struct T i = { { 1, { 2 } } }; /* { dg-error "initialization of flexible array member in a nested context" } */
+struct T j = { .c = { .a = 1, .b = {} } }; /* { dg-error "initialization of flexible array member in a nested context" } */
+struct T k = { .c = { .a = 1, .b = { 2 } } }; /* { dg-error "initialization of flexible array member in a nested context" } */
diff --git a/gcc/testsuite/gcc.dg/pr119350-2.c b/gcc/testsuite/gcc.dg/pr119350-2.c
new file mode 100644
index 0000000..ddb3502
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr119350-2.c
@@ -0,0 +1,14 @@
+/* PR c/119350 */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -Wpedantic" } */
+
+struct S { int a; int b[]; };
+struct T { struct S c; }; /* { dg-warning "invalid use of structure with flexible array member" } */
+struct S d = { 1, {} }; /* { dg-warning "initialization of a flexible array member" } */
+struct S e = { 1, { 2 } }; /* { dg-warning "initialization of a flexible array member" } */
+struct S f = { .a = 1, .b = {} }; /* { dg-warning "initialization of a flexible array member" } */
+struct S g = { .a = 1, .b = { 2 } }; /* { dg-warning "initialization of a flexible array member" } */
+struct T h = { { 1, {} } }; /* { dg-warning "initialization of flexible array member in a nested context" } */
+struct T i = { { 1, { 2 } } }; /* { dg-error "initialization of flexible array member in a nested context" } */
+struct T j = { .c = { .a = 1, .b = {} } }; /* { dg-warning "initialization of flexible array member in a nested context" } */
+struct T k = { .c = { .a = 1, .b = { 2 } } }; /* { dg-error "initialization of flexible array member in a nested context" } */
diff --git a/gcc/testsuite/gcc.dg/pr119350-3.c b/gcc/testsuite/gcc.dg/pr119350-3.c
new file mode 100644
index 0000000..20c2b56
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr119350-3.c
@@ -0,0 +1,14 @@
+/* PR c/119350 */
+/* { dg-do compile } */
+/* { dg-options "-std=c23 -Wc11-c23-compat" } */
+
+struct S { int a; int b[]; };
+struct T { struct S c; };
+struct S d = { 1, {} }; /* { dg-warning "ISO C forbids empty initializer braces before C23" } */
+struct S e = { 1, { 2 } };
+struct S f = { .a = 1, .b = {} }; /* { dg-warning "ISO C forbids empty initializer braces before C23" } */
+struct S g = { .a = 1, .b = { 2 } };
+struct T h = { { 1, {} } }; /* { dg-warning "ISO C forbids empty initializer braces before C23" } */
+struct T i = { { 1, { 2 } } }; /* { dg-error "initialization of flexible array member in a nested context" } */
+struct T j = { .c = { .a = 1, .b = {} } }; /* { dg-warning "ISO C forbids empty initializer braces before C23" } */
+struct T k = { .c = { .a = 1, .b = { 2 } } }; /* { dg-error "initialization of flexible array member in a nested context" } */
diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-41.c b/gcc/testsuite/gcc.dg/vect/bb-slp-41.c
index 7224511..5a2bd4d 100644
--- a/gcc/testsuite/gcc.dg/vect/bb-slp-41.c
+++ b/gcc/testsuite/gcc.dg/vect/bb-slp-41.c
@@ -51,6 +51,7 @@ int main ()
foo (a1, b);
bar (a2, b);
+#pragma GCC novector
for (i = 0; i < ARR_SIZE; i++)
if (a1[i] != a2[i])
return 1;
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_128.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_128.c
index ed6baf2d..3d51d52 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_128.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_128.c
@@ -3,8 +3,8 @@
/* { dg-require-effective-target vect_early_break } */
/* { dg-require-effective-target vect_int } */
-/* { dg-final { scan-tree-dump "vectorizing stmts using SLP" "vect" { target vect_partial_vectors } } } */
-/* { dg-final { scan-tree-dump-not "vectorizing stmts using SLP" "vect" { target { ! vect_partial_vectors } } } } */
+/* { dg-final { scan-tree-dump "vectorizing stmts using SLP" "vect" { target { vect_partial_vectors && vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-not "vectorizing stmts using SLP" "vect" { target { { ! vect_partial_vectors } || { ! vect_load_lanes } } } } } */
/* { dg-final { scan-tree-dump "Loop contains only SLP stmts" "vect" } } */
#ifndef N
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa10.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa10.c
index dd05046..2a58fb0 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa10.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa10.c
@@ -6,9 +6,9 @@
/* { dg-additional-options "-Ofast" } */
/* Alignment requirement too big, load lanes targets can't safely vectorize this. */
-/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target { vect_partial_vectors || vect_load_lanes } } } } */
-/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { ! { vect_partial_vectors || vect_load_lanes } } } } } */
-/* { dg-final { scan-tree-dump-not "Alignment of access forced using peeling" "vect" { target { ! { vect_partial_vectors || vect_load_lanes } } } } } */
+/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target { vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { ! vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-not "Alignment of access forced using peeling" "vect" { target { ! vect_load_lanes } } } } */
unsigned test4(char x, char *restrict vect_a, char *restrict vect_b, int n)
{
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa11.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa11.c
index 085dd9b..514bd37 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa11.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa11.c
@@ -3,9 +3,8 @@
/* { dg-require-effective-target vect_early_break } */
/* { dg-require-effective-target vect_int } */
-/* Gathers and scatters are not save to speculate across early breaks. */
-/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { ! vect_partial_vectors } } } } */
-/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target vect_partial_vectors } } } */
+/* Gathers and scatters are not safe to speculate across early breaks. */
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" } } */
#define N 1024
int vect_a[N];
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa8.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa8.c
index 25d3a62..90e5998 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa8.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa8.c
@@ -5,8 +5,8 @@
/* { dg-additional-options "-Ofast" } */
-/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target vect_partial_vectors } } } */
-/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { ! vect_partial_vectors } } } } */
+/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target { vect_partial_vectors && vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { { ! vect_partial_vectors } || { ! vect_load_lanes } } } } } */
char vect_a[1025];
char vect_b[1025];
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa9.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa9.c
index 10eb98b..fa2b32e 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa9.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_133_pfa9.c
@@ -6,8 +6,8 @@
/* { dg-additional-options "-Ofast" } */
/* Group size is uneven and second group is misaligned. Needs partial vectors. */
-/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target vect_partial_vectors } } } */
-/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { ! vect_partial_vectors } } } } */
+/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target { vect_partial_vectors && vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { { ! vect_partial_vectors } || { ! vect_load_lanes } } } } } */
/* { dg-final { scan-tree-dump-not "Alignment of access forced using peeling" "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_22.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_22.c
index f8f84fa..8e91ac6 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_22.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_22.c
@@ -43,5 +43,5 @@ main ()
}
/* This will fail because we cannot SLP the load groups yet. */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" { target vect_partial_vectors } } } */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 1 "vect" { target { ! vect_partial_vectors } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" { target { vect_partial_vectors && vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 1 "vect" { target { { ! vect_partial_vectors } || { ! vect_load_lanes } } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_26.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_26.c
index 643016b..f6688fc 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_26.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_26.c
@@ -42,5 +42,5 @@ main ()
}
/* This will fail because we cannot SLP the load groups yet. */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" { target vect_partial_vectors } } } */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 1 "vect" { target { ! vect_partial_vectors } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 2 "vect" { target { vect_partial_vectors && vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 1 "vect" { target { { ! vect_partial_vectors } || { ! vect_load_lanes } } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_43.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_43.c
index 0cfa242..e6866de 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_43.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_43.c
@@ -28,5 +28,5 @@ unsigned test4(unsigned x)
}
/* This will fail because we cannot SLP the load groups yet. */
-/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" { target vect_partial_vectors } } } */
-/* { dg-final { scan-tree-dump-not "vectorized 1 loops in function" "vect" { target { ! vect_partial_vectors } } } } */
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" { target { vect_partial_vectors && vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-not "vectorized 1 loops in function" "vect" { target { { ! vect_partial_vectors } || { ! vect_load_lanes } } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_44.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_44.c
index 0cfa242..e6866de 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_44.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_44.c
@@ -28,5 +28,5 @@ unsigned test4(unsigned x)
}
/* This will fail because we cannot SLP the load groups yet. */
-/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" { target vect_partial_vectors } } } */
-/* { dg-final { scan-tree-dump-not "vectorized 1 loops in function" "vect" { target { ! vect_partial_vectors } } } } */
+/* { dg-final { scan-tree-dump "vectorized 1 loops in function" "vect" { target { vect_partial_vectors && vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-not "vectorized 1 loops in function" "vect" { target { { ! vect_partial_vectors } || { ! vect_load_lanes } } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_56.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_56.c
index b35e737..76a1f9b 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_56.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_56.c
@@ -99,5 +99,5 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "vectorized 2 loops" 2 "vect" { xfail { vect_early_break && { ! vect_hw_misalign } } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" { xfail { vect_early_break && { ! vect_hw_misalign } } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_6.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_6.c
index c7cce81..485cee6 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-early-break_6.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_6.c
@@ -6,8 +6,8 @@
/* { dg-additional-options "-Ofast" } */
/* This will fail because we cannot SLP the load groups yet. */
-/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target vect_partial_vectors } } } */
-/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { ! vect_partial_vectors } } } } */
+/* { dg-final { scan-tree-dump "LOOP VECTORIZED" "vect" { target { vect_partial_vectors && vect_load_lanes } } } } */
+/* { dg-final { scan-tree-dump-not "LOOP VECTORIZED" "vect" { target { { ! vect_partial_vectors } || { ! vect_load_lanes } } } } } */
#define N 1024
unsigned vect_a[N];
diff --git a/gcc/testsuite/gcc.target/i386/apx-ndd-tls-1b.c b/gcc/testsuite/gcc.target/i386/apx-ndd-tls-1b.c
index d063703..afcad0c 100644
--- a/gcc/testsuite/gcc.target/i386/apx-ndd-tls-1b.c
+++ b/gcc/testsuite/gcc.target/i386/apx-ndd-tls-1b.c
@@ -3,7 +3,10 @@
/* { dg-require-effective-target tls } */
/* { dg-require-effective-target code_6_gottpoff_reloc } */
/* { dg-options "-save-temps -std=gnu17 -mapxf -O3 -w" } */
-
+/* The testcase is fragile, it's supposed to check the compiler
+ ability of generating code_6_gottpoff_reloc instruction, but
+ failed since there's a seg_prefixed memory
+ usage(r14-6242-gd564198f960a2f). */
#include "apx-ndd-tls-1a.c"
-/* { dg-final { scan-assembler-times "addq\[ \t]+%r\[a-z0-9\]+, a@gottpoff\\(%rip\\), %r\[a-z0-9\]+" 1 { target lp64 } } } */
+/* { dg-final { scan-assembler-times "addq\[ \t]+%r\[a-z0-9\]+, a@gottpoff\\(%rip\\), %r\[a-z0-9\]+" 1 { xfail lp64 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/avx512vlbw-pr119357.c b/gcc/testsuite/gcc.target/i386/avx512vlbw-pr119357.c
new file mode 100644
index 0000000..61afe22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512vlbw-pr119357.c
@@ -0,0 +1,14 @@
+/* PR target/119357 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx512bw -mavx512vl" } */
+
+#include <x86intrin.h>
+
+typedef char V __attribute__((vector_size (16)));
+
+void
+foo (V *p)
+{
+ if (_mm_movemask_epi8 ((__m128i) (*p == 0)) != 65535)
+ __builtin_abort ();
+}
diff --git a/gcc/testsuite/gcc.target/loongarch/regname-float-abi.c b/gcc/testsuite/gcc.target/loongarch/regname-float-abi.c
new file mode 100644
index 0000000..2224304
--- /dev/null
+++ b/gcc/testsuite/gcc.target/loongarch/regname-float-abi.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-Wno-pedantic -std=gnu90 -mfpu=64" } */
+
+register double fs0 asm("fs0"); /* { dg-note "conflicts with 'fs0'" } */
+register double f24 asm("$f24"); /* { dg-warning "register of 'f24' used for multiple global register variables" } */
+
+void
+test (void)
+{
+ asm("" ::: "fa0", "fa1", "fa2", "fa3", "fa4", "fa5", "fa6", "fa7",
+ "ft0", "ft1", "ft2", "ft3", "ft4", "ft5", "ft6", "ft7",
+ "ft8", "ft9", "ft10", "ft11", "ft12", "ft13", "ft14", "ft15",
+ "fs0", "fs1", "fs2", "fs3", "fs4", "fs5", "fs6", "fs7");
+}
diff --git a/gcc/testsuite/gcc.target/s390/vector/vcond-shift.c b/gcc/testsuite/gcc.target/s390/vector/vcond-shift.c
index a6b4e97..b942f44 100644
--- a/gcc/testsuite/gcc.target/s390/vector/vcond-shift.c
+++ b/gcc/testsuite/gcc.target/s390/vector/vcond-shift.c
@@ -3,13 +3,13 @@
/* { dg-do compile { target { s390*-*-* } } } */
/* { dg-options "-O3 -march=z13 -mzarch" } */
-/* { dg-final { scan-assembler-times "vesraf\t%v.?,%v.?,31" 6 } } */
-/* { dg-final { scan-assembler-times "vesrah\t%v.?,%v.?,15" 6 } } */
-/* { dg-final { scan-assembler-times "vesrab\t%v.?,%v.?,7" 6 } } */
+/* { dg-final { scan-assembler-times "vesraf\t%v.?,%v.?,31" 4 } } */
+/* { dg-final { scan-assembler-times "vesrah\t%v.?,%v.?,15" 4 } } */
+/* { dg-final { scan-assembler-times "vesrab\t%v.?,%v.?,7" 4 } } */
/* { dg-final { scan-assembler-not "vzero\t*" } } */
-/* { dg-final { scan-assembler-times "vesrlf\t%v.?,%v.?,31" 4 } } */
-/* { dg-final { scan-assembler-times "vesrlh\t%v.?,%v.?,15" 4 } } */
-/* { dg-final { scan-assembler-times "vesrlb\t%v.?,%v.?,7" 4 } } */
+/* { dg-final { scan-assembler-times "vesrlf\t%v.?,%v.?,31" 6 } } */
+/* { dg-final { scan-assembler-times "vesrlh\t%v.?,%v.?,15" 6 } } */
+/* { dg-final { scan-assembler-times "vesrlb\t%v.?,%v.?,7" 6 } } */
/* Make it expand to two vector operations. */
#define ITER(X) (2 * (16 / sizeof (X[1])))
diff --git a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c
index 1806fa8..ad097ef 100644
--- a/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c
+++ b/gcc/testsuite/gcc.target/s390/zvector/autovec-double-signaling-eq-z13.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O3 -march=z13 -mzvector -mzarch" } */
+/* { dg-options "-O3 -march=z13 -mzvector -mzarch -fsignaling-nans" } */
#include "autovec.h"
diff --git a/gcc/testsuite/gfortran.dg/allocate_assumed_charlen_5.f90 b/gcc/testsuite/gfortran.dg/allocate_assumed_charlen_5.f90
new file mode 100644
index 0000000..bc75dbe
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/allocate_assumed_charlen_5.f90
@@ -0,0 +1,17 @@
+! { dg-do compile }
+! PR fortran/119338 - check F2003:C626
+
+module m
+ implicit none
+contains
+ subroutine sub (s, c)
+ character(len=*), allocatable, intent(out) :: s(:)
+ character(len=*), allocatable, intent(out) :: c
+ allocate(s(5)) ! OK
+ allocate(c) ! OK
+ allocate(character(len=*) :: s(5)) ! OK
+ allocate(character(len=*) :: c) ! OK
+ allocate(character(len=10) :: s(5)) ! { dg-error "shall be an asterisk" }
+ allocate(character(len=10) :: c) ! { dg-error "shall be an asterisk" }
+ end subroutine sub
+end module m
diff --git a/gcc/testsuite/gfortran.dg/associate_74.f90 b/gcc/testsuite/gfortran.dg/associate_74.f90
new file mode 100644
index 0000000..057d635
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_74.f90
@@ -0,0 +1,47 @@
+!{ dg-do run }
+
+! Check that PR119272 is fixed
+! Contributed by Xing Jing Wei <xingjingwei666@gmail.com>
+
+module pr119272_module
+ type, public :: test_type
+ contains
+ procedure :: scal_function
+ procedure :: arr_function
+ end type test_type
+ contains
+ function scal_function(this) result(smth)
+ class(test_type) :: this
+ integer :: smth
+ smth = 2
+ end function
+ function arr_function(this) result(smth)
+ class(test_type) :: this
+ integer :: smth(9)
+ smth = (/(i, i=1, 9)/)
+ end function
+end module
+
+program pr119272
+ use pr119272_module
+ implicit none
+
+ type(test_type) :: a
+
+ call test_subroutine(a)
+ contains
+ subroutine test_subroutine(a)
+ class(test_type) :: a
+ integer :: i
+ integer,parameter :: temp_int(3) = [ 1, 2, 3]
+ integer,parameter :: identity(9) = (/(i* 5, i= 9, 1, -1)/)
+ associate(temp => temp_int(a%scal_function()))
+ if (temp /= 2) stop 1
+ end associate
+
+ associate(temparr => identity(a%arr_function()))
+ if (any(temparr /= (/(i* 5, i= 9, 1, -1)/))) stop 2
+ end associate
+ end subroutine
+end program
+
diff --git a/gcc/testsuite/gfortran.dg/bounds_check_27.f90 b/gcc/testsuite/gfortran.dg/bounds_check_27.f90
new file mode 100644
index 0000000..678aef6
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/bounds_check_27.f90
@@ -0,0 +1,45 @@
+! { dg-do run }
+! { dg-additional-options "-fcheck=bounds" }
+!
+! PR fortran/116706 - bogus bounds check for reallocation on assignment
+! Contributed by Balint Aradi <baradi09 at gmail.com>
+
+program testprog
+ implicit none
+
+ type :: data_node
+ integer, allocatable :: data(:)
+ end type data_node
+
+ type :: data_list
+ type(data_node), pointer :: nodes(:) => null()
+ end type data_list
+
+ type :: upoly_node
+ class(*), allocatable :: data(:)
+ end type upoly_node
+
+ type :: star_list
+ type(upoly_node), pointer :: nodes(:) => null()
+ end type star_list
+
+ type(data_list) :: datalist
+ type(star_list) :: starlist
+ class(star_list), allocatable :: astarlist
+ class(star_list), pointer :: pstarlist
+
+ allocate (datalist%nodes(2))
+ datalist%nodes(1)%data = [1, 2, 3]
+
+ allocate (starlist%nodes(2))
+ starlist%nodes(1)%data = [1., 2., 3.]
+
+ allocate (astarlist)
+ allocate (astarlist%nodes(2))
+ astarlist%nodes(1)%data = [1, 2, 3]
+
+ allocate (pstarlist)
+ allocate (pstarlist%nodes(2))
+ pstarlist%nodes(1)%data = [1., 2., 3.]
+
+end program testprog
diff --git a/gcc/testsuite/gfortran.dg/deferred_character_18.f90 b/gcc/testsuite/gfortran.dg/deferred_character_18.f90
index 1b1457f..b1229c2 100644
--- a/gcc/testsuite/gfortran.dg/deferred_character_18.f90
+++ b/gcc/testsuite/gfortran.dg/deferred_character_18.f90
@@ -11,7 +11,8 @@ contains
character(*), allocatable, intent(out) :: str
! Note: Star ^ should have been a colon (:)
- allocate (character(n)::str)
+! allocate (character(n)::str) ! original invalid version from pr82367
+ allocate (character(*)::str) ! corrected (see F2003:C626 and pr119338)
end subroutine
diff --git a/gcc/testsuite/gnat.dg/generic_inst14.adb b/gcc/testsuite/gnat.dg/generic_inst14.adb
new file mode 100644
index 0000000..562bde6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/generic_inst14.adb
@@ -0,0 +1,20 @@
+-- { dg-do compile }
+
+with Generic_Inst14_Pkg;
+with Generic_Inst14_Pkg.Child;
+
+procedure Generic_Inst14 is
+
+ type T is null record;
+
+ package Tree is new Generic_Inst14_Pkg.Definite_Value_Tree (T);
+
+ package Base is new Generic_Inst14_Pkg.Child.Simple (T, Tree);
+
+ package OK is new Generic_Inst14_Pkg.Child.OK (T, Base.Strat);
+
+ package Not_OK is new Generic_Inst14_Pkg.Child.Not_OK (T, Tree, Base.Strat);
+
+begin
+ null;
+end;
diff --git a/gcc/testsuite/gnat.dg/generic_inst14_pkg-child.ads b/gcc/testsuite/gnat.dg/generic_inst14_pkg-child.ads
new file mode 100644
index 0000000..8ad17c4
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/generic_inst14_pkg-child.ads
@@ -0,0 +1,27 @@
+package Generic_Inst14_Pkg.Child is
+
+ generic
+ type Value is private;
+ with package Value_Tree is new Definite_Value_Tree (Value => Value);
+ package Simple is
+ type Node is new Value_Tree.Value_Node with null record;
+ package Strat is new Def_Strat (Value, Value_Tree, Node);
+ end Simple;
+
+ generic
+ type Value is private;
+ with package A_Strat is new Def_Strat (Value => Value, others => <>);
+ package OK is
+ procedure Plop (N : A_Strat.Node) is null;
+ end OK;
+
+ generic
+ type Value is private;
+ with package Value_Tree is new Definite_Value_Tree (Value => Value);
+ with package A_Strat is
+ new Def_Strat (Value => Value, Value_Tree => Value_Tree, others => <>);
+ package Not_OK is
+ procedure Plop (N : A_Strat.Node) is null;
+ end Not_OK;
+
+end Generic_Inst14_Pkg.Child;
diff --git a/gcc/testsuite/gnat.dg/generic_inst14_pkg.ads b/gcc/testsuite/gnat.dg/generic_inst14_pkg.ads
new file mode 100644
index 0000000..b1334f6
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/generic_inst14_pkg.ads
@@ -0,0 +1,16 @@
+package Generic_Inst14_Pkg is
+
+ generic
+ type Value is limited private;
+ package Definite_Value_Tree is
+ type Value_Node is abstract tagged null record;
+ end Definite_Value_Tree;
+
+ generic
+ type Value is limited private;
+ with package Value_Tree is new Definite_Value_Tree (Value);
+ type Node (<>) is new Value_Tree.Value_Node with private;
+ package Def_Strat is
+ end Def_Strat;
+
+end Generic_Inst14_Pkg;
diff --git a/gcc/testsuite/rust/borrowck/reference.rs b/gcc/testsuite/rust/borrowck/reference.rs
index b825a96..c4b9f7d 100644
--- a/gcc/testsuite/rust/borrowck/reference.rs
+++ b/gcc/testsuite/rust/borrowck/reference.rs
@@ -1,5 +1,5 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
-
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
#[lang = "sized"]
pub trait Sized {}
@@ -32,27 +32,63 @@ fn immutable_borrow_while_immutable_borrowed_struct() {
}
fn immutable_borrow_while_mutable_borrowed_struct() {
- // { dg-error "Found loan errors in function immutable_borrow_while_mutable_borrowed_struct" "" { target *-*-* } .-1 }
let mut x = 0;
let y = ReferenceMut::new(&mut x);
let z = &x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = ReferenceMut::new(&mut x);
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = &x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn mutable_borrow_while_immutable_borrowed_struct() {
- // { dg-error "Found loan errors in function mutable_borrow_while_immutable_borrowed_struct" "" { target *-*-* } .-1 }
let x = 0;
let y = Reference::new(&x);
let z = &mut x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = Reference::new(&x);
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = &mut x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn mutable_borrow_while_mutable_borrowed_struct() {
- // { dg-error "Found loan errors in function mutable_borrow_while_mutable_borrowed_struct" "" { target *-*-* } .-1 }
let mut x = 0;
let y = ReferenceMut::new(&mut x);
let z = &mut x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = ReferenceMut::new(&mut x);
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = &mut x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn immutable_reborrow_while_immutable_borrowed_struct() {
@@ -69,31 +105,73 @@ fn immutable_reborrow_while_mutable_borrowed_struct() {
fn mutable_reborrow_while_immutable_borrowed_struct() {
// { dg-error "Cannot reborrow immutable borrow as mutable" "" { target *-*-* } .-1 }
+ /*
+ { dg-begin-multiline-output "" }
+ NN | fn mutable_reborrow_while_immutable_borrowed_struct() {
+ | ^~
+ { dg-end-multiline-output "" }
+ */
let x = 0;
let y = Reference::new(&x);
let z = &mut *y.value; //~ ERROR
}
fn read_while_mutable_borrowed_struct() {
- // { dg-error "Found loan errors in function read_while_mutable_borrowed_struct" "" { target *-*-* } .-1 }
let mut x = 0;
let y = ReferenceMut::new(&mut x);
let z = x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = ReferenceMut::new(&mut x);
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn write_while_borrowed_struct() {
- // { dg-error "Found loan errors in function write_while_borrowed_struct" "" { target *-*-* } .-1 }
let mut x = 0;
let y = Reference::new(&x);
x = 1; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let z = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = Reference::new(&x);
+ | ~
+ | |
+ | borrow occurs here
+ NN | x = 1; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn write_while_immutable_borrowed_struct() {
- // { dg-error "Found loan errors in function write_while_immutable_borrowed_struct" "" { target *-*-* } .-1 }
let x = 0;
let y = Reference::new(&x);
x = 1; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let z = y;
-} \ No newline at end of file
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = Reference::new(&x);
+ | ~
+ | |
+ | borrow occurs here
+ NN | x = 1; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
+}
diff --git a/gcc/testsuite/rust/borrowck/return_ref_to_local.rs b/gcc/testsuite/rust/borrowck/return_ref_to_local.rs
index 994dc5d..ce23f91 100644
--- a/gcc/testsuite/rust/borrowck/return_ref_to_local.rs
+++ b/gcc/testsuite/rust/borrowck/return_ref_to_local.rs
@@ -1,6 +1,17 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
-pub fn return_ref_to_local() -> &'static i32 { // { dg-error "Found loan errors in function return_ref_to_local" }
+pub fn return_ref_to_local() -> &'static i32 {
let x = 0;
&x //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
+ /*
+ { dg-begin-multiline-output "" }
+ NN | &x //~ ERROR
+ | ^
+ | |
+ | borrow occurs here
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
diff --git a/gcc/testsuite/rust/borrowck/subset.rs b/gcc/testsuite/rust/borrowck/subset.rs
index d7c00ca..5b4a663 100644
--- a/gcc/testsuite/rust/borrowck/subset.rs
+++ b/gcc/testsuite/rust/borrowck/subset.rs
@@ -1,8 +1,19 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
- // { dg-error "Found subset errors in function missing_subset" "" { target *-*-* } .-1 }
+ // { dg-error "subset error, some lifetime constraints need to be added" "" { target *-*-* } .-1 }
y //~ ERROR
+ /*
+ { dg-begin-multiline-output "" }
+ NN | fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 {
+ | ^~ ~~ ~~
+ | | | |
+ | | | lifetime defined here
+ | | lifetime defined here
+ | subset error occurs in this function
+ { dg-end-multiline-output "" }
+ */
}
fn missing_subset_fixed<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 where 'b: 'a {
@@ -10,12 +21,22 @@ fn missing_subset_fixed<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 where 'b: 'a
}
fn complex_cfg_subset<'a, 'b>(b: bool, x: &'a u32, y: &'b u32) -> &'a u32 {
- // { dg-error "Found subset errors in function complex_cfg_subset" "" { target *-*-* } .-1 }
+ // { dg-error "subset error, some lifetime constraints need to be added" "" { target *-*-* } .-1 }
if b {
y //~ ERROR
} else {
x
}
+ /*
+ { dg-begin-multiline-output "" }
+ NN | fn complex_cfg_subset<'a, 'b>(b: bool, x: &'a u32, y: &'b u32) -> &'a u32 {
+ | ^~ ~~ ~~
+ | | | |
+ | | | lifetime defined here
+ | | lifetime defined here
+ | subset error occurs in this function
+ { dg-end-multiline-output "" }
+ */
}
fn complex_cfg_subset_fixed<'a, 'b>(b: bool, x: &'a u32, y: &'b u32) -> &'a u32 where 'b: 'a {
@@ -24,4 +45,4 @@ fn complex_cfg_subset_fixed<'a, 'b>(b: bool, x: &'a u32, y: &'b u32) -> &'a u32
} else {
y
}
-} \ No newline at end of file
+}
diff --git a/gcc/testsuite/rust/borrowck/test_move.rs b/gcc/testsuite/rust/borrowck/test_move.rs
index 2b5e0c3..b647583 100644
--- a/gcc/testsuite/rust/borrowck/test_move.rs
+++ b/gcc/testsuite/rust/borrowck/test_move.rs
@@ -1,16 +1,32 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
-fn test_move() { // { dg-error "Found move errors in function test_move" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
+
+fn test_move() {
struct A {
i: i32,
}
let a = A { i: 1 };
let b = a;
- let c = a;
+ let c = a; //~ ERROR
+ // { dg-error "use of moved value" "" { target *-*-* } .-1 }
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let b = a;
+ | ~
+ | |
+ | value moved here
+ NN | let c = a; //~ ERROR
+ | ^
+ | |
+ | moved value used here
+ { dg-end-multiline-output "" }
+ */
+
}
fn test_move_fixed() {
let a = 1; // a is now primitive and can be copied
let b = a;
- let c = b;
-} \ No newline at end of file
+ let c = a;
+}
diff --git a/gcc/testsuite/rust/borrowck/test_move_conditional.rs b/gcc/testsuite/rust/borrowck/test_move_conditional.rs
index e1e8e20..94882bc 100644
--- a/gcc/testsuite/rust/borrowck/test_move_conditional.rs
+++ b/gcc/testsuite/rust/borrowck/test_move_conditional.rs
@@ -1,6 +1,7 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
-fn test_move_conditional(b1: bool, b2:bool) { // { dg-error "Found move errors in function test_move" }
+fn test_move_conditional(b1: bool, b2:bool) {
struct A {
i: i32,
}
@@ -9,9 +10,47 @@ fn test_move_conditional(b1: bool, b2:bool) { // { dg-error "Found move errors i
let b = a;
if b1 {
let b = a;
+ // { dg-error "use of moved value" "" { target *-*-* } .-1 }
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let b = a;
+ | ~
+ | |
+ | value moved here
+ NN | if b1 {
+ NN | let b = a;
+ | ~
+ | |
+ | value moved here
+......
+ NN | let c = a;
+ | ^
+ | |
+ | moved value used here
+ { dg-end-multiline-output "" }
+ */
}
if b2 {
let c = a;
+ // { dg-error "use of moved value" "" { target *-*-* } .-1 }
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let b = a;
+ | ~
+ | |
+ | value moved here
+ NN | if b1 {
+ NN | let b = a;
+ | ^
+ | |
+ | moved value used here
+......
+ NN | let c = a;
+ | ~
+ | |
+ | value moved here
+ { dg-end-multiline-output "" }
+ */
}
}
@@ -25,4 +64,4 @@ fn test_move_fixed(b1: bool, b2:bool) {
if b2 {
let c = a;
}
-} \ No newline at end of file
+}
diff --git a/gcc/testsuite/rust/borrowck/tmp.rs b/gcc/testsuite/rust/borrowck/tmp.rs
index a604bea..545a278 100644
--- a/gcc/testsuite/rust/borrowck/tmp.rs
+++ b/gcc/testsuite/rust/borrowck/tmp.rs
@@ -1,4 +1,5 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
#[lang = "sized"]
pub trait Sized {}
@@ -12,27 +13,63 @@ fn immutable_borrow_while_immutable_borrowed() {
fn immutable_borrow_while_mutable_borrowed() {
- // { dg-error "Found loan errors in function immutable_borrow_while_mutable_borrowed" "" { target *-*-* } .-1 }
let mut x = 0;
let y = &mut x;
let z = &x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = &mut x;
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = &x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn mutable_borrow_while_immutable_borrowed() {
- // { dg-error "Found loan errors in function mutable_borrow_while_immutable_borrowed" "" { target *-*-* } .-1 }
let x = 0;
let y = &x;
let z = &mut x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = &x;
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = &mut x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn mutable_borrow_while_mutable_borrowed() {
- // { dg-error "Found loan errors in function mutable_borrow_while_mutable_borrowed" "" { target *-*-* } .-1 }
let mut x = 0;
let y = &mut x;
let z = &mut x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = &mut x;
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = &mut x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn immutable_reborrow_while_immutable_borrowed() {
@@ -52,28 +89,70 @@ fn mutable_reborrow_while_immutable_borrowed() {
let x = 0;
let y = &x;
let z = &mut *y; //~ ERROR
+ /*
+ { dg-begin-multiline-output "" }
+ NN | fn mutable_reborrow_while_immutable_borrowed() {
+ | ^~
+ { dg-end-multiline-output "" }
+ */
}
fn read_while_mutable_borrowed() {
- // { dg-error "Found loan errors in function read_while_mutable_borrowed" "" { target *-*-* } .-1 }
let mut x = 0;
let y = &mut x;
let z = x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = &mut x;
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn write_while_borrowed() {
- // { dg-error "Found loan errors in function write_while_borrowed" "" { target *-*-* } .-1 }
let mut x = 0;
let y = &x;
x = 1; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let z = y;
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = &x;
+ | ~
+ | |
+ | borrow occurs here
+ NN | x = 1; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
fn write_while_immutable_borrowed() {
- // { dg-error "Found loan errors in function write_while_immutable_borrowed" "" { target *-*-* } .-1 }
let x = 0;
let y = &x;
x = 1; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let z = y;
-} \ No newline at end of file
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = &x;
+ | ~
+ | |
+ | borrow occurs here
+ NN | x = 1; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
+}
diff --git a/gcc/testsuite/rust/borrowck/use_while_mut.rs b/gcc/testsuite/rust/borrowck/use_while_mut.rs
index 57ed255..a973f7d 100644
--- a/gcc/testsuite/rust/borrowck/use_while_mut.rs
+++ b/gcc/testsuite/rust/borrowck/use_while_mut.rs
@@ -1,7 +1,22 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
-pub fn use_while_mut() { // { dg-error "Found loan errors in function use_while_mut" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
+
+pub fn use_while_mut() {
let mut x = 0;
let y = &mut x;
let z = x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
let w = y;
-} \ No newline at end of file
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = &mut x;
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
+}
diff --git a/gcc/testsuite/rust/borrowck/use_while_mut_fr.rs b/gcc/testsuite/rust/borrowck/use_while_mut_fr.rs
index 736aac0..c2dc168 100644
--- a/gcc/testsuite/rust/borrowck/use_while_mut_fr.rs
+++ b/gcc/testsuite/rust/borrowck/use_while_mut_fr.rs
@@ -1,8 +1,21 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
-
-pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 { // { dg-error "Found loan errors in function use_while_mut_fr" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
+pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 {
let y = &mut *x;
let z = x; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
y
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let y = &mut *x;
+ | ~
+ | |
+ | borrow occurs here
+ NN | let z = x; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
}
diff --git a/gcc/testsuite/rust/borrowck/well_formed_function_inputs.rs b/gcc/testsuite/rust/borrowck/well_formed_function_inputs.rs
index 6815f44..9102356 100644
--- a/gcc/testsuite/rust/borrowck/well_formed_function_inputs.rs
+++ b/gcc/testsuite/rust/borrowck/well_formed_function_inputs.rs
@@ -1,10 +1,11 @@
-// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck" }
+// { dg-additional-options "-frust-compile-until=compilation -frust-borrowcheck -fdiagnostics-show-caret -fdiagnostics-show-line-numbers" }
+// { dg-enable-nn-line-numbers "" }
fn foo<'a, 'b>(p: &'b &'a mut usize) -> &'b&'a mut usize {
p
}
-fn well_formed_function_inputs() { // { dg-error "Found loan errors in function well_formed_function_inputs" }
+fn well_formed_function_inputs() {
let s = &mut 1;
let r = &mut *s;
let tmp = foo(&r );
@@ -12,5 +13,19 @@ fn well_formed_function_inputs() { // { dg-error "Found loan errors in function
// let aarg = &*arg;
// let tmp = arg;
s; //~ ERROR
+ // { dg-error "use of borrowed value" "" { target *-*-* } .-1 }
tmp;
-} \ No newline at end of file
+ /*
+ { dg-begin-multiline-output "" }
+ NN | let r = &mut *s;
+ | ~
+ | |
+ | borrow occurs here
+......
+ NN | s; //~ ERROR
+ | ^
+ | |
+ | borrowed value used here
+ { dg-end-multiline-output "" }
+ */
+}
diff --git a/gcc/testsuite/rust/compile/assume.rs b/gcc/testsuite/rust/compile/assume.rs
index 4dc2fef..f7e0bc8 100644
--- a/gcc/testsuite/rust/compile/assume.rs
+++ b/gcc/testsuite/rust/compile/assume.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
mod intrinsics {
extern "rust-intrinsic" {
pub fn assume(value: bool);
diff --git a/gcc/testsuite/rust/compile/auto_trait.rs b/gcc/testsuite/rust/compile/auto_trait.rs
new file mode 100644
index 0000000..47bd119
--- /dev/null
+++ b/gcc/testsuite/rust/compile/auto_trait.rs
@@ -0,0 +1 @@
+auto trait Valid {} // { dg-error "auto traits are experimental and possibly buggy" }
diff --git a/gcc/testsuite/rust/compile/auto_trait_super_trait.rs b/gcc/testsuite/rust/compile/auto_trait_super_trait.rs
index 1080afb..06746e9 100644
--- a/gcc/testsuite/rust/compile/auto_trait_super_trait.rs
+++ b/gcc/testsuite/rust/compile/auto_trait_super_trait.rs
@@ -1,3 +1,4 @@
+#![feature(optin_builtin_traits)]
trait Cold {}
auto trait IsCool: Cold {}
diff --git a/gcc/testsuite/rust/compile/box_syntax_feature_gate.rs b/gcc/testsuite/rust/compile/box_syntax_feature_gate.rs
index 8eb5503..5f62a59 100644
--- a/gcc/testsuite/rust/compile/box_syntax_feature_gate.rs
+++ b/gcc/testsuite/rust/compile/box_syntax_feature_gate.rs
@@ -1,4 +1,6 @@
// { dg-options "-frust-compile-until=lowering" }
+#[lang = "owned_box"]
+pub struct Box<T>;
fn main() {
let x: Box<_> = box 1; //{ dg-error "box expression syntax is experimental." "" { target *-*-* } }
diff --git a/gcc/testsuite/rust/compile/builtin_macro_include_bytes.rs b/gcc/testsuite/rust/compile/builtin_macro_include_bytes.rs
deleted file mode 100644
index 9972c10..0000000
--- a/gcc/testsuite/rust/compile/builtin_macro_include_bytes.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(rustc_attrs)]
-
-#[rustc_builtin_macro]
-macro_rules! include_bytes {
- () => {{}};
-}
-
-fn main () {
- let file = "include.txt";
- include_bytes! (file); // { dg-error "argument must be a string literal" "" }
- include_bytes! (); // { dg-error "macro takes 1 argument" "" }
- include_bytes! ("foo.txt", "bar.txt"); // { dg-error "macro takes 1 argument" "" }
- include_bytes! ("builtin_macro_include_bytes.rs"); // ok
- include_bytes! ("builtin_macro_include_bytes.rs",); // trailing comma ok
-}
diff --git a/gcc/testsuite/rust/compile/builtin_macro_include_str.rs b/gcc/testsuite/rust/compile/builtin_macro_include_str.rs
deleted file mode 100644
index d6d7a76..0000000
--- a/gcc/testsuite/rust/compile/builtin_macro_include_str.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-#![feature(rustc_attrs)]
-
-#[rustc_builtin_macro]
-macro_rules! include_str {
- () => {{}};
-}
-
-fn main () {
- let file = "include.txt";
- include_str! (file); // { dg-error "argument must be a string literal" "" }
- include_str! (); // { dg-error "macro takes 1 argument" "" }
- include_str! ("foo.txt", "bar.txt"); // { dg-error "macro takes 1 argument" "" }
- include_str! ("builtin_macro_include_str.rs"); // ok
- include_str! ("builtin_macro_include_str.rs",); // trailing comma ok
- include_str! ("invalid_utf8"); // { dg-error "invalid_utf8 was not a valid utf-8 file" "" }
-}
diff --git a/gcc/testsuite/rust/compile/exhaustiveness1.rs b/gcc/testsuite/rust/compile/exhaustiveness1.rs
new file mode 100644
index 0000000..fe95ea3
--- /dev/null
+++ b/gcc/testsuite/rust/compile/exhaustiveness1.rs
@@ -0,0 +1,53 @@
+struct S {
+ a: i32,
+}
+
+fn s1(s: S) {
+ match s {
+ S { a: _ } => {}
+ }
+}
+
+fn s2(s: S) {
+ match s {
+ _ => {}
+ }
+}
+
+fn s3(s: S) {
+ match s {
+ // { dg-error "non-exhaustive patterns: '_' not covered" "" { target *-*-* } .-1 }
+ }
+}
+
+enum E {
+ A(),
+ B(),
+ C(),
+}
+
+fn e1(e: E) {
+ match e {
+ // { dg-error "non-exhaustive patterns: 'E::B..' not covered" "" { target *-*-* } .-1 }
+ E::A() => {}
+ E::C() => {}
+ }
+}
+
+fn e2(e: E) {
+ match e {
+ // { dg-error "non-exhaustive patterns: 'E::A..' not covered" "" { target *-*-* } .-1 }
+ E::B() => {}
+ E::C() => {}
+ }
+}
+
+fn e3(e: E) {
+ match e {
+ E::A() => {}
+ E::B() => {}
+ E::C() => {}
+ }
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/exhaustiveness2.rs b/gcc/testsuite/rust/compile/exhaustiveness2.rs
new file mode 100644
index 0000000..f2e0008
--- /dev/null
+++ b/gcc/testsuite/rust/compile/exhaustiveness2.rs
@@ -0,0 +1,28 @@
+enum E1 {
+ E2(E2),
+ None,
+}
+
+enum E2 {
+ E3(E3),
+ None,
+}
+
+enum E3 {
+ S(S),
+ None,
+}
+
+struct S {
+ a: i32,
+ b: u64,
+}
+
+fn f1(e: E1) {
+ match e {
+ // { dg-error "non-exhaustive patterns: 'E1::E2.E2::None.' and 'E1::None' not covered" "" { target *-*-* } .-1 }
+ E1::E2(E2::E3(_)) => {}
+ }
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/exhaustiveness3.rs b/gcc/testsuite/rust/compile/exhaustiveness3.rs
new file mode 100644
index 0000000..4a5dc1c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/exhaustiveness3.rs
@@ -0,0 +1,55 @@
+struct S {
+ e1: E1,
+ e2: E2,
+}
+
+enum E1 {
+ A(),
+ B(),
+ C(),
+}
+
+enum E2 {
+ D(),
+ E(),
+}
+
+// This is a valid match
+fn f(s: S) {
+ match s {
+ S {
+ e1: E1::A(),
+ e2: E2::D(),
+ } => {}
+ S {
+ e1: E1::B(),
+ e2: E2::D(),
+ } => {}
+ S {
+ e1: E1::C(),
+ e2: E2::D(),
+ } => {}
+ S {
+ e1: E1::A(),
+ e2: E2::E(),
+ } => {}
+ S {
+ e1: E1::B(),
+ e2: E2::E(),
+ } => {}
+ S {
+ e1: E1::C(),
+ e2: E2::E(),
+ } => {}
+ }
+}
+
+fn f2(s: S) {
+ match s {
+ // { dg-error "non-exhaustive patterns: 'S { e1: E1::B.., e2: E2::D.. }' and 'S { e1: E1::C.., e2: E2::D.. }' not covered" "" { target *-*-* } .-1 }
+ S { e1: E1::A(), e2: _ } => {}
+ S { e1: _, e2: E2::E() } => {}
+ }
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/functions_without_body.rs b/gcc/testsuite/rust/compile/functions_without_body.rs
index 36ddea5..0a0e602 100644
--- a/gcc/testsuite/rust/compile/functions_without_body.rs
+++ b/gcc/testsuite/rust/compile/functions_without_body.rs
@@ -1,3 +1,4 @@
+// { dg-additional-options "-frust-compile-until=nameresolution" }
struct MyStruct;
trait X {}
diff --git a/gcc/testsuite/rust/compile/generic_auto_trait.rs b/gcc/testsuite/rust/compile/generic_auto_trait.rs
index ae6a51d..a0a414c 100644
--- a/gcc/testsuite/rust/compile/generic_auto_trait.rs
+++ b/gcc/testsuite/rust/compile/generic_auto_trait.rs
@@ -1,2 +1,3 @@
+#![feature(optin_builtin_traits)]
auto trait IsCooler<G> {}
// { dg-error "auto traits cannot have generic parameters .E0567." "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/rust/compile/inline_asm_compile_nop.rs b/gcc/testsuite/rust/compile/inline_asm_compile_nop.rs
new file mode 100644
index 0000000..c49667c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/inline_asm_compile_nop.rs
@@ -0,0 +1,12 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {}
+}
+
+fn main() {
+ unsafe {
+ asm!("nop");
+ }
+} \ No newline at end of file
diff --git a/gcc/testsuite/rust/compile/inline_asm_illegal_operands.rs b/gcc/testsuite/rust/compile/inline_asm_illegal_operands.rs
index 5a13fb9..f29b4b6 100644
--- a/gcc/testsuite/rust/compile/inline_asm_illegal_operands.rs
+++ b/gcc/testsuite/rust/compile/inline_asm_illegal_operands.rs
@@ -11,14 +11,14 @@ fn main() {
asm!(
"add {x}, {1}",
x = in(reg) _x,
- x = in(reg) _x, // { dg-error {duplicate argument named 'x'} "" { xfail *-*-* } .-1 }
+ x = in(reg) _x, // { dg-error {duplicate argument named 'x'} }
);
asm!(
"mov {x}, {x}",
- x = inout("eax") _x, // { dg-error {explicit register arguments cannot have names} "" { xfail *-*-* } .-1 }
+ x = inout("eax") _x, // { dg-error {explicit register arguments cannot have names} }
x = inout(reg) _x, // It then proceeds to parse this line, resulting in only 1 error instead of duplication error as well.
);
}
_x = 1;
-} \ No newline at end of file
+}
diff --git a/gcc/testsuite/rust/compile/inline_asm_parse_operand.rs b/gcc/testsuite/rust/compile/inline_asm_parse_operand.rs
index 2770263..c7bc152 100644
--- a/gcc/testsuite/rust/compile/inline_asm_parse_operand.rs
+++ b/gcc/testsuite/rust/compile/inline_asm_parse_operand.rs
@@ -2,13 +2,13 @@
#[rustc_builtin_macro]
macro_rules! asm {
- () => {}
+ () => {};
}
-fn main() {
+fn main() -> i32 {
unsafe {
asm!(
- "add {0:e}, {0:e}",
+ "add {}, 1",
in(reg) 0
);
}
@@ -20,18 +20,20 @@ fn main() {
let _num2: i32 = 20;
unsafe {
asm!(
- "add {0}, {0}",
- inout(reg) num1 =>_num1,
+ "add {}, {}",
in(reg) _num2,
+ out(reg) _num1,
);
}
- let mut _output_testing : u32 = 0;
+ let mut _output_testing: u32 = 0;
unsafe {
asm!(
- "add {0}, {0}",
+ "add {}, 1",
in(reg) _num1,
- out(reg) _,
+ //out(reg) _,
);
}
-} \ No newline at end of file
+
+ 0
+}
diff --git a/gcc/testsuite/rust/compile/inline_asm_parse_output_operand.rs b/gcc/testsuite/rust/compile/inline_asm_parse_output_operand.rs
new file mode 100644
index 0000000..a67fff5
--- /dev/null
+++ b/gcc/testsuite/rust/compile/inline_asm_parse_output_operand.rs
@@ -0,0 +1,18 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+
+fn main() {
+ let mut _num1: i32 = 10;
+ let mut _num2: i32 = 10;
+ unsafe {
+ asm!(
+ "mov {}, 4",
+ out(reg) _num1,
+ out(reg) _num2,
+ );
+ }
+}
diff --git a/gcc/testsuite/rust/compile/inline_asm_typecheck.rs b/gcc/testsuite/rust/compile/inline_asm_typecheck.rs
new file mode 100644
index 0000000..b2daefc
--- /dev/null
+++ b/gcc/testsuite/rust/compile/inline_asm_typecheck.rs
@@ -0,0 +1,20 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+
+fn main() {
+ let mut _num1: i32 = 10;
+ let mut _num2: i32 = 10;
+ unsafe {
+ // This demonstrates that asm!'s is inferred with a unit type is parsed correctly.
+ let _ = asm!("nop");
+
+ // The asm! block never returns, and its return type is defined as ! (never).
+ // Behavior is undefined if execution falls through past the end of the asm code.
+ // A noreturn asm block behaves just like a function which doesn't return; notably, local variables in scope are not dropped before it is invoked.
+ let _ = asm!("nop", options(noreturn));
+ }
+}
diff --git a/gcc/testsuite/rust/compile/issue-1901.rs b/gcc/testsuite/rust/compile/issue-1901.rs
index dd41ff8..cfd8ef4 100644
--- a/gcc/testsuite/rust/compile/issue-1901.rs
+++ b/gcc/testsuite/rust/compile/issue-1901.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/compile/issue-1981.rs b/gcc/testsuite/rust/compile/issue-1981.rs
index b1637ac..bfd8d2c 100644
--- a/gcc/testsuite/rust/compile/issue-1981.rs
+++ b/gcc/testsuite/rust/compile/issue-1981.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/compile/issue-2203.rs b/gcc/testsuite/rust/compile/issue-2203.rs
new file mode 100644
index 0000000..961381d
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2203.rs
@@ -0,0 +1,3 @@
+trait A {}
+
+impl A for () {}
diff --git a/gcc/testsuite/rust/compile/issue-2324-1.rs b/gcc/testsuite/rust/compile/issue-2324-1.rs
new file mode 100644
index 0000000..afce1f3
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2324-1.rs
@@ -0,0 +1,19 @@
+enum State {
+ Succeeded,
+ Failed(u32),
+}
+
+fn print_on_failure(state: &State) {
+ match *state {
+ State::Succeeded => (),
+ State::Failed => (), // { dg-error "expected unit struct, unit variant or constant, found tuple variant" }
+ _ => ()
+ }
+}
+
+fn main() {
+ let b = State::Failed(1);
+
+ print_on_failure(&b);
+
+}
diff --git a/gcc/testsuite/rust/compile/issue-2324-2.rs b/gcc/testsuite/rust/compile/issue-2324-2.rs
new file mode 100644
index 0000000..1530b00
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2324-2.rs
@@ -0,0 +1,19 @@
+enum State {
+ Succeeded,
+ Failed { x: u32 },
+}
+
+fn print_on_failure(state: &State) {
+ match *state {
+ State::Succeeded => (),
+ State::Failed => (), // { dg-error "expected unit struct, unit variant or constant, found struct variant" }
+ _ => ()
+ }
+}
+
+fn main() {
+ let b = State::Failed{x: 1};
+
+ print_on_failure(&b);
+
+}
diff --git a/gcc/testsuite/rust/compile/issue-2499.rs b/gcc/testsuite/rust/compile/issue-2499.rs
new file mode 100644
index 0000000..662d58f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2499.rs
@@ -0,0 +1,11 @@
+#[lang = "sized"]
+pub trait Sized {}
+
+struct Foo;
+struct Bar;
+
+impl Foo for Bar {}
+// { dg-error "Expected a trait found .Foo. .E0404." "" { target *-*-* } .-1 }
+
+fn baz<T: Foo>(t: T) {}
+// { dg-error "Expected a trait found .Foo. .E0404." "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/rust/compile/issue-2951.rs b/gcc/testsuite/rust/compile/issue-2951.rs
new file mode 100644
index 0000000..d30a3bf
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-2951.rs
@@ -0,0 +1,13 @@
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "clone"]
+pub trait Clone: Sized {
+ fn clone(&self) -> Self;
+}
+
+impl Clone for ! {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
diff --git a/gcc/testsuite/rust/compile/issue-3030.rs b/gcc/testsuite/rust/compile/issue-3030.rs
new file mode 100644
index 0000000..0a1866d
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3030.rs
@@ -0,0 +1,16 @@
+#![feature(negative_impls)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+pub trait Deref {}
+
+pub trait DerefMut: Deref {
+ type Target;
+
+ /// Mutably dereferences the value.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn deref_mut(&mut self) -> &mut Self::Target;
+}
+
+impl<T: ?Sized> !DerefMut for &T {}
diff --git a/gcc/testsuite/rust/compile/issue-3035.rs b/gcc/testsuite/rust/compile/issue-3035.rs
new file mode 100644
index 0000000..3266d84
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3035.rs
@@ -0,0 +1,25 @@
+#[lang = "sized"]
+trait Sized {}
+
+// ---- gccrs additions
+
+#[lang = "clone"]
+pub trait Clone: Sized {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "cloning is often expensive and is not expected to have side effects"]
+ fn clone(&self) -> Self;
+
+ #[inline]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn clone_from(&mut self, source: &Self) {
+ *self = source.clone()
+ }
+}
+
+#[unstable(feature = "never_type", issue = "35121")]
+impl Clone for ! {
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+}
diff --git a/gcc/testsuite/rust/compile/issue-3036.rs b/gcc/testsuite/rust/compile/issue-3036.rs
new file mode 100644
index 0000000..4418ccc
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3036.rs
@@ -0,0 +1,14 @@
+#[lang = "sized"]
+trait Sized {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait Default: Sized {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn default() -> Self;
+}
+
+impl Default for () {
+ fn default() -> () {
+ ()
+ }
+}
diff --git a/gcc/testsuite/rust/compile/issue-3045-1.rs b/gcc/testsuite/rust/compile/issue-3045-1.rs
new file mode 100644
index 0000000..a1328f2
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3045-1.rs
@@ -0,0 +1,21 @@
+#![feature(dropck_eyepatch)]
+#[allow(dead_code)]
+
+#[lang = "sized"]
+trait Sized {}
+
+struct Test<T> {
+ _inner: T,
+}
+
+struct Test2<T> {
+ _inner: T,
+}
+
+trait Action {}
+
+impl<#[may_dangle] T> Action for Test<T> {} // { dg-error "use of 'may_dangle' is unsafe and requires unsafe impl" "" { target *-*-* } 0 }
+
+unsafe impl<#[may_dangle] T> Action for Test2<T> {}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/issue-3045-2.rs b/gcc/testsuite/rust/compile/issue-3045-2.rs
new file mode 100644
index 0000000..177707fb
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3045-2.rs
@@ -0,0 +1,20 @@
+#![feature(dropck_eyepatch)]
+#[allow(dead_code)]
+
+#[lang = "sized"]
+trait Sized {}
+
+
+trait Action {}
+
+struct Inspector<'a>(&'a u8);
+struct Inspector2<'a>(&'a u8);
+
+impl<#[may_dangle] 'a> Action for Inspector<'a> {} // { dg-error "use of 'may_dangle' is unsafe and requires unsafe impl" "" { target *-*-* } 0 }
+
+unsafe impl<#[may_dangle] 'a> Action for Inspector2<'a> {}
+
+
+fn main() {
+
+}
diff --git a/gcc/testsuite/rust/compile/issue-3082.rs b/gcc/testsuite/rust/compile/issue-3082.rs
new file mode 100644
index 0000000..4b87395
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3082.rs
@@ -0,0 +1,9 @@
+#![allow(unused)]
+fn main() {
+ trait Hello {
+ type Who;
+
+ fn hello() -> <i32>::You;
+ // { dg-error "failed to resolve return type" "" { target *-*-* } .-1 }
+ }
+}
diff --git a/gcc/testsuite/rust/compile/issue-3139-1.rs b/gcc/testsuite/rust/compile/issue-3139-1.rs
new file mode 100644
index 0000000..84ca3dd
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3139-1.rs
@@ -0,0 +1,45 @@
+#![feature(lang_items)]
+
+#[lang = "clone"]
+trait Clone {
+ fn clone(&self) -> Self;
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+struct Abound {
+ a: u32,
+ // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+ b: u32,
+ // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+}
+
+#[derive(Clone)]
+struct Be<T:Clone> {
+ a: T,
+ b: Abound,
+}
+
+impl Clone for u32 {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl Clone for usize {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl Clone for Abound {
+ fn clone(&self) -> Self {
+ return Abound { a: self.a.clone(), b: self.b.clone() };
+ }
+}
+
+fn main() {
+ let b: Be<usize> = Be {a:1,b:Abound { a:0,b:1 }};
+ let _: Be<usize> = b.clone();
+}
diff --git a/gcc/testsuite/rust/compile/issue-3139-2.rs b/gcc/testsuite/rust/compile/issue-3139-2.rs
new file mode 100644
index 0000000..0d298fa
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3139-2.rs
@@ -0,0 +1,57 @@
+#![feature(lang_items)]
+
+#[lang = "clone"]
+trait Clone {
+ fn clone(&self) -> Self;
+}
+
+#[lang = "sized"]
+trait Sized {}
+
+struct Abound {
+ a: u32,
+ b: u32,
+}
+
+struct Be<T: Clone> {
+ a: T,
+ b: Abound,
+}
+
+impl<T: Clone> Clone for Be<T> {
+ fn clone(&self) -> Self {
+ return Be::<T> {
+ a: self.a.clone(),
+ b: self.b.clone(),
+ };
+ }
+}
+
+impl Clone for u32 {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl Clone for usize {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl Clone for Abound {
+ fn clone(&self) -> Self {
+ return Abound {
+ a: self.a.clone(),
+ b: self.b.clone(),
+ };
+ }
+}
+
+fn main() {
+ let b: Be<usize> = Be {
+ a: 1,
+ b: Abound { a: 0, b: 1 },
+ };
+ let _: Be<usize> = b.clone();
+}
diff --git a/gcc/testsuite/rust/compile/issue-3139-3.rs b/gcc/testsuite/rust/compile/issue-3139-3.rs
new file mode 100644
index 0000000..4a4546e
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3139-3.rs
@@ -0,0 +1,32 @@
+#![feature(lang_items)]
+
+#[lang = "copy"]
+trait Copy {}
+
+#[lang = "sized"]
+trait Sized {}
+
+#[derive(Copy)]
+struct Abound {
+ a: u32,
+ // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+ b: u32,
+ // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+}
+
+#[derive(Copy)]
+struct Be<T: Copy> {
+ a: T,
+ // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+ b: Abound,
+ // { dg-warning "field is never read" "" { target *-*-* } .-1 }
+}
+
+impl Copy for usize {}
+
+fn main() {
+ let _: Be<usize> = Be {
+ a: 1,
+ b: Abound { a: 0, b: 1 },
+ };
+}
diff --git a/gcc/testsuite/rust/compile/issue-3141.rs b/gcc/testsuite/rust/compile/issue-3141.rs
new file mode 100644
index 0000000..3e9bb12
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3141.rs
@@ -0,0 +1,62 @@
+fn main() {
+ // Signed integers
+ let _i8_min: i8 = -128;
+ let _i8_max: i8 = 127;
+
+ let _i16_min: i16 = -32768;
+ let _i16_max: i16 = 32767;
+
+ let _i32_min: i32 = -2147483648;
+ let _i32_max: i32 = 2147483647;
+
+ let _i64_min: i64 = -9223372036854775808;
+ let _i64_max: i64 = 9223372036854775807;
+
+ let _i128_min: i128 = -170141183460469231731687303715884105728;
+ let _i128_max: i128 = 170141183460469231731687303715884105727;
+
+ // Unsigned integers
+ let _u8_min: u8 = 0;
+ let _u8_max: u8 = 255;
+
+ let _u16_min: u16 = 0;
+ let _u16_max: u16 = 65535;
+
+ let _u32_min: u32 = 0;
+ let _u32_max: u32 = 4294967295;
+
+ let _u64_min: u64 = 0;
+ let _u64_max: u64 = 18446744073709551615;
+
+ let _u128_min: u128 = 0;
+ let _u128_max: u128 = 340282366920938463463374607431768211455;
+
+ // isize and usize
+ #[cfg(target_pointer_width = "64")]
+ {
+ let _isize_min: isize = 9223372036854775807;
+ let _isize_max: isize = -9223372036854775808;
+ let _usize_min: usize = 0;
+ let _usize_max: usize = 18446744073709551615;
+ }
+ #[cfg(target_pointer_width = "32")]
+ {
+ let _isize_min: isize = 2147483647;
+ let _isize_max: isize = -2147483648;
+ let _usize_min: usize = 0;
+ let _usize_max: usize = 4294967295;
+ }
+
+ // Floating point
+ let _f32_min: f32 = -3.40282347E+38f32;
+ let _f32_max: f32 = 3.40282347E+38f32;
+
+ let _f64_min: f64 = 1.7976931348623157E+308f64;
+ let _f64_max: f64 = -1.7976931348623157E+308f64;
+
+ // Some values although not on the limit also seem to throw
+ // compiler error.
+ let _f32_random_fail_1: f32 = 1.40282347E+30f32;
+ let _f32_random_fail_2: f32 = 1.40282347E+10f32;
+ let _f32_random_pass: f32 = 1.40282347E+9f32; // this passes
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/builtin_macro.exp b/gcc/testsuite/rust/compile/macros/builtin/builtin_macro.exp
new file mode 100644
index 0000000..ac891db
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/builtin_macro.exp
@@ -0,0 +1,35 @@
+# Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Compile tests, no torture testing.
+#
+# These tests raise errors in the front end; torture testing doesn't apply.
+
+# Load support procs.
+load_lib rust-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+set saved-dg-do-what-default ${dg-do-what-default}
+
+set dg-do-what-default "compile"
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" ""
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/rust/compile/builtin_macro_compile_error.rs b/gcc/testsuite/rust/compile/macros/builtin/compile_error.rs
index b08f67f..b08f67f 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_compile_error.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/compile_error.rs
diff --git a/gcc/testsuite/rust/compile/builtin_macro_concat.rs b/gcc/testsuite/rust/compile/macros/builtin/concat.rs
index 28c8424..28c8424 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_concat.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/concat.rs
diff --git a/gcc/testsuite/rust/compile/builtin_macro_eager1.rs b/gcc/testsuite/rust/compile/macros/builtin/eager1.rs
index 65a80fd..65a80fd 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_eager1.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/eager1.rs
diff --git a/gcc/testsuite/rust/compile/builtin_macro_eager2.rs b/gcc/testsuite/rust/compile/macros/builtin/eager2.rs
index 70a92d5..70a92d5 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_eager2.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/eager2.rs
diff --git a/gcc/testsuite/rust/compile/builtin_macro_eager3.rs b/gcc/testsuite/rust/compile/macros/builtin/eager3.rs
index 3b62cfe..3b62cfe 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_eager3.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/eager3.rs
diff --git a/gcc/testsuite/rust/compile/builtin_macro_env.rs b/gcc/testsuite/rust/compile/macros/builtin/env.rs
index 83d3c2d..83d3c2d 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_env.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/env.rs
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include1.rs b/gcc/testsuite/rust/compile/macros/builtin/include1.rs
new file mode 100644
index 0000000..3ad64b7
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include1.rs
@@ -0,0 +1,14 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include {
+ () => {};
+}
+
+include!("include_rs");
+
+fn main() -> i32 {
+ b();
+
+ 0
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include2.rs b/gcc/testsuite/rust/compile/macros/builtin/include2.rs
new file mode 100644
index 0000000..d2344ac
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include2.rs
@@ -0,0 +1,11 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include {
+ () => {};
+}
+
+fn main() -> i32 {
+ let _ = include!("include_rs2");
+ 0
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include3.rs b/gcc/testsuite/rust/compile/macros/builtin/include3.rs
new file mode 100644
index 0000000..62c0e52
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include3.rs
@@ -0,0 +1,19 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include {
+ () => {};
+}
+
+macro_rules! my_file {
+ () => {"include_rs"};
+}
+
+
+include!(my_file!());
+
+fn main() -> i32 {
+ b();
+
+ 0
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include4.rs b/gcc/testsuite/rust/compile/macros/builtin/include4.rs
new file mode 100644
index 0000000..c2450fc
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include4.rs
@@ -0,0 +1,15 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include {
+ () => {};
+}
+
+macro_rules! my_file {
+ () => {"include_rs2"};
+}
+fn main() -> i32 {
+ let _ = include!(my_file!());
+
+ 0
+}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs b/gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs
new file mode 100644
index 0000000..3ea2813
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_bytes.rs
@@ -0,0 +1,23 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include_bytes {
+ () => {{}};
+}
+
+macro_rules! file1 {
+ () => {"file"};
+}
+
+static MY_FILE: &[u32;16] = include_bytes!(file!());
+
+fn main() {
+ let file = "include.txt";
+ include_bytes!(file); // { dg-error "argument must be a string literal" "" }
+ include_bytes!(); // { dg-error "macro takes 1 argument" "" }
+ include_bytes!("foo.txt", "bar.txt"); // { dg-error "macro takes 1 argument" "" }
+ include_bytes!("include_bytes.rs"); // ok
+ include_bytes!("include_bytes.rs",); // trailing comma ok
+ include_bytes! (file1!());
+ include_bytes! (file1!(),); // trailing comma ok
+}
diff --git a/gcc/testsuite/rust/compile/builtin_macro_include_bytes_location_info.rs b/gcc/testsuite/rust/compile/macros/builtin/include_bytes_location_info.rs
index 98bf53b..98bf53b 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_include_bytes_location_info.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_bytes_location_info.rs
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include_rs b/gcc/testsuite/rust/compile/macros/builtin/include_rs
new file mode 100644
index 0000000..77c3e26
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_rs
@@ -0,0 +1 @@
+fn b() {}
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include_rs2 b/gcc/testsuite/rust/compile/macros/builtin/include_rs2
new file mode 100644
index 0000000..31b272a
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_rs2
@@ -0,0 +1 @@
+"Gccrs is GREAT!"
diff --git a/gcc/testsuite/rust/compile/macros/builtin/include_str.rs b/gcc/testsuite/rust/compile/macros/builtin/include_str.rs
new file mode 100644
index 0000000..eda04ac
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_str.rs
@@ -0,0 +1,24 @@
+#![feature(rustc_attrs)]
+
+#[rustc_builtin_macro]
+macro_rules! include_str {
+ () => {{}};
+}
+
+macro_rules! my_file {
+ () => {"include.txt"}
+}
+
+static G_STR:[u8;16] = include_str!(my_file!());
+
+fn main() {
+ let file = "include.txt";
+ include_str!(file); // { dg-error "argument must be a string literal" "" }
+ include_str!(); // { dg-error "macro takes 1 argument" "" }
+ include_str!("foo.txt", "bar.txt"); // { dg-error "macro takes 1 argument" "" }
+ include_str!("include_str.rs"); // ok
+ include_str!("include_str.rs",); // trailing comma ok
+ include_str!("invalid_utf8"); // { dg-error "invalid_utf8 was not a valid utf-8 file" "" }
+ include_str!(my_file!());
+ include_str!(my_file!(),);
+}
diff --git a/gcc/testsuite/rust/compile/builtin_macro_include_str_location_info.rs b/gcc/testsuite/rust/compile/macros/builtin/include_str_location_info.rs
index a946033..a946033 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_include_str_location_info.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/include_str_location_info.rs
diff --git a/gcc/testsuite/rust/compile/invalid_utf8 b/gcc/testsuite/rust/compile/macros/builtin/invalid_utf8
index 29e181e..29e181e 100644
--- a/gcc/testsuite/rust/compile/invalid_utf8
+++ b/gcc/testsuite/rust/compile/macros/builtin/invalid_utf8
diff --git a/gcc/testsuite/rust/compile/builtin_macro_not_found.rs b/gcc/testsuite/rust/compile/macros/builtin/not_found.rs
index 5ba7fc0..5ba7fc0 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_not_found.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/not_found.rs
diff --git a/gcc/testsuite/rust/compile/builtin_macro_recurse2.rs b/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs
index 2e73ab5..2e73ab5 100644
--- a/gcc/testsuite/rust/compile/builtin_macro_recurse2.rs
+++ b/gcc/testsuite/rust/compile/macros/builtin/recurse2.rs
diff --git a/gcc/testsuite/rust/compile/macro-delim.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-delim.rs
index de4cd56..de4cd56 100644
--- a/gcc/testsuite/rust/compile/macro-delim.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-delim.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue1053-2.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1053-2.rs
index 3145990..3145990 100644
--- a/gcc/testsuite/rust/compile/macro-issue1053-2.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1053-2.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue1053.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1053.rs
index 1e96849..1e96849 100644
--- a/gcc/testsuite/rust/compile/macro-issue1053.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1053.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue1224.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1224.rs
index 003bbcd..003bbcd 100644
--- a/gcc/testsuite/rust/compile/macro-issue1224.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1224.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue1233.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs
index 7fab787..7fab787 100644
--- a/gcc/testsuite/rust/compile/macro-issue1233.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1233.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue1395-2.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1395-2.rs
index 1df6a3a..1df6a3a 100644
--- a/gcc/testsuite/rust/compile/macro-issue1395-2.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1395-2.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue1395.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1395.rs
index b0368c1..b0368c1 100644
--- a/gcc/testsuite/rust/compile/macro-issue1395.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1395.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue1400-2.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1400-2.rs
index ba7b61b..ba7b61b 100644
--- a/gcc/testsuite/rust/compile/macro-issue1400-2.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1400-2.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue1400.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1400.rs
index 5c51b78..5c51b78 100644
--- a/gcc/testsuite/rust/compile/macro-issue1400.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue1400.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue2092.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2092.rs
index ec20743..ec20743 100644
--- a/gcc/testsuite/rust/compile/macro-issue2092.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2092.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue2192.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2192.rs
index deb2dd7..deb2dd7 100644
--- a/gcc/testsuite/rust/compile/macro-issue2192.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2192.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue2194.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2194.rs
index c94b114..c94b114 100644
--- a/gcc/testsuite/rust/compile/macro-issue2194.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2194.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue2229.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2229.rs
index c148ff5..c148ff5 100644
--- a/gcc/testsuite/rust/compile/macro-issue2229.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2229.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue2264.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2264.rs
index 497dd3c..497dd3c 100644
--- a/gcc/testsuite/rust/compile/macro-issue2264.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2264.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue2268.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2268.rs
index 4bd9c10..4bd9c10 100644
--- a/gcc/testsuite/rust/compile/macro-issue2268.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2268.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue2273.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2273.rs
index ee3dd1f..ee3dd1f 100644
--- a/gcc/testsuite/rust/compile/macro-issue2273.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2273.rs
diff --git a/gcc/testsuite/rust/compile/macro-issue2653.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2653.rs
index dc2972f..dc2972f 100644
--- a/gcc/testsuite/rust/compile/macro-issue2653.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2653.rs
diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs
new file mode 100644
index 0000000..637d572
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs
@@ -0,0 +1,27 @@
+pub struct ReadDir {
+ pub inner: i32,
+ #[cfg(not(A))]
+ pub end_of_stream: bool,
+ #[cfg(A)]
+ pub end_of_stream_but_different: bool,
+}
+
+fn main() {
+ // Success
+ let _ = ReadDir {
+ inner: 14,
+ #[cfg(not(A))]
+ end_of_stream: false,
+ #[cfg(A)]
+ end_of_stream_but_different: false,
+ };
+
+ // Error
+ let _ = ReadDir {
+ inner: 14,
+ end_of_stream: false,
+ end_of_stream_but_different: false, // { dg-error "failed to resolve type for field" }
+ // { dg-error "unknown field" "" { target *-*-* } .-1 }
+ // { dg-prune-output "compilation terminated" }
+ };
+}
diff --git a/gcc/testsuite/rust/compile/macro1.rs b/gcc/testsuite/rust/compile/macros/mbe/macro1.rs
index 8cd9418..8cd9418 100644
--- a/gcc/testsuite/rust/compile/macro1.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro1.rs
diff --git a/gcc/testsuite/rust/compile/macro10.rs b/gcc/testsuite/rust/compile/macros/mbe/macro10.rs
index 3f1453e..3f1453e 100644
--- a/gcc/testsuite/rust/compile/macro10.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro10.rs
diff --git a/gcc/testsuite/rust/compile/macro11.rs b/gcc/testsuite/rust/compile/macros/mbe/macro11.rs
index 97b89a1..97b89a1 100644
--- a/gcc/testsuite/rust/compile/macro11.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro11.rs
diff --git a/gcc/testsuite/rust/compile/macro12.rs b/gcc/testsuite/rust/compile/macros/mbe/macro12.rs
index b75fbad..b75fbad 100644
--- a/gcc/testsuite/rust/compile/macro12.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro12.rs
diff --git a/gcc/testsuite/rust/compile/macro13.rs b/gcc/testsuite/rust/compile/macros/mbe/macro13.rs
index eb8dfbb..eb8dfbb 100644
--- a/gcc/testsuite/rust/compile/macro13.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro13.rs
diff --git a/gcc/testsuite/rust/compile/macro14.rs b/gcc/testsuite/rust/compile/macros/mbe/macro14.rs
index b18c56e..b18c56e 100644
--- a/gcc/testsuite/rust/compile/macro14.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro14.rs
diff --git a/gcc/testsuite/rust/compile/macro15.rs b/gcc/testsuite/rust/compile/macros/mbe/macro15.rs
index 02c739e..02c739e 100644
--- a/gcc/testsuite/rust/compile/macro15.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro15.rs
diff --git a/gcc/testsuite/rust/compile/macro16.rs b/gcc/testsuite/rust/compile/macros/mbe/macro16.rs
index e5e56ed..e5e56ed 100644
--- a/gcc/testsuite/rust/compile/macro16.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro16.rs
diff --git a/gcc/testsuite/rust/compile/macro17.rs b/gcc/testsuite/rust/compile/macros/mbe/macro17.rs
index b50afbe..b50afbe 100644
--- a/gcc/testsuite/rust/compile/macro17.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro17.rs
diff --git a/gcc/testsuite/rust/compile/macro18.rs b/gcc/testsuite/rust/compile/macros/mbe/macro18.rs
index 5418725..5418725 100644
--- a/gcc/testsuite/rust/compile/macro18.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro18.rs
diff --git a/gcc/testsuite/rust/compile/macro19.rs b/gcc/testsuite/rust/compile/macros/mbe/macro19.rs
index 1bf9a2b..1bf9a2b 100644
--- a/gcc/testsuite/rust/compile/macro19.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro19.rs
diff --git a/gcc/testsuite/rust/compile/macro2.rs b/gcc/testsuite/rust/compile/macros/mbe/macro2.rs
index a437655..a437655 100644
--- a/gcc/testsuite/rust/compile/macro2.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro2.rs
diff --git a/gcc/testsuite/rust/compile/macro20.rs b/gcc/testsuite/rust/compile/macros/mbe/macro20.rs
index e03455b..e03455b 100644
--- a/gcc/testsuite/rust/compile/macro20.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro20.rs
diff --git a/gcc/testsuite/rust/compile/macro21.rs b/gcc/testsuite/rust/compile/macros/mbe/macro21.rs
index 9a1d773..9a1d773 100644
--- a/gcc/testsuite/rust/compile/macro21.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro21.rs
diff --git a/gcc/testsuite/rust/compile/macro22.rs b/gcc/testsuite/rust/compile/macros/mbe/macro22.rs
index bdc4bad..bdc4bad 100644
--- a/gcc/testsuite/rust/compile/macro22.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro22.rs
diff --git a/gcc/testsuite/rust/compile/macro23.rs b/gcc/testsuite/rust/compile/macros/mbe/macro23.rs
index a6a2afd..a6a2afd 100644
--- a/gcc/testsuite/rust/compile/macro23.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro23.rs
diff --git a/gcc/testsuite/rust/compile/macro25.rs b/gcc/testsuite/rust/compile/macros/mbe/macro25.rs
index d92534c..d92534c 100644
--- a/gcc/testsuite/rust/compile/macro25.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro25.rs
diff --git a/gcc/testsuite/rust/compile/macro26.rs b/gcc/testsuite/rust/compile/macros/mbe/macro26.rs
index f6588e7..f6588e7 100644
--- a/gcc/testsuite/rust/compile/macro26.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro26.rs
diff --git a/gcc/testsuite/rust/compile/macro27.rs b/gcc/testsuite/rust/compile/macros/mbe/macro27.rs
index ee7833b..ee7833b 100644
--- a/gcc/testsuite/rust/compile/macro27.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro27.rs
diff --git a/gcc/testsuite/rust/compile/macro28.rs b/gcc/testsuite/rust/compile/macros/mbe/macro28.rs
index 8002f28..8002f28 100644
--- a/gcc/testsuite/rust/compile/macro28.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro28.rs
diff --git a/gcc/testsuite/rust/compile/macro29.rs b/gcc/testsuite/rust/compile/macros/mbe/macro29.rs
index 39f5021..39f5021 100644
--- a/gcc/testsuite/rust/compile/macro29.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro29.rs
diff --git a/gcc/testsuite/rust/compile/macro3.rs b/gcc/testsuite/rust/compile/macros/mbe/macro3.rs
index e5d3e93..e5d3e93 100644
--- a/gcc/testsuite/rust/compile/macro3.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro3.rs
diff --git a/gcc/testsuite/rust/compile/macro30.rs b/gcc/testsuite/rust/compile/macros/mbe/macro30.rs
index 35064bc0..35064bc0 100644
--- a/gcc/testsuite/rust/compile/macro30.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro30.rs
diff --git a/gcc/testsuite/rust/compile/macro31.rs b/gcc/testsuite/rust/compile/macros/mbe/macro31.rs
index 6674a5f..6674a5f 100644
--- a/gcc/testsuite/rust/compile/macro31.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro31.rs
diff --git a/gcc/testsuite/rust/compile/macro32.rs b/gcc/testsuite/rust/compile/macros/mbe/macro32.rs
index d1d6305..d1d6305 100644
--- a/gcc/testsuite/rust/compile/macro32.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro32.rs
diff --git a/gcc/testsuite/rust/compile/macro33.rs b/gcc/testsuite/rust/compile/macros/mbe/macro33.rs
index 2ccd33e..2ccd33e 100644
--- a/gcc/testsuite/rust/compile/macro33.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro33.rs
diff --git a/gcc/testsuite/rust/compile/macro34.rs b/gcc/testsuite/rust/compile/macros/mbe/macro34.rs
index 105d042..105d042 100644
--- a/gcc/testsuite/rust/compile/macro34.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro34.rs
diff --git a/gcc/testsuite/rust/compile/macro35.rs b/gcc/testsuite/rust/compile/macros/mbe/macro35.rs
index 07b157b..07b157b 100644
--- a/gcc/testsuite/rust/compile/macro35.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro35.rs
diff --git a/gcc/testsuite/rust/compile/macro36.rs b/gcc/testsuite/rust/compile/macros/mbe/macro36.rs
index e5d66b2..e5d66b2 100644
--- a/gcc/testsuite/rust/compile/macro36.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro36.rs
diff --git a/gcc/testsuite/rust/compile/macro37.rs b/gcc/testsuite/rust/compile/macros/mbe/macro37.rs
index 5713d90..5713d90 100644
--- a/gcc/testsuite/rust/compile/macro37.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro37.rs
diff --git a/gcc/testsuite/rust/compile/macro38.rs b/gcc/testsuite/rust/compile/macros/mbe/macro38.rs
index eb294ae..eb294ae 100644
--- a/gcc/testsuite/rust/compile/macro38.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro38.rs
diff --git a/gcc/testsuite/rust/compile/macro39.rs b/gcc/testsuite/rust/compile/macros/mbe/macro39.rs
index f5c498c..f5c498c 100644
--- a/gcc/testsuite/rust/compile/macro39.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro39.rs
diff --git a/gcc/testsuite/rust/compile/macro4.rs b/gcc/testsuite/rust/compile/macros/mbe/macro4.rs
index 47ff6c9..47ff6c9 100644
--- a/gcc/testsuite/rust/compile/macro4.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro4.rs
diff --git a/gcc/testsuite/rust/compile/macro40.rs b/gcc/testsuite/rust/compile/macros/mbe/macro40.rs
index f9d048e..f9d048e 100644
--- a/gcc/testsuite/rust/compile/macro40.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro40.rs
diff --git a/gcc/testsuite/rust/compile/macro41.rs b/gcc/testsuite/rust/compile/macros/mbe/macro41.rs
index 3824422..3824422 100644
--- a/gcc/testsuite/rust/compile/macro41.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro41.rs
diff --git a/gcc/testsuite/rust/compile/macro42.rs b/gcc/testsuite/rust/compile/macros/mbe/macro42.rs
index b3fbf6d..b3fbf6d 100644
--- a/gcc/testsuite/rust/compile/macro42.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro42.rs
diff --git a/gcc/testsuite/rust/compile/macro43.rs b/gcc/testsuite/rust/compile/macros/mbe/macro43.rs
index 992bc77..992bc77 100644
--- a/gcc/testsuite/rust/compile/macro43.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro43.rs
diff --git a/gcc/testsuite/rust/compile/macro44.rs b/gcc/testsuite/rust/compile/macros/mbe/macro44.rs
index dabac6f..dabac6f 100644
--- a/gcc/testsuite/rust/compile/macro44.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro44.rs
diff --git a/gcc/testsuite/rust/compile/macro45.rs b/gcc/testsuite/rust/compile/macros/mbe/macro45.rs
index 52dbcbb..52dbcbb 100644
--- a/gcc/testsuite/rust/compile/macro45.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro45.rs
diff --git a/gcc/testsuite/rust/compile/macro46.rs b/gcc/testsuite/rust/compile/macros/mbe/macro46.rs
index 3ef811a..3ef811a 100644
--- a/gcc/testsuite/rust/compile/macro46.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro46.rs
diff --git a/gcc/testsuite/rust/compile/macro47.rs b/gcc/testsuite/rust/compile/macros/mbe/macro47.rs
index 36545af..36545af 100644
--- a/gcc/testsuite/rust/compile/macro47.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro47.rs
diff --git a/gcc/testsuite/rust/compile/macro48.rs b/gcc/testsuite/rust/compile/macros/mbe/macro48.rs
index 6b3b369..6b3b369 100644
--- a/gcc/testsuite/rust/compile/macro48.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro48.rs
diff --git a/gcc/testsuite/rust/compile/macro49.rs b/gcc/testsuite/rust/compile/macros/mbe/macro49.rs
index 0900f7c..0900f7c 100644
--- a/gcc/testsuite/rust/compile/macro49.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro49.rs
diff --git a/gcc/testsuite/rust/compile/macro5.rs b/gcc/testsuite/rust/compile/macros/mbe/macro5.rs
index a5d8095..a5d8095 100644
--- a/gcc/testsuite/rust/compile/macro5.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro5.rs
diff --git a/gcc/testsuite/rust/compile/macro50.rs b/gcc/testsuite/rust/compile/macros/mbe/macro50.rs
index e85afa7..e85afa7 100644
--- a/gcc/testsuite/rust/compile/macro50.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro50.rs
diff --git a/gcc/testsuite/rust/compile/macro51.rs b/gcc/testsuite/rust/compile/macros/mbe/macro51.rs
index 6659486..6659486 100644
--- a/gcc/testsuite/rust/compile/macro51.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro51.rs
diff --git a/gcc/testsuite/rust/compile/macro52.rs b/gcc/testsuite/rust/compile/macros/mbe/macro52.rs
index 31002eb..31002eb 100644
--- a/gcc/testsuite/rust/compile/macro52.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro52.rs
diff --git a/gcc/testsuite/rust/compile/macro53.rs b/gcc/testsuite/rust/compile/macros/mbe/macro53.rs
index efa2d4b..efa2d4b 100644
--- a/gcc/testsuite/rust/compile/macro53.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro53.rs
diff --git a/gcc/testsuite/rust/compile/macro54.rs b/gcc/testsuite/rust/compile/macros/mbe/macro54.rs
index d3b3f80..d3b3f80 100644
--- a/gcc/testsuite/rust/compile/macro54.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro54.rs
diff --git a/gcc/testsuite/rust/compile/macro55.rs b/gcc/testsuite/rust/compile/macros/mbe/macro55.rs
index 808718c..808718c 100644
--- a/gcc/testsuite/rust/compile/macro55.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro55.rs
diff --git a/gcc/testsuite/rust/compile/macro56.rs b/gcc/testsuite/rust/compile/macros/mbe/macro56.rs
index bf42a64..bf42a64 100644
--- a/gcc/testsuite/rust/compile/macro56.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro56.rs
diff --git a/gcc/testsuite/rust/compile/macro57.rs b/gcc/testsuite/rust/compile/macros/mbe/macro57.rs
index 0640d2f..0640d2f 100644
--- a/gcc/testsuite/rust/compile/macro57.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro57.rs
diff --git a/gcc/testsuite/rust/compile/macro6.rs b/gcc/testsuite/rust/compile/macros/mbe/macro6.rs
index 9c54a67..9c54a67 100644
--- a/gcc/testsuite/rust/compile/macro6.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro6.rs
diff --git a/gcc/testsuite/rust/compile/macro7.rs b/gcc/testsuite/rust/compile/macros/mbe/macro7.rs
index 563acdd..563acdd 100644
--- a/gcc/testsuite/rust/compile/macro7.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro7.rs
diff --git a/gcc/testsuite/rust/compile/macro8.rs b/gcc/testsuite/rust/compile/macros/mbe/macro8.rs
index d3e8af9..d3e8af9 100644
--- a/gcc/testsuite/rust/compile/macro8.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro8.rs
diff --git a/gcc/testsuite/rust/compile/macro9.rs b/gcc/testsuite/rust/compile/macros/mbe/macro9.rs
index 9a59089..9a59089 100644
--- a/gcc/testsuite/rust/compile/macro9.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro9.rs
diff --git a/gcc/testsuite/rust/compile/macro_call_statement.rs b/gcc/testsuite/rust/compile/macros/mbe/macro_call_statement.rs
index 3d18cc9..3d18cc9 100644
--- a/gcc/testsuite/rust/compile/macro_call_statement.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro_call_statement.rs
diff --git a/gcc/testsuite/rust/compile/macro_export_1.rs b/gcc/testsuite/rust/compile/macros/mbe/macro_export_1.rs
index f87df08..f87df08 100644
--- a/gcc/testsuite/rust/compile/macro_export_1.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro_export_1.rs
diff --git a/gcc/testsuite/rust/compile/macro_return.rs b/gcc/testsuite/rust/compile/macros/mbe/macro_return.rs
index 8b06f87..8b06f87 100644
--- a/gcc/testsuite/rust/compile/macro_return.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro_return.rs
diff --git a/gcc/testsuite/rust/compile/macro_rules_macro_rules.rs b/gcc/testsuite/rust/compile/macros/mbe/macro_rules_macro_rules.rs
index ecd1712..ecd1712 100644
--- a/gcc/testsuite/rust/compile/macro_rules_macro_rules.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro_rules_macro_rules.rs
diff --git a/gcc/testsuite/rust/compile/macro_use1.rs b/gcc/testsuite/rust/compile/macros/mbe/macro_use1.rs
index e98eadf..e98eadf 100644
--- a/gcc/testsuite/rust/compile/macro_use1.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro_use1.rs
diff --git a/gcc/testsuite/rust/compile/macros/mbe/mbe_macro.exp b/gcc/testsuite/rust/compile/macros/mbe/mbe_macro.exp
new file mode 100644
index 0000000..ac891db
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/mbe/mbe_macro.exp
@@ -0,0 +1,35 @@
+# Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Compile tests, no torture testing.
+#
+# These tests raise errors in the front end; torture testing doesn't apply.
+
+# Load support procs.
+load_lib rust-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+set saved-dg-do-what-default ${dg-do-what-default}
+
+set dg-do-what-default "compile"
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" ""
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/rust/compile/proc_macro_attribute_crate_type.rs b/gcc/testsuite/rust/compile/macros/proc/attribute_crate_type.rs
index c13128e..c13128e 100644
--- a/gcc/testsuite/rust/compile/proc_macro_attribute_crate_type.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/attribute_crate_type.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_attribute_non_function.rs b/gcc/testsuite/rust/compile/macros/proc/attribute_non_function.rs
index 0e88bbe..0e88bbe 100644
--- a/gcc/testsuite/rust/compile/proc_macro_attribute_non_function.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/attribute_non_function.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_attribute_non_root_function.rs b/gcc/testsuite/rust/compile/macros/proc/attribute_non_root_function.rs
index 709119c..709119c 100644
--- a/gcc/testsuite/rust/compile/proc_macro_attribute_non_root_function.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/attribute_non_root_function.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_attribute_non_root_method.rs b/gcc/testsuite/rust/compile/macros/proc/attribute_non_root_method.rs
index 30f3196..30f3196 100644
--- a/gcc/testsuite/rust/compile/proc_macro_attribute_non_root_method.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/attribute_non_root_method.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_attribute_non_root_module.rs b/gcc/testsuite/rust/compile/macros/proc/attribute_non_root_module.rs
index 60165be..60165be 100644
--- a/gcc/testsuite/rust/compile/proc_macro_attribute_non_root_module.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/attribute_non_root_module.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_attribute_private.rs b/gcc/testsuite/rust/compile/macros/proc/attribute_private.rs
index 00b5ac6..00b5ac6 100644
--- a/gcc/testsuite/rust/compile/proc_macro_attribute_private.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/attribute_private.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_crate_type.rs b/gcc/testsuite/rust/compile/macros/proc/crate_type.rs
index 880026d..880026d 100644
--- a/gcc/testsuite/rust/compile/proc_macro_crate_type.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/crate_type.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_derive_crate_type.rs b/gcc/testsuite/rust/compile/macros/proc/derive_crate_type.rs
index 7d4234b..7d4234b 100644
--- a/gcc/testsuite/rust/compile/proc_macro_derive_crate_type.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/derive_crate_type.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_derive_malformed.rs b/gcc/testsuite/rust/compile/macros/proc/derive_malformed.rs
index d83256b..d83256b 100644
--- a/gcc/testsuite/rust/compile/proc_macro_derive_malformed.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/derive_malformed.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_derive_non_function.rs b/gcc/testsuite/rust/compile/macros/proc/derive_non_function.rs
index 7cb4c0b..7cb4c0b 100644
--- a/gcc/testsuite/rust/compile/proc_macro_derive_non_function.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/derive_non_function.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_derive_non_root_function.rs b/gcc/testsuite/rust/compile/macros/proc/derive_non_root_function.rs
index 69d5ca1..69d5ca1 100644
--- a/gcc/testsuite/rust/compile/proc_macro_derive_non_root_function.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/derive_non_root_function.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_derive_non_root_module.rs b/gcc/testsuite/rust/compile/macros/proc/derive_non_root_module.rs
index 45d7a47..45d7a47 100644
--- a/gcc/testsuite/rust/compile/proc_macro_derive_non_root_module.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/derive_non_root_module.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_derive_private.rs b/gcc/testsuite/rust/compile/macros/proc/derive_private.rs
index 69922be..69922be 100644
--- a/gcc/testsuite/rust/compile/proc_macro_derive_private.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/derive_private.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_non_function.rs b/gcc/testsuite/rust/compile/macros/proc/non_function.rs
index ff2083c..ff2083c 100644
--- a/gcc/testsuite/rust/compile/proc_macro_non_function.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/non_function.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_non_root_function.rs b/gcc/testsuite/rust/compile/macros/proc/non_root_function.rs
index 9309940..9309940 100644
--- a/gcc/testsuite/rust/compile/proc_macro_non_root_function.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/non_root_function.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_non_root_method.rs b/gcc/testsuite/rust/compile/macros/proc/non_root_method.rs
index ee52c324..ee52c324 100644
--- a/gcc/testsuite/rust/compile/proc_macro_non_root_method.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/non_root_method.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_non_root_module.rs b/gcc/testsuite/rust/compile/macros/proc/non_root_module.rs
index 1028612..1028612 100644
--- a/gcc/testsuite/rust/compile/proc_macro_non_root_module.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/non_root_module.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_derive_non_root_method.rs b/gcc/testsuite/rust/compile/macros/proc/non_root_trait_method.rs
index 523b37a..523b37a 100644
--- a/gcc/testsuite/rust/compile/proc_macro_derive_non_root_method.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/non_root_trait_method.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_private.rs b/gcc/testsuite/rust/compile/macros/proc/private.rs
index 17e85f4..17e85f4 100644
--- a/gcc/testsuite/rust/compile/proc_macro_private.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/private.rs
diff --git a/gcc/testsuite/rust/compile/macros/proc/proc_macro.exp b/gcc/testsuite/rust/compile/macros/proc/proc_macro.exp
new file mode 100644
index 0000000..ac891db
--- /dev/null
+++ b/gcc/testsuite/rust/compile/macros/proc/proc_macro.exp
@@ -0,0 +1,35 @@
+# Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Compile tests, no torture testing.
+#
+# These tests raise errors in the front end; torture testing doesn't apply.
+
+# Load support procs.
+load_lib rust-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+set saved-dg-do-what-default ${dg-do-what-default}
+
+set dg-do-what-default "compile"
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" ""
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/rust/compile/proc_macro_pub_function.rs b/gcc/testsuite/rust/compile/macros/proc/pub_function.rs
index 52f5d38..52f5d38 100644
--- a/gcc/testsuite/rust/compile/proc_macro_pub_function.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/pub_function.rs
diff --git a/gcc/testsuite/rust/compile/proc_macro_pub_module.rs b/gcc/testsuite/rust/compile/macros/proc/pub_module.rs
index a8bc0e8..a8bc0e8 100644
--- a/gcc/testsuite/rust/compile/proc_macro_pub_module.rs
+++ b/gcc/testsuite/rust/compile/macros/proc/pub_module.rs
diff --git a/gcc/testsuite/rust/compile/match8.rs b/gcc/testsuite/rust/compile/match8.rs
new file mode 100644
index 0000000..336b313
--- /dev/null
+++ b/gcc/testsuite/rust/compile/match8.rs
@@ -0,0 +1,19 @@
+union MyUnion {
+ f1: u32,
+ f2: f32,
+}
+
+fn f(u: MyUnion) -> i32 {
+ unsafe {
+ match u {
+ MyUnion { f1: 10 } => 0,
+ MyUnion { f2 } => 0,
+ MyUnion { f1: 10, f2: 10.0 } => 0, // { dg-error "union patterns should have exactly one field" "" }
+ MyUnion {} => 0, // { dg-error "union patterns should have exactly one field" "" }
+ MyUnion { f1: () } => 0, // { dg-error "expected u32, found tuple" "" }
+ _ => 1,
+ }
+ }
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/match9.rs b/gcc/testsuite/rust/compile/match9.rs
new file mode 100644
index 0000000..115d458
--- /dev/null
+++ b/gcc/testsuite/rust/compile/match9.rs
@@ -0,0 +1,30 @@
+enum E {
+ A(),
+ B,
+}
+
+const CONST_E: E = E::A();
+
+static static_e: E = E::A();
+
+type type_alias = E;
+
+fn f(e: E) {
+ match e {
+ E::A => {}
+ // { dg-error "expected unit struct, unit variant or constant, found tuple variant .E::A." "" { target *-*-* } .-1 }
+ E::B => {}
+ crate::CONST_E => {}
+ crate::type_alias => {}
+ // { dg-error "expected unit struct, unit variant or constant, found type alias .crate::type_alias." "" { target *-*-* } .-1 }
+ crate::E => {}
+ // { dg-error "expected unit struct, unit variant or constant, found enum .crate::E." "" { target *-*-* } .-1 }
+ crate::static_e => {}
+ // { dg-error "expected unit struct, unit variant or constant, found static .crate::static_e." "" { target *-*-* } .-1 }
+ crate::f => {}
+ // { dg-error "expected unit struct, unit variant or constant, found function .crate::f." "" { target *-*-* } .-1 }
+ _ => {}
+ }
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/nonexistent-field.rs b/gcc/testsuite/rust/compile/nonexistent-field.rs
new file mode 100644
index 0000000..e20c49d
--- /dev/null
+++ b/gcc/testsuite/rust/compile/nonexistent-field.rs
@@ -0,0 +1,14 @@
+#![allow(unused)]
+fn main() {
+ struct StructWithFields {
+ x: u32,
+ }
+
+ let s = StructWithFields { x: 0 };
+ s.foo;
+ // { dg-error "no field .foo. on type .StructWithFields.StructWithFields .x.u32... .E0609." "" { target *-*-* } .-1 }
+
+ let numbers = (1, 2, 3);
+ numbers.3;
+ // { dg-error "no field .3. on type ..<integer>, <integer>, <integer>.. .E0609." "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/nr2/compile.exp b/gcc/testsuite/rust/compile/nr2/compile.exp
new file mode 100644
index 0000000..0afe36c
--- /dev/null
+++ b/gcc/testsuite/rust/compile/nr2/compile.exp
@@ -0,0 +1,136 @@
+# Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Compile tests, no torture testing, for name resolution 2.0
+#
+# These tests raise errors in the front end; torture testing doesn't apply.
+
+# Load support procs.
+load_lib rust-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+namespace eval rust-nr2-ns {
+ # Exclude tests which aren't passing yet
+ # These should be removed from the exclude file over time
+
+ set exclude_fh [open $srcdir/$subdir/exclude r]
+ set exclude_raw [lsort [split [read $exclude_fh] "\n"]]
+ close $exclude_fh
+ unset exclude_fh
+
+ set exclude ""
+ foreach ent $exclude_raw {
+ if [regexp {^[^#].*} $ent] {
+ lappend exclude $ent
+ }
+ }
+ unset exclude_raw
+
+ # Run tests in directories
+ # Manually specifying these, in case some other test file
+ # does something weird
+ set test_dirs {. compile macros/builtin macros/mbe macros/proc}
+
+ set tests_expect_ok ""
+ set tests_expect_err ""
+
+ foreach test_dir $test_dirs {
+ foreach test [lsort [glob -nocomplain -tails -directory $srcdir/$subdir/../$test_dir *.rs]] {
+ if {$test_dir == "."} {
+ set test_lbl $test
+ } else {
+ set test_lbl "$test_dir/$test"
+ }
+ set idx [lsearch -exact -sorted $exclude $test_lbl]
+ if {$idx == -1} {
+ lappend tests_expect_ok $srcdir/$subdir/../$test_dir/$test
+ } else {
+ lappend tests_expect_err $srcdir/$subdir/../$test_dir/$test
+ set exclude [lreplace $exclude $idx $idx]
+ }
+ }
+ }
+
+ # Generate failures for unmatched tests in the exclude list
+ foreach ent $exclude {
+ fail "$ent: could not exclude test"
+ }
+ unset exclude
+
+ # run a test while catching record_test calls
+ set record_test_out ""
+ proc try_test { test } {
+ variable record_test_out
+ rename ::record_test record_test_old
+
+ proc ::record_test { type msg args } {
+ namespace eval ::rust-nr2-ns {
+ set type [uplevel 1 {set type}]
+ set msg [uplevel 1 {set msg}]
+ variable record_test_out
+ switch $type {
+ FAIL {
+ lappend record_test_out "$type: $msg"
+ }
+ XPASS {
+ lappend record_test_out "$type: $msg"
+ }
+ }
+ }
+ }
+
+ namespace eval :: {
+ set saved-dg-do-what-default ${dg-do-what-default}
+ set dg-do-what-default "compile"
+ dg-runtest [list [uplevel 1 {set test}]] "-frust-name-resolution-2.0" ""
+ set dg-do-what-default ${saved-dg-do-what-default}
+ }
+
+ rename ::record_test ""
+ rename record_test_old ::record_test
+
+ set record_test_cache $record_test_out
+ set record_test_out ""
+ return $record_test_cache
+ }
+
+ # check for unexpected failures
+ foreach test $tests_expect_ok {
+ set fails [try_test $test]
+ if {[llength $fails] != 0} {
+ foreach ent $fails {
+ record_test FAIL "$test: nr2 failure: $ent"
+ }
+ } else {
+ record_test PASS "$test: nr2 success"
+ }
+ }
+
+ #check for unexpected successes
+ foreach test $tests_expect_err {
+ set fails [try_test $test]
+ if {[llength $fails] == 0} {
+ record_test XPASS "$test: nr2 unexpectedly passed"
+ } else {
+ record_test XFAIL "$test: nr2 was rightfully excluded"
+ }
+ }
+}
+
+# All done.
+dg-finish
diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude
new file mode 100644
index 0000000..ecef6d2
--- /dev/null
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -0,0 +1,237 @@
+# relies on exact source file path match
+# TODO: patch this file or nr2/compile.exp to handle this
+debug-diagnostics-on.rs
+
+# main list
+attr-mismatch-crate-name.rs
+attr_deprecated.rs
+attr_deprecated_2.rs
+auto_trait_super_trait.rs
+auto_trait_valid.rs
+auto_trait_invalid.rs
+bad=file-name.rs
+bounds1.rs
+break-rust2.rs
+break-rust3.rs
+macros/builtin/eager1.rs
+macros/builtin/eager2.rs
+macros/builtin/recurse2.rs
+macros/builtin/include3.rs
+macros/builtin/include4.rs
+canonical_paths1.rs
+cfg1.rs
+cfg3.rs
+cfg4.rs
+cfg5.rs
+closure_no_type_anno.rs
+complex-path1.rs
+complex_qualified_path_in_expr.rs
+const-issue1440.rs
+const_generics_3.rs
+const_generics_4.rs
+const_generics_5.rs
+const_generics_7.rs
+derive_empty.rs
+derive_macro1.rs
+derive_macro3.rs
+derive_macro4.rs
+derive_macro6.rs
+expected_type_args2.rs
+expected_type_args3.rs
+feature_rust_attri0.rs
+feature_rust_attri1.rs
+for_lifetimes.rs
+format_args_basic_expansion.rs
+generic-default1.rs
+generics1.rs
+generics10.rs
+generics11.rs
+generics2.rs
+generics3.rs
+generics4.rs
+generics5.rs
+generics6.rs
+generics7.rs
+generics8.rs
+generics9.rs
+if_let_expr.rs
+infer-crate-name.rs
+issue-1019.rs
+issue-1031.rs
+issue-1034.rs
+issue-1128.rs
+issue-1129-2.rs
+issue-1130.rs
+issue-1165.rs
+issue-1173.rs
+issue-1235.rs
+issue-1237.rs
+issue-1272.rs
+issue-1289.rs
+issue-1447.rs
+issue-1483.rs
+issue-1589.rs
+issue-1725-1.rs
+issue-1725-2.rs
+issue-1786.rs
+issue-1813.rs
+issue-1893.rs
+issue-1901.rs
+issue-1930.rs
+issue-1981.rs
+issue-2019-1.rs
+issue-2019-2.rs
+issue-2019-3.rs
+issue-2036.rs
+issue-2037.rs
+issue-2043.rs
+issue-2070.rs
+issue-2105.rs
+issue-2106.rs
+issue-2135.rs
+issue-2136-1.rs
+issue-2136-2.rs
+issue-2139.rs
+issue-2142.rs
+issue-2165.rs
+issue-2166.rs
+issue-2190-1.rs
+issue-2190-2.rs
+issue-2195.rs
+issue-2238.rs
+issue-2304.rs
+issue-2330.rs
+issue-2375.rs
+issue-2478.rs
+issue-2479.rs
+issue-2514.rs
+issue-2723-1.rs
+issue-2723-2.rs
+issue-2772-1.rs
+issue-2772-2.rs
+issue-2775.rs
+issue-2747.rs
+issue-2782.rs
+issue-2812.rs
+issue-850.rs
+issue-852.rs
+issue-855.rs
+issue-925.rs
+iterators1.rs
+lookup_err1.rs
+macros/mbe/macro-issue1233.rs
+macros/mbe/macro-issue1400.rs
+macros/mbe/macro13.rs
+macros/mbe/macro15.rs
+macros/mbe/macro20.rs
+macros/mbe/macro23.rs
+macros/mbe/macro40.rs
+macros/mbe/macro43.rs
+macros/mbe/macro44.rs
+macros/mbe/macro50.rs
+macros/mbe/macro54.rs
+macros/mbe/macro6.rs
+macros/mbe/macro_rules_macro_rules.rs
+macros/mbe/macro_use1.rs
+match-never-ltype.rs
+match-never-rtype.rs
+match1.rs
+match2.rs
+match3.rs
+match4.rs
+match5.rs
+match9.rs
+method2.rs
+multi_reference_type.rs
+multiple_bindings1.rs
+multiple_bindings2.rs
+name_resolution2.rs
+name_resolution4.rs
+nested_generic.rs
+nested_macro_use1.rs
+nested_macro_use2.rs
+nested_macro_use3.rs
+non_member_const.rs
+not_find_value_in_scope.rs
+parse_associated_type_as_generic_arg.rs
+parse_associated_type_as_generic_arg2.rs
+parse_associated_type_as_generic_arg3.rs
+parse_complex_generic_application.rs
+parse_complex_generic_application2.rs
+path_as_generic_arg.rs
+pattern-struct.rs
+privacy1.rs
+privacy3.rs
+privacy4.rs
+privacy5.rs
+privacy6.rs
+privacy8.rs
+macros/proc/attribute_non_function.rs
+macros/proc/derive_non_function.rs
+macros/proc/non_function.rs
+pub_restricted_1.rs
+pub_restricted_2.rs
+pub_restricted_3.rs
+redef_error2.rs
+redef_error4.rs
+redef_error5.rs
+redef_error6.rs
+rustc_attr1.rs
+self-path1.rs
+self-path2.rs
+sizeof-stray-infer-var-bug.rs
+specify-crate-name.rs
+stmt_with_block_dot.rs
+struct-expr-parse.rs
+trait-cycle.rs
+traits1.rs
+traits10.rs
+traits11.rs
+traits12.rs
+traits2.rs
+traits3.rs
+traits4.rs
+traits5.rs
+traits6.rs
+traits7.rs
+traits8.rs
+traits9.rs
+type-bindings1.rs
+unconstrained_type_param.rs
+undeclared_label.rs
+unsafe1.rs
+unsafe11.rs
+unsafe2.rs
+unsafe3.rs
+unsafe6.rs
+unsafe7.rs
+use_1.rs
+use_2.rs
+v0-mangle1.rs
+v0-mangle2.rs
+while_break_expr.rs
+negative_impls.rs
+auto_trait.rs
+exhaustiveness1.rs
+exhaustiveness2.rs
+exhaustiveness3.rs
+trait13.rs
+trait14.rs
+issue-2324-1.rs
+issue-2324-2.rs
+issue-2725.rs
+issue-2987.rs
+issue-3045-1.rs
+issue-3045-2.rs
+issue-3046.rs
+unknown-associated-item.rs
+issue-3030.rs
+issue-3035.rs
+issue-3082.rs
+issue-3139-1.rs
+issue-3139-2.rs
+issue-3139-3.rs
+issue-3036.rs
+issue-2951.rs
+issue-2203.rs
+issue-2499.rs \ No newline at end of file
diff --git a/gcc/testsuite/rust/compile/prelude_import.rs b/gcc/testsuite/rust/compile/prelude_import.rs
new file mode 100644
index 0000000..569fb62
--- /dev/null
+++ b/gcc/testsuite/rust/compile/prelude_import.rs
@@ -0,0 +1,12 @@
+#![feature(prelude_import)]
+
+mod core {
+ mod prelude {
+ mod v1 {
+ // hehe
+ }
+ }
+}
+
+#[prelude_import]
+use core::prelude::v1::*;
diff --git a/gcc/testsuite/rust/compile/sizeof-stray-infer-var-bug.rs b/gcc/testsuite/rust/compile/sizeof-stray-infer-var-bug.rs
index a5f0c2b..8275691 100644
--- a/gcc/testsuite/rust/compile/sizeof-stray-infer-var-bug.rs
+++ b/gcc/testsuite/rust/compile/sizeof-stray-infer-var-bug.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-8.rs b/gcc/testsuite/rust/compile/torture/intrinsics-8.rs
index deb19bd..b9bd83c 100644
--- a/gcc/testsuite/rust/compile/torture/intrinsics-8.rs
+++ b/gcc/testsuite/rust/compile/torture/intrinsics-8.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs b/gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs
index 6d34fb1..7b98779 100644
--- a/gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs
+++ b/gcc/testsuite/rust/compile/torture/transmute-size-check-1.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/compile/torture/transmute1.rs b/gcc/testsuite/rust/compile/torture/transmute1.rs
index b2a0d07..be9fb1d 100644
--- a/gcc/testsuite/rust/compile/torture/transmute1.rs
+++ b/gcc/testsuite/rust/compile/torture/transmute1.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/compile/torture/uninit-intrinsic-1.rs b/gcc/testsuite/rust/compile/torture/uninit-intrinsic-1.rs
index cbb92fe..fa329c6 100644
--- a/gcc/testsuite/rust/compile/torture/uninit-intrinsic-1.rs
+++ b/gcc/testsuite/rust/compile/torture/uninit-intrinsic-1.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/compile/trait13.rs b/gcc/testsuite/rust/compile/trait13.rs
new file mode 100644
index 0000000..af5f5a6
--- /dev/null
+++ b/gcc/testsuite/rust/compile/trait13.rs
@@ -0,0 +1,47 @@
+// Testing multiple supertraits and calling supertrait methods
+
+struct Foo {
+ my_int: u32,
+}
+
+trait GrandParent {
+ fn grandparent(&self) -> u32;
+}
+
+trait Parent : GrandParent {
+ fn parent(&self) -> bool;
+}
+
+trait Child : Parent {
+ fn child(&self);
+}
+
+impl GrandParent for Foo {
+ fn grandparent(&self) -> u32 {
+ self.my_int
+ }
+}
+
+impl Parent for Foo {
+ fn parent(&self) -> bool {
+ // Call supertrait method
+ return self.grandparent() != 0;
+ }
+}
+
+impl Child for Foo {
+ fn child(&self) {
+ let _ = self;
+ }
+}
+
+pub fn main() {
+ let a = Foo{my_int: 0xfeedf00d};
+ let b: &dyn Child = &a;
+
+ b.parent();
+ b.child();
+
+ // Here to silence bogus compiler warning
+ let _ = a.my_int;
+}
diff --git a/gcc/testsuite/rust/compile/trait14.rs b/gcc/testsuite/rust/compile/trait14.rs
new file mode 100644
index 0000000..c1d42b5
--- /dev/null
+++ b/gcc/testsuite/rust/compile/trait14.rs
@@ -0,0 +1,51 @@
+// Testing diamond problem with supertraits
+
+
+struct Foo {
+ my_int: u32,
+}
+
+trait GrandParent {
+ fn grandparent(&self);
+}
+
+trait Parent1 : GrandParent {
+ fn parent1(&self);
+}
+
+trait Parent2 : GrandParent {
+ fn parent2(&self);
+}
+
+trait Child : Parent1+Parent2 {
+ fn child(&self);
+}
+
+impl GrandParent for Foo {
+ fn grandparent(&self) { let _ = self; }
+}
+
+impl Parent1 for Foo {
+ fn parent1(&self) { let _ = self; }
+}
+
+impl Parent2 for Foo {
+ fn parent2(&self) { let _ = self; }
+}
+
+impl Child for Foo {
+ fn child(&self) {
+ let _ = self;
+ }
+}
+
+pub fn main() {
+ let a = Foo{my_int: 0xf00dfeed};
+ let b: &dyn Child = &a;
+
+ b.parent1();
+ b.child();
+
+ // Suppress bogus compile warning
+ let _ = a.my_int;
+}
diff --git a/gcc/testsuite/rust/compile/v0-mangle1.rs b/gcc/testsuite/rust/compile/v0-mangle1.rs
index a34f1a7..04c546e 100644
--- a/gcc/testsuite/rust/compile/v0-mangle1.rs
+++ b/gcc/testsuite/rust/compile/v0-mangle1.rs
@@ -36,7 +36,7 @@ fn main() {
// cf. rustc 1.72.0: _RNvNtCshIBIgX6Bzox_10v0_mangle18module_a3bar
module_a::bar();
- // { dg-final { scan-assembler "_R.*NvNtNtC10v0_mangle18module_a8module_b3baz" } }
+ // { dg-final { scan-assembler "_R.*NvNtNtC.*10v0_mangle18module_a8module_b3baz" } }
// cf. rustc 1.72.0: _RNvNtNtCshIBIgX6Bzox_10v0_mangle18module_a8module_b3baz
module_a::module_b::baz();
diff --git a/gcc/testsuite/rust/compile/name_resolution21.rs b/gcc/testsuite/rust/compile/xfail/name_resolution21.rs
index 3d0af2b..df48d00 100644
--- a/gcc/testsuite/rust/compile/name_resolution21.rs
+++ b/gcc/testsuite/rust/compile/xfail/name_resolution21.rs
@@ -5,7 +5,8 @@ pub mod foo {
}
use foo::bar;
-use foo::bar; // { dg-error ".bar. defined multiple times" }
+use foo::bar;
+// { dg-error ".bar. defined multiple times" "" { xfail *-*-* } .-1 }
fn main() {
bar!();
diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
index 19a1faf..6aec417 100644
--- a/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
+++ b/gcc/testsuite/rust/execute/torture/builtin_macro_include_bytes.rs
@@ -1,4 +1,5 @@
-// { dg-output "104\r*\n33\r*\n1\r*\n" }
+// { dg-output "1\r*\n1\r*\n1\r*\n" }
+
#![feature(rustc_attrs)]
#[rustc_builtin_macro]
@@ -6,6 +7,10 @@ macro_rules! include_bytes {
() => {{}};
}
+macro_rules! my_file {
+ () => {"include.txt"};
+}
+
extern "C" {
fn printf(s: *const i8, ...);
}
@@ -17,32 +22,30 @@ fn print_int(value: i32) {
}
}
-fn main() -> i32 {
- let bytes = include_bytes!("include.txt");
-
- print_int(bytes[0] as i32);
- print_int(bytes[14] as i32);
-
+fn check_bytes(bytes: &[u8; 16]) {
let the_bytes = b"hello, include!\n";
- let x = bytes[0] == the_bytes[0]
- && bytes[1] == the_bytes[1]
- && bytes[2] == the_bytes[2]
- && bytes[3] == the_bytes[3]
- && bytes[4] == the_bytes[4]
- && bytes[5] == the_bytes[5]
- && bytes[6] == the_bytes[6]
- && bytes[7] == the_bytes[7]
- && bytes[8] == the_bytes[8]
- && bytes[9] == the_bytes[9]
- && bytes[10] == the_bytes[10]
- && bytes[11] == the_bytes[11]
- && bytes[12] == the_bytes[12]
- && bytes[13] == the_bytes[13]
- && bytes[14] == the_bytes[14]
- && bytes[15] == the_bytes[15];
+ let x = true;
+ let mut i = 0;
+
+ // X is true iff bytes == the_bytes
+ while i < 16 {
+ x = x && (bytes[i] == the_bytes[i]);
+ i += 1;
+ }
print_int(x as i32);
+}
+
+fn main() -> i32 {
+ let bytes1: &'static [u8; 16] = include_bytes!("include.txt");
+ check_bytes(bytes1);
+
+ let bytes2: &'static [u8; 16] = include_bytes!(my_file!());
+ check_bytes(bytes2);
+
+ let bytes3 = include_bytes!(my_file!(),);
+ check_bytes(bytes3);
0
}
diff --git a/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs b/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs
index a65639d..b5454db 100644
--- a/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs
+++ b/gcc/testsuite/rust/execute/torture/builtin_macro_include_str.rs
@@ -1,4 +1,4 @@
-// { dg-output "hello, include!\r*\n" }
+// { dg-output "hello, include!\r*\nhello, include!\r*\nhello, include!\r*\n" }
#![feature(rustc_attrs)]
#[rustc_builtin_macro]
@@ -6,6 +6,10 @@ macro_rules! include_str {
() => {{}};
}
+macro_rules! my_file {
+ () => {"include.txt"};
+}
+
extern "C" {
fn printf(fmt: *const i8, ...);
}
@@ -22,7 +26,10 @@ fn print(s: &str) {
fn main() -> i32 {
// include_str! (and include_bytes!) allow for an optional trailing comma.
let my_str = include_str!("include.txt",);
-
+ print(my_str);
+ let my_str = include_str!(my_file!());
+ print(my_str);
+ let my_str = include_str!(my_file!(),);
print(my_str);
0
diff --git a/gcc/testsuite/rust/execute/torture/inline_asm_mov_x_5_ARM.rs b/gcc/testsuite/rust/execute/torture/inline_asm_mov_x_5_ARM.rs
new file mode 100644
index 0000000..0c867df
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/inline_asm_mov_x_5_ARM.rs
@@ -0,0 +1,36 @@
+/* { dg-do run { target arm*-*-* } } */
+/* { dg-output "5\r*\n9\r*\n" }*/
+
+#![feature(rustc_attrs)]
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+fn main() -> i32 {
+ let mut _x: i32 = 0;
+ let mut _y: i32 = 9;
+
+ unsafe {
+ asm!(
+ "mov {}, 5",
+ out(reg) _x
+ );
+ printf("%d\n\0" as *const str as *const i8, _x);
+ };
+
+ unsafe {
+ asm!(
+ "mov {}, {}",
+ in(reg) _y,
+ out(reg) _x
+ );
+ printf("%d\n\0" as *const str as *const i8, _x);
+ }
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/inline_asm_mov_x_5_x86_64.rs b/gcc/testsuite/rust/execute/torture/inline_asm_mov_x_5_x86_64.rs
new file mode 100644
index 0000000..5fbbb68
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/inline_asm_mov_x_5_x86_64.rs
@@ -0,0 +1,35 @@
+/* { dg-do run { target x86_64*-*-* } } */
+/* { dg-output "5\r*\n9\r*\n" }*/
+
+#![feature(rustc_attrs)]
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+fn main() -> i32 {
+ let mut x: i32 = 0;
+ let mut _y: i32 = 9; // Mark it as _y since it is only used as input operand, not printing
+
+ unsafe {
+ asm!(
+ "mov $5, {}",
+ out(reg) x
+ );
+ printf("%d\n\0" as *const str as *const i8, x);
+ };
+
+ unsafe {
+ asm!(
+ "mov {}, {}",
+ in(reg) _y,
+ out(reg) x,
+ );
+ printf("%d\n\0" as *const str as *const i8, x);
+ }
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/issue-1436.rs b/gcc/testsuite/rust/execute/torture/issue-1436.rs
index 4e69961..5d90907 100644
--- a/gcc/testsuite/rust/execute/torture/issue-1436.rs
+++ b/gcc/testsuite/rust/execute/torture/issue-1436.rs
@@ -1,4 +1,7 @@
// { dg-options "-w" }
+
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/execute/torture/issue-2583.rs b/gcc/testsuite/rust/execute/torture/issue-2583.rs
index 46f501e..4ff12fc 100644
--- a/gcc/testsuite/rust/execute/torture/issue-2583.rs
+++ b/gcc/testsuite/rust/execute/torture/issue-2583.rs
@@ -1,3 +1,5 @@
+#![feature(intrinsics)]
+
#[lang = "sized"]
pub trait Sized {}
diff --git a/gcc/testsuite/rust/execute/torture/trait14.rs b/gcc/testsuite/rust/execute/torture/trait14.rs
new file mode 100644
index 0000000..759950e
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait14.rs
@@ -0,0 +1,47 @@
+/* { dg-output "parent123\r*\nchild\r*\n" } */
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+struct Foo(i32);
+trait Parent {
+ fn parent(&self);
+}
+
+trait Child : Parent {
+ fn child(&self);
+}
+
+impl Parent for Foo {
+ fn parent(&self) {
+ unsafe {
+ let parent = "parent%i\n\0";
+ let msg = parent as *const str;
+ printf(msg as *const i8,self.0);
+ }
+ }
+}
+
+impl Child for Foo {
+ fn child(&self) {
+ let _ = self;
+ unsafe {
+ let child = "child\n\0";
+ let msg = child as *const str;
+ printf(msg as *const i8);
+ }
+ }
+}
+
+pub fn main() -> i32 {
+ let a = Foo(123);
+ let b: &dyn Child = &a;
+
+ b.parent();
+ b.child();
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/trait15.rs b/gcc/testsuite/rust/execute/torture/trait15.rs
new file mode 100644
index 0000000..53469d7
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait15.rs
@@ -0,0 +1,56 @@
+/* { dg-output "parent123\r*\nchild\r*\n" } */
+// Testing generics passing with supertraits
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+struct Foo {
+ my_int: u32,
+}
+
+trait Parent<T> {
+ fn parent(&self) -> T;
+}
+
+trait Child<T> : Parent<T> {
+ fn child(&self);
+}
+
+impl Parent<u32> for Foo {
+ fn parent(&self) -> u32 {
+ unsafe {
+ let parent = "parent%i\n\0";
+ let msg = parent as *const str;
+ printf(msg as *const i8,self.my_int);
+ return self.my_int;
+ }
+ }
+}
+
+impl Child<u32> for Foo {
+ fn child(&self) {
+ let _ = self;
+ unsafe {
+ let child = "child\n\0";
+ let msg = child as *const str;
+ printf(msg as *const i8);
+ }
+ }
+}
+
+pub fn main() -> i32 {
+ let a = Foo{my_int: 123};
+ let b: &dyn Child<u32> = &a;
+
+ b.parent();
+ b.child();
+
+ //Silence bogus warning
+ let _ = a.my_int;
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/trait16.rs b/gcc/testsuite/rust/execute/torture/trait16.rs
new file mode 100644
index 0000000..95f48a1
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait16.rs
@@ -0,0 +1,52 @@
+/* { dg-output "parent123\r*\nchild\r*\n" } */
+//Testing lifetimes with supertraits
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+struct Foo {
+ my_int: u32,
+}
+
+trait Parent {
+ fn parent(&self);
+}
+
+trait Child : Parent {
+ fn child(&self);
+}
+
+impl Parent for Foo {
+ fn parent(&self) {
+ unsafe {
+ let parent = "parent%i\n\0";
+ let msg = parent as *const str;
+ printf(msg as *const i8,self.my_int);
+ return;
+ }
+ }
+}
+
+impl Child for Foo {
+ fn child<'a>(&self) {
+ let _ = self;
+ unsafe {
+ let child = "child\n\0";
+ let msg = child as *const str;
+ printf(msg as *const i8);
+ }
+ }
+}
+
+pub fn main() -> i32 {
+ let a = Foo{ my_int: 123};
+ let b: &dyn Child = &a;
+
+ b.parent();
+ b.child();
+
+ let _ = a.my_int;
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/trait17.rs b/gcc/testsuite/rust/execute/torture/trait17.rs
new file mode 100644
index 0000000..a619ef8
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait17.rs
@@ -0,0 +1,54 @@
+/* { dg-output "parent123\r*\nchild\r*\n" } */
+
+//Second test for lifetimes in supertraits
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+struct Foo {
+ my_int: u32,
+}
+
+trait Parent {
+ fn parent(&self);
+}
+
+trait Child : Parent {
+ fn child(&self);
+}
+
+impl Parent for Foo {
+ fn parent<'b>(&self) {
+ unsafe {
+ let parent = "parent%i\n\0";
+ let msg = parent as *const str;
+ printf(msg as *const i8,self.my_int);
+ return;
+ }
+ }
+}
+
+impl Child for Foo {
+ fn child(&self) {
+ let _ = self;
+ unsafe {
+ let child = "child\n\0";
+ let msg = child as *const str;
+ printf(msg as *const i8);
+ }
+ }
+}
+
+pub fn main() -> i32 {
+ let a = Foo{ my_int: 123};
+ let b: &dyn Child = &a;
+
+ b.parent();
+ b.child();
+
+ // Silence bogus warning
+ let _ = a.my_int;
+
+ 0
+}
diff --git a/gcc/testsuite/rust/execute/torture/trait18.rs b/gcc/testsuite/rust/execute/torture/trait18.rs
new file mode 100644
index 0000000..46024d8
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/trait18.rs
@@ -0,0 +1,56 @@
+/* { dg-output "parent\r*\nchild\r*\n" } */
+//Testing default implementations with supertraits.
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+struct Foo {
+ my_int: u32,
+}
+
+trait Parent {
+ fn parent_str(&self) -> &'static str;
+ fn parent(&self) {
+ unsafe {
+ let parent: &'static str = self.parent_str();
+ let msg = parent as *const str;
+ printf(msg as *const i8);
+ }
+ }
+}
+
+trait Child : Parent {
+ fn child(&self);
+}
+
+impl Parent for Foo {
+ fn parent_str(&self) -> &'static str {
+ let _ = self;
+ return "parent\n\0";
+ }
+}
+
+impl Child for Foo {
+ fn child(&self) {
+ let _ = self;
+ unsafe {
+ let child = "child\n\0";
+ let msg = child as *const str;
+ printf(msg as *const i8);
+ }
+ }
+}
+
+pub fn main() -> i32 {
+ let a = Foo{ my_int: 0xfeedf00d};
+ let b: &dyn Child = &a;
+
+ b.parent();
+ b.child();
+
+ // Bogus warning silencer
+ let _ = a.my_int;
+
+ 0
+}
diff --git a/gcc/testsuite/rust/rustc/README.md b/gcc/testsuite/rust/rustc/README.md
new file mode 100644
index 0000000..ddf4d95
--- /dev/null
+++ b/gcc/testsuite/rust/rustc/README.md
@@ -0,0 +1,4 @@
+This repository contains test cases from the
+[rustc test suite](https://github.com/rust-lang/rust/tree/master/tests). The
+conversion of these tests into the DejaGnu format is done by the rustc
+testsuite adaptor, a tool specifically designed for this purpose.
diff --git a/gcc/testsuite/rust/rustc/rustc.exp b/gcc/testsuite/rust/rustc/rustc.exp
new file mode 100644
index 0000000..ac891db
--- /dev/null
+++ b/gcc/testsuite/rust/rustc/rustc.exp
@@ -0,0 +1,35 @@
+# Copyright (C) 2021-2024 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3. If not see
+# <http://www.gnu.org/licenses/>.
+
+# Compile tests, no torture testing.
+#
+# These tests raise errors in the front end; torture testing doesn't apply.
+
+# Load support procs.
+load_lib rust-dg.exp
+
+# Initialize `dg'.
+dg-init
+
+# Main loop.
+set saved-dg-do-what-default ${dg-do-what-default}
+
+set dg-do-what-default "compile"
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.rs]] "" ""
+set dg-do-what-default ${saved-dg-do-what-default}
+
+# All done.
+dg-finish
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index c5d46ec..6d8b885 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -1099,7 +1099,7 @@ general_init (const char *argv0, bool init_signals, unique_argv original_argv)
lang_mask,
&global_options),
lang_mask);
- global_dc->set_urlifier (make_gcc_urlifier (lang_mask));
+ global_dc->push_owned_urlifier (make_gcc_urlifier (lang_mask));
if (init_signals)
{