clang, gcc, and ignored qualifiers: who is right? - c++

I found a difference in behavior between gcc and clang when compiling BoringSSL, and was able to whittle it down to the following test case to illustrate:
typedef char *OPENSSL_STRING;
#if USE_TYPEDEF
#define constptr const OPENSSL_STRING
#else
#define constptr const char *
#endif
int
foo (const void **ap)
{
constptr a = (constptr) *ap;
return a != 0;
}
I tested four scenarios as follows:
sh$ g++ -c t2.cc -Wignored-qualifiers -DUSE_TYPEDEF
t2.cc: In function ‘int foo(const void**)’:
t2.cc:11:30: warning: type qualifiers ignored on cast result type [-Wignored-qualifiers]
11 | constptr a = (constptr) *ap;
| ^~
sh$ g++ -c t2.cc -Wignored-qualifiers
sh$ clang++ -c t2.cc -Wignored-qualifiers -DUSE_TYPEDEF
sh$ clang++ -c t2.cc -Wignored-qualifiers
sh$
Is this a bug in gcc -- or is there something more going on that I don't understand?
For reference: the warning is in BoringSSL's stack.h

Given const OPENSSL_STRING, const is qualified on the typedef OPENSSL_STRING itself, so the type would be char * const, i.e. const pointer to non-const char (note that it's not const char *). Gcc is just trying to tell you that as the cast result the const part is ignored. i.e. (char * const) *ap; has the same effect as (char *) *ap;.
Changing the type to int might be clearer.
const int i = (int) 0; // a weird conversion
const int i = (const int) 0; // same effect as above

Related

static assertion failed: comparison object must be invocable as const when using my custom comparison function in set container [duplicate]

Sample code:
#include <string>
#include <set>
using namespace std;
class x
{
private:
int i;
public:
int get_i() const { return i; }
};
struct x_cmp
{
bool operator()(x const & m1, x const & m2)
#if _MSC_VER
const
#endif
{
return m1.get_i() > m2.get_i();
}
};
std::set<x, x_cmp> members;
void add_member(x const & member)
{
members.insert(member);
}
Invocations:
$ g++ -c -std=c++14 -pedantic -Wall -Wextra
<nothing>
$ clang++ -c -std=c++14 -pedantic -Wall -Wextra
<nothing>
$ icc -c -std=c++14 -pedantic -Wall -Wextra
<nothing>
$ cl /c /std:c++14 /Za
<nothing>
Question: why msvc requires const while others don't? Or why others don't require const?
This is LWG2542. In C++14, the wording for the comparison operator said "possibly const", which was interpreted by GCC and Clang as meaning that the comparison operator was not required to be const qualified. MSVC always required it.
This is a wording defect, as comparison operators for associative containers should be const qualified. This was changed in C++17 to require the comparator to be const. This is a breaking change, so valid (though broken) C++14 code may fail to compile in C++17.

MSVC: C++14: std:set: comparison function: why "const" is required?

Sample code:
#include <string>
#include <set>
using namespace std;
class x
{
private:
int i;
public:
int get_i() const { return i; }
};
struct x_cmp
{
bool operator()(x const & m1, x const & m2)
#if _MSC_VER
const
#endif
{
return m1.get_i() > m2.get_i();
}
};
std::set<x, x_cmp> members;
void add_member(x const & member)
{
members.insert(member);
}
Invocations:
$ g++ -c -std=c++14 -pedantic -Wall -Wextra
<nothing>
$ clang++ -c -std=c++14 -pedantic -Wall -Wextra
<nothing>
$ icc -c -std=c++14 -pedantic -Wall -Wextra
<nothing>
$ cl /c /std:c++14 /Za
<nothing>
Question: why msvc requires const while others don't? Or why others don't require const?
This is LWG2542. In C++14, the wording for the comparison operator said "possibly const", which was interpreted by GCC and Clang as meaning that the comparison operator was not required to be const qualified. MSVC always required it.
This is a wording defect, as comparison operators for associative containers should be const qualified. This was changed in C++17 to require the comparator to be const. This is a breaking change, so valid (though broken) C++14 code may fail to compile in C++17.

c++11 and gcc: internal compiler error: in convert_move

I have the following code:
typedef int __v8si __attribute__ ((__vector_size__ (32)));
class T
{
public:
__v8si v;
__attribute__((target("avx2")))
T(int p ):v(__extension__ __v8si{p,p,p,p,p,p,p,p}){}
__attribute__((target("avx2")))
T(__v8si p):v(p){}
__attribute__((target("avx2")))
T operator * ( T b ) const
{
return __builtin_ia32_pmulld256( v , b.v ) ;
}
};
void h(int *);
__attribute__((target("default")))
void h(int *)
{
}
__attribute__((target("avx2")))
void h(int *)
{
const T a(1);
const T b(2);
const T c (a * b);
}
int main()
{
return 0;
}
If I try to compile it,
I have the following error:
$ gcc test.cpp -std=c++11
test.cpp: In member function 'T T::operator*(T) const':
test.cpp:17:48: internal compiler error: in convert_move, at expr.c:315
return __builtin_ia32_pmulld256( v , b.v ) ;
^
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://bugzilla.redhat.com/bugzilla> for instructions.
I have tried to compile it with various gcc versions:
4.9.2, 5.3 and several other versions.
Have you any ideas why it happens, and how could I solve the problem?
gcc test.cpp -std=c++11 -mavx2 works.
gcc test.cpp -std=c++11 -O1 works.
but I want to compile the code with -O0
Update 1. I've filed a bug report. The report is available here:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77952

Unable to overload with references to *this

Here is a busybox I wrote to play with the new feature in gcc-4.8.1+ (I think clang-2.9+ should do this too) for N2439 (ref-qualifiers for 'this'):
class Foo
{
public:
Foo(int i) : _M_i(i) { }
int bar() & { return _M_i /= 2; }
int bar() const & { return _M_i; }
int bar() && { return 2 * _M_i; }
private:
int _M_i = 42;
};
int
main()
{
Foo ph(333);
ph.bar();
const Foo ff(123);
ff.bar();
Foo(333).bar();
}
It looks to me reading the standard 8.3.5 that the three bar() methods should be overloadable. I get a linker error though:
[ed#localhost ref_this]$ ../bin/bin/g++ -std=c++11 -o ref_this ref_this.cpp
/tmp/ccwPhzqr.s: Assembler messages:
/tmp/ccwPhzqr.s:73: Error: symbol `_ZN3Foo3barEv' is already defined
If I comment out int bar() const & I am unable to resolve ff.bar();:
[ed#localhost ref_this]$ ../bin/bin/g++ -std=c++11 -o ref_this ref_this.cpp
ref_this.cpp: In function ‘int main()’:
ref_this.cpp:26:10: error: no matching function for call to ‘Foo::bar() const’
ff.bar();
^
ref_this.cpp:26:10: note: candidates are:
ref_this.cpp:11:7: note: int Foo::bar() &
int bar() & { return _M_i /= 2; }
^
ref_this.cpp:11:7: note: no known conversion for implicit ‘this’ parameter from ‘const Foo’ to ‘Foo&’
ref_this.cpp:13:7: note: int Foo::bar() &&
int bar() && { return 2 * _M_i; }
^
ref_this.cpp:13:7: note: no known conversion for implicit ‘this’ parameter from ‘const Foo’ to ‘Foo&&’
Is this a gcc bug or part of the standard?
I'm not on my computer with clang on it but what does clang say?
This feature is not supported by GCC up to version 4.8.0. It should be supported by GCC 4.8.1, which has not been officially released yet.
To the best of my knowledge, the only major compiler that supports reference qualifiers on member functions at the moment is Clang. As you can see from this example, your code compiles fine on Clang 3.2.

using std::map gives warning: dereferencing pointer ‘<anonymous>’ does break strict-aliasing rules

I've reduced a case to the code shown below here.
When compiling, this gives the following:
$ g++ -std=c++0x -O2 -Wall t.cpp
t.cpp: In function ‘int main()’:
t.cpp:20: warning: dereferencing pointer ‘<anonymous>’ does break strict-aliasing rules
t.cpp:19: warning: dereferencing pointer ‘<anonymous>’ does break strict-aliasing rules
/usr/lib/gcc/i686-redhat-linux/4.4.6/../../../../include/c++/4.4.6/bits/stl_tree.h:175: note: initialized from here
What is this warning telling me ? What can I do about it ?
#include <stdio.h>
#include <stdint.h>
struct TimeKey {
uint64_t time_stamp;
uint64_t msg_no;
TimeKey(uint64_t tstamp, uint64_t no) :
time_stamp(tstamp),
msg_no(no)
{}
bool operator < (const TimeKey &other) const
{
if (time_stamp == other.time_stamp) //line 19
return msg_no < other.msg_no; //line 20
else
return time_stamp < other.time_stamp;
}
};
template <typename T>
class TimeBuffer {
public:
uint64_t counter;
std::map<TimeKey, T> messages;
void AddMsg(uint64_t tstamp, T val) {
messages[TimeKey(tstamp, counter++)] = val;
}
};
int main(void)
{
TimeBuffer<int> messages;
messages.AddMsg(123456, 1);
}
Note, this is on RHEL 6.3, which comes with gcc 4.4.6
This is a known (and fixed) compiler bug, see this and this. You should update your toolchain.