This is an archive of the discontinued LLVM Phabricator instance.

[clang][Interp] Handle sizeof() expressions
ClosedPublic

Authored by tbaeder on Sep 15 2022, 3:47 AM.

Details

Summary

Handle sizeof expressions.

I was a bit unsure here about alignment, but the rest is pretty self-explanatory I think.

Diff Detail

Event Timeline

tbaeder created this revision.Sep 15 2022, 3:47 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 15 2022, 3:47 AM
tbaeder requested review of this revision.Sep 15 2022, 3:47 AM
Herald added a project: Restricted Project. · View Herald TranscriptSep 15 2022, 3:47 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript
erichkeane added inline comments.Sep 15 2022, 7:33 AM
clang/lib/AST/Interp/Context.cpp
134 ↗(On Diff #460355)

This function seems pretty large for something you should be able to pick up via ASTContext::getTypeSize or ASTContext::getTypeSizeInChars or ASTContext::getTypeSizeInCharsIfKnown.

149 ↗(On Diff #460355)

Typically, I prefer we use llvm::None here.

tbaeder updated this revision to Diff 460409.Sep 15 2022, 7:48 AM

Didn't now I could just get that information from the ASTContext, nice. Thanks.

erichkeane added inline comments.Sep 15 2022, 7:49 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
289

You probably want getTypeSizeInChars. getTypeSize returns it in bits, so this would give the wrong answer. You should probably add some tests to make sure the values you are getting back are sane (like char is 1, etc).

tbaeder added inline comments.Sep 15 2022, 7:53 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
289

Yeah, right. I explicitly didn't compare with fixed values when writing the tests so I don't run into the usual problems, but they wouldn't caught this problem...

tbaeder updated this revision to Diff 460412.Sep 15 2022, 8:01 AM
erichkeane accepted this revision.Sep 15 2022, 8:05 AM
This revision is now accepted and ready to land.Sep 15 2022, 8:05 AM
shafik added inline comments.Sep 15 2022, 8:41 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

I notice that HandleSizeof special cases void and function types.

clang/test/AST/Interp/literals.cpp
85

Test for void and a function type too.

erichkeane requested changes to this revision.Sep 15 2022, 8:50 AM
erichkeane added inline comments.
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

OOOH, DEFINITELY make sure you test function types here, and figure out how HandleSizeof does it.

BUT, I think 'void' should error/be an invalid before we get here?

ALSO, now that I think further, I'm sure @aaron.ballman has a bunch of runtime-evaluated sizeof examples to share around vlas.

This revision now requires changes to proceed.Sep 15 2022, 8:50 AM
aaron.ballman added inline comments.Sep 15 2022, 8:56 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

I was just about to comment about everyone's favorite horrible C++ extension. :-D We should make sure we properly reject code like:

void func() {
  int n = 12;
  constexpr int oofda = sizeof(int[n++]);
}

while accepting code like:

consteval int foo(int n) {
  return sizeof(int[n]);
}
constinit int var = foo(5);
shafik added inline comments.Sep 15 2022, 4:17 PM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

Note, that clang currently treats that as ill-formed and there is divergence with how gcc and clang treat the constexpr case as well.

So if we are going to say we want this to work then we should file a bug against clang.

I can see that HandleSizeOf() uses 1 for void and function types as a gcc extension, but I can't reproduce that: https://godbolt.org/z/njG9zh6PM

clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

Right, the second example doesn't seem to be accepted by current clang.

tbaeder updated this revision to Diff 460648.Sep 15 2022, 11:07 PM
erichkeane added inline comments.Sep 16 2022, 6:23 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

Documentation for isConstantSizedType says it isn't legal to call it on dependent or incomplete types. so this probably needs to be:

if (ArgType->isDependentType() || ArgType->isIncompleteType() || !ArgType->isConstantSizedType())

In roughly that order.

I can see that HandleSizeOf() uses 1 for void and function types as a gcc extension, but I can't reproduce that: https://godbolt.org/z/njG9zh6PM

C code allows the construct: https://godbolt.org/z/5KfY9PPqa

Worth keeping in mind: C2x has support for constexpr objects, so we are going to have to care about this. We've not started doing the work to enable constexpr for C yet, so there's some wiggle room in terms of *when* we have to care, but we should try to keep C in mind when working on the new interpreter as much as is reasonable.

clang/lib/AST/Interp/Boolean.h
49–53

At some point, do we want to rename this (and int) to use uint32_t/int32_t?

clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

I'd add both of the test cases, put a FIXME comment above the one that currently fails but we'd like to see succeed. We can work on fixing that fixme whenever we get around to it.

clang/test/AST/Interp/literals.cpp
91

This test got me thinking about another test case:

struct S {
  void func();
};

constexpr void (S::*Func)() = &S::func;
static_assert(sizeof(Func) == sizeof(&S::func), "");

(Can't test this one against nullptr because sizeof(nullptr) is not telling you the size of a pointer to member function despite nullptr being convertible to one.)

tbaeder marked an inline comment as done.Sep 16 2022, 7:35 AM
tbaeder added inline comments.
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

isDependentType() is implicitly assumed, isn't it? ExprConstant.cpp asserts everywhere that neither types nor expressions are (value)dependent. It also doesn't handle that in HandleSizeof.

clang/test/AST/Interp/literals.cpp
91

I'll add it, but might have to #if 0 it out for the same reason I had to push https://reviews.llvm.org/rGa8843643cd75d0e93ebcf3f30b470d2b8e59868d

erichkeane added inline comments.Sep 16 2022, 7:42 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

Ok, good to know about that then. I saw you'd tested for isDependentType above, but isConstantSizedType would assert in that case.

clang/test/AST/Interp/literals.cpp
91

What is the cause of that leak? Is that something we should be fixing ASAP so we can enable these tests?

tbaeder updated this revision to Diff 460758.Sep 16 2022, 7:48 AM
tbaeder added inline comments.Sep 16 2022, 7:50 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

Yup, I switched the order around.

clang/test/AST/Interp/literals.cpp
91

IIRC it was creating a Record for the RecordDecl but never freeing it or something similar. The test case didn't do anything anyway since records aren't implemented yet. The only difference now is that I won't notice automatically that a test case suddenly starts working when I implement records.

tbaeder added inline comments.Sep 16 2022, 7:59 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
290

... and of course I run into an incomplete type assertion with the sizeof(void) example when the file type is C.

tbaeder updated this revision to Diff 460766.Sep 16 2022, 8:03 AM
tbaeder marked 11 inline comments as done.
tbaeder added inline comments.Sep 16 2022, 12:24 PM
clang/lib/AST/Interp/Boolean.h
49–53

I can do that as a follow-up commit if you want.

erichkeane added inline comments.Sep 16 2022, 12:30 PM
clang/lib/AST/Interp/Boolean.h
49–53

Please do, while we don't currently compile on any platforms with non-32 bit int/unsigned, if we ever tried to this would fail with multiple definitions somewhere.

tbaeder marked an inline comment as done.Sep 16 2022, 11:59 PM

@erichkeane Anything else still missing here?

erichkeane accepted this revision.Sep 19 2022, 5:58 AM

I think we're OK for now, LGTM.

This revision is now accepted and ready to land.Sep 19 2022, 5:58 AM