Why GCC does not report uninitialized variable? - c++

#include <ios>
#include <iostream>
#include <map>
using namespace std;
int main() {
ios_base::sync_with_stdio(false);
map<int, int> v;
int i;
int t;
while (cin >> i) {
v[i] = t++;
}
auto mi = i;
auto mt = t;
for (const auto p : v) {
if (p.second < mt) {
mi = p.first;
mt = p.second;
}
}
cout << mi << '\n';
return 0;
}
The abovementioned program makes heavy use of an uninitialized variable t, but GCC does not report it with -Wall or -Wuninitialized. Why is it so?
It is worth noting that Clang catches it:
main.cpp:13:12: warning: variable 't' is uninitialized when used here [-Wuninitialized]
v[i] = t++;
^
Used g++ (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2).
Used clang version 4.0.1 (tags/RELEASE_401/final).
As you can see in https://godbolt.org/g/kmYMC1 GCC 7.2 does not report it even when it should. I will create a ticket in GCC's issue tracker.

g++'s warning flag is not called -Wuninitialized: it is called -Wmaybe-uninitialized.
Also, as Jonathan Wakely noted in his answer, g++ is able to detect usage of uninitialized variables only when optimizations are enabled.
Enabling both -Wmaybe-initalized and optimizations produces the expected warning: https://godbolt.org/g/3CZ6kT
Note that -Wmaybe-initalized is enabled by default with both -Wall and -Wextra.

GCC can only detect uninitialized variables when optimization is enabled, because the logic for tracking the values of variables is part of the optimization machinery.
If you compile with -O -Wall you get a warning:
<source>: In function 'int main()':
12 : <source>:12:13: warning: 't' may be used uninitialized in this function [-Wmaybe-uninitialized]
v[i] = t++;
~^~
Compiler exited with result code 0
https://godbolt.org/g/327bsi

Related

Why does g++ 11 trigger "maybe uninitialized" warning in connection with this pointer casting

After a compiler update from g++ v7.5 (Ubuntu 18.04) to v11.2 (Ubuntu 22.04), the following code triggers the maybe-uninitialized warning:
#include <cstdint>
void f(std::uint16_t v)
{
(void) v;
}
int main()
{
unsigned int pixel = 0;
std::uint16_t *f16p = reinterpret_cast<std::uint16_t*>(&pixel);
f(*f16p);
}
Compiling on Ubuntu 22.04, g++ v11.2 with -O3 -Wall -Werror.
The example code is a reduced form of a real use case, and its ugliness is not the issue here.
Since we have -Werror enabled, it leads to a build error, so I'm trying figure out how to deal with it right now. Is this an instance of this gcc bug, or is there an other explanation for the warning?
https://godbolt.org/z/baaMTxhae
You don't initialize an object of type std::uint16_t, so it is used uninitialized.
This error is suppressed by -fno-strict-aliasing, allowing pixel to be accessed through a uint16_t lvalue.
Note that -fstrict-aliasing is the default at -O2 or higher.
It could also be fixed with a may_alias pointer:
using aliasing_uint16_t = std::uint16_t [[gnu::may_alias]];
aliasing_uint16_t* f16p = reinterpret_cast<std::uint16_t*>(&pixel);
f(*f16p);
Or you can use std::start_lifetime_as:
static_assert(sizeof(int) >= sizeof(std::uint16_t) && alignof(int) >= alignof(std::uint16_t));
// (C++23, not implemented in g++11 or 12 yet)
auto *f16p = std::start_lifetime_as<std::uint16_t>(&pixel);
// (C++17)
auto *f16p = std::launder(reinterpret_cast<std::uint16_t*>(new (&pixel) char[sizeof(std::uint16_t)]));

Why does `GCC 10 -Wtype-limits` not warn about comparison with `inline static constexpr` expressions when GCC 7 does?

When compiling this snippet of code (example code)
#include <iostream>
#include <cstdlib>
#include <chrono>
#ifndef USE_DEFINE
class ClassA
{
public:
inline static constexpr uint8_t A = 0;
};
#else
#define A 0
#endif
int main()
{
srand(std::chrono::system_clock::now().time_since_epoch().count());
uint8_t a = rand() % 255;
#ifndef USE_DEFINE
if(a < ClassA::A)
#else
if(a < A)
#endif
{
std::cout << "Shouldn't even compile using `-Wall -Wextra -Werror -Wfatal-errors -Wpedantic` flags." << std::endl;
return -1;
}
return 0;
}
with GCC 7.5 and the following flags
g++ -std=gnu++17 -Wall -Wextra -Wpedantic -Wfatal-errors -Werror -o test main.cc
i get the following warning/error (due to -Werror):
main.cc: In function ‘int main()’:
main.cc:40:7: error: comparison is always false due to limited range of data type [-Werror=type-limits]
40 | if(a < ClassA::A)
Which seems ok to me due to the fact that i'm trying to check if an uint8_t is less than 0. The same happens when defining USE_DEFINE. Both expressions are not constant due to the changing value of a so it could be checked if the type limits allow this kind of comparison to evaluate as true AND false.
Doing the same with a newer compiler (GCC 10.1.0 / CLang 10.0.1) i don't get this warning anymore when using the inline static constexpr uint8_t A = 0 of ClassA. When i use USE_DEFINE the same happens.
Is this behaviour of GCC/Clang erroneous or is this some sideeffect caused by attributes of const/constexpr?
The GCC-Manual says (for GCC 6.4/7.5 as well as 10):
-Wtype-limits
Warn if a comparison is always true or always false due to the limited range of the data type, but do not warn for constant expressions. For example, warn if an unsigned variable is compared against zero with < or >=. This warning is also enabled by -Wextra.
As far as i can see if(a < ClassA::A) isn't a constant expression even though i'm using the constexpr keyword. The same happens when using const instead of constexpr. What does lead to this behaviour?

Error while declaring int variable using curly braces in g++

I compiled this code using g++ and got an error:
#include<iostream>
using namespace std;
int main()
{
int j{ 0 };
cout << "j = " << j << endl;
return 0;
}
This is the error:
error: expected ';' at end of declaration
int j{ 0 };
^
;
1 error generated.
You have probably used an old version of compiler .
On Godbolt, I have checked that it may be older than 4.4.7.
You may have to add -std=c++11 flag to compile.
Newer compiler has this standard enable as default.

gcc gives no warning for comparing unsigned integer < 0 even with Wextra enabled

Take the following code
#include <iostream>
template<typename T>
T f(T x, unsigned y) {
if (y < 0) return x;
return static_cast<T>(0);
}
using namespace std;
int main() {
int a = f(2, 3);
std::cout << a << std::endl;
return 0;
}
where function f clearly always returns 0. Compiling it with g++-7.2.0 -Wall -Wextra gives no hint about pointless comparison. However, clang warns us nicely:
a.cpp:7:11: warning: comparison of unsigned expression < 0 is always false [-Wtautological-compare]
if (y < 0) return x;
~ ^ ~
1 warning generated.
Why is this so (I presume templates are the root of the problem) and can gcc be forced to output the warning in this case?
This is a regression bug in some versions of GCC (including 8.x and 9.x - which are still the default compilers on many distributions at the time of writing).
The bug was tracked here (#jureslak file it again, but that was marked as dupe) and has been resolved. See the warning with GCC 10.1 (Godbolt).

Building Transactional Memory C++ Code in g++

The cppreference website has a (work in progress) page describing transactional memory c++ code. This is the first example on the page
#include <iostream>
#include <vector>
#include <thread>
int f()
{
static int i = 0;
synchronized { // begin synchronized block
std::cout << i << " -> ";
++i; // each call to f() obtains a unique value of i
std::cout << i << '\n';
return i; // end synchronized block
}
}
int main()
{
std::vector<std::thread> v(10);
for(auto& t: v)
t = std::thread([]{ for(int n = 0; n < 10; ++n) f(); });
for(auto& t: v)
t.join();
}
Toward the bottom of that page, there is an indication that this builds on gcc (// GCC assembly with the attribute:).
I can't get this to build on g++ 5.3.1:
$ g++ --std=c++11 -fgnu-tm -lpthread trx.cpp
trx.cpp: In function ‘int f()’:
trx.cpp:7:5: error: ‘synchronized’ was not declared in this scope
synchronized { // begin synchronized block
^
$ g++ --help | grep transaction
$ g++ --version
g++ (Ubuntu 5.3.1-14ubuntu2.1) 5.3.1 20160413
gcc documentation does have a page on transactional memory, but the primitives are different (e.g., the atomic block is __transaction_atomic). The page on cppreference.com conversely appears to be related to N3919, and uses the primitives from there.
How can this code be built with g++?
The transactional_memory link you mention first says:
Compiler support
This technical specification is supported by GCC as of version 6.1 (requires -fgnu-tm to enable).
So you need GCC 6 (and probably also -std=c++1z in addition to -fgnu-tm ....)