Following code in MSVC generates warning about assignment in conditional expression.
https://godbolt.org/z/i_rwY9
int main()
{
int a;
if ((a = 5)) {
return 1;
}
return a;
}
Note that I tried to use the double () around if since that makes the warning go away with g++, but I do not know how to make it go away in msvc without extracting the assignment from condition.
Is there a way to nudge msvc to figure out that this assignment is intentional?
I know I can use pragmas to disable this warning, but pattern is very common so I would like to get a solution without pragmas if one exists.
The MSVC compiler will give this warning unless you can convince it that you really do know what you're doing. Adding at least one 'real' logical test will achieve this:
int main()
{
int a;
if ((a = 5) != 0) {
return 1;
}
return a;
}
Note that the constant 5 can readily be replaced with any variable or valid expression: adding the explicit != 0 test does nothing to actually change the outcome of the code (and it is unlikely to change the generated assembly).
Related
I have some issues with the CMonthCalCtrl control and modernizing my code. The first problem is related to the BOLDDAY macro.
This macro is used to adjust day states (making specific dates bold on the calendar) and the concept is described in detail here. As documented, you need to define a macro:
#define BOLDDAY(ds, iDay) if(iDay > 0 && iDay < 32) \
(ds) |= (0x00000001 << (iDay-1))
Here is my code that uses this macro so that you have some context:
void CMeetingScheduleAssistantDlg::InitDayStateArray(int iMonthCount, LPMONTHDAYSTATE pDayState, COleDateTime datStart)
{
int iMonth = 0;
COleDateTimeSpan spnDay;
CString strKey;
SPECIAL_EVENT_S *psEvent = nullptr;
if (pDayState == nullptr)
return;
memset(pDayState, 0, sizeof(MONTHDAYSTATE)*iMonthCount);
if (m_pMapSPtrEvents == nullptr && m_Reminders.Count() == 0)
{
return;
}
spnDay.SetDateTimeSpan(1, 0, 0, 0);
auto datDay = datStart;
const auto iStartMonth = datStart.GetMonth();
auto iThisMonth = iStartMonth;
auto iLastMonth = iThisMonth;
do
{
strKey = datDay.Format(_T("%Y-%m-%d"));
if (m_pMapSPtrEvents != nullptr)
{
psEvent = nullptr;
m_pMapSPtrEvents->Lookup(strKey, reinterpret_cast<void*&>(psEvent));
if (psEvent != nullptr)
{
BOLDDAY(pDayState[iMonth], datDay.GetDay());
}
}
if (m_Reminders.HasReminder(datDay))
{
BOLDDAY(pDayState[iMonth], datDay.GetDay());
}
datDay = datDay + spnDay;
iThisMonth = datDay.GetMonth();
if (iThisMonth != iLastMonth)
{
iLastMonth = iThisMonth;
iMonth++;
}
} while (iMonth < iMonthCount);
}
Everywhere I use this BOLDDAY macro I get a code analysis warning (C26481):
warning C26481: Don't use pointer arithmetic. Use span instead (bounds.1).
It is not clear to me if the problem is with the BOLDDAY macro or my own code?
Update
I still get the warning when I turn the macro into a function:
Update 2
If it helps, I currently call the InitDayStateArray function in the following ways:
Method 1:
void CMeetingScheduleAssistantDlg::SetDayStates(CMonthCalCtrl &rCalendar)
{
COleDateTime datFrom, datUntil;
const auto iMonthCount = rCalendar.GetMonthRange(datFrom, datUntil, GMR_DAYSTATE);
auto pDayState = new MONTHDAYSTATE[iMonthCount];
if (pDayState != nullptr)
{
InitDayStateArray(iMonthCount, pDayState, datFrom);
VERIFY(rCalendar.SetDayState(iMonthCount, pDayState));
delete[] pDayState;
}
}
Method 2
void CMeetingScheduleAssistantDlg::OnGetDayStateEnd(NMHDR* pNMHDR, LRESULT* pResult)
{
NMDAYSTATE* pDayState = reinterpret_cast<NMDAYSTATE*>(pNMHDR);
MONTHDAYSTATE mdState[3]{}; // 1 = prev 2 = curr 3 = next
const COleDateTime datStart(pDayState->stStart);
if (pDayState != nullptr)
{
InitDayStateArray(pDayState->cDayState, &mdState[0], datStart);
pDayState->prgDayState = &mdState[0];
}
if (pResult != nullptr)
*pResult = 0;
}
Perhaps if the container for the LPMONTHDAYSTATE information is tweaked somehow it would contribute to resolve this span issue?
Sample code provided by Microsoft used to be published as code that compiles both with a C and C++ compiler. That limits availability of language features, frequently producing code that particularly C++ clients shouldn't be using verbatim.
The case here being the BOLDDAY function-like macro, that's working around not having reference types in C. C++, on the other hand, does, and the macro can be replaced with a function instead:
void bold_day(DWORD& day_state, int const day) noexcept {
if (day > 0 && day < 32) {
day_state |= (0x00000001 << (day - 1));
}
}
Using this function in place of the BOLDDAY macro silences the C26481 diagnostic.
While that works, I'm at a complete loss to understand where the compiler is seeing pointer arithmetic in the macro version. Regardless, replacing a function-like macro with an actual function (or function template) where possible is always desirable.
Update
Things are starting to make sense now. While replacing the function-like macro with a function, as suggested above, is desirable, it will not resolve the issue. My test happened to have used pDayState[0] which still raises C26481 for the macro, but not for the function. Using pDayState[1] instead, the diagnostic is raised in either case.
Let's put the pieces of the puzzle together: Recall that the array subscript expression p[N] is exactly identical to the expression *(p + N) when p is a pointer type and N an integral type. That explains why the compiler is complaining about "pointer arithmetic" when it sees pDayState[iMonth].
Solving that is fairly straight forward. As suggested by the diagnostic, use a std::span (requires C++20). The following changes to InitDayStateArray() make the C26481 diagnostic go away:
void CMeetingScheduleAssistantDlg::InitDayStateArray(int iMonthCount,
LPMONTHDAYSTATE pDayState,
COleDateTime datStart)
{
std::span const day_month_state(pDayState, iMonthCount);
// ...
// memset(pDayState, 0, sizeof(MONTHDAYSTATE)*iMonthCount);
std::fill(begin(day_month_state), end(day_month_state), 0);
// ...
do
{
// ...
{
bold_day(day_month_state[iMonth], datDay.GetDay());
}
}
if (m_Reminders.HasReminder(datDay))
{
bold_day(day_month_state[iMonth], datDay.GetDay());
}
// ...
} while (iMonth < day_month_state.size());
}
A std::span "describes an object that can refer to a contiguous sequence of objects". It takes the decomposed pointer and size arguments that describe an array and reunites them into a single object, recovering the full fidelity of the array.
That sounds great. But remember, this is C++, and there's a caveat: Just like its evil C++17 ancestor std::string_view, a std::span is an unhesitating factory for dangling pointers. You can freely pass them around, and hang on to them far beyond the referenced data being alive. And this is guaranteed for every specialization, starting with C++23.
The other issue is, that addressing this one diagnostic now has several others pop out of nowhere, suggesting that std::span isn't good enough, and gsl::span should be used instead. Addressing those would probably warrant another Q&A altogether.
I am actually working on some changes to my application and klocwork keeps complaining me about one issue:
I have a struct, say
Struct A
{
long x;
bool b;
}
I have a pointer and it is assigned a return value from another function:
A* z= (A*) function.get();
if(!z->x)
{
z->x= somevalue;
}
The klocwork keeps pointing to if(!z->x), saying that z is explicitly dereferenced.
Although my application works fine now, will it affect my application in a drastic way in future?
You need to first check whether z is non-null before deferencing z and checking for z->x.
if(z && !z->k)
...
I'm new to D, and I was wondering whether it's possible to conveniently do compile-time-checked duck typing.
For instance, I'd like to define a set of methods, and require that those methods be defined for the type that's being passed into a function. It's slightly different from interface in D because I wouldn't have to declare that "type X implements interface Y" anywhere - the methods would just be found, or compilation would fail. Also, it would be good to allow this to happen on any type, not just structs and classes. The only resource I could find was this email thread, which suggests that the following approach would be a decent way to do this:
void process(T)(T s)
if( __traits(hasMember, T, "shittyNameThatProbablyGetsRefactored"))
// and presumably something to check the signature of that method
{
writeln("normal processing");
}
... and suggests that you could make it into a library call Implements so that the following would be possible:
struct Interface {
bool foo(int, float);
static void boo(float);
...
}
static assert (Implements!(S, Interface));
struct S {
bool foo(int i, float f) { ... }
static void boo(float f) { ... }
...
}
void process(T)(T s) if (Implements!(T, Interface)) { ... }
Is is possible to do this for functions which are not defined in a class or struct? Are there other/new ways to do it? Has anything similar been done?
Obviously, this set of constraints is similar to Go's type system. I'm not trying to start any flame wars - I'm just using D in a way that Go would also work well for.
This is actually a very common thing to do in D. It's how ranges work. For instance, the most basic type of range - the input range - must have 3 functions:
bool empty(); //Whether the range is empty
T front(); // Get the first element in the range
void popFront(); //pop the first element off of the range
Templated functions then use std.range.isInputRange to check whether a type is a valid range. For instance, the most basic overload of std.algorithm.find looks like
R find(alias pred = "a == b", R, E)(R haystack, E needle)
if (isInputRange!R &&
is(typeof(binaryFun!pred(haystack.front, needle)) : bool))
{ ... }
isInputRange!R is true if R is a valid input range, and is(typeof(binaryFun!pred(haystack.front, needle)) : bool) is true if pred accepts haystack.front and needle and returns a type which is implicitly convertible to bool. So, this overload is based entirely on static duck typing.
As for isInputRange itself, it looks something like
template isInputRange(R)
{
enum bool isInputRange = is(typeof(
{
R r = void; // can define a range object
if (r.empty) {} // can test for empty
r.popFront(); // can invoke popFront()
auto h = r.front; // can get the front of the range
}));
}
It's an eponymous template, so when it's used, it gets replaced with the symbol with its name, which in this case is an enum of type bool. And that bool is true if the type of the expression is non-void. typeof(x) results in void if the expression is invalid; otherwise, it's the type of the expression x. And is(y) results in true if y is non-void. So, isInputRange will end up being true if the code in the typeof expression compiles, and false otherwise.
The expression in isInputRange verifies that you can declare a variable of type R, that R has a member (be it a function, variable, or whatever) named empty which can be used in a condition, that R has a function named popFront which takes no arguments, and that R has a member front which returns a value. This is the API expected of an input range, and the expression inside of typeof will compile if R follows that API, and therefore, isInputRange will be true for that type. Otherwise, it will be false.
D's standard library has quite a few such eponymous templates (typically called traits) and makes heavy use of them in its template constraints. std.traits in particular has quite a few of them. So, if you want more examples of how such traits are written, you can look in there (though some of them are fairly complicated). The internals of such traits are not always particularly pretty, but they do encapsulate the duck typing tests nicely so that template constraints are much cleaner and more understandable (they'd be much, much uglier if such tests were inserted in them directly).
So, that's the normal approach for static duck typing in D. It does take a bit of practice to figure out how to write them well, but that's the standard way to do it, and it works. There have been people who have suggested trying to come up with something similar to your Implements!(S, Interface) suggestion, but nothing has really come of that of yet, and such an approach would actually be less flexible, making it ill-suited for a lot of traits (though it could certainly be made to work with basic ones). Regardless, the approach that I've described here is currently the standard way to do it.
Also, if you don't know much about ranges, I'd suggest reading this.
Implements!(S, Interface) is possible but did not get enough attention to get into standard library or get better language support. Probably if I won't be the only one telling it is the way to go for duck typing, we will have a chance to have it :)
Proof of concept implementation to tinker around:
http://dpaste.1azy.net/6d8f2dc4
import std.traits;
bool Implements(T, Interface)()
if (is(Interface == interface))
{
foreach (method; __traits(allMembers, Interface))
{
foreach (compareTo; MemberFunctionsTuple!(Interface, method))
{
bool found = false;
static if ( !hasMember!(T, method) )
{
pragma(msg, T, " has no member ", method);
return false;
}
else
{
foreach (compareWhat; __traits(getOverloads, T, method))
{
if (is(typeof(compareTo) == typeof(compareWhat)))
{
found = true;
break;
}
}
if (!found)
{
return false;
}
}
}
}
return true;
}
interface Test
{
bool foo(int, double);
void boo();
}
struct Tested
{
bool foo(int, double);
// void boo();
}
pragma(msg, Implements!(Tested, Test)());
void main()
{
}
int count = itemsToValidate.Count;
foreach(var item in itemsToValidate)
{
item.ValidateAsync += (x, y) => this.HandleValidate(ref count);
}
private void HandleValidate(ref int x)
{
--x;
if (x == 0)
{
// All items are validated.
}
}
For the above code resharper complained "Access to Modified Closure". Doesn't do that if I change that to type of object. Why is this a closure, even though I am passing by ref ?
This happens all the time
ReSharper is warning you that count is implicitly captured by the lambdas that you are assigning as "validation complete" event handlers, and that its value may well change between the time the lambda is created (i.e. when you assign the event handler) and the time when it is invoked. If this happens, the lambda will not see the value one would intuitively expect.
An example:
int count = itemsToValidate.Count;
foreach(var item in itemsToValidate)
{
item.ValidateAsync += (x, y) => this.HandleValidate(ref count);
}
// afterwards, at some point before the handlers get invoked:
count = 0;
In this instance the handlers will read the value of count as 0 instead of itemsToValidate.Count -- which might be called "obvious", but is surprising and counter-intuitive to many developers not familiar with the mechanics of lambdas.
And we usually solve it like this
The usual solution to "shut R# up" is to move the captured variable in an inner scope, where it is much less accessible and R# can be prove that it cannot be modified until the lambda is evaluated:
int count = itemsToValidate.Count;
foreach(var item in itemsToValidate)
{
int inner = count; // this makes inner impossible to modify
item.ValidateAsync += (x, y) => this.HandleValidate(ref inner);
}
// now this will of course not affect what the lambdas do
count = 0;
But your case is special
Your particular case is a comparatively rare one where you specifically want this behavior, and using the above trick would actually make the program behave incorrectly (you need the captured references to point to the same count).
The correct solution: disable this warning using the special line comments that R# recognizes.
When I write this code and compile with /W4
long r;
__try { r = 0; }
__finally { }
return r;
I get:
warning C4701: potentially uninitialized local variable 'r' used
Why does this happen?
The compiler can't be sure the code inside of the try block will successfully run. In this case it always will, but if there's additional code in the try block r = 0 may never execute. In that case r is uninitialized hence the error.
It's no different than if you said:
long r;
if(something) {
r = 0;
}
return r;
(where 'something' is pretty much anything other than a constant true value).
Because long r; creates r but it is not initialized; it is null.
So it warns you that the variable is not initialized. In certain cases it will cause Null Pointers.
Adding this as an answer as it is of more interest than in just a comment:
The error never appeared until a labeled-statement: was inserted before the variable. Remove the goto & associated label and there is no warning.
This might have something to do with how namespace pathing is setup with a similar warning C4702 generated on a line number before the insertion of a goto block. MVCE still to be generated if anyone is interested.