Implement P1002R1, Try-catch blocks in constexpr functions PR c++/89513
authorJakub Jelinek <jakub@redhat.com>
Fri, 1 Mar 2019 14:20:03 +0000 (15:20 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Fri, 1 Mar 2019 14:20:03 +0000 (15:20 +0100)
Implement P1002R1, Try-catch blocks in constexpr functions
PR c++/89513
* parser.c (cp_parser_ctor_initializer_opt_and_function_body):
Diagnose constexpr ctor or function with function-try-block with
pedwarn for c++17 and earlier.  Formatting fix.
(cp_parser_try_block): Use pedwarn instead of error and only for
c++17 and earlier when try block appears in constexpr function.
* constexpr.c (build_constexpr_constructor_member_initializers):
Handle TRY_BLOCK here instead of erroring on it.

* g++.dg/cpp2a/constexpr-try1.C: New test.
* g++.dg/cpp2a/constexpr-try2.C: New test.
* g++.dg/cpp2a/constexpr-try3.C: New test.
* g++.dg/cpp2a/constexpr-try4.C: New test.
* g++.dg/cpp2a/constexpr-try5.C: New test.
* g++.dg/cpp0x/constexpr-ctor10.C: Don't expect error for C++2a.

From-SVN: r269314

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/parser.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/constexpr-ctor10.C
gcc/testsuite/g++.dg/cpp2a/constexpr-try1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-try2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-try3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-try4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C [new file with mode: 0644]

index a86ffa3..11b9bb2 100644 (file)
@@ -1,3 +1,15 @@
+2019-03-01  Jakub Jelinek  <jakub@redhat.com>
+
+       Implement P1002R1, Try-catch blocks in constexpr functions
+       PR c++/89513
+       * parser.c (cp_parser_ctor_initializer_opt_and_function_body):
+       Diagnose constexpr ctor or function with function-try-block with
+       pedwarn for c++17 and earlier.  Formatting fix.
+       (cp_parser_try_block): Use pedwarn instead of error and only for
+       c++17 and earlier when try block appears in constexpr function.
+       * constexpr.c (build_constexpr_constructor_member_initializers):
+       Handle TRY_BLOCK here instead of erroring on it.
+
 2019-02-28  Jason Merrill  <jason@redhat.com>
 
        PR c++/88183 - ICE with .* fold-expression.
index 5bc5efe..65888b6 100644 (file)
@@ -601,6 +601,12 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
        gcc_unreachable ();
     }
  found:
+  if (TREE_CODE (body) == TRY_BLOCK)
+    {
+      body = TREE_OPERAND (body, 0);
+      if (TREE_CODE (body) == BIND_EXPR)
+       body = BIND_EXPR_BODY (body);
+    }
   if (TREE_CODE (body) == CLEANUP_POINT_EXPR)
     {
       body = TREE_OPERAND (body, 0);
@@ -626,12 +632,6 @@ build_constexpr_constructor_member_initializers (tree type, tree body)
            break;
        }
     }
-  else if (TREE_CODE (body) == TRY_BLOCK)
-    {
-      error ("body of %<constexpr%> constructor cannot be "
-            "a function-try-block");
-      return error_mark_node;
-    }
   else if (EXPR_P (body))
     ok = build_data_member_initialization (body, &vec);
   else
index 5f69403..2edd685 100644 (file)
@@ -22590,11 +22590,25 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser,
                                                  bool in_function_try_block)
 {
   tree body, list;
-  const bool check_body_p =
-     DECL_CONSTRUCTOR_P (current_function_decl)
-     && DECL_DECLARED_CONSTEXPR_P (current_function_decl);
+  const bool check_body_p
+     = (DECL_CONSTRUCTOR_P (current_function_decl)
+       && DECL_DECLARED_CONSTEXPR_P (current_function_decl));
   tree last = NULL;
 
+  if (in_function_try_block
+      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+      && cxx_dialect < cxx2a)
+    {
+      if (DECL_CONSTRUCTOR_P (current_function_decl))
+       pedwarn (input_location, 0,
+                "function-try-block body of %<constexpr%> constructor only "
+                "available with -std=c++2a or -std=gnu++2a");
+      else
+       pedwarn (input_location, 0,
+                "function-try-block body of %<constexpr%> function only "
+                "available with -std=c++2a or -std=gnu++2a");
+    }
+
   /* Begin the function body.  */
   body = begin_function_body ();
   /* Parse the optional ctor-initializer.  */
@@ -25329,8 +25343,11 @@ cp_parser_try_block (cp_parser* parser)
 
   cp_parser_require_keyword (parser, RID_TRY, RT_TRY);
   if (parser->in_function_body
-      && DECL_DECLARED_CONSTEXPR_P (current_function_decl))
-    error ("%<try%> in %<constexpr%> function");
+      && DECL_DECLARED_CONSTEXPR_P (current_function_decl)
+      && cxx_dialect < cxx2a)
+    pedwarn (input_location, 0,
+            "%<try%> in %<constexpr%> function only "
+            "available with -std=c++2a or -std=gnu++2a");
 
   try_block = begin_try_block ();
   cp_parser_compound_statement (parser, NULL, BCS_TRY_BLOCK, false);
index 2ad0d80..7734ac6 100644 (file)
@@ -1,3 +1,14 @@
+2019-03-01  Jakub Jelinek  <jakub@redhat.com>
+
+       Implement P1002R1, Try-catch blocks in constexpr functions
+       PR c++/89513
+       * g++.dg/cpp2a/constexpr-try1.C: New test.
+       * g++.dg/cpp2a/constexpr-try2.C: New test.
+       * g++.dg/cpp2a/constexpr-try3.C: New test.
+       * g++.dg/cpp2a/constexpr-try4.C: New test.
+       * g++.dg/cpp2a/constexpr-try5.C: New test.
+       * g++.dg/cpp0x/constexpr-ctor10.C: Don't expect error for C++2a.
+
 2019-03-01  Richard Sandiford  <richard.sandiford@arm.com>
 
        PR tree-optimization/89535
index 1dbc335..194cc7c 100644 (file)
@@ -2,5 +2,5 @@
 // { dg-do compile { target c++11 } }
 
 struct foo {
-  constexpr foo() try { } catch(...) { };  // { dg-error "constexpr" }
+  constexpr foo() try { } catch(...) { };  // { dg-error "constexpr" "" { target c++17_down } }
 };
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-try1.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-try1.C
new file mode 100644 (file)
index 0000000..977eb86
--- /dev/null
@@ -0,0 +1,44 @@
+// PR c++/89513
+// { dg-do compile { target c++11 } }
+
+constexpr bool foo ()
+try {                  // { dg-error "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  return true;
+} catch (...) {                // { dg-error "compound-statement in 'constexpr' function" "" { target c++11_only } }
+  return false;
+}                      // { dg-error "body of 'constexpr' function" "" { target c++11_only } }
+
+constexpr bool bar ()
+try {                  // { dg-error "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  try {                        // { dg-error "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+    return true;       // { dg-error "compound-statement in 'constexpr' function" "" { target c++11_only } .-1 }
+  } catch (int) {      // { dg-error "compound-statement in 'constexpr' function" "" { target c++11_only } }
+    return false;
+  }
+} catch (...) {                // { dg-error "compound-statement in 'constexpr' function" "" { target c++11_only } }
+  return false;
+}                      // { dg-error "not a return-statement" "" { target c++11_only } }
+
+constexpr bool baz ()
+{
+  try { return true; } catch (...) { return false; }   // { dg-error "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+}                      // { dg-error "not a return-statement" "" { target c++11_only } }
+                       // { dg-error "compound-statement in 'constexpr' function" "" { target c++11_only } .-2 }
+
+struct S {
+  constexpr S () try : m (1)   // { dg-error "function-try-block body of 'constexpr' constructor only available with" "" { target c++17_down } }
+  {
+    try {              // { dg-error "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+    } catch (int) {    // { dg-error "compound-statement in 'constexpr' function" "" { target c++11_only } }
+    }                  // { dg-error "compound-statement in 'constexpr' function" "" { target c++11_only } .-2 }
+  } catch (...) {      // { dg-error "'constexpr' constructor does not have empty body" "" { target c++11_only } }
+  }
+  int m;
+};
+
+struct T {
+  constexpr T ()
+  try {                        // { dg-error "function-try-block body of 'constexpr' constructor only available with" "" { target c++17_down } }
+  } catch (...) {      // { dg-error "compound-statement in 'constexpr' function" "" { target c++11_only } }
+  }
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-try2.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-try2.C
new file mode 100644 (file)
index 0000000..7ca7261
--- /dev/null
@@ -0,0 +1,45 @@
+// PR c++/89513
+// { dg-do compile { target c++11 } }
+// { dg-options "-pedantic" }
+
+constexpr bool foo ()
+try {                  // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  return true;
+} catch (...) {                // { dg-warning "compound-statement in 'constexpr' function" "" { target c++11_only } }
+  return false;
+}                      // { dg-error "body of 'constexpr' function" "" { target c++11_only } }
+
+constexpr bool bar ()
+try {                  // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  try {                        // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+    return true;       // { dg-warning "compound-statement in 'constexpr' function" "" { target c++11_only } .-1 }
+  } catch (int) {      // { dg-warning "compound-statement in 'constexpr' function" "" { target c++11_only } }
+    return false;
+  }
+} catch (...) {                // { dg-warning "compound-statement in 'constexpr' function" "" { target c++11_only } }
+  return false;
+}                      // { dg-error "not a return-statement" "" { target c++11_only } }
+
+constexpr bool baz ()
+{
+  try { return true; } catch (...) { return false; }   // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+}                      // { dg-error "not a return-statement" "" { target c++11_only } }
+                       // { dg-warning "compound-statement in 'constexpr' function" "" { target c++11_only } .-2 }
+
+struct S {
+  constexpr S () try : m (1)   // { dg-warning "function-try-block body of 'constexpr' constructor only available with" "" { target c++17_down } }
+  {
+    try {              // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+    } catch (int) {    // { dg-warning "compound-statement in 'constexpr' function" "" { target c++11_only } }
+    }                  // { dg-warning "compound-statement in 'constexpr' function" "" { target c++11_only } .-2 }
+  } catch (...) {      // { dg-error "'constexpr' constructor does not have empty body" "" { target c++11_only } }
+  }
+  int m;
+};
+
+struct T {
+  constexpr T ()
+  try {                        // { dg-warning "function-try-block body of 'constexpr' constructor only available with" "" { target c++17_down } }
+  } catch (...) {      // { dg-warning "compound-statement in 'constexpr' function" "" { target c++11_only } }
+  }
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-try3.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-try3.C
new file mode 100644 (file)
index 0000000..ab7e8f6
--- /dev/null
@@ -0,0 +1,44 @@
+// PR c++/89513
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+constexpr bool foo ()
+try {                  // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  return true;
+} catch (...) {
+  return false;
+}                      // { dg-error "body of 'constexpr' function" "" { target c++11_only } }
+
+constexpr bool bar ()
+try {                  // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  try {                        // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+    return true;
+  } catch (int) {
+    return false;
+  }
+} catch (...) {
+  return false;
+}                      // { dg-error "not a return-statement" "" { target c++11_only } }
+
+constexpr bool baz ()
+{
+  try { return true; } catch (...) { return false; }   // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+}                      // { dg-error "not a return-statement" "" { target c++11_only } }
+
+struct S {
+  constexpr S () try : m (1)   // { dg-warning "function-try-block body of 'constexpr' constructor only available with" "" { target c++17_down } }
+  {
+    try {              // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+    } catch (int) {
+    }
+  } catch (...) {      // { dg-error "'constexpr' constructor does not have empty body" "" { target c++11_only } }
+  }
+  int m;
+};
+
+struct T {
+  constexpr T ()
+  try {                        // { dg-warning "function-try-block body of 'constexpr' constructor only available with" "" { target c++17_down } }
+  } catch (...) {
+  }
+};
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-try4.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-try4.C
new file mode 100644 (file)
index 0000000..8c2baef
--- /dev/null
@@ -0,0 +1,61 @@
+// PR c++/89513
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+constexpr int foo ()
+try {                  // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  int a = 1;
+  for (int i = 0; i < 10; i++)
+    a += i;
+  return a;
+} catch (...) {
+  return -1;
+}
+
+constexpr int bar ()
+try {                  // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  int a = 0;
+  for (int i = 0; i < 9; i++)
+    try {                      // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+      a += i;
+    } catch (int) {
+      return -1;
+    }
+  return a;
+} catch (...) {
+  return -2;
+}
+
+constexpr bool baz ()
+{
+  try { return true; } catch (...) { return false; }   // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+}
+
+struct S {
+  constexpr S () try : m (1)   // { dg-warning "function-try-block body of 'constexpr' constructor only available with" "" { target c++17_down } }
+  {
+    try {              // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+      m += 2;
+    } catch (int) {
+      m = -1;
+    }
+  } catch (...) {
+    m = -2;
+  }
+  int m;
+  constexpr int get () const { return m; }
+};
+
+struct T {
+  constexpr T ()
+  try {                        // { dg-warning "function-try-block body of 'constexpr' constructor only available with" "" { target c++17_down } }
+  } catch (...) {
+  }
+};
+
+static_assert (foo () == 46, "");
+static_assert (bar () == 36, "");
+static_assert (baz (), "");
+constexpr S s;
+static_assert (s.get () == 3, "");
+constexpr T t;
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-try5.C
new file mode 100644 (file)
index 0000000..47cdce8
--- /dev/null
@@ -0,0 +1,40 @@
+// PR c++/89513
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+constexpr int foo ()
+try {                  // { dg-warning "function-try-block body of 'constexpr' function only available with" "" { target c++17_down } }
+  int a;               // { dg-error "uninitialized variable 'a' in 'constexpr' function" }
+  static double b = 1.0;// { dg-error "'b' declared 'static' in 'constexpr' function" }
+  goto l;              // { dg-error "'goto' in 'constexpr' function" }
+  l:;
+  return 0;
+} catch (...) {
+  long int c;          // { dg-error "uninitialized variable 'c' in 'constexpr' function" }
+  static float d = 2.0f;// { dg-error "'d' declared 'static' in 'constexpr' function" }
+  goto l2;             // { dg-error "'goto' in 'constexpr' function" }
+  l2:;
+  return -1;
+}
+
+constexpr int bar ()
+{
+  int a;               // { dg-error "uninitialized variable 'a' in 'constexpr' function" }
+  static long double b = 3.0;// { dg-error "'b' declared 'static' in 'constexpr' function" }
+  goto l;              // { dg-error "'goto' in 'constexpr' function" }
+  l:;
+  try {                        // { dg-warning "'try' in 'constexpr' function only available with" "" { target c++17_down } }
+    short c;           // { dg-error "uninitialized variable 'c' in 'constexpr' function" }
+    static float d;    // { dg-error "'d' declared 'static' in 'constexpr' function" }
+                       // { dg-error "uninitialized variable 'd' in 'constexpr' function" "" { target *-*-* } .-1 }
+    goto l2;           // { dg-error "'goto' in 'constexpr' function" }
+    l2:;
+    return 0;
+  } catch (int) {
+    char e;            // { dg-error "uninitialized variable 'e' in 'constexpr' function" }
+    static int f = 5;  // { dg-error "'f' declared 'static' in 'constexpr' function" }
+    goto l3;           // { dg-error "'goto' in 'constexpr' function" }
+    l3:;
+    return 1;
+  }
+}