+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,
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
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.
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
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)
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 ();
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
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
struct Bar
{
- ~Bar ();
+ ~Bar () throw(int);
Foo f;
};
was_f_in_Bar_destroyed=true;
}
-Bar::~Bar()
+Bar::~Bar() throw(int)
{
throw 1;
}
// 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>
// PR c++/50043
// { dg-do compile { target c++11 } }
+// { dg-options "-Wno-terminate" }
struct True1 {};
struct True2 { ~True2(); };
struct A {
A(int) { }
- ~A() { throw 1; };
+ ~A() throw(int) { throw 1; };
};
struct B {
B(A) { }
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;
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;
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; }
// { 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;
struct Mutex
{
bool locked;
- ~Mutex ()
+ ~Mutex () throw(int)
{
if (locked)
throw 0;
--- /dev/null
+// 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 (...) {}
+}
+
+
struct A {
A() { }
- ~A() {
+ ~A() throw(int) {
std::set_terminate (my_terminate);
throw 1; // This throws from EH dtor, should call my_terminate
}
{
Mutex() : locked(false) { }
- ~Mutex()
+ ~Mutex() throw(int)
{
if (locked)
throw 0;
counter() : _M_count(0), _M_throw(true) { }
- ~counter()
+ ~counter() throw (counter_error)
{
if (_M_throw && _M_count != 0)
throw counter_error();