diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 5 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 140 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 254 |
3 files changed, 244 insertions, 155 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index cda07077f2..11f4e81f60 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -1304,11 +1304,6 @@ public: QualType mergeObjCGCQualifiers(QualType, QualType); - /// UsualArithmeticConversionsType - handles the various conversions - /// that are common to binary operators (C99 6.3.1.8, C++ [expr]p9) - /// and returns the result type of that conversion. - QualType UsualArithmeticConversionsType(QualType lhs, QualType rhs); - void ResetObjCLayout(const ObjCContainerDecl *CD) { ObjCLayouts[CD] = 0; } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index c852482af2..7b8223f4c6 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -5537,146 +5537,6 @@ QualType ASTContext::GetBuiltinType(unsigned Id, FunctionType::ExtInfo()); } -QualType -ASTContext::UsualArithmeticConversionsType(QualType lhs, QualType rhs) { - // Perform the usual unary conversions. We do this early so that - // integral promotions to "int" can allow us to exit early, in the - // lhs == rhs check. Also, for conversion purposes, we ignore any - // qualifiers. For example, "const float" and "float" are - // equivalent. - if (lhs->isPromotableIntegerType()) - lhs = getPromotedIntegerType(lhs); - else - lhs = lhs.getUnqualifiedType(); - if (rhs->isPromotableIntegerType()) - rhs = getPromotedIntegerType(rhs); - else - rhs = rhs.getUnqualifiedType(); - - // If both types are identical, no conversion is needed. - if (lhs == rhs) - return lhs; - - // If either side is a non-arithmetic type (e.g. a pointer), we are done. - // The caller can deal with this (e.g. pointer + int). - if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) - return lhs; - - // At this point, we have two different arithmetic types. - - // Handle complex types first (C99 6.3.1.8p1). - if (lhs->isComplexType() || rhs->isComplexType()) { - // if we have an integer operand, the result is the complex type. - if (rhs->isIntegerType() || rhs->isComplexIntegerType()) { - // convert the rhs to the lhs complex type. - return lhs; - } - if (lhs->isIntegerType() || lhs->isComplexIntegerType()) { - // convert the lhs to the rhs complex type. - return rhs; - } - // This handles complex/complex, complex/float, or float/complex. - // When both operands are complex, the shorter operand is converted to the - // type of the longer, and that is the type of the result. This corresponds - // to what is done when combining two real floating-point operands. - // The fun begins when size promotion occur across type domains. - // From H&S 6.3.4: When one operand is complex and the other is a real - // floating-point type, the less precise type is converted, within it's - // real or complex domain, to the precision of the other type. For example, - // when combining a "long double" with a "double _Complex", the - // "double _Complex" is promoted to "long double _Complex". - int result = getFloatingTypeOrder(lhs, rhs); - - if (result > 0) { // The left side is bigger, convert rhs. - rhs = getFloatingTypeOfSizeWithinDomain(lhs, rhs); - } else if (result < 0) { // The right side is bigger, convert lhs. - lhs = getFloatingTypeOfSizeWithinDomain(rhs, lhs); - } - // At this point, lhs and rhs have the same rank/size. Now, make sure the - // domains match. This is a requirement for our implementation, C99 - // does not require this promotion. - if (lhs != rhs) { // Domains don't match, we have complex/float mix. - if (lhs->isRealFloatingType()) { // handle "double, _Complex double". - return rhs; - } else { // handle "_Complex double, double". - return lhs; - } - } - return lhs; // The domain/size match exactly. - } - // Now handle "real" floating types (i.e. float, double, long double). - if (lhs->isRealFloatingType() || rhs->isRealFloatingType()) { - // if we have an integer operand, the result is the real floating type. - if (rhs->isIntegerType()) { - // convert rhs to the lhs floating point type. - return lhs; - } - if (rhs->isComplexIntegerType()) { - // convert rhs to the complex floating point type. - return getComplexType(lhs); - } - if (lhs->isIntegerType()) { - // convert lhs to the rhs floating point type. - return rhs; - } - if (lhs->isComplexIntegerType()) { - // convert lhs to the complex floating point type. - return getComplexType(rhs); - } - // We have two real floating types, float/complex combos were handled above. - // Convert the smaller operand to the bigger result. - int result = getFloatingTypeOrder(lhs, rhs); - if (result > 0) // convert the rhs - return lhs; - assert(result < 0 && "illegal float comparison"); - return rhs; // convert the lhs - } - if (lhs->isComplexIntegerType() || rhs->isComplexIntegerType()) { - // Handle GCC complex int extension. - const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); - const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); - - if (lhsComplexInt && rhsComplexInt) { - if (getIntegerTypeOrder(lhsComplexInt->getElementType(), - rhsComplexInt->getElementType()) >= 0) - return lhs; // convert the rhs - return rhs; - } else if (lhsComplexInt && rhs->isIntegerType()) { - // convert the rhs to the lhs complex type. - return lhs; - } else if (rhsComplexInt && lhs->isIntegerType()) { - // convert the lhs to the rhs complex type. - return rhs; - } - } - // Finally, we have two differing integer types. - // The rules for this case are in C99 6.3.1.8 - int compare = getIntegerTypeOrder(lhs, rhs); - bool lhsSigned = lhs->hasSignedIntegerRepresentation(), - rhsSigned = rhs->hasSignedIntegerRepresentation(); - QualType destType; - if (lhsSigned == rhsSigned) { - // Same signedness; use the higher-ranked type - destType = compare >= 0 ? lhs : rhs; - } else if (compare != (lhsSigned ? 1 : -1)) { - // The unsigned type has greater than or equal rank to the - // signed type, so use the unsigned type - destType = lhsSigned ? rhs : lhs; - } else if (getIntWidth(lhs) != getIntWidth(rhs)) { - // The two types are different widths; if we are here, that - // means the signed type is larger than the unsigned type, so - // use the signed type. - destType = lhsSigned ? lhs : rhs; - } else { - // The signed type is higher-ranked than the unsigned type, - // but isn't actually any bigger (like unsigned int and long - // on most 32-bit systems). Use the unsigned type corresponding - // to the signed type. - destType = getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); - } - return destType; -} - GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) { GVALinkage External = GVA_StrongExternal; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 6eb07b5558..590685d6cc 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -348,7 +348,6 @@ bool Sema::DefaultVariadicArgumentPromotion(Expr *&Expr, VariadicCallType CT, return false; } - /// UsualArithmeticConversions - Performs various conversions that are common to /// binary operators (C99 6.3.1.8). If both operands aren't arithmetic, this /// routine returns the first non-arithmetic type found. The client is @@ -378,19 +377,254 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr, if (!lhs->isArithmeticType() || !rhs->isArithmeticType()) return lhs; - // Perform bitfield promotions. + // Apply unary and bitfield promotions to the LHS's type. + QualType lhs_unpromoted = lhs; + if (lhs->isPromotableIntegerType()) + lhs = Context.getPromotedIntegerType(lhs); QualType LHSBitfieldPromoteTy = Context.isPromotableBitField(lhsExpr); if (!LHSBitfieldPromoteTy.isNull()) lhs = LHSBitfieldPromoteTy; - QualType RHSBitfieldPromoteTy = Context.isPromotableBitField(rhsExpr); - if (!RHSBitfieldPromoteTy.isNull()) - rhs = RHSBitfieldPromoteTy; + if (lhs != lhs_unpromoted && !isCompAssign) + ImpCastExprToType(lhsExpr, lhs, CK_IntegralCast); - QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs); - if (!isCompAssign) - ImpCastExprToType(lhsExpr, destType, CK_Unknown); - ImpCastExprToType(rhsExpr, destType, CK_Unknown); - return destType; + // If both types are identical, no conversion is needed. + if (lhs == rhs) + return lhs; + + // At this point, we have two different arithmetic types. + + // Handle complex types first (C99 6.3.1.8p1). + bool LHSComplexFloat = lhs->isComplexType(); + bool RHSComplexFloat = rhs->isComplexType(); + if (LHSComplexFloat || RHSComplexFloat) { + // if we have an integer operand, the result is the complex type. + + if (LHSComplexFloat && + (rhs->isIntegerType() || rhs->isComplexIntegerType())) { + // convert the rhs to the lhs complex type. + ImpCastExprToType(rhsExpr, lhs, CK_Unknown); + return lhs; + } + + if (!LHSComplexFloat && RHSComplexFloat && + (lhs->isIntegerType() || lhs->isComplexIntegerType())) { + // convert the lhs to the rhs complex type. + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_Unknown); + return rhs; + } + + // This handles complex/complex, complex/float, or float/complex. + // When both operands are complex, the shorter operand is converted to the + // type of the longer, and that is the type of the result. This corresponds + // to what is done when combining two real floating-point operands. + // The fun begins when size promotion occur across type domains. + // From H&S 6.3.4: When one operand is complex and the other is a real + // floating-point type, the less precise type is converted, within it's + // real or complex domain, to the precision of the other type. For example, + // when combining a "long double" with a "double _Complex", the + // "double _Complex" is promoted to "long double _Complex". + int order = Context.getFloatingTypeOrder(lhs, rhs); + + // If both are complex, just cast to the more precise type. + if (LHSComplexFloat && RHSComplexFloat) { + if (order > 0) { + // _Complex float -> _Complex double + ImpCastExprToType(rhsExpr, lhs, CK_Unknown); + return lhs; + + } else if (order < 0) { + // _Complex float -> _Complex double + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_Unknown); + return rhs; + } + return lhs; + } + + // If just the LHS is complex, the RHS needs to be converted, + // and the LHS might need to be promoted. + if (LHSComplexFloat) { + if (order > 0) { // LHS is wider + // float -> _Complex double + ImpCastExprToType(rhsExpr, lhs, CK_Unknown); + return lhs; + } + + // RHS is at least as wide. Find its corresponding complex type. + QualType result = (order == 0 ? lhs : Context.getComplexType(rhs)); + + // double -> _Complex double + ImpCastExprToType(rhsExpr, result, CK_Unknown); + + // _Complex float -> _Complex double + if (!isCompAssign && order < 0) + ImpCastExprToType(lhsExpr, result, CK_Unknown); + + return result; + } + + // Just the RHS is complex, so the LHS needs to be converted + // and the RHS might need to be promoted. + assert(RHSComplexFloat); + + if (order < 0) { // RHS is wider + // float -> _Complex double + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_Unknown); + return rhs; + } + + // LHS is at least as wide. Find its corresponding complex type. + QualType result = (order == 0 ? rhs : Context.getComplexType(lhs)); + + // double -> _Complex double + if (!isCompAssign) + ImpCastExprToType(lhsExpr, result, CK_Unknown); + + // _Complex float -> _Complex double + if (order > 0) + ImpCastExprToType(rhsExpr, result, CK_Unknown); + + return result; + } + + // Now handle "real" floating types (i.e. float, double, long double). + bool LHSFloat = lhs->isRealFloatingType(); + bool RHSFloat = rhs->isRealFloatingType(); + if (LHSFloat || RHSFloat) { + // If we have two real floating types, convert the smaller operand + // to the bigger result. + if (LHSFloat && RHSFloat) { + int order = Context.getFloatingTypeOrder(lhs, rhs); + if (order > 0) { + ImpCastExprToType(rhsExpr, lhs, CK_FloatingCast); + return lhs; + } + + assert(order < 0 && "illegal float comparison"); + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_FloatingCast); + return rhs; + } + + // If we have an integer operand, the result is the real floating type. + if (LHSFloat) { + if (rhs->isIntegerType()) { + // Convert rhs to the lhs floating point type. + ImpCastExprToType(rhsExpr, lhs, CK_IntegralToFloating); + return lhs; + } + + // Convert both sides to the appropriate complex float. + assert(rhs->isComplexIntegerType()); + QualType result = Context.getComplexType(lhs); + + // _Complex int -> _Complex float + ImpCastExprToType(rhsExpr, result, CK_Unknown); + + // float -> _Complex float + if (!isCompAssign) + ImpCastExprToType(lhsExpr, result, CK_Unknown); + + return result; + } + + assert(RHSFloat); + if (lhs->isIntegerType()) { + // Convert lhs to the rhs floating point type. + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralToFloating); + return rhs; + } + + // Convert both sides to the appropriate complex float. + assert(lhs->isComplexIntegerType()); + QualType result = Context.getComplexType(rhs); + + // _Complex int -> _Complex float + if (!isCompAssign) + ImpCastExprToType(lhsExpr, result, CK_Unknown); + + // float -> _Complex float + ImpCastExprToType(rhsExpr, result, CK_Unknown); + + return result; + } + + // Handle GCC complex int extension. + // FIXME: if the operands are (int, _Complex long), we currently + // don't promote the complex. Also, signedness? + const ComplexType *lhsComplexInt = lhs->getAsComplexIntegerType(); + const ComplexType *rhsComplexInt = rhs->getAsComplexIntegerType(); + if (lhsComplexInt && rhsComplexInt) { + int order = Context.getIntegerTypeOrder(lhsComplexInt->getElementType(), + rhsComplexInt->getElementType()); + assert(order && "inequal types with equal element ordering"); + if (order > 0) { + // _Complex int -> _Complex long + ImpCastExprToType(rhsExpr, lhs, CK_Unknown); + return lhs; + } + + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_Unknown); + return rhs; + } else if (lhsComplexInt) { + // int -> _Complex int + ImpCastExprToType(rhsExpr, lhs, CK_Unknown); + return lhs; + } else if (rhsComplexInt) { + // int -> _Complex int + if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_Unknown); + return rhs; + } + + // Finally, we have two differing integer types. + // The rules for this case are in C99 6.3.1.8 + int compare = Context.getIntegerTypeOrder(lhs, rhs); + bool lhsSigned = lhs->hasSignedIntegerRepresentation(), + rhsSigned = rhs->hasSignedIntegerRepresentation(); + if (lhsSigned == rhsSigned) { + // Same signedness; use the higher-ranked type + if (compare >= 0) { + ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + return lhs; + } else if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + return rhs; + } else if (compare != (lhsSigned ? 1 : -1)) { + // The unsigned type has greater than or equal rank to the + // signed type, so use the unsigned type + if (rhsSigned) { + ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + return lhs; + } else if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + return rhs; + } else if (Context.getIntWidth(lhs) != Context.getIntWidth(rhs)) { + // The two types are different widths; if we are here, that + // means the signed type is larger than the unsigned type, so + // use the signed type. + if (lhsSigned) { + ImpCastExprToType(rhsExpr, lhs, CK_IntegralCast); + return lhs; + } else if (!isCompAssign) + ImpCastExprToType(lhsExpr, rhs, CK_IntegralCast); + return rhs; + } else { + // The signed type is higher-ranked than the unsigned type, + // but isn't actually any bigger (like unsigned int and long + // on most 32-bit systems). Use the unsigned type corresponding + // to the signed type. + QualType result = + Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs); + ImpCastExprToType(rhsExpr, result, CK_IntegralCast); + if (!isCompAssign) + ImpCastExprToType(lhsExpr, result, CK_IntegralCast); + return result; + } } //===----------------------------------------------------------------------===// |