When merging the modref summary after inlining, we merge all of the flags
of the outer functions that was inlined into. But things go wrong as
now the flags includes both ECF_NORETURN and ECF_NOTHROW. This happens
because the function which was being inlined had ECF_NOTHROW while caller
had ECF_NORETURN. When both of these are set, ignore_stores_p and
ignore_nondeterminism_p
return true. But in this case the inner function is still just nothrow
and not noreturn.
Basically we only want to combine in the CONST/PURE/NOVOPS related flags
instead.
Bootstrapped and tested on x86_64-linux-gnu.
PR tree-optimization/120987
gcc/ChangeLog:
* ipa-modref.cc (ipa_merge_modref_summary_after_inlining): Mask
off non const/pure/novops related flags when combining of outer
functions.
gcc/testsuite/ChangeLog:
* g++.dg/torture/pr120987-1.C: New test.
Signed-off-by: Andrew Pinski <[email protected]>
---
gcc/ipa-modref.cc | 11 ++++-
gcc/testsuite/g++.dg/torture/pr120987-1.C | 57 +++++++++++++++++++++++
2 files changed, 66 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/torture/pr120987-1.C
diff --git a/gcc/ipa-modref.cc b/gcc/ipa-modref.cc
index fc00acecfce..3158e9757fc 100644
--- a/gcc/ipa-modref.cc
+++ b/gcc/ipa-modref.cc
@@ -5345,9 +5345,16 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge
*edge)
int flags = flags_from_decl_or_type (edge->callee->decl);
/* Combine in outer flags. */
cgraph_node *n;
+ /* Only combine const/pure/novops related flags.
+ NoReturn and NoThrow cannot be combined.
+ An outer noreturn function might throw but an inner might be marked as
nothrow. */
+ int flags_mask;
+ flags_mask = ECF_CONST | ECF_PURE | ECF_NOVOPS | ECF_LOOPING_CONST_OR_PURE;
for (n = edge->caller; n->inlined_to; n = n->callers->caller)
- flags |= flags_from_decl_or_type (n->decl);
- flags |= flags_from_decl_or_type (n->decl);
+ flags |= flags_from_decl_or_type (n->decl) & flags_mask;
+
+ /* Combine in the outer most. */
+ flags |= flags_from_decl_or_type (n->decl) & flags_mask;
bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
if (!callee_info && to_info)
diff --git a/gcc/testsuite/g++.dg/torture/pr120987-1.C
b/gcc/testsuite/g++.dg/torture/pr120987-1.C
new file mode 100644
index 00000000000..4209679bc03
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr120987-1.C
@@ -0,0 +1,57 @@
+// { dg-do run { target c++11 } }
+// { dg-skip-if "requires hosted libstdc++ for string/memory" { ! hostedlib } }
+// PR tree-optimization/120987
+
+#include <memory>
+#include <string>
+#include <cstdlib>
+
+#define ERROR_STRING "012345678901234567"
+
+struct gdb_exception
+{
+ gdb_exception (const char *s)
+ : message (std::make_shared<std::string> (s))
+ {}
+
+ explicit gdb_exception (gdb_exception &&other) noexcept
+ : message (std::move (other.message))
+ {
+ volatile int a = 1;
+ if (a != 1)
+ abort ();
+ }
+
+
+ std::shared_ptr<std::string> message;
+};
+
+void __attribute__((noinline, noclone))
+throw_exception (gdb_exception &&exception)
+{
+ throw gdb_exception (std::move (exception));
+}
+
+static void __attribute__((noinline, noclone))
+parse_linespec (void)
+{
+ struct gdb_exception file_exception (ERROR_STRING);
+ throw_exception (std::move (file_exception));
+}
+
+int
+main (void)
+{
+ try
+ {
+ parse_linespec ();
+ }
+ catch (const gdb_exception &e)
+ {
+ if (*e.message != ERROR_STRING)
+ __builtin_abort();
+ return 0;
+ }
+
+ __builtin_abort();
+}
--
2.43.0