Commit 8243e2a9 by Jason Merrill Committed by Jason Merrill

c.opt (Wterminate): New.

gcc/c-family/
	* c.opt (Wterminate): New.
gcc/cp/
	* cp-gimplify.c (cp_genericize_r): Track TRY_BLOCK and
	MUST_NOT_THROW_EXPR, warn about a THROW_EXPR directly within a
	MUST_NOT_THROW_EXPR.
	(cp_genericize_data): Add try_block field.
	(cp_genericize_tree): Initialize it.
	* except.c (expand_end_catch_block): Set TREE_NO_WARNING on
	implicit rethrow.

From-SVN: r222842
parent 81b6a6c5
2015-05-05 Jason Merrill <jason@redhat.com>
* c.opt (Wterminate): New.
2015-04-30 Marek Polacek <polacek@redhat.com> 2015-04-30 Marek Polacek <polacek@redhat.com>
* c-common.c (maybe_warn_bool_compare): When comparing with 0/1, * c-common.c (maybe_warn_bool_compare): When comparing with 0/1,
......
...@@ -829,6 +829,10 @@ Wsystem-headers ...@@ -829,6 +829,10 @@ Wsystem-headers
C ObjC C++ ObjC++ Warning C ObjC C++ ObjC++ Warning
; Documented in common.opt ; Documented in common.opt
Wterminate
C++ ObjC++ Warning Var(warn_terminate) Init(1)
Warn if a throw expression will always result in a call to terminate()
Wtraditional Wtraditional
C ObjC CPP(cpp_warn_traditional) CppReason(CPP_W_TRADITIONAL) Var(warn_traditional) Init(0) Warning C ObjC CPP(cpp_warn_traditional) CppReason(CPP_W_TRADITIONAL) Var(warn_traditional) Init(0) Warning
Warn about features not present in traditional C Warn about features not present in traditional C
......
2015-05-05 Jason Merrill <jason@redhat.com> 2015-05-05 Jason Merrill <jason@redhat.com>
* cp-gimplify.c (cp_genericize_r): Track TRY_BLOCK and
MUST_NOT_THROW_EXPR, warn about a THROW_EXPR directly within a
MUST_NOT_THROW_EXPR.
(cp_genericize_data): Add try_block field.
(cp_genericize_tree): Initialize it.
* except.c (expand_end_catch_block): Set TREE_NO_WARNING on
implicit rethrow.
* constexpr.c (potential_constant_expression_1) [AT_ENCODE_EXPR]: * constexpr.c (potential_constant_expression_1) [AT_ENCODE_EXPR]:
Return false. Return false.
......
...@@ -905,6 +905,7 @@ struct cp_genericize_data ...@@ -905,6 +905,7 @@ struct cp_genericize_data
hash_set<tree> *p_set; hash_set<tree> *p_set;
vec<tree> bind_expr_stack; vec<tree> bind_expr_stack;
struct cp_genericize_omp_taskreg *omp_ctx; struct cp_genericize_omp_taskreg *omp_ctx;
tree try_block;
}; };
/* Perform any pre-gimplification lowering of C++ front end trees to /* Perform any pre-gimplification lowering of C++ front end trees to
...@@ -1193,6 +1194,54 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) ...@@ -1193,6 +1194,54 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
wtd->omp_ctx = omp_ctx.outer; wtd->omp_ctx = omp_ctx.outer;
splay_tree_delete (omp_ctx.variables); splay_tree_delete (omp_ctx.variables);
} }
else if (TREE_CODE (stmt) == TRY_BLOCK)
{
*walk_subtrees = 0;
tree try_block = wtd->try_block;
wtd->try_block = stmt;
cp_walk_tree (&TRY_STMTS (stmt), cp_genericize_r, data, NULL);
wtd->try_block = try_block;
cp_walk_tree (&TRY_HANDLERS (stmt), cp_genericize_r, data, NULL);
}
else if (TREE_CODE (stmt) == MUST_NOT_THROW_EXPR)
{
/* MUST_NOT_THROW_COND might be something else with TM. */
if (MUST_NOT_THROW_COND (stmt) == NULL_TREE)
{
*walk_subtrees = 0;
tree try_block = wtd->try_block;
wtd->try_block = stmt;
cp_walk_tree (&TREE_OPERAND (stmt, 0), cp_genericize_r, data, NULL);
wtd->try_block = try_block;
}
}
else if (TREE_CODE (stmt) == THROW_EXPR)
{
location_t loc = location_of (stmt);
if (TREE_NO_WARNING (stmt))
/* Never mind. */;
else if (wtd->try_block)
{
if (TREE_CODE (wtd->try_block) == MUST_NOT_THROW_EXPR
&& warning_at (loc, OPT_Wterminate,
"throw will always call terminate()")
&& cxx_dialect >= cxx11
&& DECL_DESTRUCTOR_P (current_function_decl))
inform (loc, "in C++11 destructors default to noexcept");
}
else
{
if (warn_cxx0x_compat && cxx_dialect < cxx11
&& DECL_DESTRUCTOR_P (current_function_decl)
&& (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))
== NULL_TREE)
&& (get_defaulted_eh_spec (current_function_decl)
== empty_except_spec))
warning_at (loc, OPT_Wc__0x_compat,
"in C++11 this throw will terminate because "
"destructors default to noexcept");
}
}
else if (TREE_CODE (stmt) == CONVERT_EXPR) else if (TREE_CODE (stmt) == CONVERT_EXPR)
gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt)); gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt));
else if (TREE_CODE (stmt) == FOR_STMT) else if (TREE_CODE (stmt) == FOR_STMT)
...@@ -1269,6 +1318,7 @@ cp_genericize_tree (tree* t_p) ...@@ -1269,6 +1318,7 @@ cp_genericize_tree (tree* t_p)
wtd.p_set = new hash_set<tree>; wtd.p_set = new hash_set<tree>;
wtd.bind_expr_stack.create (0); wtd.bind_expr_stack.create (0);
wtd.omp_ctx = NULL; wtd.omp_ctx = NULL;
wtd.try_block = NULL_TREE;
cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL); cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
delete wtd.p_set; delete wtd.p_set;
wtd.bind_expr_stack.release (); wtd.bind_expr_stack.release ();
......
...@@ -579,7 +579,11 @@ expand_end_catch_block (void) ...@@ -579,7 +579,11 @@ expand_end_catch_block (void)
if (in_function_try_handler if (in_function_try_handler
&& (DECL_CONSTRUCTOR_P (current_function_decl) && (DECL_CONSTRUCTOR_P (current_function_decl)
|| DECL_DESTRUCTOR_P (current_function_decl))) || DECL_DESTRUCTOR_P (current_function_decl)))
finish_expr_stmt (build_throw (NULL_TREE)); {
tree rethrow = build_throw (NULL_TREE);
TREE_NO_WARNING (rethrow) = true;
finish_expr_stmt (rethrow);
}
} }
tree tree
......
...@@ -2882,6 +2882,12 @@ Warn when overload resolution chooses a promotion from unsigned or ...@@ -2882,6 +2882,12 @@ Warn when overload resolution chooses a promotion from unsigned or
enumerated type to a signed type, over a conversion to an unsigned type of enumerated type to a signed type, over a conversion to an unsigned type of
the same size. Previous versions of G++ tried to preserve the same size. Previous versions of G++ tried to preserve
unsignedness, but the standard mandates the current behavior. unsignedness, but the standard mandates the current behavior.
@item -Wno-terminate @r{(C++ and Objective-C++ only)}
@opindex Wterminate
@opindex Wno-terminate
Disable the warning about a throw-expression that will immediately
result in a call to @code{terminate}.
@end table @end table
@node Objective-C and Objective-C++ Dialect Options @node Objective-C and Objective-C++ Dialect Options
......
...@@ -5,6 +5,6 @@ struct Foo ...@@ -5,6 +5,6 @@ struct Foo
struct Bar struct Bar
{ {
~Bar (); ~Bar () throw(int);
Foo f; Foo f;
}; };
...@@ -7,7 +7,7 @@ Foo::~Foo() ...@@ -7,7 +7,7 @@ Foo::~Foo()
was_f_in_Bar_destroyed=true; was_f_in_Bar_destroyed=true;
} }
Bar::~Bar() Bar::~Bar() throw(int)
{ {
throw 1; throw 1;
} }
// Test that checking of a nothrow specification uses the one on the // Test that checking of a nothrow specification uses the one on the
// definition. // definition.
// { dg-do run { target c++11 } } // { dg-do run { target c++11 } }
// { dg-options "-Wno-terminate" }
#include <exception> #include <exception>
#include <cstdlib> #include <cstdlib>
......
// PR c++/50043 // PR c++/50043
// { dg-do compile { target c++11 } } // { dg-do compile { target c++11 } }
// { dg-options "-Wno-terminate" }
struct True1 {}; struct True1 {};
struct True2 { ~True2(); }; struct True2 { ~True2(); };
......
...@@ -12,7 +12,7 @@ void my_terminate () ...@@ -12,7 +12,7 @@ void my_terminate ()
struct A { struct A {
A(int) { } A(int) { }
~A() { throw 1; }; ~A() throw(int) { throw 1; };
}; };
struct B { struct B {
B(A) { } B(A) { }
......
...@@ -15,7 +15,7 @@ class A<int, int> ...@@ -15,7 +15,7 @@ class A<int, int>
public: public:
A(int) { ++count; if (b) throw 1; } A(int) { ++count; if (b) throw 1; }
A(const A&) { ++count; if (b) throw 1; } A(const A&) { ++count; if (b) throw 1; }
~A() { --count; if (b) throw 1; } ~A() throw(int) { --count; if (b) throw 1; }
}; };
typedef A<int, int> B; typedef A<int, int> B;
...@@ -26,7 +26,7 @@ class A<void *, void *> ...@@ -26,7 +26,7 @@ class A<void *, void *>
public: public:
A() { if (b) throw 1; } A() { if (b) throw 1; }
A(const B&) { if (b) throw 1; } A(const B&) { if (b) throw 1; }
~A() { if (b) throw 1; } ~A() throw(int) { if (b) throw 1; }
}; };
typedef A<void *, void *> C; typedef A<void *, void *> C;
......
...@@ -8,18 +8,18 @@ template <class _Tp> class AutoPtr ...@@ -8,18 +8,18 @@ template <class _Tp> class AutoPtr
public: public:
explicit AutoPtr(_Tp* __p = 0) : _M_ptr(__p) {} explicit AutoPtr(_Tp* __p = 0) : _M_ptr(__p) {}
~AutoPtr() { delete _M_ptr; } ~AutoPtr() throw(int) { delete _M_ptr; }
}; };
struct A struct A
{ {
A() { } A() { }
~A() { throw 1.0; } ~A() throw(int) { throw 1; }
}; };
struct B struct B
{ {
virtual ~B(); virtual ~B() throw(int);
}; };
B* f (const A &s) { throw 1; } B* f (const A &s) { throw 1; }
......
// { dg-do compile { target c++11 } } // { dg-do compile { target c++11 } }
// { dg-options "-fgnu-tm -O -fdump-tree-tmmark -fdump-tree-tmlower" } // { dg-options "-fgnu-tm -O -fdump-tree-tmmark -fdump-tree-tmlower -Wno-terminate" }
int global; int global;
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
struct Mutex struct Mutex
{ {
bool locked; bool locked;
~Mutex () ~Mutex () throw(int)
{ {
if (locked) if (locked)
throw 0; throw 0;
......
// In C++98 mode this gets a -Wc++11-compat warning, in C++11 mode a
// -Wterminate warning.
// { dg-options "-Wall" }
struct A
{
~A()
{
throw 1; // { dg-warning "terminate" }
}
};
int main()
{
try { A a; }
catch (...) {}
}
...@@ -10,7 +10,7 @@ void my_terminate() { ...@@ -10,7 +10,7 @@ void my_terminate() {
struct A { struct A {
A() { } A() { }
~A() { ~A() throw(int) {
std::set_terminate (my_terminate); std::set_terminate (my_terminate);
throw 1; // This throws from EH dtor, should call my_terminate throw 1; // This throws from EH dtor, should call my_terminate
} }
......
...@@ -27,7 +27,7 @@ struct Mutex ...@@ -27,7 +27,7 @@ struct Mutex
{ {
Mutex() : locked(false) { } Mutex() : locked(false) { }
~Mutex() ~Mutex() throw(int)
{ {
if (locked) if (locked)
throw 0; throw 0;
......
...@@ -32,7 +32,7 @@ namespace __gnu_test ...@@ -32,7 +32,7 @@ namespace __gnu_test
counter() : _M_count(0), _M_throw(true) { } counter() : _M_count(0), _M_throw(true) { }
~counter() ~counter() throw (counter_error)
{ {
if (_M_throw && _M_count != 0) if (_M_throw && _M_count != 0)
throw counter_error(); throw counter_error();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment