5

I have the following test case:

testcase("[room] exits") {
    auto [center, east, north, south, west] = make_test_rooms();

    check_eq(center->east(), east);
    check_eq(center->north(), north);
    check_eq(center->south(), south);
    check_eq(center->west(), west + 1);
}

When I compile it, clang++ (clang version 5.0.1 (tags/RELEASE_501/final)) reports:

room.cpp:52:7: note: Value stored to '[center, east, north, south, west]' during its initialization is never read

In the code above, testcase and check_eq are macros defined for the doctest unit testing package that expand to DOCTEST_TEST_CASE() (some kind of self-registering variable+function pair) and DOCTEST_CHECK_EQ (basically, "assert a == b", with magic handling).

I know this code is being executed, since the west + 1 is a deliberately-introduced error. When I run my tests, I get a failure message like this one:

===============================================================================
/.../room.cpp(51)
TEST CASE:  [room] exits

/.../room.cpp(57) ERROR!
  CHECK_EQ( center->west(), west + 1 )
with expansion:
  CHECK_EQ( 0x00007fd6f1d011a0, 0x00007fd6f1d011f8 )

As far as I can see, I am using all of the values in the structured binding: center appears on the left of my checks, and north, south, east, west appear on the right. Why is clang++ reporting something as "never read"?

Update

Here is code that reproduces the issue. I run this command line (taken from the output of make VERBOSE=1 and reduced):

$ /opt/local/bin/cmake -E __run_co_compile --tidy=/opt/local/bin/clang-tidy --source=test.cpp -- /opt/local/bin/clang++  -g -std=gnu++1z -o test.cpp.o -c test.cpp
/Users/austin/Code/agb/test.cpp:12:7: warning: Value stored to '[a, b, c]' during its initialization is never read [clang-analyzer-deadcode.DeadStores]
        auto [a,b,c] = foo();
             ^
/Users/austin/Code/agb/test.cpp:12:7: note: Value stored to '[a, b, c]' during its initialization is never read

I used this source file as test.cpp:

#include <tuple>

static std::tuple<int, int, int>
foo()
{
    return {1,2,3};
}

bool
test()
{
    auto [a,b,c] = foo();

    return a<b and b<c;
}
aghast
  • 14,785
  • 3
  • 24
  • 56
  • 2
    false positive? – bolov Jan 23 '18 at 23:56
  • @bolov I hope that's the case, I guess. But the whole thing is new enough to me that I'm willing to invite much-more-clueful people to explain what's really going on. – aghast Jan 24 '18 at 00:00
  • 1
    clang bug, please report. Note that it's telling you that the underlying object isn't read, not each of its destructured components. – Barry Jan 24 '18 at 00:27
  • For completeness can you post enough code so that someone else could copy-paste it into a compiler to reproduce it, and also the full clang warning? – AndyG Jan 24 '18 at 12:49
  • @AndyG: updated – aghast Jan 24 '18 at 20:11
  • @AustinHastings: Thanks. What happens if you remove the `--tidy` option from your build? – AndyG Jan 24 '18 at 20:25
  • Not sure how to do that, since there's no mention of --tidy in any of my files. But when I strip it from the command line, I get "__run_co_compile missing command to run. Looking for one or more of the following:" (plus a list). – aghast Jan 24 '18 at 20:43

1 Answers1

-2

In the clang analyzer faq this is considered a common false positive:

Q: How do I tell the static analyzer that I don't care about a specific dead store?

When the analyzer sees that a value stored into a variable is never used, it's going to produce a message similar to this one:

Value stored to 'x' is never read

You can use the (void)x; idiom to acknowledge that there is a dead store in your code but you do not want it to be reported in the future.

There's no use reasoning about why it's a false positive. The warning can disappear/reappear with subtle changes to the code or between versions of Clang.

user167921
  • 330
  • 1
  • 7