[clang] 3ced239 - Refactor CompareReferenceRelationship and its callers in preparation for

Kim Gräsman via cfe-commits cfe-commits at lists.llvm.org
Sat Dec 28 07:35:23 PST 2019


Hi Richard,

I see the commit message mentions type sugar here; does this change
affect the AST at all?

We're seeing test failures in IWYU based on recent Clang, and I'm
suspecting this commit (it takes me a while to bisect because of Clang
build times on my laptop).

Thanks,
- Kim

On Wed, Dec 18, 2019 at 11:06 PM Richard Smith via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
>
>
> Author: Richard Smith
> Date: 2019-12-18T14:05:57-08:00
> New Revision: 3ced23976aa8a86a17017c87821c873b4ca80bc2
>
> URL: https://github.com/llvm/llvm-project/commit/3ced23976aa8a86a17017c87821c873b4ca80bc2
> DIFF: https://github.com/llvm/llvm-project/commit/3ced23976aa8a86a17017c87821c873b4ca80bc2.diff
>
> LOG: Refactor CompareReferenceRelationship and its callers in preparation for
> implementing the resolution of CWG2352.
>
> No functionality change, except that we now convert the referent of a
> reference binding to the underlying type of the reference in more cases;
> we used to happen to preserve the type sugar from the referent if the
> only type change was in the cv-qualifiers.
>
> This exposed a bug in how we generate code for trivial assignment
> operators: if the type sugar (particularly the may_alias attribute)
> got lost during reference binding, we'd use the "wrong" TBAA information
> for the load during the assignment.
>
> Added:
>
>
> Modified:
>     clang/include/clang/Sema/Sema.h
>     clang/lib/CodeGen/CGExprCXX.cpp
>     clang/lib/Sema/SemaCast.cpp
>     clang/lib/Sema/SemaExprCXX.cpp
>     clang/lib/Sema/SemaInit.cpp
>     clang/lib/Sema/SemaOverload.cpp
>     clang/test/AST/ast-dump-expr-json.cpp
>     clang/test/Index/print-type.cpp
>
> Removed:
>
>
>
> ################################################################################
> diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
> index 2730eef0bdd8..07eba0306c98 100755
> --- a/clang/include/clang/Sema/Sema.h
> +++ b/clang/include/clang/Sema/Sema.h
> @@ -31,6 +31,7 @@
>  #include "clang/AST/StmtCXX.h"
>  #include "clang/AST/TypeLoc.h"
>  #include "clang/AST/TypeOrdering.h"
> +#include "clang/Basic/BitmaskEnum.h"
>  #include "clang/Basic/ExpressionTraits.h"
>  #include "clang/Basic/Module.h"
>  #include "clang/Basic/OpenMPKinds.h"
> @@ -10703,11 +10704,26 @@ class Sema final {
>      Ref_Compatible
>    };
>
> +  // Fake up a scoped enumeration that still contextually converts to bool.
> +  struct ReferenceConversionsScope {
> +    /// The conversions that would be performed on an lvalue of type T2 when
> +    /// binding a reference of type T1 to it, as determined when evaluating
> +    /// whether T1 is reference-compatible with T2.
> +    enum ReferenceConversions {
> +      Qualification = 0x1,
> +      Function = 0x2,
> +      DerivedToBase = 0x4,
> +      ObjC = 0x8,
> +      ObjCLifetime = 0x10,
> +
> +      LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ObjCLifetime)
> +    };
> +  };
> +  using ReferenceConversions = ReferenceConversionsScope::ReferenceConversions;
> +
>    ReferenceCompareResult
>    CompareReferenceRelationship(SourceLocation Loc, QualType T1, QualType T2,
> -                               bool &DerivedToBase, bool &ObjCConversion,
> -                               bool &ObjCLifetimeConversion,
> -                               bool &FunctionConversion);
> +                               ReferenceConversions *Conv = nullptr);
>
>    ExprResult checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
>                                   Expr *CastExpr, CastKind &CastKind,
>
> diff  --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
> index 269b80b43403..3fc86136c529 100644
> --- a/clang/lib/CodeGen/CGExprCXX.cpp
> +++ b/clang/lib/CodeGen/CGExprCXX.cpp
> @@ -241,16 +241,28 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
>      }
>    }
>
> +  bool TrivialForCodegen =
> +      MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion());
> +  bool TrivialAssignment =
> +      TrivialForCodegen &&
> +      (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) &&
> +      !MD->getParent()->mayInsertExtraPadding();
> +
>    // C++17 demands that we evaluate the RHS of a (possibly-compound) assignment
>    // operator before the LHS.
>    CallArgList RtlArgStorage;
>    CallArgList *RtlArgs = nullptr;
> +  LValue TrivialAssignmentRHS;
>    if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(CE)) {
>      if (OCE->isAssignmentOp()) {
> -      RtlArgs = &RtlArgStorage;
> -      EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
> -                   drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
> -                   /*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
> +      if (TrivialAssignment) {
> +        TrivialAssignmentRHS = EmitLValue(CE->getArg(1));
> +      } else {
> +        RtlArgs = &RtlArgStorage;
> +        EmitCallArgs(*RtlArgs, MD->getType()->castAs<FunctionProtoType>(),
> +                     drop_begin(CE->arguments(), 1), CE->getDirectCallee(),
> +                     /*ParamsToSkip*/0, EvaluationOrder::ForceRightToLeft);
> +      }
>      }
>    }
>
> @@ -281,22 +293,25 @@ RValue CodeGenFunction::EmitCXXMemberOrOperatorMemberCallExpr(
>      return RValue::get(nullptr);
>    }
>
> -  if (MD->isTrivial() || (MD->isDefaulted() && MD->getParent()->isUnion())) {
> -    if (isa<CXXDestructorDecl>(MD)) return RValue::get(nullptr);
> -    if (!MD->getParent()->mayInsertExtraPadding()) {
> -      if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) {
> -        // We don't like to generate the trivial copy/move assignment operator
> -        // when it isn't necessary; just produce the proper effect here.
> -        LValue RHS = isa<CXXOperatorCallExpr>(CE)
> -                         ? MakeNaturalAlignAddrLValue(
> -                               (*RtlArgs)[0].getRValue(*this).getScalarVal(),
> -                               (*(CE->arg_begin() + 1))->getType())
> -                         : EmitLValue(*CE->arg_begin());
> -        EmitAggregateAssign(This, RHS, CE->getType());
> -        return RValue::get(This.getPointer(*this));
> -      }
> -      llvm_unreachable("unknown trivial member function");
> +  if (TrivialForCodegen) {
> +    if (isa<CXXDestructorDecl>(MD))
> +      return RValue::get(nullptr);
> +
> +    if (TrivialAssignment) {
> +      // We don't like to generate the trivial copy/move assignment operator
> +      // when it isn't necessary; just produce the proper effect here.
> +      // It's important that we use the result of EmitLValue here rather than
> +      // emitting call arguments, in order to preserve TBAA information from
> +      // the RHS.
> +      LValue RHS = isa<CXXOperatorCallExpr>(CE)
> +                       ? TrivialAssignmentRHS
> +                       : EmitLValue(*CE->arg_begin());
> +      EmitAggregateAssign(This, RHS, CE->getType());
> +      return RValue::get(This.getPointer(*this));
>      }
> +
> +    assert(MD->getParent()->mayInsertExtraPadding() &&
> +           "unknown trivial member function");
>    }
>
>    // Compute the function type we're calling.
>
> diff  --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp
> index d0b9fe122895..6216206690b0 100644
> --- a/clang/lib/Sema/SemaCast.cpp
> +++ b/clang/lib/Sema/SemaCast.cpp
> @@ -1306,10 +1306,6 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
>    // Because we try the reference downcast before this function, from now on
>    // this is the only cast possibility, so we issue an error if we fail now.
>    // FIXME: Should allow casting away constness if CStyle.
> -  bool DerivedToBase;
> -  bool ObjCConversion;
> -  bool ObjCLifetimeConversion;
> -  bool FunctionConversion;
>    QualType FromType = SrcExpr->getType();
>    QualType ToType = R->getPointeeType();
>    if (CStyle) {
> @@ -1317,9 +1313,9 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
>      ToType = ToType.getUnqualifiedType();
>    }
>
> +  Sema::ReferenceConversions RefConv;
>    Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship(
> -      SrcExpr->getBeginLoc(), ToType, FromType, DerivedToBase, ObjCConversion,
> -      ObjCLifetimeConversion, FunctionConversion);
> +      SrcExpr->getBeginLoc(), ToType, FromType, &RefConv);
>    if (RefResult != Sema::Ref_Compatible) {
>      if (CStyle || RefResult == Sema::Ref_Incompatible)
>        return TC_NotApplicable;
> @@ -1331,7 +1327,7 @@ TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr,
>      return TC_Failed;
>    }
>
> -  if (DerivedToBase) {
> +  if (RefConv & Sema::ReferenceConversions::DerivedToBase) {
>      Kind = CK_DerivedToBase;
>      CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
>                         /*DetectVirtual=*/true);
>
> diff  --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
> index 47b58df0acd9..cfb3a05e9c14 100644
> --- a/clang/lib/Sema/SemaExprCXX.cpp
> +++ b/clang/lib/Sema/SemaExprCXX.cpp
> @@ -5862,29 +5862,29 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
>    // FIXME:
>    //   Resolving a defect in P0012R1: we extend this to cover all cases where
>    //   one of the operands is reference-compatible with the other, in order
> -  //   to support conditionals between functions
> diff ering in noexcept.
> +  //   to support conditionals between functions
> diff ering in noexcept. This
> +  //   will similarly cover
> diff erence in array bounds after P0388R4.
>    ExprValueKind LVK = LHS.get()->getValueKind();
>    ExprValueKind RVK = RHS.get()->getValueKind();
>    if (!Context.hasSameType(LTy, RTy) &&
>        LVK == RVK && LVK != VK_RValue) {
>      // DerivedToBase was already handled by the class-specific case above.
>      // FIXME: Should we allow ObjC conversions here?
> -    bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
> -        FunctionConversion;
> -    if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, DerivedToBase,
> -                                     ObjCConversion, ObjCLifetimeConversion,
> -                                     FunctionConversion) == Ref_Compatible &&
> -        !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
> +    const ReferenceConversions AllowedConversions =
> +        ReferenceConversions::Qualification | ReferenceConversions::Function;
> +
> +    ReferenceConversions RefConv;
> +    if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) ==
> +            Ref_Compatible &&
> +        !(RefConv & ~AllowedConversions) &&
>          // [...] subject to the constraint that the reference must bind
>          // directly [...]
>          !RHS.get()->refersToBitField() && !RHS.get()->refersToVectorElement()) {
>        RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK);
>        RTy = RHS.get()->getType();
> -    } else if (CompareReferenceRelationship(
> -                   QuestionLoc, RTy, LTy, DerivedToBase, ObjCConversion,
> -                   ObjCLifetimeConversion,
> -                   FunctionConversion) == Ref_Compatible &&
> -               !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion &&
> +    } else if (CompareReferenceRelationship(QuestionLoc, RTy, LTy, &RefConv) ==
> +                   Ref_Compatible &&
> +               !(RefConv & ~AllowedConversions) &&
>                 !LHS.get()->refersToBitField() &&
>                 !LHS.get()->refersToVectorElement()) {
>        LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK);
>
> diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
> index cc9d1a4f6256..94d524a63f5a 100644
> --- a/clang/lib/Sema/SemaInit.cpp
> +++ b/clang/lib/Sema/SemaInit.cpp
> @@ -4229,10 +4229,8 @@ static void TryReferenceListInitialization(Sema &S,
>        return;
>
>      SourceLocation DeclLoc = Initializer->getBeginLoc();
> -    bool dummy1, dummy2, dummy3, dummy4;
>      Sema::ReferenceCompareResult RefRelationship
> -      = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, dummy1,
> -                                       dummy2, dummy3, dummy4);
> +      = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2);
>      if (RefRelationship >= Sema::Ref_Related) {
>        // Try to bind the reference here.
>        TryReferenceInitializationCore(S, Entity, Kind, Initializer, cv1T1, T1,
> @@ -4469,18 +4467,8 @@ static OverloadingResult TryRefInitWithConversionFunction(
>    QualType cv2T2 = Initializer->getType();
>    QualType T2 = cv2T2.getUnqualifiedType();
>
> -  bool DerivedToBase;
> -  bool ObjCConversion;
> -  bool ObjCLifetimeConversion;
> -  bool FunctionConversion;
> -  assert(!S.CompareReferenceRelationship(
> -             Initializer->getBeginLoc(), T1, T2, DerivedToBase, ObjCConversion,
> -             ObjCLifetimeConversion, FunctionConversion) &&
> +  assert(!S.CompareReferenceRelationship(Initializer->getBeginLoc(), T1, T2) &&
>           "Must have incompatible references when binding via conversion");
> -  (void)DerivedToBase;
> -  (void)ObjCConversion;
> -  (void)ObjCLifetimeConversion;
> -  (void)FunctionConversion;
>
>    // Build the candidate set directly in the initialization sequence
>    // structure, so that it will persist if we fail.
> @@ -4604,14 +4592,9 @@ static OverloadingResult TryRefInitWithConversionFunction(
>
>    // Determine whether we'll need to perform derived-to-base adjustments or
>    // other conversions.
> -  bool NewDerivedToBase = false;
> -  bool NewObjCConversion = false;
> -  bool NewObjCLifetimeConversion = false;
> -  bool NewFunctionConversion = false;
> +  Sema::ReferenceConversions RefConv;
>    Sema::ReferenceCompareResult NewRefRelationship =
> -      S.CompareReferenceRelationship(
> -          DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion,
> -          NewObjCLifetimeConversion, NewFunctionConversion);
> +      S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, &RefConv);
>
>    // Add the final conversion sequence, if necessary.
>    if (NewRefRelationship == Sema::Ref_Incompatible) {
> @@ -4641,12 +4624,16 @@ static OverloadingResult TryRefInitWithConversionFunction(
>    Sequence.AddReferenceBindingStep(cv1T4, VK == VK_RValue);
>    VK = IsLValueRef ? VK_LValue : VK_XValue;
>
> -  if (NewDerivedToBase)
> +  if (RefConv & Sema::ReferenceConversions::DerivedToBase)
>      Sequence.AddDerivedToBaseCastStep(cv1T1, VK);
> -  else if (NewObjCConversion)
> +  else if (RefConv & Sema::ReferenceConversions::ObjC)
>      Sequence.AddObjCObjectConversionStep(cv1T1);
> -  else if (NewFunctionConversion)
> +  else if (RefConv & Sema::ReferenceConversions::Function)
>      Sequence.AddQualificationConversionStep(cv1T1, VK);
> +  else if (RefConv & Sema::ReferenceConversions::Qualification) {
> +    if (!S.Context.hasSameType(cv1T4, cv1T1))
> +      Sequence.AddQualificationConversionStep(cv1T1, VK);
> +  }
>
>    return OR_Success;
>  }
> @@ -4700,17 +4687,15 @@ static void TryReferenceInitializationCore(Sema &S,
>                                             InitializationSequence &Sequence) {
>    QualType DestType = Entity.getType();
>    SourceLocation DeclLoc = Initializer->getBeginLoc();
> +
>    // Compute some basic properties of the types and the initializer.
>    bool isLValueRef = DestType->isLValueReferenceType();
>    bool isRValueRef = !isLValueRef;
> -  bool DerivedToBase = false;
> -  bool ObjCConversion = false;
> -  bool ObjCLifetimeConversion = false;
> -  bool FunctionConversion = false;
>    Expr::Classification InitCategory = Initializer->Classify(S.Context);
> -  Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
> -      DeclLoc, cv1T1, cv2T2, DerivedToBase, ObjCConversion,
> -      ObjCLifetimeConversion, FunctionConversion);
> +
> +  Sema::ReferenceConversions RefConv;
> +  Sema::ReferenceCompareResult RefRelationship =
> +      S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, &RefConv);
>
>    // C++0x [dcl.init.ref]p5:
>    //   A reference to type "cv1 T1" is initialized by an expression of type
> @@ -4730,19 +4715,25 @@ static void TryReferenceInitializationCore(Sema &S,
>            RefRelationship == Sema::Ref_Related))) {
>        //   - is an lvalue (but is not a bit-field), and "cv1 T1" is
>        //     reference-compatible with "cv2 T2," or
> -      if (T1Quals != T2Quals)
> -        // Convert to cv1 T2. This should only add qualifiers unless this is a
> -        // c-style cast. The removal of qualifiers in that case notionally
> -        // happens after the reference binding, but that doesn't matter.
> -        Sequence.AddQualificationConversionStep(
> -            S.Context.getQualifiedType(T2, T1Quals),
> -            Initializer->getValueKind());
> -      if (DerivedToBase)
> -        Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
> -      else if (ObjCConversion)
> -        Sequence.AddObjCObjectConversionStep(cv1T1);
> -      else if (FunctionConversion)
> -        Sequence.AddQualificationConversionStep(cv1T1, VK_LValue);
> +      if (RefConv & (Sema::ReferenceConversions::DerivedToBase |
> +                     Sema::ReferenceConversions::ObjC)) {
> +        // If we're converting the pointee, add any qualifiers first;
> +        // these qualifiers must all be top-level, so just convert to "cv1 T2".
> +        if (RefConv & (Sema::ReferenceConversions::Qualification))
> +          Sequence.AddQualificationConversionStep(
> +              S.Context.getQualifiedType(T2, T1Quals),
> +              Initializer->getValueKind());
> +        if (RefConv & Sema::ReferenceConversions::DerivedToBase)
> +          Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue);
> +        else
> +          Sequence.AddObjCObjectConversionStep(cv1T1);
> +      } else if (RefConv & (Sema::ReferenceConversions::Qualification |
> +                            Sema::ReferenceConversions::Function)) {
> +        // Perform a (possibly multi-level) qualification conversion.
> +        // FIXME: Should we use a
> diff erent step kind for function conversions?
> +        Sequence.AddQualificationConversionStep(cv1T1,
> +                                                Initializer->getValueKind());
> +      }
>
>        // We only create a temporary here when binding a reference to a
>        // bit-field or vector element. Those cases are't supposed to be
> @@ -4873,14 +4864,19 @@ static void TryReferenceInitializationCore(Sema &S,
>        T4Quals.addAddressSpace(T1Quals.getAddressSpace());
>        QualType cv1T4WithAS = S.Context.getQualifiedType(T2, T4Quals);
>        Sequence.AddQualificationConversionStep(cv1T4WithAS, ValueKind);
> +      cv1T4 = cv1T4WithAS;
>      }
>
>      //   In any case, the reference is bound to the resulting glvalue (or to
>      //   an appropriate base class subobject).
> -    if (DerivedToBase)
> +    if (RefConv & Sema::ReferenceConversions::DerivedToBase)
>        Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind);
> -    else if (ObjCConversion)
> +    else if (RefConv & Sema::ReferenceConversions::ObjC)
>        Sequence.AddObjCObjectConversionStep(cv1T1);
> +    else if (RefConv & Sema::ReferenceConversions::Qualification) {
> +      if (!S.Context.hasSameType(cv1T4, cv1T1))
> +        Sequence.AddQualificationConversionStep(cv1T1, ValueKind);
> +    }
>      return;
>    }
>
>
> diff  --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
> index 22f1a087ca22..74a0bc7c78ff 100644
> --- a/clang/lib/Sema/SemaOverload.cpp
> +++ b/clang/lib/Sema/SemaOverload.cpp
> @@ -4412,10 +4412,7 @@ static bool isTypeValid(QualType T) {
>  Sema::ReferenceCompareResult
>  Sema::CompareReferenceRelationship(SourceLocation Loc,
>                                     QualType OrigT1, QualType OrigT2,
> -                                   bool &DerivedToBase,
> -                                   bool &ObjCConversion,
> -                                   bool &ObjCLifetimeConversion,
> -                                   bool &FunctionConversion) {
> +                                   ReferenceConversions *ConvOut) {
>    assert(!OrigT1->isReferenceType() &&
>      "T1 must be the pointee type of the reference type");
>    assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type");
> @@ -4426,24 +4423,25 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
>    QualType UnqualT1 = Context.getUnqualifiedArrayType(T1, T1Quals);
>    QualType UnqualT2 = Context.getUnqualifiedArrayType(T2, T2Quals);
>
> +  ReferenceConversions ConvTmp;
> +  ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
> +  Conv = ReferenceConversions();
> +
>    // C++ [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
>    //   T1 is a base class of T2.
> -  DerivedToBase = false;
> -  ObjCConversion = false;
> -  ObjCLifetimeConversion = false;
>    QualType ConvertedT2;
>    if (UnqualT1 == UnqualT2) {
>      // Nothing to do.
>    } else if (isCompleteType(Loc, OrigT2) &&
>               isTypeValid(UnqualT1) && isTypeValid(UnqualT2) &&
>               IsDerivedFrom(Loc, UnqualT2, UnqualT1))
> -    DerivedToBase = true;
> +    Conv |= ReferenceConversions::DerivedToBase;
>    else if (UnqualT1->isObjCObjectOrInterfaceType() &&
>             UnqualT2->isObjCObjectOrInterfaceType() &&
>             Context.canBindObjCObjectType(UnqualT1, UnqualT2))
> -    ObjCConversion = true;
> +    Conv |= ReferenceConversions::ObjC;
>    else if (UnqualT2->isFunctionType() &&
>             IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
>      // C++1z [dcl.init.ref]p4:
> @@ -4452,7 +4450,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
>      //
>      // We extend this to also apply to 'noreturn', so allow any function
>      // conversion between function types.
> -    FunctionConversion = true;
> +    Conv |= ReferenceConversions::Function;
>      return Ref_Compatible;
>    } else
>      return Ref_Incompatible;
> @@ -4482,7 +4480,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
>    if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
>        T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
>      if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals))
> -      ObjCLifetimeConversion = true;
> +      Conv |= ReferenceConversions::ObjCLifetime;
>
>      T1Quals.removeObjCLifetime();
>      T2Quals.removeObjCLifetime();
> @@ -4492,6 +4490,9 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
>    T1Quals.removeUnaligned();
>    T2Quals.removeUnaligned();
>
> +  if (T1Quals != T2Quals)
> +    Conv |= ReferenceConversions::Qualification;
> +
>    if (T1Quals.compatiblyIncludes(T2Quals))
>      return Ref_Compatible;
>    else
> @@ -4532,11 +4533,6 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
>        continue;
>
>      if (AllowRvalues) {
> -      bool DerivedToBase = false;
> -      bool ObjCConversion = false;
> -      bool ObjCLifetimeConversion = false;
> -      bool FunctionConversion = false;
> -
>        // If we are initializing an rvalue reference, don't permit conversion
>        // functions that return lvalues.
>        if (!ConvTemplate && DeclType->isRValueReferenceType()) {
> @@ -4552,9 +4548,8 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
>                Conv->getConversionType()
>                    .getNonReferenceType()
>                    .getUnqualifiedType(),
> -              DeclType.getNonReferenceType().getUnqualifiedType(),
> -              DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
> -              FunctionConversion) == Sema::Ref_Incompatible)
> +              DeclType.getNonReferenceType().getUnqualifiedType()) ==
> +              Sema::Ref_Incompatible)
>          continue;
>      } else {
>        // If the conversion function doesn't return a reference type,
> @@ -4655,14 +4650,36 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
>
>    // Compute some basic properties of the types and the initializer.
>    bool isRValRef = DeclType->isRValueReferenceType();
> -  bool DerivedToBase = false;
> -  bool ObjCConversion = false;
> -  bool ObjCLifetimeConversion = false;
> -  bool FunctionConversion = false;
>    Expr::Classification InitCategory = Init->Classify(S.Context);
> -  Sema::ReferenceCompareResult RefRelationship = S.CompareReferenceRelationship(
> -      DeclLoc, T1, T2, DerivedToBase, ObjCConversion, ObjCLifetimeConversion,
> -      FunctionConversion);
> +
> +  Sema::ReferenceConversions RefConv;
> +  Sema::ReferenceCompareResult RefRelationship =
> +      S.CompareReferenceRelationship(DeclLoc, T1, T2, &RefConv);
> +
> +  auto SetAsReferenceBinding = [&](bool BindsDirectly) {
> +    ICS.setStandard();
> +    ICS.Standard.First = ICK_Identity;
> +    ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase)
> +                              ? ICK_Derived_To_Base
> +                              : (RefConv & Sema::ReferenceConversions::ObjC)
> +                                    ? ICK_Compatible_Conversion
> +                                    : ICK_Identity;
> +    ICS.Standard.Third = ICK_Identity;
> +    ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
> +    ICS.Standard.setToType(0, T2);
> +    ICS.Standard.setToType(1, T1);
> +    ICS.Standard.setToType(2, T1);
> +    ICS.Standard.ReferenceBinding = true;
> +    ICS.Standard.DirectBinding = BindsDirectly;
> +    ICS.Standard.IsLvalueReference = !isRValRef;
> +    ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
> +    ICS.Standard.BindsToRvalue = InitCategory.isRValue();
> +    ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
> +    ICS.Standard.ObjCLifetimeConversionBinding =
> +        (RefConv & Sema::ReferenceConversions::ObjCLifetime) != 0;
> +    ICS.Standard.CopyConstructor = nullptr;
> +    ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
> +  };
>
>    // C++0x [dcl.init.ref]p5:
>    //   A reference to type "cv1 T1" is initialized by an expression
> @@ -4682,25 +4699,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
>        //   has a type that is a derived class of the parameter type,
>        //   in which case the implicit conversion sequence is a
>        //   derived-to-base Conversion (13.3.3.1).
> -      ICS.setStandard();
> -      ICS.Standard.First = ICK_Identity;
> -      ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
> -                         : ObjCConversion? ICK_Compatible_Conversion
> -                         : ICK_Identity;
> -      ICS.Standard.Third = ICK_Identity;
> -      ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
> -      ICS.Standard.setToType(0, T2);
> -      ICS.Standard.setToType(1, T1);
> -      ICS.Standard.setToType(2, T1);
> -      ICS.Standard.ReferenceBinding = true;
> -      ICS.Standard.DirectBinding = true;
> -      ICS.Standard.IsLvalueReference = !isRValRef;
> -      ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
> -      ICS.Standard.BindsToRvalue = false;
> -      ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
> -      ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
> -      ICS.Standard.CopyConstructor = nullptr;
> -      ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
> +      SetAsReferenceBinding(/*BindsDirectly=*/true);
>
>        // Nothing more to do: the inaccessibility/ambiguity check for
>        // derived-to-base conversions is suppressed when we're
> @@ -4738,34 +4737,16 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
>    //               lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or
>    if (RefRelationship == Sema::Ref_Compatible &&
>        (InitCategory.isXValue() ||
> -       (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) ||
> +       (InitCategory.isPRValue() &&
> +          (T2->isRecordType() || T2->isArrayType())) ||
>         (InitCategory.isLValue() && T2->isFunctionType()))) {
> -    ICS.setStandard();
> -    ICS.Standard.First = ICK_Identity;
> -    ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base
> -                      : ObjCConversion? ICK_Compatible_Conversion
> -                      : ICK_Identity;
> -    ICS.Standard.Third = ICK_Identity;
> -    ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
> -    ICS.Standard.setToType(0, T2);
> -    ICS.Standard.setToType(1, T1);
> -    ICS.Standard.setToType(2, T1);
> -    ICS.Standard.ReferenceBinding = true;
> -    // In C++0x, this is always a direct binding. In C++98/03, it's a direct
> +    // In C++11, this is always a direct binding. In C++98/03, it's a direct
>      // binding unless we're binding to a class prvalue.
>      // Note: Although xvalues wouldn't normally show up in C++98/03 code, we
>      // allow the use of rvalue references in C++98/03 for the benefit of
>      // standard library implementors; therefore, we need the xvalue check here.
> -    ICS.Standard.DirectBinding =
> -      S.getLangOpts().CPlusPlus11 ||
> -      !(InitCategory.isPRValue() || T2->isRecordType());
> -    ICS.Standard.IsLvalueReference = !isRValRef;
> -    ICS.Standard.BindsToFunctionLvalue = T2->isFunctionType();
> -    ICS.Standard.BindsToRvalue = InitCategory.isRValue();
> -    ICS.Standard.BindsImplicitObjectArgumentWithoutRefQualifier = false;
> -    ICS.Standard.ObjCLifetimeConversionBinding = ObjCLifetimeConversion;
> -    ICS.Standard.CopyConstructor = nullptr;
> -    ICS.Standard.DeprecatedStringLiteralToCharPtr = false;
> +    SetAsReferenceBinding(/*BindsDirectly=*/S.getLangOpts().CPlusPlus11 ||
> +                          !(InitCategory.isPRValue() || T2->isRecordType()));
>      return ICS;
>    }
>
> @@ -5084,13 +5065,8 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType,
>        }
>
>        // Compute some basic properties of the types and the initializer.
> -      bool dummy1 = false;
> -      bool dummy2 = false;
> -      bool dummy3 = false;
> -      bool dummy4 = false;
>        Sema::ReferenceCompareResult RefRelationship =
> -          S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2, dummy1,
> -                                         dummy2, dummy3, dummy4);
> +          S.CompareReferenceRelationship(From->getBeginLoc(), T1, T2);
>
>        if (RefRelationship >= Sema::Ref_Related) {
>          return TryReferenceInit(S, Init, ToType, /*FIXME*/ From->getBeginLoc(),
>
> diff  --git a/clang/test/AST/ast-dump-expr-json.cpp b/clang/test/AST/ast-dump-expr-json.cpp
> index 0459c1842787..09e775e22ecf 100644
> --- a/clang/test/AST/ast-dump-expr-json.cpp
> +++ b/clang/test/AST/ast-dump-expr-json.cpp
> @@ -7991,7 +7991,6 @@ void TestNonADLCall3() {
>  // CHECK-NEXT:           }
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "type": {
> -// CHECK-NEXT:           "desugaredQualType": "const NS::X",
>  // CHECK-NEXT:           "qualType": "const NS::X"
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "valueCategory": "lvalue",
> @@ -8148,7 +8147,6 @@ void TestNonADLCall3() {
>  // CHECK-NEXT:           }
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "type": {
> -// CHECK-NEXT:           "desugaredQualType": "const NS::X",
>  // CHECK-NEXT:           "qualType": "const NS::X"
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "valueCategory": "lvalue",
> @@ -8430,7 +8428,6 @@ void TestNonADLCall3() {
>  // CHECK-NEXT:           }
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "type": {
> -// CHECK-NEXT:           "desugaredQualType": "const NS::X",
>  // CHECK-NEXT:           "qualType": "const NS::X"
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "valueCategory": "lvalue",
> @@ -8758,7 +8755,6 @@ void TestNonADLCall3() {
>  // CHECK-NEXT:           }
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "type": {
> -// CHECK-NEXT:           "desugaredQualType": "const NS::X",
>  // CHECK-NEXT:           "qualType": "const NS::X"
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "valueCategory": "lvalue",
> @@ -8915,7 +8911,6 @@ void TestNonADLCall3() {
>  // CHECK-NEXT:           }
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "type": {
> -// CHECK-NEXT:           "desugaredQualType": "const NS::X",
>  // CHECK-NEXT:           "qualType": "const NS::X"
>  // CHECK-NEXT:          },
>  // CHECK-NEXT:          "valueCategory": "lvalue",
>
> diff  --git a/clang/test/Index/print-type.cpp b/clang/test/Index/print-type.cpp
> index 32d1185eecb9..abe8d45c41db 100644
> --- a/clang/test/Index/print-type.cpp
> +++ b/clang/test/Index/print-type.cpp
> @@ -196,7 +196,7 @@ inline namespace InlineNS {}
>  // CHECK: TemplateRef=Specialization:66:8 [type=] [typekind=Invalid] [isPOD=0]
>  // CHECK: CallExpr=Specialization:66:8 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
>  // CHECK: VarDecl=autoTemplRefParam:72:6 (Definition) [type=Specialization<Specialization<bool> &>] [typekind=Auto] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
> -// CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization<Specialization<bool> &>] [typekind=Unexposed] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=const Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
> +// CHECK: UnexposedExpr=templRefParam:71:40 [type=const Specialization<Specialization<bool> &>] [typekind=Record] const [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
>  // CHECK: DeclRefExpr=templRefParam:71:40 [type=Specialization<Specialization<bool> &>] [typekind=Unexposed] [templateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [canonicaltype=Specialization<Specialization<bool> &>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=Specialization<bool> &] [typekind=LValueReference]] [isPOD=1]
>  // CHECK: TypeAliasDecl=baz:76:7 (Definition) [type=baz] [typekind=Typedef] [templateargs/1= [type=A<void>] [typekind=Unexposed]] [canonicaltype=A<void>] [canonicaltypekind=Record] [canonicaltemplateargs/1= [type=void] [typekind=Void]] [isPOD=0]
>  // CHECK: VarDecl=autoTemplPointer:78:6 (Definition) [type=Specialization<Specialization<bool> &> *] [typekind=Auto] [canonicaltype=Specialization<Specialization<bool> &> *] [canonicaltypekind=Pointer] [isPOD=1] [pointeetype=Specialization<Specialization<bool> &>] [pointeekind=Record]
>
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


More information about the cfe-commits mailing list