[clang] d801823 - Revert "CWG2352: Allow qualification conversions during reference binding."

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Sat Dec 28 04:33:35 PST 2019


On Fri, 27 Dec 2019 at 15:59, David Blaikie via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> On Fri, Dec 27, 2019 at 3:48 PM Richard Smith <richard at metafoo.co.uk>
> wrote:
>
>> On Fri, 27 Dec 2019 at 12:27, David Blaikie via cfe-commits <
>> cfe-commits at lists.llvm.org> wrote:
>>
>>>
>>> Author: David Blaikie
>>> Date: 2019-12-27T12:27:20-08:00
>>> New Revision: d8018233d1ea4234de68d5b4593abd773db79484
>>>
>>> URL:
>>> https://github.com/llvm/llvm-project/commit/d8018233d1ea4234de68d5b4593abd773db79484
>>> DIFF:
>>> https://github.com/llvm/llvm-project/commit/d8018233d1ea4234de68d5b4593abd773db79484.diff
>>>
>>> LOG: Revert "CWG2352: Allow qualification conversions during reference
>>> binding."
>>>
>>> This reverts commit de21704ba96fa80d3e9402f12c6505917a3885f4.
>>>
>>> Regressed/causes this to error due to ambiguity:
>>>
>>>   void f(const int * const &);
>>>   void f(int *);
>>>   int main() {
>>>     int * x;
>>>     f(x);
>>>   }
>>>
>>> (in case it's important - the original case where this turned up was a
>>> member function overload in a class template with, essentially:
>>>
>>>   f(const T1&)
>>>   f(T2*)
>>>
>>> (where T1 == X const *, T2 == X))
>>>
>>> It's not super clear to me if this ^ is expected behavior, in which case
>>> I'm sorry about the revert & happy to look into ways to fix the original
>>> code.
>>>
>>
>> I believe the new Clang behavior here is correct according to the
>> standard wording.
>>
>
> Ah, OK. Thanks for looking/checking!
>
>
>> However, GCC trunk also implements CWG2352 and accepts this,
>>
>
> Right, I should've mentioned I checked against GCC trunk. The other case
> that showed up with this change:
>
> template<typename T>
> void f(T&&);
> void f() {
>   int *i;
>   f<const int *>(i);
> }
>
> that one failed with both GCC and Clang (& I've written up a fix for it
> internally) & /seems/ roughly like what I believe is to be correct behavior
> form the compiler/new patch here (& consistent with GCC, giving it a bit
> more a vote for "this seems like good behavior")
>

Yes, I think this one is correct behavior.


> and there's a natural-seeming way to get that result, so I'm going to take
>> this back to the core reflector and see if people agree that this ought to
>> remain valid.
>>
>
> OK - happy to help with internal fixes if/when that's needed (I think it
> might just be the one, though - so maybe that goes to show this isn't the
> worst behavior)
>
>
>>
>>
>>> Added:
>>>
>>>
>>> Modified:
>>>     clang/include/clang/Basic/DiagnosticSemaKinds.td
>>>     clang/lib/Sema/SemaExprCXX.cpp
>>>     clang/lib/Sema/SemaInit.cpp
>>>     clang/lib/Sema/SemaOverload.cpp
>>>     clang/test/CXX/drs/dr23xx.cpp
>>>     clang/test/CXX/drs/dr4xx.cpp
>>>     clang/test/SemaObjCXX/arc-overloading.mm
>>>     clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
>>>     clang/www/cxx_dr_status.html
>>>     clang/www/make_cxx_dr_status
>>>
>>> Removed:
>>>
>>>
>>>
>>>
>>> ################################################################################
>>> diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> b/clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> index b86abd0db73e..54299a0409fd 100644
>>> --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
>>> @@ -1933,8 +1933,7 @@ def err_lvalue_reference_bind_to_unrelated : Error<
>>>    "cannot bind to a value of unrelated type}1,2">;
>>>  def err_reference_bind_drops_quals : Error<
>>>    "binding reference %
>>> diff {of type $ to value of type $|to value}0,1 "
>>> -  "%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address
>>> space|"
>>> -  "not permitted due to incompatible qualifiers}2">;
>>> +  "%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address
>>> space}2">;
>>>  def err_reference_bind_failed : Error<
>>>    "reference %
>>> diff {to %select{type|incomplete type}1 $ could not bind to an "
>>>    "%select{rvalue|lvalue}2 of type $|could not bind to
>>> %select{rvalue|lvalue}2 of "
>>>
>>> diff  --git a/clang/lib/Sema/SemaExprCXX.cpp
>>> b/clang/lib/Sema/SemaExprCXX.cpp
>>> index cd78f096bb22..cfb3a05e9c14 100644
>>> --- a/clang/lib/Sema/SemaExprCXX.cpp
>>> +++ b/clang/lib/Sema/SemaExprCXX.cpp
>>> @@ -5864,8 +5864,6 @@ QualType
>>> Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
>>>    //   one of the operands is reference-compatible with the other, in
>>> order
>>>    //   to support conditionals between functions
>>> diff ering in noexcept. This
>>>    //   will similarly cover
>>> diff erence in array bounds after P0388R4.
>>> -  // FIXME: If LTy and RTy have a composite pointer type, should we
>>> convert to
>>> -  //   that instead?
>>>    ExprValueKind LVK = LHS.get()->getValueKind();
>>>    ExprValueKind RVK = RHS.get()->getValueKind();
>>>    if (!Context.hasSameType(LTy, RTy) &&
>>>
>>> diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
>>> index ef4fa827064e..94d524a63f5a 100644
>>> --- a/clang/lib/Sema/SemaInit.cpp
>>> +++ b/clang/lib/Sema/SemaInit.cpp
>>> @@ -8919,17 +8919,11 @@ bool InitializationSequence::Diagnose(Sema &S,
>>>        S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
>>>            << NonRefType << SourceType << 1 /*addr space*/
>>>            << Args[0]->getSourceRange();
>>> -    else if (DroppedQualifiers.hasQualifiers())
>>> +    else
>>>        S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
>>>            << NonRefType << SourceType << 0 /*cv quals*/
>>>            <<
>>> Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers())
>>>            << DroppedQualifiers.getCVRQualifiers() <<
>>> Args[0]->getSourceRange();
>>> -    else
>>> -      // FIXME: Consider decomposing the type and explaining which
>>> qualifiers
>>> -      // were dropped where, or on which level a 'const' is missing,
>>> etc.
>>> -      S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
>>> -          << NonRefType << SourceType << 2 /*incompatible quals*/
>>> -          << Args[0]->getSourceRange();
>>>      break;
>>>    }
>>>
>>>
>>> diff  --git a/clang/lib/Sema/SemaOverload.cpp
>>> b/clang/lib/Sema/SemaOverload.cpp
>>> index 92058c3aa5fd..74a0bc7c78ff 100644
>>> --- a/clang/lib/Sema/SemaOverload.cpp
>>> +++ b/clang/lib/Sema/SemaOverload.cpp
>>> @@ -3153,70 +3153,6 @@ static bool
>>> isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
>>>    return true;
>>>  }
>>>
>>> -/// Perform a single iteration of the loop for checking if a
>>> qualification
>>> -/// conversion is valid.
>>> -///
>>> -/// Specifically, check whether any change between the qualifiers of \p
>>> -/// FromType and \p ToType is permissible, given knowledge about
>>> whether every
>>> -/// outer layer is const-qualified.
>>> -static bool isQualificationConversionStep(QualType FromType, QualType
>>> ToType,
>>> -                                          bool CStyle,
>>> -                                          bool
>>> &PreviousToQualsIncludeConst,
>>> -                                          bool &ObjCLifetimeConversion)
>>> {
>>> -  Qualifiers FromQuals = FromType.getQualifiers();
>>> -  Qualifiers ToQuals = ToType.getQualifiers();
>>> -
>>> -  // Ignore __unaligned qualifier if this type is void.
>>> -  if (ToType.getUnqualifiedType()->isVoidType())
>>> -    FromQuals.removeUnaligned();
>>> -
>>> -  // Objective-C ARC:
>>> -  //   Check Objective-C lifetime conversions.
>>> -  if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime()) {
>>> -    if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
>>> -      if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
>>> -        ObjCLifetimeConversion = true;
>>> -      FromQuals.removeObjCLifetime();
>>> -      ToQuals.removeObjCLifetime();
>>> -    } else {
>>> -      // Qualification conversions cannot cast between
>>> diff erent
>>> -      // Objective-C lifetime qualifiers.
>>> -      return false;
>>> -    }
>>> -  }
>>> -
>>> -  // Allow addition/removal of GC attributes but not changing GC
>>> attributes.
>>> -  if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
>>> -      (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
>>> -    FromQuals.removeObjCGCAttr();
>>> -    ToQuals.removeObjCGCAttr();
>>> -  }
>>> -
>>> -  //   -- for every j > 0, if const is in cv 1,j then const is in cv
>>> -  //      2,j, and similarly for volatile.
>>> -  if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
>>> -    return false;
>>> -
>>> -  // For a C-style cast, just require the address spaces to overlap.
>>> -  // FIXME: Does "superset" also imply the representation of a pointer
>>> is the
>>> -  // same? We're assuming that it does here and in compatiblyIncludes.
>>> -  if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
>>> -      !FromQuals.isAddressSpaceSupersetOf(ToQuals))
>>> -    return false;
>>> -
>>> -  //   -- if the cv 1,j and cv 2,j are
>>> diff erent, then const is in
>>> -  //      every cv for 0 < k < j.
>>> -  if (!CStyle && FromQuals.getCVRQualifiers() !=
>>> ToQuals.getCVRQualifiers() &&
>>> -      !PreviousToQualsIncludeConst)
>>> -    return false;
>>> -
>>> -  // Keep track of whether all prior cv-qualifiers in the "to" type
>>> -  // include const.
>>> -  PreviousToQualsIncludeConst =
>>> -      PreviousToQualsIncludeConst && ToQuals.hasConst();
>>> -  return true;
>>> -}
>>> -
>>>  /// IsQualificationConversion - Determines whether the conversion from
>>>  /// an rvalue of type FromType to ToType is a qualification conversion
>>>  /// (C++ 4.4).
>>> @@ -3242,16 +3178,73 @@ Sema::IsQualificationConversion(QualType
>>> FromType, QualType ToType,
>>>    bool PreviousToQualsIncludeConst = true;
>>>    bool UnwrappedAnyPointer = false;
>>>    while (Context.UnwrapSimilarTypes(FromType, ToType)) {
>>> -    if (!isQualificationConversionStep(FromType, ToType, CStyle,
>>> -                                       PreviousToQualsIncludeConst,
>>> -                                       ObjCLifetimeConversion))
>>> -      return false;
>>> +    // Within each iteration of the loop, we check the qualifiers to
>>> +    // determine if this still looks like a qualification
>>> +    // conversion. Then, if all is well, we unwrap one more level of
>>> +    // pointers or pointers-to-members and do it all again
>>> +    // until there are no more pointers or pointers-to-members left to
>>> +    // unwrap.
>>>      UnwrappedAnyPointer = true;
>>> +
>>> +    Qualifiers FromQuals = FromType.getQualifiers();
>>> +    Qualifiers ToQuals = ToType.getQualifiers();
>>> +
>>> +    // Ignore __unaligned qualifier if this type is void.
>>> +    if (ToType.getUnqualifiedType()->isVoidType())
>>> +      FromQuals.removeUnaligned();
>>> +
>>> +    // Objective-C ARC:
>>> +    //   Check Objective-C lifetime conversions.
>>> +    if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
>>> +        UnwrappedAnyPointer) {
>>> +      if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
>>> +        if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
>>> +          ObjCLifetimeConversion = true;
>>> +        FromQuals.removeObjCLifetime();
>>> +        ToQuals.removeObjCLifetime();
>>> +      } else {
>>> +        // Qualification conversions cannot cast between
>>> diff erent
>>> +        // Objective-C lifetime qualifiers.
>>> +        return false;
>>> +      }
>>> +    }
>>> +
>>> +    // Allow addition/removal of GC attributes but not changing GC
>>> attributes.
>>> +    if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
>>> +        (!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
>>> +      FromQuals.removeObjCGCAttr();
>>> +      ToQuals.removeObjCGCAttr();
>>> +    }
>>> +
>>> +    //   -- for every j > 0, if const is in cv 1,j then const is in cv
>>> +    //      2,j, and similarly for volatile.
>>> +    if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
>>> +      return false;
>>> +
>>> +    //   -- if the cv 1,j and cv 2,j are
>>> diff erent, then const is in
>>> +    //      every cv for 0 < k < j.
>>> +    if (!CStyle && FromQuals.getCVRQualifiers() !=
>>> ToQuals.getCVRQualifiers()
>>> +        && !PreviousToQualsIncludeConst)
>>> +      return false;
>>> +
>>> +    // Keep track of whether all prior cv-qualifiers in the "to" type
>>> +    // include const.
>>> +    PreviousToQualsIncludeConst
>>> +      = PreviousToQualsIncludeConst && ToQuals.hasConst();
>>> +  }
>>> +
>>> +  // Allows address space promotion by language rules implemented in
>>> +  // Type::Qualifiers::isAddressSpaceSupersetOf.
>>> +  Qualifiers FromQuals = FromType.getQualifiers();
>>> +  Qualifiers ToQuals = ToType.getQualifiers();
>>> +  if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
>>> +      !FromQuals.isAddressSpaceSupersetOf(ToQuals)) {
>>> +    return false;
>>>    }
>>>
>>>    // We are left with FromType and ToType being the pointee types
>>>    // after unwrapping the original FromType and ToType the same number
>>> -  // of times. If we unwrapped any pointers, and if FromType and
>>> +  // of types. If we unwrapped any pointers, and if FromType and
>>>    // ToType have the same unqualified type (since we checked
>>>    // qualifiers above), then this is a qualification conversion.
>>>    return UnwrappedAnyPointer &&
>>> Context.hasSameUnqualifiedType(FromType,ToType);
>>> @@ -3997,41 +3990,32 @@ CompareStandardConversionSequences(Sema &S,
>>> SourceLocation Loc,
>>>      //      top-level cv-qualifiers, and the type to which the reference
>>>      //      initialized by S2 refers is more cv-qualified than the type
>>>      //      to which the reference initialized by S1 refers.
>>> -    // FIXME: This should have been updated by DR2352, but was
>>> overlooked. The
>>> -    // corrected rule is:
>>> -    //   -- S1 and S2 include reference bindings, and references refer
>>> to types
>>> -    //      T1 and T2, respectively, where T2 is reference-compatible
>>> with T1.
>>>      QualType T1 = SCS1.getToType(2);
>>>      QualType T2 = SCS2.getToType(2);
>>> +    T1 = S.Context.getCanonicalType(T1);
>>> +    T2 = S.Context.getCanonicalType(T2);
>>> +    Qualifiers T1Quals, T2Quals;
>>> +    QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
>>> +    QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
>>> +    if (UnqualT1 == UnqualT2) {
>>> +      // Objective-C++ ARC: If the references refer to objects with
>>> diff erent
>>> +      // lifetimes, prefer bindings that don't change lifetime.
>>> +      if (SCS1.ObjCLifetimeConversionBinding !=
>>> +
>>> SCS2.ObjCLifetimeConversionBinding) {
>>> +        return SCS1.ObjCLifetimeConversionBinding
>>> +                                           ?
>>> ImplicitConversionSequence::Worse
>>> +                                           :
>>> ImplicitConversionSequence::Better;
>>> +      }
>>>
>>> -    // Objective-C++ ARC: If the references refer to objects with
>>> diff erent
>>> -    // lifetimes, prefer bindings that don't change lifetime.
>>> -    //
>>> -    // FIXME: Should this really override ordering based on
>>> qualification
>>> -    // conversions? In the correspnding check for pointers, we treat a
>>> case
>>> -    // where one candidate has worse qualifications and the other has a
>>> -    // lifetime conversion as ambiguous.
>>> -    if (SCS1.ObjCLifetimeConversionBinding !=
>>> -            SCS2.ObjCLifetimeConversionBinding &&
>>> -        S.Context.hasSameUnqualifiedType(T1, T2)) {
>>> -      return SCS1.ObjCLifetimeConversionBinding
>>> -                 ? ImplicitConversionSequence::Worse
>>> -                 : ImplicitConversionSequence::Better;
>>> -    }
>>> -
>>> -    if (!S.Context.hasSameType(T1, T2)) {
>>> -      // FIXME: Unfortunately, there are pairs of types that admit
>>> reference
>>> -      // bindings in both directions, so we can't shortcut the second
>>> check
>>> -      // here.
>>> -      bool Better =
>>> -          S.CompareReferenceRelationship(Loc, T2, T1) ==
>>> Sema::Ref_Compatible;
>>> -      bool Worse =
>>> -          S.CompareReferenceRelationship(Loc, T1, T2) ==
>>> Sema::Ref_Compatible;
>>> -      if (Better && Worse)
>>> -        return ImplicitConversionSequence::Indistinguishable;
>>> -      if (Better)
>>> +      // If the type is an array type, promote the element qualifiers
>>> to the
>>> +      // type for comparison.
>>> +      if (isa<ArrayType>(T1) && T1Quals)
>>> +        T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
>>> +      if (isa<ArrayType>(T2) && T2Quals)
>>> +        T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
>>> +      if (T2.isMoreQualifiedThan(T1))
>>>          return ImplicitConversionSequence::Better;
>>> -      if (Worse)
>>> +      else if (T1.isMoreQualifiedThan(T2))
>>>          return ImplicitConversionSequence::Worse;
>>>      }
>>>    }
>>> @@ -4418,19 +4402,10 @@ static bool isTypeValid(QualType T) {
>>>    return true;
>>>  }
>>>
>>> -static QualType withoutUnaligned(ASTContext &Ctx, QualType T) {
>>> -  if (!T.getQualifiers().hasUnaligned())
>>> -    return T;
>>> -
>>> -  Qualifiers Q;
>>> -  T = Ctx.getUnqualifiedArrayType(T, Q);
>>> -  Q.removeUnaligned();
>>> -  return Ctx.getQualifiedType(T, Q);
>>> -}
>>> -
>>>  /// CompareReferenceRelationship - Compare the two types T1 and T2 to
>>> -/// determine whether they are reference-compatible,
>>> -/// reference-related, or incompatible, for use in C++ initialization by
>>> +/// determine whether they are reference-related,
>>> +/// reference-compatible, reference-compatible with added
>>> +/// qualification, or incompatible, for use in C++ initialization by
>>>  /// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
>>>  /// type, and the first type (T1) is the pointee type of the reference
>>>  /// type being initialized.
>>> @@ -4452,17 +4427,10 @@
>>> Sema::CompareReferenceRelationship(SourceLocation Loc,
>>>    ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
>>>    Conv = ReferenceConversions();
>>>
>>> -  // C++2a [dcl.init.ref]p4:
>>> +  // C++ [dcl.init.ref]p4:
>>>    //   Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
>>> -  //   reference-related to "cv2 T2" if T1 is similar to T2, or
>>> +  //   reference-related to "cv2 T2" if T1 is the same type as T2, or
>>>    //   T1 is a base class of T2.
>>> -  //   "cv1 T1" is reference-compatible with "cv2 T2" if
>>> -  //   a prvalue of type "pointer to cv2 T2" can be converted to the
>>> type
>>> -  //   "pointer to cv1 T1" via a standard conversion sequence.
>>> -
>>> -  // Check for standard conversions we can apply to pointers:
>>> derived-to-base
>>> -  // conversions, ObjC pointer conversions, and function pointer
>>> conversions.
>>> -  // (Qualification conversions are checked last.)
>>>    QualType ConvertedT2;
>>>    if (UnqualT1 == UnqualT2) {
>>>      // Nothing to do.
>>> @@ -4476,47 +4444,59 @@
>>> Sema::CompareReferenceRelationship(SourceLocation Loc,
>>>      Conv |= ReferenceConversions::ObjC;
>>>    else if (UnqualT2->isFunctionType() &&
>>>             IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
>>> +    // C++1z [dcl.init.ref]p4:
>>> +    //   cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is
>>> "noexcept
>>> +    //   function" and T1 is "function"
>>> +    //
>>> +    // We extend this to also apply to 'noreturn', so allow any function
>>> +    // conversion between function types.
>>>      Conv |= ReferenceConversions::Function;
>>> -    // No need to check qualifiers; function types don't have them.
>>>      return Ref_Compatible;
>>> +  } else
>>> +    return Ref_Incompatible;
>>> +
>>> +  // At this point, we know that T1 and T2 are reference-related (at
>>> +  // least).
>>> +
>>> +  // If the type is an array type, promote the element qualifiers to
>>> the type
>>> +  // for comparison.
>>> +  if (isa<ArrayType>(T1) && T1Quals)
>>> +    T1 = Context.getQualifiedType(UnqualT1, T1Quals);
>>> +  if (isa<ArrayType>(T2) && T2Quals)
>>> +    T2 = Context.getQualifiedType(UnqualT2, T2Quals);
>>> +
>>> +  // C++ [dcl.init.ref]p4:
>>> +  //   "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
>>> +  //   reference-related to T2 and cv1 is the same cv-qualification
>>> +  //   as, or greater cv-qualification than, cv2. For purposes of
>>> +  //   overload resolution, cases for which cv1 is greater
>>> +  //   cv-qualification than cv2 are identified as
>>> +  //   reference-compatible with added qualification (see 13.3.3.2).
>>> +  //
>>> +  // Note that we also require equivalence of Objective-C GC and
>>> address-space
>>> +  // qualifiers when performing these computations, so that e.g., an
>>> int in
>>> +  // address space 1 is not reference-compatible with an int in address
>>> +  // space 2.
>>> +  if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
>>> +      T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
>>> +    if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals))
>>> +      Conv |= ReferenceConversions::ObjCLifetime;
>>> +
>>> +    T1Quals.removeObjCLifetime();
>>> +    T2Quals.removeObjCLifetime();
>>>    }
>>> -  bool ConvertedReferent = Conv != 0;
>>>
>>> -  // We can have a qualification conversion. Compute whether the types
>>> are
>>> -  // similar at the same time.
>>> -  bool PreviousToQualsIncludeConst = true;
>>> -  do {
>>> -    if (T1 == T2)
>>> -      break;
>>> +  // MS compiler ignores __unaligned qualifier for references; do the
>>> same.
>>> +  T1Quals.removeUnaligned();
>>> +  T2Quals.removeUnaligned();
>>>
>>> -    // We will need a qualification conversion.
>>> +  if (T1Quals != T2Quals)
>>>      Conv |= ReferenceConversions::Qualification;
>>>
>>> -    // MS compiler ignores __unaligned qualifier for references; do the
>>> same.
>>> -    T1 = withoutUnaligned(Context, T1);
>>> -    T2 = withoutUnaligned(Context, T2);
>>> -
>>> -    // If we find a qualifier mismatch, the types are not
>>> reference-compatible,
>>> -    // but are still be reference-related if they're similar.
>>> -    bool ObjCLifetimeConversion = false;
>>> -    if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false,
>>> -                                       PreviousToQualsIncludeConst,
>>> -                                       ObjCLifetimeConversion))
>>> -      return (ConvertedReferent || Context.hasSimilarType(T1, T2))
>>> -                 ? Ref_Related
>>> -                 : Ref_Incompatible;
>>> -
>>> -    // FIXME: Should we track this for any level other than the first?
>>> -    if (ObjCLifetimeConversion)
>>> -      Conv |= ReferenceConversions::ObjCLifetime;
>>> -  } while (Context.UnwrapSimilarTypes(T1, T2));
>>> -
>>> -  // At this point, if the types are reference-related, we must either
>>> have the
>>> -  // same inner type (ignoring qualifiers), or must have already worked
>>> out how
>>> -  // to convert the referent.
>>> -  return (ConvertedReferent || Context.hasSameUnqualifiedType(T1, T2))
>>> -             ? Ref_Compatible
>>> -             : Ref_Incompatible;
>>> +  if (T1Quals.compatiblyIncludes(T2Quals))
>>> +    return Ref_Compatible;
>>> +  else
>>> +    return Ref_Related;
>>>  }
>>>
>>>  /// Look for a user-defined conversion to a value reference-compatible
>>>
>>> diff  --git a/clang/test/CXX/drs/dr23xx.cpp
>>> b/clang/test/CXX/drs/dr23xx.cpp
>>> index caf3be114547..763abd5368ef 100644
>>> --- a/clang/test/CXX/drs/dr23xx.cpp
>>> +++ b/clang/test/CXX/drs/dr23xx.cpp
>>> @@ -4,38 +4,9 @@
>>>  // RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions
>>> -pedantic-errors 2>&1 | FileCheck %s
>>>  // RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions
>>> -pedantic-errors 2>&1 | FileCheck %s
>>>
>>> -namespace dr2352 { // dr2352: 10
>>> -  int **p;
>>> -  const int *const *const &f1() { return p; }
>>> -  int *const *const &f2() { return p; }
>>> -  int **const &f3() { return p; }
>>> -
>>> -  const int **const &f4() { return p; } // expected-error {{reference
>>> to type 'const int **const' could not bind to an lvalue of type 'int **'}}
>>> -  const int *const *&f5() { return p; } // expected-error {{binding
>>> reference of type 'const int *const *' to value of type 'int **' not
>>> permitted due to incompatible qualifiers}}
>>> -
>>> -  // FIXME: We permit this as a speculative defect resolution, allowing
>>> -  // qualification conversions when forming a glvalue conditional
>>> expression.
>>> -  const int * const * const q = 0;
>>> -  __typeof(&(true ? p : q)) x = &(true ? p : q);
>>> -
>>> -  // FIXME: Should we compute the composite pointer type here and
>>> produce an
>>> -  // lvalue of type 'const int *const * const'?
>>> -  const int * const * r;
>>> -  void *y = &(true ? p : r); // expected-error {{rvalue of type 'const
>>> int *const *'}}
>>> -
>>> -  // FIXME: We order these as a speculative defect resolution.
>>> -  void f(const int * const * const &r);
>>> -#if __cplusplus >= 201103L
>>> -  constexpr
>>> +#if __cplusplus <= 201103L
>>> +// expected-no-diagnostics
>>>  #endif
>>> -  int *const *const &f(int * const * const &r) { return r; }
>>> -
>>> -  // No temporary is created here.
>>> -  int *const *const &check_f = f(p);
>>> -#if __cplusplus >= 201103L
>>> -  static_assert(&p == &check_f, "");
>>> -#endif
>>> -}
>>>
>>>  namespace dr2353 { // dr2353: 9
>>>    struct X {
>>>
>>> diff  --git a/clang/test/CXX/drs/dr4xx.cpp b/clang/test/CXX/drs/dr4xx.cpp
>>> index d37ece6cb882..8eeb7715cadf 100644
>>> --- a/clang/test/CXX/drs/dr4xx.cpp
>>> +++ b/clang/test/CXX/drs/dr4xx.cpp
>>> @@ -486,21 +486,14 @@ namespace dr433 { // dr433: yes
>>>    S<int> s;
>>>  }
>>>
>>> -namespace dr434 { // dr434: sup 2352
>>> +namespace dr434 { // dr434: yes
>>>    void f() {
>>>      const int ci = 0;
>>>      int *pi = 0;
>>> -    const int *&rpci = pi; // expected-error {{incompatible qualifiers}}
>>> -    const int * const &rcpci = pi; // OK
>>> +    const int *&rpci = pi; // expected-error {{cannot bind}}
>>>      rpci = &ci;
>>>      *pi = 1;
>>>    }
>>> -
>>> -#if __cplusplus >= 201103L
>>> -  int *pi = 0;
>>> -  const int * const &rcpci = pi;
>>> -  static_assert(&rcpci == &pi, "");
>>> -#endif
>>>  }
>>>
>>>  // dr435: na
>>>
>>> diff  --git a/clang/test/SemaObjCXX/arc-overloading.mm
>>> b/clang/test/SemaObjCXX/arc-overloading.mm
>>> index 910b5c7be978..3ac9c51293b7 100644
>>> --- a/clang/test/SemaObjCXX/arc-overloading.mm
>>> +++ b/clang/test/SemaObjCXX/arc-overloading.mm
>>> @@ -174,36 +174,6 @@ void test_f9() {
>>>    const __autoreleasing id& ar4 = weak_a;
>>>  }
>>>
>>> -int &f10(__strong id *&); // expected-note 2{{not viable: no known
>>> conversion}}
>>> -float &f10(__autoreleasing id *&); // expected-note 2{{not viable: no
>>> known conversion}}
>>> -
>>> -void test_f10() {
>>> -  __strong id *strong_id;
>>> -  __weak id *weak_id;
>>> -  __autoreleasing id *autoreleasing_id;
>>> -  __unsafe_unretained id *unsafe_id;
>>> -
>>> -  int &ir1 = f10(strong_id);
>>> -  float &fr1 = f10(autoreleasing_id);
>>> -  float &fr2 = f10(unsafe_id); // expected-error {{no match}}
>>> -  float &fr2a = f10(weak_id); // expected-error {{no match}}
>>> -}
>>> -
>>> -int &f11(__strong id *const &); // expected-note {{not viable: 1st
>>> argument ('__weak id *') has __weak ownership, but parameter has __strong
>>> ownership}}
>>> -float &f11(const __autoreleasing id *const &); // expected-note {{not
>>> viable: 1st argument ('__weak id *') has __weak ownership, but parameter
>>> has __autoreleasing ownership}}
>>> -
>>> -void test_f11() {
>>> -  __strong id *strong_id;
>>> -  __weak id *weak_id;
>>> -  __autoreleasing id *autoreleasing_id;
>>> -  __unsafe_unretained id *unsafe_id;
>>> -
>>> -  int &ir1 = f11(strong_id);
>>> -  float &fr1 = f11(autoreleasing_id);
>>> -  float &fr2 = f11(unsafe_id);
>>> -  float &fr2a = f11(weak_id); // expected-error {{no match}}
>>> -}
>>> -
>>>  // rdar://9790531
>>>  void f9790531(void *inClientData); // expected-note {{candidate
>>> function not viable: cannot implicitly convert argument of type
>>> 'MixerEQGraphTestDelegate *const __strong' to 'void *' for 1st argument
>>> under ARC}}
>>>  void f9790531_1(struct S*inClientData); // expected-note {{candidate
>>> function not viable}}
>>>
>>> diff  --git a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
>>> b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
>>> index 14f7cf3a0e7e..c46e4e08a2cd 100644
>>> --- a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
>>> +++ b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
>>> @@ -501,9 +501,12 @@ void test_pointer_chains() {
>>>    // Case 1:
>>>    //  * address spaces of corresponded most outer pointees overlaps,
>>> their canonical types are equal
>>>    //  * CVR, address spaces and canonical types of the rest of pointees
>>> are equivalent.
>>> -  var_as_as_int = var_asc_as_int;
>>>    var_as_as_int = 0 ? var_as_as_int : var_asc_as_int;
>>> -
>>> +#if __OPENCL_CPP_VERSION__
>>> +#ifdef GENERIC
>>> +// expected-error at -3{{incompatible operand types ('__generic int
>>> *__generic *' and '__generic int *__local *')}}
>>> +#endif
>>> +#endif
>>>    // Case 2: Corresponded inner pointees has non-overlapping address
>>> spaces.
>>>    var_as_as_int = 0 ? var_as_as_int : var_asc_asn_int;
>>>  #if !__OPENCL_CPP_VERSION__
>>> @@ -513,17 +516,12 @@ void test_pointer_chains() {
>>>  #endif
>>>
>>>    // Case 3: Corresponded inner pointees has overlapping but not
>>> equivalent address spaces.
>>> -  // FIXME: Should this really be allowed in C++ mode?
>>> -  var_as_as_int = var_asc_asc_int;
>>> -#if !__OPENCL_CPP_VERSION__
>>>  #ifdef GENERIC
>>> -// expected-error at -3 {{assigning '__local int *__local *__private' to
>>> '__generic int *__generic *__private' changes address space of nested
>>> pointer}}
>>> -#endif
>>> -#endif
>>>    var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int;
>>>  #if !__OPENCL_CPP_VERSION__
>>> -#ifdef GENERIC
>>> -// expected-warning at -3{{pointer type mismatch ('__generic int
>>> *__generic *' and '__local int *__local *')}}
>>> +// expected-warning-re at -2{{pointer type mismatch
>>> ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *'
>>> and '__{{(local|global|constant)}} int *__{{(local|global|constant)}} *')}}
>>> +#else
>>> +// expected-error-re at -4{{incompatible operand types
>>> ('__{{generic|global|constant}} int *__{{generic|global|constant}} *' and
>>> '__{{local|global|constant}} int *__{{local|global|constant}} *')}}
>>>  #endif
>>>  #endif
>>>  }
>>>
>>> diff  --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
>>> index c4ec45736524..23a7218e897a 100755
>>> --- a/clang/www/cxx_dr_status.html
>>> +++ b/clang/www/cxx_dr_status.html
>>> @@ -2645,7 +2645,7 @@ <h2 id="cxxdr">C++ defect report implementation
>>> status</h2>
>>>      <td><a href="https://wg21.link/cwg434">434</a></td>
>>>      <td>NAD</td>
>>>      <td>Unclear suppression of standard conversions while binding
>>> reference to lvalue</td>
>>> -    <td class="svn" align="center">Superseded by <a
>>> href="#2352">2352</a></td>
>>> +    <td class="full" align="center">Yes</td>
>>>    </tr>
>>>    <tr id="435">
>>>      <td><a href="https://wg21.link/cwg435">435</a></td>
>>> @@ -13927,7 +13927,7 @@ <h2 id="cxxdr">C++ defect report implementation
>>> status</h2>
>>>      <td><a href="https://wg21.link/cwg2352">2352</a></td>
>>>      <td>DR</td>
>>>      <td>Similar types and reference binding</td>
>>> -    <td class="svn" align="center">SVN</td>
>>> +    <td class="none" align="center">Unknown</td>
>>>    </tr>
>>>    <tr id="2353">
>>>      <td><a href="https://wg21.link/cwg2353">2353</a></td>
>>>
>>> diff  --git a/clang/www/make_cxx_dr_status b/clang/www/make_cxx_dr_status
>>> index fd5eb7fbabb4..4351d659e41a 100755
>>> --- a/clang/www/make_cxx_dr_status
>>> +++ b/clang/www/make_cxx_dr_status
>>> @@ -28,7 +28,7 @@ def parse(dr):
>>>    _, url, issue = issue_link.split('"', 2)
>>>    url = url.strip()
>>>    issue = int(issue.split('>', 1)[1].split('<', 1)[0])
>>> -  title = title.replace('<issue_title>', '').replace('</issue_title>',
>>> '').replace('\r\n', '\n').strip()
>>> +  title = title.replace('<issue_title>', '').replace('</issue_title>',
>>> '').strip()
>>>    return DR(section, issue, url, status, title)
>>>
>>>  status_re = re.compile(r'\bdr([0-9]+): (.*)')
>>> @@ -171,7 +171,7 @@ for dr in drs:
>>>
>>>    print >> out_file, '''\
>>>    <tr%s id="%s">
>>> -    <td><a href="https://wg21.link/cwg%s">%s</a></td>
>>> +    <td><a href="http://wg21.link/cwg%s">%s</a></td>
>>>      <td>%s</td>
>>>      <td>%s</td>
>>>      <td%s align="center">%s</td>
>>>
>>>
>>>
>>> _______________________________________________
>>> cfe-commits mailing list
>>> cfe-commits at lists.llvm.org
>>> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>
>> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20191228/65e47a6d/attachment-0001.html>


More information about the cfe-commits mailing list