This is an archive of the discontinued LLVM Phabricator instance.

[clang][Interp] Array initialization via ImplicitValueInitExpr
ClosedPublic

Authored by tbaeder on Oct 1 2022, 12:34 AM.

Details

Summary

Unfortunately, I have no idea how to test this, the one and only reproducer I have so far is:

#include <array>
constexpr std::array<int, 10> IntArray = {};

which results in a InitListExpr containing a ImplicitValueInitExpr with an array type.

Diff Detail

Event Timeline

tbaeder created this revision.Oct 1 2022, 12:34 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 1 2022, 12:34 AM
tbaeder requested review of this revision.Oct 1 2022, 12:34 AM
Herald added a project: Restricted Project. · View Herald TranscriptOct 1 2022, 12:34 AM
Herald added a subscriber: cfe-commits. · View Herald Transcript

The following also generates an ImplicitValueInitExpr:

template <typename T, unsigned N>
struct B {
  T a[N];
};

int main() {
   constexpr B<int,10> arr = {};
   constexpr int x = arr.a[0];
}
shafik added inline comments.Oct 13 2022, 2:17 PM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
748

I believe you should check ArrayType before you use it.

759

I guess this covers both arrays and class types?

tbaeder updated this revision to Diff 467691.Oct 13 2022, 11:21 PM
tbaeder marked 2 inline comments as done.

Thanks for the reproducer!

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

Yes. But now that I look at it, the check should probably be outside of the loop.

I found a way to get ImplictValueInitExpr for a record: https://godbolt.org/z/Eqf9Gz1G4

I am not sure if we can achieve the same in C++ b/c value init of a class break down to default init or zero init.

I found a way to get ImplictValueInitExpr for a record: https://godbolt.org/z/Eqf9Gz1G4

I am not sure if we can achieve the same in C++ b/c value init of a class break down to default init or zero init.

Does clang generate a default constructor in this case anyway, which the interpreter could use in this case? Or is it support to just memset(0) the entire struct instance?

Ah it's the array filler which we don't handle at all right now :(

@aaron.ballman Do you maybe have a different reproducer or know more about the expected behavior of a ImplicitValueInitExpr for array and record types?

@aaron.ballman Do you maybe have a different reproducer or know more about the expected behavior of a ImplicitValueInitExpr for array and record types?

So here's another reproducer with a record type: https://godbolt.org/z/EhT4oqT3s and here's one with an array type: https://godbolt.org/z/Pbncnq418

My understanding of ImplicitValueInitExpr is that it's used to represent some of the "holes" in the middle of an array/record that need to implicit get some values.

@aaron.ballman Do you maybe have a different reproducer or know more about the expected behavior of a ImplicitValueInitExpr for array and record types?

So here's another reproducer with a record type: https://godbolt.org/z/EhT4oqT3s and here's one with an array type: https://godbolt.org/z/Pbncnq418

My understanding of ImplicitValueInitExpr is that it's used to represent some of the "holes" in the middle of an array/record that need to implicit get some values.

They are inside a struct or array, but not of array or struct type, if I understand correctly. But I see what you're getting at, I guess this should basically go through visitZeroInitializer() (which is currently unused), which should be extended to handle structs and arrays.

@aaron.ballman Do you maybe have a different reproducer or know more about the expected behavior of a ImplicitValueInitExpr for array and record types?

So here's another reproducer with a record type: https://godbolt.org/z/EhT4oqT3s and here's one with an array type: https://godbolt.org/z/Pbncnq418

My understanding of ImplicitValueInitExpr is that it's used to represent some of the "holes" in the middle of an array/record that need to implicit get some values.

They are inside a struct or array, but not of array or struct type, if I understand correctly. But I see what you're getting at, I guess this should basically go through visitZeroInitializer() (which is currently unused), which should be extended to handle structs and arrays.

Ah, yes! That's true, they are inside the struct or array. I'm not certain you can have one *of* struct type in C++ because it's either going to be zeroed or left uninitialized (due to constructors).

tbaeder updated this revision to Diff 469230.Oct 20 2022, 7:45 AM

Thinking about it some more, doesn't make much sense to add all that right now when we don't have a reproducer to test it anyway. I think the patch as it is makes sense and it it's not enough in the future, there's a proper assert in place.

aaron.ballman added inline comments.Oct 20 2022, 8:22 AM
clang/lib/AST/Interp/ByteCodeExprGen.cpp
725

Please spell out the type.

727

Should this be using cast<> as the code below is assuming this pointer will never be null?

728
tbaeder updated this revision to Diff 469243.Oct 20 2022, 8:33 AM
tbaeder marked 3 inline comments as done.
aaron.ballman accepted this revision.Oct 20 2022, 11:04 AM

Aside from a naming quirk, LGTM

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

(Sorry, I hadn't noticed you were using a type name as a variable name before! That sometimes confuses IDEs, so suggesting a different name.)

This revision is now accepted and ready to land.Oct 20 2022, 11:04 AM
tbaeder marked an inline comment as done.Oct 21 2022, 12:50 AM
tbaeder added inline comments.
clang/lib/AST/Interp/ByteCodeExprGen.cpp
725

I can't say I saw that when making the change, but now that I see it, yes, that might've been the reason I used auto here. Anyway, I changed that, thanks.

This revision was automatically updated to reflect the committed changes.
tbaeder marked an inline comment as done.