[PATCH] D91861: [clang][cli] Split DefaultAnyOf into a default value and ImpliedByAnyOf

Jan Svoboda via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 23 03:08:54 PST 2020


jansvoboda11 added a comment.

Thanks for the feedback. I left some comments inline and will update the patch accordingly.



================
Comment at: clang/lib/Frontend/CompilerInvocation.cpp:3762-3764
+    this->KEYPATH = MERGER(this->KEYPATH, DEFAULT_VALUE);                      \
+    if (IMPLIED_CHECK)                                                         \
+      this->KEYPATH = MERGER(this->KEYPATH, IMPLIED_VALUE);                    \
----------------
dexonsmith wrote:
> This flip to the logic is interesting. I see it now matches the non-flag case; I can't remember if there was a subtle reason it was different before though.
This makes more sense to me personally and I saw similar change in a later patch D84674. Let me know if you remember why it wasn't like that already.


================
Comment at: clang/lib/Frontend/CompilerInvocation.cpp:4027-4031
+  if (((FLAGS)&options::CC1Option) &&                                          \
+      (ALWAYS_EMIT ||                                                          \
+       (EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE && !(IMPLIED_CHECK)))) {     \
     DENORMALIZER(Args, SPELLING, SA, TABLE_INDEX, EXTRACTOR(this->KEYPATH));   \
   }
----------------
dexonsmith wrote:
> I'm not sure this logic is quite right. It looks to me like if an option can very be implied, it will never be seriazed to `-cc1`, even if its current value is not an implied one.
> 
> Or have I understood the conditions under which `IMPLIED_CHECK` returns `true`?
> 
> IIUC, then this logic seems closer:
> ```
> if (((FLAGS)&options::CC1Option) &&                                          \
>     (ALWAYS_EMIT ||                                                          \
>      (EXTRACTOR(this->KEYPATH) !=                                            \
>       (IMPLIED_CHECK ? (DEFAULT_VALUE)                                       \
>                      : (MERGER(DEFAULT_VALUE, IMPLIED_VALUE)))))) {          \
>   DENORMALIZER(Args, SPELLING, SA, TABLE_INDEX, EXTRACTOR(this->KEYPATH));   \
> }
> ```
> 
> It would be great to see tests in particular for a bitset (or similar) option where the merger does a union.
`IMPLIED_CHECK` is a logical disjunction of the implying option keypaths. It evaluates to `true` whenever at least one of the implying keypaths evaluates to `true`.

I think I know what you're concerned about. Let me paraphrase it and check if my understanding is correct:
Suppose option `a` has default value of `x`, and flag `b` can imply the value of `a` to be `y`. If we have a command line `-b -a=z`, then `-a=z` would not be generated with the current logic: `EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE` evaluates to true, but `!(IMPLIED_CHECK)` to `false`.

Your conditions gets close, but I think the ternary branches should be the other way around.

Here's a table exploring all cases:

```
IMPLIED_CHECK | EXTRACTOR(this->KEYPATH) == | SHOULD_EMIT
--------------+-----------------------------+-----------------------------------------
true          | IMPLIED_VALUE               | NO - emitting only the implying option is enough
true          | DEFAULT_VALUE               | YES - value explicitly specified (and it's DEFAULT_VALUE just by chance)
true          | ???                         | YES - value explicitly specified
false         | IMPLIED_VALUE               | YES - value explicitly specified (and it's IMPLIED_VALUE just by chance)
false         | DEFAULT_VALUE               | NO - default value handles this automatically
false         | ???                         | YES - value explicitly specified
```

I think this logic is what we're looking for:

```
  if (((FLAGS)&options::CC1Option) &&                                          \
      (ALWAYS_EMIT ||                                                          \
       (EXTRACTOR(this->KEYPATH) !=                                            \
        ((IMPLIED_CHECK) ? (IMPLIED_VALUE) : (DEFAULT_VALUE))))) {             \
    DENORMALIZER(Args, SPELLING, SA, TABLE_INDEX, EXTRACTOR(this->KEYPATH));   \
  }
```


================
Comment at: clang/lib/Frontend/CompilerInvocation.cpp:4027-4031
+  if (((FLAGS)&options::CC1Option) &&                                          \
+      (ALWAYS_EMIT ||                                                          \
+       (EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE && !(IMPLIED_CHECK)))) {     \
     DENORMALIZER(Args, SPELLING, SA, TABLE_INDEX, EXTRACTOR(this->KEYPATH));   \
   }
----------------
jansvoboda11 wrote:
> dexonsmith wrote:
> > I'm not sure this logic is quite right. It looks to me like if an option can very be implied, it will never be seriazed to `-cc1`, even if its current value is not an implied one.
> > 
> > Or have I understood the conditions under which `IMPLIED_CHECK` returns `true`?
> > 
> > IIUC, then this logic seems closer:
> > ```
> > if (((FLAGS)&options::CC1Option) &&                                          \
> >     (ALWAYS_EMIT ||                                                          \
> >      (EXTRACTOR(this->KEYPATH) !=                                            \
> >       (IMPLIED_CHECK ? (DEFAULT_VALUE)                                       \
> >                      : (MERGER(DEFAULT_VALUE, IMPLIED_VALUE)))))) {          \
> >   DENORMALIZER(Args, SPELLING, SA, TABLE_INDEX, EXTRACTOR(this->KEYPATH));   \
> > }
> > ```
> > 
> > It would be great to see tests in particular for a bitset (or similar) option where the merger does a union.
> `IMPLIED_CHECK` is a logical disjunction of the implying option keypaths. It evaluates to `true` whenever at least one of the implying keypaths evaluates to `true`.
> 
> I think I know what you're concerned about. Let me paraphrase it and check if my understanding is correct:
> Suppose option `a` has default value of `x`, and flag `b` can imply the value of `a` to be `y`. If we have a command line `-b -a=z`, then `-a=z` would not be generated with the current logic: `EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE` evaluates to true, but `!(IMPLIED_CHECK)` to `false`.
> 
> Your conditions gets close, but I think the ternary branches should be the other way around.
> 
> Here's a table exploring all cases:
> 
> ```
> IMPLIED_CHECK | EXTRACTOR(this->KEYPATH) == | SHOULD_EMIT
> --------------+-----------------------------+-----------------------------------------
> true          | IMPLIED_VALUE               | NO - emitting only the implying option is enough
> true          | DEFAULT_VALUE               | YES - value explicitly specified (and it's DEFAULT_VALUE just by chance)
> true          | ???                         | YES - value explicitly specified
> false         | IMPLIED_VALUE               | YES - value explicitly specified (and it's IMPLIED_VALUE just by chance)
> false         | DEFAULT_VALUE               | NO - default value handles this automatically
> false         | ???                         | YES - value explicitly specified
> ```
> 
> I think this logic is what we're looking for:
> 
> ```
>   if (((FLAGS)&options::CC1Option) &&                                          \
>       (ALWAYS_EMIT ||                                                          \
>        (EXTRACTOR(this->KEYPATH) !=                                            \
>         ((IMPLIED_CHECK) ? (IMPLIED_VALUE) : (DEFAULT_VALUE))))) {             \
>     DENORMALIZER(Args, SPELLING, SA, TABLE_INDEX, EXTRACTOR(this->KEYPATH));   \
>   }
> ```
It would be great to be able to test this logic even when no Clang options exercise it properly yet. Any ideas on that front?
Including a different `Options.inc` in `CompilerInvocation.cpp` for tests and re-linking the whole library seems wasteful.


================
Comment at: clang/lib/Frontend/CompilerInvocation.cpp:4038-4043
   if (((FLAGS)&options::CC1Option) &&                                          \
-      (ALWAYS_EMIT || EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE)) {            \
+      (ALWAYS_EMIT ||                                                          \
+       (EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE && !(IMPLIED_CHECK)))) {     \
     DENORMALIZER(Args, SPELLING, NEG_SPELLING, SA, TABLE_INDEX,                \
                  EXTRACTOR(this->KEYPATH));                                    \
   }
----------------
dexonsmith wrote:
> dexonsmith wrote:
> > I'm not entirely sure if the comment applies here, since a `bool` option is simpler, but it would be good to have tests to demonstrate correct behaviour for options with the following scenarios:
> > - option != default, it can be implied but the antecedents are false
> > - option == default, it can be implied but the antecedents are false
> > - option != default, it can be implied and the antecedents are true
> > - option == default, it can be implied and the antecedents are true
> (Maybe the tests already exist in tree; if so, please just point me at them)
The `bool` case works with the current logic, because there are only 2 options and typically, the implied value is negation of the default one.
I will change the logic to match what is discussed above to be consistent.


================
Comment at: clang/lib/Frontend/CompilerInvocation.cpp:4038-4043
   if (((FLAGS)&options::CC1Option) &&                                          \
-      (ALWAYS_EMIT || EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE)) {            \
+      (ALWAYS_EMIT ||                                                          \
+       (EXTRACTOR(this->KEYPATH) != DEFAULT_VALUE && !(IMPLIED_CHECK)))) {     \
     DENORMALIZER(Args, SPELLING, NEG_SPELLING, SA, TABLE_INDEX,                \
                  EXTRACTOR(this->KEYPATH));                                    \
   }
----------------
jansvoboda11 wrote:
> dexonsmith wrote:
> > dexonsmith wrote:
> > > I'm not entirely sure if the comment applies here, since a `bool` option is simpler, but it would be good to have tests to demonstrate correct behaviour for options with the following scenarios:
> > > - option != default, it can be implied but the antecedents are false
> > > - option == default, it can be implied but the antecedents are false
> > > - option != default, it can be implied and the antecedents are true
> > > - option == default, it can be implied and the antecedents are true
> > (Maybe the tests already exist in tree; if so, please just point me at them)
> The `bool` case works with the current logic, because there are only 2 options and typically, the implied value is negation of the default one.
> I will change the logic to match what is discussed above to be consistent.
We don't test all cases currently, I'll fix that.


Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D91861



More information about the cfe-commits mailing list