4

While playing with pointers-to-member I encountered a behaviour that seems slightly inconsistent and somewhat counterintuitive to me. Consider the following dummy structure:

struct foo {
    int x;
    double d;
};

and the following main():

int main() {
    int foo::* ptr = &foo::x;
    double foo::* ptr2 = &foo::d;
}

Here we have nothing unusual - two pointers to const members. The code compiles fine.

What caught my attention is that when we add const, the situation changes a little bit. Consider the following code:

int main() {
    // no int or double after const
    const foo::* ptr = &foo::x;
}

The code compiles fine on GCC 8.2.01. Notice that I did not specify to what data type the pointer will point.

However, this code:

int main() {
    // notice the only change - "d" instead of "x"
    const foo::* ptr = &foo::d;
}

fails to compile with the following error:

error: cannot convert 'double foo::*' to 'const int foo::*' in initialization const foo::* ptr = &foo::d;

Which is interesting - it suggests that, by default, a const pointer-to-member is implicitely declared to point to some int member. Is this correct, standard behaviour?

It's worth noting that if we drop the const, both of these lines produce errors:

int main() {
    foo::* ptr1 = &foo::x;
    foo::* ptr2 = &foo::d;
}

in the forms of:

error: expected unqualified-id before '*' token

error: 'ptr1' | 'ptr2' was not declared in this scope

So the question is - does the standard specify that const pointer-to-member implicitly points to int if we do not specify otherwise, or is it a non-standard behaviour? (either a GCC extension or GCC bug).


1EDIT: I am using GCC from MinGW - this particular build.

Community
  • 1
  • 1
Fureeish
  • 12,533
  • 4
  • 32
  • 62
  • "*The code compiles fine on GCC 8.2.0*" Eh, no it doesn't. – Nikos C. Jun 10 '19 at 00:28
  • 4
    Are you compiling with `-fpermissive`? I'd highly recommend not doing that. – chris Jun 10 '19 at 00:28
  • Usually when no type is given, int is assumed. I'm going to guess that's why it works, or rather slides by, for int, but not double. –  Jun 10 '19 at 00:32
  • @Chipster How often is "usually"? – curiousguy Jun 10 '19 at 00:35
  • @NikosC. it actually [compiles](https://godbolt.org/z/OjyDnZ) with -fpermissive and [does not compile](https://godbolt.org/z/6-QTbo) without it. – Fureeish Jun 10 '19 at 00:36
  • For the record: `const double foo::* ptr = &foo::d;` should compile just fine. –  Jun 10 '19 at 00:36
  • 1
    @Chipster did I suggest otherwise? Did not intend to. – Fureeish Jun 10 '19 at 00:37
  • @curiousguy "usually" means in Visual Studio. It gives a warning when I do things like that saying something to the effect of "int assumed". I'm guessing that's what's going on here, although I don't have an authoritative source to back me up (even though I've looked for one). –  Jun 10 '19 at 00:38
  • @Fureeish No. I'm just saying if you wanted the code to work as a constant, that should work as intended. –  Jun 10 '19 at 00:40
  • 1
    @Chipster ah yes, I am aware, but thank you. – Fureeish Jun 10 '19 at 00:41

2 Answers2

2

The code is incorrect in ISO C++, but the "implicit int" behaviour is enabled by -fms-extensions which gcc enables automatically for targeting Microsoft ABI.

You can turn it off with -fno-ms-extensions.


I checked the source code (gcc-9.1.0/gcc/cp/decl.c), it turns out that in ms-extensions mode the warning for implicit int is disabled -- anything that would have generated the message ISO C++ forbids declaration of %qs with no type is actually admitted, with int being used for the type.

This is probably a bigger hammer than was necessary to solve whatever problem it was trying to solve. You can also see the discrepancy with const *x; or const f(); for example.

I tried adding -fno-ms-extensions to the build for some of my "large" Windows projects that I use mingw-w64 for and got no errors, so perhaps it'd be good practice to give this flag as a matter of habit (or even submit a patch to mingw-w64 to have it off by default...).

M.M
  • 138,810
  • 21
  • 208
  • 365
  • I'll post a followup to my Cygwin bug report. I'm disappointed that, on systems where `-fms-extensions` is enabled by default, `g++ -std=c++11 -pedantic` fails to produce required diagnostics. I might submit a bug to gcc. – Keith Thompson Jun 11 '19 at 07:35
  • Interestingly, `gcc -fms-extensions` warns about implicit `int` in C. Do you happen to know how the option was turned on by default for MinGW and other Windows builds? Is it a configuration option, or did they modify the gcc source? (I'm trying to decide whether this is a gcc bug.) – Keith Thompson Jun 11 '19 at 07:51
  • @KeithThompson you can check the source code by finding mingw-w64 project on github. AFAIK they don't modify the gcc source at all but they obviously do turn this option on somewhere. I don't see that a bug report to gcc is warranted as this seems to be intended behaviour , but it might be nice to have finer grained control over the things that `ms-extensions` does (e.g. if they allowed `-Wimplicit-int` to overrule `-fms-extensions`. One would want to be familiar with the use cases before recommending a change; which I am not. Maybe there is some popular code bases that require this flag. – M.M Jun 11 '19 at 09:40
  • They already have a filter to not warn about this if it's identified as a System Header , maybe that doesn't correctly identify windows headers? who knows. – M.M Jun 11 '19 at 09:42
  • @KeithThompson On further checking, it turns out the flag control is in the GCC source; it enables it if the Target ABI is a Microsoft one. – M.M Jun 12 '19 at 03:48
1

So the question is - does the standard specify that const pointer-to-member implicitly points to int if we do not specify otherwise

No. GCC normally will give you the answer in plain English and refuse to compile (or emit a warning if you are using -fpermissive):

error: ISO C++ forbids declaration of 'ptr' with no type

It is not an extension. It's allowed in -fpermissive mode in order to keep very old legacy code compilable.

It seems that GCC as shipped by MinGW-w64 does not catch this error though. I don't know if it's intentional or not.

Nikos C.
  • 50,738
  • 9
  • 71
  • 96
  • 1
    The thing is that I compiled **without** `-fpermissive`. It does fail on godbolt, but on my build (I am using MinGW from [here] - STL's build), it still compiles fine, even with no compiler flags. Do you then think it's a bug with MinGW? – Fureeish Jun 10 '19 at 00:40
  • 3
    @Fureeish, You should definitely include that in the question. I can reproduce that on my MinGW's GCC 8.1. – chris Jun 10 '19 at 00:47
  • @Fureeish It also happens on a mingw GCC (8.3.0) cross-compiler that I built myself on Linux. Seems to be a general mingw issue (or more correctly, mingw-w64.) – Nikos C. Jun 10 '19 at 00:57
  • @Fureeish In comments under the question you said " it actually compiles with `-fpermissive` and does not compile without it." , but now you say it compiles without -fpermissive; which is it? – M.M Jun 10 '19 at 01:37
  • I see the same problem with both `g++` and `x86_64-w64-mingw32-g++` (both version 7.4.0) on Cygwin. I don't see it with multiple versions of `g++` on Linux. Very odd. – Keith Thompson Jun 10 '19 at 02:19
  • The `-fpermissive` option doesn't disable the diagnostic; it turns it from a fatal error to a warning. (At least that's what it's supposed to do.) I've submitted a bug report to the Cygwin mailing list. https://cygwin.com/ml/cygwin/2019-06/msg00113.html – Keith Thompson Jun 10 '19 at 04:39
  • @KeithThompson I'm not using cygwin. I use mingw-w64 under Linux (as a cross compiler) and it has the exact same issue. So it seems completely unrelated to cygwin. – Nikos C. Jun 10 '19 at 05:03
  • @NikosC.: Probably -- but I see the problem with MinGW, and under Cygwin, but not on Ubuntu (with the same version of g++, 7.4.0). Maybe the Cygwin folks can track it down. – Keith Thompson Jun 10 '19 at 05:21
  • @M.M I clearly stated that I compiled on godbolt and locally. On godbolt it fails without -fpermissive, on my compiler it compiles regardlesa of the presence of that flag. – Fureeish Jun 10 '19 at 07:09
  • 1
    @KeithThompson It seems this is expected. See M.M's answer. – Nikos C. Jun 11 '19 at 06:27
  • @NikosC.: That's ugly -- particularly the fact that `g++ -std=c++11 -pedantic` doesn't produce the required diagnostics on systems that turn `-fms-extensions` on by default. – Keith Thompson Jun 11 '19 at 07:32