Consider the following code:
#include <tuple>
struct A {
template <typename... Types> operator std::tuple<Types...>() {
int i = 0;
return std::tuple<Types...>{Types(i++)...};
}
};
struct B {
B(int i){};
};
int main() {
A a;
std::tuple<B, B> t{a};
}
It produces the following warnings in gcc
$ g++-12 main.cpp -std=c++20 -Wall
main.cpp: In instantiation of ‘A::operator std::tuple<_UTypes ...>() [with Types = {B, B}]’:
main.cpp:18:23: required from here
main.cpp:7:46: warning: operation on ‘i’ may be undefined [-Wsequence-point]
7 | return std::tuple<Types...>{Types(i++)...};
| ^
main.cpp:7:46: warning: operation on ‘i’ may be undefined [-Wsequence-point]
but not in clang:
clang++-14 main.cpp -std=c++20 -Wall
main.cpp:18:20: warning: unused variable 't' [-Wunused-variable]
std::tuple<B, B> t{a};
^
1 warning generated.
Why?
This may be related but the referenced gcc bug is already fixed. I have gcc --version gcc (Debian 12.2.0-9) 12.2.0.
The order of evaluation of elements in a braced-init-list is strictly left-to-right, already since C++11, and regardless of the context in which the syntax is used. See https://timsong-cpp.github.io/cppwp/n3337/dcl.decl#dcl.init.list-4.
So the warning is bogus. #Artyer linked this bug report for a false positive warning under the question, which probably covers your example as well.
As mentioned in the other bug report you linked, GCC had actual wrong code generation for similar cases in earlier versions though, so you might want to be careful when relying on this order.
Related
I happen to find that GCC and Clang differ in the compilation of the following code:
struct Foo
{
int mem = 42;
};
int main()
{
constexpr Foo foo;
static_assert(__builtin_constant_p(foo));
return 0;
}
I compile with g++ -std=c++17 and clang++ -std=c++17.
In particular,
g++ g++-9 (Homebrew GCC 9.3.0_1) 9.3.0 compiles, whereas
clang++ Apple clang version 11.0.3 (clang-1103.0.32.62) fails to compile, complaining that
error: static_assert failed due to requirement '__builtin_constant_p(foo)'
static_assert(__builtin_constant_p(foo));
^ ~~~~~~~~~~~~~~~~~~~~~~~~~
I didn't find any hint that there should be any difference regarding __builtin_constant_p.
For __builtin_constant_p
GCC says
You can use the built-in function __builtin_constant_p to determine if a value is known to be constant at compile time ...
Clang
says
Clang supports a number of builtin library functions with the same syntax as GCC, including things like __builtin_nan, __builtin_constant_p, __builtin_choose_expr, __builtin_types_compatible_p, __builtin_assume_aligned, __sync_fetch_and_add, etc.
Question: While I know __builtin_constant_p is a compiler extension, which one should be the correct one?
Both are poorly documented so I doubt there is a proper answer to your question.
If you need a workaround: it seems that clang gives up if the argument is not an int.
So this works:
struct Foo
{
int mem = 42;
};
int main()
{
constexpr Foo foo;
static_assert(__builtin_constant_p(foo.mem));
return 0;
}
We just got burnt by a typo: "constexpr bool maxDistance=10000;"
Both gcc and clang compile this with no warning.
The real error here is that the variable shouldn't have been of type bool, but should have been an integer type instead.
How can we ensure we get a compiler warning in future?
#include <iostream>
constexpr bool number = 1234;
int main(int argc, char* argv[])
{
std::cout << number + 10000 << std::endl; // prints 10001.
return number;
}
The error here is that the variable is declared with the wrong type, however neither clang nor gcc give a warning.
gcc -Wall -std=c++14 test.cpp -lstdc++
clang -Wall -std=c++14 test.cpp -lstdc++
(using gcc 5.4.0 and clang 3.8.0)
Note: I've since learnt about a possible compile flag: -Wint-in-bool-context however this doesn't appear to be implemented in the version I'm using (5.4.0) nor in clang (3.8.0).
Is this the right way to go?
You should use direct list initialization syntax, it prohibits narrowing:
constexpr bool number{1234}; // error: narrowing conversion of '1234' from 'int' to 'bool' [-Wnarrowing]
I've discovered that gcc has a flag '-Wint-in-bool-context' however this doesn't appear to be implemented in the version I'm using (5.4.0) nor in clang (3.8.0).
Is this the right way to go?
gcc5.4 doesn't compile the following code:
// source.cpp
int nonconstexprfunc()
{
return 14;
}
constexpr int func(int n)
{
if (n < 0)
return nonconstexprfunc();
return n*n;
}
int main()
{
constexpr int t1 = func(0);
return 0;
}
The command I use:
$ g++ -std=c++14 -c source.cpp
The output:
In function ‘constexpr int func(int)’:
error: ‘constexpr int func(int)’ called in a constant expression
constexpr int t1 = func(0);
In function ‘int main()’:
error: ‘constexpr int func(int)’ called in a constant expression
constexpr int t1 = func(0);
But I can compile that source.cpp using gcc6.4. Doesn't gcc5.4 fully support constexpr functions?
More interestingly I can compile that source.cpp using icpc (Intel C++ compiler) that uses gcc5.4 - I suppose there must be an option to compile that code using gcc5.4.
$ icpc -v
icpc version 19.0 (gcc version 5.4.0 compatibility)
$ icpc -std=c++14 -c source.cpp
no errors
The first limitation is concerning the use gcc 5.4 with -std=c++11 which produces the error because of the two return statement see The body of constexpr function not a return-statement so in order to lift your first issue you need to use -std=c++14
It then produces
'#1 with x86-64 gcc 5.4
: In function 'constexpr int func(int)':
:10:32: error: call to non-constexpr function 'int
nonconstexprfunc()'
return nonconstexprfunc(); ^
: In function 'int main()':
:16:28: error: 'constexpr int func(int)' called in a constant
expression
constexpr int t1 = func(0);
Compiler returned: 1
This next error produced seems to be a known GCC bug (misinterpretation of c++14) see
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=86678
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67026
You can also check out calling non constexpr function from constexpr allowed in some conditions
However judging from the error it produces:
It seems pretty obvious that doing
constexpr int nonconstexprfunc()
{
return 14;
}
will solve the error and will be more efficient in your case.
Check the difference with https://www.godbolt.org/ of adding constexpr or not using gcc 8.2 for example.
It seems that clang is ignoring warnings which occur in included header files:
// what.hpp
class What {
public:
What() {
int x = x;
}
};
// main.cpp
#include <iostream>
#include "what.hpp"
int main()
{
int y = y;
std::cout << "y is: " << y << std::endl;
What w;
}
Compiling this with g++ (4.9.2) gives:
$ g++ -dumpversion && g++ -Wall -Wextra main.cpp -o main
4.9.2
In file included from main.cpp:3:0:
what.hpp: In constructor ‘What::What()’:
what.hpp:5:17: warning: ‘x’ is used uninitialized in this function [-Wuninitialized]
int x = x;
^
main.cpp: In function ‘int main()’:
main.cpp:5:13: warning: ‘y’ is used uninitialized in this function [-Wuninitialized]
int y = y;
Compiling the same thing with clang:
$ clang++ --version && clang++ -Wall -Wextra main.cpp -o main
Ubuntu clang version 3.6.0-2ubuntu1~trusty1 (tags/RELEASE_360/final) (based on LLVM 3.6.0)
Target: x86_64-pc-linux-gnu
Thread model: posix
main.cpp:5:13: warning: variable 'y' is uninitialized when used within its own initialization [-Wuninitialized]
int y = y;
~ ^
1 warning generated.
I'm not sure, If I'm using clang wrong or if this is indeed a bug?
Any hints? Thanks in advance.
This is not clang bug, the warning is being suppressed because x is subsequently unused, the bug report I cite below explains the rationale behind this behavior.
In this specific case it is considered a clang feature to not to produce this warning(Wuninitialized) if the variable is otherwise unused, although most will probably find this surprising behavior.
We can see the rationale from the following bug report: No uninitialized warning for self-initialization (e.g., int x = x):
Right, this is deliberate, and is considered to be a feature rather
than a bug. We suppress the warning on 'int x = x;' only in the case
where 'x' is otherwise unused.
It is mentioned in the bug report that self-intialization in this way is:
considered the canonical way to suppress "use of uninitialized
variable" warnings
This does not depend on whether the code in question is included from a header, I put together a live example that shows the warning does not show up when the code is all in one file.
Note, initializing a variable in this way:
int x = x;
is undefined behavior, for reference see:
Does initialization entail lvalue-to-rvalue conversion? Is int x = x; UB?
Has C++ standard changed with respect to the use of indeterminate values and undefined behavior in C++14?
So in general we can not have any expectations as to the result and the compiler is not obligated to issue a diagnostic although doing so can be helpful.
The lines in question are syntactically correct. Neither are particularly useful lines of code - both exhibit undefined behavior - but they're legal C++ code. As such, the compiler is not obligated to issue any diagnostic.
This is just a quality of implementation issue - the compiler isn't obligated to issue warnings in this case, but it's very helpful when it does. As to why clang happens to warn only for y and not for x, whereas gcc warns for both - I am not sure. It definitely has nothing to do with included header files (you can see for yourself by just defining What in main.cpp) and likely has to do with the fact that you're printing y and never reading from x again.
But you can't rely on complete accuracy with these warnings. When you get them, however, they're always worth paying attention to.
I have the following code:
#include <type_traits>
int main()
{
}
g++ file.cc -std=c++0x
works just fine.
However, I need to use clang++ for some reason.
When I try
clang++ file.cc -std=c++0x
I get a bunch of errors:
In file included from file.cc:1:
In file included from /usr/include/c++/4.4.4/type_traits:50:
/usr/include/c++/4.4.4/tr1_impl/type_traits:230:41: error: expected ')'
struct is_function<_Res(_ArgTypes......)>
^
/usr/include/c++/4.4.4/tr1_impl/type_traits:230:28: note: to match this '('
struct is_function<_Res(_ArgTypes......)>
^
/usr/include/c++/4.4.4/tr1_impl/type_traits:230:12: error: redefinition of 'is_function<type-parameter-0-0 (type-parameter-0-1, ...)>'
struct is_function<_Res(_ArgTypes......)>
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/c++/4.4.4/tr1_impl/type_traits:227:12: note: previous definition is here
struct is_function<_Res(_ArgTypes...)>
^
/usr/include/c++/4.4.4/tr1_impl/type_traits:233:29: error: type qualifier is not allowed on this function
struct is_function<_Res(_ArgTypes...) const>
....
clang++ --version gives:
clang version 2.8 (branches/release_28)
Target: x86_64-redhat-linux-gnu
Thread model: posix
Any ideas how to fix that? (-std=c++11 doesn't work, not recognized.)
Clang 2.8 does not support C++11 features, you need to upgrade your compiler to use them.