Bug 65188 - improve error for member operator applied to non-class type
Summary: improve error for member operator applied to non-class type
Status: RESOLVED WORKSFORME
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 5.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: diagnostic
Depends on:
Blocks:
 
Reported: 2015-02-24 10:24 UTC by Jan Kratochvil
Modified: 2017-09-09 20:50 UTC (History)
1 user (show)

See Also:
Host:
Target: x86_64-linux-gnu
Build:
Known to work:
Known to fail:
Last reconfirmed: 2015-02-24 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Kratochvil 2015-02-24 10:24:16 UTC
class C { public: void f() {} } c;
int main() { return c.f.a; }

-Wall

g++ (GCC) 5.0.0 20150224 (experimental)
-------------------------------------------------------------------------------
10.C: In function ‘int main()’:
10.C:2:21: error: ‘c.C::f’ does not have class type
 int main() { return c.f.a; }
                     ^
-------------------------------------------------------------------------------

clang-3.5.0-6.fc21.x86_64
-------------------------------------------------------------------------------
10.C:2:23: error: reference to non-static member function must be called; did you mean to call it with no arguments?
int main() { return c.f.a; }
                    ~~^
                       ()
10.C:2:24: error: member reference base type 'void' is not a structure or union
int main() { return c.f.a; }
                    ~~~^~
2 errors generated.
-------------------------------------------------------------------------------

I had no idea what GCC errors on until I asked clang.  It may be obvious here but with complicated classes the better error message is really helpful.
Comment 1 Manuel López-Ibáñez 2015-02-24 14:27:26 UTC
How does Clang message help in this case? The suggested fix 'c.f().a' will just give 'invalid use of void type'

Of course, g++ could be better, as this testcase shows:

class C {
public:
  void g() {};
  C& f() {};
  int a;
} c;
void g2();
C&f2();
int foo(char **p, char **q) { return (p-q).a; }
int bar() { return c.f.a; }
int baz() { return c.g.a; }
int bar2() { return f2.a; }
int baz2() { return g2.a; }

g++:

test.cc:10:44: error: request for member ‘a’ in ‘((((long int)p) - ((long int)q)) (ceiling /) 8l)’, which is of non-class type ‘long int’
 int foo(char **p, char **q) { return (p-q).a; }
                                            ^
test.cc: In function ‘int bar()’:
test.cc:11:20: error: ‘c.C::f’ does not have class type
 int bar() { return c.f.a; }
                    ^
test.cc: In function ‘int baz()’:
test.cc:12:20: error: ‘c.C::g’ does not have class type
 int baz() { return c.g.a; }
                    ^
test.cc: In function ‘int bar2()’:
test.cc:13:24: error: request for member ‘a’ in ‘f2’, which is of non-class type ‘C&()’
 int bar2() { return f2.a; }
                        ^
test.cc: In function ‘int baz2()’:
test.cc:14:24: error: request for member ‘a’ in ‘g2’, which is of non-class type ‘void()’
 int baz2() { return g2.a; }
                        ^
Possible improvements:

1) Consistency: all these errors should print the same message.

2) Location: the location should point to the expression that is not of class type.

3) No pretty-printing of arbitrary expressions: If the expression is a name or a declaration, print it; otherwise, print "request for member 'a' in expression of non-class type 'long int'"

4) For types that have declarations, we could point to the declaration with a note: 'c.C::f' declared here


For your testcase, it could be:

10.C:2:23: error: request for member in ‘c.C::f’, which is of non-class type 'void (C::)()'
 int main() { return c.f.a; }
                       ^
10.C:1:19: note: declared here
 class C { public: void f() {} } c;
                        ^
Comment 2 Jan Kratochvil 2015-02-24 14:33:04 UTC
(In reply to Manuel López-Ibáñez from comment #1)
> How does Clang message help in this case? The suggested fix 'c.f().a' will
> just give 'invalid use of void type'

I have minimized the testcase maybe more than appropriate, it was in fact:

class D { public: int a; } d;
class C { public: D &f() { return d; } } c;
int main() { return c.f.a; }

g++ (GCC) 5.0.0 20150224 (experimental)
-------------------------------------------------------------------------------
10.C: In function ‘int main()’:
10.C:3:21: error: ‘c.C::f’ does not have class type
 int main() { return c.f.a; }
                     ^
-------------------------------------------------------------------------------

clang-3.5.0-6.fc21.x86_64
-------------------------------------------------------------------------------
10.C:3:23: error: reference to non-static member function must be called; did you mean to call it with no arguments?
int main() { return c.f.a; }
                    ~~^
                       ()
1 error generated.
-------------------------------------------------------------------------------


> 4) For types that have declarations, we could point to the declaration with
> a note: 'c.C::f' declared here

Yes, that would be very useful.
Comment 3 Jan Kratochvil 2017-09-09 20:50:26 UTC
gcc-7.1.1-3.fc26.x86_64
1.C:2:23: error: invalid use of member function ‘void C::f()’ (did you forget the ‘()’ ?)

It looks as fixed now.