The cast of a non-virtual member function pointer to a derived class is not working at compile time. Release: 3.0.4 Environment: Debian GNU / Linux
Fix: ?
State-Changed-From-To: open->analyzed State-Changed-Why: Confirmed: ------------------------- struct A { void foo(); }; struct B : A {}; typedef void (B::*B_ptr) (); template <class T, void (T::* U)()> struct CT {}; CT<B, (B_ptr) &A::foo> c; -------------------------- g/x> /home/bangerth/bin/gcc-3.4-pre/bin/c++ -c x.cc x.cc:8: error: `{A::foo(), 0}' is not a valid template argument x.cc:8: error: it must be a pointer-to-member of the form `&X::Y' x.cc:8: error: expected constructor, destructor, or type conversion This never compiled from 2.95 to present mainline. W.
2.91.66 accepted this so this is a regression.
This code is invalid; the cast may not appear as part of a template argument. Clearly, the error message (with the brace notation) is sub-optimal. I've removed the target milestone because I don't know if the error message has regressed; the audit trail says that most versions of G++ have correctly rejected this code.
Since this is invalid code, it's no longer a regression. Also, the error message is not a regression. 2.95 gives g/x> c++ -c x.cc x.cc:7: `(&A::foo)' is not a valid template argument x.cc:7: it must be a pointer-to-member of the form `&X::Y' x.cc:7: ANSI C++ forbids declaration `c' with no type That's about as bad as what we now get. The message is clearly suboptimal nevertheless, so let's keep this PR open. W.
this is semi-fixed on the mainline (get rid of the "()" and it would be considered fixed, unless someone says otherwise. ) pr1011.cc:7: error: `A::foo()' cannot appear in a constant-expression pr1011.cc:7: error: a casts to a type other than an integral or enumeration type cannot appear in a constant-expression pr1011.cc:7: error: template argument 2 is invalid pr1011.cc:7: error: expected constructor, destructor, or type conversion
I see two open issues here: first, the error message has wrong grammar ("a cast_s_"). The second thing is that what is being attempted here doesn't seem to be possible: neither of these work: CT<B, &A::foo> c1; CT<B, &B::foo> c2; CT<B, (B_ptr)&B::foo> c3; The second one is particularly confusing, since &B::foo immediately decays to A::*, but this has recently been discussed in another PR and seems to be standards conforming. The last one should cast this back, but this isn't allowed. The first one should of course be wrong. So we are left with a situation where something just can't be done. Someone should file a DR for this, this is clearly a less than satisfactory situation... W.
Slightly error message change: pr10118.cc:8: error: `A::foo()' cannot appear in a constant-expression pr10118.cc:8: error: `&' cannot appear in a constant-expression pr10118.cc:8: error: a cast to a type other than an integral or enumeration type cannot appear in a constant-expression pr10118.cc:8: error: template argument 2 is invalid pr10118.cc:8: error: invalid type in declaration before ';' token
Subject: Re: Bad diagnostic with cast in template argument expression "pinskia at gcc dot gnu dot org" <gcc-bugzilla@gcc.gnu.org> writes: | Slightly error message change: | pr10118.cc:8: error: `A::foo()' cannot appear in a constant-expression This is wrong and I know why. The code cp/error.c is too contrived to fix it properly. It is better to rely on the code in cp/cxx-pretty-print.c to fix it. | pr10118.cc:8: error: `&' cannot appear in a constant-expression This does nto make any sense. -- Gaby
For the test case in comment #2 GCC 7.0 print the following errors. The English text of the errors looks fine but the types are still pretty wacky: $ cat t.C && /ssd/build/gcc-git-svn/gcc/xgcc -B /ssd/build/gcc-git-svn/gcc -S -Wall -Wextra t.C struct A { void foo(); }; struct B : A {}; typedef void (B::*B_ptr) (); template <class T, void (T::* U)()> struct CT {}; CT<B, (B_ptr) &A::foo> c; t.C:7:26: error: ‘void (B::*)(){((void (B::*)())A::foo), (0 + 0)}’ is not a valid template argument for type ‘void (B::*)()’ CT<B, (B_ptr) &A::foo> c; ^ t.C:7:26: error: it must be a pointer-to-member of the form ‘&X::Y’ t.C:7:26: error: could not convert template argument ‘void (B::*)(){((void (B::*)())A::foo), (0 + 0)}’ from ‘void (B::*)()’ to ‘void (B::*)()’ Clang 5.0 prints a much clearer error message: t.C:7:11: error: non-type template argument is not a pointer to member constant CT<B, (B_ptr) &A::foo> c; ^~~~~~~~~~~~~~~
We get now: <source>:7:26: error: 'void (B::*)(){((void (B::*)())A::foo), 0}' is not a valid template argument for type 'void (B::*)()' 7 | CT<B, (B_ptr) &A::foo> c; | ^ <source>:7:26: note: it must be a pointer-to-member of the form '&X::Y' ASM generation compiler returned: 1 <source>:7:26: error: 'void (B::*)(){((void (B::*)())A::foo), 0}' is not a valid template argument for type 'void (B::*)()' 7 | CT<B, (B_ptr) &A::foo> c; | ^ <source>:7:26: note: it must be a pointer-to-member of the form '&X::Y' Execution build compiler returned: 1 While clang produces: <source>:7:11: error: non-type template argument is not a pointer to member constant CT<B, (B_ptr) &A::foo> c; ^~~~~~~~~~~~~~~ 1 error generated. ASM generation compiler returned: 1 <source>:7:11: error: non-type template argument is not a pointer to member constant CT<B, (B_ptr) &A::foo> c; ^~~~~~~~~~~~~~~ Both are not obvious but gcc is still worse as it has the "{((void (B::*)())A::foo), 0}" part there still.