Bug 67371 - Never executed "throw" in constexpr function fails to compile
Summary: Never executed "throw" in constexpr function fails to compile
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 6.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 66026 (view as bug list)
Depends on:
Blocks: constexpr
  Show dependency treegraph
 
Reported: 2015-08-27 13:26 UTC by Louis Dionne
Modified: 2019-05-13 09:54 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 5.2.1, 6.0
Last reconfirmed: 2015-08-28 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Louis Dionne 2015-08-27 13:26:43 UTC
The following code fails to compile on GCC trunk:

    constexpr void f() {
        if (false)
            throw;
    }


The error is:

    [snip]: In function 'constexpr void f()':
    [snip]: error: expression '<throw-expression>' is not a constant-expression
     }
     ^


The code should compile because the throw expression is never executed inside a constexpr context. Clang indeed compiles this just fine.

Live example: http://melpon.org/wandbox/permlink/V0g96xpWdO2eWGNx
Comment 1 Louis Dionne 2015-08-27 22:52:33 UTC
This is almost certainly a duplicate of #66026, yet it is still unconfirmed.
Comment 2 Markus Trippelsdorf 2015-08-28 05:30:03 UTC
*** Bug 66026 has been marked as a duplicate of this bug. ***
Comment 3 Markus Trippelsdorf 2015-08-28 05:32:46 UTC
Switch statements are rejected, too:

constexpr int fun(int n) {
  switch (n) {
  case 0:
    return 1;
  default:
    throw;
  }
}
static_assert(fun(0), "");

Only the ternary operator works fine.
Comment 4 Markus Trippelsdorf 2015-08-28 08:43:07 UTC
The fix might be as simple as:

diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index 1eacb8be9a44..7016b347a79c 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -4324,7 +4324,6 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
     case VEC_NEW_EXPR:
     case DELETE_EXPR:
     case VEC_DELETE_EXPR:
-    case THROW_EXPR:
     case OMP_ATOMIC:
     case OMP_ATOMIC_READ:
     case OMP_ATOMIC_CAPTURE_OLD:
@@ -4629,6 +4628,9 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict,
       /* We can see these in statement-expressions.  */
       return true;
 
+    case THROW_EXPR:
+      return true;
+
     default:
       if (objc_is_property_ref (t))
        return false;
Comment 5 Mikhail Maltsev 2015-08-28 08:57:38 UTC
(In reply to Markus Trippelsdorf from comment #4)
> The fix might be as simple as:

I tried something similar but got:

./constexpr_throw.cc:4:15: error: call to non-constexpr function 'void* __cxa_allocate_exception(long unsigned int)'
         throw 1;
or:
./constexpr_throw.cc:4:9: error: call to non-constexpr function 'void __cxa_rethrow()'
         throw;
Comment 6 Markus Trippelsdorf 2015-08-28 09:37:00 UTC
Well, my patch survives regression testing and fixes the issue.

But unfortunately it leads to accept invalid cases like:

constexpr int f1() {
  throw;
  return 0;
}

or 

constexpr void f2() {
  throw;
}

(Even clang accepts f2.)
Comment 7 Casey Carter 2015-08-28 10:06:17 UTC
(In reply to Markus Trippelsdorf from comment #6)
> Well, my patch survives regression testing and fixes the issue.
> 
> But unfortunately it leads to accept invalid cases like:
> 
> constexpr int f1() {
>   throw;
>   return 0;
> }
> 
> or 
> 
> constexpr void f2() {
>   throw;
> }
> 
> (Even clang accepts f2.)

I think it would be better for the compiler to accept constexpr functions that are ill-formed NDR - like f1 and f2 - than to reject constexpr functions that are conforming like:

constexpr int f3() {
  return 0;
  throw;
}

constexpr int* f4(bool b) {
  if (b) { return nullptr; }
  else { return new int{42}; }
}
Comment 8 Markus Trippelsdorf 2015-08-29 18:51:57 UTC
Author: trippels
Date: Sat Aug 29 18:51:26 2015
New Revision: 227323

URL: https://gcc.gnu.org/viewcvs?rev=227323&root=gcc&view=rev
Log:
Fix c++/67371 (issues with throw in constexpr)

As PR67371 shows gcc currently rejects all throw statements in
constant-expressions, even when they are never executed.

	PR c++/67371
	* constexpr.c (potential_constant_expression_1): Remove IF_STMT
	case. Move label to COND_EXPR case. Remove checking of
	SWITCH_STMT_BODY.

Added:
    trunk/gcc/testsuite/g++.dg/cpp1y/constexpr-new.C
    trunk/gcc/testsuite/g++.dg/cpp1y/constexpr-throw.C
Modified:
    trunk/gcc/cp/ChangeLog
    trunk/gcc/cp/constexpr.c
Comment 9 Markus Trippelsdorf 2015-08-29 18:55:38 UTC
Fixed.
Comment 10 rhalbersma 2015-12-19 08:53:51 UTC
Ping to get this merged into the upcoming 5.4 release.
Comment 11 Markus Trippelsdorf 2015-12-19 08:59:17 UTC
(In reply to rhalbersma from comment #10)
> Ping to get this merged into the upcoming 5.4 release.

Only regressions should be backported. This isn't one.
Comment 12 Markus Trippelsdorf 2015-12-19 09:00:30 UTC
(In reply to Markus Trippelsdorf from comment #11)
> (In reply to rhalbersma from comment #10)
> > Ping to get this merged into the upcoming 5.4 release.
> 
> Only regressions should be backported. This isn't one.

s/regressions/regression fixes/
Comment 13 Matthijs van Duin 2017-07-21 06:04:58 UTC
This is still not working for me in g++ 6 and 7:

constexpr void foo( bool ok ) {
        if( ok )
                return;
        throw;
}

In function ‘constexpr void foo(bool)’:
error: expression ‘<throw-expression>’ is not a constant-expression


Rewriting the code as:

constexpr void foo( bool ok ) {
        if( ok )
                return;
        else
                throw;
}

gets rid of the error, but this can be really awkward to do in more complicated functions.
Comment 14 Benjamin Buch 2017-08-25 10:52:40 UTC
Please reopen!

Only a part of this bug is fixed:


constexpr int f(){
    if(false) throw 0;
    return 0;
}

int main(){
    constexpr auto i = f();
}


is OK now, but


constexpr int f(){
    if(true) return 0;
    throw 0;
}

int main(){
    constexpr auto i = f();
}


still fails.

Tested with:

$ g++ --version                                                                                                                                                                                                                  
g++ (GCC) 8.0.0 20170818 (experimental)                                                                                                                                                                                                                               
Copyright (C) 2017 Free Software Foundation, Inc.                                                                                                                                                                                                                     
This is free software; see the source for copying conditions.  There is NO                                                                                                                                                                                            
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Comment 15 fiesh 2019-05-11 20:20:19 UTC
This seems to have been solved entirely with the release of 9.1!  So it should remain closed.  (8.3 is still broken)
Comment 16 Jonathan Wakely 2019-05-12 22:48:39 UTC
I'd guess it was fixed by the patch for PR 86678.
Comment 17 Jonathan Wakely 2019-05-13 09:54:49 UTC
(In reply to Jonathan Wakely from comment #16)
> I'd guess it was fixed by the patch for PR 86678.

Confirmed, it was fixed by r264171 for PR 86678.