Refactor CheckConditionalOperands() by moving chunks of code to helper functions making a slimmer function.

llvm-svn: 138992
This commit is contained in:
Richard Trieu 2011-09-02 01:51:02 +00:00
parent 5b49bb6bf5
commit 27ae4cb7c4
1 changed files with 227 additions and 163 deletions

View File

@ -4331,7 +4331,8 @@ ExprResult Sema::ActOnParenOrParenListExpr(SourceLocation L,
}
/// \brief Emit a specialized diagnostic when one expression is a null pointer
/// constant and the other is not a pointer.
/// constant and the other is not a pointer. Returns true if a diagnostic is
/// emitted.
bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS,
SourceLocation QuestionLoc) {
Expr *NullExpr = LHS;
@ -4367,6 +4368,213 @@ bool Sema::DiagnoseConditionalForNull(Expr *LHS, Expr *RHS,
return true;
}
/// \brief Return false if the condition expression is valid, true otherwise.
static bool checkCondition(Sema &S, Expr *Cond) {
QualType CondTy = Cond->getType();
// C99 6.5.15p2
if (CondTy->isScalarType()) return false;
// OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar.
if (S.getLangOptions().OpenCL && CondTy->isVectorType())
return false;
// Emit the proper error message.
S.Diag(Cond->getLocStart(), S.getLangOptions().OpenCL ?
diag::err_typecheck_cond_expect_scalar :
diag::err_typecheck_cond_expect_scalar_or_vector)
<< CondTy;
return true;
}
/// \brief Return false if the two expressions can be converted to a vector,
/// true otherwise
static bool checkConditionalConvertScalarsToVectors(Sema &S, ExprResult &LHS,
ExprResult &RHS,
QualType CondTy) {
// Both operands should be of scalar type.
if (!LHS.get()->getType()->isScalarType()) {
S.Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return true;
}
if (!RHS.get()->getType()->isScalarType()) {
S.Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return true;
}
// Implicity convert these scalars to the type of the condition.
LHS = S.ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast);
RHS = S.ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast);
return false;
}
/// \brief Handle when one or both operands are void type.
static QualType checkConditionalVoidType(Sema &S, ExprResult &LHS,
ExprResult &RHS) {
Expr *LHSExpr = LHS.get();
Expr *RHSExpr = RHS.get();
if (!LHSExpr->getType()->isVoidType())
S.Diag(RHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void)
<< RHSExpr->getSourceRange();
if (!RHSExpr->getType()->isVoidType())
S.Diag(LHSExpr->getLocStart(), diag::ext_typecheck_cond_one_void)
<< LHSExpr->getSourceRange();
LHS = S.ImpCastExprToType(LHS.take(), S.Context.VoidTy, CK_ToVoid);
RHS = S.ImpCastExprToType(RHS.take(), S.Context.VoidTy, CK_ToVoid);
return S.Context.VoidTy;
}
/// \brief Return false if the NullExpr can be promoted to PointerTy,
/// true otherwise.
static bool checkConditionalNullPointer(Sema &S, ExprResult &NullExpr,
QualType PointerTy) {
if ((!PointerTy->isAnyPointerType() && !PointerTy->isBlockPointerType()) ||
!NullExpr.get()->isNullPointerConstant(S.Context,
Expr::NPC_ValueDependentIsNull))
return true;
NullExpr = S.ImpCastExprToType(NullExpr.take(), PointerTy, CK_NullToPointer);
return false;
}
/// \brief Checks compatibility between two pointers and return the resulting
/// type.
static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
ExprResult &RHS,
SourceLocation Loc) {
QualType LHSTy = LHS.get()->getType();
QualType RHSTy = RHS.get()->getType();
if (S.Context.hasSameType(LHSTy, RHSTy)) {
// Two identical pointers types are always compatible.
return LHSTy;
}
QualType lhptee, rhptee;
// Get the pointee types.
if (LHSTy->isBlockPointerType()) {
lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
} else {
lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
}
if (!S.Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
S.Diag(Loc, diag::warn_typecheck_cond_incompatible_pointers)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
QualType incompatTy = S.Context.getPointerType(S.Context.VoidTy);
LHS = S.ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
RHS = S.ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
return incompatTy;
}
// The pointer types are compatible.
// C99 6.5.15p6: If both operands are pointers to compatible types *or* to
// differently qualified versions of compatible types, the result type is
// a pointer to an appropriately qualified version of the *composite*
// type.
// FIXME: Need to calculate the composite type.
// FIXME: Need to add qualifiers
LHS = S.ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
RHS = S.ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
/// \brief Return the resulting type when the operands are both block pointers.
static QualType checkConditionalBlockPointerCompatibility(Sema &S,
ExprResult &LHS,
ExprResult &RHS,
SourceLocation Loc) {
QualType LHSTy = LHS.get()->getType();
QualType RHSTy = RHS.get()->getType();
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
QualType destType = S.Context.getPointerType(S.Context.VoidTy);
LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast);
RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast);
return destType;
}
S.Diag(Loc, diag::err_typecheck_cond_incompatible_operands)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
return QualType();
}
// We have 2 block pointer types.
return checkConditionalPointerCompatibility(S, LHS, RHS, Loc);
}
/// \brief Return the resulting type when the operands are both pointers.
static QualType
checkConditionalObjectPointersCompatibility(Sema &S, ExprResult &LHS,
ExprResult &RHS,
SourceLocation Loc) {
// get the pointer types
QualType LHSTy = LHS.get()->getType();
QualType RHSTy = RHS.get()->getType();
// get the "pointed to" types
QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
// Figure out necessary qualifiers (C99 6.5.15p6)
QualType destPointee
= S.Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = S.Context.getPointerType(destPointee);
// Add qualifiers if necessary.
LHS = S.ImpCastExprToType(LHS.take(), destType, CK_NoOp);
// Promote to void*.
RHS = S.ImpCastExprToType(RHS.take(), destType, CK_BitCast);
return destType;
}
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
QualType destPointee
= S.Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = S.Context.getPointerType(destPointee);
// Add qualifiers if necessary.
RHS = S.ImpCastExprToType(RHS.take(), destType, CK_NoOp);
// Promote to void*.
LHS = S.ImpCastExprToType(LHS.take(), destType, CK_BitCast);
return destType;
}
return checkConditionalPointerCompatibility(S, LHS, RHS, Loc);
}
/// \brief Return false if the first expression is not an integer and the second
/// expression is not a pointer, true otherwise.
static bool checkPointerIntegerMismatch(Sema &S, ExprResult &Int,
Expr* PointerExpr, SourceLocation Loc,
bool isIntFirstExpr) {
if (!PointerExpr->getType()->isPointerType() ||
!Int.get()->getType()->isIntegerType())
return false;
Expr *Expr1 = isIntFirstExpr ? Int.get() : PointerExpr;
Expr *Expr2 = isIntFirstExpr ? PointerExpr : Int.get();
S.Diag(Loc, diag::warn_typecheck_cond_pointer_integer_mismatch)
<< Expr1->getType() << Expr2->getType()
<< Expr1->getSourceRange() << Expr2->getSourceRange();
Int = S.ImpCastExprToType(Int.take(), PointerExpr->getType(),
CK_IntegralToPointer);
return true;
}
/// Note that lhs is not null here, even if this is the gnu "x ?: y" extension.
/// In that case, lhs = cond.
/// C99 6.5.15
@ -4405,23 +4613,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
QualType RHSTy = RHS.get()->getType();
// first, check the condition.
if (!CondTy->isScalarType()) { // C99 6.5.15p2
// OpenCL: Sec 6.3.i says the condition is allowed to be a vector or scalar.
// Throw an error if its not either.
if (getLangOptions().OpenCL) {
if (!CondTy->isVectorType()) {
Diag(Cond.get()->getLocStart(),
diag::err_typecheck_cond_expect_scalar_or_vector)
<< CondTy;
return QualType();
}
}
else {
Diag(Cond.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return QualType();
}
}
if (checkCondition(*this, Cond.get()))
return QualType();
// Now check the two expressions.
if (LHSTy->isVectorType() || RHSTy->isVectorType())
@ -4430,22 +4623,9 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// OpenCL: If the condition is a vector, and both operands are scalar,
// attempt to implicity convert them to the vector type to act like the
// built in select.
if (getLangOptions().OpenCL && CondTy->isVectorType()) {
// Both operands should be of scalar type.
if (!LHSTy->isScalarType()) {
Diag(LHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
if (getLangOptions().OpenCL && CondTy->isVectorType())
if (checkConditionalConvertScalarsToVectors(*this, LHS, RHS, CondTy))
return QualType();
}
if (!RHSTy->isScalarType()) {
Diag(RHS.get()->getLocStart(), diag::err_typecheck_cond_expect_scalar)
<< CondTy;
return QualType();
}
// Implicity convert these scalars to the type of the condition.
LHS = ImpCastExprToType(LHS.take(), CondTy, CK_IntegralCast);
RHS = ImpCastExprToType(RHS.take(), CondTy, CK_IntegralCast);
}
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
@ -4470,31 +4650,13 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// C99 6.5.15p5: "If both operands have void type, the result has void type."
// The following || allows only one side to be void (a GCC-ism).
if (LHSTy->isVoidType() || RHSTy->isVoidType()) {
if (!LHSTy->isVoidType())
Diag(RHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void)
<< RHS.get()->getSourceRange();
if (!RHSTy->isVoidType())
Diag(LHS.get()->getLocStart(), diag::ext_typecheck_cond_one_void)
<< LHS.get()->getSourceRange();
LHS = ImpCastExprToType(LHS.take(), Context.VoidTy, CK_ToVoid);
RHS = ImpCastExprToType(RHS.take(), Context.VoidTy, CK_ToVoid);
return Context.VoidTy;
return checkConditionalVoidType(*this, LHS, RHS);
}
// C99 6.5.15p6 - "if one operand is a null pointer constant, the result has
// the type of the other operand."
if ((LHSTy->isAnyPointerType() || LHSTy->isBlockPointerType()) &&
RHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
// promote the null to a pointer.
RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_NullToPointer);
return LHSTy;
}
if ((RHSTy->isAnyPointerType() || RHSTy->isBlockPointerType()) &&
LHS.get()->isNullPointerConstant(Context,
Expr::NPC_ValueDependentIsNull)) {
LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_NullToPointer);
return RHSTy;
}
if (!checkConditionalNullPointer(*this, RHS, LHSTy)) return LHSTy;
if (!checkConditionalNullPointer(*this, LHS, RHSTy)) return RHSTy;
// All objective-c pointer type analysis is done here.
QualType compositeType = FindCompositeObjCPointerType(LHS, RHS,
@ -4506,121 +4668,23 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
// Handle block pointer types.
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
if (!LHSTy->isBlockPointerType() || !RHSTy->isBlockPointerType()) {
if (LHSTy->isVoidPointerType() || RHSTy->isVoidPointerType()) {
QualType destType = Context.getPointerType(Context.VoidTy);
LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast);
RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast);
return destType;
}
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
return QualType();
}
// We have 2 block pointer types.
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
// Two identical block pointer types are always compatible.
return LHSTy;
}
// The block pointer types aren't identical, continue checking.
QualType lhptee = LHSTy->getAs<BlockPointerType>()->getPointeeType();
QualType rhptee = RHSTy->getAs<BlockPointerType>()->getPointeeType();
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
QualType incompatTy = Context.getPointerType(Context.VoidTy);
LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
return incompatTy;
}
// The block pointer types are compatible.
LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
if (LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType())
return checkConditionalBlockPointerCompatibility(*this, LHS, RHS,
QuestionLoc);
// Check constraints for C object pointers types (C99 6.5.15p3,6).
if (LHSTy->isPointerType() && RHSTy->isPointerType()) {
// get the "pointed to" types
QualType lhptee = LHSTy->getAs<PointerType>()->getPointeeType();
QualType rhptee = RHSTy->getAs<PointerType>()->getPointeeType();
// ignore qualifiers on void (C99 6.5.15p3, clause 6)
if (lhptee->isVoidType() && rhptee->isIncompleteOrObjectType()) {
// Figure out necessary qualifiers (C99 6.5.15p6)
QualType destPointee
= Context.getQualifiedType(lhptee, rhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
LHS = ImpCastExprToType(LHS.take(), destType, CK_NoOp);
// Promote to void*.
RHS = ImpCastExprToType(RHS.take(), destType, CK_BitCast);
return destType;
}
if (rhptee->isVoidType() && lhptee->isIncompleteOrObjectType()) {
QualType destPointee
= Context.getQualifiedType(rhptee, lhptee.getQualifiers());
QualType destType = Context.getPointerType(destPointee);
// Add qualifiers if necessary.
RHS = ImpCastExprToType(RHS.take(), destType, CK_NoOp);
// Promote to void*.
LHS = ImpCastExprToType(LHS.take(), destType, CK_BitCast);
return destType;
}
if (Context.getCanonicalType(LHSTy) == Context.getCanonicalType(RHSTy)) {
// Two identical pointer types are always compatible.
return LHSTy;
}
if (!Context.typesAreCompatible(lhptee.getUnqualifiedType(),
rhptee.getUnqualifiedType())) {
Diag(QuestionLoc, diag::warn_typecheck_cond_incompatible_pointers)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
QualType incompatTy = Context.getPointerType(Context.VoidTy);
LHS = ImpCastExprToType(LHS.take(), incompatTy, CK_BitCast);
RHS = ImpCastExprToType(RHS.take(), incompatTy, CK_BitCast);
return incompatTy;
}
// The pointer types are compatible.
// C99 6.5.15p6: If both operands are pointers to compatible types *or* to
// differently qualified versions of compatible types, the result type is
// a pointer to an appropriately qualified version of the *composite*
// type.
// FIXME: Need to calculate the composite type.
// FIXME: Need to add qualifiers
LHS = ImpCastExprToType(LHS.take(), LHSTy, CK_BitCast);
RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_BitCast);
return LHSTy;
}
if (LHSTy->isPointerType() && RHSTy->isPointerType())
return checkConditionalObjectPointersCompatibility(*this, LHS, RHS,
QuestionLoc);
// GCC compatibility: soften pointer/integer mismatch. Note that
// null pointers have been filtered out by this point.
if (RHSTy->isPointerType() && LHSTy->isIntegerType()) {
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
LHS = ImpCastExprToType(LHS.take(), RHSTy, CK_IntegralToPointer);
if (checkPointerIntegerMismatch(*this, LHS, RHS.get(), QuestionLoc,
/*isIntFirstExpr=*/true))
return RHSTy;
}
if (LHSTy->isPointerType() && RHSTy->isIntegerType()) {
Diag(QuestionLoc, diag::warn_typecheck_cond_pointer_integer_mismatch)
<< LHSTy << RHSTy << LHS.get()->getSourceRange()
<< RHS.get()->getSourceRange();
RHS = ImpCastExprToType(RHS.take(), LHSTy, CK_IntegralToPointer);
if (checkPointerIntegerMismatch(*this, RHS, LHS.get(), QuestionLoc,
/*isIntFirstExpr=*/false))
return LHSTy;
}
// Emit a better diagnostic if one of the expressions is a null pointer
// constant and the other is not a pointer type. In this case, the user most