This is an archive of the discontinued LLVM Phabricator instance.

Change behavior with zero-sized static array extents
ClosedPublic

Authored by aaron.ballman on Jul 9 2020, 1:00 PM.

Details

Summary

Currently, Clang diagnoses this code by default: void f(int a[static 0]); saying that "static has no effect on zero-length arrays" and this diagnostic is accurate for our implementation.

However, static array extents require that the caller of the function pass a nonnull pointer to an array of *at least* that number of elements, but it can pass more (see C17 6.7.6.3p6). Given that we allow zero-sized arrays as a GNU extension and that it's valid to pass more elements than specified by the static array extent, I think we should support zero-sized static array extents with the usual semantics because it can be useful, as pointed out to me on Twitter (https://twitter.com/rep_stosq_void/status/1280892279998291973):

void my_bzero(char p[static 0], int n);
my_bzero(&c+1, 0); //ok
my_bzero(t+k,n-k); //ok, pattern from actual code

Diff Detail

Event Timeline

aaron.ballman created this revision.Jul 9 2020, 1:00 PM
rjmccall added inline comments.Jul 9 2020, 2:12 PM
clang/lib/CodeGen/CGCall.cpp
2521

Isn't the old logic still correct? If the element size is static and the element count is positive, the argument is dereferenceable out to their product; otherwise it's nonnull if null is the zero value and we aren't semantically allowing that to be a valid pointer.

aaron.ballman marked an inline comment as done.Jul 10 2020, 4:04 AM
aaron.ballman added inline comments.
clang/lib/CodeGen/CGCall.cpp
2521

I was questioning this -- I didn't think the old logic was correct because it checks that the array is in address space 0, but the nonnull-ness should apply regardless of address space (I think). The point about valid null pointers still stands, though. Am I misunderstanding the intended address space behavior?

rjmccall added inline comments.Jul 10 2020, 10:22 AM
clang/lib/CodeGen/CGCall.cpp
2521

I believe LLVM's nonnull actually always means nonzero. static just tells us that the address is valid, so (1) we always have to suppress the attribute under NullPointerIsValid and (2) we have the suppress the attribute if the null address is nonzero, because the zero address could still be valid in that case. The way the existing code is implementing the latter seems excessively conservative about non-standard address spaces, since we might know that they still use a zero null pointer; more importantly, it seems wrong in the face of an address space that lowers to LLVM's address space 0 but doesn't use a zero null pointer. You can call getTargetInfo().getNullPointerValue(ETy.getAddressSpace()) == 0 to answer this more correctly.

aaron.ballman marked an inline comment as done.

Updated based on review feedback.

clang/lib/CodeGen/CGCall.cpp
2521

Ah, I see! Thank you for the explanation -- I wasn't aware that null could be a valid address in other address spaces, but that makes sense.

rjmccall accepted this revision.Jul 10 2020, 12:47 PM

Thanks, LGTM.

clang/lib/CodeGen/CGCall.cpp
2521

(the zero representation, not null)

This revision is now accepted and ready to land.Jul 10 2020, 12:47 PM
aaron.ballman marked an inline comment as done.

Thanks for the review, I've gone ahead and committed in 006c49d890da633d1ce502117fc2a49863cd65b7

clang/lib/CodeGen/CGCall.cpp
2521

Agreed -- sorry for being imprecise when it mattered.