|
|
|
|
@@ -8998,9 +8998,10 @@ static bool IsInvalidCmseNSCallConversion(Sema &S, QualType FromType,
|
|
|
|
|
// routine is it effectively iqnores the qualifiers on the top level pointee.
|
|
|
|
|
// This circumvents the usual type rules specified in 6.2.7p1 & 6.7.5.[1-3].
|
|
|
|
|
// FIXME: add a couple examples in this comment.
|
|
|
|
|
static Sema::AssignConvertType
|
|
|
|
|
checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
SourceLocation Loc) {
|
|
|
|
|
static AssignConvertType checkPointerTypesForAssignment(Sema &S,
|
|
|
|
|
QualType LHSType,
|
|
|
|
|
QualType RHSType,
|
|
|
|
|
SourceLocation Loc) {
|
|
|
|
|
assert(LHSType.isCanonical() && "LHS not canonicalized!");
|
|
|
|
|
assert(RHSType.isCanonical() && "RHS not canonicalized!");
|
|
|
|
|
|
|
|
|
|
@@ -9012,7 +9013,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
std::tie(rhptee, rhq) =
|
|
|
|
|
cast<PointerType>(RHSType)->getPointeeType().split().asPair();
|
|
|
|
|
|
|
|
|
|
Sema::AssignConvertType ConvTy = Sema::Compatible;
|
|
|
|
|
AssignConvertType ConvTy = AssignConvertType::Compatible;
|
|
|
|
|
|
|
|
|
|
// C99 6.5.16.1p1: This following citation is common to constraints
|
|
|
|
|
// 3 & 4 (below). ...and the type *pointed to* by the left has all the
|
|
|
|
|
@@ -9029,7 +9030,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
if (!lhq.compatiblyIncludes(rhq, S.getASTContext())) {
|
|
|
|
|
// Treat address-space mismatches as fatal.
|
|
|
|
|
if (!lhq.isAddressSpaceSupersetOf(rhq, S.getASTContext()))
|
|
|
|
|
return Sema::IncompatiblePointerDiscardsQualifiers;
|
|
|
|
|
return AssignConvertType::IncompatiblePointerDiscardsQualifiers;
|
|
|
|
|
|
|
|
|
|
// It's okay to add or remove GC or lifetime qualifiers when converting to
|
|
|
|
|
// and from void*.
|
|
|
|
|
@@ -9041,15 +9042,16 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
|
|
|
|
|
// Treat lifetime mismatches as fatal.
|
|
|
|
|
else if (lhq.getObjCLifetime() != rhq.getObjCLifetime())
|
|
|
|
|
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
|
|
|
|
|
ConvTy = AssignConvertType::IncompatiblePointerDiscardsQualifiers;
|
|
|
|
|
|
|
|
|
|
// Treat pointer-auth mismatches as fatal.
|
|
|
|
|
else if (!lhq.getPointerAuth().isEquivalent(rhq.getPointerAuth()))
|
|
|
|
|
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
|
|
|
|
|
ConvTy = AssignConvertType::IncompatiblePointerDiscardsQualifiers;
|
|
|
|
|
|
|
|
|
|
// For GCC/MS compatibility, other qualifier mismatches are treated
|
|
|
|
|
// as still compatible in C.
|
|
|
|
|
else ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
|
|
|
|
|
else
|
|
|
|
|
ConvTy = AssignConvertType::CompatiblePointerDiscardsQualifiers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// C99 6.5.16.1p1 (constraint 4): If one operand is a pointer to an object or
|
|
|
|
|
@@ -9061,20 +9063,21 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
|
|
|
|
|
// As an extension, we allow cast to/from void* to function pointer.
|
|
|
|
|
assert(rhptee->isFunctionType());
|
|
|
|
|
return Sema::FunctionVoidPointer;
|
|
|
|
|
return AssignConvertType::FunctionVoidPointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rhptee->isVoidType()) {
|
|
|
|
|
// In C, void * to another pointer type is compatible, but we want to note
|
|
|
|
|
// that there will be an implicit conversion happening here.
|
|
|
|
|
if (lhptee->isIncompleteOrObjectType())
|
|
|
|
|
return ConvTy == Sema::Compatible && !S.getLangOpts().CPlusPlus
|
|
|
|
|
? Sema::CompatibleVoidPtrToNonVoidPtr
|
|
|
|
|
return ConvTy == AssignConvertType::Compatible &&
|
|
|
|
|
!S.getLangOpts().CPlusPlus
|
|
|
|
|
? AssignConvertType::CompatibleVoidPtrToNonVoidPtr
|
|
|
|
|
: ConvTy;
|
|
|
|
|
|
|
|
|
|
// As an extension, we allow cast to/from void* to function pointer.
|
|
|
|
|
assert(lhptee->isFunctionType());
|
|
|
|
|
return Sema::FunctionVoidPointer;
|
|
|
|
|
return AssignConvertType::FunctionVoidPointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!S.Diags.isIgnored(
|
|
|
|
|
@@ -9082,7 +9085,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
Loc) &&
|
|
|
|
|
RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType() &&
|
|
|
|
|
!S.IsFunctionConversion(RHSType, LHSType, RHSType))
|
|
|
|
|
return Sema::IncompatibleFunctionPointerStrict;
|
|
|
|
|
return AssignConvertType::IncompatibleFunctionPointerStrict;
|
|
|
|
|
|
|
|
|
|
// C99 6.5.16.1p1 (constraint 3): both operands are pointers to qualified or
|
|
|
|
|
// unqualified versions of compatible types, ...
|
|
|
|
|
@@ -9108,7 +9111,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
if (!S.IsAssignConvertCompatible(ConvTy))
|
|
|
|
|
return ConvTy;
|
|
|
|
|
|
|
|
|
|
return Sema::IncompatiblePointerSign;
|
|
|
|
|
return AssignConvertType::IncompatiblePointerSign;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we are a multi-level pointer, it's possible that our issue is simply
|
|
|
|
|
@@ -9131,26 +9134,27 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
// It's not clear how to actually determine when such pointers are
|
|
|
|
|
// invalidly incompatible.
|
|
|
|
|
if (lhq.getAddressSpace() != rhq.getAddressSpace())
|
|
|
|
|
return Sema::IncompatibleNestedPointerAddressSpaceMismatch;
|
|
|
|
|
return AssignConvertType::
|
|
|
|
|
IncompatibleNestedPointerAddressSpaceMismatch;
|
|
|
|
|
|
|
|
|
|
} while (isa<PointerType>(lhptee) && isa<PointerType>(rhptee));
|
|
|
|
|
|
|
|
|
|
if (lhptee == rhptee)
|
|
|
|
|
return Sema::IncompatibleNestedPointerQualifiers;
|
|
|
|
|
return AssignConvertType::IncompatibleNestedPointerQualifiers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// General pointer incompatibility takes priority over qualifiers.
|
|
|
|
|
if (RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType())
|
|
|
|
|
return Sema::IncompatibleFunctionPointer;
|
|
|
|
|
return Sema::IncompatiblePointer;
|
|
|
|
|
return AssignConvertType::IncompatibleFunctionPointer;
|
|
|
|
|
return AssignConvertType::IncompatiblePointer;
|
|
|
|
|
}
|
|
|
|
|
if (!S.getLangOpts().CPlusPlus &&
|
|
|
|
|
S.IsFunctionConversion(ltrans, rtrans, ltrans))
|
|
|
|
|
return Sema::IncompatibleFunctionPointer;
|
|
|
|
|
return AssignConvertType::IncompatibleFunctionPointer;
|
|
|
|
|
if (IsInvalidCmseNSCallConversion(S, ltrans, rtrans))
|
|
|
|
|
return Sema::IncompatibleFunctionPointer;
|
|
|
|
|
return AssignConvertType::IncompatibleFunctionPointer;
|
|
|
|
|
if (S.IsInvalidSMECallConversion(rtrans, ltrans))
|
|
|
|
|
return Sema::IncompatibleFunctionPointer;
|
|
|
|
|
return AssignConvertType::IncompatibleFunctionPointer;
|
|
|
|
|
return ConvTy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -9158,9 +9162,9 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType,
|
|
|
|
|
/// block pointer types are compatible or whether a block and normal pointer
|
|
|
|
|
/// are compatible. It is more restrict than comparing two function pointer
|
|
|
|
|
// types.
|
|
|
|
|
static Sema::AssignConvertType
|
|
|
|
|
checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType,
|
|
|
|
|
QualType RHSType) {
|
|
|
|
|
static AssignConvertType checkBlockPointerTypesForAssignment(Sema &S,
|
|
|
|
|
QualType LHSType,
|
|
|
|
|
QualType RHSType) {
|
|
|
|
|
assert(LHSType.isCanonical() && "LHS not canonicalized!");
|
|
|
|
|
assert(RHSType.isCanonical() && "RHS not canonicalized!");
|
|
|
|
|
|
|
|
|
|
@@ -9172,9 +9176,9 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType,
|
|
|
|
|
|
|
|
|
|
// In C++, the types have to match exactly.
|
|
|
|
|
if (S.getLangOpts().CPlusPlus)
|
|
|
|
|
return Sema::IncompatibleBlockPointer;
|
|
|
|
|
return AssignConvertType::IncompatibleBlockPointer;
|
|
|
|
|
|
|
|
|
|
Sema::AssignConvertType ConvTy = Sema::Compatible;
|
|
|
|
|
AssignConvertType ConvTy = AssignConvertType::Compatible;
|
|
|
|
|
|
|
|
|
|
// For blocks we enforce that qualifiers are identical.
|
|
|
|
|
Qualifiers LQuals = lhptee.getLocalQualifiers();
|
|
|
|
|
@@ -9184,7 +9188,7 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType,
|
|
|
|
|
RQuals.removeAddressSpace();
|
|
|
|
|
}
|
|
|
|
|
if (LQuals != RQuals)
|
|
|
|
|
ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
|
|
|
|
|
ConvTy = AssignConvertType::CompatiblePointerDiscardsQualifiers;
|
|
|
|
|
|
|
|
|
|
// FIXME: OpenCL doesn't define the exact compile time semantics for a block
|
|
|
|
|
// assignment.
|
|
|
|
|
@@ -9200,18 +9204,18 @@ checkBlockPointerTypesForAssignment(Sema &S, QualType LHSType,
|
|
|
|
|
if (!S.Context.typesAreBlockPointerCompatible(
|
|
|
|
|
S.Context.getQualifiedType(LHSType.getUnqualifiedType(), LQuals),
|
|
|
|
|
S.Context.getQualifiedType(RHSType.getUnqualifiedType(), RQuals)))
|
|
|
|
|
return Sema::IncompatibleBlockPointer;
|
|
|
|
|
return AssignConvertType::IncompatibleBlockPointer;
|
|
|
|
|
} else if (!S.Context.typesAreBlockPointerCompatible(LHSType, RHSType))
|
|
|
|
|
return Sema::IncompatibleBlockPointer;
|
|
|
|
|
return AssignConvertType::IncompatibleBlockPointer;
|
|
|
|
|
|
|
|
|
|
return ConvTy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// checkObjCPointerTypesForAssignment - Compares two objective-c pointer types
|
|
|
|
|
/// for assignment compatibility.
|
|
|
|
|
static Sema::AssignConvertType
|
|
|
|
|
checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
|
|
|
|
|
QualType RHSType) {
|
|
|
|
|
static AssignConvertType checkObjCPointerTypesForAssignment(Sema &S,
|
|
|
|
|
QualType LHSType,
|
|
|
|
|
QualType RHSType) {
|
|
|
|
|
assert(LHSType.isCanonical() && "LHS was not canonicalized!");
|
|
|
|
|
assert(RHSType.isCanonical() && "RHS was not canonicalized!");
|
|
|
|
|
|
|
|
|
|
@@ -9219,14 +9223,14 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
|
|
|
|
|
// Class is not compatible with ObjC object pointers.
|
|
|
|
|
if (LHSType->isObjCClassType() && !RHSType->isObjCBuiltinType() &&
|
|
|
|
|
!RHSType->isObjCQualifiedClassType())
|
|
|
|
|
return Sema::IncompatiblePointer;
|
|
|
|
|
return Sema::Compatible;
|
|
|
|
|
return AssignConvertType::IncompatiblePointer;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
if (RHSType->isObjCBuiltinType()) {
|
|
|
|
|
if (RHSType->isObjCClassType() && !LHSType->isObjCBuiltinType() &&
|
|
|
|
|
!LHSType->isObjCQualifiedClassType())
|
|
|
|
|
return Sema::IncompatiblePointer;
|
|
|
|
|
return Sema::Compatible;
|
|
|
|
|
return AssignConvertType::IncompatiblePointer;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
QualType lhptee = LHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
|
|
|
|
|
QualType rhptee = RHSType->castAs<ObjCObjectPointerType>()->getPointeeType();
|
|
|
|
|
@@ -9234,18 +9238,18 @@ checkObjCPointerTypesForAssignment(Sema &S, QualType LHSType,
|
|
|
|
|
if (!lhptee.isAtLeastAsQualifiedAs(rhptee, S.getASTContext()) &&
|
|
|
|
|
// make an exception for id<P>
|
|
|
|
|
!LHSType->isObjCQualifiedIdType())
|
|
|
|
|
return Sema::CompatiblePointerDiscardsQualifiers;
|
|
|
|
|
return AssignConvertType::CompatiblePointerDiscardsQualifiers;
|
|
|
|
|
|
|
|
|
|
if (S.Context.typesAreCompatible(LHSType, RHSType))
|
|
|
|
|
return Sema::Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
if (LHSType->isObjCQualifiedIdType() || RHSType->isObjCQualifiedIdType())
|
|
|
|
|
return Sema::IncompatibleObjCQualifiedId;
|
|
|
|
|
return Sema::IncompatiblePointer;
|
|
|
|
|
return AssignConvertType::IncompatibleObjCQualifiedId;
|
|
|
|
|
return AssignConvertType::IncompatiblePointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Sema::AssignConvertType
|
|
|
|
|
Sema::CheckAssignmentConstraints(SourceLocation Loc,
|
|
|
|
|
QualType LHSType, QualType RHSType) {
|
|
|
|
|
AssignConvertType Sema::CheckAssignmentConstraints(SourceLocation Loc,
|
|
|
|
|
QualType LHSType,
|
|
|
|
|
QualType RHSType) {
|
|
|
|
|
// Fake up an opaque expression. We don't actually care about what
|
|
|
|
|
// cast operations are required, so if CheckAssignmentConstraints
|
|
|
|
|
// adds casts to this they'll be wasted, but fortunately that doesn't
|
|
|
|
|
@@ -9282,9 +9286,10 @@ static bool isVector(QualType QT, QualType ElementType) {
|
|
|
|
|
/// C99 spec dictates.
|
|
|
|
|
///
|
|
|
|
|
/// Sets 'Kind' for any result kind except Incompatible.
|
|
|
|
|
Sema::AssignConvertType
|
|
|
|
|
Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
CastKind &Kind, bool ConvertRHS) {
|
|
|
|
|
AssignConvertType Sema::CheckAssignmentConstraints(QualType LHSType,
|
|
|
|
|
ExprResult &RHS,
|
|
|
|
|
CastKind &Kind,
|
|
|
|
|
bool ConvertRHS) {
|
|
|
|
|
QualType RHSType = RHS.get()->getType();
|
|
|
|
|
QualType OrigLHSType = LHSType;
|
|
|
|
|
|
|
|
|
|
@@ -9296,7 +9301,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
// Common case: no conversion required.
|
|
|
|
|
if (LHSType == RHSType) {
|
|
|
|
|
Kind = CK_NoOp;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the LHS has an __auto_type, there are no additional type constraints
|
|
|
|
|
@@ -9304,21 +9309,21 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
if (const auto *AT = dyn_cast<AutoType>(LHSType)) {
|
|
|
|
|
if (AT->isGNUAutoType()) {
|
|
|
|
|
Kind = CK_NoOp;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we have an atomic type, try a non-atomic assignment, then just add an
|
|
|
|
|
// atomic qualification step.
|
|
|
|
|
if (const AtomicType *AtomicTy = dyn_cast<AtomicType>(LHSType)) {
|
|
|
|
|
Sema::AssignConvertType result =
|
|
|
|
|
CheckAssignmentConstraints(AtomicTy->getValueType(), RHS, Kind);
|
|
|
|
|
if (result != Compatible)
|
|
|
|
|
AssignConvertType result =
|
|
|
|
|
CheckAssignmentConstraints(AtomicTy->getValueType(), RHS, Kind);
|
|
|
|
|
if (result != AssignConvertType::Compatible)
|
|
|
|
|
return result;
|
|
|
|
|
if (Kind != CK_NoOp && ConvertRHS)
|
|
|
|
|
RHS = ImpCastExprToType(RHS.get(), AtomicTy->getValueType(), Kind);
|
|
|
|
|
Kind = CK_NonAtomicToAtomic;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the left-hand side is a reference type, then we are in a
|
|
|
|
|
@@ -9331,22 +9336,22 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
if (const ReferenceType *LHSTypeRef = LHSType->getAs<ReferenceType>()) {
|
|
|
|
|
if (Context.typesAreCompatible(LHSTypeRef->getPointeeType(), RHSType)) {
|
|
|
|
|
Kind = CK_LValueBitCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allow scalar to ExtVector assignments, and assignments of an ExtVector type
|
|
|
|
|
// to the same ExtVector type.
|
|
|
|
|
if (LHSType->isExtVectorType()) {
|
|
|
|
|
if (RHSType->isExtVectorType())
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
if (RHSType->isArithmeticType()) {
|
|
|
|
|
// CK_VectorSplat does T -> vector T, so first cast to the element type.
|
|
|
|
|
if (ConvertRHS)
|
|
|
|
|
RHS = prepareVectorSplat(LHSType, RHS.get());
|
|
|
|
|
Kind = CK_VectorSplat;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -9357,7 +9362,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
// vector type and vice versa
|
|
|
|
|
if (Context.areCompatibleVectorTypes(LHSType, RHSType)) {
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If we are allowing lax vector conversions, and LHS and RHS are both
|
|
|
|
|
@@ -9373,7 +9378,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
Diag(RHS.get()->getExprLoc(), diag::warn_deprecated_lax_vec_conv_all)
|
|
|
|
|
<< RHSType << LHSType;
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
return IncompatibleVectors;
|
|
|
|
|
return AssignConvertType::IncompatibleVectors;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -9394,7 +9399,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
ExprResult *VecExpr = &RHS;
|
|
|
|
|
*VecExpr = ImpCastExprToType(VecExpr->get(), LHSType, CK_BitCast);
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -9404,7 +9409,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
if (Context.areCompatibleSveTypes(LHSType, RHSType) ||
|
|
|
|
|
Context.areLaxCompatibleSveTypes(LHSType, RHSType)) {
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allow assignments between fixed-length and sizeless RVV vectors.
|
|
|
|
|
@@ -9413,30 +9418,30 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
if (Context.areCompatibleRVVTypes(LHSType, RHSType) ||
|
|
|
|
|
Context.areLaxCompatibleRVVTypes(LHSType, RHSType)) {
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Diagnose attempts to convert between __ibm128, __float128 and long double
|
|
|
|
|
// where such conversions currently can't be handled.
|
|
|
|
|
if (unsupportedTypeConversion(*this, LHSType, RHSType))
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
|
|
|
|
|
// Disallow assigning a _Complex to a real type in C++ mode since it simply
|
|
|
|
|
// discards the imaginary part.
|
|
|
|
|
if (getLangOpts().CPlusPlus && RHSType->getAs<ComplexType>() &&
|
|
|
|
|
!LHSType->getAs<ComplexType>())
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
|
|
|
|
|
// Arithmetic conversions.
|
|
|
|
|
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
|
|
|
|
|
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
|
|
|
|
|
if (ConvertRHS)
|
|
|
|
|
Kind = PrepareScalarCast(RHS, LHSType);
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Conversions to normal pointers.
|
|
|
|
|
@@ -9458,7 +9463,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
// int -> T*
|
|
|
|
|
if (RHSType->isIntegerType()) {
|
|
|
|
|
Kind = CK_IntegralToPointer; // FIXME: null?
|
|
|
|
|
return IntToPointer;
|
|
|
|
|
return AssignConvertType::IntToPointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// C pointers are not compatible with ObjC object pointers,
|
|
|
|
|
@@ -9467,7 +9472,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
// - conversions to void*
|
|
|
|
|
if (LHSPointer->getPointeeType()->isVoidType()) {
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// - conversions from 'Class' to the redefinition type
|
|
|
|
|
@@ -9475,11 +9480,11 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
Context.hasSameType(LHSType,
|
|
|
|
|
Context.getObjCClassRedefinitionType())) {
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
return IncompatiblePointer;
|
|
|
|
|
return AssignConvertType::IncompatiblePointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// U^ -> void*
|
|
|
|
|
@@ -9491,11 +9496,11 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
.getAddressSpace();
|
|
|
|
|
Kind =
|
|
|
|
|
AddrSpaceL != AddrSpaceR ? CK_AddressSpaceConversion : CK_BitCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Conversions to block pointers.
|
|
|
|
|
@@ -9515,23 +9520,23 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
// int or null -> T^
|
|
|
|
|
if (RHSType->isIntegerType()) {
|
|
|
|
|
Kind = CK_IntegralToPointer; // FIXME: null
|
|
|
|
|
return IntToBlockPointer;
|
|
|
|
|
return AssignConvertType::IntToBlockPointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// id -> T^
|
|
|
|
|
if (getLangOpts().ObjC && RHSType->isObjCIdType()) {
|
|
|
|
|
Kind = CK_AnyPointerToBlockPointerCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// void* -> T^
|
|
|
|
|
if (const PointerType *RHSPT = RHSType->getAs<PointerType>())
|
|
|
|
|
if (RHSPT->getPointeeType()->isVoidType()) {
|
|
|
|
|
Kind = CK_AnyPointerToBlockPointerCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Conversions to Objective-C pointers.
|
|
|
|
|
@@ -9539,19 +9544,19 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
// A* -> B*
|
|
|
|
|
if (RHSType->isObjCObjectPointerType()) {
|
|
|
|
|
Kind = CK_BitCast;
|
|
|
|
|
Sema::AssignConvertType result =
|
|
|
|
|
checkObjCPointerTypesForAssignment(*this, LHSType, RHSType);
|
|
|
|
|
AssignConvertType result =
|
|
|
|
|
checkObjCPointerTypesForAssignment(*this, LHSType, RHSType);
|
|
|
|
|
if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
|
|
|
|
|
result == Compatible &&
|
|
|
|
|
result == AssignConvertType::Compatible &&
|
|
|
|
|
!ObjC().CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType))
|
|
|
|
|
result = IncompatibleObjCWeakRef;
|
|
|
|
|
result = AssignConvertType::IncompatibleObjCWeakRef;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// int or null -> A*
|
|
|
|
|
if (RHSType->isIntegerType()) {
|
|
|
|
|
Kind = CK_IntegralToPointer; // FIXME: null
|
|
|
|
|
return IntToPointer;
|
|
|
|
|
return AssignConvertType::IntToPointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// In general, C pointers are not compatible with ObjC object pointers,
|
|
|
|
|
@@ -9561,17 +9566,17 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
|
|
|
|
|
// - conversions from 'void*'
|
|
|
|
|
if (RHSType->isVoidPointerType()) {
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// - conversions to 'Class' from its redefinition type
|
|
|
|
|
if (LHSType->isObjCClassType() &&
|
|
|
|
|
Context.hasSameType(RHSType,
|
|
|
|
|
Context.getObjCClassRedefinitionType())) {
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return IncompatiblePointer;
|
|
|
|
|
return AssignConvertType::IncompatiblePointer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Only under strict condition T^ is compatible with an Objective-C pointer.
|
|
|
|
|
@@ -9580,10 +9585,10 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
if (ConvertRHS)
|
|
|
|
|
maybeExtendBlockObject(RHS);
|
|
|
|
|
Kind = CK_BlockPointerToObjCPointerCast;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Conversion to nullptr_t (C23 only)
|
|
|
|
|
@@ -9592,7 +9597,7 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
Expr::NPC_ValueDependentIsNull)) {
|
|
|
|
|
// null -> nullptr_t
|
|
|
|
|
Kind = CK_NullToPointer;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Conversions from pointers that are not covered by the above.
|
|
|
|
|
@@ -9600,16 +9605,16 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
// T* -> _Bool
|
|
|
|
|
if (LHSType == Context.BoolTy) {
|
|
|
|
|
Kind = CK_PointerToBoolean;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// T* -> int
|
|
|
|
|
if (LHSType->isIntegerType()) {
|
|
|
|
|
Kind = CK_PointerToIntegral;
|
|
|
|
|
return PointerToInt;
|
|
|
|
|
return AssignConvertType::PointerToInt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Conversions from Objective-C pointers that are not covered by the above.
|
|
|
|
|
@@ -9617,32 +9622,32 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
|
|
|
|
|
// T* -> _Bool
|
|
|
|
|
if (LHSType == Context.BoolTy) {
|
|
|
|
|
Kind = CK_PointerToBoolean;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// T* -> int
|
|
|
|
|
if (LHSType->isIntegerType()) {
|
|
|
|
|
Kind = CK_PointerToIntegral;
|
|
|
|
|
return PointerToInt;
|
|
|
|
|
return AssignConvertType::PointerToInt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// struct A -> struct B
|
|
|
|
|
if (isa<TagType>(LHSType) && isa<TagType>(RHSType)) {
|
|
|
|
|
if (Context.typesAreCompatible(LHSType, RHSType)) {
|
|
|
|
|
Kind = CK_NoOp;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (LHSType->isSamplerT() && RHSType->isIntegerType()) {
|
|
|
|
|
Kind = CK_IntToOCLSampler;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Constructs a transparent union from an expression that is
|
|
|
|
|
@@ -9665,7 +9670,7 @@ static void ConstructTransparentUnion(Sema &S, ASTContext &C,
|
|
|
|
|
VK_PRValue, Initializer, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Sema::AssignConvertType
|
|
|
|
|
AssignConvertType
|
|
|
|
|
Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
|
|
|
|
|
ExprResult &RHS) {
|
|
|
|
|
QualType RHSType = RHS.get()->getType();
|
|
|
|
|
@@ -9674,7 +9679,7 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
|
|
|
|
|
// transparent_union GCC extension.
|
|
|
|
|
const RecordType *UT = ArgType->getAsUnionType();
|
|
|
|
|
if (!UT || !UT->getDecl()->hasAttr<TransparentUnionAttr>())
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
|
|
|
|
|
// The field to initialize within the transparent union.
|
|
|
|
|
RecordDecl *UD = UT->getDecl();
|
|
|
|
|
@@ -9702,8 +9707,8 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CastKind Kind;
|
|
|
|
|
if (CheckAssignmentConstraints(it->getType(), RHS, Kind)
|
|
|
|
|
== Compatible) {
|
|
|
|
|
if (CheckAssignmentConstraints(it->getType(), RHS, Kind) ==
|
|
|
|
|
AssignConvertType::Compatible) {
|
|
|
|
|
RHS = ImpCastExprToType(RHS.get(), it->getType(), Kind);
|
|
|
|
|
InitField = it;
|
|
|
|
|
break;
|
|
|
|
|
@@ -9711,17 +9716,17 @@ Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!InitField)
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
|
|
|
|
|
ConstructTransparentUnion(*this, Context, RHS, ArgType, InitField);
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Sema::AssignConvertType
|
|
|
|
|
Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
|
|
|
|
bool Diagnose,
|
|
|
|
|
bool DiagnoseCFAudited,
|
|
|
|
|
bool ConvertRHS) {
|
|
|
|
|
AssignConvertType Sema::CheckSingleAssignmentConstraints(QualType LHSType,
|
|
|
|
|
ExprResult &CallerRHS,
|
|
|
|
|
bool Diagnose,
|
|
|
|
|
bool DiagnoseCFAudited,
|
|
|
|
|
bool ConvertRHS) {
|
|
|
|
|
// We need to be able to tell the caller whether we diagnosed a problem, if
|
|
|
|
|
// they ask us to issue diagnostics.
|
|
|
|
|
assert((ConvertRHS || !Diagnose) && "can't indicate whether we diagnosed");
|
|
|
|
|
@@ -9761,16 +9766,16 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
|
|
|
|
/*CStyle=*/false,
|
|
|
|
|
/*AllowObjCWritebackConversion=*/false);
|
|
|
|
|
if (ICS.isFailure())
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
|
|
|
|
|
ICS, AssignmentAction::Assigning);
|
|
|
|
|
}
|
|
|
|
|
if (RHS.isInvalid())
|
|
|
|
|
return Incompatible;
|
|
|
|
|
Sema::AssignConvertType result = Compatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
AssignConvertType result = AssignConvertType::Compatible;
|
|
|
|
|
if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
|
|
|
|
|
!ObjC().CheckObjCARCUnavailableWeakConversion(LHSType, RHSType))
|
|
|
|
|
result = IncompatibleObjCWeakRef;
|
|
|
|
|
result = AssignConvertType::IncompatibleObjCWeakRef;
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -9786,7 +9791,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
|
|
|
|
RHS.get(), LHSType, /*Complain=*/false, DAP))
|
|
|
|
|
RHS = FixOverloadedFunctionReference(RHS.get(), DAP, FD);
|
|
|
|
|
else
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This check seems unnatural, however it is necessary to ensure the proper
|
|
|
|
|
@@ -9804,7 +9809,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
|
|
|
|
// FIXME: We potentially allocate here even if ConvertRHS is false.
|
|
|
|
|
RHS = DefaultFunctionArrayLvalueConversion(RHS.get(), Diagnose);
|
|
|
|
|
if (RHS.isInvalid())
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The constraints are expressed in terms of the atomic, qualified, or
|
|
|
|
|
@@ -9827,7 +9832,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
|
|
|
|
if (ConvertRHS)
|
|
|
|
|
RHS = ImpCastExprToType(RHS.get(), LHSType, Kind, VK_PRValue, &Path);
|
|
|
|
|
}
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
// C23 6.5.16.1p1: the left operand has type atomic, qualified, or
|
|
|
|
|
// unqualified bool, and the right operand is a pointer or its type is
|
|
|
|
|
@@ -9854,12 +9859,12 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
|
|
|
|
if (LHSType->isQueueT() && RHS.get()->isNullPointerConstant(
|
|
|
|
|
Context, Expr::NPC_ValueDependentIsNull)) {
|
|
|
|
|
RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer);
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CastKind Kind;
|
|
|
|
|
Sema::AssignConvertType result =
|
|
|
|
|
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
|
|
|
|
|
AssignConvertType result =
|
|
|
|
|
CheckAssignmentConstraints(LHSType, RHS, Kind, ConvertRHS);
|
|
|
|
|
|
|
|
|
|
// C99 6.5.16.1p2: The value of the right operand is converted to the
|
|
|
|
|
// type of the assignment expression.
|
|
|
|
|
@@ -9867,7 +9872,8 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
|
|
|
|
// so that we can use references in built-in functions even in C.
|
|
|
|
|
// The getNonReferenceType() call makes sure that the resulting expression
|
|
|
|
|
// does not have reference type.
|
|
|
|
|
if (result != Incompatible && RHS.get()->getType() != LHSType) {
|
|
|
|
|
if (result != AssignConvertType::Incompatible &&
|
|
|
|
|
RHS.get()->getType() != LHSType) {
|
|
|
|
|
QualType Ty = LHSType.getNonLValueExprType(Context);
|
|
|
|
|
Expr *E = RHS.get();
|
|
|
|
|
|
|
|
|
|
@@ -9879,18 +9885,18 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
|
|
|
|
|
CheckedConversionKind::Implicit, Diagnose,
|
|
|
|
|
DiagnoseCFAudited) != SemaObjC::ACR_okay) {
|
|
|
|
|
if (!Diagnose)
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
}
|
|
|
|
|
if (getLangOpts().ObjC &&
|
|
|
|
|
(ObjC().CheckObjCBridgeRelatedConversions(E->getBeginLoc(), LHSType,
|
|
|
|
|
E->getType(), E, Diagnose) ||
|
|
|
|
|
ObjC().CheckConversionToObjCLiteral(LHSType, E, Diagnose))) {
|
|
|
|
|
if (!Diagnose)
|
|
|
|
|
return Incompatible;
|
|
|
|
|
return AssignConvertType::Incompatible;
|
|
|
|
|
// Replace the expression with a corrected version and continue so we
|
|
|
|
|
// can find further errors.
|
|
|
|
|
RHS = E;
|
|
|
|
|
return Compatible;
|
|
|
|
|
return AssignConvertType::Compatible;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ConvertRHS)
|
|
|
|
|
@@ -13945,17 +13951,15 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
|
|
|
|
|
if (RHS.isInvalid())
|
|
|
|
|
return QualType();
|
|
|
|
|
// Special case of NSObject attributes on c-style pointer types.
|
|
|
|
|
if (ConvTy == IncompatiblePointer &&
|
|
|
|
|
if (ConvTy == AssignConvertType::IncompatiblePointer &&
|
|
|
|
|
((Context.isObjCNSObjectType(LHSType) &&
|
|
|
|
|
RHSType->isObjCObjectPointerType()) ||
|
|
|
|
|
(Context.isObjCNSObjectType(RHSType) &&
|
|
|
|
|
LHSType->isObjCObjectPointerType())))
|
|
|
|
|
ConvTy = Compatible;
|
|
|
|
|
ConvTy = AssignConvertType::Compatible;
|
|
|
|
|
|
|
|
|
|
if (ConvTy == Compatible &&
|
|
|
|
|
LHSType->isObjCObjectType())
|
|
|
|
|
Diag(Loc, diag::err_objc_object_assignment)
|
|
|
|
|
<< LHSType;
|
|
|
|
|
if (ConvTy == AssignConvertType::Compatible && LHSType->isObjCObjectType())
|
|
|
|
|
Diag(Loc, diag::err_objc_object_assignment) << LHSType;
|
|
|
|
|
|
|
|
|
|
// If the RHS is a unary plus or minus, check to see if they = and + are
|
|
|
|
|
// right next to each other. If so, the user may have typo'd "x =+ 4"
|
|
|
|
|
@@ -13977,7 +13981,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ConvTy == Compatible) {
|
|
|
|
|
if (ConvTy == AssignConvertType::Compatible) {
|
|
|
|
|
if (LHSType.getObjCLifetime() == Qualifiers::OCL_Strong) {
|
|
|
|
|
// Warn about retain cycles where a block captures the LHS, but
|
|
|
|
|
// not if the LHS is a simple variable into which the block is
|
|
|
|
|
@@ -16992,15 +16996,15 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
const ObjCProtocolDecl *PDecl = nullptr;
|
|
|
|
|
|
|
|
|
|
switch (ConvTy) {
|
|
|
|
|
case Compatible:
|
|
|
|
|
DiagnoseAssignmentEnum(DstType, SrcType, SrcExpr);
|
|
|
|
|
return false;
|
|
|
|
|
case CompatibleVoidPtrToNonVoidPtr:
|
|
|
|
|
case AssignConvertType::Compatible:
|
|
|
|
|
DiagnoseAssignmentEnum(DstType, SrcType, SrcExpr);
|
|
|
|
|
return false;
|
|
|
|
|
case AssignConvertType::CompatibleVoidPtrToNonVoidPtr:
|
|
|
|
|
// Still a valid conversion, but we may want to diagnose for C++
|
|
|
|
|
// compatibility reasons.
|
|
|
|
|
DiagKind = diag::warn_compatible_implicit_pointer_conv;
|
|
|
|
|
break;
|
|
|
|
|
case PointerToInt:
|
|
|
|
|
case AssignConvertType::PointerToInt:
|
|
|
|
|
if (getLangOpts().CPlusPlus) {
|
|
|
|
|
DiagKind = diag::err_typecheck_convert_pointer_int;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
@@ -17010,7 +17014,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
|
|
|
|
|
MayHaveConvFixit = true;
|
|
|
|
|
break;
|
|
|
|
|
case IntToPointer:
|
|
|
|
|
case AssignConvertType::IntToPointer:
|
|
|
|
|
if (getLangOpts().CPlusPlus) {
|
|
|
|
|
DiagKind = diag::err_typecheck_convert_int_pointer;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
@@ -17020,13 +17024,13 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
|
|
|
|
|
MayHaveConvFixit = true;
|
|
|
|
|
break;
|
|
|
|
|
case IncompatibleFunctionPointerStrict:
|
|
|
|
|
case AssignConvertType::IncompatibleFunctionPointerStrict:
|
|
|
|
|
DiagKind =
|
|
|
|
|
diag::warn_typecheck_convert_incompatible_function_pointer_strict;
|
|
|
|
|
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
|
|
|
|
|
MayHaveConvFixit = true;
|
|
|
|
|
break;
|
|
|
|
|
case IncompatibleFunctionPointer:
|
|
|
|
|
case AssignConvertType::IncompatibleFunctionPointer:
|
|
|
|
|
if (getLangOpts().CPlusPlus) {
|
|
|
|
|
DiagKind = diag::err_typecheck_convert_incompatible_function_pointer;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
@@ -17036,7 +17040,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this);
|
|
|
|
|
MayHaveConvFixit = true;
|
|
|
|
|
break;
|
|
|
|
|
case IncompatiblePointer:
|
|
|
|
|
case AssignConvertType::IncompatiblePointer:
|
|
|
|
|
if (Action == AssignmentAction::Passing_CFAudited) {
|
|
|
|
|
DiagKind = diag::err_arc_typecheck_convert_incompatible_pointer;
|
|
|
|
|
} else if (getLangOpts().CPlusPlus) {
|
|
|
|
|
@@ -17055,7 +17059,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
}
|
|
|
|
|
MayHaveConvFixit = true;
|
|
|
|
|
break;
|
|
|
|
|
case IncompatiblePointerSign:
|
|
|
|
|
case AssignConvertType::IncompatiblePointerSign:
|
|
|
|
|
if (getLangOpts().CPlusPlus) {
|
|
|
|
|
DiagKind = diag::err_typecheck_convert_incompatible_pointer_sign;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
@@ -17063,7 +17067,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case FunctionVoidPointer:
|
|
|
|
|
case AssignConvertType::FunctionVoidPointer:
|
|
|
|
|
if (getLangOpts().CPlusPlus) {
|
|
|
|
|
DiagKind = diag::err_typecheck_convert_pointer_void_func;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
@@ -17071,7 +17075,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
DiagKind = diag::ext_typecheck_convert_pointer_void_func;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case IncompatiblePointerDiscardsQualifiers: {
|
|
|
|
|
case AssignConvertType::IncompatiblePointerDiscardsQualifiers: {
|
|
|
|
|
// Perform array-to-pointer decay if necessary.
|
|
|
|
|
if (SrcType->isArrayType()) SrcType = Context.getArrayDecayedType(SrcType);
|
|
|
|
|
|
|
|
|
|
@@ -17093,7 +17097,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
llvm_unreachable("unknown error case for discarding qualifiers!");
|
|
|
|
|
// fallthrough
|
|
|
|
|
}
|
|
|
|
|
case CompatiblePointerDiscardsQualifiers:
|
|
|
|
|
case AssignConvertType::CompatiblePointerDiscardsQualifiers:
|
|
|
|
|
// If the qualifiers lost were because we were applying the
|
|
|
|
|
// (deprecated) C++ conversion from a string literal to a char*
|
|
|
|
|
// (or wchar_t*), then there was no error (C++ 4.2p2). FIXME:
|
|
|
|
|
@@ -17114,7 +17118,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case IncompatibleNestedPointerQualifiers:
|
|
|
|
|
case AssignConvertType::IncompatibleNestedPointerQualifiers:
|
|
|
|
|
if (getLangOpts().CPlusPlus) {
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
DiagKind = diag::err_nested_pointer_qualifier_mismatch;
|
|
|
|
|
@@ -17122,19 +17126,19 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
DiagKind = diag::ext_nested_pointer_qualifier_mismatch;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case IncompatibleNestedPointerAddressSpaceMismatch:
|
|
|
|
|
case AssignConvertType::IncompatibleNestedPointerAddressSpaceMismatch:
|
|
|
|
|
DiagKind = diag::err_typecheck_incompatible_nested_address_space;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
break;
|
|
|
|
|
case IntToBlockPointer:
|
|
|
|
|
case AssignConvertType::IntToBlockPointer:
|
|
|
|
|
DiagKind = diag::err_int_to_block_pointer;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
break;
|
|
|
|
|
case IncompatibleBlockPointer:
|
|
|
|
|
case AssignConvertType::IncompatibleBlockPointer:
|
|
|
|
|
DiagKind = diag::err_typecheck_convert_incompatible_block_pointer;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
break;
|
|
|
|
|
case IncompatibleObjCQualifiedId: {
|
|
|
|
|
case AssignConvertType::IncompatibleObjCQualifiedId: {
|
|
|
|
|
if (SrcType->isObjCQualifiedIdType()) {
|
|
|
|
|
const ObjCObjectPointerType *srcOPT =
|
|
|
|
|
SrcType->castAs<ObjCObjectPointerType>();
|
|
|
|
|
@@ -17165,7 +17169,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case IncompatibleVectors:
|
|
|
|
|
case AssignConvertType::IncompatibleVectors:
|
|
|
|
|
if (getLangOpts().CPlusPlus) {
|
|
|
|
|
DiagKind = diag::err_incompatible_vectors;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
@@ -17173,11 +17177,11 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
DiagKind = diag::warn_incompatible_vectors;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case IncompatibleObjCWeakRef:
|
|
|
|
|
case AssignConvertType::IncompatibleObjCWeakRef:
|
|
|
|
|
DiagKind = diag::err_arc_weak_unavailable_assign;
|
|
|
|
|
isInvalid = true;
|
|
|
|
|
break;
|
|
|
|
|
case Incompatible:
|
|
|
|
|
case AssignConvertType::Incompatible:
|
|
|
|
|
if (maybeDiagnoseAssignmentToFunction(*this, DstType, SrcExpr)) {
|
|
|
|
|
if (Complained)
|
|
|
|
|
*Complained = true;
|
|
|
|
|
@@ -17256,7 +17260,8 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy,
|
|
|
|
|
if (CheckInferredResultType)
|
|
|
|
|
ObjC().EmitRelatedResultTypeNote(SrcExpr);
|
|
|
|
|
|
|
|
|
|
if (Action == AssignmentAction::Returning && ConvTy == IncompatiblePointer)
|
|
|
|
|
if (Action == AssignmentAction::Returning &&
|
|
|
|
|
ConvTy == AssignConvertType::IncompatiblePointer)
|
|
|
|
|
ObjC().EmitRelatedResultTypeNoteForReturn(DstType);
|
|
|
|
|
|
|
|
|
|
if (Complained)
|
|
|
|
|
|