erichkeane added a comment.

>> I think you've misunderstood; that is not required. Though with the design 
>> as-is, it might make sense to restrict this to being C++-only, given that 
>> there's not really a way to effectively use this from C.

Ah, I see the example in SemaCXX.  its sad we can't do this from C, I would 
consider the use case of `__builtin_dump_struct` to be very handy in C.

I guess I think I would want to start off with, "what do we see the 'usecase' 
of these builtins" being.  `__builtin_dump_struct` to me seems to have a pretty 
clear and semantically enforced one: its useful to printf it for debugging 
purposes.

This seems to be more useful-enough that it leaves me feeling like users would 
very quickly fall into, "man, I wish this did more" because of it.  Its just a 
shame we can't get SG7 to work quicker :)



================
Comment at: clang/docs/LanguageExtensions.rst:2434
+
+     bool print(int arg1, int arg2, std::initializer_list<Field> fields) {
+       for (auto f : fields) {
----------------
rsmith wrote:
> erichkeane wrote:
> > I'm curious as to the need for the 'arg1' and 'arg2'?  Also, what is the 
> > type of the 'fields' array that works in C?
> This is aimed to fix a major deficiency in `__builtin_dump_struct`, that 
> there's no way to pass information into its callback (other than stashing it 
> in TLS).
> 
> As noted in the patch description, this builtin is not especially usable in 
> C. I'm not sure whether that's fixable, given the very limited 
> metaprogramming support in C.
Presumably one could also put it in the functor for the callback, or even as a 
capture in the lambda.  Though, I'm not positive I see the VALUE to passing 
this information, but was just curious as to the intent.


================
Comment at: clang/docs/LanguageExtensions.rst:2437
+         std::cout << f.name;
+         if (f.bitwidth)
+           std::cout << " : " << f.bitwidth;
----------------
rsmith wrote:
> erichkeane wrote:
> > Hmm... what is the type of f.bitwidth?  A zero-length bitwidth is a valid 
> > thing, so having it just be an 'int' doesn't seem workable.
> It's a `size_t`. There are no zero-size bitfield members. (Unnamed bitfield 
> aren't members, so are excluded here.) In any case, you can tell the 
> difference between a bitfield and a regular member by the length of the 
> initialiser list; we don't pass a bit width for non-bit-field members.
>>There are no zero-size bitfield members. (Unnamed bitfield aren't members, so 
>>are excluded here.)
Hrm... Semantically YES, lexically I'm not sure folks make that 
differentiation.  One issue with skipping 'unnamed bitfields' is it makes 
something like:

```
struct Foo {
int : 31; // Take up some space so something else could have been put there.
int field : 1; 
int field2 : 2;
};
```
and comparing `sizeof` the type with the output to be... jarring at least.

>> you can tell the difference between a bitfield and a regular member by the 
>> length of the initialiser list;

I see now how you've done that with ctors in C++.  It feels that the way of 
doing this in C is unfortunately quite clunky (in addition, not being able to 
use arbitrary types).


================
Comment at: clang/docs/LanguageExtensions.rst:2462
+to the type to reflect. The second argument ``f`` should be some callable
+expression, and can be a function object or an overload set. The builtin calls
+``f``, passing any further arguments ``args...`` followed by an initializer
----------------
rsmith wrote:
> erichkeane wrote:
> > Is the purpose of the overload set/functor so you can support multiple 
> > types (seeing how the 'base' below works)?  How does this all work in C? 
> > (or do we just do fields in C, since they cannot have the rest?
> > 
> > I wonder if we would be better if we treated this function as a 'callback' 
> > or a 'callback set' that returned a discriminated union of a pre-defined 
> > type that describes what is being returned.  That way it could handle 
> > member functions, static variables, etc.
> This doesn't really work well in C, as noted in the patch description. A set 
> of callbacks might work a bit better across both languages, but I don't think 
> it solves the larger problem that there's no good way to pass type 
> information into a callback in C.
Well, if the callback itself took the discriminated union for each thing, and 
we did 1 callback per base/field/etc, perhaps that would be useful? I just am 
having a hard time seeing this being all that useful in C, which is a shame.




================
Comment at: clang/docs/LanguageExtensions.rst:2471
+
+The initializer list contains the following components:
+
----------------
rsmith wrote:
> erichkeane wrote:
> > I find myself wishing this was a more complete list.
> What else do you want? My goal here was to be able to do what 
> `__builtin_dump_struct` does but without its many arbitrary limitations. From 
> C++, this is enough for that.
I think this is again falling down the "this is close enough to reflection, I 
want reflection" hole :)  I find myself wanting to be able to introspect member 
functions, static variables/functions/etc.


================
Comment at: clang/docs/LanguageExtensions.rst:2473
+
+* For each direct base class, the address of the base class, in declaration
+  order.
----------------
rsmith wrote:
> erichkeane wrote:
> > I wonder if bases should include their virtualness or access specifier.
> I mean, maybe, but I don't have a use case for either. For access in general 
> my leaning is to say that the built-in doesn't get special access rights -- 
> either it can access everything or you'll get an access error if you use it 
> -- in which case including the access for bases and fields doesn't seem 
> likely to be super useful.
I guess it depends on the use case for these builtins.  I saw the 'dump-struct' 
builtin's purpose was for quick & dirty printf-debugging.  At which point the 
format/features were less important than the action.  So from that perspective, 
I would see this having 'special access rights' as sort of a necessity.  

Though again, this is a significantly more general builtin, which comes with 
additional potential use cases.


================
Comment at: clang/lib/Sema/SemaChecking.cpp:420
+    auto *FD = IFD ? IFD->getAnonField() : dyn_cast<FieldDecl>(D);
+    if (!FD || (FD->isUnnamedBitfield() || FD->isAnonymousStructOrUnion()))
+      continue;
----------------
rsmith wrote:
> erichkeane wrote:
> > Losing the unnamed bitfield is unfortunate, and I the 'dump struct' 
> > handles.  As is losing the anonymous struct/union.
> > 
> > Also, how does this handle 'record type' members?  Does the user have to 
> > know the inner type already?  If they already know that much information 
> > about the type, they wouldn't really need this, right?
> If `__builtin_dump_struct` includes unnamed bitfields, that's a bug in that 
> builtin.
> 
> In general, the user function gets given the bases and members with the right 
> types, so they can use an overload set or a template to dispatch based on 
> that type. See the SemaCXX test for a basic example of that.
I thought it did?  For the use case I see `__builtin_dump_struct` having, I 
would think printing the existence of unnamed bitfields to be quite useful.




================
Comment at: clang/test/CodeGenCXX/builtin-reflect-struct.cpp:24
+
+int consume(int, Expected);
+
----------------
rsmith wrote:
> erichkeane wrote:
> > OH! I see now.  This is unfortunately quite limiting by doing it this way.  
> > At this point the user of this builtin is required to know the layout of 
> > the struct before calling the builtin, which seems unfortunate. Despite the 
> > downsides of being just a 'dump function', the other builtin had the 
> > benefit of working on an arbitrary type.
> Well, no, this is set up this way to test code generation. See the SemaCXX 
> test for an example of using this to dump an arbitrary type.
Yep, thanks for that.  I see now how it can be used that way.


================
Comment at: clang/test/SemaCXX/builtin-reflect-struct.cpp:52
+
+struct FieldOrBase {
+  template <typename Base>
----------------
Ah, this is perhaps the example I was looking for.  


================
Comment at: clang/test/SemaCXX/builtin-reflect-struct.cpp:82
+    // Assume it's an integer.
+    T value = t;
+    ConstexprString s = "";
----------------
What would this look like if you needed to look into a union?  Perhaps it would 
be handled similarly to "__is_class"?  In both builtins, its a shame we don't 
have a way to properly handle the 'active member'.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D124221/new/

https://reviews.llvm.org/D124221

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to