[Bug c++/100409] C++ FE elides pure throwing call

2022-01-05 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

Richard Biener  changed:

   What|Removed |Added

 Resolution|--- |INVALID
 Status|UNCONFIRMED |RESOLVED

--- Comment #16 from Richard Biener  ---
So it's not invalid to elide this (for C++) but instead conflicting
specification by the user.

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread mpolacek at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409
Bug 100409 depends on bug 101087, which changed state.

Bug 101087 Summary: [9 Regression] Unevaluated operand of sizeof affects 
noexcept operator
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101087

   What|Removed |Added

 Status|ASSIGNED|RESOLVED
 Resolution|--- |FIXED

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #15 from Jason Merrill  ---
(In reply to Richard Biener from comment #14)
> Does that mean C++ should default to -fdelete-dead-exceptions?

That makes sense.  The C++ standard has nothing to say about this, since
pure/const are extensions.  And throwing an exception from a signal handler is
undefined behavior.

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #14 from Richard Biener  ---
(In reply to Jason Merrill from comment #13)
> (In reply to Richard Biener from comment #3)
> > -  if (! TREE_SIDE_EFFECTS (expr))
> > +  if (! TREE_SIDE_EFFECTS (expr) && expr_noexcept_p (expr, 0))
> >  expr = void_node;
> 
> The assumption that an expression with TREE_SIDE_EFFECTS unset can be
> discarded if its value is not used is made throughout the compiler. 
> Abandoning that invariant seems like a bad idea.  And changing from checking
> a flag to walking through the whole expression in all of those places sounds
> like an algorithmic complexity problem.
> 
> If a pure/const function can throw, fine.  But that shouldn't affect how
> optimization treats the function call, or we'll end up pessimizing the vast
> majority of calls to pure/const functions that don't throw (but are not
> explicitly declared noexcept).  In this testcase, if the user doesn't want
> the compiler to optimize away a call to foo(), they shouldn't mark it pure.

Hmm, fair enough.  Does that mean C++ should default to
-fdelete-dead-exceptions?

Elsewhere it's said that TREE_SIDE_EFFECTS, const/pure and EH are orthogonal
concepts but yes, that we have to walk expressions recursively to figure
nothrow sucks.  Though the convert_to_void "optimization" could be seen
as premature, on GIMPLE there's no recursive walking needed and nothrow
discovery should discover nothrow-ness of most small functions that have
the body available - so the other option I considered was to remove
that optimization.

Now, this C++ decision makes my life a bit harder (writing testcases for
the middle-end issues around throwing pure/const functions).

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread jason at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #13 from Jason Merrill  ---
(In reply to Richard Biener from comment #3)
> -  if (! TREE_SIDE_EFFECTS (expr))
> +  if (! TREE_SIDE_EFFECTS (expr) && expr_noexcept_p (expr, 0))
>  expr = void_node;

The assumption that an expression with TREE_SIDE_EFFECTS unset can be discarded
if its value is not used is made throughout the compiler.  Abandoning that
invariant seems like a bad idea.  And changing from checking a flag to walking
through the whole expression in all of those places sounds like an algorithmic
complexity problem.

If a pure/const function can throw, fine.  But that shouldn't affect how
optimization treats the function call, or we'll end up pessimizing the vast
majority of calls to pure/const functions that don't throw (but are not
explicitly declared noexcept).  In this testcase, if the user doesn't want the
compiler to optimize away a call to foo(), they shouldn't mark it pure.

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread mpolacek at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

Marek Polacek  changed:

   What|Removed |Added

 CC||mpolacek at gcc dot gnu.org

--- Comment #12 from Marek Polacek  ---
(In reply to Richard Biener from comment #10)
> (In reply to Richard Biener from comment #7)
> > Jason, any idea?
> 
> diff --git a/gcc/cp/except.c b/gcc/cp/except.c
> index a8cea53cf91..cbc94dff790 100644
> --- a/gcc/cp/except.c
> +++ b/gcc/cp/except.c
> @@ -1050,7 +1050,7 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/,
> void * /*data*/)
>if (concept_check_p (fn))
> return NULL_TREE;
>tree type = TREE_TYPE (fn);
> -  gcc_assert (INDIRECT_TYPE_P (type));
> +  gcc_assert (INDIRECT_TYPE_P (type) || type == unknown_type_node);
>type = TREE_TYPE (type);
>  
>STRIP_NOPS (fn);
> @@ -1073,7 +1073,7 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/,
> void * /*data*/)
>  to evaluate the noexcept-specifier's operand here, but that
> could
>  cause instantiations that would fail.  */
> }
> -  if (!TYPE_NOTHROW_P (type))
> +  if (type == unknown_type_node || !TYPE_NOTHROW_P (type))
> return fn;
>  }
> 
> 
> fixes all but the ICE for g++.dg/warn/noeffect4.C where we end up with
> an invalid CALL_EXPR:
> 
> arg:0  long unsigned int>
> readonly
> arg:0  0x765615e8 int>
> side-effects tree_6
> fn  0x766a5f18>
>
> 
> also notice how sizeof() doesn't have side-effects but the call has.  I
> suppose that's somehow an "unevaluated" sizeof() expression we don't
> expect to hit expr_noexcept_p?  OTOH noexcept(sizeof(foo())) might be
> "valid"?

Incidentally I just posted a patch for noexcept(sizeof(foo())) because we got
the result wrong (I hadn't been aware of this PR): bug 101087.  Not sure if
that is going to help here, but it could.

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

Richard Biener  changed:

   What|Removed |Added

 Depends on||101087

--- Comment #11 from Richard Biener  ---
(In reply to Richard Biener from comment #10)
> (In reply to Richard Biener from comment #7)
> > Jason, any idea?
... 
> which leaves us with
> 
> FAIL: g++.dg/warn/noeffect4.C  -std=gnu++98  (test for warnings, line 84)
> FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for warnings, line 84)
> FAIL: g++.dg/warn/noeffect4.C  -std=gnu++17  (test for warnings, line 84)
> FAIL: g++.dg/warn/noeffect4.C  -std=gnu++2a  (test for warnings, line 84)
> 
> not diagnosing
> 
>   sizeof (x++);// { dg-warning "no effect" }
> 
> not sure what should happen to the x++ side-effect (throwing).

Ah, that's likely PR101087


Referenced Bugs:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=101087
[Bug 101087] [9/10/11/12 Regression] Unevaluated operand of sizeof affects
noexcept operator

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #10 from Richard Biener  ---
(In reply to Richard Biener from comment #7)
> Jason, any idea?

diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index a8cea53cf91..cbc94dff790 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1050,7 +1050,7 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void
* /*data*/)
   if (concept_check_p (fn))
return NULL_TREE;
   tree type = TREE_TYPE (fn);
-  gcc_assert (INDIRECT_TYPE_P (type));
+  gcc_assert (INDIRECT_TYPE_P (type) || type == unknown_type_node);
   type = TREE_TYPE (type);

   STRIP_NOPS (fn);
@@ -1073,7 +1073,7 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void
* /*data*/)
 to evaluate the noexcept-specifier's operand here, but that could
 cause instantiations that would fail.  */
}
-  if (!TYPE_NOTHROW_P (type))
+  if (type == unknown_type_node || !TYPE_NOTHROW_P (type))
return fn;
 }


fixes all but the ICE for g++.dg/warn/noeffect4.C where we end up with
an invalid CALL_EXPR:

arg:0 
readonly
arg:0 
side-effects tree_6
fn 


also notice how sizeof() doesn't have side-effects but the call has.  I
suppose that's somehow an "unevaluated" sizeof() expression we don't
expect to hit expr_noexcept_p?  OTOH noexcept(sizeof(foo())) might be
"valid"?

Changing the assert to if (INDIRECT_TYPE_P (type)) conditionalizing the
use of 'type' beyond of course works.  Aka

 diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index a8cea53cf91..623b83b8dc2 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -1050,8 +1050,6 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void
* /*data*/)
   if (concept_check_p (fn))
return NULL_TREE;
   tree type = TREE_TYPE (fn);
-  gcc_assert (INDIRECT_TYPE_P (type));
-  type = TREE_TYPE (type);

   STRIP_NOPS (fn);
   if (TREE_CODE (fn) == ADDR_EXPR)
@@ -1073,7 +1071,8 @@ check_noexcept_r (tree *tp, int * /*walk_subtrees*/, void
* /*data*/)
 to evaluate the noexcept-specifier's operand here, but that could
 cause instantiations that would fail.  */
}
-  if (!TYPE_NOTHROW_P (type))
+  if (!INDIRECT_TYPE_P (type)
+ || !TYPE_NOTHROW_P (TREE_TYPE (type)))
return fn;
 }

which leaves us with

FAIL: g++.dg/warn/noeffect4.C  -std=gnu++98  (test for warnings, line 84)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for warnings, line 84)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++17  (test for warnings, line 84)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++2a  (test for warnings, line 84)

not diagnosing

  sizeof (x++);// { dg-warning "no effect" }

not sure what should happen to the x++ side-effect (throwing).

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread harald at gigawatt dot nl via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #9 from Harald van Dijk  ---
(In reply to Richard Biener from comment #8)
> It has been consensus that throwing exceptions and const/pure are different
> concepts that co-exist.  See for example the recent discussion at
> https://gcc.gnu.org/pipermail/gcc-patches/2021-May/569435.html

Thanks, based on that I have created PR101376.

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #8 from Richard Biener  ---
(In reply to Harald van Dijk from comment #4)
> The documentation for the pure attribute refers to "functions that have no
> observable effects on the state of the program other than to return a value"
> which implies not throwing exceptions, the Wsuggest-attribute=pure text says
> that pure functions have to return normally, and the presence of throw
> statements suppresses the compiler's suggestion to mark functions as pure.
> This function throws, so should the fact that it is marked pure not simply
> make the whole thing undefined?

It has been consensus that throwing exceptions and const/pure are different
concepts that co-exist.  See for example the recent discussion at
https://gcc.gnu.org/pipermail/gcc-patches/2021-May/569435.html

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

Richard Biener  changed:

   What|Removed |Added

 CC||jason at gcc dot gnu.org

--- Comment #7 from Richard Biener  ---
Jason, any idea?

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #6 from Richard Biener  ---
Created attachment 51116
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=51116=edit
patch I was testing

I was testing this patch.

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #5 from Richard Biener  ---
Hmm, doesn't quite work.

FAIL: g++.dg/cpp0x/sfinae19.C  -std=c++14 (internal compiler error)
FAIL: g++.dg/cpp0x/sfinae22.C  -std=c++14 (internal compiler error)
FAIL: g++.dg/cpp1y/pr61636-2.C  -std=c++14 (internal compiler error)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for errors, line 79)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for warnings, line 80)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for warnings, line 82)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for warnings, line 83)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for warnings, line 84)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for warnings, line 85)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14  (test for warnings, line 88)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14 (internal compiler error)
FAIL: g++.dg/warn/noeffect4.C  -std=gnu++14 (test for excess errors)

the ICE is

/home/rguenther/src/trunk/gcc/testsuite/g++.dg/cpp0x/sfinae19.C:8:30: internal
compiler error: in check_noexcept_r, at cp/except.c:1053^M

  if ((code == CALL_EXPR && CALL_EXPR_FN (t))
  || code == AGGR_INIT_EXPR)
{
  /* We can only use the exception specification of the called function
 for determining the value of a noexcept expression; we can't use
 TREE_NOTHROW, as it might have a different value in another
 translation unit, creating ODR problems.

 We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */
  tree fn = cp_get_callee (t);
  if (concept_check_p (fn))
return NULL_TREE;
  tree type = TREE_TYPE (fn);
  gcc_assert (INDIRECT_TYPE_P (type));

where the type is likely the lang_type in:

 
VOID
align:1 warn_if_not_align:0 symtab:0 alias-set -1 canonical-type
0x766851f8
pointer_to_this 
reference_to_this >

whatever that exactly is, it isn't a reference or pointer type.

processing_template_decl is true in this context, but if we assume
that in this context expr_noexcept_p is true we probably miss diagnostics.

Jason, any idea?

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread harald at gigawatt dot nl via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

Harald van Dijk  changed:

   What|Removed |Added

 CC||harald at gigawatt dot nl

--- Comment #4 from Harald van Dijk  ---
The documentation for the pure attribute refers to "functions that have no
observable effects on the state of the program other than to return a value"
which implies not throwing exceptions, the Wsuggest-attribute=pure text says
that pure functions have to return normally, and the presence of throw
statements suppresses the compiler's suggestion to mark functions as pure. This
function throws, so should the fact that it is marked pure not simply make the
whole thing undefined?

[Bug c++/100409] C++ FE elides pure throwing call

2021-07-08 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #3 from Richard Biener  ---
So I'm looking again at this.  For the simple cases I have at hand we can
fix the C++ FE issue with

diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index d035e611be4..81097942449 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1645,7 +1645,12 @@ convert_to_void (tree expr, impl_conv_void implicit,
tsub
st_flags_t complain)
}
   expr = build1 (CONVERT_EXPR, void_type_node, expr);
 }
-  if (! TREE_SIDE_EFFECTS (expr))
+  if (! TREE_SIDE_EFFECTS (expr)
+  && ! (CONVERT_EXPR_P (expr)
+   && TREE_CODE (TREE_OPERAND (expr, 0)) == CALL_EXPR
+   && ! TREE_NOTHROW (TREE_OPERAND (expr, 0)))
+  && ! (TREE_CODE (expr) == CALL_EXPR
+   && ! TREE_NOTHROW (expr)))
 expr = void_node;
   return expr;
 }

of course that relies on seeing f() or (void)f(), it already fails with
(void)(1 + f()).  We also diagnose such stmts as having no effect:

t.ii: In function 'int bar(int*, int)':
t.ii:13:10: warning: statement has no effect [-Wunused-value]
   13 |1 + foo (n);
  |~~^

there's expr_noexcept_p that seems to work here even for 1 + foo () but
I'm not sure it's the correct tool.  But it would simplify a fix to

diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index d035e611be4..4885a7c6584 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -1645,7 +1645,7 @@ convert_to_void (tree expr, impl_conv_void implicit,
tsubst_flags_t complain)
}
   expr = build1 (CONVERT_EXPR, void_type_node, expr);
 }
-  if (! TREE_SIDE_EFFECTS (expr))
+  if (! TREE_SIDE_EFFECTS (expr) && expr_noexcept_p (expr, 0))
 expr = void_node;
   return expr;
 }

I'm giving that full testing.

[Bug c++/100409] C++ FE elides pure throwing call

2021-05-05 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

--- Comment #2 from Richard Biener  ---
After the PR100394 fix this is now the prevailing issue.

[Bug c++/100409] C++ FE elides pure throwing call

2021-05-04 Thread rguenth at gcc dot gnu.org via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100409

Richard Biener  changed:

   What|Removed |Added

   Keywords||wrong-code

--- Comment #1 from Richard Biener  ---
Runtime testcase that aborts:

int x, y;
int __attribute__((pure,noinline)) foo () { if (x) throw 1; return y; }
int __attribute__((noinline)) foo2 () { foo (); return y; }

int __attribute__((noinline)) bar()
{
  int a[2];
  x = 1;
  try {
int res = foo2 ();
a[0] = res;
  } catch (...) {
  return 0;
  }
  return 1;
}

int main()
{
  if (bar ())
__builtin_abort ();
  return 0;
}