On Wed, May 16, 2018 at 01:53:50PM -0400, Jason Merrill wrote:
> You should be able to avoid duplication here by using cp_get_callee
> rather than *_FN.

Even better, thanks!

Bootstrapped/regtested on x86_64-linux, ok for trunk?

2018-05-16  Marek Polacek  <pola...@redhat.com>

        PR c++/85363
        * call.c (set_flags_from_callee): Handle AGGR_INIT_EXPRs too.
        * tree.c (bot_manip): Call set_flags_from_callee for
        AGGR_INIT_EXPRs too.

        * g++.dg/cpp0x/initlist-throw1.C: New test.
        * g++.dg/cpp0x/initlist-throw2.C: New test.

diff --git gcc/cp/call.c gcc/cp/call.c
index 09a3618b007..4d04785f2b9 100644
--- gcc/cp/call.c
+++ gcc/cp/call.c
@@ -319,15 +319,17 @@ build_call_n (tree function, int n, ...)
 void
 set_flags_from_callee (tree call)
 {
-  bool nothrow;
-  tree decl = get_callee_fndecl (call);
+  /* Handle both CALL_EXPRs and AGGR_INIT_EXPRs.  */
+  tree decl = cp_get_callee_fndecl_nofold (call);
 
   /* We check both the decl and the type; a function may be known not to
      throw without being declared throw().  */
-  nothrow = decl && TREE_NOTHROW (decl);
-  if (CALL_EXPR_FN (call))
-    nothrow |= TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (call))));
-  else if (internal_fn_flags (CALL_EXPR_IFN (call)) & ECF_NOTHROW)
+  bool nothrow = decl && TREE_NOTHROW (decl);
+  tree callee = cp_get_callee (call);
+  if (callee)
+    nothrow |= TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (callee)));
+  else if (TREE_CODE (call) == CALL_EXPR
+          && internal_fn_flags (CALL_EXPR_IFN (call)) & ECF_NOTHROW)
     nothrow = true;
 
   if (!nothrow && at_function_scope_p () && cfun && cp_function_chain)
diff --git gcc/cp/tree.c gcc/cp/tree.c
index ecb88df23b9..db81da91676 100644
--- gcc/cp/tree.c
+++ gcc/cp/tree.c
@@ -2987,7 +2987,7 @@ bot_manip (tree* tp, int* walk_subtrees, void* data_)
 
   /* Make a copy of this node.  */
   t = copy_tree_r (tp, walk_subtrees, NULL);
-  if (TREE_CODE (*tp) == CALL_EXPR)
+  if (TREE_CODE (*tp) == CALL_EXPR || TREE_CODE (*tp) == AGGR_INIT_EXPR)
     set_flags_from_callee (*tp);
   if (data.clear_location && EXPR_HAS_LOCATION (*tp))
     SET_EXPR_LOCATION (*tp, input_location);
diff --git gcc/testsuite/g++.dg/cpp0x/initlist-throw1.C 
gcc/testsuite/g++.dg/cpp0x/initlist-throw1.C
index e69de29bb2d..264c6c7a7a0 100644
--- gcc/testsuite/g++.dg/cpp0x/initlist-throw1.C
+++ gcc/testsuite/g++.dg/cpp0x/initlist-throw1.C
@@ -0,0 +1,29 @@
+// PR c++/85363
+// { dg-do run { target c++11 } }
+
+int
+init (int f)
+{
+  throw f;
+}
+
+struct X {
+  X (int f) : n {init (f)} {}
+  int n;
+};
+
+struct P {
+  X x{20};
+};
+
+int
+main ()
+{
+  try {
+    P p {};
+  }
+  catch (int n) {
+    return 0;
+  }
+  return 1;
+}
diff --git gcc/testsuite/g++.dg/cpp0x/initlist-throw2.C 
gcc/testsuite/g++.dg/cpp0x/initlist-throw2.C
index e69de29bb2d..2bb05834d9e 100644
--- gcc/testsuite/g++.dg/cpp0x/initlist-throw2.C
+++ gcc/testsuite/g++.dg/cpp0x/initlist-throw2.C
@@ -0,0 +1,33 @@
+// PR c++/85363
+// { dg-do run { target c++11 } }
+
+int
+init (int f)
+{
+  throw f;
+}
+
+struct X {
+  X () : n {init (42)} {}
+  int n;
+};
+
+struct P {
+  struct R {
+    struct Q {
+      X x = {};
+    } q;
+  } r;
+};
+
+int
+main ()
+{
+  try {
+    P p {};
+  }
+  catch (int n) {
+    return 0;
+  }
+  return 1;
+}

Reply via email to