aaron.ballman added inline comments.
================
Comment at: clang/tools/c-index-test/c-index-test.c:79
+ Opts.PreambleStoragePath = NULL;
+ Opts.InvocationEmissionPath =
getenv("CINDEXTEST_INVOCATION_EMISSION_PATH");
+
----------------
vedgy wrote:
> aaron.ballman wrote:
> > vedgy wrote:
> > > aaron.ballman wrote:
> > > > vedgy wrote:
> > > > > When a libclang user needs to override a single option in
> > > > > `CXIndexOptions`, [s]he has to set every member of the struct
> > > > > explicitly. When new options are added, each libclang user needs to
> > > > > update the code that sets the options under `CINDEX_VERSION_MINOR`
> > > > > `#if`s. Accidentally omitting even one member assignment risks
> > > > > undefined or wrong behavior. How about adding an `inline` helper
> > > > > function `CXIndexOptions clang_getDefaultIndexOptions()`, which
> > > > > assigns default values to all struct members? Libclang users can then
> > > > > call this function to obtain the default configuration, then tweak
> > > > > only the members they want to override.
> > > > >
> > > > > If this suggestion is to be implemented, how to deal with
> > > > > [[https://stackoverflow.com/questions/68004269/differences-of-the-inline-keyword-in-c-and-c|the
> > > > > differences of the inline keyword in C and C++]]?
> > > > By default, `0` should give you the most reasonable default behavior
> > > > for most of the existing options (and new options should follow the
> > > > same pattern). Ideally, users should be able to do:
> > > > ```
> > > > CXIndexOptions Opts;
> > > > memset(&Opts, 0, sizeof(Opts));
> > > > Opts.Size = sizeof(Opts);
> > > > Opts.Whatever = 12;
> > > > CXIndex Idx = clang_createIndexWithOptions(&Opts);
> > > > ```
> > > > Global options defaulting to 0 is fine (uses regular thread
> > > > priorities), we don't think want to default to excluding declarations
> > > > from PCH, and we want to use the default preamble and invocation
> > > > emission paths (if any). The only option that nonzero as a default
> > > > *might* make sense for is displaying diagnostics, but even that seems
> > > > reasonable to expect the developer to manually enable.
> > > >
> > > > So I don't know that we need a function to get us default indexing
> > > > options as `0` should be a reasonable default for all of the options.
> > > > As we add new options, we need to be careful to add them in backwards
> > > > compatible ways where `0` means "do the most likely thing".
> > > >
> > > > WDYT?
> > > The disadvantages of committing to defaulting to `0`:
> > > 1. The usage you propose is still more verbose and error-prone than
> > > ```
> > > CXIndexOptions Opts = clang_getDefaultIndexOptions();
> > > Opts.Whatever = 12;
> > > CXIndex Idx = clang_createIndexWithOptions(&Opts);
> > > ```
> > > 2. The `memset` would look very unclean in modern C++ code.
> > > 3. The `0` commitment may force unnatural naming of a future option to
> > > invert its meaning.
> > >
> > > The advantages:
> > > 1. No need to implement the inline function now.
> > > 2. Faster, but I am sure this performance difference doesn't matter. Even
> > > a non-inline function call itself (even if it did nothing) to
> > > `clang_createIndexWithOptions()` should take longer than assigning a few
> > > values to built-in-typed members.
> > >
> > > Another advantage of not having to remember to update the inline
> > > function's implementation when new options are added is counterbalanced
> > > by the need to be careful to add new options in backwards compatible way
> > > where `0` is the default.
> > >
> > > Any other advantages of the `0` that I miss? Maybe there are some
> > > advantages for C users, but I suspect most libclang users are C++.
> > >The usage you propose is still more verbose and error-prone than
> > > ```
> > > CXIndexOptions Opts = clang_getDefaultIndexOptions();
> > > Opts.Whatever = 12;
> > > CXIndex Idx = clang_createIndexWithOptions(&Opts);
> > > ```
> >
> > I see it as being roughly the same amount of verbosity and proneness to
> > error, but maybe that's just me.
> >
> > > The memset would look very unclean in modern C++ code.
> >
> > I don't see this as a problem. 1) `std::memset` gets plenty of usage in
> > modern C++ still, 2) you can also initialize with ` = {
> > sizeof(CXIndexOptions) };` and rely on the zero init for subsequent members
> > after the first (personally, I think that's too clever, but reasonable
> > people may disagree), 3) this is a C API, folks using C++ may wish to wrap
> > it in a better interface for C++ anyway.
> >
> > > The 0 commitment may force unnatural naming of a future option to invert
> > > its meaning.
> >
> > I do worry about this one, especially given there's no way to predict what
> > future options we'll need. But it also forces us to think about what the
> > correct default behavior should be, whereas if we push it off to a helper
> > function, we make it harder for everyone who didn't know to use that helper
> > function for whatever reason.
> >
> > > Any other advantages of the 0 that I miss? Maybe there are some
> > > advantages for C users, but I suspect most libclang users are C++.
> >
> > Familiarity for those who are used to dealing with existing C APIs that
> > behave this way (like Win32 APIs), but that can probably be argued either
> > way. My guess is that all libclang users are having to work through the C
> > interface, and some decently large amount of them do so from languages
> > other than C. But whether that means most are C++ users or not is
> > questionable -- I know I've seen uses from Python and Java as well as C++.
> >
> > I'm not strongly opposed to having an API to get the default values, but I
> > don't see a lot of value in it either. It's something we could always add
> > later if we find there's a need for it in practice.
> > I see it as being roughly the same amount of verbosity and proneness to
> > error, but maybe that's just me.
> Calling the default-value function is one requirement. Assigning `sizeof` and
> calling `memset` - 2. Plus the user has to pass the correct arguments to
> `memset`.
>
> > 1) `std::memset` gets plenty of usage in modern C++ still
> Yes, there is usage, but modern C++ guidelines recommend replacing such
> usages with standard algorithms whenever possible. `memset`-ting an object
> generally risks undefined behavior.
>
> > whereas if we push it off to a helper function, we make it harder for
> > everyone who didn't know to use that helper function for whatever reason.
> If a user doesn't read the documentation, [s]he would likely not guess that
> `memset` needs to be called either. So I don't see a disadvantage of the
> helper function here.
>
> > It's something we could always add later if we find there's a need for it
> > in practice.
> We could add it later. But if we advise using `memset` in the first version,
> introducing a struct member with non-zero default value would risk breaking
> backward compatibility for users that don't track libclang API changes
> closely. It would also force all users that **do** notice the change to
> update their code with `#if CINDEX_VERSION_MINOR >= XY` to use either
> `memset` when compiling against libclang versions that don't yet have the
> helper function, or the helper function.
>
> Introducing the helper function from the beginning affords more flexibility
> and space for future libclang API changes with less risk of breaking backward
> compatibility. If someone decides to ignore the helper function and `memset`
> the struct instead, breaking such usage should not be an obstacle/concern to
> future libclang changes.
>> I see it as being roughly the same amount of verbosity and proneness to
>> error, but maybe that's just me.
> Calling the default-value function is one requirement. Assigning sizeof and
> calling memset - 2. Plus the user has to pass the correct arguments to memset.
Both of which can be done in a single one-liner if brevity is that important
for your coding style.
> Yes, there is usage, but modern C++ guidelines recommend replacing such
> usages with standard algorithms whenever possible. memset-ting an object
> generally risks undefined behavior.
I don't see how that can be much of a real risk in a C interface.
> If a user doesn't read the documentation, [s]he would likely not guess that
> memset needs to be called either. So I don't see a disadvantage of the helper
> function here.
Agreed.
> We could add it later. But if we advise using memset in the first version,
> introducing a struct member with non-zero default value would risk breaking
> backward compatibility ...
My recommendation is that we don't add the API now and we leave a comment in
the options struct reminding folks about the importance of new options being
expressed such that `0` gives the correct default behavior. As you say, it is a
risk that we break the model in the future, but it seems like a somewhat low
risk.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D143418/new/
https://reviews.llvm.org/D143418
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits