public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* C++ PATCH for c++/50424 (wrong code with throwing default argument)
@ 2011-09-17  6:31 Jason Merrill
  0 siblings, 0 replies; only message in thread
From: Jason Merrill @ 2011-09-17  6:31 UTC (permalink / raw)
  To: gcc-patches List

[-- Attachment #1: Type: text/plain, Size: 367 bytes --]

We collect information about whether a function can throw as we compile 
the function: if we build up a call that can throw, then the current 
function can throw, too.  But we weren't doing the same for default 
arguments used in a call, which might themselves contain calls that can 
throw.

Tested x86_64-pc-linux-gnu, applying to trunk and a smaller patch to 4.6.

[-- Attachment #2: 50424.patch --]
[-- Type: text/x-patch, Size: 6251 bytes --]

commit 98ffb624642b54592956dae50c744300ba3a29c0
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Sep 15 14:31:50 2011 -0400

    	PR c++/50424
    	* call.c (set_flags_from_callee): Split out from build_call_a.
    	* cp-tree.h: Declare it.
    	* tree.c (bot_manip): Call it.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 81df80e..bdbede7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -306,11 +306,32 @@ build_call_n (tree function, int n, ...)
     }
 }
 
-tree
-build_call_a (tree function, int n, tree *argarray)
+/* Update various flags in cfun and the call itself based on what is being
+   called.  Split out of build_call_a so that bot_manip can use it too.  */
+
+void
+set_flags_from_callee (tree call)
 {
-  int is_constructor = 0;
   int nothrow;
+  tree decl = get_callee_fndecl (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))
+	     || TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (CALL_EXPR_FN (call)))));
+
+  if (!nothrow && at_function_scope_p () && cfun && cp_function_chain)
+    cp_function_chain->can_throw = 1;
+
+  if (decl && TREE_THIS_VOLATILE (decl) && cfun && cp_function_chain)
+    current_function_returns_abnormally = 1;
+
+  TREE_NOTHROW (call) = nothrow;
+}
+
+tree
+build_call_a (tree function, int n, tree *argarray)
+{
   tree decl;
   tree result_type;
   tree fntype;
@@ -327,60 +348,45 @@ build_call_a (tree function, int n, tree *argarray)
   if (SCALAR_TYPE_P (result_type) || VOID_TYPE_P (result_type))
     result_type = cv_unqualified (result_type);
 
-  if (TREE_CODE (function) == ADDR_EXPR
-      && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL)
+  function = build_call_array_loc (input_location,
+				   result_type, function, n, argarray);
+  set_flags_from_callee (function);
+
+  decl = get_callee_fndecl (function);
+
+  if (decl && !TREE_USED (decl))
     {
-      decl = TREE_OPERAND (function, 0);
-      if (!TREE_USED (decl))
-	{
-	  /* We invoke build_call directly for several library
-	     functions.  These may have been declared normally if
-	     we're building libgcc, so we can't just check
-	     DECL_ARTIFICIAL.  */
-	  gcc_assert (DECL_ARTIFICIAL (decl)
-		      || !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
-				   "__", 2));
-	  mark_used (decl);
-	}
+      /* We invoke build_call directly for several library
+	 functions.  These may have been declared normally if
+	 we're building libgcc, so we can't just check
+	 DECL_ARTIFICIAL.  */
+      gcc_assert (DECL_ARTIFICIAL (decl)
+		  || !strncmp (IDENTIFIER_POINTER (DECL_NAME (decl)),
+			       "__", 2));
+      mark_used (decl);
     }
-  else
-    decl = NULL_TREE;
-
-  /* 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))
-	     || TYPE_NOTHROW_P (TREE_TYPE (TREE_TYPE (function))));
-
-  if (!nothrow && at_function_scope_p () && cfun && cp_function_chain)
-    cp_function_chain->can_throw = 1;
-
-  if (decl && TREE_THIS_VOLATILE (decl) && cfun && cp_function_chain)
-    current_function_returns_abnormally = 1;
 
   if (decl && TREE_DEPRECATED (decl))
     warn_deprecated_use (decl, NULL_TREE);
   require_complete_eh_spec_types (fntype, decl);
 
-  if (decl && DECL_CONSTRUCTOR_P (decl))
-    is_constructor = 1;
+  TREE_HAS_CONSTRUCTOR (function) = (decl && DECL_CONSTRUCTOR_P (decl));
 
   /* Don't pass empty class objects by value.  This is useful
      for tags in STL, which are used to control overload resolution.
      We don't need to handle other cases of copying empty classes.  */
   if (! decl || ! DECL_BUILT_IN (decl))
     for (i = 0; i < n; i++)
-      if (is_empty_class (TREE_TYPE (argarray[i]))
-	  && ! TREE_ADDRESSABLE (TREE_TYPE (argarray[i])))
-	{
-	  tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (argarray[i]));
-	  argarray[i] = build2 (COMPOUND_EXPR, TREE_TYPE (t),
-				argarray[i], t);
-	}
-
-  function = build_call_array_loc (input_location,
-				   result_type, function, n, argarray);
-  TREE_HAS_CONSTRUCTOR (function) = is_constructor;
-  TREE_NOTHROW (function) = nothrow;
+      {
+	tree arg = CALL_EXPR_ARG (function, i);
+	if (is_empty_class (TREE_TYPE (arg))
+	    && ! TREE_ADDRESSABLE (TREE_TYPE (arg)))
+	  {
+	    tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg));
+	    arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
+	    CALL_EXPR_ARG (function, i) = arg;
+	  }
+      }
 
   return function;
 }
@@ -6736,7 +6742,6 @@ build_cxx_call (tree fn, int nargs, tree *argarray)
   fn = build_call_a (fn, nargs, argarray);
   SET_EXPR_LOCATION (fn, loc);
 
-  /* If this call might throw an exception, note that fact.  */
   fndecl = get_callee_fndecl (fn);
 
   /* Check that arguments to builtin functions match the expectations.  */
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 12a2895..8e52e28 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4721,6 +4721,7 @@ extern bool check_dtor_name			(tree, tree);
 extern tree build_conditional_expr		(tree, tree, tree, 
                                                  tsubst_flags_t);
 extern tree build_addr_func			(tree);
+extern void set_flags_from_callee		(tree);
 extern tree build_call_a			(tree, int, tree*);
 extern tree build_call_n			(tree, int, ...);
 extern bool null_ptr_cst_p			(tree);
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 13421a4..9987953 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1898,7 +1898,10 @@ bot_manip (tree* tp, int* walk_subtrees, void* data)
     }
 
   /* Make a copy of this node.  */
-  return copy_tree_r (tp, walk_subtrees, NULL);
+  t = copy_tree_r (tp, walk_subtrees, NULL);
+  if (TREE_CODE (*tp) == CALL_EXPR)
+    set_flags_from_callee (*tp);
+  return t;
 }
 
 /* Replace all remapped VAR_DECLs in T with their new equivalents.
diff --git a/gcc/testsuite/g++.dg/eh/defarg1.C b/gcc/testsuite/g++.dg/eh/defarg1.C
new file mode 100644
index 0000000..5c6e4df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/defarg1.C
@@ -0,0 +1,10 @@
+// PR c++/50424
+// { dg-do run }
+
+int f() { throw 1; }
+void g( int = f() ) { }
+void h() { g(); }
+int main()
+{
+  try { h(); } catch (int) { }
+}

[-- Attachment #3: 50424-4.6.patch --]
[-- Type: text/x-patch, Size: 1110 bytes --]

commit d4880772f234b9c86b0af79954ea88f2134fbaa4
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Sep 16 16:14:59 2011 -0400

    	PR c++/50424
    	* tree.c (bot_manip): Set cp_function_chain->can_throw.

diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 1fa32a0..7e7b34b 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -1861,7 +1861,11 @@ bot_manip (tree* tp, int* walk_subtrees, void* data)
     }
 
   /* Make a copy of this node.  */
-  return copy_tree_r (tp, walk_subtrees, NULL);
+  t = copy_tree_r (tp, walk_subtrees, NULL);
+  if (TREE_CODE (*tp) == CALL_EXPR && !TREE_NOTHROW (*tp)
+      && cfun && cp_function_chain)
+    cp_function_chain->can_throw = 1;
+  return t;
 }
 
 /* Replace all remapped VAR_DECLs in T with their new equivalents.
diff --git a/gcc/testsuite/g++.dg/eh/defarg1.C b/gcc/testsuite/g++.dg/eh/defarg1.C
new file mode 100644
index 0000000..5c6e4df
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/defarg1.C
@@ -0,0 +1,10 @@
+// PR c++/50424
+// { dg-do run }
+
+int f() { throw 1; }
+void g( int = f() ) { }
+void h() { g(); }
+int main()
+{
+  try { h(); } catch (int) { }
+}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2011-09-16 21:13 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-09-17  6:31 C++ PATCH for c++/50424 (wrong code with throwing default argument) Jason Merrill

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).