forked from OSchip/llvm-project
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.
This commit is contained in:
parent
a6d57a8cd4
commit
3ced23976a
|
@ -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 @@ public:
|
|||
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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 differing in noexcept.
|
||||
// to support conditionals between functions differing in noexcept. This
|
||||
// will similarly cover difference 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);
|
||||
|
|
|
@ -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 different 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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]
|
||||
|
|
Loading…
Reference in New Issue