[clang] de21704 - CWG2352: Allow qualification conversions during reference binding.

David Blaikie via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 27 12:28:45 PST 2019


Sorry if this is expected behavior, but saw a regression that looks
/plausibly/ correct & is rendered ambiguous by this change so I've gone
ahead and reverted this patch in d8018233d1ea4234de68d5b4593abd773db79484

Comment from the original:

    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))

On Thu, Dec 19, 2019 at 6:56 PM Richard Smith via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

>
> Author: Richard Smith
> Date: 2019-12-19T18:37:55-08:00
> New Revision: de21704ba96fa80d3e9402f12c6505917a3885f4
>
> URL:
> https://github.com/llvm/llvm-project/commit/de21704ba96fa80d3e9402f12c6505917a3885f4
> DIFF:
> https://github.com/llvm/llvm-project/commit/de21704ba96fa80d3e9402f12c6505917a3885f4.diff
>
> LOG: CWG2352: Allow qualification conversions during reference binding.
>
> The language wording change forgot to update overload resolution to rank
> implicit conversion sequences based on qualification conversions in
> reference bindings. The anticipated resolution for that oversight is
> implemented here -- we order candidates based on qualification
> conversion, not only on top-level cv-qualifiers.
>
> For OpenCL/C++, this allows reference binding between pointers with
> differing (nested) address spaces. This makes the behavior of reference
> binding consistent with that of implicit pointer conversions, as is the
> purpose of this change, but that pre-existing behavior for pointer
> conversions is itself probably not correct. In any case, it's now
> consistently the same behavior and implemented in only one place.
>
> 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 c7b501b9bb2b..315e836cd397 100644
> --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
> +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
> @@ -1927,7 +1927,8 @@ 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}2">;
> +  "%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address space|"
> +  "not permitted due to incompatible qualifiers}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 cfb3a05e9c14..cd78f096bb22 100644
> --- a/clang/lib/Sema/SemaExprCXX.cpp
> +++ b/clang/lib/Sema/SemaExprCXX.cpp
> @@ -5864,6 +5864,8 @@ 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 94d524a63f5a..ef4fa827064e 100644
> --- a/clang/lib/Sema/SemaInit.cpp
> +++ b/clang/lib/Sema/SemaInit.cpp
> @@ -8919,11 +8919,17 @@ bool InitializationSequence::Diagnose(Sema &S,
>        S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
>            << NonRefType << SourceType << 1 /*addr space*/
>            << Args[0]->getSourceRange();
> -    else
> +    else if (DroppedQualifiers.hasQualifiers())
>        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 74a0bc7c78ff..92058c3aa5fd 100644
> --- a/clang/lib/Sema/SemaOverload.cpp
> +++ b/clang/lib/Sema/SemaOverload.cpp
> @@ -3153,6 +3153,70 @@ 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).
> @@ -3178,73 +3242,16 @@ Sema::IsQualificationConversion(QualType FromType,
> QualType ToType,
>    bool PreviousToQualsIncludeConst = true;
>    bool UnwrappedAnyPointer = false;
>    while (Context.UnwrapSimilarTypes(FromType, ToType)) {
> -    // 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)
> +    if (!isQualificationConversionStep(FromType, ToType, CStyle,
> +                                       PreviousToQualsIncludeConst,
> +                                       ObjCLifetimeConversion))
>        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;
> +    UnwrappedAnyPointer = true;
>    }
>
>    // We are left with FromType and ToType being the pointee types
>    // after unwrapping the original FromType and ToType the same number
> -  // of types. If we unwrapped any pointers, and if FromType and
> +  // of times. 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);
> @@ -3990,32 +3997,41 @@ 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;
> -      }
>
> -      // 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))
> +    // 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)
>          return ImplicitConversionSequence::Better;
> -      else if (T1.isMoreQualifiedThan(T2))
> +      if (Worse)
>          return ImplicitConversionSequence::Worse;
>      }
>    }
> @@ -4402,10 +4418,19 @@ 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-related,
> -/// reference-compatible, reference-compatible with added
> -/// qualification, or incompatible, for use in C++ initialization by
> +/// determine whether they are reference-compatible,
> +/// reference-related, 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.
> @@ -4427,10 +4452,17 @@ Sema::CompareReferenceRelationship(SourceLocation
> Loc,
>    ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
>    Conv = ReferenceConversions();
>
> -  // C++ [dcl.init.ref]p4:
> +  // C++2a [dcl.init.ref]p4:
>    //   Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
> -  //   reference-related to "cv2 T2" if T1 is the same type as T2, or
> +  //   reference-related to "cv2 T2" if T1 is similar to 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.
> @@ -4444,59 +4476,47 @@ 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;
>
> -  // MS compiler ignores __unaligned qualifier for references; do the
> same.
> -  T1Quals.removeUnaligned();
> -  T2Quals.removeUnaligned();
> +  // We can have a qualification conversion. Compute whether the types are
> +  // similar at the same time.
> +  bool PreviousToQualsIncludeConst = true;
> +  do {
> +    if (T1 == T2)
> +      break;
>
> -  if (T1Quals != T2Quals)
> +    // We will need a qualification conversion.
>      Conv |= ReferenceConversions::Qualification;
>
> -  if (T1Quals.compatiblyIncludes(T2Quals))
> -    return Ref_Compatible;
> -  else
> -    return Ref_Related;
> +    // 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;
>  }
>
>  /// 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 763abd5368ef..caf3be114547 100644
> --- a/clang/test/CXX/drs/dr23xx.cpp
> +++ b/clang/test/CXX/drs/dr23xx.cpp
> @@ -4,9 +4,38 @@
>  // 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
>
> -#if __cplusplus <= 201103L
> -// expected-no-diagnostics
> +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
>  #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 8eeb7715cadf..d37ece6cb882 100644
> --- a/clang/test/CXX/drs/dr4xx.cpp
> +++ b/clang/test/CXX/drs/dr4xx.cpp
> @@ -486,14 +486,21 @@ namespace dr433 { // dr433: yes
>    S<int> s;
>  }
>
> -namespace dr434 { // dr434: yes
> +namespace dr434 { // dr434: sup 2352
>    void f() {
>      const int ci = 0;
>      int *pi = 0;
> -    const int *&rpci = pi; // expected-error {{cannot bind}}
> +    const int *&rpci = pi; // expected-error {{incompatible qualifiers}}
> +    const int * const &rcpci = pi; // OK
>      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 3ac9c51293b7..910b5c7be978 100644
> --- a/clang/test/SemaObjCXX/arc-overloading.mm
> +++ b/clang/test/SemaObjCXX/arc-overloading.mm
> @@ -174,6 +174,36 @@ 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 a97565f3a2e5..0209e1ea24de 100644
> --- a/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
> +++ b/clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
> @@ -501,12 +501,9 @@ 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__
> @@ -516,12 +513,17 @@ 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 *' to '__generic
> int *__generic *' 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__
> -// 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}} *')}}
> +#ifdef GENERIC
> +// expected-warning at -3{{pointer type mismatch ('__generic int *__generic
> *' and '__local int *__local *')}}
>  #endif
>  #endif
>  }
>
> diff  --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
> index 23a7218e897a..c4ec45736524 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="full" align="center">Yes</td>
> +    <td class="svn" align="center">Superseded by <a
> href="#2352">2352</a></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="none" align="center">Unknown</td>
> +    <td class="svn" align="center">SVN</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 4351d659e41a..fd5eb7fbabb4 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>',
> '').strip()
> +  title = title.replace('<issue_title>', '').replace('</issue_title>',
> '').replace('\r\n', '\n').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="http://wg21.link/cwg%s">%s</a></td>
> +    <td><a href="https://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
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20191227/ae35ad0c/attachment-0001.html>


More information about the cfe-commits mailing list