forked from OSchip/llvm-project
CWG2352: Allow qualification conversions during reference binding.
The language wording change forgot to update overload resolution to rank implicit conversion sequences based on qualification conversions in reference bindings. The anticipated resolution for that oversight is implemented here -- we order candidates based on qualification conversion, not only on top-level cv-qualifiers, including ranking reference bindings against non-reference bindings if they differ in non-top-level qualification conversions. For OpenCL/C++, this allows reference binding between pointers with differing (nested) address spaces. This makes the behavior of reference binding consistent with that of implicit pointer conversions, as is the purpose of this change, but that pre-existing behavior for pointer conversions is itself probably not correct. In any case, it's now consistently the same behavior and implemented in only one place. This reinstates commitde21704ba9
, reverted in commitd8018233d1
, with workarounds for some overload resolution ordering problems introduced by CWG2352.
This commit is contained in:
parent
3727ca3137
commit
f041e9ad70
|
@ -1933,7 +1933,8 @@ def err_lvalue_reference_bind_to_unrelated : Error<
|
||||||
"cannot bind to a value of unrelated type}1,2">;
|
"cannot bind to a value of unrelated type}1,2">;
|
||||||
def err_reference_bind_drops_quals : Error<
|
def err_reference_bind_drops_quals : Error<
|
||||||
"binding reference %diff{of type $ to value of type $|to value}0,1 "
|
"binding reference %diff{of type $ to value of type $|to value}0,1 "
|
||||||
"%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address space}2">;
|
"%select{drops %3 qualifier%plural{1:|2:|4:|:s}4|changes address space|"
|
||||||
|
"not permitted due to incompatible qualifiers}2">;
|
||||||
def err_reference_bind_failed : Error<
|
def err_reference_bind_failed : Error<
|
||||||
"reference %diff{to %select{type|incomplete type}1 $ could not bind to an "
|
"reference %diff{to %select{type|incomplete type}1 $ could not bind to an "
|
||||||
"%select{rvalue|lvalue}2 of type $|could not bind to %select{rvalue|lvalue}2 of "
|
"%select{rvalue|lvalue}2 of type $|could not bind to %select{rvalue|lvalue}2 of "
|
||||||
|
|
|
@ -10745,10 +10745,11 @@ public:
|
||||||
/// whether T1 is reference-compatible with T2.
|
/// whether T1 is reference-compatible with T2.
|
||||||
enum ReferenceConversions {
|
enum ReferenceConversions {
|
||||||
Qualification = 0x1,
|
Qualification = 0x1,
|
||||||
Function = 0x2,
|
NestedQualification = 0x2,
|
||||||
DerivedToBase = 0x4,
|
Function = 0x4,
|
||||||
ObjC = 0x8,
|
DerivedToBase = 0x8,
|
||||||
ObjCLifetime = 0x10,
|
ObjC = 0x10,
|
||||||
|
ObjCLifetime = 0x20,
|
||||||
|
|
||||||
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ObjCLifetime)
|
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ObjCLifetime)
|
||||||
};
|
};
|
||||||
|
|
|
@ -5864,6 +5864,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
|
||||||
// one of the operands is reference-compatible with the other, in order
|
// one of the operands is reference-compatible with the other, in order
|
||||||
// to support conditionals between functions differing in noexcept. This
|
// to support conditionals between functions differing in noexcept. This
|
||||||
// will similarly cover difference in array bounds after P0388R4.
|
// will similarly cover difference in array bounds after P0388R4.
|
||||||
|
// FIXME: If LTy and RTy have a composite pointer type, should we convert to
|
||||||
|
// that instead?
|
||||||
ExprValueKind LVK = LHS.get()->getValueKind();
|
ExprValueKind LVK = LHS.get()->getValueKind();
|
||||||
ExprValueKind RVK = RHS.get()->getValueKind();
|
ExprValueKind RVK = RHS.get()->getValueKind();
|
||||||
if (!Context.hasSameType(LTy, RTy) &&
|
if (!Context.hasSameType(LTy, RTy) &&
|
||||||
|
@ -5871,7 +5873,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
|
||||||
// DerivedToBase was already handled by the class-specific case above.
|
// DerivedToBase was already handled by the class-specific case above.
|
||||||
// FIXME: Should we allow ObjC conversions here?
|
// FIXME: Should we allow ObjC conversions here?
|
||||||
const ReferenceConversions AllowedConversions =
|
const ReferenceConversions AllowedConversions =
|
||||||
ReferenceConversions::Qualification | ReferenceConversions::Function;
|
ReferenceConversions::Qualification |
|
||||||
|
ReferenceConversions::NestedQualification |
|
||||||
|
ReferenceConversions::Function;
|
||||||
|
|
||||||
ReferenceConversions RefConv;
|
ReferenceConversions RefConv;
|
||||||
if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) ==
|
if (CompareReferenceRelationship(QuestionLoc, LTy, RTy, &RefConv) ==
|
||||||
|
|
|
@ -8911,11 +8911,17 @@ bool InitializationSequence::Diagnose(Sema &S,
|
||||||
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
|
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
|
||||||
<< NonRefType << SourceType << 1 /*addr space*/
|
<< NonRefType << SourceType << 1 /*addr space*/
|
||||||
<< Args[0]->getSourceRange();
|
<< Args[0]->getSourceRange();
|
||||||
else
|
else if (DroppedQualifiers.hasQualifiers())
|
||||||
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
|
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
|
||||||
<< NonRefType << SourceType << 0 /*cv quals*/
|
<< NonRefType << SourceType << 0 /*cv quals*/
|
||||||
<< Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers())
|
<< Qualifiers::fromCVRMask(DroppedQualifiers.getCVRQualifiers())
|
||||||
<< DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange();
|
<< DroppedQualifiers.getCVRQualifiers() << Args[0]->getSourceRange();
|
||||||
|
else
|
||||||
|
// FIXME: Consider decomposing the type and explaining which qualifiers
|
||||||
|
// were dropped where, or on which level a 'const' is missing, etc.
|
||||||
|
S.Diag(Kind.getLocation(), diag::err_reference_bind_drops_quals)
|
||||||
|
<< NonRefType << SourceType << 2 /*incompatible quals*/
|
||||||
|
<< Args[0]->getSourceRange();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3169,6 +3169,70 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Perform a single iteration of the loop for checking if a qualification
|
||||||
|
/// conversion is valid.
|
||||||
|
///
|
||||||
|
/// Specifically, check whether any change between the qualifiers of \p
|
||||||
|
/// FromType and \p ToType is permissible, given knowledge about whether every
|
||||||
|
/// outer layer is const-qualified.
|
||||||
|
static bool isQualificationConversionStep(QualType FromType, QualType ToType,
|
||||||
|
bool CStyle,
|
||||||
|
bool &PreviousToQualsIncludeConst,
|
||||||
|
bool &ObjCLifetimeConversion) {
|
||||||
|
Qualifiers FromQuals = FromType.getQualifiers();
|
||||||
|
Qualifiers ToQuals = ToType.getQualifiers();
|
||||||
|
|
||||||
|
// Ignore __unaligned qualifier if this type is void.
|
||||||
|
if (ToType.getUnqualifiedType()->isVoidType())
|
||||||
|
FromQuals.removeUnaligned();
|
||||||
|
|
||||||
|
// Objective-C ARC:
|
||||||
|
// Check Objective-C lifetime conversions.
|
||||||
|
if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime()) {
|
||||||
|
if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
|
||||||
|
if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
|
||||||
|
ObjCLifetimeConversion = true;
|
||||||
|
FromQuals.removeObjCLifetime();
|
||||||
|
ToQuals.removeObjCLifetime();
|
||||||
|
} else {
|
||||||
|
// Qualification conversions cannot cast between different
|
||||||
|
// Objective-C lifetime qualifiers.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow addition/removal of GC attributes but not changing GC attributes.
|
||||||
|
if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
|
||||||
|
(!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
|
||||||
|
FromQuals.removeObjCGCAttr();
|
||||||
|
ToQuals.removeObjCGCAttr();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- for every j > 0, if const is in cv 1,j then const is in cv
|
||||||
|
// 2,j, and similarly for volatile.
|
||||||
|
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// For a C-style cast, just require the address spaces to overlap.
|
||||||
|
// FIXME: Does "superset" also imply the representation of a pointer is the
|
||||||
|
// same? We're assuming that it does here and in compatiblyIncludes.
|
||||||
|
if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
|
||||||
|
!FromQuals.isAddressSpaceSupersetOf(ToQuals))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// -- if the cv 1,j and cv 2,j are different, then const is in
|
||||||
|
// every cv for 0 < k < j.
|
||||||
|
if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers() &&
|
||||||
|
!PreviousToQualsIncludeConst)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Keep track of whether all prior cv-qualifiers in the "to" type
|
||||||
|
// include const.
|
||||||
|
PreviousToQualsIncludeConst =
|
||||||
|
PreviousToQualsIncludeConst && ToQuals.hasConst();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// IsQualificationConversion - Determines whether the conversion from
|
/// IsQualificationConversion - Determines whether the conversion from
|
||||||
/// an rvalue of type FromType to ToType is a qualification conversion
|
/// an rvalue of type FromType to ToType is a qualification conversion
|
||||||
/// (C++ 4.4).
|
/// (C++ 4.4).
|
||||||
|
@ -3194,73 +3258,16 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
|
||||||
bool PreviousToQualsIncludeConst = true;
|
bool PreviousToQualsIncludeConst = true;
|
||||||
bool UnwrappedAnyPointer = false;
|
bool UnwrappedAnyPointer = false;
|
||||||
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
|
while (Context.UnwrapSimilarTypes(FromType, ToType)) {
|
||||||
// Within each iteration of the loop, we check the qualifiers to
|
if (!isQualificationConversionStep(FromType, ToType, CStyle,
|
||||||
// determine if this still looks like a qualification
|
PreviousToQualsIncludeConst,
|
||||||
// conversion. Then, if all is well, we unwrap one more level of
|
ObjCLifetimeConversion))
|
||||||
// pointers or pointers-to-members and do it all again
|
return false;
|
||||||
// until there are no more pointers or pointers-to-members left to
|
|
||||||
// unwrap.
|
|
||||||
UnwrappedAnyPointer = true;
|
UnwrappedAnyPointer = true;
|
||||||
|
|
||||||
Qualifiers FromQuals = FromType.getQualifiers();
|
|
||||||
Qualifiers ToQuals = ToType.getQualifiers();
|
|
||||||
|
|
||||||
// Ignore __unaligned qualifier if this type is void.
|
|
||||||
if (ToType.getUnqualifiedType()->isVoidType())
|
|
||||||
FromQuals.removeUnaligned();
|
|
||||||
|
|
||||||
// Objective-C ARC:
|
|
||||||
// Check Objective-C lifetime conversions.
|
|
||||||
if (FromQuals.getObjCLifetime() != ToQuals.getObjCLifetime() &&
|
|
||||||
UnwrappedAnyPointer) {
|
|
||||||
if (ToQuals.compatiblyIncludesObjCLifetime(FromQuals)) {
|
|
||||||
if (isNonTrivialObjCLifetimeConversion(FromQuals, ToQuals))
|
|
||||||
ObjCLifetimeConversion = true;
|
|
||||||
FromQuals.removeObjCLifetime();
|
|
||||||
ToQuals.removeObjCLifetime();
|
|
||||||
} else {
|
|
||||||
// Qualification conversions cannot cast between different
|
|
||||||
// Objective-C lifetime qualifiers.
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow addition/removal of GC attributes but not changing GC attributes.
|
|
||||||
if (FromQuals.getObjCGCAttr() != ToQuals.getObjCGCAttr() &&
|
|
||||||
(!FromQuals.hasObjCGCAttr() || !ToQuals.hasObjCGCAttr())) {
|
|
||||||
FromQuals.removeObjCGCAttr();
|
|
||||||
ToQuals.removeObjCGCAttr();
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- for every j > 0, if const is in cv 1,j then const is in cv
|
|
||||||
// 2,j, and similarly for volatile.
|
|
||||||
if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// -- if the cv 1,j and cv 2,j are different, then const is in
|
|
||||||
// every cv for 0 < k < j.
|
|
||||||
if (!CStyle && FromQuals.getCVRQualifiers() != ToQuals.getCVRQualifiers()
|
|
||||||
&& !PreviousToQualsIncludeConst)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Keep track of whether all prior cv-qualifiers in the "to" type
|
|
||||||
// include const.
|
|
||||||
PreviousToQualsIncludeConst
|
|
||||||
= PreviousToQualsIncludeConst && ToQuals.hasConst();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allows address space promotion by language rules implemented in
|
|
||||||
// Type::Qualifiers::isAddressSpaceSupersetOf.
|
|
||||||
Qualifiers FromQuals = FromType.getQualifiers();
|
|
||||||
Qualifiers ToQuals = ToType.getQualifiers();
|
|
||||||
if (!ToQuals.isAddressSpaceSupersetOf(FromQuals) &&
|
|
||||||
!FromQuals.isAddressSpaceSupersetOf(ToQuals)) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are left with FromType and ToType being the pointee types
|
// We are left with FromType and ToType being the pointee types
|
||||||
// after unwrapping the original FromType and ToType the same number
|
// after unwrapping the original FromType and ToType the same number
|
||||||
// of types. If we unwrapped any pointers, and if FromType and
|
// of times. If we unwrapped any pointers, and if FromType and
|
||||||
// ToType have the same unqualified type (since we checked
|
// ToType have the same unqualified type (since we checked
|
||||||
// qualifiers above), then this is a qualification conversion.
|
// qualifiers above), then this is a qualification conversion.
|
||||||
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
|
return UnwrappedAnyPointer && Context.hasSameUnqualifiedType(FromType,ToType);
|
||||||
|
@ -3982,6 +3989,14 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
|
||||||
|
// Check for a better reference binding based on the kind of bindings.
|
||||||
|
if (isBetterReferenceBindingKind(SCS1, SCS2))
|
||||||
|
return ImplicitConversionSequence::Better;
|
||||||
|
else if (isBetterReferenceBindingKind(SCS2, SCS1))
|
||||||
|
return ImplicitConversionSequence::Worse;
|
||||||
|
}
|
||||||
|
|
||||||
// Compare based on qualification conversions (C++ 13.3.3.2p3,
|
// Compare based on qualification conversions (C++ 13.3.3.2p3,
|
||||||
// bullet 3).
|
// bullet 3).
|
||||||
if (ImplicitConversionSequence::CompareKind QualCK
|
if (ImplicitConversionSequence::CompareKind QualCK
|
||||||
|
@ -3989,12 +4004,6 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
|
||||||
return QualCK;
|
return QualCK;
|
||||||
|
|
||||||
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
|
if (SCS1.ReferenceBinding && SCS2.ReferenceBinding) {
|
||||||
// Check for a better reference binding based on the kind of bindings.
|
|
||||||
if (isBetterReferenceBindingKind(SCS1, SCS2))
|
|
||||||
return ImplicitConversionSequence::Better;
|
|
||||||
else if (isBetterReferenceBindingKind(SCS2, SCS1))
|
|
||||||
return ImplicitConversionSequence::Worse;
|
|
||||||
|
|
||||||
// C++ [over.ics.rank]p3b4:
|
// C++ [over.ics.rank]p3b4:
|
||||||
// -- S1 and S2 are reference bindings (8.5.3), and the types to
|
// -- S1 and S2 are reference bindings (8.5.3), and the types to
|
||||||
// which the references refer are the same type except for
|
// which the references refer are the same type except for
|
||||||
|
@ -4026,7 +4035,7 @@ CompareStandardConversionSequences(Sema &S, SourceLocation Loc,
|
||||||
T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
|
T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
|
||||||
if (T2.isMoreQualifiedThan(T1))
|
if (T2.isMoreQualifiedThan(T1))
|
||||||
return ImplicitConversionSequence::Better;
|
return ImplicitConversionSequence::Better;
|
||||||
else if (T1.isMoreQualifiedThan(T2))
|
if (T1.isMoreQualifiedThan(T2))
|
||||||
return ImplicitConversionSequence::Worse;
|
return ImplicitConversionSequence::Worse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4100,22 +4109,16 @@ CompareQualificationConversions(Sema &S,
|
||||||
QualType T2 = SCS2.getToType(2);
|
QualType T2 = SCS2.getToType(2);
|
||||||
T1 = S.Context.getCanonicalType(T1);
|
T1 = S.Context.getCanonicalType(T1);
|
||||||
T2 = S.Context.getCanonicalType(T2);
|
T2 = S.Context.getCanonicalType(T2);
|
||||||
|
assert(!T1->isReferenceType() && !T2->isReferenceType());
|
||||||
Qualifiers T1Quals, T2Quals;
|
Qualifiers T1Quals, T2Quals;
|
||||||
QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
|
QualType UnqualT1 = S.Context.getUnqualifiedArrayType(T1, T1Quals);
|
||||||
QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
|
QualType UnqualT2 = S.Context.getUnqualifiedArrayType(T2, T2Quals);
|
||||||
|
|
||||||
// If the types are the same, we won't learn anything by unwrapped
|
// If the types are the same, we won't learn anything by unwrapping
|
||||||
// them.
|
// them.
|
||||||
if (UnqualT1 == UnqualT2)
|
if (UnqualT1 == UnqualT2)
|
||||||
return ImplicitConversionSequence::Indistinguishable;
|
return ImplicitConversionSequence::Indistinguishable;
|
||||||
|
|
||||||
// If the type is an array type, promote the element qualifiers to the type
|
|
||||||
// for comparison.
|
|
||||||
if (isa<ArrayType>(T1) && T1Quals)
|
|
||||||
T1 = S.Context.getQualifiedType(UnqualT1, T1Quals);
|
|
||||||
if (isa<ArrayType>(T2) && T2Quals)
|
|
||||||
T2 = S.Context.getQualifiedType(UnqualT2, T2Quals);
|
|
||||||
|
|
||||||
ImplicitConversionSequence::CompareKind Result
|
ImplicitConversionSequence::CompareKind Result
|
||||||
= ImplicitConversionSequence::Indistinguishable;
|
= ImplicitConversionSequence::Indistinguishable;
|
||||||
|
|
||||||
|
@ -4413,10 +4416,19 @@ static bool isTypeValid(QualType T) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QualType withoutUnaligned(ASTContext &Ctx, QualType T) {
|
||||||
|
if (!T.getQualifiers().hasUnaligned())
|
||||||
|
return T;
|
||||||
|
|
||||||
|
Qualifiers Q;
|
||||||
|
T = Ctx.getUnqualifiedArrayType(T, Q);
|
||||||
|
Q.removeUnaligned();
|
||||||
|
return Ctx.getQualifiedType(T, Q);
|
||||||
|
}
|
||||||
|
|
||||||
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
|
/// CompareReferenceRelationship - Compare the two types T1 and T2 to
|
||||||
/// determine whether they are reference-related,
|
/// determine whether they are reference-compatible,
|
||||||
/// reference-compatible, reference-compatible with added
|
/// reference-related, or incompatible, for use in C++ initialization by
|
||||||
/// qualification, or incompatible, for use in C++ initialization by
|
|
||||||
/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
|
/// reference (C++ [dcl.ref.init]p4). Neither type can be a reference
|
||||||
/// type, and the first type (T1) is the pointee type of the reference
|
/// type, and the first type (T1) is the pointee type of the reference
|
||||||
/// type being initialized.
|
/// type being initialized.
|
||||||
|
@ -4438,10 +4450,17 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
|
||||||
ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
|
ReferenceConversions &Conv = ConvOut ? *ConvOut : ConvTmp;
|
||||||
Conv = ReferenceConversions();
|
Conv = ReferenceConversions();
|
||||||
|
|
||||||
// C++ [dcl.init.ref]p4:
|
// C++2a [dcl.init.ref]p4:
|
||||||
// Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
|
// Given types "cv1 T1" and "cv2 T2," "cv1 T1" is
|
||||||
// reference-related to "cv2 T2" if T1 is the same type as T2, or
|
// reference-related to "cv2 T2" if T1 is similar to T2, or
|
||||||
// T1 is a base class of T2.
|
// T1 is a base class of T2.
|
||||||
|
// "cv1 T1" is reference-compatible with "cv2 T2" if
|
||||||
|
// a prvalue of type "pointer to cv2 T2" can be converted to the type
|
||||||
|
// "pointer to cv1 T1" via a standard conversion sequence.
|
||||||
|
|
||||||
|
// Check for standard conversions we can apply to pointers: derived-to-base
|
||||||
|
// conversions, ObjC pointer conversions, and function pointer conversions.
|
||||||
|
// (Qualification conversions are checked last.)
|
||||||
QualType ConvertedT2;
|
QualType ConvertedT2;
|
||||||
if (UnqualT1 == UnqualT2) {
|
if (UnqualT1 == UnqualT2) {
|
||||||
// Nothing to do.
|
// Nothing to do.
|
||||||
|
@ -4455,59 +4474,56 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
|
||||||
Conv |= ReferenceConversions::ObjC;
|
Conv |= ReferenceConversions::ObjC;
|
||||||
else if (UnqualT2->isFunctionType() &&
|
else if (UnqualT2->isFunctionType() &&
|
||||||
IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
|
IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) {
|
||||||
// C++1z [dcl.init.ref]p4:
|
|
||||||
// cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept
|
|
||||||
// function" and T1 is "function"
|
|
||||||
//
|
|
||||||
// We extend this to also apply to 'noreturn', so allow any function
|
|
||||||
// conversion between function types.
|
|
||||||
Conv |= ReferenceConversions::Function;
|
Conv |= ReferenceConversions::Function;
|
||||||
|
// No need to check qualifiers; function types don't have them.
|
||||||
return Ref_Compatible;
|
return Ref_Compatible;
|
||||||
} else
|
|
||||||
return Ref_Incompatible;
|
|
||||||
|
|
||||||
// At this point, we know that T1 and T2 are reference-related (at
|
|
||||||
// least).
|
|
||||||
|
|
||||||
// If the type is an array type, promote the element qualifiers to the type
|
|
||||||
// for comparison.
|
|
||||||
if (isa<ArrayType>(T1) && T1Quals)
|
|
||||||
T1 = Context.getQualifiedType(UnqualT1, T1Quals);
|
|
||||||
if (isa<ArrayType>(T2) && T2Quals)
|
|
||||||
T2 = Context.getQualifiedType(UnqualT2, T2Quals);
|
|
||||||
|
|
||||||
// C++ [dcl.init.ref]p4:
|
|
||||||
// "cv1 T1" is reference-compatible with "cv2 T2" if T1 is
|
|
||||||
// reference-related to T2 and cv1 is the same cv-qualification
|
|
||||||
// as, or greater cv-qualification than, cv2. For purposes of
|
|
||||||
// overload resolution, cases for which cv1 is greater
|
|
||||||
// cv-qualification than cv2 are identified as
|
|
||||||
// reference-compatible with added qualification (see 13.3.3.2).
|
|
||||||
//
|
|
||||||
// Note that we also require equivalence of Objective-C GC and address-space
|
|
||||||
// qualifiers when performing these computations, so that e.g., an int in
|
|
||||||
// address space 1 is not reference-compatible with an int in address
|
|
||||||
// space 2.
|
|
||||||
if (T1Quals.getObjCLifetime() != T2Quals.getObjCLifetime() &&
|
|
||||||
T1Quals.compatiblyIncludesObjCLifetime(T2Quals)) {
|
|
||||||
if (isNonTrivialObjCLifetimeConversion(T2Quals, T1Quals))
|
|
||||||
Conv |= ReferenceConversions::ObjCLifetime;
|
|
||||||
|
|
||||||
T1Quals.removeObjCLifetime();
|
|
||||||
T2Quals.removeObjCLifetime();
|
|
||||||
}
|
}
|
||||||
|
bool ConvertedReferent = Conv != 0;
|
||||||
|
|
||||||
// MS compiler ignores __unaligned qualifier for references; do the same.
|
// We can have a qualification conversion. Compute whether the types are
|
||||||
T1Quals.removeUnaligned();
|
// similar at the same time.
|
||||||
T2Quals.removeUnaligned();
|
bool PreviousToQualsIncludeConst = true;
|
||||||
|
bool TopLevel = true;
|
||||||
|
do {
|
||||||
|
if (T1 == T2)
|
||||||
|
break;
|
||||||
|
|
||||||
if (T1Quals != T2Quals)
|
// We will need a qualification conversion.
|
||||||
Conv |= ReferenceConversions::Qualification;
|
Conv |= ReferenceConversions::Qualification;
|
||||||
|
|
||||||
if (T1Quals.compatiblyIncludes(T2Quals))
|
// Track whether we performed a qualification conversion anywhere other
|
||||||
return Ref_Compatible;
|
// than the top level. This matters for ranking reference bindings in
|
||||||
else
|
// overload resolution.
|
||||||
return Ref_Related;
|
if (!TopLevel)
|
||||||
|
Conv |= ReferenceConversions::NestedQualification;
|
||||||
|
|
||||||
|
// MS compiler ignores __unaligned qualifier for references; do the same.
|
||||||
|
T1 = withoutUnaligned(Context, T1);
|
||||||
|
T2 = withoutUnaligned(Context, T2);
|
||||||
|
|
||||||
|
// If we find a qualifier mismatch, the types are not reference-compatible,
|
||||||
|
// but are still be reference-related if they're similar.
|
||||||
|
bool ObjCLifetimeConversion = false;
|
||||||
|
if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false,
|
||||||
|
PreviousToQualsIncludeConst,
|
||||||
|
ObjCLifetimeConversion))
|
||||||
|
return (ConvertedReferent || Context.hasSimilarType(T1, T2))
|
||||||
|
? Ref_Related
|
||||||
|
: Ref_Incompatible;
|
||||||
|
|
||||||
|
// FIXME: Should we track this for any level other than the first?
|
||||||
|
if (ObjCLifetimeConversion)
|
||||||
|
Conv |= ReferenceConversions::ObjCLifetime;
|
||||||
|
|
||||||
|
TopLevel = false;
|
||||||
|
} while (Context.UnwrapSimilarTypes(T1, T2));
|
||||||
|
|
||||||
|
// At this point, if the types are reference-related, we must either have the
|
||||||
|
// same inner type (ignoring qualifiers), or must have already worked out how
|
||||||
|
// to convert the referent.
|
||||||
|
return (ConvertedReferent || Context.hasSameUnqualifiedType(T1, T2))
|
||||||
|
? Ref_Compatible
|
||||||
|
: Ref_Incompatible;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Look for a user-defined conversion to a value reference-compatible
|
/// Look for a user-defined conversion to a value reference-compatible
|
||||||
|
@ -4665,12 +4681,20 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
|
||||||
auto SetAsReferenceBinding = [&](bool BindsDirectly) {
|
auto SetAsReferenceBinding = [&](bool BindsDirectly) {
|
||||||
ICS.setStandard();
|
ICS.setStandard();
|
||||||
ICS.Standard.First = ICK_Identity;
|
ICS.Standard.First = ICK_Identity;
|
||||||
|
// FIXME: A reference binding can be a function conversion too. We should
|
||||||
|
// consider that when ordering reference-to-function bindings.
|
||||||
ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase)
|
ICS.Standard.Second = (RefConv & Sema::ReferenceConversions::DerivedToBase)
|
||||||
? ICK_Derived_To_Base
|
? ICK_Derived_To_Base
|
||||||
: (RefConv & Sema::ReferenceConversions::ObjC)
|
: (RefConv & Sema::ReferenceConversions::ObjC)
|
||||||
? ICK_Compatible_Conversion
|
? ICK_Compatible_Conversion
|
||||||
: ICK_Identity;
|
: ICK_Identity;
|
||||||
ICS.Standard.Third = ICK_Identity;
|
// FIXME: As a speculative fix to a defect introduced by CWG2352, we rank
|
||||||
|
// a reference binding that performs a non-top-level qualification
|
||||||
|
// conversion as a qualification conversion, not as an identity conversion.
|
||||||
|
ICS.Standard.Third = (RefConv &
|
||||||
|
Sema::ReferenceConversions::NestedQualification)
|
||||||
|
? ICK_Qualification
|
||||||
|
: ICK_Identity;
|
||||||
ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
|
ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();
|
||||||
ICS.Standard.setToType(0, T2);
|
ICS.Standard.setToType(0, T2);
|
||||||
ICS.Standard.setToType(1, T1);
|
ICS.Standard.setToType(1, T1);
|
||||||
|
|
|
@ -1,12 +1,41 @@
|
||||||
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
// RUN: %clang_cc1 -std=c++98 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1
|
||||||
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
// RUN: %clang_cc1 -std=c++11 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
||||||
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
// RUN: %clang_cc1 -std=c++14 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
||||||
// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
// RUN: %clang_cc1 -std=c++17 %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
||||||
// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
// RUN: %clang_cc1 -std=c++2a %s -verify -fexceptions -fcxx-exceptions -pedantic-errors 2>&1 | FileCheck %s
|
||||||
|
|
||||||
#if __cplusplus <= 201103L
|
namespace dr2352 { // dr2352: 10
|
||||||
// expected-no-diagnostics
|
int **p;
|
||||||
|
const int *const *const &f1() { return p; }
|
||||||
|
int *const *const &f2() { return p; }
|
||||||
|
int **const &f3() { return p; }
|
||||||
|
|
||||||
|
const int **const &f4() { return p; } // expected-error {{reference to type 'const int **const' could not bind to an lvalue of type 'int **'}}
|
||||||
|
const int *const *&f5() { return p; } // expected-error {{binding reference of type 'const int *const *' to value of type 'int **' not permitted due to incompatible qualifiers}}
|
||||||
|
|
||||||
|
// FIXME: We permit this as a speculative defect resolution, allowing
|
||||||
|
// qualification conversions when forming a glvalue conditional expression.
|
||||||
|
const int * const * const q = 0;
|
||||||
|
__typeof(&(true ? p : q)) x = &(true ? p : q);
|
||||||
|
|
||||||
|
// FIXME: Should we compute the composite pointer type here and produce an
|
||||||
|
// lvalue of type 'const int *const * const'?
|
||||||
|
const int * const * r;
|
||||||
|
void *y = &(true ? p : r); // expected-error {{rvalue of type 'const int *const *'}}
|
||||||
|
|
||||||
|
// FIXME: We order these as a speculative defect resolution.
|
||||||
|
void f(const int * const * const &r);
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
constexpr
|
||||||
#endif
|
#endif
|
||||||
|
int *const *const &f(int * const * const &r) { return r; }
|
||||||
|
|
||||||
|
// No temporary is created here.
|
||||||
|
int *const *const &check_f = f(p);
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
static_assert(&p == &check_f, "");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
namespace dr2353 { // dr2353: 9
|
namespace dr2353 { // dr2353: 9
|
||||||
struct X {
|
struct X {
|
||||||
|
|
|
@ -486,14 +486,21 @@ namespace dr433 { // dr433: yes
|
||||||
S<int> s;
|
S<int> s;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace dr434 { // dr434: yes
|
namespace dr434 { // dr434: sup 2352
|
||||||
void f() {
|
void f() {
|
||||||
const int ci = 0;
|
const int ci = 0;
|
||||||
int *pi = 0;
|
int *pi = 0;
|
||||||
const int *&rpci = pi; // expected-error {{cannot bind}}
|
const int *&rpci = pi; // expected-error {{incompatible qualifiers}}
|
||||||
|
const int * const &rcpci = pi; // OK
|
||||||
rpci = &ci;
|
rpci = &ci;
|
||||||
*pi = 1;
|
*pi = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if __cplusplus >= 201103L
|
||||||
|
int *pi = 0;
|
||||||
|
const int * const &rcpci = pi;
|
||||||
|
static_assert(&rcpci == &pi, "");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// dr435: na
|
// dr435: na
|
||||||
|
|
|
@ -25,4 +25,26 @@ const E2 & re(C c) {
|
||||||
return c; // expected-error {{reference initialization of type 'const E2 &' with initializer of type 'C' is ambiguous}}
|
return c; // expected-error {{reference initialization of type 'const E2 &' with initializer of type 'C' is ambiguous}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace CWG2352 {
|
||||||
|
void f(const int * const &) = delete;
|
||||||
|
void f(int *);
|
||||||
|
|
||||||
|
void g(int * &);
|
||||||
|
void g(const int *) = delete;
|
||||||
|
|
||||||
|
void h1(int *const * const &);
|
||||||
|
void h1(const int *const *) = delete;
|
||||||
|
void h2(const int *const * const &) = delete;
|
||||||
|
void h2(int *const *);
|
||||||
|
|
||||||
|
void test() {
|
||||||
|
int *x;
|
||||||
|
// Under CWG2352, this became ambiguous. We order by qualification
|
||||||
|
// conversion even when comparing a reference binding to a
|
||||||
|
// non-reference-binding.
|
||||||
|
f(x);
|
||||||
|
g(x);
|
||||||
|
h1(&x);
|
||||||
|
h2(&x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -174,6 +174,36 @@ void test_f9() {
|
||||||
const __autoreleasing id& ar4 = weak_a;
|
const __autoreleasing id& ar4 = weak_a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int &f10(__strong id *&); // expected-note 2{{not viable: no known conversion}}
|
||||||
|
float &f10(__autoreleasing id *&); // expected-note 2{{not viable: no known conversion}}
|
||||||
|
|
||||||
|
void test_f10() {
|
||||||
|
__strong id *strong_id;
|
||||||
|
__weak id *weak_id;
|
||||||
|
__autoreleasing id *autoreleasing_id;
|
||||||
|
__unsafe_unretained id *unsafe_id;
|
||||||
|
|
||||||
|
int &ir1 = f10(strong_id);
|
||||||
|
float &fr1 = f10(autoreleasing_id);
|
||||||
|
float &fr2 = f10(unsafe_id); // expected-error {{no match}}
|
||||||
|
float &fr2a = f10(weak_id); // expected-error {{no match}}
|
||||||
|
}
|
||||||
|
|
||||||
|
int &f11(__strong id *const &); // expected-note {{not viable: 1st argument ('__weak id *') has __weak ownership, but parameter has __strong ownership}}
|
||||||
|
float &f11(const __autoreleasing id *const &); // expected-note {{not viable: 1st argument ('__weak id *') has __weak ownership, but parameter has __autoreleasing ownership}}
|
||||||
|
|
||||||
|
void test_f11() {
|
||||||
|
__strong id *strong_id;
|
||||||
|
__weak id *weak_id;
|
||||||
|
__autoreleasing id *autoreleasing_id;
|
||||||
|
__unsafe_unretained id *unsafe_id;
|
||||||
|
|
||||||
|
int &ir1 = f11(strong_id);
|
||||||
|
float &fr1 = f11(autoreleasing_id);
|
||||||
|
float &fr2 = f11(unsafe_id);
|
||||||
|
float &fr2a = f11(weak_id); // expected-error {{no match}}
|
||||||
|
}
|
||||||
|
|
||||||
// rdar://9790531
|
// rdar://9790531
|
||||||
void f9790531(void *inClientData); // expected-note {{candidate function not viable: cannot implicitly convert argument of type 'MixerEQGraphTestDelegate *const __strong' to 'void *' for 1st argument under ARC}}
|
void f9790531(void *inClientData); // expected-note {{candidate function not viable: cannot implicitly convert argument of type 'MixerEQGraphTestDelegate *const __strong' to 'void *' for 1st argument under ARC}}
|
||||||
void f9790531_1(struct S*inClientData); // expected-note {{candidate function not viable}}
|
void f9790531_1(struct S*inClientData); // expected-note {{candidate function not viable}}
|
||||||
|
|
|
@ -501,12 +501,9 @@ void test_pointer_chains() {
|
||||||
// Case 1:
|
// Case 1:
|
||||||
// * address spaces of corresponded most outer pointees overlaps, their canonical types are equal
|
// * address spaces of corresponded most outer pointees overlaps, their canonical types are equal
|
||||||
// * CVR, address spaces and canonical types of the rest of pointees are equivalent.
|
// * CVR, address spaces and canonical types of the rest of pointees are equivalent.
|
||||||
|
var_as_as_int = var_asc_as_int;
|
||||||
var_as_as_int = 0 ? var_as_as_int : var_asc_as_int;
|
var_as_as_int = 0 ? var_as_as_int : var_asc_as_int;
|
||||||
#if __OPENCL_CPP_VERSION__
|
|
||||||
#ifdef GENERIC
|
|
||||||
// expected-error@-3{{incompatible operand types ('__generic int *__generic *' and '__generic int *__local *')}}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
// Case 2: Corresponded inner pointees has non-overlapping address spaces.
|
// Case 2: Corresponded inner pointees has non-overlapping address spaces.
|
||||||
var_as_as_int = 0 ? var_as_as_int : var_asc_asn_int;
|
var_as_as_int = 0 ? var_as_as_int : var_asc_asn_int;
|
||||||
#if !__OPENCL_CPP_VERSION__
|
#if !__OPENCL_CPP_VERSION__
|
||||||
|
@ -516,12 +513,17 @@ void test_pointer_chains() {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces.
|
// Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces.
|
||||||
|
// FIXME: Should this really be allowed in C++ mode?
|
||||||
|
var_as_as_int = var_asc_asc_int;
|
||||||
|
#if !__OPENCL_CPP_VERSION__
|
||||||
#ifdef GENERIC
|
#ifdef GENERIC
|
||||||
|
// expected-error@-3 {{assigning '__local int *__local *__private' to '__generic int *__generic *__private' changes address space of nested pointer}}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int;
|
var_as_as_int = 0 ? var_as_as_int : var_asc_asc_int;
|
||||||
#if !__OPENCL_CPP_VERSION__
|
#if !__OPENCL_CPP_VERSION__
|
||||||
// expected-warning-re@-2{{pointer type mismatch ('__{{(generic|global|constant)}} int *__{{(generic|global|constant)}} *' and '__{{(local|global|constant)}} int *__{{(local|global|constant)}} *')}}
|
#ifdef GENERIC
|
||||||
#else
|
// expected-warning@-3{{pointer type mismatch ('__generic int *__generic *' and '__local int *__local *')}}
|
||||||
// expected-error-re@-4{{incompatible operand types ('__{{generic|global|constant}} int *__{{generic|global|constant}} *' and '__{{local|global|constant}} int *__{{local|global|constant}} *')}}
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -2645,7 +2645,7 @@ of class templates</td>
|
||||||
<td><a href="https://wg21.link/cwg434">434</a></td>
|
<td><a href="https://wg21.link/cwg434">434</a></td>
|
||||||
<td>NAD</td>
|
<td>NAD</td>
|
||||||
<td>Unclear suppression of standard conversions while binding reference to lvalue</td>
|
<td>Unclear suppression of standard conversions while binding reference to lvalue</td>
|
||||||
<td class="full" align="center">Yes</td>
|
<td class="svn" align="center">Superseded by <a href="#2352">2352</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="435">
|
<tr id="435">
|
||||||
<td><a href="https://wg21.link/cwg435">435</a></td>
|
<td><a href="https://wg21.link/cwg435">435</a></td>
|
||||||
|
@ -13927,7 +13927,7 @@ and <I>POD class</I></td>
|
||||||
<td><a href="https://wg21.link/cwg2352">2352</a></td>
|
<td><a href="https://wg21.link/cwg2352">2352</a></td>
|
||||||
<td>DR</td>
|
<td>DR</td>
|
||||||
<td>Similar types and reference binding</td>
|
<td>Similar types and reference binding</td>
|
||||||
<td class="none" align="center">Unknown</td>
|
<td class="svn" align="center">SVN</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr id="2353">
|
<tr id="2353">
|
||||||
<td><a href="https://wg21.link/cwg2353">2353</a></td>
|
<td><a href="https://wg21.link/cwg2353">2353</a></td>
|
||||||
|
|
|
@ -28,7 +28,7 @@ def parse(dr):
|
||||||
_, url, issue = issue_link.split('"', 2)
|
_, url, issue = issue_link.split('"', 2)
|
||||||
url = url.strip()
|
url = url.strip()
|
||||||
issue = int(issue.split('>', 1)[1].split('<', 1)[0])
|
issue = int(issue.split('>', 1)[1].split('<', 1)[0])
|
||||||
title = title.replace('<issue_title>', '').replace('</issue_title>', '').strip()
|
title = title.replace('<issue_title>', '').replace('</issue_title>', '').replace('\r\n', '\n').strip()
|
||||||
return DR(section, issue, url, status, title)
|
return DR(section, issue, url, status, title)
|
||||||
|
|
||||||
status_re = re.compile(r'\bdr([0-9]+): (.*)')
|
status_re = re.compile(r'\bdr([0-9]+): (.*)')
|
||||||
|
@ -171,7 +171,7 @@ for dr in drs:
|
||||||
|
|
||||||
print >> out_file, '''\
|
print >> out_file, '''\
|
||||||
<tr%s id="%s">
|
<tr%s id="%s">
|
||||||
<td><a href="http://wg21.link/cwg%s">%s</a></td>
|
<td><a href="https://wg21.link/cwg%s">%s</a></td>
|
||||||
<td>%s</td>
|
<td>%s</td>
|
||||||
<td>%s</td>
|
<td>%s</td>
|
||||||
<td%s align="center">%s</td>
|
<td%s align="center">%s</td>
|
||||||
|
|
Loading…
Reference in New Issue