[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