bogus warning for constexpr if with function pointer template parameter - c++

I always get a mysterious warning if I compile the following code:
template < void(*FUNC)() >
struct Bla
{
static void Do()
{
if constexpr ( FUNC != nullptr )// << compiler complains here "the address of 'void f1()' will never be NULL [-Waddress]"
{
FUNC();
}
else
{
std::cout << "Nothing" << std::endl;
}
}
};
void f1() { std::cout << "f1" << std::endl; }
int main()
{
Bla<f1>::Do();
Bla<nullptr>::Do();
}
Full warning from g++:
[x#y ~]$ g++ -std=c++20 -g -O2 -Wall -pedantic -Wextra main.cpp
main.cpp: In instantiation of 'static void Bla<FUNC>::Do() [with void (* FUNC)() = f1]':
main.cpp:86:18: required from here
main.cpp:71:13: warning: the address of 'void f1()' will never be NULL [-Waddress]
71 | if constexpr ( FUNC != nullptr )
| ^~
The idea of checking for template parms with constexpr if is not to get a warning if the parameter is a constant :-)
I am wrong or is it simply a gcc bug?

Related

Different compiler behaviour when using alias as scope to get parent member

This code compiles fine on Clang and Visual C++ but not on GCC:
#include <iostream>
template <class T>
struct Test {
Test(T &t) : _t(t) {
}
void method() {
std::cout << _t.Internal::_value << "\n"; // Doesn't work on GCC
std::cout << _t.T::Internal::_value << "\n"; // Work on all compilers
}
private:
T &_t;
};
template <class T>
struct Base {
T _value = 1;
};
template <class T>
struct Child : Base<int> {
using Internal = Base<int>;
int _value = 2;
};
int main(int argc, const char * argv[]) {
Child<float> child;
Test<Child<float>> test(child);
test.method();
return 0;
}
The error message from GCC is
error: 'Internal' has not been declared
9 | std::cout << _t.Internal::_value << "\n";
| ^~~~~~~~
Which one is right ?
Visual C++ and Clang are right in accepting this code.
It was a bug in GCC that prevented it from doing the same. The error as in the question was up to GCC 10, in GCC 11 its wording changed to
error: request for member 'Internal' in non-class type 'T'
9 | std::cout << _t.Internal::_value << "\n";
| ^~~~~~~~
And GCC trunk finally accepts the code as well. Demo: https://gcc.godbolt.org/z/dj34Yhns3
So we could expect the fix in GCC 12.

function pointers in array (nix c++)

I'm getting a compiler error when I'm trying to initialize my array with function pointers. Without using a class I'm able to run the code fine, but when I incorporate the code in a class I'm getting the error. I suppose this is more of a problem with my understanding of class usage, the scope resolution operator, etc. Any help to get this resolved would be much appreciated.
#include <iostream>
#include <cassert>
using namespace std;
#define F1 0
#define F2 1
#define F3 2
class A
{
private:
bool Func1();
bool Func2();
bool Func3();
public:
bool do_it(int op);
typedef bool (A::*fn)(void);
static fn funcs[3];
protected:
};
A::fn A::funcs[3] = {Func1, Func2, Func3};
int main()
{
A Obj;
cout << "Func1 returns " << Obj.do_it(F1) << endl;
cout << "Func2 returns " << Obj.do_it(F2) << endl;
cout << "Func3 returns " << Obj.do_it(F3) << endl;
return 0;
}
bool A::do_it(int op)
{
assert(op < 3 && op >= 0);
return (this->*(funcs[op]))();
}
bool A::Func1() { return false; }
bool A::Func2() { return true; }
bool A::Func3() { return false; }
The compiler spits out:
15:35:31 **** Build of configuration Debug for project JT ****
make all
make: Warning: File 'objects.mk' has modification time 7.3 s in the future
Building file: ../src/JT.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/JT.d" -MT"src/JT.o" -o "src/JT.o" "../src/JT.cpp"
../src/JT.cpp:141:41: error: cannot convert ‘A::Func1’ from type ‘bool (A::)()’ to type ‘A::fn {aka bool (A::*)()}’
A::fn A::funcs[3] = {Func1, Func2, Func3};
^
../src/JT.cpp:141:41: error: cannot convert ‘A::Func2’ from type ‘bool (A::)()’ to type ‘A::fn {aka bool (A::*)()}’
../src/JT.cpp:141:41: error: cannot convert ‘A::Func3’ from type ‘bool (A::)()’ to type ‘A::fn {aka bool (A::*)()}’
src/subdir.mk:18: recipe for target 'src/JT.o' failed
make: *** [src/JT.o] Error 1
15:35:32 Build Finished (took 1s.64ms)
Use A::fn A::funcs[3] = {&A::Func1, &A::Func2, &A::Func3};

undefined reference to variable template of pointer to function in clang but not gcc

#include <iostream>
static constexpr bool isSSE2 = true;
template<typename T>
static void (*fp)();
template<typename T>
static void foo_c() {
std::cout << "foo_c get called." << std::endl;
}
template<typename T>
static void foo_sse2() {
std::cout << "foo_sse2 get called." << std::endl;
}
int main() {
if (isSSE2)
fp<int> = foo_sse2<int>;
else
fp<int> = foo_c<int>;
fp<int>();
return 0;
}
I have a project that uses variable template which itself is a pointer to function. The example code above compiles and executes fine in GCC 6.3, but gives warning and error in clang 3.9.1.
$ clang++ "Source.cpp" -o "foo.exe" -std=c++14 -O2
Source.cpp:6:15: warning: variable 'fp<int>' has internal linkage but is not defined [-Wundefined-internal]
static void (*fp)();
^
Source.cpp:20:9: note: used here
fp<int> = foo_sse2<int>;
^
1 warning generated.
C:\msys64\tmp\Source-6600e8.o:(.text+0x2a): undefined reference to `fp<int>'
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
Any help is appreciated.
You have to initialize your fp<>() first:
template<typename T>
static void (*fp)() = nullptr;
It compiles and runs fine in Clang 4.0: sample code.
And try to always initialize your variables — it may save you from all sorts of headaches. :)

constexpr different exception specifier when splitting definition and declaration

I have the following test piece of code tested on gcc 4.7.2:
#include <iostream>
#include <type_traits>
#ifdef REMOVE_CONSTEXPR_NOEXCEPT
# define CONSTEXPR_NOEXCEPT
#else
# define CONSTEXPR_NOEXCEPT noexcept
#endif
class ConstExpr {
public:
// Some constructors
private:
// Some member data
public:
// Cannot split the declaration if noexcept
static constexpr unsigned int Int(unsigned int i) CONSTEXPR_NOEXCEPT
#ifndef SPLIT_CONSTEXPR_DECLARATION
{
return i;
}
#else
;
#endif
};
#ifdef SPLIT_CONSTEXPR_DECLARATION
constexpr unsigned int ConstExpr::Int(unsigned int i) CONSTEXPR_NOEXCEPT {
return i;
}
#endif
class NoConstExpr {
public:
// Some constructors
private:
// Some member data
public:
// Cannot split the declaration if noexcept
static unsigned int Int(unsigned int i) noexcept;
};
// It's OK on normal functions
inline unsigned int NoConstExpr::Int(unsigned int i) noexcept {
return i;
}
int main()
{
std::cout << "ConstExpr: " << std::integral_constant<unsigned int,
ConstExpr::Int(5)>::value << std::endl;
std::cout << "NoConstExpr: " << NoConstExpr::Int(5) << std::endl;
}
I get the following compilation output:
[matt test] g++ -std=c++11 main.cpp && ./a.out
ConstExpr: 5
NoConstExpr: 5
[matt test] g++ -std=c++11 main.cpp -DSPLIT_CONSTEXPR_DECLARATION && ./a.out
main.cpp:28:55: error: declaration of ‘static constexpr unsigned int ConstExpr::Int(unsigned int)’ has a different exception specifier
main.cpp:17:33: error: from previous declaration ‘static constexpr unsigned int ConstExpr::Int(unsigned int) noexcept (true)’
[matt test] g++ -std=c++11 main.cpp -DSPLIT_CONSTEXPR_DECLARATION -DREMOVE_CONSTEXPR_NOEXCEPT && ./a.out
ConstExpr: 5
NoConstExpr: 5
So my question is: Is it part of the C++11 spec to be able to split the definition and declaration of constexpr functions or is this a gcc bug?
Looks like the gcc bug solves this in 4.8.1

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.