()->getPointeeType();
if (!lhptee.isAtLeastAsQualifiedAs(rhptee) &&
// make an exception for id
!LHSType->isObjCQualifiedIdType())
return Sema::CompatiblePointerDiscardsQualifiers;
if (S.Context.typesAreCompatible(LHSType, RHSType))
return Sema::Compatible;
if (LHSType->isObjCQualifiedIdType() || RHSType->isObjCQualifiedIdType())
return Sema::IncompatibleObjCQualifiedId;
return Sema::IncompatiblePointer;
}
Sema::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
// usually happen on valid code.
OpaqueValueExpr RHSExpr(Loc, RHSType, VK_RValue);
ExprResult RHSPtr = &RHSExpr;
CastKind K = CK_Invalid;
return CheckAssignmentConstraints(LHSType, RHSPtr, K);
}
/// CheckAssignmentConstraints (C99 6.5.16) - This routine currently
/// has code to accommodate several GCC extensions when type checking
/// pointers. Here are some objectionable examples that GCC considers warnings:
///
/// int a, *pint;
/// short *pshort;
/// struct foo *pfoo;
///
/// pint = pshort; // warning: assignment from incompatible pointer type
/// a = pint; // warning: assignment makes integer from pointer without a cast
/// pint = a; // warning: assignment makes pointer from integer without a cast
/// pint = pfoo; // warning: assignment from incompatible pointer type
///
/// As a result, the code for dealing with pointers is more complex than the
/// C99 spec dictates.
///
/// Sets 'Kind' for any result kind except Incompatible.
Sema::AssignConvertType
Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
CastKind &Kind) {
QualType RHSType = RHS.get()->getType();
QualType OrigLHSType = LHSType;
// Get canonical types. We're not formatting these types, just comparing
// them.
LHSType = Context.getCanonicalType(LHSType).getUnqualifiedType();
RHSType = Context.getCanonicalType(RHSType).getUnqualifiedType();
// Common case: no conversion required.
if (LHSType == RHSType) {
Kind = CK_NoOp;
return Compatible;
}
if (const AtomicType *AtomicTy = dyn_cast(LHSType)) {
if (AtomicTy->getValueType() == RHSType) {
Kind = CK_NonAtomicToAtomic;
return Compatible;
}
}
if (const AtomicType *AtomicTy = dyn_cast(RHSType)) {
if (AtomicTy->getValueType() == LHSType) {
Kind = CK_AtomicToNonAtomic;
return Compatible;
}
}
// If the left-hand side is a reference type, then we are in a
// (rare!) case where we've allowed the use of references in C,
// e.g., as a parameter type in a built-in function. In this case,
// just make sure that the type referenced is compatible with the
// right-hand side type. The caller is responsible for adjusting
// LHSType so that the resulting expression does not have reference
// type.
if (const ReferenceType *LHSTypeRef = LHSType->getAs()) {
if (Context.typesAreCompatible(LHSTypeRef->getPointeeType(), RHSType)) {
Kind = CK_LValueBitCast;
return Compatible;
}
return 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;
if (RHSType->isArithmeticType()) {
// CK_VectorSplat does T -> vector T, so first cast to the
// element type.
QualType elType = cast(LHSType)->getElementType();
if (elType != RHSType) {
Kind = PrepareScalarCast(RHS, elType);
RHS = ImpCastExprToType(RHS.take(), elType, Kind);
}
Kind = CK_VectorSplat;
return Compatible;
}
}
// Conversions to or from vector type.
if (LHSType->isVectorType() || RHSType->isVectorType()) {
if (LHSType->isVectorType() && RHSType->isVectorType()) {
// Allow assignments of an AltiVec vector type to an equivalent GCC
// vector type and vice versa
if (Context.areCompatibleVectorTypes(LHSType, RHSType)) {
Kind = CK_BitCast;
return Compatible;
}
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a bitcast;
// no bits are changed but the result type is different.
if (getLangOpts().LaxVectorConversions &&
(Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType))) {
Kind = CK_BitCast;
return IncompatibleVectors;
}
}
return Incompatible;
}
// Arithmetic conversions.
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
Kind = PrepareScalarCast(RHS, LHSType);
return Compatible;
}
// Conversions to normal pointers.
if (const PointerType *LHSPointer = dyn_cast(LHSType)) {
// U* -> T*
if (isa(RHSType)) {
Kind = CK_BitCast;
return checkPointerTypesForAssignment(*this, LHSType, RHSType);
}
// int -> T*
if (RHSType->isIntegerType()) {
Kind = CK_IntegralToPointer; // FIXME: null?
return IntToPointer;
}
// C pointers are not compatible with ObjC object pointers,
// with two exceptions:
if (isa(RHSType)) {
// - conversions to void*
if (LHSPointer->getPointeeType()->isVoidType()) {
Kind = CK_BitCast;
return Compatible;
}
// - conversions from 'Class' to the redefinition type
if (RHSType->isObjCClassType() &&
Context.hasSameType(LHSType,
Context.getObjCClassRedefinitionType())) {
Kind = CK_BitCast;
return Compatible;
}
Kind = CK_BitCast;
return IncompatiblePointer;
}
// U^ -> void*
if (RHSType->getAs()) {
if (LHSPointer->getPointeeType()->isVoidType()) {
Kind = CK_BitCast;
return Compatible;
}
}
return Incompatible;
}
// Conversions to block pointers.
if (isa(LHSType)) {
// U^ -> T^
if (RHSType->isBlockPointerType()) {
Kind = CK_BitCast;
return checkBlockPointerTypesForAssignment(*this, LHSType, RHSType);
}
// int or null -> T^
if (RHSType->isIntegerType()) {
Kind = CK_IntegralToPointer; // FIXME: null
return IntToBlockPointer;
}
// id -> T^
if (getLangOpts().ObjC1 && RHSType->isObjCIdType()) {
Kind = CK_AnyPointerToBlockPointerCast;
return Compatible;
}
// void* -> T^
if (const PointerType *RHSPT = RHSType->getAs())
if (RHSPT->getPointeeType()->isVoidType()) {
Kind = CK_AnyPointerToBlockPointerCast;
return Compatible;
}
return Incompatible;
}
// Conversions to Objective-C pointers.
if (isa(LHSType)) {
// A* -> B*
if (RHSType->isObjCObjectPointerType()) {
Kind = CK_BitCast;
Sema::AssignConvertType result =
checkObjCPointerTypesForAssignment(*this, LHSType, RHSType);
if (getLangOpts().ObjCAutoRefCount &&
result == Compatible &&
!CheckObjCARCUnavailableWeakConversion(OrigLHSType, RHSType))
result = IncompatibleObjCWeakRef;
return result;
}
// int or null -> A*
if (RHSType->isIntegerType()) {
Kind = CK_IntegralToPointer; // FIXME: null
return IntToPointer;
}
// In general, C pointers are not compatible with ObjC object pointers,
// with two exceptions:
if (isa(RHSType)) {
Kind = CK_CPointerToObjCPointerCast;
// - conversions from 'void*'
if (RHSType->isVoidPointerType()) {
return Compatible;
}
// - conversions to 'Class' from its redefinition type
if (LHSType->isObjCClassType() &&
Context.hasSameType(RHSType,
Context.getObjCClassRedefinitionType())) {
return Compatible;
}
return IncompatiblePointer;
}
// T^ -> A*
if (RHSType->isBlockPointerType()) {
maybeExtendBlockObject(*this, RHS);
Kind = CK_BlockPointerToObjCPointerCast;
return Compatible;
}
return Incompatible;
}
// Conversions from pointers that are not covered by the above.
if (isa(RHSType)) {
// T* -> _Bool
if (LHSType == Context.BoolTy) {
Kind = CK_PointerToBoolean;
return Compatible;
}
// T* -> int
if (LHSType->isIntegerType()) {
Kind = CK_PointerToIntegral;
return PointerToInt;
}
return Incompatible;
}
// Conversions from Objective-C pointers that are not covered by the above.
if (isa(RHSType)) {
// T* -> _Bool
if (LHSType == Context.BoolTy) {
Kind = CK_PointerToBoolean;
return Compatible;
}
// T* -> int
if (LHSType->isIntegerType()) {
Kind = CK_PointerToIntegral;
return PointerToInt;
}
return Incompatible;
}
// struct A -> struct B
if (isa(LHSType) && isa(RHSType)) {
if (Context.typesAreCompatible(LHSType, RHSType)) {
Kind = CK_NoOp;
return Compatible;
}
}
return Incompatible;
}
/// \brief Constructs a transparent union from an expression that is
/// used to initialize the transparent union.
static void ConstructTransparentUnion(Sema &S, ASTContext &C,
ExprResult &EResult, QualType UnionType,
FieldDecl *Field) {
// Build an initializer list that designates the appropriate member
// of the transparent union.
Expr *E = EResult.take();
InitListExpr *Initializer = new (C) InitListExpr(C, SourceLocation(),
&E, 1,
SourceLocation());
Initializer->setType(UnionType);
Initializer->setInitializedFieldInUnion(Field);
// Build a compound literal constructing a value of the transparent
// union type from this initializer list.
TypeSourceInfo *unionTInfo = C.getTrivialTypeSourceInfo(UnionType);
EResult = S.Owned(
new (C) CompoundLiteralExpr(SourceLocation(), unionTInfo, UnionType,
VK_RValue, Initializer, false));
}
Sema::AssignConvertType
Sema::CheckTransparentUnionArgumentConstraints(QualType ArgType,
ExprResult &RHS) {
QualType RHSType = RHS.get()->getType();
// If the ArgType is a Union type, we want to handle a potential
// transparent_union GCC extension.
const RecordType *UT = ArgType->getAsUnionType();
if (!UT || !UT->getDecl()->hasAttr())
return Incompatible;
// The field to initialize within the transparent union.
RecordDecl *UD = UT->getDecl();
FieldDecl *InitField = 0;
// It's compatible if the expression matches any of the fields.
for (RecordDecl::field_iterator it = UD->field_begin(),
itend = UD->field_end();
it != itend; ++it) {
if (it->getType()->isPointerType()) {
// If the transparent union contains a pointer type, we allow:
// 1) void pointer
// 2) null pointer constant
if (RHSType->isPointerType())
if (RHSType->castAs()->getPointeeType()->isVoidType()) {
RHS = ImpCastExprToType(RHS.take(), it->getType(), CK_BitCast);
InitField = *it;
break;
}
if (RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
RHS = ImpCastExprToType(RHS.take(), it->getType(),
CK_NullToPointer);
InitField = *it;
break;
}
}
CastKind Kind = CK_Invalid;
if (CheckAssignmentConstraints(it->getType(), RHS, Kind)
== Compatible) {
RHS = ImpCastExprToType(RHS.take(), it->getType(), Kind);
InitField = *it;
break;
}
}
if (!InitField)
return Incompatible;
ConstructTransparentUnion(*this, Context, RHS, ArgType, InitField);
return Compatible;
}
Sema::AssignConvertType
Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &RHS,
bool Diagnose) {
if (getLangOpts().CPlusPlus) {
if (!LHSType->isRecordType() && !LHSType->isAtomicType()) {
// C++ 5.17p3: If the left operand is not of class type, the
// expression is implicitly converted (C++ 4) to the
// cv-unqualified type of the left operand.
ExprResult Res;
if (Diagnose) {
Res = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
AA_Assigning);
} else {
ImplicitConversionSequence ICS =
TryImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
/*SuppressUserConversions=*/false,
/*AllowExplicit=*/false,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
/*AllowObjCWritebackConversion=*/false);
if (ICS.isFailure())
return Incompatible;
Res = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
ICS, AA_Assigning);
}
if (Res.isInvalid())
return Incompatible;
Sema::AssignConvertType result = Compatible;
if (getLangOpts().ObjCAutoRefCount &&
!CheckObjCARCUnavailableWeakConversion(LHSType,
RHS.get()->getType()))
result = IncompatibleObjCWeakRef;
RHS = move(Res);
return result;
}
// FIXME: Currently, we fall through and treat C++ classes like C
// structures.
// FIXME: We also fall through for atomics; not sure what should
// happen there, though.
}
// C99 6.5.16.1p1: the left operand is a pointer and the right is
// a null pointer constant.
if ((LHSType->isPointerType() ||
LHSType->isObjCObjectPointerType() ||
LHSType->isBlockPointerType())
&& RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer);
return Compatible;
}
// This check seems unnatural, however it is necessary to ensure the proper
// conversion of functions/arrays. If the conversion were done for all
// DeclExpr's (created by ActOnIdExpression), it would mess up the unary
// expressions that suppress this implicit conversion (&, sizeof).
//
// Suppress this for references: C++ 8.5.3p5.
if (!LHSType->isReferenceType()) {
RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
if (RHS.isInvalid())
return Incompatible;
}
CastKind Kind = CK_Invalid;
Sema::AssignConvertType result =
CheckAssignmentConstraints(LHSType, RHS, Kind);
// C99 6.5.16.1p2: The value of the right operand is converted to the
// type of the assignment expression.
// CheckAssignmentConstraints allows the left-hand side to be a reference,
// 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)
RHS = ImpCastExprToType(RHS.take(),
LHSType.getNonLValueExprType(Context), Kind);
return result;
}
QualType Sema::InvalidOperands(SourceLocation Loc, ExprResult &LHS,
ExprResult &RHS) {
Diag(Loc, diag::err_typecheck_invalid_operands)
<< LHS.get()->getType() << RHS.get()->getType()
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompAssign) {
if (!IsCompAssign) {
LHS = DefaultFunctionArrayLvalueConversion(LHS.take());
if (LHS.isInvalid())
return QualType();
}
RHS = DefaultFunctionArrayLvalueConversion(RHS.take());
if (RHS.isInvalid())
return QualType();
// For conversion purposes, we ignore any qualifiers.
// For example, "const float" and "float" are equivalent.
QualType LHSType =
Context.getCanonicalType(LHS.get()->getType()).getUnqualifiedType();
QualType RHSType =
Context.getCanonicalType(RHS.get()->getType()).getUnqualifiedType();
// If the vector types are identical, return.
if (LHSType == RHSType)
return LHSType;
// Handle the case of equivalent AltiVec and GCC vector types
if (LHSType->isVectorType() && RHSType->isVectorType() &&
Context.areCompatibleVectorTypes(LHSType, RHSType)) {
if (LHSType->isExtVectorType()) {
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return LHSType;
}
if (!IsCompAssign)
LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
return RHSType;
}
if (getLangOpts().LaxVectorConversions &&
Context.getTypeSize(LHSType) == Context.getTypeSize(RHSType)) {
// If we are allowing lax vector conversions, and LHS and RHS are both
// vectors, the total size only needs to be the same. This is a
// bitcast; no bits are changed but the result type is different.
// FIXME: Should we really be allowing this?
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return LHSType;
}
// Canonicalize the ExtVector to the LHS, remember if we swapped so we can
// swap back (so that we don't reverse the inputs to a subtract, for instance.
bool swapped = false;
if (RHSType->isExtVectorType() && !IsCompAssign) {
swapped = true;
std::swap(RHS, LHS);
std::swap(RHSType, LHSType);
}
// Handle the case of an ext vector and scalar.
if (const ExtVectorType *LV = LHSType->getAs()) {
QualType EltTy = LV->getElementType();
if (EltTy->isIntegralType(Context) && RHSType->isIntegralType(Context)) {
int order = Context.getIntegerTypeOrder(EltTy, RHSType);
if (order > 0)
RHS = ImpCastExprToType(RHS.take(), EltTy, CK_IntegralCast);
if (order >= 0) {
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
if (swapped) std::swap(RHS, LHS);
return LHSType;
}
}
if (EltTy->isRealFloatingType() && RHSType->isScalarType() &&
RHSType->isRealFloatingType()) {
int order = Context.getFloatingTypeOrder(EltTy, RHSType);
if (order > 0)
RHS = ImpCastExprToType(RHS.take(), EltTy, CK_FloatingCast);
if (order >= 0) {
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_VectorSplat);
if (swapped) std::swap(RHS, LHS);
return LHSType;
}
}
}
// Vectors of different size or scalar and non-ext-vector are errors.
if (swapped) std::swap(RHS, LHS);
Diag(Loc, diag::err_typecheck_vector_not_convertable)
<< LHS.get()->getType() << RHS.get()->getType()
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return QualType();
}
// checkArithmeticNull - Detect when a NULL constant is used improperly in an
// expression. These are mainly cases where the null pointer is used as an
// integer instead of a pointer.
static void checkArithmeticNull(Sema &S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, bool IsCompare) {
// The canonical way to check for a GNU null is with isNullPointerConstant,
// but we use a bit of a hack here for speed; this is a relatively
// hot path, and isNullPointerConstant is slow.
bool LHSNull = isa(LHS.get()->IgnoreParenImpCasts());
bool RHSNull = isa(RHS.get()->IgnoreParenImpCasts());
QualType NonNullType = LHSNull ? RHS.get()->getType() : LHS.get()->getType();
// Avoid analyzing cases where the result will either be invalid (and
// diagnosed as such) or entirely valid and not something to warn about.
if ((!LHSNull && !RHSNull) || NonNullType->isBlockPointerType() ||
NonNullType->isMemberPointerType() || NonNullType->isFunctionType())
return;
// Comparison operations would not make sense with a null pointer no matter
// what the other expression is.
if (!IsCompare) {
S.Diag(Loc, diag::warn_null_in_arithmetic_operation)
<< (LHSNull ? LHS.get()->getSourceRange() : SourceRange())
<< (RHSNull ? RHS.get()->getSourceRange() : SourceRange());
return;
}
// The rest of the operations only make sense with a null pointer
// if the other expression is a pointer.
if (LHSNull == RHSNull || NonNullType->isAnyPointerType() ||
NonNullType->canDecayToPointerType())
return;
S.Diag(Loc, diag::warn_null_in_comparison_operation)
<< LHSNull /* LHS is NULL */ << NonNullType
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
bool IsCompAssign, bool IsDiv) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType())
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign);
QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (!LHS.get()->getType()->isArithmeticType() ||
!RHS.get()->getType()->isArithmeticType()) {
if (IsCompAssign &&
LHS.get()->getType()->isAtomicType() &&
RHS.get()->getType()->isArithmeticType())
return compType;
return InvalidOperands(Loc, LHS, RHS);
}
// Check for division by zero.
if (IsDiv &&
RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull))
DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_division_by_zero)
<< RHS.get()->getSourceRange());
return compType;
}
QualType Sema::CheckRemainderOperands(
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
if (LHS.get()->getType()->hasIntegerRepresentation() &&
RHS.get()->getType()->hasIntegerRepresentation())
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign);
return InvalidOperands(Loc, LHS, RHS);
}
QualType compType = UsualArithmeticConversions(LHS, RHS, IsCompAssign);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
if (!LHS.get()->getType()->isIntegerType() ||
!RHS.get()->getType()->isIntegerType())
return InvalidOperands(Loc, LHS, RHS);
// Check for remainder by zero.
if (RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNotNull))
DiagRuntimeBehavior(Loc, RHS.get(), PDiag(diag::warn_remainder_by_zero)
<< RHS.get()->getSourceRange());
return compType;
}
/// \brief Diagnose invalid arithmetic on two void pointers.
static void diagnoseArithmeticOnTwoVoidPointers(Sema &S, SourceLocation Loc,
Expr *LHSExpr, Expr *RHSExpr) {
S.Diag(Loc, S.getLangOpts().CPlusPlus
? diag::err_typecheck_pointer_arith_void_type
: diag::ext_gnu_void_ptr)
<< 1 /* two pointers */ << LHSExpr->getSourceRange()
<< RHSExpr->getSourceRange();
}
/// \brief Diagnose invalid arithmetic on a void pointer.
static void diagnoseArithmeticOnVoidPointer(Sema &S, SourceLocation Loc,
Expr *Pointer) {
S.Diag(Loc, S.getLangOpts().CPlusPlus
? diag::err_typecheck_pointer_arith_void_type
: diag::ext_gnu_void_ptr)
<< 0 /* one pointer */ << Pointer->getSourceRange();
}
/// \brief Diagnose invalid arithmetic on two function pointers.
static void diagnoseArithmeticOnTwoFunctionPointers(Sema &S, SourceLocation Loc,
Expr *LHS, Expr *RHS) {
assert(LHS->getType()->isAnyPointerType());
assert(RHS->getType()->isAnyPointerType());
S.Diag(Loc, S.getLangOpts().CPlusPlus
? diag::err_typecheck_pointer_arith_function_type
: diag::ext_gnu_ptr_func_arith)
<< 1 /* two pointers */ << LHS->getType()->getPointeeType()
// We only show the second type if it differs from the first.
<< (unsigned)!S.Context.hasSameUnqualifiedType(LHS->getType(),
RHS->getType())
<< RHS->getType()->getPointeeType()
<< LHS->getSourceRange() << RHS->getSourceRange();
}
/// \brief Diagnose invalid arithmetic on a function pointer.
static void diagnoseArithmeticOnFunctionPointer(Sema &S, SourceLocation Loc,
Expr *Pointer) {
assert(Pointer->getType()->isAnyPointerType());
S.Diag(Loc, S.getLangOpts().CPlusPlus
? diag::err_typecheck_pointer_arith_function_type
: diag::ext_gnu_ptr_func_arith)
<< 0 /* one pointer */ << Pointer->getType()->getPointeeType()
<< 0 /* one pointer, so only one type */
<< Pointer->getSourceRange();
}
/// \brief Emit error if Operand is incomplete pointer type
///
/// \returns True if pointer has incomplete type
static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc,
Expr *Operand) {
if ((Operand->getType()->isPointerType() &&
!Operand->getType()->isDependentType()) ||
Operand->getType()->isObjCObjectPointerType()) {
QualType PointeeTy = Operand->getType()->getPointeeType();
if (S.RequireCompleteType(
Loc, PointeeTy,
S.PDiag(diag::err_typecheck_arithmetic_incomplete_type)
<< PointeeTy << Operand->getSourceRange()))
return true;
}
return false;
}
/// \brief Check the validity of an arithmetic pointer operand.
///
/// If the operand has pointer type, this code will check for pointer types
/// which are invalid in arithmetic operations. These will be diagnosed
/// appropriately, including whether or not the use is supported as an
/// extension.
///
/// \returns True when the operand is valid to use (even if as an extension).
static bool checkArithmeticOpPointerOperand(Sema &S, SourceLocation Loc,
Expr *Operand) {
if (!Operand->getType()->isAnyPointerType()) return true;
QualType PointeeTy = Operand->getType()->getPointeeType();
if (PointeeTy->isVoidType()) {
diagnoseArithmeticOnVoidPointer(S, Loc, Operand);
return !S.getLangOpts().CPlusPlus;
}
if (PointeeTy->isFunctionType()) {
diagnoseArithmeticOnFunctionPointer(S, Loc, Operand);
return !S.getLangOpts().CPlusPlus;
}
if (checkArithmeticIncompletePointerType(S, Loc, Operand)) return false;
return true;
}
/// \brief Check the validity of a binary arithmetic operation w.r.t. pointer
/// operands.
///
/// This routine will diagnose any invalid arithmetic on pointer operands much
/// like \see checkArithmeticOpPointerOperand. However, it has special logic
/// for emitting a single diagnostic even for operations where both LHS and RHS
/// are (potentially problematic) pointers.
///
/// \returns True when the operand is valid to use (even if as an extension).
static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc,
Expr *LHSExpr, Expr *RHSExpr) {
bool isLHSPointer = LHSExpr->getType()->isAnyPointerType();
bool isRHSPointer = RHSExpr->getType()->isAnyPointerType();
if (!isLHSPointer && !isRHSPointer) return true;
QualType LHSPointeeTy, RHSPointeeTy;
if (isLHSPointer) LHSPointeeTy = LHSExpr->getType()->getPointeeType();
if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType();
// Check for arithmetic on pointers to incomplete types.
bool isLHSVoidPtr = isLHSPointer && LHSPointeeTy->isVoidType();
bool isRHSVoidPtr = isRHSPointer && RHSPointeeTy->isVoidType();
if (isLHSVoidPtr || isRHSVoidPtr) {
if (!isRHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, LHSExpr);
else if (!isLHSVoidPtr) diagnoseArithmeticOnVoidPointer(S, Loc, RHSExpr);
else diagnoseArithmeticOnTwoVoidPointers(S, Loc, LHSExpr, RHSExpr);
return !S.getLangOpts().CPlusPlus;
}
bool isLHSFuncPtr = isLHSPointer && LHSPointeeTy->isFunctionType();
bool isRHSFuncPtr = isRHSPointer && RHSPointeeTy->isFunctionType();
if (isLHSFuncPtr || isRHSFuncPtr) {
if (!isRHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc, LHSExpr);
else if (!isLHSFuncPtr) diagnoseArithmeticOnFunctionPointer(S, Loc,
RHSExpr);
else diagnoseArithmeticOnTwoFunctionPointers(S, Loc, LHSExpr, RHSExpr);
return !S.getLangOpts().CPlusPlus;
}
if (checkArithmeticIncompletePointerType(S, Loc, LHSExpr)) return false;
if (checkArithmeticIncompletePointerType(S, Loc, RHSExpr)) return false;
return true;
}
/// \brief Check bad cases where we step over interface counts.
static bool checkArithmethicPointerOnNonFragileABI(Sema &S,
SourceLocation OpLoc,
Expr *Op) {
assert(Op->getType()->isAnyPointerType());
QualType PointeeTy = Op->getType()->getPointeeType();
if (!PointeeTy->isObjCObjectType() || !S.LangOpts.ObjCNonFragileABI)
return true;
S.Diag(OpLoc, diag::err_arithmetic_nonfragile_interface)
<< PointeeTy << Op->getSourceRange();
return false;
}
/// diagnoseStringPlusInt - Emit a warning when adding an integer to a string
/// literal.
static void diagnoseStringPlusInt(Sema &Self, SourceLocation OpLoc,
Expr *LHSExpr, Expr *RHSExpr) {
StringLiteral* StrExpr = dyn_cast(LHSExpr->IgnoreImpCasts());
Expr* IndexExpr = RHSExpr;
if (!StrExpr) {
StrExpr = dyn_cast(RHSExpr->IgnoreImpCasts());
IndexExpr = LHSExpr;
}
bool IsStringPlusInt = StrExpr &&
IndexExpr->getType()->isIntegralOrUnscopedEnumerationType();
if (!IsStringPlusInt)
return;
llvm::APSInt index;
if (IndexExpr->EvaluateAsInt(index, Self.getASTContext())) {
unsigned StrLenWithNull = StrExpr->getLength() + 1;
if (index.isNonNegative() &&
index <= llvm::APSInt(llvm::APInt(index.getBitWidth(), StrLenWithNull),
index.isUnsigned()))
return;
}
SourceRange DiagRange(LHSExpr->getLocStart(), RHSExpr->getLocEnd());
Self.Diag(OpLoc, diag::warn_string_plus_int)
<< DiagRange << IndexExpr->IgnoreImpCasts()->getType();
// Only print a fixit for "str" + int, not for int + "str".
if (IndexExpr == RHSExpr) {
SourceLocation EndLoc = Self.PP.getLocForEndOfToken(RHSExpr->getLocEnd());
Self.Diag(OpLoc, diag::note_string_plus_int_silence)
<< FixItHint::CreateInsertion(LHSExpr->getLocStart(), "&")
<< FixItHint::CreateReplacement(SourceRange(OpLoc), "[")
<< FixItHint::CreateInsertion(EndLoc, "]");
} else
Self.Diag(OpLoc, diag::note_string_plus_int_silence);
}
/// \brief Emit error when two pointers are incompatible.
static void diagnosePointerIncompatibility(Sema &S, SourceLocation Loc,
Expr *LHSExpr, Expr *RHSExpr) {
assert(LHSExpr->getType()->isAnyPointerType());
assert(RHSExpr->getType()->isAnyPointerType());
S.Diag(Loc, diag::err_typecheck_sub_ptr_compatible)
<< LHSExpr->getType() << RHSExpr->getType() << LHSExpr->getSourceRange()
<< RHSExpr->getSourceRange();
}
QualType Sema::CheckAdditionOperands( // C99 6.5.6
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc,
QualType* CompLHSTy) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
QualType compType = CheckVectorOperands(LHS, RHS, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
// Diagnose "string literal" '+' int.
if (Opc == BO_Add)
diagnoseStringPlusInt(*this, Loc, LHS.get(), RHS.get());
// handle the common case first (both operands are arithmetic).
if (LHS.get()->getType()->isArithmeticType() &&
RHS.get()->getType()->isArithmeticType()) {
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
if (LHS.get()->getType()->isAtomicType() &&
RHS.get()->getType()->isArithmeticType()) {
*CompLHSTy = LHS.get()->getType();
return compType;
}
// Put any potential pointer into PExp
Expr* PExp = LHS.get(), *IExp = RHS.get();
if (IExp->getType()->isAnyPointerType())
std::swap(PExp, IExp);
if (!PExp->getType()->isAnyPointerType())
return InvalidOperands(Loc, LHS, RHS);
if (!IExp->getType()->isIntegerType())
return InvalidOperands(Loc, LHS, RHS);
if (!checkArithmeticOpPointerOperand(*this, Loc, PExp))
return QualType();
// Diagnose bad cases where we step over interface counts.
if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, PExp))
return QualType();
// Check array bounds for pointer arithemtic
CheckArrayAccess(PExp, IExp);
if (CompLHSTy) {
QualType LHSTy = Context.isPromotableBitField(LHS.get());
if (LHSTy.isNull()) {
LHSTy = LHS.get()->getType();
if (LHSTy->isPromotableIntegerType())
LHSTy = Context.getPromotedIntegerType(LHSTy);
}
*CompLHSTy = LHSTy;
}
return PExp->getType();
}
// C99 6.5.6
QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
QualType* CompLHSTy) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
QualType compType = CheckVectorOperands(LHS, RHS, Loc, CompLHSTy);
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
QualType compType = UsualArithmeticConversions(LHS, RHS, CompLHSTy);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
// Enforce type constraints: C99 6.5.6p3.
// Handle the common case first (both operands are arithmetic).
if (LHS.get()->getType()->isArithmeticType() &&
RHS.get()->getType()->isArithmeticType()) {
if (CompLHSTy) *CompLHSTy = compType;
return compType;
}
if (LHS.get()->getType()->isAtomicType() &&
RHS.get()->getType()->isArithmeticType()) {
*CompLHSTy = LHS.get()->getType();
return compType;
}
// Either ptr - int or ptr - ptr.
if (LHS.get()->getType()->isAnyPointerType()) {
QualType lpointee = LHS.get()->getType()->getPointeeType();
// Diagnose bad cases where we step over interface counts.
if (!checkArithmethicPointerOnNonFragileABI(*this, Loc, LHS.get()))
return QualType();
// The result type of a pointer-int computation is the pointer type.
if (RHS.get()->getType()->isIntegerType()) {
if (!checkArithmeticOpPointerOperand(*this, Loc, LHS.get()))
return QualType();
// Check array bounds for pointer arithemtic
CheckArrayAccess(LHS.get(), RHS.get(), /*ArraySubscriptExpr*/0,
/*AllowOnePastEnd*/true, /*IndexNegated*/true);
if (CompLHSTy) *CompLHSTy = LHS.get()->getType();
return LHS.get()->getType();
}
// Handle pointer-pointer subtractions.
if (const PointerType *RHSPTy
= RHS.get()->getType()->getAs()) {
QualType rpointee = RHSPTy->getPointeeType();
if (getLangOpts().CPlusPlus) {
// Pointee types must be the same: C++ [expr.add]
if (!Context.hasSameUnqualifiedType(lpointee, rpointee)) {
diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get());
}
} else {
// Pointee types must be compatible C99 6.5.6p3
if (!Context.typesAreCompatible(
Context.getCanonicalType(lpointee).getUnqualifiedType(),
Context.getCanonicalType(rpointee).getUnqualifiedType())) {
diagnosePointerIncompatibility(*this, Loc, LHS.get(), RHS.get());
return QualType();
}
}
if (!checkArithmeticBinOpPointerOperands(*this, Loc,
LHS.get(), RHS.get()))
return QualType();
if (CompLHSTy) *CompLHSTy = LHS.get()->getType();
return Context.getPointerDiffType();
}
}
return InvalidOperands(Loc, LHS, RHS);
}
static bool isScopedEnumerationType(QualType T) {
if (const EnumType *ET = dyn_cast(T))
return ET->getDecl()->isScoped();
return false;
}
static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned Opc,
QualType LHSType) {
llvm::APSInt Right;
// Check right/shifter operand
if (RHS.get()->isValueDependent() ||
!RHS.get()->isIntegerConstantExpr(Right, S.Context))
return;
if (Right.isNegative()) {
S.DiagRuntimeBehavior(Loc, RHS.get(),
S.PDiag(diag::warn_shift_negative)
<< RHS.get()->getSourceRange());
return;
}
llvm::APInt LeftBits(Right.getBitWidth(),
S.Context.getTypeSize(LHS.get()->getType()));
if (Right.uge(LeftBits)) {
S.DiagRuntimeBehavior(Loc, RHS.get(),
S.PDiag(diag::warn_shift_gt_typewidth)
<< RHS.get()->getSourceRange());
return;
}
if (Opc != BO_Shl)
return;
// When left shifting an ICE which is signed, we can check for overflow which
// according to C++ has undefined behavior ([expr.shift] 5.8/2). Unsigned
// integers have defined behavior modulo one more than the maximum value
// representable in the result type, so never warn for those.
llvm::APSInt Left;
if (LHS.get()->isValueDependent() ||
!LHS.get()->isIntegerConstantExpr(Left, S.Context) ||
LHSType->hasUnsignedIntegerRepresentation())
return;
llvm::APInt ResultBits =
static_cast(Right) + Left.getMinSignedBits();
if (LeftBits.uge(ResultBits))
return;
llvm::APSInt Result = Left.extend(ResultBits.getLimitedValue());
Result = Result.shl(Right);
// Print the bit representation of the signed integer as an unsigned
// hexadecimal number.
SmallString<40> HexResult;
Result.toString(HexResult, 16, /*Signed =*/false, /*Literal =*/true);
// If we are only missing a sign bit, this is less likely to result in actual
// bugs -- if the result is cast back to an unsigned type, it will have the
// expected value. Thus we place this behind a different warning that can be
// turned off separately if needed.
if (LeftBits == ResultBits - 1) {
S.Diag(Loc, diag::warn_shift_result_sets_sign_bit)
<< HexResult.str() << LHSType
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
return;
}
S.Diag(Loc, diag::warn_shift_result_gt_typewidth)
<< HexResult.str() << Result.getMinSignedBits() << LHSType
<< Left.getBitWidth() << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
}
// C99 6.5.7
QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned Opc,
bool IsCompAssign) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
// C99 6.5.7p2: Each of the operands shall have integer type.
if (!LHS.get()->getType()->hasIntegerRepresentation() ||
!RHS.get()->getType()->hasIntegerRepresentation())
return InvalidOperands(Loc, LHS, RHS);
// C++0x: Don't allow scoped enums. FIXME: Use something better than
// hasIntegerRepresentation() above instead of this.
if (isScopedEnumerationType(LHS.get()->getType()) ||
isScopedEnumerationType(RHS.get()->getType())) {
return InvalidOperands(Loc, LHS, RHS);
}
// Vector shifts promote their scalar inputs to vector type.
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType())
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign);
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
// For the LHS, do usual unary conversions, but then reset them away
// if this is a compound assignment.
ExprResult OldLHS = LHS;
LHS = UsualUnaryConversions(LHS.take());
if (LHS.isInvalid())
return QualType();
QualType LHSType = LHS.get()->getType();
if (IsCompAssign) LHS = OldLHS;
// The RHS is simpler.
RHS = UsualUnaryConversions(RHS.take());
if (RHS.isInvalid())
return QualType();
// Sanity-check shift operands
DiagnoseBadShiftValues(*this, LHS, RHS, Loc, Opc, LHSType);
// "The type of the result is that of the promoted left operand."
return LHSType;
}
static bool IsWithinTemplateSpecialization(Decl *D) {
if (DeclContext *DC = D->getDeclContext()) {
if (isa(DC))
return true;
if (FunctionDecl *FD = dyn_cast(DC))
return FD->isFunctionTemplateSpecialization();
}
return false;
}
/// If two different enums are compared, raise a warning.
static void checkEnumComparison(Sema &S, SourceLocation Loc, ExprResult &LHS,
ExprResult &RHS) {
QualType LHSStrippedType = LHS.get()->IgnoreParenImpCasts()->getType();
QualType RHSStrippedType = RHS.get()->IgnoreParenImpCasts()->getType();
const EnumType *LHSEnumType = LHSStrippedType->getAs();
if (!LHSEnumType)
return;
const EnumType *RHSEnumType = RHSStrippedType->getAs();
if (!RHSEnumType)
return;
// Ignore anonymous enums.
if (!LHSEnumType->getDecl()->getIdentifier())
return;
if (!RHSEnumType->getDecl()->getIdentifier())
return;
if (S.Context.hasSameUnqualifiedType(LHSStrippedType, RHSStrippedType))
return;
S.Diag(Loc, diag::warn_comparison_of_mixed_enum_types)
<< LHSStrippedType << RHSStrippedType
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
/// \brief Diagnose bad pointer comparisons.
static void diagnoseDistinctPointerComparison(Sema &S, SourceLocation Loc,
ExprResult &LHS, ExprResult &RHS,
bool IsError) {
S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_distinct_pointers
: diag::ext_typecheck_comparison_of_distinct_pointers)
<< LHS.get()->getType() << RHS.get()->getType()
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
/// \brief Returns false if the pointers are converted to a composite type,
/// true otherwise.
static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc,
ExprResult &LHS, ExprResult &RHS) {
// C++ [expr.rel]p2:
// [...] Pointer conversions (4.10) and qualification
// conversions (4.4) are performed on pointer operands (or on
// a pointer operand and a null pointer constant) to bring
// them to their composite pointer type. [...]
//
// C++ [expr.eq]p1 uses the same notion for (in)equality
// comparisons of pointers.
// C++ [expr.eq]p2:
// In addition, pointers to members can be compared, or a pointer to
// member and a null pointer constant. Pointer to member conversions
// (4.11) and qualification conversions (4.4) are performed to bring
// them to a common type. If one operand is a null pointer constant,
// the common type is the type of the other operand. Otherwise, the
// common type is a pointer to member type similar (4.4) to the type
// of one of the operands, with a cv-qualification signature (4.4)
// that is the union of the cv-qualification signatures of the operand
// types.
QualType LHSType = LHS.get()->getType();
QualType RHSType = RHS.get()->getType();
assert((LHSType->isPointerType() && RHSType->isPointerType()) ||
(LHSType->isMemberPointerType() && RHSType->isMemberPointerType()));
bool NonStandardCompositeType = false;
bool *BoolPtr = S.isSFINAEContext() ? 0 : &NonStandardCompositeType;
QualType T = S.FindCompositePointerType(Loc, LHS, RHS, BoolPtr);
if (T.isNull()) {
diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true);
return true;
}
if (NonStandardCompositeType)
S.Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard)
<< LHSType << RHSType << T << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
LHS = S.ImpCastExprToType(LHS.take(), T, CK_BitCast);
RHS = S.ImpCastExprToType(RHS.take(), T, CK_BitCast);
return false;
}
static void diagnoseFunctionPointerToVoidComparison(Sema &S, SourceLocation Loc,
ExprResult &LHS,
ExprResult &RHS,
bool IsError) {
S.Diag(Loc, IsError ? diag::err_typecheck_comparison_of_fptr_to_void
: diag::ext_typecheck_comparison_of_fptr_to_void)
<< LHS.get()->getType() << RHS.get()->getType()
<< LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
}
// C99 6.5.8, C++ [expr.rel]
QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc, unsigned OpaqueOpc,
bool IsRelational) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/true);
BinaryOperatorKind Opc = (BinaryOperatorKind) OpaqueOpc;
// Handle vector comparisons separately.
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType())
return CheckVectorCompareOperands(LHS, RHS, Loc, IsRelational);
QualType LHSType = LHS.get()->getType();
QualType RHSType = RHS.get()->getType();
Expr *LHSStripped = LHS.get()->IgnoreParenImpCasts();
Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts();
checkEnumComparison(*this, Loc, LHS, RHS);
if (!LHSType->hasFloatingRepresentation() &&
!(LHSType->isBlockPointerType() && IsRelational) &&
!LHS.get()->getLocStart().isMacroID() &&
!RHS.get()->getLocStart().isMacroID()) {
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
//
// NOTE: Don't warn about comparison expressions resulting from macro
// expansion. Also don't warn about comparisons which are only self
// comparisons within a template specialization. The warnings should catch
// obvious cases in the definition of the template anyways. The idea is to
// warn when the typed comparison operator will always evaluate to the same
// result.
if (DeclRefExpr* DRL = dyn_cast(LHSStripped)) {
if (DeclRefExpr* DRR = dyn_cast(RHSStripped)) {
if (DRL->getDecl() == DRR->getDecl() &&
!IsWithinTemplateSpecialization(DRL->getDecl())) {
DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
<< 0 // self-
<< (Opc == BO_EQ
|| Opc == BO_LE
|| Opc == BO_GE));
} else if (LHSType->isArrayType() && RHSType->isArrayType() &&
!DRL->getDecl()->getType()->isReferenceType() &&
!DRR->getDecl()->getType()->isReferenceType()) {
// what is it always going to eval to?
char always_evals_to;
switch(Opc) {
case BO_EQ: // e.g. array1 == array2
always_evals_to = 0; // false
break;
case BO_NE: // e.g. array1 != array2
always_evals_to = 1; // true
break;
default:
// best we can say is 'a constant'
always_evals_to = 2; // e.g. array1 <= array2
break;
}
DiagRuntimeBehavior(Loc, 0, PDiag(diag::warn_comparison_always)
<< 1 // array
<< always_evals_to);
}
}
}
if (isa(LHSStripped))
LHSStripped = LHSStripped->IgnoreParenCasts();
if (isa(RHSStripped))
RHSStripped = RHSStripped->IgnoreParenCasts();
// Warn about comparisons against a string constant (unless the other
// operand is null), the user probably wants strcmp.
Expr *literalString = 0;
Expr *literalStringStripped = 0;
if ((isa(LHSStripped) || isa(LHSStripped)) &&
!RHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
literalString = LHS.get();
literalStringStripped = LHSStripped;
} else if ((isa(RHSStripped) ||
isa(RHSStripped)) &&
!LHSStripped->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
literalString = RHS.get();
literalStringStripped = RHSStripped;
}
if (literalString) {
std::string resultComparison;
switch (Opc) {
case BO_LT: resultComparison = ") < 0"; break;
case BO_GT: resultComparison = ") > 0"; break;
case BO_LE: resultComparison = ") <= 0"; break;
case BO_GE: resultComparison = ") >= 0"; break;
case BO_EQ: resultComparison = ") == 0"; break;
case BO_NE: resultComparison = ") != 0"; break;
default: llvm_unreachable("Invalid comparison operator");
}
DiagRuntimeBehavior(Loc, 0,
PDiag(diag::warn_stringcompare)
<< isa(literalStringStripped)
<< literalString->getSourceRange());
}
}
// C99 6.5.8p3 / C99 6.5.9p4
if (LHS.get()->getType()->isArithmeticType() &&
RHS.get()->getType()->isArithmeticType()) {
UsualArithmeticConversions(LHS, RHS);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
}
else {
LHS = UsualUnaryConversions(LHS.take());
if (LHS.isInvalid())
return QualType();
RHS = UsualUnaryConversions(RHS.take());
if (RHS.isInvalid())
return QualType();
}
LHSType = LHS.get()->getType();
RHSType = RHS.get()->getType();
// The result of comparisons is 'bool' in C++, 'int' in C.
QualType ResultTy = Context.getLogicalOperationType();
if (IsRelational) {
if (LHSType->isRealType() && RHSType->isRealType())
return ResultTy;
} else {
// Check for comparisons of floating point operands using != and ==.
if (LHSType->hasFloatingRepresentation())
CheckFloatComparison(Loc, LHS.get(), RHS.get());
if (LHSType->isArithmeticType() && RHSType->isArithmeticType())
return ResultTy;
}
bool LHSIsNull = LHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
bool RHSIsNull = RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull);
// All of the following pointer-related warnings are GCC extensions, except
// when handling null pointer constants.
if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2
QualType LCanPointeeTy =
LHSType->castAs()->getPointeeType().getCanonicalType();
QualType RCanPointeeTy =
RHSType->castAs()->getPointeeType().getCanonicalType();
if (getLangOpts().CPlusPlus) {
if (LCanPointeeTy == RCanPointeeTy)
return ResultTy;
if (!IsRelational &&
(LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
// Valid unless comparison between non-null pointer and function pointer
// This is a gcc extension compatibility comparison.
// In a SFINAE context, we treat this as a hard error to maintain
// conformance with the C++ standard.
if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
&& !LHSIsNull && !RHSIsNull) {
diagnoseFunctionPointerToVoidComparison(
*this, Loc, LHS, RHS, /*isError*/ isSFINAEContext());
if (isSFINAEContext())
return QualType();
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return ResultTy;
}
}
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
else
return ResultTy;
}
// C99 6.5.9p2 and C99 6.5.8p2
if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(),
RCanPointeeTy.getUnqualifiedType())) {
// Valid unless a relational comparison of function pointers
if (IsRelational && LCanPointeeTy->isFunctionType()) {
Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers)
<< LHSType << RHSType << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
}
} else if (!IsRelational &&
(LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) {
// Valid unless comparison between non-null pointer and function pointer
if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType())
&& !LHSIsNull && !RHSIsNull)
diagnoseFunctionPointerToVoidComparison(*this, Loc, LHS, RHS,
/*isError*/false);
} else {
// Invalid
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS, /*isError*/false);
}
if (LCanPointeeTy != RCanPointeeTy) {
if (LHSIsNull && !RHSIsNull)
LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
else
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
}
return ResultTy;
}
if (getLangOpts().CPlusPlus) {
// Comparison of nullptr_t with itself.
if (LHSType->isNullPtrType() && RHSType->isNullPtrType())
return ResultTy;
// Comparison of pointers with null pointer constants and equality
// comparisons of member pointers to null pointer constants.
if (RHSIsNull &&
((LHSType->isAnyPointerType() || LHSType->isNullPtrType()) ||
(!IsRelational &&
(LHSType->isMemberPointerType() || LHSType->isBlockPointerType())))) {
RHS = ImpCastExprToType(RHS.take(), LHSType,
LHSType->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer);
return ResultTy;
}
if (LHSIsNull &&
((RHSType->isAnyPointerType() || RHSType->isNullPtrType()) ||
(!IsRelational &&
(RHSType->isMemberPointerType() || RHSType->isBlockPointerType())))) {
LHS = ImpCastExprToType(LHS.take(), RHSType,
RHSType->isMemberPointerType()
? CK_NullToMemberPointer
: CK_NullToPointer);
return ResultTy;
}
// Comparison of member pointers.
if (!IsRelational &&
LHSType->isMemberPointerType() && RHSType->isMemberPointerType()) {
if (convertPointersToCompositeType(*this, Loc, LHS, RHS))
return QualType();
else
return ResultTy;
}
// Handle scoped enumeration types specifically, since they don't promote
// to integers.
if (LHS.get()->getType()->isEnumeralType() &&
Context.hasSameUnqualifiedType(LHS.get()->getType(),
RHS.get()->getType()))
return ResultTy;
}
// Handle block pointer types.
if (!IsRelational && LHSType->isBlockPointerType() &&
RHSType->isBlockPointerType()) {
QualType lpointee = LHSType->castAs()->getPointeeType();
QualType rpointee = RHSType->castAs()->getPointeeType();
if (!LHSIsNull && !RHSIsNull &&
!Context.typesAreCompatible(lpointee, rpointee)) {
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
<< LHSType << RHSType << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
}
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return ResultTy;
}
// Allow block pointers to be compared with null pointer constants.
if (!IsRelational
&& ((LHSType->isBlockPointerType() && RHSType->isPointerType())
|| (LHSType->isPointerType() && RHSType->isBlockPointerType()))) {
if (!LHSIsNull && !RHSIsNull) {
if (!((RHSType->isPointerType() && RHSType->castAs()
->getPointeeType()->isVoidType())
|| (LHSType->isPointerType() && LHSType->castAs()
->getPointeeType()->isVoidType())))
Diag(Loc, diag::err_typecheck_comparison_of_distinct_blocks)
<< LHSType << RHSType << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
}
if (LHSIsNull && !RHSIsNull)
LHS = ImpCastExprToType(LHS.take(), RHSType,
RHSType->isPointerType() ? CK_BitCast
: CK_AnyPointerToBlockPointerCast);
else
RHS = ImpCastExprToType(RHS.take(), LHSType,
LHSType->isPointerType() ? CK_BitCast
: CK_AnyPointerToBlockPointerCast);
return ResultTy;
}
if (LHSType->isObjCObjectPointerType() ||
RHSType->isObjCObjectPointerType()) {
const PointerType *LPT = LHSType->getAs();
const PointerType *RPT = RHSType->getAs();
if (LPT || RPT) {
bool LPtrToVoid = LPT ? LPT->getPointeeType()->isVoidType() : false;
bool RPtrToVoid = RPT ? RPT->getPointeeType()->isVoidType() : false;
if (!LPtrToVoid && !RPtrToVoid &&
!Context.typesAreCompatible(LHSType, RHSType)) {
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS,
/*isError*/false);
}
if (LHSIsNull && !RHSIsNull)
LHS = ImpCastExprToType(LHS.take(), RHSType,
RPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
else
RHS = ImpCastExprToType(RHS.take(), LHSType,
LPT ? CK_BitCast :CK_CPointerToObjCPointerCast);
return ResultTy;
}
if (LHSType->isObjCObjectPointerType() &&
RHSType->isObjCObjectPointerType()) {
if (!Context.areComparableObjCPointerTypes(LHSType, RHSType))
diagnoseDistinctPointerComparison(*this, Loc, LHS, RHS,
/*isError*/false);
if (LHSIsNull && !RHSIsNull)
LHS = ImpCastExprToType(LHS.take(), RHSType, CK_BitCast);
else
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_BitCast);
return ResultTy;
}
}
if ((LHSType->isAnyPointerType() && RHSType->isIntegerType()) ||
(LHSType->isIntegerType() && RHSType->isAnyPointerType())) {
unsigned DiagID = 0;
bool isError = false;
if ((LHSIsNull && LHSType->isIntegerType()) ||
(RHSIsNull && RHSType->isIntegerType())) {
if (IsRelational && !getLangOpts().CPlusPlus)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero;
} else if (IsRelational && !getLangOpts().CPlusPlus)
DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer;
else if (getLangOpts().CPlusPlus) {
DiagID = diag::err_typecheck_comparison_of_pointer_integer;
isError = true;
} else
DiagID = diag::ext_typecheck_comparison_of_pointer_integer;
if (DiagID) {
Diag(Loc, DiagID)
<< LHSType << RHSType << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
if (isError)
return QualType();
}
if (LHSType->isIntegerType())
LHS = ImpCastExprToType(LHS.take(), RHSType,
LHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
else
RHS = ImpCastExprToType(RHS.take(), LHSType,
RHSIsNull ? CK_NullToPointer : CK_IntegralToPointer);
return ResultTy;
}
// Handle block pointers.
if (!IsRelational && RHSIsNull
&& LHSType->isBlockPointerType() && RHSType->isIntegerType()) {
RHS = ImpCastExprToType(RHS.take(), LHSType, CK_NullToPointer);
return ResultTy;
}
if (!IsRelational && LHSIsNull
&& LHSType->isIntegerType() && RHSType->isBlockPointerType()) {
LHS = ImpCastExprToType(LHS.take(), RHSType, CK_NullToPointer);
return ResultTy;
}
return InvalidOperands(Loc, LHS, RHS);
}
// Return a signed type that is of identical size and number of elements.
// For floating point vectors, return an integer type of identical size
// and number of elements.
QualType Sema::GetSignedVectorType(QualType V) {
const VectorType *VTy = V->getAs();
unsigned TypeSize = Context.getTypeSize(VTy->getElementType());
if (TypeSize == Context.getTypeSize(Context.CharTy))
return Context.getExtVectorType(Context.CharTy, VTy->getNumElements());
else if (TypeSize == Context.getTypeSize(Context.ShortTy))
return Context.getExtVectorType(Context.ShortTy, VTy->getNumElements());
else if (TypeSize == Context.getTypeSize(Context.IntTy))
return Context.getExtVectorType(Context.IntTy, VTy->getNumElements());
else if (TypeSize == Context.getTypeSize(Context.LongTy))
return Context.getExtVectorType(Context.LongTy, VTy->getNumElements());
assert(TypeSize == Context.getTypeSize(Context.LongLongTy) &&
"Unhandled vector element size in vector compare");
return Context.getExtVectorType(Context.LongLongTy, VTy->getNumElements());
}
/// CheckVectorCompareOperands - vector comparisons are a clang extension that
/// operates on extended vector types. Instead of producing an IntTy result,
/// like a scalar comparison, a vector comparison produces a vector of integer
/// types.
QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc,
bool IsRelational) {
// Check to make sure we're operating on vectors of the same type and width,
// Allowing one side to be a scalar of element type.
QualType vType = CheckVectorOperands(LHS, RHS, Loc, /*isCompAssign*/false);
if (vType.isNull())
return vType;
QualType LHSType = LHS.get()->getType();
// If AltiVec, the comparison results in a numeric type, i.e.
// bool for C++, int for C
if (vType->getAs()->getVectorKind() == VectorType::AltiVecVector)
return Context.getLogicalOperationType();
// For non-floating point types, check for self-comparisons of the form
// x == x, x != x, x < x, etc. These always evaluate to a constant, and
// often indicate logic errors in the program.
if (!LHSType->hasFloatingRepresentation()) {
if (DeclRefExpr* DRL
= dyn_cast(LHS.get()->IgnoreParenImpCasts()))
if (DeclRefExpr* DRR
= dyn_cast(RHS.get()->IgnoreParenImpCasts()))
if (DRL->getDecl() == DRR->getDecl())
DiagRuntimeBehavior(Loc, 0,
PDiag(diag::warn_comparison_always)
<< 0 // self-
<< 2 // "a constant"
);
}
// Check for comparisons of floating point operands using != and ==.
if (!IsRelational && LHSType->hasFloatingRepresentation()) {
assert (RHS.get()->getType()->hasFloatingRepresentation());
CheckFloatComparison(Loc, LHS.get(), RHS.get());
}
// Return a signed type for the vector.
return GetSignedVectorType(LHSType);
}
QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc) {
// Ensure that either both operands are of the same vector type, or
// one operand is of a vector type and the other is of its element type.
QualType vType = CheckVectorOperands(LHS, RHS, Loc, false);
if (vType.isNull() || vType->isFloatingType())
return InvalidOperands(Loc, LHS, RHS);
return GetSignedVectorType(LHS.get()->getType());
}
inline QualType Sema::CheckBitwiseOperands(
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) {
checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false);
if (LHS.get()->getType()->isVectorType() ||
RHS.get()->getType()->isVectorType()) {
if (LHS.get()->getType()->hasIntegerRepresentation() &&
RHS.get()->getType()->hasIntegerRepresentation())
return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign);
return InvalidOperands(Loc, LHS, RHS);
}
ExprResult LHSResult = Owned(LHS), RHSResult = Owned(RHS);
QualType compType = UsualArithmeticConversions(LHSResult, RHSResult,
IsCompAssign);
if (LHSResult.isInvalid() || RHSResult.isInvalid())
return QualType();
LHS = LHSResult.take();
RHS = RHSResult.take();
if (LHS.get()->getType()->isIntegralOrUnscopedEnumerationType() &&
RHS.get()->getType()->isIntegralOrUnscopedEnumerationType())
return compType;
return InvalidOperands(Loc, LHS, RHS);
}
inline QualType Sema::CheckLogicalOperands( // C99 6.5.[13,14]
ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, unsigned Opc) {
// Check vector operands differently.
if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType())
return CheckVectorLogicalOperands(LHS, RHS, Loc);
// Diagnose cases where the user write a logical and/or but probably meant a
// bitwise one. We do this when the LHS is a non-bool integer and the RHS
// is a constant.
if (LHS.get()->getType()->isIntegerType() &&
!LHS.get()->getType()->isBooleanType() &&
RHS.get()->getType()->isIntegerType() && !RHS.get()->isValueDependent() &&
// Don't warn in macros or template instantiations.
!Loc.isMacroID() && ActiveTemplateInstantiations.empty()) {
// If the RHS can be constant folded, and if it constant folds to something
// that isn't 0 or 1 (which indicate a potential logical operation that
// happened to fold to true/false) then warn.
// Parens on the RHS are ignored.
llvm::APSInt Result;
if (RHS.get()->EvaluateAsInt(Result, Context))
if ((getLangOpts().Bool && !RHS.get()->getType()->isBooleanType()) ||
(Result != 0 && Result != 1)) {
Diag(Loc, diag::warn_logical_instead_of_bitwise)
<< RHS.get()->getSourceRange()
<< (Opc == BO_LAnd ? "&&" : "||");
// Suggest replacing the logical operator with the bitwise version
Diag(Loc, diag::note_logical_instead_of_bitwise_change_operator)
<< (Opc == BO_LAnd ? "&" : "|")
<< FixItHint::CreateReplacement(SourceRange(
Loc, Lexer::getLocForEndOfToken(Loc, 0, getSourceManager(),
getLangOpts())),
Opc == BO_LAnd ? "&" : "|");
if (Opc == BO_LAnd)
// Suggest replacing "Foo() && kNonZero" with "Foo()"
Diag(Loc, diag::note_logical_instead_of_bitwise_remove_constant)
<< FixItHint::CreateRemoval(
SourceRange(
Lexer::getLocForEndOfToken(LHS.get()->getLocEnd(),
0, getSourceManager(),
getLangOpts()),
RHS.get()->getLocEnd()));
}
}
if (!Context.getLangOpts().CPlusPlus) {
LHS = UsualUnaryConversions(LHS.take());
if (LHS.isInvalid())
return QualType();
RHS = UsualUnaryConversions(RHS.take());
if (RHS.isInvalid())
return QualType();
if (!LHS.get()->getType()->isScalarType() ||
!RHS.get()->getType()->isScalarType())
return InvalidOperands(Loc, LHS, RHS);
return Context.IntTy;
}
// The following is safe because we only use this method for
// non-overloadable operands.
// C++ [expr.log.and]p1
// C++ [expr.log.or]p1
// The operands are both contextually converted to type bool.
ExprResult LHSRes = PerformContextuallyConvertToBool(LHS.get());
if (LHSRes.isInvalid())
return InvalidOperands(Loc, LHS, RHS);
LHS = move(LHSRes);
ExprResult RHSRes = PerformContextuallyConvertToBool(RHS.get());
if (RHSRes.isInvalid())
return InvalidOperands(Loc, LHS, RHS);
RHS = move(RHSRes);
// C++ [expr.log.and]p2
// C++ [expr.log.or]p2
// The result is a bool.
return Context.BoolTy;
}
/// IsReadonlyProperty - Verify that otherwise a valid l-value expression
/// is a read-only property; return true if so. A readonly property expression
/// depends on various declarations and thus must be treated specially.
///
static bool IsReadonlyProperty(Expr *E, Sema &S) {
const ObjCPropertyRefExpr *PropExpr = dyn_cast(E);
if (!PropExpr) return false;
if (PropExpr->isImplicitProperty()) return false;
ObjCPropertyDecl *PDecl = PropExpr->getExplicitProperty();
QualType BaseType = PropExpr->isSuperReceiver() ?
PropExpr->getSuperReceiverType() :
PropExpr->getBase()->getType();
if (const ObjCObjectPointerType *OPT =
BaseType->getAsObjCInterfacePointerType())
if (ObjCInterfaceDecl *IFace = OPT->getInterfaceDecl())
if (S.isPropertyReadonly(PDecl, IFace))
return true;
return false;
}
static bool IsReadonlyMessage(Expr *E, Sema &S) {
const MemberExpr *ME = dyn_cast(E);
if (!ME) return false;
if (!isa(ME->getMemberDecl())) return false;
ObjCMessageExpr *Base =
dyn_cast(ME->getBase()->IgnoreParenImpCasts());
if (!Base) return false;
return Base->getMethodDecl() != 0;
}
/// Is the given expression (which must be 'const') a reference to a
/// variable which was originally non-const, but which has become
/// 'const' due to being captured within a block?
enum NonConstCaptureKind { NCCK_None, NCCK_Block, NCCK_Lambda };
static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
assert(E->isLValue() && E->getType().isConstQualified());
E = E->IgnoreParens();
// Must be a reference to a declaration from an enclosing scope.
DeclRefExpr *DRE = dyn_cast