summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEli Friedman <eli.friedman@gmail.com>2009-08-19 07:44:53 +0000
committerEli Friedman <eli.friedman@gmail.com>2009-08-19 07:44:53 +0000
commita95d75769edae299816ec7fd9bbcdf1ef617c5c9 (patch)
tree1515c1593af4e08ba6b1178c0906efee6082e3e0
parent09765ece710f29dcdbd66eec361d60e53bd5a4fd (diff)
Make integer promotions work correctly on PIC16 and other platforms
where sizeof(short) == sizeof(int). Move UsualArithmeticConversionsType out of Sema, since it was only there as a historical artifact. Patch by Enea Zaffanella. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79412 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h10
-rw-r--r--lib/AST/ASTContext.cpp154
-rw-r--r--lib/Sema/Sema.h6
-rw-r--r--lib/Sema/SemaExpr.cpp158
-rw-r--r--lib/Sema/SemaOverload.cpp9
-rw-r--r--lib/Sema/SemaType.cpp2
-rw-r--r--test/Sema/promote-int-16bit.c6
7 files changed, 186 insertions, 159 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 7d7c25c895..e4166c117c 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -813,6 +813,11 @@ public:
/// See C99 6.7.5.3p7 and C99 6.3.2.1p3.
QualType getArrayDecayedType(QualType T);
+ /// getPromotedIntegerType - Returns the type that Promotable will
+ /// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable
+ /// integer type.
+ QualType getPromotedIntegerType(QualType PromotableType);
+
/// getIntegerTypeOrder - Returns the highest ranked integer type:
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
/// LHS < RHS, return -1.
@@ -869,6 +874,11 @@ public:
QualType mergeTypes(QualType, QualType);
QualType mergeFunctionTypes(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);
+
//===--------------------------------------------------------------------===//
// Integer Predicates
//===--------------------------------------------------------------------===//
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 063bb2a89b..8a1f601603 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -2487,6 +2487,20 @@ unsigned ASTContext::getIntegerRank(Type *T) {
}
}
+/// getPromotedIntegerType - Returns the type that Promotable will
+/// promote to: C99 6.3.1.1p2, assuming that Promotable is a promotable
+/// integer type.
+QualType ASTContext::getPromotedIntegerType(QualType Promotable) {
+ assert(!Promotable.isNull());
+ assert(Promotable->isPromotableIntegerType());
+ if (Promotable->isSignedIntegerType())
+ return IntTy;
+ uint64_t PromotableSize = getTypeSize(Promotable);
+ uint64_t IntSize = getTypeSize(IntTy);
+ assert(Promotable->isUnsignedIntegerType() && PromotableSize <= IntSize);
+ return (PromotableSize != IntSize) ? IntTy : UnsignedIntTy;
+}
+
/// getIntegerTypeOrder - Returns the highest ranked integer type:
/// C99 6.3.1.8p1. If LHS > RHS, return 1. If LHS == RHS, return 0. If
/// LHS < RHS, return -1.
@@ -4157,3 +4171,143 @@ QualType ASTContext::GetBuiltinType(unsigned id,
return getFunctionType(ResType, ArgTypes.data(), ArgTypes.size(),
TypeStr[0] == '.', 0);
}
+
+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->isSignedIntegerType(),
+ rhsSigned = rhs->isSignedIntegerType();
+ 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;
+}
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 8921baef1a..f3ec417235 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -3115,12 +3115,6 @@ public:
QualType UsualArithmeticConversions(Expr *&lExpr, Expr *&rExpr,
bool isCompAssign = false);
- /// 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);
-
-
/// AssignConvertType - All of the 'assignment' semantic checks return this
/// enum to indicate whether the assignment was allowed. These checks are
/// done for simple assignments, as well as initialization, return from
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 4b8cc0e5e8..ef8165e167 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -273,7 +273,8 @@ Expr *Sema::UsualUnaryConversions(Expr *&Expr) {
// unsigned int. These are called the integer promotions. All
// other types are unchanged by the integer promotions.
if (Ty->isPromotableIntegerType()) {
- ImpCastExprToType(Expr, Context.IntTy);
+ QualType PT = Context.getPromotedIntegerType(Ty);
+ ImpCastExprToType(Expr, PT);
return Expr;
} else {
QualType T = isPromotableBitField(Expr, Context);
@@ -361,152 +362,13 @@ QualType Sema::UsualArithmeticConversions(Expr *&lhsExpr, Expr *&rhsExpr,
if (!RHSBitfieldPromoteTy.isNull())
rhs = RHSBitfieldPromoteTy;
- QualType destType = UsualArithmeticConversionsType(lhs, rhs);
+ QualType destType = Context.UsualArithmeticConversionsType(lhs, rhs);
if (!isCompAssign)
ImpCastExprToType(lhsExpr, destType);
ImpCastExprToType(rhsExpr, destType);
return destType;
}
-QualType Sema::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 = Context.IntTy;
- else
- lhs = lhs.getUnqualifiedType();
- if (rhs->isPromotableIntegerType())
- rhs = Context.IntTy;
- 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 = Context.getFloatingTypeOrder(lhs, rhs);
-
- if (result > 0) { // The left side is bigger, convert rhs.
- rhs = Context.getFloatingTypeOfSizeWithinDomain(lhs, rhs);
- } else if (result < 0) { // The right side is bigger, convert lhs.
- lhs = Context.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 Context.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 Context.getComplexType(rhs);
- }
- // We have two real floating types, float/complex combos were handled above.
- // Convert the smaller operand to the bigger result.
- int result = Context.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 (Context.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 = Context.getIntegerTypeOrder(lhs, rhs);
- bool lhsSigned = lhs->isSignedIntegerType(),
- rhsSigned = rhs->isSignedIntegerType();
- 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 (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.
- 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 = Context.getCorrespondingUnsignedType(lhsSigned ? lhs : rhs);
- }
- return destType;
-}
-
//===----------------------------------------------------------------------===//
// Semantic Analysis for various Expression Types
//===----------------------------------------------------------------------===//
@@ -4088,7 +3950,7 @@ inline QualType Sema::CheckAdditionOperands( // C99 6.5.6
if (CompLHSTy) {
QualType LHSTy = lex->getType();
if (LHSTy->isPromotableIntegerType())
- LHSTy = Context.IntTy;
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
else {
QualType T = isPromotableBitField(lex, Context);
if (!T.isNull())
@@ -4256,13 +4118,13 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc,
// Shifts don't perform usual arithmetic conversions, they just do integer
// promotions on each operand. C99 6.5.7p3
- QualType LHSTy;
- if (lex->getType()->isPromotableIntegerType())
- LHSTy = Context.IntTy;
+ QualType LHSTy = lex->getType();
+ if (LHSTy->isPromotableIntegerType())
+ LHSTy = Context.getPromotedIntegerType(LHSTy);
else {
- LHSTy = isPromotableBitField(lex, Context);
- if (LHSTy.isNull())
- LHSTy = lex->getType();
+ QualType T = isPromotableBitField(lex, Context);
+ if (!T.isNull())
+ LHSTy = T;
}
if (!isCompAssign)
ImpCastExprToType(lex, LHSTy);
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 6b76ce80d7..d338e427c8 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -3101,9 +3101,10 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
for (unsigned Right = FirstPromotedArithmeticType;
Right < LastPromotedArithmeticType; ++Right) {
QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
- QualType Result
- = isComparison? Context.BoolTy
- : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ QualType Result
+ = isComparison
+ ? Context.BoolTy
+ : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]);
AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
@@ -3136,7 +3137,7 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op,
QualType LandR[2] = { ArithmeticTypes[Left], ArithmeticTypes[Right] };
QualType Result = (Op == OO_LessLess || Op == OO_GreaterGreater)
? LandR[0]
- : UsualArithmeticConversionsType(LandR[0], LandR[1]);
+ : Context.UsualArithmeticConversionsType(LandR[0], LandR[1]);
AddBuiltinCandidate(Result, LandR, Args, 2, CandidateSet);
}
}
diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp
index 136440d438..db01ad094e 100644
--- a/lib/Sema/SemaType.cpp
+++ b/lib/Sema/SemaType.cpp
@@ -1127,7 +1127,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S,
}
} else if (!FTI.hasPrototype) {
if (ArgTy->isPromotableIntegerType()) {
- ArgTy = Context.IntTy;
+ ArgTy = Context.getPromotedIntegerType(ArgTy);
} else if (const BuiltinType* BTy = ArgTy->getAsBuiltinType()) {
if (BTy->getKind() == BuiltinType::Float)
ArgTy = Context.DoubleTy;
diff --git a/test/Sema/promote-int-16bit.c b/test/Sema/promote-int-16bit.c
new file mode 100644
index 0000000000..fbd1215d90
--- /dev/null
+++ b/test/Sema/promote-int-16bit.c
@@ -0,0 +1,6 @@
+// RUN: clang-cc -fsyntax-only -verify %s -triple pic16-unknown-unknown
+
+// Check that unsigned short promotes to unsigned int on targets where
+// sizeof(unsigned short) == sizeof(unsigned int)
+__typeof(1+(unsigned short)1) x;
+unsigned x;