On 2 May, Martin Sebor wrote: > On 05/01/2017 02:38 AM, Volker Reichelt wrote: >> Hi, >> >> catching exceptions by value is a bad thing, as it may cause slicing, i.e. >> a) a superfluous copy >> b) which is only partial. >> See also >> https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#e15-catch-exceptions-from-a-hierarchy-by-reference >> >> To warn the user about catch handlers of non-reference type, >> the following patch adds a new C++/ObjC++ warning option "-Wcatch-value". > > I think the problems related to catching exceptions by value > apply to (a subset of) class types but not so much to fundamental > types. I would expect indiscriminately warning on every type to > be overly restrictive. > > The Enforcement section of the C++ guideline suggests to > > Flag by-value exceptions if their types are part of a hierarchy > (could require whole-program analysis to be perfect). > > The corresponding CERT C++ Coding Standard guideline offers > a similar suggestion here: > > https://www.securecoding.cert.org/confluence/x/TAD5CQ > > so I would suggest to model the warning on that approach (within > limits of a single translation unit, of course). I.e., warn only > for catching by value objects of non-trivial types, or perhaps even > only polymorphic types? > > Martin
I've never seen anybody throw integers in real-world code, so I didn't want to complicate things for this case. But maybe I should only warn about class-types. IMHO it makes sense to warn about non-polymorphic class types (although slicing is not a problem there), because you still have to deal with redundant copies. Another thing would be pointers. I've never seen pointers in catch handlers (except some 'catch (const char*)' which I would consider bad practice). Therefore I'd like to warn about 'catch (const A*)' which might be a typo that should read 'catch (const A&)' instead. Would that be OK? Regards, Volker >> Bootstrapped and regtested on x86_64-pc-linux-gnu. >> OK for trunk? >> >> Regards, >> Volker >> >> >> 2017-05-01 Volker Reichelt <v.reich...@netcologne.de> >> >> * doc/invoke.texi (-Wcatch-value): Document new warning option. >> >> Index: gcc/doc/invoke.texi >> =================================================================== >> --- gcc/doc/invoke.texi (revision 247416) >> +++ gcc/doc/invoke.texi (working copy) >> @@ -265,7 +265,7 @@ >> -Wno-builtin-declaration-mismatch @gol >> -Wno-builtin-macro-redefined -Wc90-c99-compat -Wc99-c11-compat @gol >> -Wc++-compat -Wc++11-compat -Wc++14-compat -Wcast-align -Wcast-qual >> @gol >> --Wchar-subscripts -Wchkp -Wclobbered -Wcomment @gol >> +-Wchar-subscripts -Wchkp -Wcatch-value -Wclobbered -Wcomment @gol >> -Wconditionally-supported @gol >> -Wconversion -Wcoverage-mismatch -Wno-cpp -Wdangling-else -Wdate-time >> @gol >> -Wdelete-incomplete @gol >> @@ -5827,6 +5827,11 @@ >> literals to @code{char *}. This warning is enabled by default for C++ >> programs. >> >> +@item -Wcatch-value @r{(C++ and Objective-C++ only)} >> +@opindex Wcatch-value >> +@opindex Wno-catch-value >> +Warn about catch handler of non-reference type. >> + >> @item -Wclobbered >> @opindex Wclobbered >> @opindex Wno-clobbered >> =================================================================== >> >> 2017-05-01 Volker Reichelt <v.reich...@netcologne.de> >> >> * c.opt (Wcatch-value): New C++ warning flag. >> >> Index: gcc/c-family/c.opt >> =================================================================== >> --- gcc/c-family/c.opt (revision 247416) >> +++ gcc/c-family/c.opt (working copy) >> @@ -388,6 +388,10 @@ >> C ObjC C++ ObjC++ Var(warn_cast_qual) Warning >> Warn about casts which discard qualifiers. >> >> +Wcatch-value >> +C++ ObjC++ Var(warn_catch_value) Warning >> +Warn about catch handlers of non-reference type. >> + >> Wchar-subscripts >> C ObjC C++ ObjC++ Var(warn_char_subscripts) Warning LangEnabledBy(C ObjC >> C++ ObjC++,Wall) >> Warn about subscripts whose type is \"char\". >> =================================================================== >> >> 2017-05-01 Volker Reichelt <v.reich...@netcologne.de> >> >> * semantics.c (finish_handler_parms): Warn about non-reference type >> catch handlers. >> >> Index: gcc/cp/semantics.c >> =================================================================== >> --- gcc/cp/semantics.c (revision 247416) >> +++ gcc/cp/semantics.c (working copy) >> @@ -1321,7 +1321,15 @@ >> } >> } >> else >> - type = expand_start_catch_block (decl); >> + { >> + type = expand_start_catch_block (decl); >> + if (warn_catch_value >> + && type != NULL_TREE >> + && type != error_mark_node >> + && TREE_CODE (TREE_TYPE (decl)) != REFERENCE_TYPE) >> + warning (OPT_Wcatch_value, >> + "catching non-reference type %qT", TREE_TYPE (decl)); >> + } >> HANDLER_TYPE (handler) = type; >> } >> >> =================================================================== >> >> 2017-05-01 Volker Reichelt <v.reich...@netcologne.de> >> >> * g++.dg/warn/Wcatch-value-1.C: New test. >> >> Index: gcc/testsuite/g++.dg/warn/Wcatch-value-1.C >> =================================================================== >> --- gcc/testsuite/g++.dg/warn/Wcatch-value-1.C 2017-05-01 >> +++ gcc/testsuite/g++.dg/warn/Wcatch-value-1.C 2017-05-01 >> @@ -0,0 +1,45 @@ >> +// { dg-options "-Wcatch-value" } >> + >> +struct A {}; >> +struct B {}; >> +struct C {}; >> + >> +void foo() >> +{ >> + try {} >> + catch (int) {} // { dg-warning "catching non-reference type" } >> + catch (double*) {} // { dg-warning "catching non-reference type" } >> + catch (float&) {} >> + catch (A) {} // { dg-warning "catching non-reference type" } >> + catch (A[2]) {} // { dg-warning "catching non-reference type" } >> + catch (B*) {} // { dg-warning "catching non-reference type" } >> + catch (B&) {} >> + catch (const C&) {} >> +} >> + >> +template<typename T> void foo1() >> +{ >> + try {} >> + catch (T) {} >> +} >> + >> +void bar1() >> +{ >> + foo1<int&>(); >> + foo1<const A&>(); >> +} >> + >> +template<typename T> void foo2() >> +{ >> + try {} >> + catch (T) {} // { dg-warning "catching non-reference type" } >> + >> + try {} >> + catch (T&) {} >> +} >> + >> +void bar2() >> +{ >> + foo2<int*>(); // { dg-message "required" } >> + foo2<A>(); // { dg-message "required" } >> +} >> =================================================================== >> >