From patchwork Wed Jun 16 15:47:42 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 55899 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id D7C86B7D85 for ; Thu, 17 Jun 2010 01:48:08 +1000 (EST) Received: (qmail 10906 invoked by alias); 16 Jun 2010 15:48:03 -0000 Received: (qmail 10851 invoked by uid 22791); 16 Jun 2010 15:47:59 -0000 X-SWARE-Spam-Status: No, hits=-5.8 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, SPF_HELO_PASS, TW_BF, TW_PM, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 16 Jun 2010 15:47:45 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o5GFlhX4009765 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 16 Jun 2010 11:47:44 -0400 Received: from [IPv6:::1] (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o5GFlgoD032367 for ; Wed, 16 Jun 2010 11:47:43 -0400 Message-ID: <4C18F21E.9090207@redhat.com> Date: Wed, 16 Jun 2010 11:47:42 -0400 From: Jason Merrill User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.10) Gecko/20100610 Lightning/1.0b1 Shredder/3.0.6pre MIME-Version: 1.0 To: gcc-patches List Subject: C++0x PATCH to add -Wnoexcept, fix defaulted fn exception specs Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Two noexcept related changes: 1) We were failing to give in-class defaulted methods the same exception specification as an implicit declaration, as specified in the FCD. 2) I've added a -Wnoexcept flag to help identify places where adding a noexcept specifier would be helpful. Tested x86_64-pc-linux-gnu, applied to trunk. commit d5a95e55cff9bc03308ec27f05988146d9aadb43 Author: Jason Merrill Date: Tue Jun 15 21:42:03 2010 -0400 * method.c (defaulted_late_check): Give the defaulted method the same exception specification as the implicit declaration. diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 97f3566..0400277 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1022,6 +1022,15 @@ defaulted_late_check (tree fn) error_at (DECL_SOURCE_LOCATION (fn), "does not match expected signature %qD", implicit_fn); } + + /* 8.4.2/2: If it is explicitly defaulted on its first declaration, it is + implicitly considered to have the same exception-specification as if + it had been implicitly declared. */ + if (DECL_DEFAULTED_IN_CLASS_P (fn)) + { + tree eh_spec = TYPE_RAISES_EXCEPTIONS (TREE_TYPE (implicit_fn)); + TREE_TYPE (fn) = build_exception_variant (TREE_TYPE (fn), eh_spec); + } } /* Returns true iff FN can be explicitly defaulted, and gives any diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept01.C b/gcc/testsuite/g++.dg/cpp0x/noexcept01.C index e3341d8..f314684 100644 --- a/gcc/testsuite/g++.dg/cpp0x/noexcept01.C +++ b/gcc/testsuite/g++.dg/cpp0x/noexcept01.C @@ -59,6 +59,14 @@ struct F SA (noexcept (F())); +struct G +{ + G() = default; + ~G() = default; +}; + +SA (noexcept (G())); + template void tf() { commit 6ccf227626b3ac9a09f5061daf2cece776c0be7c Author: Jason Merrill Date: Wed Jun 16 11:30:02 2010 -0400 * 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. diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 5122e1a..0517d35 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/cp-tree.h b/gcc/cp/cp-tree.h index b71f8af..f63ec2e 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 c682c8d..64f4171 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 0a7006a..c6f8d7e 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 55ea539..b97d3f5 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 9e517e9..34acfbc 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/g++.dg/cpp0x/noexcept03.C b/gcc/testsuite/g++.dg/cpp0x/noexcept03.C index d992245..c759f6f 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);