Bug 52145 (cwg903) - [C++11] [DR 903] zero-valued integer constant expression should prefer conversion to pointer
Summary: [C++11] [DR 903] zero-valued integer constant expression should prefer conver...
Status: NEW
Alias: cwg903
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 4.7.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: accepts-invalid
: dr903 88655 96761 107260 116619 (view as bug list)
Depends on:
Blocks: c++-core-issues
  Show dependency treegraph
 
Reported: 2012-02-07 00:59 UTC by Nathan Ridge
Modified: 2024-09-05 18:48 UTC (History)
9 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2012-02-07 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Nathan Ridge 2012-02-07 00:59:55 UTC
In the following example:

#include <iostream>
using std::cerr;

struct S { int n; };
struct X { X(int) {} };
void f(void*)
{
    cerr << "Pointer!\n";
}
void f(X)
{
    cerr << "X!\n";
}
int main()
{
    f(S().n);
}

With GCC 4.7.0-20120128 with the --std=c++11 flag, the output is "X!". The correct output would be "Pointer!".

The reason is that S's implicit default constructor is constexpr, so it value-initializes n. Therefore S().n is a zero-valued integer constant expression, whose conversion to a pointer is preferred over the user-defined conversion to X.

(This example was taken from Chandler Carruth's talk at the GoingNative 2012 conference.)
Comment 1 Daniel Krügler 2012-02-07 13:51:59 UTC
(In reply to comment #0)
The core language is in the process to make it clear, that S().n no longer is a null-pointer constant, see

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#903

This would mean that the current behaviour is as intended. I would make the outcome of this issue dependent on the final CWG 903 decision.
Comment 2 Jonathan Wakely 2012-02-07 14:39:07 UTC
suspending
Comment 3 Jeffrey Yasskin 2012-04-26 19:42:19 UTC
A simpler test case is:

$ cat test.cc
const long kNullPtr = 0;
const long* ptr = kNullPtr;
$ g++-4.7pre -c test.cc -std=gnu++11
test.cc:2:19: error: invalid conversion from ‘long int’ to ‘const long int*’ [-fpermissive]
$ g++-4.7pre --version
g++-4.7pre (GCC) 4.7.1 20120412 (prerelease)


I'm going to unsuspend this because DR903 is "ready", and gcc-4.7's behavior doesn't match either the proposed wording or the current definition of C++11. The proposed wording discusses a change to C++17 rather than to C++11 (we can tell because it adds a "C.3 C++ and ISO C++ 2011" section), so the new error should only show up under -std=gnu++17, and be a warning in -std=gnu++11.
Comment 4 Paolo Carlini 2012-04-26 23:03:11 UTC
17?
Comment 5 Jeffrey Yasskin 2012-04-26 23:06:05 UTC
"17" was the rough consensus at Kona for the target for the next standard. You could use -std=c++1y or c++1x or whatever instead.
Comment 6 Paolo Carlini 2012-04-26 23:14:18 UTC
Oh, Ok, I wasn't there. In GCC we currently use -std=c++1y, but you know that.
Comment 7 Jeffrey Yasskin 2012-04-26 23:56:22 UTC
Oops, I didn't actually realize you'd allocated an option for that in 4.8, and was just making one up. Sorry for the distraction.
Comment 8 Jonathan Wakely 2014-12-10 13:29:59 UTC
DR 903 is a DR against C++11 ([diff.cpp03.conv] identifies it as an incompatibility with C++03, not with C++11).

Clang also implements DR 903 in C++11 mode.
Comment 9 Andrew Pinski 2021-12-04 06:43:46 UTC
*** Bug 88655 has been marked as a duplicate of this bug. ***
Comment 10 Andrew Pinski 2021-12-04 06:43:57 UTC
*** Bug 77712 has been marked as a duplicate of this bug. ***
Comment 11 Andrew Pinski 2021-12-04 06:52:33 UTC
Here is a testcase which tests all of the null pointerness in C++11 (+):
#include <cstddef>
extern "C" int puts(const char*);
typedef unsigned long uint64_t;
typedef long int64_t;

struct Foo { Foo(int64_t) { } };
bool t = true;

void foo(const char*)
{
  if (t)
    __builtin_abort();
  puts("In foo(const char*)");
}

void foo(const Foo&)
{
  if (!t)
    __builtin_abort();
  puts("In foo(const Foo&)");
}

int main()
{
#if __cplusplus >= 201103L
  t= true;
#else
  t= false;
#endif
  foo((int)0);
  foo((unsigned)0);
  foo((short)0);
  foo((unsigned short)0);
  foo((int64_t)0);
  foo((uint64_t)0);
  foo(int());
#if __cplusplus >= 201103L
  foo(int{});
  t= false;
  foo(nullptr);
#endif
  foo(0u);
  foo(0ul);
  foo(0ull);
  foo(0);
  foo(NULL);
}

---- CUT ----
We get this right for C++98 but wrong for C++11.
Comment 12 Andrew Pinski 2021-12-07 12:39:47 UTC
*** Bug 96761 has been marked as a duplicate of this bug. ***
Comment 13 Andrew Pinski 2022-10-14 15:14:58 UTC
*** Bug 107260 has been marked as a duplicate of this bug. ***
Comment 14 Andrew Pinski 2024-09-05 18:48:57 UTC
*** Bug 116619 has been marked as a duplicate of this bug. ***