On Sun, Nov 8, 2015 at 10:30 PM, Patrick Palka <patr...@parcs.ath.cx> wrote: > When either the static type or the target type of a dynamic cast is > marked 'final', and the type marked final is not derived from the other, > then there is no way to declare a class that is derived from both types > (since one of the types is marked final) so there is no way for such a > dynamic cast to possibly succeed. > > This patch detects this case and emits a warning accordingly. > > Bootstrap + regtest in progress. Is this OK to commit if testing > succeeds? > > gcc/cp/ChangeLog: > > PR c++/12277 > * rtti.c (build_dynamic_cast_1): Warn on dynamic_cast that can > never succeed due to either the target type or the static type > being marked final. > > gcc/testsuite/ChangeLog: > > PR c++/12277 > * g++.dg/rtti/dyncast8.C: New test. > --- > gcc/cp/rtti.c | 18 ++++++++++++++ > gcc/testsuite/g++.dg/rtti/dyncast8.C | 47 > ++++++++++++++++++++++++++++++++++++ > 2 files changed, 65 insertions(+) > create mode 100644 gcc/testsuite/g++.dg/rtti/dyncast8.C > > diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c > index be25be4..b823f8b 100644 > --- a/gcc/cp/rtti.c > +++ b/gcc/cp/rtti.c > @@ -698,6 +698,24 @@ build_dynamic_cast_1 (tree type, tree expr, > tsubst_flags_t complain) > > target_type = TYPE_MAIN_VARIANT (TREE_TYPE (type)); > static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype)); > + > + if ((CLASSTYPE_FINAL (static_type) > + && !DERIVED_FROM_P (target_type, static_type)) > + || (CLASSTYPE_FINAL (target_type) > + && !DERIVED_FROM_P (static_type, target_type))) > + { > + if (complain & tf_warning) > + { > + if (VAR_P (old_expr)) > + warning (0, "dynamic_cast of %q#D to %q#T can never > succeed", > + old_expr, type); > + else > + warning (0, "dynamic_cast of %q#E to %q#T can never > succeed", > + old_expr, type); > + } > + return build_zero_cst (type); > + } > + > td2 = get_tinfo_decl (target_type); > if (!mark_used (td2, complain) && !(complain & tf_error)) > return error_mark_node; > diff --git a/gcc/testsuite/g++.dg/rtti/dyncast8.C > b/gcc/testsuite/g++.dg/rtti/dyncast8.C > new file mode 100644 > index 0000000..d98878c > --- /dev/null > +++ b/gcc/testsuite/g++.dg/rtti/dyncast8.C > @@ -0,0 +1,47 @@ > +// PR c++/12277 > +// { dg-do require { target c++11 } } > + > +struct A1 { virtual ~A1 () { } }; > +struct A2 { virtual ~A2 () { } }; > + > +struct B1 { virtual ~B1 () { } }; > +struct B2 final : B1 { virtual ~B2 () { } }; > + > +struct C1 { virtual ~C1 () { } }; > +struct C2 final { virtual ~C2 () { } }; > + > +A1 *a1; > + > +B1 *b1; > +B2 *b2; > + > +C1 *c1; > +C2 *c2; > + > +void > +foo (void) > +{ > + { > + A2 *x = dynamic_cast<A2 *> (a1); // { dg-bogus "can never succeed" } > + } > + > + { > + B2 *x = dynamic_cast<B2 *> (b1); // { dg-bogus "can never suceed" } > + B2 &y = dynamic_cast<B2 &> (*b1); // { dg-bogus "can never suceed" } > + } > + > + { > + B1 *x = dynamic_cast<B1 *> (b2); // { dg-bogus "can never suceed" } > + B1 &y = dynamic_cast<B1 &> (*b2); // { dg-bogus "can never suceed" } > + } > + > + { > + C2 *x = dynamic_cast<C2 *> (c1); // { dg-warning "can never succeed" } > + C2 &y = dynamic_cast<C2 &> (*c1); // { dg-warning "can never suceed" } > + } > + > + { > + C1 *x = dynamic_cast<C1 *> (c2); // { dg-warning "can never succeed" } > + C1 &y = dynamic_cast<C1 &> (*c2); // { dg-warning "can never suceed" } > + } > +} > -- > 2.6.3.412.gac8e876.dirty >
Oops, this is the wrong test case (forgot to amend the patch before sending). The correct test case has s/require/compile/ and s/suceed/succeed/g done on it.