C++ Unexpected Left Shift of Negative Value Warning - c++

I compiled my code with the same version of GCC using both -std=gnu++17 and -std=gnu++20. This warning appears for c++17 but is NOT present when using c++20.
I am going to state right up front that, try as I might, I have been unable to create a minimum reproducible example of this problem, but I will continue to try. In the absence of an example, I am just looking for some guidance or would like to know if anyone has ever encountered a similar problem.
I am encountering a large number of the following warnings in my code:
left shift of negative value [-Wshift-negative-value]
The odd thing is, the place where the error is occurring is on the following lines which occur all over my code (as part of a state machine framework):
CState(static_cast<CState::State>(...))
Where CState and State are:
class CState {
public:
using State = CState (AbstractStateMachineV2::*)(const AbstractEventV2&);
constexpr CState(State fn = nullptr) : _fn(fn) {}
static constexpr CState null() { return CState(); }
inline CState operator()(AbstractStateMachineV2& context, const AbstractEventV2& e) {
return context.call(_fn, e);
}
inline operator bool() const { return _fn != nullptr; }
inline bool operator==(CState const& other) { return _fn == other._fn;}
inline bool operator!=(CState const& other) { return _fn != other._fn;}
private:
State _fn;
};
Where the value being casted is just a pointer to a member method used like so:
class MyStateMachine : public AbstractStateMachineV2
{
protected:
CState myState(const AbstractEventV2& e);
};
auto s = CState(static_cast<CState::State>(&MyStateMachine::myState));
As you can see, there is no shifting being done here. And none of the other code that I didn't show involves shifting either.
Unfortunately, I can provide no further insight than this.
I am using the following GCC version but also get the same results on the latest version:
arm-none-eabi-g++.exe (GNU Tools for STM32 10.3-2021.10.20211105-1100) 10.3.1 20210824 (release)
I would really appreciate even the smallest bit of insight anyone could provide on this.
I don't know if this will help at all, but here is a snippet of the actual compilation output for a single source file of my project:
arm-none-eabi-g++ -g3 --specs=nano.specs -mfpu=fpv5-sp-d16 -mfloat-abi=hard -O1 -Wno-missing-field-initializers --debug -g -DBUILD_VERSION_RELEASE=0 -DBUILD_VERSION_MAJOR=0 -DBUILD_VERSION_MINOR=0 -DBUILD_VERSION_BUILD=0 -DBUILD_VERSION_STEM="'a'" -DBUILD_VERSION=\"\" -DUNIX_TIMESTAMP_COMPILE_DATE=\""NO-COMPILE-TIME-PROVIDED"\" -DCOMPILE_BRANCH=\""no-branch"\" -DCODE_REVISION=\""0000000000000000000000000000000000000000"\" -DCODE_REVISION_HASH="{"0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00"}" -DPROJECT_NAME=\"prj-tw-av-base\" -DBUILD_CONFIGURATION=\"debug\" -DBUILD_TARGET_ARCH=\"stm32l562xx\" -DNULL=0 -DDEBUG=1 -DHAVE_CONFIG_H -DOPUS_ARM_ASM -DTW_DEBUG=1 -DLFS_THREADSAFE=1 -DUSE_HAL_DRIVER -DSTM32L562xx -DUSE_FULL_LL_DRIVER -fdata-sections -ffunction-sections -fstack-usage -mcpu=cortex-m33 -MMD -MP -mthumb -Wall -Wextra -mfpu=fpv5-sp-d16 -mfloat-abi=hard -c -std=gnu++17 -fno-exceptions -fno-rtti -fno-use-cxa-atexit -Wdelete-non-virtual-dtor -Wno-volatile -Ilibraries/lib-ext-ctti/include/ -Ilibraries/lib-ext-etl/include/ -Ilibraries/lib-gsp-core-framework/include/ -Ilibraries/lib-tw-av-base-littlefs/include/ -Isources/prj-tw-av-base/include -Isources/prj-tw-av-base/private-include -Itwframework/include -Itwstm32/include -Itwcommon/include -Itwstm32/freertos/include -Itwstm32/stm32cube/STM32L5xx_HAL_Driver/Inc -Itwstm32/stm32cube/CMSIS/Device/ST/STM32L5xx/Include -Itwstm32/stm32cube/CMSIS/Include -Itwstm32/freertos/portable/GCC/ARM_CM33_NTZ/non_secure -Iavbase/include -Iconfig/include -Itwinnet/include -Ist8500/include -Itwfreertos/include -Itwstm32/stm32cube/STM32L5xx_HAL_Driver/Inc/Legacy -Iseggersystemview/include -Iopus/include -Iopus/silk -Iopus/celt -Iopus -Iopus/silk/fixed -Iopus/silk/arm -Iopus/silk/fixed/arm -Iopus/celt/arm -o "build/stm32l562xx/debug/obj/./avbase/src/tw/avbase/filesystem/FilesystemSubsystem.cpp.obj" "avbase/src/tw/avbase/filesystem/FilesystemSubsystem.cpp"
In file included from twframework/include/tw/statemachinev2/StateMachine.h:10,
from avbase/include/tw/avbase/filesystem/FilesystemSubsystem.h:26,
from avbase/src/tw/avbase/filesystem/FilesystemSubsystem.cpp:10:
avbase/include/tw/avbase/filesystem/FilesystemSubsystem.h: In static member function 'static constexpr tw::AbstractStateMachineV2::CState tw::avbase::FilesystemSubsystem::sFS_INFO::init()':
twframework/include/tw/statemachinev2/macros.h:31:89: warning: left shift of negative value [-Wshift-negative-value]
31 | static constexpr CState init() { return CState(static_cast<CState::State>(&init_)); }\
| ^
twframework/include/tw/statemachinev2/macros.h:19:50: note: in expansion of macro '_TW_DECLARE_STATE3'
19 | #define _TW_DECLARE_STATEN(_1, _2, _3, FN_, ...) FN_
| ^~~
twframework/include/tw/statemachinev2/macros.h:18:31: note: in expansion of macro '_TW_DECLARE_STATEN'
18 | #define TW_DECLARE_STATE(...) _TW_DECLARE_STATEN(__VA_ARGS__, _TW_DECLARE_STATE3, _TW_DECLARE_STATE2, _TW_DECLARE_STATE1)(__VA_ARGS__)
| ^~~~~~~~~~~~~~~~~~
avbase/include/tw/avbase/filesystem/FilesystemSubsystem.h:77:2: note: in expansion of macro 'TW_DECLARE_STATE'
77 | TW_DECLARE_STATE(sFS, FilesystemSubsystem::top, FilesystemSubsystem::sFSIdle);
| ^~~~~~~~~~~~~~~~
avbase/src/tw/avbase/filesystem/FilesystemSubsystem.cpp: In constructor 'tw::avbase::FilesystemSubsystem::FilesystemSubsystem(tw::AbstractActiveThread&, tw::twfs::AbstractFilesystem&, tw::twinnet::app::MessageRouter&, tw::twinnet::app::SubAddress, const char*, tw::logging::AbstractLoggable*)':
twframework/include/tw/statemachinev2/macros.h:161:54: warning: left shift of negative value [-Wshift-negative-value]
161 | transition(CState(static_cast<CState::State>(&state_)))
| ^
avbase/src/tw/avbase/filesystem/FilesystemSubsystem.cpp:39:2: note: in expansion of macro 'TW_INITIAL_TRANSITION'
39 | TW_INITIAL_TRANSITION(FilesystemSubsystem::sFS);
| ^~~~~~~~~~~~~~~~~~~~~
...
Every time I do that function pointer casting (via a helper macro), a warning is generated.
The warning is even generated if I add a line as simple as:
FilesystemSubsystem::FilesystemSubsystem()
{
//Warning generated at the following line
auto s = CState(static_cast<CState::State>(&FilesystemSubsystem::state1));
}
AbstractStateMachineV2::CState FilesystemSubsystem::state1(const AbstractEventV2& _e)
{
//...
}
This makes me start to wonder if there is some sort of really odd compiler bug that is exhibiting itself.

Related

gcc c++ how to disable the `-Wno-error=permissive` error when `-fpermissive` and `-Werror` are both on?

For this struct and function:
typedef struct data_s
{
int i1;
int i2;
} data_t;
void print_data_passed_by_ptr(const data_t *data)
{
printf(" i1 = %i\n"
" i2 = %i\n\n",
data->i1,
data->i2);
}
this works fine in C:
// Print R-value struct passed by ptr
print_data_passed_by_ptr(&(data_t){
.i1 = 7,
.i2 = 8,
});
My C build command is:
gcc -Wall -Wextra -Werror -O3 -std=c17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
But, in C++ it fails with
error: taking address of temporary [-fpermissive]
My C++ build command is:
g++ -Wall -Wextra -Werror -O3 -std=c++17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
So, I added -fpermissive to my C++ build command:
g++ -Wall -Wextra -Werror -O3 -std=c++17 -fpermissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
and now the C++ build fails with this:
error: taking address of temporary [-Werror=permissive]
I tried turning off -Werror=permissive with -Wno-error=permissive (see here for that GCC documentation: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html, and search the page for -Wno-error=), but that's not a valid option. New build cmd I attempted:
g++ -Wall -Wextra -Werror -O3 -std=c++17 -fpermissive -Wno-error=permissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
...fails with:
cc1plus: error: -Werror=permissive: no option -Wpermissive
So, how do I solve this to force this C code to build in C++? Either suppressing the warning/error, OR providing some modification to the code other than the one shown just below are acceptable answers. I want the code to compile as C also, not just C++, in the end.
I know I can use "const reference" in C++ instead of ptr, like this, and that's great and all and it might answer somebody else's question, but that's not my question:
void print_data_passed_by_cpp_reference(const data_t& data)
{
printf(" i1 = %i\n"
" i2 = %i\n\n",
data.i1,
data.i2);
}
// Print R-value struct passed by C++ reference
print_data_passed_by_cpp_reference({
.i1 = 9,
.i2 = 10,
});
I also know I can remove -Werror and keep -fpermissive to make it build, with warnings, like this:
eRCaGuy_hello_world/cpp$ g++ -Wall -Wextra -O3 -std=c++17 -fpermissive \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
struct_pass_R_values_by_cpp_reference_and_ptr.c: In function ‘int main()’:
struct_pass_R_values_by_cpp_reference_and_ptr.c:87:5: warning: taking address of temporary [-fpermissive]
});
^
Hello world.
i1 = 7
i2 = 8
i1 = 9
i2 = 10
...but I'd really like to keep -Werror on and make that warning go away.
How to automatically pass an R-value parameter into a function as a const ptr for C and as a const reference for C++
(emphasis added to my original quote)
So, how do I solve this to force this C code to build in C++? Either suppressing the warning/error, OR providing some modification to the code other than the one shown just below are acceptable answers. I want the code to compile as C also, not just C++, in the end.
This works! It is one approach. If there are ways to disable the warning/error in gcc via command-line options I'd still like to know those though.
This is pretty clever I think. It passes the R-value by const ptr for C and by const reference for C++ by using two separate definitions for the print_data() function and the DATA_T macro, depending on the language.
#ifndef __cplusplus
// For C
void print_data(const data_t *data)
{
printf(" i1 = %i\n"
" i2 = %i\n\n",
data->i1,
data->i2);
}
#else
// For C++
void print_data(const data_t& data)
{
printf(" i1 = %i\n"
" i2 = %i\n\n",
data.i1,
data.i2);
}
#endif
#ifndef __cplusplus
// For C
#define DATA_T &(data_t)
#else
// For C++
#define DATA_T // leave empty
#endif
Usage:
// Print R-value struct passed by C++ reference, OR by C ptr, depending on
// whether this code is compiled as C or C++
print_data(DATA_T{
.i1 = 9,
.i2 = 10,
});
Build commands:
# For C
gcc -Wall -Wextra -Werror -O3 -std=c17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a
# For C++
g++ -Wall -Wextra -Werror -O3 -std=c++17 \
struct_pass_R_values_by_cpp_reference_and_ptr.c -o bin/a && bin/a

Deadlock in __cxa_guard_acquire

First the code:
#pragma once
#include <type_traits>
// assign unique identifiers to types
template<typename ...>
class Family
{
static std::size_t identifier() noexcept
{
static std::size_t value = 0;
return value++;
}
template<typename ...>
static std::size_t family() noexcept
{
static const std::size_t value = identifier();
return value;
}
public:
using family_type = std::size_t;
template<typename ... Type>
static family_type type() noexcept
{
return family<std::decay_t<Type>...>();
}
};
// usage
using introspection_family = Family<struct IntrospectionRegistry>;
template<typename Structure>
void addIntrospectData(DataType introspection[MAX_TYPES], DataType const& dataType)
{
/* reserve index for this type in the introspection register */
const auto num = introspection_family::type<Structure>();
assert(num < MAX_TYPES);
introspection[num - 1] = dataType;
}
This code give an integer to each type and I use it in some kind of C++ introspection implementation.
The application isn't multi threaded.
When I compiled it in -O0, sometimes, the call to introspection_family::type<Structure>() blocks at __cxa_guard_acquire#plt and I get a deadlock.
When compiled with -O3, I don't have any problem, but that might just be because it becomes very difficult to reproduce.
__cxa_guard_acquire is used to ensure that the static variable is constructed before we access it but here it should be irrelevant as I'm not even in a threaded application.
Does anyone have any idea why this is happening ?
I use:
CXXFLAGS=-std=c++14 -O0 -g3 -pthread -Wall -Wextra -Werror
LDFLAGS= -g -pthread -lGLEW -lGLU -lGL -lSDL2_mixer -lSDL2
And I use gcc (Ubuntu 5.4.0-6ubuntu1~16.04.10) 5.4.0 20160609
Adding the compile option -fno-threadsafe-statics helped. Since your application is single thread, this is OK.
I had a similar issue. However, the reason in my code was recursion. __cxa_guard_acquire will block when called recursively. A proper fix was needed. I did not check your code if this could also be your problem.
Additional info: The lock used might have a different name than __cxa_guard_acquire. It might also work with recursion, but this is compiler/libc++ specific and you should not rely on that.

Why can a const Class& be initialized to itself?

I was hit by a very stupid but hard to detect bug today. Here is the relevant code:
class Vector;
class PointIterator {
const Vector & x;
const Vector & yv;
PointIterator(const Vector & xv, const Vector & yvo) :
x(xv), yv(yv) { ;};
// ^^ here is wrong
};
Why is such a code legal C++ ? Is there any situation where you could make use of the yv variable ? I'm aware of similar questions about int x = x+1;, (see this question) but while the latter isn't properly initialized, you still can use the x variable, while in the code above, I don't think you can make any use of yv.
Bonus point: is there any compilation option that would have made me detect this ? (preferably using gcc, but I also use clang), besides the "unused argument" warning (I have quite a few of those, I know I should clean them up).
If you compile with g++ -O0 -g main.cpp -Wall -pedantic -Wextra -std=c++14 -o go
main.cpp: In constructor 'PointIterator::PointIterator(const Vector&, const Vector&)':
main.cpp:11:5: warning: 'PointIterator::yv' is initialized with itself [-Winit-self]
PointIterator(const Vector & xv, const Vector & yvo) :
^~~~~~~~~~~~~
main.cpp:11:53: warning: unused parameter 'yvo' [-Wunused-parameter]
PointIterator(const Vector & xv, const Vector & yvo) :
As you can see, you get the warning two times. One for the self init and one for the unused parameter. Fine!
The same for clang:clang++ -O0 -g main.cpp -Wall -pedantic -Wextra -std=c++14 -o go
main.cpp:12:19: warning: reference 'yv' is not yet bound to a value when used
here [-Wuninitialized]
x(xv), yv(yv) { ;};
^
main.cpp:11:53: warning: unused parameter 'yvo' [-Wunused-parameter]
PointIterator(const Vector & xv, const Vector & yvo) :
^
main.cpp:8:20: warning: private field 'x' is not used [-Wunused-private-field]
const Vector & x;
So clang reports also the problem, that the uninitialized ref is used before init. Fine!
What you learn:
* use multiple compilers in highest warning level to get all warnings!
That is what we do for all our code, especially in unit tests connected to code coverage.
And you should use a coding guideline which makes it easy to detect such problems by review. Maybe use "m_" for class vars or "_var" for parameters or whatever you prefer. Var names with only a list of letters instead of speaking names is a not so well.

C++ Range-V3 dividing an audio stream into Chunks

I am reading a wav file,and pushing the data in a std::array in the end.
I need to make some operation on the chunks of data. So I thought this is a good opportunity to learn Eric Niebler's ranges.
I saw view_facade in manual page under "custom ranges" section but than I saw this question: link . Now I am not sure how to make a custom range class. Can anybody help me about that? The code below shows what I am trying to achieve.
#include <iostream>
#include <range/v3/all.hpp>
using namespace ranges;
using namespace std;
struct A
{
static constexpr size_t MAX_SIZE = 100000;
A ()
{
for ( size_t i = 0; i < MAX_SIZE; i++)
data[i] = i;
size = MAX_SIZE;
}
auto begin() const { return data.begin(); }
auto end() const { return data.end(); }
std::array< double , MAX_SIZE > data;
size_t size;
};
int main()
{
A instance;
RANGES_FOR(auto chunk, view::all(instance) | view::chunk(256)) {
}
return 0;
}
Part of compile output:
14:47:23: Running steps for project tryOuts...
14:47:23: Configuration unchanged, skipping qmake step.
14:47:23: Starting: "C:\Qt\Tools\mingw491_32\bin\mingw32-make.exe"
C:/Qt/Tools/mingw491_32/bin/mingw32-make -f Makefile.Debug
mingw32-make[1]: Entering directory 'C:/Users/Erdem/Documents/build-tryOuts-Desktop_Qt_5_4_2_MinGW_32bit-Debug'
g++ -c -pipe -fno-keep-inline-dllexport -std=gnu++1y -pthread -lpthread -O3 -g -frtti -Wall -Wextra -fexceptions -mthreads -DUNICODE -I"..\tryOuts" -I"." -I"..\..\..\..\range-v3-master\include" -I"D:\cvOutNoIPP\install\include" -I"..\..\..\..\Qt\5.4\mingw491_32\mkspecs\win32-g++" -o debug\main.o ..\tryOuts\main.cpp
In file included from ..\..\..\..\range-v3-master\include/range/v3/utility/iterator.hpp:28:0,
from ..\..\..\..\range-v3-master\include/range/v3/begin_end.hpp:24,
from ..\..\..\..\range-v3-master\include/range/v3/core.hpp:17,
from ..\..\..\..\range-v3-master\include/range/v3/all.hpp:17,
from ..\tryOuts\main.cpp:2:
..\..\..\..\range-v3-master\include/range/v3/utility/basic_iterator.hpp:445:22: error: 'constexpr const T& ranges::v3::basic_mixin<Cur>::get() const' cannot be overloaded
T const &get() const noexcept
^
------------ Update -------------------------------------------
If I add
CONFIG += c++14 the code almost compiles except auto return type deduction errors below :
main.cpp:22: deduced return type only available with -std=c++1y or -std=gnu++1y
to avoid those errors I am using CONFIG += c++1y.But in this case I am getting bunch of errors that I post in first place. I know from D language so called "Voldemort Types" are important, I don't want to give up return type deduction. Which flag in gcc should I use?
I'm still learning the range library myself, but my understanding is that things that expose STL-compatible begin() and end() methods can be used as a view. So for example, with your Reader class you could have
struct Reader {
// ...
auto begin() const { return rawData.begin(); }
auto end() const { return rawData.end(); }
};
You could then use view::all() to create a view around the Reader, something like
Reader r;
RANGES_FOR(auto chunk, view::all(r) | view::chunk(256)) {
...
}
As I say, I'm still learning the library myself, but hopefully this will help.

STL push_back optimize cause array subscript is above array bounds

Test environment:
CentOS 7.0 g++ 4.8.2
Arch Linux g++ 4.9.0 20140604 (prerelease)
Arch Linux g++ 4.9.1
Compile command cases:
PASS: g++ -Wall t.cpp
FAIL: g++ -Wall -O2 t.cpp
PASS: g++ -Wall -O2 t.cpp # and replace 2 with 3 on line 13
PASS: g++ -Wall -O2 t.cpp # and comment out line 14
PASS: g++ -Wall -O2 --std=c++11 t.cpp # for g++ 4.8/4.9
The FAIL message:
t.cpp: In member function ‘void std::vector<_Tp, _Alloc>::_M_insert_aux(std::vecto
<_Tp, _Alloc>::iterator, const _Tp&) [with _Tp = Object; _Alloc = std::allocator<Ob
ject>; std::vector<_Tp, _Alloc>::iterator = __gnu_cxx::__normal_iterator<Object*, s
td::vector<Object> >; typename std::_Vector_base<_Tp, _Alloc>::pointer = Object*]’
t.cpp:17:15: warning: array subscript is above array bounds [-Warray-bounds]
~Object() {};
^
t.cpp:17:15: warning: array subscript is above array bounds [-Warray-bounds]
t.cpp
#include <vector>
class TestCls {
public:
TestCls() {};
virtual ~TestCls() {};
};
class TestCls1 : public TestCls
{
};
class Object {
public:
TestCls m_member[2];
TestCls1 m_member1[2]; // LINE 13, if change to [3] it works.
TestCls1 m_member2[2]; // LINE 14, if comment out this line, it works.
Object() {};
~Object() {}; // LINE 17 the warning line
};
class Container {
public:
std::vector<Object> m_obj;
Container() {};
~Container() {};
};
int main() {
Container con;
Object obj;
con.m_obj.push_back(obj);
}
This is a type of bogus warning generated by GCC due to issues with Value Range Propagation (which is the middle-end pass that generates array bounds warnings) interacting with the various loop optimizer passes (such as loop peeling and loop unrolling). As is mentioned in the various bugzillas linked, these represent missed optimization opportunities as well, but the underlying issue (or issues) in VRP have proved elusive for the GCC developers. That said, reporting this occurrence to the GCC Bugzilla is a good idea, especially since you have a MWE at hand.
I found a solution, but I don't know the reason.
// ...
class Object {
public:
// ...
~Object();
};
Object::~Object() {}; // move to outside LINE 19
//...
gcc -Wall enables all compiler's warning messages. This option should
always be used, in order to generate better code.
So, try delete -Wall. Example:
with -Wall http://goo.gl/d4cces
without -Wall http://goo.gl/4vY2Un