[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