[clang] 3ced239 - Refactor CompareReferenceRelationship and its callers in preparation for
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Wed Dec 18 14:06:27 PST 2019
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]
More information about the cfe-commits
mailing list