Jason Merrill <[email protected]> writes:

> It actually wouldn't; in boolean contexts like conditions and && the
> expression is "contextually converted to bool"
> (https://eel.is/c++draft/conv.general#4), which uses an explicit
> conversion operator.

Ah, okay, excellent.  I'll add it.

>> Or, we could settle on using 'nonempty_p' for all these cases.
>> 
>>>> -    unqual_elt = c_build_qualified_type (elt, KEEP_QUAL_ADDR_SPACE 
>>>> (quals));
>>>> +    unqual_elt = c_build_qualified_type (elt,
>>>> +                                   quals.without (TYPE_QUAL_ALL));
>>> The quals.without (TYPE_QUAL_ALL) pattern seems awkward, especially given 
>>> the
>>> semi-ambiguity of "ALL".  How about a without_cv member function?
>> Yes, "ALL" is ambiguous.  I couldn't think of a better term.
>> This only occurred once, which is why I didn't add 'without_cv'.
>> But, I can add it.
>
> It seems useful; wanting the cv-unqualified type comes up a lot.

In the C++ FE, for CV-unqualified versions of a type, the FE uses:

  gcc/cp/tree.cc-tree
  gcc/cp/tree.cc:cv_unqualified (tree type)
  gcc/cp/tree.cc-{
  gcc/cp/tree.cc-  if (type == error_mark_node)
  gcc/cp/tree.cc-    return type;
  gcc/cp/tree.cc-
  gcc/cp/tree.cc-  auto quals = cp_type_quals (type);
  gcc/cp/tree.cc-  quals.remove (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE);
  gcc/cp/tree.cc-  return cp_build_qualified_type (type, quals);
  gcc/cp/tree.cc-}

... presumably so that it can keep 'restrict' (and _Atomic, but that's
immaterial in C++); could 'without_cv' maybe get confused with that?

(so, maybe 'without_cvra' is better)

Surprisingly, even in the branch where named address space support is present
in C++, I only see one match of 'without (TYPE_QUAL_ALL)', the one
above.

Presumably all the other cases go through 'cv_unqualified'.

>>>> +  /* Returns true if qualifiers in SUBSET can be replaced with qualifiers 
>>>> in
>>>> +     THIS safely.
>>>> +
>>>> +     In general, this means that an object qualified per SUBSET can be 
>>>> used as
>>>> +     if it was qualified per this qualifier set (e.g. 'T' as 'const T', or
>>>> +     'const T' as 'const volatile AS1 T', presuming that AS1 is a 
>>>> superset of
>>>> +     the generic address space).
>>>> +
>>>> +     If NOP_ONLY, return 'true' iff a pointer with a pointee qualified via
>>>> +     SUBSET can be converted into a pointer with a pointee qualified via 
>>>> THIS
>>>> +     (i.e. if a NOP_EXPR conversion would be valid).  In particular, this 
>>>> means
>>>> +     address space mismatches are forbidden.  */
>>>> +  bool can_qualify (qualifier_set subset, bool nop_only = false) const;
>>>
>>> This name and the first paragraph are confusing.  What does "safely" mean?  
>>> If
>>> it means there's a C++ standard conversion, let's say that.
>> That's what the second paragraph expands on.
>> I didn't refer to standard conversions because a single qualifier set
>> alone doesn't suffice to decide whether a conversion is allowed (whether
>> 'T * cv *' can be converted to 'const T * cv *' depends on 'cv' rather
>> than just the qualification of the innermost T).
>
> Sure, but doesn't that same argument apply to the second paragraph as
> it is?  In cases where there isn't a standard conversion, it's
> specifically because such a conversion would not be safe.

Well, in the second paragraph, the qualifier set being referred to is
necessarily the toplevel one.  (even though T is a placeholder for any
type, its inner qualifications are the same in both cases and are
obscured by the placeholder itself, so they aren't relevant)

> And we're only dealing with one set of qualifiers here, we could frame it in
> terms of whether cv1 int* can convert to cv2 int* without referring to an
> arbitrary type T.

Yeah, that could work.

>>> How about "superset_of"?
>> Hmm, a superset does not necessarily mean that THIS can be used to
>> qualify an object previously qualified as SUBSET (particularly when
>> NOP_ONLY, or when the sets differ by _Atomic qualification), so it has
>> different semantics.
>
> And yet you call the parameter "SUBSET" :)

Names are hard ;)

Probably, that should be OTHER.

> Maybe "compatible_with" (in a sense similar to C++ reference-compatible)?

Hmm, that seems fine to me, unless it conflicts with some notion of
compatibility in C, at least in the context of qualification.

Assuming it does not, how about:

  /* Returns true if qualifiers in SUBSET can be replaced with
     qualifiers in THIS safely.

     If !POINTEE, such a replacement is safe iff 'cv2 int *' can be
     converted into 'cv1 int *' where cv1 are the qualifiers in THIS and
     cv2 the qualifiers in OTHER.

     Otherwise, such a replacement is safe iff 'cv2 int * const *' can
     be converted into 'cv1 int * const *' with cv1 and cv2 as
     above.  */
  bool compatible_with (qualifier_set other, bool pointee = false) const;
-- 
Arsen Arsenović

Attachment: signature.asc
Description: PGP signature

Reply via email to