dblaikie added inline comments.
================
Comment at: clang/bindings/python/clang/cindex.py:1530
+
+ def record_needs_implicit_default_constructor(self):
+ """Returns True if the cursor refers to a C++ record declaration
----------------
aaron.ballman wrote:
> anderslanglands wrote:
> > dblaikie wrote:
> > > aaron.ballman wrote:
> > > > dblaikie wrote:
> > > > > anderslanglands wrote:
> > > > > > dblaikie wrote:
> > > > > > > royjacobson wrote:
> > > > > > > > anderslanglands wrote:
> > > > > > > > > dblaikie wrote:
> > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > > anderslanglands wrote:
> > > > > > > > > > > > > dblaikie wrote:
> > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > royjacobson wrote:
> > > > > > > > > > > > > > > > anderslanglands wrote:
> > > > > > > > > > > > > > > > > royjacobson wrote:
> > > > > > > > > > > > > > > > > > anderslanglands wrote:
> > > > > > > > > > > > > > > > > > > royjacobson wrote:
> > > > > > > > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > > > > > > > aaron.ballman wrote:
> > > > > > > > > > > > > > > > > > > > > > I don't think we should expose any
> > > > > > > > > > > > > > > > > > > > > > of the "needs" functions like this
> > > > > > > > > > > > > > > > > > > > > > -- those are internal
> > > > > > > > > > > > > > > > > > > > > > implementation details of the class
> > > > > > > > > > > > > > > > > > > > > > and I don't think we want to
> > > > > > > > > > > > > > > > > > > > > > calcify that into something we have
> > > > > > > > > > > > > > > > > > > > > > to support forever. As we add
> > > > > > > > > > > > > > > > > > > > > > members to a class, we recalculate
> > > > > > > > > > > > > > > > > > > > > > whether the added member causes us
> > > > > > > > > > > > > > > > > > > > > > to delete defaulted special members
> > > > > > > > > > > > > > > > > > > > > > (among other things), and the
> > > > > > > > > > > > > > > > > > > > > > "needs" functions are basically
> > > > > > > > > > > > > > > > > > > > > > used when the class is completed to
> > > > > > > > > > > > > > > > > > > > > > handle lazily created special
> > > > > > > > > > > > > > > > > > > > > > members. I'm pretty sure that lazy
> > > > > > > > > > > > > > > > > > > > > > creation is not mandated by the
> > > > > > > > > > > > > > > > > > > > > > standard, which is why I think the
> > > > > > > > > > > > > > > > > > > > > > "needs" functions are more of an
> > > > > > > > > > > > > > > > > > > > > > implementation detail.
> > > > > > > > > > > > > > > > > > > > > CC @erichkeane and @royjacobson as
> > > > > > > > > > > > > > > > > > > > > folks who have been in this same area
> > > > > > > > > > > > > > > > > > > > > of the compiler to see if they agree
> > > > > > > > > > > > > > > > > > > > > or disagree with my assessment there.
> > > > > > > > > > > > > > > > > > > > I think so. The 'needs_*' functions
> > > > > > > > > > > > > > > > > > > > query `DeclaredSpecialMembers` and I'm
> > > > > > > > > > > > > > > > > > > > pretty sure it's modified when we add
> > > > > > > > > > > > > > > > > > > > the implicit definitions in the class
> > > > > > > > > > > > > > > > > > > > completion code. So this looks a bit
> > > > > > > > > > > > > > > > > > > > suspicious. Is this API //meant// to be
> > > > > > > > > > > > > > > > > > > > used with incomplete classes?
> > > > > > > > > > > > > > > > > > > > For complete classes I think looking up
> > > > > > > > > > > > > > > > > > > > the default/move/copy constructor and
> > > > > > > > > > > > > > > > > > > > calling `isImplicit()` is the way to do
> > > > > > > > > > > > > > > > > > > > it.
> > > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > > > About the 'is deleted' API - can't the
> > > > > > > > > > > > > > > > > > > > same be done for those functions as
> > > > > > > > > > > > > > > > > > > > well so we have a smaller API?
> > > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > > > If this //is// meant to be used with
> > > > > > > > > > > > > > > > > > > > incomplete classes for efficiency that
> > > > > > > > > > > > > > > > > > > > would be another thing, I guess.
> > > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > > So the intended use case here is I'm
> > > > > > > > > > > > > > > > > > > using libclang to parse an existing C++
> > > > > > > > > > > > > > > > > > > libray's headers and generate a C
> > > > > > > > > > > > > > > > > > > interface to it. To do that I need to
> > > > > > > > > > > > > > > > > > > know if I need to generate default
> > > > > > > > > > > > > > > > > > > constructors etc, which the needs*
> > > > > > > > > > > > > > > > > > > methods do for me (I believe). The
> > > > > > > > > > > > > > > > > > > alternative is I have to check manually
> > > > > > > > > > > > > > > > > > > whether all the constructors/assignment
> > > > > > > > > > > > > > > > > > > operators exist, then implement the
> > > > > > > > > > > > > > > > > > > implicit declaration rules myself
> > > > > > > > > > > > > > > > > > > correctly for each version of the
> > > > > > > > > > > > > > > > > > > standard, which I'd rather avoid.
> > > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > > > Would putting a note in the doc comment
> > > > > > > > > > > > > > > > > > > about the behaviour differing when the
> > > > > > > > > > > > > > > > > > > class is being constructed as originally
> > > > > > > > > > > > > > > > > > > suggested work for everyone?
> > > > > > > > > > > > > > > > > > Why is the `__is_default_constructible`
> > > > > > > > > > > > > > > > > > builtin type trait not enough? Do you have
> > > > > > > > > > > > > > > > > > different behavior for user provided and
> > > > > > > > > > > > > > > > > > implicit default constructors?
> > > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Can I evaluate that from libclang somewhow?
> > > > > > > > > > > > > > > > > I can't modify the C++ libraries I'm
> > > > > > > > > > > > > > > > > wrapping.
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Basically, given:
> > > > > > > > > > > > > > > > > ```
> > > > > > > > > > > > > > > > > struct Foo { /* ... */ };
> > > > > > > > > > > > > > > > > ```
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > I want to generate:
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > ```
> > > > > > > > > > > > > > > > > typedef struct Foo_t;
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > Foo_t* Foo_ctor();
> > > > > > > > > > > > > > > > > Foo_t* Foo_copy_ctor(Foo_t*);
> > > > > > > > > > > > > > > > > /* etc... */
> > > > > > > > > > > > > > > > > Foo_dtor(Foo_t*);
> > > > > > > > > > > > > > > > > ```
> > > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > > In order to know which ones to generate for
> > > > > > > > > > > > > > > > > an arbitrary struct that may or may not have
> > > > > > > > > > > > > > > > > any combination of ctor/assignments defined,
> > > > > > > > > > > > > > > > > I need to know which ones exist and follow
> > > > > > > > > > > > > > > > > the implicit generation rules for the ones
> > > > > > > > > > > > > > > > > that don't. I can do this myself with a whole
> > > > > > > > > > > > > > > > > bunch of version-dependent logic, but I'd
> > > > > > > > > > > > > > > > > rather just rely on libclang since it already
> > > > > > > > > > > > > > > > > knows all this much better than I do.
> > > > > > > > > > > > > > > > I looked a bit, and it seems they aren't, and
> > > > > > > > > > > > > > > > that generally libclang doesn't really know
> > > > > > > > > > > > > > > > about Sema, so exporting the type traits is not
> > > > > > > > > > > > > > > > that easy :/
> > > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > > I'm not sure what's the best way forward here,
> > > > > > > > > > > > > > > > but I don't like the idea of exporting those
> > > > > > > > > > > > > > > > half baked internal API calls when there are
> > > > > > > > > > > > > > > > actual standardized and implemented type traits
> > > > > > > > > > > > > > > > that perform the same goal.
> > > > > > > > > > > > > > > CCing folks who may have more historical memory
> > > > > > > > > > > > > > > of the C APIs and whether they're expected to
> > > > > > > > > > > > > > > operate on a completed AST or are expected to
> > > > > > > > > > > > > > > work on an AST as it is under construction. My
> > > > > > > > > > > > > > > unverified belief is that these APIs are expected
> > > > > > > > > > > > > > > to work on a completed AST.
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > @echristo @dblaikie @rjmccall @rsmith
> > > > > > > > > > > > > > >
> > > > > > > > > > > > > > > I'm also not certain of what the best path
> > > > > > > > > > > > > > > forward is here. I'm not comfortable exposing the
> > > > > > > > > > > > > > > needs* functions because they really are
> > > > > > > > > > > > > > > implementation details and I don't want to
> > > > > > > > > > > > > > > promise we'll support that API forever. But at
> > > > > > > > > > > > > > > the same time, the use case is reasonably
> > > > > > > > > > > > > > > compelling on the assumption you need to inspect
> > > > > > > > > > > > > > > the AST nodes as they're still under construction
> > > > > > > > > > > > > > > instead of inspecting them once the AST is
> > > > > > > > > > > > > > > completed. If the AST is fully constructed, then
> > > > > > > > > > > > > > > we should have already added the AST nodes for
> > > > > > > > > > > > > > > any special member functions that needed to be
> > > > > > > > > > > > > > > generated implicitly, so as Roy mentioned, you
> > > > > > > > > > > > > > > should be able to find the special member
> > > > > > > > > > > > > > > function you're after and check `isImplicit()` on
> > > > > > > > > > > > > > > it.
> > > > > > > > > > > > > > Not sure I'm quite following - it doesn't look
> > > > > > > > > > > > > > (admittedly, sorry, at a somewhat superficial look
> > > > > > > > > > > > > > at the discussion here) like this is necessarily
> > > > > > > > > > > > > > about incomplete AST - could parse the header and
> > > > > > > > > > > > > > stop. That's a complete AST, yeah? And then it
> > > > > > > > > > > > > > might be OK/reasonable to ask "could this type be
> > > > > > > > > > > > > > default constructed" (even if the implicit ctor has
> > > > > > > > > > > > > > been implicitly instantiated/there was no use in
> > > > > > > > > > > > > > the source code that's been parsed)
> > > > > > > > > > > > > >
> > > > > > > > > > > > > > Is that correct?
> > > > > > > > > > > > > I am just parsing the headers of a library using
> > > > > > > > > > > > > `clang_parseTranslationUnit()` then using
> > > > > > > > > > > > > `clang_visitChildren()` to inspect the AST. Doing
> > > > > > > > > > > > > this I do NOT see any implicitly generated methods,
> > > > > > > > > > > > > hence why I need these functions. It sounds like you
> > > > > > > > > > > > > expect those methods to be in the AST already? Which
> > > > > > > > > > > > > suggests I'm doing something wrong in my parsing
> > > > > > > > > > > > > (missing another function call/option or something)?
> > > > > > > > > > > > Ah, no, I wouldn't expect them to be in the AST unless
> > > > > > > > > > > > there was code that used them in the header.
> > > > > > > > > > > >
> > > > > > > > > > > > But I'm saying/trying to say is this isn't a "AST nodes
> > > > > > > > > > > > still under construction" that @aaron.ballman is
> > > > > > > > > > > > describing, so far as I can see - you can completely
> > > > > > > > > > > > parse the header, have a complete AST then reasonably
> > > > > > > > > > > > want to ask "could I default construct an object like
> > > > > > > > > > > > this" - even if the implicit default ctor hasn't been
> > > > > > > > > > > > instantiated because none of the parsed code asked that
> > > > > > > > > > > > question.
> > > > > > > > > > > >
> > > > > > > > > > > > Not sure what the API to do this should look like, but
> > > > > > > > > > > > it seems like a pretty reasonable use case.
> > > > > > > > > > > >
> > > > > > > > > > > > Not sure about whether they cross some threshold where
> > > > > > > > > > > > they're too complex/nuanced to go in the C API or not -
> > > > > > > > > > > > maybe that's a question.
> > > > > > > > > > > >> I am just parsing the headers of a library using
> > > > > > > > > > > >> clang_parseTranslationUnit() then using
> > > > > > > > > > > >> clang_visitChildren() to inspect the AST. Doing this I
> > > > > > > > > > > >> do NOT see any implicitly generated methods, hence why
> > > > > > > > > > > >> I need these functions. It sounds like you expect
> > > > > > > > > > > >> those methods to be in the AST already? Which suggests
> > > > > > > > > > > >> I'm doing something wrong in my parsing (missing
> > > > > > > > > > > >> another function call/option or something)?
> > > > > > > > > > > > Ah, no, I wouldn't expect them to be in the AST unless
> > > > > > > > > > > > there was code that used them in the header.
> > > > > > > > > > >
> > > > > > > > > > > That's part of the "this is an implementation detail" I
> > > > > > > > > > > was talking about. *Today* we don't generate the AST
> > > > > > > > > > > nodes for those functions unless we have to. Nothing says
> > > > > > > > > > > we won't find a reason we need to always generate those
> > > > > > > > > > > AST nodes, which makes the `needs*` functions useless. I
> > > > > > > > > > > suppose in that situation, the breakage for the C APIs is
> > > > > > > > > > > mostly that the exposed `needs*` functions start
> > > > > > > > > > > trivially returning `false` though, so maybe it's not as
> > > > > > > > > > > bad as it could be...
> > > > > > > > > > >
> > > > > > > > > > > > But I'm saying/trying to say is this isn't a "AST nodes
> > > > > > > > > > > > still under construction" that @aaron.ballman is
> > > > > > > > > > > > describing, so far as I can see - you can completely
> > > > > > > > > > > > parse the header, have a complete AST then reasonably
> > > > > > > > > > > > want to ask "could I default construct an object like
> > > > > > > > > > > > this" - even if the implicit default ctor hasn't been
> > > > > > > > > > > > instantiated because none of the parsed code asked that
> > > > > > > > > > > > question.
> > > > > > > > > > >
> > > > > > > > > > > Yeah, the situation I mentioned earlier was the validity
> > > > > > > > > > > of the calls when the class has not been fully
> > > > > > > > > > > constructed in the AST yet. That's not the case here,
> > > > > > > > > > > which is great.
> > > > > > > > > > >
> > > > > > > > > > > > Not sure what the API to do this should look like, but
> > > > > > > > > > > > it seems like a pretty reasonable use case.
> > > > > > > > > > >
> > > > > > > > > > > Agreed that the use case is reasonable.
> > > > > > > > > > >
> > > > > > > > > > > > Not sure about whether they cross some threshold where
> > > > > > > > > > > > they're too complex/nuanced to go in the C API or not -
> > > > > > > > > > > > maybe that's a question.
> > > > > > > > > > >
> > > > > > > > > > > Mostly, I think we try to expose APIs that we think we
> > > > > > > > > > > can support long-term based on what needs folks have.
> > > > > > > > > > > Given that there's a need here, and the use case seems
> > > > > > > > > > > reasonable, it seems to be something we should consider
> > > > > > > > > > > supporting.
> > > > > > > > > > >
> > > > > > > > > > > I suppose there's another way we could view this need
> > > > > > > > > > > though -- some folks need those special member functions
> > > > > > > > > > > even if Clang doesn't think they're necessary to
> > > > > > > > > > > generate. Not only is this use case one such time, but
> > > > > > > > > > > running AST matchers over the AST (like in clang-query or
> > > > > > > > > > > clang-tidy) may also have a similar expectation of
> > > > > > > > > > > finding all the special members. So maybe what we need is
> > > > > > > > > > > some flag to tell Clang "force the generation of those
> > > > > > > > > > > special member functions" so that we don't have to expose
> > > > > > > > > > > a `needs` function for them (which helps for the C API
> > > > > > > > > > > users but doesn't help folks like consumers of AST
> > > > > > > > > > > matchers). (Note, I don't yet know how good or bad of an
> > > > > > > > > > > idea this is.)
> > > > > > > > > > Yeah - if someone is interested in doing the work, I'd be
> > > > > > > > > > curious how some equivalent operations work in the AST
> > > > > > > > > > matchers? I'd assume there's some way to query if something
> > > > > > > > > > is copy constructible - and maybe that's more likely to be
> > > > > > > > > > the query the user wants, rather than the "needs"
> > > > > > > > > > operations?
> > > > > > > > > >
> > > > > > > > > > (like, if we did add the implicit copy constructors into
> > > > > > > > > > the AST proactively, I don't think I'd want these queries
> > > > > > > > > > to return "false" - I think likely the intended query is
> > > > > > > > > > "is this thing copy constructible" (or similar) less about
> > > > > > > > > > whether the operation is or isn't present in the AST)
> > > > > > > > > In my case it's "do I need to generate a copy ctor for this
> > > > > > > > > type?". @aaron.ballman 's suggestion of a way to force the
> > > > > > > > > implicits to be generated in the AST would work just fine for
> > > > > > > > > me.
> > > > > > > > > That's part of the "this is an implementation detail" I was
> > > > > > > > > talking about. *Today* we don't generate the AST nodes for
> > > > > > > > > those functions unless we have to. Nothing says we won't find
> > > > > > > > > a reason we need to always generate those AST nodes, which
> > > > > > > > > makes the `needs*` functions useless. I suppose in that
> > > > > > > > > situation, the breakage for the C APIs is mostly that the
> > > > > > > > > exposed `needs*` functions start trivially returning `false`
> > > > > > > > > though, so maybe it's not as bad as it could be...
> > > > > > > > >
> > > > > > > > > ...
> > > > > > > > >
> > > > > > > > > Yeah, the situation I mentioned earlier was the validity of
> > > > > > > > > the calls when the class has not been fully constructed in
> > > > > > > > > the AST yet. That's not the case here, which is great.
> > > > > > > > >
> > > > > > > >
> > > > > > > > This is not even about future proofing - this is already bad
> > > > > > > > API. Simply adding
> > > > > > > >
> > > > > > > > ```
> > > > > > > > void f() {
> > > > > > > > Test t;
> > > > > > > > }
> > > > > > > > ```
> > > > > > > >
> > > > > > > > in the test in this PR is changing the printed line from
> > > > > > > > `ClassDecl=Test:3:7 (Definition) (needs ctor) (needs cctor)
> > > > > > > > (needs mctor) (needs cassign) (needs massign) (needs dtor)
> > > > > > > > Extent=[3:1 - 17:2]`
> > > > > > > > to
> > > > > > > > `ClassDecl=Test:3:7 (Definition) (needs cassign) (needs
> > > > > > > > massign) (needs dtor) Extent=[3:1 - 17:2]`
> > > > > > > >
> > > > > > > > I don't think making functions in libclang conditional on
> > > > > > > > whether somewhere in the headers types are actually used or not
> > > > > > > > is likely to provide value. It's impossible to enforce non-use
> > > > > > > > of a type if it's definition is available and it's very
> > > > > > > > unnatural to C++ to rely on it.
> > > > > > > >
> > > > > > > > I'm now also pessimistic about the possibility of implementing
> > > > > > > > **correct** versions of those `std::is...` type traits without
> > > > > > > > Sema. Default constructors might be template functions that are
> > > > > > > > SFINAE-disabled, for example. This isn't very exotic - the
> > > > > > > > default constructors of pair, optional, etc.. are all
> > > > > > > > implemented like this. The other type traits that we'd want to
> > > > > > > > expose are also pretty similar.
> > > > > > > >
> > > > > > > > A solution might be useful even if it doesn't handle all cases
> > > > > > > > correctly, of course. But IMHO in this case an approach with
> > > > > > > > only AST would be too partial to justify its shortcomings.
> > > > > > > >
> > > > > > > > In my case it's "do I need to generate a copy ctor for this
> > > > > > > > type?". @aaron.ballman 's suggestion of a way to force the
> > > > > > > > implicits to be generated in the AST would work just fine for
> > > > > > > > me.
> > > > > > >
> > > > > > > But by "generate" you mean "generate a wrapper for this
> > > > > > > operation", yeah?
> > > > > > >
> > > > > > > If you could query the type for "is this type copy
> > > > > > > constructible", "is this type copy assignable", etc, be adequate
> > > > > > > for your needs?
> > > > > > > > In my case it's "do I need to generate a copy ctor for this
> > > > > > > > type?". @aaron.ballman 's suggestion of a way to force the
> > > > > > > > implicits to be generated in the AST would work just fine for
> > > > > > > > me.
> > > > > > >
> > > > > > > But by "generate" you mean "generate a wrapper for this
> > > > > > > operation", yeah?
> > > > > > >
> > > > > > > If you could query the type for "is this type copy
> > > > > > > constructible", "is this type copy assignable", etc, be adequate
> > > > > > > for your needs?
> > > > > >
> > > > > > Thinking about it some more, yes I think it probably would. I would
> > > > > > have to do some minor book-keeping to track whether there was one
> > > > > > already declared on the class or not, but that's a lot simpler than
> > > > > > reimplementing the implicit rules. I guess I would need
> > > > > > `isDefaultConstructible`, `isCopyConstructible`,
> > > > > > `isMoveConstructible`, `isCopyAssignable`, and `isMoveAssignable`
> > > > > @royjacobson it's also going to be pretty problematic to instantiate
> > > > > those templates as members too.
> > > > >
> > > > > The AST is pretty accurately reflective of the compiler's
> > > > > understanding of the type at the time - adding extra instantiations
> > > > > isn't necessarily an improvement in fidelity. I'd argue it's a loss
> > > > > in fidelity because these things weren't instantiated by the original
> > > > > code.
> > > > >
> > > > > (types won't be entirely consistent/stable - member function
> > > > > templates are a great example - you can add code that'll cause new
> > > > > instantiations, and there's no way to fully enumerate all possible
> > > > > instantiations. So it's not a goal for a type description to be
> > > > > stable regardless of the code that uses the type)
> > > > To my thinking, there's a difference between "is this copy
> > > > constructible" and "does this have a copy constructor (even
> > > > implicitly)". My understanding of what @anderslanglands is trying to do
> > > > is to find classes that have a special member function so that the
> > > > wrapper can expose the same functionality. That's not "is this copy
> > > > constructible", that's "does this have a copy constructor (even
> > > > implicitly)."
> > > >
> > > > The C++ standard specifies when classes get implicit special member
> > > > functions and our AST does not reflect that accurately unless the class
> > > > is being used: https://godbolt.org/z/13h3T3dPq. Both have definition
> > > > data that accurately reflects whether the class could get those special
> > > > members (and that definition data is an internal implementation
> > > > detail), but only one of those classes have AST nodes for the special
> > > > members, which means trying to run an AST matcher query for every class
> > > > with a constructor gives unexpected results:
> > > > https://godbolt.org/z/PhMY57anM
> > > Perhaps a simple test: @anderslanglands, if the class had a ctor template
> > > that could be used for copying the type - would that meet your
> > > requirements? Would you want to write a wrapper that invoked/instantiated
> > > that template to perform a copy? Or would you want your wrapper not to
> > > expose copy construction?
> > >
> > > If it does, then the property of interest is "is this type copy
> > > constructible" and not "does this type have a copy constructor", I think?
> > >
> > > All that said, I don't outright object to the implicit special members
> > > being eagerly generated if it doesn't cost much compile time/memory
> > > usage/etc, but I'm certainly a little hesitant. Totally your call,
> > > @aaron.ballman
> > @dblaikie what do you mean by "ctor template" in this context?
> >
> > note: for "copy ctor" here and in what follows, read "all the potentially
> > implicitly defined functions"
> >
> > What I'm trying to do is this. I'm essentially transpiling C++ libraries to
> > C (which are then wrapped in Rust, but it could in theory be any other
> > language). I do this by iterating over the AST and extracting all the
> > methods (and all methods from bases), then transforming them into C
> > equivalents. Thus if a class I'm interested in defines a copy ctor itself,
> > my regular AST extraction will generate a C version of that and all is
> > right with the world.
> >
> > The tricky bit comes when a class *doesnt* define a copy ctor. I then have
> > to figure out if it's not defined because:
> > 1) The library author didn't bother and is relying on it being implicitly
> > defined
> > or
> > 2) The class *cannot* have a copy ctor because of the implicit rules
> >
> > In the case of 1) I currently then need to detect this and generate the C
> > version of the copy ctor which calls the (implicitly defined) C++ copy ctor
> > (and of course I'm generating the library that calls this *after* I've
> > extracted the AST, which means I can't rely on this call to define that
> > ctor in the AST).
> >
> > In the case of 2) I need to detect that and then do nothing (and possibly
> > some other stuff later on if I decide to represent C++ objects as bags of
> > bytes that I pass around but that's another story).
> >
> > So there a few ways of achieving what I need:
> >
> > a) I just implement the implicit rules manually, detect what is and isn't
> > there and decide whether to create the copy ctor myself. This is what I did
> > initially, but of course I screwed it up first time which led to me
> > thinking "surely there's a better way".
> >
> > b) libclang exposes the `needs*` functions in this patch. I just call those
> > during extraction to decide what I do and do not need to implement manually
> > on the C side. Works perfectly for me, but obviously feels wrong to a few
> > people here.
> >
> > c) libclang exposes `isCopyConstructible()` etc. This also works for me,
> > just requires a little more book-keeping my end, i.e. is
> > `isCopyConstructible()` is true AND the class (or its bases) does not have
> > an explicit copy constructor, I need to generate one.
> >
> > d) There's some way to force clang to instantiate all the implicit methods
> > in the AST. This would make my life very easy, as I wouldn't have to think
> > about any of this, they'd just be treated like regular methods and
> > everything would just be extracted without any special handling.
> >
> > So I'd be fine with anything that's not a) :)
> > All that said, I don't outright object to the implicit special members
> > being eagerly generated if it doesn't cost much compile time/memory
> > usage/etc, but I'm certainly a little hesitant. Totally your call,
> > @aaron.ballman
>
> Well, I'm hoping we can find a way to avoid doing that in the general case
> while still giving users a way to opt into that behavior if they need it for
> the C APIs or AST matching. I think the overhead would be problematic for
> general compilation (and it would likely impact things like template
> instantiation depths due to memory overhead pressure), but allowing folks to
> opt in gives them the power to decide which properties of the compilation are
> more important to them.
> @dblaikie what do you mean by "ctor template" in this context?
```
struct t1 {
template<typename T>
t1(const T&) { ... }
};
```
But actually I got that wrong - the compiler won't consider a template for use
when copy constructing.
It does for default constructing, though ( https://godbolt.org/z/hax4jhbPY ):
```
#include <iostream>
struct t1 {
template<typename ...Ts>
t1(Ts ...args) {
std::cout << "Called the variadic template ctor\n";
}
};
int main() {
t1 v2;
}
static_assert(std::is_default_constructible_v<t1>, "");
```
This type doesn't have a default constructor, but it is default constructible.
So maybe that's a place to ask the question: In this case, which property are
you interested in? "has a default constructor" or "is default constructible"?
(would you want to write a wrapper around an instantiation of the ctor template
taking no args?)
Answering that question might suggest the design for the other implicit
ctors/operations, even if they don't have quite the same problems.
> Well, I'm hoping we can find a way to avoid doing that in the general case
> while still giving users a way to opt into that behavior if they need it for
> the C APIs or AST matching.
Ah, I was figuring not wanting to diverge/provide toggles if we can help it -
like unused warnings, opt-in features may go undertested (especially for these
sort of operations being a bit subtle in some ways). Like we've discussed (at
least I remember it coming up many years ago) trying to unify more of the
static analyzer and IRGen to avoid divergence there - adding more divergence
between static analysis and IRGen/etc seems liable to create more risk of
bugs/inconsistencies.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D135557/new/
https://reviews.llvm.org/D135557
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits