[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 10:33:14 PST 2019


Yes, it is this change that broke us.

I still don't fully understand what the change was, but it appears to
mess things up for IWYU for operator== with templates and const,
somehow.

Could you expand on what changed here and how the AST might be affected?

Thanks,
- Kim

On Sat, Dec 28, 2019 at 4:35 PM Kim Gräsman <kim.grasman at gmail.com> wrote:
>
> 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