From 59f9c2ed530507a5dcaaf4c6d3789b908dc3dfa6 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 16 Jun 2010 11:45:36 -0400 Subject: [PATCH] c.opt: Add -Wnoexcept. * c.opt: Add -Wnoexcept. * except.c (check_noexcept_r): Return the problematic function. (finish_noexcept_expr): Give -Wnoexcept warning. Add complain parm. * pt.c (tsubst_copy_and_build): Pass it. * parser.c (cp_parser_unary_expression): Likewise. * cp-tree.h: Adjust prototype. From-SVN: r160842 --- gcc/c-family/ChangeLog | 4 +++ gcc/c-family/c.opt | 4 +++ gcc/cp/ChangeLog | 6 ++++ gcc/cp/cp-tree.h | 2 +- gcc/cp/except.c | 39 +++++++++++++++++-------- gcc/cp/parser.c | 2 +- gcc/cp/pt.c | 2 +- gcc/doc/invoke.texi | 10 ++++++- gcc/testsuite/ChangeLog | 2 ++ gcc/testsuite/g++.dg/cpp0x/noexcept03.C | 6 ++-- 10 files changed, 58 insertions(+), 19 deletions(-) diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 433d699faab..8c7eed1886c 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,7 @@ +2010-06-16 Jason Merrill + + * c.opt: Add -Wnoexcept. + 2010-06-16 Richard Guenther PR c/44555 diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 5122e1a80ef..0517d3506a2 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -341,6 +341,10 @@ Wnested-externs C ObjC Var(warn_nested_externs) Warning Warn about \"extern\" declarations not at file scope +Wnoexcept +C++ ObjC++ Var(warn_noexcept) Warning +Warn when a noexcept expression evaluates to true even though the expression can't actually throw + Wnon-template-friend C++ ObjC++ Var(warn_nontemplate_friend) Init(1) Warning Warn when non-templatized friend functions are declared within a template diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 37a35447dcb..8402afd176e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2010-06-16 Jason Merrill + * except.c (check_noexcept_r): Return the problematic function. + (finish_noexcept_expr): Give -Wnoexcept warning. Add complain parm. + * pt.c (tsubst_copy_and_build): Pass it. + * parser.c (cp_parser_unary_expression): Likewise. + * cp-tree.h: Adjust prototype. + * method.c (defaulted_late_check): Give the defaulted method the same exception specification as the implicit declaration. diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index b71f8af0a0c..f63ec2e795c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4845,7 +4845,7 @@ extern tree build_exc_ptr (void); extern tree build_throw (tree); extern int nothrow_libfn_p (const_tree); extern void check_handlers (tree); -extern tree finish_noexcept_expr (tree); +extern tree finish_noexcept_expr (tree, tsubst_flags_t); extern bool nothrow_spec_p (const_tree); extern bool type_noexcept_p (const_tree); extern bool type_throw_all_p (const_tree); diff --git a/gcc/cp/except.c b/gcc/cp/except.c index c682c8d8cfe..64f417154ce 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -1028,20 +1028,22 @@ check_noexcept_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, We could use TREE_NOTHROW (t) for !TREE_PUBLIC fns, though... */ tree fn = (code == AGGR_INIT_EXPR ? AGGR_INIT_EXPR_FN (t) : CALL_EXPR_FN (t)); + tree type = TREE_TYPE (TREE_TYPE (fn)); + + STRIP_NOPS (fn); if (TREE_CODE (fn) == ADDR_EXPR) { /* We do use TREE_NOTHROW for ABI internals like __dynamic_cast, and for C library functions known not to throw. */ - tree fn2 = TREE_OPERAND (fn, 0); - if (TREE_CODE (fn2) == FUNCTION_DECL - && DECL_EXTERN_C_P (fn2) - && (DECL_ARTIFICIAL (fn2) - || nothrow_libfn_p (fn2))) - return TREE_NOTHROW (fn2) ? NULL_TREE : t; + fn = TREE_OPERAND (fn, 0); + if (TREE_CODE (fn) == FUNCTION_DECL + && DECL_EXTERN_C_P (fn) + && (DECL_ARTIFICIAL (fn) + || nothrow_libfn_p (fn))) + return TREE_NOTHROW (fn) ? NULL_TREE : fn; } - fn = TREE_TYPE (TREE_TYPE (fn)); - if (!TYPE_NOTHROW_P (fn)) - return t; + if (!TYPE_NOTHROW_P (type)) + return fn; } return NULL_TREE; @@ -1050,13 +1052,26 @@ check_noexcept_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, /* Evaluate noexcept ( EXPR ). */ tree -finish_noexcept_expr (tree expr) +finish_noexcept_expr (tree expr, tsubst_flags_t complain) { + tree fn; + if (processing_template_decl) return build_min (NOEXCEPT_EXPR, boolean_type_node, expr); - if (cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0)) - return boolean_false_node; + fn = cp_walk_tree_without_duplicates (&expr, check_noexcept_r, 0); + if (fn) + { + if ((complain & tf_warning) && TREE_CODE (fn) == FUNCTION_DECL + && TREE_NOTHROW (fn) && !DECL_ARTIFICIAL (fn)) + { + warning (OPT_Wnoexcept, "noexcept-expression evaluates to % " + "because of a call to %qD", fn); + warning (OPT_Wnoexcept, "but %q+D does not throw; perhaps " + "it should be declared %", fn); + } + return boolean_false_node; + } else return boolean_true_node; } diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0a7006a7d1b..c6f8d7ee769 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -5883,7 +5883,7 @@ cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p, parser->type_definition_forbidden_message = saved_message; cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN); - return finish_noexcept_expr (expr); + return finish_noexcept_expr (expr, tf_warning_or_error); } default: diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 55ea5397d8a..b97d3f5cc09 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -12259,7 +12259,7 @@ tsubst_copy_and_build (tree t, /*integral_constant_expression_p=*/false); --cp_unevaluated_operand; --c_inhibit_evaluation_warnings; - return finish_noexcept_expr (op1); + return finish_noexcept_expr (op1, complain); case MODOP_EXPR: { diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 9e517e9c678..34acfbc526a 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -196,7 +196,7 @@ in the following sections. -fno-default-inline -fvisibility-inlines-hidden @gol -fvisibility-ms-compat @gol -Wabi -Wconversion-null -Wctor-dtor-privacy @gol --Wnon-virtual-dtor -Wreorder @gol +-Wnoexcept -Wnon-virtual-dtor -Wreorder @gol -Weffc++ -Wstrict-null-sentinel @gol -Wno-non-template-friend -Wold-style-cast @gol -Woverloaded-virtual -Wno-pmf-conversions @gol @@ -2282,6 +2282,14 @@ Warn when a class seems unusable because all the constructors or destructors in that class are private, and it has neither friends nor public static member functions. +@item -Wnoexcept @r{(C++ and Objective-C++ only)} +@opindex Wnoexcept +@opindex Wno-noexcept +Warn when a noexcept-expression evaluates to false because of a call +to a function that does not have a non-throwing exception +specification (i.e. @samp{throw()} or @samp{noexcept}) but is known by +the compiler to never throw an exception. + @item -Wnon-virtual-dtor @r{(C++ and Objective-C++ only)} @opindex Wnon-virtual-dtor @opindex Wno-non-virtual-dtor diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index b06e3811ec3..d9ddc0b444d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,7 @@ 2010-06-16 Jason Merrill + * g++.dg/cpp0x/noexcept03.C: Test -Wnoexcept. + * g++.dg/cpp0x/noexcept01.C: Test defaulted fns. 2010-06-16 Richard Guenther diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept03.C b/gcc/testsuite/g++.dg/cpp0x/noexcept03.C index d9922454425..c759f6fb21d 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept03.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept03.C @@ -1,5 +1,5 @@ // Runtime test for noexcept-specification. -// { dg-options "-std=c++0x" } +// { dg-options "-std=c++0x -Wnoexcept" } // { dg-do run } #include @@ -23,7 +23,7 @@ void f () noexcept (false) } template -void f(T) noexcept (noexcept (T())) +void f(T) noexcept (noexcept (T())) // { dg-warning "false" } { p(); } @@ -34,7 +34,7 @@ void f2(T a) noexcept (noexcept (f (a))) f(a); } -struct A { A() { } }; +struct A { A() { } }; // { dg-warning "does not throw" } // throw(int) overrides noexcept(false) in either order. void h() throw (int, std::bad_exception);