aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog293
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/analyzer/ChangeLog419
-rw-r--r--gcc/analyzer/access-diagram.cc77
-rw-r--r--gcc/analyzer/access-diagram.h2
-rw-r--r--gcc/analyzer/analysis-plan.cc20
-rw-r--r--gcc/analyzer/analyzer-language.cc10
-rw-r--r--gcc/analyzer/analyzer-pass.cc11
-rw-r--r--gcc/analyzer/analyzer-selftests.cc8
-rw-r--r--gcc/analyzer/analyzer.cc70
-rw-r--r--gcc/analyzer/analyzer.opt4
-rw-r--r--gcc/analyzer/analyzer.opt.urls3
-rw-r--r--gcc/analyzer/bounds-checking.cc117
-rw-r--r--gcc/analyzer/call-details.cc115
-rw-r--r--gcc/analyzer/call-details.h14
-rw-r--r--gcc/analyzer/call-info.cc40
-rw-r--r--gcc/analyzer/call-info.h8
-rw-r--r--gcc/analyzer/call-string.cc23
-rw-r--r--gcc/analyzer/call-summary.cc16
-rw-r--r--gcc/analyzer/call-summary.h6
-rw-r--r--gcc/analyzer/checker-event.cc164
-rw-r--r--gcc/analyzer/checker-event.h216
-rw-r--r--gcc/analyzer/checker-path.cc60
-rw-r--r--gcc/analyzer/common.h (renamed from gcc/analyzer/analyzer.h)51
-rw-r--r--gcc/analyzer/complexity.cc28
-rw-r--r--gcc/analyzer/constraint-manager.cc77
-rw-r--r--gcc/analyzer/constraint-manager.h6
-rw-r--r--gcc/analyzer/diagnostic-manager.cc322
-rw-r--r--gcc/analyzer/diagnostic-manager.h1
-rw-r--r--gcc/analyzer/engine.cc736
-rw-r--r--gcc/analyzer/exploded-graph.h56
-rw-r--r--gcc/analyzer/feasible-graph.cc28
-rw-r--r--gcc/analyzer/infinite-loop.cc101
-rw-r--r--gcc/analyzer/infinite-recursion.cc53
-rw-r--r--gcc/analyzer/kf-analyzer.cc50
-rw-r--r--gcc/analyzer/kf-lang-cp.cc198
-rw-r--r--gcc/analyzer/kf.cc391
-rw-r--r--gcc/analyzer/known-function-manager.cc15
-rw-r--r--gcc/analyzer/pending-diagnostic.cc51
-rw-r--r--gcc/analyzer/program-point.cc32
-rw-r--r--gcc/analyzer/program-state.cc121
-rw-r--r--gcc/analyzer/program-state.h26
-rw-r--r--gcc/analyzer/ranges.cc34
-rw-r--r--gcc/analyzer/record-layout.cc14
-rw-r--r--gcc/analyzer/region-model-asm.cc18
-rw-r--r--gcc/analyzer/region-model-manager.cc36
-rw-r--r--gcc/analyzer/region-model-reachability.cc31
-rw-r--r--gcc/analyzer/region-model.cc983
-rw-r--r--gcc/analyzer/region-model.h131
-rw-r--r--gcc/analyzer/region.cc49
-rw-r--r--gcc/analyzer/sm-fd.cc387
-rw-r--r--gcc/analyzer/sm-file.cc95
-rw-r--r--gcc/analyzer/sm-malloc.cc120
-rw-r--r--gcc/analyzer/sm-pattern-test.cc20
-rw-r--r--gcc/analyzer/sm-sensitive.cc29
-rw-r--r--gcc/analyzer/sm-signal.cc67
-rw-r--r--gcc/analyzer/sm-taint.cc65
-rw-r--r--gcc/analyzer/sm.cc68
-rw-r--r--gcc/analyzer/sm.h24
-rw-r--r--gcc/analyzer/state-purge.cc25
-rw-r--r--gcc/analyzer/store.cc55
-rw-r--r--gcc/analyzer/store.h4
-rw-r--r--gcc/analyzer/supergraph.cc289
-rw-r--r--gcc/analyzer/supergraph.h169
-rw-r--r--gcc/analyzer/svalue.cc60
-rw-r--r--gcc/analyzer/svalue.h19
-rw-r--r--gcc/analyzer/symbol.cc7
-rw-r--r--gcc/analyzer/trimmed-graph.cc17
-rw-r--r--gcc/analyzer/varargs.cc101
-rw-r--r--gcc/c-family/ChangeLog17
-rw-r--r--gcc/c-family/c-pretty-print.cc3
-rw-r--r--gcc/c-family/name-hint.h6
-rw-r--r--gcc/c/ChangeLog28
-rw-r--r--gcc/c/c-decl.cc18
-rw-r--r--gcc/c/c-objc-common.cc3
-rw-r--r--gcc/c/c-parser.cc8
-rw-r--r--gcc/c/gimple-parser.cc109
-rw-r--r--gcc/cp/ChangeLog35
-rw-r--r--gcc/cp/cxx-pretty-print.cc3
-rw-r--r--gcc/cp/error.cc1
-rw-r--r--gcc/cp/name-lookup.cc48
-rw-r--r--gcc/cp/parser.cc48
-rw-r--r--gcc/diagnostic-format-json.cc33
-rw-r--r--gcc/diagnostic-format-sarif.cc320
-rw-r--r--gcc/diagnostic-format-sarif.h36
-rw-r--r--gcc/diagnostic-format-text.cc3
-rw-r--r--gcc/diagnostic.cc7
-rw-r--r--gcc/diagnostic.h22
-rw-r--r--gcc/doc/invoke.texi13
-rw-r--r--gcc/dumpfile.cc35
-rw-r--r--gcc/gcc-attribute-urlifier.cc1
-rw-r--r--gcc/gcc-urlifier.cc3
-rw-r--r--gcc/gimple-range-cache.cc2
-rw-r--r--gcc/gimple-range-fold.cc14
-rw-r--r--gcc/gimple.h2
-rw-r--r--gcc/jit/ChangeLog5
-rw-r--r--gcc/jit/dummy-frontend.cc6
-rw-r--r--gcc/json-parsing.cc21
-rw-r--r--gcc/json.cc5
-rw-r--r--gcc/lazy-diagnostic-path.cc5
-rw-r--r--gcc/libgdiagnostics.cc59
-rw-r--r--gcc/libsarifreplay.cc5
-rw-r--r--gcc/lto-wrapper.cc1
-rw-r--r--gcc/make-unique.h35
-rw-r--r--gcc/opts-diagnostic.cc15
-rw-r--r--gcc/opts.cc2
-rw-r--r--gcc/pass_manager.h20
-rw-r--r--gcc/passes.cc34
-rw-r--r--gcc/pretty-print.cc7
-rw-r--r--gcc/range-op-ptr.cc59
-rw-r--r--gcc/range-op.cc20
-rw-r--r--gcc/range-op.h4
-rw-r--r--gcc/rtl.h2
-rw-r--r--gcc/rust/ChangeLog353
-rw-r--r--gcc/rust/ast/rust-ast-collector.cc45
-rw-r--r--gcc/rust/ast/rust-ast-collector.h1
-rw-r--r--gcc/rust/ast/rust-ast-visitor.cc30
-rw-r--r--gcc/rust/ast/rust-ast-visitor.h4
-rw-r--r--gcc/rust/ast/rust-ast.cc6
-rw-r--r--gcc/rust/ast/rust-ast.h19
-rw-r--r--gcc/rust/ast/rust-expr.h93
-rw-r--r--gcc/rust/ast/rust-path.cc2
-rw-r--r--gcc/rust/ast/rust-path.h28
-rw-r--r--gcc/rust/backend/rust-compile-asm.cc54
-rw-r--r--gcc/rust/backend/rust-compile-asm.h14
-rw-r--r--gcc/rust/backend/rust-compile-block.h2
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc11
-rw-r--r--gcc/rust/backend/rust-compile-expr.h1
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-expr-stmt.cc4
-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-lazyboolexpr.h1
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h1
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir-place.h12
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-bir.h40
-rw-r--r--gcc/rust/checks/errors/borrowck/rust-function-collector.h1
-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.cc4
-rw-r--r--gcc/rust/checks/errors/rust-const-checker.h1
-rw-r--r--gcc/rust/checks/errors/rust-hir-pattern-analysis.cc4
-rw-r--r--gcc/rust/checks/errors/rust-hir-pattern-analysis.h1
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.cc16
-rw-r--r--gcc/rust/checks/errors/rust-unsafe-checker.h1
-rw-r--r--gcc/rust/expand/rust-derive-clone.cc8
-rw-r--r--gcc/rust/expand/rust-derive.h1
-rw-r--r--gcc/rust/expand/rust-expand-visitor.cc3
-rw-r--r--gcc/rust/expand/rust-macro-builtins-asm.cc237
-rw-r--r--gcc/rust/expand/rust-macro-builtins-asm.h32
-rw-r--r--gcc/rust/expand/rust-macro-builtins.cc11
-rw-r--r--gcc/rust/expand/rust-macro-builtins.h4
-rw-r--r--gcc/rust/hir/rust-ast-lower-base.cc4
-rw-r--r--gcc/rust/hir/rust-ast-lower-base.h1
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.cc44
-rw-r--r--gcc/rust/hir/rust-ast-lower-expr.h1
-rw-r--r--gcc/rust/hir/rust-ast-lower-type.cc2
-rw-r--r--gcc/rust/hir/rust-hir-dump.cc8
-rw-r--r--gcc/rust/hir/rust-hir-dump.h1
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr-abstract.h1
-rw-r--r--gcc/rust/hir/tree/rust-hir-expr.h74
-rw-r--r--gcc/rust/hir/tree/rust-hir-full-decls.h1
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h2
-rw-r--r--gcc/rust/hir/tree/rust-hir-visitor.h3
-rw-r--r--gcc/rust/hir/tree/rust-hir.cc11
-rw-r--r--gcc/rust/parse/rust-parse-impl.h36
-rw-r--r--gcc/rust/parse/rust-parse.h2
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.cc4
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-base.h1
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.cc11
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h1
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-path.cc8
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.cc3
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h4
-rw-r--r--gcc/rust/resolve/rust-default-resolver.cc8
-rw-r--r--gcc/rust/resolve/rust-default-resolver.h2
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.cc9
-rw-r--r--gcc/rust/resolve/rust-early-name-resolver-2.0.h16
-rw-r--r--gcc/rust/resolve/rust-forever-stack.h24
-rw-r--r--gcc/rust/resolve/rust-forever-stack.hxx44
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.cc153
-rw-r--r--gcc/rust/resolve/rust-late-name-resolver-2.0.h8
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.cc59
-rw-r--r--gcc/rust/resolve/rust-name-resolution-context.h145
-rw-r--r--gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc5
-rw-r--r--gcc/rust/rust-gcc.cc1
-rw-r--r--gcc/rust/typecheck/rust-hir-trait-resolve.cc21
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-base.cc44
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.cc31
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h1
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-item.cc44
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct-field.h3
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-struct.cc54
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc85
-rw-r--r--gcc/rust/typecheck/rust-tyty.h19
-rw-r--r--gcc/rust/util/rust-stacked-contexts.h9
-rw-r--r--gcc/simplify-rtx.cc38
-rw-r--r--gcc/testsuite/ChangeLog312
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/attr-const-2.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/attr-malloc-exception.c17
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/capacity-2.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/data-model-22.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/data-model-5d.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/edges-2.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/fd-2.c4
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/fd-3.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/fd-meaning.c5
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/file-1.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/file-3.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/hard-reg-1.c8
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/leak-3.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/paths-7.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr110830.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr97072.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr98575-1.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr99716-1.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr99716-2.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pr99716-3.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/pragma-2.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/strndup-1.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c2
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c1
-rw-r--r--gcc/testsuite/c-c++-common/analyzer/zlib-5.c1
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-could-throw-1.C37
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-could-throw-2.C32
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-dynamic-spec.C62
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-leak-1.C8
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-leak-2.C18
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-leak-3.C12
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-leak-4.C16
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-leak-5.C51
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-leak-6.C22
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-nothrow.C26
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-path-1.C34
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-1.C16
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-2.C22
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C55
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple.C48
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-path-unwind-single.C43
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-path-with-cleanups.C27
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-rethrow-1.C13
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-rethrow-2.C25
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-stack-1.C35
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-stack-2.C44
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C21
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-subclass-2.C25
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-value-1.C20
-rw-r--r--gcc/testsuite/g++.dg/analyzer/exception-value-2.C36
-rw-r--r--gcc/testsuite/g++.dg/analyzer/fno-exception.C12
-rw-r--r--gcc/testsuite/g++.dg/analyzer/nrvo-1.C18
-rw-r--r--gcc/testsuite/g++.dg/analyzer/nrvo-2.C26
-rw-r--r--gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1.C11
-rw-r--r--gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1b.C12
-rw-r--r--gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2.C10
-rw-r--r--gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2b.C13
-rw-r--r--gcc/testsuite/g++.dg/analyzer/pr94028.C2
-rw-r--r--gcc/testsuite/g++.dg/analyzer/std-unexpected.C9
-rw-r--r--gcc/testsuite/g++.dg/analyzer/unique_ptr-1.C13
-rw-r--r--gcc/testsuite/g++.dg/analyzer/unique_ptr-2.C17
-rw-r--r--gcc/testsuite/g++.dg/coroutines/pr105287.C2
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr100038.C17
-rw-r--r--gcc/testsuite/gcc.dg/gimplefe-57.c11
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc36
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc40
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc17
-rw-r--r--gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc12
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc4
-rw-r--r--gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc49
-rw-r--r--gcc/testsuite/gcc.dg/pr119712.c27
-rw-r--r--gcc/testsuite/gcc.dg/pr83072-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr95801.c13
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/tailcall-14.c25
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/tailcall-15.c16
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/vrp122.c4
-rw-r--r--gcc/testsuite/rust/compile/black_box.rs28
-rw-r--r--gcc/testsuite/rust/compile/derive-debug1.rs2
-rw-r--r--gcc/testsuite/rust/compile/generics9.rs3
-rw-r--r--gcc/testsuite/rust/compile/issue-3530-1.rs2
-rw-r--r--gcc/testsuite/rust/compile/issue-3530-2.rs2
-rw-r--r--gcc/testsuite/rust/compile/issue-3568.rs2
-rw-r--r--gcc/testsuite/rust/compile/issue-3581-1.rs12
-rw-r--r--gcc/testsuite/rust/compile/issue-3581-2.rs9
-rw-r--r--gcc/testsuite/rust/compile/issue-3612.rs7
-rw-r--r--gcc/testsuite/rust/compile/issue-3628.rs10
-rw-r--r--gcc/testsuite/rust/compile/issue-3649.rs2
-rw-r--r--gcc/testsuite/rust/compile/issue-3652.rs7
-rw-r--r--gcc/testsuite/rust/compile/issue-3662.rs8
-rw-r--r--gcc/testsuite/rust/compile/issue-3664.rs5
-rw-r--r--gcc/testsuite/rust/compile/issue-3711.rs17
-rw-r--r--gcc/testsuite/rust/compile/issue-402.rs14
-rw-r--r--gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs5
-rw-r--r--gcc/testsuite/rust/compile/multiple_bindings1.rs29
-rw-r--r--gcc/testsuite/rust/compile/name_resolution9.rs4
-rw-r--r--gcc/testsuite/rust/compile/nonexistent-field.rs2
-rw-r--r--gcc/testsuite/rust/compile/nr2/exclude12
-rw-r--r--gcc/testsuite/rust/compile/self-path2.rs4
-rw-r--r--gcc/testsuite/rust/compile/struct_init1.rs6
-rw-r--r--gcc/testsuite/rust/compile/use_1.rs9
-rw-r--r--gcc/testsuite/rust/execute/black_box.rs30
-rw-r--r--gcc/text-art/style.cc1
-rw-r--r--gcc/text-art/styled-string.cc1
-rw-r--r--gcc/text-art/table.cc1
-rw-r--r--gcc/text-art/tree-widget.cc5
-rw-r--r--gcc/text-art/widget.cc11
-rw-r--r--gcc/timevar.cc15
-rw-r--r--gcc/toplev.cc7
-rw-r--r--gcc/tree-cfg.cc13
-rw-r--r--gcc/tree-diagnostic-client-data-hooks.cc3
-rw-r--r--gcc/tree-pretty-print.cc4
-rw-r--r--gcc/tree-tailcall.cc109
-rw-r--r--gcc/value-range.cc64
-rw-r--r--gcc/value-range.h1
-rw-r--r--gcc/value-relation.cc90
-rw-r--r--gcc/value-relation.h35
341 files changed, 9039 insertions, 3316 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 5e84f05..eab3231 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,296 @@
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/97111
+ * doc/invoke.texi: Add -Wanalyzer-throw-of-unexpected-type.
+ * gimple.h (gimple_call_nothrow_p): Make arg const.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-format-json.cc: Drop include of "make-unique.h".
+ Replace uses of ::make_unique with std::make_unique.
+ * diagnostic-format-sarif.cc: Likewise.
+ * diagnostic-format-text.cc: Likewise.
+ * diagnostic.cc: Likewise.
+ * dumpfile.cc: Likewise.
+ * gcc-attribute-urlifier.cc: Likewise.
+ * gcc-urlifier.cc: Likewise.
+ * json-parsing.cc: Likewise.
+ * json.cc: Likewise.
+ * lazy-diagnostic-path.cc: Likewise.
+ * libgdiagnostics.cc: Likewise.
+ * libsarifreplay.cc: Likewise.
+ * lto-wrapper.cc: Likewise.
+ * make-unique.h: Delete.
+ * opts-diagnostic.cc: Drop include of "make-unique.h".
+ Replace uses of ::make_unique with std::make_unique.
+ * pretty-print.cc: Likewise.
+ * text-art/style.cc: Likewise.
+ * text-art/styled-string.cc: Likewise.
+ * text-art/table.cc: Likewise.
+ * text-art/tree-widget.cc: Likewise.
+ * text-art/widget.cc: Likewise.
+ * timevar.cc: Likewise.
+ * toplev.cc: Likewise.
+ * tree-diagnostic-client-data-hooks.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * pass_manager.h (class pass_manager): Add "m_" prefix to all pass
+ fields.
+ * passes.cc (pass_manager::execute_early_local_passes): Update
+ for added "m_" prefix.
+ (pass_manager::execute_pass_mode_switching): Likewise.
+ (pass_manager::finish_optimization_passes): Likewise.
+ (pass_manager::pass_manager): Likewise.
+ (pass_manager::dump_profile_report): Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h (diagnostic_context::m_opt_permissive): Convert
+ from int to diagnostic_option_id. Update comment.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic.h (diagnostic_context::set_abort_on_error): New.
+ (diagnostic_context::m_abort_on_error): Make private.
+ (diagnostic_abort_on_error): Delete.
+ * opts.cc (setup_core_dumping): Update for above changes.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * diagnostic-format-sarif.cc (sarif_builder::get_opts): New
+ accessor.
+ (sarif_builder::get_version): Update for...
+ (sarif_builder::m_version): Replace this field...
+ (sarif_builder::m_m_sarif_gen_opts): ...with this.
+ (sarif_builder::sarif_builder): Replace version with
+ sarif_gen_opts throughout.
+ (sarif_builder::make_top_level_object): Use get_version.
+ (sarif_output_format::sarif_output_format): Replace version with
+ sarif_gen_opts throughout.
+ (sarif_stream_output_format::sarif_stream_output_format):
+ Likewise.
+ (sarif_file_output_format::sarif_file_output_format): Likewise.
+ (diagnostic_output_format_init_sarif_stderr): Drop version param
+ and use default for sarif_generation_options instead.
+ (diagnostic_output_format_init_sarif_file): Likewise.
+ (diagnostic_output_format_init_sarif_stream): Likewise.
+ (make_sarif_sink): Replace version with sarif_gen_opts throughout.
+ (sarif_generation_options::sarif_generation_options): New.
+ (selftest::test_sarif_diagnostic_context::test_sarif_diagnostic_context):
+ Replace version with sarif_gen_opts throughout.
+ (selftest::test_make_location_object): Likewise.
+ (selftest::test_simple_log): Likewise.
+ (selftest::test_simple_log_2): Likewise.
+ (selftest::test_message_with_embedded_link): Likewise.
+ (selftest::test_message_with_braces): Likewise.
+ (selftest::test_buffering): Likewise.
+ (selftest::run_tests_per_version): Replace with...
+ (selftest::for_each_sarif_gen_option): ...this...
+ (selftest::run_line_table_case_tests_per_version): ...and this.
+ (selftest::diagnostic_format_sarif_cc_tests): Update to use
+ for_each_sarif_gen_option and
+ run_line_table_case_tests_per_version.
+ * diagnostic-format-sarif.h (enum class sarif_version): Move lower
+ down.
+ (diagnostic_output_format_init_sarif_stderr): Drop "version"
+ param.
+ (diagnostic_output_format_init_sarif_file): Likewise.
+ (diagnostic_output_format_init_sarif_stream): Likewise.
+ (struct sarif_generation_options): New.
+ (make_sarif_sink): Add "formatted" param. Replace version param
+ with sarif_gen_opts.
+ * diagnostic.cc (diagnostic_output_format_init): Drop hardcoded
+ sarif_version::v2_1_0 arguments from calls, which instead use
+ the default ctor for sarif_generation_options internally.
+ * libgdiagnostics.cc (sarif_sink::sarif_sink): Replace version
+ param with sarif_gen_opts, and update for changes to
+ make_sarif_sink.
+ (diagnostic_manager_add_sarif_sink): Use sarif_gen_opts rather
+ than version.
+ * opts-diagnostic.cc (sarif_scheme_handler::make_sink): Likewise.
+ Pass "true" for "formatted" param.
+
+2025-04-28 Andrew MacLeod <amacleod@redhat.com>
+
+ * value-relation.cc (value_relation::swap): New.
+ (value_relation::negate): Remove.
+ (dom_oracle::next_relation): New.
+ (block_relation_iterator::block_relation_iterator): New.
+ (block_relation_iterator::get_next_relation): New.
+ (dom_oracle::dump): Use iterator.
+ * value-relation.h (relation_oracle::next_relation): New.
+ (dom_oracle::next_relation): New prototype.
+ (class block_relation_iterator): New.
+ (FOR_EACH_RELATION_BB): New.
+ (FOR_EACH_RELATION_NAME): New.
+
+2025-04-28 Andrew MacLeod <amacleod@redhat.com>
+
+ * range-op-ptr.cc (range_operator::lhs_op1_relation): Add
+ prange/prange/irange (PPI) default.
+ (pointer_plus_operator::lhs_op1_relation): New.
+ * range-op.cc (range_op_handler::lhs_op1_relation): Add RO_PPI case.
+ * range-op.h (range_op_handler::lhs_op1_relation): Add prototype.
+
+2025-04-28 Andrew MacLeod <amacleod@redhat.com>
+
+ * gimple-range-fold.cc (fold_using_range::range_of_range_op): Use a
+ new local variable for intermediate relation results.
+
+2025-04-28 Andrew MacLeod <amacleod@redhat.com>
+
+ * gimple-range-cache.cc (ranger_cache::apply_inferred_ranges): Pass
+ 'this' as the range-query to the inferred range constructor.
+
+2025-04-28 Andrew MacLeod <amacleod@redhat.com>
+
+ PR tree-optimization/95801
+ * range-op.cc (operator_div::op2_range): New.
+
+2025-04-28 Andrew MacLeod <amacleod@redhat.com>
+
+ PR tree-optimization/119712
+ * value-range.cc (range_bitmask::adjust_range): Delete.
+ (irange::set_range_from_bitmask): Integrate adjust_range.
+ (irange::update_bitmask): Do nothing if bitmask doesnt change.
+ (irange:intersect_bitmask): Do not call adjust_range. Exit if there
+ is no second bitmask.
+ * value-range.h (adjust_range): Remove prototype.
+
+2025-04-28 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR tree-optimization/67797
+ * tree-tailcall.cc (find_tail_calls): Add support for ERF_RETURNS_ARG.
+
+2025-04-28 Andrew Pinski <quic_apinski@quicinc.com>
+
+ * tree-cfg.cc (verify_gimple_cond): Error out if the comparison
+ throws.
+
+2025-04-28 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR c/119432
+ * tree-pretty-print.cc (op_symbol_code): For LROTATE_EXPR,
+ output __ROTATE_LEFT for gimple.
+ For RROTATE_EXPR output __ROTATE_RIGHT for gimple.
+
+2025-04-28 Richard Sandiford <richard.sandiford@arm.com>
+
+ * rtl.h (native_decode_int): Declare.
+ * simplify-rtx.cc (native_decode_int): New function, split out from...
+ (native_decode_rtx): ...here.
+
+2025-04-28 H.J. Lu <hjl.tools@gmail.com>
+ Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/109780
+ PR target/109093
+ * config/i386/i386.cc (stack_access_data): New.
+ (ix86_update_stack_alignment): Likewise.
+ (ix86_find_all_reg_use_1): Likewise.
+ (ix86_find_all_reg_use): Likewise.
+ (ix86_find_max_used_stack_alignment): Also check memory accesses
+ from registers defined by stack or frame registers.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR ipa/119973
+ * tree-ssa-structalias.cc (create_variable_info_for):
+ Build constraints from DECL_INITIAL directly rather than
+ the IPA reference list which is incomplete.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR lto/113207
+ * ipa-free-lang-data.cc (fld_type_variant): Add extra checking.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/119044
+ * tree-predcom.cc (ref_at_iteration): Copy alias info
+ from the original ref.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/119103
+ * tree-ssa-loop-im.cc (in_loop_pipeline): Globalize.
+ (compute_invariantness): Override costing when we run
+ right before PRE and PRE is enabled.
+ (pass_lim::execute): Adjust.
+ * tree-vect-patterns.cc (vect_determine_precisions_from_users):
+ For variable shift amounts use range information.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ * genmatch.cc (::gen_transform): Add in_place parameter.
+ Assert it isn't set in unexpected places.
+ (possible_noop_convert): New.
+ (expr::gen_transform): Support in_place and emit code to
+ compute a child in-place when the operation is a conversion.
+ (dt_simplify::gen_1): Arrange for an outermost conversion
+ to be elided by generating the transform of the operand
+ in-place.
+ * match.pd (__real cepxi (x) -> cos (x)): Use single_use.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/60779
+ * common.opt (fcx-method=): New, map to flag_complex_method.
+ (Enum complex_method): New.
+ (fcx-limited-range): Alias to -fcx-method=limited-range.
+ (fcx-fortran-rules): Alias to -fcx-medhot=fortran.
+ * ipa-inline-transform.cc (inline_call): Check flag_complex_method.
+ * ipa-inline.cc (can_inline_edge_by_limits_p): Likewise.
+ * opts.cc (finish_options): Adjust.
+ (set_fast_math_flags): Likewise.
+ * doc/invoke.texi (fcx-method=): Document.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/116083
+ * stor-layout.cc (layout_type): Compute TYPE_SIZE and
+ TYPE_SIZE_UNIT for vector types from the component mode
+ sizes.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-loop.cc (vect_analyze_loop_operations): Prune
+ all actual analysis and only fail when we discover a not
+ SLP covered stmt.
+ (vect_analyze_loop_2): Remove path trying without SLP.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ * tree-vect-loop.cc (vect_loop_kill_debug_uses): Remove.
+ (maybe_set_vectorized_backedge_value): Likewise.
+ (vect_transform_loop_stmt): Likewise. Move dump printing
+ to vect_transform_stmt.
+ (vect_transform_loop): Remove loop over loop stmts transforming
+ them, but retain some DCE code still necessary.
+ * tree-vect-stmts.cc (vect_transform_stmt): Dump that
+ we're vectorizing a stmt.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ * params.opt (--param=vect-force-slp): Remove.
+ * doc/invoke.texi (--param=vect-force-slp): Likewise.
+ * tree-vect-loop.cc (vect_analyze_loop_2): Assume
+ param_vect_force_slp is 1.
+ * tree-vect-stmts.cc (vect_analyze_stmt): Likewise.
+
+2025-04-28 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/119493
+ * tree-tailcall.cc (find_tail_calls): Handle non-gimple_reg_type
+ arguments which aren't just passed through for tail recursions
+ even for non-musttail calls.
+
+2025-04-28 LIU Hao <lh_mouse@126.com>
+
+ PR target/111107
+ * config/i386/cygming.h (STACK_REALIGN_DEFAULT): Copy from sol2.h.
+
2025-04-27 H.J. Lu <hjl.tools@gmail.com>
PR c/48274
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index bd9df64..e697180 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20250428
+20250429
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index 443dc6d..ce2f385 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,422 @@
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/111536
+ * engine.cc (maybe_update_for_edge): Update for new call_stmt
+ param to region_model::push_frame.
+ * program-state.cc (program_state::push_frame): Likewise.
+ * region-model.cc (region_model::update_for_gcall): Likewise.
+ (region_model::push_frame): Add "call_stmt" param.
+ Handle DECL_RESULT with DECL_BY_REFERENCE set on it by stashing
+ the region of the lhs of the call_stmt in the caller frame,
+ and writing a reference to it within the "result" in the callee
+ frame.
+ (region_model::pop_frame): Don't write back to the LHS for
+ DECL_BY_REFERENCE results.
+ (selftest::test_stack_frames): Update for new call_stmt param to
+ region_model::push_frame.
+ (selftest::test_get_representative_path_var): Likewise.
+ (selftest::test_state_merging): Likewise.
+ (selftest::test_alloca): Likewise.
+ * region-model.h (region_model::push_frame): Add "call_stmt"
+ param.
+ * region.cc: Include "tree-ssa.h".
+ (region::can_have_initial_svalue_p): Use ssa_defined_default_def_p
+ for ssa names, rather than special-casing it for just parameters.
+ This should now also cover DECL_RESULT with DECL_BY_REFERENCE and
+ hard registers.
+ * sm-signal.cc (update_model_for_signal_handler): Update for new
+ call_stmt param to region_model::push_frame.
+ * state-purge.cc (state_purge_per_decl::process_worklists):
+ Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/109366
+ * region-model-manager.cc
+ (region_model_manager::maybe_fold_sub_svalue): Sub-values of zero
+ constants are zero.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/97111
+ * analyzer.cc (is_cxa_throw_p): New.
+ (is_cxa_rethrow_p): New.
+ * analyzer.opt (Wanalyzer-throw-of-unexpected-type): New.
+ * analyzer.opt.urls: Regenerate.
+ * call-info.cc (custom_edge_info::create_enode): New.
+ * call-info.h (call_info::print): Drop "final".
+ (call_info::add_events_to_path): Likewise.
+ * checker-event.cc (event_kind_to_string): Add cases for
+ event_kind::catch_, event_kind::throw_, and event_kind::unwind.
+ (explicit_throw_event::print_desc): New.
+ (throw_from_call_to_external_fn_event::print_desc): New.
+ (unwind_event::print_desc): New.
+ * checker-event.h (enum class event_kind): Add catch_, throw_,
+ and unwind.
+ (class catch_cfg_edge_event): New.
+ (class throw_event): New.
+ (class explicit_throw_event): New.
+ (class throw_from_call_to_external_fn_event): New.
+ (class unwind_event): New.
+ * common.h (class eh_dispatch_cfg_superedge): New forward decl.
+ (class eh_dispatch_try_cfg_superedge): New forward decl.
+ (class eh_dispatch_allowed_cfg_superedge): New forward decl.
+ (custom_edge_info::create_enode): New vfunc decl.
+ (is_cxa_throw_p): New decl.
+ (is_cxa_rethrow_p): New decl.
+ * diagnostic-manager.cc
+ (diagnostic_manager::add_events_for_superedge): Special-case edges
+ for eh_dispach_try.
+ (diagnostic_manager::prune_path): Call consolidate_unwind_events.
+ (diagnostic_manager::prune_for_sm_diagnostic): Don't filter the new
+ event_kinds.
+ (diagnostic_manager::consolidate_unwind_events): New.
+ * diagnostic-manager.h
+ (diagnostic_manager::consolidate_unwind_events): New decl.
+ * engine.cc (exploded_node::on_stmt_pre): Handle "__cxa_throw",
+ "__cxa_rethrow", and resx statements.
+ (class throw_custom_edge): New.
+ (class unwind_custom_edge): New.
+ (get_eh_outedge): New.
+ (exploded_graph::unwind_from_exception): New.
+ (exploded_node::on_throw): New.
+ (exploded_node::on_resx): New.
+ (exploded_graph::get_or_create_node): Add "add_to_worklist" param
+ and use it.
+ (exploded_graph::process_node): Use edge_info's create_enode vfunc
+ to create enodes, rather than calling get_or_create_node directly.
+ Ignore CFG edges in the sgraph flagged with EH whilst we're
+ exploring the egraph.
+ (exploded_graph_annotator::print_enode): Handle case
+ exploded_node::status::special.
+ * exploded-graph.h (exploded_node::status): Add value "special".
+ (exploded_node::on_throw): New decl.
+ (exploded_node::on_resx): New decl.
+ (exploded_graph::get_or_create_node): Add optional
+ "add_to_worklist" param.
+ (exploded_graph::unwind_from_exception): New decl.
+ * kf-lang-cp.cc (class kf_cxa_allocate_exception): New.
+ (class kf_cxa_begin_catch): New.
+ (class kf_cxa_end_catch): New.
+ (class throw_of_unexpected_type): New.
+ (class kf_cxa_call_unexpected): New.
+ (register_known_functions_lang_cp): Register known functions
+ "__cxa_allocate_exception", "__cxa_begin_catch",
+ "__cxa_end_catch", and "__cxa_call_unexpected".
+ * kf.cc (class kf_eh_pointer): New.
+ (register_known_functions): Register it for BUILT_IN_EH_POINTER.
+ * region-model.cc: Include "analyzer/function-set.h".
+ (exception_node::operator==): New.
+ (exception_node::dump_to_pp): New.
+ (exception_node::dump): New.
+ (exception_node::to_json): New.
+ (exception_node::make_dump_widget): New.
+ (exception_node::maybe_get_type): New.
+ (exception_node::add_to_reachable_regions): New.
+ (region_model::region_model): Initialize
+ m_thrown_exceptions_stack and m_caught_exceptions_stack.
+ (region_model::operator=): Likewise.
+ (region_model::operator==): Compare them.
+ (region_model::dump_to_pp): Dump exception stacks.
+ (region_model::to_json): Add exception stacks.
+ (region_model::make_dump_widget): Likewise.
+ (class exception_thrown_from_unrecognized_call): New.
+ (get_fns_assumed_not_to_throw): New.
+ (can_throw_p): New.
+ (region_model::check_for_throw_inside_call): New.
+ (region_model::on_call_pre): Call check_for_throw_inside_call
+ on unknown fns or those we don't have a body for.
+ (region_model::maybe_update_for_edge): Handle eh_dispatch_stmt
+ statements. Drop old code that called
+ apply_constraints_for_exception on EDGE_EH edges.
+ (class rejected_eh_dispatch): New.
+ (exception_matches_type_p): New.
+ (matches_any_exception_type_p): New.
+ (region_model::apply_constraints_for_eh_dispatch): New.
+ (region_model::apply_constraints_for_eh_dispatch_try): New.
+ (region_model::apply_constraints_for_eh_dispatch_allowed): New.
+ (region_model::apply_constraints_for_exception): Delete.
+ (region_model::can_merge_with_p): Don't merge models with
+ non-equal exception stacks.
+ (region_model::get_referenced_base_regions): Add regions from
+ exception stacks.
+ * region-model.h (struct exception_node): New.
+ (region_model::push_thrown_exception): New.
+ (region_model::get_current_thrown_exception): New.
+ (region_model::pop_thrown_exception): New.
+ (region_model::push_caught_exception): New.
+ (region_model::get_current_caught_exception): New.
+ (region_model::pop_caught_exception): New.
+ (region_model::apply_constraints_for_eh_dispatch_try): New decl.
+ (region_model::apply_constraints_for_eh_dispatch_allowed) New decl.
+ (region_model::apply_constraints_for_exception): Delete.
+ (region_model::apply_constraints_for_eh_dispatch): New decl.
+ (region_model::check_for_throw_inside_call): New decl.
+ (region_model::m_thrown_exceptions_stack): New field.
+ (region_model::m_caught_exceptions_stack): New field.
+ * supergraph.cc: Include "except.h" and "analyzer/region-model.h".
+ (supergraph::add_cfg_edge): Special-case eh_dispatch edges.
+ (superedge::get_description): Use default_tree_printer.
+ (get_catch): New.
+ (eh_dispatch_cfg_superedge::make): New.
+ (eh_dispatch_cfg_superedge::eh_dispatch_cfg_superedge): New.
+ (eh_dispatch_cfg_superedge::get_eh_status): New.
+ (eh_dispatch_try_cfg_superedge::dump_label_to_pp): New.
+ (eh_dispatch_try_cfg_superedge::apply_constraints): New.
+ (eh_dispatch_allowed_cfg_superedge::eh_dispatch_allowed_cfg_superedge):
+ New.
+ (eh_dispatch_allowed_cfg_superedge::dump_label_to_pp): New.
+ (eh_dispatch_allowed_cfg_superedge::apply_constraints): New.
+ * supergraph.h: Include "except.h".
+ (superedge::dyn_cast_eh_dispatch_cfg_superedge): New vfunc.
+ (superedge::dyn_cast_eh_dispatch_try_cfg_superedge): New vfunc.
+ (superedge::dyn_cast_eh_dispatch_allowed_cfg_superedge): New
+ vfunc.
+ (class eh_dispatch_cfg_superedge): New.
+ (is_a_helper <const eh_dispatch_cfg_superedge *>::test): New.
+ (class eh_dispatch_try_cfg_superedge): New.
+ (is_a_helper <const eh_dispatch_try_cfg_superedge *>::test): New.
+ (class eh_dispatch_allowed_cfg_superedge): New.
+ (is_a_helper <const eh_dispatch_allowed_cfg_superedge *>::test):
+ New.
+ * svalue.cc (svalue::maybe_get_type_from_typeinfo): New.
+ * svalue.h (svalue::maybe_get_type_from_typeinfo): New decl.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * access-diagram.cc: Replace uses of ::make_unique with
+ std::make_unique.
+ * analyzer.cc: Likewise.
+ * bounds-checking.cc: Likewise.
+ * call-details.cc: Likewise.
+ * call-info.cc: Likewise.
+ * call-string.cc: Likewise.
+ * checker-path.cc: Likewise.
+ * common.h: Drop include of "make-unique.h".
+ * constraint-manager.cc: Replace uses of ::make_unique with
+ std::make_unique.
+ * diagnostic-manager.cc: Likewise.
+ * engine.cc: Likewise.
+ * infinite-loop.cc: Likewise.
+ * infinite-recursion.cc: Likewise.
+ * kf-analyzer.cc: Likewise.
+ * kf-lang-cp.cc: Likewise.
+ * kf.cc: Likewise.
+ * pending-diagnostic.cc: Likewise.
+ * program-point.cc: Likewise; drop #include.
+ * program-state.cc: Likewise.
+ * ranges.cc: Likewise.
+ * region-model.cc: Likewise.
+ * region.cc: Likewise; drop #include.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-pattern-test.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * sm.cc: Likewise.
+ * store.cc: Likewise.
+ * supergraph.cc: Likewise.
+ * svalue.cc: Likewise; drop #include.
+ * varargs.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * engine.cc (class plugin_analyzer_init_impl): Convert
+ "m_checkers" to use std::vector of std::unique_ptr. Convert
+ "m_known_fn_mgr" to a reference.
+ (impl_run_checkers): Convert "checkers" to use std::vector of
+ std::unique_ptr and move it into the extrinsic_state.
+ * program-state.cc (extrinsic_state::dump_to_pp): Update for
+ changes to m_checkers.
+ (extrinsic_state::to_json): Likewise.
+ (extrinsic_state::get_sm_idx_by_name): Likewise.
+ (selftest::test_sm_state_map): Update to use std::unique_ptr
+ for state machines.
+ (selftest::test_program_state_1): Likewise.
+ (selftest::test_program_state_2): Likewise.
+ (selftest::test_program_state_merging): Likewise.
+ (selftest::test_program_state_merging_2): Likewise.
+ * program-state.h (class extrinsic_state): Convert "m_checkers" to
+ use std::vector of std::unique_ptr and to be owned by this object,
+ rather than a reference. Add ctor for use in selftests.
+ * sm-fd.cc (make_fd_state_machine): Update to use std::unique_ptr.
+ * sm-file.cc (make_fileptr_state_machine): Likewise.
+ * sm-malloc.cc (make_malloc_state_machine): Likewise.
+ * sm-pattern-test.cc (make_pattern_test_state_machine): Likewise.
+ * sm-sensitive.cc (make_sensitive_state_machine): Likewise.
+ * sm-signal.cc (make_signal_state_machine): Likewise.
+ * sm-taint.cc (make_taint_state_machine): Likewise.
+ * sm.cc: Define INCLUDE_LIST.
+ (make_checkers): Return the vector directly, rather than pass it
+ in by reference. Update to use std::unique_ptr throughout. Use
+ an intermediate list, and use that to filter with
+ flag_analyzer_checker, fixing memory leak for this case.
+ * sm.h: (make_checkers): Return the vector directly, rather than
+ pass it in by reference, and use std::vector of std::unique_ptr.
+ (make_malloc_state_machine): Convert return type to use std::unique_ptr.
+ (make_fileptr_state_machine): Likewise.
+ (make_taint_state_machine): Likewise.
+ (make_sensitive_state_machine): Likewise.
+ (make_signal_state_machine): Likewise.
+ (make_pattern_test_state_machine): Likewise.
+ (make_va_list_state_machine): Likewise.
+ (make_fd_state_machine): Likewise.
+ * varargs.cc (make_va_list_state_machine): Update to use
+ std::unique_ptr.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * call-summary.cc (call_summary_replay::call_summary_replay):
+ Convert "summary" from call_summary * to call_summary &.
+ (call_summary_replay::dump_to_pp): Likewise for m_summary.
+ * call-summary.h (call_summary_replay::call_summary_replay):
+ Likewise for "summary".
+ (call_summary_replay::m_summary): Likewise.
+ * engine.cc (call_summary_edge_info::call_summary_edge_info):
+ Likewise.
+ (call_summary_edge_info::update_state): Likewise.
+ (call_summary_edge_info::update_model): Likewise.
+ (call_summary_edge_info::print_desc): Likewise for m_summary.
+ (call_summary_edge_info::m_summary): Likewise.
+ (exploded_node::replay_call_summaries): Update for change to
+ replay_call_summary.
+ (exploded_node::replay_call_summary): Convert "summary" from
+ call_summary * to call_summary &.
+ * exploded-graph.h (exploded_node::replay_call_summary): Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * analyzer.cc: Convert gcall * to gcall & where we know the
+ pointer must be non-null.
+ * call-details.cc: Likewise.
+ * call-details.h: Likewise.
+ * call-info.cc: Likewise.
+ * call-info.h: Likewise.
+ * call-summary.h: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-event.h: Likewise.
+ * common.h: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * engine.cc: Likewise.
+ * exploded-graph.h: Likewise.
+ * kf-analyzer.cc: Likewise.
+ * kf-lang-cp.cc: Likewise.
+ * kf.cc: Likewise.
+ * known-function-manager.cc: Likewise.
+ * program-state.cc: Likewise.
+ * program-state.h: Likewise.
+ * region-model.cc: Likewise.
+ * region-model.h: Likewise.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * sm.h: Likewise.
+ * store.cc: Likewise.
+ * store.h: Likewise.
+ * supergraph.cc: Likewise.
+ * supergraph.h: Likewise.
+ * svalue.h: Likewise.
+ * varargs.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * access-diagram.cc: Convert enum access_direction to
+ "enum class".
+ * bounds-checking.cc: Likewise.
+ * checker-event.cc: Convert enum event_kind to "enum class".
+ * checker-event.h: Likewise.
+ * checker-path.cc: Likewise.
+ * common.h: Convert enum access_direction to "enum class".
+ * constraint-manager.cc: Convert enum bound_kind to "enum class".
+ * constraint-manager.h: Likewise.
+ * diagnostic-manager.cc: Convert enum event_kind to "enum class".
+ * engine.cc: Convert enum status to "enum class".
+ * exploded-graph.h: Likewise.
+ * infinite-loop.cc: Likewise.
+ * kf-lang-cp.cc: Convert enum poison_kind to "enum class".
+ * kf.cc: Likewise.
+ * region-model-manager.cc: Likewise.
+ * region-model.cc: Likewise; also for enum access_direction.
+ * svalue.cc: Likewise.
+ * svalue.h: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * analyzer.h: Rename to...
+ * common.h: ...this. Add define of INCLUDE_VECTOR, includes of
+ "config.h", "system.h", "coretypes.h", "make-unique.h", "tree.h",
+ "function.h", "basic-block.h", "gimple.h", "options.h",
+ "bitmap.h", "diagnostic-core.h", and "diagnostic-path.h".
+ * access-diagram.h: Don't include "analyzer/analyzer.h".
+ * access-diagram.cc: Reorganize includes to #include
+ "analyzer/common.h" first, then group by subsystem, dropping
+ redundant headers.
+ * analysis-plan.cc: Likewise.
+ * analyzer-language.cc: Likewise.
+ * analyzer-pass.cc: Likewise.
+ * analyzer-selftests.cc: Likewise.
+ * analyzer.cc: Likewise.
+ * bounds-checking.cc: Likewise.
+ * call-details.cc: Likewise.
+ * call-info.cc: Likewise.
+ * call-string.cc: Likewise.
+ * call-summary.cc: Likewise.
+ * checker-event.cc: Likewise.
+ * checker-path.cc: Likewise.
+ * complexity.cc: Likewise.
+ * constraint-manager.cc: Likewise.
+ * diagnostic-manager.cc: Likewise.
+ * engine.cc: Likewise.
+ * feasible-graph.cc: Likewise.
+ * infinite-loop.cc: Likewise.
+ * infinite-recursion.cc: Likewise.
+ * kf-analyzer.cc: Likewise.
+ * kf-lang-cp.cc: Likewise.
+ * kf.cc: Likewise.
+ * known-function-manager.cc: Likewise.
+ * pending-diagnostic.cc: Likewise.
+ * program-point.cc: Likewise.
+ * program-state.cc: Likewise.
+ * ranges.cc: Likewise.
+ * record-layout.cc: Likewise.
+ * region-model-asm.cc: Likewise.
+ * region-model-manager.cc: Likewise.
+ * region-model-reachability.cc: Likewise.
+ * region-model.cc: Likewise.
+ * region.cc: Likewise.
+ * sm-fd.cc: Likewise.
+ * sm-file.cc: Likewise.
+ * sm-malloc.cc: Likewise.
+ * sm-pattern-test.cc: Likewise.
+ * sm-sensitive.cc: Likewise.
+ * sm-signal.cc: Likewise.
+ * sm-taint.cc: Likewise.
+ * sm.cc: Likewise.
+ * state-purge.cc: Likewise.
+ * store.cc: Likewise.
+ * supergraph.cc: Likewise.
+ * svalue.cc: Likewise.
+ * symbol.cc: Likewise.
+ * trimmed-graph.cc: Likewise.
+ * varargs.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * region-model.cc (region_model::on_stmt_pre): Use internal_error
+ if we see an unexpected gimple stmt code.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * call-details.cc (call_details::dump): New overload.
+ (call_details::make_dump_widget): New.
+ * call-details.h (call_details::dump): Declare new overload.
+ (call_details::make_dump_widget): New decl.
+
2025-03-14 Jakub Jelinek <jakub@redhat.com>
PR analyzer/119278
diff --git a/gcc/analyzer/access-diagram.cc b/gcc/analyzer/access-diagram.cc
index e1596bb..4283360 100644
--- a/gcc/analyzer/access-diagram.cc
+++ b/gcc/analyzer/access-diagram.cc
@@ -17,28 +17,18 @@ 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 "config.h"
#define INCLUDE_ALGORITHM
#define INCLUDE_MAP
#define INCLUDE_SET
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "diagnostic.h"
+#include "analyzer/common.h"
+
+#include "fold-const.h"
#include "intl.h"
-#include "make-unique.h"
-#include "tree-diagnostic.h" /* for default_tree_printer. */
-#include "analyzer/analyzer.h"
+
+#include "text-art/ruler.h"
+
#include "analyzer/region-model.h"
#include "analyzer/access-diagram.h"
-#include "text-art/ruler.h"
-#include "fold-const.h"
#include "analyzer/analyzer-selftests.h"
#if ENABLE_ANALYZER
@@ -245,7 +235,7 @@ get_access_size_str (style_manager &sm,
pp_format_decoder (&pp) = default_tree_printer;
if (num_bits.maybe_print_for_user (&pp, op.m_model))
{
- if (op.m_dir == DIR_READ)
+ if (op.m_dir == access_direction::read)
return fmt_styled_string (sm,
_("read of %qT (%s)"),
type,
@@ -257,7 +247,7 @@ get_access_size_str (style_manager &sm,
pp_formatted_text (&pp));
}
}
- if (op.m_dir == DIR_READ)
+ if (op.m_dir == access_direction::read)
{
if (auto p
= num_bits.maybe_get_formatted_str (sm, op.m_model,
@@ -284,13 +274,13 @@ get_access_size_str (style_manager &sm,
if (type)
{
- if (op.m_dir == DIR_READ)
+ if (op.m_dir == access_direction::read)
return fmt_styled_string (sm, _("read of %qT"), type);
else
return fmt_styled_string (sm, _("write of %qT"), type);
}
- if (op.m_dir == DIR_READ)
+ if (op.m_dir == access_direction::read)
return styled_string (sm, _("read"));
else
return styled_string (sm, _("write"));
@@ -375,11 +365,11 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
if (!wi::fits_uhwi_p (concrete_num_bytes))
return nullptr;
if (concrete_num_bytes == 1)
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, concrete_single_byte_fmt,
concrete_num_bytes.to_uhwi ()));
else
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, concrete_plural_bytes_fmt,
concrete_num_bytes.to_uhwi ()));
}
@@ -389,7 +379,7 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
pp_format_decoder (&pp) = default_tree_printer;
if (!num_bytes->maybe_print_for_user (&pp, model))
return nullptr;
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, symbolic_bytes_fmt,
pp_formatted_text (&pp)));
}
@@ -400,11 +390,11 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
if (!wi::fits_uhwi_p (concrete_num_bits))
return nullptr;
if (concrete_num_bits == 1)
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, concrete_single_bit_fmt,
concrete_num_bits.to_uhwi ()));
else
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, concrete_plural_bits_fmt,
concrete_num_bits.to_uhwi ()));
}
@@ -414,7 +404,7 @@ bit_size_expr::maybe_get_formatted_str (text_art::style_manager &sm,
pp_format_decoder (&pp) = default_tree_printer;
if (!m_num_bits.maybe_print_for_user (&pp, model))
return nullptr;
- return ::make_unique <text_art::styled_string>
+ return std::make_unique <text_art::styled_string>
(fmt_styled_string (sm, symbolic_bits_fmt,
pp_formatted_text (&pp)));
}
@@ -1975,11 +1965,11 @@ make_written_svalue_spatial_item (const access_operation &op,
if (const initial_svalue *initial_sval = sval.dyn_cast_initial_svalue ())
if (const string_region *string_reg
= initial_sval->get_region ()->dyn_cast_string_region ())
- return make_unique <string_literal_spatial_item>
+ return std::make_unique <string_literal_spatial_item>
(sval, actual_bits,
*string_reg, theme,
svalue_spatial_item::kind::WRITTEN);
- return make_unique <written_svalue_spatial_item> (op, sval, actual_bits);
+ return std::make_unique <written_svalue_spatial_item> (op, sval, actual_bits);
}
static std::unique_ptr<spatial_item>
@@ -2000,7 +1990,7 @@ make_existing_svalue_spatial_item (const svalue *sval,
const initial_svalue *initial_sval = (const initial_svalue *)sval;
if (const string_region *string_reg
= initial_sval->get_region ()->dyn_cast_string_region ())
- return make_unique <string_literal_spatial_item>
+ return std::make_unique <string_literal_spatial_item>
(*sval, bits,
*string_reg, theme,
svalue_spatial_item::kind::EXISTING);
@@ -2008,7 +1998,7 @@ make_existing_svalue_spatial_item (const svalue *sval,
}
case SK_COMPOUND:
- return make_unique<compound_svalue_spatial_item>
+ return std::make_unique<compound_svalue_spatial_item>
(*((const compound_svalue *)sval),
bits,
svalue_spatial_item::kind::EXISTING,
@@ -2116,7 +2106,7 @@ public:
}
m_col_widths
- = make_unique <table_dimension_sizes> (m_btm.get_num_columns ());
+ = std::make_unique <table_dimension_sizes> (m_btm.get_num_columns ());
/* Now create child widgets. */
@@ -2211,8 +2201,8 @@ private:
std::unique_ptr<boundaries>
find_boundaries () const
{
- std::unique_ptr<boundaries> result
- = make_unique<boundaries> (*m_op.m_base_region, m_logger);
+ auto result
+ = std::make_unique<boundaries> (*m_op.m_base_region, m_logger);
m_valid_region_spatial_item.add_boundaries (*result, m_logger);
m_accessed_region_spatial_item.add_boundaries (*result, m_logger);
@@ -2271,7 +2261,7 @@ private:
void add_direction_widget ()
{
- add_child (::make_unique<direction_widget> (*this, m_btm));
+ add_child (std::make_unique<direction_widget> (*this, m_btm));
}
void add_invalid_accesses_to_region_table (table &t_region)
@@ -2382,7 +2372,7 @@ private:
bit_size_expr num_before_bits
(invalid_before_bits.get_size (m_op.get_manager ()));
std::unique_ptr<styled_string> label;
- if (m_op.m_dir == DIR_READ)
+ if (m_op.m_dir == access_direction::read)
label = num_before_bits.maybe_get_formatted_str
(m_sm, m_op.m_model,
_("under-read of %wi bit"),
@@ -2423,7 +2413,7 @@ private:
maybe_add_gap (w, invalid_before_bits, valid_bits);
std::unique_ptr<styled_string> label;
- if (m_op.m_dir == DIR_READ)
+ if (m_op.m_dir == access_direction::read)
label = num_valid_bits.maybe_get_formatted_str (m_sm,
m_op.m_model,
_("size: %wi bit"),
@@ -2459,7 +2449,7 @@ private:
bit_size_expr num_after_bits
(invalid_after_bits.get_size (m_op.get_manager ()));
std::unique_ptr<styled_string> label;
- if (m_op.m_dir == DIR_READ)
+ if (m_op.m_dir == access_direction::read)
label = num_after_bits.maybe_get_formatted_str
(m_sm, m_op.m_model,
_("over-read of %wi bit"),
@@ -2658,7 +2648,7 @@ direction_widget::paint_to_canvas (canvas &canvas)
(canvas,
canvas_x,
canvas::range_t (get_y_range ()),
- (m_dia_impl.get_op ().m_dir == DIR_READ
+ (m_dia_impl.get_op ().m_dir == access_direction::read
? theme::y_arrow_dir::UP
: theme::y_arrow_dir::DOWN),
style_id);
@@ -2676,11 +2666,12 @@ access_diagram::access_diagram (const access_operation &op,
style_manager &sm,
const theme &theme,
logger *logger)
-: wrapper_widget (make_unique <access_diagram_impl> (op,
- region_creation_event_id,
- sm,
- theme,
- logger))
+: wrapper_widget
+ (std::make_unique <access_diagram_impl> (op,
+ region_creation_event_id,
+ sm,
+ theme,
+ logger))
{
}
diff --git a/gcc/analyzer/access-diagram.h b/gcc/analyzer/access-diagram.h
index ba4649a..e31dd28 100644
--- a/gcc/analyzer/access-diagram.h
+++ b/gcc/analyzer/access-diagram.h
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "text-art/canvas.h"
#include "text-art/theme.h"
#include "text-art/widget.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/store.h"
namespace ana {
diff --git a/gcc/analyzer/analysis-plan.cc b/gcc/analyzer/analysis-plan.cc
index 7ae01c0..c563554 100644
--- a/gcc/analyzer/analysis-plan.cc
+++ b/gcc/analyzer/analysis-plan.cc
@@ -18,27 +18,19 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "options.h"
-#include "cgraph.h"
+#include "analyzer/common.h"
+
#include "timevar.h"
-#include "ipa-utils.h"
-#include "function.h"
-#include "analyzer/analyzer.h"
-#include "diagnostic-core.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/analysis-plan.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
#include "gimple-iterator.h"
#include "digraph.h"
+#include "ipa-utils.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/analysis-plan.h"
#include "analyzer/supergraph.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/analyzer-language.cc b/gcc/analyzer/analyzer-language.cc
index a0fa9f5..9a25baf 100644
--- a/gcc/analyzer/analyzer-language.cc
+++ b/gcc/analyzer/analyzer-language.cc
@@ -18,15 +18,13 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
+#include "analyzer/common.h"
+
+#include "diagnostic.h"
#include "stringpool.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/analyzer-language.h"
#include "analyzer/analyzer-logging.h"
-#include "diagnostic.h"
/* Map from identifier to INTEGER_CST. */
static GTY (()) hash_map <tree, tree> *analyzer_stashed_constants;
diff --git a/gcc/analyzer/analyzer-pass.cc b/gcc/analyzer/analyzer-pass.cc
index ab41de4..b3a0dfd 100644
--- a/gcc/analyzer/analyzer-pass.cc
+++ b/gcc/analyzer/analyzer-pass.cc
@@ -18,15 +18,10 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "context.h"
+#include "analyzer/common.h"
+
#include "tree-pass.h"
-#include "diagnostic.h"
-#include "options.h"
-#include "tree.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/engine.h"
namespace {
diff --git a/gcc/analyzer/analyzer-selftests.cc b/gcc/analyzer/analyzer-selftests.cc
index 0f131f0..334c355 100644
--- a/gcc/analyzer/analyzer-selftests.cc
+++ b/gcc/analyzer/analyzer-selftests.cc
@@ -18,12 +18,10 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
+#include "analyzer/common.h"
+
#include "stringpool.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/analyzer-selftests.h"
#if CHECKING_P
diff --git a/gcc/analyzer/analyzer.cc b/gcc/analyzer/analyzer.cc
index da7491b..56cb370 100644
--- a/gcc/analyzer/analyzer.cc
+++ b/gcc/analyzer/analyzer.cc
@@ -18,20 +18,12 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic.h"
-#include "intl.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "tree-pretty-print.h"
#include "diagnostic-event-id.h"
#include "tree-dfa.h"
-#include "make-unique.h"
+#include "intl.h"
#if ENABLE_ANALYZER
@@ -227,11 +219,11 @@ std::unique_ptr<json::value>
tree_to_json (tree node)
{
if (!node)
- return ::make_unique<json::literal> (json::JSON_NULL);
+ return std::make_unique<json::literal> (json::JSON_NULL);
pretty_printer pp;
dump_generic_node (&pp, node, 0, TDF_VOPS|TDF_MEMSYMS, false);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
/* Generate a JSON value for EVENT_ID.
@@ -246,10 +238,10 @@ diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id)
{
pretty_printer pp;
pp_printf (&pp, "%@", &event_id);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
else
- return ::make_unique<json::literal> (json::JSON_NULL);
+ return std::make_unique<json::literal> (json::JSON_NULL);
}
/* Generate a JSON value for OFFSET.
@@ -261,7 +253,7 @@ bit_offset_to_json (const bit_offset_t &offset)
{
pretty_printer pp;
pp_wide_int_large (&pp, offset, SIGNED);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
/* Generate a JSON value for OFFSET.
@@ -273,7 +265,7 @@ byte_offset_to_json (const byte_offset_t &offset)
{
pretty_printer pp;
pp_wide_int_large (&pp, offset, SIGNED);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
/* Workaround for lack of const-correctness of ssa_default_def. */
@@ -298,12 +290,12 @@ get_ssa_default_def (const function &fun, tree var)
If LOOK_IN_STD is true, then also look for within std:: for the name. */
bool
-is_special_named_call_p (const gcall *call, const char *funcname,
+is_special_named_call_p (const gcall &call, const char *funcname,
unsigned int num_args, bool look_in_std)
{
gcc_assert (funcname);
- tree fndecl = gimple_call_fndecl (call);
+ tree fndecl = gimple_call_fndecl (&call);
if (!fndecl)
return false;
@@ -396,7 +388,7 @@ is_std_named_call_p (const_tree fndecl, const char *funcname)
bool
is_named_call_p (const_tree fndecl, const char *funcname,
- const gcall *call, unsigned int num_args)
+ const gcall &call, unsigned int num_args)
{
gcc_assert (fndecl);
gcc_assert (funcname);
@@ -404,7 +396,7 @@ is_named_call_p (const_tree fndecl, const char *funcname,
if (!is_named_call_p (fndecl, funcname))
return false;
- if (gimple_call_num_args (call) != num_args)
+ if (gimple_call_num_args (&call) != num_args)
return false;
return true;
@@ -414,7 +406,7 @@ is_named_call_p (const_tree fndecl, const char *funcname,
bool
is_std_named_call_p (const_tree fndecl, const char *funcname,
- const gcall *call, unsigned int num_args)
+ const gcall &call, unsigned int num_args)
{
gcc_assert (fndecl);
gcc_assert (funcname);
@@ -422,7 +414,7 @@ is_std_named_call_p (const_tree fndecl, const char *funcname,
if (!is_std_named_call_p (fndecl, funcname))
return false;
- if (gimple_call_num_args (call) != num_args)
+ if (gimple_call_num_args (&call) != num_args)
return false;
return true;
@@ -431,12 +423,12 @@ is_std_named_call_p (const_tree fndecl, const char *funcname,
/* Return true if stmt is a setjmp or sigsetjmp call. */
bool
-is_setjmp_call_p (const gcall *call)
+is_setjmp_call_p (const gcall &call)
{
if (is_special_named_call_p (call, "setjmp", 1)
|| is_special_named_call_p (call, "sigsetjmp", 2))
/* region_model::on_setjmp requires a pointer. */
- if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
+ if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (&call, 0))))
return true;
return false;
@@ -445,26 +437,46 @@ is_setjmp_call_p (const gcall *call)
/* Return true if stmt is a longjmp or siglongjmp call. */
bool
-is_longjmp_call_p (const gcall *call)
+is_longjmp_call_p (const gcall &call)
{
if (is_special_named_call_p (call, "longjmp", 2)
|| is_special_named_call_p (call, "siglongjmp", 2))
/* exploded_node::on_longjmp requires a pointer for the initial
argument. */
- if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, 0))))
+ if (POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (&call, 0))))
return true;
return false;
}
+bool
+is_cxa_throw_p (const gcall &call)
+{
+ tree fndecl = gimple_call_fndecl (&call);
+ if (!fndecl)
+ return false;
+
+ return is_named_call_p (fndecl, "__cxa_throw");
+}
+
+bool
+is_cxa_rethrow_p (const gcall &call)
+{
+ tree fndecl = gimple_call_fndecl (&call);
+ if (!fndecl)
+ return false;
+
+ return is_named_call_p (fndecl, "__cxa_rethrow");
+}
+
/* For a CALL that matched is_special_named_call_p or is_named_call_p for
some name, return a name for the called function suitable for use in
diagnostics (stripping the leading underscores). */
const char *
-get_user_facing_name (const gcall *call)
+get_user_facing_name (const gcall &call)
{
- tree fndecl = gimple_call_fndecl (call);
+ tree fndecl = gimple_call_fndecl (&call);
gcc_assert (fndecl);
tree identifier = DECL_NAME (fndecl);
diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt
index d5f82c6..2ca9058 100644
--- a/gcc/analyzer/analyzer.opt
+++ b/gcc/analyzer/analyzer.opt
@@ -222,6 +222,10 @@ Wanalyzer-tainted-size
Common Var(warn_analyzer_tainted_size) Init(1) Warning
Warn about code paths in which an unsanitized value is used as a size.
+Wanalyzer-throw-of-unexpected-type
+Common Var(warn_analyzer_throw_of_unexpected_type) Init(1) Warning
+Warn about code paths in which an exception of unexpected type is thrown.
+
Wanalyzer-undefined-behavior-ptrdiff
Common Var(warn_analyzer_undefined_behavior_ptrdiff) Init(1) Warning
Warn about code paths in which pointer subtraction involves undefined behavior.
diff --git a/gcc/analyzer/analyzer.opt.urls b/gcc/analyzer/analyzer.opt.urls
index 18a0d69..e76e6e5 100644
--- a/gcc/analyzer/analyzer.opt.urls
+++ b/gcc/analyzer/analyzer.opt.urls
@@ -114,6 +114,9 @@ UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-tainted-offset)
Wanalyzer-tainted-size
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-tainted-size)
+Wanalyzer-throw-of-unexpected-type
+UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-throw-of-unexpected-type)
+
Wanalyzer-undefined-behavior-ptrdiff
UrlSuffix(gcc/Static-Analyzer-Options.html#index-Wanalyzer-undefined-behavior-ptrdiff)
diff --git a/gcc/analyzer/bounds-checking.cc b/gcc/analyzer/bounds-checking.cc
index c83b419..a3b1345 100644
--- a/gcc/analyzer/bounds-checking.cc
+++ b/gcc/analyzer/bounds-checking.cc
@@ -17,21 +17,12 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
+#include "analyzer/common.h"
+
#include "intl.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
#include "diagnostic-diagram.h"
#include "diagnostic-format-sarif.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/checker-event.h"
@@ -105,9 +96,9 @@ public:
so we don't need an event for that. */
if (byte_capacity)
emission_path.add_event
- (make_unique<oob_region_creation_event_capacity> (byte_capacity,
- loc_info,
- *this));
+ (std::make_unique<oob_region_creation_event_capacity> (byte_capacity,
+ loc_info,
+ *this));
}
void maybe_add_sarif_properties (sarif_object &result_obj)
@@ -116,7 +107,7 @@ public:
sarif_property_bag &props = result_obj.get_or_create_properties ();
#define PROPERTY_PREFIX "gcc/analyzer/out_of_bounds/"
props.set_string (PROPERTY_PREFIX "dir",
- get_dir () == DIR_READ ? "read" : "write");
+ get_dir () == access_direction::read ? "read" : "write");
props.set (PROPERTY_PREFIX "model", m_model.to_json ());
props.set (PROPERTY_PREFIX "region", m_reg->to_json ());
props.set (PROPERTY_PREFIX "diag_arg", tree_to_json (m_diag_arg));
@@ -298,9 +289,9 @@ public:
{
if (m_byte_bound && TREE_CODE (m_byte_bound) == INTEGER_CST)
emission_path.add_event
- (make_unique<oob_region_creation_event_capacity> (m_byte_bound,
- loc_info,
- *this));
+ (std::make_unique<oob_region_creation_event_capacity> (m_byte_bound,
+ loc_info,
+ *this));
}
void maybe_add_sarif_properties (sarif_object &result_obj)
@@ -505,7 +496,7 @@ public:
}
}
- enum access_direction get_dir () const final override { return DIR_WRITE; }
+ enum access_direction get_dir () const final override { return access_direction::write; }
};
/* Concrete subclass to complain about buffer over-reads. */
@@ -689,7 +680,7 @@ public:
}
}
- enum access_direction get_dir () const final override { return DIR_READ; }
+ enum access_direction get_dir () const final override { return access_direction::read; }
};
/* Concrete subclass to complain about buffer underwrites. */
@@ -817,7 +808,7 @@ public:
}
}
- enum access_direction get_dir () const final override { return DIR_WRITE; }
+ enum access_direction get_dir () const final override { return access_direction::write; }
};
/* Concrete subclass to complain about buffer under-reads. */
@@ -945,7 +936,7 @@ public:
}
}
- enum access_direction get_dir () const final override { return DIR_READ; }
+ enum access_direction get_dir () const final override { return access_direction::read; }
};
/* Abstract class to complain about out-of-bounds read/writes where
@@ -1116,7 +1107,7 @@ public:
return true;
}
- enum access_direction get_dir () const final override { return DIR_WRITE; }
+ enum access_direction get_dir () const final override { return access_direction::write; }
};
/* Concrete subclass to complain about over-reads with symbolic values. */
@@ -1243,7 +1234,7 @@ public:
return true;
}
- enum access_direction get_dir () const final override { return DIR_READ; }
+ enum access_direction get_dir () const final override { return access_direction::read; }
};
const svalue *
@@ -1427,24 +1418,26 @@ region_model::check_symbolic_bounds (const region *base_reg,
default:
gcc_unreachable ();
break;
- case DIR_READ:
+ case access_direction::read:
gcc_assert (sval_hint == nullptr);
- ctxt->warn (make_unique<symbolic_buffer_over_read> (*this,
- sized_offset_reg,
- diag_arg,
- offset_tree,
- num_bytes_tree,
- capacity_tree));
+ ctxt->warn
+ (std::make_unique<symbolic_buffer_over_read> (*this,
+ sized_offset_reg,
+ diag_arg,
+ offset_tree,
+ num_bytes_tree,
+ capacity_tree));
return false;
break;
- case DIR_WRITE:
- ctxt->warn (make_unique<symbolic_buffer_overflow> (*this,
- sized_offset_reg,
- diag_arg,
- offset_tree,
- num_bytes_tree,
- capacity_tree,
- sval_hint));
+ case access_direction::write:
+ ctxt->warn
+ (std::make_unique<symbolic_buffer_overflow> (*this,
+ sized_offset_reg,
+ diag_arg,
+ offset_tree,
+ num_bytes_tree,
+ capacity_tree,
+ sval_hint));
return false;
break;
}
@@ -1535,18 +1528,20 @@ region_model::check_region_bounds (const region *reg,
default:
gcc_unreachable ();
break;
- case DIR_READ:
+ case access_direction::read:
gcc_assert (sval_hint == nullptr);
- ctxt->warn (make_unique<concrete_buffer_under_read> (*this, reg,
- diag_arg,
- bits_outside));
+ ctxt->warn
+ (std::make_unique<concrete_buffer_under_read> (*this, reg,
+ diag_arg,
+ bits_outside));
oob_safe = false;
break;
- case DIR_WRITE:
- ctxt->warn (make_unique<concrete_buffer_underwrite> (*this,
- reg, diag_arg,
- bits_outside,
- sval_hint));
+ case access_direction::write:
+ ctxt->warn
+ (std::make_unique<concrete_buffer_underwrite> (*this,
+ reg, diag_arg,
+ bits_outside,
+ sval_hint));
oob_safe = false;
break;
}
@@ -1571,20 +1566,22 @@ region_model::check_region_bounds (const region *reg,
default:
gcc_unreachable ();
break;
- case DIR_READ:
+ case access_direction::read:
gcc_assert (sval_hint == nullptr);
- ctxt->warn (make_unique<concrete_buffer_over_read> (*this,
- reg, diag_arg,
- bits_outside,
- bit_bound));
+ ctxt->warn
+ (std::make_unique<concrete_buffer_over_read> (*this,
+ reg, diag_arg,
+ bits_outside,
+ bit_bound));
oob_safe = false;
break;
- case DIR_WRITE:
- ctxt->warn (make_unique<concrete_buffer_overflow> (*this,
- reg, diag_arg,
- bits_outside,
- bit_bound,
- sval_hint));
+ case access_direction::write:
+ ctxt->warn
+ (std::make_unique<concrete_buffer_overflow> (*this,
+ reg, diag_arg,
+ bits_outside,
+ bit_bound,
+ sval_hint));
oob_safe = false;
break;
}
diff --git a/gcc/analyzer/call-details.cc b/gcc/analyzer/call-details.cc
index 4122f84..bca8658 100644
--- a/gcc/analyzer/call-details.cc
+++ b/gcc/analyzer/call-details.cc
@@ -18,28 +18,20 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "diagnostic.h"
#include "tree-diagnostic.h" /* for default_tree_printer. */
#include "gimple-pretty-print.h"
-#include "analyzer/region-model.h"
-#include "analyzer/call-details.h"
-#include "analyzer/ranges.h"
#include "stringpool.h"
#include "attribs.h"
-#include "make-unique.h"
#include "diagnostic-format-sarif.h"
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/region-model.h"
+#include "analyzer/call-details.h"
+#include "analyzer/ranges.h"
+
#if ENABLE_ANALYZER
namespace ana {
@@ -48,13 +40,13 @@ namespace ana {
/* call_details's ctor. */
-call_details::call_details (const gcall *call, region_model *model,
+call_details::call_details (const gcall &call, region_model *model,
region_model_context *ctxt)
: m_call (call), m_model (model), m_ctxt (ctxt),
m_lhs_type (NULL_TREE), m_lhs_region (NULL)
{
m_lhs_type = NULL_TREE;
- if (tree lhs = gimple_call_lhs (call))
+ if (tree lhs = gimple_call_lhs (&call))
{
m_lhs_region = model->get_lvalue (lhs, ctxt);
m_lhs_type = TREE_TYPE (lhs);
@@ -66,9 +58,11 @@ call_details::call_details (const gcall *call, region_model *model,
call_details::call_details (const call_details &cd,
region_model_context *ctxt)
+: m_call (cd.m_call), m_model (cd.m_model),
+ m_ctxt (ctxt),
+ m_lhs_type (cd.m_lhs_type),
+ m_lhs_region (cd.m_lhs_region)
{
- *this = cd;
- m_ctxt = ctxt;
}
/* Get the manager from m_model. */
@@ -252,7 +246,7 @@ call_details::set_any_lhs_with_defaults () const
unsigned
call_details::num_args () const
{
- return gimple_call_num_args (m_call);
+ return gimple_call_num_args (&m_call);
}
/* Return true if argument IDX is a size_t (or compatible with it). */
@@ -268,7 +262,7 @@ call_details::arg_is_size_p (unsigned idx) const
location_t
call_details::get_location () const
{
- return m_call->location;
+ return m_call.location;
}
/* Get argument IDX at the callsite as a tree. */
@@ -276,7 +270,7 @@ call_details::get_location () const
tree
call_details::get_arg_tree (unsigned idx) const
{
- return gimple_call_arg (m_call, idx);
+ return gimple_call_arg (&m_call, idx);
}
/* Get the type of argument IDX. */
@@ -284,7 +278,7 @@ call_details::get_arg_tree (unsigned idx) const
tree
call_details::get_arg_type (unsigned idx) const
{
- return TREE_TYPE (gimple_call_arg (m_call, idx));
+ return TREE_TYPE (gimple_call_arg (&m_call, idx));
}
/* Get argument IDX at the callsite as an svalue. */
@@ -340,7 +334,7 @@ void
call_details::dump_to_pp (pretty_printer *pp, bool simple) const
{
pp_string (pp, "gcall: ");
- pp_gimple_stmt_1 (pp, m_call, 0 /* spc */, TDF_NONE /* flags */);
+ pp_gimple_stmt_1 (pp, &m_call, 0 /* spc */, TDF_NONE /* flags */);
pp_newline (pp);
pp_string (pp, "return region: ");
if (m_lhs_region)
@@ -348,7 +342,7 @@ call_details::dump_to_pp (pretty_printer *pp, bool simple) const
else
pp_string (pp, "NULL");
pp_newline (pp);
- for (unsigned i = 0; i < gimple_call_num_args (m_call); i++)
+ for (unsigned i = 0; i < gimple_call_num_args (&m_call); i++)
{
const svalue *arg_sval = get_arg_svalue (i);
pp_printf (pp, "arg %i: ", i);
@@ -366,6 +360,65 @@ call_details::dump (bool simple) const
dump_to_pp (&pp, simple);
}
+/* Dump a tree-like representation of this call to stderr. */
+
+DEBUG_FUNCTION void
+call_details::dump () const
+{
+ text_art::dump (*this);
+}
+
+std::unique_ptr<text_art::tree_widget>
+call_details::make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> cd_widget
+ (tree_widget::from_fmt (dwi, nullptr, "Call Details"));
+
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_string (pp, "gcall: ");
+ pp_gimple_stmt_1 (pp, &m_call, 0 /* spc */, TDF_NONE /* flags */);
+ cd_widget->add_child (tree_widget::make (dwi, pp));
+ }
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ pp_string (pp, "return region: ");
+ if (m_lhs_region)
+ m_lhs_region->dump_to_pp (pp, true);
+ else
+ pp_string (pp, "NULL");
+ auto w = tree_widget::make (dwi, pp);
+ if (m_lhs_region)
+ w->add_child (m_lhs_region->make_dump_widget (dwi));
+ cd_widget->add_child (std::move (w));
+ }
+ if (gimple_call_num_args (&m_call) > 0)
+ {
+ std::unique_ptr<tree_widget> args_widget
+ (tree_widget::from_fmt (dwi, nullptr, "Arguments"));
+ for (unsigned i = 0; i < gimple_call_num_args (&m_call); i++)
+ {
+ pretty_printer the_pp;
+ pretty_printer * const pp = &the_pp;
+ pp_format_decoder (pp) = default_tree_printer;
+ const svalue *arg_sval = get_arg_svalue (i);
+ pp_printf (pp, "%i: ", i);
+ arg_sval->dump_to_pp (pp, true);
+ auto w = tree_widget::make (dwi, pp);
+ w->add_child (arg_sval->make_dump_widget (dwi));
+ args_widget->add_child (std::move (w));
+ }
+ cd_widget->add_child (std::move (args_widget));
+ }
+
+ return cd_widget;
+}
+
/* Get a conjured_svalue for this call for REG,
and purge any state already relating to that conjured_svalue. */
@@ -373,7 +426,7 @@ const svalue *
call_details::get_or_create_conjured_svalue (const region *reg) const
{
region_model_manager *mgr = m_model->get_manager ();
- return mgr->get_or_create_conjured_svalue (reg->get_type (), m_call, reg,
+ return mgr->get_or_create_conjured_svalue (reg->get_type (), &m_call, reg,
conjured_purge (m_model, m_ctxt));
}
@@ -388,7 +441,7 @@ call_details::lookup_function_attribute (const char *attr_name) const
if (tree fndecl = get_fndecl_for_call ())
allocfntype = TREE_TYPE (fndecl);
else
- allocfntype = gimple_call_fntype (m_call);
+ allocfntype = gimple_call_fntype (&m_call);
if (!allocfntype)
return NULL_TREE;
@@ -540,10 +593,10 @@ call_details::complain_about_overlap (unsigned arg_idx_a,
if (!byte_range_a.intersection (byte_range_b, *model).is_true ())
return;
- ctxt->warn (make_unique<overlapping_buffers> (get_fndecl_for_call (),
- byte_range_a,
- byte_range_b,
- num_bytes_read_sval));
+ ctxt->warn (std::make_unique<overlapping_buffers> (get_fndecl_for_call (),
+ byte_range_a,
+ byte_range_b,
+ num_bytes_read_sval));
}
} // namespace ana
diff --git a/gcc/analyzer/call-details.h b/gcc/analyzer/call-details.h
index fee7ad4..c0a9118 100644
--- a/gcc/analyzer/call-details.h
+++ b/gcc/analyzer/call-details.h
@@ -28,7 +28,7 @@ namespace ana {
class call_details
{
public:
- call_details (const gcall *call, region_model *model,
+ call_details (const gcall &call, region_model *model,
region_model_context *ctxt);
call_details (const call_details &cd, region_model_context *ctxt);
@@ -55,7 +55,7 @@ public:
return INTEGRAL_TYPE_P (get_arg_type (idx));
}
- const gcall *get_call_stmt () const { return m_call; }
+ const gcall &get_call_stmt () const { return m_call; }
location_t get_location () const;
tree get_arg_tree (unsigned idx) const;
@@ -68,6 +68,10 @@ public:
void dump_to_pp (pretty_printer *pp, bool simple) const;
void dump (bool simple) const;
+ void dump () const;
+
+ std::unique_ptr<text_art::tree_widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
const svalue *get_or_create_conjured_svalue (const region *) const;
@@ -86,7 +90,7 @@ public:
const svalue *num_bytes_read_sval) const;
private:
- const gcall *m_call;
+ const gcall &m_call;
region_model *m_model;
region_model_context *m_ctxt;
tree m_lhs_type;
@@ -110,13 +114,13 @@ public:
bool operator== (const call_arg_details &other) const
{
- return (m_call == other.m_call
+ return (&m_call == &other.m_call
&& m_called_fndecl == other.m_called_fndecl
&& m_arg_idx == other.m_arg_idx
&& pending_diagnostic::same_tree_p (m_arg_expr, other.m_arg_expr));
}
- const gcall *m_call;
+ const gcall &m_call;
tree m_called_fndecl;
unsigned m_arg_idx; // 0-based
tree m_arg_expr;
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index 1adbf64..9a698ef 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -18,45 +18,31 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "ordered-hash-map.h"
#include "cfg.h"
#include "digraph.h"
-#include "analyzer/supergraph.h"
#include "sbitmap.h"
+#include "diagnostic-event-id.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/supergraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "diagnostic-event-id.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/region-model-reachability.h"
#include "analyzer/analyzer-selftests.h"
#include "analyzer/program-state.h"
-#include "diagnostic-path.h"
#include "analyzer/checker-path.h"
#include "analyzer/diagnostic-manager.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -72,6 +58,18 @@ custom_edge_info::update_state (program_state *state,
return update_model (state->m_region_model, eedge, ctxt);
}
+/* Base implementation of custom_edge_info::create_enode vfunc. */
+
+exploded_node *
+custom_edge_info::create_enode (exploded_graph &eg,
+ const program_point &point,
+ program_state &&state,
+ exploded_node *enode_for_diag,
+ region_model_context *) const
+{
+ return eg.get_or_create_node (point, state, enode_for_diag);
+}
+
/* class call_info : public custom_edge_info. */
/* Implementation of custom_edge_info::print vfunc for call_info. */
@@ -115,7 +113,7 @@ call_info::add_events_to_path (checker_path *emission_path,
const int stack_depth = src_point.get_stack_depth ();
emission_path->add_event
- (make_unique<call_event> (event_loc_info (get_call_stmt ()->location,
+ (std::make_unique<call_event> (event_loc_info (get_call_stmt ().location,
caller_fndecl,
stack_depth),
this));
diff --git a/gcc/analyzer/call-info.h b/gcc/analyzer/call-info.h
index ec304d8..6548d86 100644
--- a/gcc/analyzer/call-info.h
+++ b/gcc/analyzer/call-info.h
@@ -30,11 +30,11 @@ namespace ana {
class call_info : public custom_edge_info
{
public:
- void print (pretty_printer *pp) const final override;
+ void print (pretty_printer *pp) const override;
void add_events_to_path (checker_path *emission_path,
- const exploded_edge &eedge) const final override;
+ const exploded_edge &eedge) const override;
- const gcall *get_call_stmt () const { return m_call_stmt; }
+ const gcall &get_call_stmt () const { return m_call_stmt; }
tree get_fndecl () const { return m_fndecl; }
virtual void print_desc (pretty_printer &pp) const = 0;
@@ -47,7 +47,7 @@ protected:
call_info (const call_details &cd, const function &called_fn);
private:
- const gcall *m_call_stmt;
+ const gcall &m_call_stmt;
tree m_fndecl;
};
diff --git a/gcc/analyzer/call-string.cc b/gcc/analyzer/call-string.cc
index 5099986..afa8004 100644
--- a/gcc/analyzer/call-string.cc
+++ b/gcc/analyzer/call-string.cc
@@ -18,26 +18,11 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "pretty-print.h"
-#include "tree.h"
-#include "options.h"
-#include "ordered-hash-map.h"
-#include "options.h"
-#include "cgraph.h"
-#include "function.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "digraph.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/supergraph.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -106,11 +91,11 @@ call_string::print (pretty_printer *pp) const
std::unique_ptr<json::value>
call_string::to_json () const
{
- auto arr = ::make_unique<json::array> ();
+ auto arr = std::make_unique<json::array> ();
for (const call_string::element_t &e : m_elements)
{
- auto e_obj = ::make_unique<json::object> ();
+ auto e_obj = std::make_unique<json::object> ();
e_obj->set_integer ("src_snode_idx", e.m_callee->m_index);
e_obj->set_integer ("dst_snode_idx", e.m_caller->m_index);
e_obj->set_string ("funcname", function_name (e.m_caller->m_fun));
diff --git a/gcc/analyzer/call-summary.cc b/gcc/analyzer/call-summary.cc
index 27fb575..33de3d6 100644
--- a/gcc/analyzer/call-summary.cc
+++ b/gcc/analyzer/call-summary.cc
@@ -17,16 +17,8 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "tree-dfa.h"
-#include "diagnostic-core.h"
-#include "diagnostic.h"
-#include "tree-diagnostic.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/region-model.h"
#include "analyzer/call-summary.h"
#include "analyzer/exploded-graph.h"
@@ -165,7 +157,7 @@ call_summary::dump (const extrinsic_state &ext_state, bool simple) const
call_summary_replay::call_summary_replay (const call_details &cd,
const function &called_fn,
- call_summary *summary,
+ call_summary &summary,
const extrinsic_state &ext_state)
: m_cd (cd),
m_summary (summary),
@@ -816,7 +808,7 @@ call_summary_replay::dump_to_pp (pretty_printer *pp, bool simple) const
pp_newline (pp);
pp_string (pp, "CALLEE SUMMARY:");
pp_newline (pp);
- m_summary->dump_to_pp (m_ext_state, pp, simple);
+ m_summary.dump_to_pp (m_ext_state, pp, simple);
/* Current state of caller (could be in mid-update). */
pp_newline (pp);
diff --git a/gcc/analyzer/call-summary.h b/gcc/analyzer/call-summary.h
index 220dd083..7280cca 100644
--- a/gcc/analyzer/call-summary.h
+++ b/gcc/analyzer/call-summary.h
@@ -69,11 +69,11 @@ class call_summary_replay
public:
call_summary_replay (const call_details &cd,
const function &called_fn,
- call_summary *m_summary,
+ call_summary &summary,
const extrinsic_state &ext_state);
const call_details &get_call_details () const { return m_cd; }
- const gcall *get_call_stmt () const { return m_cd.get_call_stmt (); }
+ const gcall &get_call_stmt () const { return m_cd.get_call_stmt (); }
region_model_manager *get_manager () const { return m_cd.get_manager (); }
store_manager *get_store_manager () const
{
@@ -102,7 +102,7 @@ private:
const region *convert_region_from_summary_1 (const region *);
const call_details &m_cd;
- call_summary *m_summary;
+ call_summary &m_summary;
const extrinsic_state &m_ext_state;
// Mapping from svalues in summary to svalues for callsite:
diff --git a/gcc/analyzer/checker-event.cc b/gcc/analyzer/checker-event.cc
index 5d7647c..958cdbf 100644
--- a/gcc/analyzer/checker-event.cc
+++ b/gcc/analyzer/checker-event.cc
@@ -18,45 +18,31 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
+#include "analyzer/common.h"
+
#include "gimple-pretty-print.h"
+#include "sbitmap.h"
+#include "ordered-hash-map.h"
#include "fold-const.h"
-#include "diagnostic-path.h"
-#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
-#include "digraph.h"
-#include "diagnostic-event-id.h"
-#include "analyzer/analyzer.h"
+#include "gimple-iterator.h"
+#include "inlining-iterator.h"
+#include "tree-logical-location.h"
+#include "diagnostic-format-sarif.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-path.h"
-#include "gimple-iterator.h"
-#include "inlining-iterator.h"
#include "analyzer/supergraph.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
#include "analyzer/constraint-manager.h"
#include "analyzer/checker-event.h"
#include "analyzer/exploded-graph.h"
-#include "diagnostic-format-sarif.h"
-#include "tree-logical-location.h"
#if ENABLE_ANALYZER
@@ -71,40 +57,46 @@ event_kind_to_string (enum event_kind ek)
{
default:
gcc_unreachable ();
- case EK_DEBUG:
- return "EK_DEBUG";
- case EK_CUSTOM:
- return "EK_CUSTOM";
- case EK_STMT:
- return "EK_STMT";
- case EK_REGION_CREATION:
- return "EK_REGION_CREATION";
- case EK_FUNCTION_ENTRY:
- return "EK_FUNCTION_ENTRY";
- case EK_STATE_CHANGE:
- return "EK_STATE_CHANGE";
- case EK_START_CFG_EDGE:
- return "EK_START_CFG_EDGE";
- case EK_END_CFG_EDGE:
- return "EK_END_CFG_EDGE";
- case EK_CALL_EDGE:
- return "EK_CALL_EDGE";
- case EK_RETURN_EDGE:
- return "EK_RETURN_EDGE";
- case EK_START_CONSOLIDATED_CFG_EDGES:
- return "EK_START_CONSOLIDATED_CFG_EDGES";
- case EK_END_CONSOLIDATED_CFG_EDGES:
- return "EK_END_CONSOLIDATED_CFG_EDGES";
- case EK_INLINED_CALL:
- return "EK_INLINED_CALL";
- case EK_SETJMP:
- return "EK_SETJMP";
- case EK_REWIND_FROM_LONGJMP:
- return "EK_REWIND_FROM_LONGJMP";
- case EK_REWIND_TO_SETJMP:
- return "EK_REWIND_TO_SETJMP";
- case EK_WARNING:
- return "EK_WARNING";
+ case event_kind::debug:
+ return "debug";
+ case event_kind::custom:
+ return "custom";
+ case event_kind::stmt:
+ return "stmt";
+ case event_kind::region_creation:
+ return "region_creation";
+ case event_kind::function_entry:
+ return "function_entry";
+ case event_kind::state_change:
+ return "state_change";
+ case event_kind::start_cfg_edge:
+ return "start_cfg_edge";
+ case event_kind::end_cfg_edge:
+ return "end_cfg_edge";
+ case event_kind::catch_:
+ return "catch";
+ case event_kind::call_edge:
+ return "call_edge";
+ case event_kind::return_edge:
+ return "return_edge";
+ case event_kind::start_consolidated_cfg_edges:
+ return "start_consolidated_cfg_edges";
+ case event_kind::end_consolidated_cfg_edges:
+ return "end_consolidated_cfg_edges";
+ case event_kind::inlined_call:
+ return "inlined_call";
+ case event_kind::setjmp_:
+ return "setjmp";
+ case event_kind::rewind_from_longjmp:
+ return "rewind_from_longjmp";
+ case event_kind::rewind_to_setjmp:
+ return "rewind_to_setjmp";
+ case event_kind::throw_:
+ return "throw";
+ case event_kind::unwind:
+ return "unwind";
+ case event_kind::warning:
+ return "warning";
}
}
@@ -258,7 +250,7 @@ precanned_custom_event::print_desc (pretty_printer &pp) const
statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
const program_state &dst_state)
-: checker_event (EK_STMT,
+: checker_event (event_kind::stmt,
event_loc_info (gimple_location (stmt), fndecl, depth)),
m_stmt (stmt),
m_dst_state (dst_state)
@@ -279,7 +271,7 @@ statement_event::print_desc (pretty_printer &pp) const
/* class region_creation_event : public checker_event. */
region_creation_event::region_creation_event (const event_loc_info &loc_info)
-: checker_event (EK_REGION_CREATION, loc_info)
+: checker_event (event_kind::region_creation, loc_info)
{
}
@@ -351,7 +343,7 @@ region_creation_event_debug::print_desc (pretty_printer &pp) const
/* class function_entry_event : public checker_event. */
function_entry_event::function_entry_event (const program_point &dst_point)
-: checker_event (EK_FUNCTION_ENTRY,
+: checker_event (event_kind::function_entry,
event_loc_info (dst_point.get_supernode
()->get_start_location (),
dst_point.get_fndecl (),
@@ -393,7 +385,7 @@ state_change_event::state_change_event (const supernode *node,
const svalue *origin,
const program_state &dst_state,
const exploded_node *enode)
-: checker_event (EK_STATE_CHANGE,
+: checker_event (event_kind::state_change,
event_loc_info (stmt->location,
node->m_fun->decl,
stack_depth)),
@@ -741,7 +733,7 @@ start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
&& zerop (rhs))
{
if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
- if (is_special_named_call_p (call, "strcmp", 2))
+ if (is_special_named_call_p (*call, "strcmp", 2))
{
if (op == EQ_EXPR)
return label_text::borrow ("when the strings are equal");
@@ -804,7 +796,7 @@ start_cfg_edge_event::should_print_expr_p (tree expr)
call_event::call_event (const exploded_edge &eedge,
const event_loc_info &loc_info)
-: superedge_event (EK_CALL_EDGE, eedge, loc_info)
+: superedge_event (event_kind::call_edge, eedge, loc_info)
{
if (eedge.m_sedge)
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
@@ -880,7 +872,7 @@ call_event::get_callee_fndecl () const
return_event::return_event (const exploded_edge &eedge,
const event_loc_info &loc_info)
-: superedge_event (EK_RETURN_EDGE, eedge, loc_info)
+: superedge_event (event_kind::return_edge, eedge, loc_info)
{
if (eedge.m_sedge)
gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
@@ -1118,6 +1110,50 @@ rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
&m_original_setjmp_event_id);
}
+/* class throw_event : public checker_event. */
+
+/* class explicit_throw_event : public throw_event. */
+void
+explicit_throw_event::print_desc (pretty_printer &pp) const
+{
+ if (m_is_rethrow)
+ {
+ if (m_type)
+ pp_printf (&pp, "rethrowing exception of type %qT here...", m_type);
+ else
+ pp_printf (&pp, "rethrowing exception here...");
+ }
+ else
+ {
+ if (m_type)
+ pp_printf (&pp, "throwing exception of type %qT here...", m_type);
+ else
+ pp_printf (&pp, "throwing exception here...");
+ }
+}
+
+/* class throw_from_call_to_external_fn_event : public throw_event. */
+
+void
+throw_from_call_to_external_fn_event::print_desc (pretty_printer &pp) const
+{
+ if (m_fndecl)
+ pp_printf (&pp, "if %qD throws an exception...", m_fndecl);
+ else
+ pp_printf (&pp, "if the called function throws an exception...");
+}
+
+// class unwind_event : public checker_event
+
+void
+unwind_event::print_desc (pretty_printer &pp) const
+{
+ if (m_num_frames > 1)
+ pp_printf (&pp, "unwinding %i stack frames", m_num_frames);
+ else
+ pp_printf (&pp, "unwinding stack frame");
+}
+
/* class warning_event : public checker_event. */
/* Implementation of diagnostic_event::print_desc vfunc for
diff --git a/gcc/analyzer/checker-event.h b/gcc/analyzer/checker-event.h
index f92f514..f3ab899 100644
--- a/gcc/analyzer/checker-event.h
+++ b/gcc/analyzer/checker-event.h
@@ -30,25 +30,28 @@ namespace ana {
/* An enum for discriminating between the concrete subclasses of
checker_event. */
-enum event_kind
-{
- EK_DEBUG,
- EK_CUSTOM,
- EK_STMT,
- EK_REGION_CREATION,
- EK_FUNCTION_ENTRY,
- EK_STATE_CHANGE,
- EK_START_CFG_EDGE,
- EK_END_CFG_EDGE,
- EK_CALL_EDGE,
- EK_RETURN_EDGE,
- EK_START_CONSOLIDATED_CFG_EDGES,
- EK_END_CONSOLIDATED_CFG_EDGES,
- EK_INLINED_CALL,
- EK_SETJMP,
- EK_REWIND_FROM_LONGJMP,
- EK_REWIND_TO_SETJMP,
- EK_WARNING
+enum class event_kind
+{
+ debug,
+ custom,
+ stmt,
+ region_creation,
+ function_entry,
+ state_change,
+ start_cfg_edge,
+ end_cfg_edge,
+ catch_,
+ call_edge,
+ return_edge,
+ start_consolidated_cfg_edges,
+ end_consolidated_cfg_edges,
+ inlined_call,
+ setjmp_,
+ rewind_from_longjmp,
+ rewind_to_setjmp,
+ throw_,
+ unwind,
+ warning
};
extern const char *event_kind_to_string (enum event_kind ek);
@@ -60,27 +63,32 @@ extern const char *event_kind_to_string (enum event_kind ek);
diagnostic_event
checker_event
- debug_event (EK_DEBUG)
- custom_event (EK_CUSTOM)
+ debug_event (event_kind::debug)
+ custom_event (event_kind::custom)
precanned_custom_event
- statement_event (EK_STMT)
- region_creation_event (EK_REGION_CREATION)
- function_entry_event (EK_FUNCTION_ENTRY)
- state_change_event (EK_STATE_CHANGE)
+ statement_event (event_kind::stmt)
+ region_creation_event (event_kind::region_creation)
+ function_entry_event (event_kind::function_entry)
+ state_change_event (event_kind::state_change)
superedge_event
cfg_edge_event
- start_cfg_edge_event (EK_START_CFG_EDGE)
- end_cfg_edge_event (EK_END_CFG_EDGE)
- call_event (EK_CALL_EDGE)
- return_edge (EK_RETURN_EDGE)
- start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
- end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
- inlined_call_event (EK_INLINED_CALL)
- setjmp_event (EK_SETJMP)
+ start_cfg_edge_event (event_kind::start_cfg_edge)
+ end_cfg_edge_event (event_kind::end_cfg_edge)
+ catch_cfg_edge_event (event_kind::catch_cfg_edge)
+ call_event (event_kind::call_edge)
+ return_edge (event_kind::return_edge)
+ start_consolidated_cfg_edges_event (event_kind::start_consolidated_cfg_edges)
+ end_consolidated_cfg_edges_event (event_kind::end_consolidated_cfg_edges)
+ inlined_call_event (event_kind::inlined_call)
+ setjmp_event (event_kind::setjmp_)
rewind_event
- rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
- rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
- warning_event (EK_WARNING). */
+ rewind_from_longjmp_event (event_kind::rewind_from_longjmp)
+ rewind_to_setjmp_event (event_kind::rewind_to_setjmp)
+ throw_event (event_kind:throw_)
+ explicit_throw_event
+ throw_from_call_to_external_fn_event
+ unwind_event (event_kind::unwind)
+ warning_event (event_kind::warning). */
/* Abstract subclass of diagnostic_event; the base class for use in
checker_path (the analyzer's diagnostic_path subclass). */
@@ -158,7 +166,7 @@ public:
debug_event (const event_loc_info &loc_info,
const char *desc)
- : checker_event (EK_DEBUG, loc_info),
+ : checker_event (event_kind::debug, loc_info),
m_desc (xstrdup (desc))
{
}
@@ -180,7 +188,7 @@ class custom_event : public checker_event
{
protected:
custom_event (const event_loc_info &loc_info)
- : checker_event (EK_CUSTOM, loc_info)
+ : checker_event (event_kind::custom, loc_info)
{
}
};
@@ -329,7 +337,7 @@ class function_entry_event : public checker_event
{
public:
function_entry_event (const event_loc_info &loc_info)
- : checker_event (EK_FUNCTION_ENTRY, loc_info)
+ : checker_event (event_kind::function_entry, loc_info)
{
}
@@ -435,7 +443,7 @@ class start_cfg_edge_event : public cfg_edge_event
public:
start_cfg_edge_event (const exploded_edge &eedge,
const event_loc_info &loc_info)
- : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc_info)
+ : cfg_edge_event (event_kind::start_cfg_edge, eedge, loc_info)
{
}
@@ -461,7 +469,7 @@ class end_cfg_edge_event : public cfg_edge_event
public:
end_cfg_edge_event (const exploded_edge &eedge,
const event_loc_info &loc_info)
- : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc_info)
+ : cfg_edge_event (event_kind::end_cfg_edge, eedge, loc_info)
{
}
@@ -471,6 +479,32 @@ public:
}
};
+/* A concrete event subclass for catching an exception
+ e.g. "...catching 'struct io_error' here". */
+
+class catch_cfg_edge_event : public cfg_edge_event
+{
+public:
+ catch_cfg_edge_event (const exploded_edge &eedge,
+ const event_loc_info &loc_info,
+ tree type)
+ : cfg_edge_event (event_kind::catch_, eedge, loc_info),
+ m_type (type)
+ {
+ }
+
+ void print_desc (pretty_printer &pp) const final override
+ {
+ if (m_type)
+ pp_printf (&pp, "...catching exception of type %qT here", m_type);
+ else
+ pp_string (&pp, "...catching exception here");
+ }
+
+private:
+ tree m_type;
+};
+
/* A concrete event subclass for an interprocedural call. */
class call_event : public superedge_event
@@ -517,7 +551,7 @@ class start_consolidated_cfg_edges_event : public checker_event
public:
start_consolidated_cfg_edges_event (const event_loc_info &loc_info,
bool edge_sense)
- : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc_info),
+ : checker_event (event_kind::start_consolidated_cfg_edges, loc_info),
m_edge_sense (edge_sense)
{
}
@@ -537,7 +571,7 @@ class end_consolidated_cfg_edges_event : public checker_event
{
public:
end_consolidated_cfg_edges_event (const event_loc_info &loc_info)
- : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc_info)
+ : checker_event (event_kind::end_consolidated_cfg_edges, loc_info)
{
}
@@ -558,7 +592,7 @@ public:
tree apparent_caller_fndecl,
int actual_depth,
int stack_depth_adjustment)
- : checker_event (EK_INLINED_CALL,
+ : checker_event (event_kind::inlined_call,
event_loc_info (loc,
apparent_caller_fndecl,
actual_depth + stack_depth_adjustment)),
@@ -583,8 +617,8 @@ class setjmp_event : public checker_event
public:
setjmp_event (const event_loc_info &loc_info,
const exploded_node *enode,
- const gcall *setjmp_call)
- : checker_event (EK_SETJMP, loc_info),
+ const gcall &setjmp_call)
+ : checker_event (event_kind::setjmp_, loc_info),
m_enode (enode), m_setjmp_call (setjmp_call)
{
}
@@ -597,7 +631,7 @@ public:
private:
const exploded_node *m_enode;
- const gcall *m_setjmp_call;
+ const gcall &m_setjmp_call;
};
/* An abstract event subclass for rewinding from a longjmp to a setjmp
@@ -633,7 +667,7 @@ public:
rewind_from_longjmp_event (const exploded_edge *eedge,
const event_loc_info &loc_info,
const rewind_info_t *rewind_info)
- : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc_info,
+ : rewind_event (eedge, event_kind::rewind_from_longjmp, loc_info,
rewind_info)
{
}
@@ -650,7 +684,7 @@ public:
rewind_to_setjmp_event (const exploded_edge *eedge,
const event_loc_info &loc_info,
const rewind_info_t *rewind_info)
- : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc_info,
+ : rewind_event (eedge, event_kind::rewind_to_setjmp, loc_info,
rewind_info)
{
}
@@ -665,6 +699,88 @@ private:
diagnostic_event_id_t m_original_setjmp_event_id;
};
+/* An abstract subclass for throwing/rethrowing an exception. */
+
+class throw_event : public checker_event
+{
+public:
+ throw_event (const event_loc_info &loc_info,
+ const exploded_node *enode,
+ const gcall &throw_call)
+ : checker_event (event_kind::throw_, loc_info),
+ m_enode (enode),
+ m_throw_call (throw_call)
+ {
+ }
+
+protected:
+ const exploded_node *m_enode;
+ const gcall &m_throw_call;
+};
+
+/* A concrete event subclass for an explicit "throw EXC;"
+ or "throw;" (actually, a call to __cxa_throw or __cxa_rethrow). */
+
+class explicit_throw_event : public throw_event
+{
+public:
+ explicit_throw_event (const event_loc_info &loc_info,
+ const exploded_node *enode,
+ const gcall &throw_call,
+ tree type,
+ bool is_rethrow)
+ : throw_event (loc_info, enode, throw_call),
+ m_type (type),
+ m_is_rethrow (is_rethrow)
+ {
+ }
+
+ void print_desc (pretty_printer &pp) const final override;
+
+private:
+ tree m_type;
+ bool m_is_rethrow;
+};
+
+/* A concrete event subclass for an exception being thrown
+ from within a call to a function we don't have the body of,
+ or where we don't know what function was called. */
+
+class throw_from_call_to_external_fn_event : public throw_event
+{
+public:
+ throw_from_call_to_external_fn_event (const event_loc_info &loc_info,
+ const exploded_node *enode,
+ const gcall &throw_call,
+ tree fndecl)
+ : throw_event (loc_info, enode, throw_call),
+ m_fndecl (fndecl)
+ {
+ }
+
+ void print_desc (pretty_printer &pp) const final override;
+
+private:
+ tree m_fndecl;
+};
+
+/* A concrete event subclass for unwinding a stack frame when
+ processing an exception. */
+
+class unwind_event : public checker_event
+{
+public:
+ unwind_event (const event_loc_info &loc_info)
+ : checker_event (event_kind::unwind, loc_info),
+ m_num_frames (1)
+ {
+ }
+
+ void print_desc (pretty_printer &pp) const final override;
+
+ int m_num_frames;
+};
+
/* Concrete subclass of checker_event for use at the end of a path:
a repeat of the warning message at the end of the path (perhaps with
references to pertinent events that occurred on the way), at the point
@@ -677,7 +793,7 @@ public:
const exploded_node *enode,
const state_machine *sm,
tree var, state_machine::state_t state)
- : checker_event (EK_WARNING, loc_info),
+ : checker_event (event_kind::warning, loc_info),
m_enode (enode),
m_sm (sm), m_var (var), m_state (state)
{
diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index d97378e..9bde6f2 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -18,37 +18,22 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "fold-const.h"
-#include "diagnostic-path.h"
-#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
-#include "digraph.h"
-#include "diagnostic-event-id.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/sm.h"
+#include "analyzer/common.h"
+
+#include "tree-pretty-print.h"
#include "sbitmap.h"
-#include "bitmap.h"
#include "ordered-hash-map.h"
+#include "gimple-iterator.h"
+#include "inlining-iterator.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/sm.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-path.h"
-#include "gimple-iterator.h"
-#include "inlining-iterator.h"
#include "analyzer/supergraph.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
@@ -56,7 +41,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/diagnostic-manager.h"
#include "analyzer/checker-path.h"
#include "analyzer/exploded-graph.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -164,8 +148,8 @@ checker_path::add_region_creation_events (pending_diagnostic *pd,
pd->add_region_creation_events (reg, capacity, loc_info, *this);
if (debug)
- add_event (make_unique<region_creation_event_debug> (reg, capacity,
- loc_info));
+ add_event (std::make_unique<region_creation_event_debug> (reg, capacity,
+ loc_info));
}
void
@@ -183,8 +167,8 @@ checker_path::cfg_edge_pair_at_p (unsigned idx) const
{
if (m_events.length () < idx + 1)
return false;
- return (m_events[idx]->m_kind == EK_START_CFG_EDGE
- && m_events[idx + 1]->m_kind == EK_END_CFG_EDGE);
+ return (m_events[idx]->m_kind == event_kind::start_cfg_edge
+ && m_events[idx + 1]->m_kind == event_kind::end_cfg_edge);
}
/* Consider a call from "outer" to "middle" which calls "inner",
@@ -202,38 +186,38 @@ checker_path::cfg_edge_pair_at_p (unsigned idx) const
(for gcc.dg/analyzer/inlining-4.c):
before[0]:
- EK_FUNCTION_ENTRY "entry to ‘outer’"
+ event_kind::function_entry "entry to ‘outer’"
(depth 1, fndecl ‘outer’, m_loc=511c4)
before[1]:
- EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..."
+ event_kind::start_cfg_edge "following ‘true’ branch (when ‘flag != 0’)..."
(depth 3 corrected from 1,
fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f)
before[2]:
- EK_END_CFG_EDGE "...to here"
+ event_kind::end_cfg_edge "...to here"
(depth 1, fndecl ‘outer’, m_loc=0)
before[3]:
- EK_WARNING "here (‘<unknown>’ is in state ‘null’)"
+ event_kind::warning "here (‘<unknown>’ is in state ‘null’)"
(depth 1, fndecl ‘outer’, m_loc=80000004)
We want to add inlined_call_events showing the calls, so that
the above becomes:
after[0]:
- EK_FUNCTION_ENTRY "entry to ‘outer’"
+ event_kind::function_entry "entry to ‘outer’"
(depth 1, fndecl ‘outer’, m_loc=511c4)
after[1]:
- EK_INLINED_CALL "inlined call to ‘middle’ from ‘outer’"
+ event_kind::inlined_call "inlined call to ‘middle’ from ‘outer’"
(depth 1, fndecl ‘outer’, m_loc=53300)
after[2]:
- EK_INLINED_CALL "inlined call to ‘inner’ from ‘middle’"
+ event_kind::inlined_call "inlined call to ‘inner’ from ‘middle’"
(depth 2, fndecl ‘middle’, m_loc=4d2e0)
after[3]:
- EK_START_CFG_EDGE "following ‘true’ branch (when ‘flag != 0’)..."
+ event_kind::start_cfg_edge "following ‘true’ branch (when ‘flag != 0’)..."
(depth 3 corrected from 1,
fndecl ‘inner’ corrected from ‘outer’, m_loc=8000000f)
- after[4]: EK_END_CFG_EDGE "...to here"
+ after[4]: event_kind::end_cfg_edge "...to here"
(depth 1, fndecl ‘outer’, m_loc=0)
- after[5]: EK_WARNING "here (‘<unknown>’ is in state ‘null’)"
+ after[5]: event_kind::warning "here (‘<unknown>’ is in state ‘null’)"
(depth 1, fndecl ‘outer’, m_loc=80000004)
where we've added events between before[0] and before[1] to show
diff --git a/gcc/analyzer/analyzer.h b/gcc/analyzer/common.h
index 4843d99..cb03004 100644
--- a/gcc/analyzer/analyzer.h
+++ b/gcc/analyzer/common.h
@@ -1,4 +1,4 @@
-/* Utility functions for the analyzer.
+/* Base header for the analyzer, plus utility functions.
Copyright (C) 2019-2025 Free Software Foundation, Inc.
Contributed by David Malcolm <dmalcolm@redhat.com>.
@@ -18,9 +18,21 @@ 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 GCC_ANALYZER_ANALYZER_H
-#define GCC_ANALYZER_ANALYZER_H
+#ifndef GCC_ANALYZER_COMMON_H
+#define GCC_ANALYZER_COMMON_H
+#include "config.h"
+#define INCLUDE_VECTOR
+#include "system.h"
+#include "coretypes.h"
+#include "tree.h"
+#include "function.h"
+#include "basic-block.h"
+#include "gimple.h"
+#include "options.h"
+#include "bitmap.h"
+#include "diagnostic-core.h"
+#include "diagnostic-path.h"
#include "rich-location.h"
#include "function.h"
#include "json.h"
@@ -37,6 +49,9 @@ class supernode;
class superedge;
class cfg_superedge;
class switch_cfg_superedge;
+ class eh_dispatch_cfg_superedge;
+ class eh_dispatch_try_cfg_superedge;
+ class eh_dispatch_allowed_cfg_superedge;
class callgraph_superedge;
class call_superedge;
class return_superedge;
@@ -350,10 +365,10 @@ public:
/* An enum for describing the direction of an access to memory. */
-enum access_direction
+enum class access_direction
{
- DIR_READ,
- DIR_WRITE
+ read,
+ write
};
/* Abstract base class for associating custom data with an
@@ -384,6 +399,12 @@ public:
virtual void add_events_to_path (checker_path *emission_path,
const exploded_edge &eedge) const = 0;
+
+ virtual exploded_node *create_enode (exploded_graph &eg,
+ const program_point &point,
+ program_state &&state,
+ exploded_node *enode_for_diag,
+ region_model_context *ctxt) const;
};
/* Abstract base class for splitting state.
@@ -447,21 +468,23 @@ extern tree remove_ssa_names (tree expr);
} // namespace ana
-extern bool is_special_named_call_p (const gcall *call, const char *funcname,
+extern bool is_special_named_call_p (const gcall &call, const char *funcname,
unsigned int num_args,
bool look_in_std = false);
extern bool is_named_call_p (const_tree fndecl, const char *funcname);
extern bool is_named_call_p (const_tree fndecl, const char *funcname,
- const gcall *call, unsigned int num_args);
+ const gcall &call, unsigned int num_args);
extern bool is_std_function_p (const_tree fndecl);
extern bool is_std_named_call_p (const_tree fndecl, const char *funcname);
extern bool is_std_named_call_p (const_tree fndecl, const char *funcname,
- const gcall *call, unsigned int num_args);
-extern bool is_setjmp_call_p (const gcall *call);
-extern bool is_longjmp_call_p (const gcall *call);
-extern bool is_placement_new_p (const gcall *call);
+ const gcall &call, unsigned int num_args);
+extern bool is_setjmp_call_p (const gcall &call);
+extern bool is_longjmp_call_p (const gcall &call);
+extern bool is_placement_new_p (const gcall &call);
+extern bool is_cxa_throw_p (const gcall &call);
+extern bool is_cxa_rethrow_p (const gcall &call);
-extern const char *get_user_facing_name (const gcall *call);
+extern const char *get_user_facing_name (const gcall &call);
extern void register_analyzer_pass ();
@@ -577,4 +600,4 @@ private:
extern void sorry_no_analyzer ();
#endif /* #if !ENABLE_ANALYZER */
-#endif /* GCC_ANALYZER_ANALYZER_H */
+#endif /* GCC_ANALYZER_COMMON_H */
diff --git a/gcc/analyzer/complexity.cc b/gcc/analyzer/complexity.cc
index cb88f60..4a0a156 100644
--- a/gcc/analyzer/complexity.cc
+++ b/gcc/analyzer/complexity.cc
@@ -18,34 +18,14 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
#include "digraph.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
diff --git a/gcc/analyzer/constraint-manager.cc b/gcc/analyzer/constraint-manager.cc
index 55d8996..a3e682c 100644
--- a/gcc/analyzer/constraint-manager.cc
+++ b/gcc/analyzer/constraint-manager.cc
@@ -18,28 +18,17 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
+#include "analyzer/common.h"
+
#include "fold-const.h"
-#include "selftest.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "analyzer/analyzer.h"
#include "ordered-hash-map.h"
-#include "options.h"
#include "cgraph.h"
#include "cfg.h"
#include "digraph.h"
-#include "analyzer/supergraph.h"
#include "sbitmap.h"
-#include "bitmap.h"
+#include "tree-pretty-print.h"
+
+#include "analyzer/supergraph.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -48,8 +37,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/constraint-manager.h"
#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
-#include "tree-pretty-print.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -126,7 +113,7 @@ bound::ensure_closed (enum bound_kind bound_kind)
and convert x < 5 into x <= 4. */
gcc_assert (CONSTANT_CLASS_P (m_constant));
gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (m_constant)));
- m_constant = fold_build2 (bound_kind == BK_UPPER ? MINUS_EXPR : PLUS_EXPR,
+ m_constant = fold_build2 (bound_kind == bound_kind::upper ? MINUS_EXPR : PLUS_EXPR,
TREE_TYPE (m_constant),
m_constant, integer_one_node);
gcc_assert (CONSTANT_CLASS_P (m_constant));
@@ -203,8 +190,8 @@ range::constrained_to_single_element ()
return NULL_TREE;
/* Convert any open bounds to closed bounds. */
- m_lower_bound.ensure_closed (BK_LOWER);
- m_upper_bound.ensure_closed (BK_UPPER);
+ m_lower_bound.ensure_closed (bound_kind::lower);
+ m_upper_bound.ensure_closed (bound_kind::upper);
// Are they equal?
tree comparison = fold_binary (EQ_EXPR, boolean_type_node,
@@ -315,18 +302,18 @@ range::add_bound (bound b, enum bound_kind bound_kind)
{
default:
gcc_unreachable ();
- case BK_LOWER:
+ case bound_kind::lower:
/* Discard redundant bounds. */
if (m_lower_bound.m_constant)
{
- m_lower_bound.ensure_closed (BK_LOWER);
+ m_lower_bound.ensure_closed (bound_kind::lower);
if (tree_int_cst_le (b.m_constant,
m_lower_bound.m_constant))
return true;
}
if (m_upper_bound.m_constant)
{
- m_upper_bound.ensure_closed (BK_UPPER);
+ m_upper_bound.ensure_closed (bound_kind::upper);
/* Reject B <= V <= UPPER when B > UPPER. */
if (!tree_int_cst_le (b.m_constant,
m_upper_bound.m_constant))
@@ -335,18 +322,18 @@ range::add_bound (bound b, enum bound_kind bound_kind)
m_lower_bound = b;
break;
- case BK_UPPER:
+ case bound_kind::upper:
/* Discard redundant bounds. */
if (m_upper_bound.m_constant)
{
- m_upper_bound.ensure_closed (BK_UPPER);
+ m_upper_bound.ensure_closed (bound_kind::upper);
if (!tree_int_cst_lt (b.m_constant,
m_upper_bound.m_constant))
return true;
}
if (m_lower_bound.m_constant)
{
- m_lower_bound.ensure_closed (BK_LOWER);
+ m_lower_bound.ensure_closed (bound_kind::lower);
/* Reject LOWER <= V <= B when LOWER > B. */
if (!tree_int_cst_le (m_lower_bound.m_constant,
b.m_constant))
@@ -371,16 +358,16 @@ range::add_bound (enum tree_code op, tree rhs_const)
return true;
case LT_EXPR:
/* "V < RHS_CONST" */
- return add_bound (bound (rhs_const, false), BK_UPPER);
+ return add_bound (bound (rhs_const, false), bound_kind::upper);
case LE_EXPR:
/* "V <= RHS_CONST" */
- return add_bound (bound (rhs_const, true), BK_UPPER);
+ return add_bound (bound (rhs_const, true), bound_kind::upper);
case GE_EXPR:
/* "V >= RHS_CONST" */
- return add_bound (bound (rhs_const, true), BK_LOWER);
+ return add_bound (bound (rhs_const, true), bound_kind::lower);
case GT_EXPR:
/* "V > RHS_CONST" */
- return add_bound (bound (rhs_const, false), BK_LOWER);
+ return add_bound (bound (rhs_const, false), bound_kind::lower);
}
}
@@ -449,7 +436,7 @@ bounded_range::dump (bool show_types) const
std::unique_ptr<json::object>
bounded_range::to_json () const
{
- auto range_obj = ::make_unique<json::object> ();
+ auto range_obj = std::make_unique<json::object> ();
set_json_attr (*range_obj, "lower", m_lower);
set_json_attr (*range_obj, "upper", m_upper);
return range_obj;
@@ -718,7 +705,7 @@ bounded_ranges::dump (bool show_types) const
std::unique_ptr<json::value>
bounded_ranges::to_json () const
{
- auto arr_obj = ::make_unique<json::array> ();
+ auto arr_obj = std::make_unique<json::array> ();
for (unsigned i = 0; i < m_ranges.length (); ++i)
arr_obj->append (m_ranges[i].to_json ());
@@ -1116,9 +1103,9 @@ equiv_class::print (pretty_printer *pp) const
std::unique_ptr<json::object>
equiv_class::to_json () const
{
- auto ec_obj = ::make_unique<json::object> ();
+ auto ec_obj = std::make_unique<json::object> ();
- auto sval_arr = ::make_unique<json::array> ();
+ auto sval_arr = std::make_unique<json::array> ();
for (const svalue *sval : m_vars)
sval_arr->append (sval->to_json ());
ec_obj->set ("svals", std::move (sval_arr));
@@ -1383,7 +1370,7 @@ constraint::print (pretty_printer *pp, const constraint_manager &cm) const
std::unique_ptr<json::object>
constraint::to_json () const
{
- auto con_obj = ::make_unique<json::object> ();
+ auto con_obj = std::make_unique<json::object> ();
con_obj->set_integer ("lhs", m_lhs.as_int ());
con_obj->set_string ("op", constraint_op_code (m_op));
@@ -1471,7 +1458,7 @@ bounded_ranges_constraint::print (pretty_printer *pp,
std::unique_ptr<json::object>
bounded_ranges_constraint::to_json () const
{
- auto con_obj = ::make_unique<json::object> ();
+ auto con_obj = std::make_unique<json::object> ();
con_obj->set_integer ("ec", m_ec_id.as_int ());
con_obj->set ("ranges", m_ranges->to_json ());
@@ -1784,11 +1771,11 @@ debug (const constraint_manager &cm)
std::unique_ptr<json::object>
constraint_manager::to_json () const
{
- auto cm_obj = ::make_unique<json::object> ();
+ auto cm_obj = std::make_unique<json::object> ();
/* Equivalence classes. */
{
- auto ec_arr = ::make_unique<json::array> ();
+ auto ec_arr = std::make_unique<json::array> ();
for (const equiv_class *ec : m_equiv_classes)
ec_arr->append (ec->to_json ());
cm_obj->set ("ecs", std::move (ec_arr));
@@ -1796,7 +1783,7 @@ constraint_manager::to_json () const
/* Constraints. */
{
- auto con_arr = ::make_unique<json::array> ();
+ auto con_arr = std::make_unique<json::array> ();
for (const constraint &c : m_constraints)
con_arr->append (c.to_json ());
cm_obj->set ("constraints", std::move (con_arr));
@@ -1804,7 +1791,7 @@ constraint_manager::to_json () const
/* m_bounded_ranges_constraints. */
{
- auto con_arr = ::make_unique<json::array> ();
+ auto con_arr = std::make_unique<json::array> ();
for (const auto &c : m_bounded_ranges_constraints)
con_arr->append (c.to_json ());
cm_obj->set ("bounded_ranges_constraints", std::move (con_arr));
@@ -2578,12 +2565,12 @@ constraint_manager::get_ec_bounds (equiv_class_id ec_id) const
case CONSTRAINT_LT:
/* We have "EC_ID < OTHER_CST". */
- result.add_bound (bound (other_cst, false), BK_UPPER);
+ result.add_bound (bound (other_cst, false), bound_kind::upper);
break;
case CONSTRAINT_LE:
/* We have "EC_ID <= OTHER_CST". */
- result.add_bound (bound (other_cst, true), BK_UPPER);
+ result.add_bound (bound (other_cst, true), bound_kind::upper);
break;
}
}
@@ -2600,13 +2587,13 @@ constraint_manager::get_ec_bounds (equiv_class_id ec_id) const
case CONSTRAINT_LT:
/* We have "OTHER_CST < EC_ID"
i.e. "EC_ID > OTHER_CST". */
- result.add_bound (bound (other_cst, false), BK_LOWER);
+ result.add_bound (bound (other_cst, false), bound_kind::lower);
break;
case CONSTRAINT_LE:
/* We have "OTHER_CST <= EC_ID"
i.e. "EC_ID >= OTHER_CST". */
- result.add_bound (bound (other_cst, true), BK_LOWER);
+ result.add_bound (bound (other_cst, true), bound_kind::lower);
break;
}
}
diff --git a/gcc/analyzer/constraint-manager.h b/gcc/analyzer/constraint-manager.h
index c22b99e..a26b48d 100644
--- a/gcc/analyzer/constraint-manager.h
+++ b/gcc/analyzer/constraint-manager.h
@@ -25,10 +25,10 @@ namespace ana {
class constraint_manager;
-enum bound_kind
+enum class bound_kind
{
- BK_LOWER,
- BK_UPPER
+ lower,
+ upper
};
/* One of the end-points of a range. */
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 4bf1dce..7575b16 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -18,22 +18,19 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "input.h"
-#include "diagnostic-core.h"
-#include "pretty-print.h"
-#include "gcc-rich-location.h"
+#include "analyzer/common.h"
+
+#include "cfg.h"
+#include "basic-block.h"
+#include "gimple.h"
#include "gimple-pretty-print.h"
-#include "function.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
-#include "analyzer/analyzer.h"
+#include "gimple-iterator.h"
+#include "inlining-iterator.h"
+#include "cgraph.h"
+#include "digraph.h"
+#include "gcc-rich-location.h"
+#include "diagnostic-format-sarif.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -43,13 +40,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "inlining-iterator.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
@@ -57,8 +47,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/feasible-graph.h"
#include "analyzer/checker-path.h"
#include "analyzer/reachability.h"
-#include "make-unique.h"
-#include "diagnostic-format-sarif.h"
#if ENABLE_ANALYZER
@@ -203,7 +191,7 @@ epath_finder::get_best_epath (const exploded_node *enode,
logger->log ("trying to find shortest path ignoring feasibility");
gcc_assert (m_sep);
std::unique_ptr<exploded_path> epath
- = make_unique<exploded_path> (m_sep->get_shortest_path (enode));
+ = std::make_unique<exploded_path> (m_sep->get_shortest_path (enode));
if (epath->feasible_p (logger, out_problem, m_eg.get_engine (), &m_eg))
{
if (logger)
@@ -742,7 +730,7 @@ saved_diagnostic::add_event (std::unique_ptr<checker_event> event)
std::unique_ptr<json::object>
saved_diagnostic::to_json () const
{
- auto sd_obj = ::make_unique<json::object> ();
+ auto sd_obj = std::make_unique<json::object> ();
if (m_sm)
sd_obj->set_string ("sm", m_sm->get_name ());
@@ -1048,10 +1036,10 @@ saved_diagnostic::maybe_add_sarif_properties (sarif_object &result_obj) const
props.set_integer (PROPERTY_PREFIX "idx", m_idx);
if (m_duplicates.length () > 0)
{
- auto duplicates_arr = ::make_unique<json::array> ();
+ auto duplicates_arr = std::make_unique<json::array> ();
for (auto iter : m_duplicates)
{
- auto sd_obj = ::make_unique<sarif_object> ();
+ auto sd_obj = std::make_unique<sarif_object> ();
iter->maybe_add_sarif_properties (*sd_obj);
duplicates_arr->append (std::move (sd_obj));
}
@@ -1242,10 +1230,10 @@ diagnostic_manager::add_event (std::unique_ptr<checker_event> event)
std::unique_ptr<json::object>
diagnostic_manager::to_json () const
{
- auto dm_obj = ::make_unique<json::object> ();
+ auto dm_obj = std::make_unique<json::object> ();
{
- auto sd_arr = ::make_unique<json::array> ();
+ auto sd_arr = std::make_unique<json::array> ();
int i;
saved_diagnostic *sd;
FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
@@ -1816,16 +1804,16 @@ public:
int stack_depth = src_stack_depth;
m_emission_path->add_event
- (make_unique<state_change_event> (supernode,
- stmt,
- stack_depth,
- sm,
- nullptr,
- src_sm_val,
- dst_sm_val,
- nullptr,
- dst_state,
- src_node));
+ (std::make_unique<state_change_event> (supernode,
+ stmt,
+ stack_depth,
+ sm,
+ nullptr,
+ src_sm_val,
+ dst_sm_val,
+ nullptr,
+ dst_state,
+ src_node));
return false;
}
@@ -1861,16 +1849,16 @@ public:
return false;
m_emission_path->add_event
- (make_unique<state_change_event> (supernode,
- stmt,
- stack_depth,
- sm,
- sval,
- src_sm_val,
- dst_sm_val,
- dst_origin_sval,
- dst_state,
- src_node));
+ (std::make_unique<state_change_event> (supernode,
+ stmt,
+ stack_depth,
+ sm,
+ sval,
+ src_sm_val,
+ dst_sm_val,
+ dst_origin_sval,
+ dst_state,
+ src_node));
return false;
}
@@ -1963,7 +1951,7 @@ struct null_assignment_sm_context : public sm_context
{
}
- tree get_fndecl_for_call (const gcall */*call*/) final override
+ tree get_fndecl_for_call (const gcall &/*call*/) final override
{
return NULL_TREE;
}
@@ -2007,15 +1995,15 @@ struct null_assignment_sm_context : public sm_context
int stack_depth = m_point->get_stack_depth ();
m_emission_path->add_event
- (make_unique<state_change_event> (supernode,
- m_stmt,
- stack_depth,
- m_sm,
- var_new_sval,
- from, to,
- nullptr,
- *m_new_state,
- nullptr));
+ (std::make_unique<state_change_event> (supernode,
+ m_stmt,
+ stack_depth,
+ m_sm,
+ var_new_sval,
+ from, to,
+ nullptr,
+ *m_new_state,
+ nullptr));
}
void set_next_state (const gimple *stmt,
@@ -2033,15 +2021,15 @@ struct null_assignment_sm_context : public sm_context
int stack_depth = m_point->get_stack_depth ();
m_emission_path->add_event
- (make_unique<state_change_event> (supernode,
- m_stmt,
- stack_depth,
- m_sm,
- sval,
- from, to,
- nullptr,
- *m_new_state,
- nullptr));
+ (std::make_unique<state_change_event> (supernode,
+ m_stmt,
+ stack_depth,
+ m_sm,
+ sval,
+ from, to,
+ nullptr,
+ *m_new_state,
+ nullptr));
}
void warn (const supernode *, const gimple *,
@@ -2220,18 +2208,19 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
{
const gimple *stmt = dst_point.get_stmt ();
const gcall *call = dyn_cast <const gcall *> (stmt);
- if (call && is_setjmp_call_p (call))
+ if (call && is_setjmp_call_p (*call))
emission_path->add_event
- (make_unique<setjmp_event> (event_loc_info (stmt->location,
- dst_point.get_fndecl (),
- dst_stack_depth),
- dst_node,
- call));
+ (std::make_unique<setjmp_event>
+ (event_loc_info (stmt->location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ dst_node,
+ *call));
else
emission_path->add_event
- (make_unique<statement_event> (stmt,
- dst_point.get_fndecl (),
- dst_stack_depth, dst_state));
+ (std::make_unique<statement_event> (stmt,
+ dst_point.get_fndecl (),
+ dst_stack_depth, dst_state));
/* Create state change events for assignment to NULL.
Iterate through the stmts in dst_enode, adding state change
@@ -2324,11 +2313,11 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
" at this edge: ");
pb.get_feasibility_problem ()->dump_to_pp (&pp);
emission_path->add_event
- (make_unique<precanned_custom_event>
- (event_loc_info (dst_point.get_location (),
- dst_point.get_fndecl (),
- dst_stack_depth),
- pp_formatted_text (&pp)));
+ (std::make_unique<precanned_custom_event>
+ (event_loc_info (dst_point.get_location (),
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ pp_formatted_text (&pp)));
}
}
@@ -2438,18 +2427,48 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
{
case SUPEREDGE_CFG_EDGE:
{
+ if (auto eh_dispatch_try_sedge
+ = eedge.m_sedge->dyn_cast_eh_dispatch_try_cfg_superedge ())
+ {
+ if (eh_dispatch_try_sedge->get_eh_catch ())
+ {
+ const region_model *model = src_node->get_state ().m_region_model;
+ auto curr_thrown_exception_node
+ = model->get_current_thrown_exception ();
+ gcc_assert (curr_thrown_exception_node);
+ tree type = curr_thrown_exception_node->maybe_get_type ();
+ emission_path->add_event
+ (std::make_unique<catch_cfg_edge_event>
+ (eedge,
+ event_loc_info (dst_point.get_supernode ()->get_start_location (),
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ type));
+ return;
+ }
+ else
+ {
+ /* We have the "uncaught exception" sedge, from eh_dispatch
+ to a block containing resx.
+ Don't add any events for this, so that we can consolidate
+ adjacent stack unwinding events. */
+ return;
+ }
+ }
+
emission_path->add_event
- (make_unique<start_cfg_edge_event>
- (eedge,
- event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
- src_point.get_fndecl (),
- src_stack_depth)));
+ (std::make_unique<start_cfg_edge_event>
+ (eedge,
+ event_loc_info
+ (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth)));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (eedge,
- event_loc_info (dst_point.get_supernode ()->get_start_location (),
- dst_point.get_fndecl (),
- dst_stack_depth)));
+ (std::make_unique<end_cfg_edge_event>
+ (eedge,
+ event_loc_info (dst_point.get_supernode ()->get_start_location (),
+ dst_point.get_fndecl (),
+ dst_stack_depth)));
}
break;
@@ -2462,12 +2481,13 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
/* TODO: add a subclass for this, or generate events for the
summary. */
emission_path->add_event
- (make_unique<debug_event> (event_loc_info (last_stmt
- ? last_stmt->location
- : UNKNOWN_LOCATION,
- src_point.get_fndecl (),
- src_stack_depth),
- "call summary"));
+ (std::make_unique<debug_event>
+ (event_loc_info (last_stmt
+ ? last_stmt->location
+ : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth),
+ "call summary"));
}
break;
@@ -2476,14 +2496,13 @@ diagnostic_manager::add_events_for_superedge (const path_builder &pb,
const return_superedge *return_edge
= as_a <const return_superedge *> (eedge.m_sedge);
- const gcall *call_stmt = return_edge->get_call_stmt ();
+ const gcall &call_stmt = return_edge->get_call_stmt ();
emission_path->add_event
- (make_unique<return_event> (eedge,
- event_loc_info (call_stmt
- ? call_stmt->location
- : UNKNOWN_LOCATION,
- dst_point.get_fndecl (),
- dst_stack_depth)));
+ (std::make_unique<return_event>
+ (eedge,
+ event_loc_info (call_stmt.location,
+ dst_point.get_fndecl (),
+ dst_stack_depth)));
}
break;
}
@@ -2512,6 +2531,7 @@ diagnostic_manager::prune_path (checker_path *path,
if (! flag_analyzer_show_events_in_system_headers)
prune_system_headers (path);
consolidate_conditions (path);
+ consolidate_unwind_events (path);
finish_pruning (path);
path->maybe_log (get_logger (), "pruned");
}
@@ -2586,7 +2606,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
default:
gcc_unreachable ();
- case EK_DEBUG:
+ case event_kind::debug:
if (m_verbosity < 4)
{
log ("filtering event %i: debug event", idx);
@@ -2594,11 +2614,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_CUSTOM:
+ case event_kind::custom:
/* Don't filter custom events. */
break;
- case EK_STMT:
+ case event_kind::stmt:
{
if (m_verbosity < 4)
{
@@ -2608,11 +2628,11 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_REGION_CREATION:
+ case event_kind::region_creation:
/* Don't filter these. */
break;
- case EK_FUNCTION_ENTRY:
+ case event_kind::function_entry:
if (m_verbosity < 1)
{
log ("filtering event %i: function entry", idx);
@@ -2620,7 +2640,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_STATE_CHANGE:
+ case event_kind::state_change:
{
state_change_event *state_change = (state_change_event *)base_event;
gcc_assert (state_change->m_dst_state.m_region_model);
@@ -2674,7 +2694,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_START_CFG_EDGE:
+ case event_kind::start_cfg_edge:
{
cfg_edge_event *event = (cfg_edge_event *)base_event;
@@ -2687,20 +2707,26 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
{
log ("filtering events %i and %i: CFG edge", idx, idx + 1);
path->delete_event (idx);
- /* Also delete the corresponding EK_END_CFG_EDGE. */
+ /* Also delete the corresponding event_kind::end_cfg_edge. */
gcc_assert (path->get_checker_event (idx)->m_kind
- == EK_END_CFG_EDGE);
+ == event_kind::end_cfg_edge);
path->delete_event (idx);
}
}
break;
- case EK_END_CFG_EDGE:
- /* These come in pairs with EK_START_CFG_EDGE events and are
+ case event_kind::end_cfg_edge:
+ /* These come in pairs with event_kind::start_cfg_edge events and are
filtered when their start event is filtered. */
break;
- case EK_CALL_EDGE:
+ case event_kind::catch_:
+ case event_kind::throw_:
+ case event_kind::unwind:
+ /* Don't filter these. */
+ break;
+
+ case event_kind::call_edge:
{
call_event *event = (call_event *)base_event;
const region_model *callee_model
@@ -2741,7 +2767,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_RETURN_EDGE:
+ case event_kind::return_edge:
{
if (sval)
{
@@ -2785,19 +2811,19 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
}
break;
- case EK_INLINED_CALL:
+ case event_kind::inlined_call:
/* We don't expect to see these yet, as they're added later.
We'd want to keep them around. */
break;
- case EK_SETJMP:
+ case event_kind::setjmp_:
/* TODO: only show setjmp_events that matter i.e. those for which
there is a later rewind event using them. */
- case EK_REWIND_FROM_LONGJMP:
- case EK_REWIND_TO_SETJMP:
+ case event_kind::rewind_from_longjmp:
+ case event_kind::rewind_to_setjmp:
break;
- case EK_WARNING:
+ case event_kind::warning:
/* Always show the final "warning" event in the path. */
break;
}
@@ -3073,7 +3099,7 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const
continue;
/* Are we looking for a run of all TRUE edges, or all FALSE edges? */
- gcc_assert (old_start_ev->m_kind == EK_START_CFG_EDGE);
+ gcc_assert (old_start_ev->m_kind == event_kind::start_cfg_edge);
const start_cfg_edge_event *old_start_cfg_ev
= (const start_cfg_edge_event *)old_start_ev;
const cfg_superedge& first_cfg_sedge
@@ -3096,7 +3122,7 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const
{
const checker_event *iter_ev
= path->get_checker_event (next_idx);
- gcc_assert (iter_ev->m_kind == EK_START_CFG_EDGE);
+ gcc_assert (iter_ev->m_kind == event_kind::start_cfg_edge);
const start_cfg_edge_event *iter_cfg_ev
= (const start_cfg_edge_event *)iter_ev;
const cfg_superedge& iter_cfg_sedge
@@ -3140,6 +3166,48 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const
}
}
+/* Consolidate runs of consecutive unwind_event. */
+
+void
+diagnostic_manager::consolidate_unwind_events (checker_path *path) const
+{
+ /* Don't simplify edges if we're debugging them. */
+ if (flag_analyzer_verbose_edges)
+ return;
+
+ for (int start_idx = 0;
+ start_idx < (signed)path->num_events () - 1;
+ start_idx++)
+ {
+ /* Find a run of consecutive unwind_event instances. */
+ if (path->get_checker_event (start_idx)->m_kind != event_kind::unwind)
+ continue;
+ int iter_idx = start_idx + 1;
+ while (iter_idx < (int)path->num_events ())
+ if (path->get_checker_event (iter_idx)->m_kind == event_kind::unwind)
+ ++iter_idx;
+ else
+ break;
+
+ /* iter_idx should now be one after the last unwind_event in the run. */
+ const int last_idx = iter_idx - 1;
+ if (last_idx == start_idx)
+ continue;
+
+ gcc_assert (last_idx > start_idx);
+
+ log ("consolidating unwind events %i-%i into %i",
+ start_idx, last_idx, start_idx);
+
+ unwind_event *first_event
+ = (unwind_event *)path->get_checker_event (start_idx);
+ const unwind_event *last_event
+ = (const unwind_event *)path->get_checker_event (last_idx);
+ first_event->m_num_frames += last_event->m_num_frames;
+ path->delete_events (start_idx + 1, last_idx - start_idx);
+ }
+}
+
/* Final pass of diagnostic_manager::prune_path.
If all we're left with is in one function, then filter function entry
@@ -3154,7 +3222,7 @@ diagnostic_manager::finish_pruning (checker_path *path) const
while (idx >= 0 && idx < (signed)path->num_events ())
{
checker_event *base_event = path->get_checker_event (idx);
- if (base_event->m_kind == EK_FUNCTION_ENTRY)
+ if (base_event->m_kind == event_kind::function_entry)
{
log ("filtering event %i:"
" function entry for purely intraprocedural path", idx);
diff --git a/gcc/analyzer/diagnostic-manager.h b/gcc/analyzer/diagnostic-manager.h
index 06a8233..b62fc7a 100644
--- a/gcc/analyzer/diagnostic-manager.h
+++ b/gcc/analyzer/diagnostic-manager.h
@@ -229,6 +229,7 @@ private:
void prune_interproc_events (checker_path *path) const;
void prune_system_headers (checker_path *path) const;
void consolidate_conditions (checker_path *path) const;
+ void consolidate_unwind_events (checker_path *path) const;
void finish_pruning (checker_path *path) const;
engine *m_eng;
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 71d7ed7..c3e4800 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -18,23 +18,27 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "fold-const.h"
+#include "analyzer/common.h"
+
+#include <zlib.h>
+
+#include "cfg.h"
+#include "basic-block.h"
#include "gcc-rich-location.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "function.h"
-#include "pretty-print.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
-#include "analyzer/analyzer.h"
+#include "gimple.h"
+#include "gimple-iterator.h"
+#include "gimple-pretty-print.h"
+#include "cgraph.h"
+#include "fold-const.h"
+#include "digraph.h"
+#include "plugin.h"
+#include "target.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "tree-dfa.h"
+
+#include "text-art/dump.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -44,13 +48,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "gimple-pretty-print.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
@@ -59,16 +56,8 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/state-purge.h"
#include "analyzer/bar-chart.h"
#include "analyzer/call-info.h"
-#include <zlib.h>
-#include "plugin.h"
-#include "target.h"
-#include <memory>
-#include "stringpool.h"
-#include "attribs.h"
-#include "tree-dfa.h"
#include "analyzer/known-function-manager.h"
#include "analyzer/call-summary.h"
-#include "text-art/dump.h"
/* For an overview, see gcc/doc/analyzer.texi. */
@@ -322,11 +311,11 @@ public:
logger *get_logger () const { return m_logger.get_logger (); }
- tree get_fndecl_for_call (const gcall *call) final override
+ tree get_fndecl_for_call (const gcall &call) final override
{
impl_region_model_context old_ctxt
(m_eg, m_enode_for_diag, NULL, NULL, NULL/*m_enode->get_state ()*/,
- NULL, call);
+ NULL, &call);
region_model *model = m_new_state->m_region_model;
return model->get_fndecl_for_call (call, &old_ctxt);
}
@@ -583,17 +572,17 @@ get_state_map_by_name (const char *name,
{
const sm_state_map *old_smap = m_old_state->m_checker_states[sm_idx];
*out_sm_context
- = make_unique<impl_sm_context> (*m_eg,
- sm_idx,
- *sm,
- m_enode_for_diag,
- m_old_state,
- m_new_state,
- old_smap,
- new_smap,
- m_path_ctxt,
- m_stmt_finder,
- false);
+ = std::make_unique<impl_sm_context> (*m_eg,
+ sm_idx,
+ *sm,
+ m_enode_for_diag,
+ m_old_state,
+ m_new_state,
+ old_smap,
+ new_smap,
+ m_path_ctxt,
+ m_stmt_finder,
+ false);
}
return true;
}
@@ -609,7 +598,7 @@ public:
std::unique_ptr<stmt_finder> clone () const final override
{
- return make_unique<leak_stmt_finder> (m_eg, m_var);
+ return std::make_unique<leak_stmt_finder> (m_eg, m_var);
}
const gimple *find_stmt (const exploded_path &epath)
@@ -1207,10 +1196,10 @@ exploded_node::status_to_str (enum status s)
switch (s)
{
default: gcc_unreachable ();
- case STATUS_WORKLIST: return "WORKLIST";
- case STATUS_PROCESSED: return "PROCESSED";
- case STATUS_MERGER: return "MERGER";
- case STATUS_BULK_MERGED: return "BULK_MERGED";
+ case status::worklist: return "worklist";
+ case status::processed: return "processed";
+ case status::merger: return "merger";
+ case status::bulk_merged: return "bulk_merged";
}
}
@@ -1218,7 +1207,7 @@ exploded_node::status_to_str (enum status s)
exploded_node::exploded_node (const point_and_state &ps,
int index)
-: m_ps (ps), m_status (STATUS_WORKLIST), m_index (index),
+: m_ps (ps), m_status (status::worklist), m_index (index),
m_num_processed_stmts (0)
{
gcc_checking_assert (ps.get_state ().m_region_model->canonicalized_p ());
@@ -1296,9 +1285,9 @@ exploded_node::dump_dot (graphviz_out *gv, const dump_args_t &args) const
pp_write_text_to_stream (pp);
pp_printf (pp, "EN: %i", m_index);
- if (m_status == STATUS_MERGER)
+ if (m_status == status::merger)
pp_string (pp, " (merger)");
- else if (m_status == STATUS_BULK_MERGED)
+ else if (m_status == status::bulk_merged)
pp_string (pp, " (bulk merged)");
pp_newline (pp);
@@ -1440,7 +1429,7 @@ exploded_node::dump (const extrinsic_state &ext_state) const
std::unique_ptr<json::object>
exploded_node::to_json (const extrinsic_state &ext_state) const
{
- auto enode_obj = ::make_unique<json::object> ();
+ auto enode_obj = std::make_unique<json::object> ();
enode_obj->set ("point", get_point ().to_json ());
enode_obj->set ("state", get_state ().to_json (ext_state));
@@ -1522,7 +1511,7 @@ exploded_node::on_stmt (exploded_graph &eg,
gcc_assert (called_fn);
return replay_call_summaries (eg,
snode,
- as_a <const gcall *> (stmt),
+ *as_a <const gcall *> (stmt),
state,
path_ctxt,
*called_fn,
@@ -1579,8 +1568,9 @@ exploded_node::on_stmt_pre (exploded_graph &eg,
region_model_context *ctxt)
{
/* Handle special-case calls that require the full program_state. */
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
{
+ const gcall &call = *call_stmt;
if (is_special_named_call_p (call, "__analyzer_dump", 0))
{
/* Handle the builtin "__analyzer_dump" by dumping state
@@ -1609,6 +1599,24 @@ exploded_node::on_stmt_pre (exploded_graph &eg,
ctxt->maybe_did_work ();
return;
}
+ else if (is_cxa_throw_p (call))
+ {
+ on_throw (eg, call, state, false, ctxt);
+ *out_terminate_path = true;
+ return;
+ }
+ else if (is_cxa_rethrow_p (call))
+ {
+ on_throw (eg, call, state, true, ctxt);
+ *out_terminate_path = true;
+ return;
+ }
+ }
+ else if (const gresx *resx = dyn_cast <const gresx *> (stmt))
+ {
+ on_resx (eg, *resx, state, ctxt);
+ *out_terminate_path = true;
+ return;
}
/* Otherwise, defer to m_region_model. */
@@ -1626,7 +1634,7 @@ exploded_node::on_stmt_post (const gimple *stmt,
region_model_context *ctxt)
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- state->m_region_model->on_call_post (call, unknown_side_effects, ctxt);
+ state->m_region_model->on_call_post (*call, unknown_side_effects, ctxt);
}
/* A concrete call_info subclass representing a replay of a call summary. */
@@ -1636,7 +1644,7 @@ class call_summary_edge_info : public call_info
public:
call_summary_edge_info (const call_details &cd,
const function &called_fn,
- call_summary *summary,
+ call_summary &summary,
const extrinsic_state &ext_state)
: call_info (cd, called_fn),
m_called_fn (called_fn),
@@ -1651,7 +1659,7 @@ public:
/* Update STATE based on summary_end_state. */
call_details cd (get_call_details (state->m_region_model, ctxt));
call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
- const program_state &summary_end_state = m_summary->get_state ();
+ const program_state &summary_end_state = m_summary.get_state ();
return state->replay_call_summary (r, summary_end_state);
}
@@ -1662,19 +1670,19 @@ public:
/* Update STATE based on summary_end_state. */
call_details cd (get_call_details (model, ctxt));
call_summary_replay r (cd, m_called_fn, m_summary, m_ext_state);
- const program_state &summary_end_state = m_summary->get_state ();
+ const program_state &summary_end_state = m_summary.get_state ();
model->replay_call_summary (r, *summary_end_state.m_region_model);
return true;
}
void print_desc (pretty_printer &pp) const final override
{
- pp_string (&pp, m_summary->get_desc ().get ());
+ pp_string (&pp, m_summary.get_desc ().get ());
}
private:
const function &m_called_fn;
- call_summary *m_summary;
+ call_summary &m_summary;
const extrinsic_state &m_ext_state;
};
@@ -1684,7 +1692,7 @@ private:
exploded_node::on_stmt_flags
exploded_node::replay_call_summaries (exploded_graph &eg,
const supernode *snode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
program_state *state,
path_context *path_ctxt,
const function &called_fn,
@@ -1696,8 +1704,11 @@ exploded_node::replay_call_summaries (exploded_graph &eg,
/* Each summary will call bifurcate on the PATH_CTXT. */
for (auto summary : called_fn_data.m_summaries)
- replay_call_summary (eg, snode, call_stmt, state,
- path_ctxt, called_fn, summary, ctxt);
+ {
+ gcc_assert (summary);
+ replay_call_summary (eg, snode, call_stmt, state,
+ path_ctxt, called_fn, *summary, ctxt);
+ }
path_ctxt->terminate_path ();
return on_stmt_flags ();
@@ -1710,27 +1721,25 @@ exploded_node::replay_call_summaries (exploded_graph &eg,
void
exploded_node::replay_call_summary (exploded_graph &eg,
const supernode *snode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
program_state *old_state,
path_context *path_ctxt,
const function &called_fn,
- call_summary *summary,
+ call_summary &summary,
region_model_context *ctxt)
{
logger *logger = eg.get_logger ();
LOG_SCOPE (logger);
gcc_assert (snode);
- gcc_assert (call_stmt);
gcc_assert (old_state);
- gcc_assert (summary);
if (logger)
logger->log ("using %s as summary for call to %qE from %qE",
- summary->get_desc ().get (),
+ summary.get_desc ().get (),
called_fn.decl,
snode->get_function ()->decl);
const extrinsic_state &ext_state = eg.get_ext_state ();
- const program_state &summary_end_state = summary->get_state ();
+ const program_state &summary_end_state = summary.get_state ();
if (logger)
{
pretty_printer *pp = logger->get_printer ();
@@ -1752,10 +1761,11 @@ exploded_node::replay_call_summary (exploded_graph &eg,
call_summary_replay r (cd, called_fn, summary, ext_state);
if (path_ctxt)
- path_ctxt->bifurcate (make_unique<call_summary_edge_info> (cd,
- called_fn,
- summary,
- ext_state));
+ path_ctxt->bifurcate
+ (std::make_unique<call_summary_edge_info> (cd,
+ called_fn,
+ summary,
+ ext_state));
}
@@ -1826,7 +1836,7 @@ valid_longjmp_stack_p (const program_point &longjmp_point,
class stale_jmp_buf : public pending_diagnostic_subclass<stale_jmp_buf>
{
public:
- stale_jmp_buf (const gcall *setjmp_call, const gcall *longjmp_call,
+ stale_jmp_buf (const gcall &setjmp_call, const gcall &longjmp_call,
const program_point &setjmp_point)
: m_setjmp_call (setjmp_call), m_longjmp_call (longjmp_call),
m_setjmp_point (setjmp_point), m_stack_pop_event (NULL)
@@ -1849,8 +1859,8 @@ public:
bool operator== (const stale_jmp_buf &other) const
{
- return (m_setjmp_call == other.m_setjmp_call
- && m_longjmp_call == other.m_longjmp_call);
+ return (&m_setjmp_call == &other.m_setjmp_call
+ && &m_longjmp_call == &other.m_longjmp_call);
}
bool
@@ -1903,8 +1913,8 @@ public:
private:
- const gcall *m_setjmp_call;
- const gcall *m_longjmp_call;
+ const gcall &m_setjmp_call;
+ const gcall &m_longjmp_call;
program_point m_setjmp_point;
custom_event *m_stack_pop_event;
};
@@ -1917,11 +1927,11 @@ private:
void
exploded_node::on_longjmp (exploded_graph &eg,
- const gcall *longjmp_call,
+ const gcall &longjmp_call,
program_state *new_state,
region_model_context *ctxt)
{
- tree buf_ptr = gimple_call_arg (longjmp_call, 0);
+ tree buf_ptr = gimple_call_arg (&longjmp_call, 0);
gcc_assert (POINTER_TYPE_P (TREE_TYPE (buf_ptr)));
region_model *new_region_model = new_state->m_region_model;
@@ -1942,7 +1952,7 @@ exploded_node::on_longjmp (exploded_graph &eg,
call back to the setjmp/sigsetjmp. */
rewind_info_t rewind_info (tmp_setjmp_record, longjmp_call);
- const gcall *setjmp_call = rewind_info.get_setjmp_call ();
+ const gcall &setjmp_call = rewind_info.get_setjmp_call ();
const program_point &setjmp_point = rewind_info.get_setjmp_point ();
const program_point &longjmp_point = get_point ();
@@ -1950,9 +1960,9 @@ exploded_node::on_longjmp (exploded_graph &eg,
/* Verify that the setjmp's call_stack hasn't been popped. */
if (!valid_longjmp_stack_p (longjmp_point, setjmp_point))
{
- ctxt->warn (make_unique<stale_jmp_buf> (setjmp_call,
- longjmp_call,
- setjmp_point));
+ ctxt->warn (std::make_unique<stale_jmp_buf> (setjmp_call,
+ longjmp_call,
+ setjmp_point));
return;
}
@@ -1986,8 +1996,8 @@ exploded_node::on_longjmp (exploded_graph &eg,
{
exploded_edge *eedge
= eg.add_edge (const_cast<exploded_node *> (this), next, NULL, true,
- make_unique<rewind_info_t> (tmp_setjmp_record,
- longjmp_call));
+ std::make_unique<rewind_info_t> (tmp_setjmp_record,
+ longjmp_call));
/* For any diagnostics that were queued here (such as leaks) we want
the checker_path to show the rewinding events after the "final event"
@@ -2025,6 +2035,332 @@ exploded_node::on_longjmp (exploded_graph &eg,
}
}
+/* Subclass of call_info for exploded edges that express
+ a throw or rethrow of an exception (actually a call
+ to __cxa_throw or __cxa_rethrow). */
+
+class throw_custom_edge : public call_info
+{
+public:
+ throw_custom_edge (const call_details &cd,
+ tree type,
+ bool is_rethrow)
+ : call_info (cd),
+ m_type (type),
+ m_is_rethrow (is_rethrow)
+ {
+ }
+
+ void print (pretty_printer *pp) const final override
+ {
+ if (m_is_rethrow)
+ {
+ if (m_type)
+ pp_printf (pp, "rethrowing %qT", m_type);
+ else
+ pp_printf (pp, "rethrowing");
+ }
+ else
+ {
+ if (m_type)
+ pp_printf (pp, "throwing %qT", m_type);
+ else
+ pp_printf (pp, "throwing");
+ }
+ }
+
+ void print_desc (pretty_printer &pp) const final override
+ {
+ print (&pp);
+ }
+
+ bool update_model (region_model *model,
+ const exploded_edge *,
+ region_model_context *ctxt) const final override
+ {
+ if (m_is_rethrow)
+ {
+ auto eh_node = model->get_current_caught_exception ();
+ gcc_assert (eh_node);
+ model->push_thrown_exception (*eh_node);
+ }
+ else
+ {
+ call_details cd (get_call_details (model, ctxt));
+
+ const svalue *exception_sval = cd.get_arg_svalue (0);
+ const svalue *tinfo_sval = cd.get_arg_svalue (1);
+ const svalue *destructor_sval = cd.get_arg_svalue (2);
+
+ /* Push a new exception_node on the model's m_exception_stack. */
+ exception_node eh_node (exception_sval, tinfo_sval, destructor_sval);
+ model->push_thrown_exception (eh_node);
+ }
+
+ return true;
+ }
+
+ void add_events_to_path (checker_path *emission_path,
+ const exploded_edge &eedge) const final override
+ {
+ const exploded_node *dst_node = eedge.m_dest;
+ const program_point &dst_point = dst_node->get_point ();
+ const int dst_stack_depth = dst_point.get_stack_depth ();
+
+ const gcall &call = get_call_stmt ();
+
+ emission_path->add_event
+ (std::make_unique<explicit_throw_event>
+ (event_loc_info (call.location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ dst_node,
+ call,
+ m_type,
+ m_is_rethrow));
+ }
+
+private:
+ tree m_type;
+ bool m_is_rethrow;
+};
+
+/* Subclass of custom_edge_info for an exploded edge that expresses
+ unwinding one stack frame during exception handling. */
+
+class unwind_custom_edge : public custom_edge_info
+{
+public:
+ unwind_custom_edge (location_t loc)
+ : m_loc (loc)
+ {
+ }
+
+ void print (pretty_printer *pp) const final override
+ {
+ pp_printf (pp, "unwinding frame");
+ }
+
+ bool update_model (region_model *model,
+ const exploded_edge *,
+ region_model_context *ctxt) const final override
+ {
+ model->pop_frame (NULL_TREE, nullptr, ctxt, nullptr, false);
+ return true;
+ }
+
+ void add_events_to_path (checker_path *emission_path,
+ const exploded_edge &eedge) const final override
+ {
+ const exploded_node *src_node = eedge.m_src;
+ const program_point &src_point = src_node->get_point ();
+ const int src_stack_depth = src_point.get_stack_depth ();
+ emission_path->add_event
+ (std::make_unique<unwind_event> (event_loc_info (m_loc,
+ src_point.get_fndecl (),
+ src_stack_depth)));
+ }
+
+private:
+ location_t m_loc;
+};
+
+/* Locate an SNODE that's a CFG edge with the EH flag,
+ or return nullptr. */
+
+static const superedge *
+get_eh_outedge (const supernode &snode)
+{
+ for (auto out_sedge : snode.m_succs)
+ if (::edge cfg_edge = out_sedge->get_any_cfg_edge ())
+ if (cfg_edge->flags & EDGE_EH)
+ return out_sedge;
+
+ // Not found
+ return nullptr;
+}
+
+/* Given THROWN_ENODE, which expreses a throw or rethrow occurring at
+ THROW_STMT, unwind intraprocedurally and interprocedurally to find
+ the next eh_dispatch statement to handle exceptions, if any.
+
+ Add eedges and enodes to this graph expressing the actions taken
+ to reach an enode containing the eh_dispatch stmt, if any.
+ Only the final enode is added to this graph's worklist.
+
+ Use CTXT to warn about problems e.g. memory leaks due to stack frames
+ being unwound. */
+
+void
+exploded_graph::unwind_from_exception (exploded_node &thrown_enode,
+ const gimple *throw_stmt,
+ region_model_context *ctxt)
+{
+ logger * const logger = get_logger ();
+ LOG_FUNC_1 (logger, "thrown EN: %i", thrown_enode.m_index);
+
+ /* Iteratively unwind the stack looking for an out-cfg-edge
+ flagged EH. */
+ exploded_node *iter_enode = &thrown_enode;
+ while (iter_enode)
+ {
+ /* If we have an out-cfg-edge flagged EH, follow that,
+ presumably to a bb with a label and an eh_dispatch stmt.
+ Otherwise assume no out-cfgs-edges, and we are unwinding to the
+ caller. */
+ if (auto sedge = get_eh_outedge (*iter_enode->get_supernode ()))
+ {
+ /* Intraprocedural case.
+ Assume we have an out-edge flagged with EH leading to
+ code for dispatch to catch handlers. */
+ const program_point next_point
+ = program_point::before_supernode (sedge->m_dest,
+ sedge,
+ iter_enode->get_point ().get_call_string ());
+ exploded_node *next_enode
+ = get_or_create_node (next_point,
+ iter_enode->get_state (),
+ iter_enode,
+ /* Add this enode to the worklist. */
+ true);
+ if (!next_enode)
+ return;
+
+ add_edge (iter_enode, next_enode, NULL, false, nullptr);
+ return;
+ }
+ else
+ {
+ /* Interprocedural case.
+ No out-cfg-edge. Unwind one stack frame. */
+ program_state unwound_state (iter_enode->get_state ());
+ location_t loc = throw_stmt ? throw_stmt->location : UNKNOWN_LOCATION;
+ auto unwind_edge_info
+ = std::make_unique<unwind_custom_edge> (loc);
+ unwind_edge_info->update_model (unwound_state.m_region_model, nullptr,
+ ctxt);
+
+ /* Detect leaks in the new state relative to the old state.
+ Use an alternate ctxt that uses the original enode and the stmt
+ (if any) for the location of any diagnostics. */
+ {
+ uncertainty_t uncertainty;
+ impl_region_model_context ctxt (*this,
+ &thrown_enode,
+ &iter_enode->get_state (),
+ &unwound_state,
+ &uncertainty,
+ nullptr,
+ throw_stmt);
+ program_state::detect_leaks (iter_enode->get_state (),
+ unwound_state,
+ NULL,
+ get_ext_state (), &ctxt);
+ }
+ const call_string &cs = iter_enode->get_point ().get_call_string ();
+ if (cs.empty_p ())
+ {
+ /* Top-level stack frame in analysis: unwinding
+ to the outside world that called us. */
+ return;
+ }
+ else
+ {
+ /* Nested function in analysis: unwinding to
+ the callsite in the analysis (or beyond). */
+ program_point unwound_point
+ = program_point::after_supernode (cs.get_caller_node (), cs);
+ unwound_point.pop_from_call_stack ();
+
+ exploded_node *after_unwind_enode
+ = get_or_create_node (unwound_point,
+ std::move (unwound_state),
+ iter_enode,
+ /* Don't add this enode to the
+ worklist; we will process it
+ on the next iteration. */
+ false);
+
+ if (!after_unwind_enode)
+ return;
+
+ add_edge (iter_enode, after_unwind_enode, NULL, true,
+ std::move (unwind_edge_info));
+ iter_enode = after_unwind_enode;
+ }
+ }
+ }
+}
+
+/* Handle THROW_CALL, a call to __cxa_throw or __cxa_rethrow.
+
+ Create an eedge and destination enode for the throw/rethrow, adding
+ them to this egraph. The new enode isn't added to the worklist, but
+ instead exploded_graph::unwind_from_exception is immediately called
+ on it, potentially creating more eedges and enodes leading to an
+ eh_handler stmt. */
+
+void
+exploded_node::on_throw (exploded_graph &eg,
+ const gcall &throw_call,
+ program_state *new_state,
+ bool is_rethrow,
+ region_model_context *ctxt)
+{
+ region_model *model = new_state->m_region_model;
+ call_details cd (throw_call, model, ctxt);
+
+ /* Create an enode and eedge for the "throw". */
+ tree type = NULL_TREE;
+ if (is_rethrow)
+ {
+ const exception_node *eh_node = model->get_current_caught_exception ();
+ gcc_assert (eh_node);
+ type = eh_node->maybe_get_type ();
+ }
+ else
+ {
+ const svalue *tinfo_sval = cd.get_arg_svalue (1);
+ type = tinfo_sval->maybe_get_type_from_typeinfo ();
+ }
+ auto throw_edge_info
+ = std::make_unique<throw_custom_edge> (cd, type, is_rethrow);
+ throw_edge_info->update_model (model, nullptr, ctxt);
+
+ program_point after_throw_point = get_point ().get_next ();
+
+ exploded_node *after_throw_enode
+ = eg.get_or_create_node (after_throw_point, *new_state, this,
+ /* Don't add to worklist; we process
+ this immediately below. */
+ false);
+
+ if (!after_throw_enode)
+ return;
+
+ /* Create custom exploded_edge for a throw. */
+ eg.add_edge (this, after_throw_enode, NULL, true,
+ std::move (throw_edge_info));
+
+ eg.unwind_from_exception (*after_throw_enode, &throw_call, ctxt);
+}
+
+/* Handle a gimple "resx" statement by adding eedges and enode.
+ that unwind to the next eh_dispatch statement, if any. Only
+ the final enode is added to the worklist. */
+
+void
+exploded_node::on_resx (exploded_graph &eg,
+ const gresx &/*resx*/,
+ program_state */*new_state*/,
+ region_model_context *ctxt)
+{
+ eg.unwind_from_exception (*this,
+ nullptr,
+ ctxt);
+}
+
+
/* Subroutine of exploded_graph::process_node for finding the successors
of the supernode for a function exit basic block.
@@ -2131,20 +2467,16 @@ dynamic_call_info_t::add_events_to_path (checker_path *emission_path,
if (m_is_returning_call)
emission_path->add_event
- (make_unique<return_event> (eedge,
- event_loc_info (m_dynamic_call
- ? m_dynamic_call->location
- : UNKNOWN_LOCATION,
- dest_point.get_fndecl (),
- dest_stack_depth)));
+ (std::make_unique<return_event> (eedge,
+ event_loc_info (m_dynamic_call.location,
+ dest_point.get_fndecl (),
+ dest_stack_depth)));
else
emission_path->add_event
- (make_unique<call_event> (eedge,
- event_loc_info (m_dynamic_call
- ? m_dynamic_call->location
- : UNKNOWN_LOCATION,
- src_point.get_fndecl (),
- src_stack_depth)));
+ (std::make_unique<call_event> (eedge,
+ event_loc_info (m_dynamic_call.location,
+ src_point.get_fndecl (),
+ src_stack_depth)));
}
/* class rewind_info_t : public custom_edge_info. */
@@ -2189,19 +2521,19 @@ rewind_info_t::add_events_to_path (checker_path *emission_path,
const int dst_stack_depth = dst_point.get_stack_depth ();
emission_path->add_event
- (make_unique<rewind_from_longjmp_event>
- (&eedge,
- event_loc_info (get_longjmp_call ()->location,
- src_point.get_fndecl (),
- src_stack_depth),
- this));
+ (std::make_unique<rewind_from_longjmp_event>
+ (&eedge,
+ event_loc_info (get_longjmp_call ().location,
+ src_point.get_fndecl (),
+ src_stack_depth),
+ this));
emission_path->add_event
- (make_unique<rewind_to_setjmp_event>
- (&eedge,
- event_loc_info (get_setjmp_call ()->location,
- dst_point.get_fndecl (),
- dst_stack_depth),
- this));
+ (std::make_unique<rewind_to_setjmp_event>
+ (&eedge,
+ event_loc_info (get_setjmp_call ().location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ this));
}
/* class exploded_edge : public dedge<eg_traits>. */
@@ -2294,7 +2626,7 @@ exploded_edge::dump_dot_label (pretty_printer *pp) const
std::unique_ptr<json::object>
exploded_edge::to_json () const
{
- auto eedge_obj = ::make_unique<json::object> ();
+ auto eedge_obj = std::make_unique<json::object> ();
eedge_obj->set_integer ("src_idx", m_src->m_index);
eedge_obj->set_integer ("dst_idx", m_dest->m_index);
if (m_sedge)
@@ -2420,9 +2752,9 @@ strongly_connected_components::dump () const
std::unique_ptr<json::array>
strongly_connected_components::to_json () const
{
- auto scc_arr = ::make_unique<json::array> ();
+ auto scc_arr = std::make_unique<json::array> ();
for (int i = 0; i < m_sg.num_nodes (); i++)
- scc_arr->append (::make_unique<json::integer_number> (get_scc_id (i)));
+ scc_arr->append (std::make_unique<json::integer_number> (get_scc_id (i)));
return scc_arr;
}
@@ -2518,7 +2850,7 @@ worklist::peek_next ()
void
worklist::add_node (exploded_node *enode)
{
- gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
+ gcc_assert (enode->get_status () == exploded_node::status::worklist);
m_queue.insert (key_t (*this, enode), enode);
}
@@ -2641,7 +2973,7 @@ worklist::key_t::cmp (const worklist::key_t &ka, const worklist::key_t &kb)
std::unique_ptr<json::object>
worklist::to_json () const
{
- auto worklist_obj = ::make_unique<json::object> ();
+ auto worklist_obj = std::make_unique<json::object> ();
worklist_obj->set ("scc", m_scc.to_json ());
@@ -2791,8 +3123,8 @@ public:
const exploded_edge &) const final override
{
emission_path->add_event
- (make_unique<tainted_args_function_custom_event>
- (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0)));
+ (std::make_unique<tainted_args_function_custom_event>
+ (event_loc_info (DECL_SOURCE_LOCATION (m_fndecl), m_fndecl, 0)));
}
private:
@@ -2833,7 +3165,7 @@ exploded_graph::add_function_entry (const function &fun)
if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun.decl)))
{
if (mark_params_as_tainted (&state, fun.decl, m_ext_state))
- edge_info = make_unique<tainted_args_function_info> (fun.decl);
+ edge_info = std::make_unique<tainted_args_function_info> (fun.decl);
}
if (!state.m_valid)
@@ -2851,7 +3183,8 @@ exploded_graph::add_function_entry (const function &fun)
}
/* Get or create an exploded_node for (POINT, STATE).
- If a new node is created, it is added to the worklist.
+ If a new node is created and ADD_TO_WORKLIST is true,
+ it is added to the worklist.
Use ENODE_FOR_DIAG, a pre-existing enode, for any diagnostics
that need to be emitted (e.g. when purging state *before* we have
@@ -2860,7 +3193,8 @@ exploded_graph::add_function_entry (const function &fun)
exploded_node *
exploded_graph::get_or_create_node (const program_point &point,
const program_state &state,
- exploded_node *enode_for_diag)
+ exploded_node *enode_for_diag,
+ bool add_to_worklist)
{
logger * const logger = get_logger ();
LOG_FUNC (logger);
@@ -3035,7 +3369,10 @@ exploded_graph::get_or_create_node (const program_point &point,
}
/* Add the new node to the worlist. */
- m_worklist.add_node (node);
+ if (add_to_worklist)
+ m_worklist.add_node (node);
+ else
+ node->set_status (exploded_node::status::special);
return node;
}
@@ -3238,16 +3575,16 @@ public:
/* Show the field in the struct declaration, e.g.
"(1) field 'store' is marked with '__attribute__((tainted_args))'" */
emission_path->add_event
- (make_unique<tainted_args_field_custom_event> (m_field));
+ (std::make_unique<tainted_args_field_custom_event> (m_field));
/* Show the callback in the initializer
e.g.
"(2) function 'gadget_dev_desc_UDC_store' used as initializer
for field 'store' marked with '__attribute__((tainted_args))'". */
emission_path->add_event
- (make_unique<tainted_args_callback_custom_event>
- (event_loc_info (m_loc, m_fndecl, 0),
- m_field));
+ (std::make_unique<tainted_args_callback_custom_event>
+ (event_loc_info (m_loc, m_fndecl, 0),
+ m_field));
}
private:
@@ -3304,7 +3641,7 @@ add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl,
}
eg->add_edge (eg->get_origin (), enode, NULL, false,
- make_unique<tainted_args_call_info> (field, fndecl, loc));
+ std::make_unique<tainted_args_call_info> (field, fndecl, loc));
}
/* Callback for walk_tree for finding callbacks within initializers;
@@ -3397,7 +3734,7 @@ exploded_graph::process_worklist ()
while (m_worklist.length () > 0)
{
exploded_node *node = m_worklist.take_next ();
- gcc_assert (node->get_status () == exploded_node::STATUS_WORKLIST);
+ gcc_assert (node->get_status () == exploded_node::status::worklist);
gcc_assert (node->m_succs.length () == 0
|| node == m_origin);
@@ -3417,7 +3754,7 @@ exploded_graph::process_worklist ()
if (exploded_node *node_2 = m_worklist.peek_next ())
{
gcc_assert (node_2->get_status ()
- == exploded_node::STATUS_WORKLIST);
+ == exploded_node::status::worklist);
gcc_assert (node->m_succs.length () == 0);
gcc_assert (node_2->m_succs.length () == 0);
@@ -3462,7 +3799,7 @@ exploded_graph::process_worklist ()
/* Remove node_2 from the worklist. */
m_worklist.take_next ();
- node_2->set_status (exploded_node::STATUS_MERGER);
+ node_2->set_status (exploded_node::status::merger);
/* Continue processing "node" below. */
}
@@ -3472,7 +3809,7 @@ exploded_graph::process_worklist ()
in the worklist, to be processed on the next
iteration. */
add_edge (node, node_2, NULL, false);
- node->set_status (exploded_node::STATUS_MERGER);
+ node->set_status (exploded_node::status::merger);
continue;
}
else
@@ -3517,7 +3854,7 @@ exploded_graph::process_worklist ()
else
{
add_edge (node, merged_enode, NULL, false);
- node->set_status (exploded_node::STATUS_MERGER);
+ node->set_status (exploded_node::status::merger);
}
if (merged_enode == node_2)
@@ -3525,7 +3862,7 @@ exploded_graph::process_worklist ()
else
{
add_edge (node_2, merged_enode, NULL, false);
- node_2->set_status (exploded_node::STATUS_MERGER);
+ node_2->set_status (exploded_node::status::merger);
}
continue;
@@ -3575,7 +3912,7 @@ exploded_graph::process_worklist ()
If ENODE's point is of the form (before-supernode, SNODE) and the next
nodes in the worklist are a consecutive run of enodes of the same form,
for the same supernode as ENODE (but potentially from different in-edges),
- process them all together, setting their status to STATUS_BULK_MERGED,
+ process them all together, setting their status to status::bulk_merged,
and return true.
Otherwise, return false, in which case ENODE must be processed in the
normal way.
@@ -3614,7 +3951,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode)
int m_merger_idx;
};
- gcc_assert (enode->get_status () == exploded_node::STATUS_WORKLIST);
+ gcc_assert (enode->get_status () == exploded_node::status::worklist);
gcc_assert (enode->m_succs.length () == 0);
const program_point &point = enode->get_point ();
@@ -3634,7 +3971,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode)
while (exploded_node *enode_2 = m_worklist.peek_next ())
{
gcc_assert (enode_2->get_status ()
- == exploded_node::STATUS_WORKLIST);
+ == exploded_node::status::worklist);
gcc_assert (enode_2->m_succs.length () == 0);
const program_point &point_2 = enode_2->get_point ();
@@ -3761,7 +4098,7 @@ maybe_process_run_of_before_supernode_enodes (exploded_node *enode)
if (next)
add_edge (it->m_input_enode, next, NULL,
false); /* no "work" is done during merger. */
- it->m_input_enode->set_status (exploded_node::STATUS_BULK_MERGED);
+ it->m_input_enode->set_status (exploded_node::status::bulk_merged);
}
if (logger)
@@ -3779,8 +4116,9 @@ static bool
stmt_requires_new_enode_p (const gimple *stmt,
const gimple *prev_stmt)
{
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
{
+ const gcall &call = *call_stmt;
/* Stop consolidating at calls to
"__analyzer_dump_exploded_nodes", so they always appear at the
start of an exploded_node. */
@@ -3849,7 +4187,7 @@ state_change_requires_new_enode_p (const program_state &old_state,
functions or calls that happen via function pointer. */
bool
-exploded_graph::maybe_create_dynamic_call (const gcall *call,
+exploded_graph::maybe_create_dynamic_call (const gcall &call,
tree fn_decl,
exploded_node *node,
program_state next_state,
@@ -3904,7 +4242,7 @@ exploded_graph::maybe_create_dynamic_call (const gcall *call,
if (enode)
add_edge (node,enode, NULL,
false, /* No work is done by the call itself. */
- make_unique<dynamic_call_info_t> (call));
+ std::make_unique<dynamic_call_info_t> (call));
return true;
}
}
@@ -3992,7 +4330,7 @@ private:
class jump_through_null : public pending_diagnostic_subclass<jump_through_null>
{
public:
- jump_through_null (const gcall *call)
+ jump_through_null (const gcall &call)
: m_call (call)
{}
@@ -4003,7 +4341,7 @@ public:
bool operator== (const jump_through_null &other) const
{
- return m_call == other.m_call;
+ return &m_call == &other.m_call;
}
int get_controlling_option () const final override
@@ -4024,7 +4362,7 @@ public:
}
private:
- const gcall *m_call;
+ const gcall &m_call;
};
/* The core of exploded_graph::process_worklist (the main analysis loop),
@@ -4041,7 +4379,7 @@ exploded_graph::process_node (exploded_node *node)
logger * const logger = get_logger ();
LOG_FUNC_1 (logger, "EN: %i", node->m_index);
- node->set_status (exploded_node::STATUS_PROCESSED);
+ node->set_status (exploded_node::status::processed);
const program_point &point = node->get_point ();
@@ -4269,12 +4607,18 @@ exploded_graph::process_node (exploded_node *node)
NULL, /* no exploded_edge yet. */
&bifurcation_ctxt))
{
- exploded_node *next2
- = get_or_create_node (next_point, bifurcated_new_state, node);
- if (next2)
- add_edge (node, next2, NULL,
- true /* assume that work could be done */,
- std::move (edge_info));
+ if (exploded_node *next2
+ = edge_info->create_enode
+ (*this,
+ next_point,
+ std::move (bifurcated_new_state),
+ node,
+ &bifurcation_ctxt))
+ {
+ add_edge (node, next2, NULL,
+ true /* assume that work could be done */,
+ std::move (edge_info));
+ }
}
else
{
@@ -4344,8 +4688,8 @@ exploded_graph::process_node (exploded_node *node)
if (succ->m_kind == SUPEREDGE_INTRAPROCEDURAL_CALL
&& !(succ->get_any_callgraph_edge ()))
{
- const gcall *call
- = point.get_supernode ()->get_final_call ();
+ const gcall &call
+ = *point.get_supernode ()->get_final_call ();
impl_region_model_context ctxt (*this,
node,
@@ -4369,12 +4713,13 @@ exploded_graph::process_node (exploded_node *node)
if (!call_discovered)
{
/* Check for jump through NULL. */
- if (tree fn_ptr = gimple_call_fn (call))
+ if (tree fn_ptr = gimple_call_fn (&call))
{
const svalue *fn_ptr_sval
= model->get_rvalue (fn_ptr, &ctxt);
if (fn_ptr_sval->all_zeroes_p ())
- ctxt.warn (make_unique<jump_through_null> (call));
+ ctxt.warn
+ (std::make_unique<jump_through_null> (call));
}
/* An unknown function or a special function was called
@@ -4394,6 +4739,18 @@ exploded_graph::process_node (exploded_node *node)
}
}
+ /* Ignore CFG edges in the sgraph flagged with EH whilst
+ we're exploring the egraph.
+ We only use these sedges in special-case logic for
+ dealing with exception-handling. */
+ if (auto cfg_sedge = succ->dyn_cast_cfg_superedge ())
+ if (cfg_sedge->get_flags () & EDGE_EH)
+ {
+ if (logger)
+ logger->log ("rejecting EH edge");
+ continue;
+ }
+
if (!node->on_edge (*this, succ, &next_point, &next_state,
&uncertainty))
{
@@ -4431,7 +4788,7 @@ exploded_graph::process_node (exploded_node *node)
= next_point.get_supernode ()->get_returning_call ();
if (call)
- next_state.returning_call (*this, node, call, &uncertainty);
+ next_state.returning_call (*this, node, *call, &uncertainty);
if (next_state.m_valid)
{
@@ -4441,7 +4798,7 @@ exploded_graph::process_node (exploded_node *node)
node);
if (enode)
add_edge (node, enode, NULL, false,
- make_unique<dynamic_call_info_t> (call, true));
+ std::make_unique<dynamic_call_info_t> (*call, true));
}
}
}
@@ -4660,11 +5017,11 @@ exploded_graph::dump_states_for_supernode (FILE *out,
std::unique_ptr<json::object>
exploded_graph::to_json () const
{
- auto egraph_obj = ::make_unique<json::object> ();
+ auto egraph_obj = std::make_unique<json::object> ();
/* Nodes. */
{
- auto nodes_arr = ::make_unique<json::array> ();
+ auto nodes_arr = std::make_unique<json::array> ();
unsigned i;
exploded_node *n;
FOR_EACH_VEC_ELT (m_nodes, i, n)
@@ -4674,7 +5031,7 @@ exploded_graph::to_json () const
/* Edges. */
{
- auto edges_arr = ::make_unique<json::array> ();
+ auto edges_arr = std::make_unique<json::array> ();
unsigned i;
exploded_edge *n;
FOR_EACH_VEC_ELT (m_edges, i, n)
@@ -4780,9 +5137,9 @@ exploded_path::feasible_p (logger *logger,
const program_point &src_point = src_enode.get_point ();
const gimple *last_stmt
= src_point.get_supernode ()->get_last_stmt ();
- *out = ::make_unique<feasibility_problem> (edge_idx, *eedge,
- last_stmt,
- std::move (rc));
+ *out = std::make_unique<feasibility_problem> (edge_idx, *eedge,
+ last_stmt,
+ std::move (rc));
}
return false;
}
@@ -4986,7 +5343,7 @@ maybe_update_for_edge (logger *logger,
== PK_BEFORE_SUPERNODE);
function *fun = eedge->m_dest->get_function ();
gcc_assert (fun);
- m_model.push_frame (*fun, NULL, ctxt);
+ m_model.push_frame (*fun, nullptr, nullptr, ctxt);
if (logger)
logger->log (" pushing frame for %qD", fun->decl);
}
@@ -5037,8 +5394,8 @@ feasibility_state::update_for_stmt (const gimple *stmt)
m_model.on_asm_stmt (asm_stmt, NULL);
else if (const gcall *call = dyn_cast <const gcall *> (stmt))
{
- bool unknown_side_effects = m_model.on_call_pre (call, NULL);
- m_model.on_call_post (call, unknown_side_effects, NULL);
+ bool unknown_side_effects = m_model.on_call_pre (*call, NULL);
+ m_model.on_call_post (*call, unknown_side_effects, NULL);
}
else if (const greturn *return_ = dyn_cast <const greturn *> (stmt))
m_model.on_return (return_, NULL);
@@ -5499,7 +5856,7 @@ exploded_graph::dump_exploded_nodes () const
if (const gimple *stmt = enode->get_stmt ())
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (is_special_named_call_p (call, "__analyzer_dump_exploded_nodes",
+ if (is_special_named_call_p (*call, "__analyzer_dump_exploded_nodes",
1))
{
if (seen.contains (stmt))
@@ -5520,13 +5877,13 @@ exploded_graph::dump_exploded_nodes () const
{
default:
gcc_unreachable ();
- case exploded_node::STATUS_WORKLIST:
+ case exploded_node::status::worklist:
worklist_enodes.safe_push (other_enode);
break;
- case exploded_node::STATUS_PROCESSED:
+ case exploded_node::status::processed:
processed_enodes.safe_push (other_enode);
break;
- case exploded_node::STATUS_MERGER:
+ case exploded_node::status::merger:
merger_enodes.safe_push (other_enode);
break;
}
@@ -6007,15 +6364,18 @@ private:
{
default:
gcc_unreachable ();
- case exploded_node::STATUS_WORKLIST:
+ case exploded_node::status::worklist:
pp_string (pp, "(W)");
break;
- case exploded_node::STATUS_PROCESSED:
+ case exploded_node::status::processed:
+ break;
+ case exploded_node::status::special:
+ pp_string (pp, "(S)");
break;
- case exploded_node::STATUS_MERGER:
+ case exploded_node::status::merger:
pp_string (pp, "(M)");
break;
- case exploded_node::STATUS_BULK_MERGED:
+ case exploded_node::status::bulk_merged:
pp_string (pp, "(BM)");
break;
}
@@ -6094,7 +6454,7 @@ dump_analyzer_json (const supergraph &sg,
return;
}
- auto toplev_obj = ::make_unique<json::object> ();
+ auto toplev_obj = std::make_unique<json::object> ();
toplev_obj->set ("sgraph", sg.to_json ());
toplev_obj->set ("egraph", eg.to_json ());
@@ -6115,8 +6475,8 @@ dump_analyzer_json (const supergraph &sg,
class plugin_analyzer_init_impl : public plugin_analyzer_init_iface
{
public:
- plugin_analyzer_init_impl (auto_delete_vec <state_machine> *checkers,
- known_function_manager *known_fn_mgr,
+ plugin_analyzer_init_impl (std::vector<std::unique_ptr<state_machine>> &checkers,
+ known_function_manager &known_fn_mgr,
logger *logger)
: m_checkers (checkers),
m_known_fn_mgr (known_fn_mgr),
@@ -6126,14 +6486,14 @@ public:
void register_state_machine (std::unique_ptr<state_machine> sm) final override
{
LOG_SCOPE (m_logger);
- m_checkers->safe_push (sm.release ());
+ m_checkers.push_back (std::move (sm));
}
void register_known_function (const char *name,
std::unique_ptr<known_function> kf) final override
{
LOG_SCOPE (m_logger);
- m_known_fn_mgr->add (name, std::move (kf));
+ m_known_fn_mgr.add (name, std::move (kf));
}
logger *get_logger () const final override
@@ -6142,8 +6502,8 @@ public:
}
private:
- auto_delete_vec <state_machine> *m_checkers;
- known_function_manager *m_known_fn_mgr;
+ std::vector<std::unique_ptr<state_machine>> &m_checkers;
+ known_function_manager &m_known_fn_mgr;
logger *m_logger;
};
@@ -6197,27 +6557,25 @@ impl_run_checkers (logger *logger)
free (filename);
}
- auto_delete_vec <state_machine> checkers;
- make_checkers (checkers, logger);
+ auto checkers = make_checkers (logger);
register_known_functions (*eng.get_known_function_manager (),
*eng.get_model_manager ());
- plugin_analyzer_init_impl data (&checkers,
- eng.get_known_function_manager (),
+ plugin_analyzer_init_impl data (checkers,
+ *eng.get_known_function_manager (),
logger);
invoke_plugin_callbacks (PLUGIN_ANALYZER_INIT, &data);
if (logger)
{
- int i;
- state_machine *sm;
- FOR_EACH_VEC_ELT (checkers, i, sm)
- logger->log ("checkers[%i]: %s", i, sm->get_name ());
+ int i = 0;
+ for (auto &sm : checkers)
+ logger->log ("checkers[%i]: %s", ++i, sm->get_name ());
}
/* Extrinsic state shared by nodes in the graph. */
- const extrinsic_state ext_state (checkers, &eng, logger);
+ const extrinsic_state ext_state (std::move (checkers), &eng, logger);
const analysis_plan plan (sg, logger);
diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h
index 6148ed7..32c72dc 100644
--- a/gcc/analyzer/exploded-graph.h
+++ b/gcc/analyzer/exploded-graph.h
@@ -206,20 +206,24 @@ class exploded_node : public dnode<eg_traits>
This allows us to distinguish enodes that were merged during
worklist-handling, and thus never had process_node called on them
(in favor of processing the merged node). */
- enum status
+ enum class status
{
/* Node is in the worklist. */
- STATUS_WORKLIST,
+ worklist,
/* Node has had exploded_graph::process_node called on it. */
- STATUS_PROCESSED,
+ processed,
+
+ /* Node was excluded from worklist on creation.
+ e.g. for handling exception-unwinding. */
+ special,
/* Node was left unprocessed due to merger; it won't have had
exploded_graph::process_node called on it. */
- STATUS_MERGER,
+ merger,
/* Node was processed by maybe_process_run_of_before_supernode_enodes. */
- STATUS_BULK_MERGED
+ bulk_merged
};
static const char * status_to_str (enum status s);
@@ -282,7 +286,7 @@ class exploded_node : public dnode<eg_traits>
on_stmt_flags replay_call_summaries (exploded_graph &eg,
const supernode *snode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
program_state *state,
path_context *path_ctxt,
const function &called_fn,
@@ -290,11 +294,11 @@ class exploded_node : public dnode<eg_traits>
region_model_context *ctxt);
void replay_call_summary (exploded_graph &eg,
const supernode *snode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
program_state *state,
path_context *path_ctxt,
const function &called_fn,
- call_summary *summary,
+ call_summary &summary,
region_model_context *ctxt);
bool on_edge (exploded_graph &eg,
@@ -303,9 +307,18 @@ class exploded_node : public dnode<eg_traits>
program_state *next_state,
uncertainty_t *uncertainty);
void on_longjmp (exploded_graph &eg,
- const gcall *call,
+ const gcall &call,
program_state *new_state,
region_model_context *ctxt);
+ void on_throw (exploded_graph &eg,
+ const gcall &call,
+ program_state *new_state,
+ bool is_rethrow,
+ region_model_context *ctxt);
+ void on_resx (exploded_graph &eg,
+ const gresx &resx,
+ program_state *new_state,
+ region_model_context *ctxt);
void detect_leaks (exploded_graph &eg);
@@ -335,7 +348,7 @@ class exploded_node : public dnode<eg_traits>
enum status get_status () const { return m_status; }
void set_status (enum status status)
{
- gcc_assert (m_status == STATUS_WORKLIST);
+ gcc_assert (m_status == status::worklist);
m_status = status;
}
@@ -424,7 +437,7 @@ private:
class dynamic_call_info_t : public custom_edge_info
{
public:
- dynamic_call_info_t (const gcall *dynamic_call,
+ dynamic_call_info_t (const gcall &dynamic_call,
const bool is_returning_call = false)
: m_dynamic_call (dynamic_call),
m_is_returning_call (is_returning_call)
@@ -445,7 +458,7 @@ public:
void add_events_to_path (checker_path *emission_path,
const exploded_edge &eedge) const final override;
private:
- const gcall *m_dynamic_call;
+ const gcall &m_dynamic_call;
const bool m_is_returning_call;
};
@@ -457,7 +470,7 @@ class rewind_info_t : public custom_edge_info
{
public:
rewind_info_t (const setjmp_record &setjmp_record,
- const gcall *longjmp_call)
+ const gcall &longjmp_call)
: m_setjmp_record (setjmp_record),
m_longjmp_call (longjmp_call)
{}
@@ -486,12 +499,12 @@ public:
return origin_point;
}
- const gcall *get_setjmp_call () const
+ const gcall &get_setjmp_call () const
{
- return m_setjmp_record.m_setjmp_call;
+ return *m_setjmp_record.m_setjmp_call;
}
- const gcall *get_longjmp_call () const
+ const gcall &get_longjmp_call () const
{
return m_longjmp_call;
}
@@ -503,7 +516,7 @@ public:
private:
setjmp_record m_setjmp_record;
- const gcall *m_longjmp_call;
+ const gcall &m_longjmp_call;
};
/* Statistics about aspects of an exploded_graph. */
@@ -817,7 +830,7 @@ public:
bool maybe_process_run_of_before_supernode_enodes (exploded_node *node);
void process_node (exploded_node *node);
- bool maybe_create_dynamic_call (const gcall *call,
+ bool maybe_create_dynamic_call (const gcall &call,
tree fn_decl,
exploded_node *node,
program_state next_state,
@@ -827,7 +840,8 @@ public:
exploded_node *get_or_create_node (const program_point &point,
const program_state &state,
- exploded_node *enode_for_diag);
+ exploded_node *enode_for_diag,
+ bool add_to_worklist = true);
exploded_edge *add_edge (exploded_node *src, exploded_node *dest,
const superedge *sedge, bool could_do_work,
std::unique_ptr<custom_edge_info> custom = NULL);
@@ -881,6 +895,10 @@ public:
void on_escaped_function (tree fndecl);
+ void unwind_from_exception (exploded_node &enode,
+ const gimple *stmt,
+ region_model_context *ctxt);
+
/* In infinite-loop.cc */
void detect_infinite_loops ();
diff --git a/gcc/analyzer/feasible-graph.cc b/gcc/analyzer/feasible-graph.cc
index f8d28ac..25a97e7 100644
--- a/gcc/analyzer/feasible-graph.cc
+++ b/gcc/analyzer/feasible-graph.cc
@@ -18,21 +18,13 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "pretty-print.h"
-#include "gcc-rich-location.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+#include "digraph.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -42,12 +34,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
diff --git a/gcc/analyzer/infinite-loop.cc b/gcc/analyzer/infinite-loop.cc
index d6f05d8..ec0b079 100644
--- a/gcc/analyzer/infinite-loop.cc
+++ b/gcc/analyzer/infinite-loop.cc
@@ -18,28 +18,15 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "fold-const.h"
-#include "gcc-rich-location.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "function.h"
-#include "pretty-print.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "tristate.h"
-#include "ordered-hash-map.h"
-#include "selftest.h"
-#include "json.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-pretty-print.h"
+#include "cgraph.h"
+#include "digraph.h"
+#include "diagnostic-format-sarif.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -49,20 +36,11 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "gimple-pretty-print.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/checker-path.h"
#include "analyzer/feasible-graph.h"
-#include "make-unique.h"
-#include "diagnostic-format-sarif.h"
/* A bundle of data characterizing a particular infinite loop
identified within the exploded graph. */
@@ -108,9 +86,9 @@ struct infinite_loop
std::unique_ptr<json::object>
to_json () const
{
- auto loop_obj = ::make_unique<json::object> ();
+ auto loop_obj = std::make_unique<json::object> ();
loop_obj->set_integer ("enode", m_enode.m_index);
- auto edge_arr = ::make_unique<json::array> ();
+ auto edge_arr = std::make_unique<json::array> ();
for (auto eedge : m_eedge_vec)
edge_arr->append (eedge->to_json ());
loop_obj->set ("eedges", std::move (edge_arr));
@@ -237,7 +215,7 @@ public:
checker_path *emission_path) final override
{
emission_path->add_event
- (make_unique<warning_event>
+ (std::make_unique<warning_event>
(event_loc_info (m_inf_loop->m_loc,
enode->get_function ()->decl,
enode->get_stack_depth ()),
@@ -285,43 +263,46 @@ public:
if (switch_cfg_sedge->implicitly_created_default_p ())
{
emission_path->add_event
- (make_unique<perpetual_start_cfg_edge_event> (*eedge,
- loc_info_from));
+ (std::make_unique<perpetual_start_cfg_edge_event>
+ (*eedge,
+ loc_info_from));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (*eedge,
- loc_info_to));
+ (std::make_unique<end_cfg_edge_event>
+ (*eedge,
+ loc_info_to));
}
}
if (cfg_sedge->true_value_p ())
{
emission_path->add_event
- (make_unique<perpetual_start_cfg_edge_event> (*eedge,
- loc_info_from));
+ (std::make_unique<perpetual_start_cfg_edge_event>
+ (*eedge,
+ loc_info_from));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (*eedge,
- loc_info_to));
+ (std::make_unique<end_cfg_edge_event>
+ (*eedge,
+ loc_info_to));
}
else if (cfg_sedge->false_value_p ())
{
emission_path->add_event
- (make_unique<perpetual_start_cfg_edge_event> (*eedge,
- loc_info_from));
+ (std::make_unique<perpetual_start_cfg_edge_event>
+ (*eedge,
+ loc_info_from));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (*eedge,
- loc_info_to));
+ (std::make_unique<end_cfg_edge_event>
+ (*eedge,
+ loc_info_to));
}
else if (cfg_sedge->back_edge_p ())
{
emission_path->add_event
- (make_unique<looping_back_event> (*eedge, loc_info_from));
+ (std::make_unique<looping_back_event> (*eedge, loc_info_from));
emission_path->add_event
- (make_unique<end_cfg_edge_event>
- (*eedge,
- loc_info_to));
+ (std::make_unique<end_cfg_edge_event>
+ (*eedge,
+ loc_info_to));
}
}
}
@@ -415,7 +396,7 @@ starts_infinite_loop_p (const exploded_node &enode,
feasible_node *curr_fnode = nullptr;
if (flag_dump_analyzer_infinite_loop)
- fg = ::make_unique<feasible_graph> ();
+ fg = std::make_unique<feasible_graph> ();
location_t first_loc = UNKNOWN_LOCATION;
const exploded_node *iter = &enode;
@@ -432,7 +413,7 @@ starts_infinite_loop_p (const exploded_node &enode,
if (logger)
logger->log ("iter: EN: %i", iter->m_index);
/* Analysis bailed out before processing this node. */
- if (iter->get_status () == exploded_node::STATUS_WORKLIST)
+ if (iter->get_status () == exploded_node::status::worklist)
{
if (logger)
logger->log ("rejecting: EN: %i is still in worklist",
@@ -460,10 +441,10 @@ starts_infinite_loop_p (const exploded_node &enode,
fg->dump_dot (filename, nullptr, dump_args);
free (filename);
}
- return ::make_unique<infinite_loop> (enode,
- first_loc,
- std::move (eedges),
- logger);
+ return std::make_unique<infinite_loop> (enode,
+ first_loc,
+ std::move (eedges),
+ logger);
}
else
{
@@ -593,7 +574,7 @@ exploded_graph::detect_infinite_loops ()
pending_location ploc (enode, snode, inf_loop->m_loc);
auto d
- = ::make_unique<infinite_loop_diagnostic> (std::move (inf_loop));
+ = std::make_unique<infinite_loop_diagnostic> (std::move (inf_loop));
get_diagnostic_manager ().add_diagnostic (ploc, std::move (d));
}
}
diff --git a/gcc/analyzer/infinite-recursion.cc b/gcc/analyzer/infinite-recursion.cc
index 42f87ed..0641117 100644
--- a/gcc/analyzer/infinite-recursion.cc
+++ b/gcc/analyzer/infinite-recursion.cc
@@ -18,28 +18,14 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "fold-const.h"
-#include "gcc-rich-location.h"
-#include "alloc-pool.h"
-#include "fibonacci_heap.h"
-#include "shortest-paths.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "function.h"
-#include "pretty-print.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "tristate.h"
-#include "ordered-hash-map.h"
-#include "selftest.h"
-#include "json.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "gimple-pretty-print.h"
+#include "cgraph.h"
+#include "digraph.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -49,17 +35,9 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "gimple-pretty-print.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
-#include "make-unique.h"
#include "analyzer/checker-path.h"
#include "analyzer/feasible-graph.h"
#include "diagnostic-format-sarif.h"
@@ -170,14 +148,15 @@ public:
{
gcc_assert (m_prev_entry_event == NULL);
std::unique_ptr<checker_event> prev_entry_event
- = make_unique <recursive_function_entry_event> (dst_point,
- *this, false);
+ = std::make_unique <recursive_function_entry_event> (dst_point,
+ *this, false);
m_prev_entry_event = prev_entry_event.get ();
emission_path->add_event (std::move (prev_entry_event));
}
else if (eedge.m_dest == m_new_entry_enode)
emission_path->add_event
- (make_unique<recursive_function_entry_event> (dst_point, *this, true));
+ (std::make_unique<recursive_function_entry_event>
+ (dst_point, *this, true));
else
pending_diagnostic::add_function_entry_event (eedge, emission_path);
}
@@ -193,7 +172,7 @@ public:
{
gcc_assert (m_new_entry_enode);
emission_path->add_event
- (make_unique<warning_event>
+ (std::make_unique<warning_event>
(event_loc_info (m_new_entry_enode->get_supernode
()->get_start_location (),
m_callee_fndecl,
@@ -645,7 +624,7 @@ exploded_graph::detect_infinite_recursion (exploded_node *enode)
nullptr);
get_diagnostic_manager ().add_diagnostic
(ploc,
- make_unique<infinite_recursion_diagnostic> (prev_entry_enode,
- enode,
- fndecl));
+ std::make_unique<infinite_recursion_diagnostic> (prev_entry_enode,
+ enode,
+ fndecl));
}
diff --git a/gcc/analyzer/kf-analyzer.cc b/gcc/analyzer/kf-analyzer.cc
index 54f85a4..3e671e5 100644
--- a/gcc/analyzer/kf-analyzer.cc
+++ b/gcc/analyzer/kf-analyzer.cc
@@ -18,24 +18,16 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "diagnostic.h"
#include "tree-diagnostic.h" /* for default_tree_printer. */
+#include "pretty-print-markup.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/call-details.h"
-#include "make-unique.h"
-#include "pretty-print-markup.h"
#if ENABLE_ANALYZER
@@ -110,7 +102,7 @@ public:
const region *base_reg = reg->get_base_region ();
const svalue *capacity = model->get_capacity (base_reg);
label_text desc = capacity->get_desc (true);
- warning_at (cd.get_call_stmt ()->location, 0,
+ warning_at (cd.get_call_stmt ().location, 0,
"capacity: %qs", desc.get ());
}
};
@@ -305,7 +297,7 @@ public:
region_model_context *ctxt = cd.get_ctxt ();
if (!ctxt)
return;
- ctxt->warn (make_unique<dump_path_diagnostic> ());
+ ctxt->warn (std::make_unique<dump_path_diagnostic> ());
}
};
@@ -382,22 +374,28 @@ public:
void
register_known_analyzer_functions (known_function_manager &kfm)
{
- kfm.add ("__analyzer_break", make_unique<kf_analyzer_break> ());
- kfm.add ("__analyzer_describe", make_unique<kf_analyzer_describe> ());
+ kfm.add ("__analyzer_break",
+ std::make_unique<kf_analyzer_break> ());
+ kfm.add ("__analyzer_describe",
+ std::make_unique<kf_analyzer_describe> ());
kfm.add ("__analyzer_dump_capacity",
- make_unique<kf_analyzer_dump_capacity> ());
- kfm.add ("__analyzer_dump_escaped", make_unique<kf_analyzer_dump_escaped> ());
+ std::make_unique<kf_analyzer_dump_capacity> ());
+ kfm.add ("__analyzer_dump_escaped",
+ std::make_unique<kf_analyzer_dump_escaped> ());
kfm.add ("__analyzer_dump_exploded_nodes",
- make_unique<kf_analyzer_dump_exploded_nodes> ());
+ std::make_unique<kf_analyzer_dump_exploded_nodes> ());
kfm.add ("__analyzer_dump_named_constant",
- make_unique<kf_analyzer_dump_named_constant> ());
- kfm.add ("__analyzer_dump_path", make_unique<kf_analyzer_dump_path> ());
+ std::make_unique<kf_analyzer_dump_named_constant> ());
+ kfm.add ("__analyzer_dump_path",
+ std::make_unique<kf_analyzer_dump_path> ());
kfm.add ("__analyzer_dump_region_model",
- make_unique<kf_analyzer_dump_region_model> ());
- kfm.add ("__analyzer_eval", make_unique<kf_analyzer_eval> ());
+ std::make_unique<kf_analyzer_dump_region_model> ());
+ kfm.add ("__analyzer_eval",
+ std::make_unique<kf_analyzer_eval> ());
kfm.add ("__analyzer_get_unknown_ptr",
- make_unique<kf_analyzer_get_unknown_ptr> ());
- kfm.add ("__analyzer_get_strlen", make_kf_strlen ());
+ std::make_unique<kf_analyzer_get_unknown_ptr> ());
+ kfm.add ("__analyzer_get_strlen",
+ make_kf_strlen ());
}
} // namespace ana
diff --git a/gcc/analyzer/kf-lang-cp.cc b/gcc/analyzer/kf-lang-cp.cc
index b2b0c9b..01a98b0 100644
--- a/gcc/analyzer/kf-lang-cp.cc
+++ b/gcc/analyzer/kf-lang-cp.cc
@@ -18,20 +18,13 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "diagnostic.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -43,10 +36,9 @@ along with GCC; see the file COPYING3. If not see
See https://en.cppreference.com/w/cpp/memory/new/operator_new. */
-bool is_placement_new_p (const gcall *call)
+bool is_placement_new_p (const gcall &call)
{
- gcc_assert (call);
- tree fndecl = gimple_call_fndecl (call);
+ tree fndecl = gimple_call_fndecl (&call);
if (!fndecl || TREE_CODE (TREE_TYPE (fndecl)) == METHOD_TYPE)
/* Give up on overloaded operator new. */
@@ -91,7 +83,7 @@ public:
region_model_manager *mgr = cd.get_manager ();
const svalue *size_sval = cd.get_arg_svalue (0);
region_model_context *ctxt = cd.get_ctxt ();
- const gcall *call = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
/* If the call was actually a placement new, check that accessing
the buffer lhs is placed into does not result in out-of-bounds. */
@@ -169,10 +161,165 @@ public:
/* If the ptr points to an underlying heap region, delete it,
poisoning pointers. */
model->unbind_region_and_descendents (freed_reg,
- POISON_KIND_DELETED);
+ poison_kind::deleted);
+ }
+ }
+
+};
+
+class kf_cxa_allocate_exception : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 1 && cd.arg_is_size_p (0);
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ region_model_manager *mgr = cd.get_manager ();
+ const svalue *size_sval = cd.get_arg_svalue (0);
+ region_model_context *ctxt = cd.get_ctxt ();
+
+ /* Create a heap allocated region. */
+ const region *new_reg
+ = model->get_or_create_region_for_heap_alloc (size_sval, ctxt);
+ if (cd.get_lhs_type ())
+ {
+ const svalue *ptr_sval
+ = mgr->get_ptr_svalue (cd.get_lhs_type (), new_reg);
+ cd.maybe_set_lhs (ptr_sval);
+ }
+ }
+};
+
+class kf_cxa_begin_catch : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return (cd.num_args () == 1
+ && POINTER_TYPE_P (cd.get_arg_type (0)));
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+
+ auto node = model->pop_thrown_exception ();
+ model->push_caught_exception (node);
+ cd.maybe_set_lhs (node.m_exception_sval);
+ }
+};
+
+class kf_cxa_end_catch : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return cd.num_args () == 0;
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ region_model *model = cd.get_model ();
+ model->pop_caught_exception ();
+ }
+};
+
+/* A subclass of pending_diagnostic for complaining about an exception
+ of an unexpected type being thrown (due to a call to
+ __cxa_call_unexpected).
+ See https://en.cppreference.com/w/cpp/language/except_spec */
+
+class throw_of_unexpected_type
+: public pending_diagnostic_subclass<throw_of_unexpected_type>
+{
+public:
+ throw_of_unexpected_type (tree exception_type,
+ tree thrown_from_fndecl)
+ : m_exception_type (exception_type),
+ m_thrown_from_fndecl (thrown_from_fndecl)
+ {
+ gcc_assert (m_exception_type);
+ gcc_assert (m_thrown_from_fndecl);
+ }
+
+ const char *get_kind () const final override
+ {
+ return "throw_of_unexpected_type";
+ }
+
+ bool operator== (const throw_of_unexpected_type &other) const
+ {
+ return (m_exception_type == other.m_exception_type
+ && m_thrown_from_fndecl == other.m_thrown_from_fndecl);
+ }
+
+ int get_controlling_option () const final override
+ {
+ return OPT_Wanalyzer_throw_of_unexpected_type;
+ }
+
+ bool emit (diagnostic_emission_context &ctxt) final override
+ {
+ auto_diagnostic_group d;
+
+ bool warned
+ = ctxt.warn ("throwing exception of unexpected type %qT from %qE",
+ m_exception_type, m_thrown_from_fndecl);
+ if (warned)
+ {
+ inform (DECL_SOURCE_LOCATION (m_thrown_from_fndecl),
+ "%qE declared here", m_thrown_from_fndecl);
+ // TODO: show specified types?
}
+ return warned;
+ }
+
+ bool
+ describe_final_event (pretty_printer &pp,
+ const evdesc::final_event &) final override
+ {
+ pp_printf (&pp,
+ "exception of unexpected type %qT thrown from %qE",
+ m_exception_type, m_thrown_from_fndecl);
+ return true;
+ }
+
+private:
+ tree m_exception_type;
+ tree m_thrown_from_fndecl;
+};
+
+/* See https://en.cppreference.com/w/cpp/language/except_spec */
+
+class kf_cxa_call_unexpected : public known_function
+{
+public:
+ bool matches_call_types_p (const call_details &cd) const final override
+ {
+ return (cd.num_args () == 1
+ && POINTER_TYPE_P (cd.get_arg_type (0)));
}
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ if (region_model_context *ctxt = cd.get_ctxt ())
+ {
+ region_model *model = cd.get_model ();
+ tree thrown_from_fndecl = model->get_current_function ()->decl;
+ /* We must have a thrown exception. */
+ auto eh_node = model->get_current_thrown_exception ();
+ gcc_assert (eh_node);
+ tree exception_type = eh_node->maybe_get_type ();
+ ctxt->warn
+ (std::make_unique<throw_of_unexpected_type> (exception_type,
+ thrown_from_fndecl));
+ ctxt->terminate_path ();
+ }
+ }
};
/* Populate KFM with instances of known functions relating to C++. */
@@ -180,10 +327,21 @@ public:
void
register_known_functions_lang_cp (known_function_manager &kfm)
{
- kfm.add ("operator new", make_unique<kf_operator_new> ());
- kfm.add ("operator new []", make_unique<kf_operator_new> ());
- kfm.add ("operator delete", make_unique<kf_operator_delete> ());
- kfm.add ("operator delete []", make_unique<kf_operator_delete> ());
+ kfm.add ("operator new", std::make_unique<kf_operator_new> ());
+ kfm.add ("operator new []", std::make_unique<kf_operator_new> ());
+ kfm.add ("operator delete", std::make_unique<kf_operator_delete> ());
+ kfm.add ("operator delete []", std::make_unique<kf_operator_delete> ());
+
+ /* Functions mentioned in "Itanium C++ ABI: Exception Handling"'s
+ "Level II: C++ ABI"
+ https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-abi */
+ kfm.add ("__cxa_allocate_exception",
+ std::make_unique<kf_cxa_allocate_exception> ());
+ // We treat __cxa_throw and __cxa_rethrow as special cases
+ kfm.add ("__cxa_begin_catch", std::make_unique<kf_cxa_begin_catch> ());
+ kfm.add ("__cxa_end_catch", std::make_unique<kf_cxa_end_catch> ());
+ kfm.add ("__cxa_call_unexpected",
+ std::make_unique<kf_cxa_call_unexpected> ());
}
} // namespace ana
diff --git a/gcc/analyzer/kf.cc b/gcc/analyzer/kf.cc
index dceedd4..75b6279 100644
--- a/gcc/analyzer/kf.cc
+++ b/gcc/analyzer/kf.cc
@@ -18,23 +18,14 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "diagnostic-metadata.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "diagnostic.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -50,7 +41,6 @@ public:
: m_call_stmt (cd.get_call_stmt ()),
m_callee_fndecl (cd.get_fndecl_for_call ())
{
- gcc_assert (m_call_stmt);
gcc_assert (m_callee_fndecl);
}
@@ -61,7 +51,7 @@ public:
bool operator== (const undefined_function_behavior &other) const
{
- return (m_call_stmt == other.m_call_stmt
+ return (&m_call_stmt == &other.m_call_stmt
&& m_callee_fndecl == other.m_callee_fndecl);
}
@@ -70,7 +60,7 @@ public:
tree get_callee_fndecl () const { return m_callee_fndecl; }
private:
- const gimple *m_call_stmt;
+ const gimple &m_call_stmt;
tree m_callee_fndecl;
};
@@ -596,7 +586,7 @@ kf_free::impl_call_post (const call_details &cd) const
/* If the ptr points to an underlying heap region, delete it,
poisoning pointers. */
region_model *model = cd.get_model ();
- model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
+ model->unbind_region_and_descendents (freed_reg, poison_kind::freed);
model->unset_dynamic_extents (freed_reg);
}
}
@@ -881,7 +871,7 @@ public:
break;
case MEMSPACE_STACK:
if (ctxt)
- ctxt->warn (make_unique<putenv_of_auto_var> (fndecl, reg));
+ ctxt->warn (std::make_unique<putenv_of_auto_var> (fndecl, reg));
break;
}
cd.set_any_lhs_with_defaults ();
@@ -1084,7 +1074,7 @@ kf_realloc::impl_call_post (const call_details &cd) const
/* If the ptr points to an underlying heap region, delete it,
poisoning pointers. */
- model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
+ model->unbind_region_and_descendents (freed_reg, poison_kind::freed);
model->unset_dynamic_extents (freed_reg);
}
@@ -1129,9 +1119,9 @@ kf_realloc::impl_call_post (const call_details &cd) const
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<success_no_move> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<success_with_move> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<failure> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<success_no_move> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<success_with_move> (cd));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1200,7 +1190,7 @@ kf_strchr::impl_call_post (const call_details &cd) const
using the str_reg as the id of the conjured_svalue. */
const svalue *offset
= mgr->get_or_create_conjured_svalue (size_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
str_reg,
conjured_purge (model,
ctxt));
@@ -1220,8 +1210,8 @@ kf_strchr::impl_call_post (const call_details &cd) const
/* Body of kf_strchr::impl_call_post. */
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<strchr_call_info> (cd, true));
+ cd.get_ctxt ()->bifurcate (std::make_unique<strchr_call_info> (cd, false));
+ cd.get_ctxt ()->bifurcate (std::make_unique<strchr_call_info> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1286,6 +1276,27 @@ public:
/* Currently a no-op. */
};
+/* Handler for "__builtin_eh_pointer". */
+
+class kf_eh_pointer : public builtin_known_function
+{
+public:
+ bool matches_call_types_p (const call_details &) const final override
+ {
+ return true;
+ }
+
+ enum built_in_function builtin_code () const final override
+ {
+ return BUILT_IN_EH_POINTER;
+ }
+
+ void impl_call_pre (const call_details &cd) const final override
+ {
+ cd.set_any_lhs_with_defaults ();
+ }
+};
+
/* Handler for "strcat" and "__builtin_strcat_chk". */
class kf_strcat : public builtin_known_function
@@ -1476,7 +1487,7 @@ public:
std::unique_ptr<known_function>
make_kf_strlen ()
{
- return make_unique<kf_strlen> ();
+ return std::make_unique<kf_strlen> ();
}
/* Handler for "strncpy" and "__builtin_strncpy".
@@ -1650,11 +1661,13 @@ kf_strncpy::impl_call_post (const call_details &cd) const
nullptr,
nullptr);
cd.get_ctxt ()->bifurcate
- (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval,
- false));
+ (std::make_unique<strncpy_call_info>
+ (cd, num_bytes_with_terminator_sval,
+ false));
cd.get_ctxt ()->bifurcate
- (make_unique<strncpy_call_info> (cd, num_bytes_with_terminator_sval,
- true));
+ (std::make_unique<strncpy_call_info>
+ (cd, num_bytes_with_terminator_sval,
+ true));
cd.get_ctxt ()->terminate_path ();
}
};
@@ -1757,7 +1770,7 @@ kf_strstr::impl_call_post (const call_details &cd) const
using the str_reg as the id of the conjured_svalue. */
const svalue *offset
= mgr->get_or_create_conjured_svalue (size_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
str_reg,
conjured_purge (model,
ctxt));
@@ -1777,8 +1790,8 @@ kf_strstr::impl_call_post (const call_details &cd) const
/* Body of kf_strstr::impl_call_post. */
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<strstr_call_info> (cd, true));
+ cd.get_ctxt ()->bifurcate (std::make_unique<strstr_call_info> (cd, false));
+ cd.get_ctxt ()->bifurcate (std::make_unique<strstr_call_info> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1924,7 +1937,7 @@ public:
if (cd.get_arg_svalue (0)->all_zeroes_p ())
{
if (ctxt)
- ctxt->warn (::make_unique<undefined_behavior> (cd));
+ ctxt->warn (::std::make_unique<undefined_behavior> (cd));
}
/* Assume that "str" was actually non-null; terminate
@@ -1958,14 +1971,14 @@ public:
using the str_reg as the id of the conjured_svalue. */
const svalue *start_offset
= mgr->get_or_create_conjured_svalue (size_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
str_reg,
conjured_purge (model,
ctxt),
0);
const svalue *nul_offset
= mgr->get_or_create_conjured_svalue (size_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
str_reg,
conjured_purge (model,
ctxt),
@@ -2042,13 +2055,13 @@ public:
Typically the str is either null or non-null at a particular site,
so hopefully this will generally just lead to two out-edges. */
cd.get_ctxt ()->bifurcate
- (make_unique<strtok_call_info> (cd, m_private_reg, false, false));
+ (std::make_unique<strtok_call_info> (cd, m_private_reg, false, false));
cd.get_ctxt ()->bifurcate
- (make_unique<strtok_call_info> (cd, m_private_reg, false, true));
+ (std::make_unique<strtok_call_info> (cd, m_private_reg, false, true));
cd.get_ctxt ()->bifurcate
- (make_unique<strtok_call_info> (cd, m_private_reg, true, false));
+ (std::make_unique<strtok_call_info> (cd, m_private_reg, true, false));
cd.get_ctxt ()->bifurcate
- (make_unique<strtok_call_info> (cd, m_private_reg, true, true));
+ (std::make_unique<strtok_call_info> (cd, m_private_reg, true, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2074,127 +2087,127 @@ region_model::impl_deallocation_call (const call_details &cd)
static void
register_atomic_builtins (known_function_manager &kfm)
{
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE, make_unique<kf_atomic_exchange> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, make_unique<kf_atomic_exchange_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD, make_unique<kf_atomic_load> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_N, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_1, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_2, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_4, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_8, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_LOAD_16, make_unique<kf_atomic_load_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE, make_unique<kf_atomic_store> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_N, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_1, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_2, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_4, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_8, make_unique<kf_atomic_store_n> ());
- kfm.add (BUILT_IN_ATOMIC_STORE_16, make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE, std::make_unique<kf_atomic_exchange> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_N, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_1, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_2, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_4, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_8, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_EXCHANGE_16, std::make_unique<kf_atomic_exchange_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD, std::make_unique<kf_atomic_load> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_N, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_1, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_2, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_4, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_8, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_LOAD_16, std::make_unique<kf_atomic_load_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE, std::make_unique<kf_atomic_store> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_N, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_1, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_2, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_4, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_8, std::make_unique<kf_atomic_store_n> ());
+ kfm.add (BUILT_IN_ATOMIC_STORE_16, std::make_unique<kf_atomic_store_n> ());
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_1,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_2,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_4,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_8,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_ADD_FETCH_16,
- make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_1,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_2,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_4,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_8,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_SUB_FETCH_16,
- make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_1,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_2,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_4,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_8,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_AND_FETCH_16,
- make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_1,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_2,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_4,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_8,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_XOR_FETCH_16,
- make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_1,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_2,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_4,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_8,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_OR_FETCH_16,
- make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_op_fetch> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_1,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_2,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_4,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_8,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_ADD_16,
- make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (PLUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_1,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_2,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_4,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_8,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_SUB_16,
- make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (MINUS_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_1,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_2,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_4,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_8,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_AND_16,
- make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_AND_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_1,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_2,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_4,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_8,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_XOR_16,
- make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_XOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_1,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_2,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_4,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_8,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
kfm.add (BUILT_IN_ATOMIC_FETCH_OR_16,
- make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
+ std::make_unique<kf_atomic_fetch_op> (BIT_IOR_EXPR));
}
/* Handle calls to the various IFN_UBSAN_* with no return value.
@@ -2224,14 +2237,14 @@ register_sanitizer_builtins (known_function_manager &kfm)
/* Handle calls to the various IFN_UBSAN_* with no return value.
For now, treat these as no-ops. */
kfm.add (IFN_UBSAN_NULL,
- make_unique<kf_ubsan_noop> ());
+ std::make_unique<kf_ubsan_noop> ());
kfm.add (IFN_UBSAN_BOUNDS,
- make_unique<kf_ubsan_noop> ());
+ std::make_unique<kf_ubsan_noop> ());
kfm.add (IFN_UBSAN_PTR,
- make_unique<kf_ubsan_noop> ());
+ std::make_unique<kf_ubsan_noop> ());
kfm.add (BUILT_IN_UBSAN_HANDLE_NONNULL_ARG,
- make_unique<kf_ubsan_handler> ());
+ std::make_unique<kf_ubsan_handler> ());
}
/* Populate KFM with instances of known functions supported by the core of the
@@ -2246,17 +2259,19 @@ register_known_functions (known_function_manager &kfm,
/* Internal fns the analyzer has known_functions for. */
{
- kfm.add (IFN_BUILTIN_EXPECT, make_unique<kf_expect> ());
+ kfm.add (IFN_BUILTIN_EXPECT, std::make_unique<kf_expect> ());
}
/* GCC built-ins that do not correspond to a function
in the standard library. */
{
- kfm.add (BUILT_IN_EXPECT, make_unique<kf_expect> ());
- kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, make_unique<kf_expect> ());
- kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, make_unique<kf_alloca> ());
- kfm.add (BUILT_IN_STACK_RESTORE, make_unique<kf_stack_restore> ());
- kfm.add (BUILT_IN_STACK_SAVE, make_unique<kf_stack_save> ());
+ kfm.add (BUILT_IN_EXPECT, std::make_unique<kf_expect> ());
+ kfm.add (BUILT_IN_EXPECT_WITH_PROBABILITY, std::make_unique<kf_expect> ());
+ kfm.add (BUILT_IN_ALLOCA_WITH_ALIGN, std::make_unique<kf_alloca> ());
+ kfm.add (BUILT_IN_STACK_RESTORE, std::make_unique<kf_stack_restore> ());
+ kfm.add (BUILT_IN_STACK_SAVE, std::make_unique<kf_stack_save> ());
+
+ kfm.add (BUILT_IN_EH_POINTER, std::make_unique<kf_eh_pointer> ());
register_atomic_builtins (kfm);
register_sanitizer_builtins (kfm);
@@ -2266,58 +2281,58 @@ register_known_functions (known_function_manager &kfm,
/* Known builtins and C standard library functions
the analyzer has known functions for. */
{
- kfm.add ("alloca", make_unique<kf_alloca> ());
- kfm.add ("__builtin_alloca", make_unique<kf_alloca> ());
- kfm.add ("calloc", make_unique<kf_calloc> ());
- kfm.add ("__builtin_calloc", make_unique<kf_calloc> ());
- kfm.add ("free", make_unique<kf_free> ());
- kfm.add ("__builtin_free", make_unique<kf_free> ());
- kfm.add ("malloc", make_unique<kf_malloc> ());
- kfm.add ("__builtin_malloc", make_unique<kf_malloc> ());
+ kfm.add ("alloca", std::make_unique<kf_alloca> ());
+ kfm.add ("__builtin_alloca", std::make_unique<kf_alloca> ());
+ kfm.add ("calloc", std::make_unique<kf_calloc> ());
+ kfm.add ("__builtin_calloc", std::make_unique<kf_calloc> ());
+ kfm.add ("free", std::make_unique<kf_free> ());
+ kfm.add ("__builtin_free", std::make_unique<kf_free> ());
+ kfm.add ("malloc", std::make_unique<kf_malloc> ());
+ kfm.add ("__builtin_malloc", std::make_unique<kf_malloc> ());
kfm.add ("memcpy",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
kfm.add ("__builtin_memcpy",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
- kfm.add ("__memcpy_chk", make_unique<kf_memcpy_memmove>
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
+ kfm.add ("__memcpy_chk", std::make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMCPY_CHK));
- kfm.add ("__builtin___memcpy_chk", make_unique<kf_memcpy_memmove>
+ kfm.add ("__builtin___memcpy_chk", std::make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMCPY_CHK));
kfm.add ("memmove",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
kfm.add ("__builtin_memmove",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
- kfm.add ("__memmove_chk", make_unique<kf_memcpy_memmove>
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
+ kfm.add ("__memmove_chk", std::make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMMOVE_CHK));
- kfm.add ("__builtin___memmove_chk", make_unique<kf_memcpy_memmove>
+ kfm.add ("__builtin___memmove_chk", std::make_unique<kf_memcpy_memmove>
(kf_memcpy_memmove::KF_MEMMOVE_CHK));
- kfm.add ("memset", make_unique<kf_memset> (false));
- kfm.add ("__builtin_memset", make_unique<kf_memset> (false));
- kfm.add ("__memset_chk", make_unique<kf_memset> (true));
- kfm.add ("__builtin___memset_chk", make_unique<kf_memset> (true));
- kfm.add ("realloc", make_unique<kf_realloc> ());
- kfm.add ("__builtin_realloc", make_unique<kf_realloc> ());
- kfm.add ("sprintf", make_unique<kf_sprintf> ());
- kfm.add ("__builtin_sprintf", make_unique<kf_sprintf> ());
- kfm.add ("strchr", make_unique<kf_strchr> ());
- kfm.add ("__builtin_strchr", make_unique<kf_strchr> ());
- kfm.add ("strcpy", make_unique<kf_strcpy> (2, false));
- kfm.add ("__builtin_strcpy", make_unique<kf_strcpy> (2, false));
- kfm.add ("__strcpy_chk", make_unique<kf_strcpy> (3, true));
- kfm.add ("__builtin___strcpy_chk", make_unique<kf_strcpy> (3, true));
- kfm.add ("strcat", make_unique<kf_strcat> (2, false));
- kfm.add ("__builtin_strcat", make_unique<kf_strcat> (2, false));
- kfm.add ("__strcat_chk", make_unique<kf_strcat> (3, true));
- kfm.add ("__builtin___strcat_chk", make_unique<kf_strcat> (3, true));
- kfm.add ("strdup", make_unique<kf_strdup> ());
- kfm.add ("__builtin_strdup", make_unique<kf_strdup> ());
- kfm.add ("strncpy", make_unique<kf_strncpy> ());
- kfm.add ("__builtin_strncpy", make_unique<kf_strncpy> ());
- kfm.add ("strndup", make_unique<kf_strndup> ());
- kfm.add ("__builtin_strndup", make_unique<kf_strndup> ());
- kfm.add ("strlen", make_unique<kf_strlen> ());
- kfm.add ("__builtin_strlen", make_unique<kf_strlen> ());
- kfm.add ("strstr", make_unique<kf_strstr> ());
- kfm.add ("__builtin_strstr", make_unique<kf_strstr> ());
+ kfm.add ("memset", std::make_unique<kf_memset> (false));
+ kfm.add ("__builtin_memset", std::make_unique<kf_memset> (false));
+ kfm.add ("__memset_chk", std::make_unique<kf_memset> (true));
+ kfm.add ("__builtin___memset_chk", std::make_unique<kf_memset> (true));
+ kfm.add ("realloc", std::make_unique<kf_realloc> ());
+ kfm.add ("__builtin_realloc", std::make_unique<kf_realloc> ());
+ kfm.add ("sprintf", std::make_unique<kf_sprintf> ());
+ kfm.add ("__builtin_sprintf", std::make_unique<kf_sprintf> ());
+ kfm.add ("strchr", std::make_unique<kf_strchr> ());
+ kfm.add ("__builtin_strchr", std::make_unique<kf_strchr> ());
+ kfm.add ("strcpy", std::make_unique<kf_strcpy> (2, false));
+ kfm.add ("__builtin_strcpy", std::make_unique<kf_strcpy> (2, false));
+ kfm.add ("__strcpy_chk", std::make_unique<kf_strcpy> (3, true));
+ kfm.add ("__builtin___strcpy_chk", std::make_unique<kf_strcpy> (3, true));
+ kfm.add ("strcat", std::make_unique<kf_strcat> (2, false));
+ kfm.add ("__builtin_strcat", std::make_unique<kf_strcat> (2, false));
+ kfm.add ("__strcat_chk", std::make_unique<kf_strcat> (3, true));
+ kfm.add ("__builtin___strcat_chk", std::make_unique<kf_strcat> (3, true));
+ kfm.add ("strdup", std::make_unique<kf_strdup> ());
+ kfm.add ("__builtin_strdup", std::make_unique<kf_strdup> ());
+ kfm.add ("strncpy", std::make_unique<kf_strncpy> ());
+ kfm.add ("__builtin_strncpy", std::make_unique<kf_strncpy> ());
+ kfm.add ("strndup", std::make_unique<kf_strndup> ());
+ kfm.add ("__builtin_strndup", std::make_unique<kf_strndup> ());
+ kfm.add ("strlen", std::make_unique<kf_strlen> ());
+ kfm.add ("__builtin_strlen", std::make_unique<kf_strlen> ());
+ kfm.add ("strstr", std::make_unique<kf_strstr> ());
+ kfm.add ("__builtin_strstr", std::make_unique<kf_strstr> ());
register_atomic_builtins (kfm);
register_varargs_builtins (kfm);
@@ -2325,9 +2340,9 @@ register_known_functions (known_function_manager &kfm,
/* Known POSIX functions, and some non-standard extensions. */
{
- kfm.add ("fopen", make_unique<kf_fopen> ());
- kfm.add ("putenv", make_unique<kf_putenv> ());
- kfm.add ("strtok", make_unique<kf_strtok> (rmm));
+ kfm.add ("fopen", std::make_unique<kf_fopen> ());
+ kfm.add ("putenv", std::make_unique<kf_putenv> ());
+ kfm.add ("strtok", std::make_unique<kf_strtok> (rmm));
register_known_fd_functions (kfm);
register_known_file_functions (kfm);
@@ -2335,13 +2350,13 @@ register_known_functions (known_function_manager &kfm,
/* glibc functions. */
{
- kfm.add ("__errno_location", make_unique<kf_errno_location> ());
- kfm.add ("error", make_unique<kf_error> (3));
- kfm.add ("error_at_line", make_unique<kf_error> (5));
+ kfm.add ("__errno_location", std::make_unique<kf_errno_location> ());
+ kfm.add ("error", std::make_unique<kf_error> (3));
+ kfm.add ("error_at_line", std::make_unique<kf_error> (5));
/* Variants of "error" and "error_at_line" seen by the
analyzer at -O0 (PR analyzer/115724). */
- kfm.add ("__error_alias", make_unique<kf_error> (3));
- kfm.add ("__error_at_line_alias", make_unique<kf_error> (5));
+ kfm.add ("__error_alias", std::make_unique<kf_error> (3));
+ kfm.add ("__error_at_line_alias", std::make_unique<kf_error> (5));
}
/* Other implementations of C standard library. */
@@ -2355,9 +2370,9 @@ register_known_functions (known_function_manager &kfm,
#define errno (*__error())
and similarly __errno for newlib.
Add these as synonyms for "__errno_location". */
- kfm.add ("___errno", make_unique<kf_errno_location> ());
- kfm.add ("__error", make_unique<kf_errno_location> ());
- kfm.add ("__errno", make_unique<kf_errno_location> ());
+ kfm.add ("___errno", std::make_unique<kf_errno_location> ());
+ kfm.add ("__error", std::make_unique<kf_errno_location> ());
+ kfm.add ("__errno", std::make_unique<kf_errno_location> ());
}
/* Language-specific support functions. */
@@ -2367,22 +2382,22 @@ register_known_functions (known_function_manager &kfm,
from <cstdlib> etc for the C spellings of these headers (e.g. <stdlib.h>),
so we must match against these too. */
{
- kfm.add_std_ns ("malloc", make_unique<kf_malloc> ());
- kfm.add_std_ns ("free", make_unique<kf_free> ());
- kfm.add_std_ns ("realloc", make_unique<kf_realloc> ());
- kfm.add_std_ns ("calloc", make_unique<kf_calloc> ());
+ kfm.add_std_ns ("malloc", std::make_unique<kf_malloc> ());
+ kfm.add_std_ns ("free", std::make_unique<kf_free> ());
+ kfm.add_std_ns ("realloc", std::make_unique<kf_realloc> ());
+ kfm.add_std_ns ("calloc", std::make_unique<kf_calloc> ());
kfm.add_std_ns
("memcpy",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMCPY));
kfm.add_std_ns
("memmove",
- make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
- kfm.add_std_ns ("memset", make_unique<kf_memset> (false));
- kfm.add_std_ns ("strcat", make_unique<kf_strcat> (2, false));
- kfm.add_std_ns ("strcpy", make_unique<kf_strcpy> (2, false));
- kfm.add_std_ns ("strlen", make_unique<kf_strlen> ());
- kfm.add_std_ns ("strncpy", make_unique<kf_strncpy> ());
- kfm.add_std_ns ("strtok", make_unique<kf_strtok> (rmm));
+ std::make_unique<kf_memcpy_memmove> (kf_memcpy_memmove::KF_MEMMOVE));
+ kfm.add_std_ns ("memset", std::make_unique<kf_memset> (false));
+ kfm.add_std_ns ("strcat", std::make_unique<kf_strcat> (2, false));
+ kfm.add_std_ns ("strcpy", std::make_unique<kf_strcpy> (2, false));
+ kfm.add_std_ns ("strlen", std::make_unique<kf_strlen> ());
+ kfm.add_std_ns ("strncpy", std::make_unique<kf_strncpy> ());
+ kfm.add_std_ns ("strtok", std::make_unique<kf_strtok> (rmm));
}
}
diff --git a/gcc/analyzer/known-function-manager.cc b/gcc/analyzer/known-function-manager.cc
index db670b8..1a2930e 100644
--- a/gcc/analyzer/known-function-manager.cc
+++ b/gcc/analyzer/known-function-manager.cc
@@ -18,17 +18,12 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "diagnostic-core.h"
-#include "analyzer/analyzer-logging.h"
#include "stringpool.h"
-#include "basic-block.h"
-#include "gimple.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/known-function-manager.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
@@ -108,7 +103,7 @@ known_function_manager::get_match (tree fndecl, const call_details &cd) const
{
if (const known_function *candidate
= get_normal_builtin (DECL_FUNCTION_CODE (fndecl)))
- if (gimple_builtin_call_types_compatible_p (cd.get_call_stmt (),
+ if (gimple_builtin_call_types_compatible_p (&cd.get_call_stmt (),
fndecl))
return candidate;
}
diff --git a/gcc/analyzer/pending-diagnostic.cc b/gcc/analyzer/pending-diagnostic.cc
index 0f69d02..70dc815 100644
--- a/gcc/analyzer/pending-diagnostic.cc
+++ b/gcc/analyzer/pending-diagnostic.cc
@@ -18,18 +18,18 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "intl.h"
-#include "diagnostic.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "diagnostic-event-id.h"
+#include "cpplib.h"
+#include "digraph.h"
+#include "ordered-hash-map.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
-#include "diagnostic-event-id.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
@@ -37,20 +37,10 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
-#include "cpplib.h"
-#include "digraph.h"
-#include "ordered-hash-map.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
-#include "diagnostic-path.h"
#include "analyzer/checker-path.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -195,7 +185,7 @@ pending_diagnostic::add_function_entry_event (const exploded_edge &eedge,
{
const exploded_node *dst_node = eedge.m_dest;
const program_point &dst_point = dst_node->get_point ();
- emission_path->add_event (make_unique<function_entry_event> (dst_point));
+ emission_path->add_event (std::make_unique<function_entry_event> (dst_point));
}
/* Base implementation of pending_diagnostic::add_call_event.
@@ -210,12 +200,12 @@ pending_diagnostic::add_call_event (const exploded_edge &eedge,
const int src_stack_depth = src_point.get_stack_depth ();
const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
emission_path->add_event
- (make_unique<call_event> (eedge,
- event_loc_info (last_stmt
- ? last_stmt->location
- : UNKNOWN_LOCATION,
- src_point.get_fndecl (),
- src_stack_depth)));
+ (std::make_unique<call_event> (eedge,
+ event_loc_info (last_stmt
+ ? last_stmt->location
+ : UNKNOWN_LOCATION,
+ src_point.get_fndecl (),
+ src_stack_depth)));
}
/* Base implementation of pending_diagnostic::add_region_creation_events.
@@ -228,12 +218,13 @@ pending_diagnostic::add_region_creation_events (const region *reg,
checker_path &emission_path)
{
emission_path.add_event
- (make_unique<region_creation_event_memory_space> (reg->get_memory_space (),
- loc_info));
+ (std::make_unique<region_creation_event_memory_space>
+ (reg->get_memory_space (),
+ loc_info));
if (capacity)
emission_path.add_event
- (make_unique<region_creation_event_capacity> (capacity, loc_info));
+ (std::make_unique<region_creation_event_capacity> (capacity, loc_info));
}
/* Base implementation of pending_diagnostic::add_final_event.
@@ -247,7 +238,7 @@ pending_diagnostic::add_final_event (const state_machine *sm,
checker_path *emission_path)
{
emission_path->add_event
- (make_unique<warning_event>
+ (std::make_unique<warning_event>
(loc_info,
enode,
sm, var, state));
diff --git a/gcc/analyzer/program-point.cc b/gcc/analyzer/program-point.cc
index 473c102..c95f863 100644
--- a/gcc/analyzer/program-point.cc
+++ b/gcc/analyzer/program-point.cc
@@ -18,42 +18,28 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "gimple-pretty-print.h"
+#include "analyzer/common.h"
+
+#include "diagnostic-event-id.h"
#include "gcc-rich-location.h"
-#include "ordered-hash-map.h"
-#include "options.h"
-#include "cgraph.h"
-#include "function.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "digraph.h"
-#include "analyzer/analyzer.h"
+#include "gimple-pretty-print.h"
+#include "sbitmap.h"
+#include "selftest.h"
+#include "shortest-paths.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-point.h"
-#include "sbitmap.h"
-#include "bitmap.h"
-#include "selftest.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/sm.h"
#include "analyzer/program-state.h"
-#include "diagnostic-event-id.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "shortest-paths.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/analysis-plan.h"
#include "analyzer/inlining-iterator.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -316,7 +302,7 @@ program_point::dump () const
std::unique_ptr<json::object>
program_point::to_json () const
{
- auto point_obj = ::make_unique<json::object> ();
+ auto point_obj = std::make_unique<json::object> ();
point_obj->set_string ("kind", point_kind_to_string (get_kind ()));
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index ec96900..21f78e5 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -18,44 +18,36 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "diagnostic.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/sm.h"
+#include "analyzer/common.h"
+
#include "sbitmap.h"
-#include "bitmap.h"
#include "ordered-hash-map.h"
#include "selftest.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+#include "digraph.h"
+#include "diagnostic-event-id.h"
+
+#include "text-art/tree-widget.h"
+#include "text-art/dump.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/sm.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/constraint-manager.h"
-#include "diagnostic-event-id.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/diagnostic-manager.h"
-#include "cfg.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
-#include "digraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-state.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/state-purge.h"
#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
-#include "text-art/tree-widget.h"
-#include "text-art/dump.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -69,11 +61,10 @@ void
extrinsic_state::dump_to_pp (pretty_printer *pp) const
{
pp_printf (pp, "extrinsic_state: %i checker(s)\n", get_num_checkers ());
- unsigned i;
- state_machine *checker;
- FOR_EACH_VEC_ELT (m_checkers, i, checker)
+ unsigned i = 0;
+ for (auto &checker : m_checkers)
{
- pp_printf (pp, "m_checkers[%i]: %qs\n", i, checker->get_name ());
+ pp_printf (pp, "m_checkers[%i]: %qs\n", ++i, checker->get_name ());
checker->dump_to_pp (pp);
}
}
@@ -101,13 +92,11 @@ extrinsic_state::dump () const
std::unique_ptr<json::object>
extrinsic_state::to_json () const
{
- auto ext_state_obj = ::make_unique<json::object> ();
+ auto ext_state_obj = std::make_unique<json::object> ();
{
- auto checkers_arr = ::make_unique<json::array> ();
- unsigned i;
- state_machine *sm;
- FOR_EACH_VEC_ELT (m_checkers, i, sm)
+ auto checkers_arr = std::make_unique<json::array> ();
+ for (auto &sm : m_checkers)
checkers_arr->append (sm->to_json ());
ext_state_obj->set ("checkers", std::move (checkers_arr));
}
@@ -133,10 +122,8 @@ extrinsic_state::get_model_manager () const
bool
extrinsic_state::get_sm_idx_by_name (const char *name, unsigned *out) const
{
- unsigned i;
- state_machine *sm;
- FOR_EACH_VEC_ELT (m_checkers, i, sm)
- if (0 == strcmp (name, sm->get_name ()))
+ for (size_t i = 0; i < m_checkers.size (); ++i)
+ if (0 == strcmp (name, m_checkers[i]->get_name ()))
{
/* Found NAME. */
*out = i;
@@ -279,7 +266,7 @@ sm_state_map::dump (bool simple) const
std::unique_ptr<json::object>
sm_state_map::to_json () const
{
- auto map_obj = ::make_unique<json::object> ();
+ auto map_obj = std::make_unique<json::object> ();
if (m_global_state != m_sm.get_start_state ())
map_obj->set ("global", m_global_state->to_json ());
@@ -1188,7 +1175,7 @@ program_state::dump () const
std::unique_ptr<json::object>
program_state::to_json (const extrinsic_state &ext_state) const
{
- auto state_obj = ::make_unique<json::object> ();
+ auto state_obj = std::make_unique<json::object> ();
state_obj->set ("store", m_region_model->get_store ()->to_json ());
state_obj->set ("constraints",
@@ -1199,7 +1186,7 @@ program_state::to_json (const extrinsic_state &ext_state) const
/* Provide m_checker_states as an object, using names as keys. */
{
- auto checkers_obj = ::make_unique<json::object> ();
+ auto checkers_obj = std::make_unique<json::object> ();
int i;
sm_state_map *smap;
@@ -1244,7 +1231,7 @@ void
program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED,
const function &fun)
{
- m_region_model->push_frame (fun, NULL, NULL);
+ m_region_model->push_frame (fun, nullptr, nullptr, nullptr);
}
/* Get the current function of this state. */
@@ -1348,7 +1335,7 @@ program_state::on_edge (exploded_graph &eg,
void
program_state::push_call (exploded_graph &eg,
exploded_node *enode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
uncertainty_t *uncertainty)
{
/* Update state. */
@@ -1371,7 +1358,7 @@ program_state::push_call (exploded_graph &eg,
void
program_state::returning_call (exploded_graph &eg,
exploded_node *enode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
uncertainty_t *uncertainty)
{
/* Update state. */
@@ -1749,7 +1736,7 @@ program_state::replay_call_summary (call_summary_replay &r,
/* Handle calls to "__analyzer_dump_state". */
void
-program_state::impl_call_analyzer_dump_state (const gcall *call,
+program_state::impl_call_analyzer_dump_state (const gcall &call,
const extrinsic_state &ext_state,
region_model_context *ctxt)
{
@@ -1757,13 +1744,13 @@ program_state::impl_call_analyzer_dump_state (const gcall *call,
const char *sm_name = cd.get_arg_string_literal (0);
if (!sm_name)
{
- error_at (call->location, "cannot determine state machine");
+ error_at (call.location, "cannot determine state machine");
return;
}
unsigned sm_idx;
if (!ext_state.get_sm_idx_by_name (sm_name, &sm_idx))
{
- error_at (call->location, "unrecognized state machine %qs", sm_name);
+ error_at (call.location, "unrecognized state machine %qs", sm_name);
return;
}
const sm_state_map *smap = m_checker_states[sm_idx];
@@ -1775,7 +1762,7 @@ program_state::impl_call_analyzer_dump_state (const gcall *call,
sval = cast;
state_machine::state_t state = smap->get_state (sval, ext_state);
- warning_at (call->location, 0, "state: %qs", state->get_name ());
+ warning_at (call.location, 0, "state: %qs", state->get_name ());
}
#if CHECKING_P
@@ -1791,12 +1778,13 @@ test_sm_state_map ()
tree y = build_global_decl ("y", integer_type_node);
tree z = build_global_decl ("z", integer_type_node);
- state_machine *sm = make_malloc_state_machine (NULL);
- auto_delete_vec <state_machine> checkers;
- checkers.safe_push (sm);
- engine eng;
- extrinsic_state ext_state (checkers, &eng);
+ std::unique_ptr<state_machine> sm = make_malloc_state_machine (NULL);
state_machine::state_t start = sm->get_start_state ();
+ std::vector<std::unique_ptr<state_machine>> checkers;
+ const state_machine &borrowed_sm = *sm.get ();
+ checkers.push_back (std::move (sm));
+ engine eng;
+ extrinsic_state ext_state (std::move (checkers), &eng);
/* Test setting states on svalue_id instances directly. */
{
@@ -1808,7 +1796,7 @@ test_sm_state_map ()
const svalue *y_sval = model.get_rvalue (y, NULL);
const svalue *z_sval = model.get_rvalue (z, NULL);
- sm_state_map map (*sm);
+ sm_state_map map (borrowed_sm);
ASSERT_TRUE (map.is_empty_p ());
ASSERT_EQ (map.get_state (x_sval, ext_state), start);
@@ -1837,7 +1825,7 @@ test_sm_state_map ()
const svalue *y_sval = model.get_rvalue (y, NULL);
const svalue *z_sval = model.get_rvalue (z, NULL);
- sm_state_map map (*sm);
+ sm_state_map map (borrowed_sm);
ASSERT_TRUE (map.is_empty_p ());
ASSERT_EQ (map.get_state (x_sval, ext_state), start);
ASSERT_EQ (map.get_state (y_sval, ext_state), start);
@@ -1860,9 +1848,9 @@ test_sm_state_map ()
const svalue *y_sval = model.get_rvalue (y, NULL);
const svalue *z_sval = model.get_rvalue (z, NULL);
- sm_state_map map0 (*sm);
- sm_state_map map1 (*sm);
- sm_state_map map2 (*sm);
+ sm_state_map map0 (borrowed_sm);
+ sm_state_map map1 (borrowed_sm);
+ sm_state_map map2 (borrowed_sm);
ASSERT_EQ (map0.hash (), map1.hash ());
ASSERT_EQ (map0, map1);
@@ -1883,9 +1871,9 @@ test_sm_state_map ()
const state_machine::state_t TEST_STATE_2 = &test_state_2;
const state_machine::state test_state_3 ("test state 3", 3);
const state_machine::state_t TEST_STATE_3 = &test_state_3;
- sm_state_map map0 (*sm);
- sm_state_map map1 (*sm);
- sm_state_map map2 (*sm);
+ sm_state_map map0 (borrowed_sm);
+ sm_state_map map1 (borrowed_sm);
+ sm_state_map map2 (borrowed_sm);
ASSERT_EQ (map0.hash (), map1.hash ());
ASSERT_EQ (map0, map1);
@@ -1920,14 +1908,12 @@ test_program_state_1 ()
malloc sm-state, pointing to a region on the heap. */
tree p = build_global_decl ("p", ptr_type_node);
- state_machine *sm = make_malloc_state_machine (NULL);
+ std::unique_ptr<state_machine> sm = make_malloc_state_machine (NULL);
const state_machine::state_t UNCHECKED_STATE
= sm->get_state_by_name ("unchecked");
- auto_delete_vec <state_machine> checkers;
- checkers.safe_push (sm);
engine eng;
- extrinsic_state ext_state (checkers, &eng);
+ extrinsic_state ext_state (std::move (sm), &eng);
region_model_manager *mgr = eng.get_model_manager ();
program_state s (ext_state);
region_model *model = s.m_region_model;
@@ -1955,9 +1941,9 @@ test_program_state_2 ()
tree string_cst_ptr = build_string_literal (4, "foo");
- auto_delete_vec <state_machine> checkers;
+ std::vector<std::unique_ptr<state_machine>> checkers;
engine eng;
- extrinsic_state ext_state (checkers, &eng);
+ extrinsic_state ext_state (std::move (checkers), &eng);
program_state s (ext_state);
region_model *model = s.m_region_model;
@@ -1979,9 +1965,8 @@ test_program_state_merging ()
engine eng;
region_model_manager *mgr = eng.get_model_manager ();
program_point point (program_point::origin (*mgr));
- auto_delete_vec <state_machine> checkers;
- checkers.safe_push (make_malloc_state_machine (NULL));
- extrinsic_state ext_state (checkers, &eng);
+ extrinsic_state ext_state (make_malloc_state_machine (NULL),
+ &eng);
program_state s0 (ext_state);
uncertainty_t uncertainty;
@@ -2047,9 +2032,7 @@ test_program_state_merging_2 ()
engine eng;
region_model_manager *mgr = eng.get_model_manager ();
program_point point (program_point::origin (*mgr));
- auto_delete_vec <state_machine> checkers;
- checkers.safe_push (make_signal_state_machine (NULL));
- extrinsic_state ext_state (checkers, &eng);
+ extrinsic_state ext_state (make_signal_state_machine (NULL), &eng);
const state_machine::state test_state_0 ("test state 0", 0);
const state_machine::state test_state_1 ("test state 1", 1);
diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h
index e0f4ee8..269ffde 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -30,13 +30,25 @@ namespace ana {
class extrinsic_state
{
public:
- extrinsic_state (auto_delete_vec <state_machine> &checkers,
+ extrinsic_state (std::vector<std::unique_ptr<state_machine>> &&checkers,
engine *eng,
logger *logger = NULL)
- : m_checkers (checkers), m_logger (logger), m_engine (eng)
+ : m_checkers (std::move (checkers)),
+ m_logger (logger),
+ m_engine (eng)
{
}
+ // For use in selftests that use just one state machine
+ extrinsic_state (std::unique_ptr<state_machine> sm,
+ engine *eng,
+ logger *logger = NULL)
+ : m_logger (logger),
+ m_engine (eng)
+ {
+ m_checkers.push_back (std::move (sm));
+ }
+
const state_machine &get_sm (int idx) const
{
return *m_checkers[idx];
@@ -47,7 +59,7 @@ public:
return m_checkers[idx]->get_name ();
}
- unsigned get_num_checkers () const { return m_checkers.length (); }
+ unsigned get_num_checkers () const { return m_checkers.size (); }
logger *get_logger () const { return m_logger; }
@@ -64,7 +76,7 @@ public:
private:
/* The state machines. */
- auto_delete_vec <state_machine> &m_checkers;
+ std::vector<std::unique_ptr<state_machine>> m_checkers;
logger *m_logger;
engine *m_engine;
@@ -242,12 +254,12 @@ public:
void push_call (exploded_graph &eg,
exploded_node *enode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
uncertainty_t *uncertainty);
void returning_call (exploded_graph &eg,
exploded_node *enode,
- const gcall *call_stmt,
+ const gcall &call_stmt,
uncertainty_t *uncertainty);
@@ -298,7 +310,7 @@ public:
bool replay_call_summary (call_summary_replay &r,
const program_state &summary);
- void impl_call_analyzer_dump_state (const gcall *call,
+ void impl_call_analyzer_dump_state (const gcall &call,
const extrinsic_state &ext_state,
region_model_context *ctxt);
diff --git a/gcc/analyzer/ranges.cc b/gcc/analyzer/ranges.cc
index 4c63ecc..1a960fa 100644
--- a/gcc/analyzer/ranges.cc
+++ b/gcc/analyzer/ranges.cc
@@ -18,34 +18,13 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
+#include "sbitmap.h"
#include "ordered-hash-map.h"
-#include "options.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/supergraph.h"
-#include "sbitmap.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
@@ -53,7 +32,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/constraint-manager.h"
#include "analyzer/analyzer-selftests.h"
#include "analyzer/ranges.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -158,7 +136,7 @@ symbolic_byte_range::dump (bool simple, region_model_manager &mgr) const
std::unique_ptr<json::value>
symbolic_byte_range::to_json () const
{
- auto obj = ::make_unique<json::object> ();
+ auto obj = std::make_unique<json::object> ();
obj->set ("start", m_start.to_json ());
obj->set ("size", m_size.to_json ());
return obj;
diff --git a/gcc/analyzer/record-layout.cc b/gcc/analyzer/record-layout.cc
index 2eb3444..aaf8ccd 100644
--- a/gcc/analyzer/record-layout.cc
+++ b/gcc/analyzer/record-layout.cc
@@ -18,18 +18,10 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "diagnostic.h"
+#include "analyzer/common.h"
+
#include "tree-diagnostic.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/record-layout.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/region-model-asm.cc b/gcc/analyzer/region-model-asm.cc
index 0da5cc5..7d7e3b9 100644
--- a/gcc/analyzer/region-model-asm.cc
+++ b/gcc/analyzer/region-model-asm.cc
@@ -18,26 +18,16 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "pretty-print.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
+#include "stmt.h"
+
#include "analyzer/analyzer-logging.h"
-#include "options.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/region-model-reachability.h"
-#include "stmt.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index dfce420..df92503 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -18,34 +18,16 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
+#include "analyzer/common.h"
+
#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "analyzer/supergraph.h"
#include "sbitmap.h"
+#include "target.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
@@ -325,7 +307,7 @@ region_model_manager::get_or_create_initial_value (const region *reg,
bool check_poisoned)
{
if (!reg->can_have_initial_svalue_p () && check_poisoned)
- return get_or_create_poisoned_svalue (POISON_KIND_UNINIT,
+ return get_or_create_poisoned_svalue (poison_kind::uninit,
reg->get_type ());
/* The initial value of a cast is a cast of the initial value. */
@@ -962,6 +944,12 @@ region_model_manager::maybe_fold_sub_svalue (tree type,
if (!parent_svalue->can_have_associated_state_p ())
return get_or_create_unknown_svalue (type);
+ /* If we have a subvalue of a zero constant, it's zero. */
+ if (tree cst = parent_svalue->maybe_get_constant ())
+ if (TREE_CODE (cst) == INTEGER_CST)
+ if (zerop (cst))
+ return get_or_create_cast (type, parent_svalue);
+
/* If we have a subregion of a zero-fill, it's zero. */
if (const unaryop_svalue *unary
= parent_svalue->dyn_cast_unaryop_svalue ())
diff --git a/gcc/analyzer/region-model-reachability.cc b/gcc/analyzer/region-model-reachability.cc
index 4799ba8..d3bfeb7 100644
--- a/gcc/analyzer/region-model-reachability.cc
+++ b/gcc/analyzer/region-model-reachability.cc
@@ -18,37 +18,18 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "ordered-hash-map.h"
-#include "options.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/region-model-reachability.h"
-#include "diagnostic.h"
-#include "tree-diagnostic.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 84b81e9..1ee882c 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -18,70 +18,53 @@ 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 "config.h"
#define INCLUDE_ALGORITHM
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
+#include "analyzer/common.h"
+
+#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
-#include "tree-dfa.h"
+#include "cfg.h"
+#include "sbitmap.h"
+#include "diagnostic-event-id.h"
+#include "stor-layout.h"
#include "stringpool.h"
-#include "convert.h"
+#include "attribs.h"
+#include "tree-object-size.h"
+#include "gimple-ssa.h"
+#include "tree-phinodes.h"
+#include "tree-ssa-operands.h"
+#include "ssa-iterators.h"
#include "target.h"
-#include "fold-const.h"
+#include "calls.h"
+#include "is-a.h"
+#include "gcc-rich-location.h"
+#include "gcc-urlifier.h"
+#include "diagnostic-format-sarif.h"
#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "bitmap.h"
-#include "selftest.h"
+#include "fold-const.h"
#include "selftest-tree.h"
-#include "analyzer/analyzer.h"
+
+#include "text-art/tree-widget.h"
+
#include "analyzer/analyzer-logging.h"
-#include "ordered-hash-map.h"
-#include "options.h"
-#include "cgraph.h"
-#include "cfg.h"
#include "analyzer/supergraph.h"
-#include "sbitmap.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/constraint-manager.h"
-#include "diagnostic-event-id.h"
-#include "analyzer/sm.h"
-#include "diagnostic-event-id.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/region-model-reachability.h"
#include "analyzer/analyzer-selftests.h"
#include "analyzer/program-state.h"
#include "analyzer/call-summary.h"
-#include "stor-layout.h"
-#include "attribs.h"
-#include "tree-object-size.h"
-#include "gimple-ssa.h"
-#include "tree-phinodes.h"
-#include "tree-ssa-operands.h"
-#include "ssa-iterators.h"
-#include "calls.h"
-#include "is-a.h"
-#include "gcc-rich-location.h"
#include "analyzer/checker-event.h"
#include "analyzer/checker-path.h"
#include "analyzer/feasible-graph.h"
#include "analyzer/record-layout.h"
-#include "diagnostic-format-sarif.h"
-#include "text-art/tree-widget.h"
-#include "gcc-urlifier.h"
+#include "analyzer/function-set.h"
#if ENABLE_ANALYZER
@@ -235,7 +218,7 @@ region_to_value_map::dump (bool simple) const
std::unique_ptr<json::object>
region_to_value_map::to_json () const
{
- auto map_obj = ::make_unique<json::object> ();
+ auto map_obj = std::make_unique<json::object> ();
auto_vec<const region *> regs;
for (iterator iter = begin (); iter != end (); ++iter)
@@ -332,12 +315,97 @@ region_to_value_map::purge_state_involving (const svalue *sval)
m_hash_map.remove (iter);
}
+// struct exception_node
+
+bool
+exception_node::operator== (const exception_node &other) const
+{
+ return (m_exception_sval == other.m_exception_sval
+ && m_typeinfo_sval == other.m_typeinfo_sval
+ && m_destructor_sval == other.m_destructor_sval);
+}
+
+void
+exception_node::dump_to_pp (pretty_printer *pp,
+ bool simple) const
+{
+ pp_printf (pp, "{exception: ");
+ m_exception_sval->dump_to_pp (pp, simple);
+ pp_string (pp, ", typeinfo: ");
+ m_typeinfo_sval->dump_to_pp (pp, simple);
+ pp_string (pp, ", destructor: ");
+ m_destructor_sval->dump_to_pp (pp, simple);
+ pp_string (pp, "}");
+}
+
+void
+exception_node::dump (FILE *fp, bool simple) const
+{
+ tree_dump_pretty_printer pp (fp);
+ dump_to_pp (&pp, simple);
+ pp_newline (&pp);
+}
+
+/* Dump a multiline representation of this model to stderr. */
+
+DEBUG_FUNCTION void
+exception_node::dump (bool simple) const
+{
+ dump (stderr, simple);
+}
+
+DEBUG_FUNCTION void
+exception_node::dump () const
+{
+ text_art::dump (*this);
+}
+
+std::unique_ptr<json::object>
+exception_node::to_json () const
+{
+ auto obj = std::make_unique<json::object> ();
+ obj->set ("exception", m_exception_sval->to_json ());
+ obj->set ("typeinfo", m_typeinfo_sval->to_json ());
+ obj->set ("destructor", m_destructor_sval->to_json ());
+ return obj;
+}
+
+std::unique_ptr<text_art::tree_widget>
+exception_node::make_dump_widget (const text_art::dump_widget_info &dwi) const
+{
+ using text_art::tree_widget;
+ std::unique_ptr<tree_widget> w
+ (tree_widget::from_fmt (dwi, nullptr, "Exception Node"));
+
+ w->add_child (m_exception_sval->make_dump_widget (dwi, "exception"));
+ w->add_child (m_typeinfo_sval->make_dump_widget (dwi, "typeinfo"));
+ w->add_child (m_destructor_sval->make_dump_widget (dwi, "destructor"));
+
+ return w;
+}
+
+tree
+exception_node::maybe_get_type () const
+{
+ return m_typeinfo_sval->maybe_get_type_from_typeinfo ();
+}
+
+void
+exception_node::add_to_reachable_regions (reachable_regions &regs) const
+{
+ regs.handle_sval (m_exception_sval);
+ regs.handle_sval (m_typeinfo_sval);
+ regs.handle_sval (m_destructor_sval);
+}
+
/* class region_model. */
/* Ctor for region_model: construct an "empty" model. */
region_model::region_model (region_model_manager *mgr)
: m_mgr (mgr), m_store (), m_current_frame (NULL),
+ m_thrown_exceptions_stack (),
+ m_caught_exceptions_stack (),
m_dynamic_extents ()
{
m_constraints = new constraint_manager (mgr);
@@ -349,6 +417,8 @@ region_model::region_model (const region_model &other)
: m_mgr (other.m_mgr), m_store (other.m_store),
m_constraints (new constraint_manager (*other.m_constraints)),
m_current_frame (other.m_current_frame),
+ m_thrown_exceptions_stack (other.m_thrown_exceptions_stack),
+ m_caught_exceptions_stack (other.m_caught_exceptions_stack),
m_dynamic_extents (other.m_dynamic_extents)
{
}
@@ -375,6 +445,9 @@ region_model::operator= (const region_model &other)
m_current_frame = other.m_current_frame;
+ m_thrown_exceptions_stack = other.m_thrown_exceptions_stack;
+ m_caught_exceptions_stack = other.m_caught_exceptions_stack;
+
m_dynamic_extents = other.m_dynamic_extents;
return *this;
@@ -401,6 +474,11 @@ region_model::operator== (const region_model &other) const
if (m_current_frame != other.m_current_frame)
return false;
+ if (m_thrown_exceptions_stack != other.m_thrown_exceptions_stack)
+ return false;
+ if (m_caught_exceptions_stack != other.m_caught_exceptions_stack)
+ return false;
+
if (m_dynamic_extents != other.m_dynamic_extents)
return false;
@@ -427,7 +505,7 @@ void
region_model::dump_to_pp (pretty_printer *pp, bool simple,
bool multiline) const
{
- /* Dump stack. */
+ /* Dump frame stack. */
pp_printf (pp, "stack depth: %i", get_stack_depth ());
if (multiline)
pp_newline (pp);
@@ -448,6 +526,50 @@ region_model::dump_to_pp (pretty_printer *pp, bool simple,
if (!multiline)
pp_string (pp, "}");
+ /* Dump exception stacks. */
+ if (m_thrown_exceptions_stack.size () > 0)
+ {
+ pp_printf (pp, "thrown exceptions: %i", (int)m_thrown_exceptions_stack.size ());
+ if (multiline)
+ pp_newline (pp);
+ else
+ pp_string (pp, " {");
+ for (size_t idx = 0; idx < m_thrown_exceptions_stack.size (); ++idx)
+ {
+ if (multiline)
+ pp_string (pp, " ");
+ else if (idx > 0)
+ pp_string (pp, ", ");
+ pp_printf (pp, "exception (index %i): ", (int)idx);
+ m_thrown_exceptions_stack[idx].dump_to_pp (pp, simple);
+ if (multiline)
+ pp_newline (pp);
+ }
+ if (!multiline)
+ pp_string (pp, "}");
+ }
+ if (m_caught_exceptions_stack.size () > 0)
+ {
+ pp_printf (pp, "caught exceptions: %i", (int)m_caught_exceptions_stack.size ());
+ if (multiline)
+ pp_newline (pp);
+ else
+ pp_string (pp, " {");
+ for (size_t idx = 0; idx < m_caught_exceptions_stack.size (); ++idx)
+ {
+ if (multiline)
+ pp_string (pp, " ");
+ else if (idx > 0)
+ pp_string (pp, ", ");
+ pp_printf (pp, "exception (index %i): ", (int)idx);
+ m_caught_exceptions_stack[idx].dump_to_pp (pp, simple);
+ if (multiline)
+ pp_newline (pp);
+ }
+ if (!multiline)
+ pp_string (pp, "}");
+ }
+
/* Dump store. */
if (!multiline)
pp_string (pp, ", {");
@@ -515,11 +637,22 @@ region_model::debug () const
std::unique_ptr<json::object>
region_model::to_json () const
{
- auto model_obj = ::make_unique<json::object> ();
+ auto model_obj = std::make_unique<json::object> ();
model_obj->set ("store", m_store.to_json ());
model_obj->set ("constraints", m_constraints->to_json ());
if (m_current_frame)
model_obj->set ("current_frame", m_current_frame->to_json ());
+
+ auto thrown_exceptions_arr = std::make_unique<json::array> ();
+ for (auto &node : m_thrown_exceptions_stack)
+ thrown_exceptions_arr->append (node.to_json ());
+ model_obj->set ("thrown_exception_stack", std::move (thrown_exceptions_arr));
+
+ auto caught_exceptions_arr = std::make_unique<json::array> ();
+ for (auto &node : m_caught_exceptions_stack)
+ caught_exceptions_arr->append (node.to_json ());
+ model_obj->set ("caught_exception_stack", std::move (caught_exceptions_arr));
+
model_obj->set ("dynamic_extents", m_dynamic_extents.to_json ());
return model_obj;
}
@@ -543,6 +676,26 @@ region_model::make_dump_widget (const text_art::dump_widget_info &dwi) const
m_current_frame->dump_to_pp (pp, simple);
model_widget->add_child (tree_widget::make (dwi, pp));
}
+
+ if (m_thrown_exceptions_stack.size () > 0)
+ {
+ auto thrown_exceptions_widget
+ = tree_widget::make (dwi, "Thrown Exceptions");
+ for (auto &thrown_exception : m_thrown_exceptions_stack)
+ thrown_exceptions_widget->add_child
+ (thrown_exception.make_dump_widget (dwi));
+ model_widget->add_child (std::move (thrown_exceptions_widget));
+ }
+ if (m_caught_exceptions_stack.size () > 0)
+ {
+ auto caught_exceptions_widget
+ = tree_widget::make (dwi, "Caught Exceptions");
+ for (auto &caught_exception : m_caught_exceptions_stack)
+ caught_exceptions_widget->add_child
+ (caught_exception.make_dump_widget (dwi));
+ model_widget->add_child (std::move (caught_exceptions_widget));
+ }
+
model_widget->add_child
(m_store.make_dump_widget (dwi,
m_mgr->get_store_manager ()));
@@ -606,7 +759,7 @@ public:
bool use_of_uninit_p () const final override
{
- return m_pkind == POISON_KIND_UNINIT;
+ return m_pkind == poison_kind::uninit;
}
bool operator== (const poisoned_value_diagnostic &other) const
@@ -622,12 +775,12 @@ public:
{
default:
gcc_unreachable ();
- case POISON_KIND_UNINIT:
+ case poison_kind::uninit:
return OPT_Wanalyzer_use_of_uninitialized_value;
- case POISON_KIND_FREED:
- case POISON_KIND_DELETED:
+ case poison_kind::freed:
+ case poison_kind::deleted:
return OPT_Wanalyzer_use_after_free;
- case POISON_KIND_POPPED_STACK:
+ case poison_kind::popped_stack:
return OPT_Wanalyzer_use_of_pointer_in_stale_stack_frame;
}
}
@@ -640,28 +793,28 @@ public:
{
default:
gcc_unreachable ();
- case POISON_KIND_UNINIT:
+ case poison_kind::uninit:
{
ctxt.add_cwe (457); /* "CWE-457: Use of Uninitialized Variable". */
return ctxt.warn ("use of uninitialized value %qE",
m_expr);
}
break;
- case POISON_KIND_FREED:
+ case poison_kind::freed:
{
ctxt.add_cwe (416); /* "CWE-416: Use After Free". */
return ctxt.warn ("use after %<free%> of %qE",
m_expr);
}
break;
- case POISON_KIND_DELETED:
+ case poison_kind::deleted:
{
ctxt.add_cwe (416); /* "CWE-416: Use After Free". */
return ctxt.warn ("use after %<delete%> of %qE",
m_expr);
}
break;
- case POISON_KIND_POPPED_STACK:
+ case poison_kind::popped_stack:
{
/* TODO: which CWE? */
return ctxt.warn
@@ -680,28 +833,28 @@ public:
{
default:
gcc_unreachable ();
- case POISON_KIND_UNINIT:
+ case poison_kind::uninit:
{
pp_printf (&pp,
"use of uninitialized value %qE here",
m_expr);
return true;
}
- case POISON_KIND_FREED:
+ case poison_kind::freed:
{
pp_printf (&pp,
"use after %<free%> of %qE here",
m_expr);
return true;
}
- case POISON_KIND_DELETED:
+ case poison_kind::deleted:
{
pp_printf (&pp,
"use after %<delete%> of %qE here",
m_expr);
return true;
}
- case POISON_KIND_POPPED_STACK:
+ case poison_kind::popped_stack:
{
pp_printf (&pp,
"dereferencing pointer %qE to within stale stack frame",
@@ -956,10 +1109,10 @@ public:
{
if (reg == m_base_reg_a)
emission_path.add_event
- (make_unique<ptrdiff_region_creation_event> (loc_info, true));
+ (std::make_unique<ptrdiff_region_creation_event> (loc_info, true));
else if (reg == m_base_reg_b)
emission_path.add_event
- (make_unique<ptrdiff_region_creation_event> (loc_info, false));
+ (std::make_unique<ptrdiff_region_creation_event> (loc_info, false));
}
bool
@@ -1009,11 +1162,12 @@ check_for_invalid_ptrdiff (const gassign *assign,
if (base_reg_b->get_kind () == RK_SYMBOLIC)
return;
- ctxt.warn (make_unique<undefined_ptrdiff_diagnostic> (assign,
- sval_a,
- sval_b,
- base_reg_a,
- base_reg_b));
+ ctxt.warn
+ (std::make_unique<undefined_ptrdiff_diagnostic> (assign,
+ sval_a,
+ sval_b,
+ base_reg_a,
+ base_reg_b));
}
/* If ASSIGN is a stmt that can be modelled via
@@ -1192,13 +1346,13 @@ region_model::get_gassign_result (const gassign *assign,
{
if (tree_int_cst_sgn (rhs2_cst) < 0)
ctxt->warn
- (make_unique<shift_count_negative_diagnostic>
+ (std::make_unique<shift_count_negative_diagnostic>
(assign, rhs2_cst));
else if (compare_tree_int (rhs2_cst,
TYPE_PRECISION (TREE_TYPE (rhs1)))
>= 0)
ctxt->warn
- (make_unique<shift_count_overflow_diagnostic>
+ (std::make_unique<shift_count_overflow_diagnostic>
(assign,
int (TYPE_PRECISION (TREE_TYPE (rhs1))),
rhs2_cst));
@@ -1392,12 +1546,12 @@ region_model::check_for_poison (const svalue *sval,
/* Ignore uninitialized uses of empty types; there's nothing
to initialize. */
- if (pkind == POISON_KIND_UNINIT
+ if (pkind == poison_kind::uninit
&& sval->get_type ()
&& is_empty_type (sval->get_type ()))
return sval;
- if (pkind == POISON_KIND_UNINIT)
+ if (pkind == poison_kind::uninit)
if (const gimple *curr_stmt = ctxt->get_stmt ())
if (const gassign *assign_stmt
= dyn_cast <const gassign *> (curr_stmt))
@@ -1418,7 +1572,7 @@ region_model::check_for_poison (const svalue *sval,
the tree other than via the def stmts, using
fixup_tree_for_diagnostic. */
tree diag_arg = fixup_tree_for_diagnostic (expr);
- if (src_region == NULL && pkind == POISON_KIND_UNINIT)
+ if (src_region == NULL && pkind == poison_kind::uninit)
src_region = get_region_for_poisoned_expr (expr);
/* Can we reliably get the poisoned value from "expr"?
@@ -1432,10 +1586,11 @@ region_model::check_for_poison (const svalue *sval,
check_expr = expr;
else
check_expr = NULL;
- if (ctxt->warn (make_unique<poisoned_value_diagnostic> (diag_arg,
- pkind,
- src_region,
- check_expr)))
+ if (ctxt->warn
+ (std::make_unique<poisoned_value_diagnostic> (diag_arg,
+ pkind,
+ src_region,
+ check_expr)))
{
/* We only want to report use of a poisoned value at the first
place it gets used; return an unknown value to avoid generating
@@ -1570,13 +1725,15 @@ region_model::on_stmt_pre (const gimple *stmt,
{
switch (gimple_code (stmt))
{
- default:
- /* No-op for now. */
- break;
-
- case GIMPLE_DEBUG:
- /* We should have stripped these out when building the supergraph. */
- gcc_unreachable ();
+ case GIMPLE_COND:
+ case GIMPLE_EH_DISPATCH:
+ case GIMPLE_GOTO:
+ case GIMPLE_LABEL:
+ case GIMPLE_NOP:
+ case GIMPLE_PREDICT:
+ case GIMPLE_RESX:
+ case GIMPLE_SWITCH:
+ /* No-ops here. */
break;
case GIMPLE_ASSIGN:
@@ -1601,7 +1758,7 @@ region_model::on_stmt_pre (const gimple *stmt,
anything, for which we don't have a function body, or for which we
don't know the fndecl. */
const gcall *call = as_a <const gcall *> (stmt);
- *out_unknown_side_effects = on_call_pre (call, ctxt);
+ *out_unknown_side_effects = on_call_pre (*call, ctxt);
}
break;
@@ -1611,6 +1768,13 @@ region_model::on_stmt_pre (const gimple *stmt,
on_return (return_, ctxt);
}
break;
+
+ /* We don't expect to see any other statement kinds in the analyzer. */
+ case GIMPLE_DEBUG: // should have stripped these out when building the supergraph
+ default:
+ internal_error ("unexpected gimple stmt code: %qs",
+ gimple_code_name[gimple_code (stmt)]);
+ break;
}
}
@@ -1689,7 +1853,7 @@ region_model::check_call_format_attr (const call_details &cd,
};
call_arg_details arg_details (m_cd, m_fmt_param_idx);
- add_note (make_unique<reason_format_attr> (arg_details));
+ add_note (std::make_unique<reason_format_attr> (arg_details));
}
private:
const call_details &m_cd;
@@ -1898,7 +2062,7 @@ region_model::get_known_function (enum internal_fn ifn) const
attributes. */
const builtin_known_function *
-region_model::get_builtin_kf (const gcall *call,
+region_model::get_builtin_kf (const gcall &call,
region_model_context *ctxt /* = NULL */) const
{
region_model *mut_this = const_cast <region_model *> (this);
@@ -1913,6 +2077,170 @@ region_model::get_builtin_kf (const gcall *call,
return NULL;
}
+/* Subclass of custom_edge_info for use by exploded_edges that represent
+ an exception being thrown from a call we don't have the code for. */
+
+class exception_thrown_from_unrecognized_call : public custom_edge_info
+{
+public:
+ exception_thrown_from_unrecognized_call (const gcall &call,
+ tree fndecl)
+ : m_call (call),
+ m_fndecl (fndecl)
+ {
+ }
+
+ void print (pretty_printer *pp) const
+ {
+ if (m_fndecl)
+ pp_printf (pp, "if %qD throws an exception...", m_fndecl);
+ else
+ pp_printf (pp, "if the called function throws an exception...");
+ };
+
+ bool
+ update_model (region_model *model,
+ const exploded_edge *,
+ region_model_context *ctxt) const final override
+ {
+ /* Allocate an exception and set it as the current exception. */
+ const region *exception_reg
+ = model->get_or_create_region_for_heap_alloc
+ (nullptr, /* We don't know the size of the region. */
+ ctxt);
+
+ region_model_manager *mgr = model->get_manager ();
+ conjured_purge p (model, ctxt);
+
+ /* The contents of the region are some conjured svalue. */
+ const svalue *exception_sval
+ = mgr->get_or_create_conjured_svalue (NULL_TREE,
+ &m_call,
+ exception_reg, p, 0);
+ model->set_value (exception_reg, exception_sval, ctxt);
+ const svalue *exception_ptr_sval
+ = mgr->get_ptr_svalue (ptr_type_node, exception_reg);
+ const svalue *tinfo_sval
+ = mgr->get_or_create_conjured_svalue (ptr_type_node,
+ &m_call,
+ exception_reg, p, 1);
+ const svalue *destructor_sval
+ = mgr->get_or_create_conjured_svalue (ptr_type_node,
+ &m_call,
+ exception_reg, p, 2);
+
+ /* Push a new exception_node on the model's thrown exception stack. */
+ exception_node eh_node (exception_ptr_sval, tinfo_sval, destructor_sval);
+ model->push_thrown_exception (eh_node);
+
+ return true;
+ }
+
+ void
+ add_events_to_path (checker_path *emission_path,
+ const exploded_edge &eedge) const final override
+ {
+ const exploded_node *dst_node = eedge.m_dest;
+ const program_point &dst_point = dst_node->get_point ();
+ const int dst_stack_depth = dst_point.get_stack_depth ();
+
+ emission_path->add_event
+ (std::make_unique<throw_from_call_to_external_fn_event>
+ (event_loc_info (m_call.location,
+ dst_point.get_fndecl (),
+ dst_stack_depth),
+ dst_node,
+ m_call,
+ m_fndecl));
+ }
+
+ exploded_node *
+ create_enode (exploded_graph &eg,
+ const program_point &point,
+ program_state &&state,
+ exploded_node *enode_for_diag,
+ region_model_context *ctxt) const final override
+ {
+ exploded_node *thrown_enode
+ = eg.get_or_create_node (point, state, enode_for_diag,
+ /* Don't add to worklist. */
+ false);
+ if (!thrown_enode)
+ return nullptr;
+
+ /* Add successor edges for thrown_enode "by hand" for the exception. */
+ eg.unwind_from_exception (*thrown_enode,
+ &m_call,
+ ctxt);
+ return thrown_enode;
+ }
+
+private:
+ const gcall &m_call;
+ tree m_fndecl; // could be null
+};
+
+/* Get a set of functions that are assumed to not throw exceptions. */
+
+static function_set
+get_fns_assumed_not_to_throw ()
+{
+ // TODO: populate this list more fully
+ static const char * const fn_names[] = {
+ /* This array must be kept sorted. */
+
+ "fclose"
+ };
+ const size_t count = ARRAY_SIZE (fn_names);
+ function_set fs (fn_names, count);
+ return fs;
+}
+
+/* Return true if CALL could throw an exception.
+ FNDECL could be NULL_TREE. */
+
+static bool
+can_throw_p (const gcall &call, tree fndecl)
+{
+ if (!flag_exceptions)
+ return false;
+
+ if (gimple_call_nothrow_p (&call))
+ return false;
+
+ if (fndecl)
+ {
+ const function_set fs = get_fns_assumed_not_to_throw ();
+ if (fs.contains_decl_p (fndecl))
+ return false;
+ }
+
+ return true;
+}
+
+/* Given CALL where we don't know what code is being called
+ (by not having the body of FNDECL, or having NULL_TREE for FNDECL),
+ potentially bifurcate control flow to simulate the call throwing
+ an exception. */
+
+void
+region_model::check_for_throw_inside_call (const gcall &call,
+ tree fndecl,
+ region_model_context *ctxt)
+{
+ if (!ctxt)
+ return;
+
+ /* Could this function throw an exception?
+ If so, add an extra e-edge for that. */
+ if (!can_throw_p (call, fndecl))
+ return;
+
+ auto throws_exception
+ = std::make_unique<exception_thrown_from_unrecognized_call> (call, fndecl);
+ ctxt->bifurcate (std::move (throws_exception));
+}
+
/* Update this model for the CALL stmt, using CTXT to report any
diagnostics - the first half.
@@ -1925,7 +2253,7 @@ region_model::get_builtin_kf (const gcall *call,
fndecl it is). */
bool
-region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
+region_model::on_call_pre (const gcall &call, region_model_context *ctxt)
{
call_details cd (call, this, ctxt);
@@ -1935,8 +2263,8 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
Handle IFN_DEFERRED_INIT by treating it as no-op: don't touch the
lhs of the call, so that it is still uninitialized from the point of
view of the analyzer. */
- if (gimple_call_internal_p (call)
- && gimple_call_internal_fn (call) == IFN_DEFERRED_INIT)
+ if (gimple_call_internal_p (&call)
+ && gimple_call_internal_fn (&call) == IFN_DEFERRED_INIT)
return false; /* No side effects. */
/* Get svalues for all of the arguments at the callsite, to ensure that we
@@ -1948,9 +2276,9 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
tree callee_fndecl = get_fndecl_for_call (call, ctxt);
- if (gimple_call_internal_p (call))
+ if (gimple_call_internal_p (&call))
if (const known_function *kf
- = get_known_function (gimple_call_internal_fn (call)))
+ = get_known_function (gimple_call_internal_fn (&call)))
{
kf->impl_call_pre (cd);
return false; /* No further side effects. */
@@ -1958,6 +2286,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
if (!callee_fndecl)
{
+ check_for_throw_inside_call (call, NULL_TREE, ctxt);
cd.set_any_lhs_with_defaults ();
return true; /* Unknown side effects. */
}
@@ -1978,7 +2307,10 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
return true; /* Unknown side effects. */
if (!fndecl_has_gimple_body_p (callee_fndecl))
- return true; /* Unknown side effects. */
+ {
+ check_for_throw_inside_call (call, callee_fndecl, ctxt);
+ return true; /* Unknown side effects. */
+ }
return false; /* No side effects. */
}
@@ -1994,7 +2326,7 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt)
to purge state. */
void
-region_model::on_call_post (const gcall *call,
+region_model::on_call_post (const gcall &call,
bool unknown_side_effects,
region_model_context *ctxt)
{
@@ -2102,12 +2434,11 @@ private:
attribute. */
void
-region_model::check_function_attr_access (const gcall *call,
+region_model::check_function_attr_access (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx) const
{
- gcc_assert (call);
gcc_assert (callee_fndecl);
gcc_assert (ctxt);
@@ -2145,8 +2476,8 @@ region_model::check_function_attr_access (const gcall *call,
}
void add_annotations () final override
{
- add_note (make_unique<reason_attr_access>
- (m_callee_fndecl, m_access));
+ add_note (std::make_unique<reason_attr_access>
+ (m_callee_fndecl, m_access));
}
private:
tree m_callee_fndecl;
@@ -2157,7 +2488,7 @@ region_model::check_function_attr_access (const gcall *call,
note added to them. */
annotating_ctxt my_ctxt (callee_fndecl, *access, ctxt);
- tree ptr_tree = gimple_call_arg (call, access->ptrarg);
+ tree ptr_tree = gimple_call_arg (&call, access->ptrarg);
const svalue *ptr_sval = get_rvalue (ptr_tree, &my_ctxt);
const region *reg = deref_rvalue (ptr_sval, ptr_tree, &my_ctxt);
check_region_for_write (reg, nullptr, &my_ctxt);
@@ -2171,13 +2502,12 @@ region_model::check_function_attr_access (const gcall *call,
void
region_model::
-check_one_function_attr_null_terminated_string_arg (const gcall *call,
+check_one_function_attr_null_terminated_string_arg (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx,
tree attr)
{
- gcc_assert (call);
gcc_assert (callee_fndecl);
gcc_assert (ctxt);
gcc_assert (attr);
@@ -2245,12 +2575,11 @@ check_one_function_attr_null_terminated_string_arg (const gcall *call,
void
region_model::
-check_function_attr_null_terminated_string_arg (const gcall *call,
+check_function_attr_null_terminated_string_arg (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx)
{
- gcc_assert (call);
gcc_assert (callee_fndecl);
gcc_assert (ctxt);
@@ -2275,11 +2604,10 @@ check_function_attr_null_terminated_string_arg (const gcall *call,
function attributes, complaining to CTXT about any issues. */
void
-region_model::check_function_attrs (const gcall *call,
+region_model::check_function_attrs (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt)
{
- gcc_assert (call);
gcc_assert (callee_fndecl);
gcc_assert (ctxt);
@@ -2310,7 +2638,7 @@ region_model::check_function_attrs (const gcall *call,
from their values, and from values that point to them. */
void
-region_model::handle_unrecognized_call (const gcall *call,
+region_model::handle_unrecognized_call (const gcall &call,
region_model_context *ctxt)
{
tree fndecl = get_fndecl_for_call (call, ctxt);
@@ -2331,7 +2659,8 @@ region_model::handle_unrecognized_call (const gcall *call,
tree iter_param_types = NULL_TREE;
if (fndecl)
iter_param_types = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
- for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
+ for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (&call);
+ arg_idx++)
{
/* Track expected param type, where available. */
tree param_type = NULL_TREE;
@@ -2342,7 +2671,7 @@ region_model::handle_unrecognized_call (const gcall *call,
iter_param_types = TREE_CHAIN (iter_param_types);
}
- tree parm = gimple_call_arg (call, arg_idx);
+ tree parm = gimple_call_arg (&call, arg_idx);
const svalue *parm_sval = get_rvalue (parm, ctxt);
reachable_regs.handle_parm (parm_sval, param_type);
}
@@ -2466,11 +2795,11 @@ region_model::on_return (const greturn *return_stmt, region_model_context *ctxt)
0), as opposed to any second return due to longjmp/sigsetjmp. */
void
-region_model::on_setjmp (const gcall *call, const exploded_node *enode,
+region_model::on_setjmp (const gcall &call, const exploded_node *enode,
region_model_context *ctxt)
{
- const svalue *buf_ptr = get_rvalue (gimple_call_arg (call, 0), ctxt);
- const region *buf_reg = deref_rvalue (buf_ptr, gimple_call_arg (call, 0),
+ const svalue *buf_ptr = get_rvalue (gimple_call_arg (&call, 0), ctxt);
+ const region *buf_reg = deref_rvalue (buf_ptr, gimple_call_arg (&call, 0),
ctxt);
/* Create a setjmp_svalue for this call and store it in BUF_REG's
@@ -2484,7 +2813,7 @@ region_model::on_setjmp (const gcall *call, const exploded_node *enode,
}
/* Direct calls to setjmp return 0. */
- if (tree lhs = gimple_call_lhs (call))
+ if (tree lhs = gimple_call_lhs (&call))
{
const svalue *new_sval
= m_mgr->get_or_create_int_cst (TREE_TYPE (lhs), 0);
@@ -2499,11 +2828,11 @@ region_model::on_setjmp (const gcall *call, const exploded_node *enode,
done, and should be done by the caller. */
void
-region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
+region_model::on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call,
int setjmp_stack_depth, region_model_context *ctxt)
{
/* Evaluate the val, using the frame of the "longjmp". */
- tree fake_retval = gimple_call_arg (longjmp_call, 1);
+ tree fake_retval = gimple_call_arg (&longjmp_call, 1);
const svalue *fake_retval_sval = get_rvalue (fake_retval, ctxt);
/* Pop any frames until we reach the stack depth of the function where
@@ -2515,7 +2844,7 @@ region_model::on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
gcc_assert (get_stack_depth () == setjmp_stack_depth);
/* Assign to LHS of "setjmp" in new_state. */
- if (tree lhs = gimple_call_lhs (setjmp_call))
+ if (tree lhs = gimple_call_lhs (&setjmp_call))
{
/* Passing 0 as the val to longjmp leads to setjmp returning 1. */
const svalue *zero_sval
@@ -3092,7 +3421,7 @@ region_model::deref_rvalue (const svalue *ptr_sval, tree ptr_tree,
const poisoned_svalue *poisoned_sval
= as_a <const poisoned_svalue *> (ptr_sval);
enum poison_kind pkind = poisoned_sval->get_poison_kind ();
- ctxt->warn (::make_unique<poisoned_value_diagnostic>
+ ctxt->warn (std::make_unique<poisoned_value_diagnostic>
(ptr, pkind, nullptr, nullptr));
}
}
@@ -3263,16 +3592,18 @@ region_model::check_for_writable_region (const region* dest_reg,
{
const function_region *func_reg = as_a <const function_region *> (base_reg);
tree fndecl = func_reg->get_fndecl ();
- ctxt->warn (make_unique<write_to_const_diagnostic>
- (func_reg, fndecl));
+ ctxt->warn
+ (std::make_unique<write_to_const_diagnostic>
+ (func_reg, fndecl));
}
break;
case RK_LABEL:
{
const label_region *label_reg = as_a <const label_region *> (base_reg);
tree label = label_reg->get_label ();
- ctxt->warn (make_unique<write_to_const_diagnostic>
- (label_reg, label));
+ ctxt->warn
+ (std::make_unique<write_to_const_diagnostic>
+ (label_reg, label));
}
break;
case RK_DECL:
@@ -3285,11 +3616,13 @@ region_model::check_for_writable_region (const region* dest_reg,
"this" param is "T* const"). */
if (TREE_READONLY (decl)
&& is_global_var (decl))
- ctxt->warn (make_unique<write_to_const_diagnostic> (dest_reg, decl));
+ ctxt->warn
+ (std::make_unique<write_to_const_diagnostic> (dest_reg, decl));
}
break;
case RK_STRING:
- ctxt->warn (make_unique<write_to_string_literal_diagnostic> (dest_reg));
+ ctxt->warn
+ (std::make_unique<write_to_string_literal_diagnostic> (dest_reg));
break;
}
}
@@ -3367,10 +3700,10 @@ region_model::check_region_access (const region *reg,
{
default:
gcc_unreachable ();
- case DIR_READ:
+ case access_direction::read:
/* Currently a no-op. */
break;
- case DIR_WRITE:
+ case access_direction::write:
check_for_writable_region (reg, ctxt);
break;
}
@@ -3384,7 +3717,7 @@ region_model::check_region_for_write (const region *dest_reg,
const svalue *sval_hint,
region_model_context *ctxt) const
{
- check_region_access (dest_reg, DIR_WRITE, sval_hint, ctxt);
+ check_region_access (dest_reg, access_direction::write, sval_hint, ctxt);
}
/* If CTXT is non-NULL, use it to warn about any problems reading from REG.
@@ -3394,7 +3727,7 @@ bool
region_model::check_region_for_read (const region *src_reg,
region_model_context *ctxt) const
{
- return check_region_access (src_reg, DIR_READ, NULL, ctxt);
+ return check_region_access (src_reg, access_direction::read, NULL, ctxt);
}
/* Concrete subclass for casts of pointers that lead to trailing bytes. */
@@ -3491,7 +3824,8 @@ public:
checker_path &emission_path) final override
{
emission_path.add_event
- (make_unique<region_creation_event_allocation_size> (capacity, loc_info));
+ (std::make_unique<region_creation_event_allocation_size>
+ (capacity, loc_info));
m_has_allocation_event = true;
}
@@ -3827,9 +4161,10 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval,
if (TREE_CODE (cst_cap) == INTEGER_CST
&& !capacity_compatible_with_type (cst_cap, pointee_size_tree,
is_struct))
- ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg, rhs_reg,
- capacity, cst_cap,
- ctxt->get_stmt ()));
+ ctxt->warn
+ (std::make_unique <dubious_allocation_size> (lhs_reg, rhs_reg,
+ capacity, cst_cap,
+ ctxt->get_stmt ()));
}
break;
default:
@@ -3841,10 +4176,11 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval,
m_constraints))
{
tree expr = get_representative_tree (capacity);
- ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg,
- rhs_reg,
- capacity, expr,
- ctxt->get_stmt ()));
+ ctxt->warn
+ (std::make_unique <dubious_allocation_size> (lhs_reg,
+ rhs_reg,
+ capacity, expr,
+ ctxt->get_stmt ()));
}
}
break;
@@ -4637,9 +4973,11 @@ region_model::check_for_null_terminated_string_arg (const call_details &cd,
m_cd.get_model ()->get_current_function ()->decl,
m_cd.get_model ()->get_stack_depth ());
- add_event (make_unique<null_terminator_check_event> (loc_info,
- arg_details));
- add_note (make_unique <null_terminator_check_decl_note> (arg_details));
+ add_event
+ (std::make_unique<null_terminator_check_event> (loc_info,
+ arg_details));
+ add_note
+ (std::make_unique <null_terminator_check_decl_note> (arg_details));
}
private:
const call_details &m_cd;
@@ -5385,7 +5723,7 @@ region_model::add_constraint (tree lhs, enum tree_code op, tree rhs,
{
bool sat = add_constraint (lhs, op, rhs, ctxt);
if (!sat && out)
- *out = make_unique <rejected_op_constraint> (*this, lhs, op, rhs);
+ *out = std::make_unique <rejected_op_constraint> (*this, lhs, op, rhs);
return sat;
}
@@ -5885,17 +6223,22 @@ region_model::maybe_update_for_edge (const superedge &edge,
ctxt, out);
}
+ if (const geh_dispatch *eh_dispatch_stmt
+ = dyn_cast <const geh_dispatch *> (last_stmt))
+ {
+ const eh_dispatch_cfg_superedge *eh_dispatch_cfg_sedge
+ = as_a <const eh_dispatch_cfg_superedge *> (&edge);
+ return apply_constraints_for_eh_dispatch (*eh_dispatch_cfg_sedge,
+ eh_dispatch_stmt,
+ ctxt, out);
+ }
+
if (const ggoto *goto_stmt = dyn_cast <const ggoto *> (last_stmt))
{
const cfg_superedge *cfg_sedge = as_a <const cfg_superedge *> (&edge);
return apply_constraints_for_ggoto (*cfg_sedge, goto_stmt, ctxt);
}
- /* Apply any constraints due to an exception being thrown. */
- if (const cfg_superedge *cfg_sedge = dyn_cast <const cfg_superedge *> (&edge))
- if (cfg_sedge->get_flags () & EDGE_EH)
- return apply_constraints_for_exception (last_stmt, ctxt, out);
-
return true;
}
@@ -5905,29 +6248,29 @@ region_model::maybe_update_for_edge (const superedge &edge,
caller's frame. */
void
-region_model::update_for_gcall (const gcall *call_stmt,
+region_model::update_for_gcall (const gcall &call_stmt,
region_model_context *ctxt,
function *callee)
{
/* Build a vec of argument svalues, using the current top
frame for resolving tree expressions. */
- auto_vec<const svalue *> arg_svals (gimple_call_num_args (call_stmt));
+ auto_vec<const svalue *> arg_svals (gimple_call_num_args (&call_stmt));
- for (unsigned i = 0; i < gimple_call_num_args (call_stmt); i++)
+ for (unsigned i = 0; i < gimple_call_num_args (&call_stmt); i++)
{
- tree arg = gimple_call_arg (call_stmt, i);
+ tree arg = gimple_call_arg (&call_stmt, i);
arg_svals.quick_push (get_rvalue (arg, ctxt));
}
if(!callee)
{
/* Get the function * from the gcall. */
- tree fn_decl = get_fndecl_for_call (call_stmt,ctxt);
+ tree fn_decl = get_fndecl_for_call (call_stmt, ctxt);
callee = DECL_STRUCT_FUNCTION (fn_decl);
}
gcc_assert (callee);
- push_frame (*callee, &arg_svals, ctxt);
+ push_frame (*callee, &call_stmt, &arg_svals, ctxt);
}
/* Pop the top-most frame_region from the stack, and copy the return
@@ -5935,14 +6278,14 @@ region_model::update_for_gcall (const gcall *call_stmt,
the call (if any). */
void
-region_model::update_for_return_gcall (const gcall *call_stmt,
+region_model::update_for_return_gcall (const gcall &call_stmt,
region_model_context *ctxt)
{
/* Get the lvalue for the result of the call, passing it to pop_frame,
so that pop_frame can determine the region with respect to the
*caller* frame. */
- tree lhs = gimple_call_lhs (call_stmt);
- pop_frame (lhs, NULL, ctxt, call_stmt);
+ tree lhs = gimple_call_lhs (&call_stmt);
+ pop_frame (lhs, NULL, ctxt, &call_stmt);
}
/* Extract calling information from the superedge and update the model for the
@@ -5952,7 +6295,7 @@ void
region_model::update_for_call_superedge (const call_superedge &call_edge,
region_model_context *ctxt)
{
- const gcall *call_stmt = call_edge.get_call_stmt ();
+ const gcall &call_stmt = call_edge.get_call_stmt ();
update_for_gcall (call_stmt, ctxt, call_edge.get_callee_function ());
}
@@ -5963,7 +6306,7 @@ void
region_model::update_for_return_superedge (const return_superedge &return_edge,
region_model_context *ctxt)
{
- const gcall *call_stmt = return_edge.get_call_stmt ();
+ const gcall &call_stmt = return_edge.get_call_stmt ();
update_for_return_gcall (call_stmt, ctxt);
}
@@ -6156,7 +6499,7 @@ apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
&& !ctxt->possibly_tainted_p (index_sval))
{
if (out)
- *out = make_unique <rejected_default_case> (*this);
+ *out = std::make_unique <rejected_default_case> (*this);
return false;
}
@@ -6165,12 +6508,180 @@ apply_constraints_for_gswitch (const switch_cfg_superedge &edge,
= ranges_mgr->get_or_create_ranges_for_switch (&edge, switch_stmt);
bool sat = m_constraints->add_bounded_ranges (index_sval, all_cases_ranges);
if (!sat && out)
- *out = make_unique <rejected_ranges_constraint> (*this, index, all_cases_ranges);
+ *out = std::make_unique <rejected_ranges_constraint>
+ (*this, index, all_cases_ranges);
if (sat && ctxt && !all_cases_ranges->empty_p ())
ctxt->on_bounded_ranges (*index_sval, *all_cases_ranges);
return sat;
}
+class rejected_eh_dispatch : public rejected_constraint
+{
+public:
+ rejected_eh_dispatch (const region_model &model)
+ : rejected_constraint (model)
+ {}
+
+ void dump_to_pp (pretty_printer *pp) const final override
+ {
+ pp_printf (pp, "rejected_eh_dispatch");
+ }
+};
+
+static bool
+exception_matches_type_p (tree exception_type,
+ tree catch_type)
+{
+ if (catch_type == exception_type)
+ return true;
+
+ /* TODO (PR analyzer/119697): we should also handle subclasses etc;
+ see the rules in https://en.cppreference.com/w/cpp/language/catch
+
+ It looks like we should be calling (or emulating)
+ can_convert_eh from the C++ FE, but that's specific to the C++ FE. */
+
+ return false;
+}
+
+static bool
+matches_any_exception_type_p (eh_catch ehc, tree exception_type)
+{
+ if (ehc->type_list == NULL_TREE)
+ /* All exceptions are caught here. */
+ return true;
+
+ for (tree iter = ehc->type_list; iter; iter = TREE_CHAIN (iter))
+ if (exception_matches_type_p (TREE_VALUE (iter),
+ exception_type))
+ return true;
+ return false;
+}
+
+bool
+region_model::
+apply_constraints_for_eh_dispatch (const eh_dispatch_cfg_superedge &edge,
+ const geh_dispatch *,
+ region_model_context *ctxt,
+ std::unique_ptr<rejected_constraint> *out)
+{
+ const exception_node *current_node = get_current_thrown_exception ();
+ gcc_assert (current_node);
+ tree curr_exception_type = current_node->maybe_get_type ();
+ if (!curr_exception_type)
+ /* We don't know the specific type. */
+ return true;
+
+ return edge.apply_constraints (this, ctxt, curr_exception_type, out);
+}
+
+bool
+region_model::
+apply_constraints_for_eh_dispatch_try (const eh_dispatch_try_cfg_superedge &edge,
+ region_model_context */*ctxt*/,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out)
+{
+ /* TODO: can we rely on this ordering?
+ or do we need to iterate through prev_catch ? */
+ /* The exception must not match any of the previous edges. */
+ for (auto sibling_sedge : edge.m_src->m_succs)
+ {
+ if (sibling_sedge == &edge)
+ break;
+
+ const eh_dispatch_try_cfg_superedge *sibling_eh_sedge
+ = as_a <const eh_dispatch_try_cfg_superedge *> (sibling_sedge);
+ if (eh_catch ehc = sibling_eh_sedge->get_eh_catch ())
+ if (matches_any_exception_type_p (ehc, exception_type))
+ {
+ /* The earlier sibling matches, so the "unhandled" edge is
+ not taken. */
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+ }
+ }
+
+ if (eh_catch ehc = edge.get_eh_catch ())
+ {
+ /* We have an edge that tried to match one or more types. */
+
+ /* The exception must not match any of the previous edges. */
+
+ /* It must match this type. */
+ if (matches_any_exception_type_p (ehc, exception_type))
+ return true;
+ else
+ {
+ /* Exception type doesn't match. */
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+ }
+ }
+ else
+ {
+ /* This is the "unhandled exception" edge.
+ If we get here then no sibling edges matched;
+ we will follow this edge. */
+ return true;
+ }
+}
+
+bool
+region_model::
+apply_constraints_for_eh_dispatch_allowed (const eh_dispatch_allowed_cfg_superedge &edge,
+ region_model_context */*ctxt*/,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out)
+{
+ auto curr_thrown_exception_node = get_current_thrown_exception ();
+ gcc_assert (curr_thrown_exception_node);
+ tree curr_exception_type = curr_thrown_exception_node->maybe_get_type ();
+ eh_region eh_reg = edge.get_eh_region ();
+ tree type_list = eh_reg->u.allowed.type_list;
+
+ switch (edge.get_eh_kind ())
+ {
+ default:
+ gcc_unreachable ();
+ case eh_dispatch_allowed_cfg_superedge::eh_kind::expected:
+ if (!curr_exception_type)
+ {
+ /* We don't know the specific type;
+ assume we have one of an expected type. */
+ return true;
+ }
+ for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
+ if (exception_matches_type_p (TREE_VALUE (iter),
+ exception_type))
+ return true;
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+
+ case eh_dispatch_allowed_cfg_superedge::eh_kind::unexpected:
+ if (!curr_exception_type)
+ {
+ /* We don't know the specific type;
+ assume we don't have one of an expected type. */
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+ }
+ for (tree iter = type_list; iter; iter = TREE_CHAIN (iter))
+ if (exception_matches_type_p (TREE_VALUE (iter),
+ exception_type))
+ {
+ if (out)
+ *out = std::make_unique<rejected_eh_dispatch> (*this);
+ return false;
+ }
+ return true;
+ }
+}
+
/* Given an edge reached by GOTO_STMT, determine appropriate constraints
for the edge to be taken.
@@ -6202,38 +6713,6 @@ region_model::apply_constraints_for_ggoto (const cfg_superedge &edge,
return true;
}
-/* Apply any constraints due to an exception being thrown at LAST_STMT.
-
- If they are feasible, add the constraints and return true.
-
- Return false if the constraints contradict existing knowledge
- (and so the edge should not be taken).
- When returning false, if OUT is non-NULL, write a new rejected_constraint
- to it. */
-
-bool
-region_model::
-apply_constraints_for_exception (const gimple *last_stmt,
- region_model_context *ctxt,
- std::unique_ptr<rejected_constraint> *out)
-{
- gcc_assert (last_stmt);
- if (const gcall *call = dyn_cast <const gcall *> (last_stmt))
- if (tree callee_fndecl = get_fndecl_for_call (call, ctxt))
- if (is_named_call_p (callee_fndecl, "operator new", call, 1)
- || is_named_call_p (callee_fndecl, "operator new []", call, 1))
- {
- /* We have an exception thrown from operator new.
- Add a constraint that the result was NULL, to avoid a false
- leak report due to the result being lost when following
- the EH edge. */
- if (tree lhs = gimple_call_lhs (call))
- return add_constraint (lhs, EQ_EXPR, null_pointer_node, ctxt, out);
- return true;
- }
- return true;
-}
-
/* For use with push_frame when handling a top-level call within the analysis.
PARAM has a defined but unknown initial value.
Anything it points to has escaped, since the calling context "knows"
@@ -6265,6 +6744,10 @@ region_model::on_top_level_param (tree param,
/* Update this region_model to reflect pushing a frame onto the stack
for a call to FUN.
+ If CALL_STMT is non-NULL, this is for the interprocedural case where
+ we already have an execution path into the caller. It can be NULL for
+ top-level entrypoints into the analysis, or in selftests.
+
If ARG_SVALS is non-NULL, use it to populate the parameters
in the new frame.
Otherwise, the params have their initial_svalues.
@@ -6273,14 +6756,32 @@ region_model::on_top_level_param (tree param,
const region *
region_model::push_frame (const function &fun,
+ const gcall *call_stmt,
const vec<const svalue *> *arg_svals,
region_model_context *ctxt)
{
- m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
+ tree fndecl = fun.decl;
if (arg_svals)
{
+ /* If the result of the callee is DECL_BY_REFERENCE, then
+ we'll need to store a reference to the caller's lhs of
+ CALL_STMT within callee's result.
+ If so, determine the region of CALL_STMT's lhs within
+ the caller's frame before updating m_current_frame. */
+ const region *caller_return_by_reference_reg = nullptr;
+ if (tree result = DECL_RESULT (fndecl))
+ if (DECL_BY_REFERENCE (result))
+ {
+ gcc_assert (call_stmt);
+ tree lhs = gimple_call_lhs (call_stmt);
+ gcc_assert (lhs);
+ caller_return_by_reference_reg = get_lvalue (lhs, ctxt);
+ }
+
+ /* Update m_current_frame. */
+ m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
+
/* Arguments supplied from a caller frame. */
- tree fndecl = fun.decl;
unsigned idx = 0;
for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
iter_parm = DECL_CHAIN (iter_parm), ++idx)
@@ -6308,13 +6809,39 @@ region_model::push_frame (const function &fun,
va_arg_idx);
set_value (var_arg_reg, arg_sval, ctxt);
}
+
+ /* If the result of the callee is DECL_BY_REFERENCE, then above
+ we should have determined the region within the
+ caller's frame that the callee will be writing back to.
+ Use this now to initialize the reference in callee's frame. */
+ if (tree result = DECL_RESULT (fndecl))
+ if (DECL_BY_REFERENCE (result))
+ {
+ /* Get reference to the caller lhs. */
+ gcc_assert (caller_return_by_reference_reg);
+ const svalue *ref_sval
+ = m_mgr->get_ptr_svalue (TREE_TYPE (result),
+ caller_return_by_reference_reg);
+
+ /* Get region for default val of DECL_RESULT within the
+ callee. */
+ tree result_default_ssa = get_ssa_default_def (fun, result);
+ gcc_assert (result_default_ssa);
+ const region *callee_result_reg
+ = get_lvalue (result_default_ssa, ctxt);
+
+ /* Set the callee's reference to refer to the caller's lhs. */
+ set_value (callee_result_reg, ref_sval, ctxt);
+ }
}
else
{
/* Otherwise we have a top-level call within the analysis. The params
have defined but unknown initial values.
Anything they point to has escaped. */
- tree fndecl = fun.decl;
+
+ /* Update m_current_frame. */
+ m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
/* Handle "__attribute__((nonnull))". */
tree fntype = TREE_TYPE (fndecl);
@@ -6382,7 +6909,7 @@ public:
{}
std::unique_ptr<stmt_finder> clone () const override
{
- return ::make_unique<my_finder> (m_call_stmt, m_caller_frame);
+ return std::make_unique<my_finder> (m_call_stmt, m_caller_frame);
}
const gimple *find_stmt (const exploded_path &) override
{
@@ -6433,7 +6960,7 @@ private:
Purge the frame region and all its descendent regions.
Convert any pointers that point into such regions into
- POISON_KIND_POPPED_STACK svalues. */
+ poison_kind::popped_stack svalues. */
void
region_model::pop_frame (tree result_lvalue,
@@ -6467,7 +6994,11 @@ region_model::pop_frame (tree result_lvalue,
/* Pop the frame. */
m_current_frame = m_current_frame->get_calling_frame ();
- if (result_lvalue && retval)
+ if (result_lvalue
+ && retval
+ /* Don't write back for DECL_BY_REFERENCE; the writes
+ should have happened within the callee already. */
+ && !DECL_BY_REFERENCE (result))
{
gcc_assert (eval_return_svalue);
@@ -6483,7 +7014,7 @@ region_model::pop_frame (tree result_lvalue,
set_value (result_dst_reg, retval, call_stmt ? &caller_ctxt : ctxt);
}
- unbind_region_and_descendents (frame_reg,POISON_KIND_POPPED_STACK);
+ unbind_region_and_descendents (frame_reg,poison_kind::popped_stack);
notify_on_pop_frame (this, &pre_popped_model, retval, ctxt);
}
@@ -6640,6 +7171,14 @@ region_model::can_merge_with_p (const region_model &other_model,
for (auto iter : m.m_svals_changing_meaning)
out_model->m_constraints->purge_state_involving (iter);
+ if (m_thrown_exceptions_stack != other_model.m_thrown_exceptions_stack)
+ return false;
+ out_model->m_thrown_exceptions_stack = m_thrown_exceptions_stack;
+
+ if (m_caught_exceptions_stack != other_model.m_caught_exceptions_stack)
+ return false;
+ out_model->m_caught_exceptions_stack = m_caught_exceptions_stack;
+
return true;
}
@@ -6647,10 +7186,10 @@ region_model::can_merge_with_p (const region_model &other_model,
otherwise. */
tree
-region_model::get_fndecl_for_call (const gcall *call,
+region_model::get_fndecl_for_call (const gcall &call,
region_model_context *ctxt)
{
- tree fn_ptr = gimple_call_fn (call);
+ tree fn_ptr = gimple_call_fn (&call);
if (fn_ptr == NULL_TREE)
return NULL_TREE;
const svalue *fn_ptr_sval = get_rvalue (fn_ptr, ctxt);
@@ -6825,7 +7364,7 @@ region_model::check_dynamic_size_for_floats (const svalue *size_in_bytes,
if (const svalue *float_sval = v.get_svalue_to_report ())
{
tree diag_arg = get_representative_tree (float_sval);
- ctxt->warn (make_unique<float_as_size_arg> (diag_arg));
+ ctxt->warn (std::make_unique<float_as_size_arg> (diag_arg));
}
}
@@ -6894,6 +7433,12 @@ region_model::get_referenced_base_regions (auto_bitmap &out_ids) const
reachable_regs.add (base_reg, false);
}
+ for (auto &eh_node : m_thrown_exceptions_stack)
+ eh_node.add_to_reachable_regions (reachable_regs);
+ for (auto &eh_node : m_caught_exceptions_stack)
+ eh_node.add_to_reachable_regions (reachable_regs);
+
+
bitmap_clear (out_ids);
for (auto iter_reg : reachable_regs)
bitmap_set_bit (out_ids, iter_reg->get_id ());
@@ -7077,7 +7622,7 @@ private:
{
const poisoned_svalue *poisoned_sval
= as_a <const poisoned_svalue *> (m_copied_sval);
- gcc_assert (poisoned_sval->get_poison_kind () == POISON_KIND_UNINIT);
+ gcc_assert (poisoned_sval->get_poison_kind () == poison_kind::uninit);
/* Give up if don't have type information. */
if (m_copied_sval->get_type () == NULL_TREE)
@@ -7102,7 +7647,7 @@ private:
const svalue *sval = iter.second;
if (const poisoned_svalue *psval
= sval->dyn_cast_poisoned_svalue ())
- if (psval->get_poison_kind () == POISON_KIND_UNINIT)
+ if (psval->get_poison_kind () == poison_kind::uninit)
{
const binding_key *key = iter.first;
const concrete_binding *ckey
@@ -7154,7 +7699,7 @@ private:
const svalue *sval = iter.second;
if (const poisoned_svalue *psval
= sval->dyn_cast_poisoned_svalue ())
- if (psval->get_poison_kind () == POISON_KIND_UNINIT)
+ if (psval->get_poison_kind () == poison_kind::uninit)
{
const binding_key *key = iter.first;
const concrete_binding *ckey
@@ -7171,8 +7716,7 @@ private:
tree type = m_copied_sval->get_type ();
if (type && TREE_CODE (type) == RECORD_TYPE)
{
- // (std::make_unique is C++14)
- layout = std::unique_ptr<record_layout> (new record_layout (type));
+ layout = std::make_unique<record_layout> (type);
if (0)
layout->dump ();
@@ -7358,7 +7902,7 @@ contains_uninit_p (const svalue *sval)
{
const poisoned_svalue *psval
= as_a <const poisoned_svalue *> (sval);
- return psval->get_poison_kind () == POISON_KIND_UNINIT;
+ return psval->get_poison_kind () == poison_kind::uninit;
}
case SK_COMPOUND:
{
@@ -7370,7 +7914,7 @@ contains_uninit_p (const svalue *sval)
const svalue *sval = iter.second;
if (const poisoned_svalue *psval
= sval->dyn_cast_poisoned_svalue ())
- if (psval->get_poison_kind () == POISON_KIND_UNINIT)
+ if (psval->get_poison_kind () == poison_kind::uninit)
return true;
}
@@ -7397,9 +7941,10 @@ region_model::maybe_complain_about_infoleak (const region *dst_reg,
{
/* Check for exposure. */
if (contains_uninit_p (copied_sval))
- ctxt->warn (make_unique<exposure_through_uninit_copy> (src_reg,
- dst_reg,
- copied_sval));
+ ctxt->warn
+ (std::make_unique<exposure_through_uninit_copy> (src_reg,
+ dst_reg,
+ copied_sval));
}
/* Set errno to a positive symbolic int, as if some error has occurred. */
@@ -7411,7 +7956,7 @@ region_model::set_errno (const call_details &cd)
conjured_purge p (this, cd.get_ctxt ());
const svalue *new_errno_sval
= m_mgr->get_or_create_conjured_svalue (integer_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
errno_reg, p);
const svalue *zero
= m_mgr->get_or_create_int_cst (integer_type_node, 0);
@@ -8432,7 +8977,7 @@ test_stack_frames ()
/* Push stack frame for "parent_fn". */
const region *parent_frame_reg
= model.push_frame (*DECL_STRUCT_FUNCTION (parent_fndecl),
- NULL, &ctxt);
+ nullptr, nullptr, &ctxt);
ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
const region *a_in_parent_reg = model.get_lvalue (a, &ctxt);
@@ -8447,7 +8992,8 @@ test_stack_frames ()
/* Push stack frame for "child_fn". */
const region *child_frame_reg
- = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
+ = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl),
+ nullptr, nullptr, &ctxt);
ASSERT_EQ (model.get_current_frame (), child_frame_reg);
ASSERT_TRUE (model.region_exists_p (child_frame_reg));
const region *x_in_child_reg = model.get_lvalue (x, &ctxt);
@@ -8488,7 +9034,7 @@ test_stack_frames ()
const svalue *new_p_sval = model.get_rvalue (p, NULL);
ASSERT_EQ (new_p_sval->get_kind (), SK_POISONED);
ASSERT_EQ (new_p_sval->dyn_cast_poisoned_svalue ()->get_poison_kind (),
- POISON_KIND_POPPED_STACK);
+ poison_kind::popped_stack);
/* Verify that q still points to p, in spite of the region
renumbering. */
@@ -8540,7 +9086,8 @@ test_get_representative_path_var ()
for (int depth = 0; depth < 5; depth++)
{
const region *frame_n_reg
- = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt);
+ = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
+ nullptr, nullptr, &ctxt);
const region *parm_n_reg = model.get_lvalue (path_var (n, depth), &ctxt);
parm_regs.safe_push (parm_n_reg);
@@ -8786,9 +9333,11 @@ test_state_merging ()
region_model model0 (&mgr);
region_model model1 (&mgr);
ASSERT_EQ (model0.get_stack_depth (), 0);
- model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, &ctxt);
ASSERT_EQ (model0.get_stack_depth (), 1);
- model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
+ model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, &ctxt);
placeholder_svalue test_sval (mgr.alloc_symbol_id (),
integer_type_node, "test sval");
@@ -8880,7 +9429,8 @@ test_state_merging ()
/* Pointers: non-NULL and non-NULL: ptr to a local. */
{
region_model model0 (&mgr);
- model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, nullptr);
model0.set_value (model0.get_lvalue (p, NULL),
model0.get_rvalue (addr_of_a, NULL), NULL);
@@ -9019,12 +9569,14 @@ test_state_merging ()
frame points to a local in a more recent stack frame. */
{
region_model model0 (&mgr);
- model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, nullptr);
const region *q_in_first_frame = model0.get_lvalue (q, NULL);
/* Push a second frame. */
const region *reg_2nd_frame
- = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, nullptr);
/* Have a pointer in the older frame point to a local in the
more recent frame. */
@@ -9051,7 +9603,8 @@ test_state_merging ()
/* Verify that we can merge a model in which a local points to a global. */
{
region_model model0 (&mgr);
- model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl),
+ nullptr, nullptr, nullptr);
model0.set_value (model0.get_lvalue (q, NULL),
model0.get_rvalue (addr_of_y, NULL), NULL);
@@ -9583,7 +10136,7 @@ test_alloca ()
/* Push stack frame. */
const region *frame_reg
= model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
- NULL, &ctxt);
+ nullptr, nullptr, &ctxt);
/* "p = alloca (n * 4);". */
const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
const region *reg = model.create_region_for_alloca (size_sval, &ctxt);
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index d8e508d..2c7f737 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -250,6 +250,41 @@ typedef void (*pop_frame_callback) (const region_model *model,
const svalue *retval,
region_model_context *ctxt);
+/* Roughly equivalent to a struct __cxa_exception, except we store a std::vector
+ rather than a linked list. */
+
+struct exception_node
+{
+ exception_node (const svalue *exception_sval,
+ const svalue *typeinfo_sval,
+ const svalue *destructor_sval)
+ : m_exception_sval (exception_sval),
+ m_typeinfo_sval (typeinfo_sval),
+ m_destructor_sval (destructor_sval)
+ {
+ }
+
+ bool operator== (const exception_node &other) const;
+
+ void dump_to_pp (pretty_printer *pp, bool simple) const;
+ void dump (FILE *fp, bool simple) const;
+ void dump (bool simple) const;
+ void dump () const;
+
+ std::unique_ptr<json::object> to_json () const;
+
+ std::unique_ptr<text_art::tree_widget>
+ make_dump_widget (const text_art::dump_widget_info &dwi) const;
+
+ tree maybe_get_type () const;
+
+ void add_to_reachable_regions (reachable_regions &) const;
+
+ const svalue *m_exception_sval;
+ const svalue *m_typeinfo_sval;
+ const svalue *m_destructor_sval;
+};
+
/* A region_model encapsulates a representation of the state of memory, with
a tree of regions, along with their associated values.
The representation is graph-like because values can be pointers to
@@ -305,8 +340,8 @@ class region_model
const svalue *get_gassign_result (const gassign *assign,
region_model_context *ctxt);
void on_asm_stmt (const gasm *asm_stmt, region_model_context *ctxt);
- bool on_call_pre (const gcall *stmt, region_model_context *ctxt);
- void on_call_post (const gcall *stmt,
+ bool on_call_pre (const gcall &stmt, region_model_context *ctxt);
+ void on_call_post (const gcall &stmt,
bool unknown_side_effects,
region_model_context *ctxt);
@@ -323,16 +358,16 @@ class region_model
bool unmergeable);
void update_for_nonzero_return (const call_details &cd);
- void handle_unrecognized_call (const gcall *call,
+ void handle_unrecognized_call (const gcall &call,
region_model_context *ctxt);
void get_reachable_svalues (svalue_set *out,
const svalue *extra_sval,
const uncertainty_t *uncertainty);
void on_return (const greturn *stmt, region_model_context *ctxt);
- void on_setjmp (const gcall *stmt, const exploded_node *enode,
+ void on_setjmp (const gcall &stmt, const exploded_node *enode,
region_model_context *ctxt);
- void on_longjmp (const gcall *longjmp_call, const gcall *setjmp_call,
+ void on_longjmp (const gcall &longjmp_call, const gcall &setjmp_call,
int setjmp_stack_depth, region_model_context *ctxt);
void update_for_phis (const supernode *snode,
@@ -349,14 +384,16 @@ class region_model
region_model_context *ctxt,
std::unique_ptr<rejected_constraint> *out);
- void update_for_gcall (const gcall *call_stmt,
+ void update_for_gcall (const gcall &call_stmt,
region_model_context *ctxt,
function *callee = NULL);
- void update_for_return_gcall (const gcall *call_stmt,
+ void update_for_return_gcall (const gcall &call_stmt,
region_model_context *ctxt);
- const region *push_frame (const function &fun, const vec<const svalue *> *arg_sids,
+ const region *push_frame (const function &fun,
+ const gcall *call_stmt,
+ const vec<const svalue *> *arg_sids,
region_model_context *ctxt);
const frame_region *get_current_frame () const { return m_current_frame; }
const function *get_current_function () const;
@@ -484,7 +521,7 @@ class region_model
const program_state *state_a = NULL,
const program_state *state_b = NULL) const;
- tree get_fndecl_for_call (const gcall *call,
+ tree get_fndecl_for_call (const gcall &call,
region_model_context *ctxt);
void get_regions_for_current_frame (auto_vec<const decl_region *> *out) const;
@@ -562,7 +599,7 @@ class region_model
const svalue **out_sval) const;
const builtin_known_function *
- get_builtin_kf (const gcall *call,
+ get_builtin_kf (const gcall &call,
region_model_context *ctxt = NULL) const;
static void
@@ -583,6 +620,56 @@ class region_model
bool called_from_main_p () const;
+ void push_thrown_exception (const exception_node &node)
+ {
+ m_thrown_exceptions_stack.push_back (node);
+ }
+ const exception_node *get_current_thrown_exception () const
+ {
+ if (m_thrown_exceptions_stack.empty ())
+ return nullptr;
+ return &m_thrown_exceptions_stack.back ();
+ }
+ exception_node pop_thrown_exception ()
+ {
+ gcc_assert (!m_thrown_exceptions_stack.empty ());
+ const exception_node retval = m_thrown_exceptions_stack.back ();
+ m_thrown_exceptions_stack.pop_back ();
+ return retval;
+ }
+
+ void push_caught_exception (const exception_node &node)
+ {
+ m_caught_exceptions_stack.push_back (node);
+ }
+ const exception_node *get_current_caught_exception () const
+ {
+ if (m_caught_exceptions_stack.empty ())
+ return nullptr;
+ return &m_caught_exceptions_stack.back ();
+ }
+ exception_node pop_caught_exception ()
+ {
+ gcc_assert (!m_caught_exceptions_stack.empty ());
+ const exception_node retval = m_caught_exceptions_stack.back ();
+ m_caught_exceptions_stack.pop_back ();
+ return retval;
+ }
+
+ bool
+ apply_constraints_for_eh_dispatch_try
+ (const eh_dispatch_try_cfg_superedge &edge,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out);
+
+ bool
+ apply_constraints_for_eh_dispatch_allowed
+ (const eh_dispatch_allowed_cfg_superedge &edge,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out);
+
private:
const region *get_lvalue_1 (path_var pv, region_model_context *ctxt) const;
const svalue *get_rvalue_1 (path_var pv, region_model_context *ctxt) const;
@@ -621,9 +708,12 @@ private:
bool apply_constraints_for_ggoto (const cfg_superedge &edge,
const ggoto *goto_stmt,
region_model_context *ctxt);
- bool apply_constraints_for_exception (const gimple *last_stmt,
- region_model_context *ctxt,
- std::unique_ptr<rejected_constraint> *out);
+
+ bool
+ apply_constraints_for_eh_dispatch (const eh_dispatch_cfg_superedge &edge,
+ const geh_dispatch *eh_dispatch_stmt,
+ region_model_context *ctxt,
+ std::unique_ptr<rejected_constraint> *out);
int poison_any_pointers_to_descendents (const region *reg,
enum poison_kind pkind);
@@ -672,23 +762,27 @@ private:
void check_call_args (const call_details &cd) const;
void check_call_format_attr (const call_details &cd,
tree format_attr) const;
- void check_function_attr_access (const gcall *call,
+ void check_function_attr_access (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx) const;
- void check_function_attr_null_terminated_string_arg (const gcall *call,
+ void check_function_attr_null_terminated_string_arg (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx);
- void check_one_function_attr_null_terminated_string_arg (const gcall *call,
+ void check_one_function_attr_null_terminated_string_arg (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt,
rdwr_map &rdwr_idx,
tree attr);
- void check_function_attrs (const gcall *call,
+ void check_function_attrs (const gcall &call,
tree callee_fndecl,
region_model_context *ctxt);
+ void check_for_throw_inside_call (const gcall &call,
+ tree fndecl,
+ region_model_context *ctxt);
+
static auto_vec<pop_frame_callback> pop_frame_callbacks;
/* Storing this here to avoid passing it around everywhere. */
region_model_manager *const m_mgr;
@@ -699,6 +793,9 @@ private:
const frame_region *m_current_frame;
+ std::vector<exception_node> m_thrown_exceptions_stack;
+ std::vector<exception_node> m_caught_exceptions_stack;
+
/* Map from base region to size in bytes, for tracking the sizes of
dynamically-allocated regions.
This is part of the region_model rather than the region to allow for
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index d464153..efbbca0 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -18,38 +18,19 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
#include "digraph.h"
-#include "analyzer/supergraph.h"
#include "sbitmap.h"
+#include "fold-const.h"
+#include "tree-ssa.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/supergraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
@@ -58,7 +39,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/sm.h"
#include "analyzer/program-state.h"
#include "text-art/dump.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -567,15 +547,12 @@ region::can_have_initial_svalue_p () const
case SSA_NAME:
{
+ /* Some SSA names have an implicit default defined value. */
tree ssa_name = decl;
- /* SSA names that are the default defn of a PARM_DECL
- have initial_svalues; other SSA names don't. */
- if (SSA_NAME_IS_DEFAULT_DEF (ssa_name)
- && SSA_NAME_VAR (ssa_name)
- && TREE_CODE (SSA_NAME_VAR (ssa_name)) == PARM_DECL)
- return true;
- else
- return false;
+ if (SSA_NAME_IS_DEFAULT_DEF (ssa_name))
+ return ssa_defined_default_def_p (ssa_name);
+ /* Others don't. */
+ return false;
}
}
}
@@ -1039,7 +1016,7 @@ std::unique_ptr<json::value>
region::to_json () const
{
label_text desc = get_desc (true);
- auto reg_js = ::make_unique<json::string> (desc.get ());
+ auto reg_js = std::make_unique<json::string> (desc.get ());
return reg_js;
}
diff --git a/gcc/analyzer/sm-fd.cc b/gcc/analyzer/sm-fd.cc
index e9016f1..cee8d2d 100644
--- a/gcc/analyzer/sm-fd.cc
+++ b/gcc/analyzer/sm-fd.cc
@@ -18,32 +18,21 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "diagnostic-event-id.h"
+#include "stringpool.h"
+#include "attribs.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/function-set.h"
#include "analyzer/analyzer-selftests.h"
-#include "stringpool.h"
-#include "attribs.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
-#include "bitmap.h"
#include "analyzer/program-state.h"
#include "analyzer/supergraph.h"
#include "analyzer/analyzer-language.h"
@@ -230,17 +219,17 @@ public:
private:
void on_open (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call) const;
+ const gcall &call) const;
void on_creat (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call) const;
+ const gcall &call) const;
void on_close (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call) const;
+ const gcall &call) const;
void on_read (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call, const tree callee_fndecl) const;
+ const gcall &call, const tree callee_fndecl) const;
void on_write (sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call, const tree callee_fndecl) const;
+ const gcall &call, const tree callee_fndecl) const;
void check_for_open_fd (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl,
enum access_directions access_fn) const;
@@ -253,11 +242,11 @@ private:
const gimple *stmt,
const svalue *lhs) const;
void check_for_fd_attrs (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl, const char *attr_name,
access_directions fd_attr_access_dir) const;
void check_for_dup (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call, const tree callee_fndecl,
+ const gimple *stmt, const gcall &call, const tree callee_fndecl,
enum dup kind) const;
state_t get_state_for_socket_type (const svalue *socket_type_sval) const;
@@ -1324,70 +1313,70 @@ fd_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node,
const gimple *stmt) const
{
if (const gcall *call = dyn_cast<const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
{
- if (is_named_call_p (callee_fndecl, "open", call, 2))
+ if (is_named_call_p (callee_fndecl, "open", *call, 2))
{
- on_open (sm_ctxt, node, stmt, call);
+ on_open (sm_ctxt, node, stmt, *call);
return true;
} // "open"
- if (is_named_call_p (callee_fndecl, "creat", call, 2))
+ if (is_named_call_p (callee_fndecl, "creat", *call, 2))
{
- on_creat (sm_ctxt, node, stmt, call);
+ on_creat (sm_ctxt, node, stmt, *call);
return true;
} // "creat"
- if (is_named_call_p (callee_fndecl, "close", call, 1))
+ if (is_named_call_p (callee_fndecl, "close", *call, 1))
{
- on_close (sm_ctxt, node, stmt, call);
+ on_close (sm_ctxt, node, stmt, *call);
return true;
} // "close"
- if (is_named_call_p (callee_fndecl, "write", call, 3))
+ if (is_named_call_p (callee_fndecl, "write", *call, 3))
{
- on_write (sm_ctxt, node, stmt, call, callee_fndecl);
+ on_write (sm_ctxt, node, stmt, *call, callee_fndecl);
return true;
} // "write"
- if (is_named_call_p (callee_fndecl, "read", call, 3))
+ if (is_named_call_p (callee_fndecl, "read", *call, 3))
{
- on_read (sm_ctxt, node, stmt, call, callee_fndecl);
+ on_read (sm_ctxt, node, stmt, *call, callee_fndecl);
return true;
} // "read"
- if (is_named_call_p (callee_fndecl, "dup", call, 1))
+ if (is_named_call_p (callee_fndecl, "dup", *call, 1))
{
- check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_1);
+ check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_1);
return true;
}
- if (is_named_call_p (callee_fndecl, "dup2", call, 2))
+ if (is_named_call_p (callee_fndecl, "dup2", *call, 2))
{
- check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_2);
+ check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_2);
return true;
}
- if (is_named_call_p (callee_fndecl, "dup3", call, 3))
+ if (is_named_call_p (callee_fndecl, "dup3", *call, 3))
{
- check_for_dup (sm_ctxt, node, stmt, call, callee_fndecl, DUP_3);
+ check_for_dup (sm_ctxt, node, stmt, *call, callee_fndecl, DUP_3);
return true;
}
{
// Handle __attribute__((fd_arg))
- check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
+ check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl,
"fd_arg", DIRS_READ_WRITE);
// Handle __attribute__((fd_arg_read))
- check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
+ check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl,
"fd_arg_read", DIRS_READ);
// Handle __attribute__((fd_arg_write))
- check_for_fd_attrs (sm_ctxt, node, stmt, call, callee_fndecl,
+ check_for_fd_attrs (sm_ctxt, node, stmt, *call, callee_fndecl,
"fd_arg_write", DIRS_WRITE);
}
}
@@ -1398,7 +1387,7 @@ fd_state_machine::on_stmt (sm_context &sm_ctxt, const supernode *node,
void
fd_state_machine::check_for_fd_attrs (
sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call, const tree callee_fndecl, const char *attr_name,
+ const gcall &call, const tree callee_fndecl, const char *attr_name,
access_directions fd_attr_access_dir) const
{
/* Handle interesting fd attributes of the callee_fndecl,
@@ -1431,9 +1420,9 @@ fd_state_machine::check_for_fd_attrs (
if (bitmap_empty_p (argmap))
return;
- for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (call); arg_idx++)
+ for (unsigned arg_idx = 0; arg_idx < gimple_call_num_args (&call); arg_idx++)
{
- tree arg = gimple_call_arg (call, arg_idx);
+ tree arg = gimple_call_arg (&call, arg_idx);
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
state_t state = sm_ctxt.get_state (stmt, arg);
bool bit_set = bitmap_bit_p (argmap, arg_idx);
@@ -1449,7 +1438,7 @@ fd_state_machine::check_for_fd_attrs (
{
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_use_after_close>
+ std::make_unique<fd_use_after_close>
(*this, diag_arg,
fndecl, attr_name,
arg_idx));
@@ -1461,7 +1450,7 @@ fd_state_machine::check_for_fd_attrs (
if (!is_constant_fd_p (state))
{
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_use_without_check>
+ std::make_unique<fd_use_without_check>
(*this, diag_arg,
fndecl, attr_name,
arg_idx));
@@ -1477,13 +1466,13 @@ fd_state_machine::check_for_fd_attrs (
if (is_writeonly_fd_p (state))
{
- sm_ctxt.warn (
- node, stmt, arg,
- make_unique<fd_access_mode_mismatch> (*this, diag_arg,
- DIRS_WRITE,
- fndecl,
- attr_name,
- arg_idx));
+ sm_ctxt.warn
+ (node, stmt, arg,
+ std::make_unique<fd_access_mode_mismatch> (*this, diag_arg,
+ DIRS_WRITE,
+ fndecl,
+ attr_name,
+ arg_idx));
}
break;
@@ -1491,13 +1480,13 @@ fd_state_machine::check_for_fd_attrs (
if (is_readonly_fd_p (state))
{
- sm_ctxt.warn (
- node, stmt, arg,
- make_unique<fd_access_mode_mismatch> (*this, diag_arg,
- DIRS_READ,
- fndecl,
- attr_name,
- arg_idx));
+ sm_ctxt.warn
+ (node, stmt, arg,
+ std::make_unique<fd_access_mode_mismatch> (*this, diag_arg,
+ DIRS_READ,
+ fndecl,
+ attr_name,
+ arg_idx));
}
break;
@@ -1509,12 +1498,12 @@ fd_state_machine::check_for_fd_attrs (
void
fd_state_machine::on_open (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call) const
+ const gimple *stmt, const gcall &call) const
{
- tree lhs = gimple_call_lhs (call);
+ tree lhs = gimple_call_lhs (&call);
if (lhs)
{
- tree arg = gimple_call_arg (call, 1);
+ tree arg = gimple_call_arg (&call, 1);
enum access_mode mode = READ_WRITE;
if (TREE_CODE (arg) == INTEGER_CST)
{
@@ -1539,29 +1528,29 @@ fd_state_machine::on_open (sm_context &sm_ctxt, const supernode *node,
else
{
sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<fd_leak> (*this, NULL_TREE));
+ std::make_unique<fd_leak> (*this, NULL_TREE));
}
}
void
fd_state_machine::on_creat (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call) const
+ const gimple *stmt, const gcall &call) const
{
- tree lhs = gimple_call_lhs (call);
+ tree lhs = gimple_call_lhs (&call);
if (lhs)
sm_ctxt.on_transition (node, stmt, lhs, m_start, m_unchecked_write_only);
else
sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<fd_leak> (*this, NULL_TREE));
+ std::make_unique<fd_leak> (*this, NULL_TREE));
}
void
fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl, enum dup kind) const
{
- tree lhs = gimple_call_lhs (call);
- tree arg_1 = gimple_call_arg (call, 0);
+ tree lhs = gimple_call_lhs (&call);
+ tree arg_1 = gimple_call_arg (&call, 0);
state_t state_arg_1 = sm_ctxt.get_state (stmt, arg_1);
if (state_arg_1 == m_stop)
return;
@@ -1587,7 +1576,7 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
case DUP_2:
case DUP_3:
- tree arg_2 = gimple_call_arg (call, 1);
+ tree arg_2 = gimple_call_arg (&call, 1);
state_t state_arg_2 = sm_ctxt.get_state (stmt, arg_2);
tree diag_arg_2 = sm_ctxt.get_diagnostic_tree (arg_2);
if (state_arg_2 == m_stop)
@@ -1598,8 +1587,8 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
{
sm_ctxt.warn (
node, stmt, arg_2,
- make_unique<fd_use_without_check> (*this, diag_arg_2,
- callee_fndecl));
+ std::make_unique<fd_use_without_check> (*this, diag_arg_2,
+ callee_fndecl));
return;
}
/* dup2 returns value of its second argument on success.But, the
@@ -1620,9 +1609,9 @@ fd_state_machine::check_for_dup (sm_context &sm_ctxt, const supernode *node,
void
fd_state_machine::on_close (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call) const
+ const gimple *stmt, const gcall &call) const
{
- tree arg = gimple_call_arg (call, 0);
+ tree arg = gimple_call_arg (&call, 0);
state_t state = sm_ctxt.get_state (stmt, arg);
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
@@ -1646,20 +1635,20 @@ fd_state_machine::on_close (sm_context &sm_ctxt, const supernode *node,
if (is_closed_fd_p (state))
{
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_double_close> (*this, diag_arg));
+ std::make_unique<fd_double_close> (*this, diag_arg));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
}
void
fd_state_machine::on_read (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl) const
{
check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_READ);
}
void
fd_state_machine::on_write (sm_context &sm_ctxt, const supernode *node,
- const gimple *stmt, const gcall *call,
+ const gimple *stmt, const gcall &call,
const tree callee_fndecl) const
{
check_for_open_fd (sm_ctxt, node, stmt, call, callee_fndecl, DIRS_WRITE);
@@ -1668,18 +1657,18 @@ fd_state_machine::on_write (sm_context &sm_ctxt, const supernode *node,
void
fd_state_machine::check_for_open_fd (
sm_context &sm_ctxt, const supernode *node, const gimple *stmt,
- const gcall *call, const tree callee_fndecl,
+ const gcall &call, const tree callee_fndecl,
enum access_directions callee_fndecl_dir) const
{
- tree arg = gimple_call_arg (call, 0);
+ tree arg = gimple_call_arg (&call, 0);
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
state_t state = sm_ctxt.get_state (stmt, arg);
if (is_closed_fd_p (state))
{
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_use_after_close> (*this, diag_arg,
- callee_fndecl));
+ std::make_unique<fd_use_after_close> (*this, diag_arg,
+ callee_fndecl));
}
else
@@ -1690,10 +1679,10 @@ fd_state_machine::check_for_open_fd (
/* Complain about fncall on socket in wrong phase. */
sm_ctxt.warn
(node, stmt, arg,
- make_unique<fd_phase_mismatch> (*this, diag_arg,
- callee_fndecl,
- state,
- EXPECTED_PHASE_CAN_TRANSFER));
+ std::make_unique<fd_phase_mismatch> (*this, diag_arg,
+ callee_fndecl,
+ state,
+ EXPECTED_PHASE_CAN_TRANSFER));
else if (!(is_valid_fd_p (state)
|| state == m_new_datagram_socket
|| state == m_bound_unknown_socket
@@ -1704,8 +1693,8 @@ fd_state_machine::check_for_open_fd (
if (!is_constant_fd_p (state))
sm_ctxt.warn (
node, stmt, arg,
- make_unique<fd_use_without_check> (*this, diag_arg,
- callee_fndecl));
+ std::make_unique<fd_use_without_check> (*this, diag_arg,
+ callee_fndecl));
}
switch (callee_fndecl_dir)
{
@@ -1716,8 +1705,8 @@ fd_state_machine::check_for_open_fd (
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_access_mode_mismatch> (
- *this, diag_arg, DIRS_WRITE, callee_fndecl));
+ std::make_unique<fd_access_mode_mismatch>
+ (*this, diag_arg, DIRS_WRITE, callee_fndecl));
}
break;
@@ -1727,8 +1716,8 @@ fd_state_machine::check_for_open_fd (
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<fd_access_mode_mismatch> (
- *this, diag_arg, DIRS_READ, callee_fndecl));
+ std::make_unique<fd_access_mode_mismatch>
+ (*this, diag_arg, DIRS_READ, callee_fndecl));
}
break;
}
@@ -1775,21 +1764,21 @@ fd_state_machine::on_socket (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (stmt);
+ const supernode *node = sg->get_supernode_for_stmt (&call);
region_model *model = cd.get_model ();
if (successful)
{
- if (gimple_call_lhs (stmt))
+ if (gimple_call_lhs (&call))
{
conjured_purge p (model, cd.get_ctxt ());
region_model_manager *mgr = model->get_manager ();
const svalue *new_fd
= mgr->get_or_create_conjured_svalue (integer_type_node,
- stmt,
+ &call,
cd.get_lhs_region (),
p);
if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
@@ -1798,12 +1787,12 @@ fd_state_machine::on_socket (const call_details &cd,
const svalue *socket_type_sval = cd.get_arg_svalue (1);
state_machine::state_t new_state
= get_state_for_socket_type (socket_type_sval);
- sm_ctxt.on_transition (node, stmt, new_fd, m_start, new_state);
+ sm_ctxt.on_transition (node, &call, new_fd, m_start, new_state);
model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
}
else
- sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<fd_leak> (*this, NULL_TREE));
+ sm_ctxt.warn (node, &call, NULL_TREE,
+ std::make_unique<fd_leak> (*this, NULL_TREE));
}
else
{
@@ -1833,15 +1822,15 @@ fd_state_machine::check_for_socket_fd (const call_details &cd,
state_t old_state,
bool *complained) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
if (is_closed_fd_p (old_state))
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_use_after_close> (*this, diag_arg,
- cd.get_fndecl_for_call ()));
+ (node, &call, fd_sval,
+ std::make_unique<fd_use_after_close> (*this, diag_arg,
+ cd.get_fndecl_for_call ()));
if (complained)
*complained = true;
if (successful)
@@ -1852,11 +1841,11 @@ fd_state_machine::check_for_socket_fd (const call_details &cd,
/* Complain about non-socket. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_type_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_TYPE_SOCKET));
+ (node, &call, fd_sval,
+ std::make_unique<fd_type_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_TYPE_SOCKET));
if (complained)
*complained = true;
if (successful)
@@ -1866,9 +1855,9 @@ fd_state_machine::check_for_socket_fd (const call_details &cd,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_use_without_check> (*this, diag_arg,
- cd.get_fndecl_for_call ()));
+ (node, &call, fd_sval,
+ std::make_unique<fd_use_without_check> (*this, diag_arg,
+ cd.get_fndecl_for_call ()));
if (complained)
*complained = true;
if (successful)
@@ -1929,11 +1918,11 @@ fd_state_machine::check_for_new_socket_fd (const call_details &cd,
/* Complain about "bind" or "connect" in wrong phase. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
sm_ctxt.warn
- (node, cd.get_call_stmt (), fd_sval,
- make_unique<fd_phase_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- expected_phase));
+ (node, &cd.get_call_stmt (), fd_sval,
+ std::make_unique<fd_phase_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ expected_phase));
if (successful)
return false;
}
@@ -1941,7 +1930,7 @@ fd_state_machine::check_for_new_socket_fd (const call_details &cd,
{
/* If we were in the start state, assume we had a new socket. */
if (old_state == m_start)
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval,
m_new_unknown_socket);
}
@@ -1963,13 +1952,13 @@ fd_state_machine::on_bind (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (stmt);
+ const supernode *node = sg->get_supernode_for_stmt (&call);
const svalue *fd_sval = cd.get_arg_svalue (0);
region_model *model = cd.get_model ();
- state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
+ state_t old_state = sm_ctxt.get_state (&call, fd_sval);
if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
fd_sval, node, old_state,
@@ -1992,7 +1981,7 @@ fd_state_machine::on_bind (const call_details &cd,
next_state = m_stop;
else
gcc_unreachable ();
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, next_state);
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, next_state);
model->update_for_zero_return (cd, true);
}
else
@@ -2015,13 +2004,13 @@ fd_state_machine::on_listen (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (cd.get_call_stmt ());
+ const supernode *node = sg->get_supernode_for_stmt (&cd.get_call_stmt ());
const svalue *fd_sval = cd.get_arg_svalue (0);
region_model *model = cd.get_model ();
- state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
+ state_t old_state = sm_ctxt.get_state (&call, fd_sval);
/* We expect a stream socket that's had "bind" called on it. */
if (!check_for_socket_fd (cd, successful, sm_ctxt, fd_sval, node, old_state))
@@ -2039,18 +2028,18 @@ fd_state_machine::on_listen (const call_details &cd,
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
if (is_stream_socket_fd_p (old_state))
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_phase_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_PHASE_CAN_LISTEN));
+ (node, &call, fd_sval,
+ std::make_unique<fd_phase_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_PHASE_CAN_LISTEN));
else
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_type_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_TYPE_STREAM_SOCKET));
+ (node, &call, fd_sval,
+ std::make_unique<fd_type_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_TYPE_STREAM_SOCKET));
if (successful)
return false;
}
@@ -2058,7 +2047,7 @@ fd_state_machine::on_listen (const call_details &cd,
if (successful)
{
model->update_for_zero_return (cd, true);
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval,
m_listening_stream_socket);
}
else
@@ -2067,7 +2056,7 @@ fd_state_machine::on_listen (const call_details &cd,
model->update_for_int_cst_return (cd, -1, true);
model->set_errno (cd);
if (old_state == m_start)
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval,
m_bound_stream_socket);
}
@@ -2084,15 +2073,15 @@ fd_state_machine::on_accept (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (stmt);
+ const supernode *node = sg->get_supernode_for_stmt (&call);
const svalue *fd_sval = cd.get_arg_svalue (0);
const svalue *address_sval = cd.get_arg_svalue (1);
const svalue *len_ptr_sval = cd.get_arg_svalue (2);
region_model *model = cd.get_model ();
- state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
+ state_t old_state = sm_ctxt.get_state (&call, fd_sval);
if (!address_sval->all_zeroes_p ())
{
@@ -2127,14 +2116,14 @@ fd_state_machine::on_accept (const call_details &cd,
old_len_sval);
const svalue *new_addr_sval
= mgr->get_or_create_conjured_svalue (NULL_TREE,
- stmt,
+ &call,
old_sized_address_reg,
p);
model->set_value (old_sized_address_reg, new_addr_sval,
cd.get_ctxt ());
const svalue *new_addr_len
= mgr->get_or_create_conjured_svalue (NULL_TREE,
- stmt,
+ &call,
len_reg,
p);
model->set_value (len_reg, new_addr_len, cd.get_ctxt ());
@@ -2148,7 +2137,7 @@ fd_state_machine::on_accept (const call_details &cd,
if (old_state == m_start || old_state == m_constant_fd)
/* If we were in the start state (or a constant), assume we had the
expected state. */
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval,
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval,
m_listening_stream_socket);
else if (old_state == m_stop)
{
@@ -2160,18 +2149,18 @@ fd_state_machine::on_accept (const call_details &cd,
tree diag_arg = sm_ctxt.get_diagnostic_tree (fd_sval);
if (is_stream_socket_fd_p (old_state))
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_phase_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_PHASE_CAN_ACCEPT));
+ (node, &call, fd_sval,
+ std::make_unique<fd_phase_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_PHASE_CAN_ACCEPT));
else
sm_ctxt.warn
- (node, stmt, fd_sval,
- make_unique<fd_type_mismatch> (*this, diag_arg,
- cd.get_fndecl_for_call (),
- old_state,
- EXPECTED_TYPE_STREAM_SOCKET));
+ (node, &call, fd_sval,
+ std::make_unique<fd_type_mismatch> (*this, diag_arg,
+ cd.get_fndecl_for_call (),
+ old_state,
+ EXPECTED_TYPE_STREAM_SOCKET));
if (successful)
return false;
}
@@ -2179,24 +2168,24 @@ fd_state_machine::on_accept (const call_details &cd,
if (successful)
{
/* Return new conjured FD in "connected" state. */
- if (gimple_call_lhs (stmt))
+ if (gimple_call_lhs (&call))
{
conjured_purge p (model, cd.get_ctxt ());
region_model_manager *mgr = model->get_manager ();
const svalue *new_fd
= mgr->get_or_create_conjured_svalue (integer_type_node,
- stmt,
+ &call,
cd.get_lhs_region (),
p);
if (!add_constraint_ge_zero (model, new_fd, cd.get_ctxt ()))
return false;
- sm_ctxt.on_transition (node, stmt, new_fd,
+ sm_ctxt.on_transition (node, &call, new_fd,
m_start, m_connected_stream_socket);
model->set_value (cd.get_lhs_region (), new_fd, cd.get_ctxt ());
}
else
- sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<fd_leak> (*this, NULL_TREE));
+ sm_ctxt.warn (node, &call, NULL_TREE,
+ std::make_unique<fd_leak> (*this, NULL_TREE));
}
else
{
@@ -2218,13 +2207,13 @@ fd_state_machine::on_connect (const call_details &cd,
sm_context &sm_ctxt,
const extrinsic_state &ext_state) const
{
- const gcall *stmt = cd.get_call_stmt ();
+ const gcall &call = cd.get_call_stmt ();
engine *eng = ext_state.get_engine ();
const supergraph *sg = eng->get_supergraph ();
- const supernode *node = sg->get_supernode_for_stmt (stmt);
+ const supernode *node = sg->get_supernode_for_stmt (&call);
const svalue *fd_sval = cd.get_arg_svalue (0);
region_model *model = cd.get_model ();
- state_t old_state = sm_ctxt.get_state (stmt, fd_sval);
+ state_t old_state = sm_ctxt.get_state (&call, fd_sval);
if (!check_for_new_socket_fd (cd, successful, sm_ctxt,
fd_sval, node, old_state,
@@ -2250,7 +2239,7 @@ fd_state_machine::on_connect (const call_details &cd,
next_state = m_stop;
else
gcc_unreachable ();
- sm_ctxt.set_next_state (cd.get_call_stmt (), fd_sval, next_state);
+ sm_ctxt.set_next_state (&cd.get_call_stmt (), fd_sval, next_state);
}
else
{
@@ -2334,14 +2323,14 @@ fd_state_machine::can_purge_p (state_t s) const
std::unique_ptr<pending_diagnostic>
fd_state_machine::on_leak (tree var) const
{
- return make_unique<fd_leak> (*this, var);
+ return std::make_unique<fd_leak> (*this, var);
}
} // namespace
-state_machine *
+std::unique_ptr<state_machine>
make_fd_state_machine (logger *logger)
{
- return new fd_state_machine (logger);
+ return std::make_unique<fd_state_machine> (logger);
}
static bool
@@ -2426,8 +2415,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_socket> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_socket> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_socket> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2478,8 +2469,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_bind> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_bind> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_bind> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2530,8 +2523,10 @@ class kf_listen : public known_function
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_listen> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_listen> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_listen> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2584,8 +2579,10 @@ class kf_accept : public known_function
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_accept> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_accept> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_accept> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2638,8 +2635,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_connect> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_connect> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_connect> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2696,7 +2695,7 @@ class kf_isatty : public known_function
const svalue *fd_sval = cd.get_arg_svalue (0);
state_machine::state_t old_state
- = sm_ctxt->get_state (cd.get_call_stmt (), fd_sval);
+ = sm_ctxt->get_state (&cd.get_call_stmt (), fd_sval);
if (fd_sm->is_closed_fd_p (old_state)
|| old_state == fd_sm->m_invalid)
@@ -2716,8 +2715,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, false));
- cd.get_ctxt ()->bifurcate (make_unique<outcome_of_isatty> (cd, true));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_isatty> (cd, false));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<outcome_of_isatty> (cd, true));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2773,7 +2774,7 @@ class kf_pipe : public known_function
conjured_purge p (model, cd.get_ctxt ());
const svalue *fd_sval
= mgr->get_or_create_conjured_svalue (integer_type_node,
- cd.get_call_stmt (),
+ &cd.get_call_stmt (),
element_reg,
p);
model->set_value (element_reg, fd_sval, cd.get_ctxt ());
@@ -2799,8 +2800,10 @@ public:
{
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<failure> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<failure> (cd));
+ cd.get_ctxt ()->bifurcate
+ (std::make_unique<success> (cd));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -2848,15 +2851,15 @@ public:
void
register_known_fd_functions (known_function_manager &kfm)
{
- kfm.add ("accept", make_unique<kf_accept> ());
- kfm.add ("bind", make_unique<kf_bind> ());
- kfm.add ("connect", make_unique<kf_connect> ());
- kfm.add ("isatty", make_unique<kf_isatty> ());
- kfm.add ("listen", make_unique<kf_listen> ());
- kfm.add ("pipe", make_unique<kf_pipe> (1));
- kfm.add ("pipe2", make_unique<kf_pipe> (2));
- kfm.add ("read", make_unique<kf_read> ());
- kfm.add ("socket", make_unique<kf_socket> ());
+ kfm.add ("accept", std::make_unique<kf_accept> ());
+ kfm.add ("bind", std::make_unique<kf_bind> ());
+ kfm.add ("connect", std::make_unique<kf_connect> ());
+ kfm.add ("isatty", std::make_unique<kf_isatty> ());
+ kfm.add ("listen", std::make_unique<kf_listen> ());
+ kfm.add ("pipe", std::make_unique<kf_pipe> (1));
+ kfm.add ("pipe2", std::make_unique<kf_pipe> (2));
+ kfm.add ("read", std::make_unique<kf_read> ());
+ kfm.add ("socket", std::make_unique<kf_socket> ());
}
} // namespace ana
diff --git a/gcc/analyzer/sm-file.cc b/gcc/analyzer/sm-file.cc
index 1e41dc9..d7dbe2f 100644
--- a/gcc/analyzer/sm-file.cc
+++ b/gcc/analyzer/sm-file.cc
@@ -18,26 +18,16 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "diagnostic-event-id.h"
+#include "selftest.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/function-set.h"
#include "analyzer/analyzer-selftests.h"
-#include "selftest.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
@@ -403,9 +393,9 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt,
const gimple *stmt) const
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
{
- if (is_named_call_p (callee_fndecl, "fopen", call, 2))
+ if (is_named_call_p (callee_fndecl, "fopen", *call, 2))
{
tree lhs = gimple_call_lhs (call);
if (lhs)
@@ -417,7 +407,7 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt,
return true;
}
- if (is_named_call_p (callee_fndecl, "fclose", call, 1))
+ if (is_named_call_p (callee_fndecl, "fclose", *call, 1))
{
tree arg = gimple_call_arg (call, 0);
@@ -433,7 +423,8 @@ fileptr_state_machine::on_stmt (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<double_fclose> (*this, diag_arg));
+ std::make_unique<double_fclose> (*this,
+ diag_arg));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
return true;
@@ -503,17 +494,17 @@ fileptr_state_machine::can_purge_p (state_t s) const
std::unique_ptr<pending_diagnostic>
fileptr_state_machine::on_leak (tree var) const
{
- return make_unique<file_leak> (*this, var);
+ return std::make_unique<file_leak> (*this, var);
}
} // anonymous namespace
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_fileptr_state_machine (logger *logger)
{
- return new fileptr_state_machine (logger);
+ return std::make_unique<fileptr_state_machine> (logger);
}
/* Handler for various stdio-related builtins that merely have external
@@ -655,40 +646,40 @@ public:
void
register_known_file_functions (known_function_manager &kfm)
{
- kfm.add (BUILT_IN_FPRINTF, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPRINTF_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPUTC, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPUTC_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPUTS, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FPUTS_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FWRITE, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_FWRITE_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PRINTF, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PRINTF_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTC, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTCHAR, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTCHAR_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTC_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTS, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_PUTS_UNLOCKED, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_VFPRINTF, make_unique<kf_stdio_output_fn> ());
- kfm.add (BUILT_IN_VPRINTF, make_unique<kf_stdio_output_fn> ());
-
- kfm.add ("ferror", make_unique<kf_ferror> ());
- kfm.add ("fgets", make_unique<kf_fgets> ());
- kfm.add ("fgets_unlocked", make_unique<kf_fgets> ()); // non-standard
- kfm.add ("fileno", make_unique<kf_fileno> ());
- kfm.add ("fread", make_unique<kf_fread> ());
- kfm.add ("getc", make_unique<kf_getc> ());
- kfm.add ("getchar", make_unique<kf_getchar> ());
+ kfm.add (BUILT_IN_FPRINTF, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPRINTF_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPUTC, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPUTC_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPUTS, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FPUTS_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FWRITE, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_FWRITE_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PRINTF, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PRINTF_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTC, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTCHAR, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTCHAR_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTC_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTS, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_PUTS_UNLOCKED, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_VFPRINTF, std::make_unique<kf_stdio_output_fn> ());
+ kfm.add (BUILT_IN_VPRINTF, std::make_unique<kf_stdio_output_fn> ());
+
+ kfm.add ("ferror", std::make_unique<kf_ferror> ());
+ kfm.add ("fgets", std::make_unique<kf_fgets> ());
+ kfm.add ("fgets_unlocked", std::make_unique<kf_fgets> ()); // non-standard
+ kfm.add ("fileno", std::make_unique<kf_fileno> ());
+ kfm.add ("fread", std::make_unique<kf_fread> ());
+ kfm.add ("getc", std::make_unique<kf_getc> ());
+ kfm.add ("getchar", std::make_unique<kf_getchar> ());
/* Some C++ implementations use the std:: copies of these functions
from <cstdio> for <stdio.h>, so we must match against these too. */
- kfm.add_std_ns ("ferror", make_unique<kf_ferror> ());
- kfm.add_std_ns ("fgets", make_unique<kf_fgets> ());
- kfm.add_std_ns ("fread", make_unique<kf_fread> ());
- kfm.add_std_ns ("getc", make_unique<kf_getc> ());
- kfm.add_std_ns ("getchar", make_unique<kf_getchar> ());
+ kfm.add_std_ns ("ferror", std::make_unique<kf_ferror> ());
+ kfm.add_std_ns ("fgets", std::make_unique<kf_fgets> ());
+ kfm.add_std_ns ("fread", std::make_unique<kf_fread> ());
+ kfm.add_std_ns ("getc", std::make_unique<kf_getc> ());
+ kfm.add_std_ns ("getchar", std::make_unique<kf_getchar> ());
}
#if CHECKING_P
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 6972a55..0186268 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -18,21 +18,12 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "bitmap.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "diagnostic-event-id.h"
+#include "stringpool.h"
+#include "attribs.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -41,8 +32,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
-#include "stringpool.h"
-#include "attribs.h"
#include "analyzer/function-set.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-event.h"
@@ -482,22 +471,22 @@ private:
tree ptr) const;
void on_allocator_call (sm_context &sm_ctxt,
- const gcall *call,
+ const gcall &call,
const deallocator_set *deallocators,
bool returns_nonnull = false) const;
void handle_free_of_non_heap (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree arg,
const deallocator *d) const;
void on_deallocator_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
const deallocator *d,
unsigned argno) const;
void on_realloc_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void on_zero_assignment (sm_context &sm_ctxt,
const gimple *stmt,
tree lhs) const;
@@ -1955,7 +1944,7 @@ get_or_create_assumed_non_null_state_for_frame (const frame_region *frame)
builtin. */
static bool
-known_allocator_p (const_tree fndecl, const gcall *call)
+known_allocator_p (const_tree fndecl, const gcall &call)
{
/* Either it is a function we know by name and number of arguments... */
if (is_named_call_p (fndecl, "malloc", call, 1)
@@ -2029,9 +2018,10 @@ malloc_state_machine::handle_nonnull (sm_context &sm_ctxt,
if (unchecked_p (state))
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, stmt, arg,
- make_unique<possible_null_arg> (*this, diag_arg, fndecl,
- i));
+ sm_ctxt.warn
+ (node, stmt, arg,
+ std::make_unique<possible_null_arg> (*this, diag_arg, fndecl,
+ i));
const allocation_state *astate
= as_a_allocation_state (state);
sm_ctxt.set_next_state (stmt, arg, astate->get_nonnull ());
@@ -2040,7 +2030,7 @@ malloc_state_machine::handle_nonnull (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<null_arg> (*this, diag_arg, fndecl, i));
+ std::make_unique<null_arg> (*this, diag_arg, fndecl, i));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
else if (state == m_start)
@@ -2054,9 +2044,11 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
const supernode *node,
const gimple *stmt) const
{
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call_stmt))
{
+ const gcall &call = *call_stmt;
+
if (known_allocator_p (callee_fndecl, call))
{
on_allocator_call (sm_ctxt, call, &m_free);
@@ -2092,7 +2084,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
if (is_named_call_p (callee_fndecl, "alloca", call, 1)
|| is_named_call_p (callee_fndecl, "__builtin_alloca", call, 1))
{
- tree lhs = gimple_call_lhs (call);
+ tree lhs = gimple_call_lhs (&call);
if (lhs)
sm_ctxt.on_transition (node, stmt, lhs, m_start, m_non_heap);
return true;
@@ -2260,8 +2252,8 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<possible_null_deref> (*this,
- diag_arg));
+ std::make_unique<possible_null_deref> (*this,
+ diag_arg));
const allocation_state *astate = as_a_allocation_state (state);
sm_ctxt.set_next_state (stmt, arg, astate->get_nonnull ());
}
@@ -2269,7 +2261,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<null_deref> (*this, diag_arg));
+ std::make_unique<null_deref> (*this, diag_arg));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
else if (freed_p (state))
@@ -2277,7 +2269,7 @@ malloc_state_machine::on_stmt (sm_context &sm_ctxt,
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
const allocation_state *astate = as_a_allocation_state (state);
sm_ctxt.warn (node, stmt, arg,
- make_unique<use_after_free>
+ std::make_unique<use_after_free>
(*this, diag_arg, astate->m_deallocator));
sm_ctxt.set_next_state (stmt, arg, m_stop);
}
@@ -2339,7 +2331,7 @@ maybe_complain_about_deref_before_check (sm_context &sm_ctxt,
if (diag_ptr)
sm_ctxt.warn
(node, stmt, ptr,
- make_unique<deref_before_check> (*this, diag_ptr));
+ std::make_unique<deref_before_check> (*this, diag_ptr));
sm_ctxt.set_next_state (stmt, ptr, m_stop);
}
@@ -2349,15 +2341,15 @@ maybe_complain_about_deref_before_check (sm_context &sm_ctxt,
void
malloc_state_machine::on_allocator_call (sm_context &sm_ctxt,
- const gcall *call,
+ const gcall &call,
const deallocator_set *deallocators,
bool returns_nonnull) const
{
- tree lhs = gimple_call_lhs (call);
+ tree lhs = gimple_call_lhs (&call);
if (lhs)
{
- if (sm_ctxt.get_state (call, lhs) == m_start)
- sm_ctxt.set_next_state (call, lhs,
+ if (sm_ctxt.get_state (&call, lhs) == m_start)
+ sm_ctxt.set_next_state (&call, lhs,
(returns_nonnull
? deallocators->m_nonnull
: deallocators->m_unchecked));
@@ -2374,7 +2366,7 @@ malloc_state_machine::on_allocator_call (sm_context &sm_ctxt,
void
malloc_state_machine::handle_free_of_non_heap (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree arg,
const deallocator *d) const
{
@@ -2386,28 +2378,28 @@ malloc_state_machine::handle_free_of_non_heap (sm_context &sm_ctxt,
const svalue *ptr_sval = old_model->get_rvalue (arg, NULL);
freed_reg = old_model->deref_rvalue (ptr_sval, arg, NULL);
}
- sm_ctxt.warn (node, call, arg,
- make_unique<free_of_non_heap>
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<free_of_non_heap>
(*this, diag_arg, freed_reg, d->m_name));
- sm_ctxt.set_next_state (call, arg, m_stop);
+ sm_ctxt.set_next_state (&call, arg, m_stop);
}
void
malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
const deallocator *d,
unsigned argno) const
{
- if (argno >= gimple_call_num_args (call))
+ if (argno >= gimple_call_num_args (&call))
return;
- tree arg = gimple_call_arg (call, argno);
+ tree arg = gimple_call_arg (&call, argno);
- state_t state = sm_ctxt.get_state (call, arg);
+ state_t state = sm_ctxt.get_state (&call, arg);
/* start/assumed_non_null/unchecked/nonnull -> freed. */
if (state == m_start || assumed_non_null_p (state))
- sm_ctxt.set_next_state (call, arg, d->m_freed);
+ sm_ctxt.set_next_state (&call, arg, d->m_freed);
else if (unchecked_p (state) || nonnull_p (state))
{
const allocation_state *astate = as_a_allocation_state (state);
@@ -2416,13 +2408,13 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt,
{
/* Wrong allocator. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, call, arg,
- make_unique<mismatching_deallocation>
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<mismatching_deallocation>
(*this, diag_arg,
astate->m_deallocators,
d));
}
- sm_ctxt.set_next_state (call, arg, d->m_freed);
+ sm_ctxt.set_next_state (&call, arg, d->m_freed);
}
/* Keep state "null" as-is, rather than transitioning to "freed";
@@ -2431,9 +2423,9 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt,
{
/* freed -> stop, with warning. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, call, arg,
- make_unique<double_free> (*this, diag_arg, d->m_name));
- sm_ctxt.set_next_state (call, arg, m_stop);
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<double_free> (*this, diag_arg, d->m_name));
+ sm_ctxt.set_next_state (&call, arg, m_stop);
}
else if (state == m_non_heap)
{
@@ -2453,14 +2445,14 @@ malloc_state_machine::on_deallocator_call (sm_context &sm_ctxt,
void
malloc_state_machine::on_realloc_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const
+ const gcall &call) const
{
const unsigned argno = 0;
const deallocator *d = &m_realloc;
- tree arg = gimple_call_arg (call, argno);
+ tree arg = gimple_call_arg (&call, argno);
- state_t state = sm_ctxt.get_state (call, arg);
+ state_t state = sm_ctxt.get_state (&call, arg);
if (unchecked_p (state) || nonnull_p (state))
{
@@ -2470,11 +2462,11 @@ malloc_state_machine::on_realloc_call (sm_context &sm_ctxt,
{
/* Wrong allocator. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, call, arg,
- make_unique<mismatching_deallocation>
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<mismatching_deallocation>
(*this, diag_arg,
astate->m_deallocators, d));
- sm_ctxt.set_next_state (call, arg, m_stop);
+ sm_ctxt.set_next_state (&call, arg, m_stop);
if (path_context *path_ctxt = sm_ctxt.get_path_context ())
path_ctxt->terminate_path ();
}
@@ -2483,9 +2475,9 @@ malloc_state_machine::on_realloc_call (sm_context &sm_ctxt,
{
/* freed -> stop, with warning. */
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
- sm_ctxt.warn (node, call, arg,
- make_unique<double_free> (*this, diag_arg, "free"));
- sm_ctxt.set_next_state (call, arg, m_stop);
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<double_free> (*this, diag_arg, "free"));
+ sm_ctxt.set_next_state (&call, arg, m_stop);
if (path_context *path_ctxt = sm_ctxt.get_path_context ())
path_ctxt->terminate_path ();
}
@@ -2594,7 +2586,7 @@ malloc_state_machine::can_purge_p (state_t s) const
std::unique_ptr<pending_diagnostic>
malloc_state_machine::on_leak (tree var) const
{
- return make_unique<malloc_leak> (*this, var);
+ return std::make_unique<malloc_leak> (*this, var);
}
/* Implementation of state_machine::reset_when_passed_to_unknown_fn_p vfunc
@@ -2707,10 +2699,10 @@ malloc_state_machine::transition_ptr_sval_non_null (region_model *model,
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_malloc_state_machine (logger *logger)
{
- return new malloc_state_machine (logger);
+ return std::make_unique<malloc_state_machine> (logger);
}
/* Specialcase hook for handling realloc, for use by
diff --git a/gcc/analyzer/sm-pattern-test.cc b/gcc/analyzer/sm-pattern-test.cc
index 5b98067..f05ffe0 100644
--- a/gcc/analyzer/sm-pattern-test.cc
+++ b/gcc/analyzer/sm-pattern-test.cc
@@ -20,19 +20,11 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
+#include "analyzer/common.h"
+
#include "tree-pretty-print.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
#include "diagnostic-event-id.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -140,7 +132,7 @@ pattern_test_state_machine::on_condition (sm_context &sm_ctxt,
if (tree lhs_expr = sm_ctxt.get_diagnostic_tree (lhs))
{
sm_ctxt.warn (node, stmt, lhs_expr,
- make_unique<pattern_match> (lhs_expr, op, rhs_cst));
+ std::make_unique<pattern_match> (lhs_expr, op, rhs_cst));
}
}
@@ -154,10 +146,10 @@ pattern_test_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_pattern_test_state_machine (logger *logger)
{
- return new pattern_test_state_machine (logger);
+ return std::make_unique<pattern_test_state_machine> (logger);
}
} // namespace ana
diff --git a/gcc/analyzer/sm-sensitive.cc b/gcc/analyzer/sm-sensitive.cc
index 6e185cb..7bd5ef6 100644
--- a/gcc/analyzer/sm-sensitive.cc
+++ b/gcc/analyzer/sm-sensitive.cc
@@ -19,19 +19,10 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "diagnostic-event-id.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -196,8 +187,8 @@ sensitive_state_machine::warn_for_any_exposure (sm_context &sm_ctxt,
{
tree diag_arg = sm_ctxt.get_diagnostic_tree (arg);
sm_ctxt.warn (node, stmt, arg,
- make_unique<exposure_through_output_file> (*this,
- diag_arg));
+ std::make_unique<exposure_through_output_file> (*this,
+ diag_arg));
}
}
@@ -210,9 +201,9 @@ sensitive_state_machine::on_stmt (sm_context &sm_ctxt,
const gimple *stmt) const
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
{
- if (is_named_call_p (callee_fndecl, "getpass", call, 1))
+ if (is_named_call_p (callee_fndecl, "getpass", *call, 1))
{
tree lhs = gimple_call_lhs (call);
if (lhs)
@@ -230,7 +221,7 @@ sensitive_state_machine::on_stmt (sm_context &sm_ctxt,
}
return true;
}
- else if (is_named_call_p (callee_fndecl, "fwrite", call, 4))
+ else if (is_named_call_p (callee_fndecl, "fwrite", *call, 4))
{
tree arg = gimple_call_arg (call, 0);
warn_for_any_exposure (sm_ctxt, node, stmt, arg);
@@ -251,10 +242,10 @@ sensitive_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_sensitive_state_machine (logger *logger)
{
- return new sensitive_state_machine (logger);
+ return std::make_unique<sensitive_state_machine> (logger);
}
} // namespace ana
diff --git a/gcc/analyzer/sm-signal.cc b/gcc/analyzer/sm-signal.cc
index f8b378f..83f2808 100644
--- a/gcc/analyzer/sm-signal.cc
+++ b/gcc/analyzer/sm-signal.cc
@@ -20,39 +20,28 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "bitmap.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "diagnostic-event-id.h"
-#include "analyzer/analyzer-logging.h"
-#include "analyzer/sm.h"
-#include "analyzer/pending-diagnostic.h"
#include "sbitmap.h"
#include "ordered-hash-map.h"
#include "selftest.h"
+#include "cfg.h"
+#include "gimple-iterator.h"
+#include "cgraph.h"
+#include "shortest-paths.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/sm.h"
+#include "analyzer/pending-diagnostic.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/program-state.h"
#include "analyzer/checker-path.h"
-#include "cfg.h"
-#include "gimple-iterator.h"
-#include "cgraph.h"
#include "analyzer/supergraph.h"
#include "analyzer/diagnostic-manager.h"
-#include "shortest-paths.h"
#include "analyzer/exploded-graph.h"
#include "analyzer/function-set.h"
#include "analyzer/analyzer-selftests.h"
@@ -95,7 +84,7 @@ class signal_unsafe_call
: public pending_diagnostic_subclass<signal_unsafe_call>
{
public:
- signal_unsafe_call (const signal_state_machine &sm, const gcall *unsafe_call,
+ signal_unsafe_call (const signal_state_machine &sm, const gcall &unsafe_call,
tree unsafe_fndecl)
: m_sm (sm), m_unsafe_call (unsafe_call), m_unsafe_fndecl (unsafe_fndecl)
{
@@ -106,7 +95,7 @@ public:
bool operator== (const signal_unsafe_call &other) const
{
- return m_unsafe_call == other.m_unsafe_call;
+ return &m_unsafe_call == &other.m_unsafe_call;
}
int get_controlling_option () const final override
@@ -126,7 +115,7 @@ public:
suggesting the replacement. */
if (const char *replacement = get_replacement_fn ())
{
- location_t note_loc = gimple_location (m_unsafe_call);
+ location_t note_loc = gimple_location (&m_unsafe_call);
/* It would be nice to add a fixit, but the gimple call
location covers the whole call expression. It isn't
currently possible to cut this down to just the call
@@ -170,7 +159,7 @@ public:
private:
const signal_state_machine &m_sm;
- const gcall *m_unsafe_call;
+ const gcall &m_unsafe_call;
tree m_unsafe_fndecl;
/* Returns a replacement function as text if it exists. Currently
@@ -207,7 +196,7 @@ update_model_for_signal_handler (region_model *model,
gcc_assert (model);
/* Purge all state within MODEL. */
*model = region_model (model->get_manager ());
- model->push_frame (handler_fun, NULL, NULL);
+ model->push_frame (handler_fun, nullptr, nullptr, nullptr);
}
/* Custom exploded_edge info: entry into a signal-handler. */
@@ -236,10 +225,10 @@ public:
const final override
{
emission_path->add_event
- (make_unique<precanned_custom_event>
- (event_loc_info (UNKNOWN_LOCATION, NULL_TREE, 0),
- "later on,"
- " when the signal is delivered to the process"));
+ (std::make_unique<precanned_custom_event>
+ (event_loc_info (UNKNOWN_LOCATION, NULL_TREE, 0),
+ "later on,"
+ " when the signal is delivered to the process"));
}
};
@@ -282,7 +271,7 @@ public:
if (dst_enode)
eg->add_edge (src_enode, dst_enode, NULL, /*state_change (),*/
true, /* assume does work */
- make_unique<signal_delivery_edge_info_t> ());
+ std::make_unique<signal_delivery_edge_info_t> ());
}
const signal_state_machine &m_sm;
@@ -342,9 +331,9 @@ signal_state_machine::on_stmt (sm_context &sm_ctxt,
if (global_state == m_start)
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
- if (is_named_call_p (callee_fndecl, "signal", call, 2)
- || is_std_named_call_p (callee_fndecl, "signal", call, 2))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
+ if (is_named_call_p (callee_fndecl, "signal", *call, 2)
+ || is_std_named_call_p (callee_fndecl, "signal", *call, 2))
{
tree handler = gimple_call_arg (call, 1);
if (TREE_CODE (handler) == ADDR_EXPR
@@ -359,12 +348,12 @@ signal_state_machine::on_stmt (sm_context &sm_ctxt,
else if (global_state == m_in_signal_handler)
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
if (signal_unsafe_p (callee_fndecl))
if (sm_ctxt.get_global_state () == m_in_signal_handler)
sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<signal_unsafe_call>
- (*this, call, callee_fndecl));
+ std::make_unique<signal_unsafe_call>
+ (*this, *call, callee_fndecl));
}
return false;
@@ -380,10 +369,10 @@ signal_state_machine::can_purge_p (state_t s ATTRIBUTE_UNUSED) const
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_signal_state_machine (logger *logger)
{
- return new signal_state_machine (logger);
+ return std::make_unique<signal_state_machine> (logger);
}
#if CHECKING_P
diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
index 5d0aec3..e782081 100644
--- a/gcc/analyzer/sm-taint.cc
+++ b/gcc/analyzer/sm-taint.cc
@@ -20,20 +20,8 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "gimple-iterator.h"
#include "ordered-hash-map.h"
#include "cgraph.h"
@@ -42,6 +30,10 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "fold-const.h"
+#include "diagnostic-format-sarif.h"
+#include "gcc-urlifier.h"
+
+#include "analyzer/analyzer-logging.h"
#include "analyzer/supergraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
@@ -51,8 +43,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/program-state.h"
#include "analyzer/pending-diagnostic.h"
#include "analyzer/constraint-manager.h"
-#include "diagnostic-format-sarif.h"
-#include "gcc-urlifier.h"
#if ENABLE_ANALYZER
@@ -140,7 +130,7 @@ private:
void check_for_tainted_size_arg (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree callee_fndecl) const;
void check_for_tainted_divisor (sm_context &sm_ctxt,
const supernode *node,
@@ -1099,9 +1089,9 @@ taint_state_machine::on_stmt (sm_context &sm_ctxt,
const gimple *stmt) const
{
if (const gcall *call = dyn_cast <const gcall *> (stmt))
- if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
+ if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (*call))
{
- if (is_named_call_p (callee_fndecl, "fread", call, 4))
+ if (is_named_call_p (callee_fndecl, "fread", *call, 4))
{
tree arg = gimple_call_arg (call, 0);
@@ -1117,14 +1107,14 @@ taint_state_machine::on_stmt (sm_context &sm_ctxt,
/* External function with "access" attribute. */
if (sm_ctxt.unknown_side_effects_p ())
- check_for_tainted_size_arg (sm_ctxt, node, call, callee_fndecl);
+ check_for_tainted_size_arg (sm_ctxt, node, *call, callee_fndecl);
if (is_assertion_failure_handler_p (callee_fndecl)
&& sm_ctxt.get_global_state () == m_tainted_control_flow)
{
sm_ctxt.warn (node, call, NULL_TREE,
- make_unique<tainted_assertion> (*this, NULL_TREE,
- callee_fndecl));
+ std::make_unique<tainted_assertion> (*this, NULL_TREE,
+ callee_fndecl));
}
}
// TODO: ...etc; many other sources of untrusted data
@@ -1433,7 +1423,7 @@ taint_state_machine::combine_states (state_t s0, state_t s1) const
void
taint_state_machine::check_for_tainted_size_arg (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree callee_fndecl) const
{
tree fntype = TREE_TYPE (callee_fndecl);
@@ -1464,17 +1454,17 @@ taint_state_machine::check_for_tainted_size_arg (sm_context &sm_ctxt,
if (access->sizarg == UINT_MAX)
continue;
- tree size_arg = gimple_call_arg (call, access->sizarg);
+ tree size_arg = gimple_call_arg (&call, access->sizarg);
- state_t state = sm_ctxt.get_state (call, size_arg);
+ state_t state = sm_ctxt.get_state (&call, size_arg);
enum bounds b;
if (get_taint (state, TREE_TYPE (size_arg), &b))
{
const char* const access_str =
TREE_STRING_POINTER (access->to_external_string ());
tree diag_size = sm_ctxt.get_diagnostic_tree (size_arg);
- sm_ctxt.warn (node, call, size_arg,
- make_unique<tainted_access_attrib_size>
+ sm_ctxt.warn (node, &call, size_arg,
+ std::make_unique<tainted_access_attrib_size>
(*this, diag_size, b,
callee_fndecl,
access->sizarg,
@@ -1518,8 +1508,9 @@ taint_state_machine::check_for_tainted_divisor (sm_context &sm_ctxt,
return;
tree diag_divisor = sm_ctxt.get_diagnostic_tree (divisor_expr);
- sm_ctxt.warn (node, assign, divisor_expr,
- make_unique <tainted_divisor> (*this, diag_divisor, b));
+ sm_ctxt.warn
+ (node, assign, divisor_expr,
+ std::make_unique <tainted_divisor> (*this, diag_divisor, b));
sm_ctxt.set_next_state (assign, divisor_sval, m_stop);
}
}
@@ -1528,10 +1519,10 @@ taint_state_machine::check_for_tainted_divisor (sm_context &sm_ctxt,
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_taint_state_machine (logger *logger)
{
- return new taint_state_machine (logger);
+ return std::make_unique<taint_state_machine> (logger);
}
/* A closed concrete range. */
@@ -1682,8 +1673,8 @@ region_model::check_region_for_taint (const region *reg,
if (index_can_be_out_of_bounds_p (element_reg))
{
tree arg = get_representative_tree (index);
- ctxt->warn (make_unique<tainted_array_index> (taint_sm,
- arg, b));
+ ctxt->warn (std::make_unique<tainted_array_index> (taint_sm,
+ arg, b));
}
else if (ctxt->get_logger ())
ctxt->get_logger ()->log ("rejecting tainted_array_index as"
@@ -1709,8 +1700,8 @@ region_model::check_region_for_taint (const region *reg,
if (taint_sm.get_taint (state, effective_type, &b))
{
tree arg = get_representative_tree (offset);
- ctxt->warn (make_unique<tainted_offset> (taint_sm, arg, b,
- offset));
+ ctxt->warn (std::make_unique<tainted_offset> (taint_sm, arg, b,
+ offset));
}
}
break;
@@ -1727,7 +1718,7 @@ region_model::check_region_for_taint (const region *reg,
if (taint_sm.get_taint (state, size_sval->get_type (), &b))
{
tree arg = get_representative_tree (size_sval);
- ctxt->warn (make_unique<tainted_size> (taint_sm, arg, b));
+ ctxt->warn (std::make_unique<tainted_size> (taint_sm, arg, b));
}
}
break;
@@ -1773,7 +1764,7 @@ region_model::check_dynamic_size_for_taint (enum memory_space mem_space,
if (taint_sm.get_taint (state, size_in_bytes->get_type (), &b))
{
tree arg = get_representative_tree (size_in_bytes);
- ctxt->warn (make_unique<tainted_allocation_size>
+ ctxt->warn (std::make_unique<tainted_allocation_size>
(taint_sm, arg, size_in_bytes, b, mem_space));
}
}
diff --git a/gcc/analyzer/sm.cc b/gcc/analyzer/sm.cc
index 3e7fa66..0abbdd6 100644
--- a/gcc/analyzer/sm.cc
+++ b/gcc/analyzer/sm.cc
@@ -18,21 +18,11 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "options.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "pretty-print.h"
-#include "diagnostic.h"
+#define INCLUDE_LIST
+#include "analyzer/common.h"
+
#include "tree-diagnostic.h"
-#include "analyzer/analyzer.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/call-string.h"
@@ -41,7 +31,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/svalue.h"
#include "analyzer/program-state.h"
#include "analyzer/pending-diagnostic.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -83,7 +72,7 @@ state_machine::state::to_json () const
pretty_printer pp;
pp_format_decoder (&pp) = default_tree_printer;
dump_to_pp (&pp);
- return ::make_unique<json::string> (pp_formatted_text (&pp));
+ return std::make_unique<json::string> (pp_formatted_text (&pp));
}
/* class state_machine. */
@@ -154,11 +143,11 @@ state_machine::dump_to_pp (pretty_printer *pp) const
std::unique_ptr<json::object>
state_machine::to_json () const
{
- auto sm_obj = ::make_unique<json::object> ();
+ auto sm_obj = std::make_unique<json::object> ();
sm_obj->set_string ("name", m_name);
{
- auto states_arr = ::make_unique<json::array> ();
+ auto states_arr = std::make_unique<json::array> ();
unsigned i;
state *s;
FOR_EACH_VEC_ELT (m_states, i, s)
@@ -181,35 +170,40 @@ sm_context::get_old_region_model () const
}
/* Create instances of the various state machines, each using LOGGER,
- and populate OUT with them. */
+ returning a vector of them. */
-void
-make_checkers (auto_delete_vec <state_machine> &out, logger *logger)
+std::vector<std::unique_ptr<state_machine>>
+make_checkers (logger *logger)
{
- out.safe_push (make_malloc_state_machine (logger));
- out.safe_push (make_fileptr_state_machine (logger));
- out.safe_push (make_fd_state_machine (logger));
- out.safe_push (make_taint_state_machine (logger));
- out.safe_push (make_sensitive_state_machine (logger));
- out.safe_push (make_signal_state_machine (logger));
- out.safe_push (make_va_list_state_machine (logger));
+ /* Start with a list so that we can filter it. */
+ std::list<std::unique_ptr<state_machine>> out;
+ out.push_back (make_malloc_state_machine (logger));
+ out.push_back (make_fileptr_state_machine (logger));
+ out.push_back (make_fd_state_machine (logger));
+ out.push_back (make_taint_state_machine (logger));
+ out.push_back (make_sensitive_state_machine (logger));
+ out.push_back (make_signal_state_machine (logger));
+ out.push_back (make_va_list_state_machine (logger));
/* We only attempt to run the pattern tests if it might have been manually
enabled (for DejaGnu purposes). */
if (flag_analyzer_checker)
- out.safe_push (make_pattern_test_state_machine (logger));
+ out.push_back (make_pattern_test_state_machine (logger));
if (flag_analyzer_checker)
{
- unsigned read_index, write_index;
- state_machine **sm;
-
- /* TODO: this leaks the machines
- Would be nice to log the things that were removed. */
- VEC_ORDERED_REMOVE_IF (out, read_index, write_index, sm,
- 0 != strcmp (flag_analyzer_checker,
- (*sm)->get_name ()));
+ out.remove_if ([] (auto &sm)
+ {
+ return 0 != strcmp (flag_analyzer_checker,
+ sm->get_name ());
+ });
}
+
+ std::vector<std::unique_ptr<state_machine>> out_vec;
+ for (auto &iter: out)
+ out_vec.push_back (std::move (iter));
+
+ return out_vec;
}
} // namespace ana
diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h
index a1f96e2..a932765 100644
--- a/gcc/analyzer/sm.h
+++ b/gcc/analyzer/sm.h
@@ -235,7 +235,7 @@ public:
Use in preference to gimple_call_fndecl (and gimple_call_addr_fndecl),
since it can look through function pointer assignments and
other callback handling. */
- virtual tree get_fndecl_for_call (const gcall *call) = 0;
+ virtual tree get_fndecl_for_call (const gcall &call) = 0;
/* Get the old state of VAR at STMT. */
virtual state_machine::state_t get_state (const gimple *stmt,
@@ -341,17 +341,17 @@ protected:
/* The various state_machine subclasses are hidden in their respective
implementation files. */
-extern void make_checkers (auto_delete_vec <state_machine> &out,
- logger *logger);
-
-extern state_machine *make_malloc_state_machine (logger *logger);
-extern state_machine *make_fileptr_state_machine (logger *logger);
-extern state_machine *make_taint_state_machine (logger *logger);
-extern state_machine *make_sensitive_state_machine (logger *logger);
-extern state_machine *make_signal_state_machine (logger *logger);
-extern state_machine *make_pattern_test_state_machine (logger *logger);
-extern state_machine *make_va_list_state_machine (logger *logger);
-extern state_machine *make_fd_state_machine (logger *logger);
+extern std::vector<std::unique_ptr<state_machine>>
+make_checkers (logger *logger);
+
+extern std::unique_ptr<state_machine> make_malloc_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_fileptr_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_taint_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_sensitive_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_signal_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_pattern_test_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_va_list_state_machine (logger *);
+extern std::unique_ptr<state_machine> make_fd_state_machine (logger *);
} // namespace ana
diff --git a/gcc/analyzer/state-purge.cc b/gcc/analyzer/state-purge.cc
index b7a5260..7a93cee 100644
--- a/gcc/analyzer/state-purge.cc
+++ b/gcc/analyzer/state-purge.cc
@@ -18,26 +18,21 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
+#include "analyzer/common.h"
+
#include "timevar.h"
-#include "tree-ssa-alias.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "stringpool.h"
+#include "gimple-pretty-print.h"
#include "tree-vrp.h"
#include "gimple-ssa.h"
+#include "stringpool.h"
#include "tree-ssanames.h"
#include "tree-phinodes.h"
#include "options.h"
#include "ssa-iterators.h"
-#include "diagnostic-core.h"
-#include "gimple-pretty-print.h"
-#include "analyzer/analyzer.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
+#include "cgraph.h"
+
#include "analyzer/call-string.h"
#include "analyzer/supergraph.h"
#include "analyzer/program-point.h"
@@ -45,8 +40,6 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/state-purge.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
-#include "gimple-walk.h"
-#include "cgraph.h"
#if ENABLE_ANALYZER
@@ -737,7 +730,7 @@ state_purge_per_decl::process_worklists (const state_purge_map &map,
worklist.safe_push (iter);
region_model model (mgr);
- model.push_frame (get_function (), NULL, NULL);
+ model.push_frame (get_function (), nullptr, nullptr, nullptr);
/* Process worklist by walking backwards until we reach a stmt
that fully overwrites the decl. */
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index ab469dd..e6723c7 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -18,44 +18,23 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
-#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "diagnostic-color.h"
-#include "bitmap.h"
-#include "selftest.h"
-#include "analyzer/analyzer.h"
-#include "analyzer/analyzer-logging.h"
+#include "analyzer/common.h"
+
#include "ordered-hash-map.h"
-#include "options.h"
#include "cfg.h"
-#include "analyzer/supergraph.h"
#include "sbitmap.h"
+#include "stor-layout.h"
+
+#include "text-art/tree-widget.h"
+
+#include "analyzer/analyzer-logging.h"
+#include "analyzer/supergraph.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/region-model.h"
#include "analyzer/call-summary.h"
#include "analyzer/analyzer-selftests.h"
-#include "stor-layout.h"
-#include "text-art/tree-widget.h"
-#include "make-unique.h"
#if ENABLE_ANALYZER
@@ -234,7 +213,7 @@ bit_range::dump () const
std::unique_ptr<json::object>
bit_range::to_json () const
{
- auto obj = ::make_unique<json::object> ();
+ auto obj = std::make_unique<json::object> ();
obj->set ("start_bit_offset",
bit_offset_to_json (m_start_bit_offset));
obj->set ("size_in_bits",
@@ -508,7 +487,7 @@ byte_range::dump () const
std::unique_ptr<json::object>
byte_range::to_json () const
{
- auto obj = ::make_unique<json::object> ();
+ auto obj = std::make_unique<json::object> ();
obj->set ("start_byte_offset",
byte_offset_to_json (m_start_byte_offset));
obj->set ("size_in_bytes",
@@ -773,7 +752,7 @@ binding_map::dump (bool simple) const
std::unique_ptr<json::object>
binding_map::to_json () const
{
- auto map_obj = ::make_unique<json::object> ();
+ auto map_obj = std::make_unique<json::object> ();
auto_vec <const binding_key *> binding_keys;
for (map_t::iterator iter = m_map.begin ();
@@ -1455,7 +1434,7 @@ binding_cluster::validate () const
std::unique_ptr<json::object>
binding_cluster::to_json () const
{
- auto cluster_obj = ::make_unique<json::object> ();
+ auto cluster_obj = std::make_unique<json::object> ();
cluster_obj->set_bool ("escaped", m_escaped);
cluster_obj->set_bool ("touched", m_touched);
@@ -2208,7 +2187,7 @@ binding_cluster::mark_as_escaped ()
Use P to purge state involving conjured_svalues. */
void
-binding_cluster::on_unknown_fncall (const gcall *call,
+binding_cluster::on_unknown_fncall (const gcall &call,
store_manager *mgr,
const conjured_purge &p)
{
@@ -2221,7 +2200,7 @@ binding_cluster::on_unknown_fncall (const gcall *call,
/* Bind it to a new "conjured" value using CALL. */
const svalue *sval
= mgr->get_svalue_manager ()->get_or_create_conjured_svalue
- (m_base_region->get_type (), call, m_base_region, p);
+ (m_base_region->get_type (), &call, m_base_region, p);
bind (mgr, m_base_region, sval);
}
@@ -2672,7 +2651,7 @@ store::validate () const
std::unique_ptr<json::object>
store::to_json () const
{
- auto store_obj = ::make_unique<json::object> ();
+ auto store_obj = std::make_unique<json::object> ();
/* Sort into some deterministic order. */
auto_vec<const region *> base_regions;
@@ -2695,7 +2674,7 @@ store::to_json () const
{
gcc_assert (parent_reg);
- auto clusters_in_parent_reg_obj = ::make_unique<json::object> ();
+ auto clusters_in_parent_reg_obj = std::make_unique<json::object> ();
const region *base_reg;
unsigned j;
@@ -3259,7 +3238,7 @@ store::mark_as_escaped (const region *base_reg)
(either in this fncall, or in a prior one). */
void
-store::on_unknown_fncall (const gcall *call, store_manager *mgr,
+store::on_unknown_fncall (const gcall &call, store_manager *mgr,
const conjured_purge &p)
{
m_called_unknown_fn = true;
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index 6c84812..171324c 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -666,7 +666,7 @@ public:
store_manager *mgr);
void mark_as_escaped ();
- void on_unknown_fncall (const gcall *call, store_manager *mgr,
+ void on_unknown_fncall (const gcall &call, store_manager *mgr,
const conjured_purge &p);
void on_asm (const gasm *stmt, store_manager *mgr,
const conjured_purge &p);
@@ -800,7 +800,7 @@ public:
model_merger *merger);
void mark_as_escaped (const region *base_reg);
- void on_unknown_fncall (const gcall *call, store_manager *mgr,
+ void on_unknown_fncall (const gcall &call, store_manager *mgr,
const conjured_purge &p);
bool escaped_p (const region *reg) const;
diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
index f35adf0..de2c330 100644
--- a/gcc/analyzer/supergraph.cc
+++ b/gcc/analyzer/supergraph.cc
@@ -18,42 +18,23 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "tm.h"
-#include "toplev.h"
-#include "hash-table.h"
-#include "vec.h"
-#include "ggc.h"
-#include "basic-block.h"
-#include "function.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "gimple-fold.h"
-#include "tree-eh.h"
-#include "gimple-expr.h"
-#include "is-a.h"
+#include "analyzer/common.h"
+
#include "timevar.h"
#include "gimple-pretty-print.h"
-#include "tree-pretty-print.h"
-#include "graphviz.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "bitmap.h"
-#include "cfganal.h"
-#include "function.h"
-#include "analyzer/analyzer.h"
#include "ordered-hash-map.h"
#include "options.h"
#include "cgraph.h"
#include "cfg.h"
#include "digraph.h"
#include "tree-cfg.h"
+#include "tree-dfa.h"
+#include "cfganal.h"
+#include "except.h"
+
#include "analyzer/supergraph.h"
#include "analyzer/analyzer-logging.h"
-#include "make-unique.h"
+#include "analyzer/region-model.h"
#if ENABLE_ANALYZER
@@ -465,11 +446,11 @@ supergraph::dump_dot (const char *path, const dump_args_t &dump_args) const
std::unique_ptr<json::object>
supergraph::to_json () const
{
- auto sgraph_obj = ::make_unique<json::object> ();
+ auto sgraph_obj = std::make_unique<json::object> ();
/* Nodes. */
{
- auto nodes_arr = ::make_unique<json::array> ();
+ auto nodes_arr = std::make_unique<json::array> ();
unsigned i;
supernode *n;
FOR_EACH_VEC_ELT (m_nodes, i, n)
@@ -479,7 +460,7 @@ supergraph::to_json () const
/* Edges. */
{
- auto edges_arr = ::make_unique<json::array> ();
+ auto edges_arr = std::make_unique<json::array> ();
unsigned i;
superedge *n;
FOR_EACH_VEC_ELT (m_edges, i, n)
@@ -511,21 +492,25 @@ supergraph::add_node (function *fun, basic_block bb, gcall *returning_call,
/* Create a new cfg_superedge from SRC to DEST for the underlying CFG edge E,
adding it to this supergraph.
- If the edge is for a switch statement, create a switch_cfg_superedge
- subclass. */
+ If the edge is for a switch or eh_dispatch statement, create a
+ switch_cfg_superedge or eh_dispatch_cfg_superedge subclass,
+ respectively */
cfg_superedge *
supergraph::add_cfg_edge (supernode *src, supernode *dest, ::edge e)
{
- /* Special-case switch edges. */
+ /* Special-case switch and eh_dispatch edges. */
gimple *stmt = src->get_last_stmt ();
- cfg_superedge *new_edge;
+ std::unique_ptr<cfg_superedge> new_edge;
if (stmt && stmt->code == GIMPLE_SWITCH)
- new_edge = new switch_cfg_superedge (src, dest, e);
+ new_edge = std::make_unique<switch_cfg_superedge> (src, dest, e);
+ else if (stmt && stmt->code == GIMPLE_EH_DISPATCH)
+ new_edge = eh_dispatch_cfg_superedge::make (src, dest, e,
+ as_a <geh_dispatch *> (stmt));
else
- new_edge = new cfg_superedge (src, dest, e);
- add_edge (new_edge);
- return new_edge;
+ new_edge = std::make_unique<cfg_superedge> (src, dest, e);
+ add_edge (new_edge.get ());
+ return new_edge.release ();
}
/* Create and add a call_superedge representing an interprocedural call
@@ -720,7 +705,7 @@ supernode::dump_dot_id (pretty_printer *pp) const
std::unique_ptr<json::object>
supernode::to_json () const
{
- auto snode_obj = ::make_unique<json::object> ();
+ auto snode_obj = std::make_unique<json::object> ();
snode_obj->set_integer ("idx", m_index);
snode_obj->set_integer ("bb_idx", m_bb->index);
@@ -737,7 +722,7 @@ supernode::to_json () const
/* Phi nodes. */
{
- auto phi_arr = ::make_unique<json::array> ();
+ auto phi_arr = std::make_unique<json::array> ();
for (gphi_iterator gpi = const_cast<supernode *> (this)->start_phis ();
!gsi_end_p (gpi); gsi_next (&gpi))
{
@@ -752,7 +737,7 @@ supernode::to_json () const
/* Statements. */
{
- auto stmt_arr = ::make_unique<json::array> ();
+ auto stmt_arr = std::make_unique<json::array> ();
int i;
gimple *stmt;
FOR_EACH_VEC_ELT (m_stmts, i, stmt)
@@ -983,7 +968,7 @@ superedge::dump_dot (graphviz_out *gv, const dump_args_t &) const
std::unique_ptr<json::object>
superedge::to_json () const
{
- auto sedge_obj = ::make_unique<json::object> ();
+ auto sedge_obj = std::make_unique<json::object> ();
sedge_obj->set_string ("kind", edge_kind_to_string (m_kind));
sedge_obj->set_integer ("src_idx", m_src->m_index);
sedge_obj->set_integer ("dst_idx", m_dest->m_index);
@@ -1030,6 +1015,7 @@ label_text
superedge::get_description (bool user_facing) const
{
pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
dump_label_to_pp (&pp, user_facing);
return label_text::take (xstrdup (pp_formatted_text (&pp)));
}
@@ -1099,6 +1085,8 @@ cfg_superedge::get_phi_arg (const gphi *phi) const
return gimple_phi_arg_def (phi, index);
}
+/* class switch_cfg_superedge : public cfg_superedge. */
+
switch_cfg_superedge::switch_cfg_superedge (supernode *src,
supernode *dst,
::edge e)
@@ -1206,6 +1194,203 @@ switch_cfg_superedge::implicitly_created_default_p () const
return EXPR_LOCATION (case_label) == UNKNOWN_LOCATION;
}
+/* class eh_dispatch_cfg_superedge : public cfg_superedge. */
+
+/* Given an ERT_TRY region, get the eh_catch corresponding to
+ the label of DST_SNODE, if any. */
+
+static eh_catch
+get_catch (eh_region eh_reg, supernode *dst_snode)
+{
+ gcc_assert (eh_reg->type == ERT_TRY);
+
+ tree dst_snode_label = dst_snode->get_label ();
+ if (!dst_snode_label)
+ return nullptr;
+
+ for (eh_catch iter = eh_reg->u.eh_try.first_catch;
+ iter;
+ iter = iter->next_catch)
+ if (iter->label == dst_snode_label)
+ return iter;
+
+ return nullptr;
+}
+
+std::unique_ptr<eh_dispatch_cfg_superedge>
+eh_dispatch_cfg_superedge::make (supernode *src_snode,
+ supernode *dst_snode,
+ ::edge e,
+ const geh_dispatch *eh_dispatch_stmt)
+{
+ const eh_status *eh = src_snode->get_function ()->eh;
+ gcc_assert (eh);
+ int region_idx = gimple_eh_dispatch_region (eh_dispatch_stmt);
+ gcc_assert (region_idx > 0);
+ gcc_assert ((*eh->region_array)[region_idx]);
+ eh_region eh_reg = (*eh->region_array)[region_idx];
+ gcc_assert (eh_reg);
+ switch (eh_reg->type)
+ {
+ default:
+ gcc_unreachable ();
+ case ERT_CLEANUP:
+ // TODO
+ gcc_unreachable ();
+ break;
+ case ERT_TRY:
+ {
+ eh_catch ehc = get_catch (eh_reg, dst_snode);
+ return std::make_unique<eh_dispatch_try_cfg_superedge>
+ (src_snode, dst_snode,
+ e, eh_dispatch_stmt,
+ eh_reg, ehc);
+ }
+ break;
+ case ERT_ALLOWED_EXCEPTIONS:
+ return std::make_unique<eh_dispatch_allowed_cfg_superedge>
+ (src_snode, dst_snode,
+ e, eh_dispatch_stmt,
+ eh_reg);
+ break;
+ case ERT_MUST_NOT_THROW:
+ // TODO
+ gcc_unreachable ();
+ break;
+ }
+}
+
+eh_dispatch_cfg_superedge::
+eh_dispatch_cfg_superedge (supernode *src,
+ supernode *dst,
+ ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg)
+: cfg_superedge (src, dst, e),
+ m_eh_dispatch_stmt (eh_dispatch_stmt),
+ m_eh_region (eh_reg)
+{
+ gcc_assert (m_eh_region);
+}
+
+const eh_status &
+eh_dispatch_cfg_superedge::get_eh_status () const
+{
+ const eh_status *eh = m_src->get_function ()->eh;
+ gcc_assert (eh);
+ return *eh;
+}
+
+// class eh_dispatch_try_cfg_superedge : public eh_dispatch_cfg_superedge
+
+/* Implementation of superedge::dump_label_to_pp for CFG superedges for
+ "eh_dispatch" statements for ERT_TRY regions. */
+
+void
+eh_dispatch_try_cfg_superedge::dump_label_to_pp (pretty_printer *pp,
+ bool user_facing) const
+{
+ if (!user_facing)
+ pp_string (pp, "ERT_TRY: ");
+ if (m_eh_catch)
+ {
+ bool first = true;
+ for (tree iter = m_eh_catch->type_list; iter; iter = TREE_CHAIN (iter))
+ {
+ if (!first)
+ pp_string (pp, ", ");
+ pp_printf (pp, "on catch %qT", TREE_VALUE (iter));
+ first = false;
+ }
+ }
+ else
+ pp_string (pp, "on uncaught exception");
+}
+
+bool
+eh_dispatch_try_cfg_superedge::
+apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out) const
+{
+ return model->apply_constraints_for_eh_dispatch_try
+ (*this, ctxt, exception_type, out);
+}
+
+// class eh_dispatch_allowed_cfg_superedge : public eh_dispatch_cfg_superedge
+
+eh_dispatch_allowed_cfg_superedge::
+eh_dispatch_allowed_cfg_superedge (supernode *src, supernode *dst, ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg)
+: eh_dispatch_cfg_superedge (src, dst, e, eh_dispatch_stmt, eh_reg)
+{
+ gcc_assert (eh_reg->type == ERT_ALLOWED_EXCEPTIONS);
+
+ /* We expect two sibling out-edges at an eh_dispatch from such a region:
+
+ - one to a bb without a gimple label, with a resx,
+ for exceptions of expected types
+
+ - one to a bb with a gimple label, with a call to __cxa_unexpected,
+ for exceptions of unexpected types.
+
+ Set m_kind for this edge accordingly. */
+ gcc_assert (e->src->succs->length () == 2);
+ tree label_for_unexpected_exceptions = eh_reg->u.allowed.label;
+ tree label_for_dest_enode = dst->get_label ();
+ if (label_for_dest_enode == label_for_unexpected_exceptions)
+ m_kind = eh_kind::unexpected;
+ else
+ {
+ gcc_assert (label_for_dest_enode == nullptr);
+ m_kind = eh_kind::expected;
+ }
+}
+
+void
+eh_dispatch_allowed_cfg_superedge::dump_label_to_pp (pretty_printer *pp,
+ bool user_facing) const
+{
+ if (!user_facing)
+ {
+ switch (m_kind)
+ {
+ default:
+ gcc_unreachable ();
+ case eh_dispatch_allowed_cfg_superedge::eh_kind::expected:
+ pp_string (pp, "expected: ");
+ break;
+ case eh_dispatch_allowed_cfg_superedge::eh_kind::unexpected:
+ pp_string (pp, "unexpected: ");
+ break;
+ }
+ pp_string (pp, "ERT_ALLOWED_EXCEPTIONS: ");
+ eh_region eh_reg = get_eh_region ();
+ bool first = true;
+ for (tree iter = eh_reg->u.allowed.type_list; iter;
+ iter = TREE_CHAIN (iter))
+ {
+ if (!first)
+ pp_string (pp, ", ");
+ pp_printf (pp, "%qT", TREE_VALUE (iter));
+ first = false;
+ }
+ }
+}
+
+bool
+eh_dispatch_allowed_cfg_superedge::
+apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out) const
+{
+ return model->apply_constraints_for_eh_dispatch_allowed
+ (*this, ctxt, exception_type, out);
+}
+
/* Implementation of superedge::dump_label_to_pp for interprocedural
superedges. */
@@ -1261,13 +1446,13 @@ callgraph_superedge::get_callee_decl () const
/* Get the gcall * of this interprocedural call/return edge. */
-gcall *
+const gcall &
callgraph_superedge::get_call_stmt () const
{
if (m_cedge)
- return m_cedge->call_stmt;
+ return *m_cedge->call_stmt;
- return m_src->get_final_call ();
+ return *m_src->get_final_call ();
}
/* Get the calling fndecl at this interprocedural call/return edge. */
@@ -1289,19 +1474,19 @@ callgraph_superedge::get_arg_for_parm (tree parm_to_find,
gcc_assert (TREE_CODE (parm_to_find) == PARM_DECL);
tree callee = get_callee_decl ();
- const gcall *call_stmt = get_call_stmt ();
+ const gcall &call_stmt = get_call_stmt ();
unsigned i = 0;
for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm;
iter_parm = DECL_CHAIN (iter_parm), ++i)
{
- if (i >= gimple_call_num_args (call_stmt))
+ if (i >= gimple_call_num_args (&call_stmt))
return NULL_TREE;
if (iter_parm == parm_to_find)
{
if (out)
*out = callsite_expr::from_zero_based_param (i);
- return gimple_call_arg (call_stmt, i);
+ return gimple_call_arg (&call_stmt, i);
}
}
@@ -1319,15 +1504,15 @@ callgraph_superedge::get_parm_for_arg (tree arg_to_find,
callsite_expr *out) const
{
tree callee = get_callee_decl ();
- const gcall *call_stmt = get_call_stmt ();
+ const gcall &call_stmt = get_call_stmt ();
unsigned i = 0;
for (tree iter_parm = DECL_ARGUMENTS (callee); iter_parm;
iter_parm = DECL_CHAIN (iter_parm), ++i)
{
- if (i >= gimple_call_num_args (call_stmt))
+ if (i >= gimple_call_num_args (&call_stmt))
return NULL_TREE;
- tree param = gimple_call_arg (call_stmt, i);
+ tree param = gimple_call_arg (&call_stmt, i);
if (arg_to_find == param)
{
if (out)
@@ -1353,7 +1538,7 @@ callgraph_superedge::map_expr_from_caller_to_callee (tree caller_expr,
if (parm)
return parm;
/* Otherwise try return value. */
- if (caller_expr == gimple_call_lhs (get_call_stmt ()))
+ if (caller_expr == gimple_call_lhs (&get_call_stmt ()))
{
if (out)
*out = callsite_expr::from_return_value ();
@@ -1388,7 +1573,7 @@ callgraph_superedge::map_expr_from_callee_to_caller (tree callee_expr,
{
if (out)
*out = callsite_expr::from_return_value ();
- return gimple_call_lhs (get_call_stmt ());
+ return gimple_call_lhs (&get_call_stmt ());
}
return NULL_TREE;
diff --git a/gcc/analyzer/supergraph.h b/gcc/analyzer/supergraph.h
index 6f94f99..8796ab7 100644
--- a/gcc/analyzer/supergraph.h
+++ b/gcc/analyzer/supergraph.h
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "gimple-iterator.h"
#include "digraph.h"
+#include "except.h"
using namespace ana;
@@ -42,6 +43,9 @@ class superedge;
class return_superedge;
class cfg_superedge;
class switch_cfg_superedge;
+ class eh_dispatch_cfg_superedge;
+ class eh_dispatch_try_cfg_superedge;
+ class eh_dispatch_allowed_cfg_superedge;
class supercluster;
class dot_annotator;
@@ -126,7 +130,7 @@ public:
return *const_cast <bb_to_node_t &> (m_bb_to_initial_node).get (bb);
}
- /* Get the supernode containing the second half of the gcall *
+ /* Get the supernode containing the second half of the gcall &
at an interprocedural call, within the caller. */
supernode *get_caller_next_node (cgraph_edge *edge) const
{
@@ -330,6 +334,9 @@ class superedge : public dedge<supergraph_traits>
virtual cfg_superedge *dyn_cast_cfg_superedge () { return NULL; }
virtual const cfg_superedge *dyn_cast_cfg_superedge () const { return NULL; }
virtual const switch_cfg_superedge *dyn_cast_switch_cfg_superedge () const { return NULL; }
+ virtual const eh_dispatch_cfg_superedge *dyn_cast_eh_dispatch_cfg_superedge () const { return nullptr; }
+ virtual const eh_dispatch_try_cfg_superedge *dyn_cast_eh_dispatch_try_cfg_superedge () const { return nullptr; }
+ virtual const eh_dispatch_allowed_cfg_superedge *dyn_cast_eh_dispatch_allowed_cfg_superedge () const { return nullptr; }
virtual callgraph_superedge *dyn_cast_callgraph_superedge () { return NULL; }
virtual const callgraph_superedge *dyn_cast_callgraph_superedge () const { return NULL; }
virtual call_superedge *dyn_cast_call_superedge () { return NULL; }
@@ -415,7 +422,7 @@ class callgraph_superedge : public superedge
function *get_caller_function () const;
tree get_callee_decl () const;
tree get_caller_decl () const;
- gcall *get_call_stmt () const;
+ const gcall &get_call_stmt () const;
tree get_arg_for_parm (tree parm, callsite_expr *out) const;
tree get_parm_for_arg (tree arg, callsite_expr *out) const;
tree map_expr_from_caller_to_callee (tree caller_expr,
@@ -592,6 +599,164 @@ is_a_helper <const switch_cfg_superedge *>::test (const superedge *sedge)
namespace ana {
+/* A subclass for edges from eh_dispatch statements, retaining enough
+ information to identify the various types being caught, vs the
+ "unhandled type" case, and for adding labels when rendering
+ via graphviz.
+ This is abstract; there are concrete subclasses based on the type
+ of the eh_region. */
+
+class eh_dispatch_cfg_superedge : public cfg_superedge
+{
+ public:
+ static std::unique_ptr<eh_dispatch_cfg_superedge>
+ make (supernode *src,
+ supernode *dest,
+ ::edge e,
+ const geh_dispatch *eh_dispatch_stmt);
+
+ const eh_dispatch_cfg_superedge *dyn_cast_eh_dispatch_cfg_superedge () const
+ final override
+ {
+ return this;
+ }
+
+ const geh_dispatch *
+ get_eh_dispatch_stmt () const
+ {
+ return m_eh_dispatch_stmt;
+ }
+
+ const eh_status &get_eh_status () const;
+ eh_region get_eh_region () const { return m_eh_region; }
+
+ virtual bool
+ apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out) const = 0;
+
+protected:
+ eh_dispatch_cfg_superedge (supernode *src, supernode *dst, ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg);
+
+private:
+ const geh_dispatch *m_eh_dispatch_stmt;
+ eh_region m_eh_region;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <const eh_dispatch_cfg_superedge *>::test (const superedge *sedge)
+{
+ return sedge->dyn_cast_eh_dispatch_cfg_superedge () != NULL;
+}
+
+namespace ana {
+
+/* A concrete subclass for edges from an eh_dispatch statements
+ for ERT_TRY regions. */
+
+class eh_dispatch_try_cfg_superedge : public eh_dispatch_cfg_superedge
+{
+ public:
+ eh_dispatch_try_cfg_superedge (supernode *src, supernode *dst, ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg,
+ eh_catch ehc)
+ : eh_dispatch_cfg_superedge (src, dst, e, eh_dispatch_stmt, eh_reg),
+ m_eh_catch (ehc)
+ {
+ gcc_assert (eh_reg->type == ERT_TRY);
+ }
+
+ const eh_dispatch_try_cfg_superedge *
+ dyn_cast_eh_dispatch_try_cfg_superedge () const final override
+ {
+ return this;
+ }
+
+ void dump_label_to_pp (pretty_printer *pp,
+ bool user_facing) const final override;
+
+ eh_catch get_eh_catch () const { return m_eh_catch; }
+
+ bool
+ apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out)
+ const final override;
+
+private:
+ eh_catch m_eh_catch;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <const eh_dispatch_try_cfg_superedge *>::test (const superedge *sedge)
+{
+ return sedge->dyn_cast_eh_dispatch_try_cfg_superedge () != NULL;
+}
+
+namespace ana {
+
+/* A concrete subclass for edges from an eh_dispatch statements
+ for ERT_ALLOWED_EXCEPTIONS regions. */
+
+class eh_dispatch_allowed_cfg_superedge : public eh_dispatch_cfg_superedge
+{
+ public:
+ enum eh_kind
+ {
+ expected,
+ unexpected
+ };
+
+ eh_dispatch_allowed_cfg_superedge (supernode *src, supernode *dst, ::edge e,
+ const geh_dispatch *eh_dispatch_stmt,
+ eh_region eh_reg);
+
+ const eh_dispatch_allowed_cfg_superedge *
+ dyn_cast_eh_dispatch_allowed_cfg_superedge () const final override
+ {
+ return this;
+ }
+
+ void dump_label_to_pp (pretty_printer *pp,
+ bool user_facing) const final override;
+
+ bool
+ apply_constraints (region_model *model,
+ region_model_context *ctxt,
+ tree exception_type,
+ std::unique_ptr<rejected_constraint> *out)
+ const final override;
+
+ enum eh_kind get_eh_kind () const { return m_kind; }
+
+private:
+ enum eh_kind m_kind;
+};
+
+} // namespace ana
+
+template <>
+template <>
+inline bool
+is_a_helper <const eh_dispatch_allowed_cfg_superedge *>::test (const superedge *sedge)
+{
+ return sedge->dyn_cast_eh_dispatch_allowed_cfg_superedge () != NULL;
+}
+
+namespace ana {
/* Base class for adding additional content to the .dot output
for a supergraph. */
diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc
index 2e3f051..f3f80d1 100644
--- a/gcc/analyzer/svalue.cc
+++ b/gcc/analyzer/svalue.cc
@@ -18,39 +18,22 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "diagnostic-core.h"
+#include "analyzer/common.h"
+
+#include "tree-pretty-print.h"
#include "gimple-pretty-print.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "gimple-iterator.h"
-#include "diagnostic-core.h"
-#include "graphviz.h"
-#include "options.h"
-#include "cgraph.h"
-#include "tree-dfa.h"
-#include "stringpool.h"
-#include "convert.h"
-#include "target.h"
#include "fold-const.h"
-#include "tree-pretty-print.h"
-#include "bitmap.h"
-#include "analyzer/analyzer.h"
+#include "diagnostic.h"
+#include "tree-diagnostic.h"
+
+#include "text-art/dump.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/call-string.h"
#include "analyzer/program-point.h"
#include "analyzer/store.h"
#include "analyzer/svalue.h"
#include "analyzer/region-model.h"
-#include "diagnostic.h"
-#include "tree-diagnostic.h"
-#include "make-unique.h"
-#include "text-art/dump.h"
#if ENABLE_ANALYZER
@@ -107,7 +90,7 @@ std::unique_ptr<json::value>
svalue::to_json () const
{
label_text desc = get_desc (true);
- auto sval_js = ::make_unique<json::string> (desc.get ());
+ auto sval_js = std::make_unique<json::string> (desc.get ());
return sval_js;
}
@@ -572,8 +555,8 @@ svalue::cmp_ptr (const svalue *sval1, const svalue *sval2)
{
const poisoned_svalue *poisoned_sval1 = (const poisoned_svalue *)sval1;
const poisoned_svalue *poisoned_sval2 = (const poisoned_svalue *)sval2;
- return (poisoned_sval1->get_poison_kind ()
- - poisoned_sval2->get_poison_kind ());
+ return (static_cast<int> (poisoned_sval1->get_poison_kind ())
+ - static_cast<int> (poisoned_sval2->get_poison_kind ()));
}
break;
case SK_SETJMP:
@@ -877,6 +860,19 @@ svalue::maybe_get_deref_base_region () const
}
}
+/* If this svalue is a pointer to the typeinfo instance for a particular
+ type, return that type. Otherwise return NULL_TREE. */
+
+tree
+svalue::maybe_get_type_from_typeinfo () const
+{
+ if (const region *reg = maybe_get_region ())
+ if (const decl_region *decl_reg = reg->dyn_cast_decl_region ())
+ return TREE_TYPE (DECL_NAME (decl_reg->get_decl ()));
+
+ return NULL_TREE;
+}
+
/* class region_svalue : public svalue. */
/* Implementation of svalue::dump_to_pp vfunc for region_svalue. */
@@ -1234,13 +1230,13 @@ poison_kind_to_str (enum poison_kind kind)
{
default:
gcc_unreachable ();
- case POISON_KIND_UNINIT:
+ case poison_kind::uninit:
return "uninit";
- case POISON_KIND_FREED:
+ case poison_kind::freed:
return "freed";
- case POISON_KIND_DELETED:
+ case poison_kind::deleted:
return "deleted";
- case POISON_KIND_POPPED_STACK:
+ case poison_kind::popped_stack:
return "popped stack";
}
}
diff --git a/gcc/analyzer/svalue.h b/gcc/analyzer/svalue.h
index bf9e12b..7a27cb6 100644
--- a/gcc/analyzer/svalue.h
+++ b/gcc/analyzer/svalue.h
@@ -188,6 +188,8 @@ public:
const region_model &model,
const svalue *outer_sval = nullptr) const;
+ tree maybe_get_type_from_typeinfo () const;
+
protected:
svalue (complexity c, symbol::id_t id, tree type)
: symbol (c, id), m_type (type)
@@ -421,19 +423,19 @@ public:
/* An enum describing a particular kind of "poisoned" value. */
-enum poison_kind
+enum class poison_kind
{
/* For use to describe uninitialized memory. */
- POISON_KIND_UNINIT,
+ uninit,
/* For use to describe freed memory. */
- POISON_KIND_FREED,
+ freed,
/* For use to describe deleted memory. */
- POISON_KIND_DELETED,
+ deleted,
/* For use on pointers to regions within popped stack frames. */
- POISON_KIND_POPPED_STACK
+ popped_stack
};
extern const char *poison_kind_to_str (enum poison_kind);
@@ -454,7 +456,7 @@ public:
hashval_t hash () const
{
inchash::hash hstate;
- hstate.add_int (m_kind);
+ hstate.add_int (static_cast<int> (m_kind));
hstate.add_ptr (m_type);
return hstate.end ();
}
@@ -528,8 +530,8 @@ namespace ana {
struct setjmp_record
{
setjmp_record (const exploded_node *enode,
- const gcall *setjmp_call)
- : m_enode (enode), m_setjmp_call (setjmp_call)
+ const gcall &setjmp_call)
+ : m_enode (enode), m_setjmp_call (&setjmp_call)
{
}
@@ -549,6 +551,7 @@ struct setjmp_record
const exploded_node *m_enode;
const gcall *m_setjmp_call;
+ // non-null, but we can't use a reference since we're putting these in a hash_map
};
/* Concrete subclass of svalue representing buffers for setjmp/sigsetjmp,
diff --git a/gcc/analyzer/symbol.cc b/gcc/analyzer/symbol.cc
index 068801a..8643284 100644
--- a/gcc/analyzer/symbol.cc
+++ b/gcc/analyzer/symbol.cc
@@ -18,11 +18,8 @@ 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 "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/symbol.h"
#if ENABLE_ANALYZER
diff --git a/gcc/analyzer/trimmed-graph.cc b/gcc/analyzer/trimmed-graph.cc
index 993084c..bdf378a 100644
--- a/gcc/analyzer/trimmed-graph.cc
+++ b/gcc/analyzer/trimmed-graph.cc
@@ -18,21 +18,8 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "tree.h"
-#include "pretty-print.h"
-#include "gcc-rich-location.h"
-#include "gimple-pretty-print.h"
-#include "function.h"
-#include "diagnostic-core.h"
-#include "diagnostic-event-id.h"
-#include "diagnostic-path.h"
-#include "bitmap.h"
-#include "ordered-hash-map.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
diff --git a/gcc/analyzer/varargs.cc b/gcc/analyzer/varargs.cc
index 0cacc9b..6ea0d29 100644
--- a/gcc/analyzer/varargs.cc
+++ b/gcc/analyzer/varargs.cc
@@ -18,18 +18,8 @@ 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 "config.h"
-#define INCLUDE_VECTOR
-#include "system.h"
-#include "coretypes.h"
-#include "make-unique.h"
-#include "tree.h"
-#include "function.h"
-#include "basic-block.h"
-#include "gimple.h"
-#include "diagnostic-core.h"
-#include "diagnostic-path.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
+
#include "analyzer/analyzer-logging.h"
#include "analyzer/sm.h"
#include "analyzer/pending-diagnostic.h"
@@ -167,10 +157,10 @@ get_va_list_diag_arg (tree va_list_tree)
static const svalue *
get_va_copy_arg (const region_model *model,
region_model_context *ctxt,
- const gcall *call,
+ const gcall &call,
unsigned arg_idx)
{
- tree arg = gimple_call_arg (call, arg_idx);
+ tree arg = gimple_call_arg (&call, arg_idx);
const svalue *arg_sval = model->get_rvalue (arg, ctxt);
if (const svalue *cast = arg_sval->maybe_undo_cast ())
arg_sval = cast;
@@ -225,16 +215,16 @@ public:
private:
void on_va_start (sm_context &sm_ctxt, const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void on_va_copy (sm_context &sm_ctxt, const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void on_va_arg (sm_context &sm_ctxt, const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void on_va_end (sm_context &sm_ctxt, const supernode *node,
- const gcall *call) const;
+ const gcall &call) const;
void check_for_ended_va_list (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
const svalue *arg,
const char *usage_fnname) const;
};
@@ -256,10 +246,12 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt,
const supernode *node,
const gimple *stmt) const
{
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
{
- if (gimple_call_internal_p (call)
- && gimple_call_internal_fn (call) == IFN_VA_ARG)
+ const gcall &call = *call_stmt;
+
+ if (gimple_call_internal_p (call_stmt)
+ && gimple_call_internal_fn (call_stmt) == IFN_VA_ARG)
{
on_va_arg (sm_ctxt, node, call);
return false;
@@ -267,7 +259,7 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt,
if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
if (fndecl_built_in_p (callee_fndecl, BUILT_IN_NORMAL)
- && gimple_builtin_call_types_compatible_p (call, callee_fndecl))
+ && gimple_builtin_call_types_compatible_p (&call, callee_fndecl))
switch (DECL_UNCHECKED_FUNCTION_CODE (callee_fndecl))
{
default:
@@ -293,9 +285,9 @@ va_list_state_machine::on_stmt (sm_context &sm_ctxt,
IDX to CALL. */
static const svalue *
-get_stateful_arg (sm_context &sm_ctxt, const gcall *call, unsigned arg_idx)
+get_stateful_arg (sm_context &sm_ctxt, const gcall &call, unsigned arg_idx)
{
- tree ap = gimple_call_arg (call, arg_idx);
+ tree ap = gimple_call_arg (&call, arg_idx);
if (ap
&& POINTER_TYPE_P (TREE_TYPE (ap)))
{
@@ -542,14 +534,14 @@ private:
void
va_list_state_machine::on_va_start (sm_context &sm_ctxt,
const supernode *,
- const gcall *call) const
+ const gcall &call) const
{
const svalue *arg = get_stateful_arg (sm_ctxt, call, 0);
if (arg)
{
/* Transition from start state to "started". */
- if (sm_ctxt.get_state (call, arg) == m_start)
- sm_ctxt.set_next_state (call, arg, m_started);
+ if (sm_ctxt.get_state (&call, arg) == m_start)
+ sm_ctxt.set_next_state (&call, arg, m_started);
}
}
@@ -558,13 +550,13 @@ va_list_state_machine::on_va_start (sm_context &sm_ctxt,
void
va_list_state_machine::check_for_ended_va_list (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
const svalue *arg,
const char *usage_fnname) const
{
- if (sm_ctxt.get_state (call, arg) == m_ended)
- sm_ctxt.warn (node, call, arg,
- make_unique<va_list_use_after_va_end>
+ if (sm_ctxt.get_state (&call, arg) == m_ended)
+ sm_ctxt.warn (node, &call, arg,
+ std::make_unique<va_list_use_after_va_end>
(*this, arg, NULL_TREE, usage_fnname));
}
@@ -574,7 +566,7 @@ va_list_state_machine::check_for_ended_va_list (sm_context &sm_ctxt,
static const svalue *
get_stateful_va_copy_arg (sm_context &sm_ctxt,
- const gcall *call,
+ const gcall &call,
unsigned arg_idx)
{
if (const program_state *new_state = sm_ctxt.get_new_program_state ())
@@ -591,7 +583,7 @@ get_stateful_va_copy_arg (sm_context &sm_ctxt,
void
va_list_state_machine::on_va_copy (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const
+ const gcall &call) const
{
const svalue *src_arg = get_stateful_va_copy_arg (sm_ctxt, call, 1);
if (src_arg)
@@ -601,8 +593,8 @@ va_list_state_machine::on_va_copy (sm_context &sm_ctxt,
if (dst_arg)
{
/* Transition from start state to "started". */
- if (sm_ctxt.get_state (call, dst_arg) == m_start)
- sm_ctxt.set_next_state (call, dst_arg, m_started);
+ if (sm_ctxt.get_state (&call, dst_arg) == m_start)
+ sm_ctxt.set_next_state (&call, dst_arg, m_started);
}
}
@@ -611,7 +603,7 @@ va_list_state_machine::on_va_copy (sm_context &sm_ctxt,
void
va_list_state_machine::on_va_arg (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const
+ const gcall &call) const
{
const svalue *arg = get_stateful_arg (sm_ctxt, call, 0);
if (arg)
@@ -623,15 +615,15 @@ va_list_state_machine::on_va_arg (sm_context &sm_ctxt,
void
va_list_state_machine::on_va_end (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call) const
+ const gcall &call) const
{
const svalue *arg = get_stateful_arg (sm_ctxt, call, 0);
if (arg)
{
- state_t s = sm_ctxt.get_state (call, arg);
+ state_t s = sm_ctxt.get_state (&call, arg);
/* Transition from "started" to "ended". */
if (s == m_started)
- sm_ctxt.set_next_state (call, arg, m_ended);
+ sm_ctxt.set_next_state (&call, arg, m_ended);
else if (s == m_ended)
check_for_ended_va_list (sm_ctxt, node, call, arg, "va_end");
}
@@ -643,17 +635,17 @@ va_list_state_machine::on_va_end (sm_context &sm_ctxt,
std::unique_ptr<pending_diagnostic>
va_list_state_machine::on_leak (tree var) const
{
- return make_unique<va_list_leak> (*this, nullptr, var);
+ return std::make_unique<va_list_leak> (*this, nullptr, var);
}
} // anonymous namespace
/* Internal interface to this file. */
-state_machine *
+std::unique_ptr<state_machine>
make_va_list_state_machine (logger *logger)
{
- return new va_list_state_machine (logger);
+ return std::make_unique<va_list_state_machine> (logger);
}
/* Handler for "__builtin_va_start". */
@@ -757,13 +749,13 @@ kf_va_copy::impl_call_pre (const call_details &cd) const
static int
get_num_variadic_arguments (tree callee_fndecl,
- const gcall *call_stmt)
+ const gcall &call_stmt)
{
int num_positional = 0;
for (tree iter_parm = DECL_ARGUMENTS (callee_fndecl); iter_parm;
iter_parm = DECL_CHAIN (iter_parm))
num_positional++;
- return gimple_call_num_args (call_stmt) - num_positional;
+ return gimple_call_num_args (&call_stmt) - num_positional;
}
/* An abstract subclass of pending_diagnostic for diagnostics relating
@@ -817,12 +809,12 @@ public:
const program_point &src_point = src_node->get_point ();
const int src_stack_depth = src_point.get_stack_depth ();
const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
- const gcall *call_stmt = as_a <const gcall *> (last_stmt);
+ const gcall &call_stmt = *as_a <const gcall *> (last_stmt);
int num_variadic_arguments
= get_num_variadic_arguments (dst_node->get_function ()->decl,
call_stmt);
emission_path->add_event
- (make_unique<va_arg_call_event>
+ (std::make_unique<va_arg_call_event>
(eedge,
event_loc_info (last_stmt ? last_stmt->location : UNKNOWN_LOCATION,
src_point.get_fndecl (),
@@ -1078,7 +1070,7 @@ kf_va_arg::impl_call_pre (const call_details &cd) const
else
{
if (ctxt)
- ctxt->warn (make_unique <va_arg_type_mismatch>
+ ctxt->warn (std::make_unique <va_arg_type_mismatch>
(va_list_tree,
arg_reg,
lhs_type,
@@ -1089,8 +1081,9 @@ kf_va_arg::impl_call_pre (const call_details &cd) const
else
{
if (ctxt)
- ctxt->warn (make_unique <va_list_exhausted> (va_list_tree,
- arg_reg));
+ ctxt->warn
+ (std::make_unique <va_list_exhausted> (va_list_tree,
+ arg_reg));
saw_problem = true;
}
}
@@ -1139,10 +1132,10 @@ public:
void
register_varargs_builtins (known_function_manager &kfm)
{
- kfm.add (BUILT_IN_VA_START, make_unique<kf_va_start> ());
- kfm.add (BUILT_IN_VA_COPY, make_unique<kf_va_copy> ());
- kfm.add (IFN_VA_ARG, make_unique<kf_va_arg> ());
- kfm.add (BUILT_IN_VA_END, make_unique<kf_va_end> ());
+ kfm.add (BUILT_IN_VA_START, std::make_unique<kf_va_start> ());
+ kfm.add (BUILT_IN_VA_COPY, std::make_unique<kf_va_copy> ());
+ kfm.add (IFN_VA_ARG, std::make_unique<kf_va_arg> ());
+ kfm.add (BUILT_IN_VA_END, std::make_unique<kf_va_end> ());
}
} // namespace ana
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 732b2c9..1572c8b 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,20 @@
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * c-pretty-print.cc: Drop include of "make-unique.h".
+ Replace uses of ::make_unique with std::make_unique.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * name-hint.h (name_hint::name_hint): Use std::unique_ptr for
+ param.
+
+2025-04-28 Lewis Hyatt <lhyatt@gmail.com>
+
+ PR c/118838
+ * c-lex.cc (cb_def_pragma): Call cpp_get_diagnostic_override_loc()
+ to get a valid location at which to issue -Wunknown-pragmas, in case
+ it was triggered from a _Pragma.
+
2025-04-25 Jason Merrill <jason@redhat.com>
* c-opts.cc (c_common_post_options): Bump default ABI to 21
diff --git a/gcc/c-family/c-pretty-print.cc b/gcc/c-family/c-pretty-print.cc
index 1ce19f5..fad6b5e 100644
--- a/gcc/c-family/c-pretty-print.cc
+++ b/gcc/c-family/c-pretty-print.cc
@@ -36,7 +36,6 @@ along with GCC; see the file COPYING3. If not see
#include "function.h"
#include "basic-block.h"
#include "gimple.h"
-#include "make-unique.h"
/* The pretty-printer code is primarily designed to closely follow
(GNU) C and C++ grammars. That is to be contrasted with spaghetti
@@ -2994,7 +2993,7 @@ c_pretty_printer::c_pretty_printer (dump_flags_t dump_flags)
std::unique_ptr<pretty_printer>
c_pretty_printer::clone () const
{
- return ::make_unique<c_pretty_printer> (*this);
+ return std::make_unique<c_pretty_printer> (*this);
}
/* Print the tree T in full, on file FILE. */
diff --git a/gcc/c-family/name-hint.h b/gcc/c-family/name-hint.h
index 3d4f2f5..13ade71 100644
--- a/gcc/c-family/name-hint.h
+++ b/gcc/c-family/name-hint.h
@@ -85,8 +85,10 @@ class name_hint
public:
name_hint () : m_suggestion (NULL), m_deferred () {}
- name_hint (const char *suggestion, deferred_diagnostic *deferred)
- : m_suggestion (suggestion), m_deferred (deferred)
+ name_hint (const char *suggestion,
+ std::unique_ptr<deferred_diagnostic> deferred)
+ : m_suggestion (suggestion),
+ m_deferred (std::move (deferred))
{
}
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index c8f9206..4c8fde7 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,31 @@
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * c-decl.cc: Drop include of "make-unique.h".
+ Replace uses of ::make_unique with std::make_unique.
+ * c-objc-common.cc: Likewise.
+ * c-parser.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * c-decl.cc: Include "make-unique.h".
+ (lookup_name_fuzzy): Use ::make_unique rather than "new" when
+ making suggest_missing_header and suggest_missing_option.
+ * c-parser.cc: Include "make-unique.h"
+ (c_parser_error_richloc): Use ::make_unique rather than "new" when
+ making suggest_missing_header.
+
+2025-04-28 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR c/119432
+ * gimple-parser.cc (gimple_binary_identifier_code): Add
+ __ROTATE_LEFT and __ROTATE_RIGHT.
+
+2025-04-28 Andrew Pinski <quic_apinski@quicinc.com>
+
+ * gimple-parser.cc (gimple_binary_identifier_code): New variable.
+ (c_parser_gimple_binary_expression): Use gimple_binary_identifier_code
+ instead of doing if statements on the strings.
+
2025-04-27 H.J. Lu <hjl.tools@gmail.com>
PR c/48274
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index e7aee8a..4e200f9 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -4547,10 +4547,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
= get_c_stdlib_header_for_name (IDENTIFIER_POINTER (name));
if (header_hint)
- return name_hint (NULL,
- new suggest_missing_header (loc,
- IDENTIFIER_POINTER (name),
- header_hint));
+ return name_hint
+ (nullptr,
+ std::make_unique<suggest_missing_header> (loc,
+ IDENTIFIER_POINTER (name),
+ header_hint));
/* Next, look for exact matches for builtin defines that would have been
defined if the user had passed a command-line option (e.g. -fopenmp
@@ -4558,10 +4559,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
diagnostic_option_id option_id
= get_option_for_builtin_define (IDENTIFIER_POINTER (name));
if (option_id.m_idx > 0)
- return name_hint (nullptr,
- new suggest_missing_option (loc,
- IDENTIFIER_POINTER (name),
- option_id));
+ return name_hint
+ (nullptr,
+ std::make_unique<suggest_missing_option> (loc,
+ IDENTIFIER_POINTER (name),
+ option_id));
/* Only suggest names reserved for the implementation if NAME begins
with an underscore. */
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index 7e227d3..2016eae 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3. If not see
#include "stringpool.h"
#include "attribs.h"
#include "dwarf2.h"
-#include "make-unique.h"
static bool c_tree_printer (pretty_printer *, text_info *, const char *,
int, bool, bool, bool, bool *, pp_token_list &);
@@ -412,7 +411,7 @@ has_c_linkage (const_tree decl ATTRIBUTE_UNUSED)
void
c_initialize_diagnostics (diagnostic_context *context)
{
- context->set_pretty_printer (::make_unique<c_pretty_printer> ());
+ context->set_pretty_printer (std::make_unique<c_pretty_printer> ());
c_common_diagnostics_set_defaults (context);
context->set_format_decoder (&c_tree_printer);
}
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 22ec0f8..8a63dc5 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1072,9 +1072,11 @@ c_parser_error_richloc (c_parser *parser, const char *gmsgid,
const char *header_hint
= get_c_stdlib_header_for_string_macro_name (token_name);
if (header_hint != NULL)
- h = name_hint (NULL, new suggest_missing_header (token->location,
- token_name,
- header_hint));
+ h = name_hint (nullptr,
+ std::make_unique<suggest_missing_header>
+ (token->location,
+ token_name,
+ header_hint));
}
c_parse_error (gmsgid,
diff --git a/gcc/c/gimple-parser.cc b/gcc/c/gimple-parser.cc
index 90b9beb..5fd1db8 100644
--- a/gcc/c/gimple-parser.cc
+++ b/gcc/c/gimple-parser.cc
@@ -963,6 +963,29 @@ c_parser_gimple_statement (gimple_parser &parser, gimple_seq *seq)
return;
}
+/* A mapping between an identifier to a tree code for binary operations. */
+static const std::pair<const char *, tree_code> gimple_binary_identifier_code[] =
+ {
+ {"__MULT_HIGHPART", MULT_HIGHPART_EXPR},
+ {"__UNLT", UNLT_EXPR},
+ {"__UNLE", UNLE_EXPR},
+ {"__UNGT", UNGT_EXPR},
+ {"__UNGE", UNGE_EXPR},
+ {"__UNEQ", UNEQ_EXPR},
+ {"__UNORDERED", UNORDERED_EXPR},
+ {"__ORDERED", ORDERED_EXPR},
+ {"__LTGT", LTGT_EXPR},
+ {"__FLOOR_DIV", FLOOR_DIV_EXPR},
+ {"__ROUND_DIV", ROUND_DIV_EXPR},
+ {"__EXACT_DIV", EXACT_DIV_EXPR},
+ {"__CEIL_DIV", CEIL_DIV_EXPR},
+ {"__FLOOR_MOD", FLOOR_MOD_EXPR},
+ {"__ROUND_MOD", ROUND_MOD_EXPR},
+ {"__CEIL_MOD", CEIL_MOD_EXPR},
+ {"__ROTATE_LEFT", LROTATE_EXPR},
+ {"__ROTATE_RIGHT", RROTATE_EXPR},
+ };
+
/* Parse gimple binary expr.
gimple-binary-expression:
@@ -1061,86 +1084,16 @@ c_parser_gimple_binary_expression (gimple_parser &parser, tree ret_type)
case CPP_NAME:
{
tree id = c_parser_peek_token (parser)->value;
- if (strcmp (IDENTIFIER_POINTER (id), "__MULT_HIGHPART") == 0)
- {
- code = MULT_HIGHPART_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__UNLT") == 0)
- {
- code = UNLT_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__UNLE") == 0)
- {
- code = UNLE_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__UNGT") == 0)
- {
- code = UNGT_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__UNGE") == 0)
- {
- code = UNGE_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__UNEQ") == 0)
- {
- code = UNEQ_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__UNORDERED") == 0)
- {
- code = UNORDERED_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__ORDERED") == 0)
- {
- code = ORDERED_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__LTGT") == 0)
+ for (auto &p : gimple_binary_identifier_code)
{
- code = LTGT_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__FLOOR_DIV") == 0)
- {
- code = FLOOR_DIV_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__ROUND_DIV") == 0)
- {
- code = ROUND_DIV_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__EXACT_DIV") == 0)
- {
- code = EXACT_DIV_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__CEIL_DIV") == 0)
- {
- code = CEIL_DIV_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__FLOOR_MOD") == 0)
- {
- code = FLOOR_MOD_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__ROUND_MOD") == 0)
- {
- code = ROUND_MOD_EXPR;
- break;
- }
- else if (strcmp (IDENTIFIER_POINTER (id), "__CEIL_MOD") == 0)
- {
- code = CEIL_MOD_EXPR;
- break;
+ if (strcmp (IDENTIFIER_POINTER (id), p.first) == 0)
+ {
+ code = p.second;
+ break;
+ }
}
+ if (code != ERROR_MARK)
+ break;
}
/* Fallthru. */
default:
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 9d5db06..480e9c4 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,38 @@
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * parser.cc: Include "analyzer/analyzer-language.h".
+ (ana::cp_translation_unit): New class.
+ (cp_parser_translation_unit): Add call to
+ ana::on_finish_translation_unit.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * cxx-pretty-print.cc: Drop include of "make-unique.h".
+ Replace uses of ::make_unique with std::make_unique.
+ * error.cc: Likewise.
+ * name-lookup.cc: Likewise.
+ * parser.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * name-lookup.cc: Include "make-unique.h".
+ (namespace_hints::convert_candidates_to_name_hint): Use
+ ::make_unique rather than "new" when making
+ show_candidate_location and suggest_alternatives.
+ (namespace_hints::maybe_decorate_with_limit): Likewise when making
+ namespace_limit_reached.
+ (suggest_alternatives_for_1): Likewise when making
+ suggest_missing_option.
+ (maybe_suggest_missing_std_header): Likewise when making
+ missing_std_header.
+ (macro_use_before_def::maybe_make): Use std::unique_ptr.
+ (macro_use_before_def::macro_use_before_def): Make public.
+ (lookup_name_fuzzy): Use ::make_unique rather than "new" when
+ making suggest_missing_header.
+ * parser.cc: Include "make-unique.h".
+ (cp_parser_error_1): Use ::make_unique rather than "new" when
+ making suggest_missing_header.
+
2025-04-27 Nathaniel Shead <nathanieloshead@gmail.com>
PR c++/119939
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index cf301bd..5f24015 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "cp-tree.h"
#include "cxx-pretty-print.h"
#include "tree-pretty-print.h"
-#include "make-unique.h"
static void pp_cxx_unqualified_id (cxx_pretty_printer *, tree);
static void pp_cxx_nested_name_specifier (cxx_pretty_printer *, tree);
@@ -2954,5 +2953,5 @@ cxx_pretty_printer::cxx_pretty_printer ()
std::unique_ptr<pretty_printer>
cxx_pretty_printer::clone () const
{
- return ::make_unique<cxx_pretty_printer> (*this);
+ return std::make_unique<cxx_pretty_printer> (*this);
}
diff --git a/gcc/cp/error.cc b/gcc/cp/error.cc
index 499eb1b..75bf7dc 100644
--- a/gcc/cp/error.cc
+++ b/gcc/cp/error.cc
@@ -38,7 +38,6 @@ along with GCC; see the file COPYING3. If not see
#include "cp-name-hint.h"
#include "attribs.h"
#include "pretty-print-format-impl.h"
-#include "make-unique.h"
#include "diagnostic-format-text.h"
#define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
diff --git a/gcc/cp/name-lookup.cc b/gcc/cp/name-lookup.cc
index aa2dc0e..9b317c4 100644
--- a/gcc/cp/name-lookup.cc
+++ b/gcc/cp/name-lookup.cc
@@ -7085,13 +7085,16 @@ namespace_hints::convert_candidates_to_name_hint ()
/* Clean up CANDIDATES. */
m_candidates.release ();
return name_hint (expr_to_string (candidate),
- new show_candidate_location (m_loc, candidate));
+ std::make_unique<show_candidate_location> (m_loc,
+ candidate));
}
else if (m_candidates.length () > 1)
/* If we have more than one candidate, issue a name_hint without a single
"suggestion", but with a deferred diagnostic that lists the
various candidates. This takes ownership of m_candidates. */
- return name_hint (NULL, new suggest_alternatives (m_loc, m_candidates));
+ return name_hint (NULL,
+ std::make_unique<suggest_alternatives> (m_loc,
+ m_candidates));
/* Otherwise, m_candidates ought to be empty, so no cleanup is necessary. */
gcc_assert (m_candidates.length () == 0);
@@ -7111,10 +7114,11 @@ name_hint
namespace_hints::maybe_decorate_with_limit (name_hint hint)
{
if (m_limited)
- return name_hint (hint.suggestion (),
- new namespace_limit_reached (m_loc, m_limit,
- m_name,
- hint.take_deferred ()));
+ return name_hint
+ (hint.suggestion (),
+ std::make_unique<namespace_limit_reached> (m_loc, m_limit,
+ m_name,
+ hint.take_deferred ()));
else
return hint;
}
@@ -7191,10 +7195,11 @@ suggest_alternatives_for_1 (location_t location, tree name,
diagnostic_option_id option_id
= get_option_for_builtin_define (IDENTIFIER_POINTER (name));
if (option_id.m_idx > 0)
- return name_hint (nullptr,
- new suggest_missing_option (location,
- IDENTIFIER_POINTER (name),
- option_id));
+ return name_hint
+ (nullptr,
+ std::make_unique<suggest_missing_option> (location,
+ IDENTIFIER_POINTER (name),
+ option_id));
/* Otherwise, consider misspellings. */
if (!suggest_misspellings)
@@ -7322,8 +7327,9 @@ maybe_suggest_missing_std_header (location_t location, tree name)
if (!header_hint)
return name_hint ();
- return name_hint (NULL, new missing_std_header (location, name_str,
- header_hint));
+ return name_hint (nullptr,
+ std::make_unique<missing_std_header> (location, name_str,
+ header_hint));
}
/* Attempt to generate a name_hint that suggests a missing header file
@@ -7705,12 +7711,12 @@ class macro_use_before_def : public deferred_diagnostic
public:
/* Factory function. Return a new macro_use_before_def instance if
appropriate, or return NULL. */
- static macro_use_before_def *
+ static std::unique_ptr<macro_use_before_def>
maybe_make (location_t use_loc, cpp_hashnode *macro)
{
location_t def_loc = cpp_macro_definition_location (macro);
if (def_loc == UNKNOWN_LOCATION)
- return NULL;
+ return nullptr;
/* We only want to issue a note if the macro was used *before* it was
defined.
@@ -7718,12 +7724,11 @@ class macro_use_before_def : public deferred_diagnostic
used, leaving it unexpanded (e.g. by using the wrong argument
count). */
if (!linemap_location_before_p (line_table, use_loc, def_loc))
- return NULL;
+ return nullptr;
- return new macro_use_before_def (use_loc, macro);
+ return std::make_unique<macro_use_before_def> (use_loc, macro);
}
- private:
/* Ctor. LOC is the location of the usage. MACRO is the
macro that was used. */
macro_use_before_def (location_t loc, cpp_hashnode *macro)
@@ -7790,10 +7795,11 @@ lookup_name_fuzzy (tree name, enum lookup_name_fuzzy_kind kind, location_t loc)
const char *header_hint
= get_cp_stdlib_header_for_name (IDENTIFIER_POINTER (name));
if (header_hint)
- return name_hint (NULL,
- new suggest_missing_header (loc,
- IDENTIFIER_POINTER (name),
- header_hint));
+ return name_hint
+ (nullptr,
+ std::make_unique<suggest_missing_header> (loc,
+ IDENTIFIER_POINTER (name),
+ header_hint));
best_match <tree, const char *> bm (name);
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 3628cfe..1fb9e7f 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -50,6 +50,7 @@ along with GCC; see the file COPYING3. If not see
#include "contracts.h"
#include "bitmap.h"
#include "builtins.h"
+#include "analyzer/analyzer-language.h"
/* The lexer. */
@@ -286,6 +287,37 @@ static FILE *cp_lexer_debug_stream;
sizeof, typeof, or alignof. */
int cp_unevaluated_operand;
+#if ENABLE_ANALYZER
+
+namespace ana {
+
+/* Concrete implementation of ana::translation_unit for the C++ frontend. */
+
+class cp_translation_unit : public translation_unit
+{
+public:
+ tree lookup_constant_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+
+ tree
+ lookup_type_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+
+ tree
+ lookup_global_var_by_id (tree /*id*/) const final override
+ {
+ return NULL_TREE;
+ }
+};
+
+} // namespace ana
+
+#endif /* #if ENABLE_ANALYZER */
+
/* Dump up to NUM tokens in BUFFER to FILE starting with token
START_TOKEN. If START_TOKEN is NULL, the dump starts with the
first token in BUFFER. If NUM is 0, dump all the tokens. If
@@ -3434,9 +3466,11 @@ cp_parser_error_1 (cp_parser* parser, const char* gmsgid,
const char *header_hint
= get_cp_stdlib_header_for_string_macro_name (token_name);
if (header_hint != NULL)
- h = name_hint (NULL, new suggest_missing_header (token->location,
- token_name,
- header_hint));
+ h = name_hint
+ (nullptr,
+ std::make_unique<suggest_missing_header> (token->location,
+ token_name,
+ header_hint));
}
/* Actually emit the error. */
@@ -5469,6 +5503,14 @@ cp_parser_translation_unit (cp_parser* parser)
cp_parser_toplevel_declaration (parser);
}
+#if ENABLE_ANALYZER
+ if (flag_analyzer)
+ {
+ ana::cp_translation_unit tu;
+ ana::on_finish_translation_unit (tu);
+ }
+#endif
+
/* Get rid of the token array; we don't need it any more. */
cp_lexer_destroy (parser->lexer);
parser->lexer = NULL;
diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
index 883b0ea..c28804e 100644
--- a/gcc/diagnostic-format-json.cc
+++ b/gcc/diagnostic-format-json.cc
@@ -32,7 +32,6 @@ along with GCC; see the file COPYING3. If not see
#include "json.h"
#include "selftest.h"
#include "logical-location.h"
-#include "make-unique.h"
class json_output_format;
@@ -74,7 +73,7 @@ public:
std::unique_ptr<diagnostic_per_format_buffer>
make_per_format_buffer () final override
{
- return ::make_unique<diagnostic_json_format_buffer> (*this);
+ return std::make_unique<diagnostic_json_format_buffer> (*this);
}
void set_buffer (diagnostic_per_format_buffer *base_buffer) final override
{
@@ -118,7 +117,7 @@ protected:
bool formatted)
: diagnostic_output_format (context),
m_buffer (nullptr),
- m_toplevel_array (::make_unique<json::array> ()),
+ m_toplevel_array (std::make_unique<json::array> ()),
m_cur_group (nullptr),
m_cur_children_array (nullptr),
m_formatted (formatted)
@@ -156,7 +155,7 @@ static std::unique_ptr<json::object>
json_from_expanded_location (diagnostic_context &context, location_t loc)
{
expanded_location exploc = expand_location (loc);
- std::unique_ptr<json::object> result = ::make_unique <json::object> ();
+ std::unique_ptr<json::object> result = std::make_unique <json::object> ();
if (exploc.file)
result->set_string ("file", exploc.file);
result->set_integer ("line", exploc.line);
@@ -200,7 +199,7 @@ json_from_location_range (diagnostic_context &context,
location_t start_loc = get_start (loc_range->m_loc);
location_t finish_loc = get_finish (loc_range->m_loc);
- std::unique_ptr<json::object> result = ::make_unique <json::object> ();
+ std::unique_ptr<json::object> result = std::make_unique <json::object> ();
result->set ("caret",
json_from_expanded_location (context, caret_loc));
if (start_loc != caret_loc
@@ -227,7 +226,7 @@ json_from_location_range (diagnostic_context &context,
static std::unique_ptr<json::object>
json_from_fixit_hint (diagnostic_context &context, const fixit_hint *hint)
{
- std::unique_ptr<json::object> fixit_obj = ::make_unique <json::object> ();
+ std::unique_ptr<json::object> fixit_obj = std::make_unique <json::object> ();
location_t start_loc = hint->get_start_loc ();
fixit_obj->set ("start",
@@ -245,7 +244,7 @@ json_from_fixit_hint (diagnostic_context &context, const fixit_hint *hint)
static std::unique_ptr<json::object>
json_from_metadata (const diagnostic_metadata *metadata)
{
- std::unique_ptr<json::object> metadata_obj = ::make_unique <json::object> ();
+ std::unique_ptr<json::object> metadata_obj = std::make_unique <json::object> ();
if (metadata->get_cwe ())
metadata_obj->set_integer ("cwe", metadata->get_cwe ());
@@ -260,12 +259,12 @@ make_json_for_path (diagnostic_context &context,
pretty_printer *ref_pp,
const diagnostic_path *path)
{
- std::unique_ptr<json::array> path_array = ::make_unique<json::array> ();
+ std::unique_ptr<json::array> path_array = std::make_unique<json::array> ();
for (unsigned i = 0; i < path->num_events (); i++)
{
const diagnostic_event &event = path->get_event (i);
- std::unique_ptr<json::object> event_obj = ::make_unique <json::object> ();
+ std::unique_ptr<json::object> event_obj = std::make_unique <json::object> ();
if (event.get_location ())
event_obj->set ("location",
json_from_expanded_location (context,
@@ -395,7 +394,7 @@ json_output_format::on_report_diagnostic (const diagnostic_info &diagnostic,
add a "children" array and record the column origin. */
m_cur_group = diag_obj;
std::unique_ptr<json::array> children_array
- = ::make_unique<json::array> ();
+ = std::make_unique<json::array> ();
m_cur_children_array = children_array.get (); // borrowed
diag_obj->set ("children", std::move (children_array));
diag_obj->set_integer ("column-origin", m_context.m_column_origin);
@@ -409,7 +408,7 @@ json_output_format::on_report_diagnostic (const diagnostic_info &diagnostic,
const rich_location *richloc = diagnostic.richloc;
{
- std::unique_ptr<json::array> loc_array = ::make_unique<json::array> ();
+ std::unique_ptr<json::array> loc_array = std::make_unique<json::array> ();
for (unsigned int i = 0; i < richloc->get_num_locations (); i++)
{
const location_range *loc_range = richloc->get_range (i);
@@ -422,7 +421,7 @@ json_output_format::on_report_diagnostic (const diagnostic_info &diagnostic,
if (richloc->get_num_fixit_hints ())
{
- std::unique_ptr<json::array> fixit_array = ::make_unique<json::array> ();
+ std::unique_ptr<json::array> fixit_array = std::make_unique<json::array> ();
for (unsigned int i = 0; i < richloc->get_num_fixit_hints (); i++)
{
const fixit_hint *hint = richloc->get_fixit_hint (i);
@@ -524,8 +523,8 @@ diagnostic_output_format_init_json_stderr (diagnostic_context &context,
{
diagnostic_output_format_init_json
(context,
- ::make_unique<json_stderr_output_format> (context,
- formatted));
+ std::make_unique<json_stderr_output_format> (context,
+ formatted));
}
/* Populate CONTEXT in preparation for JSON output to a file named
@@ -538,9 +537,9 @@ diagnostic_output_format_init_json_file (diagnostic_context &context,
{
diagnostic_output_format_init_json
(context,
- ::make_unique<json_file_output_format> (context,
- formatted,
- base_file_name));
+ std::make_unique<json_file_output_format> (context,
+ formatted,
+ base_file_name));
}
#if CHECKING_P
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index 8dbc91e..f322991 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -41,7 +41,6 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-format-text.h"
#include "ordered-hash-map.h"
#include "sbitmap.h"
-#include "make-unique.h"
#include "selftest.h"
#include "selftest-diagnostic.h"
#include "selftest-diagnostic-show-locus.h"
@@ -158,7 +157,7 @@ make_date_time_string_for_current_time ()
"%02i:%02i:%02iZ"),
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
- return ::make_unique<json::string> (buf);
+ return std::make_unique<json::string> (buf);
}
/* Subclass of sarif_object for SARIF "invocation" objects
@@ -689,7 +688,7 @@ public:
const line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version);
+ const sarif_generation_options &sarif_gen_opts);
~sarif_builder ();
void set_printer (pretty_printer &printer)
@@ -743,7 +742,7 @@ public:
diagnostic_context &get_context () const { return m_context; }
pretty_printer *get_printer () const { return m_printer; }
token_printer &get_token_printer () { return m_token_printer; }
- enum sarif_version get_version () const { return m_version; }
+ enum sarif_version get_version () const { return m_sarif_gen_opts.m_version; }
size_t num_results () const { return m_results_array->size (); }
sarif_result &get_result (size_t idx)
@@ -753,6 +752,8 @@ public:
return *static_cast<sarif_result *> (element);
}
+ const sarif_generation_options &get_opts () const { return m_sarif_gen_opts; }
+
private:
class sarif_token_printer : public token_printer
{
@@ -865,7 +866,6 @@ private:
pretty_printer *m_printer;
const line_maps *m_line_maps;
sarif_token_printer m_token_printer;
- enum sarif_version m_version;
/* The JSON object for the invocation object. */
std::unique_ptr<sarif_invocation> m_invocation_obj;
@@ -892,6 +892,7 @@ private:
int m_tabstop;
bool m_formatted;
+ const sarif_generation_options m_sarif_gen_opts;
unsigned m_next_result_idx;
sarif_code_flow *m_current_code_flow;
@@ -918,13 +919,13 @@ sarif_object::get_or_create_properties ()
sarif_invocation::sarif_invocation (sarif_builder &builder,
const char * const *original_argv)
-: m_notifications_arr (::make_unique<json::array> ()),
+: m_notifications_arr (std::make_unique<json::array> ()),
m_success (true)
{
// "arguments" property (SARIF v2.1.0 section 3.20.2)
if (original_argv)
{
- auto arguments_arr = ::make_unique<json::array> ();
+ auto arguments_arr = std::make_unique<json::array> ();
for (size_t i = 0; original_argv[i]; ++i)
arguments_arr->append_string (original_argv[i]);
set<json::array> ("arguments", std::move (arguments_arr));
@@ -951,9 +952,9 @@ sarif_invocation::add_notification_for_ice (const diagnostic_info &diagnostic,
m_success = false;
auto notification
- = ::make_unique<sarif_ice_notification> (diagnostic,
- builder,
- std::move (backtrace));
+ = std::make_unique<sarif_ice_notification> (diagnostic,
+ builder,
+ std::move (backtrace));
/* Support for related locations within a notification was added
in SARIF 2.2; see https://github.com/oasis-tcs/sarif-spec/issues/540 */
@@ -1068,7 +1069,7 @@ sarif_artifact::populate_roles ()
{
if (bitmap_empty_p (m_roles))
return;
- auto roles_arr (::make_unique<json::array> ());
+ auto roles_arr (std::make_unique<json::array> ());
for (int i = 0; i < (int)diagnostic_artifact_role::NUM_ROLES; i++)
if (bitmap_bit_p (m_roles, i))
{
@@ -1245,7 +1246,7 @@ void
sarif_result::on_diagram (const diagnostic_diagram &diagram,
sarif_builder &builder)
{
- auto location_obj = ::make_unique<sarif_location> ();
+ auto location_obj = std::make_unique<sarif_location> ();
auto message_obj = builder.make_message_object_for_diagram (diagram);
location_obj->set<sarif_message> ("message", std::move (message_obj));
@@ -1344,7 +1345,7 @@ sarif_location::lazily_add_relationship_object (sarif_location &target,
/* No existing locationRelationship from THIS to TARGET; make one,
record it, and add it to the "relationships" array. */
auto relationship_obj
- = ::make_unique<sarif_location_relationship> (target, loc_mgr);
+ = std::make_unique<sarif_location_relationship> (target, loc_mgr);
sarif_location_relationship *relationship = relationship_obj.get ();
auto kv
= std::pair<sarif_location *,
@@ -1472,7 +1473,7 @@ sarif_code_flow::sarif_code_flow (sarif_result &parent,
m_idx_within_parent (idx_within_parent)
{
/* "threadFlows" property (SARIF v2.1.0 section 3.36.3). */
- auto thread_flows_arr = ::make_unique<json::array> ();
+ auto thread_flows_arr = std::make_unique<json::array> ();
m_thread_flows_arr = thread_flows_arr.get (); // borrowed
set<json::array> ("threadFlows", std::move (thread_flows_arr));
}
@@ -1487,7 +1488,7 @@ sarif_code_flow::get_or_append_thread_flow (const diagnostic_thread &thread,
unsigned next_thread_flow_idx = m_thread_flows_arr->size ();
auto thread_flow_obj
- = ::make_unique<sarif_thread_flow> (*this, thread, next_thread_flow_idx);
+ = std::make_unique<sarif_thread_flow> (*this, thread, next_thread_flow_idx);
m_thread_id_map.put (thread_id, thread_flow_obj.get ()); // borrowed
sarif_thread_flow *result = thread_flow_obj.get ();
m_thread_flows_arr->append<sarif_thread_flow> (std::move (thread_flow_obj));
@@ -1561,15 +1562,14 @@ sarif_builder::sarif_builder (diagnostic_context &context,
const line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version)
+ const sarif_generation_options &sarif_gen_opts)
: m_context (context),
m_printer (&printer),
m_line_maps (line_maps),
m_token_printer (*this),
- m_version (version),
m_invocation_obj
- (::make_unique<sarif_invocation> (*this,
- context.get_original_argv ())),
+ (std::make_unique<sarif_invocation> (*this,
+ context.get_original_argv ())),
m_results_array (new json::array ()),
m_cur_group_result (nullptr),
m_seen_any_relative_paths (false),
@@ -1577,6 +1577,7 @@ sarif_builder::sarif_builder (diagnostic_context &context,
m_rules_arr (new json::array ()),
m_tabstop (context.m_tabstop),
m_formatted (formatted),
+ m_sarif_gen_opts (sarif_gen_opts),
m_next_result_idx (0),
m_current_code_flow (nullptr)
{
@@ -1685,7 +1686,7 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
}
}
- auto frame_obj = ::make_unique<json::object> ();
+ auto frame_obj = std::make_unique<json::object> ();
/* I tried using sarifStack and sarifStackFrame for this
but it's not a good fit e.g. PC information. */
@@ -1711,7 +1712,7 @@ bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
std::unique_ptr<json::object>
sarif_builder::make_stack_from_backtrace ()
{
- auto frames_arr = ::make_unique<json::array> ();
+ auto frames_arr = std::make_unique<json::array> ();
backtrace_state *state = nullptr;
state = backtrace_create_state (nullptr, 0, nullptr, nullptr);
@@ -1724,7 +1725,7 @@ sarif_builder::make_stack_from_backtrace ()
if (frames_arr->size () == 0)
return nullptr;
- auto stack = ::make_unique<json::object> ();
+ auto stack = std::make_unique<json::object> ();
stack->set ("frames", std::move (frames_arr));
return stack;
}
@@ -1873,7 +1874,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
diagnostic_t orig_diag_kind,
unsigned idx_within_parent)
{
- auto result_obj = ::make_unique<sarif_result> (idx_within_parent);
+ auto result_obj = std::make_unique<sarif_result> (idx_within_parent);
/* "ruleId" property (SARIF v2.1.0 section 3.27.5). */
/* Ideally we'd have an option_name for these. */
@@ -1914,7 +1915,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
/* "taxa" property (SARIF v2.1.0 section 3.27.8). */
if (int cwe_id = diagnostic.metadata->get_cwe ())
{
- auto taxa_arr = ::make_unique<json::array> ();
+ auto taxa_arr = std::make_unique<json::array> ();
taxa_arr->append<sarif_reporting_descriptor_reference>
(make_reporting_descriptor_reference_object_for_cwe_id (cwe_id));
result_obj->set<json::array> ("taxa", std::move (taxa_arr));
@@ -1945,7 +1946,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
/* "codeFlows" property (SARIF v2.1.0 section 3.27.18). */
if (const diagnostic_path *path = diagnostic.richloc->get_path ())
{
- auto code_flows_arr = ::make_unique<json::array> ();
+ auto code_flows_arr = std::make_unique<json::array> ();
const unsigned code_flow_index = 0;
code_flows_arr->append<sarif_code_flow>
(make_code_flow_object (*result_obj.get (),
@@ -1962,7 +1963,7 @@ sarif_builder::make_result_object (const diagnostic_info &diagnostic,
const rich_location *richloc = diagnostic.richloc;
if (richloc->get_num_fixit_hints ())
{
- auto fix_arr = ::make_unique<json::array> ();
+ auto fix_arr = std::make_unique<json::array> ();
fix_arr->append<sarif_fix> (make_fix_object (*richloc));
result_obj->set<json::array> ("fixes", std::move (fix_arr));
}
@@ -1979,7 +1980,7 @@ make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic,
diagnostic_t /*orig_diag_kind*/,
const char *option_text)
{
- auto reporting_desc = ::make_unique<sarif_reporting_descriptor> ();
+ auto reporting_desc = std::make_unique<sarif_reporting_descriptor> ();
/* "id" property (SARIF v2.1.0 section 3.49.3). */
reporting_desc->set_string ("id", option_text);
@@ -2003,7 +2004,7 @@ make_reporting_descriptor_object_for_warning (const diagnostic_info &diagnostic,
std::unique_ptr<sarif_reporting_descriptor>
sarif_builder::make_reporting_descriptor_object_for_cwe_id (int cwe_id) const
{
- auto reporting_desc = ::make_unique<sarif_reporting_descriptor> ();
+ auto reporting_desc = std::make_unique<sarif_reporting_descriptor> ();
/* "id" property (SARIF v2.1.0 section 3.49.3). */
{
@@ -2030,7 +2031,7 @@ std::unique_ptr<sarif_reporting_descriptor_reference>
sarif_builder::
make_reporting_descriptor_reference_object_for_cwe_id (int cwe_id)
{
- auto desc_ref_obj = ::make_unique<sarif_reporting_descriptor_reference> ();
+ auto desc_ref_obj = std::make_unique<sarif_reporting_descriptor_reference> ();
/* "id" property (SARIF v2.1.0 section 3.52.4). */
{
@@ -2057,7 +2058,7 @@ std::unique_ptr<sarif_tool_component_reference>
sarif_builder::
make_tool_component_reference_object_for_cwe () const
{
- auto comp_ref_obj = ::make_unique<sarif_tool_component_reference> ();
+ auto comp_ref_obj = std::make_unique<sarif_tool_component_reference> ();
/* "name" property (SARIF v2.1.0 section 3.54.3). */
comp_ref_obj->set_string ("name", "cwe");
@@ -2075,7 +2076,7 @@ sarif_builder::make_locations_arr (sarif_location_manager &loc_mgr,
const diagnostic_info &diagnostic,
enum diagnostic_artifact_role role)
{
- auto locations_arr = ::make_unique<json::array> ();
+ auto locations_arr = std::make_unique<json::array> ();
const logical_location *logical_loc = nullptr;
if (auto client_data_hooks = m_context.get_client_data_hooks ())
logical_loc = client_data_hooks->get_current_logical_location ();
@@ -2099,7 +2100,7 @@ set_any_logical_locs_arr (sarif_location &location_obj,
{
if (!logical_loc)
return;
- auto location_locs_arr = ::make_unique<json::array> ();
+ auto location_locs_arr = std::make_unique<json::array> ();
location_locs_arr->append<sarif_logical_location>
(make_sarif_logical_location_object (*logical_loc));
location_obj.set<json::array> ("logicalLocations",
@@ -2159,7 +2160,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
} the_renderer (rich_loc,
m_context.get_escape_format ());
- auto location_obj = ::make_unique<sarif_location> ();
+ auto location_obj = std::make_unique<sarif_location> ();
/* Get primary loc from RICH_LOC. */
location_t loc = rich_loc.get_loc ();
@@ -2197,7 +2198,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
if (region)
{
if (!annotations_arr)
- annotations_arr = ::make_unique<json::array> ();
+ annotations_arr = std::make_unique<json::array> ();
region->set<sarif_message>
("message", make_message_object (text.get ()));
annotations_arr->append<sarif_region> (std::move (region));
@@ -2277,7 +2278,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
location_t loc,
enum diagnostic_artifact_role role)
{
- auto location_obj = ::make_unique<sarif_location> ();
+ auto location_obj = std::make_unique<sarif_location> ();
/* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
if (auto phs_loc_obj
@@ -2298,7 +2299,7 @@ sarif_builder::make_location_object (sarif_location_manager &loc_mgr,
const diagnostic_event &event,
enum diagnostic_artifact_role role)
{
- auto location_obj = ::make_unique<sarif_location> ();
+ auto location_obj = std::make_unique<sarif_location> ();
/* "physicalLocation" property (SARIF v2.1.0 section 3.28.3). */
location_t loc = event.get_location ();
@@ -2342,7 +2343,7 @@ maybe_make_physical_location_object (location_t loc,
if (loc <= BUILTINS_LOCATION || LOCATION_FILE (loc) == nullptr)
return nullptr;
- auto phys_loc_obj = ::make_unique<sarif_physical_location> ();
+ auto phys_loc_obj = std::make_unique<sarif_physical_location> ();
/* "artifactLocation" property (SARIF v2.1.0 section 3.29.3). */
phys_loc_obj->set<sarif_artifact_location>
@@ -2386,7 +2387,7 @@ sarif_builder::make_artifact_location_object (location_t loc)
std::unique_ptr<sarif_artifact_location>
sarif_builder::make_artifact_location_object (const char *filename)
{
- auto artifact_loc_obj = ::make_unique<sarif_artifact_location> ();
+ auto artifact_loc_obj = std::make_unique<sarif_artifact_location> ();
/* "uri" property (SARIF v2.1.0 section 3.4.3). */
artifact_loc_obj->set_string ("uri", filename);
@@ -2432,7 +2433,7 @@ make_pwd_uri_str ()
std::unique_ptr<sarif_artifact_location>
sarif_builder::make_artifact_location_object_for_pwd () const
{
- auto artifact_loc_obj = ::make_unique<sarif_artifact_location> ();
+ auto artifact_loc_obj = std::make_unique<sarif_artifact_location> ();
/* "uri" property (SARIF v2.1.0 section 3.4.3). */
if (char *pwd = make_pwd_uri_str ())
@@ -2492,7 +2493,7 @@ sarif_builder::maybe_make_region_object (location_t loc,
if (exploc_start.line <= 0)
return nullptr;
- auto region_obj = ::make_unique<sarif_region> ();
+ auto region_obj = std::make_unique<sarif_region> ();
/* "startLine" property (SARIF v2.1.0 section 3.30.5) */
region_obj->set_integer ("startLine", exploc_start.line);
@@ -2569,7 +2570,7 @@ maybe_make_region_object_for_context (location_t loc,
if (exploc_start.line <= 0)
return nullptr;
- auto region_obj = ::make_unique<sarif_region> ();
+ auto region_obj = std::make_unique<sarif_region> ();
/* "startLine" property (SARIF v2.1.0 section 3.30.5) */
region_obj->set_integer ("startLine", exploc_start.line);
@@ -2603,7 +2604,7 @@ sarif_builder::make_region_object_for_hint (const fixit_hint &hint) const
expanded_location exploc_start = expand_location (start_loc);
expanded_location exploc_next = expand_location (next_loc);
- auto region_obj = ::make_unique<sarif_region> ();
+ auto region_obj = std::make_unique<sarif_region> ();
/* "startLine" property (SARIF v2.1.0 section 3.30.5) */
region_obj->set_integer ("startLine", exploc_start.line);
@@ -2663,7 +2664,7 @@ maybe_get_sarif_kind (enum logical_location_kind kind)
std::unique_ptr<sarif_logical_location>
make_sarif_logical_location_object (const logical_location &logical_loc)
{
- auto logical_loc_obj = ::make_unique<sarif_logical_location> ();
+ auto logical_loc_obj = std::make_unique<sarif_logical_location> ();
/* "name" property (SARIF v2.1.0 section 3.33.4). */
if (const char *short_name = logical_loc.get_short_name ())
@@ -2724,7 +2725,7 @@ sarif_builder::make_code_flow_object (sarif_result &result,
const diagnostic_path &path)
{
auto code_flow_obj
- = ::make_unique <sarif_code_flow> (result, idx_within_parent);
+ = std::make_unique <sarif_code_flow> (result, idx_within_parent);
/* First pass:
Create threadFlows and threadFlowLocation objects within them,
@@ -2809,7 +2810,7 @@ sarif_builder::maybe_make_kinds_array (diagnostic_event::meaning m) const
&& m.m_property == diagnostic_event::PROPERTY_unknown)
return nullptr;
- auto kinds_arr = ::make_unique<json::array> ();
+ auto kinds_arr = std::make_unique<json::array> ();
if (const char *verb_str
= diagnostic_event::meaning::maybe_get_verb_str (m.m_verb))
kinds_arr->append_string (verb_str);
@@ -2859,7 +2860,7 @@ set_string_property_escaping_braces (json::object &obj,
std::unique_ptr<sarif_message>
sarif_builder::make_message_object (const char *msg) const
{
- auto message_obj = ::make_unique<sarif_message> ();
+ auto message_obj = std::make_unique<sarif_message> ();
/* "text" property (SARIF v2.1.0 section 3.11.8). */
set_string_property_escaping_braces (*message_obj,
@@ -2875,7 +2876,7 @@ sarif_builder::make_message_object (const char *msg) const
std::unique_ptr<sarif_message>
sarif_builder::make_message_object_for_diagram (const diagnostic_diagram &diagram)
{
- auto message_obj = ::make_unique<sarif_message> ();
+ auto message_obj = std::make_unique<sarif_message> ();
/* "text" property (SARIF v2.1.0 section 3.11.8). */
set_string_property_escaping_braces (*message_obj,
@@ -2906,7 +2907,7 @@ sarif_builder::make_message_object_for_diagram (const diagnostic_diagram &diagra
std::unique_ptr<sarif_multiformat_message_string>
sarif_builder::make_multiformat_message_string (const char *msg) const
{
- auto message_obj = ::make_unique<sarif_multiformat_message_string> ();
+ auto message_obj = std::make_unique<sarif_multiformat_message_string> ();
/* "text" property (SARIF v2.1.0 section 3.12.3). */
set_string_property_escaping_braces (*message_obj,
@@ -2958,16 +2959,16 @@ sarif_builder::
make_top_level_object (std::unique_ptr<sarif_invocation> invocation_obj,
std::unique_ptr<json::array> results)
{
- auto log_obj = ::make_unique<sarif_log> ();
+ auto log_obj = std::make_unique<sarif_log> ();
/* "$schema" property (SARIF v2.1.0 section 3.13.3) . */
- log_obj->set_string ("$schema", sarif_version_to_url (m_version));
+ log_obj->set_string ("$schema", sarif_version_to_url (get_version ()));
/* "version" property (SARIF v2.1.0 section 3.13.2). */
- log_obj->set_string ("version", sarif_version_to_property (m_version));
+ log_obj->set_string ("version", sarif_version_to_property (get_version ()));
/* "runs" property (SARIF v2.1.0 section 3.13.4). */
- auto run_arr = ::make_unique<json::array> ();
+ auto run_arr = std::make_unique<json::array> ();
auto run_obj = make_run_object (std::move (invocation_obj),
std::move (results));
run_arr->append<sarif_run> (std::move (run_obj));
@@ -2983,7 +2984,7 @@ sarif_builder::
make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
std::unique_ptr<json::array> results)
{
- auto run_obj = ::make_unique<sarif_run> ();
+ auto run_obj = std::make_unique<sarif_run> ();
/* "tool" property (SARIF v2.1.0 section 3.14.6). */
run_obj->set<sarif_tool> ("tool", make_tool_object ());
@@ -2994,7 +2995,7 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
/* "invocations" property (SARIF v2.1.0 section 3.14.11). */
{
- auto invocations_arr = ::make_unique<json::array> ();
+ auto invocations_arr = std::make_unique<json::array> ();
invocations_arr->append (std::move (invocation_obj));
run_obj->set<json::array> ("invocations", std::move (invocations_arr));
}
@@ -3002,7 +3003,7 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
/* "originalUriBaseIds (SARIF v2.1.0 section 3.14.14). */
if (m_seen_any_relative_paths)
{
- auto orig_uri_base_ids = ::make_unique<json::object> ();
+ auto orig_uri_base_ids = std::make_unique<json::object> ();
orig_uri_base_ids->set<sarif_artifact_location>
(PWD_PROPERTY_NAME, make_artifact_location_object_for_pwd ());
run_obj->set<json::object> ("originalUriBaseIds",
@@ -3010,7 +3011,7 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
}
/* "artifacts" property (SARIF v2.1.0 section 3.14.15). */
- auto artifacts_arr = ::make_unique<json::array> ();
+ auto artifacts_arr = std::make_unique<json::array> ();
for (auto iter : m_filename_to_artifact_map)
{
sarif_artifact *artifact_obj = iter.second;
@@ -3033,7 +3034,7 @@ make_run_object (std::unique_ptr<sarif_invocation> invocation_obj,
std::unique_ptr<sarif_tool>
sarif_builder::make_tool_object ()
{
- auto tool_obj = ::make_unique<sarif_tool> ();
+ auto tool_obj = std::make_unique<sarif_tool> ();
/* "driver" property (SARIF v2.1.0 section 3.18.2). */
tool_obj->set<sarif_tool_component> ("driver",
@@ -3052,7 +3053,7 @@ sarif_builder::make_tool_object ()
{
/* Create a "toolComponent" object (SARIF v2.1.0 section 3.19)
for the plugin. */
- auto plugin_obj = ::make_unique<sarif_tool_component> ();
+ auto plugin_obj = std::make_unique<sarif_tool_component> ();
/* "name" property (SARIF v2.1.0 section 3.19.8). */
if (const char *short_name = p.get_short_name ())
@@ -3074,7 +3075,7 @@ sarif_builder::make_tool_object ()
vinfo->for_each_plugin (v);
if (v.m_plugin_objs.size () > 0)
{
- auto extensions_arr = ::make_unique<json::array> ();
+ auto extensions_arr = std::make_unique<json::array> ();
for (auto &iter : v.m_plugin_objs)
extensions_arr->append<sarif_tool_component> (std::move (iter));
tool_obj->set<json::array> ("extensions",
@@ -3094,7 +3095,7 @@ sarif_builder::make_tool_object ()
std::unique_ptr<sarif_tool_component>
sarif_builder::make_driver_tool_component_object ()
{
- auto driver_obj = ::make_unique<sarif_tool_component> ();
+ auto driver_obj = std::make_unique<sarif_tool_component> ();
if (auto client_data_hooks = m_context.get_client_data_hooks ())
if (const client_version_info *vinfo
@@ -3143,7 +3144,7 @@ sarif_builder::maybe_make_taxonomies_array () const
return nullptr;
/* "taxonomies" property (SARIF v2.1.0 section 3.14.8). */
- auto taxonomies_arr = ::make_unique<json::array> ();
+ auto taxonomies_arr = std::make_unique<json::array> ();
taxonomies_arr->append<sarif_tool_component> (std::move (cwe_obj));
return taxonomies_arr;
}
@@ -3160,7 +3161,7 @@ sarif_builder::maybe_make_cwe_taxonomy_object () const
if (m_cwe_id_set.is_empty ())
return nullptr;
- auto taxonomy_obj = ::make_unique<sarif_tool_component> ();
+ auto taxonomy_obj = std::make_unique<sarif_tool_component> ();
/* "name" property (SARIF v2.1.0 section 3.19.8). */
taxonomy_obj->set_string ("name", "CWE");
@@ -3178,7 +3179,7 @@ sarif_builder::maybe_make_cwe_taxonomy_object () const
" Common Weakness Enumeration"));
/* "taxa" property (SARIF v2.1.0 3.section 3.19.25). */
- auto taxa_arr = ::make_unique<json::array> ();
+ auto taxa_arr = std::make_unique<json::array> ();
for (auto cwe_id : m_cwe_id_set)
taxa_arr->append<sarif_reporting_descriptor>
(make_reporting_descriptor_object_for_cwe_id (cwe_id));
@@ -3252,10 +3253,10 @@ sarif_builder::maybe_make_artifact_content_object (const char *filename) const
if (!cpp_valid_utf8_p(utf8_content.get_buffer (), utf8_content.length ()))
return nullptr;
- auto artifact_content_obj = ::make_unique<sarif_artifact_content> ();
+ auto artifact_content_obj = std::make_unique<sarif_artifact_content> ();
artifact_content_obj->set<json::string>
("text",
- ::make_unique <json::string> (utf8_content.get_buffer (),
+ std::make_unique <json::string> (utf8_content.get_buffer (),
utf8_content.length ()));
return artifact_content_obj;
}
@@ -3310,7 +3311,7 @@ maybe_make_artifact_content_object (const char *filename,
return nullptr;
}
- auto artifact_content_obj = ::make_unique<sarif_artifact_content> ();
+ auto artifact_content_obj = std::make_unique<sarif_artifact_content> ();
artifact_content_obj->set_string ("text", text_utf8);
free (text_utf8);
@@ -3328,11 +3329,11 @@ maybe_make_artifact_content_object (const char *filename,
std::unique_ptr<sarif_fix>
sarif_builder::make_fix_object (const rich_location &richloc)
{
- auto fix_obj = ::make_unique<sarif_fix> ();
+ auto fix_obj = std::make_unique<sarif_fix> ();
/* "artifactChanges" property (SARIF v2.1.0 section 3.55.3). */
/* We assume that all fix-it hints in RICHLOC affect the same file. */
- auto artifact_change_arr = ::make_unique<json::array> ();
+ auto artifact_change_arr = std::make_unique<json::array> ();
artifact_change_arr->append<sarif_artifact_change>
(make_artifact_change_object (richloc));
fix_obj->set<json::array> ("artifactChanges",
@@ -3346,7 +3347,7 @@ sarif_builder::make_fix_object (const rich_location &richloc)
std::unique_ptr<sarif_artifact_change>
sarif_builder::make_artifact_change_object (const rich_location &richloc)
{
- auto artifact_change_obj = ::make_unique<sarif_artifact_change> ();
+ auto artifact_change_obj = std::make_unique<sarif_artifact_change> ();
/* "artifactLocation" property (SARIF v2.1.0 section 3.56.2). */
artifact_change_obj->set<sarif_artifact_location>
@@ -3354,7 +3355,7 @@ sarif_builder::make_artifact_change_object (const rich_location &richloc)
make_artifact_location_object (richloc.get_loc ()));
/* "replacements" property (SARIF v2.1.0 section 3.56.3). */
- auto replacement_arr = ::make_unique<json::array> ();
+ auto replacement_arr = std::make_unique<json::array> ();
for (unsigned int i = 0; i < richloc.get_num_fixit_hints (); i++)
{
const fixit_hint *hint = richloc.get_fixit_hint (i);
@@ -3372,7 +3373,7 @@ sarif_builder::make_artifact_change_object (const rich_location &richloc)
std::unique_ptr<sarif_replacement>
sarif_builder::make_replacement_object (const fixit_hint &hint) const
{
- auto replacement_obj = ::make_unique<sarif_replacement> ();
+ auto replacement_obj = std::make_unique<sarif_replacement> ();
/* "deletedRegion" property (SARIF v2.1.0 section 3.57.3). */
replacement_obj->set<sarif_region> ("deletedRegion",
@@ -3391,7 +3392,7 @@ sarif_builder::make_replacement_object (const fixit_hint &hint) const
std::unique_ptr<sarif_artifact_content>
sarif_builder::make_artifact_content_object (const char *text) const
{
- auto content_obj = ::make_unique<sarif_artifact_content> ();
+ auto content_obj = std::make_unique<sarif_artifact_content> ();
/* "text" property (SARIF v2.1.0 section 3.3.2). */
content_obj->set_string ("text", text);
@@ -3470,7 +3471,7 @@ public:
std::unique_ptr<diagnostic_per_format_buffer>
make_per_format_buffer () final override
{
- return ::make_unique<diagnostic_sarif_format_buffer> (m_builder);
+ return std::make_unique<diagnostic_sarif_format_buffer> (m_builder);
}
void set_buffer (diagnostic_per_format_buffer *base_buffer) final override
{
@@ -3534,10 +3535,10 @@ protected:
const line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version)
+ const sarif_generation_options &sarif_gen_opts)
: diagnostic_output_format (context),
m_builder (context, *get_printer (), line_maps, main_input_filename_,
- formatted, version),
+ formatted, sarif_gen_opts),
m_buffer (nullptr)
{}
@@ -3552,10 +3553,11 @@ public:
const line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version,
+ const sarif_generation_options &sarif_gen_opts,
FILE *stream)
: sarif_output_format (context, line_maps, main_input_filename_,
- formatted, version),
+ formatted,
+ sarif_gen_opts),
m_stream (stream)
{
}
@@ -3578,10 +3580,10 @@ public:
const line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version,
+ const sarif_generation_options &sarif_gen_opts,
diagnostic_output_file output_file)
: sarif_output_format (context, line_maps, main_input_filename_,
- formatted, version),
+ formatted, sarif_gen_opts),
m_output_file (std::move (output_file))
{
gcc_assert (m_output_file.get_open_file ());
@@ -3741,18 +3743,18 @@ void
diagnostic_output_format_init_sarif_stderr (diagnostic_context &context,
const line_maps *line_maps,
const char *main_input_filename_,
- bool formatted,
- enum sarif_version version)
+ bool formatted)
{
gcc_assert (line_maps);
+ const sarif_generation_options sarif_gen_opts;
diagnostic_output_format_init_sarif
(context,
- ::make_unique<sarif_stream_output_format> (context,
- line_maps,
- main_input_filename_,
- formatted,
- version,
- stderr));
+ std::make_unique<sarif_stream_output_format> (context,
+ line_maps,
+ main_input_filename_,
+ formatted,
+ sarif_gen_opts,
+ stderr));
}
/* Attempt to open BASE_FILE_NAME.sarif for writing.
@@ -3798,7 +3800,6 @@ diagnostic_output_format_init_sarif_file (diagnostic_context &context,
line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version,
const char *base_file_name)
{
gcc_assert (line_maps);
@@ -3808,14 +3809,15 @@ diagnostic_output_format_init_sarif_file (diagnostic_context &context,
line_maps,
base_file_name);
+ const sarif_generation_options sarif_gen_opts;
diagnostic_output_format_init_sarif
(context,
- ::make_unique<sarif_file_output_format> (context,
- line_maps,
- main_input_filename_,
- formatted,
- version,
- std::move (output_file)));
+ std::make_unique<sarif_file_output_format> (context,
+ line_maps,
+ main_input_filename_,
+ formatted,
+ sarif_gen_opts,
+ std::move (output_file)));
}
/* Populate CONTEXT in preparation for SARIF output to STREAM. */
@@ -3825,37 +3827,46 @@ diagnostic_output_format_init_sarif_stream (diagnostic_context &context,
const line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version,
FILE *stream)
{
gcc_assert (line_maps);
+ const sarif_generation_options sarif_gen_opts;
diagnostic_output_format_init_sarif
(context,
- ::make_unique<sarif_stream_output_format> (context,
- line_maps,
- main_input_filename_,
- formatted,
- version,
- stream));
+ std::make_unique<sarif_stream_output_format> (context,
+ line_maps,
+ main_input_filename_,
+ formatted,
+ sarif_gen_opts,
+ stream));
}
std::unique_ptr<diagnostic_output_format>
make_sarif_sink (diagnostic_context &context,
const line_maps &line_maps,
const char *main_input_filename_,
- enum sarif_version version,
+ bool formatted,
+ const sarif_generation_options &sarif_gen_opts,
diagnostic_output_file output_file)
{
- auto sink = ::make_unique<sarif_file_output_format> (context,
- &line_maps,
- main_input_filename_,
- true,
- version,
- std::move (output_file));
+ auto sink
+ = std::make_unique<sarif_file_output_format> (context,
+ &line_maps,
+ main_input_filename_,
+ formatted,
+ sarif_gen_opts,
+ std::move (output_file));
sink->update_printer ();
return sink;
}
+// struct sarif_generation_options
+
+sarif_generation_options::sarif_generation_options ()
+: m_version (sarif_version::v2_1_0)
+{
+}
+
#if CHECKING_P
namespace selftest {
@@ -3868,13 +3879,13 @@ class test_sarif_diagnostic_context : public test_diagnostic_context
{
public:
test_sarif_diagnostic_context (const char *main_input_filename,
- enum sarif_version version)
+ const sarif_generation_options &sarif_gen_opts)
{
- auto format = ::make_unique<buffered_output_format> (*this,
- line_table,
- main_input_filename,
- true,
- version);
+ auto format = std::make_unique<buffered_output_format> (*this,
+ line_table,
+ main_input_filename,
+ true,
+ sarif_gen_opts);
m_format = format.get (); // borrowed
diagnostic_output_format_init_sarif (*this, std::move (format));
}
@@ -3895,9 +3906,9 @@ private:
const line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version)
+ const sarif_generation_options &sarif_gen_opts)
: sarif_output_format (context, line_maps, main_input_filename_,
- formatted, version)
+ formatted, sarif_gen_opts)
{
}
bool machine_readable_stderr_p () const final override
@@ -3917,8 +3928,8 @@ private:
with labels and escape-on-output. */
static void
-test_make_location_object (const line_table_case &case_,
- enum sarif_version version)
+test_make_location_object (const sarif_generation_options &sarif_gen_opts,
+ const line_table_case &case_)
{
diagnostic_show_locus_fixture_one_liner_utf8 f (case_);
location_t line_end = linemap_position_for_column (line_table, 31);
@@ -3930,7 +3941,7 @@ test_make_location_object (const line_table_case &case_,
test_diagnostic_context dc;
pretty_printer pp;
sarif_builder builder (dc, pp, line_table, "MAIN_INPUT_FILENAME",
- true, version);
+ true, sarif_gen_opts);
/* These "columns" are byte offsets, whereas later on the columns
in the generated SARIF use sarif_builder::get_sarif_column and
@@ -4041,9 +4052,9 @@ test_make_location_object (const line_table_case &case_,
Verify various basic properties. */
static void
-test_simple_log (enum sarif_version version)
+test_simple_log (const sarif_generation_options &sarif_gen_opts)
{
- test_sarif_diagnostic_context dc ("MAIN_INPUT_FILENAME", version);
+ test_sarif_diagnostic_context dc ("MAIN_INPUT_FILENAME", sarif_gen_opts);
rich_location richloc (line_table, UNKNOWN_LOCATION);
dc.report (DK_ERROR, richloc, nullptr, 0, "this is a test: %i", 42);
@@ -4052,6 +4063,7 @@ test_simple_log (enum sarif_version version)
// 3.13 sarifLog:
auto log = log_ptr.get ();
+ const enum sarif_version version = sarif_gen_opts.m_version;
ASSERT_JSON_STRING_PROPERTY_EQ (log, "$schema",
sarif_version_to_url (version));
ASSERT_JSON_STRING_PROPERTY_EQ (log, "version",
@@ -4158,8 +4170,8 @@ test_simple_log (enum sarif_version version)
/* As above, but with a "real" location_t. */
static void
-test_simple_log_2 (const line_table_case &case_,
- enum sarif_version version)
+test_simple_log_2 (const sarif_generation_options &sarif_gen_opts,
+ const line_table_case &case_)
{
auto_fix_quotes fix_quotes;
@@ -4174,7 +4186,7 @@ test_simple_log_2 (const line_table_case &case_,
if (line_end > LINE_MAP_MAX_LOCATION_WITH_COLS)
return;
- test_sarif_diagnostic_context dc (f.get_filename (), version);
+ test_sarif_diagnostic_context dc (f.get_filename (), sarif_gen_opts);
const location_t typo_loc
= make_location (linemap_position_for_column (line_table, 1),
@@ -4304,11 +4316,11 @@ get_message_from_log (const sarif_log *log)
/* Tests of messages with embedded links; see SARIF v2.1.0 3.11.6. */
static void
-test_message_with_embedded_link (enum sarif_version version)
+test_message_with_embedded_link (const sarif_generation_options &sarif_gen_opts)
{
auto_fix_quotes fix_quotes;
{
- test_sarif_diagnostic_context dc ("test.c", version);
+ test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
rich_location richloc (line_table, UNKNOWN_LOCATION);
dc.report (DK_ERROR, richloc, nullptr, 0,
"before %{text%} after",
@@ -4324,7 +4336,7 @@ test_message_with_embedded_link (enum sarif_version version)
/* Escaping in message text.
This is "EXAMPLE 1" from 3.11.6. */
{
- test_sarif_diagnostic_context dc ("test.c", version);
+ test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
rich_location richloc (line_table, UNKNOWN_LOCATION);
/* Disable "unquoted sequence of 2 consecutive punctuation
@@ -4364,8 +4376,8 @@ test_message_with_embedded_link (enum sarif_version version)
}
};
- test_sarif_diagnostic_context dc ("test.c", version);
- dc.push_owned_urlifier (::make_unique<test_urlifier> ());
+ test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
+ dc.push_owned_urlifier (std::make_unique<test_urlifier> ());
rich_location richloc (line_table, UNKNOWN_LOCATION);
dc.report (DK_ERROR, richloc, nullptr, 0,
"foo %<-foption%> %<unrecognized%> bar");
@@ -4382,11 +4394,11 @@ test_message_with_embedded_link (enum sarif_version version)
3.11.5 ("Messages with placeholders"). */
static void
-test_message_with_braces (enum sarif_version version)
+test_message_with_braces (const sarif_generation_options &sarif_gen_opts)
{
auto_fix_quotes fix_quotes;
{
- test_sarif_diagnostic_context dc ("test.c", version);
+ test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
rich_location richloc (line_table, UNKNOWN_LOCATION);
dc.report (DK_ERROR, richloc, nullptr, 0,
"open brace: %qs close brace: %qs",
@@ -4401,9 +4413,9 @@ test_message_with_braces (enum sarif_version version)
}
static void
-test_buffering (enum sarif_version version)
+test_buffering (const sarif_generation_options &sarif_gen_opts)
{
- test_sarif_diagnostic_context dc ("test.c", version);
+ test_sarif_diagnostic_context dc ("test.c", sarif_gen_opts);
diagnostic_buffer buf_a (dc);
diagnostic_buffer buf_b (dc);
@@ -4487,41 +4499,45 @@ test_buffering (enum sarif_version version)
}
}
+template <class ...ArgTypes>
static void
-run_tests_per_version (const line_table_case &case_)
+for_each_sarif_gen_option (void (*callback) (const sarif_generation_options &,
+ ArgTypes ...),
+ ArgTypes ...args)
{
+ sarif_generation_options sarif_gen_opts;
for (int version_idx = 0;
version_idx < (int)sarif_version::num_versions;
++version_idx)
{
- enum sarif_version version
- = static_cast<enum sarif_version> (version_idx);
+ sarif_gen_opts.m_version = static_cast<enum sarif_version> (version_idx);
- test_make_location_object (case_, version);
- test_simple_log_2 (case_, version);
+ callback (sarif_gen_opts, args...);
}
}
+static void
+run_line_table_case_tests_per_version (const line_table_case &case_)
+{
+ for_each_sarif_gen_option<const line_table_case &>
+ (test_make_location_object, case_);
+
+ for_each_sarif_gen_option<const line_table_case &>
+ (test_simple_log_2, case_);
+}
+
/* Run all of the selftests within this file. */
void
diagnostic_format_sarif_cc_tests ()
{
- for (int version_idx = 0;
- version_idx < (int)sarif_version::num_versions;
- ++version_idx)
- {
- enum sarif_version version
- = static_cast<enum sarif_version> (version_idx);
-
- test_simple_log (version);
- test_message_with_embedded_link (version);
- test_message_with_braces (version);
- test_buffering (version);
- }
+ for_each_sarif_gen_option (test_simple_log);
+ for_each_sarif_gen_option (test_message_with_embedded_link);
+ for_each_sarif_gen_option (test_message_with_braces);
+ for_each_sarif_gen_option (test_buffering);
- /* Run tests per (line-table-case, SARIF version) pair. */
- for_each_line_table_case (run_tests_per_version);
+ /* Run tests per (SARIF gen-option, line-table-case) pair. */
+ for_each_line_table_case (run_line_table_case_tests_per_version);
}
} // namespace selftest
diff --git a/gcc/diagnostic-format-sarif.h b/gcc/diagnostic-format-sarif.h
index 5dc6176..524a0c7 100644
--- a/gcc/diagnostic-format-sarif.h
+++ b/gcc/diagnostic-format-sarif.h
@@ -27,14 +27,6 @@ along with GCC; see the file COPYING3. If not see
class logical_location;
-enum class sarif_version
-{
- v2_1_0,
- v2_2_prerelease_2024_08_08,
-
- num_versions
-};
-
extern diagnostic_output_file
diagnostic_output_format_open_sarif_file (diagnostic_context &context,
line_maps *line_maps,
@@ -44,27 +36,45 @@ extern void
diagnostic_output_format_init_sarif_stderr (diagnostic_context &context,
const line_maps *line_maps,
const char *main_input_filename_,
- bool formatted,
- enum sarif_version version);
+ bool formatted);
extern void
diagnostic_output_format_init_sarif_file (diagnostic_context &context,
line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version,
const char *base_file_name);
extern void
diagnostic_output_format_init_sarif_stream (diagnostic_context &context,
const line_maps *line_maps,
const char *main_input_filename_,
bool formatted,
- enum sarif_version version,
FILE *stream);
+
+enum class sarif_version
+{
+ v2_1_0,
+ v2_2_prerelease_2024_08_08,
+
+ num_versions
+};
+
+/* A bundle of state for controlling what to put in SARIF output,
+ such as which version of SARIF to generate
+ (as opposed to SARIF *serialization* options, such as formatting). */
+
+struct sarif_generation_options
+{
+ sarif_generation_options ();
+
+ enum sarif_version m_version;
+};
+
extern std::unique_ptr<diagnostic_output_format>
make_sarif_sink (diagnostic_context &context,
const line_maps &line_maps,
const char *main_input_filename_,
- enum sarif_version version,
+ bool formatted,
+ const sarif_generation_options &sarif_gen_opts,
diagnostic_output_file output_file);
/* Concrete subclass of json::object for SARIF property bags
diff --git a/gcc/diagnostic-format-text.cc b/gcc/diagnostic-format-text.cc
index 9273973..5df3894 100644
--- a/gcc/diagnostic-format-text.cc
+++ b/gcc/diagnostic-format-text.cc
@@ -34,7 +34,6 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-format-text.h"
#include "diagnostic-buffer.h"
#include "text-art/theme.h"
-#include "make-unique.h"
/* Disable warnings about quoting issues in the pp_xxx calls below
that (intentionally) don't follow GCC diagnostic conventions. */
@@ -193,7 +192,7 @@ diagnostic_text_output_format::set_buffer (diagnostic_per_format_buffer *base)
std::unique_ptr<diagnostic_per_format_buffer>
diagnostic_text_output_format::make_per_format_buffer ()
{
- return ::make_unique<diagnostic_text_format_buffer> (*this);
+ return std::make_unique<diagnostic_text_format_buffer> (*this);
}
/* Implementation of diagnostic_output_format::on_report_diagnostic vfunc
diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc
index 07c76b6..429c4b1 100644
--- a/gcc/diagnostic.cc
+++ b/gcc/diagnostic.cc
@@ -49,7 +49,6 @@ along with GCC; see the file COPYING3. If not see
#include "pretty-print-urlifier.h"
#include "logical-location.h"
#include "diagnostic-buffer.h"
-#include "make-unique.h"
#ifdef HAVE_TERMIOS_H
# include <termios.h>
@@ -223,7 +222,7 @@ diagnostic_context::initialize (int n_opts)
{
/* Allocate a basic pretty-printer. Clients will replace this a
much more elaborated pretty-printer if they wish. */
- m_reference_printer = ::make_unique<pretty_printer> ().release ();
+ m_reference_printer = std::make_unique<pretty_printer> ().release ();
m_file_cache = new file_cache ();
m_diagnostic_counters.clear ();
@@ -1830,8 +1829,7 @@ diagnostic_output_format_init (diagnostic_context &context,
diagnostic_output_format_init_sarif_stderr (context,
line_table,
main_input_filename_,
- json_formatting,
- sarif_version::v2_1_0);
+ json_formatting);
break;
case DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE:
@@ -1839,7 +1837,6 @@ diagnostic_output_format_init (diagnostic_context &context,
line_table,
main_input_filename_,
json_formatting,
- sarif_version::v2_1_0,
base_file_name);
break;
}
diff --git a/gcc/diagnostic.h b/gcc/diagnostic.h
index 62bffd2..36f4a1c 100644
--- a/gcc/diagnostic.h
+++ b/gcc/diagnostic.h
@@ -772,6 +772,13 @@ public:
bool supports_fnotice_on_stderr_p () const;
+ /* Raise SIGABRT on any diagnostic of severity DK_ERROR or higher. */
+ void
+ set_abort_on_error (bool val)
+ {
+ m_abort_on_error = val;
+ }
+
private:
void error_recursion () ATTRIBUTE_NORETURN;
@@ -828,10 +835,10 @@ private:
each diagnostic, if known. */
bool m_show_option_requested;
-public:
/* True if we should raise a SIGABRT on errors. */
bool m_abort_on_error;
+public:
/* True if we should show the column number on diagnostics. */
bool m_show_column;
@@ -841,9 +848,9 @@ public:
/* True if permerrors are warnings. */
bool m_permissive;
- /* The index of the option to associate with turning permerrors into
- warnings. */
- int m_opt_permissive;
+ /* The option to associate with turning permerrors into warnings,
+ if any. */
+ diagnostic_option_id m_opt_permissive;
/* True if errors are fatal. */
bool m_fatal_errors;
@@ -1042,13 +1049,6 @@ diagnostic_text_finalizer (diagnostic_context *context)
#define diagnostic_context_auxiliary_data(DC) (DC)->m_client_aux_data
#define diagnostic_info_auxiliary_data(DI) (DI)->x_data
-/* Raise SIGABRT on any diagnostic of severity DK_ERROR or higher. */
-inline void
-diagnostic_abort_on_error (diagnostic_context *context)
-{
- context->m_abort_on_error = true;
-}
-
/* This diagnostic_context is used by front-ends that directly output
diagnostic messages without going through `error', `warning',
and similar functions. */
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 7fcf7de..d5a2bf6 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -513,6 +513,7 @@ Objective-C and Objective-C++ Dialects}.
-Wno-analyzer-tainted-divisor
-Wno-analyzer-tainted-offset
-Wno-analyzer-tainted-size
+-Wno-analyzer-throw-of-unexpected-type
-Wanalyzer-symbol-too-complex
-Wanalyzer-too-complex
-Wno-analyzer-undefined-behavior-ptrdiff
@@ -11008,6 +11009,7 @@ Enabling this option effectively enables the following warnings:
-Wanalyzer-tainted-divisor
-Wanalyzer-tainted-offset
-Wanalyzer-tainted-size
+-Wanalyzer-throw-of-unexpected-type
-Wanalyzer-undefined-behavior-ptrdiff
-Wanalyzer-undefined-behavior-strtok
-Wanalyzer-unsafe-call-within-signal-handler
@@ -11659,6 +11661,17 @@ attacker could inject an out-of-bounds access.
See @uref{https://cwe.mitre.org/data/definitions/129.html, CWE-129: Improper Validation of Array Index}.
+@opindex Wanalyzer-throw-of-unexpected-type
+@opindex Wno-analyzer-throw-of-unexpected-type
+@item -Wno-analyzer-throw-of-unexpected-type
+This warning requires @option{-fanalyzer} which enables it;
+use @option{-Wno-analyzer-throw-of-unexpected-type} to disable it.
+Dynamic exception specifications are only available in C++14 and earlier.
+
+This diagnostic warns for paths through the code in which a an exception
+is thrown from a function with a dynamic exception specification where
+the exception does not comply with the specification.
+
@opindex Wanalyzer-undefined-behavior-ptrdiff
@opindex Wno-analyzer-undefined-behavior-ptrdiff
@item -Wno-analyzer-undefined-behavior-ptrdiff
diff --git a/gcc/dumpfile.cc b/gcc/dumpfile.cc
index 65bd5c5..ebee8e5 100644
--- a/gcc/dumpfile.cc
+++ b/gcc/dumpfile.cc
@@ -40,7 +40,6 @@ along with GCC; see the file COPYING3. If not see
#include "optinfo-emit-json.h"
#include "stringpool.h" /* for get_identifier. */
#include "spellcheck.h"
-#include "make-unique.h"
#include "pretty-print-format-impl.h"
/* If non-NULL, return one past-the-end of the matching SUBPART of
@@ -638,9 +637,9 @@ make_item_for_dump_gimple_stmt (gimple *stmt, int spc, dump_flags_t dump_flags)
pp_newline (&pp);
std::unique_ptr<optinfo_item> item
- = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE,
- gimple_location (stmt),
- xstrdup (pp_formatted_text (&pp)));
+ = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE,
+ gimple_location (stmt),
+ xstrdup (pp_formatted_text (&pp)));
return item;
}
@@ -686,9 +685,9 @@ make_item_for_dump_gimple_expr (gimple *stmt, int spc, dump_flags_t dump_flags)
pp_gimple_stmt_1 (&pp, stmt, spc, dump_flags);
std::unique_ptr<optinfo_item> item
- = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE,
- gimple_location (stmt),
- xstrdup (pp_formatted_text (&pp)));
+ = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_GIMPLE,
+ gimple_location (stmt),
+ xstrdup (pp_formatted_text (&pp)));
return item;
}
@@ -740,8 +739,8 @@ make_item_for_dump_generic_expr (tree node, dump_flags_t dump_flags)
loc = EXPR_LOCATION (node);
std::unique_ptr<optinfo_item> item
- = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TREE, loc,
- xstrdup (pp_formatted_text (&pp)));
+ = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TREE, loc,
+ xstrdup (pp_formatted_text (&pp)));
return item;
}
@@ -785,8 +784,8 @@ make_item_for_dump_symtab_node (symtab_node *node)
{
location_t loc = DECL_SOURCE_LOCATION (node->decl);
std::unique_ptr<optinfo_item> item
- = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_SYMTAB_NODE, loc,
- xstrdup (node->dump_name ()));
+ = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_SYMTAB_NODE, loc,
+ xstrdup (node->dump_name ()));
return item;
}
@@ -847,7 +846,7 @@ dump_pretty_printer::stash_item (pp_token_list &formatted_tok_list,
gcc_assert (item.get ());
auto custom_data
- = ::make_unique<wrapped_optinfo_item> (std::move (item));
+ = std::make_unique<wrapped_optinfo_item> (std::move (item));
formatted_tok_list.push_back<pp_token_custom_data> (std::move (custom_data));
}
@@ -1013,8 +1012,8 @@ emit_any_pending_textual_chunks ()
char *formatted_text = xstrdup (pp_formatted_text (pp));
std::unique_ptr<optinfo_item> item
- = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
- formatted_text);
+ = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
+ formatted_text);
pp->emit_item (std::move (item), m_optinfo);
/* Clear the pending text by unwinding formatted_text back to the start
@@ -1085,8 +1084,8 @@ make_item_for_dump_dec (const poly_int<N, C> &value)
}
auto item
- = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
- xstrdup (pp_formatted_text (&pp)));
+ = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
+ xstrdup (pp_formatted_text (&pp)));
return item;
}
@@ -1164,8 +1163,8 @@ dump_context::begin_scope (const char *name,
pp_printf (&pp, "%s %s %s", "===", name, "===");
pp_newline (&pp);
std::unique_ptr<optinfo_item> item
- = make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
- xstrdup (pp_formatted_text (&pp)));
+ = std::make_unique<optinfo_item> (OPTINFO_ITEM_KIND_TEXT, UNKNOWN_LOCATION,
+ xstrdup (pp_formatted_text (&pp)));
emit_item (*item.get (), MSG_NOTE);
if (optinfo_enabled_p ())
diff --git a/gcc/gcc-attribute-urlifier.cc b/gcc/gcc-attribute-urlifier.cc
index d066624..fd3d629 100644
--- a/gcc/gcc-attribute-urlifier.cc
+++ b/gcc/gcc-attribute-urlifier.cc
@@ -29,7 +29,6 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "diagnostic.h"
#include "selftest.h"
-#include "make-unique.h"
#include "target.h"
/* class attribute_urlifier : public urlifier. */
diff --git a/gcc/gcc-urlifier.cc b/gcc/gcc-urlifier.cc
index a409458..677720b 100644
--- a/gcc/gcc-urlifier.cc
+++ b/gcc/gcc-urlifier.cc
@@ -28,7 +28,6 @@ along with GCC; see the file COPYING3. If not see
#include "options.h"
#include "diagnostic.h"
#include "selftest.h"
-#include "make-unique.h"
char *
make_doc_url (const char *doc_url_suffix)
@@ -215,7 +214,7 @@ gcc_urlifier::get_url_suffix_for_option (const char *p, size_t sz) const
std::unique_ptr<urlifier>
make_gcc_urlifier (unsigned int lang_mask)
{
- return ::make_unique<gcc_urlifier> (lang_mask);
+ return std::make_unique<gcc_urlifier> (lang_mask);
}
/* class auto_override_urlifier. */
diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 818b801..ecf0331 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -1861,7 +1861,7 @@ ranger_cache::apply_inferred_ranges (gimple *s)
bool update = true;
basic_block bb = gimple_bb (s);
- gimple_infer_range infer(s);
+ gimple_infer_range infer(s, this);
if (infer.num () == 0)
return;
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 3bb24d5..aed5c7d 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -759,15 +759,17 @@ fold_using_range::range_of_range_op (vrange &r,
}
if (gimple_range_ssa_p (op1))
{
- rel = handler.lhs_op1_relation (r, range1, range2, rel);
- if (rel != VREL_VARYING)
- src.register_relation (s, rel, lhs, op1);
+ relation_kind rel2 = handler.lhs_op1_relation (r, range1,
+ range2, rel);
+ if (rel2 != VREL_VARYING)
+ src.register_relation (s, rel2, lhs, op1);
}
if (gimple_range_ssa_p (op2))
{
- rel = handler.lhs_op2_relation (r, range1, range2, rel);
- if (rel != VREL_VARYING)
- src.register_relation (s, rel, lhs, op2);
+ relation_kind rel2 = handler.lhs_op2_relation (r, range1,
+ range2, rel);
+ if (rel2 != VREL_VARYING)
+ src.register_relation (s, rel2, lhs, op2);
}
}
// Check for an existing BB, as we maybe asked to fold an
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 7e3086f..032365f 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -3561,7 +3561,7 @@ gimple_call_set_nothrow (gcall *s, bool nothrow_p)
/* Return true if S is a nothrow call. */
inline bool
-gimple_call_nothrow_p (gcall *s)
+gimple_call_nothrow_p (const gcall *s)
{
return (gimple_call_flags (s) & ECF_NOTHROW) != 0;
}
diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog
index f0b70c2..adee3de 100644
--- a/gcc/jit/ChangeLog
+++ b/gcc/jit/ChangeLog
@@ -1,3 +1,8 @@
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * dummy-frontend.cc: Drop include of "make-unique.h".
+ Replace uses of ::make_unique with std::make_unique.
+
2025-03-29 Iain Sandoe <iain@sandoe.co.uk>
* libgccjit.exports: Add symbols for ABI 28 to 34.
diff --git a/gcc/jit/dummy-frontend.cc b/gcc/jit/dummy-frontend.cc
index 88784ec..bf31a9d 100644
--- a/gcc/jit/dummy-frontend.cc
+++ b/gcc/jit/dummy-frontend.cc
@@ -33,7 +33,6 @@ along with GCC; see the file COPYING3. If not see
#include "cgraph.h"
#include "target.h"
#include "diagnostic-format-text.h"
-#include "make-unique.h"
#include "print-tree.h"
#include <mpfr.h>
@@ -1085,8 +1084,9 @@ jit_langhook_init (void)
diagnostic_text_starter (global_dc) = jit_begin_diagnostic;
diagnostic_text_finalizer (global_dc) = jit_end_diagnostic;
auto sink
- = ::make_unique<jit_diagnostic_listener> (*global_dc,
- *gcc::jit::active_playback_ctxt);
+ = std::make_unique<jit_diagnostic_listener>
+ (*global_dc,
+ *gcc::jit::active_playback_ctxt);
global_dc->set_output_format (std::move (sink));
build_common_tree_nodes (flag_signed_char);
diff --git a/gcc/json-parsing.cc b/gcc/json-parsing.cc
index 0b9715c..fc78500 100644
--- a/gcc/json-parsing.cc
+++ b/gcc/json-parsing.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "json-parsing.h"
#include "pretty-print.h"
#include "math.h"
-#include "make-unique.h"
#include "selftest.h"
using namespace json;
@@ -1037,7 +1036,7 @@ lexer::make_error (const char *msg)
location_map::range r;
r.m_start = p;
r.m_end = p;
- return ::make_unique<error> (r, xstrdup (msg));
+ return std::make_unique<error> (r, xstrdup (msg));
}
/* parser's ctor. */
@@ -1092,7 +1091,7 @@ parser::parse_value (int depth)
case TOK_STRING:
{
- auto val = ::make_unique<string> (tok->u.string);
+ auto val = std::make_unique<string> (tok->u.string);
m_lexer.consume ();
maybe_record_range (val.get (), tok->range);
return parser_result_t (std::move (val));
@@ -1103,7 +1102,7 @@ parser::parse_value (int depth)
case TOK_FLOAT_NUMBER:
{
- auto val = ::make_unique<float_number> (tok->u.float_number);
+ auto val = std::make_unique<float_number> (tok->u.float_number);
m_lexer.consume ();
maybe_record_range (val.get (), tok->range);
return parser_result_t (std::move (val));
@@ -1111,7 +1110,7 @@ parser::parse_value (int depth)
case TOK_INTEGER_NUMBER:
{
- auto val = ::make_unique<integer_number> (tok->u.integer_number);
+ auto val = std::make_unique<integer_number> (tok->u.integer_number);
m_lexer.consume ();
maybe_record_range (val.get (), tok->range);
return parser_result_t (std::move (val));
@@ -1119,7 +1118,7 @@ parser::parse_value (int depth)
case TOK_TRUE:
{
- auto val = ::make_unique<literal> (JSON_TRUE);
+ auto val = std::make_unique<literal> (JSON_TRUE);
m_lexer.consume ();
maybe_record_range (val.get (), tok->range);
return parser_result_t (std::move (val));
@@ -1127,7 +1126,7 @@ parser::parse_value (int depth)
case TOK_FALSE:
{
- auto val = ::make_unique<literal> (JSON_FALSE);
+ auto val = std::make_unique<literal> (JSON_FALSE);
m_lexer.consume ();
maybe_record_range (val.get (), tok->range);
return parser_result_t (std::move (val));
@@ -1135,7 +1134,7 @@ parser::parse_value (int depth)
case TOK_NULL:
{
- auto val = ::make_unique<literal> (JSON_NULL);
+ auto val = std::make_unique<literal> (JSON_NULL);
m_lexer.consume ();
maybe_record_range (val.get (), tok->range);
return parser_result_t (std::move (val));
@@ -1160,7 +1159,7 @@ parser::parse_object (int depth)
require (TOK_OPEN_CURLY);
- auto obj = ::make_unique<object> ();
+ auto obj = std::make_unique<object> ();
const token *tok = m_lexer.peek ();
if (tok->id == TOK_CLOSE_CURLY)
@@ -1223,7 +1222,7 @@ parser::parse_array (int depth)
if (auto err = require (TOK_OPEN_SQUARE))
return parser_result_t (std::move (err));
- auto arr = ::make_unique<array> ();
+ auto arr = std::make_unique<array> ();
const token *tok = m_lexer.peek ();
if (tok->id == TOK_CLOSE_SQUARE)
@@ -1340,7 +1339,7 @@ parser::error_at (const location_map::range &r, const char *fmt, ...)
char *formatted_msg = xvasprintf (fmt, ap);
va_end (ap);
- return ::make_unique<error> (r, formatted_msg);
+ return std::make_unique<error> (r, formatted_msg);
}
/* Record that JV has range R within the input file. */
diff --git a/gcc/json.cc b/gcc/json.cc
index 4cf962f..e66a7ae 100644
--- a/gcc/json.cc
+++ b/gcc/json.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "json.h"
#include "pretty-print.h"
#include "math.h"
-#include "make-unique.h"
#include "selftest.h"
using namespace json;
@@ -510,7 +509,7 @@ test_formatting ()
{
object obj;
object *child = new object;
- std::unique_ptr<object> grandchild = ::make_unique<object> ();
+ std::unique_ptr<object> grandchild = std::make_unique<object> ();
obj.set_string ("str", "bar");
obj.set ("child", child);
@@ -518,7 +517,7 @@ test_formatting ()
array *arr = new array;
for (int i = 0; i < 3; i++)
- arr->append (::make_unique<integer_number> (i));
+ arr->append (std::make_unique<integer_number> (i));
grandchild->set ("arr", arr);
grandchild->set_integer ("int", 1066);
diff --git a/gcc/lazy-diagnostic-path.cc b/gcc/lazy-diagnostic-path.cc
index ba62097..1474f70 100644
--- a/gcc/lazy-diagnostic-path.cc
+++ b/gcc/lazy-diagnostic-path.cc
@@ -28,7 +28,6 @@ along with GCC; see the file COPYING3. If not see
#include "intl.h"
#include "diagnostic.h"
#include "lazy-diagnostic-path.h"
-#include "make-unique.h"
#include "selftest.h"
#include "selftest-diagnostic.h"
#include "simple-diagnostic-path.h"
@@ -100,7 +99,7 @@ public:
tree fntype_void_void
= build_function_type_array (void_type_node, 0, NULL);
tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
- auto path = ::make_unique<simple_diagnostic_path> (&m_pp);
+ auto path = std::make_unique<simple_diagnostic_path> (&m_pp);
path->add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "first %qs", "free");
path->add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "double %qs", "free");
return path;
@@ -167,7 +166,7 @@ test_emission (pretty_printer *event_pp)
is skipped. */
{
test_diagnostic_context dc;
- dc.set_option_manager (::make_unique<all_warnings_disabled> (), 0);
+ dc.set_option_manager (std::make_unique<all_warnings_disabled> (), 0);
test_rich_location rich_loc (*event_pp);
ASSERT_FALSE (rich_loc.m_path.generated_p ());
diff --git a/gcc/libgdiagnostics.cc b/gcc/libgdiagnostics.cc
index d274283..49524cc 100644
--- a/gcc/libgdiagnostics.cc
+++ b/gcc/libgdiagnostics.cc
@@ -33,7 +33,6 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-format-text.h"
#include "logical-location.h"
#include "edit-context.h"
-#include "make-unique.h"
#include "libgdiagnostics.h"
class owned_nullable_string
@@ -298,7 +297,7 @@ public:
sarif_sink (diagnostic_manager &mgr,
FILE *dst_stream,
const diagnostic_file *main_input_file,
- enum sarif_version version);
+ const sarif_generation_options &sarif_gen_opts);
};
/* Helper for the linemap code. */
@@ -398,11 +397,11 @@ public:
m_dc.m_client_aux_data = this;
m_dc.set_client_data_hooks
- (::make_unique<impl_diagnostic_client_data_hooks> (*this));
+ (std::make_unique<impl_diagnostic_client_data_hooks> (*this));
diagnostic_text_starter (&m_dc) = diagnostic_text_sink::text_starter;
- m_edit_context = ::make_unique <edit_context> (m_dc.get_file_cache ());
+ m_edit_context = std::make_unique <edit_context> (m_dc.get_file_cache ());
}
~diagnostic_manager ()
@@ -503,11 +502,11 @@ public:
return (*iter).second.get ();
std::unique_ptr<diagnostic_logical_location> logical_loc
- = ::make_unique<diagnostic_logical_location> (kind,
- parent,
- short_name,
- fully_qualified_name,
- decorated_name);
+ = std::make_unique<diagnostic_logical_location> (kind,
+ parent,
+ short_name,
+ fully_qualified_name,
+ decorated_name);
const diagnostic_logical_location *result = logical_loc.get ();
m_logical_locs.insert
(logical_locs_map_t::value_type (std::move (key),
@@ -785,11 +784,12 @@ struct diagnostic_execution_path : public diagnostic_path
const char *gmsgid,
va_list *args)
{
- m_events.push_back (::make_unique<libgdiagnostics_path_event> (physical_loc,
- logical_loc,
- stack_depth,
- gmsgid,
- args));
+ m_events.push_back
+ (std::make_unique<libgdiagnostics_path_event> (physical_loc,
+ logical_loc,
+ stack_depth,
+ gmsgid,
+ args));
return m_events.size () - 1;
}
@@ -860,7 +860,7 @@ public:
void add_rule (const char *title,
const char *url)
{
- std::unique_ptr<impl_rule> rule = ::make_unique<impl_rule> (title, url);
+ std::unique_ptr<impl_rule> rule = std::make_unique<impl_rule> (title, url);
m_metadata.add_rule (*rule.get ());
m_rules.push_back (std::move (rule));
}
@@ -882,7 +882,7 @@ public:
const char *text)
{
std::unique_ptr<range_label> label
- = ::make_unique <impl_range_label> (text);
+ = std::make_unique <impl_range_label> (text);
m_rich_loc.add_range (as_location_t (loc),
SHOW_RANGE_WITHOUT_CARET,
label.get ());
@@ -902,7 +902,7 @@ public:
diagnostic_execution_path *
add_execution_path ()
{
- m_path = ::make_unique<diagnostic_execution_path> ();
+ m_path = std::make_unique<diagnostic_execution_path> ();
m_rich_loc.set_path (m_path.get ());
return m_path.get ();
}
@@ -946,7 +946,7 @@ diagnostic_t_from_diagnostic_level (enum diagnostic_level level)
void
diagnostic_file::set_buffered_content (const char *buf, size_t sz)
{
- m_content = ::make_unique<content_buffer> (buf, sz);
+ m_content = std::make_unique<content_buffer> (buf, sz);
// Populate file_cache:
file_cache &fc = m_mgr.get_dc ().get_file_cache ();
@@ -1004,8 +1004,8 @@ diagnostic_text_sink::diagnostic_text_sink (diagnostic_manager &mgr,
m_source_printing (mgr.get_dc ().m_source_printing)
{
auto inner_sink
- = ::make_unique<diagnostic_text_output_format> (mgr.get_dc (),
- &m_source_printing);
+ = std::make_unique<diagnostic_text_output_format> (mgr.get_dc (),
+ &m_source_printing);
inner_sink->get_printer ()->set_output_stream (dst_stream);
m_inner_sink = inner_sink.get ();
set_colorize (colorize);
@@ -1071,7 +1071,7 @@ diagnostic_text_sink::text_starter (diagnostic_text_output_format &text_output,
sarif_sink::sarif_sink (diagnostic_manager &mgr,
FILE *dst_stream,
const diagnostic_file *main_input_file,
- enum sarif_version version)
+ const sarif_generation_options &sarif_gen_opts)
: sink (mgr)
{
diagnostic_output_file output_file (dst_stream, false,
@@ -1079,7 +1079,8 @@ sarif_sink::sarif_sink (diagnostic_manager &mgr,
auto inner_sink = make_sarif_sink (mgr.get_dc (),
*mgr.get_line_table (),
main_input_file->get_name (),
- version,
+ true,
+ sarif_gen_opts,
std::move (output_file));
mgr.get_dc ().add_sink (std::move (inner_sink));
}
@@ -1271,7 +1272,7 @@ diagnostic_manager_add_sarif_sink (diagnostic_manager *diag_mgr,
FAIL_IF_NULL (dst_stream);
FAIL_IF_NULL (main_input_file);
- enum sarif_version internal_version;
+ sarif_generation_options sarif_gen_opts;
switch (version)
{
default:
@@ -1279,17 +1280,17 @@ diagnostic_manager_add_sarif_sink (diagnostic_manager *diag_mgr,
__func__, (int)version);
abort ();
case DIAGNOSTIC_SARIF_VERSION_2_1_0:
- internal_version = sarif_version::v2_1_0;
+ sarif_gen_opts.m_version = sarif_version::v2_1_0;
break;
case DIAGNOSTIC_SARIF_VERSION_2_2_PRERELEASE:
- internal_version = sarif_version::v2_2_prerelease_2024_08_08;
+ sarif_gen_opts.m_version = sarif_version::v2_2_prerelease_2024_08_08;
break;
}
- diag_mgr->add_sink (make_unique<sarif_sink> (*diag_mgr,
- dst_stream,
- main_input_file,
- internal_version));
+ diag_mgr->add_sink (std::make_unique<sarif_sink> (*diag_mgr,
+ dst_stream,
+ main_input_file,
+ sarif_gen_opts));
}
/* Public entrypoint. */
diff --git a/gcc/libsarifreplay.cc b/gcc/libsarifreplay.cc
index ce42bda..f5f1f20 100644
--- a/gcc/libsarifreplay.cc
+++ b/gcc/libsarifreplay.cc
@@ -25,7 +25,6 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_STRING
#include "system.h"
#include "coretypes.h"
-#include "make-unique.h"
#include "libgdiagnostics++.h"
#include "json-parsing.h"
#include "intl.h"
@@ -51,7 +50,7 @@ read_file (const char *path, libgdiagnostics::manager &mgr)
}
/* Read content, allocating a buffer for it. */
- auto result = ::make_unique<std::vector<char>> ();
+ auto result = std::make_unique<std::vector<char>> ();
char buf[4096];
size_t iter_sz_in;
@@ -1350,7 +1349,7 @@ maybe_consume_embedded_link (const char *&iter_src)
}
iter_src = iter;
- return ::make_unique<embedded_link> (std::move (result));
+ return std::make_unique<embedded_link> (std::move (result));
}
/* Lookup the plain text string within a result.message (§3.27.11),
diff --git a/gcc/lto-wrapper.cc b/gcc/lto-wrapper.cc
index a980b20..27405e8 100644
--- a/gcc/lto-wrapper.cc
+++ b/gcc/lto-wrapper.cc
@@ -55,7 +55,6 @@ along with GCC; see the file COPYING3. If not see
#include "opts-diagnostic.h"
#include "opt-suggestions.h"
#include "opts-jobserver.h"
-#include "make-unique.h"
#include "lto-ltrans-cache.h"
/* Environment variable, used for passing the names of offload targets from GCC
diff --git a/gcc/make-unique.h b/gcc/make-unique.h
deleted file mode 100644
index 6f5aeee..0000000
--- a/gcc/make-unique.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* Minimal implementation of make_unique for C++11 compatibility.
- Copyright (C) 2022-2025 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 GCC_MAKE_UNIQUE
-#define GCC_MAKE_UNIQUE
-
-#include <type_traits>
-
-/* Minimal implementation of make_unique for C++11 compatibility
- (std::make_unique is C++14). */
-
-template<typename T, typename... Args>
-inline typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
-make_unique(Args&&... args)
-{
- return std::unique_ptr<T> (new T (std::forward<Args> (args)...));
-}
-
-#endif /* ! GCC_MAKE_UNIQUE */
diff --git a/gcc/opts-diagnostic.cc b/gcc/opts-diagnostic.cc
index cab7925..b51c8a8 100644
--- a/gcc/opts-diagnostic.cc
+++ b/gcc/opts-diagnostic.cc
@@ -39,7 +39,6 @@ along with GCC; see the file COPYING3. If not see
#include "pretty-print-markup.h"
#include "opts.h"
#include "options.h"
-#include "make-unique.h"
/* A namespace for handling the DSL of the arguments of
-fdiagnostics-add-output= and -fdiagnostics-set-output=. */
@@ -308,7 +307,7 @@ parse (const context &ctxt, const char *unparsed_arg)
}
else
result.m_scheme_name = unparsed_arg;
- return ::make_unique<scheme_name_and_params> (std::move (result));
+ return std::make_unique<scheme_name_and_params> (std::move (result));
}
/* class output_factory::scheme_handler. */
@@ -317,8 +316,8 @@ parse (const context &ctxt, const char *unparsed_arg)
output_factory::output_factory ()
{
- m_scheme_handlers.push_back (::make_unique<text_scheme_handler> ());
- m_scheme_handlers.push_back (::make_unique<sarif_scheme_handler> ());
+ m_scheme_handlers.push_back (std::make_unique<text_scheme_handler> ());
+ m_scheme_handlers.push_back (std::make_unique<sarif_scheme_handler> ());
}
const output_factory::scheme_handler *
@@ -405,7 +404,7 @@ text_scheme_handler::make_sink (const context &ctxt,
return nullptr;
}
- auto sink = ::make_unique<diagnostic_text_output_format> (ctxt.m_dc);
+ auto sink = std::make_unique<diagnostic_text_output_format> (ctxt.m_dc);
sink->set_show_nesting (show_nesting);
sink->set_show_locations_in_nesting (show_locations_in_nesting);
sink->set_show_nesting_levels (show_levels);
@@ -485,10 +484,14 @@ sarif_scheme_handler::make_sink (const context &ctxt,
if (!output_file)
return nullptr;
+ sarif_generation_options sarif_gen_opts;
+ sarif_gen_opts.m_version = version;
+
auto sink = make_sarif_sink (ctxt.m_dc,
*line_table,
ctxt.m_opts.x_main_input_filename,
- version,
+ true,
+ sarif_gen_opts,
std::move (output_file));
return sink;
}
diff --git a/gcc/opts.cc b/gcc/opts.cc
index d3e3a2d..a9b9b91 100644
--- a/gcc/opts.cc
+++ b/gcc/opts.cc
@@ -3628,7 +3628,7 @@ setup_core_dumping (diagnostic_context *dc)
"setting core file size limit to maximum: %m");
}
#endif
- diagnostic_abort_on_error (dc);
+ dc->set_abort_on_error (true);
}
/* Parse a -d<ARG> command line switch for OPTS, location LOC,
diff --git a/gcc/pass_manager.h b/gcc/pass_manager.h
index 5fb7b09..d4f8900 100644
--- a/gcc/pass_manager.h
+++ b/gcc/pass_manager.h
@@ -67,13 +67,13 @@ public:
/* Various passes are manually cloned by avr and epiphany. */
opt_pass *get_pass_split_all_insns () const {
- return pass_split_all_insns_1;
+ return m_pass_split_all_insns_1;
}
opt_pass *get_pass_mode_switching () const {
- return pass_mode_switching_1;
+ return m_pass_mode_switching_1;
}
- opt_pass *get_pass_peephole2 () const { return pass_peephole2_1; }
- opt_pass *get_pass_profile () const { return pass_profile_1; }
+ opt_pass *get_pass_peephole2 () const { return m_pass_peephole2_1; }
+ opt_pass *get_pass_profile () const { return m_pass_profile_1; }
void register_pass_name (opt_pass *pass, const char *name);
@@ -81,9 +81,9 @@ public:
opt_pass *get_rest_of_compilation () const
{
- return pass_rest_of_compilation_1;
+ return m_pass_rest_of_compilation_1;
}
- opt_pass *get_clean_slate () const { return pass_clean_state_1; }
+ opt_pass *get_clean_slate () const { return m_pass_clean_state_1; }
public:
/* The root of the compilation pass tree, once constructed. */
@@ -114,21 +114,21 @@ private:
For example:
NEXT_PASS (pass_build_cfg, 1);
within pass-instances.def means that there is a field:
- opt_pass *pass_build_cfg_1;
+ opt_pass *m_pass_build_cfg_1;
Similarly, the various:
NEXT_PASS (pass_copy_prop, 1);
...
NEXT_PASS (pass_copy_prop, 8);
in pass-instances.def lead to fields:
- opt_pass *pass_copy_prop_1;
+ opt_pass *m_pass_copy_prop_1;
...
- opt_pass *pass_copy_prop_8; */
+ opt_pass *m_pass_copy_prop_8; */
#define INSERT_PASSES_AFTER(PASS)
#define PUSH_INSERT_PASSES_WITHIN(PASS, NUM)
#define POP_INSERT_PASSES()
-#define NEXT_PASS(PASS, NUM) opt_pass *PASS ## _ ## NUM
+#define NEXT_PASS(PASS, NUM) opt_pass *m_ ## PASS ## _ ## NUM
#define NEXT_PASS_WITH_ARG(PASS, NUM, ARG) NEXT_PASS (PASS, NUM)
#define NEXT_PASS_WITH_ARGS(PASS, NUM, ...) NEXT_PASS (PASS, NUM)
#define TERMINATE_PASS_LIST(PASS)
diff --git a/gcc/passes.cc b/gcc/passes.cc
index 3c28db7..0482de0 100644
--- a/gcc/passes.cc
+++ b/gcc/passes.cc
@@ -116,14 +116,14 @@ opt_pass::opt_pass (const pass_data &data, context *ctxt)
void
pass_manager::execute_early_local_passes ()
{
- execute_pass_list (cfun, pass_build_ssa_passes_1->sub);
- execute_pass_list (cfun, pass_local_optimization_passes_1->sub);
+ execute_pass_list (cfun, m_pass_build_ssa_passes_1->sub);
+ execute_pass_list (cfun, m_pass_local_optimization_passes_1->sub);
}
unsigned int
pass_manager::execute_pass_mode_switching ()
{
- return pass_mode_switching_1->execute (cfun);
+ return m_pass_mode_switching_1->execute (cfun);
}
@@ -355,9 +355,9 @@ finish_optimization_passes (void)
if (coverage_instrumentation_p () || flag_test_coverage
|| flag_branch_probabilities)
{
- dumps->dump_start (pass_profile_1->static_pass_number, NULL);
+ dumps->dump_start (m_pass_profile_1->static_pass_number, NULL);
end_branch_prob ();
- dumps->dump_finish (pass_profile_1->static_pass_number);
+ dumps->dump_finish (m_pass_profile_1->static_pass_number);
}
/* Do whatever is necessary to finish printing the graphs. */
@@ -1587,7 +1587,7 @@ pass_manager::pass_manager (context *ctxt)
#define INSERT_PASSES_AFTER(PASS)
#define PUSH_INSERT_PASSES_WITHIN(PASS, NUM)
#define POP_INSERT_PASSES()
-#define NEXT_PASS(PASS, NUM) PASS ## _ ## NUM = NULL
+#define NEXT_PASS(PASS, NUM) m_ ## PASS ## _ ## NUM = NULL
#define NEXT_PASS_WITH_ARG(PASS, NUM, ARG) NEXT_PASS (PASS, NUM)
#define NEXT_PASS_WITH_ARGS(PASS, NUM, ...) NEXT_PASS (PASS, NUM)
#define TERMINATE_PASS_LIST(PASS)
@@ -1612,28 +1612,28 @@ pass_manager::pass_manager (context *ctxt)
#define PUSH_INSERT_PASSES_WITHIN(PASS, NUM) \
{ \
- opt_pass **p = &(PASS ## _ ## NUM)->sub;
+ opt_pass **p = &(m_ ## PASS ## _ ## NUM)->sub;
#define POP_INSERT_PASSES() \
}
#define NEXT_PASS(PASS, NUM) \
do { \
- gcc_assert (PASS ## _ ## NUM == NULL); \
+ gcc_assert (m_ ## PASS ## _ ## NUM == NULL); \
if ((NUM) == 1) \
- PASS ## _1 = make_##PASS (m_ctxt); \
+ m_ ## PASS ## _1 = make_##PASS (m_ctxt); \
else \
{ \
- gcc_assert (PASS ## _1); \
- PASS ## _ ## NUM = PASS ## _1->clone (); \
+ gcc_assert (m_ ## PASS ## _1); \
+ m_ ## PASS ## _ ## NUM = m_ ## PASS ## _1->clone (); \
} \
- p = next_pass_1 (p, PASS ## _ ## NUM, PASS ## _1); \
+ p = next_pass_1 (p, m_ ## PASS ## _ ## NUM, m_ ## PASS ## _1); \
} while (0)
#define NEXT_PASS_WITH_ARG(PASS, NUM, ARG) \
do { \
NEXT_PASS (PASS, NUM); \
- PASS ## _ ## NUM->set_pass_param (0, ARG); \
+ m_ ## PASS ## _ ## NUM->set_pass_param (0, ARG); \
} while (0)
#define NEXT_PASS_WITH_ARGS(PASS, NUM, ...) \
@@ -1643,7 +1643,7 @@ pass_manager::pass_manager (context *ctxt)
unsigned i = 0; \
for (bool value : values) \
{ \
- PASS ## _ ## NUM->set_pass_param (i, value); \
+ m_ ## PASS ## _ ## NUM->set_pass_param (i, value); \
i++; \
} \
} while (0)
@@ -2020,7 +2020,7 @@ pass_manager::dump_profile_report () const
fprintf (dump_file, " ");
/* Size/time units change across gimple and RTL. */
- if (i == pass_expand_1->static_pass_number)
+ if (i == m_pass_expand_1->static_pass_number)
fprintf (dump_file,
"|-------------------|--------------------------");
else
@@ -2032,8 +2032,8 @@ pass_manager::dump_profile_report () const
fprintf (dump_file, " ");
fprintf (dump_file, "| %12.0f", profile_record[i].time);
/* Time units changes with profile estimate and feedback. */
- if (i == pass_profile_1->static_pass_number
- || i == pass_ipa_tree_profile_1->static_pass_number)
+ if (i == m_pass_profile_1->static_pass_number
+ || i == m_pass_ipa_tree_profile_1->static_pass_number)
fprintf (dump_file, "-------------");
else if (rel_time_change)
fprintf (dump_file, " %+11.1f%%", rel_time_change);
diff --git a/gcc/pretty-print.cc b/gcc/pretty-print.cc
index abd6c0b..1f38702 100644
--- a/gcc/pretty-print.cc
+++ b/gcc/pretty-print.cc
@@ -30,7 +30,6 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-color.h"
#include "diagnostic-event-id.h"
#include "diagnostic-highlight-colors.h"
-#include "make-unique.h"
#include "selftest.h"
#if HAVE_ICONV
@@ -2521,7 +2520,7 @@ pretty_printer::~pretty_printer ()
std::unique_ptr<pretty_printer>
pretty_printer::clone () const
{
- return ::make_unique<pretty_printer> (*this);
+ return std::make_unique<pretty_printer> (*this);
}
/* Append a string delimited by START and END to the output area of
@@ -3542,7 +3541,7 @@ test_custom_tokens_1 ()
void add_to_phase_2 (pp_markup::context &ctxt) final override
{
- auto val_ptr = make_unique<value> (*this);
+ auto val_ptr = std::make_unique<value> (*this);
ctxt.m_formatted_token_list->push_back<pp_token_custom_data>
(std::move (val_ptr));
}
@@ -3622,7 +3621,7 @@ test_custom_tokens_2 ()
void add_to_phase_2 (pp_markup::context &ctxt) final override
{
- auto val_ptr = make_unique<value> (*this);
+ auto val_ptr = std::make_unique<value> (*this);
ctxt.m_formatted_token_list->push_back<pp_token_custom_data>
(std::move (val_ptr));
}
diff --git a/gcc/range-op-ptr.cc b/gcc/range-op-ptr.cc
index dd51c2e..36e9dfc 100644
--- a/gcc/range-op-ptr.cc
+++ b/gcc/range-op-ptr.cc
@@ -218,6 +218,15 @@ range_operator::lhs_op1_relation (const prange &lhs ATTRIBUTE_UNUSED,
return VREL_VARYING;
}
+relation_kind
+range_operator::lhs_op1_relation (const prange &lhs ATTRIBUTE_UNUSED,
+ const prange &op1 ATTRIBUTE_UNUSED,
+ const irange &op2 ATTRIBUTE_UNUSED,
+ relation_kind rel ATTRIBUTE_UNUSED) const
+{
+ return VREL_VARYING;
+}
+
void
range_operator::update_bitmask (irange &,
const prange &,
@@ -293,6 +302,7 @@ class pointer_plus_operator : public range_operator
using range_operator::update_bitmask;
using range_operator::fold_range;
using range_operator::op2_range;
+ using range_operator::lhs_op1_relation;
public:
virtual bool fold_range (prange &r, tree type,
const prange &op1,
@@ -302,6 +312,10 @@ public:
const prange &lhs,
const prange &op1,
relation_trio = TRIO_VARYING) const final override;
+ virtual relation_kind lhs_op1_relation (const prange &lhs,
+ const prange &op1,
+ const irange &op2,
+ relation_kind) const;
void update_bitmask (prange &r, const prange &lh, const irange &rh) const
{ update_known_bitmask (r, POINTER_PLUS_EXPR, lh, rh); }
} op_pointer_plus;
@@ -379,6 +393,51 @@ pointer_plus_operator::op2_range (irange &r, tree type,
return true;
}
+// Return the relation between the LHS and OP1 based on the value of the
+// operand being added. Pointer_plus is define to have a size_type for
+// operand 2 which can be interpreted as negative, so always used SIGNED.
+// Any overflow is considered UB and thus ignored.
+
+relation_kind
+pointer_plus_operator::lhs_op1_relation (const prange &lhs,
+ const prange &op1,
+ const irange &op2,
+ relation_kind) const
+{
+ if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ())
+ return VREL_VARYING;
+
+ unsigned prec = TYPE_PRECISION (op2.type ());
+
+ // LHS = OP1 + 0 indicates LHS == OP1.
+ if (op2.zero_p ())
+ return VREL_EQ;
+
+ tree val;
+ // Only deal with singletons for now.
+ if (TYPE_OVERFLOW_UNDEFINED (lhs.type ()) && op2.singleton_p (&val))
+ {
+ // Always interpret VALUE as a signed value. Positive will increase
+ // the pointer value, and negative will decrease the poiinter value.
+ // It cannot be zero or the earlier zero_p () condition will catch it.
+ wide_int value = wi::to_wide (val);
+
+ // Positive op2 means lhs > op1.
+ if (wi::gt_p (value, wi::zero (prec), SIGNED))
+ return VREL_GT;
+
+ // Negative op2 means lhs < op1.
+ if (wi::lt_p (value, wi::zero (prec), SIGNED))
+ return VREL_LT;
+ }
+
+ // If op2 does not contain 0, then LHS and OP1 can never be equal.
+ if (!range_includes_zero_p (op2))
+ return VREL_NE;
+
+ return VREL_VARYING;
+}
+
bool
operator_bitwise_or::fold_range (prange &r, tree type,
const prange &op1,
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index f72b4ae..35b3e18 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -390,6 +390,10 @@ range_op_handler::lhs_op1_relation (const vrange &lhs,
return m_operator->lhs_op1_relation (as_a <prange> (lhs),
as_a <irange> (op1),
as_a <irange> (op2), rel);
+ case RO_PPI:
+ return m_operator->lhs_op1_relation (as_a <prange> (lhs),
+ as_a <prange> (op1),
+ as_a <irange> (op2), rel);
case RO_IFF:
return m_operator->lhs_op1_relation (as_a <irange> (lhs),
as_a <frange> (op1),
@@ -2415,8 +2419,11 @@ operator_widen_mult_unsigned::wi_fold (irange &r, tree type,
class operator_div : public cross_product_operator
{
using range_operator::update_bitmask;
+ using range_operator::op2_range;
public:
operator_div (tree_code div_kind) { m_code = div_kind; }
+ bool op2_range (irange &r, tree type, const irange &lhs, const irange &,
+ relation_trio) const;
virtual void wi_fold (irange &r, tree type,
const wide_int &lh_lb,
const wide_int &lh_ub,
@@ -2436,6 +2443,19 @@ static operator_div op_floor_div (FLOOR_DIV_EXPR);
static operator_div op_round_div (ROUND_DIV_EXPR);
static operator_div op_ceil_div (CEIL_DIV_EXPR);
+// Set OP2 to non-zero if the LHS isn't UNDEFINED.
+bool
+operator_div::op2_range (irange &r, tree type, const irange &lhs,
+ const irange &, relation_trio) const
+{
+ if (!lhs.undefined_p ())
+ {
+ r.set_nonzero (type);
+ return true;
+ }
+ return false;
+}
+
bool
operator_div::wi_op_overflows (wide_int &res, tree type,
const wide_int &w0, const wide_int &w1) const
diff --git a/gcc/range-op.h b/gcc/range-op.h
index 5dcb3fb..594e678 100644
--- a/gcc/range-op.h
+++ b/gcc/range-op.h
@@ -189,6 +189,10 @@ public:
const prange &op1,
const prange &op2,
relation_kind = VREL_VARYING) const;
+ virtual relation_kind lhs_op1_relation (const prange &lhs,
+ const prange &op1,
+ const irange &op2,
+ relation_kind = VREL_VARYING) const;
virtual relation_kind lhs_op1_relation (const frange &lhs,
const frange &op1,
const frange &op2,
diff --git a/gcc/rtl.h b/gcc/rtl.h
index 3b676c4..cc25aed 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2443,6 +2443,8 @@ extern void get_full_rtx_cost (rtx, machine_mode, enum rtx_code, int,
struct full_rtx_costs *);
extern bool native_encode_rtx (machine_mode, rtx, vec<target_unit> &,
unsigned int, unsigned int);
+extern wide_int native_decode_int (const vec<target_unit> &, unsigned int,
+ unsigned int, unsigned int);
extern rtx native_decode_rtx (machine_mode, const vec<target_unit> &,
unsigned int);
extern rtx native_decode_vector_rtx (machine_mode, const vec<target_unit> &,
diff --git a/gcc/rust/ChangeLog b/gcc/rust/ChangeLog
index 453b9f7..5cb9311 100644
--- a/gcc/rust/ChangeLog
+++ b/gcc/rust/ChangeLog
@@ -1,3 +1,356 @@
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * checks/errors/borrowck/rust-bir-place.h
+ (IndexVec::size_type): Add.
+ (IndexVec::MAX_INDEX): Add.
+ (IndexVec::size): Change the return type to the type of the
+ internal value used by the index type.
+ (PlaceDB::lookup_or_add_variable): Use the return value from the
+ PlaceDB::add_place call.
+ * checks/errors/borrowck/rust-bir.h
+ (struct BasicBlockId): Move this definition before the
+ definition of the struct Function.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit visibility.
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * ast/rust-ast-visitor.cc
+ (DefaultASTVisitor::visit): Visit the loop labels of
+ WhileLetLoopExpr instances before visiting their scrutinee
+ expressions.
+ * resolve/rust-early-name-resolver-2.0.cc
+ (Early::resolve_glob_import): Pass the glob import's path
+ directly to NameResolutionContext::resolve_path.
+ * resolve/rust-toplevel-name-resolver-2.0.cc
+ (TopLevel::visit): Remove unnecessary call to
+ Identifier::as_string.
+ (flatten_glob): Improve handling of cases where a glob use tree
+ has no path.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * expand/rust-derive-clone.cc (DeriveClone::clone_enum_struct): Clone
+ path to avoid using the same nodeid.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit_function_params):
+ Add specialized function to visit function parameters.
+ (DefaultASTVisitor::visit): Remove parameter visit and call specialized
+ function instead.
+ * ast/rust-ast-visitor.h: Add function prototye.
+ * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Remove
+ function.
+ (Late::visit_function_params): Override specialized visit function.
+ * resolve/rust-late-name-resolver-2.0.h: Add overriden function
+ prototype.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * resolve/rust-name-resolution-context.h: Use BindingLayer instead.
+ * resolve/rust-name-resolution-context.cc (BindingLayer::BindingLayer):
+ Add new constructor for binding layer.
+ (BindingLayer::bind_test): Add a function to test a binding constraint.
+ (BindingLayer::push): Push a new binding group.
+ (BindingLayer::and_binded): Add function to test and-binding
+ constraint.
+ (BindingLayer::or_binded): Add function to test or-binding constraints.
+ (BindingLayer::insert_ident): Insert a new identifier in the current
+ binding group.
+ (BindingLayer::merge): Merge current binding group with it's parent.
+ (BindingLayer::get_source): Get the source of the current binding
+ group.
+ * resolve/rust-late-name-resolver-2.0.cc: Use stacked context for
+ binding group.
+ * util/rust-stacked-contexts.h: Add mutable peek function.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Add binding
+ creation in visitor.
+ * resolve/rust-late-name-resolver-2.0.h: Add function prototypes.
+ * resolve/rust-name-resolution-context.h: Add binding context.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * resolve/rust-name-resolution-context.h (struct Binding): Add Binding
+ struct to differentiate Or and Product bindings in patterns.
+ (enum class): Add Binding kind.
+ (class BindingContext): Add binding context with Binding stack.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * ast/rust-ast.h: Add hash function.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * ast/rust-ast.h: Add equality operator.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * resolve/rust-default-resolver.cc (DefaultResolver::visit): Add visit
+ function for TypeParam.
+ * resolve/rust-default-resolver.h: Add function prototype.
+ * resolve/rust-forever-stack.h: Add function to check for forward
+ declaration ban.
+ * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Check forward
+ declarations.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * ast/rust-ast-collector.cc (TokenCollector::visit): Remove error kind
+ and change function call.
+ * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Change call name.
+ * ast/rust-path.cc (ConstGenericParam::as_string): Likewise.
+ * ast/rust-path.h: Remove error kind.
+ * hir/rust-ast-lower-type.cc (ASTLowerGenericParam::visit): Change call
+ name.
+ * parse/rust-parse-impl.h (Parser::parse_generic_param): Use optional
+ on parsing failure.
+ (Parser::parse_generic_arg): Likewise.
+ (Parser::parse_path_generic_args): Likewise.
+ * parse/rust-parse.h: Likewise.
+ * resolve/rust-ast-resolve-type.h: Change call name.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * resolve/rust-late-name-resolver-2.0.cc (Late::visit): Change error
+ message.
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * resolve/rust-early-name-resolver-2.0.cc
+ (Early::build_import_mapping): Avoid outputting an "unresolved
+ import" error if other errors are outputted during resolution.
+ * resolve/rust-early-name-resolver-2.0.h
+ (Early::resolve_path_in_all_ns): Collect path resolution errors
+ while avoiding duplicate errors for resolutions in each
+ namespace.
+ * resolve/rust-forever-stack.h
+ (ForeverStack::resolve_path): Add parameter for collecting
+ errors.
+ (ForeverStack::find_starting_point): Likewise.
+ (ForeverStack::resolve_segments): Likewise.
+ * resolve/rust-forever-stack.hxx
+ (check_leading_kw_at_start): Likewise.
+ (ForeverStack::find_starting_point): Likewise.
+ (ForeverStack::resolve_segments): Likewise.
+ (ForeverStack::resolve_path): Likewise.
+ * resolve/rust-name-resolution-context.h
+ (NameResolutionContext::resolve_path): Add optional parameter
+ for collecting errors.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * backend/rust-compile-expr.cc (CompileExpr::array_copied_expr): prealloc the vector
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): add guard
+ * expand/rust-expand-visitor.cc (ExpandVisitor::visit): add guard
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * resolve/rust-ast-resolve-path.cc
+ (ResolvePath::resolve_path): Adjust error messages.
+ * resolve/rust-ast-resolve-type.cc
+ (ResolveRelativeTypePath::go): Likewise.
+ * resolve/rust-forever-stack.hxx
+ (check_leading_kw_at_start): Likewise.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit): fix bad assertion
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * resolve/rust-forever-stack.hxx
+ (ForeverStack::resolve_path): Pass instance of Node to lambda by
+ reference instead of by value.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * typecheck/rust-hir-type-check-struct-field.h: keep reference to parent expression
+ * typecheck/rust-hir-type-check-struct.cc (TypeCheckStructExpr::TypeCheckStructExpr):
+ update ctor
+ (TypeCheckStructExpr::resolve): remove bad rust_fatal_errors
+ (TypeCheckStructExpr::visit): cleanup errors
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * resolve/rust-late-name-resolver-2.0.cc
+ (Late::visit): Handle StructPatternFieldIdent.
+ * resolve/rust-late-name-resolver-2.0.h
+ (Late::visit): Likewise.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * ast/rust-ast-collector.cc (TokenCollector::visit): Dump llvm inline
+ asm tokens.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * ast/rust-ast-collector.cc (TokenCollector::visit): Remove unreachable
+ code.
+ * ast/rust-expr.h (struct LlvmOperand): Add LlvmOperand struct to
+ represent input and outputs.
+ (class LlvmInlineAsm): Add input, output and clobber operands.
+ (struct TupleTemplateStr): Add locus getter.
+ * backend/rust-compile-block.h: Add visit for LlvmInlineAsm.
+ * backend/rust-compile-expr.cc (CompileExpr::visit): Add llvm inline
+ asm stmt compilation.
+ * backend/rust-compile-expr.h: Add function prototype.
+ * backend/rust-compile-asm.h (class CompileLlvmAsm): Add llvm asm hir
+ not to gimple.
+ * backend/rust-compile-asm.cc (CompileLlvmAsm::CompileLlvmAsm): Add
+ constructor.
+ (CompileLlvmAsm::construct_operands): Add function to construct operand
+ tree.
+ (CompileLlvmAsm::construct_clobbers): Add function to construct clobber
+ tree.
+ (CompileLlvmAsm::tree_codegen_asm): Generate the whole tree for a given
+ llvm inline assembly node.
+ * checks/errors/borrowck/rust-bir-builder-expr-stmt.cc (ExprStmtBuilder::visit):
+ Add visit function.
+ * checks/errors/borrowck/rust-bir-builder-expr-stmt.h: Add function
+ prototype.
+ * checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h: Add visit
+ function.
+ * checks/errors/borrowck/rust-bir-builder-struct.h: Likewise.
+ * checks/errors/borrowck/rust-function-collector.h: Likewise.
+ * checks/errors/privacy/rust-privacy-reporter.cc (PrivacyReporter::visit):
+ Likewise.
+ * checks/errors/privacy/rust-privacy-reporter.h: Add visit function
+ prototype.
+ * checks/errors/rust-const-checker.cc (ConstChecker::visit): Add visit
+ function.
+ * checks/errors/rust-const-checker.h: Add visit function prototype.
+ * checks/errors/rust-hir-pattern-analysis.cc (PatternChecker::visit):
+ Add visit function.
+ * checks/errors/rust-hir-pattern-analysis.h: Add visit function
+ prototype.
+ * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): Add
+ visit function.
+ * checks/errors/rust-unsafe-checker.h: Add function prototype.
+ * expand/rust-macro-builtins-asm.cc (parse_llvm_templates): Parse
+ templates.
+ (parse_llvm_arguments): Add function to parse non template tokens.
+ (parse_llvm_operands): Add function to parse operands, either input or
+ output.
+ (parse_llvm_outputs): Add function to parse and collect llvm asm
+ outputs.
+ (parse_llvm_inputs): Likewise with inputs.
+ (parse_llvm_clobbers): Add function to parse llvm asm clobbers.
+ (parse_llvm_options): Add function to parse llvm asm options.
+ (parse_llvm_asm): Add function to parse llvm asm.
+ * expand/rust-macro-builtins-asm.h (class LlvmAsmContext): Add context
+ for llvm asm parser.
+ (parse_llvm_outputs): Add function prototype.
+ (parse_llvm_inputs): Likewise.
+ (parse_llvm_clobbers): Likewise.
+ (parse_llvm_options): Likewise.
+ * hir/rust-ast-lower-expr.cc (ASTLoweringExpr::visit): Lower AST llvm
+ asm node to HIR.
+ * hir/rust-ast-lower-expr.h: Add function prototype.
+ * hir/rust-hir-dump.cc (Dump::visit): Add visit function.
+ * hir/rust-hir-dump.h: Add function prototype.
+ * hir/tree/rust-hir-expr-abstract.h: Add HIR llvm asm node kind.
+ * hir/tree/rust-hir-expr.h (struct LlvmOperand): Add LlvmOperand type
+ to represent input and outputs.
+ (class LlvmInlineAsm): Add LlvmInlineAsm hir node.
+ * hir/tree/rust-hir-full-decls.h (class LlvmInlineAsm): Add
+ LlvmInlineAsm hir node forward declaration.
+ * hir/tree/rust-hir-visitor.h: Add visit functions for LlvmInlineAsm
+ hir node.
+ * hir/tree/rust-hir.cc (LlvmInlineAsm::accept_vis): Add hir node
+ visitor related functions.
+ * typecheck/rust-hir-type-check-expr.cc (TypeCheckExpr::visit):
+ Type check input and output operands.
+ * typecheck/rust-hir-type-check-expr.h: Add function prototype.
+ * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Visit input and
+ output operand expressions.
+ * resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit): Resolve input
+ and output expressions.
+ * resolve/rust-ast-resolve-expr.h: Add function prototypes.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * ast/rust-ast-collector.cc (TokenCollector::visit): Make visitor
+ unreachable.
+ * ast/rust-ast-collector.h: Add visit for LlvmInlineAsmNode.
+ * ast/rust-ast-visitor.cc (DefaultASTVisitor::visit): Add visit
+ function for the default ast visitor.
+ * ast/rust-ast-visitor.h: Add function prototype.
+ * ast/rust-ast.cc (LlvmInlineAsm::accept_vis): Add accept_vis to
+ LlvmInlineAsm node.
+ * ast/rust-ast.h: Add LlvmInlineAsm node kind.
+ * ast/rust-expr.h (class LlvmInlineAsm): Add LlvmInlineAsm node.
+ * expand/rust-derive.h: Add visit function for LlvmInlineAsm node.
+ * expand/rust-macro-builtins-asm.cc (MacroBuiltin::llvm_asm_handler):
+ Add handler for llvm inline assembly nodes.
+ (parse_llvm_asm): Add function to parse llvm assembly nodes.
+ * expand/rust-macro-builtins-asm.h (parse_llvm_asm): Add function
+ prototypes.
+ * expand/rust-macro-builtins.cc (inline_llvm_asm_maker): Add macro
+ transcriber.
+ * expand/rust-macro-builtins.h: Add transcriber function prototype.
+ * hir/rust-ast-lower-base.cc (ASTLoweringBase::visit): Add visit
+ function for LlvmInlineAsm node.
+ * hir/rust-ast-lower-base.h: Add visit function prototype.
+ * resolve/rust-ast-resolve-base.cc (ResolverBase::visit): Add visit
+ function for LlvmInlineAsm node.
+ * resolve/rust-ast-resolve-base.h: Add visit function prototype.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * expand/rust-macro-builtins-asm.cc (parse_asm_arg): Emit error
+ message.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * typecheck/rust-hir-type-check-item.cc (TypeCheckItem::visit): add diagnostic
+ * typecheck/rust-tyty.cc (BaseType::contains_infer): new helper to grab first infer var
+ * typecheck/rust-tyty.h: prototype
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust-gcc.cc (arithmetic_or_logical_expression): Ensure this is an integer
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * hir/rust-hir-dump.cc (Dump::visit): add guard for optional label
+
+2025-04-28 Yap Zhi Heng <yapzhhg@gmail.com>
+
+ * typecheck/rust-tyty.h: Remove extra redundant comment.
+ * typecheck/rust-hir-type-check-base.cc: Update comment on repr
+ handling.
+
+2025-04-28 Zhi Heng <yapzhhg@gmail.com>
+
+ * typecheck/rust-hir-type-check-base.cc: Set enum representing
+ type properly if repr is an integer type.
+ * typecheck/rust-hir-type-check-item.cc: Update comments.
+
+2025-04-28 Zhi Heng <yapzhhg@gmail.com>
+
+ * typecheck/rust-tyty.h: Add new `ReprKind` enum to
+ `ReprOptions`.
+ * typecheck/rust-hir-type-check-base.cc: Handle setting of
+ `repr_kind`.
+ * typecheck/rust-hir-type-check-item.cc: New check for
+ zero-variant enums.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * checks/errors/rust-unsafe-checker.cc (UnsafeChecker::visit): add null check
+ * hir/tree/rust-hir-item.h: add has_type helper
+ * typecheck/rust-hir-trait-resolve.cc (TraitItemReference::resolve_item):
+ add missing type checking
+
2025-04-14 Arthur Cohen <arthur.cohen@embecosm.com>
* util/rust-lang-item.h: Add new manually_drop lang item.
diff --git a/gcc/rust/ast/rust-ast-collector.cc b/gcc/rust/ast/rust-ast-collector.cc
index 8ee6375..c850e96 100644
--- a/gcc/rust/ast/rust-ast-collector.cc
+++ b/gcc/rust/ast/rust-ast-collector.cc
@@ -491,7 +491,7 @@ TokenCollector::visit (ConstGenericParam &param)
if (param.has_default_value ())
{
push (Rust::Token::make (EQUAL, UNDEF_LOCATION));
- visit (param.get_default_value ());
+ visit (param.get_default_value_unchecked ());
}
}
@@ -639,8 +639,6 @@ TokenCollector::visit (GenericArg &arg)
push (Rust::Token::make_identifier (UNDEF_LOCATION, std::move (path)));
}
break;
- case GenericArg::Kind::Error:
- rust_unreachable ();
}
}
@@ -1522,6 +1520,47 @@ void
TokenCollector::visit (InlineAsm &expr)
{}
+void
+TokenCollector::visit (LlvmInlineAsm &expr)
+{
+ push (Rust::Token::make_identifier (expr.get_locus (), "llvm_asm"));
+ push (Rust::Token::make (EXCLAM, expr.get_locus ()));
+ push (Rust::Token::make (LEFT_PAREN, expr.get_locus ()));
+ for (auto &template_str : expr.get_templates ())
+ push (Rust::Token::make_string (template_str.get_locus (),
+ std::move (template_str.symbol)));
+
+ push (Rust::Token::make (COLON, expr.get_locus ()));
+ for (auto output : expr.get_outputs ())
+ {
+ push (Rust::Token::make_string (expr.get_locus (),
+ std::move (output.constraint)));
+ visit (output.expr);
+ push (Rust::Token::make (COMMA, expr.get_locus ()));
+ }
+
+ push (Rust::Token::make (COLON, expr.get_locus ()));
+ for (auto input : expr.get_inputs ())
+ {
+ push (Rust::Token::make_string (expr.get_locus (),
+ std::move (input.constraint)));
+ visit (input.expr);
+ push (Rust::Token::make (COMMA, expr.get_locus ()));
+ }
+
+ push (Rust::Token::make (COLON, expr.get_locus ()));
+ for (auto &clobber : expr.get_clobbers ())
+ {
+ push (Rust::Token::make_string (expr.get_locus (),
+ std::move (clobber.symbol)));
+ push (Rust::Token::make (COMMA, expr.get_locus ()));
+ }
+ push (Rust::Token::make (COLON, expr.get_locus ()));
+ // Dump options
+
+ push (Rust::Token::make (RIGHT_PAREN, expr.get_locus ()));
+}
+
// rust-item.h
void
diff --git a/gcc/rust/ast/rust-ast-collector.h b/gcc/rust/ast/rust-ast-collector.h
index b014c23..f45e3cc 100644
--- a/gcc/rust/ast/rust-ast-collector.h
+++ b/gcc/rust/ast/rust-ast-collector.h
@@ -303,6 +303,7 @@ public:
void visit (AwaitExpr &expr);
void visit (AsyncBlockExpr &expr);
void visit (InlineAsm &expr);
+ void visit (LlvmInlineAsm &expr);
// rust-item.h
void visit (TypeParam &param);
void visit (LifetimeWhereClauseItem &item);
diff --git a/gcc/rust/ast/rust-ast-visitor.cc b/gcc/rust/ast/rust-ast-visitor.cc
index 9d524c3..b6833f6 100644
--- a/gcc/rust/ast/rust-ast-visitor.cc
+++ b/gcc/rust/ast/rust-ast-visitor.cc
@@ -82,7 +82,7 @@ DefaultASTVisitor::visit (AST::ConstGenericParam &const_param)
if (const_param.has_type ())
visit (const_param.get_type ());
if (const_param.has_default_value ())
- visit (const_param.get_default_value ());
+ visit (const_param.get_default_value_unchecked ());
}
void
@@ -108,7 +108,8 @@ DefaultASTVisitor::visit (GenericArgsBinding &binding)
void
DefaultASTVisitor::visit (AST::TypePathSegmentGeneric &segment)
{
- visit (segment.get_generic_args ());
+ if (segment.has_generic_args ())
+ visit (segment.get_generic_args ());
}
void
@@ -581,8 +582,8 @@ DefaultASTVisitor::visit (AST::WhileLetLoopExpr &expr)
visit_outer_attrs (expr);
for (auto &pattern : expr.get_patterns ())
visit (pattern);
- visit (expr.get_scrutinee_expr ());
visit (expr.get_loop_label ());
+ visit (expr.get_scrutinee_expr ());
visit (expr.get_loop_block ());
}
@@ -714,6 +715,16 @@ DefaultASTVisitor::visit (AST::InlineAsm &expr)
}
void
+DefaultASTVisitor::visit (AST::LlvmInlineAsm &expr)
+{
+ for (auto &output : expr.get_outputs ())
+ visit (output.expr);
+
+ for (auto &input : expr.get_inputs ())
+ visit (input.expr);
+}
+
+void
DefaultASTVisitor::visit (AST::TypeParam &param)
{
visit_outer_attrs (param);
@@ -817,10 +828,18 @@ DefaultASTVisitor::visit (AST::UseTreeRebind &use_tree)
void
DefaultASTVisitor::visit (AST::UseDeclaration &use_decl)
{
+ visit (use_decl.get_visibility ());
visit (use_decl.get_tree ());
}
void
+DefaultASTVisitor::visit_function_params (AST::Function &function)
+{
+ for (auto &param : function.get_function_params ())
+ visit (param);
+}
+
+void
DefaultASTVisitor::visit (AST::Function &function)
{
visit_outer_attrs (function);
@@ -828,8 +847,9 @@ DefaultASTVisitor::visit (AST::Function &function)
visit (function.get_qualifiers ());
for (auto &generic : function.get_generic_params ())
visit (generic);
- for (auto &param : function.get_function_params ())
- visit (param);
+
+ visit_function_params (function);
+
if (function.has_return_type ())
visit (function.get_return_type ());
if (function.has_where_clause ())
diff --git a/gcc/rust/ast/rust-ast-visitor.h b/gcc/rust/ast/rust-ast-visitor.h
index 51661df..b1fc504 100644
--- a/gcc/rust/ast/rust-ast-visitor.h
+++ b/gcc/rust/ast/rust-ast-visitor.h
@@ -131,6 +131,7 @@ public:
virtual void visit (AwaitExpr &expr) = 0;
virtual void visit (AsyncBlockExpr &expr) = 0;
virtual void visit (InlineAsm &expr) = 0;
+ virtual void visit (LlvmInlineAsm &expr) = 0;
// rust-item.h
virtual void visit (TypeParam &param) = 0;
@@ -241,6 +242,8 @@ public:
class DefaultASTVisitor : public ASTVisitor
{
public:
+ virtual void visit_function_params (AST::Function &function);
+
virtual void visit (AST::Crate &crate);
virtual void visit (AST::Token &tok) override;
@@ -314,6 +317,7 @@ public:
virtual void visit (AST::AwaitExpr &expr) override;
virtual void visit (AST::AsyncBlockExpr &expr) override;
virtual void visit (InlineAsm &expr) override;
+ virtual void visit (LlvmInlineAsm &expr) override;
virtual void visit (AST::TypeParam &param) override;
virtual void visit (AST::LifetimeWhereClauseItem &item) override;
diff --git a/gcc/rust/ast/rust-ast.cc b/gcc/rust/ast/rust-ast.cc
index 06e0e7b..4e82be4 100644
--- a/gcc/rust/ast/rust-ast.cc
+++ b/gcc/rust/ast/rust-ast.cc
@@ -4651,6 +4651,12 @@ InlineAsm::accept_vis (ASTVisitor &vis)
}
void
+LlvmInlineAsm::accept_vis (ASTVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
TypeParam::accept_vis (ASTVisitor &vis)
{
vis.visit (*this);
diff --git a/gcc/rust/ast/rust-ast.h b/gcc/rust/ast/rust-ast.h
index 91611ec..aa6ad50 100644
--- a/gcc/rust/ast/rust-ast.h
+++ b/gcc/rust/ast/rust-ast.h
@@ -57,6 +57,11 @@ public:
bool empty () const { return ident.empty (); }
+ bool operator== (const Identifier &other) const
+ {
+ return ident == other.ident;
+ }
+
private:
std::string ident;
location_t loc;
@@ -1264,6 +1269,7 @@ public:
Await,
AsyncBlock,
InlineAsm,
+ LlvmInlineAsm,
Identifier,
FormatArgs,
MacroInvocation,
@@ -2096,6 +2102,19 @@ template <> struct less<Rust::Identifier>
return lhs.as_string () < rhs.as_string ();
}
};
+
+template <> struct hash<Rust::Identifier>
+{
+ std::size_t operator() (const Rust::Identifier &k) const
+ {
+ using std::hash;
+ using std::size_t;
+ using std::string;
+
+ return hash<string> () (k.as_string ()) ^ (hash<int> () (k.get_locus ()));
+ }
+};
+
} // namespace std
#endif
diff --git a/gcc/rust/ast/rust-expr.h b/gcc/rust/ast/rust-expr.h
index 69538df..fdb6360 100644
--- a/gcc/rust/ast/rust-expr.h
+++ b/gcc/rust/ast/rust-expr.h
@@ -4885,6 +4885,27 @@ struct InlineAsmRegOrRegClass
location_t locus;
};
+struct LlvmOperand
+{
+ std::string constraint;
+ std::unique_ptr<Expr> expr;
+
+ LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr)
+ : constraint (constraint), expr (std::move (expr))
+ {}
+
+ LlvmOperand (const LlvmOperand &other)
+ : constraint (other.constraint), expr (other.expr->clone_expr ())
+ {}
+ LlvmOperand &operator= (const LlvmOperand &other)
+ {
+ constraint = other.constraint;
+ expr = other.expr->clone_expr ();
+
+ return *this;
+ }
+};
+
class InlineAsmOperand
{
public:
@@ -5258,6 +5279,7 @@ struct TupleTemplateStr
location_t loc;
std::string symbol;
+ location_t get_locus () { return loc; }
TupleTemplateStr (location_t loc, const std::string &symbol)
: loc (loc), symbol (symbol)
{}
@@ -5330,6 +5352,77 @@ public:
Expr::Kind get_expr_kind () const override { return Expr::Kind::InlineAsm; }
};
+class LlvmInlineAsm : public ExprWithoutBlock
+{
+ // llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
+ // Asm, Outputs, Inputs, Clobbers, Options,
+
+public:
+ enum class Dialect
+ {
+ Att,
+ Intel,
+ };
+
+private:
+ location_t locus;
+ std::vector<Attribute> outer_attrs;
+ std::vector<LlvmOperand> inputs;
+ std::vector<LlvmOperand> outputs;
+ std::vector<TupleTemplateStr> templates;
+ std::vector<TupleClobber> clobbers;
+ bool volatility;
+ bool align_stack;
+ Dialect dialect;
+
+public:
+ LlvmInlineAsm (location_t locus) : locus (locus) {}
+
+ Dialect get_dialect () { return dialect; }
+
+ location_t get_locus () const override { return locus; }
+
+ void mark_for_strip () override {}
+
+ bool is_marked_for_strip () const override { return false; }
+
+ std::vector<Attribute> &get_outer_attrs () override { return outer_attrs; }
+
+ void accept_vis (ASTVisitor &vis) override;
+
+ std::string as_string () const override { return "InlineAsm AST Node"; }
+
+ void set_outer_attrs (std::vector<Attribute> v) override { outer_attrs = v; }
+
+ LlvmInlineAsm *clone_expr_without_block_impl () const override
+ {
+ return new LlvmInlineAsm (*this);
+ }
+
+ std::vector<TupleTemplateStr> &get_templates () { return templates; }
+
+ Expr::Kind get_expr_kind () const override
+ {
+ return Expr::Kind::LlvmInlineAsm;
+ }
+
+ void set_align_stack (bool align_stack) { this->align_stack = align_stack; }
+ bool is_stack_aligned () { return align_stack; }
+
+ void set_volatile (bool volatility) { this->volatility = volatility; }
+ bool is_volatile () { return volatility; }
+
+ void set_dialect (Dialect dialect) { this->dialect = dialect; }
+
+ void set_inputs (std::vector<LlvmOperand> operands) { inputs = operands; }
+ void set_outputs (std::vector<LlvmOperand> operands) { outputs = operands; }
+
+ std::vector<LlvmOperand> &get_inputs () { return inputs; }
+ std::vector<LlvmOperand> &get_outputs () { return outputs; }
+
+ std::vector<TupleClobber> &get_clobbers () { return clobbers; }
+};
+
} // namespace AST
} // namespace Rust
diff --git a/gcc/rust/ast/rust-path.cc b/gcc/rust/ast/rust-path.cc
index 69627be8..8e43ddf 100644
--- a/gcc/rust/ast/rust-path.cc
+++ b/gcc/rust/ast/rust-path.cc
@@ -119,7 +119,7 @@ ConstGenericParam::as_string () const
str += "const " + name.as_string () + ": " + type->as_string ();
if (has_default_value ())
- str += " = " + get_default_value ().as_string ();
+ str += " = " + get_default_value_unchecked ().as_string ();
return str;
}
diff --git a/gcc/rust/ast/rust-path.h b/gcc/rust/ast/rust-path.h
index 805be8e..a4ba93b 100644
--- a/gcc/rust/ast/rust-path.h
+++ b/gcc/rust/ast/rust-path.h
@@ -167,17 +167,11 @@ public:
*/
enum class Kind
{
- Error,
Const, // A const value
Type, // A type argument (not discernable during parsing)
Either, // Either a type or a const value, cleared up during resolving
};
- static GenericArg create_error ()
- {
- return GenericArg (nullptr, nullptr, {""}, Kind::Error, UNDEF_LOCATION);
- }
-
static GenericArg create_const (std::unique_ptr<Expr> expression)
{
auto locus = expression->get_locus ();
@@ -222,8 +216,6 @@ public:
GenericArg (GenericArg &&other) = default;
GenericArg &operator= (GenericArg &&other) = default;
- bool is_error () const { return kind == Kind::Error; }
-
Kind get_kind () const { return kind; }
location_t get_locus () const { return locus; }
@@ -239,8 +231,6 @@ public:
break;
case Kind::Either:
break;
- case Kind::Error:
- rust_unreachable ();
}
}
@@ -283,8 +273,6 @@ public:
{
switch (get_kind ())
{
- case Kind::Error:
- rust_unreachable ();
case Kind::Either:
return "Ambiguous: " + path.as_string ();
case Kind::Const:
@@ -355,15 +343,15 @@ class ConstGenericParam : public GenericParam
/**
* Default value for the const generic parameter
*/
- GenericArg default_value;
+ tl::optional<GenericArg> default_value;
AST::AttrVec outer_attrs;
location_t locus;
public:
ConstGenericParam (Identifier name, std::unique_ptr<AST::Type> type,
- GenericArg default_value, AST::AttrVec outer_attrs,
- location_t locus)
+ tl::optional<GenericArg> default_value,
+ AST::AttrVec outer_attrs, location_t locus)
: name (name), type (std::move (type)),
default_value (std::move (default_value)), outer_attrs (outer_attrs),
locus (locus)
@@ -376,7 +364,7 @@ public:
{}
bool has_type () const { return type != nullptr; }
- bool has_default_value () const { return !default_value.is_error (); }
+ bool has_default_value () const { return default_value.has_value (); }
const Identifier &get_name () const { return name; }
@@ -389,18 +377,18 @@ public:
return *type;
}
- GenericArg &get_default_value ()
+ GenericArg &get_default_value_unchecked ()
{
rust_assert (has_default_value ());
- return default_value;
+ return default_value.value ();
}
- const GenericArg &get_default_value () const
+ const GenericArg &get_default_value_unchecked () const
{
rust_assert (has_default_value ());
- return default_value;
+ return default_value.value ();
}
std::string as_string () const override;
diff --git a/gcc/rust/backend/rust-compile-asm.cc b/gcc/rust/backend/rust-compile-asm.cc
index 22498bc..7351cf0 100644
--- a/gcc/rust/backend/rust-compile-asm.cc
+++ b/gcc/rust/backend/rust-compile-asm.cc
@@ -1,5 +1,7 @@
#include "rust-compile-asm.h"
#include "rust-compile-expr.h"
+#include "rust-system.h"
+
namespace Rust {
namespace Compile {
@@ -141,5 +143,57 @@ CompileAsm::asm_construct_label_tree (HIR::InlineAsm &expr)
return NULL_TREE;
}
+CompileLlvmAsm::CompileLlvmAsm (Context *ctx) : HIRCompileBase (ctx) {}
+
+tree
+CompileLlvmAsm::construct_operands (std::vector<HIR::LlvmOperand> operands)
+{
+ tree head = NULL_TREE;
+ for (auto &operand : operands)
+ {
+ tree t = CompileExpr::Compile (*operand.expr, this->ctx);
+ auto name = build_string (operand.constraint.size () + 1,
+ operand.constraint.c_str ());
+ head = chainon (head,
+ build_tree_list (build_tree_list (NULL_TREE, name), t));
+ }
+ return head;
+}
+
+tree
+CompileLlvmAsm::construct_clobbers (std::vector<AST::TupleClobber> clobbers)
+{
+ tree head = NULL_TREE;
+ for (auto &clobber : clobbers)
+ {
+ auto name
+ = build_string (clobber.symbol.size () + 1, clobber.symbol.c_str ());
+ head = chainon (head, build_tree_list (NULL_TREE, name));
+ }
+ return head;
+}
+
+tree
+CompileLlvmAsm::tree_codegen_asm (HIR::LlvmInlineAsm &expr)
+{
+ tree ret = make_node (ASM_EXPR);
+ TREE_TYPE (ret) = void_type_node;
+ SET_EXPR_LOCATION (ret, expr.get_locus ());
+ ASM_VOLATILE_P (ret) = expr.options.is_volatile;
+
+ std::stringstream ss;
+ for (const auto &template_str : expr.templates)
+ {
+ ss << template_str.symbol << "\n";
+ }
+
+ ASM_STRING (ret) = Backend::string_constant_expression (ss.str ());
+ ASM_INPUTS (ret) = construct_operands (expr.inputs);
+ ASM_OUTPUTS (ret) = construct_operands (expr.outputs);
+ ASM_CLOBBERS (ret) = construct_clobbers (expr.get_clobbers ());
+
+ return ret;
+}
+
} // namespace Compile
} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-asm.h b/gcc/rust/backend/rust-compile-asm.h
index 4abd24e..22be94a 100644
--- a/gcc/rust/backend/rust-compile-asm.h
+++ b/gcc/rust/backend/rust-compile-asm.h
@@ -56,6 +56,20 @@ public:
tree tree_codegen_asm (HIR::InlineAsm &);
};
+
+class CompileLlvmAsm : private HIRCompileBase
+{
+private:
+ tree construct_operands (std::vector<HIR::LlvmOperand> operands);
+
+ tree construct_clobbers (std::vector<AST::TupleClobber>);
+
+public:
+ CompileLlvmAsm (Context *ctx);
+
+ tree tree_codegen_asm (HIR::LlvmInlineAsm &);
+};
+
} // 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 37e3980..3f38d08 100644
--- a/gcc/rust/backend/rust-compile-block.h
+++ b/gcc/rust/backend/rust-compile-block.h
@@ -100,6 +100,7 @@ public:
void visit (HIR::AwaitExpr &) override {}
void visit (HIR::AsyncBlockExpr &) override {}
void visit (HIR::InlineAsm &) override {}
+ void visit (HIR::LlvmInlineAsm &) override {}
private:
CompileConditionalBlocks (Context *ctx, Bvariable *result)
@@ -182,6 +183,7 @@ public:
void visit (HIR::AwaitExpr &) override {}
void visit (HIR::AsyncBlockExpr &) override {}
void visit (HIR::InlineAsm &) override {}
+ void visit (HIR::LlvmInlineAsm &) 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 37856a7..dd3420f 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -368,6 +368,13 @@ CompileExpr::visit (HIR::InlineAsm &expr)
}
void
+CompileExpr::visit (HIR::LlvmInlineAsm &expr)
+{
+ CompileLlvmAsm asm_codegen (ctx);
+ ctx->add_statement (asm_codegen.tree_codegen_asm (expr));
+}
+
+void
CompileExpr::visit (HIR::IfExprConseqElse &expr)
{
TyTy::BaseType *if_type = nullptr;
@@ -1965,8 +1972,12 @@ CompileExpr::array_copied_expr (location_t expr_locus,
if (ctx->const_context_p ())
{
size_t idx = 0;
+
std::vector<unsigned long> indexes;
std::vector<tree> constructor;
+
+ indexes.reserve (len);
+ constructor.reserve (len);
for (unsigned HOST_WIDE_INT i = 0; i < len; i++)
{
constructor.push_back (translated_expr);
diff --git a/gcc/rust/backend/rust-compile-expr.h b/gcc/rust/backend/rust-compile-expr.h
index dc78dee..65ed4b3 100644
--- a/gcc/rust/backend/rust-compile-expr.h
+++ b/gcc/rust/backend/rust-compile-expr.h
@@ -69,6 +69,7 @@ public:
void visit (HIR::RangeFromToInclExpr &expr) override;
void visit (HIR::ClosureExpr &expr) override;
void visit (HIR::InlineAsm &expr) override;
+ void visit (HIR::LlvmInlineAsm &expr) override;
// TODO
void visit (HIR::ErrorPropagationExpr &) override {}
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 d6acc6a..6b8b2e9 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
@@ -325,6 +325,10 @@ ExprStmtBuilder::visit (HIR::InlineAsm &expr)
{}
void
+ExprStmtBuilder::visit (HIR::LlvmInlineAsm &expr)
+{}
+
+void
ExprStmtBuilder::visit (HIR::MethodCallExpr &expr)
{}
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 daedb68..5cab3c4 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
@@ -100,6 +100,7 @@ protected: // Expr
void visit (HIR::IfExpr &expr) override;
void visit (HIR::IfExprConseqElse &expr) override;
void visit (HIR::InlineAsm &expr) override;
+ void visit (HIR::LlvmInlineAsm &expr) override;
void visit (HIR::MatchExpr &expr) override;
void visit (HIR::AwaitExpr &expr) override;
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 3bc622c..b7a1555 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-lazyboolexpr.h
@@ -207,6 +207,7 @@ public:
}
void visit (HIR::InlineAsm &expr) override {}
+ void visit (HIR::LlvmInlineAsm &expr) override {}
protected: // Illegal at this position.
void visit (HIR::StructExprFieldIdentifier &field) override
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
index 94fcecd..84311cc 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-struct.h
@@ -153,6 +153,7 @@ protected:
void visit (HIR::AwaitExpr &expr) override { rust_unreachable (); }
void visit (HIR::AsyncBlockExpr &expr) override { rust_unreachable (); }
void visit (HIR::InlineAsm &expr) override { rust_unreachable (); }
+ void visit (HIR::LlvmInlineAsm &expr) override { rust_unreachable (); }
void visit (HIR::TypeParam &param) override { rust_unreachable (); }
void visit (HIR::ConstGenericParam &param) override { rust_unreachable (); }
void visit (HIR::LifetimeWhereClauseItem &item) override
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-place.h b/gcc/rust/checks/errors/borrowck/rust-bir-place.h
index 67ca90b..dd9e672 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-place.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-place.h
@@ -204,6 +204,9 @@ template <typename I, typename T> class IndexVec
{
std::vector<T> internal_vector;
+ typedef decltype (std::declval<I> ().value) size_type;
+ static constexpr auto MAX_INDEX = std::numeric_limits<size_type>::max ();
+
public:
IndexVec () = default;
IndexVec (size_t size) { internal_vector.reserve (size); }
@@ -219,7 +222,11 @@ public:
internal_vector.emplace_back (std::forward<Args> (args)...);
}
- size_t size () const { return internal_vector.size (); }
+ size_type size () const
+ {
+ rust_assert (internal_vector.size () < MAX_INDEX);
+ return static_cast<size_type> (internal_vector.size ());
+ }
std::vector<T> &get_vector () { return internal_vector; }
};
@@ -418,8 +425,7 @@ public:
if (lookup != INVALID_PLACE)
return lookup;
- add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty});
- return {places.size () - 1};
+ return add_place ({Place::VARIABLE, id, {}, is_type_copy (tyty), tyty});
};
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 e90e508..8a5f7be 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir.h
+++ b/gcc/rust/checks/errors/borrowck/rust-bir.h
@@ -35,6 +35,26 @@ using BasicBlocks = IndexVec<BasicBlockId, BasicBlock>;
class Statement;
class AbstractExpr;
+/** Unique identifier for a basic block in the BIR. */
+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<uint32_t>::max ()};
+static constexpr BasicBlockId ENTRY_BASIC_BLOCK = {0};
+
/**
* Top-level entity of the Borrow-checker IR (BIR).
* It represents a single function (method, closure, etc.), which is the
@@ -132,26 +152,6 @@ public:
WARN_UNUSED_RESULT location_t get_location () const { return location; }
};
-/** Unique identifier for a basic block in the BIR. */
-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<uint32_t>::max ()};
-static constexpr BasicBlockId ENTRY_BASIC_BLOCK = {0};
-
struct BasicBlock
{
// BIR "instructions".
diff --git a/gcc/rust/checks/errors/borrowck/rust-function-collector.h b/gcc/rust/checks/errors/borrowck/rust-function-collector.h
index cdb20e8..7cf0952 100644
--- a/gcc/rust/checks/errors/borrowck/rust-function-collector.h
+++ b/gcc/rust/checks/errors/borrowck/rust-function-collector.h
@@ -123,6 +123,7 @@ public:
void visit (HIR::AwaitExpr &expr) override {}
void visit (HIR::AsyncBlockExpr &expr) override {}
void visit (HIR::InlineAsm &expr) override {}
+ void visit (HIR::LlvmInlineAsm &expr) override {}
void visit (HIR::TypeParam &param) override {}
void visit (HIR::ConstGenericParam &param) override {}
void visit (HIR::LifetimeWhereClauseItem &item) override {}
diff --git a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
index a537c42..2a10053 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.cc
@@ -306,6 +306,10 @@ PrivacyReporter::visit (HIR::InlineAsm &)
{}
void
+PrivacyReporter::visit (HIR::LlvmInlineAsm &)
+{}
+
+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 5111a3e..7df2cf4 100644
--- a/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
+++ b/gcc/rust/checks/errors/privacy/rust-privacy-reporter.h
@@ -125,6 +125,7 @@ types
virtual void visit (HIR::AwaitExpr &expr);
virtual void visit (HIR::AsyncBlockExpr &expr);
virtual void visit (HIR::InlineAsm &expr);
+ virtual void visit (HIR::LlvmInlineAsm &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 4c2257a..3716ea5 100644
--- a/gcc/rust/checks/errors/rust-const-checker.cc
+++ b/gcc/rust/checks/errors/rust-const-checker.cc
@@ -537,6 +537,10 @@ ConstChecker::visit (InlineAsm &)
{}
void
+ConstChecker::visit (LlvmInlineAsm &)
+{}
+
+void
ConstChecker::visit (TypeParam &)
{}
diff --git a/gcc/rust/checks/errors/rust-const-checker.h b/gcc/rust/checks/errors/rust-const-checker.h
index 00f57988..b954330 100644
--- a/gcc/rust/checks/errors/rust-const-checker.h
+++ b/gcc/rust/checks/errors/rust-const-checker.h
@@ -132,6 +132,7 @@ private:
virtual void visit (AwaitExpr &expr) override;
virtual void visit (AsyncBlockExpr &expr) override;
virtual void visit (InlineAsm &expr) override;
+ virtual void visit (LlvmInlineAsm &expr) override;
virtual void visit (TypeParam &param) override;
virtual void visit (ConstGenericParam &param) override;
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
index 257f4cd..648bc07 100644
--- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.cc
@@ -423,6 +423,10 @@ PatternChecker::visit (InlineAsm &expr)
{}
void
+PatternChecker::visit (LlvmInlineAsm &expr)
+{}
+
+void
PatternChecker::visit (TypeParam &)
{}
diff --git a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
index 2171340..6d60ced 100644
--- a/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
+++ b/gcc/rust/checks/errors/rust-hir-pattern-analysis.h
@@ -106,6 +106,7 @@ private:
virtual void visit (AwaitExpr &expr) override;
virtual void visit (AsyncBlockExpr &expr) override;
virtual void visit (InlineAsm &expr) override;
+ virtual void visit (LlvmInlineAsm &expr) override;
virtual void visit (TypeParam &param) override;
virtual void visit (ConstGenericParam &param) override;
virtual void visit (LifetimeWhereClauseItem &item) override;
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.cc b/gcc/rust/checks/errors/rust-unsafe-checker.cc
index 8aa59ee..46eef11 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.cc
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.cc
@@ -481,9 +481,14 @@ UnsafeChecker::visit (MethodCallExpr &expr)
TyTy::BaseType *method_type;
context.lookup_type (expr.get_method_name ().get_mappings ().get_hirid (),
&method_type);
+ if (!method_type || !method_type->is<TyTy::FnType> ())
+ return;
auto &fn = static_cast<TyTy::FnType &> (*method_type);
+ // FIXME
+ // should probably use the defid lookup instead
+ // tl::optional<HIR::Item *> lookup_defid (DefId id);
auto method = mappings.lookup_hir_implitem (fn.get_ref ());
if (!unsafe_context.is_in_context () && method)
check_unsafe_call (static_cast<Function *> (method->first),
@@ -666,6 +671,17 @@ UnsafeChecker::visit (InlineAsm &expr)
}
void
+UnsafeChecker::visit (LlvmInlineAsm &expr)
+{
+ if (unsafe_context.is_in_context ())
+ return;
+
+ rust_error_at (
+ expr.get_locus (), ErrorCode::E0133,
+ "use of inline assembly is unsafe and requires unsafe function or block");
+}
+
+void
UnsafeChecker::visit (TypeParam &)
{}
diff --git a/gcc/rust/checks/errors/rust-unsafe-checker.h b/gcc/rust/checks/errors/rust-unsafe-checker.h
index 63098fe..9a8fb7c 100644
--- a/gcc/rust/checks/errors/rust-unsafe-checker.h
+++ b/gcc/rust/checks/errors/rust-unsafe-checker.h
@@ -114,6 +114,7 @@ private:
virtual void visit (AwaitExpr &expr) override;
virtual void visit (AsyncBlockExpr &expr) override;
virtual void visit (InlineAsm &expr) override;
+ virtual void visit (LlvmInlineAsm &expr) override;
virtual void visit (TypeParam &param) override;
virtual void visit (ConstGenericParam &param) override;
virtual void visit (LifetimeWhereClauseItem &item) override;
diff --git a/gcc/rust/expand/rust-derive-clone.cc b/gcc/rust/expand/rust-derive-clone.cc
index a955b58..321fa00 100644
--- a/gcc/rust/expand/rust-derive-clone.cc
+++ b/gcc/rust/expand/rust-derive-clone.cc
@@ -293,8 +293,14 @@ DeriveClone::clone_enum_struct (PathInExpression variant_path,
new ReferencePattern (std::unique_ptr<Pattern> (new StructPattern (
variant_path, loc, pattern_elts)),
false, false, loc));
+
+ PathInExpression new_path (variant_path.get_segments (),
+ variant_path.get_outer_attrs (),
+ variant_path.get_locus (),
+ variant_path.opening_scope_resolution ());
+
auto expr = std::unique_ptr<Expr> (
- new StructExprStructFields (variant_path, std::move (cloned_fields), loc));
+ new StructExprStructFields (new_path, std::move (cloned_fields), loc));
return builder.match_case (std::move (pattern), std::move (expr));
}
diff --git a/gcc/rust/expand/rust-derive.h b/gcc/rust/expand/rust-derive.h
index d8cc0a4..5fca49c 100644
--- a/gcc/rust/expand/rust-derive.h
+++ b/gcc/rust/expand/rust-derive.h
@@ -171,6 +171,7 @@ private:
virtual void visit (AwaitExpr &expr) override final{};
virtual void visit (AsyncBlockExpr &expr) override final{};
virtual void visit (InlineAsm &expr) override final{};
+ virtual void visit (LlvmInlineAsm &expr) override final{};
virtual void visit (TypeParam &param) override final{};
virtual void visit (LifetimeWhereClauseItem &item) override final{};
virtual void visit (TypeBoundWhereClauseItem &item) override final{};
diff --git a/gcc/rust/expand/rust-expand-visitor.cc b/gcc/rust/expand/rust-expand-visitor.cc
index d4db313..42df5e1 100644
--- a/gcc/rust/expand/rust-expand-visitor.cc
+++ b/gcc/rust/expand/rust-expand-visitor.cc
@@ -489,7 +489,8 @@ ExpandVisitor::visit (AST::PathInExpression &path)
void
ExpandVisitor::visit (AST::TypePathSegmentGeneric &segment)
{
- expand_generic_args (segment.get_generic_args ());
+ if (segment.has_generic_args ())
+ expand_generic_args (segment.get_generic_args ());
}
void
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.cc b/gcc/rust/expand/rust-macro-builtins-asm.cc
index 4d02604..e255729 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.cc
+++ b/gcc/rust/expand/rust-macro-builtins-asm.cc
@@ -22,6 +22,7 @@
#include "rust-ast.h"
#include "rust-fmt.h"
#include "rust-stmt.h"
+#include "rust-parse.h"
namespace Rust {
std::map<AST::InlineAsmOption, std::string> InlineAsmOptionMap{
@@ -660,6 +661,15 @@ MacroBuiltin::asm_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
return parse_asm (invoc_locus, invoc, semicolon, is_global_asm);
}
+tl::optional<AST::Fragment>
+MacroBuiltin::llvm_asm_handler (location_t invoc_locus,
+ AST::MacroInvocData &invoc,
+ AST::InvocKind semicolon,
+ AST::AsmKind is_global_asm)
+{
+ return parse_llvm_asm (invoc_locus, invoc, semicolon, is_global_asm);
+}
+
tl::expected<InlineAsmContext, InlineAsmParseError>
parse_asm_arg (InlineAsmContext inline_asm_ctx)
{
@@ -671,6 +681,14 @@ parse_asm_arg (InlineAsmContext inline_asm_ctx)
{
token = parser.peek_current_token ();
+ if (token->get_id () == COLON || token->get_id () == SCOPE_RESOLUTION)
+ {
+ rust_error_at (
+ token->get_locus (),
+ "the legacy LLVM-style %<asm!%> syntax is no longer supported");
+ return tl::unexpected<InlineAsmParseError> (COMMITTED);
+ }
+
// We accept a comma token here.
if (token->get_id () != COMMA
&& inline_asm_ctx.consumed_comma_without_formatted_string)
@@ -962,4 +980,223 @@ validate (InlineAsmContext inline_asm_ctx)
{
return tl::expected<InlineAsmContext, InlineAsmParseError> (inline_asm_ctx);
}
+
+tl::optional<LlvmAsmContext>
+parse_llvm_templates (LlvmAsmContext ctx)
+{
+ auto &parser = ctx.parser;
+
+ auto token = parser.peek_current_token ();
+
+ if (token->get_id () == ctx.last_token_id
+ || token->get_id () != STRING_LITERAL)
+ {
+ return tl::nullopt;
+ }
+
+ ctx.llvm_asm.get_templates ().emplace_back (token->get_locus (),
+ strip_double_quotes (
+ token->as_string ()));
+ ctx.parser.skip_token ();
+
+ token = parser.peek_current_token ();
+ if (token->get_id () != ctx.last_token_id && token->get_id () != COLON
+ && token->get_id () != SCOPE_RESOLUTION)
+ {
+ // We do not handle multiple template string, we provide minimal support
+ // for the black_box intrinsics.
+ rust_unreachable ();
+ }
+
+ return ctx;
+}
+
+tl::optional<LlvmAsmContext>
+parse_llvm_arguments (LlvmAsmContext ctx)
+{
+ auto &parser = ctx.parser;
+ enum State
+ {
+ Templates = 0,
+ Output,
+ Input,
+ Clobbers,
+ Options
+ } current_state
+ = State::Templates;
+
+ while (parser.peek_current_token ()->get_id () != ctx.last_token_id
+ && parser.peek_current_token ()->get_id () != END_OF_FILE)
+ {
+ if (parser.peek_current_token ()->get_id () == SCOPE_RESOLUTION)
+ {
+ parser.skip_token (SCOPE_RESOLUTION);
+ current_state = static_cast<State> (current_state + 2);
+ }
+ else
+ {
+ parser.skip_token (COLON);
+ current_state = static_cast<State> (current_state + 1);
+ }
+
+ switch (current_state)
+ {
+ case State::Output:
+ parse_llvm_outputs (ctx);
+ break;
+ case State::Input:
+ parse_llvm_inputs (ctx);
+ break;
+ case State::Clobbers:
+ parse_llvm_clobbers (ctx);
+ break;
+ case State::Options:
+ parse_llvm_options (ctx);
+ break;
+ case State::Templates:
+ default:
+ rust_unreachable ();
+ }
+ }
+
+ return ctx;
+}
+
+void
+parse_llvm_operands (LlvmAsmContext &ctx, std::vector<AST::LlvmOperand> &result)
+{
+ auto &parser = ctx.parser;
+ auto token = parser.peek_current_token ();
+ while (token->get_id () != COLON && token->get_id () != SCOPE_RESOLUTION
+ && token->get_id () != ctx.last_token_id)
+ {
+ std::string constraint;
+ if (token->get_id () == STRING_LITERAL)
+ {
+ constraint = strip_double_quotes (token->as_string ());
+ }
+ parser.skip_token (STRING_LITERAL);
+ parser.skip_token (LEFT_PAREN);
+
+ token = parser.peek_current_token ();
+
+ ParseRestrictions restrictions;
+ restrictions.expr_can_be_null = true;
+ auto expr = parser.parse_expr ();
+
+ parser.skip_token (RIGHT_PAREN);
+
+ result.emplace_back (constraint, std::move (expr));
+
+ if (parser.peek_current_token ()->get_id () == COMMA)
+ parser.skip_token (COMMA);
+
+ token = parser.peek_current_token ();
+ }
+}
+
+void
+parse_llvm_outputs (LlvmAsmContext &ctx)
+{
+ parse_llvm_operands (ctx, ctx.llvm_asm.get_outputs ());
+}
+
+void
+parse_llvm_inputs (LlvmAsmContext &ctx)
+{
+ parse_llvm_operands (ctx, ctx.llvm_asm.get_inputs ());
+}
+
+void
+parse_llvm_clobbers (LlvmAsmContext &ctx)
+{
+ auto &parser = ctx.parser;
+ auto token = parser.peek_current_token ();
+ while (token->get_id () != COLON && token->get_id () != ctx.last_token_id)
+ {
+ if (token->get_id () == STRING_LITERAL)
+ {
+ ctx.llvm_asm.get_clobbers ().push_back (
+ {strip_double_quotes (token->as_string ()), token->get_locus ()});
+ }
+ parser.skip_token (STRING_LITERAL);
+ token = parser.peek_current_token ();
+ }
+}
+
+void
+parse_llvm_options (LlvmAsmContext &ctx)
+{
+ auto &parser = ctx.parser;
+ auto token = parser.peek_current_token ();
+
+ while (token->get_id () != ctx.last_token_id)
+ {
+ if (token->get_id () == STRING_LITERAL)
+ {
+ auto token_str = strip_double_quotes (token->as_string ());
+
+ if (token_str == "volatile")
+ ctx.llvm_asm.set_volatile (true);
+ else if (token_str == "alignstack")
+ ctx.llvm_asm.set_align_stack (true);
+ else if (token_str == "intel")
+ ctx.llvm_asm.set_dialect (AST::LlvmInlineAsm::Dialect::Intel);
+ else
+ rust_error_at (token->get_locus (),
+ "Unknown llvm assembly option %qs",
+ token_str.c_str ());
+ }
+ parser.skip_token (STRING_LITERAL);
+
+ token = parser.peek_current_token ();
+
+ if (token->get_id () == ctx.last_token_id)
+ continue;
+ parser.skip_token (COMMA);
+ }
+
+ parser.skip_token ();
+}
+
+tl::optional<AST::Fragment>
+parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
+ AST::InvocKind semicolon, AST::AsmKind is_global_asm)
+{
+ MacroInvocLexer lex (invoc.get_delim_tok_tree ().to_token_stream ());
+ Parser<MacroInvocLexer> parser (lex);
+ auto last_token_id = macro_end_token (invoc.get_delim_tok_tree (), parser);
+
+ AST::LlvmInlineAsm llvm_asm{invoc_locus};
+
+ auto asm_ctx = LlvmAsmContext (llvm_asm, parser, last_token_id);
+
+ auto resulting_context
+ = parse_llvm_templates (asm_ctx).and_then (parse_llvm_arguments);
+
+ if (resulting_context)
+ {
+ auto node = (*resulting_context).llvm_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 (semicolon == AST::InvocKind::Semicoloned)
+ single_vec.emplace_back (AST::SingleASTNode (
+ std::make_unique<AST::ExprStmt> (std::move (node), invoc_locus,
+ semicolon
+ == AST::InvocKind::Semicoloned)));
+ else
+ single_vec.emplace_back (AST::SingleASTNode (std::move (node)));
+
+ AST::Fragment fragment_ast
+ = AST::Fragment (single_vec,
+ std::vector<std::unique_ptr<AST::Token>> ());
+ return fragment_ast;
+ }
+ return tl::nullopt;
+}
+
} // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-builtins-asm.h b/gcc/rust/expand/rust-macro-builtins-asm.h
index 8081dae..bd64a7f 100644
--- a/gcc/rust/expand/rust-macro-builtins-asm.h
+++ b/gcc/rust/expand/rust-macro-builtins-asm.h
@@ -172,4 +172,36 @@ tl::optional<std::string>
parse_label (Parser<MacroInvocLexer> &parser, TokenId last_token_id,
InlineAsmContext &inline_asm_ctx);
+// LLVM ASM bits
+
+class LlvmAsmContext
+{
+public:
+ AST::LlvmInlineAsm &llvm_asm;
+ Parser<MacroInvocLexer> &parser;
+ int last_token_id;
+
+public:
+ LlvmAsmContext (AST::LlvmInlineAsm &llvm_asm, Parser<MacroInvocLexer> &parser,
+ int last_token_id)
+ : llvm_asm (llvm_asm), parser (parser), last_token_id (last_token_id)
+ {}
+};
+
+void
+parse_llvm_outputs (LlvmAsmContext &ctx);
+
+void
+parse_llvm_inputs (LlvmAsmContext &ctx);
+
+void
+parse_llvm_clobbers (LlvmAsmContext &ctx);
+
+void
+parse_llvm_options (LlvmAsmContext &ctx);
+
+WARN_UNUSED_RESULT tl::optional<AST::Fragment>
+parse_llvm_asm (location_t invoc_locus, AST::MacroInvocData &invoc,
+ AST::InvocKind semicolon, AST::AsmKind is_global_asm);
+
} // namespace Rust
diff --git a/gcc/rust/expand/rust-macro-builtins.cc b/gcc/rust/expand/rust-macro-builtins.cc
index 8b406ff..b58ed71 100644
--- a/gcc/rust/expand/rust-macro-builtins.cc
+++ b/gcc/rust/expand/rust-macro-builtins.cc
@@ -103,6 +103,15 @@ inline_asm_maker (AST::AsmKind global_asm)
};
}
+AST::MacroTranscriberFunc
+inline_llvm_asm_maker (AST::AsmKind global_asm)
+{
+ return [global_asm] (location_t loc, AST::MacroInvocData &invoc,
+ AST::InvocKind semicolon) {
+ return MacroBuiltin::llvm_asm_handler (loc, invoc, semicolon, global_asm);
+ };
+}
+
std::unordered_map<std::string, AST::MacroTranscriberFunc>
MacroBuiltin::builtin_transcribers = {
{"assert", MacroBuiltin::assert_handler},
@@ -121,7 +130,7 @@ std::unordered_map<std::string, AST::MacroTranscriberFunc>
{"format_args_nl", format_args_maker (AST::FormatArgs::Newline::Yes)},
{"asm", inline_asm_maker (AST::AsmKind::Inline)},
// FIXME: Is that okay?
- {"llvm_asm", inline_asm_maker (AST::AsmKind::Inline)},
+ {"llvm_asm", inline_llvm_asm_maker (AST::AsmKind::Inline)},
{"global_asm", inline_asm_maker (AST::AsmKind::Global)},
{"option_env", MacroBuiltin::option_env_handler},
/* Unimplemented macro builtins */
diff --git a/gcc/rust/expand/rust-macro-builtins.h b/gcc/rust/expand/rust-macro-builtins.h
index ff06ebf..541e956 100644
--- a/gcc/rust/expand/rust-macro-builtins.h
+++ b/gcc/rust/expand/rust-macro-builtins.h
@@ -181,6 +181,10 @@ public:
AST::AsmKind is_global_asm);
static tl::optional<AST::Fragment>
+ llvm_asm_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
+ AST::InvocKind semicolon, AST::AsmKind is_global_asm);
+
+ static tl::optional<AST::Fragment>
format_args_handler (location_t invoc_locus, AST::MacroInvocData &invoc,
AST::InvocKind semicolon, AST::FormatArgs::Newline nl);
diff --git a/gcc/rust/hir/rust-ast-lower-base.cc b/gcc/rust/hir/rust-ast-lower-base.cc
index 5039798..2d9a445 100644
--- a/gcc/rust/hir/rust-ast-lower-base.cc
+++ b/gcc/rust/hir/rust-ast-lower-base.cc
@@ -267,6 +267,10 @@ void
ASTLoweringBase::visit (AST::InlineAsm &)
{}
+void
+ASTLoweringBase::visit (AST::LlvmInlineAsm &)
+{}
+
// void ASTLoweringBase::visit(MatchCasematch_case) {}
// void ASTLoweringBase:: (AST::MatchCaseBlockExpr &) {}
// void ASTLoweringBase:: (AST::MatchCaseExpr &) {}
diff --git a/gcc/rust/hir/rust-ast-lower-base.h b/gcc/rust/hir/rust-ast-lower-base.h
index b3bb174..3116181 100644
--- a/gcc/rust/hir/rust-ast-lower-base.h
+++ b/gcc/rust/hir/rust-ast-lower-base.h
@@ -152,6 +152,7 @@ public:
virtual void visit (AST::IfLetExpr &expr) override;
virtual void visit (AST::IfLetExprConseqElse &expr) override;
virtual void visit (AST::InlineAsm &expr) override;
+ virtual void visit (AST::LlvmInlineAsm &expr) override;
// virtual void visit(MatchCase& match_case) override;
// virtual void visit (AST::MatchCaseBlockExpr &match_case) override;
// virtual void visit (AST::MatchCaseExpr &match_case) override;
diff --git a/gcc/rust/hir/rust-ast-lower-expr.cc b/gcc/rust/hir/rust-ast-lower-expr.cc
index 3784e74..07d0c835 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.cc
+++ b/gcc/rust/hir/rust-ast-lower-expr.cc
@@ -955,6 +955,50 @@ ASTLoweringExpr::visit (AST::InlineAsm &expr)
hir_operands, expr.get_clobber_abi (),
expr.get_options (), mapping);
}
+
+void
+ASTLoweringExpr::visit (AST::LlvmInlineAsm &expr)
+{
+ auto crate_num = mappings.get_current_crate ();
+ Analysis::NodeMapping mapping (crate_num, expr.get_node_id (),
+ mappings.get_next_hir_id (crate_num),
+ mappings.get_next_localdef_id (crate_num));
+
+ std::vector<LlvmOperand> inputs;
+ std::vector<LlvmOperand> outputs;
+
+ for (auto i : expr.get_inputs ())
+ {
+ std::unique_ptr<Expr> inner_expr
+ = std::unique_ptr<Expr> (translate (*i.expr.get ()));
+ inputs.emplace_back (i.constraint, std::move (inner_expr));
+ }
+
+ for (auto o : expr.get_outputs ())
+ {
+ std::unique_ptr<Expr> inner_expr
+ = std::unique_ptr<Expr> (translate (*o.expr.get ()));
+ outputs.emplace_back (o.constraint, std::move (inner_expr));
+ }
+
+ HIR::LlvmInlineAsm::Options options{expr.is_volatile (),
+ expr.is_stack_aligned (),
+ expr.get_dialect ()};
+
+ // We're not really supporting llvm_asm, only the bare minimum
+ // we're quite conservative here as the current code support more usecase.
+ rust_assert (outputs.size () == 0);
+ rust_assert (inputs.size () <= 1);
+ rust_assert (expr.get_clobbers ().size () <= 1);
+ rust_assert (expr.get_templates ().size () == 1);
+ rust_assert (expr.get_templates ()[0].symbol == "");
+
+ translated
+ = new HIR::LlvmInlineAsm (expr.get_locus (), inputs, outputs,
+ expr.get_templates (), expr.get_clobbers (),
+ options, expr.get_outer_attrs (), mapping);
+}
+
void
ASTLoweringExpr::visit (AST::FormatArgs &fmt)
{
diff --git a/gcc/rust/hir/rust-ast-lower-expr.h b/gcc/rust/hir/rust-ast-lower-expr.h
index af60e01..adedeb3 100644
--- a/gcc/rust/hir/rust-ast-lower-expr.h
+++ b/gcc/rust/hir/rust-ast-lower-expr.h
@@ -122,6 +122,7 @@ public:
void visit (AST::ClosureExprInner &expr) override;
void visit (AST::ClosureExprInnerTyped &expr) override;
void visit (AST::InlineAsm &expr) override;
+ void visit (AST::LlvmInlineAsm &expr) override;
// Extra visitor for FormatArgs nodes
void visit (AST::FormatArgs &fmt) override;
diff --git a/gcc/rust/hir/rust-ast-lower-type.cc b/gcc/rust/hir/rust-ast-lower-type.cc
index d3e528d..a678f18 100644
--- a/gcc/rust/hir/rust-ast-lower-type.cc
+++ b/gcc/rust/hir/rust-ast-lower-type.cc
@@ -557,7 +557,7 @@ ASTLowerGenericParam::visit (AST::ConstGenericParam &param)
HIR::Expr *default_expr = nullptr;
if (param.has_default_value ())
default_expr = ASTLoweringExpr::translate (
- param.get_default_value ().get_expression ());
+ param.get_default_value_unchecked ().get_expression ());
translated = new HIR::ConstGenericParam (param.get_name ().as_string (),
std::unique_ptr<Type> (type),
diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc
index dafa823..cb32f68 100644
--- a/gcc/rust/hir/rust-hir-dump.cc
+++ b/gcc/rust/hir/rust-hir-dump.cc
@@ -1284,7 +1284,9 @@ Dump::visit (BlockExpr &e)
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 ());
+
+ if (e.has_label ())
+ put_field ("label", e.get_label ().as_string ());
visit_collection ("statements", e.get_statements ());
@@ -1508,6 +1510,10 @@ Dump::visit (InlineAsm &e)
{}
void
+Dump::visit (LlvmInlineAsm &e)
+{}
+
+void
Dump::visit (TypeParam &e)
{
begin ("TypeParam");
diff --git a/gcc/rust/hir/rust-hir-dump.h b/gcc/rust/hir/rust-hir-dump.h
index afcd668..45b1708 100644
--- a/gcc/rust/hir/rust-hir-dump.h
+++ b/gcc/rust/hir/rust-hir-dump.h
@@ -166,6 +166,7 @@ private:
virtual void visit (AwaitExpr &) override;
virtual void visit (AsyncBlockExpr &) override;
virtual void visit (InlineAsm &) override;
+ virtual void visit (LlvmInlineAsm &) override;
virtual void visit (TypeParam &) override;
virtual void visit (ConstGenericParam &) override;
diff --git a/gcc/rust/hir/tree/rust-hir-expr-abstract.h b/gcc/rust/hir/tree/rust-hir-expr-abstract.h
index ecf9bd1..5bc5d89 100644
--- a/gcc/rust/hir/tree/rust-hir-expr-abstract.h
+++ b/gcc/rust/hir/tree/rust-hir-expr-abstract.h
@@ -71,6 +71,7 @@ public:
AsyncBlock,
Path,
InlineAsm,
+ LlvmInlineAsm,
};
BaseKind get_hir_kind () override final { return Node::BaseKind::EXPR; }
diff --git a/gcc/rust/hir/tree/rust-hir-expr.h b/gcc/rust/hir/tree/rust-hir-expr.h
index 96f0cf6..375f474 100644
--- a/gcc/rust/hir/tree/rust-hir-expr.h
+++ b/gcc/rust/hir/tree/rust-hir-expr.h
@@ -3118,6 +3118,80 @@ public:
AST::AttrVec outer_attribs = AST::AttrVec ());
};
+struct LlvmOperand
+{
+ std::string constraint;
+ std::unique_ptr<Expr> expr;
+
+ LlvmOperand (std::string constraint, std::unique_ptr<Expr> &&expr)
+ : constraint (constraint), expr (std::move (expr))
+ {}
+
+ LlvmOperand (const LlvmOperand &other)
+ : constraint (other.constraint), expr (other.expr->clone_expr ())
+ {}
+ LlvmOperand &operator= (const LlvmOperand &other)
+ {
+ constraint = other.constraint;
+ expr = other.expr->clone_expr ();
+
+ return *this;
+ }
+};
+
+class LlvmInlineAsm : public ExprWithoutBlock
+{
+public:
+ struct Options
+ {
+ bool is_volatile;
+ bool align_stack;
+ AST::LlvmInlineAsm::Dialect dialect;
+ };
+
+ location_t locus;
+ AST::AttrVec outer_attrs;
+ std::vector<LlvmOperand> inputs;
+ std::vector<LlvmOperand> outputs;
+ std::vector<AST::TupleTemplateStr> templates;
+ std::vector<AST::TupleClobber> clobbers;
+ Options options;
+
+ LlvmInlineAsm (location_t locus, std::vector<LlvmOperand> inputs,
+ std::vector<LlvmOperand> outputs,
+ std::vector<AST::TupleTemplateStr> templates,
+ std::vector<AST::TupleClobber> clobbers, Options options,
+ AST::AttrVec outer_attrs, Analysis::NodeMapping mappings)
+ : ExprWithoutBlock (mappings, std::move (outer_attrs)), locus (locus),
+ inputs (std::move (inputs)), outputs (std::move (outputs)),
+ templates (std::move (templates)), clobbers (std::move (clobbers)),
+ options (options)
+ {}
+
+ AST::LlvmInlineAsm::Dialect get_dialect () { return options.dialect; }
+
+ location_t get_locus () const override { return locus; }
+
+ std::vector<AST::Attribute> &get_outer_attrs () { return outer_attrs; }
+
+ void accept_vis (HIRFullVisitor &vis) override;
+ void accept_vis (HIRExpressionVisitor &vis) override;
+
+ LlvmInlineAsm *clone_expr_without_block_impl () const override
+ {
+ return new LlvmInlineAsm (*this);
+ }
+
+ std::vector<AST::TupleTemplateStr> &get_templates () { return templates; }
+
+ Expr::ExprType get_expression_type () const override
+ {
+ return Expr::ExprType::LlvmInlineAsm;
+ }
+
+ std::vector<AST::TupleClobber> get_clobbers () { return clobbers; }
+};
+
} // namespace HIR
} // namespace Rust
diff --git a/gcc/rust/hir/tree/rust-hir-full-decls.h b/gcc/rust/hir/tree/rust-hir-full-decls.h
index 6c19f24..1e313ec 100644
--- a/gcc/rust/hir/tree/rust-hir-full-decls.h
+++ b/gcc/rust/hir/tree/rust-hir-full-decls.h
@@ -126,6 +126,7 @@ class InlineAsmRegClass;
struct AnonConst;
class InlineAsmOperand;
class InlineAsm;
+class LlvmInlineAsm;
// rust-stmt.h
class EmptyStmt;
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index b9b105b..37f599c 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -2070,6 +2070,8 @@ public:
Identifier get_name () const { return name; }
+ bool has_type () const { return expr != nullptr; }
+
bool has_expr () const { return expr != nullptr; }
Type &get_type ()
diff --git a/gcc/rust/hir/tree/rust-hir-visitor.h b/gcc/rust/hir/tree/rust-hir-visitor.h
index 800e647..283cc34 100644
--- a/gcc/rust/hir/tree/rust-hir-visitor.h
+++ b/gcc/rust/hir/tree/rust-hir-visitor.h
@@ -84,6 +84,7 @@ public:
virtual void visit (AwaitExpr &expr) = 0;
virtual void visit (AsyncBlockExpr &expr) = 0;
virtual void visit (InlineAsm &expr) = 0;
+ virtual void visit (LlvmInlineAsm &expr) = 0;
virtual void visit (TypeParam &param) = 0;
virtual void visit (ConstGenericParam &param) = 0;
virtual void visit (LifetimeWhereClauseItem &item) = 0;
@@ -220,6 +221,7 @@ public:
virtual void visit (AwaitExpr &) override {}
virtual void visit (AsyncBlockExpr &) override {}
virtual void visit (InlineAsm &) override {}
+ virtual void visit (LlvmInlineAsm &) override {}
virtual void visit (TypeParam &) override {}
virtual void visit (ConstGenericParam &) override {}
@@ -441,6 +443,7 @@ public:
virtual void visit (IfExpr &expr) = 0;
virtual void visit (IfExprConseqElse &expr) = 0;
virtual void visit (InlineAsm &expr) = 0;
+ virtual void visit (LlvmInlineAsm &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 c8bf9da..093d8d5 100644
--- a/gcc/rust/hir/tree/rust-hir.cc
+++ b/gcc/rust/hir/tree/rust-hir.cc
@@ -3822,6 +3822,17 @@ InlineAsm::accept_vis (HIRFullVisitor &vis)
}
void
+LlvmInlineAsm::accept_vis (HIRFullVisitor &vis)
+{
+ vis.visit (*this);
+}
+void
+LlvmInlineAsm::accept_vis (HIRExpressionVisitor &vis)
+{
+ vis.visit (*this);
+}
+
+void
BorrowExpr::accept_vis (HIRExpressionVisitor &vis)
{
vis.visit (*this);
diff --git a/gcc/rust/parse/rust-parse-impl.h b/gcc/rust/parse/rust-parse-impl.h
index 3bb758e..9dda231 100644
--- a/gcc/rust/parse/rust-parse-impl.h
+++ b/gcc/rust/parse/rust-parse-impl.h
@@ -3174,24 +3174,28 @@ Parser<ManagedTokenSource>::parse_generic_param (EndTokenPred is_end_token)
return nullptr;
// optional default value
- auto default_expr = AST::GenericArg::create_error ();
+ tl::optional<AST::GenericArg> default_expr = tl::nullopt;
if (lexer.peek_token ()->get_id () == EQUAL)
{
lexer.skip_token ();
auto tok = lexer.peek_token ();
default_expr = parse_generic_arg ();
- if (default_expr.is_error ())
- rust_error_at (tok->get_locus (),
- "invalid token for start of default value for "
- "const generic parameter: expected %<block%>, "
- "%<identifier%> or %<literal%>, got %qs",
- token_id_to_str (tok->get_id ()));
+ if (!default_expr)
+ {
+ rust_error_at (tok->get_locus (),
+ "invalid token for start of default value for "
+ "const generic parameter: expected %<block%>, "
+ "%<identifier%> or %<literal%>, got %qs",
+ token_id_to_str (tok->get_id ()));
+ return nullptr;
+ }
// At this point, we *know* that we are parsing a const
// expression
- if (default_expr.get_kind () == AST::GenericArg::Kind::Either)
- default_expr = default_expr.disambiguate_to_const ();
+ if (default_expr.value ().get_kind ()
+ == AST::GenericArg::Kind::Either)
+ default_expr = default_expr.value ().disambiguate_to_const ();
}
param = std::unique_ptr<AST::ConstGenericParam> (
@@ -6249,7 +6253,7 @@ Parser<ManagedTokenSource>::parse_type_path ()
}
template <typename ManagedTokenSource>
-AST::GenericArg
+tl::optional<AST::GenericArg>
Parser<ManagedTokenSource>::parse_generic_arg ()
{
auto tok = lexer.peek_token ();
@@ -6270,7 +6274,7 @@ Parser<ManagedTokenSource>::parse_generic_arg ()
if (type)
return AST::GenericArg::create_type (std::move (type));
else
- return AST::GenericArg::create_error ();
+ return tl::nullopt;
}
else if (next_tok->get_id () == COLON)
{
@@ -6287,7 +6291,7 @@ Parser<ManagedTokenSource>::parse_generic_arg ()
if (type)
return AST::GenericArg::create_type (std::move (type));
else
- return AST::GenericArg::create_error ();
+ return tl::nullopt;
}
lexer.skip_token ();
return AST::GenericArg::create_ambiguous (tok->get_str (),
@@ -6313,12 +6317,12 @@ Parser<ManagedTokenSource>::parse_generic_arg ()
if (type)
return AST::GenericArg::create_type (std::move (type));
else
- return AST::GenericArg::create_error ();
+ return tl::nullopt;
}
}
if (!expr)
- return AST::GenericArg::create_error ();
+ return tl::nullopt;
return AST::GenericArg::create_const (std::move (expr));
}
@@ -6383,9 +6387,9 @@ Parser<ManagedTokenSource>::parse_path_generic_args ()
break;
auto arg = parse_generic_arg ();
- if (!arg.is_error ())
+ if (arg)
{
- generic_args.emplace_back (std::move (arg));
+ generic_args.emplace_back (std::move (arg.value ()));
}
// FIXME: Do we need to break if we encounter an error?
diff --git a/gcc/rust/parse/rust-parse.h b/gcc/rust/parse/rust-parse.h
index ff79879..827d91d 100644
--- a/gcc/rust/parse/rust-parse.h
+++ b/gcc/rust/parse/rust-parse.h
@@ -226,7 +226,7 @@ private:
AST::TypePath parse_type_path ();
std::unique_ptr<AST::TypePathSegment> parse_type_path_segment ();
AST::PathIdentSegment parse_path_ident_segment ();
- AST::GenericArg parse_generic_arg ();
+ tl::optional<AST::GenericArg> parse_generic_arg ();
AST::GenericArgs parse_path_generic_args ();
AST::GenericArgsBinding parse_generic_args_binding ();
AST::TypePathFunction parse_type_path_function (location_t locus);
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc
index 6c35a22..b781ce33 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-base.cc
@@ -328,6 +328,10 @@ ResolverBase::visit (AST::InlineAsm &)
{}
void
+ResolverBase::visit (AST::LlvmInlineAsm &)
+{}
+
+void
ResolverBase::visit (AST::TypeParam &)
{}
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h
index ab74e84..5bb9e4f 100644
--- a/gcc/rust/resolve/rust-ast-resolve-base.h
+++ b/gcc/rust/resolve/rust-ast-resolve-base.h
@@ -110,6 +110,7 @@ public:
void visit (AST::AwaitExpr &);
void visit (AST::AsyncBlockExpr &);
void visit (AST::InlineAsm &);
+ void visit (AST::LlvmInlineAsm &);
void visit (AST::TypeParam &);
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc
index 8070fc1..6242235 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc
@@ -368,6 +368,17 @@ ResolveExpr::visit (AST::InlineAsm &expr)
{
translate_operand (expr, prefix, canonical_prefix);
}
+
+void
+ResolveExpr::visit (AST::LlvmInlineAsm &expr)
+{
+ for (auto &output : expr.get_outputs ())
+ ResolveExpr::go (*output.expr, prefix, canonical_prefix);
+
+ for (auto &input : expr.get_inputs ())
+ ResolveExpr::go (*input.expr, prefix, canonical_prefix);
+}
+
void
ResolveExpr::visit (AST::UnsafeBlockExpr &expr)
{
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h
index 562a3bd..b296d66 100644
--- a/gcc/rust/resolve/rust-ast-resolve-expr.h
+++ b/gcc/rust/resolve/rust-ast-resolve-expr.h
@@ -57,6 +57,7 @@ public:
void visit (AST::IfLetExprConseqElse &expr) override;
void visit (AST::BlockExpr &expr) override;
void visit (AST::InlineAsm &expr) override;
+ void visit (AST::LlvmInlineAsm &expr) override;
void visit (AST::UnsafeBlockExpr &expr) override;
void visit (AST::ArrayElemsValues &elems) override;
void visit (AST::ArrayExpr &expr) override;
diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc
index 530926d..fb6715d 100644
--- a/gcc/rust/resolve/rust-ast-resolve-path.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-path.cc
@@ -68,8 +68,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr)
if (in_middle_of_path && segment.is_lower_self_seg ())
{
rust_error_at (segment.get_locus (), ErrorCode::E0433,
- "leading path segment %qs can only be used at the "
- "beginning of a path",
+ "%qs in paths can only be used in start position",
segment.as_string ().c_str ());
return UNKNOWN_NODEID;
}
@@ -372,8 +371,9 @@ ResolvePath::resolve_path (AST::SimplePath &expr)
{
if (!is_first_segment)
{
- rust_error_at (segment.get_locus (),
- "%<super%> can only be used in start position");
+ rust_error_at (
+ segment.get_locus (), ErrorCode::E0433,
+ "%<super%> in paths can only be used in start position");
return UNKNOWN_NODEID;
}
if (module_scope_id == crate_scope_id)
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc
index 606141c..8fd69c3 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.cc
+++ b/gcc/rust/resolve/rust-ast-resolve-type.cc
@@ -176,8 +176,7 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
if (in_middle_of_path && segment->is_lower_self_seg ())
{
rust_error_at (segment->get_locus (), ErrorCode::E0433,
- "leading path segment %qs can only be used at the "
- "beginning of a path",
+ "%qs in paths can only be used in start position",
segment->as_string ().c_str ());
return false;
}
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h
index 8379d0e..f1481fc 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.h
+++ b/gcc/rust/resolve/rust-ast-resolve-type.h
@@ -141,8 +141,8 @@ public:
if (first_pass)
ResolveType::go (param.get_type ());
else if (param.has_default_value ())
- ResolveExpr::go (param.get_default_value ().get_expression (), prefix,
- canonical_prefix);
+ ResolveExpr::go (param.get_default_value_unchecked ().get_expression (),
+ prefix, canonical_prefix);
}
void visit (AST::TypeParam &param) override
diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc
index 7528e79..480034c 100644
--- a/gcc/rust/resolve/rust-default-resolver.cc
+++ b/gcc/rust/resolve/rust-default-resolver.cc
@@ -179,5 +179,13 @@ DefaultResolver::visit (AST::StaticItem &item)
ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis);
}
+void
+DefaultResolver::visit (AST::TypeParam &param)
+{
+ auto expr_vis = [this, &param] () { AST::DefaultASTVisitor::visit (param); };
+
+ ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis);
+}
+
} // namespace Resolver2_0
} // namespace Rust
diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h
index 587d7d4..2a987ef 100644
--- a/gcc/rust/resolve/rust-default-resolver.h
+++ b/gcc/rust/resolve/rust-default-resolver.h
@@ -50,6 +50,8 @@ public:
void visit (AST::InherentImpl &) override;
void visit (AST::TraitImpl &) override;
+ void visit (AST::TypeParam &) override;
+
// type dec nodes, which visit their fields or variants by default
void visit (AST::StructStruct &) override;
void visit (AST::TupleStruct &) override;
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 36456e1..3390f09 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc
@@ -70,8 +70,7 @@ Early::go (AST::Crate &crate)
bool
Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob)
{
- auto resolved
- = ctx.resolve_path (glob.to_resolve.get_segments (), Namespace::Types);
+ auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types);
if (!resolved.has_value ())
return false;
@@ -141,6 +140,10 @@ Early::build_import_mapping (
// be moved into the newly created import mappings
auto path = import.to_resolve;
+ // used to skip the "unresolved import" error
+ // if we output other errors during resolution
+ size_t old_error_count = macro_resolve_errors.size ();
+
switch (import.kind)
{
case TopLevel::ImportKind::Kind::Glob:
@@ -154,7 +157,7 @@ Early::build_import_mapping (
break;
}
- if (!found)
+ if (!found && old_error_count == macro_resolve_errors.size ())
collect_error (Error (path.get_final_segment ().get_locus (),
ErrorCode::E0433, "unresolved import %qs",
path.as_string ().c_str ()));
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 c4226fe..e78bec0 100644
--- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h
@@ -218,7 +218,6 @@ private:
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
@@ -229,13 +228,22 @@ private:
};
};
- ctx.resolve_path (segments, Namespace::Values)
+ std::vector<Error> value_errors;
+ std::vector<Error> type_errors;
+ std::vector<Error> macro_errors;
+
+ ctx.resolve_path (path, value_errors, Namespace::Values)
.map (pair_with_ns (Namespace::Values));
- ctx.resolve_path (segments, Namespace::Types)
+ ctx.resolve_path (path, type_errors, Namespace::Types)
.map (pair_with_ns (Namespace::Types));
- ctx.resolve_path (segments, Namespace::Macros)
+ ctx.resolve_path (path, macro_errors, Namespace::Macros)
.map (pair_with_ns (Namespace::Macros));
+ if (!value_errors.empty () && !type_errors.empty ()
+ && !macro_errors.empty ())
+ for (auto &ent : value_errors)
+ collect_error (std::move (ent));
+
return resolved;
}
diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h
index cf02651..81468e5 100644
--- a/gcc/rust/resolve/rust-forever-stack.h
+++ b/gcc/rust/resolve/rust-forever-stack.h
@@ -673,7 +673,8 @@ public:
template <typename S>
tl::optional<Rib::Definition> resolve_path (
const std::vector<S> &segments, bool has_opening_scope_resolution,
- std::function<void (const S &, NodeId)> insert_segment_resolution);
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
// FIXME: Documentation
tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const;
@@ -792,13 +793,15 @@ private:
tl::optional<SegIterator<S>> find_starting_point (
const std::vector<S> &segments,
std::reference_wrapper<Node> &starting_point,
- std::function<void (const S &, NodeId)> insert_segment_resolution);
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
template <typename S>
tl::optional<Node &> resolve_segments (
Node &starting_point, const std::vector<S> &segments,
SegIterator<S> iterator,
- std::function<void (const S &, NodeId)> insert_segment_resolution);
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors);
tl::optional<Rib::Definition> resolve_final_segment (Node &final_node,
std::string &seg_name,
@@ -828,6 +831,21 @@ private:
tl::optional<Node &> dfs_node (Node &starting_point, NodeId to_find);
tl::optional<const Node &> dfs_node (const Node &starting_point,
NodeId to_find) const;
+
+public:
+ bool forward_declared (NodeId definition, NodeId usage)
+ {
+ if (peek ().kind != Rib::Kind::ForwardTypeParamBan)
+ return false;
+
+ const auto &definition_rib = dfs_rib (cursor (), definition);
+
+ if (!definition_rib)
+ return false;
+
+ return (definition_rib
+ && definition_rib.value ().kind == Rib::Kind::ForwardTypeParamBan);
+ }
};
} // namespace Resolver2_0
diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx
index 993e2d4..069111ee 100644
--- a/gcc/rust/resolve/rust-forever-stack.hxx
+++ b/gcc/rust/resolve/rust-forever-stack.hxx
@@ -398,12 +398,13 @@ ForeverStack<N>::find_closest_module (Node &starting_point)
* segments */
template <typename S>
static inline bool
-check_leading_kw_at_start (const S &segment, bool condition)
+check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment,
+ bool condition)
{
if (condition)
- rust_error_at (
+ collect_errors.emplace_back (
segment.get_locus (), ErrorCode::E0433,
- "leading path segment %qs can only be used at the beginning of a path",
+ "%qs in paths can only be used in start position",
segment.as_string ().c_str ());
return condition;
@@ -419,7 +420,8 @@ template <typename S>
tl::optional<typename std::vector<S>::const_iterator>
ForeverStack<N>::find_starting_point (
const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point,
- std::function<void (const S &, NodeId)> insert_segment_resolution)
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
auto iterator = segments.begin ();
@@ -436,8 +438,9 @@ ForeverStack<N>::find_starting_point (
// if we're after the first path segment and meet `self` or `crate`, it's
// an error - we should only be seeing `super` keywords at this point
- if (check_leading_kw_at_start (seg, !is_start (iterator, segments)
- && is_self_or_crate))
+ if (check_leading_kw_at_start (collect_errors, seg,
+ !is_start (iterator, segments)
+ && is_self_or_crate))
return tl::nullopt;
if (seg.is_crate_path_seg ())
@@ -460,8 +463,9 @@ ForeverStack<N>::find_starting_point (
starting_point = find_closest_module (starting_point);
if (starting_point.get ().is_root ())
{
- rust_error_at (seg.get_locus (), ErrorCode::E0433,
- "too many leading %<super%> keywords");
+ collect_errors.emplace_back (
+ seg.get_locus (), ErrorCode::E0433,
+ "too many leading %<super%> keywords");
return tl::nullopt;
}
@@ -487,7 +491,8 @@ tl::optional<typename ForeverStack<N>::Node &>
ForeverStack<N>::resolve_segments (
Node &starting_point, const std::vector<S> &segments,
typename std::vector<S>::const_iterator iterator,
- std::function<void (const S &, NodeId)> insert_segment_resolution)
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
Node *current_node = &starting_point;
for (; !is_last (iterator, segments); iterator++)
@@ -509,9 +514,10 @@ ForeverStack<N>::resolve_segments (
rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ());
// check that we don't encounter *any* leading keywords afterwards
- if (check_leading_kw_at_start (seg, seg.is_crate_path_seg ()
- || seg.is_super_path_seg ()
- || seg.is_lower_self_seg ()))
+ if (check_leading_kw_at_start (collect_errors, seg,
+ seg.is_crate_path_seg ()
+ || seg.is_super_path_seg ()
+ || seg.is_lower_self_seg ()))
return tl::nullopt;
tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt;
@@ -620,7 +626,8 @@ template <typename S>
tl::optional<Rib::Definition>
ForeverStack<N>::resolve_path (
const std::vector<S> &segments, bool has_opening_scope_resolution,
- std::function<void (const S &, NodeId)> insert_segment_resolution)
+ std::function<void (const S &, NodeId)> insert_segment_resolution,
+ std::vector<Error> &collect_errors)
{
// TODO: What to do if segments.empty() ?
@@ -668,15 +675,16 @@ ForeverStack<N>::resolve_path (
std::reference_wrapper<Node> starting_point = cursor ();
auto res
- = find_starting_point (segments, starting_point, insert_segment_resolution)
+ = find_starting_point (segments, starting_point, insert_segment_resolution,
+ collect_errors)
.and_then (
- [this, &segments, &starting_point, &insert_segment_resolution] (
- typename std::vector<S>::const_iterator iterator) {
+ [this, &segments, &starting_point, &insert_segment_resolution,
+ &collect_errors] (typename std::vector<S>::const_iterator iterator) {
return resolve_segments (starting_point.get (), segments, iterator,
- insert_segment_resolution);
+ insert_segment_resolution, collect_errors);
})
.and_then ([this, &segments, &insert_segment_resolution] (
- Node final_node) -> tl::optional<Rib::Definition> {
+ Node &final_node) -> tl::optional<Rib::Definition> {
// leave resolution within impl blocks to type checker
if (final_node.rib.kind == Rib::Kind::TraitOrImpl)
return tl::nullopt;
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 f743e1e..6ec0422 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc
@@ -129,6 +129,54 @@ Late::new_label (Identifier name, NodeId id)
}
void
+Late::visit (AST::ForLoopExpr &expr)
+{
+ visit_outer_attrs (expr);
+
+ ctx.bindings.enter (BindingSource::For);
+
+ visit (expr.get_pattern ());
+
+ ctx.bindings.exit ();
+
+ visit (expr.get_iterator_expr ());
+ visit (expr.get_loop_label ());
+ visit (expr.get_loop_block ());
+}
+
+void
+Late::visit (AST::IfLetExpr &expr)
+{
+ visit_outer_attrs (expr);
+
+ ctx.bindings.enter (BindingSource::Let);
+
+ for (auto &pattern : expr.get_patterns ())
+ visit (pattern);
+
+ ctx.bindings.exit ();
+
+ visit (expr.get_value_expr ());
+ visit (expr.get_if_block ());
+}
+
+void
+Late::visit (AST::MatchArm &arm)
+{
+ visit_outer_attrs (arm);
+
+ ctx.bindings.enter (BindingSource::Match);
+
+ for (auto &pattern : arm.get_patterns ())
+ visit (pattern);
+
+ ctx.bindings.exit ();
+
+ if (arm.has_match_arm_guard ())
+ visit (arm.get_guard_expr ());
+}
+
+void
Late::visit (AST::LetStmt &let)
{
DefaultASTVisitor::visit_outer_attrs (let);
@@ -138,8 +186,13 @@ Late::visit (AST::LetStmt &let)
// this makes variable shadowing work properly
if (let.has_init_expr ())
visit (let.get_init_expr ());
+
+ ctx.bindings.enter (BindingSource::Let);
+
visit (let.get_pattern ());
+ ctx.bindings.exit ();
+
if (let.has_else_expr ())
visit (let.get_init_expr ());
@@ -167,9 +220,68 @@ Late::visit (AST::IdentifierPattern &identifier)
// but values does not allow shadowing... since functions cannot shadow
// do we insert functions in labels as well?
+ if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ()))
+ {
+ if (ctx.bindings.peek ().get_source () == BindingSource::Param)
+ rust_error_at (
+ identifier.get_locus (), ErrorCode::E0415,
+ "identifier %qs is bound more than once in the same parameter list",
+ identifier.as_string ().c_str ());
+ else
+ rust_error_at (
+ identifier.get_locus (), ErrorCode::E0416,
+ "identifier %qs is bound more than once in the same pattern",
+ identifier.as_string ().c_str ());
+ return;
+ }
+
+ ctx.bindings.peek ().insert_ident (identifier.get_ident ());
+
+ if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ()))
+ {
+ // FIXME: map usage instead
+ std::ignore = ctx.values.insert_shadowable (identifier.get_ident (),
+ identifier.get_node_id ());
+ }
+ else
+ {
+ // 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
+Late::visit (AST::AltPattern &pattern)
+{
+ ctx.bindings.peek ().push (Binding::Kind::Or);
+ for (auto &alt : pattern.get_alts ())
+ {
+ ctx.bindings.peek ().push (Binding::Kind::Product);
+ visit (alt);
+ ctx.bindings.peek ().merge ();
+ }
+ ctx.bindings.peek ().merge ();
+}
+
+void
+Late::visit_function_params (AST::Function &function)
+{
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : function.get_function_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
+}
+
+void
+Late::visit (AST::StructPatternFieldIdent &field)
+{
// 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 ());
+ std::ignore = ctx.values.insert_shadowable (field.get_identifier (),
+ field.get_node_id ());
}
void
@@ -347,8 +459,8 @@ Late::visit (AST::PathInExpression &expr)
if (!resolved)
{
if (!ctx.lookup (expr.get_segments ().front ().get_node_id ()))
- rust_error_at (expr.get_locus (),
- "could not resolve path expression: %qs",
+ rust_error_at (expr.get_locus (), ErrorCode::E0433,
+ "Cannot find path %qs in this scope",
expr.as_simple_path ().as_string ().c_str ());
return;
}
@@ -393,6 +505,14 @@ Late::visit (AST::TypePath &type)
return;
}
+ if (ctx.types.forward_declared (resolved->get_node_id (),
+ type.get_node_id ()))
+ {
+ rust_error_at (type.get_locus (), ErrorCode::E0128,
+ "type parameters with a default cannot use forward "
+ "declared identifiers");
+ }
+
ctx.map_usage (Usage (type.get_node_id ()),
Definition (resolved->get_node_id ()));
}
@@ -509,14 +629,35 @@ void
Late::visit (AST::ClosureExprInner &closure)
{
add_captures (closure, ctx);
- DefaultResolver::visit (closure);
+
+ visit_outer_attrs (closure);
+
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : closure.get_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
+
+ visit (closure.get_definition_expr ());
}
void
Late::visit (AST::ClosureExprInnerTyped &closure)
{
add_captures (closure, ctx);
- DefaultResolver::visit (closure);
+
+ visit_outer_attrs (closure);
+
+ ctx.bindings.enter (BindingSource::Param);
+
+ for (auto &param : closure.get_params ())
+ visit (param);
+
+ ctx.bindings.exit ();
+
+ visit (closure.get_return_type ());
+ visit (closure.get_definition_block ());
}
} // namespace Resolver2_0
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 5703b15..171d9bf 100644
--- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h
+++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h
@@ -37,12 +37,20 @@ public:
void new_label (Identifier name, NodeId id);
+ // Specialized visit bits
+ void visit_function_params (AST::Function &function) override;
+
// some more label declarations
void visit (AST::LetStmt &) override;
// TODO: Do we need this?
// void visit (AST::Method &) override;
void visit (AST::IdentifierPattern &) override;
+ void visit (AST::StructPatternFieldIdent &) override;
+ void visit (AST::AltPattern &) override;
void visit (AST::SelfParam &) override;
+ void visit (AST::MatchArm &) override;
+ void visit (AST::ForLoopExpr &) override;
+ void visit (AST::IfLetExpr &) override;
// resolutions
void visit (AST::IdentifierExpr &) override;
diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc
index 92c4863..f098e48 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.cc
+++ b/gcc/rust/resolve/rust-name-resolution-context.cc
@@ -23,6 +23,65 @@
namespace Rust {
namespace Resolver2_0 {
+BindingLayer::BindingLayer (BindingSource source) : source (source)
+{
+ push (Binding::Kind::Product);
+}
+
+bool
+BindingLayer::bind_test (Identifier ident, Binding::Kind kind)
+{
+ for (auto &bind : bindings)
+ {
+ if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind)
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+BindingLayer::push (Binding::Kind kind)
+{
+ bindings.push_back (Binding (kind));
+}
+
+bool
+BindingLayer::is_and_bound (Identifier ident)
+{
+ return bind_test (ident, Binding::Kind::Product);
+}
+
+bool
+BindingLayer::is_or_bound (Identifier ident)
+{
+ return bind_test (ident, Binding::Kind::Or);
+}
+
+void
+BindingLayer::insert_ident (Identifier ident)
+{
+ bindings.back ().set.insert (ident);
+}
+
+void
+BindingLayer::merge ()
+{
+ auto last_binding = bindings.back ();
+ bindings.pop_back ();
+ for (auto &value : last_binding.set)
+ {
+ bindings.back ().set.insert (value);
+ }
+}
+
+BindingSource
+BindingLayer::get_source () const
+{
+ return source;
+}
+
NameResolutionContext::NameResolutionContext ()
: mappings (Analysis::Mappings::get ())
{}
diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h
index 84c0800..19ba750 100644
--- a/gcc/rust/resolve/rust-name-resolution-context.h
+++ b/gcc/rust/resolve/rust-name-resolution-context.h
@@ -23,6 +23,7 @@
#include "rust-forever-stack.h"
#include "rust-hir-map.h"
#include "rust-rib.h"
+#include "rust-stacked-contexts.h"
namespace Rust {
namespace Resolver2_0 {
@@ -156,6 +157,62 @@ public:
NodeId id;
};
+struct Binding
+{
+ enum class Kind
+ {
+ Product,
+ Or,
+ } kind;
+
+ std::unordered_set<Identifier> set;
+
+ Binding (Binding::Kind kind) : kind (kind) {}
+};
+
+/**
+ * Used to identify the source of a binding, and emit the correct error message.
+ */
+enum class BindingSource
+{
+ Match,
+ Let,
+ For,
+ /* Closure param or function param */
+ Param
+};
+
+class BindingLayer
+{
+ BindingSource source;
+ std::vector<Binding> bindings;
+
+ bool bind_test (Identifier ident, Binding::Kind kind);
+
+public:
+ void push (Binding::Kind kind);
+
+ BindingLayer (BindingSource source);
+
+ /**
+ * Identifies if the identifier has been used in a product binding context.
+ * eg. `let (a, a) = test();`
+ */
+ bool is_and_bound (Identifier ident);
+
+ /**
+ * Identifies if the identifier has been used in a or context.
+ * eg. `let (a, 1) | (a, 2) = test()`
+ */
+ bool is_or_bound (Identifier ident);
+
+ void insert_ident (Identifier ident);
+
+ void merge ();
+
+ BindingSource get_source () const;
+};
+
// Now our resolver, which keeps track of all the `ForeverStack`s we could want
class NameResolutionContext
{
@@ -212,6 +269,7 @@ public:
ForeverStack<Namespace::Labels> labels;
Analysis::Mappings &mappings;
+ StackedContexts<BindingLayer> bindings;
// TODO: Rename
// TODO: Use newtype pattern for Usage and Definition
@@ -220,9 +278,10 @@ public:
tl::optional<NodeId> lookup (NodeId usage) const;
template <typename S>
- tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments,
- bool has_opening_scope_resolution,
- Namespace ns)
+ tl::optional<Rib::Definition>
+ resolve_path (const std::vector<S> &segments,
+ bool has_opening_scope_resolution,
+ std::vector<Error> &collect_errors, Namespace ns)
{
std::function<void (const S &, NodeId)> insert_segment_resolution
= [this] (const S &seg, NodeId id) {
@@ -234,60 +293,102 @@ public:
{
case Namespace::Values:
return values.resolve_path (segments, has_opening_scope_resolution,
- insert_segment_resolution);
+ insert_segment_resolution, collect_errors);
case Namespace::Types:
return types.resolve_path (segments, has_opening_scope_resolution,
- insert_segment_resolution);
+ insert_segment_resolution, collect_errors);
case Namespace::Macros:
return macros.resolve_path (segments, has_opening_scope_resolution,
- insert_segment_resolution);
+ insert_segment_resolution, collect_errors);
case Namespace::Labels:
return labels.resolve_path (segments, has_opening_scope_resolution,
- insert_segment_resolution);
+ insert_segment_resolution, collect_errors);
default:
rust_unreachable ();
}
}
template <typename S, typename... Args>
- tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments,
- bool has_opening_scope_resolution,
- Args... ns_args)
+ tl::optional<Rib::Definition>
+ resolve_path (const std::vector<S> &segments,
+ bool has_opening_scope_resolution,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
{
- std::initializer_list<Namespace> namespaces = {ns_args...};
+ std::initializer_list<Namespace> namespaces = {ns_first, ns_args...};
for (auto ns : namespaces)
{
- if (auto ret
- = resolve_path (segments, has_opening_scope_resolution, ns))
+ std::vector<Error> collect_errors_inner;
+ if (auto ret = resolve_path (segments, has_opening_scope_resolution,
+ collect_errors_inner, ns))
return ret;
+ if (!collect_errors_inner.empty ())
+ {
+ if (collect_errors.has_value ())
+ {
+ std::move (collect_errors_inner.begin (),
+ collect_errors_inner.end (),
+ std::back_inserter (collect_errors.value ()));
+ }
+ else
+ {
+ for (auto &e : collect_errors_inner)
+ e.emit ();
+ }
+ return tl::nullopt;
+ }
}
return tl::nullopt;
}
template <typename... Args>
- tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path,
- Args... ns_args)
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::SimplePath &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
{
return resolve_path (path.get_segments (),
- path.has_opening_scope_resolution (), ns_args...);
+ path.has_opening_scope_resolution (), collect_errors,
+ ns_first, ns_args...);
}
template <typename... Args>
- tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path,
- Args... ns_args)
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::PathInExpression &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
{
return resolve_path (path.get_segments (), path.opening_scope_resolution (),
- ns_args...);
+ collect_errors, ns_first, ns_args...);
}
template <typename... Args>
- tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path,
- Args... ns_args)
+ tl::optional<Rib::Definition>
+ resolve_path (const AST::TypePath &path,
+ tl::optional<std::vector<Error> &> collect_errors,
+ Namespace ns_first, Args... ns_args)
{
return resolve_path (path.get_segments (),
- path.has_opening_scope_resolution_op (), ns_args...);
+ path.has_opening_scope_resolution_op (),
+ collect_errors, ns_first, ns_args...);
+ }
+
+ template <typename P, typename... Args>
+ tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first,
+ Args... ns_args)
+ {
+ return resolve_path (path, tl::nullopt, ns_first, ns_args...);
+ }
+
+ template <typename P, typename... Args>
+ tl::optional<Rib::Definition>
+ resolve_path (const P &path_segments, bool has_opening_scope_resolution,
+ Namespace ns_first, Args... ns_args)
+ {
+ return resolve_path (path_segments, has_opening_scope_resolution,
+ tl::nullopt, ns_first, ns_args...);
}
private:
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 ba37dee..2f036fe 100644
--- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
+++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc
@@ -135,8 +135,7 @@ TopLevel::visit (AST::Module &module)
void
TopLevel::visit (AST::Trait &trait)
{
- insert_or_error_out (trait.get_identifier ().as_string (), trait,
- Namespace::Types);
+ insert_or_error_out (trait.get_identifier (), trait, Namespace::Types);
DefaultResolver::visit (trait);
}
@@ -548,6 +547,8 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths,
{
if (glob.has_path ())
paths.emplace_back (glob.get_path ());
+ else
+ paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ()));
}
void
diff --git a/gcc/rust/rust-gcc.cc b/gcc/rust/rust-gcc.cc
index 234721c..e5319d3 100644
--- a/gcc/rust/rust-gcc.cc
+++ b/gcc/rust/rust-gcc.cc
@@ -1109,6 +1109,7 @@ arithmetic_or_logical_expression (ArithmeticOrLogicalOperator op, tree left,
rust_error_at (location, "division by zero");
}
else if (op == ArithmeticOrLogicalOperator::LEFT_SHIFT
+ && TREE_CODE (right) == INTEGER_CST
&& (compare_tree_int (right, TYPE_PRECISION (TREE_TYPE (ret))) >= 0))
{
rust_error_at (location, "left shift count >= width of type");
diff --git a/gcc/rust/typecheck/rust-hir-trait-resolve.cc b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
index e78c192..032bb58 100644
--- a/gcc/rust/typecheck/rust-hir-trait-resolve.cc
+++ b/gcc/rust/typecheck/rust-hir-trait-resolve.cc
@@ -384,7 +384,26 @@ TraitItemReference::resolve_item (HIR::TraitItemType &type)
void
TraitItemReference::resolve_item (HIR::TraitItemConst &constant)
{
- // TODO
+ TyTy::BaseType *ty = nullptr;
+ if (constant.has_type ())
+ ty = TypeCheckType::Resolve (constant.get_type ());
+
+ TyTy::BaseType *expr = nullptr;
+ if (constant.has_expr ())
+ expr = TypeCheckExpr::Resolve (constant.get_expr ());
+
+ bool have_specified_ty = ty != nullptr && !ty->is<TyTy::ErrorType> ();
+ bool have_expr_ty = expr != nullptr && !expr->is<TyTy::ErrorType> ();
+
+ if (have_specified_ty && have_expr_ty)
+ {
+ coercion_site (constant.get_mappings ().get_hirid (),
+ TyTy::TyWithLocation (ty,
+ constant.get_type ().get_locus ()),
+ TyTy::TyWithLocation (expr,
+ constant.get_expr ().get_locus ()),
+ constant.get_locus ());
+ }
}
void
diff --git a/gcc/rust/typecheck/rust-hir-type-check-base.cc b/gcc/rust/typecheck/rust-hir-type-check-base.cc
index beee91e..14b8ab8 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-base.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-base.cc
@@ -308,7 +308,8 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
repr.pack = 0;
repr.align = 0;
- // FIXME handle repr types....
+ // Default repr for enums is isize, but we now check for other repr in the
+ // attributes.
bool ok = context->lookup_builtin ("isize", &repr.repr);
rust_assert (ok);
@@ -353,13 +354,29 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
// manually parsing the string "packed(2)" here.
size_t oparen = inline_option.find ('(', 0);
- bool is_pack = false, is_align = false;
+ bool is_pack = false;
+ bool is_align = false;
+ bool is_c = false;
+ bool is_integer = false;
unsigned char value = 1;
if (oparen == std::string::npos)
{
is_pack = inline_option.compare ("packed") == 0;
is_align = inline_option.compare ("align") == 0;
+ is_c = inline_option.compare ("C") == 0;
+ is_integer = (inline_option.compare ("isize") == 0
+ || inline_option.compare ("i8") == 0
+ || inline_option.compare ("i16") == 0
+ || inline_option.compare ("i32") == 0
+ || inline_option.compare ("i64") == 0
+ || inline_option.compare ("i128") == 0
+ || inline_option.compare ("usize") == 0
+ || inline_option.compare ("u8") == 0
+ || inline_option.compare ("u16") == 0
+ || inline_option.compare ("u32") == 0
+ || inline_option.compare ("u64") == 0
+ || inline_option.compare ("u128") == 0);
}
else
@@ -379,9 +396,28 @@ TypeCheckBase::parse_repr_options (const AST::AttrVec &attrs, location_t locus)
}
if (is_pack)
- repr.pack = value;
+ {
+ repr.repr_kind = TyTy::ADTType::ReprKind::PACKED;
+ repr.pack = value;
+ }
else if (is_align)
- repr.align = value;
+ {
+ repr.repr_kind = TyTy::ADTType::ReprKind::ALIGN;
+ repr.align = value;
+ }
+ else if (is_c)
+ {
+ repr.repr_kind = TyTy::ADTType::ReprKind::C;
+ }
+ else if (is_integer)
+ {
+ repr.repr_kind = TyTy::ADTType::ReprKind::INT;
+ bool ok = context->lookup_builtin (inline_option, &repr.repr);
+ if (!ok)
+ {
+ rust_error_at (attr.get_locus (), "Invalid repr type");
+ }
+ }
delete meta_items;
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.cc b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
index b2bcac0..cbf529a7 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.cc
@@ -844,6 +844,19 @@ TypeCheckExpr::visit (HIR::InlineAsm &expr)
}
void
+TypeCheckExpr::visit (HIR::LlvmInlineAsm &expr)
+{
+ for (auto &i : expr.inputs)
+ TypeCheckExpr::Resolve (*i.expr);
+
+ for (auto &o : expr.outputs)
+ TypeCheckExpr::Resolve (*o.expr);
+
+ // Black box hint is unit type
+ infered = TyTy::TupleType::get_unit_type ();
+}
+
+void
TypeCheckExpr::visit (HIR::RangeFullExpr &expr)
{
auto lang_item_type = LangItem::Kind::RANGE_FULL;
@@ -1129,27 +1142,25 @@ TypeCheckExpr::visit (HIR::FieldAccessExpr &expr)
bool is_valid_type = struct_base->get_kind () == TyTy::TypeKind::ADT;
if (!is_valid_type)
{
- rust_error_at (expr.get_locus (),
- "expected algebraic data type got: [%s]",
- struct_base->as_string ().c_str ());
+ rust_error_at (expr.get_locus (), "expected algebraic data type got %qs",
+ struct_base->get_name ().c_str ());
return;
}
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (struct_base);
- rust_assert (!adt->is_enum ());
- rust_assert (adt->number_of_variants () == 1);
-
+ rust_assert (adt->number_of_variants () > 0);
TyTy::VariantDef *vaiant = adt->get_variants ().at (0);
TyTy::StructFieldType *lookup = nullptr;
bool found = vaiant->lookup_field (expr.get_field_name ().as_string (),
&lookup, nullptr);
- if (!found)
+ if (!found || adt->is_enum ())
{
- rust_error_at (expr.get_locus (), ErrorCode::E0609,
- "no field %qs on type %qs",
+ rich_location r (line_table, expr.get_locus ());
+ r.add_range (expr.get_field_name ().get_locus ());
+ rust_error_at (r, ErrorCode::E0609, "no field %qs on type %qs",
expr.get_field_name ().as_string ().c_str (),
- adt->as_string ().c_str ());
+ adt->get_name ().c_str ());
return;
}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 2a0022c..79121b3 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -70,6 +70,7 @@ public:
void visit (HIR::WhileLoopExpr &expr) override;
void visit (HIR::ClosureExpr &expr) override;
void visit (HIR::InlineAsm &expr) override;
+ void visit (HIR::LlvmInlineAsm &expr) override;
// TODO
void visit (HIR::ErrorPropagationExpr &) override {}
diff --git a/gcc/rust/typecheck/rust-hir-type-check-item.cc b/gcc/rust/typecheck/rust-hir-type-check-item.cc
index 9774921..aaa04af 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-item.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-item.cc
@@ -355,6 +355,18 @@ TypeCheckItem::visit (HIR::Enum &enum_decl)
variants.push_back (field_type);
}
+ // Check for zero-variant enum compatibility
+ if (enum_decl.is_zero_variant ())
+ {
+ if (repr.repr_kind == TyTy::ADTType::ReprKind::INT
+ || repr.repr_kind == TyTy::ADTType::ReprKind::C)
+ {
+ rust_error_at (enum_decl.get_locus (),
+ "unsupported representation for zero-variant enum");
+ return;
+ }
+ }
+
// get the path
tl::optional<CanonicalPath> canonical_path;
@@ -637,6 +649,38 @@ TypeCheckItem::visit (HIR::Function &function)
context->switch_to_fn_body ();
auto block_expr_ty = TypeCheckExpr::Resolve (function.get_definition ());
+ // emit check for
+ // error[E0121]: the type placeholder `_` is not allowed within types on item
+ const auto placeholder = ret_type->contains_infer ();
+ if (placeholder != nullptr && function.has_return_type ())
+ {
+ // FIXME
+ // this will be a great place for the Default Hir Visitor we want to
+ // grab the locations of the placeholders (HIR::InferredType) their
+ // location, for now maybe we can use their hirid to lookup the location
+ location_t placeholder_locus
+ = mappings.lookup_location (placeholder->get_ref ());
+ location_t type_locus = function.get_return_type ().get_locus ();
+ rich_location r (line_table, placeholder_locus);
+
+ bool have_expected_type
+ = block_expr_ty != nullptr && !block_expr_ty->is<TyTy::ErrorType> ();
+ if (!have_expected_type)
+ {
+ r.add_range (type_locus);
+ }
+ else
+ {
+ std::string fixit
+ = "replace with the correct type " + block_expr_ty->get_name ();
+ r.add_fixit_replace (type_locus, fixit.c_str ());
+ }
+
+ rust_error_at (r, ErrorCode::E0121,
+ "the type placeholder %<_%> is not allowed within types "
+ "on item signatures");
+ }
+
location_t fn_return_locus = function.has_function_return_type ()
? function.get_return_type ().get_locus ()
: function.get_locus ();
diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
index 800f7ca..7e3a57a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-struct-field.h
@@ -60,6 +60,9 @@ private:
TyTy::BaseType *resolved_field_value_expr;
std::set<std::string> fields_assigned;
std::map<size_t, HIR::StructExprField *> adtFieldIndexToField;
+
+ // parent
+ HIR::Expr &parent;
};
} // namespace Resolver
diff --git a/gcc/rust/typecheck/rust-hir-type-check-struct.cc b/gcc/rust/typecheck/rust-hir-type-check-struct.cc
index 40c42b2..df1636a 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-struct.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-struct.cc
@@ -28,7 +28,7 @@ TypeCheckStructExpr::TypeCheckStructExpr (HIR::Expr &e)
: TypeCheckBase (),
resolved (new TyTy::ErrorType (e.get_mappings ().get_hirid ())),
struct_path_resolved (nullptr),
- variant (&TyTy::VariantDef::get_error_node ())
+ variant (&TyTy::VariantDef::get_error_node ()), parent (e)
{}
TyTy::BaseType *
@@ -65,7 +65,7 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
if (base_unify->get_kind () != struct_path_ty->get_kind ())
{
- rust_fatal_error (
+ rust_error_at (
struct_expr.get_struct_base ().get_base ().get_locus (),
"incompatible types for base struct reference");
return;
@@ -82,7 +82,16 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
bool ok = context->lookup_variant_definition (
struct_expr.get_struct_name ().get_mappings ().get_hirid (),
&variant_id);
- rust_assert (ok);
+ if (!ok)
+ {
+ rich_location r (line_table, struct_expr.get_locus ());
+ r.add_range (struct_expr.get_struct_name ().get_locus ());
+ rust_error_at (
+ struct_expr.get_struct_name ().get_locus (), ErrorCode::E0574,
+ "expected a struct, variant or union type, found enum %qs",
+ struct_path_resolved->get_name ().c_str ());
+ return;
+ }
ok = struct_path_resolved->lookup_variant_by_id (variant_id, &variant);
rust_assert (ok);
@@ -118,29 +127,14 @@ TypeCheckStructExpr::resolve (HIR::StructExprStructFields &struct_expr)
break;
}
- if (!ok)
- {
- return;
- }
-
- if (resolved_field_value_expr == nullptr)
- {
- rust_fatal_error (field->get_locus (),
- "failed to resolve type for field");
- ok = false;
- break;
- }
-
- context->insert_type (field->get_mappings (), resolved_field_value_expr);
+ if (ok)
+ context->insert_type (field->get_mappings (),
+ resolved_field_value_expr);
}
- // something failed setting up the fields
+ // something failed setting up the fields and error's emitted
if (!ok)
- {
- rust_error_at (struct_expr.get_locus (),
- "constructor type resolution failure");
- return;
- }
+ return;
// check the arguments are all assigned and fix up the ordering
std::vector<std::string> missing_field_names;
@@ -271,8 +265,11 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIdentifierValue &field)
&field_index);
if (!ok)
{
- rust_error_at (field.get_locus (), "unknown field");
- return true;
+ rich_location r (line_table, parent.get_locus ());
+ r.add_range (field.get_locus ());
+ rust_error_at (r, ErrorCode::E0560, "unknown field %qs",
+ field.field_name.as_string ().c_str ());
+ return false;
}
auto it = adtFieldIndexToField.find (field_index);
@@ -317,8 +314,11 @@ TypeCheckStructExpr::visit (HIR::StructExprFieldIndexValue &field)
bool ok = variant->lookup_field (field_name, &field_type, &field_index);
if (!ok)
{
- rust_error_at (field.get_locus (), "unknown field");
- return true;
+ rich_location r (line_table, parent.get_locus ());
+ r.add_range (field.get_locus ());
+ rust_error_at (r, ErrorCode::E0560, "unknown field %qs",
+ field_name.c_str ());
+ return false;
}
auto it = adtFieldIndexToField.find (field_index);
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index efad5f6..f0f4a07 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -682,6 +682,91 @@ BaseType::debug () const
debug_str ().c_str ());
}
+const TyTy::BaseType *
+BaseType::contains_infer () const
+{
+ const TyTy::BaseType *x = destructure ();
+
+ if (auto fn = x->try_as<const FnType> ())
+ {
+ for (const auto &param : fn->get_params ())
+ {
+ auto infer = param.get_type ()->contains_infer ();
+ if (infer)
+ return infer;
+ }
+ return fn->get_return_type ()->contains_infer ();
+ }
+ else if (auto fn = x->try_as<const FnPtr> ())
+ {
+ for (const auto &param : fn->get_params ())
+ {
+ auto infer = param.get_tyty ()->contains_infer ();
+ if (infer)
+ return infer;
+ }
+ return fn->get_return_type ()->contains_infer ();
+ }
+ else if (auto adt = x->try_as<const ADTType> ())
+ {
+ for (auto &variant : adt->get_variants ())
+ {
+ bool is_num_variant
+ = variant->get_variant_type () == VariantDef::VariantType::NUM;
+ if (is_num_variant)
+ continue;
+
+ for (auto &field : variant->get_fields ())
+ {
+ const BaseType *field_type = field->get_field_type ();
+ auto infer = (field_type->contains_infer ());
+ if (infer)
+ return infer;
+ }
+ }
+ return nullptr;
+ }
+ else if (auto arr = x->try_as<const ArrayType> ())
+ {
+ return arr->get_element_type ()->contains_infer ();
+ }
+ else if (auto slice = x->try_as<const SliceType> ())
+ {
+ return slice->get_element_type ()->contains_infer ();
+ }
+ else if (auto ptr = x->try_as<const PointerType> ())
+ {
+ return ptr->get_base ()->contains_infer ();
+ }
+ else if (auto ref = x->try_as<const ReferenceType> ())
+ {
+ return ref->get_base ()->contains_infer ();
+ }
+ else if (auto tuple = x->try_as<const TupleType> ())
+ {
+ for (size_t i = 0; i < tuple->num_fields (); i++)
+ {
+ auto infer = (tuple->get_field (i)->contains_infer ());
+ if (infer)
+ return infer;
+ }
+ return nullptr;
+ }
+ else if (auto closure = x->try_as<const ClosureType> ())
+ {
+ auto infer = (closure->get_parameters ().contains_infer ());
+ if (infer)
+ return infer;
+ return closure->get_result_type ().contains_infer ();
+ }
+ else if (x->is<InferType> ())
+ {
+ return x;
+ }
+
+ return nullptr;
+}
+
bool
BaseType::is_concrete () const
{
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index e814f07..1cada9a 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -137,6 +137,9 @@ public:
void inherit_bounds (
const std::vector<TyTy::TypeBoundPredicate> &specified_bounds);
+ // contains_infer checks if there is an inference variable inside the type
+ const TyTy::BaseType *contains_infer () const;
+
// is_unit returns whether this is just a unit-struct
bool is_unit () const;
@@ -711,12 +714,22 @@ public:
ENUM
};
+ enum ReprKind
+ {
+ RUST,
+ C,
+ INT,
+ ALIGN,
+ PACKED,
+ // TRANSPARENT,
+ // SIMD,
+ // ...
+ };
+
// Representation options, specified via attributes e.g. #[repr(packed)]
struct ReprOptions
{
- // bool is_c;
- // bool is_transparent;
- //...
+ ReprKind repr_kind = ReprKind::RUST;
// For align and pack: 0 = unspecified. Nonzero = byte alignment.
// It is an error for both to be nonzero, this should be caught when
diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h
index fe0bc8a..b263d75 100644
--- a/gcc/rust/util/rust-stacked-contexts.h
+++ b/gcc/rust/util/rust-stacked-contexts.h
@@ -71,7 +71,14 @@ public:
return last;
}
- const T &peek ()
+ const T &peek () const
+ {
+ rust_assert (!stack.empty ());
+
+ return stack.back ();
+ }
+
+ T &peek ()
{
rust_assert (!stack.empty ());
diff --git a/gcc/simplify-rtx.cc b/gcc/simplify-rtx.cc
index 06b52ca..d9aa049 100644
--- a/gcc/simplify-rtx.cc
+++ b/gcc/simplify-rtx.cc
@@ -7713,6 +7713,28 @@ native_decode_vector_rtx (machine_mode mode, const vec<target_unit> &bytes,
return builder.build ();
}
+/* Extract a PRECISION-bit integer from bytes [FIRST_BYTE, FIRST_BYTE + SIZE)
+ of target memory image BYTES. */
+
+wide_int
+native_decode_int (const vec<target_unit> &bytes, unsigned int first_byte,
+ unsigned int size, unsigned int precision)
+{
+ /* Pull the bytes msb first, so that we can use simple
+ shift-and-insert wide_int operations. */
+ wide_int result (wi::zero (precision));
+ for (unsigned int i = 0; i < size; ++i)
+ {
+ unsigned int lsb = (size - i - 1) * BITS_PER_UNIT;
+ /* Always constant because the inputs are. */
+ unsigned int subbyte
+ = subreg_size_offset_from_lsb (1, size, lsb).to_constant ();
+ result <<= BITS_PER_UNIT;
+ result |= bytes[first_byte + subbyte];
+ }
+ return result;
+}
+
/* Read an rtx of mode MODE from the target memory image given by BYTES,
starting at byte FIRST_BYTE. Each element of BYTES contains BITS_PER_UNIT
bits and the bytes are in target memory order. The image has enough
@@ -7738,19 +7760,9 @@ native_decode_rtx (machine_mode mode, const vec<target_unit> &bytes,
if (is_a <scalar_int_mode> (mode, &imode)
&& GET_MODE_PRECISION (imode) <= MAX_BITSIZE_MODE_ANY_INT)
{
- /* Pull the bytes msb first, so that we can use simple
- shift-and-insert wide_int operations. */
- unsigned int size = GET_MODE_SIZE (imode);
- wide_int result (wi::zero (GET_MODE_PRECISION (imode)));
- for (unsigned int i = 0; i < size; ++i)
- {
- unsigned int lsb = (size - i - 1) * BITS_PER_UNIT;
- /* Always constant because the inputs are. */
- unsigned int subbyte
- = subreg_size_offset_from_lsb (1, size, lsb).to_constant ();
- result <<= BITS_PER_UNIT;
- result |= bytes[first_byte + subbyte];
- }
+ auto result = native_decode_int (bytes, first_byte,
+ GET_MODE_SIZE (imode),
+ GET_MODE_PRECISION (imode));
return immed_wide_int_const (result, imode);
}
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 314de8d..053765b 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,315 @@
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/111536
+ * c-c++-common/analyzer/hard-reg-1.c: New test.
+ * g++.dg/analyzer/nrvo-1.C: New test.
+ * g++.dg/analyzer/nrvo-2.C: New test.
+ * g++.dg/analyzer/nrvo-pr111536-1.C: New test.
+ * g++.dg/analyzer/nrvo-pr111536-1b.C: New test.
+ * g++.dg/analyzer/nrvo-pr111536-2.C: New test.
+ * g++.dg/analyzer/nrvo-pr111536-2b.C: New test.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/109366
+ * g++.dg/analyzer/unique_ptr-1.C: New test.
+ * g++.dg/analyzer/unique_ptr-2.C: New test.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/97111
+ * c-c++-common/analyzer/analyzer-verbosity-2a.c: Add
+ -fno-exceptions.
+ * c-c++-common/analyzer/analyzer-verbosity-3a.c: Likewise.
+ * c-c++-common/analyzer/attr-const-2.c: Add
+ __attribute__((nothrow)).
+ * c-c++-common/analyzer/attr-malloc-4.c: Likewise.
+ * c-c++-common/analyzer/attr-malloc-5.c: Likewise.
+ * c-c++-common/analyzer/attr-malloc-6.c: Add -fno-exceptions.
+ * c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c:
+ Likewise.
+ * c-c++-common/analyzer/attr-malloc-exception.c: New test.
+ * c-c++-common/analyzer/call-summaries-pr107158-2.c: Add
+ -fno-exceptions.
+ * c-c++-common/analyzer/call-summaries-pr107158.c: Likewise.
+ * c-c++-common/analyzer/capacity-2.c: Likewise.
+ * c-c++-common/analyzer/coreutils-sum-pr108666.c: Likewise.
+ * c-c++-common/analyzer/data-model-22.c: Likewise.
+ * c-c++-common/analyzer/data-model-5d.c: Likewise.
+ * c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c:
+ Likewise.
+ * c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c:
+ Likewise.
+ * c-c++-common/analyzer/edges-2.c: Likewise.
+ * c-c++-common/analyzer/fd-2.c: Likewise.
+ * c-c++-common/analyzer/fd-3.c: Likewise.
+ * c-c++-common/analyzer/fd-meaning.c: Likewise.
+ * c-c++-common/analyzer/file-1.c: Likewise.
+ * c-c++-common/analyzer/file-3.c: Likewise.
+ * c-c++-common/analyzer/file-meaning-1.c: Likewise.
+ * c-c++-common/analyzer/infinite-recursion.c: Likewise.
+ * c-c++-common/analyzer/leak-3.c: Likewise.
+ * c-c++-common/analyzer/malloc-dedupe-1.c: Likewise.
+ * c-c++-common/analyzer/malloc-in-loop.c: Likewise.
+ * c-c++-common/analyzer/malloc-many-paths-3.c: Likewise.
+ * c-c++-common/analyzer/malloc-paths-5.c: Likewise.
+ * c-c++-common/analyzer/malloc-paths-7.c: Likewise.
+ * c-c++-common/analyzer/malloc-paths-8.c: Likewise.
+ * c-c++-common/analyzer/malloc-vs-local-1a.c: Likewise.
+ * c-c++-common/analyzer/malloc-vs-local-2.c: Likewise.
+ * c-c++-common/analyzer/malloc-vs-local-3.c: Likewise.
+ * c-c++-common/analyzer/paths-7.c: Likewise.
+ * c-c++-common/analyzer/pr110830.c: Likewise.
+ * c-c++-common/analyzer/pr93032-mztools-simplified.c: Likewise.
+ * c-c++-common/analyzer/pr93355-localealias-feasibility-3.c:
+ Likewise.
+ * c-c++-common/analyzer/pr93355-localealias-simplified.c:
+ Likewise.
+ * c-c++-common/analyzer/pr96650-1-trans.c: Likewise.
+ * c-c++-common/analyzer/pr97072.c: Add __attribute__((nothrow)).
+ * c-c++-common/analyzer/pr98575-1.c: Likewise.
+ * c-c++-common/analyzer/pr99716-1.c: Add -fno-exceptions.
+ * c-c++-common/analyzer/pr99716-2.c: Likewise.
+ * c-c++-common/analyzer/pr99716-3.c: Likewise.
+ * c-c++-common/analyzer/pragma-2.c: Likewise.
+ * c-c++-common/analyzer/rhbz1878600.c: Likewise.
+ * c-c++-common/analyzer/strndup-1.c: Likewise.
+ * c-c++-common/analyzer/write-to-string-literal-4-disabled.c:
+ Likewise.
+ * c-c++-common/analyzer/write-to-string-literal-4.c: Likewise.
+ * c-c++-common/analyzer/write-to-string-literal-5.c: Likewise.
+ * c-c++-common/analyzer/zlib-5.c: Likewise.
+ * g++.dg/analyzer/exception-could-throw-1.C: New test.
+ * g++.dg/analyzer/exception-could-throw-2.C: New test.
+ * g++.dg/analyzer/exception-dynamic-spec.C: New test.
+ * g++.dg/analyzer/exception-leak-1.C: New test.
+ * g++.dg/analyzer/exception-leak-2.C: New test.
+ * g++.dg/analyzer/exception-leak-3.C: New test.
+ * g++.dg/analyzer/exception-leak-4.C: New test.
+ * g++.dg/analyzer/exception-leak-5.C: New test.
+ * g++.dg/analyzer/exception-leak-6.C: New test.
+ * g++.dg/analyzer/exception-nothrow.C: New test.
+ * g++.dg/analyzer/exception-path-1.C: New test.
+ * g++.dg/analyzer/exception-path-catch-all-1.C: New test.
+ * g++.dg/analyzer/exception-path-catch-all-2.C: New test.
+ * g++.dg/analyzer/exception-path-unwind-multiple-2.C: New test.
+ * g++.dg/analyzer/exception-path-unwind-multiple.C: New test.
+ * g++.dg/analyzer/exception-path-unwind-single.C: New test.
+ * g++.dg/analyzer/exception-path-with-cleanups.C: New test.
+ * g++.dg/analyzer/exception-rethrow-1.C: New test.
+ * g++.dg/analyzer/exception-rethrow-2.C: New test.
+ * g++.dg/analyzer/exception-stack-1.C: New test.
+ * g++.dg/analyzer/exception-stack-2.C: New test.
+ * g++.dg/analyzer/exception-subclass-1.C: New test.
+ * g++.dg/analyzer/exception-subclass-2.C: New test.
+ * g++.dg/analyzer/exception-value-1.C: New test.
+ * g++.dg/analyzer/exception-value-2.C: New test.
+ * g++.dg/analyzer/fno-exception.C: New test.
+ * g++.dg/analyzer/pr94028.C: Drop xfail.
+ * g++.dg/analyzer/std-unexpected.C: New test.
+ * g++.dg/coroutines/pr105287.C: Drop dg-excess-errors.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/analyzer_cpython_plugin.cc: Drop include of
+ "make-unique.h". Replace uses of ::make_unique with
+ std::make_unique.
+ * gcc.dg/plugin/analyzer_gil_plugin.cc: Likewise.
+ * gcc.dg/plugin/analyzer_kernel_plugin.cc: Likewise.
+ * gcc.dg/plugin/analyzer_known_fns_plugin.cc: Likewise.
+ * gcc.dg/plugin/diagnostic_group_plugin.cc: Likewise.
+ * gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc: Likewise.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/analyzer_gil_plugin.cc: Convert gcall * to gcall &
+ where we know the pointer must be non-null.
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/analyzer_cpython_plugin.cc: Convert
+ enum poison_kind to "enum class".
+
+2025-04-28 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/plugin/analyzer_cpython_plugin.cc: Update for renaming
+ of analyzer/analyzer.h to analyzer/common.h.
+ * gcc.dg/plugin/analyzer_gil_plugin.cc: Likewise.
+ * gcc.dg/plugin/analyzer_kernel_plugin.cc: Likewise.
+ * gcc.dg/plugin/analyzer_known_fns_plugin.cc: Likewise.
+
+2025-04-28 Andrew MacLeod <amacleod@redhat.com>
+
+ PR tree-optimization/95801
+ * gcc.dg/tree-ssa/pr95801.c: New.
+
+2025-04-28 Andrew MacLeod <amacleod@redhat.com>
+
+ PR tree-optimization/119712
+ * gcc.dg/pr119712.c: New.
+ * gcc.dg/pr83072-2.c: Adjust.
+ * gcc.dg/tree-ssa/phi-opt-value-5.c: Adjust.
+ * gcc.dg/tree-ssa/vrp122.c: Adjust
+
+2025-04-28 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR tree-optimization/67797
+ * gcc.dg/tree-ssa/tailcall-14.c: New test.
+ * gcc.dg/tree-ssa/tailcall-15.c: New test.
+
+2025-04-28 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR c/119432
+ * gcc.dg/gimplefe-57.c: New test.
+
+2025-04-28 Andrew Pinski <quic_apinski@quicinc.com>
+
+ PR tree-optimization/100038
+ * g++.dg/tree-ssa/pr100038.C: New test.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * rust/compile/nr2/exclude: Remove now passing test from exclusion
+ list.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * rust/compile/nr2/exclude: Remove passing test from exclusion list.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * rust/compile/multiple_bindings1.rs: Add missing lang items.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * rust/compile/nr2/exclude: Remove test from exclusion list.
+ * rust/compile/use_1.rs: Change expected output and remove test from
+ nr1.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * rust/compile/generics9.rs: Change expected error message.
+ * rust/compile/nr2/exclude: Remove test from exclusion list.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * rust/compile/nr2/exclude: Remove passing test from exclusion list.
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * rust/compile/nr2/exclude: Remove entry.
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * rust/compile/derive-debug1.rs: Adjust a path.
+ * rust/compile/nr2/exclude: Remove derive-debug1.rs.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/nr2/exclude: nr2 is missing error for this
+ * rust/compile/issue-3649.rs: New test.
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * rust/compile/issue-3568.rs: Adjust expected errors.
+ * rust/compile/name_resolution9.rs: Likewise.
+ * rust/compile/self-path2.rs: Likewise.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/nonexistent-field.rs: fix bad error message
+ * rust/compile/issue-3581-1.rs: New test.
+ * rust/compile/issue-3581-2.rs: New test.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/nr2/exclude: nr2 does not error on the T it should require Self::T
+ * rust/compile/issue-3652.rs: New test.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/macros/mbe/macro-issue2983_2984.rs: cleanup error diagnotics
+ * rust/compile/struct_init1.rs: likewise
+ * rust/compile/issue-3628.rs: New test.
+
+2025-04-28 Owen Avery <powerboat9.gamer@gmail.com>
+
+ * rust/compile/nr2/exclude: Remove entry.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/issue-3662.rs: New test.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/issue-3711.rs: New test.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * rust/compile/black_box.rs: New test.
+
+2025-04-28 Pierre-Emmanuel Patry <pierre-emmanuel.patry@embecosm.com>
+
+ * rust/execute/black_box.rs: New test.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/issue-402.rs: New test.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/issue-3664.rs: New test.
+
+2025-04-28 Zhi Heng <yapzhhg@gmail.com>
+
+ * rust/compile/issue-3530-1.rs: New file.
+ * rust/compile/issue-3530-2.rs: New file.
+
+2025-04-28 Philip Herron <herron.philip@googlemail.com>
+
+ * rust/compile/issue-3612.rs: New test.
+
+2025-04-28 H.J. Lu <hjl.tools@gmail.com>
+ Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/109780
+ PR target/109093
+ * g++.target/i386/pr109780-1.C: New test.
+ * gcc.target/i386/pr109093-1.c: Likewise.
+ * gcc.target/i386/pr109780-1.c: Likewise.
+ * gcc.target/i386/pr109780-2.c: Likewise.
+ * gcc.target/i386/pr109780-3.c: Likewise.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR ipa/119973
+ * gcc.dg/torture/pr119973.c: New testcase.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/119103
+ * gcc.target/i386/pr119103.c: New testcase.
+
+2025-04-28 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/60779
+ * gcc.dg/lto/pr60779_0.c: New testcase.
+ * gcc.dg/lto/pr60779_1.c: Likewise.
+
+2025-04-28 Lewis Hyatt <lhyatt@gmail.com>
+
+ PR c/118838
+ * c-c++-common/cpp/pragma-diagnostic-loc-2.c: New test.
+ * g++.dg/gomp/macro-4.C: Adjust expected output.
+ * gcc.dg/gomp/macro-4.c: Likewise.
+ * gcc.dg/cpp/Wunknown-pragmas-1.c: Likewise.
+
+2025-04-28 Jonathan Yong <10walls@gmail.com>
+
+ * gcc.dg/graphite/id-15.c: Use __SIZE_TYPE__ instead of
+ unsigned long.
+ * gcc.dg/plugin/infoleak-net-ethtool-ioctl.c: ditto.
+
2025-04-27 Nathaniel Shead <nathanieloshead@gmail.com>
PR c++/119939
diff --git a/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c b/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c
index cf014b0..175d9c3 100644
--- a/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c
+++ b/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-2a.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fanalyzer-verbosity=2" } */
+/* { dg-additional-options "-fanalyzer-verbosity=2 -fno-exceptions" } */
typedef struct FILE FILE;
diff --git a/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c b/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c
index b0ece20..8d66c8f 100644
--- a/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c
+++ b/gcc/testsuite/c-c++-common/analyzer/analyzer-verbosity-3a.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fanalyzer-verbosity=3" } */
+/* { dg-additional-options "-fanalyzer-verbosity=3 -fno-exceptions" } */
typedef struct FILE FILE;
diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-const-2.c b/gcc/testsuite/c-c++-common/analyzer/attr-const-2.c
index ab79514..5329a89 100644
--- a/gcc/testsuite/c-c++-common/analyzer/attr-const-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/attr-const-2.c
@@ -1,5 +1,5 @@
extern int const_p (int) __attribute__((const));
-extern void do_stuff (void);
+extern void do_stuff (void) __attribute__((nothrow));
void test (int a)
{
diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c
index 1517667..1e2e1f9 100644
--- a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c
+++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-4.c
@@ -2,7 +2,7 @@
struct foo;
extern void foo_release (struct foo *)
- __attribute__((nonnull));
+ __attribute__((nonnull, nothrow));
extern struct foo *foo_acquire (void)
__attribute__ ((malloc (foo_release)));
diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c
index 7ff4e57..8b7ffc1 100644
--- a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c
+++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-5.c
@@ -1,7 +1,7 @@
/* Example of extra argument to "malloc" attribute. */
struct foo;
-extern void foo_release (int, struct foo *);
+extern void foo_release (int, struct foo *) __attribute__((nothrow));
extern struct foo *foo_acquire (void)
__attribute__ ((malloc (foo_release, 2)));
diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c
index 1665d41..45ee406f 100644
--- a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c
+++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-6.c
@@ -1,4 +1,5 @@
/* Adapted from gcc.dg/Wmismatched-dealloc.c. */
+/* { dg-additional-options "-fno-exceptions" } */
#define A(...) __attribute__ ((malloc (__VA_ARGS__)))
diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c
index 87ad42a..fd51630 100644
--- a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c
+++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-CVE-2019-19078-usb-leak.c
@@ -1,6 +1,8 @@
/* Adapted from linux 5.3.11: drivers/net/wireless/ath/ath10k/usb.c
Reduced reproducer for CVE-2019-19078 (leak of struct urb). */
+/* { dg-additional-options "-fno-exceptions" } */
+
typedef unsigned char u8;
typedef unsigned short u16;
diff --git a/gcc/testsuite/c-c++-common/analyzer/attr-malloc-exception.c b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-exception.c
new file mode 100644
index 0000000..9f5e2e8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/analyzer/attr-malloc-exception.c
@@ -0,0 +1,17 @@
+/* { dg-additional-options "-fexceptions" } */
+
+extern void free (void *);
+
+/* Not marked "nothrow", so assume it could throw. */
+char *xstrdup (const char *)
+ __attribute__((malloc (free), returns_nonnull));
+
+void test_1 (const char *s, const char *t)
+{
+ char *p = xstrdup (s); /* { dg-message "allocated here" } */
+ char *q = xstrdup (t); /* { dg-warning "leak of 'p'" } */
+ /* { dg-message "if .* throws an exception\.\.\." "" { target *-*-* } .-1 } */
+
+ free (q);
+ free (p);
+}
diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c
index b395623..a15ab65 100644
--- a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
+/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex -fno-exceptions" } */
/* { dg-skip-if "c++98 has no noreturn attribute" { c++98_only } } */
#ifdef __cplusplus
diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c
index de70583..6fbbce4 100644
--- a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c
+++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-symbol-too-complex" } */
+/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-symbol-too-complex -fno-exceptions" } */
typedef __SIZE_TYPE__ size_t;
enum { _ISspace = ((5) < 8 ? ((1 << (5)) << 8) : ((1 << (5)) >> 8)) };
diff --git a/gcc/testsuite/c-c++-common/analyzer/capacity-2.c b/gcc/testsuite/c-c++-common/analyzer/capacity-2.c
index 7d2de4e..3846239 100644
--- a/gcc/testsuite/c-c++-common/analyzer/capacity-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/capacity-2.c
@@ -1,5 +1,6 @@
/* { dg-skip-if "" { powerpc*-*-aix* } } */
/* { dg-skip-if "requires hosted libstdc++ for stdlib size_t" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
#include "analyzer-decls.h"
diff --git a/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c b/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c
index c41b61d..95091e7 100644
--- a/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c
+++ b/gcc/testsuite/c-c++-common/analyzer/coreutils-sum-pr108666.c
@@ -1,5 +1,7 @@
/* Reduced from coreutils's sum.c: bsd_sum_stream */
+/* { dg-additional-options "-fno-exceptions" } */
+
typedef __SIZE_TYPE__ size_t;
typedef unsigned char __uint8_t;
typedef unsigned long int __uintmax_t;
diff --git a/gcc/testsuite/c-c++-common/analyzer/data-model-22.c b/gcc/testsuite/c-c++-common/analyzer/data-model-22.c
index 8429b2f..65bf346 100644
--- a/gcc/testsuite/c-c++-common/analyzer/data-model-22.c
+++ b/gcc/testsuite/c-c++-common/analyzer/data-model-22.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
#include <string.h>
#include "analyzer-decls.h"
diff --git a/gcc/testsuite/c-c++-common/analyzer/data-model-5d.c b/gcc/testsuite/c-c++-common/analyzer/data-model-5d.c
index a86d506..bb45917 100644
--- a/gcc/testsuite/c-c++-common/analyzer/data-model-5d.c
+++ b/gcc/testsuite/c-c++-common/analyzer/data-model-5d.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
/* A toy re-implementation of CPython's object model. */
diff --git a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c
index 7431bd1..b790997 100644
--- a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c
+++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108455-git-pack-revindex.c
@@ -1,4 +1,5 @@
/* Reduced from git-2.39.0's pack-revindex.c */
+/* { dg-additional-options "-fno-exceptions" } */
typedef unsigned int __uint32_t;
typedef unsigned long int __uintmax_t;
diff --git a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c
index 7123cf5..a7f8049 100644
--- a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c
+++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr108475-haproxy-tcpcheck.c
@@ -1,6 +1,7 @@
/* Reduced from haproxy-2.7.1: src/tcpcheck.c. */
/* { dg-additional-options "-Wno-analyzer-too-complex" } */
+/* { dg-additional-options "-fno-exceptions" } */
typedef __SIZE_TYPE__ size_t;
diff --git a/gcc/testsuite/c-c++-common/analyzer/edges-2.c b/gcc/testsuite/c-c++-common/analyzer/edges-2.c
index 7e4543c..df4bfaa 100644
--- a/gcc/testsuite/c-c++-common/analyzer/edges-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/edges-2.c
@@ -1,5 +1,7 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
+
#include <stdlib.h>
int foo ();
diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-2.c b/gcc/testsuite/c-c++-common/analyzer/fd-2.c
index 10c9ecd..b6b0a57 100644
--- a/gcc/testsuite/c-c++-common/analyzer/fd-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/fd-2.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
int open(const char *, int mode);
void close(int fd);
#define O_RDONLY 0
@@ -61,4 +63,4 @@ test_5 (const char *path, mode_t mode)
int fd = creat (path, mode);
close(fd);
close(fd); /* { dg-warning "double 'close' of file descriptor 'fd' \\\[CWE-1341\\\]" "warning" } */
-} \ No newline at end of file
+}
diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-3.c b/gcc/testsuite/c-c++-common/analyzer/fd-3.c
index 8e71b14..4894b64 100644
--- a/gcc/testsuite/c-c++-common/analyzer/fd-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/fd-3.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
int open(const char *, int mode);
void close(int fd);
int write (int fd, void *buf, int nbytes);
diff --git a/gcc/testsuite/c-c++-common/analyzer/fd-meaning.c b/gcc/testsuite/c-c++-common/analyzer/fd-meaning.c
index 6a9ec92..bd0d458a 100644
--- a/gcc/testsuite/c-c++-common/analyzer/fd-meaning.c
+++ b/gcc/testsuite/c-c++-common/analyzer/fd-meaning.c
@@ -1,4 +1,5 @@
- /* { dg-additional-options "-fanalyzer-verbose-state-changes" } */
+/* { dg-additional-options "-fno-exceptions" } */
+/* { dg-additional-options "-fanalyzer-verbose-state-changes" } */
int open(const char *, int mode);
void close(int fd);
@@ -34,4 +35,4 @@ void test_3 (const char* path)
close(fd); /* { dg-message "meaning: \\{verb: 'release', noun: 'resource'\\}" } */
close(fd); /* { dg-warning "double 'close' of file descriptor 'fd' \\\[CWE-1341\\\]" } */
}
-} \ No newline at end of file
+}
diff --git a/gcc/testsuite/c-c++-common/analyzer/file-1.c b/gcc/testsuite/c-c++-common/analyzer/file-1.c
index 316cbb3..e87cf73 100644
--- a/gcc/testsuite/c-c++-common/analyzer/file-1.c
+++ b/gcc/testsuite/c-c++-common/analyzer/file-1.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
typedef struct FILE FILE;
FILE* fopen (const char*, const char*);
diff --git a/gcc/testsuite/c-c++-common/analyzer/file-3.c b/gcc/testsuite/c-c++-common/analyzer/file-3.c
index 8f93a98..ca992bf 100644
--- a/gcc/testsuite/c-c++-common/analyzer/file-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/file-3.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
typedef struct _IO_FILE FILE;
extern struct _IO_FILE *stderr;
diff --git a/gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c b/gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c
index 66b72a7..c9aee5e 100644
--- a/gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c
+++ b/gcc/testsuite/c-c++-common/analyzer/file-meaning-1.c
@@ -1,3 +1,4 @@
+/* { dg-additional-options "-fno-exceptions" } */
/* { dg-additional-options "-fanalyzer-verbose-state-changes" } */
typedef struct FILE FILE;
diff --git a/gcc/testsuite/c-c++-common/analyzer/hard-reg-1.c b/gcc/testsuite/c-c++-common/analyzer/hard-reg-1.c
new file mode 100644
index 0000000..d22a5b5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/analyzer/hard-reg-1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target x86_64-*-* } } */
+
+void *
+get_from_hard_reg (void)
+{
+ register void *sp asm ("sp");
+ return sp;
+}
diff --git a/gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c
index 6b7d25c..bbbb68e 100644
--- a/gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c
+++ b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
extern void marker_A(void);
extern void marker_B(void);
extern void marker_C(void);
diff --git a/gcc/testsuite/c-c++-common/analyzer/leak-3.c b/gcc/testsuite/c-c++-common/analyzer/leak-3.c
index a386d88..19d7501 100644
--- a/gcc/testsuite/c-c++-common/analyzer/leak-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/leak-3.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c b/gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c
index 8653c67..c296061 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-dedupe-1.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c b/gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c
index e7179f0..0d86801 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-in-loop.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
#include "../../gcc.dg/analyzer/analyzer-decls.h"
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c b/gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c
index 6ee30f3..5daa696 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-many-paths-3.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c
index f03f978..4a1870d 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-5.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdio.h>
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c
index 766bbe7..12b93b2 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-7.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c
index 77e3e02..8af84ed 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-paths-8.c
@@ -1,3 +1,4 @@
+/* { dg-additional-options "-fno-exceptions" } */
/* { dg-additional-options "-fanalyzer-transitivity" } */
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c
index 4e40833..ffb0ffe 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-1a.c
@@ -1,3 +1,4 @@
+/* { dg-additional-options "-fno-exceptions" } */
/* { dg-additional-options "-fno-analyzer-call-summaries -fanalyzer-transitivity" } */
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c
index 36ec510..052b401 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-2.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
#include "analyzer-decls.h"
diff --git a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c
index 70b3edd..258706c 100644
--- a/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/malloc-vs-local-3.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
#include "analyzer-decls.h"
diff --git a/gcc/testsuite/c-c++-common/analyzer/paths-7.c b/gcc/testsuite/c-c++-common/analyzer/paths-7.c
index 2743de5..f7c5cbf 100644
--- a/gcc/testsuite/c-c++-common/analyzer/paths-7.c
+++ b/gcc/testsuite/c-c++-common/analyzer/paths-7.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
#include "analyzer-decls.h"
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr110830.c b/gcc/testsuite/c-c++-common/analyzer/pr110830.c
index f5a39b7..ebfd38d 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr110830.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr110830.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
typedef __SIZE_TYPE__ size_t;
void free(void *);
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c b/gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c
index 4a08f0f1..e389e43 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr93032-mztools-simplified.c
@@ -1,4 +1,5 @@
/* { dg-do "compile" } */
+/* { dg-additional-options "-fno-exceptions" } */
/* Minimal replacement of system headers. */
#define NULL ((void *) 0)
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c b/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c
index 50d3388..19a3023 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-feasibility-3.c
@@ -3,6 +3,7 @@
Adapted from intl/localealias.c, with all #includes removed. */
/* { dg-do "compile" } */
+/* { dg-additional-options "-fno-exceptions" } */
/* Handle aliases for locale names.
Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc.
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c b/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c
index 6f65add..45517468 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr93355-localealias-simplified.c
@@ -3,6 +3,7 @@
Adapted from intl/localealias.c, with all #includes removed. */
/* { dg-do "compile" } */
+/* { dg-additional-options "-fno-exceptions" } */
/* Handle aliases for locale names.
Copyright (C) 1995-1999, 2000-2001, 2003 Free Software Foundation, Inc.
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c b/gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c
index b20630b..fb194ad 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr96650-1-trans.c
@@ -1,4 +1,5 @@
/* { dg-additional-options "-O2 -fanalyzer-transitivity" } */
+/* { dg-additional-options "-fno-exceptions" } */
int *wf;
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr97072.c b/gcc/testsuite/c-c++-common/analyzer/pr97072.c
index 4024124..82411a1 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr97072.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr97072.c
@@ -1,4 +1,4 @@
-void unknown_fn_1 (void *);
+void unknown_fn_1 (void *) __attribute__((nothrow));
void test_1 (int co, int y)
{
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr98575-1.c b/gcc/testsuite/c-c++-common/analyzer/pr98575-1.c
index 6472e76..b8ddf77c 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr98575-1.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr98575-1.c
@@ -4,7 +4,7 @@
void **g;
-extern void unknown_fn (void);
+extern void unknown_fn (void) __attribute__((nothrow));
/* Without a call to unknown_fn. */
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c b/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c
index 41be8ca..60f3a598 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr99716-1.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
typedef struct FILE FILE;
FILE* fopen (const char*, const char*);
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr99716-2.c b/gcc/testsuite/c-c++-common/analyzer/pr99716-2.c
index ef7cc5f..caf5c86 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr99716-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr99716-2.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib rand" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
/* Reduced from
https://github.com/libguestfs/libguestfs/blob/e0a11061035d47b118c95706240bcc17fd576edc/tests/mount-local/test-parallel-mount-local.c#L299-L335
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr99716-3.c b/gcc/testsuite/c-c++-common/analyzer/pr99716-3.c
index 414d57e..98f656f 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr99716-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr99716-3.c
@@ -1,4 +1,5 @@
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/analyzer/pragma-2.c b/gcc/testsuite/c-c++-common/analyzer/pragma-2.c
index bd96a25..f309876 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pragma-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pragma-2.c
@@ -1,6 +1,7 @@
/* { dg-skip-if "" { powerpc*-*-aix* } } */
/* Verify that we can disable -Wanalyzer-too-complex via pragmas. */
/* { dg-additional-options "-Wanalyzer-too-complex -Werror=analyzer-too-complex -fno-analyzer-state-merge -g" } */
+/* { dg-additional-options "-fno-exceptions" } */
/* { dg-skip-if "requires hosted libstdc++ for stdlib malloc" { ! hostedlib } } */
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c b/gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c
index 9f6ccb6..9606044 100644
--- a/gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c
+++ b/gcc/testsuite/c-c++-common/analyzer/rhbz1878600.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
#include <stdio.h>
#define INI_MAX_LINE 200
diff --git a/gcc/testsuite/c-c++-common/analyzer/strndup-1.c b/gcc/testsuite/c-c++-common/analyzer/strndup-1.c
index 3f90afe..915f220 100644
--- a/gcc/testsuite/c-c++-common/analyzer/strndup-1.c
+++ b/gcc/testsuite/c-c++-common/analyzer/strndup-1.c
@@ -1,6 +1,7 @@
/* { dg-skip-if "no strndup in libc" { *-*-darwin[789]* *-*-darwin10* hppa*-*-hpux* *-*-mingw* *-*-vxworks* } } */
/* { dg-additional-options "-D_POSIX_C_SOURCE=200809L" } */
/* { dg-skip-if "requires hosted libstdc++ for stdlib free" { ! hostedlib } } */
+/* { dg-additional-options "-fno-exceptions" } */
#include <string.h>
#include <stdlib.h>
diff --git a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c
index 868c393..1aa4159e 100644
--- a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c
+++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4-disabled.c
@@ -2,6 +2,7 @@
region_model_context_decorator::add_note. */
/* { dg-additional-options "-Wno-analyzer-write-to-string-literal" } */
+/* { dg-additional-options "-fno-exceptions" } */
typedef __SIZE_TYPE__ size_t;
diff --git a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c
index 971e8f3..b60fba0 100644
--- a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c
+++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-4.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
typedef __SIZE_TYPE__ size_t;
int getrandom (void *__buffer, size_t __length, /* { dg-line getrandom } */
diff --git a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c
index 2ecad8c..78b2204 100644
--- a/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c
+++ b/gcc/testsuite/c-c++-common/analyzer/write-to-string-literal-5.c
@@ -2,6 +2,7 @@
notes) works. */
/* { dg-additional-options "-fanalyzer-show-duplicate-count" } */
+/* { dg-additional-options "-fno-exceptions" } */
#include "../../gcc.dg/analyzer/analyzer-decls.h"
diff --git a/gcc/testsuite/c-c++-common/analyzer/zlib-5.c b/gcc/testsuite/c-c++-common/analyzer/zlib-5.c
index 1e3746d..fa82e43 100644
--- a/gcc/testsuite/c-c++-common/analyzer/zlib-5.c
+++ b/gcc/testsuite/c-c++-common/analyzer/zlib-5.c
@@ -1,4 +1,5 @@
/* { dg-additional-options "-O3" } */
+/* { dg-additional-options "-fno-exceptions" } */
#include "analyzer-decls.h"
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-could-throw-1.C b/gcc/testsuite/g++.dg/analyzer/exception-could-throw-1.C
new file mode 100644
index 0000000..4671e62
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-could-throw-1.C
@@ -0,0 +1,37 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+extern void do_something ();
+extern void do_something_nothrow () __attribute__ ((nothrow));;
+
+int test ()
+{
+ try
+ {
+ do_something ();
+ }
+ catch (int i)
+ {
+ int j = i;
+ __analyzer_eval (i == 42); // { dg-warning "UNKNOWN" }
+ __analyzer_eval (i == j); // { dg-warning "TRUE" }
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 1;
+ }
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 0;
+}
+
+int test_nothrow ()
+{
+ try
+ {
+ do_something_nothrow ();
+ }
+ catch (int i)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 1;
+ }
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-could-throw-2.C b/gcc/testsuite/g++.dg/analyzer/exception-could-throw-2.C
new file mode 100644
index 0000000..6572113
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-could-throw-2.C
@@ -0,0 +1,32 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct io_error {};
+struct value_error {};
+struct runtime_error {};
+
+extern void do_something ();
+
+int test ()
+{
+ try
+ {
+ do_something ();
+ }
+ catch (const io_error &err)
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 1;
+ }
+ catch (const value_error &err)
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 2;
+ }
+ catch (const runtime_error &err)
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 3;
+ }
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-dynamic-spec.C b/gcc/testsuite/g++.dg/analyzer/exception-dynamic-spec.C
new file mode 100644
index 0000000..9847203
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-dynamic-spec.C
@@ -0,0 +1,62 @@
+// Tests of dynamic exception specifications
+// { dg-require-effective-target c++14_down }
+// { dg-prune-output "dynamic exception specifications are deprecated" }
+
+struct io_error {};
+struct file_io_error : public io_error {};
+struct mem_error {};
+
+// Valid intraprocedural:
+
+void test_1 (int flag) throw (io_error)
+{
+ if (flag)
+ throw io_error();
+}
+
+// Invalid intraprocedural:
+
+void test_2 (int flag) throw (io_error) // { dg-warning "throwing exception of unexpected type 'mem_error' from 'test_2'" }
+// { dg-message "exception of unexpected type 'mem_error' thrown from 'test_2'" "" { target *-*-* } .-1 }
+// { dg-message "'test_2' declared here" "" { target *-*-* } .-2 }
+{
+ if (flag)
+ throw mem_error(); // { dg-message "throwing exception of type 'mem_error' here\.\.\." }
+}
+
+// Valid intraprocedural with subclass:
+
+void test_3 (int flag) throw (io_error) // { dg-bogus "throwing exception of unexpected type 'file_io_error' from 'test_3'" "PR analyzer/119697" { xfail *-*-* } }
+{
+ if (flag)
+ throw file_io_error();
+}
+
+// Valid interprocedural:
+
+void test_4_inner (int flag)
+{
+ if (flag)
+ throw io_error ();
+}
+
+void test_4_outer (int flag) throw (io_error)
+{
+ test_4_inner (flag);
+}
+
+// Invalid interprocedural:
+
+void test_5_inner (int flag)
+{
+ if (flag)
+ throw mem_error (); // { dg-message "throwing exception of type 'mem_error' here\.\.\." }
+ // { dg-message "unwinding stack frame" "" { target *-*-* } .-1 }
+}
+
+void test_5_outer (int flag) throw (io_error) // { dg-warning "throwing exception of unexpected type 'mem_error' from 'test_5_outer'" }
+// { dg-message "exception of unexpected type 'mem_error' thrown from 'test_5_outer'" "" { target *-*-* } .-1 }
+// { dg-message "'test_5_outer' declared here" "" { target *-*-* } .-2 }
+{
+ test_5_inner (flag);
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-1.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-1.C
new file mode 100644
index 0000000..25467ea
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-1.C
@@ -0,0 +1,8 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+int test ()
+{
+ void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" }
+
+ throw 42; // { dg-warning "leak of 'ptr'" }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-2.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-2.C
new file mode 100644
index 0000000..0e0eef8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-2.C
@@ -0,0 +1,18 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+int test ()
+{
+ void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" }
+
+ try
+ {
+ throw 42;
+ }
+ catch (int i) // { dg-message "\.\.\.catching exception of type 'int' here" }
+ {
+ return -1;
+ } // { dg-warning "leak of 'ptr'" }
+
+ __builtin_free (ptr);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-3.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-3.C
new file mode 100644
index 0000000..3684d66
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-3.C
@@ -0,0 +1,12 @@
+extern void do_something ();
+
+int test ()
+{
+ void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" }
+
+ do_something (); // { dg-message "if 'void do_something\\(\\)' throws an exception\.\.\." }
+ // { dg-warning "leak of 'ptr'" "" { target *-*-* } .-1 }
+
+ __builtin_free (ptr);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-4.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-4.C
new file mode 100644
index 0000000..7280d32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-4.C
@@ -0,0 +1,16 @@
+static void
+do_something (int flag)
+{
+ if (flag)
+ throw 42; // { dg-warning "leak of 'ptr'" }
+}
+
+int test (int flag)
+{
+ void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" }
+
+ do_something (flag);
+
+ __builtin_free (ptr);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-5.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-5.C
new file mode 100644
index 0000000..d99e53c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-5.C
@@ -0,0 +1,51 @@
+/* Verify that we detect a leak when unwinding multiple frames. */
+
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct io_error {};
+struct value_error {};
+struct runtime_error {};
+
+int inner (int flag)
+{
+ if (flag)
+ throw value_error (); // { dg-warning "leak" }
+ // { dg-message "throwing exception of type 'value_error' here\.\.\." "" { target *-*-* } .-1 }
+
+ return 0;
+}
+
+int __analyzer_middle (int flag)
+{
+ void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" }
+
+ int rval = inner (flag);
+
+ __builtin_free (ptr);
+
+ return rval;
+}
+
+int outer ()
+{
+ try
+ {
+ __analyzer_middle (1);
+ }
+ catch (const io_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 1;
+ }
+ catch (const value_error &err)
+ {
+ return 2;
+ }
+ catch (const runtime_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 3;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-leak-6.C b/gcc/testsuite/g++.dg/analyzer/exception-leak-6.C
new file mode 100644
index 0000000..cb70230
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-leak-6.C
@@ -0,0 +1,22 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+extern void do_something (int x);
+
+int inner (int x)
+{
+ do_something (x); // { dg-warning "leak" }
+ // { dg-message "if 'void do_something\\(int\\)' throws an exception\.\.\." "" { target *-*-* } .-1 }
+
+ return 0;
+}
+
+int outer (int x)
+{
+ void *ptr = __builtin_malloc (1024); // { dg-message "allocated here" }
+
+ int rval = inner (x);
+
+ __builtin_free (ptr);
+
+ return rval;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-nothrow.C b/gcc/testsuite/g++.dg/analyzer/exception-nothrow.C
new file mode 100644
index 0000000..9625748
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-nothrow.C
@@ -0,0 +1,26 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+extern void do_something () __attribute__((nothrow));
+
+/* A wrapper function to stop the try/catch being optimized away. */
+
+void wrapper () __attribute__((noinline));
+void wrapper ()
+{
+ do_something ();
+}
+
+int test ()
+{
+ try
+ {
+ wrapper ();
+ }
+ catch (int i)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 1;
+ }
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-1.C b/gcc/testsuite/g++.dg/analyzer/exception-path-1.C
new file mode 100644
index 0000000..486ca193
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-1.C
@@ -0,0 +1,34 @@
+/* Verify that we follow the correct paths when we know the typeinfo of
+ an exception. */
+
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct io_error {};
+struct value_error {};
+struct runtime_error {};
+
+int test ()
+{
+ try
+ {
+ throw value_error (); // { dg-message "\\(1\\) throwing exception of type 'value_error' here..." }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ catch (const io_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 1;
+ }
+ catch (const value_error &err) // { dg-message "\\(2\\) \.\.\.catching exception of type 'value_error' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 2;
+ }
+ catch (const runtime_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 3;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-1.C b/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-1.C
new file mode 100644
index 0000000..8aa9814
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-1.C
@@ -0,0 +1,16 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+int test ()
+{
+ try
+ {
+ throw 42;
+ }
+ catch (...)
+ {
+ __analyzer_dump_path ();
+ return -1;
+ }
+ __analyzer_dump_path ();
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-2.C b/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-2.C
new file mode 100644
index 0000000..d185056
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-catch-all-2.C
@@ -0,0 +1,22 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+int test ()
+{
+ try
+ {
+ throw 42; // { dg-message "throwing exception of type 'int' here\.\.\." }
+ }
+ catch (int i) // { dg-message "\.\.\.catching exception of type 'int' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ __analyzer_eval (i == 42); // { dg-warning "TRUE" }
+ return -2;
+ }
+ catch (...)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return -1;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C
new file mode 100644
index 0000000..2608f17
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple-2.C
@@ -0,0 +1,55 @@
+/* Verify that we follow the correct paths when we know the typeinfo of
+ an exception: interprocedural case where unwind multiple frame,
+ failing to match the type. */
+
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct io_error {};
+struct value_error {};
+struct runtime_error {};
+
+int inner (int flag)
+{
+ if (flag)
+ throw value_error (); // { dg-message "throwing exception of type 'value_error' here..." }
+ // { dg-message "unwinding 2 stack frames" "" { target *-*-* } .-1 }
+
+ return 0;
+}
+
+int middle (int flag)
+{
+ try
+ {
+ return inner (flag);
+ }
+ catch (const io_error &err) // this shouldn't be matched
+ {
+ return -1;
+ }
+}
+
+int outer ()
+{
+ try
+ {
+ middle (1);
+ }
+ catch (const io_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 1;
+ }
+ catch (const value_error &err) // { dg-message "\.\.\.catching exception of type 'value_error' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 2;
+ }
+ catch (const runtime_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 3;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple.C b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple.C
new file mode 100644
index 0000000..a52312a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-multiple.C
@@ -0,0 +1,48 @@
+/* Verify that we follow the correct paths when we know the typeinfo of
+ an exception: interprocedural case where we unwind one frame. */
+
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct io_error {};
+struct value_error {};
+struct runtime_error {};
+
+int inner (int flag)
+{
+ if (flag)
+ throw value_error (); // { dg-message "throwing exception of type 'value_error' here..." }
+
+ return 0;
+}
+
+int middle (int flag)
+{
+ return inner (flag);
+}
+
+int outer ()
+{
+ try
+ {
+ middle (1);
+ }
+ catch (const io_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 1;
+ }
+ catch (const value_error &err) // { dg-message "\.\.\.catching exception of type 'value_error' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 2;
+ }
+ catch (const runtime_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 3;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
+
+// TODO: test coverage for unwinding stack frame events
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-single.C b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-single.C
new file mode 100644
index 0000000..055fe27
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-unwind-single.C
@@ -0,0 +1,43 @@
+/* Verify that we follow the correct paths when we know the typeinfo of
+ an exception: interprocedural case where we unwind two frames. */
+
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct io_error {};
+struct value_error {};
+struct runtime_error {};
+
+int inner (int flag)
+{
+ if (flag)
+ throw value_error (); // { dg-message "throwing exception of type 'value_error' here..." }
+
+ return 0;
+}
+
+int outer ()
+{
+ try
+ {
+ inner (1);
+ }
+ catch (const io_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 1;
+ }
+ catch (const value_error &err) // { dg-message "\.\.\.catching exception of type 'value_error' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 2;
+ }
+ catch (const runtime_error &err)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 3;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
+
+// TODO: test coverage for unwinding stack frame events
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-path-with-cleanups.C b/gcc/testsuite/g++.dg/analyzer/exception-path-with-cleanups.C
new file mode 100644
index 0000000..fc18a21
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-path-with-cleanups.C
@@ -0,0 +1,27 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct foo
+{
+ foo (int x) : m_x (x) {}
+ ~foo () __attribute__((nothrow));
+
+ int m_x;
+};
+
+int test (bool flag)
+{
+ foo outside (1);
+ try
+ {
+ foo inside_try (2);
+ if (flag)
+ throw foo (3); // { dg-message "throwing exception of type 'foo' here\.\.\." }
+ }
+ catch (foo &f) // { dg-message "\.\.\.catching exception of type 'foo' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ __analyzer_eval (f.m_x == 3); // { dg-warning "TRUE" }
+ return f.m_x;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-rethrow-1.C b/gcc/testsuite/g++.dg/analyzer/exception-rethrow-1.C
new file mode 100644
index 0000000..10484fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-rethrow-1.C
@@ -0,0 +1,13 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+int test ()
+{
+ try
+ {
+ throw 42;
+ }
+ catch (...)
+ {
+ throw;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-rethrow-2.C b/gcc/testsuite/g++.dg/analyzer/exception-rethrow-2.C
new file mode 100644
index 0000000..22242a3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-rethrow-2.C
@@ -0,0 +1,25 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+int test ()
+{
+ try
+ {
+ try
+ {
+ throw 42; // { dg-message "\\(1\\) throwing exception of type 'int' here\.\.\." }
+ }
+ catch (...) // { dg-message "\\(2\\) \.\.\.catching exception of type 'int' here" }
+ {
+ throw; // { dg-message "\\(3\\) rethrowing exception of type 'int' here\.\.\." }
+ }
+ }
+ catch (int i) // { dg-message "\\(4\\) \.\.\.catching exception of type 'int' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ __analyzer_eval (i == 42); // { dg-warning "TRUE" }
+ return -1;
+ }
+
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-stack-1.C b/gcc/testsuite/g++.dg/analyzer/exception-stack-1.C
new file mode 100644
index 0000000..c6aa415
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-stack-1.C
@@ -0,0 +1,35 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+void test (void)
+{
+ try
+ {
+ try
+ {
+ throw 42;
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ catch (...)
+ {
+ try
+ {
+ throw 1066; // throw an inner exception
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ catch (int i)
+ {
+ __analyzer_eval (i == 1066); // { dg-warning "TRUE" }
+ }
+ throw; // rethrow the outer exception
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ catch (int j)
+ {
+ __analyzer_eval (j == 42); // { dg-warning "TRUE" }
+ __analyzer_dump_path (); // { dg-message "path" }
+ throw;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-stack-2.C b/gcc/testsuite/g++.dg/analyzer/exception-stack-2.C
new file mode 100644
index 0000000..5e6a3c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-stack-2.C
@@ -0,0 +1,44 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct io_error {};
+struct value_error {};
+struct runtime_error {};
+
+void test (void)
+{
+ try
+ {
+ try
+ {
+ throw value_error (); // { dg-message "\\(1\\) throwing exception of type 'value_error' here..." }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ catch (...) // { dg-message "\\(2\\) \.\.\.catching exception of type 'value_error' here" }
+ {
+ try
+ {
+ throw io_error (); // { dg-message "\\(3\\) throwing exception of type 'io_error' here..." }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ catch (const io_error &err) // { dg-message "\\(4\\) \.\.\.catching exception of type 'io_error' here" }
+ {
+ /* discard it */
+ }
+
+ // rethrow the outer exception
+ throw; // { dg-message "\\(5\\) rethrowing exception of type 'value_error' here..." }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ catch (const value_error &err) // { dg-message "\\(6\\) \.\.\.catching exception of type 'value_error' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ throw;
+ }
+ catch (...)
+ {
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C b/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C
new file mode 100644
index 0000000..79df330
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-subclass-1.C
@@ -0,0 +1,21 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+class exception
+{
+};
+
+class io_error : public exception
+{
+};
+
+int test ()
+{
+ try {
+ throw io_error();
+ } catch (exception &exc) {
+ __analyzer_dump_path (); // { dg-message "path" "PR analyzer/119697" { xfail *-*-* } }
+ return -1;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-subclass-2.C b/gcc/testsuite/g++.dg/analyzer/exception-subclass-2.C
new file mode 100644
index 0000000..e9fb617
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-subclass-2.C
@@ -0,0 +1,25 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+class exception
+{
+};
+
+class io_error : public exception
+{
+};
+
+int __analyzer_inner ()
+{
+ try {
+ throw io_error();
+ } catch (exception &exc) {
+ return -1;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
+
+int test ()
+{
+ return __analyzer_inner (); // { dg-message "path" "PR analyzer/119697" { xfail *-*-* } }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-value-1.C b/gcc/testsuite/g++.dg/analyzer/exception-value-1.C
new file mode 100644
index 0000000..0d06dd8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-value-1.C
@@ -0,0 +1,20 @@
+/* Verify that we can access values in exceptions. */
+
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+int test ()
+{
+ try
+ {
+ throw 42; // { dg-message "\\(1\\) throwing exception of type 'int' here..." }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ }
+ catch (int i) // { dg-message "\\(2\\) \.\.\.catching exception of type 'int' here" }
+ {
+ __analyzer_dump_path (); // { dg-message "path" }
+ __analyzer_eval (i == 42); // { dg-warning "TRUE" }
+ return 1;
+ }
+ __analyzer_dump_path (); // { dg-bogus "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/exception-value-2.C b/gcc/testsuite/g++.dg/analyzer/exception-value-2.C
new file mode 100644
index 0000000..ef9dd46
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/exception-value-2.C
@@ -0,0 +1,36 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct foo {};
+
+int inner (bool flag)
+{
+ try
+ {
+ if (flag)
+ throw 42;
+ }
+ catch (foo &f)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+int middle (bool flag)
+{
+ try
+ {
+ int rval = inner (flag);
+ return rval;
+ }
+ catch (int ei)
+ {
+ return ei;
+ }
+}
+
+void outer (void)
+{
+ __analyzer_eval (middle (false) == 0); // { dg-warning "TRUE" }
+ __analyzer_eval (middle (true) == 42); // { dg-warning "TRUE" }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/fno-exception.C b/gcc/testsuite/g++.dg/analyzer/fno-exception.C
new file mode 100644
index 0000000..2ec4e06e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/fno-exception.C
@@ -0,0 +1,12 @@
+/* { dg-additional-options "-fno-exceptions" } */
+
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+extern void do_something ();
+
+int test ()
+{
+ do_something ();
+ __analyzer_dump_path (); // { dg-message "path" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-1.C b/gcc/testsuite/g++.dg/analyzer/nrvo-1.C
new file mode 100644
index 0000000..146b80a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/nrvo-1.C
@@ -0,0 +1,18 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+struct s1
+{
+ s1 (int x) : m_x (x) {}
+ int m_x;
+};
+
+s1 make_s1 (int x)
+{
+ return s1 (x);
+}
+
+void test_1 (int x)
+{
+ s1 s = make_s1 (x);
+ __analyzer_eval (s.m_x == x); // { dg-warning "TRUE" }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-2.C b/gcc/testsuite/g++.dg/analyzer/nrvo-2.C
new file mode 100644
index 0000000..e0567c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/nrvo-2.C
@@ -0,0 +1,26 @@
+#include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+// { dg-do compile { target c++11 } }
+
+struct s1
+{
+ int t;
+ s1() { t = 42; }
+ s1(const s1& other) { t = other.t; }
+};
+
+s1 inner()
+{
+ return s1{}; // { dg-bogus "uninitialized" }
+}
+
+s1 middle()
+{
+ return inner();
+}
+
+void outer()
+{
+ s1 obj = middle();
+ __analyzer_eval (obj.t == 42); // { dg-warning "TRUE" }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1.C b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1.C
new file mode 100644
index 0000000..de447ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1.C
@@ -0,0 +1,11 @@
+struct Guard {
+ int i;
+ ~Guard() {}
+};
+Guard lock() {
+ return Guard(); // { dg-bogus "uninitialized" }
+}
+void bar() {
+ Guard foo = lock();
+}
+
diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1b.C b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1b.C
new file mode 100644
index 0000000..681795d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-1b.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+
+struct Guard {
+ int i;
+ ~Guard() {}
+};
+Guard lock() {
+ return Guard(); // { dg-bogus "uninitialized" }
+}
+void bar() {
+ auto foo = lock();
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2.C b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2.C
new file mode 100644
index 0000000..aa011e2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2.C
@@ -0,0 +1,10 @@
+struct g
+{
+ int t;
+ g();
+};
+
+g foo1()
+{
+ return g(); // { dg-bogus "uninitialized" }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2b.C b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2b.C
new file mode 100644
index 0000000..31df5a8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/nrvo-pr111536-2b.C
@@ -0,0 +1,13 @@
+// { dg-do compile { target c++11 } }
+
+struct g
+{
+ int t;
+ g();
+ g(const g&);
+};
+
+g foo1()
+{
+ return g{}; // { dg-bogus "uninitialized" }
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/pr94028.C b/gcc/testsuite/g++.dg/analyzer/pr94028.C
index 0573d30..53bfa29 100644
--- a/gcc/testsuite/g++.dg/analyzer/pr94028.C
+++ b/gcc/testsuite/g++.dg/analyzer/pr94028.C
@@ -19,7 +19,7 @@ struct j
throw()
#endif
{
- return calloc (b, sizeof (int)); // { dg-bogus "leak" "" { xfail c++98_only } }
+ return calloc (b, sizeof (int));
}
j (B *, int)
{
diff --git a/gcc/testsuite/g++.dg/analyzer/std-unexpected.C b/gcc/testsuite/g++.dg/analyzer/std-unexpected.C
new file mode 100644
index 0000000..4eb2672
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/std-unexpected.C
@@ -0,0 +1,9 @@
+// { dg-require-effective-target c++14_down }
+// { dg-additional-options "-Wno-deprecated-declarations" }
+
+#include <exception>
+
+void test_1 ()
+{
+ std::unexpected ();
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/unique_ptr-1.C b/gcc/testsuite/g++.dg/analyzer/unique_ptr-1.C
new file mode 100644
index 0000000..cc9cf71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/unique_ptr-1.C
@@ -0,0 +1,13 @@
+// Verify that we complain about trivial uses of NULL unique_ptr.
+
+// { dg-do compile { target c++11 } }
+
+#include <memory>
+
+struct A {int x; int y;};
+
+int main() {
+ std::unique_ptr<A> a;
+ a->x = 12; // { dg-warning "dereference of NULL" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/analyzer/unique_ptr-2.C b/gcc/testsuite/g++.dg/analyzer/unique_ptr-2.C
new file mode 100644
index 0000000..e8d3e7e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/analyzer/unique_ptr-2.C
@@ -0,0 +1,17 @@
+// { dg-do compile { target c++11 } }
+// { dg-additional-options "-Wno-analyzer-too-complex" } */
+
+#include <memory>
+
+struct A {int x; int y;};
+
+extern std::unique_ptr<A> make_ptr ();
+
+int test (int flag) {
+ std::unique_ptr<A> a;
+ if (flag)
+ a = make_ptr ();
+ a->x = 12; // { dg-warning "dereference of NULL" "" { xfail *-*-*} }
+ // TODO: this is failing due to "too complex" warnings
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/coroutines/pr105287.C b/gcc/testsuite/g++.dg/coroutines/pr105287.C
index c54d1fd..0436572 100644
--- a/gcc/testsuite/g++.dg/coroutines/pr105287.C
+++ b/gcc/testsuite/g++.dg/coroutines/pr105287.C
@@ -1,5 +1,5 @@
// { dg-additional-options "-fanalyzer" }
-// { dg-excess-errors "lots of analyzer output, but no ICE" }
+
namespace std {
template <typename _Result> struct coroutine_traits : _Result {};
template <typename = void> struct coroutine_handle {
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr100038.C b/gcc/testsuite/g++.dg/tree-ssa/pr100038.C
new file mode 100644
index 0000000..7024c4d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr100038.C
@@ -0,0 +1,17 @@
+// { dg-do compile }
+// { dg-options "-O2 -Wextra -Wall -Warray-bounds" }
+
+struct SparseBitVectorElement {
+ long Bits[2];
+ int find_first() const;
+};
+
+// we should not get an `array subscript 2 is above array bounds of`
+// warning here because we have an unreachable at that point
+
+int SparseBitVectorElement::find_first() const {
+ for (unsigned i = 0; i < 2; ++i)
+ if (Bits[i]) // { dg-bogus "is above array bounds of" }
+ return i;
+ __builtin_unreachable();
+}
diff --git a/gcc/testsuite/gcc.dg/gimplefe-57.c b/gcc/testsuite/gcc.dg/gimplefe-57.c
new file mode 100644
index 0000000..d3eca56
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gimplefe-57.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-fgimple" } */
+
+int __GIMPLE
+foo (int a, int b)
+{
+ int tem;
+ tem = a __ROTATE_LEFT b;
+ tem = tem __ROTATE_RIGHT b;
+ return tem;
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc
index 467af16..0f1f864 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_cpython_plugin.cc
@@ -29,7 +29,7 @@
#include "selftest.h"
#include "function.h"
#include "json.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
#include "analyzer/analyzer-language.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
@@ -46,7 +46,6 @@
#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
#include "analyzer/exploded-graph.h"
-#include "make-unique.h"
int plugin_is_GPL_compatible;
@@ -207,7 +206,7 @@ public:
std::unique_ptr<stmt_finder>
clone () const final override
{
- return make_unique<refcnt_stmt_finder> (m_eg, m_var);
+ return std::make_unique<refcnt_stmt_finder> (m_eg, m_var);
}
const gimple *
@@ -451,8 +450,9 @@ check_refcnt (const region_model *model,
const auto &eg = ctxt->get_eg ();
refcnt_stmt_finder finder (*eg, reg_tree);
- auto pd = make_unique<refcnt_mismatch> (curr_region, ob_refcnt_sval,
- actual_refcnt_sval, reg_tree);
+ auto pd = std::make_unique<refcnt_mismatch> (curr_region, ob_refcnt_sval,
+ actual_refcnt_sval,
+ reg_tree);
if (pd && eg)
ctxt->warn (std::move (pd), &finder);
}
@@ -680,7 +680,7 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const
= old_ptr_sval->dyn_cast_region_svalue ())
{
const region *freed_reg = old_reg->get_pointee ();
- model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
+ model->unbind_region_and_descendents (freed_reg, poison_kind::freed);
model->unset_dynamic_extents (freed_reg);
}
@@ -885,7 +885,7 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const
model->mark_region_as_unknown (freed_reg, cd.get_uncertainty ());
}
- model->unbind_region_and_descendents (freed_reg, POISON_KIND_FREED);
+ model->unbind_region_and_descendents (freed_reg, poison_kind::freed);
model->unset_dynamic_extents (freed_reg);
}
@@ -943,9 +943,9 @@ kf_PyList_Append::impl_call_post (const call_details &cd) const
/* Body of kf_PyList_Append::impl_call_post. */
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<realloc_failure> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<realloc_success_no_move> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<realloc_success_move> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<realloc_failure> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<realloc_success_no_move> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<realloc_success_move> (cd));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1078,8 +1078,8 @@ kf_PyList_New::impl_call_post (const call_details &cd) const
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<pyobj_init_fail> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<pyobj_init_fail> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<success> (cd));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1147,8 +1147,8 @@ kf_PyLong_FromLong::impl_call_post (const call_details &cd) const
if (cd.get_ctxt ())
{
- cd.get_ctxt ()->bifurcate (make_unique<pyobj_init_fail> (cd));
- cd.get_ctxt ()->bifurcate (make_unique<success> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<pyobj_init_fail> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<success> (cd));
cd.get_ctxt ()->terminate_path ();
}
}
@@ -1290,14 +1290,14 @@ cpython_analyzer_init_cb (void *gcc_data, void * /*user_data */)
}
iface->register_known_function ("PyList_Append",
- make_unique<kf_PyList_Append> ());
- iface->register_known_function ("PyList_New", make_unique<kf_PyList_New> ());
+ std::make_unique<kf_PyList_Append> ());
+ iface->register_known_function ("PyList_New", std::make_unique<kf_PyList_New> ());
iface->register_known_function ("PyLong_FromLong",
- make_unique<kf_PyLong_FromLong> ());
+ std::make_unique<kf_PyLong_FromLong> ());
iface->register_known_function (
"__analyzer_cpython_dump_refcounts",
- make_unique<kf_analyzer_cpython_dump_refcounts> ());
+ std::make_unique<kf_analyzer_cpython_dump_refcounts> ());
}
} // namespace ana
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc
index 77767c8..3cac3f8f 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_gil_plugin.cc
@@ -10,14 +10,13 @@
#include "config.h"
#include "system.h"
#include "coretypes.h"
-#include "make-unique.h"
#include "diagnostic.h"
#include "tree.h"
#include "gimple.h"
#include "gimple-iterator.h"
#include "gimple-walk.h"
#include "diagnostic-event-id.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
#include "analyzer/analyzer-logging.h"
#include "json.h"
#include "analyzer/sm.h"
@@ -66,7 +65,7 @@ public:
private:
void check_for_pyobject_in_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree callee_fndecl) const;
public:
@@ -147,7 +146,7 @@ public:
class double_save_thread : public gil_diagnostic
{
public:
- double_save_thread (const gil_state_machine &sm, const gcall *call)
+ double_save_thread (const gil_state_machine &sm, const gcall &call)
: gil_diagnostic (sm), m_call (call)
{}
@@ -160,7 +159,7 @@ class double_save_thread : public gil_diagnostic
{
const double_save_thread &sub_other
= (const double_save_thread &)base_other;
- return m_call == sub_other.m_call;
+ return &m_call == &sub_other.m_call;
}
bool emit (diagnostic_emission_context &ctxt) final override
@@ -179,13 +178,13 @@ class double_save_thread : public gil_diagnostic
}
private:
- const gcall *m_call;
+ const gcall &m_call;
};
class fncall_without_gil : public gil_diagnostic
{
public:
- fncall_without_gil (const gil_state_machine &sm, const gcall *call,
+ fncall_without_gil (const gil_state_machine &sm, const gcall &call,
tree callee_fndecl, unsigned arg_idx)
: gil_diagnostic (sm), m_call (call), m_callee_fndecl (callee_fndecl),
m_arg_idx (arg_idx)
@@ -200,7 +199,7 @@ class fncall_without_gil : public gil_diagnostic
{
const fncall_without_gil &sub_other
= (const fncall_without_gil &)base_other;
- return (m_call == sub_other.m_call
+ return (&m_call == &sub_other.m_call
&& m_callee_fndecl == sub_other.m_callee_fndecl
&& m_arg_idx == sub_other.m_arg_idx);
}
@@ -233,7 +232,7 @@ class fncall_without_gil : public gil_diagnostic
}
private:
- const gcall *m_call;
+ const gcall &m_call;
tree m_callee_fndecl;
unsigned m_arg_idx;
};
@@ -313,21 +312,21 @@ check_for_pyobject (gimple *, tree op, tree, void *data)
void
gil_state_machine::check_for_pyobject_in_call (sm_context &sm_ctxt,
const supernode *node,
- const gcall *call,
+ const gcall &call,
tree callee_fndecl) const
{
- for (unsigned i = 0; i < gimple_call_num_args (call); i++)
+ for (unsigned i = 0; i < gimple_call_num_args (&call); i++)
{
- tree arg = gimple_call_arg (call, i);
+ tree arg = gimple_call_arg (&call, i);
if (TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
continue;
tree type = TREE_TYPE (TREE_TYPE (arg));
if (type_based_on_pyobject_p (type))
{
- sm_ctxt.warn (node, call, NULL_TREE,
- make_unique<fncall_without_gil> (*this, call,
- callee_fndecl,
- i));
+ sm_ctxt.warn (node, &call, NULL_TREE,
+ std::make_unique<fncall_without_gil> (*this, call,
+ callee_fndecl,
+ i));
sm_ctxt.set_global_state (m_stop);
}
}
@@ -341,8 +340,9 @@ gil_state_machine::on_stmt (sm_context &sm_ctxt,
const gimple *stmt) const
{
const state_t global_state = sm_ctxt.get_global_state ();
- if (const gcall *call = dyn_cast <const gcall *> (stmt))
+ if (const gcall *call_stmt = dyn_cast <const gcall *> (stmt))
{
+ const gcall &call = *call_stmt;
if (tree callee_fndecl = sm_ctxt.get_fndecl_for_call (call))
{
if (is_named_call_p (callee_fndecl, "PyEval_SaveThread", call, 0))
@@ -353,7 +353,7 @@ gil_state_machine::on_stmt (sm_context &sm_ctxt,
if (global_state == m_released_gil)
{
sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<double_save_thread> (*this, call));
+ std::make_unique<double_save_thread> (*this, call));
sm_ctxt.set_global_state (m_stop);
}
else
@@ -409,7 +409,7 @@ gil_state_machine::check_for_pyobject_usage_without_gil (sm_context &sm_ctxt,
if (type_based_on_pyobject_p (type))
{
sm_ctxt.warn (node, stmt, NULL_TREE,
- make_unique<pyobject_usage_without_gil> (*this, op));
+ std::make_unique<pyobject_usage_without_gil> (*this, op));
sm_ctxt.set_global_state (m_stop);
}
}
@@ -425,7 +425,7 @@ gil_analyzer_init_cb (void *gcc_data, void */*user_data*/)
if (0)
inform (input_location, "got here: gil_analyzer_init_cb");
iface->register_state_machine
- (make_unique<gil_state_machine> (iface->get_logger ()));
+ (std::make_unique<gil_state_machine> (iface->get_logger ()));
}
} // namespace ana
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc
index 7f2158e..771ff75 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_kernel_plugin.cc
@@ -29,7 +29,7 @@
#include "selftest.h"
#include "function.h"
#include "json.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
@@ -44,7 +44,6 @@
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
-#include "make-unique.h"
int plugin_is_GPL_compatible;
@@ -106,7 +105,7 @@ class copy_across_boundary_fn : public known_function
if (ctxt)
{
/* Bifurcate state, creating a "failure" out-edge. */
- ctxt->bifurcate (make_unique<copy_failure> (cd));
+ ctxt->bifurcate (std::make_unique<copy_failure> (cd));
/* The "unbifurcated" state is the "success" case. */
copy_success success (cd,
@@ -238,11 +237,13 @@ kernel_analyzer_init_cb (void *gcc_data, void */*user_data*/)
inform (input_location, "got here: kernel_analyzer_init_cb");
iface->register_known_function
("copy_from_user",
- make_unique<known_function_copy_from_user> ());
- iface->register_known_function ("copy_to_user",
- make_unique<known_function_copy_to_user> ());
- iface->register_known_function ("__check_object_size",
- make_unique<known_function___check_object_size> ());
+ std::make_unique<known_function_copy_from_user> ());
+ iface->register_known_function
+ ("copy_to_user",
+ std::make_unique<known_function_copy_to_user> ());
+ iface->register_known_function
+ ("__check_object_size",
+ std::make_unique<known_function___check_object_size> ());
}
} // namespace ana
diff --git a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc
index c060407..c7087f0 100644
--- a/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/analyzer_known_fns_plugin.cc
@@ -29,7 +29,7 @@
#include "selftest.h"
#include "function.h"
#include "json.h"
-#include "analyzer/analyzer.h"
+#include "analyzer/common.h"
#include "analyzer/analyzer-logging.h"
#include "ordered-hash-map.h"
#include "options.h"
@@ -44,7 +44,6 @@
#include "analyzer/region-model.h"
#include "analyzer/call-details.h"
#include "analyzer/call-info.h"
-#include "make-unique.h"
int plugin_is_GPL_compatible;
@@ -168,7 +167,7 @@ public:
if (cd.get_ctxt ())
{
/* Bifurcate state, creating a "failure" out-edge. */
- cd.get_ctxt ()->bifurcate (make_unique<copy_failure> (cd));
+ cd.get_ctxt ()->bifurcate (std::make_unique<copy_failure> (cd));
/* The "unbifurcated" state is the "success" case. */
copy_success success (cd,
@@ -189,11 +188,12 @@ known_fn_analyzer_init_cb (void *gcc_data, void */*user_data*/)
LOG_SCOPE (iface->get_logger ());
if (0)
inform (input_location, "got here: known_fn_analyzer_init_cb");
- iface->register_known_function ("returns_42",
- make_unique<known_function_returns_42> ());
+ iface->register_known_function
+ ("returns_42",
+ std::make_unique<known_function_returns_42> ());
iface->register_known_function
("attempt_to_copy",
- make_unique<known_function_attempt_to_copy> ());
+ std::make_unique<known_function_attempt_to_copy> ());
}
} // namespace ana
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc
index 7e6d7e1..5ec3418 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_group_plugin.cc
@@ -29,7 +29,6 @@
#include "diagnostic.h"
#include "diagnostic-format-text.h"
#include "context.h"
-#include "make-unique.h"
int plugin_is_GPL_compatible;
@@ -230,7 +229,8 @@ plugin_init (struct plugin_name_args *plugin_info,
diagnostic_text_starter (global_dc) = test_diagnostic_text_starter;
diagnostic_start_span (global_dc) = test_diagnostic_start_span_fn;
- global_dc->set_output_format (::make_unique<test_output_format> (*global_dc));
+ global_dc->set_output_format
+ (::std::make_unique<test_output_format> (*global_dc));
pass_info.pass = new pass_test_groups (g);
pass_info.reference_pass_name = "*warn_function_noreturn";
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc
index 2ce267c..24c6f8c 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic_plugin_xhtml_format.cc
@@ -39,7 +39,6 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic-buffer.h"
#include "ordered-hash-map.h"
#include "sbitmap.h"
-#include "make-unique.h"
#include "selftest.h"
#include "selftest-diagnostic.h"
#include "selftest-diagnostic-show-locus.h"
@@ -179,7 +178,7 @@ void
node_with_children::add_text (label_text str)
{
gcc_assert (str.get ());
- add_child (::make_unique <text> (std::move (str)));
+ add_child (std::make_unique <text> (std::move (str)));
}
@@ -338,7 +337,7 @@ private:
static std::unique_ptr<xml::element>
make_div (label_text class_)
{
- auto div = ::make_unique<xml::element> ("div", false);
+ auto div = std::make_unique<xml::element> ("div", false);
div->set_attr ("class", std::move (class_));
return div;
}
@@ -346,7 +345,7 @@ make_div (label_text class_)
static std::unique_ptr<xml::element>
make_span (label_text class_)
{
- auto span = ::make_unique<xml::element> ("span", true);
+ auto span = std::make_unique<xml::element> ("span", true);
span->set_attr ("class", std::move (class_));
return span;
}
@@ -410,24 +409,24 @@ xhtml_builder::xhtml_builder (diagnostic_context &context,
{
gcc_assert (m_line_maps);
- m_document = ::make_unique<xml::document> ();
+ m_document = std::make_unique<xml::document> ();
{
- auto html_element = ::make_unique<xml::element> ("html", false);
+ auto html_element = std::make_unique<xml::element> ("html", false);
html_element->set_attr
("xmlns",
label_text::borrow ("http://www.w3.org/1999/xhtml"));
{
{
- auto head_element = ::make_unique<xml::element> ("head", false);
+ auto head_element = std::make_unique<xml::element> ("head", false);
{
- auto title_element = ::make_unique<xml::element> ("title", true);
+ auto title_element = std::make_unique<xml::element> ("title", true);
label_text title (label_text::borrow ("Title goes here")); // TODO
title_element->add_text (std::move (title));
head_element->add_child (std::move (title_element));
}
html_element->add_child (std::move (head_element));
- auto body_element = ::make_unique<xml::element> ("body", false);
+ auto body_element = std::make_unique<xml::element> ("body", false);
{
auto diagnostics_element
= make_div (label_text::borrow ("gcc-diagnostic-list"));
@@ -531,7 +530,7 @@ xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
case pp_token::kind::begin_url:
{
pp_token_begin_url *sub = as_a <pp_token_begin_url *> (iter);
- auto anchor = ::make_unique<xml::element> ("a", true);
+ auto anchor = std::make_unique<xml::element> ("a", true);
anchor->set_attr ("href", std::move (sub->m_value));
push_element (std::move (anchor));
}
@@ -585,7 +584,7 @@ xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
auto cwe_span = make_span (label_text::borrow ("gcc-cwe-metadata"));
cwe_span->add_text (label_text::borrow ("["));
{
- auto anchor = ::make_unique<xml::element> ("a", true);
+ auto anchor = std::make_unique<xml::element> ("a", true);
anchor->set_attr ("href", label_text::take (get_cwe_url (cwe)));
pretty_printer pp;
pp_printf (&pp, "CWE-%i", cwe);
@@ -614,7 +613,7 @@ xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
{
if (option_url.get ())
{
- auto anchor = ::make_unique<xml::element> ("a", true);
+ auto anchor = std::make_unique<xml::element> ("a", true);
anchor->set_attr ("href", std::move (option_url));
anchor->add_text (std::move (option_text));
option_span->add_child (std::move (anchor));
@@ -627,7 +626,7 @@ xhtml_builder::make_element_for_diagnostic (const diagnostic_info &diagnostic,
}
{
- auto pre = ::make_unique<xml::element> ("pre", true);
+ auto pre = std::make_unique<xml::element> ("pre", true);
pre->set_attr ("class", label_text::borrow ("gcc-annotated-source"));
// TODO: ideally we'd like to capture elements within the following:
diagnostic_show_locus (&m_context, m_context.m_source_printing,
@@ -698,7 +697,7 @@ public:
std::unique_ptr<diagnostic_per_format_buffer>
make_per_format_buffer () final override
{
- return ::make_unique<diagnostic_xhtml_format_buffer> (m_builder);
+ return std::make_unique<diagnostic_xhtml_format_buffer> (m_builder);
}
void set_buffer (diagnostic_per_format_buffer *base_buffer) final override
{
@@ -844,9 +843,9 @@ diagnostic_output_format_init_xhtml_stderr (diagnostic_context &context,
const line_maps *line_maps)
{
gcc_assert (line_maps);
- auto format = ::make_unique<xhtml_stream_output_format> (context,
- line_maps,
- stderr);
+ auto format = std::make_unique<xhtml_stream_output_format> (context,
+ line_maps,
+ stderr);
diagnostic_output_format_init_xhtml (context, std::move (format));
}
@@ -859,9 +858,9 @@ diagnostic_output_format_init_xhtml_file (diagnostic_context &context,
const char *base_file_name)
{
gcc_assert (line_maps);
- auto format = ::make_unique<xhtml_file_output_format> (context,
- line_maps,
- base_file_name);
+ auto format = std::make_unique<xhtml_file_output_format> (context,
+ line_maps,
+ base_file_name);
diagnostic_output_format_init_xhtml (context, std::move (format));
}
@@ -878,8 +877,8 @@ class test_xhtml_diagnostic_context : public test_diagnostic_context
public:
test_xhtml_diagnostic_context ()
{
- auto format = ::make_unique<xhtml_buffered_output_format> (*this,
- line_table);
+ auto format = std::make_unique<xhtml_buffered_output_format> (*this,
+ line_table);
m_format = format.get (); // borrowed
diagnostic_output_format_init_xhtml (*this, std::move (format));
}
@@ -974,9 +973,9 @@ plugin_init (struct plugin_name_args *plugin_info,
return 1;
global_dc->set_output_format
- (::make_unique<xhtml_stream_output_format> (*global_dc,
- line_table,
- stderr));
+ (std::make_unique<xhtml_stream_output_format> (*global_dc,
+ line_table,
+ stderr));
#if CHECKING_P
selftest::xhtml_format_selftests ();
diff --git a/gcc/testsuite/gcc.dg/pr119712.c b/gcc/testsuite/gcc.dg/pr119712.c
new file mode 100644
index 0000000..e845dd9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr119712.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+int a, b, c, d, e, f;
+int main() {
+ f--;
+ goto q;
+j:
+ if (-1642776935 * c + 7 >= 0)
+ goto l;
+m:
+ if (4 * a - c - 21 >= 0)
+ goto i;
+ return 0;
+i:
+ if (d)
+ goto l;
+q:
+ c = 4 * c - 3;
+ if (c - f)
+ goto m;
+ goto j;
+l:
+ e = b + 1958960196 * c - 1016458303;
+ if (20 * e + 1 >= 0)
+ return 0;
+ goto j;
+}
diff --git a/gcc/testsuite/gcc.dg/pr83072-2.c b/gcc/testsuite/gcc.dg/pr83072-2.c
index dff6b50..485e804 100644
--- a/gcc/testsuite/gcc.dg/pr83072-2.c
+++ b/gcc/testsuite/gcc.dg/pr83072-2.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-evrp-details" } */
+/* { dg-options "-O2 -fdump-tree-evrp-details -fno-tree-forwprop" } */
int f1(int a, int b, int c){
if(c==0)__builtin_unreachable();
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c
index 12ba475..ed8ee3a 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/phi-opt-value-5.c
@@ -31,9 +31,7 @@ int fdiv1(int a, int b)
return a != 0 ? c : 0;
}
-/* fdiv1 requires until later than phiopt2 to be able to detect that
- d is non-zero. to be able to remove the conditional. */
-/* { dg-final { scan-tree-dump-times "goto" 2 "phiopt2" } } */
+/* { dg-final { scan-tree-dump-not "goto" "phiopt2" } } */
/* { dg-final { scan-tree-dump-not "goto" "phiopt3" } } */
/* { dg-final { scan-tree-dump-not "goto" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr95801.c b/gcc/testsuite/gcc.dg/tree-ssa/pr95801.c
new file mode 100644
index 0000000..c3c80a0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr95801.c
@@ -0,0 +1,13 @@
+// { dg-do compile }
+// { dg-options "-O2 -fdump-tree-evrp" }
+
+int always1(int a, int b) {
+ if (a / b)
+ return b != 0;
+ return 1;
+}
+
+// If b != 0 is optimized by recognizing divide by 0 cannot happen,
+// there should be no PHI node.
+
+// { dg-final { scan-tree-dump-not "PHI" "evrp" } }
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-14.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-14.c
new file mode 100644
index 0000000..6fadff8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-14.c
@@ -0,0 +1,25 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-tailc-details" } */
+
+/* PR tree-optimization/67797 */
+
+void *my_func(void *s, int n)
+{
+ __builtin_memset(s, 0, n);
+ return s;
+}
+void *my_func1(void *d, void *s, int n)
+{
+ __builtin_memcpy(d, s, n);
+ return d;
+}
+void *my_func2(void *s, void *p1, int n)
+{
+ if (p1)
+ __builtin_memcpy(s, p1, n);
+ else
+ __builtin_memset(s, 0, n);
+ return s;
+}
+
+/* { dg-final { scan-tree-dump-times "Found tail call" 4 "tailc"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/tailcall-15.c b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-15.c
new file mode 100644
index 0000000..bf24fd8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/tailcall-15.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-tailc-details" } */
+
+/* PR tree-optimization/67797 */
+
+/* We should not get a tail call here since the
+ types don't match and we don't know how the argument
+ truncation will work. */
+
+unsigned char my_func(int n)
+{
+ __builtin_memset((void*)0, 0, n);
+ return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "Found tail call" "tailc"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp122.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp122.c
index 5a4ca85..def2b89 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp122.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp122.c
@@ -1,5 +1,5 @@
// { dg-do compile }
-// { dg-options "-O2 -fdump-tree-evrp-details" }
+// { dg-options "-O2 -fdump-tree-ccp1-details" }
void gg(void);
int f(unsigned t)
@@ -16,4 +16,4 @@ int f(unsigned t)
return 0;
}
-// { dg-final { scan-tree-dump "Global Exported: g_.* MASK 0x1 VALUE 0x0" "evrp" } }
+// { dg-final { scan-tree-dump "Global Exported: g_.*MASK.*0 VALUE 0x0" "ccp1" } }
diff --git a/gcc/testsuite/rust/compile/black_box.rs b/gcc/testsuite/rust/compile/black_box.rs
new file mode 100644
index 0000000..80615af
--- /dev/null
+++ b/gcc/testsuite/rust/compile/black_box.rs
@@ -0,0 +1,28 @@
+// { dg-options "-fdump-tree-gimple" }
+#![feature(rustc_attrs)]
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[rustc_builtin_macro]
+macro_rules! llvm_asm {
+ () => {};
+}
+
+pub fn black_box<T>(mut dummy: T) -> T {
+ unsafe {
+ // { dg-final { scan-tree-dump-times {memory} 1 gimple } }
+ llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
+ }
+
+ dummy
+}
+
+fn my_function(a: i32) -> i32 {
+ a
+}
+
+fn main() {
+ let dummy: i32 = 42;
+ let _ = black_box(my_function(dummy));
+}
diff --git a/gcc/testsuite/rust/compile/derive-debug1.rs b/gcc/testsuite/rust/compile/derive-debug1.rs
index 2596a37..cf2187d 100644
--- a/gcc/testsuite/rust/compile/derive-debug1.rs
+++ b/gcc/testsuite/rust/compile/derive-debug1.rs
@@ -15,7 +15,7 @@ mod core {
struct Formatter; // { dg-warning "is never constructed" }
struct Error; // { dg-warning "is never constructed" }
- type Result = core::result::Result<(), Error>;
+ type Result = crate::core::result::Result<(), Error>;
trait Debug {
fn fmt(&self, fmt: &mut Formatter) -> Result;
diff --git a/gcc/testsuite/rust/compile/generics9.rs b/gcc/testsuite/rust/compile/generics9.rs
index 3c787aa..56c6198 100644
--- a/gcc/testsuite/rust/compile/generics9.rs
+++ b/gcc/testsuite/rust/compile/generics9.rs
@@ -1,5 +1,6 @@
+// { dg-additional-options "-frust-name-resolution-2.0" }
struct Foo<A, B = (A, B)>(A, B);
-// { dg-error "could not resolve type path .B." "" { target *-*-* } .-1 }
+// { dg-error "type parameters with a default cannot use forward declared identifiers" "" { target *-*-* } .-1 }
fn main() {
let a: Foo<bool>;
diff --git a/gcc/testsuite/rust/compile/issue-3530-1.rs b/gcc/testsuite/rust/compile/issue-3530-1.rs
new file mode 100644
index 0000000..b38b5cd
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3530-1.rs
@@ -0,0 +1,2 @@
+#[repr(i32)]
+enum NightsWatch {} // { dg-error "unsupported representation for zero-variant enum" }
diff --git a/gcc/testsuite/rust/compile/issue-3530-2.rs b/gcc/testsuite/rust/compile/issue-3530-2.rs
new file mode 100644
index 0000000..7432730
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3530-2.rs
@@ -0,0 +1,2 @@
+#[repr(C)]
+enum NightsWatch {} // { dg-error "unsupported representation for zero-variant enum" }
diff --git a/gcc/testsuite/rust/compile/issue-3568.rs b/gcc/testsuite/rust/compile/issue-3568.rs
index 222a174..fef43b5 100644
--- a/gcc/testsuite/rust/compile/issue-3568.rs
+++ b/gcc/testsuite/rust/compile/issue-3568.rs
@@ -4,4 +4,4 @@ mod foo {
}
pub use foo::super::foo::S as T;
-// { dg-error ".super. can only be used in start position" "" { target *-*-* } .-1 }
+// { dg-error ".super. in paths can only be used in start position" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/rust/compile/issue-3581-1.rs b/gcc/testsuite/rust/compile/issue-3581-1.rs
new file mode 100644
index 0000000..eb2f5f0
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3581-1.rs
@@ -0,0 +1,12 @@
+enum Foo {
+ Bar,
+}
+
+struct Baz;
+
+fn main() {
+ Foo::Bar.a;
+ // { dg-error "no field .a. on type .Foo. .E0609." "" { target *-*-* } .-1 }
+ Baz.a;
+ // { dg-error "no field .a. on type .Baz. .E0609." "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/issue-3581-2.rs b/gcc/testsuite/rust/compile/issue-3581-2.rs
new file mode 100644
index 0000000..5059784
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3581-2.rs
@@ -0,0 +1,9 @@
+enum A {
+ X { inner: i32 },
+ Y,
+}
+
+pub fn test() {
+ let _ = A::Y.inner;
+ // { dg-error "no field .inner. on type .A. .E0609." "" { target *-*-* } .-1 }
+}
diff --git a/gcc/testsuite/rust/compile/issue-3612.rs b/gcc/testsuite/rust/compile/issue-3612.rs
new file mode 100644
index 0000000..5256d0a
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3612.rs
@@ -0,0 +1,7 @@
+trait _St1 {
+ pub const UNDERFLOW: *const u16 = unsafe { [0u16; 1].as_ptr().offset(isize::MIN) };
+ // { dg-error "no method named .as_ptr. found in the current scope .E0599." "" { target *-*-* } .-1 }
+ // { dg-error "failed to resolve receiver in MethodCallExpr" "" { target *-*-* } .-2 }
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/issue-3628.rs b/gcc/testsuite/rust/compile/issue-3628.rs
new file mode 100644
index 0000000..5f59789
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3628.rs
@@ -0,0 +1,10 @@
+pub enum Enum {
+ Variant1(isize),
+}
+
+impl Enum {
+ fn static_meth_enum() -> Enum {
+ Enum { x: 1 }
+ // { dg-error "expected a struct, variant or union type, found enum .Enum. .E0574." "" { target *-*-* } .-1 }
+ }
+}
diff --git a/gcc/testsuite/rust/compile/issue-3649.rs b/gcc/testsuite/rust/compile/issue-3649.rs
new file mode 100644
index 0000000..b85b193
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3649.rs
@@ -0,0 +1,2 @@
+struct T(Box<>);
+// { dg-error "could not resolve type path .Box. .E0412." "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/rust/compile/issue-3652.rs b/gcc/testsuite/rust/compile/issue-3652.rs
new file mode 100644
index 0000000..537ca9f
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3652.rs
@@ -0,0 +1,7 @@
+trait Foo {
+ type T;
+ fn foo() -> T<<Self as Foo>::T>;
+ // { dg-error "could not resolve type path .T. .E0412." "" { target *-*-* } .-1 }
+}
+
+fn foo() {}
diff --git a/gcc/testsuite/rust/compile/issue-3662.rs b/gcc/testsuite/rust/compile/issue-3662.rs
new file mode 100644
index 0000000..88baa2e
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3662.rs
@@ -0,0 +1,8 @@
+pub fn rlib() {
+ let _ = ((-1 as i8) << 8 - 1) as f32;
+ let _ = 0u8 as char;
+ let _ = true > false;
+ let _ = true >= false;
+ let _ = true < false;
+ let _ = true >= false;
+}
diff --git a/gcc/testsuite/rust/compile/issue-3664.rs b/gcc/testsuite/rust/compile/issue-3664.rs
new file mode 100644
index 0000000..c52a758
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3664.rs
@@ -0,0 +1,5 @@
+const ARR: [usize; 1] = [2];
+
+pub fn l8() {
+ let _ = 5 << ARR[0];
+}
diff --git a/gcc/testsuite/rust/compile/issue-3711.rs b/gcc/testsuite/rust/compile/issue-3711.rs
new file mode 100644
index 0000000..a3f9c39
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-3711.rs
@@ -0,0 +1,17 @@
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "fn_once"]
+pub trait FnOnce<Args> {
+ #[lang = "fn_once_output"]
+ type Output;
+
+ extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+fn returns_closure() -> _ {
+ // { dg-error "the type placeholder ._. is not allowed within types on item signatures .E0121." "" { target *-*-* } .-1 }
+ || 0
+}
+
+fn main() {}
diff --git a/gcc/testsuite/rust/compile/issue-402.rs b/gcc/testsuite/rust/compile/issue-402.rs
new file mode 100644
index 0000000..2c99fc8
--- /dev/null
+++ b/gcc/testsuite/rust/compile/issue-402.rs
@@ -0,0 +1,14 @@
+#[lang = "sized"]
+pub trait Sized {}
+
+struct GenericStruct<T>(T, usize);
+
+pub fn test() -> GenericStruct<_> {
+ // { dg-error "the type placeholder ._. is not allowed within types on item signatures .E0121." "" { target *-*-* } .-1 }
+ GenericStruct(1, 2)
+}
+
+fn square(num: i32) -> _ {
+ // { dg-error "the type placeholder ._. is not allowed within types on item signatures .E0121." "" { target *-*-* } .-1 }
+ num * num
+}
diff --git a/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs
index 637d572..eeae6eb 100644
--- a/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs
+++ b/gcc/testsuite/rust/compile/macros/mbe/macro-issue2983_2984.rs
@@ -18,10 +18,9 @@ fn main() {
// Error
let _ = ReadDir {
+ // { dg-error "unknown field .end_of_stream_but_different. .E0560." "" { target *-*-* } .-1 }
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" }
+ end_of_stream_but_different: false,
};
}
diff --git a/gcc/testsuite/rust/compile/multiple_bindings1.rs b/gcc/testsuite/rust/compile/multiple_bindings1.rs
index e73dc2a..8a2e18c 100644
--- a/gcc/testsuite/rust/compile/multiple_bindings1.rs
+++ b/gcc/testsuite/rust/compile/multiple_bindings1.rs
@@ -1,29 +1,38 @@
+#[lang = "sized"]
+pub trait Sized {}
+
+#[lang = "fn_once"]
+trait FnOnce<Args> {
+ type Output;
+
+ fn call_once(self, args: Args) -> Self::Output;
+}
+
fn f1(i: i32, i: i32) {}
// { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
trait Foo {
- fn f2(i: i32, i: i32) {}
- // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+ fn f2(i: i32, i: i32) {}
+ // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
}
trait Bar {
- fn f3(i: i32, j: i32) {}
+ fn f3(i: i32, j: i32) {}
}
struct S;
impl S {
- fn f4(i: i32, i: i32) {}
- // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+ fn f4(i: i32, i: i32) {}
+ // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
}
impl Bar for S {
- fn f3(i: i32, i: i32) {}
- // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+ fn f3(i: i32, i: i32) {}
+ // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
}
fn main() {
- let _ = |i, i| {};
- // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+ let _ = |i, i| {};
+ // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
}
-
diff --git a/gcc/testsuite/rust/compile/name_resolution9.rs b/gcc/testsuite/rust/compile/name_resolution9.rs
index 93adb46..792b3bd 100644
--- a/gcc/testsuite/rust/compile/name_resolution9.rs
+++ b/gcc/testsuite/rust/compile/name_resolution9.rs
@@ -6,11 +6,11 @@ pub mod foo {
super::super::super::foo!(); // { dg-error "too many leading .super. keywords" }
// { dg-error "could not resolve macro invocation" "" { target *-*-* } .-1 }
- super::crate::foo!(); // { dg-error "leading path segment .crate. can only be used" }
+ super::crate::foo!(); // { dg-error ".crate. in paths can only be used" }
// { dg-error "could not resolve macro invocation" "" { target *-*-* } .-1 }
- crate::foo::bar::super::foo!(); // { dg-error "leading path segment .super. can only be used" }
+ crate::foo::bar::super::foo!(); // { dg-error ".super. in paths can only be used" }
// { dg-error "could not resolve macro invocation" "" { target *-*-* } .-1 }
}
}
diff --git a/gcc/testsuite/rust/compile/nonexistent-field.rs b/gcc/testsuite/rust/compile/nonexistent-field.rs
index e20c49d..9bcfb2f 100644
--- a/gcc/testsuite/rust/compile/nonexistent-field.rs
+++ b/gcc/testsuite/rust/compile/nonexistent-field.rs
@@ -6,7 +6,7 @@ fn main() {
let s = StructWithFields { x: 0 };
s.foo;
- // { dg-error "no field .foo. on type .StructWithFields.StructWithFields .x.u32... .E0609." "" { target *-*-* } .-1 }
+ // { dg-error "no field .foo. on type .StructWithFields. .E0609." "" { target *-*-* } .-1 }
let numbers = (1, 2, 3);
numbers.3;
diff --git a/gcc/testsuite/rust/compile/nr2/exclude b/gcc/testsuite/rust/compile/nr2/exclude
index 4772517..c020e36 100644
--- a/gcc/testsuite/rust/compile/nr2/exclude
+++ b/gcc/testsuite/rust/compile/nr2/exclude
@@ -1,25 +1,17 @@
canonical_paths1.rs
-cfg1.rs
-generics9.rs
issue-3315-2.rs
-lookup_err1.rs
-multiple_bindings1.rs
-multiple_bindings2.rs
privacy5.rs
privacy8.rs
pub_restricted_1.rs
pub_restricted_2.rs
pub_restricted_3.rs
-use_1.rs
issue-2905-2.rs
-derive_clone_enum3.rs
-derive-debug1.rs
derive-default1.rs
derive-eq-invalid.rs
-derive-hash1.rs
torture/alt_patterns1.rs
torture/name_resolve1.rs
-issue-3568.rs
issue-3663.rs
issue-3671.rs
+issue-3652.rs
+issue-3649.rs
# please don't delete the trailing newline
diff --git a/gcc/testsuite/rust/compile/self-path2.rs b/gcc/testsuite/rust/compile/self-path2.rs
index 6441c33..d955ed0 100644
--- a/gcc/testsuite/rust/compile/self-path2.rs
+++ b/gcc/testsuite/rust/compile/self-path2.rs
@@ -11,11 +11,11 @@ fn baz() {
crate::bar();
crate::self::foo();
- // { dg-error "leading path segment .self. can only be used at the beginning of a path" "" { target *-*-* } .-1 }
+ // { dg-error ".self. in paths can only be used in start position" "" { target *-*-* } .-1 }
}
type a = foo;
type b = crate::foo;
type c = self::foo;
type d = crate::self::foo;
-// { dg-error "leading path segment .self. can only be used at the beginning of a path" "" { target *-*-* } .-1 }
+// { dg-error ".self. in paths can only be used in start position" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/rust/compile/struct_init1.rs b/gcc/testsuite/rust/compile/struct_init1.rs
index 1875fb4..38f6f38 100644
--- a/gcc/testsuite/rust/compile/struct_init1.rs
+++ b/gcc/testsuite/rust/compile/struct_init1.rs
@@ -4,7 +4,7 @@ struct Foo {
}
fn main() {
- let a = Foo { 0: 10.0, 1: 20.0 }; // { dg-error "failed to resolve type for field" }
- // { dg-error "unknown field" "" { target *-*-* } .-1 }
- // { dg-prune-output "compilation terminated" }
+ let a = Foo { 0: 10.0, 1: 20.0 };
+ // { dg-error "unknown field .0. .E0560." "" { target *-*-* } .-1 }
+ // { dg-error "unknown field .1. .E0560." "" { target *-*-* } .-2 }
}
diff --git a/gcc/testsuite/rust/compile/use_1.rs b/gcc/testsuite/rust/compile/use_1.rs
index 94b9632..e8e2037 100644
--- a/gcc/testsuite/rust/compile/use_1.rs
+++ b/gcc/testsuite/rust/compile/use_1.rs
@@ -1,7 +1,8 @@
+// { dg-additional-options "-frust-name-resolution-2.0" }
mod frob {}
-use foo::bar::baz; // { dg-error "cannot find simple path segment .foo." }
-use frob::ulator; // { dg-error "cannot find simple path segment .ulator." }
+use foo::bar::baz; // { dg-error "unresolved import .foo::bar::baz." }
+use frob::ulator; // { dg-error "unresolved import .frob::ulator." }
mod sain {
mod doux {}
@@ -9,8 +10,8 @@ mod sain {
mod dron {}
}
-use not_sain::*; // { dg-error "cannot find simple path segment .not_sain." }
+use not_sain::*; // { dg-error "unresolved import .not_sain." }
use sain::*;
use sain::{doux, dron};
-use sain::{doux, dron, graal}; // { dg-error "cannot find simple path segment .graal." }
+use sain::{doux, dron, graal}; // { dg-error "unresolved import .sain::graal." }
diff --git a/gcc/testsuite/rust/execute/black_box.rs b/gcc/testsuite/rust/execute/black_box.rs
new file mode 100644
index 0000000..7a9920e
--- /dev/null
+++ b/gcc/testsuite/rust/execute/black_box.rs
@@ -0,0 +1,30 @@
+/* { dg-output "Value is: 42\r*\n" } */
+#![feature(rustc_attrs)]
+
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+#[lang = "sized"]
+pub trait Sized {}
+
+#[rustc_builtin_macro]
+macro_rules! llvm_asm {
+ () => {};
+}
+
+pub fn black_box<T>(mut dummy: T) -> T {
+ unsafe {
+ llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile");
+ }
+
+ dummy
+}
+
+fn main() {
+ let dummy: i32 = 42;
+ let result = black_box(dummy);
+ unsafe {
+ printf("Value is: %i\n\0" as *const str as *const i8, result);
+ }
+}
diff --git a/gcc/text-art/style.cc b/gcc/text-art/style.cc
index 1793405..ffc75b6 100644
--- a/gcc/text-art/style.cc
+++ b/gcc/text-art/style.cc
@@ -23,7 +23,6 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
-#include "make-unique.h"
#include "pretty-print.h"
#include "intl.h"
#include "selftest.h"
diff --git a/gcc/text-art/styled-string.cc b/gcc/text-art/styled-string.cc
index e13278b..3b7145f 100644
--- a/gcc/text-art/styled-string.cc
+++ b/gcc/text-art/styled-string.cc
@@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
-#include "make-unique.h"
#include "pretty-print.h"
#include "intl.h"
#include "diagnostic.h"
diff --git a/gcc/text-art/table.cc b/gcc/text-art/table.cc
index 4b73bff..d3ddae0 100644
--- a/gcc/text-art/table.cc
+++ b/gcc/text-art/table.cc
@@ -22,7 +22,6 @@ along with GCC; see the file COPYING3. If not see
#define INCLUDE_VECTOR
#include "system.h"
#include "coretypes.h"
-#include "make-unique.h"
#include "pretty-print.h"
#include "diagnostic.h"
#include "selftest.h"
diff --git a/gcc/text-art/tree-widget.cc b/gcc/text-art/tree-widget.cc
index 597374f..33c918d 100644
--- a/gcc/text-art/tree-widget.cc
+++ b/gcc/text-art/tree-widget.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "pretty-print.h"
#include "selftest.h"
-#include "make-unique.h"
#include "text-art/selftests.h"
#include "text-art/tree-widget.h"
#include "text-art/dump-widget-info.h"
@@ -38,8 +37,8 @@ static const int margin_width = 3;
std::unique_ptr<tree_widget>
tree_widget::make (styled_string str, const theme &theme, style::id_t style_id)
{
- return ::make_unique <tree_widget>
- (::make_unique <text_widget> (std::move (str)),
+ return std::make_unique <tree_widget>
+ (std::make_unique <text_widget> (std::move (str)),
theme,
style_id);
}
diff --git a/gcc/text-art/widget.cc b/gcc/text-art/widget.cc
index d980b53..3c68018 100644
--- a/gcc/text-art/widget.cc
+++ b/gcc/text-art/widget.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "pretty-print.h"
#include "selftest.h"
-#include "make-unique.h"
#include "text-art/selftests.h"
#include "text-art/widget.h"
@@ -191,7 +190,7 @@ static void
test_wrapper_widget ()
{
style_manager sm;
- wrapper_widget w (::make_unique<test_widget> (canvas::size_t (3, 3), 'B'));
+ wrapper_widget w (std::make_unique<test_widget> (canvas::size_t (3, 3), 'B'));
canvas c (w.to_canvas (sm));
ASSERT_CANVAS_STREQ
(c, false,
@@ -207,7 +206,7 @@ test_vbox_1 ()
vbox_widget w;
for (int i = 0; i < 5; i++)
w.add_child
- (::make_unique <text_widget>
+ (std::make_unique <text_widget>
(styled_string::from_fmt (sm, nullptr,
"this is line %i", i)));
canvas c (w.to_canvas (sm));
@@ -225,9 +224,9 @@ test_vbox_2 ()
{
style_manager sm;
vbox_widget w;
- w.add_child (::make_unique<test_widget> (canvas::size_t (1, 3), 'A'));
- w.add_child (::make_unique<test_widget> (canvas::size_t (4, 1), 'B'));
- w.add_child (::make_unique<test_widget> (canvas::size_t (1, 2), 'C'));
+ w.add_child (std::make_unique<test_widget> (canvas::size_t (1, 3), 'A'));
+ w.add_child (std::make_unique<test_widget> (canvas::size_t (4, 1), 'B'));
+ w.add_child (std::make_unique<test_widget> (canvas::size_t (1, 2), 'C'));
canvas c (w.to_canvas (sm));
ASSERT_CANVAS_STREQ
(c, false,
diff --git a/gcc/timevar.cc b/gcc/timevar.cc
index 2e11be9..16ae5c8 100644
--- a/gcc/timevar.cc
+++ b/gcc/timevar.cc
@@ -24,7 +24,6 @@ along with GCC; see the file COPYING3. If not see
#include "timevar.h"
#include "options.h"
#include "json.h"
-#include "make-unique.h"
/* Non-NULL if timevars should be used. In GCC, this happens with
the -ftime-report flag. */
@@ -139,7 +138,7 @@ timer::named_items::print (FILE *fp, const timevar_time_def *total)
std::unique_ptr<json::value>
timer::named_items::make_json () const
{
- auto arr = ::make_unique<json::array> ();
+ auto arr = std::make_unique<json::array> ();
for (const char *item_name : m_names)
{
hash_map_t &mut_map = const_cast <hash_map_t &> (m_hash_map);
@@ -703,7 +702,7 @@ timer::print (FILE *fp)
std::unique_ptr<json::object>
make_json_for_timevar_time_def (const timevar_time_def &ttd)
{
- auto obj = ::make_unique<json::object> ();
+ auto obj = std::make_unique<json::object> ();
obj->set_float ("wall", nanosec_to_floating_sec (ttd.wall));
obj->set_integer ("ggc_mem", ttd.ggc_mem);
return obj;
@@ -717,7 +716,7 @@ make_json_for_timevar_time_def (const timevar_time_def &ttd)
std::unique_ptr<json::value>
timer::timevar_def::make_json () const
{
- auto timevar_obj = ::make_unique<json::object> ();
+ auto timevar_obj = std::make_unique<json::object> ();
timevar_obj->set_string ("name", name);
timevar_obj->set ("elapsed", make_json_for_timevar_time_def (elapsed));
@@ -732,14 +731,14 @@ timer::timevar_def::make_json () const
}
if (any_children_with_time)
{
- auto children_arr = ::make_unique<json::array> ();
+ auto children_arr = std::make_unique<json::array> ();
for (auto i : *children)
{
/* Don't emit timing variables if we're going to get a row of
zeroes. */
if (all_zero (i.second))
continue;
- auto child_obj = ::make_unique<json::object> ();
+ auto child_obj = std::make_unique<json::object> ();
child_obj->set_string ("name", i.first->name);
child_obj->set ("elapsed",
make_json_for_timevar_time_def (i.second));
@@ -759,7 +758,7 @@ std::unique_ptr<json::value>
timer::make_json () const
{
#if defined (HAVE_WALL_TIME)
- auto report_obj = ::make_unique<json::object> ();
+ auto report_obj = std::make_unique<json::object> ();
json::array *json_arr = new json::array ();
report_obj->set ("timevars", json_arr);
@@ -803,7 +802,7 @@ timer::make_json () const
get_time (&total_now);
timevar_diff (&total_elapsed, m_timevars[TV_TOTAL].start_time, total_now);
- auto total_obj = ::make_unique<json::object> ();
+ auto total_obj = std::make_unique<json::object> ();
total_obj->set_string ("name", "TOTAL");
total_obj->set ("elapsed", make_json_for_timevar_time_def (total_elapsed));
json_arr->append (std::move (total_obj));
diff --git a/gcc/toplev.cc b/gcc/toplev.cc
index 6d8b885..7e457b5 100644
--- a/gcc/toplev.cc
+++ b/gcc/toplev.cc
@@ -94,7 +94,6 @@ along with GCC; see the file COPYING3. If not see
#include "dbgcnt.h"
#include "gcc-urlifier.h"
#include "unique-argv.h"
-#include "make-unique.h"
#include "selftest.h"
@@ -1095,9 +1094,9 @@ general_init (const char *argv0, bool init_signals, unique_argv original_argv)
global_dc->m_internal_error = internal_error_function;
const unsigned lang_mask = lang_hooks.option_lang_mask ();
global_dc->set_option_manager
- (::make_unique<compiler_diagnostic_option_manager> (*global_dc,
- lang_mask,
- &global_options),
+ (std::make_unique<compiler_diagnostic_option_manager> (*global_dc,
+ lang_mask,
+ &global_options),
lang_mask);
global_dc->push_owned_urlifier (make_gcc_urlifier (lang_mask));
diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index ecf19d2..6a95b82 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -5104,6 +5104,19 @@ verify_gimple_cond (gcond *stmt)
return true;
}
+ tree lhs = gimple_cond_lhs (stmt);
+
+ /* GIMPLE_CONDs condition may not throw. */
+ if (flag_exceptions
+ && cfun->can_throw_non_call_exceptions
+ && operation_could_trap_p (gimple_cond_code (stmt),
+ FLOAT_TYPE_P (TREE_TYPE (lhs)),
+ false, NULL_TREE))
+ {
+ error ("gimple cond condition cannot throw");
+ return true;
+ }
+
return verify_gimple_comparison (boolean_type_node,
gimple_cond_lhs (stmt),
gimple_cond_rhs (stmt),
diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc
index 80717c1..11701f5 100644
--- a/gcc/tree-diagnostic-client-data-hooks.cc
+++ b/gcc/tree-diagnostic-client-data-hooks.cc
@@ -31,7 +31,6 @@ along with GCC; see the file COPYING3. If not see
#include "langhooks.h"
#include "plugin.h"
#include "timevar.h"
-#include "make-unique.h"
/* Concrete class for supplying a diagnostic_context with information
about a specific plugin within the client, when the client is the
@@ -169,5 +168,5 @@ private:
std::unique_ptr<diagnostic_client_data_hooks>
make_compiler_data_hooks ()
{
- return ::make_unique<compiler_data_hooks> ();
+ return std::make_unique<compiler_data_hooks> ();
}
diff --git a/gcc/tree-pretty-print.cc b/gcc/tree-pretty-print.cc
index c1a21e7..359359d 100644
--- a/gcc/tree-pretty-print.cc
+++ b/gcc/tree-pretty-print.cc
@@ -4795,10 +4795,10 @@ op_symbol_code (enum tree_code code, dump_flags_t flags)
return ">>";
case LROTATE_EXPR:
- return "r<<";
+ return (flags & TDF_GIMPLE) ? "__ROTATE_LEFT" : "r<<";
case RROTATE_EXPR:
- return "r>>";
+ return (flags & TDF_GIMPLE) ? "__ROTATE_RIGHT" : "r>>";
case WIDEN_LSHIFT_EXPR:
return "w<<";
diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc
index fc05928..10e88d9 100644
--- a/gcc/tree-tailcall.cc
+++ b/gcc/tree-tailcall.cc
@@ -1082,57 +1082,74 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail,
{
bool ok = false;
value_range val;
- tree valr;
- /* If IPA-VRP proves called function always returns a singleton range,
- the return value is replaced by the only value in that range.
- For tail call purposes, pretend such replacement didn't happen. */
if (ass_var == NULL_TREE && !tail_recursion)
- if (tree type = gimple_range_type (call))
- if (tree callee = gimple_call_fndecl (call))
- if ((INTEGRAL_TYPE_P (type)
- || SCALAR_FLOAT_TYPE_P (type)
- || POINTER_TYPE_P (type))
- && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (callee)),
- type)
- && useless_type_conversion_p (TREE_TYPE (ret_var), type)
- && ipa_return_value_range (val, callee)
- && val.singleton_p (&valr))
+ {
+ tree other_value = NULL_TREE;
+ /* If we have a function call that we know the return value is the same
+ as the argument, try the argument too. */
+ int flags = gimple_call_return_flags (call);
+ if ((flags & ERF_RETURNS_ARG) != 0
+ && (flags & ERF_RETURN_ARG_MASK) < gimple_call_num_args (call))
+ {
+ tree arg = gimple_call_arg (call, flags & ERF_RETURN_ARG_MASK);
+ if (useless_type_conversion_p (TREE_TYPE (ret_var), TREE_TYPE (arg) ))
+ other_value = arg;
+ }
+ /* If IPA-VRP proves called function always returns a singleton range,
+ the return value is replaced by the only value in that range.
+ For tail call purposes, pretend such replacement didn't happen. */
+ else if (tree type = gimple_range_type (call))
+ if (tree callee = gimple_call_fndecl (call))
{
- tree rv = ret_var;
- unsigned int i = edges.length ();
- /* If ret_var is equal to valr, we can tail optimize. */
- if (operand_equal_p (ret_var, valr, 0))
- ok = true;
- else
- /* Otherwise, if ret_var is a PHI result, try to find out
- if valr isn't propagated through PHIs on the path from
- call's bb to SSA_NAME_DEF_STMT (ret_var)'s bb. */
- while (TREE_CODE (rv) == SSA_NAME
- && gimple_code (SSA_NAME_DEF_STMT (rv)) == GIMPLE_PHI)
- {
- tree nrv = NULL_TREE;
- gimple *g = SSA_NAME_DEF_STMT (rv);
- for (; i; --i)
- {
- if (edges[i - 1]->dest == gimple_bb (g))
- {
- nrv
- = gimple_phi_arg_def_from_edge (g,
+ tree valr;
+ if ((INTEGRAL_TYPE_P (type)
+ || SCALAR_FLOAT_TYPE_P (type)
+ || POINTER_TYPE_P (type))
+ && useless_type_conversion_p (TREE_TYPE (TREE_TYPE (callee)),
+ type)
+ && useless_type_conversion_p (TREE_TYPE (ret_var), type)
+ && ipa_return_value_range (val, callee)
+ && val.singleton_p (&valr))
+ other_value = valr;
+ }
+
+ if (other_value)
+ {
+ tree rv = ret_var;
+ unsigned int i = edges.length ();
+ /* If ret_var is equal to other_value, we can tail optimize. */
+ if (operand_equal_p (ret_var, other_value, 0))
+ ok = true;
+ else
+ /* Otherwise, if ret_var is a PHI result, try to find out
+ if other_value isn't propagated through PHIs on the path from
+ call's bb to SSA_NAME_DEF_STMT (ret_var)'s bb. */
+ while (TREE_CODE (rv) == SSA_NAME
+ && gimple_code (SSA_NAME_DEF_STMT (rv)) == GIMPLE_PHI)
+ {
+ tree nrv = NULL_TREE;
+ gimple *g = SSA_NAME_DEF_STMT (rv);
+ for (; i; --i)
+ {
+ if (edges[i - 1]->dest == gimple_bb (g))
+ {
+ nrv = gimple_phi_arg_def_from_edge (g,
edges[i - 1]);
- --i;
- break;
- }
- }
- if (nrv == NULL_TREE)
+ --i;
+ break;
+ }
+ }
+ if (nrv == NULL_TREE)
+ break;
+ if (operand_equal_p (nrv, other_value, 0))
+ {
+ ok = true;
break;
- if (operand_equal_p (nrv, valr, 0))
- {
- ok = true;
- break;
- }
+ }
rv = nrv;
- }
- }
+ }
+ }
+ }
if (!ok)
{
maybe_error_musttail (call, _("call and return value are different"),
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 5136674..a770b41 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -2251,37 +2251,9 @@ irange::invert ()
verify_range ();
}
-// Remove trailing ranges that this bitmask indicates can't exist.
-
-void
-irange_bitmask::adjust_range (irange &r) const
-{
- if (unknown_p () || r.undefined_p ())
- return;
-
- int_range_max range;
- tree type = r.type ();
- int prec = TYPE_PRECISION (type);
- // If there are trailing zeros, create a range representing those bits.
- gcc_checking_assert (m_mask != 0);
- int z = wi::ctz (m_mask);
- if (z)
- {
- wide_int ub = (wi::one (prec) << z) - 1;
- range = int_range<5> (type, wi::zero (prec), ub);
- // Then remove the specific value these bits contain from the range.
- wide_int value = m_value & ub;
- range.intersect (int_range<2> (type, value, value, VR_ANTI_RANGE));
- // Inverting produces a list of ranges which can be valid.
- range.invert ();
- // And finally select R from only those valid values.
- r.intersect (range);
- return;
- }
-}
-
-// If the mask can be trivially converted to a range, do so and
-// return TRUE.
+// If the mask can be trivially converted to a range, do so.
+// Otherwise attempt to remove the lower bits from the range.
+// Return true if the range changed in any way.
bool
irange::set_range_from_bitmask ()
@@ -2326,7 +2298,28 @@ irange::set_range_from_bitmask ()
set_zero (type ());
return true;
}
- return false;
+
+ // If the mask doesn't have any trailing zero, return.
+ int z = wi::ctz (m_bitmask.mask ());
+ if (!z)
+ return false;
+
+ // Remove trailing ranges that this bitmask indicates can't exist.
+ int_range_max mask_range;
+ int prec = TYPE_PRECISION (type ());
+ wide_int ub = (wi::one (prec) << z) - 1;
+ mask_range = int_range<2> (type (), wi::zero (prec), ub);
+
+ // Then remove the specific value these bits contain from the range.
+ wide_int value = m_bitmask.value () & ub;
+ mask_range.intersect (int_range<2> (type (), value, value, VR_ANTI_RANGE));
+
+ // Inverting produces a list of ranges which can be valid.
+ mask_range.invert ();
+
+ // And finally select R from only those valid values.
+ intersect (mask_range);
+ return true;
}
void
@@ -2334,6 +2327,10 @@ irange::update_bitmask (const irange_bitmask &bm)
{
gcc_checking_assert (!undefined_p ());
+ // If masks are the same, there is no change.
+ if (m_bitmask == bm)
+ return;
+
// Drop VARYINGs with known bits to a plain range.
if (m_kind == VR_VARYING && !bm.unknown_p ())
m_kind = VR_RANGE;
@@ -2408,7 +2405,7 @@ irange::intersect_bitmask (const irange &r)
{
gcc_checking_assert (!undefined_p () && !r.undefined_p ());
- if (m_bitmask == r.m_bitmask)
+ if (r.m_bitmask.unknown_p () || m_bitmask == r.m_bitmask)
return false;
irange_bitmask bm = get_bitmask ();
@@ -2427,7 +2424,6 @@ irange::intersect_bitmask (const irange &r)
if (!set_range_from_bitmask ())
normalize_kind ();
- m_bitmask.adjust_range (*this);
if (flag_checking)
verify_range ();
return true;
diff --git a/gcc/value-range.h b/gcc/value-range.h
index b50cb89..f694298 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -149,7 +149,6 @@ public:
void dump (FILE *) const;
bool member_p (const wide_int &val) const;
- void adjust_range (irange &r) const;
// Convenience functions for nonzero bitmask compatibility.
wide_int get_nonzero_bits () const;
diff --git a/gcc/value-relation.cc b/gcc/value-relation.cc
index 08449b7..c7ced44 100644
--- a/gcc/value-relation.cc
+++ b/gcc/value-relation.cc
@@ -780,15 +780,20 @@ equiv_oracle::dump (FILE *f) const
// --------------------------------------------------------------------------
-// Negate the current relation.
+
+// Adjust the relation by Swapping the operands and relation.
void
-value_relation::negate ()
+value_relation::swap ()
{
- related = relation_negate (related);
+ related = relation_swap (related);
+ tree tmp = name1;
+ name1 = name2;
+ name2 = tmp;
}
// Perform an intersection between 2 relations. *this &&= p.
+// Return false if the relations cannot be intersected.
bool
value_relation::intersect (value_relation &p)
@@ -951,6 +956,79 @@ public:
relation_chain *m_next;
};
+// Given relation record PTR in block BB, return the next relation in the
+// list. If PTR is NULL, retreive the first relation in BB.
+// If NAME is sprecified, return only relations which include NAME.
+// Return NULL when there are no relations left.
+
+relation_chain *
+dom_oracle::next_relation (basic_block bb, relation_chain *ptr,
+ tree name) const
+{
+ relation_chain *p;
+ // No value_relation pointer is used to intialize the iterator.
+ if (!ptr)
+ {
+ int bbi = bb->index;
+ if (bbi >= (int)m_relations.length())
+ return NULL;
+ else
+ p = m_relations[bbi].m_head;
+ }
+ else
+ p = ptr->m_next;
+
+ if (name)
+ for ( ; p; p = p->m_next)
+ if (p->op1 () == name || p->op2 () == name)
+ break;
+ return p;
+}
+
+// Instatiate a block relation iterator to iterate over the relations
+// on exit from block BB in ORACLE. Limit this to relations involving NAME
+// if specified. Return the first such relation in VR if there is one.
+
+block_relation_iterator::block_relation_iterator (const relation_oracle *oracle,
+ basic_block bb,
+ value_relation &vr,
+ tree name)
+{
+ m_oracle = oracle;
+ m_bb = bb;
+ m_name = name;
+ m_ptr = oracle->next_relation (bb, NULL, m_name);
+ if (m_ptr)
+ {
+ m_done = false;
+ vr = *m_ptr;
+ }
+ else
+ m_done = true;
+}
+
+// Retreive the next relation from the iterator and return it in VR.
+
+void
+block_relation_iterator::get_next_relation (value_relation &vr)
+{
+ m_ptr = m_oracle->next_relation (m_bb, m_ptr, m_name);
+ if (m_ptr)
+ {
+ vr = *m_ptr;
+ if (m_name)
+ {
+ if (vr.op1 () != m_name)
+ {
+ gcc_checking_assert (vr.op2 () == m_name);
+ vr.swap ();
+ }
+ }
+ }
+ else
+ m_done = true;
+}
+
// ------------------------------------------------------------------------
// Find the relation between any ssa_name in B1 and any name in B2 in LIST.
@@ -1441,11 +1519,11 @@ dom_oracle::dump (FILE *f, basic_block bb) const
if (!m_relations[bb->index].m_names)
return;
- relation_chain *ptr = m_relations[bb->index].m_head;
- for (; ptr; ptr = ptr->m_next)
+ value_relation vr;
+ FOR_EACH_RELATION_BB (this, bb, vr)
{
fprintf (f, "Relational : ");
- ptr->dump (f);
+ vr.dump (f);
fprintf (f, "\n");
}
}
diff --git a/gcc/value-relation.h b/gcc/value-relation.h
index 23cfb41..1081877 100644
--- a/gcc/value-relation.h
+++ b/gcc/value-relation.h
@@ -114,6 +114,11 @@ public:
void debug () const;
protected:
friend class equiv_relation_iterator;
+ friend class block_relation_iterator;
+ virtual class relation_chain *next_relation (basic_block,
+ relation_chain *,
+ tree) const
+ { return NULL; }
// Return equivalency set for an SSA name in a basic block.
virtual const_bitmap equiv_set (tree, basic_block) { return NULL; }
// Return partial equivalency record for an SSA name.
@@ -228,7 +233,9 @@ public:
void dump (FILE *f, basic_block bb) const final override;
void dump (FILE *f) const final override;
-private:
+protected:
+ virtual relation_chain *next_relation (basic_block, relation_chain *,
+ tree) const;
bool m_do_trans_p;
bitmap m_tmp, m_tmp2;
bitmap m_relation_set; // Index by ssa-name. True if a relation exists
@@ -431,7 +438,7 @@ public:
relation_trio create_trio (tree lhs, tree op1, tree op2);
bool union_ (value_relation &p);
bool intersect (value_relation &p);
- void negate ();
+ void swap ();
bool apply_transitive (const value_relation &rel);
void dump (FILE *f) const;
@@ -470,6 +477,30 @@ value_relation::value_relation (relation_kind kind, tree n1, tree n2)
set_relation (kind, n1, n2);
}
+
+class block_relation_iterator {
+public:
+ block_relation_iterator (const relation_oracle *oracle, basic_block bb,
+ value_relation &, tree name = NULL);
+ void get_next_relation (value_relation &vr);
+ const relation_oracle *m_oracle;
+ basic_block m_bb;
+ relation_chain *m_ptr;
+ bool m_done;
+ tree m_name;
+};
+
+#define FOR_EACH_RELATION_BB(oracle, bb, vr) \
+ for (block_relation_iterator iter (oracle, bb, vr); \
+ !iter.m_done; \
+ iter.get_next_relation (vr))
+
+#define FOR_EACH_RELATION_NAME(oracle, bb, name, vr) \
+ for (block_relation_iterator iter (oracle, bb, vr, name); \
+ !iter.m_done; \
+ iter.get_next_relation (vr))
+
+
// Return the number of bits associated with partial equivalency T.
// Return 0 if this is not a supported partial equivalency relation.