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
This commit is contained in:
parent
81b6a6c55b
commit
8243e2a9d0
@ -1,3 +1,7 @@
|
||||
2015-05-05 Jason Merrill <jason@redhat.com>
|
||||
|
||||
* c.opt (Wterminate): New.
|
||||
|
||||
2015-04-30 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
* c-common.c (maybe_warn_bool_compare): When comparing with 0/1,
|
||||
|
@ -829,6 +829,10 @@ Wsystem-headers
|
||||
C ObjC C++ ObjC++ Warning
|
||||
; 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
|
||||
C ObjC CPP(cpp_warn_traditional) CppReason(CPP_W_TRADITIONAL) Var(warn_traditional) Init(0) Warning
|
||||
Warn about features not present in traditional C
|
||||
|
@ -1,5 +1,13 @@
|
||||
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]:
|
||||
Return false.
|
||||
|
||||
|
@ -905,6 +905,7 @@ struct cp_genericize_data
|
||||
hash_set<tree> *p_set;
|
||||
vec<tree> bind_expr_stack;
|
||||
struct cp_genericize_omp_taskreg *omp_ctx;
|
||||
tree try_block;
|
||||
};
|
||||
|
||||
/* 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)
|
||||
wtd->omp_ctx = omp_ctx.outer;
|
||||
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)
|
||||
gcc_assert (!CONVERT_EXPR_VBASE_PATH (stmt));
|
||||
else if (TREE_CODE (stmt) == FOR_STMT)
|
||||
@ -1269,6 +1318,7 @@ cp_genericize_tree (tree* t_p)
|
||||
wtd.p_set = new hash_set<tree>;
|
||||
wtd.bind_expr_stack.create (0);
|
||||
wtd.omp_ctx = NULL;
|
||||
wtd.try_block = NULL_TREE;
|
||||
cp_walk_tree (t_p, cp_genericize_r, &wtd, NULL);
|
||||
delete wtd.p_set;
|
||||
wtd.bind_expr_stack.release ();
|
||||
|
@ -579,7 +579,11 @@ expand_end_catch_block (void)
|
||||
if (in_function_try_handler
|
||||
&& (DECL_CONSTRUCTOR_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
|
||||
|
@ -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
|
||||
the same size. Previous versions of G++ tried to preserve
|
||||
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
|
||||
|
||||
@node Objective-C and Objective-C++ Dialect Options
|
||||
|
@ -5,6 +5,6 @@ struct Foo
|
||||
|
||||
struct Bar
|
||||
{
|
||||
~Bar ();
|
||||
~Bar () throw(int);
|
||||
Foo f;
|
||||
};
|
||||
|
@ -7,7 +7,7 @@ Foo::~Foo()
|
||||
was_f_in_Bar_destroyed=true;
|
||||
}
|
||||
|
||||
Bar::~Bar()
|
||||
Bar::~Bar() throw(int)
|
||||
{
|
||||
throw 1;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// Test that checking of a nothrow specification uses the one on the
|
||||
// definition.
|
||||
// { dg-do run { target c++11 } }
|
||||
// { dg-options "-Wno-terminate" }
|
||||
|
||||
#include <exception>
|
||||
#include <cstdlib>
|
||||
|
@ -1,5 +1,6 @@
|
||||
// PR c++/50043
|
||||
// { dg-do compile { target c++11 } }
|
||||
// { dg-options "-Wno-terminate" }
|
||||
|
||||
struct True1 {};
|
||||
struct True2 { ~True2(); };
|
||||
|
@ -12,7 +12,7 @@ void my_terminate ()
|
||||
|
||||
struct A {
|
||||
A(int) { }
|
||||
~A() { throw 1; };
|
||||
~A() throw(int) { throw 1; };
|
||||
};
|
||||
struct B {
|
||||
B(A) { }
|
||||
|
@ -15,7 +15,7 @@ class A<int, int>
|
||||
public:
|
||||
A(int) { ++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;
|
||||
@ -26,7 +26,7 @@ class A<void *, void *>
|
||||
public:
|
||||
A() { 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;
|
||||
|
@ -8,18 +8,18 @@ template <class _Tp> class AutoPtr
|
||||
public:
|
||||
explicit AutoPtr(_Tp* __p = 0) : _M_ptr(__p) {}
|
||||
|
||||
~AutoPtr() { delete _M_ptr; }
|
||||
~AutoPtr() throw(int) { delete _M_ptr; }
|
||||
};
|
||||
|
||||
struct A
|
||||
{
|
||||
A() { }
|
||||
~A() { throw 1.0; }
|
||||
~A() throw(int) { throw 1; }
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
virtual ~B();
|
||||
virtual ~B() throw(int);
|
||||
};
|
||||
|
||||
B* f (const A &s) { throw 1; }
|
||||
|
@ -1,5 +1,5 @@
|
||||
// { 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;
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
struct Mutex
|
||||
{
|
||||
bool locked;
|
||||
~Mutex ()
|
||||
~Mutex () throw(int)
|
||||
{
|
||||
if (locked)
|
||||
throw 0;
|
||||
|
20
gcc/testsuite/g++.dg/warn/Wterminate1.C
Normal file
20
gcc/testsuite/g++.dg/warn/Wterminate1.C
Normal file
@ -0,0 +1,20 @@
|
||||
// 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() {
|
||||
|
||||
struct A {
|
||||
A() { }
|
||||
~A() {
|
||||
~A() throw(int) {
|
||||
std::set_terminate (my_terminate);
|
||||
throw 1; // This throws from EH dtor, should call my_terminate
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ struct Mutex
|
||||
{
|
||||
Mutex() : locked(false) { }
|
||||
|
||||
~Mutex()
|
||||
~Mutex() throw(int)
|
||||
{
|
||||
if (locked)
|
||||
throw 0;
|
||||
|
@ -32,7 +32,7 @@ namespace __gnu_test
|
||||
|
||||
counter() : _M_count(0), _M_throw(true) { }
|
||||
|
||||
~counter()
|
||||
~counter() throw (counter_error)
|
||||
{
|
||||
if (_M_throw && _M_count != 0)
|
||||
throw counter_error();
|
||||
|
Loading…
Reference in New Issue
Block a user