aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-07-18 09:50:59 +0200
committerMartin Liska <mliska@suse.cz>2022-07-18 09:50:59 +0200
commit85df616e13a6a176883e39362c764a2dfa3448e8 (patch)
treef8a689c7075c69fce355abdbe5bc97b0d10bb144
parentc29d4ad6d7f4ca1ebfd9489bb62178ea09ae6c6b (diff)
parent2907bfc3412dd8aef6c6acc17f2152a4e0ac4979 (diff)
downloadgcc-85df616e13a6a176883e39362c764a2dfa3448e8.zip
gcc-85df616e13a6a176883e39362c764a2dfa3448e8.tar.gz
gcc-85df616e13a6a176883e39362c764a2dfa3448e8.tar.bz2
Merge branch 'master' into devel/sphinx
-rw-r--r--ChangeLog4
-rw-r--r--MAINTAINERS1
-rw-r--r--gcc/ChangeLog168
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in1
-rw-r--r--gcc/analyzer/ChangeLog34
-rw-r--r--gcc/analyzer/call-info.cc2
-rw-r--r--gcc/analyzer/checker-path.cc46
-rw-r--r--gcc/analyzer/diagnostic-manager.cc20
-rw-r--r--gcc/analyzer/engine.cc2
-rw-r--r--gcc/analyzer/program-state.cc2
-rw-r--r--gcc/analyzer/region-model-impl-calls.cc4
-rw-r--r--gcc/analyzer/region.cc2
-rw-r--r--gcc/analyzer/sm-malloc.cc10
-rw-r--r--gcc/analyzer/sm-taint.cc42
-rw-r--r--gcc/analyzer/store.cc6
-rw-r--r--gcc/analyzer/supergraph.cc4
-rw-r--r--gcc/analyzer/svalue.cc2
-rw-r--r--gcc/c-family/ChangeLog14
-rw-r--r--gcc/c-family/c-common.cc4
-rw-r--r--gcc/c-family/c-common.h2
-rw-r--r--gcc/c-family/c-format.cc4
-rw-r--r--gcc/config/aarch64/aarch64-builtins.cc9
-rw-r--r--gcc/config/aarch64/aarch64-modes.def1
-rw-r--r--gcc/config/aarch64/aarch64-simd-builtin-types.def6
-rw-r--r--gcc/config/aarch64/aarch64-simd.md14
-rw-r--r--gcc/config/aarch64/aarch64.cc6
-rw-r--r--gcc/config/aarch64/iterators.md14
-rw-r--r--gcc/config/i386/i386-builtin.def32
-rw-r--r--gcc/config/i386/i386-expand.cc140
-rw-r--r--gcc/config/i386/i386-features.cc34
-rw-r--r--gcc/config/i386/i386.cc10
-rw-r--r--gcc/config/i386/i386.md66
-rw-r--r--gcc/config/i386/predicates.md4
-rw-r--r--gcc/config/i386/sse.md36
-rw-r--r--gcc/config/xtensa/xtensa.cc58
-rw-r--r--gcc/config/xtensa/xtensa.md73
-rw-r--r--gcc/cp/ChangeLog25
-rw-r--r--gcc/cp/call.cc20
-rw-r--r--gcc/cp/constraint.cc8
-rw-r--r--gcc/cp/cp-tree.h8
-rw-r--r--gcc/cp/cxx-pretty-print.cc6
-rw-r--r--gcc/cp/method.cc25
-rw-r--r--gcc/cp/parser.cc36
-rw-r--r--gcc/cp/semantics.cc8
-rw-r--r--gcc/diagnostic-format-json.cc4
-rw-r--r--gcc/diagnostic-format-sarif.cc2
-rw-r--r--gcc/diagnostic-show-locus.cc7
-rw-r--r--gcc/doc/invoke.texi10
-rw-r--r--gcc/fortran/ChangeLog13
-rw-r--r--gcc/fortran/decl.cc15
-rw-r--r--gcc/fortran/trans-decl.cc2
-rw-r--r--gcc/gimple-pretty-print.cc32
-rw-r--r--gcc/gimplify.cc29
-rw-r--r--gcc/go/ChangeLog10
-rw-r--r--gcc/go/go-gcc.cc20
-rw-r--r--gcc/jit/ChangeLog7
-rw-r--r--gcc/jit/jit-recording.h8
-rw-r--r--gcc/pretty-print.h7
-rw-r--r--gcc/testsuite/ChangeLog78
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-1.c28
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-10.c10
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-2.c30
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-3.c28
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-4.c28
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-5.c26
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-6.c27
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-7.c27
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-8.c27
-rw-r--r--gcc/testsuite/c-c++-common/pr103798-9.c10
-rw-r--r--gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C214
-rw-r--r--gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C214
-rw-r--r--gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c56
-rw-r--r--gcc/testsuite/gcc.dg/pr106278.c22
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-vcomisd-pr106113-2.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-vcomiss-pr106113-2.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-vucomisd-pr106113-2.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-vucomiss-pr106113-2.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106231-1.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106231-2.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/pr106273.c27
-rw-r--r--gcc/testsuite/gcc.target/i386/pr85620-2.c3
-rw-r--r--gcc/testsuite/gcc.target/i386/pr85620-5.c13
-rw-r--r--gcc/testsuite/gcc.target/i386/pr85620-6.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/pr85620-7.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-1.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-2.c59
-rw-r--r--gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-1.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-2.c59
-rw-r--r--gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-1.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-2.c59
-rw-r--r--gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-1.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-2.c59
-rw-r--r--gcc/testsuite/gfortran.dg/pr104313.f11
-rw-r--r--gcc/testsuite/gfortran.dg/pr106209.f909
-rw-r--r--gcc/testsuite/gnat.dg/opt98.adb14
-rw-r--r--gcc/testsuite/gnat.dg/opt98.ads19
-rw-r--r--gcc/tree-diagnostic-path.cc16
-rw-r--r--gcc/tree-ssa-forwprop.cc72
-rw-r--r--gcc/tree-ssa-strlen.cc4
-rw-r--r--gcc/tree-ssa-strlen.h2
-rw-r--r--gcc/value-range-pretty-print.cc111
-rw-r--r--gcc/value-range-pretty-print.h37
-rw-r--r--gcc/value-range.cc125
-rw-r--r--gcc/value-range.h19
-rw-r--r--libcpp/ChangeLog7
-rw-r--r--libcpp/include/line-map.h25
-rw-r--r--libiberty/ChangeLog4
-rw-r--r--libstdc++-v3/ChangeLog17
-rw-r--r--libstdc++-v3/include/std/type_traits39
-rw-r--r--libstdc++-v3/include/std/version5
-rw-r--r--libstdc++-v3/testsuite/20_util/reference_from_temporary/value.cc110
-rw-r--r--libstdc++-v3/testsuite/20_util/reference_from_temporary/value2.cc28
-rw-r--r--libstdc++-v3/testsuite/20_util/reference_from_temporary/version.cc27
-rw-r--r--libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc14
-rw-r--r--lto-plugin/ChangeLog8
-rw-r--r--lto-plugin/Makefile.am3
-rw-r--r--lto-plugin/Makefile.in4
-rwxr-xr-xlto-plugin/configure10
-rw-r--r--lto-plugin/configure.ac5
120 files changed, 2739 insertions, 443 deletions
diff --git a/ChangeLog b/ChangeLog
index 2c32b64..171f490 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2022-07-15 Andrew Carlotti <andrew.carlotti@arm.com>
+
+ * MAINTAINERS: Add myself to Write After Approval.
+
2022-07-04 Martin Liska <mliska@suse.cz>
* MAINTAINERS: fix sorting of names
diff --git a/MAINTAINERS b/MAINTAINERS
index 7d9aab7..7a7ad42 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -352,6 +352,7 @@ Kevin Buettner <kevinb@redhat.com>
Andrew Burgess <aburgess@redhat.com>
Adam Butcher <adam@jessamine.co.uk>
Andrew Cagney <cagney@gnu.org>
+Andrew Carlotti <andrew.carlotti@arm.com>
Daniel Carrera <dcarrera@gmail.com>
Stephane Carrez <stcarrez@nerim.fr>
Gabriel Charette <gchare@google.com>
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b759cf4..994875f 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,171 @@
+2022-07-16 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * config/xtensa/xtensa.md
+ (*masktrue_const_pow2_minus_one, *masktrue_const_negative_pow2,
+ *masktrue_const_shifted_mask): If the immediate for bitwise AND is
+ represented as '-(1 << N)', decrease the lower bound of N from 12
+ to 1. And the other immediate for conditional branch is now no
+ longer limited to zero, but also one of some positive integers.
+ Finally, remove the checks of some conditions, because the comparison
+ expressions that don't satisfy such checks are determined as
+ compile-time constants and thus will be optimized away before
+ RTL expansion.
+
+2022-07-16 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * config/xtensa/xtensa.cc (xtensa_emit_constantsynth): Remove.
+ (xtensa_constantsynth_2insn): Change to try all three synthetic
+ methods and to use the one that fits the immediate value of
+ the seed into a Narrow Move Immediate instruction "MOVI.N"
+ when the Code Density Option is configured.
+
+2022-07-15 H.J. Lu <hjl.tools@gmail.com>
+
+ PR target/85620
+ * config/i386/i386.cc (ix86_function_ok_for_sibcall): Return
+ false if callee has indirect_return attribute and caller
+ doesn't.
+
+2022-07-15 Roger Sayle <roger@nextmovesoftware.com>
+
+ PR target/106273
+ * config/i386/i386.md (*andn<dwi>3_doubleword_bmi): Update the
+ constraints to reflect the output is earlyclobber, unless it is
+ the same register (pair) as one of the operands.
+
+2022-07-15 David Malcolm <dmalcolm@redhat.com>
+
+ * doc/invoke.texi (Static Analyzer Options): Add the new fd
+ warnings to the initial gccoptlist, and to the list of those
+ disabled by -fanalyzer-checker=taint.
+
+2022-07-15 Andrew Carlotti <andrew.carlotti@arm.com>
+
+ * config/aarch64/aarch64-builtins.cc
+ (enum aarch64_type_qualifiers): Remove qualifier_internal.
+ (aarch64_init_simd_builtin_functions): Remove qualifier_internal check.
+
+2022-07-15 Andrew Carlotti <andrew.carlotti@arm.com>
+
+ * config/aarch64/aarch64-builtins.cc
+ (v1di_UP): Add V1DI mode to _UP macros.
+ * config/aarch64/aarch64-modes.def (VECTOR_MODE): Add V1DI mode.
+ * config/aarch64/aarch64-simd-builtin-types.def: Use V1DI mode.
+ * config/aarch64/aarch64-simd.md
+ (vec_extractv2dfv1df): Replace with...
+ (vec_extract<mode><V1half>): ...this.
+ * config/aarch64/aarch64.cc
+ (aarch64_classify_vector_mode): Add V1DI mode.
+ * config/aarch64/iterators.md
+ (VQ_2E, V1HALF, V1half): New.
+ (nunits): Add V1DI mode.
+
+2022-07-15 Roger Sayle <roger@nextmovesoftware.com>
+
+ PR target/106278
+ * config/i386/i386-features.cc (general_scalar_chain::convert_insn):
+ Fix indentation whitespace.
+ (timode_scalar_chain::fix_debug_reg_uses): Likewise.
+ (timode_scalar_chain::convert_insn): Delete dead code.
+ Update TImode REG_EQUAL_NOTE even if the SET_DEST is already V1TI.
+ Fix indentation whitespace.
+ (convertible_comparison_p): Likewise.
+ (timode_scalar_to_vector_candidate_p): Likewise.
+
+2022-07-15 Aldy Hernandez <aldyh@redhat.com>
+
+ * gimple-pretty-print.cc (dump_ssaname_info): Use pp_vrange.
+
+2022-07-15 Aldy Hernandez <aldyh@redhat.com>
+
+ * Makefile.in (OBJS): Add value-range-pretty-print.o.
+ * pretty-print.h (pp_vrange): New.
+ * value-range.cc (vrange::dump): Call pp version.
+ (unsupported_range::dump): Move to its own file.
+ (dump_bound_with_infinite_markers): Same.
+ (irange::dump): Same.
+ (irange::dump_bitmasks): Same.
+ (vrange::debug): Remove.
+ * value-range.h: Remove virtual designation for dump methods.
+ Remove dump_bitmasks method.
+ * value-range-pretty-print.cc: New file.
+ * value-range-pretty-print.h: New file.
+
+2022-07-15 Aldy Hernandez <aldyh@redhat.com>
+
+ * value-range.cc (irange::accept): New.
+ (unsupported_range::accept): New.
+ * value-range.h (class vrange_visitor): New.
+ (class vrange): Add accept method.
+ (class unsupported_range): Same.
+ (class Value_Range): Same.
+
+2022-07-15 Jonathan Wakely <jwakely@redhat.com>
+
+ * diagnostic-format-json.cc (json_from_location_range): Adjust
+ to new label_text API.
+ * diagnostic-format-sarif.cc (sarif_builder::make_location_object):
+ Likewise.
+ * diagnostic-show-locus.cc (struct pod_label_text): Likewise.
+ (layout::print_any_labels): Likewise.
+ * tree-diagnostic-path.cc (class path_label): Likewise.
+ (struct event_range): Likewise.
+ (default_tree_diagnostic_path_printer): Likewise.
+ (default_tree_make_json_for_path): Likewise.
+
+2022-07-15 konglin1 <lingling.kong@intel.com>
+
+ PR target/106113
+ * config/i386/i386-builtin.def (BDESC): Fix [u]comi{ss,sd}
+ comparison due to intrinsics changed over time.
+ * config/i386/i386-expand.cc (ix86_ssecom_setcc):
+ Add unordered check and mode for sse comi codegen.
+ (ix86_expand_sse_comi): Add unordered check and check a different
+ CCmode.
+ (ix86_expand_sse_comi_round):Extract unordered check and mode part
+ in ix86_ssecom_setcc.
+
+2022-07-15 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ * config/aarch64/aarch64.cc (aarch64_vectorize_vec_perm_const): Use
+ op_mode instead of vmode in calls to force_reg for op0 and op1.
+
+2022-07-14 H.J. Lu <hjl.tools@gmail.com>
+
+ PR tree-optimization/103798
+ * tree-ssa-forwprop.cc: Include "tree-ssa-strlen.h".
+ (simplify_builtin_call): Inline memchr with constant strings of
+ no more than the bytes of a word.
+ * tree-ssa-strlen.cc (use_in_zero_equality): Make it global.
+ * tree-ssa-strlen.h (use_in_zero_equality): New.
+
+2022-07-14 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gimplify.cc (lookup_tmp_var): Add NOT_GIMPLE_REG boolean parameter
+ and set DECL_NOT_GIMPLE_REG_P on the variable according to it.
+ (internal_get_tmp_var): Add NOT_GIMPLE_REG boolean parameter and
+ pass it in the call to lookup_tmp_var.
+ (get_formal_tmp_var): Pass false in the call to lookup_tmp_var.
+ (get_initialized_tmp_var): Likewise.
+ (prepare_gimple_addressable): Call internal_get_tmp_var instead of
+ get_initialized_tmp_var with NOT_GIMPLE_REG set to true.
+
+2022-07-14 Martin Liska <mliska@suse.cz>
+
+ * doc/gimple.texi: Close properly a deftypefn.
+
+2022-07-14 Martin Liska <mliska@suse.cz>
+
+ * doc/gimple.texi: Close properly a deftypefn.
+
+2022-07-14 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * config/xtensa/xtensa.md:
+ In FP constant synthesis split pattern, subcontract to
+ avoid_constant_pool_reference() as in the case of integer,
+ because it can handle well too. And cast to int32_t before
+ calling xtensa_constantsynth() in order to ignore upper 32-bit.
+
2022-07-13 Aldy Hernandez <aldyh@redhat.com>
* range-op.cc (operator_lt::fold_range): Use nonzero bits.
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index 56754ca..2ac5479 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20220714
+20220718
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 3ae2370..001506f 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1711,6 +1711,7 @@ OBJS = \
value-query.o \
value-range.o \
value-range-equiv.o \
+ value-range-pretty-print.o \
value-range-storage.o \
value-relation.o \
value-prof.o \
diff --git a/gcc/analyzer/ChangeLog b/gcc/analyzer/ChangeLog
index 06d8454..4f010eb 100644
--- a/gcc/analyzer/ChangeLog
+++ b/gcc/analyzer/ChangeLog
@@ -1,3 +1,37 @@
+2022-07-15 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106284
+ * sm-taint.cc (taint_state_machine::on_condition): Handle range
+ checks optimized by build_range_check.
+
+2022-07-15 Jonathan Wakely <jwakely@redhat.com>
+
+ * call-info.cc (call_info::print): Adjust to new label_text API.
+ * checker-path.cc (checker_event::dump): Likewise.
+ (region_creation_event::get_desc): Likewise.
+ (state_change_event::get_desc): Likewise.
+ (superedge_event::should_filter_p): Likewise.
+ (start_cfg_edge_event::get_desc): Likewise.
+ (call_event::get_desc): Likewise.
+ (return_event::get_desc): Likewise.
+ (warning_event::get_desc): Likewise.
+ (checker_path::dump): Likewise.
+ (checker_path::debug): Likewise.
+ * diagnostic-manager.cc (diagnostic_manager::prune_for_sm_diagnostic):
+ Likewise.
+ (diagnostic_manager::prune_interproc_events): Likewise.
+ * engine.cc (feasibility_state::maybe_update_for_edge):
+ Likewise.
+ * program-state.cc (sm_state_map::to_json): Likewise.
+ * region-model-impl-calls.cc (region_model::impl_call_analyzer_describe): Likewise.
+ (region_model::impl_call_analyzer_dump_capacity): Likewise.
+ * region.cc (region::to_json): Likewise.
+ * sm-malloc.cc (inform_nonnull_attribute): Likewise.
+ * store.cc (binding_map::to_json): Likewise.
+ (store::to_json): Likewise.
+ * supergraph.cc (superedge::dump): Likewise.
+ * svalue.cc (svalue::to_json): Likewise.
+
2022-07-07 David Malcolm <dmalcolm@redhat.com>
* checker-path.cc (start_cfg_edge_event::get_desc): Update for
diff --git a/gcc/analyzer/call-info.cc b/gcc/analyzer/call-info.cc
index e1142d7..efc070b 100644
--- a/gcc/analyzer/call-info.cc
+++ b/gcc/analyzer/call-info.cc
@@ -75,7 +75,7 @@ void
call_info::print (pretty_printer *pp) const
{
label_text desc (get_desc (pp_show_color (pp)));
- pp_string (pp, desc.m_buffer);
+ pp_string (pp, desc.get ());
}
/* Implementation of custom_edge_info::add_events_to_path vfunc for
diff --git a/gcc/analyzer/checker-path.cc b/gcc/analyzer/checker-path.cc
index 211cf3e..273f40d 100644
--- a/gcc/analyzer/checker-path.cc
+++ b/gcc/analyzer/checker-path.cc
@@ -195,7 +195,7 @@ checker_event::dump (pretty_printer *pp) const
{
label_text event_desc (get_desc (false));
pp_printf (pp, "\"%s\" (depth %i",
- event_desc.m_buffer, m_effective_depth);
+ event_desc.get (), m_effective_depth);
if (m_effective_depth != m_original_depth)
pp_printf (pp, " corrected from %i",
@@ -307,7 +307,7 @@ region_creation_event::get_desc (bool can_colorize) const
label_text custom_desc
= m_pending_diagnostic->describe_region_creation_event
(evdesc::region_creation (can_colorize, m_reg));
- if (custom_desc.m_buffer)
+ if (custom_desc.get ())
return custom_desc;
}
@@ -390,7 +390,7 @@ state_change_event::get_desc (bool can_colorize) const
= m_pending_diagnostic->describe_state_change
(evdesc::state_change (can_colorize, var, origin,
m_from, m_to, m_emission_id, *this));
- if (custom_desc.m_buffer)
+ if (custom_desc.get ())
{
if (flag_analyzer_verbose_state_changes)
{
@@ -404,7 +404,7 @@ state_change_event::get_desc (bool can_colorize) const
return make_label_text
(can_colorize,
"%s (state of %qE: %qs -> %qs, origin: %qE, meaning: %s)",
- custom_desc.m_buffer,
+ custom_desc.get (),
var,
m_from->get_name (),
m_to->get_name (),
@@ -414,7 +414,7 @@ state_change_event::get_desc (bool can_colorize) const
return make_label_text
(can_colorize,
"%s (state of %qE: %qs -> %qs, NULL origin, meaning: %s)",
- custom_desc.m_buffer,
+ custom_desc.get (),
var,
m_from->get_name (),
m_to->get_name (),
@@ -435,16 +435,16 @@ state_change_event::get_desc (bool can_colorize) const
return make_label_text
(can_colorize,
"state of %qs: %qs -> %qs (origin: %qs)",
- sval_desc.m_buffer,
+ sval_desc.get (),
m_from->get_name (),
m_to->get_name (),
- origin_desc.m_buffer);
+ origin_desc.get ());
}
else
return make_label_text
(can_colorize,
"state of %qs: %qs -> %qs (NULL origin)",
- sval_desc.m_buffer,
+ sval_desc.get (),
m_from->get_name (),
m_to->get_name ());
}
@@ -509,8 +509,8 @@ superedge_event::should_filter_p (int verbosity) const
/* Filter events with empty descriptions. This ought to filter
FALLTHRU, but retain true/false/switch edges. */
label_text desc = get_desc (false);
- gcc_assert (desc.m_buffer);
- if (desc.m_buffer[0] == '\0')
+ gcc_assert (desc.get ());
+ if (desc.get ()[0] == '\0')
return true;
}
}
@@ -597,28 +597,28 @@ start_cfg_edge_event::get_desc (bool can_colorize) const
label_text edge_desc (m_sedge->get_description (user_facing));
if (user_facing)
{
- if (edge_desc.m_buffer && strlen (edge_desc.m_buffer) > 0)
+ if (edge_desc.get () && strlen (edge_desc.get ()) > 0)
{
label_text cond_desc = maybe_describe_condition (can_colorize);
label_text result;
- if (cond_desc.m_buffer)
+ if (cond_desc.get ())
return make_label_text (can_colorize,
"following %qs branch (%s)...",
- edge_desc.m_buffer, cond_desc.m_buffer);
+ edge_desc.get (), cond_desc.get ());
else
return make_label_text (can_colorize,
"following %qs branch...",
- edge_desc.m_buffer);
+ edge_desc.get ());
}
else
return label_text::borrow ("");
}
else
{
- if (strlen (edge_desc.m_buffer) > 0)
+ if (strlen (edge_desc.get ()) > 0)
return make_label_text (can_colorize,
"taking %qs edge SN:%i -> SN:%i",
- edge_desc.m_buffer,
+ edge_desc.get (),
m_sedge->m_src->m_index,
m_sedge->m_dest->m_index);
else
@@ -798,7 +798,7 @@ call_event::get_desc (bool can_colorize) const
m_dest_snode->m_fun->decl,
var,
m_critical_state));
- if (custom_desc.m_buffer)
+ if (custom_desc.get ())
return custom_desc;
}
@@ -878,7 +878,7 @@ return_event::get_desc (bool can_colorize) const
m_dest_snode->m_fun->decl,
m_src_snode->m_fun->decl,
m_critical_state));
- if (custom_desc.m_buffer)
+ if (custom_desc.get ())
return custom_desc;
}
return make_label_text (can_colorize,
@@ -1105,19 +1105,19 @@ warning_event::get_desc (bool can_colorize) const
label_text ev_desc
= m_pending_diagnostic->describe_final_event
(evdesc::final_event (can_colorize, var, m_state));
- if (ev_desc.m_buffer)
+ if (ev_desc.get ())
{
if (m_sm && flag_analyzer_verbose_state_changes)
{
if (var)
return make_label_text (can_colorize,
"%s (%qE is in state %qs)",
- ev_desc.m_buffer,
+ ev_desc.get (),
var, m_state->get_name ());
else
return make_label_text (can_colorize,
"%s (in global state %qs)",
- ev_desc.m_buffer,
+ ev_desc.get (),
m_state->get_name ());
}
else
@@ -1163,7 +1163,7 @@ checker_path::dump (pretty_printer *pp) const
if (i > 0)
pp_string (pp, ", ");
label_text event_desc (e->get_desc (false));
- pp_printf (pp, "\"%s\"", event_desc.m_buffer);
+ pp_printf (pp, "\"%s\"", event_desc.get ());
}
pp_character (pp, ']');
}
@@ -1203,7 +1203,7 @@ checker_path::debug () const
"[%i]: %s \"%s\"\n",
i,
event_kind_to_string (m_events[i]->m_kind),
- event_desc.m_buffer);
+ event_desc.get ());
}
}
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 083f66b..fded828 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -2297,7 +2297,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
label_text sval_desc = sval->get_desc ();
log ("considering event %i (%s), with sval: %qs, state: %qs",
idx, event_kind_to_string (base_event->m_kind),
- sval_desc.m_buffer, state->get_name ());
+ sval_desc.get (), state->get_name ());
}
else
log ("considering event %i (%s), with global state: %qs",
@@ -2363,8 +2363,8 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
= state_change->m_origin->get_desc ();
log ("event %i:"
" switching var of interest from %qs to %qs",
- idx, sval_desc.m_buffer,
- origin_sval_desc.m_buffer);
+ idx, sval_desc.get (),
+ origin_sval_desc.get ());
}
sval = state_change->m_origin;
}
@@ -2386,12 +2386,12 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
label_text sval_desc = sval->get_desc ();
log ("filtering event %i:"
" state change to %qs unrelated to %qs",
- idx, change_sval_desc.m_buffer,
- sval_desc.m_buffer);
+ idx, change_sval_desc.get (),
+ sval_desc.get ());
}
else
log ("filtering event %i: state change to %qs",
- idx, change_sval_desc.m_buffer);
+ idx, change_sval_desc.get ());
}
else
log ("filtering event %i: global state change", idx);
@@ -2460,7 +2460,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
log ("event %i:"
" recording critical state for %qs at call"
" from %qE in callee to %qE in caller",
- idx, sval_desc.m_buffer, callee_var, caller_var);
+ idx, sval_desc.get (), callee_var, caller_var);
}
if (expr.param_p ())
event->record_critical_state (caller_var, state);
@@ -2503,7 +2503,7 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
log ("event %i:"
" recording critical state for %qs at return"
" from %qE in caller to %qE in callee",
- idx, sval_desc.m_buffer, callee_var, callee_var);
+ idx, sval_desc.get (), callee_var, callee_var);
}
if (expr.return_value_p ())
event->record_critical_state (callee_var, state);
@@ -2586,7 +2586,7 @@ diagnostic_manager::prune_interproc_events (checker_path *path) const
(path->get_checker_event (idx)->get_desc (false));
log ("filtering events %i-%i:"
" irrelevant call/entry/return: %s",
- idx, idx + 2, desc.m_buffer);
+ idx, idx + 2, desc.get ());
}
path->delete_event (idx + 2);
path->delete_event (idx + 1);
@@ -2608,7 +2608,7 @@ diagnostic_manager::prune_interproc_events (checker_path *path) const
(path->get_checker_event (idx)->get_desc (false));
log ("filtering events %i-%i:"
" irrelevant call/return: %s",
- idx, idx + 1, desc.m_buffer);
+ idx, idx + 1, desc.get ());
}
path->delete_event (idx + 1);
path->delete_event (idx);
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 888123f..9ffcc41 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -4590,7 +4590,7 @@ feasibility_state::maybe_update_for_edge (logger *logger,
logger->log (" sedge: SN:%i -> SN:%i %s",
sedge->m_src->m_index,
sedge->m_dest->m_index,
- desc.m_buffer);
+ desc.get ());
}
const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 90a56e3..f0f4046 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -300,7 +300,7 @@ sm_state_map::to_json () const
entry_t e = (*iter).second;
label_text sval_desc = sval->get_desc ();
- map_obj->set (sval_desc.m_buffer, e.m_state->to_json ());
+ map_obj->set (sval_desc.get (), e.m_state->to_json ());
/* This doesn't yet JSONify e.m_origin. */
}
diff --git a/gcc/analyzer/region-model-impl-calls.cc b/gcc/analyzer/region-model-impl-calls.cc
index 55d6fa7..8c38e92 100644
--- a/gcc/analyzer/region-model-impl-calls.cc
+++ b/gcc/analyzer/region-model-impl-calls.cc
@@ -255,7 +255,7 @@ region_model::impl_call_analyzer_describe (const gcall *call,
const svalue *sval = get_rvalue (t_val, ctxt);
bool simple = zerop (t_verbosity);
label_text desc = sval->get_desc (simple);
- warning_at (call->location, 0, "svalue: %qs", desc.m_buffer);
+ warning_at (call->location, 0, "svalue: %qs", desc.get ());
}
/* Handle a call to "__analyzer_dump_capacity".
@@ -274,7 +274,7 @@ region_model::impl_call_analyzer_dump_capacity (const gcall *call,
const region *base_reg = reg->get_base_region ();
const svalue *capacity = get_capacity (base_reg);
label_text desc = capacity->get_desc (true);
- warning_at (call->location, 0, "capacity: %qs", desc.m_buffer);
+ warning_at (call->location, 0, "capacity: %qs", desc.get ());
}
/* Compare D1 and D2 using their names, and then IDs to order them. */
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 5b00e6a..a8d1ae9 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -589,7 +589,7 @@ json::value *
region::to_json () const
{
label_text desc = get_desc (true);
- json::value *reg_js = new json::string (desc.m_buffer);
+ json::value *reg_js = new json::string (desc.get ());
return reg_js;
}
diff --git a/gcc/analyzer/sm-malloc.cc b/gcc/analyzer/sm-malloc.cc
index 553fcd8..608aceb 100644
--- a/gcc/analyzer/sm-malloc.cc
+++ b/gcc/analyzer/sm-malloc.cc
@@ -1007,7 +1007,7 @@ inform_nonnull_attribute (tree fndecl, int arg_idx)
label_text arg_desc = describe_argument_index (fndecl, arg_idx);
inform (DECL_SOURCE_LOCATION (fndecl),
"argument %s of %qD must be non-null",
- arg_desc.m_buffer, fndecl);
+ arg_desc.get (), fndecl);
/* Ideally we would use the location of the parm and underline the
attribute also - but we don't have the location_t values at this point
in the middle-end.
@@ -1065,12 +1065,12 @@ public:
if (m_origin_of_unchecked_event.known_p ())
result = ev.formatted_print ("argument %s (%qE) from %@ could be NULL"
" where non-null expected",
- arg_desc.m_buffer, ev.m_expr,
+ arg_desc.get (), ev.m_expr,
&m_origin_of_unchecked_event);
else
result = ev.formatted_print ("argument %s (%qE) could be NULL"
" where non-null expected",
- arg_desc.m_buffer, ev.m_expr);
+ arg_desc.get (), ev.m_expr);
return result;
}
@@ -1173,11 +1173,11 @@ public:
label_text result;
if (zerop (ev.m_expr))
result = ev.formatted_print ("argument %s NULL where non-null expected",
- arg_desc.m_buffer);
+ arg_desc.get ());
else
result = ev.formatted_print ("argument %s (%qE) NULL"
" where non-null expected",
- arg_desc.m_buffer, ev.m_expr);
+ arg_desc.get (), ev.m_expr);
return result;
}
diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
index 4075cf6..2de9284 100644
--- a/gcc/analyzer/sm-taint.cc
+++ b/gcc/analyzer/sm-taint.cc
@@ -848,6 +848,48 @@ taint_state_machine::on_condition (sm_context *sm_ctxt,
case LE_EXPR:
case LT_EXPR:
{
+ /* Detect where build_range_check has optimized
+ (c>=low) && (c<=high)
+ into
+ (c-low>=0) && (c-low<=high-low)
+ and thus into:
+ (unsigned)(c - low) <= (unsigned)(high-low). */
+ if (const binop_svalue *binop_sval
+ = lhs->dyn_cast_binop_svalue ())
+ {
+ const svalue *inner_lhs = binop_sval->get_arg0 ();
+ enum tree_code inner_op = binop_sval->get_op ();
+ const svalue *inner_rhs = binop_sval->get_arg1 ();
+ if (const svalue *before_cast = inner_lhs->maybe_undo_cast ())
+ inner_lhs = before_cast;
+ if (tree outer_rhs_cst = rhs->maybe_get_constant ())
+ if (tree inner_rhs_cst = inner_rhs->maybe_get_constant ())
+ if (inner_op == PLUS_EXPR
+ && TREE_CODE (inner_rhs_cst) == INTEGER_CST
+ && TREE_CODE (outer_rhs_cst) == INTEGER_CST
+ && TYPE_UNSIGNED (TREE_TYPE (inner_rhs_cst))
+ && TYPE_UNSIGNED (TREE_TYPE (outer_rhs_cst)))
+ {
+ /* We have
+ (unsigned)(INNER_LHS + CST_A) </<= UNSIGNED_CST_B
+ and thus an optimized test of INNER_LHS (before any
+ cast to unsigned) against a range.
+ Transition any of the tainted states to the stop state.
+ We have to special-case this here rather than in
+ region_model::on_condition since we can't apply
+ both conditions simultaneously (we'd have a transition
+ from the old state to has_lb, then a transition from
+ the old state *again* to has_ub). */
+ state_t old_state
+ = sm_ctxt->get_state (stmt, inner_lhs);
+ if (old_state == m_tainted
+ || old_state == m_has_lb
+ || old_state == m_has_ub)
+ sm_ctxt->set_next_state (stmt, inner_lhs, m_stop);
+ return;
+ }
+ }
+
sm_ctxt->on_transition (node, stmt, lhs, m_tainted,
m_has_ub);
sm_ctxt->on_transition (node, stmt, lhs, m_has_lb,
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index d558d47..06151d8 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -675,7 +675,7 @@ binding_map::to_json () const
{
const svalue *value = *const_cast <map_t &> (m_map).get (key);
label_text key_desc = key->get_desc ();
- map_obj->set (key_desc.m_buffer, value->to_json ());
+ map_obj->set (key_desc.get (), value->to_json ());
}
return map_obj;
@@ -2402,11 +2402,11 @@ store::to_json () const
binding_cluster *cluster
= *const_cast<cluster_map_t &> (m_cluster_map).get (base_reg);
label_text base_reg_desc = base_reg->get_desc ();
- clusters_in_parent_reg_obj->set (base_reg_desc.m_buffer,
+ clusters_in_parent_reg_obj->set (base_reg_desc.get (),
cluster->to_json ());
}
label_text parent_reg_desc = parent_reg->get_desc ();
- store_obj->set (parent_reg_desc.m_buffer, clusters_in_parent_reg_obj);
+ store_obj->set (parent_reg_desc.get (), clusters_in_parent_reg_obj);
}
store_obj->set ("called_unknown_fn", new json::literal (m_called_unknown_fn));
diff --git a/gcc/analyzer/supergraph.cc b/gcc/analyzer/supergraph.cc
index 52b48524..01e30f7 100644
--- a/gcc/analyzer/supergraph.cc
+++ b/gcc/analyzer/supergraph.cc
@@ -855,10 +855,10 @@ superedge::dump (pretty_printer *pp) const
{
pp_printf (pp, "edge: SN: %i -> SN: %i", m_src->m_index, m_dest->m_index);
label_text desc (get_description (false));
- if (strlen (desc.m_buffer) > 0)
+ if (strlen (desc.get ()) > 0)
{
pp_space (pp);
- pp_string (pp, desc.m_buffer);
+ pp_string (pp, desc.get ());
}
}
diff --git a/gcc/analyzer/svalue.cc b/gcc/analyzer/svalue.cc
index 78a6eef..f5a5f1c 100644
--- a/gcc/analyzer/svalue.cc
+++ b/gcc/analyzer/svalue.cc
@@ -96,7 +96,7 @@ json::value *
svalue::to_json () const
{
label_text desc = get_desc (true);
- json::value *sval_js = new json::string (desc.m_buffer);
+ json::value *sval_js = new json::string (desc.get ());
return sval_js;
}
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index d46eb18..ade553f 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,17 @@
+2022-07-15 Marek Polacek <polacek@redhat.com>
+
+ PR c++/104477
+ * c-common.cc (c_common_reswords): Add
+ __reference_constructs_from_temporary and
+ __reference_converts_from_temporary.
+ * c-common.h (enum rid): Add RID_REF_CONSTRUCTS_FROM_TEMPORARY and
+ RID_REF_CONVERTS_FROM_TEMPORARY.
+
+2022-07-15 Jonathan Wakely <jwakely@redhat.com>
+
+ * c-format.cc (class range_label_for_format_type_mismatch):
+ Adjust to new label_text API.
+
2022-07-11 Lewis Hyatt <lhyatt@gmail.com>
PR preprocessor/106252
diff --git a/gcc/c-family/c-common.cc b/gcc/c-family/c-common.cc
index 1b8e73f..655c3ae 100644
--- a/gcc/c-family/c-common.cc
+++ b/gcc/c-family/c-common.cc
@@ -537,6 +537,10 @@ const struct c_common_resword c_common_reswords[] =
{ "__is_constructible", RID_IS_CONSTRUCTIBLE, D_CXXONLY },
{ "__is_nothrow_assignable", RID_IS_NOTHROW_ASSIGNABLE, D_CXXONLY },
{ "__is_nothrow_constructible", RID_IS_NOTHROW_CONSTRUCTIBLE, D_CXXONLY },
+ { "__reference_constructs_from_temporary", RID_REF_CONSTRUCTS_FROM_TEMPORARY,
+ D_CXXONLY },
+ { "__reference_converts_from_temporary", RID_REF_CONVERTS_FROM_TEMPORARY,
+ D_CXXONLY },
/* C++ transactional memory. */
{ "synchronized", RID_SYNCHRONIZED, D_CXX_OBJC | D_TRANSMEM },
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index c090084..f906439 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -184,6 +184,8 @@ enum rid
RID_IS_UNION, RID_UNDERLYING_TYPE,
RID_IS_ASSIGNABLE, RID_IS_CONSTRUCTIBLE,
RID_IS_NOTHROW_ASSIGNABLE, RID_IS_NOTHROW_CONSTRUCTIBLE,
+ RID_REF_CONSTRUCTS_FROM_TEMPORARY,
+ RID_REF_CONVERTS_FROM_TEMPORARY,
/* C++11 */
RID_CONSTEXPR, RID_DECLTYPE, RID_NOEXCEPT, RID_NULLPTR, RID_STATIC_ASSERT,
diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc
index 2faed0c..68b94da 100644
--- a/gcc/c-family/c-format.cc
+++ b/gcc/c-family/c-format.cc
@@ -4617,14 +4617,14 @@ class range_label_for_format_type_mismatch
label_text get_text (unsigned range_idx) const final override
{
label_text text = range_label_for_type_mismatch::get_text (range_idx);
- if (text.m_buffer == NULL)
+ if (text.get () == NULL)
return text;
indirection_suffix suffix (m_pointer_count);
char *p = (char *) alloca (suffix.get_buffer_size ());
suffix.fill_buffer (p);
- char *result = concat (text.m_buffer, p, NULL);
+ char *result = concat (text.get (), p, NULL);
return label_text::take (result);
}
diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
index 4621c6d..69f1e4e 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -55,6 +55,7 @@
#define v2si_UP E_V2SImode
#define v2sf_UP E_V2SFmode
#define v1df_UP E_V1DFmode
+#define v1di_UP E_V1DImode
#define di_UP E_DImode
#define df_UP E_DFmode
#define v16qi_UP E_V16QImode
@@ -144,9 +145,7 @@ enum aarch64_type_qualifiers
qualifier_maybe_immediate = 0x10, /* 1 << 4 */
/* void foo (...). */
qualifier_void = 0x20, /* 1 << 5 */
- /* Some patterns may have internal operands, this qualifier is an
- instruction to the initialisation code to skip this operand. */
- qualifier_internal = 0x40, /* 1 << 6 */
+ /* 1 << 6 is now unused */
/* Some builtins should use the T_*mode* encoded in a simd_builtin_datum
rather than using the type of the operand. */
qualifier_map_mode = 0x80, /* 1 << 7 */
@@ -1206,10 +1205,6 @@ aarch64_init_simd_builtin_functions (bool called_from_pragma)
else
type_signature[op_num] = 's';
- /* Skip an internal operand for vget_{low, high}. */
- if (qualifiers & qualifier_internal)
- continue;
-
/* Some builtins have different user-facing types
for certain arguments, encoded in d->mode. */
if (qualifiers & qualifier_map_mode)
diff --git a/gcc/config/aarch64/aarch64-modes.def b/gcc/config/aarch64/aarch64-modes.def
index 8f39922..d3c9b74 100644
--- a/gcc/config/aarch64/aarch64-modes.def
+++ b/gcc/config/aarch64/aarch64-modes.def
@@ -70,6 +70,7 @@ VECTOR_MODES (INT, 8); /* V8QI V4HI V2SI. */
VECTOR_MODES (INT, 16); /* V16QI V8HI V4SI V2DI. */
VECTOR_MODES (FLOAT, 8); /* V2SF. */
VECTOR_MODES (FLOAT, 16); /* V4SF V2DF. */
+VECTOR_MODE (INT, DI, 1); /* V1DI. */
VECTOR_MODE (FLOAT, DF, 1); /* V1DF. */
VECTOR_MODE (FLOAT, HF, 2); /* V2HF. */
diff --git a/gcc/config/aarch64/aarch64-simd-builtin-types.def b/gcc/config/aarch64/aarch64-simd-builtin-types.def
index 248e51e..4054558 100644
--- a/gcc/config/aarch64/aarch64-simd-builtin-types.def
+++ b/gcc/config/aarch64/aarch64-simd-builtin-types.def
@@ -24,7 +24,7 @@
ENTRY (Int16x8_t, V8HI, none, 11)
ENTRY (Int32x2_t, V2SI, none, 11)
ENTRY (Int32x4_t, V4SI, none, 11)
- ENTRY (Int64x1_t, DI, none, 11)
+ ENTRY (Int64x1_t, V1DI, none, 11)
ENTRY (Int64x2_t, V2DI, none, 11)
ENTRY (Uint8x8_t, V8QI, unsigned, 11)
ENTRY (Uint8x16_t, V16QI, unsigned, 12)
@@ -32,7 +32,7 @@
ENTRY (Uint16x8_t, V8HI, unsigned, 12)
ENTRY (Uint32x2_t, V2SI, unsigned, 12)
ENTRY (Uint32x4_t, V4SI, unsigned, 12)
- ENTRY (Uint64x1_t, DI, unsigned, 12)
+ ENTRY (Uint64x1_t, V1DI, unsigned, 12)
ENTRY (Uint64x2_t, V2DI, unsigned, 12)
ENTRY (Poly8_t, QI, poly, 9)
ENTRY (Poly16_t, HI, poly, 10)
@@ -42,7 +42,7 @@
ENTRY (Poly8x16_t, V16QI, poly, 12)
ENTRY (Poly16x4_t, V4HI, poly, 12)
ENTRY (Poly16x8_t, V8HI, poly, 12)
- ENTRY (Poly64x1_t, DI, poly, 12)
+ ENTRY (Poly64x1_t, V1DI, poly, 12)
ENTRY (Poly64x2_t, V2DI, poly, 12)
ENTRY (Float16x4_t, V4HF, none, 13)
ENTRY (Float16x8_t, V8HF, none, 13)
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index a00e1c6..587a45d 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -8026,16 +8026,16 @@
})
;; Extract a single-element 64-bit vector from one half of a 128-bit vector.
-(define_expand "vec_extractv2dfv1df"
- [(match_operand:V1DF 0 "register_operand")
- (match_operand:V2DF 1 "register_operand")
+(define_expand "vec_extract<mode><V1half>"
+ [(match_operand:<V1HALF> 0 "register_operand")
+ (match_operand:VQ_2E 1 "register_operand")
(match_operand 2 "immediate_operand")]
"TARGET_SIMD"
{
- /* V1DF is rarely used by other patterns, so it should be better to hide
- it in a subreg destination of a normal DF op. */
- rtx scalar0 = gen_lowpart (DFmode, operands[0]);
- emit_insn (gen_vec_extractv2dfdf (scalar0, operands[1], operands[2]));
+ /* V1DI and V1DF are rarely used by other patterns, so it should be better
+ to hide it in a subreg destination of a normal DI or DF op. */
+ rtx scalar0 = gen_lowpart (<VHALF>mode, operands[0]);
+ emit_insn (gen_vec_extract<mode><Vhalf> (scalar0, operands[1], operands[2]));
DONE;
})
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 25f4cbb..1a514c1 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -3552,7 +3552,7 @@ aarch64_classify_vector_mode (machine_mode mode)
case E_V8QImode:
case E_V4HImode:
case E_V2SImode:
- /* ...E_V1DImode doesn't exist. */
+ case E_V1DImode:
case E_V4HFmode:
case E_V4BFmode:
case E_V2SFmode:
@@ -24129,11 +24129,11 @@ aarch64_vectorize_vec_perm_const (machine_mode vmode, machine_mode op_mode,
d.op_mode = op_mode;
d.op_vec_flags = aarch64_classify_vector_mode (d.op_mode);
d.target = target;
- d.op0 = op0 ? force_reg (vmode, op0) : NULL_RTX;
+ d.op0 = op0 ? force_reg (op_mode, op0) : NULL_RTX;
if (op0 == op1)
d.op1 = d.op0;
else
- d.op1 = op1 ? force_reg (vmode, op1) : NULL_RTX;
+ d.op1 = op1 ? force_reg (op_mode, op1) : NULL_RTX;
d.testing_p = !target;
if (!d.testing_p)
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 1be6a91..0dd9dc6 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -135,6 +135,9 @@
;; VQ without 2 element modes.
(define_mode_iterator VQ_NO2E [V16QI V8HI V4SI V8HF V4SF V8BF])
+;; 2 element quad vector modes.
+(define_mode_iterator VQ_2E [V2DI V2DF])
+
;; BFmode vector modes.
(define_mode_iterator VBF [V4BF V8BF])
@@ -1067,12 +1070,13 @@
(define_mode_attr nunits [(V8QI "8") (V16QI "16")
(V4HI "4") (V8HI "8")
(V2SI "2") (V4SI "4")
- (V2DI "2") (V8DI "8")
+ (V1DI "1") (V2DI "2")
(V4HF "4") (V8HF "8")
(V4BF "4") (V8BF "8")
(V2SF "2") (V4SF "4")
(V1DF "1") (V2DF "2")
- (DI "1") (DF "1")])
+ (DI "1") (DF "1")
+ (V8DI "8")])
;; Map a mode to the number of bits in it, if the size of the mode
;; is constant.
@@ -1442,6 +1446,12 @@
(V2DI "di") (V2SF "sf")
(V4SF "v2sf") (V2DF "df")])
+;; Single-element half modes of quad vector modes.
+(define_mode_attr V1HALF [(V2DI "V1DI") (V2DF "V1DF")])
+
+;; Single-element half modes of quad vector modes, in lower-case
+(define_mode_attr V1half [(V2DI "v1di") (V2DF "v1df")])
+
;; Double modes of vector modes.
(define_mode_attr VDBL [(V8QI "V16QI") (V4HI "V8HI")
(V4HF "V8HF") (V4BF "V8BF")
diff --git a/gcc/config/i386/i386-builtin.def b/gcc/config/i386/i386-builtin.def
index fd16093..acb7e8c 100644
--- a/gcc/config/i386/i386-builtin.def
+++ b/gcc/config/i386/i386-builtin.def
@@ -35,30 +35,30 @@
IX86_BUILTIN__BDESC_##NEXT_KIND##_FIRST - 1. */
BDESC_FIRST (comi, COMI,
- OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comieq", IX86_BUILTIN_COMIEQSS, UNEQ, 0)
-BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comilt", IX86_BUILTIN_COMILTSS, UNLT, 0)
-BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comile", IX86_BUILTIN_COMILESS, UNLE, 0)
+ OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comieq", IX86_BUILTIN_COMIEQSS, EQ, 0)
+BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comilt", IX86_BUILTIN_COMILTSS, LT, 0)
+BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comile", IX86_BUILTIN_COMILESS, LE, 0)
BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comigt", IX86_BUILTIN_COMIGTSS, GT, 0)
BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comige", IX86_BUILTIN_COMIGESS, GE, 0)
-BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comineq", IX86_BUILTIN_COMINEQSS, LTGT, 0)
-BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomieq", IX86_BUILTIN_UCOMIEQSS, UNEQ, 0)
-BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomilt", IX86_BUILTIN_UCOMILTSS, UNLT, 0)
-BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomile", IX86_BUILTIN_UCOMILESS, UNLE, 0)
+BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_comi, "__builtin_ia32_comineq", IX86_BUILTIN_COMINEQSS, NE, 0)
+BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomieq", IX86_BUILTIN_UCOMIEQSS, EQ, 0)
+BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomilt", IX86_BUILTIN_UCOMILTSS, LT, 0)
+BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomile", IX86_BUILTIN_UCOMILESS, LE, 0)
BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomigt", IX86_BUILTIN_UCOMIGTSS, GT, 0)
BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomige", IX86_BUILTIN_UCOMIGESS, GE, 0)
-BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomineq", IX86_BUILTIN_UCOMINEQSS, LTGT, 0)
-BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdeq", IX86_BUILTIN_COMIEQSD, UNEQ, 0)
-BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdlt", IX86_BUILTIN_COMILTSD, UNLT, 0)
-BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdle", IX86_BUILTIN_COMILESD, UNLE, 0)
+BDESC (OPTION_MASK_ISA_SSE, 0, CODE_FOR_sse_ucomi, "__builtin_ia32_ucomineq", IX86_BUILTIN_UCOMINEQSS, NE, 0)
+BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdeq", IX86_BUILTIN_COMIEQSD, EQ, 0)
+BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdlt", IX86_BUILTIN_COMILTSD, LT, 0)
+BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdle", IX86_BUILTIN_COMILESD, LE, 0)
BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdgt", IX86_BUILTIN_COMIGTSD, GT, 0)
BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdge", IX86_BUILTIN_COMIGESD, GE, 0)
-BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdneq", IX86_BUILTIN_COMINEQSD, LTGT, 0)
-BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdeq", IX86_BUILTIN_UCOMIEQSD, UNEQ, 0)
-BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdlt", IX86_BUILTIN_UCOMILTSD, UNLT, 0)
-BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdle", IX86_BUILTIN_UCOMILESD, UNLE, 0)
+BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_comi, "__builtin_ia32_comisdneq", IX86_BUILTIN_COMINEQSD, NE, 0)
+BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdeq", IX86_BUILTIN_UCOMIEQSD, EQ, 0)
+BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdlt", IX86_BUILTIN_UCOMILTSD, LT, 0)
+BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdle", IX86_BUILTIN_UCOMILESD, LE, 0)
BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdgt", IX86_BUILTIN_UCOMIGTSD, GT, 0)
BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdge", IX86_BUILTIN_UCOMIGESD, GE, 0)
-BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdneq", IX86_BUILTIN_UCOMINEQSD, LTGT, 0)
+BDESC (OPTION_MASK_ISA_SSE2, 0, CODE_FOR_sse2_ucomi, "__builtin_ia32_ucomisdneq", IX86_BUILTIN_UCOMINEQSD, NE, 0)
BDESC_END (COMI, PCMPESTR)
diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index 6a3fcde..40f821e 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -9770,47 +9770,121 @@ ix86_expand_sse_compare (const struct builtin_description *d,
return target;
}
+/* Subroutine of ix86_sse_comi and ix86_sse_comi_round to take care of
+ * ordered EQ or unordered NE, generate PF jump. */
+
+static rtx
+ix86_ssecom_setcc (const enum rtx_code comparison,
+ bool check_unordered, machine_mode mode,
+ rtx set_dst, rtx target)
+{
+
+ rtx_code_label *label = NULL;
+
+ /* NB: For ordered EQ or unordered NE, check ZF alone isn't sufficient
+ with NAN operands. */
+ if (check_unordered)
+ {
+ gcc_assert (comparison == EQ || comparison == NE);
+
+ rtx flag = gen_rtx_REG (CCFPmode, FLAGS_REG);
+ label = gen_label_rtx ();
+ rtx tmp = gen_rtx_fmt_ee (UNORDERED, VOIDmode, flag, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, label),
+ pc_rtx);
+ emit_jump_insn (gen_rtx_SET (pc_rtx, tmp));
+ }
+
+ /* NB: Set CCFPmode and check a different CCmode which is in subset
+ of CCFPmode. */
+ if (GET_MODE (set_dst) != mode)
+ {
+ gcc_assert (mode == CCAmode || mode == CCCmode
+ || mode == CCOmode || mode == CCPmode
+ || mode == CCSmode || mode == CCZmode);
+ set_dst = gen_rtx_REG (mode, FLAGS_REG);
+ }
+
+ emit_insn (gen_rtx_SET (gen_rtx_STRICT_LOW_PART (VOIDmode, target),
+ gen_rtx_fmt_ee (comparison, QImode,
+ set_dst,
+ const0_rtx)));
+
+ if (label)
+ emit_label (label);
+
+ return SUBREG_REG (target);
+}
+
/* Subroutine of ix86_expand_builtin to take care of comi insns. */
static rtx
ix86_expand_sse_comi (const struct builtin_description *d, tree exp,
rtx target)
{
- rtx pat;
+ rtx pat, set_dst;
tree arg0 = CALL_EXPR_ARG (exp, 0);
tree arg1 = CALL_EXPR_ARG (exp, 1);
rtx op0 = expand_normal (arg0);
rtx op1 = expand_normal (arg1);
- machine_mode mode0 = insn_data[d->icode].operand[0].mode;
- machine_mode mode1 = insn_data[d->icode].operand[1].mode;
- enum rtx_code comparison = d->comparison;
+ enum insn_code icode = d->icode;
+ const struct insn_data_d *insn_p = &insn_data[icode];
+ machine_mode mode0 = insn_p->operand[0].mode;
+ machine_mode mode1 = insn_p->operand[1].mode;
if (VECTOR_MODE_P (mode0))
op0 = safe_vector_operand (op0, mode0);
if (VECTOR_MODE_P (mode1))
op1 = safe_vector_operand (op1, mode1);
+ enum rtx_code comparison = d->comparison;
+ rtx const_val = const0_rtx;
+
+ bool check_unordered = false;
+ machine_mode mode = CCFPmode;
+ switch (comparison)
+ {
+ case LE: /* -> GE */
+ case LT: /* -> GT */
+ std::swap (op0, op1);
+ comparison = swap_condition (comparison);
+ /* FALLTHRU */
+ case GT:
+ case GE:
+ break;
+ case EQ:
+ check_unordered = true;
+ mode = CCZmode;
+ break;
+ case NE:
+ check_unordered = true;
+ mode = CCZmode;
+ const_val = const1_rtx;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
target = gen_reg_rtx (SImode);
- emit_move_insn (target, const0_rtx);
+ emit_move_insn (target, const_val);
target = gen_rtx_SUBREG (QImode, target, 0);
if ((optimize && !register_operand (op0, mode0))
- || !insn_data[d->icode].operand[0].predicate (op0, mode0))
+ || !insn_p->operand[0].predicate (op0, mode0))
op0 = copy_to_mode_reg (mode0, op0);
if ((optimize && !register_operand (op1, mode1))
- || !insn_data[d->icode].operand[1].predicate (op1, mode1))
+ || !insn_p->operand[1].predicate (op1, mode1))
op1 = copy_to_mode_reg (mode1, op1);
- pat = GEN_FCN (d->icode) (op0, op1);
+ pat = GEN_FCN (icode) (op0, op1);
if (! pat)
return 0;
- emit_insn (pat);
- emit_insn (gen_rtx_SET (gen_rtx_STRICT_LOW_PART (VOIDmode, target),
- gen_rtx_fmt_ee (comparison, QImode,
- SET_DEST (pat),
- const0_rtx)));
- return SUBREG_REG (target);
+ set_dst = SET_DEST (pat);
+ emit_insn (pat);
+ return ix86_ssecom_setcc (comparison, check_unordered, mode,
+ set_dst, target);
}
/* Subroutines of ix86_expand_args_builtin to take care of round insns. */
@@ -11410,42 +11484,8 @@ ix86_expand_sse_comi_round (const struct builtin_description *d,
emit_insn (pat);
- rtx_code_label *label = NULL;
-
- /* NB: For ordered EQ or unordered NE, check ZF alone isn't sufficient
- with NAN operands. */
- if (check_unordered)
- {
- gcc_assert (comparison == EQ || comparison == NE);
-
- rtx flag = gen_rtx_REG (CCFPmode, FLAGS_REG);
- label = gen_label_rtx ();
- rtx tmp = gen_rtx_fmt_ee (UNORDERED, VOIDmode, flag, const0_rtx);
- tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
- gen_rtx_LABEL_REF (VOIDmode, label),
- pc_rtx);
- emit_jump_insn (gen_rtx_SET (pc_rtx, tmp));
- }
-
- /* NB: Set CCFPmode and check a different CCmode which is in subset
- of CCFPmode. */
- if (GET_MODE (set_dst) != mode)
- {
- gcc_assert (mode == CCAmode || mode == CCCmode
- || mode == CCOmode || mode == CCPmode
- || mode == CCSmode || mode == CCZmode);
- set_dst = gen_rtx_REG (mode, FLAGS_REG);
- }
-
- emit_insn (gen_rtx_SET (gen_rtx_STRICT_LOW_PART (VOIDmode, target),
- gen_rtx_fmt_ee (comparison, QImode,
- set_dst,
- const0_rtx)));
-
- if (label)
- emit_label (label);
-
- return SUBREG_REG (target);
+ return ix86_ssecom_setcc (comparison, check_unordered, mode,
+ set_dst, target);
}
static rtx
diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index f1b03c3..813b203 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -1054,13 +1054,13 @@ general_scalar_chain::convert_insn (rtx_insn *insn)
else if (REG_P (dst) && GET_MODE (dst) == smode)
{
/* Replace the definition with a SUBREG to the definition we
- use inside the chain. */
+ use inside the chain. */
rtx *vdef = defs_map.get (dst);
if (vdef)
dst = *vdef;
dst = gen_rtx_SUBREG (vmode, dst, 0);
/* IRA doesn't like to have REG_EQUAL/EQUIV notes when the SET_DEST
- is a non-REG_P. So kill those off. */
+ is a non-REG_P. So kill those off. */
rtx note = find_reg_equal_equiv_note (insn);
if (note)
remove_note (insn, note);
@@ -1246,7 +1246,7 @@ timode_scalar_chain::fix_debug_reg_uses (rtx reg)
{
rtx_insn *insn = DF_REF_INSN (ref);
/* Make sure the next ref is for a different instruction,
- so that we're not affected by the rescan. */
+ so that we're not affected by the rescan. */
next = DF_REF_NEXT_REG (ref);
while (next && DF_REF_INSN (next) == insn)
next = DF_REF_NEXT_REG (next);
@@ -1336,21 +1336,19 @@ timode_scalar_chain::convert_insn (rtx_insn *insn)
rtx dst = SET_DEST (def_set);
rtx tmp;
- if (MEM_P (dst) && !REG_P (src))
- {
- /* There are no scalar integer instructions and therefore
- temporary register usage is required. */
- }
switch (GET_CODE (dst))
{
case REG:
if (GET_MODE (dst) == TImode)
{
+ PUT_MODE (dst, V1TImode);
+ fix_debug_reg_uses (dst);
+ }
+ if (GET_MODE (dst) == V1TImode)
+ {
tmp = find_reg_equal_equiv_note (insn);
if (tmp && GET_MODE (XEXP (tmp, 0)) == TImode)
PUT_MODE (XEXP (tmp, 0), V1TImode);
- PUT_MODE (dst, V1TImode);
- fix_debug_reg_uses (dst);
}
break;
case MEM:
@@ -1410,8 +1408,8 @@ timode_scalar_chain::convert_insn (rtx_insn *insn)
if (MEM_P (dst))
{
tmp = gen_reg_rtx (V1TImode);
- emit_insn_before (gen_rtx_SET (tmp, src), insn);
- src = tmp;
+ emit_insn_before (gen_rtx_SET (tmp, src), insn);
+ src = tmp;
}
break;
@@ -1434,8 +1432,8 @@ timode_scalar_chain::convert_insn (rtx_insn *insn)
if (MEM_P (dst))
{
tmp = gen_reg_rtx (V1TImode);
- emit_insn_before (gen_rtx_SET (tmp, src), insn);
- src = tmp;
+ emit_insn_before (gen_rtx_SET (tmp, src), insn);
+ src = tmp;
}
break;
@@ -1448,8 +1446,8 @@ timode_scalar_chain::convert_insn (rtx_insn *insn)
if (MEM_P (dst))
{
tmp = gen_reg_rtx (V1TImode);
- emit_insn_before (gen_rtx_SET (tmp, src), insn);
- src = tmp;
+ emit_insn_before (gen_rtx_SET (tmp, src), insn);
+ src = tmp;
}
break;
@@ -1585,7 +1583,7 @@ convertible_comparison_p (rtx_insn *insn, enum machine_mode mode)
/* *cmp<dwi>_doubleword. */
if ((CONST_INT_P (op1)
|| ((REG_P (op1) || MEM_P (op1))
- && GET_MODE (op1) == mode))
+ && GET_MODE (op1) == mode))
&& (CONST_INT_P (op2)
|| ((REG_P (op2) || MEM_P (op2))
&& GET_MODE (op2) == mode)))
@@ -1745,7 +1743,7 @@ timode_scalar_to_vector_candidate_p (rtx_insn *insn)
if (GET_MODE (dst) != TImode
|| (GET_MODE (src) != TImode
- && !CONST_SCALAR_INT_P (src)))
+ && !CONST_SCALAR_INT_P (src)))
return false;
if (!REG_P (dst) && !MEM_P (dst))
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 3a3c729..e03f86d 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -1024,6 +1024,16 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
return false;
}
+ /* Disable sibcall if callee has indirect_return attribute and
+ caller doesn't since callee will return to the caller's caller
+ via an indirect jump. */
+ if (((flag_cf_protection & (CF_RETURN | CF_BRANCH))
+ == (CF_RETURN | CF_BRANCH))
+ && lookup_attribute ("indirect_return", TYPE_ATTRIBUTES (type))
+ && !lookup_attribute ("indirect_return",
+ TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl))))
+ return false;
+
/* Otherwise okay. That also includes certain types of indirect calls. */
return true;
}
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index bf29f444..9aaeb69 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -10423,10 +10423,10 @@
})
(define_insn_and_split "*andn<dwi>3_doubleword_bmi"
- [(set (match_operand:<DWI> 0 "register_operand" "=r")
+ [(set (match_operand:<DWI> 0 "register_operand" "=&r,r,r")
(and:<DWI>
- (not:<DWI> (match_operand:<DWI> 1 "register_operand" "r"))
- (match_operand:<DWI> 2 "nonimmediate_operand" "ro")))
+ (not:<DWI> (match_operand:<DWI> 1 "register_operand" "r,0,r"))
+ (match_operand:<DWI> 2 "nonimmediate_operand" "ro,ro,0")))
(clobber (reg:CC FLAGS_REG))]
"TARGET_BMI"
"#"
@@ -16431,6 +16431,66 @@
(set_attr "prefix_rep" "1")
(set_attr "mode" "SI")])
+(define_insn_and_split "*ctzsidi2_<s>ext"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (any_extend:DI
+ (ctz:SI
+ (match_operand:SI 1 "nonimmediate_operand" "rm"))))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+{
+ if (TARGET_BMI)
+ return "tzcnt{l}\t{%1, %k0|%k0, %1}";
+ else if (TARGET_CPU_P (GENERIC)
+ && !optimize_function_for_size_p (cfun))
+ /* tzcnt expands to 'rep bsf' and we can use it even if !TARGET_BMI. */
+ return "rep%; bsf{l}\t{%1, %k0|%k0, %1}";
+ return "bsf{l}\t{%1, %k0|%k0, %1}";
+}
+ "(TARGET_BMI || TARGET_CPU_P (GENERIC))
+ && TARGET_AVOID_FALSE_DEP_FOR_BMI && epilogue_completed
+ && optimize_function_for_speed_p (cfun)
+ && !reg_mentioned_p (operands[0], operands[1])"
+ [(parallel
+ [(set (match_dup 0)
+ (any_extend:DI (ctz:SI (match_dup 1))))
+ (unspec [(match_dup 0)] UNSPEC_INSN_FALSE_DEP)
+ (clobber (reg:CC FLAGS_REG))])]
+ "ix86_expand_clear (operands[0]);"
+ [(set_attr "type" "alu1")
+ (set_attr "prefix_0f" "1")
+ (set (attr "prefix_rep")
+ (if_then_else
+ (ior (match_test "TARGET_BMI")
+ (and (not (match_test "optimize_function_for_size_p (cfun)"))
+ (match_test "TARGET_CPU_P (GENERIC)")))
+ (const_string "1")
+ (const_string "0")))
+ (set_attr "mode" "SI")])
+
+(define_insn "*ctzsidi2_<s>ext_falsedep"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (any_extend:DI
+ (ctz:SI
+ (match_operand:SI 1 "nonimmediate_operand" "rm"))))
+ (unspec [(match_operand:DI 2 "register_operand" "0")]
+ UNSPEC_INSN_FALSE_DEP)
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+{
+ if (TARGET_BMI)
+ return "tzcnt{l}\t{%1, %k0|%k0, %1}";
+ else if (TARGET_CPU_P (GENERIC))
+ /* tzcnt expands to 'rep bsf' and we can use it even if !TARGET_BMI. */
+ return "rep%; bsf{l}\t{%1, %k0|%k0, %1}";
+ else
+ gcc_unreachable ();
+}
+ [(set_attr "type" "alu1")
+ (set_attr "prefix_0f" "1")
+ (set_attr "prefix_rep" "1")
+ (set_attr "mode" "SI")])
+
(define_insn "bsr_rex64"
[(set (reg:CCZ FLAGS_REG)
(compare:CCZ (match_operand:DI 1 "nonimmediate_operand" "rm")
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index c71c453..42053ea 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -1199,6 +1199,10 @@
(define_predicate "x86_64_const_vector_operand"
(match_code "const_vector")
{
+ if (mode == VOIDmode)
+ mode = GET_MODE (op);
+ else if (GET_MODE (op) != mode)
+ return false;
if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
return false;
HOST_WIDE_INT val = ix86_convert_const_vector_to_integer (op, mode);
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index a755d72..14d12d1 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -2068,7 +2068,8 @@
(ashift:HI
(zero_extend:HI (match_operand:QI 1 "register_operand" "k"))
(const_int 8))
- (zero_extend:HI (match_operand:QI 2 "register_operand" "k"))))]
+ (zero_extend:HI (match_operand:QI 2 "register_operand" "k"))))
+ (unspec [(const_int 0)] UNSPEC_MASKOP)]
"TARGET_AVX512F"
"kunpckbw\t{%2, %1, %0|%0, %1, %2}"
[(set_attr "mode" "HI")
@@ -2081,7 +2082,8 @@
(ashift:SI
(zero_extend:SI (match_operand:HI 1 "register_operand" "k"))
(const_int 16))
- (zero_extend:SI (match_operand:HI 2 "register_operand" "k"))))]
+ (zero_extend:SI (match_operand:HI 2 "register_operand" "k"))))
+ (unspec [(const_int 0)] UNSPEC_MASKOP)]
"TARGET_AVX512BW"
"kunpckwd\t{%2, %1, %0|%0, %1, %2}"
[(set_attr "mode" "SI")])
@@ -2092,7 +2094,8 @@
(ashift:DI
(zero_extend:DI (match_operand:SI 1 "register_operand" "k"))
(const_int 32))
- (zero_extend:DI (match_operand:SI 2 "register_operand" "k"))))]
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "k"))))
+ (unspec [(const_int 0)] UNSPEC_MASKOP)]
"TARGET_AVX512BW"
"kunpckdq\t{%2, %1, %0|%0, %1, %2}"
[(set_attr "mode" "DI")])
@@ -17419,21 +17422,26 @@
})
(define_expand "vec_pack_trunc_qi"
- [(set (match_operand:HI 0 "register_operand")
- (ior:HI (ashift:HI (zero_extend:HI (match_operand:QI 2 "register_operand"))
- (const_int 8))
- (zero_extend:HI (match_operand:QI 1 "register_operand"))))]
+ [(parallel
+ [(set (match_operand:HI 0 "register_operand")
+ (ior:HI
+ (ashift:HI (zero_extend:HI (match_operand:QI 2 "register_operand"))
+ (const_int 8))
+ (zero_extend:HI (match_operand:QI 1 "register_operand"))))
+ (unspec [(const_int 0)] UNSPEC_MASKOP)])]
"TARGET_AVX512F")
(define_expand "vec_pack_trunc_<mode>"
- [(set (match_operand:<DOUBLEMASKMODE> 0 "register_operand")
- (ior:<DOUBLEMASKMODE>
- (ashift:<DOUBLEMASKMODE>
+ [(parallel
+ [(set (match_operand:<DOUBLEMASKMODE> 0 "register_operand")
+ (ior:<DOUBLEMASKMODE>
+ (ashift:<DOUBLEMASKMODE>
+ (zero_extend:<DOUBLEMASKMODE>
+ (match_operand:SWI24 2 "register_operand"))
+ (match_dup 3))
(zero_extend:<DOUBLEMASKMODE>
- (match_operand:SWI24 2 "register_operand"))
- (match_dup 3))
- (zero_extend:<DOUBLEMASKMODE>
- (match_operand:SWI24 1 "register_operand"))))]
+ (match_operand:SWI24 1 "register_operand"))))
+ (unspec [(const_int 0)] UNSPEC_MASKOP)])]
"TARGET_AVX512BW"
{
operands[3] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode));
diff --git a/gcc/config/xtensa/xtensa.cc b/gcc/config/xtensa/xtensa.cc
index 13f2b2b..9433745 100644
--- a/gcc/config/xtensa/xtensa.cc
+++ b/gcc/config/xtensa/xtensa.cc
@@ -1035,35 +1035,35 @@ xtensa_split_operand_pair (rtx operands[4], machine_mode mode)
load-immediate / arithmetic ones, instead of a L32R instruction
(plus a constant in litpool). */
-static void
-xtensa_emit_constantsynth (rtx dst, enum rtx_code code,
- HOST_WIDE_INT imm0, HOST_WIDE_INT imm1,
- rtx (*gen_op)(rtx, HOST_WIDE_INT),
- HOST_WIDE_INT imm2)
-{
- gcc_assert (REG_P (dst));
- emit_move_insn (dst, GEN_INT (imm0));
- emit_move_insn (dst, gen_rtx_fmt_ee (code, SImode,
- dst, GEN_INT (imm1)));
- if (gen_op)
- emit_move_insn (dst, gen_op (dst, imm2));
-}
-
static int
xtensa_constantsynth_2insn (rtx dst, HOST_WIDE_INT srcval,
rtx (*gen_op)(rtx, HOST_WIDE_INT),
HOST_WIDE_INT op_imm)
{
- int shift = exact_log2 (srcval + 1);
+ HOST_WIDE_INT imm = INT_MAX;
+ rtx x = NULL_RTX;
+ int shift;
+ gcc_assert (REG_P (dst));
+
+ shift = exact_log2 (srcval + 1);
if (IN_RANGE (shift, 1, 31))
{
- xtensa_emit_constantsynth (dst, LSHIFTRT, -1, 32 - shift,
- gen_op, op_imm);
- return 1;
+ imm = -1;
+ x = gen_lshrsi3 (dst, dst, GEN_INT (32 - shift));
}
- if (IN_RANGE (srcval, (-2048 - 32768), (2047 + 32512)))
+
+ shift = ctz_hwi (srcval);
+ if ((!x || (TARGET_DENSITY && ! IN_RANGE (imm, -32, 95)))
+ && xtensa_simm12b (srcval >> shift))
+ {
+ imm = srcval >> shift;
+ x = gen_ashlsi3 (dst, dst, GEN_INT (shift));
+ }
+
+ if ((!x || (TARGET_DENSITY && ! IN_RANGE (imm, -32, 95)))
+ && IN_RANGE (srcval, (-2048 - 32768), (2047 + 32512)))
{
HOST_WIDE_INT imm0, imm1;
@@ -1076,19 +1076,19 @@ xtensa_constantsynth_2insn (rtx dst, HOST_WIDE_INT srcval,
imm0 = srcval - imm1;
if (TARGET_DENSITY && imm1 < 32512 && IN_RANGE (imm0, 224, 255))
imm0 -= 256, imm1 += 256;
- xtensa_emit_constantsynth (dst, PLUS, imm0, imm1, gen_op, op_imm);
- return 1;
+ imm = imm0;
+ x = gen_addsi3 (dst, dst, GEN_INT (imm1));
}
- shift = ctz_hwi (srcval);
- if (xtensa_simm12b (srcval >> shift))
- {
- xtensa_emit_constantsynth (dst, ASHIFT, srcval >> shift, shift,
- gen_op, op_imm);
- return 1;
- }
+ if (!x)
+ return 0;
- return 0;
+ emit_move_insn (dst, GEN_INT (imm));
+ emit_insn (x);
+ if (gen_op)
+ emit_move_insn (dst, gen_op (dst, op_imm));
+
+ return 1;
}
static rtx
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 6a58d3e..c02f1a5 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -1716,63 +1716,78 @@
(define_insn_and_split "*masktrue_const_pow2_minus_one"
[(set (pc)
- (if_then_else (match_operator 3 "boolean_operator"
+ (if_then_else (match_operator 4 "boolean_operator"
[(and:SI (match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "const_int_operand" "i"))
- (const_int 0)])
- (label_ref (match_operand 2 "" ""))
+ (match_operand:SI 2 "const_int_operand" "i")])
+ (label_ref (match_operand 3 "" ""))
(pc)))]
- "IN_RANGE (exact_log2 (INTVAL (operands[1]) + 1), 17, 31)"
+ "IN_RANGE (exact_log2 (INTVAL (operands[1]) + 1), 17, 31)
+ /* && (~INTVAL (operands[1]) & INTVAL (operands[2])) == 0 // can be omitted */
+ && xtensa_b4const_or_zero (INTVAL (operands[2]) << (32 - floor_log2 (INTVAL (operands[1]) + 1)))"
"#"
"&& can_create_pseudo_p ()"
- [(set (match_dup 4)
+ [(set (match_dup 5)
(ashift:SI (match_dup 0)
(match_dup 1)))
(set (pc)
- (if_then_else (match_op_dup 3
- [(match_dup 4)
- (const_int 0)])
- (label_ref (match_dup 2))
+ (if_then_else (match_op_dup 4
+ [(match_dup 5)
+ (match_dup 2)])
+ (label_ref (match_dup 3))
(pc)))]
{
- operands[1] = GEN_INT (32 - floor_log2 (INTVAL (operands[1]) + 1));
- operands[4] = gen_reg_rtx (SImode);
+ int shift = 32 - floor_log2 (INTVAL (operands[1]) + 1);
+ operands[1] = GEN_INT (shift);
+ operands[2] = GEN_INT (INTVAL (operands[2]) << shift);
+ operands[5] = gen_reg_rtx (SImode);
}
[(set_attr "type" "jump")
(set_attr "mode" "none")
(set (attr "length")
- (if_then_else (match_test "TARGET_DENSITY
- && INTVAL (operands[1]) == 0x7FFFFFFF")
- (const_int 5)
- (const_int 6)))])
+ (if_then_else (match_test "(TARGET_DENSITY && INTVAL (operands[1]) == 0x7FFFFFFF)
+ && INTVAL (operands[2]) == 0")
+ (const_int 4)
+ (if_then_else (match_test "TARGET_DENSITY
+ && (INTVAL (operands[1]) == 0x7FFFFFFF
+ || INTVAL (operands[2]) == 0)")
+ (const_int 5)
+ (const_int 6))))])
(define_insn_and_split "*masktrue_const_negative_pow2"
[(set (pc)
- (if_then_else (match_operator 3 "boolean_operator"
+ (if_then_else (match_operator 4 "boolean_operator"
[(and:SI (match_operand:SI 0 "register_operand" "r")
(match_operand:SI 1 "const_int_operand" "i"))
- (const_int 0)])
- (label_ref (match_operand 2 "" ""))
+ (match_operand:SI 2 "const_int_operand" "i")])
+ (label_ref (match_operand 3 "" ""))
(pc)))]
- "IN_RANGE (exact_log2 (-INTVAL (operands[1])), 12, 30)"
+ "IN_RANGE (exact_log2 (-INTVAL (operands[1])), 1, 30)
+ /* && (~INTVAL (operands[1]) & INTVAL (operands[2])) == 0 // can be omitted */
+ && xtensa_b4const_or_zero (INTVAL (operands[2]) >> floor_log2 (-INTVAL (operands[1])))"
"#"
"&& can_create_pseudo_p ()"
- [(set (match_dup 4)
+ [(set (match_dup 5)
(lshiftrt:SI (match_dup 0)
(match_dup 1)))
(set (pc)
- (if_then_else (match_op_dup 3
- [(match_dup 4)
- (const_int 0)])
- (label_ref (match_dup 2))
+ (if_then_else (match_op_dup 4
+ [(match_dup 5)
+ (match_dup 2)])
+ (label_ref (match_dup 3))
(pc)))]
{
- operands[1] = GEN_INT (floor_log2 (-INTVAL (operands[1])));
- operands[4] = gen_reg_rtx (SImode);
+ int shift = floor_log2 (-INTVAL (operands[1]));
+ operands[1] = GEN_INT (shift);
+ operands[2] = GEN_INT (INTVAL (operands[2]) >> shift);
+ operands[5] = gen_reg_rtx (SImode);
}
[(set_attr "type" "jump")
(set_attr "mode" "none")
- (set_attr "length" "6")])
+ (set (attr "length")
+ (if_then_else (match_test "TARGET_DENSITY && INTVAL (operands[2]) == 0")
+ (const_int 5)
+ (const_int 6)))])
(define_insn_and_split "*masktrue_const_shifted_mask"
[(set (pc)
@@ -1782,8 +1797,8 @@
(match_operand:SI 2 "const_int_operand" "i")])
(label_ref (match_operand 3 "" ""))
(pc)))]
- "(INTVAL (operands[2]) & ((1 << ctz_hwi (INTVAL (operands[1]))) - 1)) == 0
- && xtensa_b4const_or_zero ((uint32_t)INTVAL (operands[2]) >> ctz_hwi (INTVAL (operands[1])))"
+ "/* (INTVAL (operands[2]) & ((1 << ctz_hwi (INTVAL (operands[1]))) - 1)) == 0 // can be omitted
+ && */ xtensa_b4const_or_zero ((uint32_t)INTVAL (operands[2]) >> ctz_hwi (INTVAL (operands[1])))"
"#"
"&& can_create_pseudo_p ()"
[(set (match_dup 6)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index aa317e8..ce6f8ea 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,28 @@
+2022-07-15 Marek Polacek <polacek@redhat.com>
+
+ PR c++/104477
+ * call.cc (ref_conv_binds_directly_p): Rename to ...
+ (ref_conv_binds_directly): ... this. Add a new bool parameter. Change
+ the return type to tristate.
+ * constraint.cc (diagnose_trait_expr): Handle
+ CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY.
+ * cp-tree.h: Include "tristate.h".
+ (enum cp_trait_kind): Add CPTK_REF_CONSTRUCTS_FROM_TEMPORARY
+ and CPTK_REF_CONVERTS_FROM_TEMPORARY.
+ (ref_conv_binds_directly_p): Rename to ...
+ (ref_conv_binds_directly): ... this.
+ (ref_xes_from_temporary): Declare.
+ * cxx-pretty-print.cc (pp_cxx_trait_expression): Handle
+ CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY.
+ * method.cc (ref_xes_from_temporary): New.
+ * parser.cc (cp_parser_primary_expression): Handle
+ RID_REF_CONSTRUCTS_FROM_TEMPORARY and RID_REF_CONVERTS_FROM_TEMPORARY.
+ (cp_parser_trait_expr): Likewise.
+ (warn_for_range_copy): Adjust to call ref_conv_binds_directly.
+ * semantics.cc (trait_expr_value): Handle
+ CPTK_REF_CONSTRUCTS_FROM_TEMPORARY and CPTK_REF_CONVERTS_FROM_TEMPORARY.
+ (finish_trait_expr): Likewise.
+
2022-07-13 Patrick Palka <ppalka@redhat.com>
PR c++/105912
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index fc98552..191c68c 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -9109,21 +9109,27 @@ conv_binds_ref_to_prvalue (conversion *c)
return conv_is_prvalue (next_conversion (c));
}
-/* True iff converting EXPR to a reference type TYPE does not involve
- creating a temporary. */
+/* Return tristate::TS_TRUE if converting EXPR to a reference type TYPE does
+ not involve creating a temporary. Return tristate::TS_FALSE if converting
+ EXPR to a reference type TYPE binds the reference to a temporary. If the
+ conversion is invalid or bad, return tristate::TS_UNKNOWN. DIRECT_INIT_P
+ says whether the conversion should be done in direct- or copy-initialization
+ context. */
-bool
-ref_conv_binds_directly_p (tree type, tree expr)
+tristate
+ref_conv_binds_directly (tree type, tree expr, bool direct_init_p /*= false*/)
{
gcc_assert (TYPE_REF_P (type));
/* Get the high-water mark for the CONVERSION_OBSTACK. */
void *p = conversion_obstack_alloc (0);
+ const int flags = direct_init_p ? LOOKUP_NORMAL : LOOKUP_IMPLICIT;
conversion *conv = implicit_conversion (type, TREE_TYPE (expr), expr,
- /*c_cast_p=*/false,
- LOOKUP_IMPLICIT, tf_none);
- bool ret = conv && !conv->bad_p && !conv_binds_ref_to_prvalue (conv);
+ /*c_cast_p=*/false, flags, tf_none);
+ tristate ret (tristate::TS_UNKNOWN);
+ if (conv && !conv->bad_p)
+ ret = tristate (!conv_binds_ref_to_prvalue (conv));
/* Free all the conversions we allocated. */
obstack_free (&conversion_obstack, p);
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index f2137eb..568318f 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -3697,6 +3697,14 @@ diagnose_trait_expr (tree expr, tree args)
case CPTK_HAS_UNIQUE_OBJ_REPRESENTATIONS:
inform (loc, " %qT does not have unique object representations", t1);
break;
+ case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
+ inform (loc, " %qT is not a reference that binds to a temporary "
+ "object of type %qT (direct-initialization)", t1, t2);
+ break;
+ case CPTK_REF_CONVERTS_FROM_TEMPORARY:
+ inform (loc, " %qT is not a reference that binds to a temporary "
+ "object of type %qT (copy-initialization)", t1, t2);
+ break;
case CPTK_BASES:
case CPTK_DIRECT_BASES:
case CPTK_UNDERLYING_TYPE:
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index bec98aa..cf51c39 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm.h"
#include "hard-reg-set.h"
#include "function.h"
+#include "tristate.h"
/* In order for the format checking to accept the C++ front end
diagnostic framework extensions, you must include this file before
@@ -1397,7 +1398,9 @@ enum cp_trait_kind
CPTK_IS_ASSIGNABLE,
CPTK_IS_CONSTRUCTIBLE,
CPTK_IS_NOTHROW_ASSIGNABLE,
- CPTK_IS_NOTHROW_CONSTRUCTIBLE
+ CPTK_IS_NOTHROW_CONSTRUCTIBLE,
+ CPTK_REF_CONSTRUCTS_FROM_TEMPORARY,
+ CPTK_REF_CONVERTS_FROM_TEMPORARY
};
/* The types that we are processing. */
@@ -6520,7 +6523,7 @@ extern bool sufficient_parms_p (const_tree);
extern tree type_decays_to (tree);
extern tree extract_call_expr (tree);
extern tree build_trivial_dtor_call (tree, bool = false);
-extern bool ref_conv_binds_directly_p (tree, tree);
+extern tristate ref_conv_binds_directly (tree, tree, bool = false);
extern tree build_user_type_conversion (tree, tree, int,
tsubst_flags_t);
extern tree build_new_function_call (tree, vec<tree, va_gc> **,
@@ -7105,6 +7108,7 @@ extern tree forward_parm (tree);
extern bool is_trivially_xible (enum tree_code, tree, tree);
extern bool is_nothrow_xible (enum tree_code, tree, tree);
extern bool is_xible (enum tree_code, tree, tree);
+extern bool ref_xes_from_temporary (tree, tree, bool);
extern tree get_defaulted_eh_spec (tree, tsubst_flags_t = tf_warning_or_error);
extern bool maybe_explain_implicit_delete (tree);
extern void explain_implicit_non_constexpr (tree);
diff --git a/gcc/cp/cxx-pretty-print.cc b/gcc/cp/cxx-pretty-print.cc
index 7e4db2e..4459083 100644
--- a/gcc/cp/cxx-pretty-print.cc
+++ b/gcc/cp/cxx-pretty-print.cc
@@ -2696,6 +2696,12 @@ pp_cxx_trait_expression (cxx_pretty_printer *pp, tree t)
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
pp_cxx_ws_string (pp, "__is_nothrow_constructible");
break;
+ case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
+ pp_cxx_ws_string (pp, "__reference_constructs_from_temporary");
+ break;
+ case CPTK_REF_CONVERTS_FROM_TEMPORARY:
+ pp_cxx_ws_string (pp, "__reference_converts_from_temporary");
+ break;
default:
gcc_unreachable ();
diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc
index 0dffd64..f2050f6 100644
--- a/gcc/cp/method.cc
+++ b/gcc/cp/method.cc
@@ -2211,6 +2211,31 @@ is_xible (enum tree_code code, tree to, tree from)
return !!expr;
}
+/* Return true iff conjunction_v<is_reference<T>, is_constructible<T, U>> is
+ true, and the initialization
+ T t(VAL<U>); // DIRECT_INIT_P
+ or
+ T t = VAL<U>; // !DIRECT_INIT_P
+ binds t to a temporary object whose lifetime is extended.
+ VAL<T> is defined in [meta.unary.prop]:
+ -- If T is a reference or function type, VAL<T> is an expression with the
+ same type and value category as declval<T>().
+ -- Otherwise, VAL<T> is a prvalue that initially has type T. */
+
+bool
+ref_xes_from_temporary (tree to, tree from, bool direct_init_p)
+{
+ /* Check is_reference<T>. */
+ if (!TYPE_REF_P (to))
+ return false;
+ /* We don't check is_constructible<T, U>: if T isn't constructible
+ from U, we won't be able to create a conversion. */
+ tree val = build_stub_object (from);
+ if (!TYPE_REF_P (from) && TREE_CODE (from) != FUNCTION_TYPE)
+ val = CLASS_TYPE_P (from) ? force_rvalue (val, tf_none) : rvalue (val);
+ return ref_conv_binds_directly (to, val, direct_init_p).is_false ();
+}
+
/* Categorize various special_function_kinds. */
#define SFK_CTOR_P(sfk) \
((sfk) >= sfk_constructor && (sfk) <= sfk_move_constructor)
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index bf9ea36..4f67441 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -5917,6 +5917,8 @@ cp_parser_primary_expression (cp_parser *parser,
case RID_IS_CONSTRUCTIBLE:
case RID_IS_NOTHROW_ASSIGNABLE:
case RID_IS_NOTHROW_CONSTRUCTIBLE:
+ case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
+ case RID_REF_CONVERTS_FROM_TEMPORARY:
return cp_parser_trait_expr (parser, token->keyword);
// C++ concepts
@@ -10988,6 +10990,14 @@ cp_parser_trait_expr (cp_parser* parser, enum rid keyword)
kind = CPTK_IS_NOTHROW_CONSTRUCTIBLE;
variadic = true;
break;
+ case RID_REF_CONSTRUCTS_FROM_TEMPORARY:
+ kind = CPTK_REF_CONSTRUCTS_FROM_TEMPORARY;
+ binary = true;
+ break;
+ case RID_REF_CONVERTS_FROM_TEMPORARY:
+ kind = CPTK_REF_CONVERTS_FROM_TEMPORARY;
+ binary = true;
+ break;
default:
gcc_unreachable ();
}
@@ -13811,7 +13821,7 @@ warn_for_range_copy (tree decl, tree expr)
if (TYPE_REF_P (type))
{
- if (glvalue_p (expr) && !ref_conv_binds_directly_p (type, expr))
+ if (glvalue_p (expr) && ref_conv_binds_directly (type, expr).is_false ())
{
auto_diagnostic_group d;
if (warning_at (loc, OPT_Wrange_loop_construct,
@@ -13839,20 +13849,20 @@ warn_for_range_copy (tree decl, tree expr)
&& trivially_copyable_p (type)))
return;
+ /* If we can initialize a reference directly, suggest that to avoid the
+ copy. */
tree rtype = cp_build_reference_type (type, /*rval*/false);
- /* If we could initialize the reference directly, it wouldn't involve any
- copies. */
- if (!ref_conv_binds_directly_p (rtype, expr))
- return;
-
- auto_diagnostic_group d;
- if (warning_at (loc, OPT_Wrange_loop_construct,
- "loop variable %qD creates a copy from type %qT",
- decl, type))
+ if (ref_conv_binds_directly (rtype, expr).is_true ())
{
- gcc_rich_location richloc (loc);
- richloc.add_fixit_insert_before ("&");
- inform (&richloc, "use reference type to prevent copying");
+ auto_diagnostic_group d;
+ if (warning_at (loc, OPT_Wrange_loop_construct,
+ "loop variable %qD creates a copy from type %qT",
+ decl, type))
+ {
+ gcc_rich_location richloc (loc);
+ richloc.add_fixit_insert_before ("&");
+ inform (&richloc, "use reference type to prevent copying");
+ }
}
}
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 2344b5e..96037c2 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -12007,6 +12007,12 @@ trait_expr_value (cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
return is_nothrow_xible (INIT_EXPR, type1, type2);
+ case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
+ return ref_xes_from_temporary (type1, type2, /*direct_init=*/true);
+
+ case CPTK_REF_CONVERTS_FROM_TEMPORARY:
+ return ref_xes_from_temporary (type1, type2, /*direct_init=*/false);
+
default:
gcc_unreachable ();
return false;
@@ -12088,6 +12094,8 @@ finish_trait_expr (location_t loc, cp_trait_kind kind, tree type1, tree type2)
case CPTK_IS_TRIVIALLY_CONSTRUCTIBLE:
case CPTK_IS_NOTHROW_ASSIGNABLE:
case CPTK_IS_NOTHROW_CONSTRUCTIBLE:
+ case CPTK_REF_CONSTRUCTS_FROM_TEMPORARY:
+ case CPTK_REF_CONVERTS_FROM_TEMPORARY:
if (!check_trait_type (type1)
|| !check_trait_type (type2))
return error_mark_node;
diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc
index 872c67e..baadc4b2 100644
--- a/gcc/diagnostic-format-json.cc
+++ b/gcc/diagnostic-format-json.cc
@@ -102,8 +102,8 @@ json_from_location_range (diagnostic_context *context,
if (loc_range->m_label)
{
label_text text (loc_range->m_label->get_text (range_idx));
- if (text.m_buffer)
- result->set ("label", new json::string (text.m_buffer));
+ if (text.get ())
+ result->set ("label", new json::string (text.get ()));
}
return result;
diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc
index 1e4ebc8..fc28d16 100644
--- a/gcc/diagnostic-format-sarif.cc
+++ b/gcc/diagnostic-format-sarif.cc
@@ -582,7 +582,7 @@ sarif_builder::make_location_object (const diagnostic_event &event)
/* "message" property (SARIF v2.1.0 section 3.28.5). */
label_text ev_desc = event.get_desc (false);
- json::object *message_obj = make_message_object (ev_desc.m_buffer);
+ json::object *message_obj = make_message_object (ev_desc.get ());
location_obj->set ("message", message_obj);
return location_obj;
diff --git a/gcc/diagnostic-show-locus.cc b/gcc/diagnostic-show-locus.cc
index 08dab20..9d430b5 100644
--- a/gcc/diagnostic-show-locus.cc
+++ b/gcc/diagnostic-show-locus.cc
@@ -1877,9 +1877,10 @@ struct pod_label_text
{}
pod_label_text (label_text &&other)
- : m_buffer (other.m_buffer), m_caller_owned (other.m_owned)
+ : m_buffer (const_cast<char*> (other.get ())),
+ m_caller_owned (other.is_owner ())
{
- other.moved_from ();
+ other.release ();
}
void maybe_free ()
@@ -1963,7 +1964,7 @@ layout::print_any_labels (linenum_type row)
/* Allow for labels that return NULL from their get_text
implementation (so e.g. such labels can control their own
visibility). */
- if (text.m_buffer == NULL)
+ if (text.get () == NULL)
continue;
labels.safe_push (line_label (m_policy, i, disp_col, std::move (text)));
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index a3797ae..7594245 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -409,6 +409,11 @@ Objective-C and Objective-C++ Dialects}.
-Wno-analyzer-double-fclose @gol
-Wno-analyzer-double-free @gol
-Wno-analyzer-exposure-through-output-file @gol
+-Wno-analyzer-fd-access-mode-mismatch @gol
+-Wno-analyzer-fd-double-close @gol
+-Wno-analyzer-fd-leak @gol
+-Wno-analyzer-fd-use-after-close @gol
+-Wno-analyzer-fd-use-without-check @gol
-Wno-analyzer-file-leak @gol
-Wno-analyzer-free-of-non-heap @gol
-Wno-analyzer-malloc-leak @gol
@@ -10194,6 +10199,11 @@ following warnings from @option{-fanalyzer}:
-Wanalyzer-double-fclose @gol
-Wanalyzer-double-free @gol
-Wanalyzer-exposure-through-output-file @gol
+-Wanalyzer-fd-access-mode-mismatch @gol
+-Wanalyzer-fd-double-close @gol
+-Wanalyzer-fd-leak @gol
+-Wanalyzer-fd-use-after-close @gol
+-Wanalyzer-fd-use-without-check @gol
-Wanalyzer-file-leak @gol
-Wanalyzer-free-of-non-heap @gol
-Wanalyzer-malloc-leak @gol
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index f13ce09..cfe1e6d 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,16 @@
+2022-07-15 Steve Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/104313
+ * trans-decl.cc (gfc_generate_return): Do not generate conflicting
+ fake results for functions with no result variable under -ff2c.
+
+2022-07-14 Harald Anlauf <anlauf@gmx.de>
+ Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/106209
+ * decl.cc (add_init_expr_to_sym): Handle bad initializers for
+ implied-shape arrays.
+
2022-07-12 Harald Anlauf <anlauf@gmx.de>
PR fortran/106049
diff --git a/gcc/fortran/decl.cc b/gcc/fortran/decl.cc
index 339f8b1..b640051 100644
--- a/gcc/fortran/decl.cc
+++ b/gcc/fortran/decl.cc
@@ -2129,10 +2129,21 @@ add_init_expr_to_sym (const char *name, gfc_expr **initp, locus *var_locus)
/* The shape may be NULL for EXPR_ARRAY, set it. */
if (init->shape == NULL)
{
- gcc_assert (init->expr_type == EXPR_ARRAY);
+ if (init->expr_type != EXPR_ARRAY)
+ {
+ gfc_error ("Bad shape of initializer at %L", &init->where);
+ return false;
+ }
+
init->shape = gfc_get_shape (1);
if (!gfc_array_size (init, &init->shape[0]))
- gfc_internal_error ("gfc_array_size failed");
+ {
+ gfc_error ("Cannot determine shape of initializer at %L",
+ &init->where);
+ free (init->shape);
+ init->shape = NULL;
+ return false;
+ }
}
for (dim = 0; dim < sym->as->rank; ++dim)
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 6493cc2..908a4c6 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -6474,7 +6474,7 @@ gfc_generate_return (void)
NULL_TREE, and a 'return' is generated without a variable.
The following generates a 'return __result_XXX' where XXX is
the function name. */
- if (sym == sym->result && sym->attr.function)
+ if (sym == sym->result && sym->attr.function && !flag_f2c)
{
result = gfc_get_fake_result_decl (sym, 0);
result = fold_build2_loc (input_location, MODIFY_EXPR,
diff --git a/gcc/gimple-pretty-print.cc b/gcc/gimple-pretty-print.cc
index ebd87b2..f18baec 100644
--- a/gcc/gimple-pretty-print.cc
+++ b/gcc/gimple-pretty-print.cc
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "ssa.h"
#include "cgraph.h"
#include "gimple-pretty-print.h"
+#include "value-range-pretty-print.h"
#include "internal-fn.h"
#include "tree-eh.h"
#include "gimple-iterator.h"
@@ -2335,35 +2336,10 @@ dump_ssaname_info (pretty_printer *buffer, tree node, int spc)
if (!POINTER_TYPE_P (TREE_TYPE (node))
&& SSA_NAME_RANGE_INFO (node))
{
- wide_int min, max, nonzero_bits;
- value_range r;
-
+ Value_Range r (TREE_TYPE (node));
get_global_range_query ()->range_of_expr (r, node);
- value_range_kind range_type = r.kind ();
- if (!r.undefined_p ())
- {
- min = wi::to_wide (r.min ());
- max = wi::to_wide (r.max ());
- }
-
- // FIXME: Use irange::dump() instead.
- if (range_type == VR_VARYING)
- pp_printf (buffer, "# RANGE VR_VARYING");
- else if (range_type == VR_RANGE || range_type == VR_ANTI_RANGE)
- {
- pp_printf (buffer, "# RANGE ");
- pp_printf (buffer, "%s[", range_type == VR_RANGE ? "" : "~");
- pp_wide_int (buffer, min, TYPE_SIGN (TREE_TYPE (node)));
- pp_printf (buffer, ", ");
- pp_wide_int (buffer, max, TYPE_SIGN (TREE_TYPE (node)));
- pp_printf (buffer, "]");
- }
- nonzero_bits = get_nonzero_bits (node);
- if (nonzero_bits != -1)
- {
- pp_string (buffer, " NONZERO ");
- pp_wide_int (buffer, nonzero_bits, UNSIGNED);
- }
+ pp_string (buffer, "# RANGE ");
+ pp_vrange (buffer, &r);
newline_and_indent (buffer, spc);
}
}
diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc
index 04990ad..2ac7ca0 100644
--- a/gcc/gimplify.cc
+++ b/gcc/gimplify.cc
@@ -573,20 +573,26 @@ create_tmp_from_val (tree val)
}
/* Create a temporary to hold the value of VAL. If IS_FORMAL, try to reuse
- an existing expression temporary. */
+ an existing expression temporary. If NOT_GIMPLE_REG, mark it as such. */
static tree
-lookup_tmp_var (tree val, bool is_formal)
+lookup_tmp_var (tree val, bool is_formal, bool not_gimple_reg)
{
tree ret;
+ /* We cannot mark a formal temporary with DECL_NOT_GIMPLE_REG_P. */
+ gcc_assert (!is_formal || !not_gimple_reg);
+
/* If not optimizing, never really reuse a temporary. local-alloc
won't allocate any variable that is used in more than one basic
block, which means it will go into memory, causing much extra
work in reload and final and poorer code generation, outweighing
the extra memory allocation here. */
if (!optimize || !is_formal || TREE_SIDE_EFFECTS (val))
- ret = create_tmp_from_val (val);
+ {
+ ret = create_tmp_from_val (val);
+ DECL_NOT_GIMPLE_REG_P (ret) = not_gimple_reg;
+ }
else
{
elt_t elt, *elt_p;
@@ -617,7 +623,7 @@ lookup_tmp_var (tree val, bool is_formal)
static tree
internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p,
- bool is_formal, bool allow_ssa)
+ bool is_formal, bool allow_ssa, bool not_gimple_reg)
{
tree t, mod;
@@ -639,7 +645,7 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p,
}
}
else
- t = lookup_tmp_var (val, is_formal);
+ t = lookup_tmp_var (val, is_formal, not_gimple_reg);
mod = build2 (INIT_EXPR, TREE_TYPE (t), t, unshare_expr (val));
@@ -667,7 +673,7 @@ internal_get_tmp_var (tree val, gimple_seq *pre_p, gimple_seq *post_p,
tree
get_formal_tmp_var (tree val, gimple_seq *pre_p)
{
- return internal_get_tmp_var (val, pre_p, NULL, true, true);
+ return internal_get_tmp_var (val, pre_p, NULL, true, true, false);
}
/* Return a temporary variable initialized with VAL. PRE_P and POST_P
@@ -678,7 +684,7 @@ get_initialized_tmp_var (tree val, gimple_seq *pre_p,
gimple_seq *post_p /* = NULL */,
bool allow_ssa /* = true */)
{
- return internal_get_tmp_var (val, pre_p, post_p, false, allow_ssa);
+ return internal_get_tmp_var (val, pre_p, post_p, false, allow_ssa, false);
}
/* Declare all the variables in VARS in SCOPE. If DEBUG_INFO is true,
@@ -4574,13 +4580,10 @@ prepare_gimple_addressable (tree *expr_p, gimple_seq *seq_p)
{
while (handled_component_p (*expr_p))
expr_p = &TREE_OPERAND (*expr_p, 0);
+
+ /* Do not allow an SSA name as the temporary. */
if (is_gimple_reg (*expr_p))
- {
- /* Do not allow an SSA name as the temporary. */
- tree var = get_initialized_tmp_var (*expr_p, seq_p, NULL, false);
- DECL_NOT_GIMPLE_REG_P (var) = 1;
- *expr_p = var;
- }
+ *expr_p = internal_get_tmp_var (*expr_p, seq_p, NULL, false, false, true);
}
/* A subroutine of gimplify_modify_expr. Replace a MODIFY_EXPR with
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index 5fdf423..5dbcb29 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,13 @@
+2022-07-16 Ian Lance Taylor <iant@golang.org>
+
+ * go-gcc.cc (Gcc_backend::struct_field_expression): Handle a void
+ expression, as for f().x where f returns a zero-sized type.
+
+2022-07-15 Ian Lance Taylor <iant@golang.org>
+
+ * go-gcc.cc (Gcc_backend::call_expression): Handle a void
+ argument, as for f(g()) where g returns a zero-sized type.
+
2022-06-02 David Malcolm <dmalcolm@redhat.com>
* go-lang.cc (go_get_sarif_source_language): New.
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index f3de7a8..1ba7206 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -1707,6 +1707,13 @@ Gcc_backend::struct_field_expression(Bexpression* bstruct, size_t index,
if (struct_tree == error_mark_node
|| TREE_TYPE(struct_tree) == error_mark_node)
return this->error_expression();
+
+ // A function call that returns a zero-sized object will have been
+ // changed to return void. A zero-sized object can have a
+ // (zero-sized) field, so support that case.
+ if (TREE_TYPE(struct_tree) == void_type_node)
+ return bstruct;
+
gcc_assert(TREE_CODE(TREE_TYPE(struct_tree)) == RECORD_TYPE);
tree field = TYPE_FIELDS(TREE_TYPE(struct_tree));
if (field == NULL_TREE)
@@ -2112,6 +2119,19 @@ Gcc_backend::call_expression(Bfunction*, // containing fcn for call
args[i] = fn_args.at(i)->get_tree();
if (args[i] == error_mark_node)
return this->error_expression();
+ if (TREE_TYPE(args[i]) == void_type_node)
+ {
+ // This can happen for a case like f(g()) where g returns a
+ // zero-sized type, because in that case we've changed g to
+ // return void.
+ tree t = TYPE_ARG_TYPES(TREE_TYPE(TREE_TYPE(fn)));
+ for (size_t j = 0; j < i; ++j)
+ t = TREE_CHAIN(t);
+ tree arg_type = TREE_TYPE(TREE_VALUE(t));
+ args[i] = fold_build2_loc(EXPR_LOCATION(args[i]), COMPOUND_EXPR,
+ arg_type, args[i],
+ build_zero_cst(arg_type));
+ }
}
tree fndecl = fn;
diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog
index d16b573..581f682 100644
--- a/gcc/jit/ChangeLog
+++ b/gcc/jit/ChangeLog
@@ -1,3 +1,10 @@
+2022-07-14 Jonathan Wakely <jwakely@redhat.com>
+
+ * jit-recording.h (recording::memento): Define copy constructor
+ and copy assignment operator as deleted.
+ (recording::string): Likewise.
+ (recording::string::c_str): Add const qualifier.
+
2022-06-29 Antoni Boucher <bouanto@zoho.com>
PR jit/105812
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 0dfb42f..8610ea9 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -405,6 +405,9 @@ public:
virtual void write_reproducer (reproducer &r) = 0;
virtual location *dyn_cast_location () { return NULL; }
+ memento (const memento&) = delete;
+ memento& operator= (const memento&) = delete;
+
protected:
memento (context *ctxt)
: m_ctxt (ctxt),
@@ -436,13 +439,16 @@ public:
string (context *ctxt, const char *text, bool escaped);
~string ();
- const char *c_str () { return m_buffer; }
+ const char *c_str () const { return m_buffer; }
static string * from_printf (context *ctxt, const char *fmt, ...)
GNU_PRINTF(2, 3);
void replay_into (replayer *) final override {}
+ string (const string&) = delete;
+ string& operator= (const string&) = delete;
+
private:
string * make_debug_string () final override;
void write_reproducer (reproducer &r) final override;
diff --git a/gcc/pretty-print.h b/gcc/pretty-print.h
index fc58844..d810e57 100644
--- a/gcc/pretty-print.h
+++ b/gcc/pretty-print.h
@@ -340,6 +340,13 @@ pp_get_prefix (const pretty_printer *pp) { return pp->prefix; }
pp_string (PP, pp_buffer (PP)->digit_buffer); \
} \
while (0)
+#define pp_vrange(PP, R) \
+ do \
+ { \
+ vrange_printer vrange_pp (PP); \
+ (R)->accept (vrange_pp); \
+ } \
+ while (0)
#define pp_double(PP, F) pp_scalar (PP, "%f", F)
#define pp_pointer(PP, P) pp_scalar (PP, "%p", P)
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 97b9f5f..cc8ea71 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,81 @@
+2022-07-15 H.J. Lu <hjl.tools@gmail.com>
+
+ PR target/85620
+ * gcc.target/i386/pr85620-2.c: Updated.
+ * gcc.target/i386/pr85620-5.c: New test.
+ * gcc.target/i386/pr85620-6.c: Likewise.
+ * gcc.target/i386/pr85620-7.c: Likewise.
+
+2022-07-15 Roger Sayle <roger@nextmovesoftware.com>
+
+ PR target/106273
+ * gcc.target/i386/pr106273.c: New test case.
+
+2022-07-15 Steve Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/104313
+ * gfortran.dg/pr104313.f: New test.
+
+2022-07-15 Marek Polacek <polacek@redhat.com>
+
+ PR c++/104477
+ * g++.dg/ext/reference_constructs_from_temporary1.C: New test.
+ * g++.dg/ext/reference_converts_from_temporary1.C: New test.
+
+2022-07-15 David Malcolm <dmalcolm@redhat.com>
+
+ PR analyzer/106284
+ * gcc.dg/analyzer/torture/taint-read-index-2.c: New test.
+
+2022-07-15 Roger Sayle <roger@nextmovesoftware.com>
+
+ * gcc.dg/pr106278.c: New test case.
+
+2022-07-15 konglin1 <lingling.kong@intel.com>
+
+ PR target/106113
+ * gcc.target/i386/avx-vcomisd-pr106113-2.c: New test.
+ * gcc.target/i386/avx-vcomiss-pr106113-2.c: Ditto.
+ * gcc.target/i386/avx-vucomisd-pr106113-2.c: Ditto.
+ * gcc.target/i386/avx-vucomiss-pr106113-2.c: Ditto.
+ * gcc.target/i386/sse-comiss-pr106113-1.c: Ditto.
+ * gcc.target/i386/sse-comiss-pr106113-2.c: Ditto.
+ * gcc.target/i386/sse-ucomiss-pr106113-1.c: Ditto.
+ * gcc.target/i386/sse-ucomiss-pr106113-2.c: Ditto.
+ * gcc.target/i386/sse2-comisd-pr106113-1.c: Ditto.
+ * gcc.target/i386/sse2-comisd-pr106113-2.c: Ditto.
+ * gcc.target/i386/sse2-ucomisd-pr106113-1.c: Ditto.
+ * gcc.target/i386/sse2-ucomisd-pr106113-2.c: Ditto.
+
+2022-07-14 H.J. Lu <hjl.tools@gmail.com>
+
+ PR tree-optimization/103798
+ * c-c++-common/pr103798-1.c: New test.
+ * c-c++-common/pr103798-2.c: Likewise.
+ * c-c++-common/pr103798-3.c: Likewise.
+ * c-c++-common/pr103798-4.c: Likewise.
+ * c-c++-common/pr103798-5.c: Likewise.
+ * c-c++-common/pr103798-6.c: Likewise.
+ * c-c++-common/pr103798-7.c: Likewise.
+ * c-c++-common/pr103798-8.c: Likewise.
+ * c-c++-common/pr103798-9.c: Likewise.
+ * c-c++-common/pr103798-10.c: Likewise.
+
+2022-07-14 Harald Anlauf <anlauf@gmx.de>
+ Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/106209
+ * gfortran.dg/pr106209.f90: New test.
+
+2022-07-14 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/opt98.ads, gnat.dg/opt98.adb: New test.
+
+2022-07-14 Takayuki 'January June' Suwa <jjsuwa_sys3175@yahoo.co.jp>
+
+ * gcc.target/xtensa/constsynth_double.c:
+ Modify in order to catch the issue.
+
2022-07-13 Patrick Palka <ppalka@redhat.com>
PR c++/105912
diff --git a/gcc/testsuite/c-c++-common/pr103798-1.c b/gcc/testsuite/c-c++-common/pr103798-1.c
new file mode 100644
index 0000000..cd3edf5
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-1.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int
+f (char a)
+{
+ return __builtin_memchr ("a", a, 1) == 0;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+ return a != 'a';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-10.c b/gcc/testsuite/c-c++-common/pr103798-10.c
new file mode 100644
index 0000000..4677e95
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-10.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fdump-tree-optimized -save-temps" } */
+
+int
+f (char a)
+{
+ return __builtin_memchr ("ac", a, 1) == 0;
+}
+
+/* { dg-final { scan-assembler "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-2.c b/gcc/testsuite/c-c++-common/pr103798-2.c
new file mode 100644
index 0000000..e7e99c3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-2.c
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+#include <string.h>
+
+__attribute__ ((weak))
+int
+f (int a)
+{
+ return memchr ("aE", a, 2) != NULL;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+ return a == 'a' || a == 'E';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i + 256) != g (i + 256))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-3.c b/gcc/testsuite/c-c++-common/pr103798-3.c
new file mode 100644
index 0000000..ddcedc7
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-3.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int
+f (char a)
+{
+ return __builtin_memchr ("aEgZ", a, 3) == 0;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+ return a != 'a' && a != 'E' && a != 'g';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-4.c b/gcc/testsuite/c-c++-common/pr103798-4.c
new file mode 100644
index 0000000..00e8302
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-4.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int
+f (char a)
+{
+ return __builtin_memchr ("aEgi", a, 4) != 0;
+}
+
+__attribute__ ((weak))
+int
+g (char a)
+{
+ return a == 'a' || a == 'E' || a == 'g' || a == 'i';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-5.c b/gcc/testsuite/c-c++-common/pr103798-5.c
new file mode 100644
index 0000000..0d6487a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-5.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int f(char a)
+{
+ return __builtin_memchr ("aEgiH", a, 5) == 0;
+}
+
+__attribute__ ((weak))
+int g(char a)
+{
+ return a != 'a' && a != 'E' && a != 'g' && a != 'i' && a != 'H';
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-6.c b/gcc/testsuite/c-c++-common/pr103798-6.c
new file mode 100644
index 0000000..5ccb5ee
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-6.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int f(char a)
+{
+ return __builtin_memchr ("aEgiHx", a, 6) != 0;
+}
+
+__attribute__ ((weak))
+int g(char a)
+{
+ return (a == 'a' || a == 'E' || a == 'g' || a == 'i' || a == 'H'
+ || a == 'x');
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-7.c b/gcc/testsuite/c-c++-common/pr103798-7.c
new file mode 100644
index 0000000..40fd382
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-7.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int f(char a)
+{
+ return __builtin_memchr ("aEgiHjZ", a, 7) == 0;
+}
+
+__attribute__ ((weak))
+int g(char a)
+{
+ return (a != 'a' && a != 'E' && a != 'g' && a != 'i' && a != 'H'
+ && a != 'j' && a != 'Z');
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i) != g (i))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-8.c b/gcc/testsuite/c-c++-common/pr103798-8.c
new file mode 100644
index 0000000..0841b18
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-8.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2 -fdump-tree-optimized -save-temps" } */
+
+__attribute__ ((weak))
+int f(int a)
+{
+ return __builtin_memchr ("aEgiHx19ABC", a, 8) != 0;
+}
+
+__attribute__ ((weak))
+int g(char a)
+{
+ return (a == 'a' || a == 'E' || a == 'g' || a == 'i' || a == 'H'
+ || a == 'x' || a == '1' || a == '9');
+}
+
+int
+main ()
+{
+ for (int i = 0; i < 255; i++)
+ if (f (i + 256) != g (i + 256))
+ __builtin_abort ();
+
+ return 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/c-c++-common/pr103798-9.c b/gcc/testsuite/c-c++-common/pr103798-9.c
new file mode 100644
index 0000000..c5f0f94
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr103798-9.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-Os -fdump-tree-optimized -save-temps" } */
+
+int
+f (char a)
+{
+ return __builtin_memchr ("a", a, 1) == 0;
+}
+
+/* { dg-final { scan-assembler-not "memchr" } } */
diff --git a/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C b/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C
new file mode 100644
index 0000000..76de905
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/reference_constructs_from_temporary1.C
@@ -0,0 +1,214 @@
+// P2255R2
+// PR c++/104477
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+struct A { A(); };
+struct B { operator A(); };
+struct C { explicit C(); };
+struct D { explicit operator A(); };
+struct E { explicit operator A&(); };
+struct F { explicit operator A&&(); };
+// Could use a class template with explicit(bool), but then this would need
+// C++20.
+struct G {
+ operator int();
+ explicit operator int&&();
+};
+struct G2 {
+ explicit operator int();
+ operator int&&();
+};
+struct H {
+ operator int();
+ explicit operator int&();
+};
+struct H2 {
+ explicit operator int();
+ operator int&();
+};
+
+struct Base { };
+struct Der : Base { };
+
+template<typename T, typename RT>
+struct morph {
+ mutable T val{};
+ operator RT() const { return static_cast<RT>(val); }
+};
+
+template<typename T> using id = T;
+
+// Built-in types.
+SA(!__reference_constructs_from_temporary(int, int));
+SA(!__reference_constructs_from_temporary(int&, void));
+SA(!__reference_constructs_from_temporary(int&, const void));
+SA(!__reference_constructs_from_temporary(int&, volatile void));
+SA(!__reference_constructs_from_temporary(int&, const volatile void));
+SA(!__reference_constructs_from_temporary(void, void));
+SA(!__reference_constructs_from_temporary(void, int));
+SA(!__reference_constructs_from_temporary(int&, int));
+SA(!__reference_constructs_from_temporary(int&, int&));
+SA(!__reference_constructs_from_temporary(int&, int&&));
+SA(!__reference_constructs_from_temporary(int&, long));
+// non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'long'
+SA(!__reference_constructs_from_temporary(int&, long&));
+SA(!__reference_constructs_from_temporary(int&, long&&));
+SA( __reference_constructs_from_temporary(const int&, int));
+SA(!__reference_constructs_from_temporary(const int&, int&));
+SA(!__reference_constructs_from_temporary(const int&, const int&));
+SA(!__reference_constructs_from_temporary(const int&, int&&));
+SA( __reference_constructs_from_temporary(const int&, long));
+SA( __reference_constructs_from_temporary(const int&, long&));
+SA( __reference_constructs_from_temporary(const int&, long&&));
+SA( __reference_constructs_from_temporary(int&&, int));
+SA(!__reference_constructs_from_temporary(int&&, int&));
+SA(!__reference_constructs_from_temporary(int&&, int&&));
+SA( __reference_constructs_from_temporary(int&&, long));
+SA( __reference_constructs_from_temporary(int&&, long&));
+SA( __reference_constructs_from_temporary(int&&, long&&));
+SA(!__reference_constructs_from_temporary(unsigned int&, double));
+SA(!__reference_constructs_from_temporary(volatile int&, int));
+SA(!__reference_constructs_from_temporary(const volatile int&, int));
+SA(!__reference_constructs_from_temporary(volatile int&, int&));
+SA(!__reference_constructs_from_temporary(const volatile int&, int&));
+SA(!__reference_constructs_from_temporary(volatile int&, int&&));
+SA(!__reference_constructs_from_temporary(const volatile int&, int&&));
+
+// Classes.
+SA(!__reference_constructs_from_temporary(A, A));
+// A& r(A{}); doesn't construct.
+SA(!__reference_constructs_from_temporary(A&, A));
+SA(!__reference_constructs_from_temporary(A&, A&));
+SA(!__reference_constructs_from_temporary(A&, A&&));
+// Here we get const struct A & r = (const struct A &) &D.2414;
+SA( __reference_constructs_from_temporary(const A&, A));
+SA(!__reference_constructs_from_temporary(const A&, A&));
+SA(!__reference_constructs_from_temporary(const A&, const A&));
+SA(!__reference_constructs_from_temporary(const A&, A&&));
+// Here we get struct A & r = (struct A &) &D.2439;
+SA( __reference_constructs_from_temporary(A&&, A));
+SA(!__reference_constructs_from_temporary(A&&, A&));
+SA(!__reference_constructs_from_temporary(A&&, const A&));
+SA(!__reference_constructs_from_temporary(A&&, A&&));
+
+SA(!__reference_constructs_from_temporary(A, B));
+SA(!__reference_constructs_from_temporary(A&, B));
+SA(!__reference_constructs_from_temporary(A&, B&));
+SA(!__reference_constructs_from_temporary(A&, const B&));
+SA(!__reference_constructs_from_temporary(A&, B&&));
+SA( __reference_constructs_from_temporary(const A&, B));
+SA( __reference_constructs_from_temporary(const A&, B&));
+// Doesn't construct, so it's false.
+SA(!__reference_constructs_from_temporary(const A&, const B&));
+SA( __reference_constructs_from_temporary(const A&, B&&));
+SA( __reference_constructs_from_temporary(A&&, B));
+SA( __reference_constructs_from_temporary(A&&, B&));
+SA(!__reference_constructs_from_temporary(A&&, const B&));
+SA( __reference_constructs_from_temporary(A&&, B&&));
+
+SA(!__reference_constructs_from_temporary(const A&, C));
+SA(!__reference_constructs_from_temporary(const A&, C&));
+
+// Doesn't construct, so it's false.
+SA(!__reference_constructs_from_temporary(int&, morph<int, int>));
+// Here we get
+// const int & r2 = D.2580 = morph<int, int>::operator int
+// (&TARGET_EXPR <D.2578, {.val=0}>); (const int &) &D.2580;
+SA( __reference_constructs_from_temporary(const int&, morph<int, int>));
+SA(!__reference_constructs_from_temporary(int&, morph<int, int&>));
+SA(!__reference_constructs_from_temporary(int&, morph<int, const int&>));
+SA(!__reference_constructs_from_temporary(int&, morph<int, int&&>));
+SA( __reference_constructs_from_temporary(const int&, morph<long, long&>));
+
+// These are like const C& c(cref); so the explicit ctor C isn't a problem
+// even in copy-init context. const C& r = {}; would be a different story.
+SA(!__reference_constructs_from_temporary(C, C));
+SA(!__reference_constructs_from_temporary(C&, C));
+SA(!__reference_constructs_from_temporary(C&, C&));
+SA(!__reference_constructs_from_temporary(C&, C&&));
+SA( __reference_constructs_from_temporary(const C&, C));
+SA(!__reference_constructs_from_temporary(const C&, C&));
+SA(!__reference_constructs_from_temporary(const C&, const C&));
+SA(!__reference_constructs_from_temporary(const C&, C&&));
+SA( __reference_constructs_from_temporary(C&&, C));
+SA(!__reference_constructs_from_temporary(C&&, C&));
+SA(!__reference_constructs_from_temporary(C&&, const C&));
+SA(!__reference_constructs_from_temporary(C&&, C&&));
+
+// These are all false ultimately because of CWG 2267, which we implement.
+SA(!__reference_constructs_from_temporary(A, D));
+SA(!__reference_constructs_from_temporary(A&, D));
+SA(!__reference_constructs_from_temporary(A&, D&));
+SA(!__reference_constructs_from_temporary(A&, const D&));
+SA(!__reference_constructs_from_temporary(A&, D&&));
+SA(!__reference_constructs_from_temporary(const A&, D));
+SA(!__reference_constructs_from_temporary(const A&, D&));
+SA(!__reference_constructs_from_temporary(const A&, const D&));
+SA(!__reference_constructs_from_temporary(const A&, D&&));
+SA(!__reference_constructs_from_temporary(A&&, D));
+SA(!__reference_constructs_from_temporary(A&&, D&));
+SA(!__reference_constructs_from_temporary(A&&, const D&));
+SA(!__reference_constructs_from_temporary(A&&, D&&));
+
+SA(!__reference_constructs_from_temporary(A, E));
+/* A& a1(E{}); compiles, but A& a2 = E{}; doesn't.
+ With the former, we get A& a = E::operator A& (&TARGET_EXPR <D.2715, {}>)
+ so we're not binding the reference to a temporary, although there is
+ a temporary involved. So the result is false in both copy- and direct-
+ init, albeit for different reasons! */
+SA(!__reference_constructs_from_temporary(A&, E));
+// A& a = E::operator A& ((struct E *) r)); copy-init doesn't compile.
+SA(!__reference_constructs_from_temporary(A&, E&));
+SA(!__reference_constructs_from_temporary(A&, const E&));
+SA(!__reference_constructs_from_temporary(A&, E&&));
+// direct-init:
+// const A& a = (const struct A &) E::operator A& (&TARGET_EXPR <D.2720, {}>)
+SA(!__reference_constructs_from_temporary(const A&, E));
+SA(!__reference_constructs_from_temporary(const A&, E&));
+SA(!__reference_constructs_from_temporary(const A&, const E&));
+SA(!__reference_constructs_from_temporary(const A&, E&&));
+SA(!__reference_constructs_from_temporary(A&&, E));
+SA(!__reference_constructs_from_temporary(A&&, E&));
+SA(!__reference_constructs_from_temporary(A&&, const E&));
+SA(!__reference_constructs_from_temporary(A&&, E&&));
+
+SA(!__reference_constructs_from_temporary(A, F));
+// A& a1(F{}); and A& a2 = F{}; both invalid.
+SA(!__reference_constructs_from_temporary(A&, F));
+SA(!__reference_constructs_from_temporary(A&, F&));
+SA(!__reference_constructs_from_temporary(A&, const F&));
+SA(!__reference_constructs_from_temporary(A&, F&&));
+SA(!__reference_constructs_from_temporary(const A&, F));
+SA(!__reference_constructs_from_temporary(const A&, F&));
+SA(!__reference_constructs_from_temporary(const A&, const F&));
+SA(!__reference_constructs_from_temporary(const A&, F&&));
+SA(!__reference_constructs_from_temporary(A&&, F));
+SA(!__reference_constructs_from_temporary(A&&, F&));
+SA(!__reference_constructs_from_temporary(A&&, const F&));
+SA(!__reference_constructs_from_temporary(A&&, F&&));
+
+/* This is where _converts_ and _constructs_ will differ:
+ in direct-init we use G::operator int&& (no temporary),
+ but in copy-init we use G::operator int, where a temporary is created
+ to be bound to int&&. */
+SA(!__reference_constructs_from_temporary(int&&, G));
+// Similar to the previous one.
+SA(!__reference_constructs_from_temporary(const int&, H));
+/* And here I've switched the explicit-ness. In both copy- and direct-init
+ we call operator int&, so no temporary. */
+SA(!__reference_constructs_from_temporary(int&&, G2));
+SA(!__reference_constructs_from_temporary(const int&, H2));
+
+SA(!__reference_constructs_from_temporary(const Base&, Der));
+
+// This fails because std::is_constructible_v<int&&, id<int[3]>> is false.
+SA(!__reference_constructs_from_temporary(int&&, id<int[3]>));
+
+// Arrays.
+SA(!__reference_constructs_from_temporary(int, int[]));
+SA(!__reference_constructs_from_temporary(int[], int[]));
+SA(!__reference_constructs_from_temporary(int&, int[]));
+SA(!__reference_constructs_from_temporary(int&&, int[]));
+SA(!__reference_constructs_from_temporary(const int&, int[]));
diff --git a/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C b/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C
new file mode 100644
index 0000000..90196c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/reference_converts_from_temporary1.C
@@ -0,0 +1,214 @@
+// P2255R2
+// PR c++/104477
+// { dg-do compile { target c++11 } }
+
+#define SA(X) static_assert((X),#X)
+
+struct A { A(); };
+struct B { operator A(); };
+struct C { explicit C(); };
+struct D { explicit operator A(); };
+struct E { explicit operator A&(); };
+struct F { explicit operator A&&(); };
+// Could use a class template with explicit(bool), but then this would need
+// C++20.
+struct G {
+ operator int();
+ explicit operator int&&();
+};
+struct G2 {
+ explicit operator int();
+ operator int&&();
+};
+struct H {
+ operator int();
+ explicit operator int&();
+};
+struct H2 {
+ explicit operator int();
+ operator int&();
+};
+
+struct Base { };
+struct Der : Base { };
+
+template<typename T, typename RT>
+struct morph {
+ mutable T val{};
+ operator RT() const { return static_cast<RT>(val); }
+};
+
+template<typename T> using id = T;
+
+// Built-in types.
+SA(!__reference_converts_from_temporary(int, int));
+SA(!__reference_converts_from_temporary(int&, void));
+SA(!__reference_converts_from_temporary(int&, const void));
+SA(!__reference_converts_from_temporary(int&, volatile void));
+SA(!__reference_converts_from_temporary(int&, const volatile void));
+SA(!__reference_converts_from_temporary(void, void));
+SA(!__reference_converts_from_temporary(void, int));
+SA(!__reference_converts_from_temporary(int&, int));
+SA(!__reference_converts_from_temporary(int&, int&));
+SA(!__reference_converts_from_temporary(int&, int&&));
+SA(!__reference_converts_from_temporary(int&, long));
+// non-const lvalue reference to type 'int' cannot bind to a value of unrelated type 'long'
+SA(!__reference_converts_from_temporary(int&, long&));
+SA(!__reference_converts_from_temporary(int&, long&&));
+SA( __reference_converts_from_temporary(const int&, int));
+SA(!__reference_converts_from_temporary(const int&, int&));
+SA(!__reference_converts_from_temporary(const int&, const int&));
+SA(!__reference_converts_from_temporary(const int&, int&&));
+SA( __reference_converts_from_temporary(const int&, long));
+SA( __reference_converts_from_temporary(const int&, long&));
+SA( __reference_converts_from_temporary(const int&, long&&));
+SA( __reference_converts_from_temporary(int&&, int));
+SA(!__reference_converts_from_temporary(int&&, int&));
+SA(!__reference_converts_from_temporary(int&&, int&&));
+SA( __reference_converts_from_temporary(int&&, long));
+SA( __reference_converts_from_temporary(int&&, long&));
+SA( __reference_converts_from_temporary(int&&, long&&));
+SA(!__reference_converts_from_temporary(unsigned int&, double));
+SA(!__reference_converts_from_temporary(volatile int&, int));
+SA(!__reference_converts_from_temporary(const volatile int&, int));
+SA(!__reference_converts_from_temporary(volatile int&, int&));
+SA(!__reference_converts_from_temporary(const volatile int&, int&));
+SA(!__reference_converts_from_temporary(volatile int&, int&&));
+SA(!__reference_converts_from_temporary(const volatile int&, int&&));
+
+// Classes.
+SA(!__reference_converts_from_temporary(A, A));
+// A& r(A{}); doesn't construct.
+SA(!__reference_converts_from_temporary(A&, A));
+SA(!__reference_converts_from_temporary(A&, A&));
+SA(!__reference_converts_from_temporary(A&, A&&));
+// Here we get const struct A & r = (const struct A &) &D.2414;
+SA( __reference_converts_from_temporary(const A&, A));
+SA(!__reference_converts_from_temporary(const A&, A&));
+SA(!__reference_converts_from_temporary(const A&, const A&));
+SA(!__reference_converts_from_temporary(const A&, A&&));
+// Here we get struct A & r = (struct A &) &D.2439;
+SA( __reference_converts_from_temporary(A&&, A));
+SA(!__reference_converts_from_temporary(A&&, A&));
+SA(!__reference_converts_from_temporary(A&&, const A&));
+SA(!__reference_converts_from_temporary(A&&, A&&));
+
+SA(!__reference_converts_from_temporary(A, B));
+SA(!__reference_converts_from_temporary(A&, B));
+SA(!__reference_converts_from_temporary(A&, B&));
+SA(!__reference_converts_from_temporary(A&, const B&));
+SA(!__reference_converts_from_temporary(A&, B&&));
+SA( __reference_converts_from_temporary(const A&, B));
+SA( __reference_converts_from_temporary(const A&, B&));
+// Doesn't construct, so it's false.
+SA(!__reference_converts_from_temporary(const A&, const B&));
+SA( __reference_converts_from_temporary(const A&, B&&));
+SA( __reference_converts_from_temporary(A&&, B));
+SA( __reference_converts_from_temporary(A&&, B&));
+SA(!__reference_converts_from_temporary(A&&, const B&));
+SA( __reference_converts_from_temporary(A&&, B&&));
+
+SA(!__reference_converts_from_temporary(const A&, C));
+SA(!__reference_converts_from_temporary(const A&, C&));
+
+// Doesn't construct, so it's false.
+SA(!__reference_converts_from_temporary(int&, morph<int, int>));
+// Here we get
+// const int & r2 = D.2580 = morph<int, int>::operator int
+// (&TARGET_EXPR <D.2578, {.val=0}>); (const int &) &D.2580;
+SA( __reference_converts_from_temporary(const int&, morph<int, int>));
+SA(!__reference_converts_from_temporary(int&, morph<int, int&>));
+SA(!__reference_converts_from_temporary(int&, morph<int, const int&>));
+SA(!__reference_converts_from_temporary(int&, morph<int, int&&>));
+SA( __reference_converts_from_temporary(const int&, morph<long, long&>));
+
+// These are like const C& c(cref); so the explicit ctor C isn't a problem
+// even in copy-init context. const C& r = {}; would be a different story.
+SA(!__reference_converts_from_temporary(C, C));
+SA(!__reference_converts_from_temporary(C&, C));
+SA(!__reference_converts_from_temporary(C&, C&));
+SA(!__reference_converts_from_temporary(C&, C&&));
+SA( __reference_converts_from_temporary(const C&, C));
+SA(!__reference_converts_from_temporary(const C&, C&));
+SA(!__reference_converts_from_temporary(const C&, const C&));
+SA(!__reference_converts_from_temporary(const C&, C&&));
+SA( __reference_converts_from_temporary(C&&, C));
+SA(!__reference_converts_from_temporary(C&&, C&));
+SA(!__reference_converts_from_temporary(C&&, const C&));
+SA(!__reference_converts_from_temporary(C&&, C&&));
+
+// These are all false ultimately because of CWG 2267, which we implement.
+SA(!__reference_converts_from_temporary(A, D));
+SA(!__reference_converts_from_temporary(A&, D));
+SA(!__reference_converts_from_temporary(A&, D&));
+SA(!__reference_converts_from_temporary(A&, const D&));
+SA(!__reference_converts_from_temporary(A&, D&&));
+SA(!__reference_converts_from_temporary(const A&, D));
+SA(!__reference_converts_from_temporary(const A&, D&));
+SA(!__reference_converts_from_temporary(const A&, const D&));
+SA(!__reference_converts_from_temporary(const A&, D&&));
+SA(!__reference_converts_from_temporary(A&&, D));
+SA(!__reference_converts_from_temporary(A&&, D&));
+SA(!__reference_converts_from_temporary(A&&, const D&));
+SA(!__reference_converts_from_temporary(A&&, D&&));
+
+SA(!__reference_converts_from_temporary(A, E));
+/* A& a1(E{}); compiles, but A& a2 = E{}; doesn't.
+ With the former, we get A& a = E::operator A& (&TARGET_EXPR <D.2715, {}>)
+ so we're not binding the reference to a temporary, although there is
+ a temporary involved. So the result is false in both copy- and direct-
+ init, albeit for different reasons! */
+SA(!__reference_converts_from_temporary(A&, E));
+// A& a = E::operator A& ((struct E *) r)); copy-init doesn't compile.
+SA(!__reference_converts_from_temporary(A&, E&));
+SA(!__reference_converts_from_temporary(A&, const E&));
+SA(!__reference_converts_from_temporary(A&, E&&));
+// direct-init:
+// const A& a = (const struct A &) E::operator A& (&TARGET_EXPR <D.2720, {}>)
+SA(!__reference_converts_from_temporary(const A&, E));
+SA(!__reference_converts_from_temporary(const A&, E&));
+SA(!__reference_converts_from_temporary(const A&, const E&));
+SA(!__reference_converts_from_temporary(const A&, E&&));
+SA(!__reference_converts_from_temporary(A&&, E));
+SA(!__reference_converts_from_temporary(A&&, E&));
+SA(!__reference_converts_from_temporary(A&&, const E&));
+SA(!__reference_converts_from_temporary(A&&, E&&));
+
+SA(!__reference_converts_from_temporary(A, F));
+// A& a1(F{}); and A& a2 = F{}; both invalid.
+SA(!__reference_converts_from_temporary(A&, F));
+SA(!__reference_converts_from_temporary(A&, F&));
+SA(!__reference_converts_from_temporary(A&, const F&));
+SA(!__reference_converts_from_temporary(A&, F&&));
+SA(!__reference_converts_from_temporary(const A&, F));
+SA(!__reference_converts_from_temporary(const A&, F&));
+SA(!__reference_converts_from_temporary(const A&, const F&));
+SA(!__reference_converts_from_temporary(const A&, F&&));
+SA(!__reference_converts_from_temporary(A&&, F));
+SA(!__reference_converts_from_temporary(A&&, F&));
+SA(!__reference_converts_from_temporary(A&&, const F&));
+SA(!__reference_converts_from_temporary(A&&, F&&));
+
+/* This is where _converts_ and _constructs_ will differ:
+ in direct-init we use G::operator int&& (no temporary),
+ but in copy-init we use G::operator int, where a temporary is created
+ to be bound to int&&. */
+SA( __reference_converts_from_temporary(int&&, G));
+// Similar to the previous one.
+SA( __reference_converts_from_temporary(const int&, H));
+/* And here I've switched the explicit-ness. In both copy- and direct-init
+ we call operator int&, so no temporary. */
+SA(!__reference_converts_from_temporary(int&&, G2));
+SA(!__reference_converts_from_temporary(const int&, H2));
+
+SA(!__reference_converts_from_temporary(const Base&, Der));
+
+// This fails because std::is_constructible_v<int&&, id<int[3]>> is false.
+SA(!__reference_converts_from_temporary(int&&, id<int[3]>));
+
+// Arrays.
+SA(!__reference_converts_from_temporary(int, int[]));
+SA(!__reference_converts_from_temporary(int[], int[]));
+SA(!__reference_converts_from_temporary(int&, int[]));
+SA(!__reference_converts_from_temporary(int&&, int[]));
+SA(!__reference_converts_from_temporary(const int&, int[]));
diff --git a/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c b/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c
new file mode 100644
index 0000000..6a4ebdb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/torture/taint-read-index-2.c
@@ -0,0 +1,56 @@
+// TODO: remove need for the taint option:
+/* { dg-additional-options "-fanalyzer-checker=taint" } */
+/* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */
+
+#define LOWER_LIMIT 5
+#define UPPER_LIMIT 20
+
+static int arr[UPPER_LIMIT];
+
+static int
+called_by_test_1 (int iarg)
+{
+ return arr[iarg]; /* { dg-warning "without bounds checking" } */
+}
+
+int __attribute__((tainted_args))
+test_1 (unsigned long ularg)
+{
+ return called_by_test_1 (ularg);
+}
+
+static int
+called_by_test_2 (int iarg)
+{
+ if (iarg < LOWER_LIMIT || iarg > UPPER_LIMIT)
+ return 0;
+ return arr[iarg]; /* { dg-bogus "bounds checking" } */
+}
+
+int __attribute__((tainted_args))
+test_2 (unsigned long ularg)
+{
+ return called_by_test_2 (ularg);
+}
+
+int __attribute__((tainted_args))
+test_3 (int iarg)
+{
+ if (iarg < LOWER_LIMIT || iarg > UPPER_LIMIT)
+ return 0;
+ return arr[iarg]; /* { dg-bogus "bounds checking" } */
+}
+
+static int
+called_by_test_4 (int iarg)
+{
+ if (iarg < LOWER_LIMIT || iarg > UPPER_LIMIT)
+ return 0;
+ return arr[iarg]; /* { dg-bogus "bounds checking" } */
+}
+
+int __attribute__((tainted_args))
+test_4 (unsigned uarg)
+{
+ return called_by_test_4 (uarg);
+}
diff --git a/gcc/testsuite/gcc.dg/pr106278.c b/gcc/testsuite/gcc.dg/pr106278.c
new file mode 100644
index 0000000..ab312b3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr106278.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+void __assert_fail();
+struct a {
+ int b;
+ int c;
+ int d;
+ int : 2;
+};
+int e, f;
+struct a g, i;
+const struct a h;
+int main() {
+ struct a j;
+ g = h;
+ if (e)
+ __assert_fail();
+ if (f)
+ j = h;
+ i = j;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/avx-vcomisd-pr106113-2.c b/gcc/testsuite/gcc.target/i386/avx-vcomisd-pr106113-2.c
new file mode 100644
index 0000000..9025b1b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx-vcomisd-pr106113-2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-require-effective-target avx } */
+/* { dg-options "-O2 -mavx" } */
+
+#define CHECK_H "avx-check.h"
+#define TEST avx_test
+
+#include "sse2-comisd-pr106113-2.c"
diff --git a/gcc/testsuite/gcc.target/i386/avx-vcomiss-pr106113-2.c b/gcc/testsuite/gcc.target/i386/avx-vcomiss-pr106113-2.c
new file mode 100644
index 0000000..dc0bf51
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx-vcomiss-pr106113-2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-require-effective-target avx } */
+/* { dg-options "-O2 -mavx" } */
+
+#define CHECK_H "avx-check.h"
+#define TEST avx_test
+
+#include "sse-comiss-pr106113-2.c"
diff --git a/gcc/testsuite/gcc.target/i386/avx-vucomisd-pr106113-2.c b/gcc/testsuite/gcc.target/i386/avx-vucomisd-pr106113-2.c
new file mode 100644
index 0000000..3b0c5db
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx-vucomisd-pr106113-2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-require-effective-target avx } */
+/* { dg-options "-O2 -mavx" } */
+
+#define CHECK_H "avx-check.h"
+#define TEST avx_test
+
+#include "sse2-ucomisd-pr106113-2.c"
diff --git a/gcc/testsuite/gcc.target/i386/avx-vucomiss-pr106113-2.c b/gcc/testsuite/gcc.target/i386/avx-vucomiss-pr106113-2.c
new file mode 100644
index 0000000..d67e4ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx-vucomiss-pr106113-2.c
@@ -0,0 +1,8 @@
+/* { dg-do run } */
+/* { dg-require-effective-target avx } */
+/* { dg-options "-O2 -mavx" } */
+
+#define CHECK_H "avx-check.h"
+#define TEST avx_test
+
+#include "sse-ucomiss-pr106113-2.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr106231-1.c b/gcc/testsuite/gcc.target/i386/pr106231-1.c
new file mode 100644
index 0000000..d17297f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr106231-1.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mtune=generic" } */
+long long
+foo(long long x, unsigned bits)
+{
+ return x + (unsigned) __builtin_ctz(bits);
+}
+/* { dg-final { scan-assembler-not "cltq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr106231-2.c b/gcc/testsuite/gcc.target/i386/pr106231-2.c
new file mode 100644
index 0000000..fd3a8e3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr106231-2.c
@@ -0,0 +1,8 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-options "-O2 -mtune=ivybridge" } */
+long long
+foo(long long x, unsigned bits)
+{
+ return x + (unsigned) __builtin_ctz(bits);
+}
+/* { dg-final { scan-assembler-not "cltq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr106273.c b/gcc/testsuite/gcc.target/i386/pr106273.c
new file mode 100644
index 0000000..0f42213
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr106273.c
@@ -0,0 +1,27 @@
+/* { dg-do compile { target int128 } } */
+/* { dg-options "-Og -march=cascadelake" } */
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned long long u64;
+
+u8 g;
+
+void
+foo (__int128 i, u8 *r)
+{
+ u16 a = __builtin_sub_overflow_p (0, i * g, 0);
+ i ^= g & i;
+ u64 s = (i >> 64) + i;
+ *r = ((union { u16 a; u8 b[2]; }) a).b[1] + s;
+}
+
+int
+bar (void)
+{
+ u8 x;
+ foo (5, &x);
+ if (x != 5)
+ __builtin_abort ();
+ return 0;
+}
+/* { dg-final { scan-assembler-not "andn\[ \\t\]+%rdi, %r11, %rdi" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr85620-2.c b/gcc/testsuite/gcc.target/i386/pr85620-2.c
index b2e680f..14ce0ff 100644
--- a/gcc/testsuite/gcc.target/i386/pr85620-2.c
+++ b/gcc/testsuite/gcc.target/i386/pr85620-2.c
@@ -1,6 +1,7 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fcf-protection" } */
-/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+/* { dg-final { scan-assembler-not "jmp" } } */
struct ucontext;
diff --git a/gcc/testsuite/gcc.target/i386/pr85620-5.c b/gcc/testsuite/gcc.target/i386/pr85620-5.c
new file mode 100644
index 0000000..0453770
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr85620-5.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler-not "jmp" } } */
+
+struct ucontext;
+
+extern int (*bar) (struct ucontext *) __attribute__((__indirect_return__));
+
+int
+foo (struct ucontext *oucp)
+{
+ return bar (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr85620-6.c b/gcc/testsuite/gcc.target/i386/pr85620-6.c
new file mode 100644
index 0000000..0b6a64e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr85620-6.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler "jmp" } } */
+
+struct ucontext;
+
+extern int bar (struct ucontext *) __attribute__((__indirect_return__));
+
+__attribute__((__indirect_return__))
+int
+foo (struct ucontext *oucp)
+{
+ return bar (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr85620-7.c b/gcc/testsuite/gcc.target/i386/pr85620-7.c
new file mode 100644
index 0000000..fa62d56
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr85620-7.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection" } */
+/* { dg-final { scan-assembler "jmp" } } */
+
+struct ucontext;
+
+extern int (*bar) (struct ucontext *) __attribute__((__indirect_return__));
+extern int foo (struct ucontext *) __attribute__((__indirect_return__));
+
+int
+foo (struct ucontext *oucp)
+{
+ return bar (oucp);
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-1.c b/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-1.c
new file mode 100644
index 0000000..9562102
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-msse -O2" } */
+/* { dg-final { scan-assembler-times "comiss\[ \\t\]+\[^\n\]*\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 6 } } */
+/* { dg-final { scan-assembler-times "jp" 2 } } */
+#include <xmmintrin.h>
+
+volatile __m128 x1, x2;
+volatile int res;
+
+void extern
+sse_comi_test (void)
+{
+ res = _mm_comieq_ss (x1, x2);
+ res = _mm_comilt_ss (x1, x2);
+ res = _mm_comile_ss (x1, x2);
+ res = _mm_comigt_ss (x1, x2);
+ res = _mm_comige_ss (x1, x2);
+ res = _mm_comineq_ss (x1, x2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-2.c b/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-2.c
new file mode 100644
index 0000000..a90f333
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse-comiss-pr106113-2.c
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -msse" } */
+/* { dg-require-effective-target sse } */
+
+#ifndef CHECK_H
+#define CHECK_H "sse-check.h"
+#endif
+
+#ifndef TEST
+#define TEST sse_test
+#endif
+
+#include CHECK_H
+
+#include <xmmintrin.h>
+
+#define CMP(PRED, EXP) \
+ res = _mm_comi##PRED##_ss (__A, __B); \
+ if (res != EXP) \
+ abort ();
+static void
+__attribute__((noinline, unused))
+do_check (float s1, float s2)
+{
+ __m128 __A = _mm_load_ss (&s1);
+ __m128 __B = _mm_load_ss (&s2);
+ int res;
+
+ CMP (eq, (!__builtin_isunordered (s1, s2) && s1 == s2));
+ CMP (ge, (!__builtin_isunordered (s1, s2) && s1 >= s2));
+ CMP (gt, (!__builtin_isunordered (s1, s2) && s1 > s2));
+ CMP (lt, (!__builtin_isunordered (s1, s2) && s1 < s2));
+ CMP (le, (!__builtin_isunordered (s1, s2) && s1 <= s2));
+ CMP (neq, (__builtin_isunordered (s1, s2) || s1 != s2));
+}
+
+static void
+TEST (void)
+{
+ struct
+ {
+ float x1;
+ float x2;
+ }
+ inputs[] =
+ {
+ { 4.3, 2.18 },
+ { -4.3, 3.18 },
+ { __builtin_nanf (""), -5.8 },
+ { -4.8, __builtin_nansf ("") },
+ { 3.8, __builtin_nansf ("") },
+ { 4.2, 4.2 },
+ { __builtin_nanf (""), __builtin_nansf ("") },
+ };
+ int i;
+
+ for (i = 0; i < sizeof (inputs) / sizeof (inputs[0]); i++)
+ do_check (inputs[i].x1, inputs[i].x2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-1.c b/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-1.c
new file mode 100644
index 0000000..e337e11
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-msse -O2" } */
+/* { dg-final { scan-assembler-times "ucomiss\[ \\t\]+\[^\n\]*\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 6 } } */
+/* { dg-final { scan-assembler-times "jp" 2 } } */
+#include <xmmintrin.h>
+
+volatile __m128 x1, x2;
+volatile int res;
+
+void extern
+sse_ucomi_test (void)
+{
+ res = _mm_ucomieq_ss (x1, x2);
+ res = _mm_ucomilt_ss (x1, x2);
+ res = _mm_ucomile_ss (x1, x2);
+ res = _mm_ucomigt_ss (x1, x2);
+ res = _mm_ucomige_ss (x1, x2);
+ res = _mm_ucomineq_ss (x1, x2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-2.c b/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-2.c
new file mode 100644
index 0000000..37d8450
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse-ucomiss-pr106113-2.c
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -msse" } */
+/* { dg-require-effective-target sse } */
+
+#ifndef CHECK_H
+#define CHECK_H "sse-check.h"
+#endif
+
+#ifndef TEST
+#define TEST sse_test
+#endif
+
+#include CHECK_H
+
+#include <xmmintrin.h>
+
+#define CMP(PRED, EXP) \
+ res = _mm_ucomi##PRED##_ss (__A, __B); \
+ if (res != EXP) \
+ abort ();
+static void
+__attribute__((noinline, unused))
+do_check (float s1, float s2)
+{
+ __m128 __A = _mm_load_ss (&s1);
+ __m128 __B = _mm_load_ss (&s2);
+ int res;
+
+ CMP (eq, (!__builtin_isunordered (s1, s2) && s1 == s2));
+ CMP (ge, (!__builtin_isunordered (s1, s2) && s1 >= s2));
+ CMP (gt, (!__builtin_isunordered (s1, s2) && s1 > s2));
+ CMP (lt, (!__builtin_isunordered (s1, s2) && s1 < s2));
+ CMP (le, (!__builtin_isunordered (s1, s2) && s1 <= s2));
+ CMP (neq, (__builtin_isunordered (s1, s2) || s1 != s2));
+}
+
+static void
+TEST (void)
+{
+ struct
+ {
+ float x1;
+ float x2;
+ }
+ inputs[] =
+ {
+ { 4.3, 2.18 },
+ { -4.3, 3.18 },
+ { __builtin_nanf (""), -5.8 },
+ { -4.8, __builtin_nansf ("") },
+ { 3.8, __builtin_nansf ("") },
+ { 4.2, 4.2 },
+ { __builtin_nanf (""), __builtin_nansf ("") },
+ };
+ int i;
+
+ for (i = 0; i < sizeof (inputs) / sizeof (inputs[0]); i++)
+ do_check (inputs[i].x1, inputs[i].x2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-1.c b/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-1.c
new file mode 100644
index 0000000..6268977
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-msse2 -O2" } */
+/* { dg-final { scan-assembler-times "comisd\[ \\t\]+\[^\n\]*\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 6 } } */
+/* { dg-final { scan-assembler-times "jp" 2 } } */
+#include <xmmintrin.h>
+
+volatile __m128d x1, x2;
+volatile int res;
+
+void extern
+sse2_comisd_test (void)
+{
+ res = _mm_comieq_sd (x1, x2);
+ res = _mm_comilt_sd (x1, x2);
+ res = _mm_comile_sd (x1, x2);
+ res = _mm_comigt_sd (x1, x2);
+ res = _mm_comige_sd (x1, x2);
+ res = _mm_comineq_sd (x1, x2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-2.c b/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-2.c
new file mode 100644
index 0000000..f49771c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-comisd-pr106113-2.c
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -msse2" } */
+/* { dg-require-effective-target sse2 } */
+
+#ifndef CHECK_H
+#define CHECK_H "sse2-check.h"
+#endif
+
+#ifndef TEST
+#define TEST sse2_test
+#endif
+
+#include CHECK_H
+
+#include <emmintrin.h>
+
+#define CMP(PRED, EXP) \
+ res = _mm_comi##PRED##_sd (__A, __B); \
+ if (res != EXP) \
+ abort ();
+static void
+__attribute__((noinline, unused))
+do_check (double s1, double s2)
+{
+ __m128d __A = _mm_load_sd (&s1);
+ __m128d __B = _mm_load_sd (&s2);
+ int res;
+
+ CMP (eq, (!__builtin_isunordered (s1, s2) && s1 == s2));
+ CMP (ge, (!__builtin_isunordered (s1, s2) && s1 >= s2));
+ CMP (gt, (!__builtin_isunordered (s1, s2) && s1 > s2));
+ CMP (lt, (!__builtin_isunordered (s1, s2) && s1 < s2));
+ CMP (le, (!__builtin_isunordered (s1, s2) && s1 <= s2));
+ CMP (neq, (__builtin_isunordered (s1, s2) || s1 != s2));
+}
+
+static void
+TEST (void)
+{
+ struct
+ {
+ double x1;
+ double x2;
+ }
+ inputs[] =
+ {
+ { 4.3, 2.18 },
+ { -4.3, 3.18 },
+ { __builtin_nan (""), -5.8 },
+ { -4.8, __builtin_nans ("") },
+ { 3.8, __builtin_nans ("") },
+ { 4.2, 4.2 },
+ { __builtin_nan (""), __builtin_nans ("") },
+ };
+ int i;
+
+ for (i = 0; i < sizeof (inputs) / sizeof (inputs[0]); i++)
+ do_check (inputs[i].x1, inputs[i].x2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-1.c b/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-1.c
new file mode 100644
index 0000000..e64c0ac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-1.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-msse2 -O2" } */
+/* { dg-final { scan-assembler-times "ucomisd\[ \\t\]+\[^\n\]*\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 6 } } */
+/* { dg-final { scan-assembler-times "jp" 2 } } */
+#include <xmmintrin.h>
+
+volatile __m128d x1, x2;
+volatile int res;
+
+void extern
+sse2_ucomisd_test (void)
+{
+ res = _mm_ucomieq_sd (x1, x2);
+ res = _mm_ucomilt_sd (x1, x2);
+ res = _mm_ucomile_sd (x1, x2);
+ res = _mm_ucomigt_sd (x1, x2);
+ res = _mm_ucomige_sd (x1, x2);
+ res = _mm_ucomineq_sd (x1, x2);
+}
diff --git a/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-2.c b/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-2.c
new file mode 100644
index 0000000..606a897
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sse2-ucomisd-pr106113-2.c
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -msse2" } */
+/* { dg-require-effective-target sse2 } */
+
+#ifndef CHECK_H
+#define CHECK_H "sse2-check.h"
+#endif
+
+#ifndef TEST
+#define TEST sse2_test
+#endif
+
+#include CHECK_H
+
+#include <emmintrin.h>
+
+#define CMP(PRED, EXP) \
+ res = _mm_ucomi##PRED##_sd (__A, __B); \
+ if (res != EXP) \
+ abort ();
+static void
+__attribute__((noinline, unused))
+do_check (double s1, double s2)
+{
+ __m128d __A = _mm_load_sd (&s1);
+ __m128d __B = _mm_load_sd (&s2);
+ int res;
+
+ CMP (eq, (!__builtin_isunordered (s1, s2) && s1 == s2));
+ CMP (ge, (!__builtin_isunordered (s1, s2) && s1 >= s2));
+ CMP (gt, (!__builtin_isunordered (s1, s2) && s1 > s2));
+ CMP (lt, (!__builtin_isunordered (s1, s2) && s1 < s2));
+ CMP (le, (!__builtin_isunordered (s1, s2) && s1 <= s2));
+ CMP (neq, (__builtin_isunordered (s1, s2) || s1 != s2));
+}
+
+static void
+TEST (void)
+{
+ struct
+ {
+ double x1;
+ double x2;
+ }
+ inputs[] =
+ {
+ { 4.3, 2.18 },
+ { -4.3, 3.18 },
+ { __builtin_nan (""), -5.8 },
+ { -4.8, __builtin_nans ("") },
+ { 3.8, __builtin_nans ("") },
+ { 4.2, 4.2 },
+ { __builtin_nan (""), __builtin_nans ("") },
+ };
+ int i;
+
+ for (i = 0; i < sizeof (inputs) / sizeof (inputs[0]); i++)
+ do_check (inputs[i].x1, inputs[i].x2);
+}
diff --git a/gcc/testsuite/gfortran.dg/pr104313.f b/gcc/testsuite/gfortran.dg/pr104313.f
new file mode 100644
index 0000000..89c8947
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr104313.f
@@ -0,0 +1,11 @@
+! { dg-do compile }
+! { dg-additional-options "-ff2c -fdump-tree-original" }
+!
+! PR fortran/104313 - ICE verify_gimple failed with -ff2c
+! Contributed by G.Steinmetz
+
+ function f(a)
+ return
+ end
+
+! { dg-final { scan-tree-dump-times "return" 1 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/pr106209.f90 b/gcc/testsuite/gfortran.dg/pr106209.f90
new file mode 100644
index 0000000..44f9233
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr106209.f90
@@ -0,0 +1,9 @@
+! { dg-do compile }
+! PR fortran/106209 - ICE in add_init_expr_to_sym
+! Contributed by G.Steinmetz
+
+program p
+ integer, parameter :: a(:) = 0 ! { dg-error "of deferred shape" }
+ integer, parameter :: b(*) = a ! { dg-error "Bad shape of initializer" }
+ integer, parameter :: c(*) = [a] ! { dg-error "Cannot determine shape" }
+end
diff --git a/gcc/testsuite/gnat.dg/opt98.adb b/gcc/testsuite/gnat.dg/opt98.adb
new file mode 100644
index 0000000..6d42338
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt98.adb
@@ -0,0 +1,14 @@
+-- { dg-do compile }
+-- { dg-options "-O -gnatws" }
+
+package body Opt98 is
+
+ function Func return Rec is
+ R :Rec;
+ begin
+ A := To_Address ((I => 0));
+ R := To_Rec (A);
+ return R;
+ end;
+
+end Opt98;
diff --git a/gcc/testsuite/gnat.dg/opt98.ads b/gcc/testsuite/gnat.dg/opt98.ads
new file mode 100644
index 0000000..fcc70577
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/opt98.ads
@@ -0,0 +1,19 @@
+with Ada.Unchecked_Conversion;
+with System;
+
+package Opt98 is
+
+ type Rec is record
+ I : Integer;
+ end record;
+
+ function To_Address is new Ada.Unchecked_Conversion (Rec, System.Address);
+
+ function To_Rec is new Ada.Unchecked_Conversion (System.Address, Rec);
+
+ A : System.Address with Atomic;
+
+ function Func return Rec;
+
+end Opt98;
+
diff --git a/gcc/tree-diagnostic-path.cc b/gcc/tree-diagnostic-path.cc
index 2f297fa..6612b61 100644
--- a/gcc/tree-diagnostic-path.cc
+++ b/gcc/tree-diagnostic-path.cc
@@ -61,11 +61,11 @@ class path_label : public range_label
is special-cased for diagnostic paths. */
bool colorize = pp_show_color (global_dc->printer);
label_text event_text (event.get_desc (colorize));
- gcc_assert (event_text.m_buffer);
+ gcc_assert (event_text.get ());
pretty_printer pp;
pp_show_color (&pp) = pp_show_color (global_dc->printer);
diagnostic_event_id_t event_id (event_idx);
- pp_printf (&pp, "%@ %s", &event_id, event_text.m_buffer);
+ pp_printf (&pp, "%@ %s", &event_id, event_text.get ());
label_text result = label_text::take (xstrdup (pp_formatted_text (&pp)));
return result;
}
@@ -173,7 +173,7 @@ struct event_range
diagnostic_event_id_t event_id (i);
label_text event_text (iter_event.get_desc (true));
pretty_printer *pp = dc->printer;
- pp_printf (pp, " %@: %s", &event_id, event_text.m_buffer);
+ pp_printf (pp, " %@: %s", &event_id, event_text.get ());
pp_newline (pp);
}
return;
@@ -459,7 +459,7 @@ default_tree_diagnostic_path_printer (diagnostic_context *context,
{
const diagnostic_event &event = path->get_event (i);
label_text event_text (event.get_desc (false));
- gcc_assert (event_text.m_buffer);
+ gcc_assert (event_text.get ());
diagnostic_event_id_t event_id (i);
if (context->show_path_depths)
{
@@ -471,17 +471,17 @@ default_tree_diagnostic_path_printer (diagnostic_context *context,
if (fndecl)
inform (event.get_location (),
"%@ %s (fndecl %qD, depth %i)",
- &event_id, event_text.m_buffer,
+ &event_id, event_text.get (),
fndecl, stack_depth);
else
inform (event.get_location (),
"%@ %s (depth %i)",
- &event_id, event_text.m_buffer,
+ &event_id, event_text.get (),
stack_depth);
}
else
inform (event.get_location (),
- "%@ %s", &event_id, event_text.m_buffer);
+ "%@ %s", &event_id, event_text.get ());
}
}
break;
@@ -519,7 +519,7 @@ default_tree_make_json_for_path (diagnostic_context *context,
json_from_expanded_location (context,
event.get_location ()));
label_text event_text (event.get_desc (false));
- event_obj->set ("description", new json::string (event_text.m_buffer));
+ event_obj->set ("description", new json::string (event_text.get ()));
if (tree fndecl = event.get_fndecl ())
{
const char *function
diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
index 69567ab..fdc4bc8 100644
--- a/gcc/tree-ssa-forwprop.cc
+++ b/gcc/tree-ssa-forwprop.cc
@@ -42,6 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-dfa.h"
#include "tree-ssa-propagate.h"
#include "tree-ssa-dom.h"
+#include "tree-ssa-strlen.h"
#include "builtins.h"
#include "tree-cfgcleanup.h"
#include "cfganal.h"
@@ -1177,6 +1178,15 @@ constant_pointer_difference (tree p1, tree p2)
memcpy (p, "abcd ", 7);
call if the latter can be stored by pieces during expansion.
+ Optimize
+ memchr ("abcd", a, 4) == 0;
+ or
+ memchr ("abcd", a, 4) != 0;
+ to
+ (a == 'a' || a == 'b' || a == 'c' || a == 'd') == 0
+ or
+ (a == 'a' || a == 'b' || a == 'c' || a == 'd') != 0
+
Also canonicalize __atomic_fetch_op (p, x, y) op x
to __atomic_op_fetch (p, x, y) or
__atomic_op_fetch (p, x, y) iop x
@@ -1193,8 +1203,70 @@ simplify_builtin_call (gimple_stmt_iterator *gsi_p, tree callee2)
return false;
stmt1 = SSA_NAME_DEF_STMT (vuse);
+ tree res;
+
switch (DECL_FUNCTION_CODE (callee2))
{
+ case BUILT_IN_MEMCHR:
+ if (gimple_call_num_args (stmt2) == 3
+ && (res = gimple_call_lhs (stmt2)) != nullptr
+ && use_in_zero_equality (res) != nullptr
+ && CHAR_BIT == 8
+ && BITS_PER_UNIT == 8)
+ {
+ tree ptr = gimple_call_arg (stmt2, 0);
+ if (TREE_CODE (ptr) != ADDR_EXPR
+ || TREE_CODE (TREE_OPERAND (ptr, 0)) != STRING_CST)
+ break;
+ unsigned HOST_WIDE_INT slen
+ = TREE_STRING_LENGTH (TREE_OPERAND (ptr, 0));
+ /* It must be a non-empty string constant. */
+ if (slen < 2)
+ break;
+ /* For -Os, only simplify strings with a single character. */
+ if (!optimize_bb_for_speed_p (gimple_bb (stmt2))
+ && slen > 2)
+ break;
+ tree size = gimple_call_arg (stmt2, 2);
+ /* Size must be a constant which is <= UNITS_PER_WORD and
+ <= the string length. */
+ if (TREE_CODE (size) != INTEGER_CST || integer_zerop (size))
+ break;
+
+ if (!tree_fits_uhwi_p (size))
+ break;
+
+ unsigned HOST_WIDE_INT sz = tree_to_uhwi (size);
+ if (sz > UNITS_PER_WORD || sz >= slen)
+ break;
+
+ tree ch = gimple_call_arg (stmt2, 1);
+ location_t loc = gimple_location (stmt2);
+ if (!useless_type_conversion_p (char_type_node,
+ TREE_TYPE (ch)))
+ ch = fold_convert_loc (loc, char_type_node, ch);
+ const char *p = TREE_STRING_POINTER (TREE_OPERAND (ptr, 0));
+ unsigned int isize = sz;
+ tree *op = XALLOCAVEC (tree, isize);
+ for (unsigned int i = 0; i < isize; i++)
+ {
+ op[i] = build_int_cst (char_type_node, p[i]);
+ op[i] = fold_build2_loc (loc, EQ_EXPR, boolean_type_node,
+ op[i], ch);
+ }
+ for (unsigned int i = isize - 1; i >= 1; i--)
+ op[i - 1] = fold_convert_loc (loc, boolean_type_node,
+ fold_build2_loc (loc,
+ BIT_IOR_EXPR,
+ boolean_type_node,
+ op[i - 1],
+ op[i]));
+ res = fold_convert_loc (loc, TREE_TYPE (res), op[0]);
+ gimplify_and_update_call_from_tree (gsi_p, res);
+ return true;
+ }
+ break;
+
case BUILT_IN_MEMSET:
if (gimple_call_num_args (stmt2) != 3
|| gimple_call_lhs (stmt2)
diff --git a/gcc/tree-ssa-strlen.cc b/gcc/tree-ssa-strlen.cc
index 7b3e389..5afbae1 100644
--- a/gcc/tree-ssa-strlen.cc
+++ b/gcc/tree-ssa-strlen.cc
@@ -3913,8 +3913,8 @@ strlen_pass::handle_builtin_memset (bool *zero_write)
nonnull if and only RES is used in such expressions exclusively and
in none other. */
-static gimple *
-use_in_zero_equality (tree res, bool exclusive = true)
+gimple *
+use_in_zero_equality (tree res, bool exclusive)
{
gimple *first_use = NULL;
diff --git a/gcc/tree-ssa-strlen.h b/gcc/tree-ssa-strlen.h
index 8d15545..fdb4d9d 100644
--- a/gcc/tree-ssa-strlen.h
+++ b/gcc/tree-ssa-strlen.h
@@ -35,6 +35,8 @@ struct c_strlen_data;
extern void get_range_strlen_dynamic (tree, gimple *, c_strlen_data *,
pointer_query &);
+extern gimple *use_in_zero_equality (tree, bool = true);
+
/* APIs internal to strlen pass. Defined in gimple-ssa-sprintf.cc. */
extern bool handle_printf_call (gimple_stmt_iterator *, pointer_query &);
diff --git a/gcc/value-range-pretty-print.cc b/gcc/value-range-pretty-print.cc
new file mode 100644
index 0000000..b795e92
--- /dev/null
+++ b/gcc/value-range-pretty-print.cc
@@ -0,0 +1,111 @@
+/* Pretty print support for value ranges.
+ Copyright (C) 2019-2022 Free Software Foundation, Inc.
+ Contributed by Aldy Hernandez <aldyh@redhat.com>.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "tree.h"
+#include "gimple.h"
+#include "ssa.h"
+#include "tree-pretty-print.h"
+#include "fold-const.h"
+#include "gimple-range.h"
+#include "value-range-pretty-print.h"
+
+void
+vrange_printer::visit (const unsupported_range &r) const
+{
+ pp_string (pp, "[unsupported_range] ");
+ if (r.undefined_p ())
+ {
+ pp_string (pp, "UNDEFINED");
+ return;
+ }
+ if (r.varying_p ())
+ {
+ pp_string (pp, "VARYING");
+ return;
+ }
+ gcc_unreachable ();
+}
+
+void
+vrange_printer::visit (const irange &r) const
+{
+ pp_string (pp, "[irange] ");
+ if (r.undefined_p ())
+ {
+ pp_string (pp, "UNDEFINED");
+ return;
+ }
+ dump_generic_node (pp, r.type (), 0, TDF_NONE, false);
+ pp_character (pp, ' ');
+ if (r.varying_p ())
+ {
+ pp_string (pp, "VARYING");
+ return;
+ }
+ for (unsigned i = 0; i < r.num_pairs (); ++i)
+ {
+ tree lb = wide_int_to_tree (r.type (), r.lower_bound (i));
+ tree ub = wide_int_to_tree (r.type (), r.upper_bound (i));
+ pp_character (pp, '[');
+ print_irange_bound (lb);
+ pp_string (pp, ", ");
+ print_irange_bound (ub);
+ pp_character (pp, ']');
+ }
+ print_irange_bitmasks (r);
+}
+
+void
+vrange_printer::print_irange_bound (tree bound) const
+{
+ tree type = TREE_TYPE (bound);
+ wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+ wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+
+ if (INTEGRAL_TYPE_P (type)
+ && !TYPE_UNSIGNED (type)
+ && TREE_CODE (bound) == INTEGER_CST
+ && wi::to_wide (bound) == type_min
+ && TYPE_PRECISION (type) != 1)
+ pp_string (pp, "-INF");
+ else if (TREE_CODE (bound) == INTEGER_CST
+ && wi::to_wide (bound) == type_max
+ && TYPE_PRECISION (type) != 1)
+ pp_string (pp, "+INF");
+ else
+ dump_generic_node (pp, bound, 0, TDF_NONE, false);
+}
+
+void
+vrange_printer::print_irange_bitmasks (const irange &r) const
+{
+ wide_int nz = r.get_nonzero_bits ();
+ if (nz == -1)
+ return;
+
+ pp_string (pp, " NONZERO ");
+ char buf[WIDE_INT_PRINT_BUFFER_SIZE];
+ print_hex (nz, buf);
+ pp_string (pp, buf);
+}
diff --git a/gcc/value-range-pretty-print.h b/gcc/value-range-pretty-print.h
new file mode 100644
index 0000000..6d2fb74
--- /dev/null
+++ b/gcc/value-range-pretty-print.h
@@ -0,0 +1,37 @@
+/* Pretty print support for value ranges.
+ Copyright (C) 2022 Free Software Foundation, Inc.
+ Contributed by Aldy Hernandez <aldyh@redhat.com>.
+
+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_VALUE_RANGE_PRETTY_H
+#define GCC_VALUE_RANGE_PRETTY_H
+
+class vrange_printer : public vrange_visitor
+{
+public:
+ vrange_printer (pretty_printer *pp_) : pp (pp_) { }
+ void visit (const unsupported_range &) const override;
+ void visit (const irange &) const override;
+private:
+ void print_irange_bound (tree bound) const;
+ void print_irange_bitmasks (const irange &) const;
+
+ pretty_printer *pp;
+};
+
+#endif // GCC_VALUE_RANGE_PRETTY_H
diff --git a/gcc/value-range.cc b/gcc/value-range.cc
index 528ed54..525e192 100644
--- a/gcc/value-range.cc
+++ b/gcc/value-range.cc
@@ -27,9 +27,22 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "ssa.h"
#include "tree-pretty-print.h"
+#include "value-range-pretty-print.h"
#include "fold-const.h"
#include "gimple-range.h"
+void
+irange::accept (const vrange_visitor &v) const
+{
+ v.visit (*this);
+}
+
+void
+unsupported_range::accept (const vrange_visitor &v) const
+{
+ v.visit (*this);
+}
+
// Convenience function only available for integers and pointers.
wide_int
@@ -200,6 +213,19 @@ vrange::operator== (const vrange &src) const
gcc_unreachable ();
}
+// Wrapper for vrange_printer to dump a range to a file.
+
+void
+vrange::dump (FILE *file) const
+{
+ pretty_printer buffer;
+ pp_needs_newline (&buffer) = true;
+ buffer.buffer->stream = file;
+ vrange_printer vrange_pp (&buffer);
+ this->accept (vrange_pp);
+ pp_flush (&buffer);
+}
+
bool
irange::supports_type_p (tree type) const
{
@@ -226,23 +252,6 @@ unsupported_range::unsupported_range ()
set_undefined ();
}
-void
-unsupported_range::dump (FILE *file) const
-{
- fprintf (file, "[unsupported_range] ");
- if (undefined_p ())
- {
- fprintf (file, "UNDEFINED");
- return;
- }
- if (varying_p ())
- {
- fprintf (file, "VARYING");
- return;
- }
- gcc_unreachable ();
-}
-
// Here we copy between any two irange's. The ranges can be legacy or
// multi-ranges, and copying between any combination works correctly.
@@ -2449,88 +2458,6 @@ irange::union_nonzero_bits (const irange &r)
return false;
}
-static void
-dump_bound_with_infinite_markers (FILE *file, tree bound)
-{
- tree type = TREE_TYPE (bound);
- wide_int type_min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
- wide_int type_max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
-
- if (INTEGRAL_TYPE_P (type)
- && !TYPE_UNSIGNED (type)
- && TREE_CODE (bound) == INTEGER_CST
- && wi::to_wide (bound) == type_min
- && TYPE_PRECISION (type) != 1)
- fprintf (file, "-INF");
- else if (TREE_CODE (bound) == INTEGER_CST
- && wi::to_wide (bound) == type_max
- && TYPE_PRECISION (type) != 1)
- fprintf (file, "+INF");
- else
- print_generic_expr (file, bound);
-}
-
-void
-irange::dump (FILE *file) const
-{
- fprintf (file, "[irange] ");
- if (undefined_p ())
- {
- fprintf (file, "UNDEFINED");
- return;
- }
- print_generic_expr (file, type ());
- fprintf (file, " ");
- if (varying_p ())
- {
- fprintf (file, "VARYING");
- dump_bitmasks (file);
- return;
- }
- if (legacy_mode_p ())
- {
- fprintf (file, "%s[", (m_kind == VR_ANTI_RANGE) ? "~" : "");
- dump_bound_with_infinite_markers (file, min ());
- fprintf (file, ", ");
- dump_bound_with_infinite_markers (file, max ());
- fprintf (file, "]");
- dump_bitmasks (file);
- return;
- }
- for (unsigned i = 0; i < m_num_ranges; ++i)
- {
- tree lb = m_base[i * 2];
- tree ub = m_base[i * 2 + 1];
- fprintf (file, "[");
- dump_bound_with_infinite_markers (file, lb);
- fprintf (file, ", ");
- dump_bound_with_infinite_markers (file, ub);
- fprintf (file, "]");
- }
- dump_bitmasks (file);
-}
-
-void
-irange::dump_bitmasks (FILE *file) const
-{
- if (m_nonzero_mask)
- {
- wide_int nz = get_nonzero_bits ();
- if (nz != -1)
- {
- fprintf (file, " NONZERO ");
- print_hex (nz, file);
- }
- }
-}
-
-void
-vrange::debug () const
-{
- dump (stderr);
- fprintf (stderr, "\n");
-}
-
void
dump_value_range (FILE *file, const vrange *vr)
{
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 0e34118..4af92fd 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -73,12 +73,12 @@ class vrange
template <typename T> friend bool is_a (vrange &);
friend class Value_Range;
public:
+ virtual void accept (const class vrange_visitor &v) const = 0;
virtual void set (tree, tree, value_range_kind = VR_RANGE);
virtual tree type () const;
virtual bool supports_type_p (tree type) const;
virtual void set_varying (tree type);
virtual void set_undefined ();
- virtual void dump (FILE * = stderr) const = 0;
virtual bool union_ (const vrange &);
virtual bool intersect (const vrange &);
virtual bool singleton_p (tree *result = NULL) const;
@@ -95,9 +95,9 @@ public:
vrange& operator= (const vrange &);
bool operator== (const vrange &) const;
bool operator!= (const vrange &r) const { return !(*this == r); }
+ void dump (FILE *) const;
enum value_range_kind kind () const; // DEPRECATED
- void debug () const;
protected:
ENUM_BITFIELD(value_range_kind) m_kind : 8;
@@ -148,7 +148,7 @@ public:
// Misc methods.
virtual bool fits_p (const vrange &r) const override;
- virtual void dump (FILE * = stderr) const override;
+ virtual void accept (const vrange_visitor &v) const override;
// Nonzero masks.
wide_int get_nonzero_bits () const;
@@ -204,7 +204,6 @@ private:
void set_nonzero_bits (tree mask);
bool intersect_nonzero_bits (const irange &r);
bool union_nonzero_bits (const irange &r);
- void dump_bitmasks (FILE *) const;
bool intersect (const wide_int& lb, const wide_int& ub);
unsigned char m_num_ranges;
@@ -250,7 +249,7 @@ class unsupported_range : public vrange
{
public:
unsupported_range ();
- virtual void dump (FILE *) const override;
+ virtual void accept (const vrange_visitor &v) const override;
};
// is_a<> and as_a<> implementation for vrange.
@@ -298,6 +297,13 @@ is_a <irange> (vrange &v)
return v.m_discriminator == VR_IRANGE;
}
+class vrange_visitor
+{
+public:
+ virtual void visit (const irange &) const { }
+ virtual void visit (const unsupported_range &) const { }
+};
+
// This is a special int_range<1> with only one pair, plus
// VR_ANTI_RANGE magic to describe slightly more than can be described
// in one pair. It is described in the code as a "legacy range" (as
@@ -329,7 +335,7 @@ public:
bool operator!= (const Value_Range &r) const;
operator vrange &();
operator const vrange &() const;
- void dump (FILE *out = stderr) const;
+ void dump (FILE *) const;
static bool supports_type_p (tree type);
// Convenience methods for vrange compatability.
@@ -348,6 +354,7 @@ public:
bool zero_p () const { return m_vrange->zero_p (); }
wide_int lower_bound () const; // For irange/prange compatability.
wide_int upper_bound () const; // For irange/prange compatability.
+ void accept (const vrange_visitor &v) const { m_vrange->accept (v); }
private:
void init (tree type);
unsupported_range m_unsupported;
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index fe02298..4905bd5 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,10 @@
+2022-07-15 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/line-map.h (label_text::take_or_copy): Remove.
+ (label_text::moved_from): Rename to release.
+ (label_text::m_buffer, label_text::m_owned): Make private.
+ (label_text::get, label_text::is_owned): New accessors.
+
2022-07-13 Marek Polacek <polacek@redhat.com>
PR preprocessor/106272
diff --git a/libcpp/include/line-map.h b/libcpp/include/line-map.h
index c434a24..9bdd5b9 100644
--- a/libcpp/include/line-map.h
+++ b/libcpp/include/line-map.h
@@ -1851,7 +1851,7 @@ public:
label_text (label_text &&other)
: m_buffer (other.m_buffer), m_owned (other.m_owned)
{
- other.moved_from ();
+ other.release ();
}
/* Move assignment. */
@@ -1861,7 +1861,7 @@ public:
free (m_buffer);
m_buffer = other.m_buffer;
m_owned = other.m_owned;
- other.moved_from ();
+ other.release ();
return *this;
}
@@ -1882,25 +1882,26 @@ public:
return label_text (buffer, true);
}
- /* Take ownership of the buffer, copying if necessary. */
- char *take_or_copy ()
+ void release ()
{
- if (m_owned)
- return m_buffer;
- else
- return xstrdup (m_buffer);
+ m_buffer = NULL;
+ m_owned = false;
}
- void moved_from ()
+ const char *get () const
{
- m_buffer = NULL;
- m_owned = false;
+ return m_buffer;
}
+ bool is_owner () const
+ {
+ return m_owned;
+ }
+
+private:
char *m_buffer;
bool m_owned;
-private:
label_text (char *buffer, bool owned)
: m_buffer (buffer), m_owned (owned)
{}
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 547ef8b..45fd827 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,7 @@
+2022-07-14 Martin Liska <mliska@suse.cz>
+
+ * functions.texi: Replace strtoul with strtoull.
+
2022-07-04 Nick Clifton <nickc@redhat.com>
* rust-demangle.c (demangle_const): Add a missing goto pass_return
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 5f0bbd7..1980646 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,20 @@
+2022-07-15 Marek Polacek <polacek@redhat.com>
+
+ PR c++/104477
+ * include/std/type_traits (reference_constructs_from_temporary,
+ reference_converts_from_temporary): New class templates.
+ (reference_constructs_from_temporary_v,
+ reference_converts_from_temporary_v): New variable templates.
+ (__cpp_lib_reference_from_temporary): Define for C++23.
+ * include/std/version (__cpp_lib_reference_from_temporary): Define for
+ C++23.
+ * testsuite/20_util/variable_templates_for_traits.cc: Test
+ reference_constructs_from_temporary_v and
+ reference_converts_from_temporary_v.
+ * testsuite/20_util/reference_from_temporary/value.cc: New test.
+ * testsuite/20_util/reference_from_temporary/value2.cc: New test.
+ * testsuite/20_util/reference_from_temporary/version.cc: New test.
+
2022-07-12 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/106248
diff --git a/libstdc++-v3/include/std/type_traits b/libstdc++-v3/include/std/type_traits
index e5f58bc..b1a1dee 100644
--- a/libstdc++-v3/include/std/type_traits
+++ b/libstdc++-v3/include/std/type_traits
@@ -3505,6 +3505,45 @@ template<typename _Ret, typename _Fn, typename... _Args>
template<typename _Tp>
inline constexpr bool is_scoped_enum_v = is_scoped_enum<_Tp>::value;
+#define __cpp_lib_reference_from_temporary 202202L
+
+ /// True if _Tp is a reference type, a _Up value can be bound to _Tp in
+ /// direct-initialization, and a temporary object would be bound to
+ /// the reference, false otherwise.
+ /// @since C++23
+ template<typename _Tp, typename _Up>
+ struct reference_constructs_from_temporary
+ : public bool_constant<__reference_constructs_from_temporary(_Tp, _Up)>
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{})
+ && std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
+
+ /// True if _Tp is a reference type, a _Up value can be bound to _Tp in
+ /// copy-initialization, and a temporary object would be bound to
+ /// the reference, false otherwise.
+ /// @since C++23
+ template<typename _Tp, typename _Up>
+ struct reference_converts_from_temporary
+ : public bool_constant<__reference_converts_from_temporary(_Tp, _Up)>
+ {
+ static_assert(std::__is_complete_or_unbounded(__type_identity<_Tp>{})
+ && std::__is_complete_or_unbounded(__type_identity<_Up>{}),
+ "template argument must be a complete class or an unbounded array");
+ };
+
+ /// @ingroup variable_templates
+ /// @since C++23
+ template<typename _Tp, typename _Up>
+ inline constexpr bool reference_constructs_from_temporary_v
+ = reference_constructs_from_temporary<_Tp, _Up>::value;
+
+ /// @ingroup variable_templates
+ /// @since C++23
+ template<typename _Tp, typename _Up>
+ inline constexpr bool reference_converts_from_temporary_v
+ = reference_converts_from_temporary<_Tp, _Up>::value;
#endif // C++23
#if _GLIBCXX_HAVE_IS_CONSTANT_EVALUATED
diff --git a/libstdc++-v3/include/std/version b/libstdc++-v3/include/std/version
index 22280e1..5edca2f 100644
--- a/libstdc++-v3/include/std/version
+++ b/libstdc++-v3/include/std/version
@@ -300,10 +300,11 @@
#endif
#if __cplusplus > 202002L
-// c++2b
+// c++23
#define __cpp_lib_byteswap 202110L
#define __cpp_lib_constexpr_typeinfo 202106L
#define __cpp_lib_is_scoped_enum 202011L
+#define __cpp_lib_reference_from_temporary 202202L
#if _GLIBCXX_HOSTED
#define __cpp_lib_adaptor_iterator_pair_constructor 202106L
@@ -335,7 +336,7 @@
#define __cpp_lib_to_underlying 202102L
#define __cpp_lib_unreachable 202202L
#endif
-#endif // C++2b
+#endif // C++23
#endif // C++20
#endif // C++17
#endif // C++14
diff --git a/libstdc++-v3/testsuite/20_util/reference_from_temporary/value.cc b/libstdc++-v3/testsuite/20_util/reference_from_temporary/value.cc
new file mode 100644
index 0000000..2f62e54
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/reference_from_temporary/value.cc
@@ -0,0 +1,110 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <type_traits>
+#include <testsuite_tr1.h>
+
+#ifndef __cpp_lib_reference_from_temporary
+# error "Feature test macro for reference_from_temporary is missing in <version>"
+#elif __cpp_lib_reference_from_temporary < 202202L
+# error "Feature test macro for reference_from_temporary has wrong value in <version>"
+#endif
+
+void test01()
+{
+ using std::reference_constructs_from_temporary;
+ using std::reference_converts_from_temporary;
+ using namespace __gnu_test;
+
+ struct A { A(); };
+
+ struct B {
+ operator int();
+ explicit operator int&&();
+ };
+
+ struct C {
+ operator int();
+ explicit operator int&();
+ };
+
+ static_assert(test_property<reference_constructs_from_temporary, int, int>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, void>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, const volatile void>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, void, void>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, int>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, int&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, int&&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, long>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, long&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, long&&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, const int&, int>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, const int&, int&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, const int&, int&&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, const int&, long>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, const int&, long&>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, const int&, long&&>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&&, int>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&&, int&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&&, int&&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&&, long>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&&, long&>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&&, long&&>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, const A&, A>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, const A&, A&&>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, A&&, A>(true), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&, int[]>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, const int&, int[]>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, int&&, int[]>(false), "");
+
+ static_assert(test_property<reference_converts_from_temporary, int, int>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, void>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, const volatile void>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, void, void>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, int>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, int&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, int&&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, long>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, long&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, long&&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, const int&, int>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, const int&, int&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, const int&, int&&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, const int&, long>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, const int&, long&>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, const int&, long&&>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, int&&, int>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, int&&, int&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&&, int&&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&&, long>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, int&&, long&>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, int&&, long&&>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, const A&, A>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, const A&, A&&>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, A&&, A>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, int&, int[]>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, const int&, int[]>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&&, int[]>(false), "");
+
+ static_assert(test_property<reference_constructs_from_temporary, int&&, B>(false), "");
+ static_assert(test_property<reference_constructs_from_temporary, const int&, C>(false), "");
+ static_assert(test_property<reference_converts_from_temporary, int&&, B>(true), "");
+ static_assert(test_property<reference_converts_from_temporary, const int&, C>(true), "");
+}
diff --git a/libstdc++-v3/testsuite/20_util/reference_from_temporary/value2.cc b/libstdc++-v3/testsuite/20_util/reference_from_temporary/value2.cc
new file mode 100644
index 0000000..6577075
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/reference_from_temporary/value2.cc
@@ -0,0 +1,28 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <type_traits>
+#include <string>
+
+void test01()
+{
+ static_assert(std::reference_converts_from_temporary_v<const std::string&, const char*>);
+ static_assert(std::reference_constructs_from_temporary_v<const std::string&, const char*>);
+}
diff --git a/libstdc++-v3/testsuite/20_util/reference_from_temporary/version.cc b/libstdc++-v3/testsuite/20_util/reference_from_temporary/version.cc
new file mode 100644
index 0000000..f56e7c0
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/reference_from_temporary/version.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2022 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++23" }
+// { dg-do compile { target c++23 } }
+
+#include <version>
+
+#ifndef __cpp_lib_reference_from_temporary
+# error "Feature test macro for reference_from_temporary is missing in <version>"
+#elif __cpp_lib_reference_from_temporary < 202202L
+# error "Feature test macro for reference_from_temporary has wrong value in <version>"
+#endif
diff --git a/libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc b/libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc
index 9b3957f..2b03ad7 100644
--- a/libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc
+++ b/libstdc++-v3/testsuite/20_util/variable_templates_for_traits.cc
@@ -346,3 +346,17 @@ static_assert(disjunction_v<false_type, false_type,
true_type>, "");
static_assert(!disjunction_v<false_type, false_type,
false_type>, "");
+#if __cpp_lib_reference_from_temporary >= 202202L
+static_assert(std::reference_converts_from_temporary_v<int&&, int>
+ && std::reference_converts_from_temporary_v<const int&, int>
+ && !std::reference_converts_from_temporary_v<int&&, int&&>
+ && !std::reference_converts_from_temporary_v<const int&, int&&>
+ && std::reference_converts_from_temporary_v<int&&, long&&>
+ && std::reference_converts_from_temporary_v<int&&, long>, "");
+static_assert(std::reference_constructs_from_temporary_v<int&&, int>
+ && std::reference_constructs_from_temporary_v<const int&, int>
+ && !std::reference_constructs_from_temporary_v<int&&, int&&>
+ && !std::reference_constructs_from_temporary_v<const int&, int&&>
+ && std::reference_constructs_from_temporary_v<int&&, long&&>
+ && std::reference_constructs_from_temporary_v<int&&, long>, "");
+#endif
diff --git a/lto-plugin/ChangeLog b/lto-plugin/ChangeLog
index 42760af..eb37870 100644
--- a/lto-plugin/ChangeLog
+++ b/lto-plugin/ChangeLog
@@ -1,3 +1,11 @@
+2022-07-14 Martin Liska <mliska@suse.cz>
+
+ PR bootstrap/106156
+ * Makefile.am: Use ac_lto_plugin_extra_ldflags for AM_LDFLAGS.
+ * configure.ac: Use AC_SUBST(ac_lto_plugin_extra_ldflags).
+ * Makefile.in: Regenerate.
+ * configure: Regenerate.
+
2022-07-12 Martin Liska <mliska@suse.cz>
* lto-plugin.c (negotiate_api_version): New.
diff --git a/lto-plugin/Makefile.am b/lto-plugin/Makefile.am
index 482946e..aba3c5a 100644
--- a/lto-plugin/Makefile.am
+++ b/lto-plugin/Makefile.am
@@ -9,8 +9,7 @@ libexecsubdir := $(libexecdir)/gcc/$(real_target_noncanonical)/$(gcc_version)$(a
AM_CPPFLAGS = -I$(top_srcdir)/../include $(DEFS)
AM_CFLAGS = @ac_lto_plugin_warn_cflags@ $(CET_HOST_FLAGS) -DBASE_VERSION='"$(gcc_version)"'
-# The plug-in depends on pthreads.
-AM_LDFLAGS = -pthread @ac_lto_plugin_ldflags@
+AM_LDFLAGS = @ac_lto_plugin_ldflags@ @ac_lto_plugin_extra_ldflags@
AM_LIBTOOLFLAGS = --tag=disable-static
override CFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(CFLAGS))
override LDFLAGS := $(filter-out -fsanitize=address -fsanitize=hwaddress,$(LDFLAGS))
diff --git a/lto-plugin/Makefile.in b/lto-plugin/Makefile.in
index 9453bc7..cb568e1 100644
--- a/lto-plugin/Makefile.in
+++ b/lto-plugin/Makefile.in
@@ -276,6 +276,7 @@ abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_lto_plugin_extra_ldflags = @ac_lto_plugin_extra_ldflags@
ac_lto_plugin_ldflags = @ac_lto_plugin_ldflags@
ac_lto_plugin_warn_cflags = @ac_lto_plugin_warn_cflags@
accel_dir_suffix = @accel_dir_suffix@
@@ -344,8 +345,7 @@ gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
libexecsubdir := $(libexecdir)/gcc/$(real_target_noncanonical)/$(gcc_version)$(accel_dir_suffix)
AM_CPPFLAGS = -I$(top_srcdir)/../include $(DEFS)
AM_CFLAGS = @ac_lto_plugin_warn_cflags@ $(CET_HOST_FLAGS) -DBASE_VERSION='"$(gcc_version)"'
-# The plug-in depends on pthreads.
-AM_LDFLAGS = -pthread @ac_lto_plugin_ldflags@
+AM_LDFLAGS = @ac_lto_plugin_ldflags@ @ac_lto_plugin_extra_ldflags@
AM_LIBTOOLFLAGS = --tag=disable-static
libexecsub_LTLIBRARIES = liblto_plugin.la
in_gcc_libs = $(foreach lib, $(libexecsub_LTLIBRARIES), $(gcc_build_dir)/$(lib))
diff --git a/lto-plugin/configure b/lto-plugin/configure
index 870e49b..fdb8a59 100755
--- a/lto-plugin/configure
+++ b/lto-plugin/configure
@@ -650,6 +650,7 @@ LD
FGREP
SED
LIBTOOL
+ac_lto_plugin_extra_ldflags
LTO_PLUGIN_USE_SYMVER_SUN_FALSE
LTO_PLUGIN_USE_SYMVER_SUN_TRUE
LTO_PLUGIN_USE_SYMVER_GNU_FALSE
@@ -6012,6 +6013,7 @@ fi
# Check for thread headers.
use_locking=no
+ac_lto_plugin_extra_ldflags=
case $target in
riscv*)
@@ -6031,8 +6033,12 @@ $as_echo "#define HAVE_PTHREAD_LOCKING 1" >>confdefs.h
fi
+
+ ac_lto_plugin_extra_ldflags="-pthread"
fi
+
+
case `pwd` in
*\ * | *\ *)
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
@@ -12104,7 +12110,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 12107 "configure"
+#line 12113 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12210,7 +12216,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 12213 "configure"
+#line 12219 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
diff --git a/lto-plugin/configure.ac b/lto-plugin/configure.ac
index 18eb4f6..e69a7bd 100644
--- a/lto-plugin/configure.ac
+++ b/lto-plugin/configure.ac
@@ -89,6 +89,7 @@ AM_CONDITIONAL(LTO_PLUGIN_USE_SYMVER_SUN, [test "x$lto_plugin_use_symver" = xsun
# Check for thread headers.
use_locking=no
+ac_lto_plugin_extra_ldflags=
case $target in
riscv*)
@@ -102,8 +103,12 @@ esac
if test x$use_locking = xyes; then
AC_CHECK_HEADER(pthread.h,
[AC_DEFINE(HAVE_PTHREAD_LOCKING, 1, [Define if the system provides pthread locking mechanism.])])
+
+ ac_lto_plugin_extra_ldflags="-pthread"
fi
+AC_SUBST(ac_lto_plugin_extra_ldflags)
+
AM_PROG_LIBTOOL
ACX_LT_HOST_FLAGS
AC_SUBST(target_noncanonical)