Consider this example: -- struct Base {}; struct X; // X derived from Base later but incomplete here struct Y {}; // Y not derived from Base int test1(int Base::* p2m, X* object) { return object->*p2m; // fails because X is incomplete } struct X : Base { }; int test2(int Base::* p2m, X* object) { return object->*p2m; // OK } int test3(int Base::* p2m, Y* object) { return object->*p2m; // fails because Y is not derived from A } -- produces the following errors: In function 'int test1(int Base::*, X*)': error: pointer to member type 'int' incompatible with object type 'X' In function 'int test3(int Base::*, Y*)': error: pointer to member type 'int' incompatible with object type 'Y' The error messages could be made more useful to the user by a) including the class type of the pointer to member type or the full p2m type (this might be a bug, depending on whether the programmer's intention was to actually print that instead of the rather uninteresting pointed-to type) b) adding to the message for test1 something that points out that X was incomplete when evaluated. The code in cp/typeck2.c build_m_component_ref() uses a shortcut here to print the identical message for two errors that have very different implications from the user's perspective.
in the example the last comment should read // fails because Y is not derived from Base instead of // fails because Y is not derived from A
Created attachment 16977 [details] Broader test case for incomplete base and object types test1 shows the case where the base type is incomplete test2 shows the case where the object type is incomplete test3 shows the case where the object type is incompatible (to which the original error message is taylored)
Created attachment 16978 [details] proposed patch to gcc/cp/typeck2.c - changes type in error message from type to ptrmem_type as was probably intended originally - adds distinct messages for the two cases where incomplete types were evaluated
I agree the diagnostic could be much better but I'm not fully convinced by your proposal. Clang++ says: pr38612.cc:7:16: error: left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'X' return object->*p2m;// fails because X is incomplete ^ pr38612.cc:2:8: note: forward declaration of 'X' struct X;// X derived from Base later but incomplete here ^ pr38612.cc:21:16: error: left hand operand to ->* must be a pointer to class compatible with the right hand operand, but is 'Y *' return object->*p2m;// fails because Y is not derived from A ^ which to me is only slightly better. I think I would like to get: pr38612.cc:7:16: error: right hand operand 'Base::*' to '->*' is not compatible with left-hand operand 'X *' because 'X' is not a complete type return object->*p2m;// fails because X is incomplete ^ pr38612.cc:2:8: note: forward declaration of 'X' struct X;// X derived from Base later but incomplete here ^ pr38612.cc:21:16: error: right hand operand 'Base::*' to '->*' is not compatible with left-hand operand 'Y *' because 'Y' is not derived from 'Base' return object->*p2m;// fails because Y is not derived from A ^ pr38612.cc:3:8: note: 'Y' declared here struct Y {};// Y not derived from Base ^ What do you think? Jason?
(In reply to Manuel López-Ibáñez from comment #4) Those sound good to me.
(In reply to Manuel López-Ibáñez from comment #4) > > What do you think? > Looks great. My main beef was that the two errors were merged into one diagnostic.