aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/ASTContext.cpp40
-rw-r--r--lib/AST/Type.cpp9
-rw-r--r--test/CXX/conv/conv.prom/p2.cpp16
3 files changed, 49 insertions, 16 deletions
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index ae28149407..cb4e09bfc9 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -3549,18 +3549,6 @@ int ASTContext::getFloatingTypeOrder(QualType LHS, QualType RHS) const {
/// or if it is not canonicalized.
unsigned ASTContext::getIntegerRank(const Type *T) const {
assert(T->isCanonicalUnqualified() && "T should be canonicalized");
- if (const EnumType* ET = dyn_cast<EnumType>(T))
- T = ET->getDecl()->getPromotionType().getTypePtr();
-
- if (T->isSpecificBuiltinType(BuiltinType::WChar_S) ||
- T->isSpecificBuiltinType(BuiltinType::WChar_U))
- T = getFromTargetType(Target->getWCharType()).getTypePtr();
-
- if (T->isSpecificBuiltinType(BuiltinType::Char16))
- T = getFromTargetType(Target->getChar16Type()).getTypePtr();
-
- if (T->isSpecificBuiltinType(BuiltinType::Char32))
- T = getFromTargetType(Target->getChar32Type()).getTypePtr();
switch (cast<BuiltinType>(T)->getKind()) {
default: llvm_unreachable("getIntegerRank(): not a built-in integer");
@@ -3630,6 +3618,34 @@ QualType ASTContext::getPromotedIntegerType(QualType Promotable) const {
assert(Promotable->isPromotableIntegerType());
if (const EnumType *ET = Promotable->getAs<EnumType>())
return ET->getDecl()->getPromotionType();
+
+ if (const BuiltinType *BT = Promotable->getAs<BuiltinType>()) {
+ // C++ [conv.prom]: A prvalue of type char16_t, char32_t, or wchar_t
+ // (3.9.1) can be converted to a prvalue of the first of the following
+ // types that can represent all the values of its underlying type:
+ // int, unsigned int, long int, unsigned long int, long long int, or
+ // unsigned long long int [...]
+ // FIXME: Is there some better way to compute this?
+ if (BT->getKind() == BuiltinType::WChar_S ||
+ BT->getKind() == BuiltinType::WChar_U ||
+ BT->getKind() == BuiltinType::Char16 ||
+ BT->getKind() == BuiltinType::Char32) {
+ bool FromIsSigned = BT->getKind() == BuiltinType::WChar_S;
+ uint64_t FromSize = getTypeSize(BT);
+ QualType PromoteTypes[] = { IntTy, UnsignedIntTy, LongTy, UnsignedLongTy,
+ LongLongTy, UnsignedLongLongTy };
+ for (size_t Idx = 0; Idx < llvm::array_lengthof(PromoteTypes); ++Idx) {
+ uint64_t ToSize = getTypeSize(PromoteTypes[Idx]);
+ if (FromSize < ToSize ||
+ (FromSize == ToSize &&
+ FromIsSigned == PromoteTypes[Idx]->isSignedIntegerType()))
+ return PromoteTypes[Idx];
+ }
+ llvm_unreachable("char type should fit into long long");
+ }
+ }
+
+ // At this point, we should have a signed or unsigned integer type.
if (Promotable->isSignedIntegerType())
return IntTy;
uint64_t PromotableSize = getTypeSize(Promotable);
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 0bac5f4f61..e01346cdb6 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1272,6 +1272,10 @@ bool Type::isPromotableIntegerType() const {
case BuiltinType::UChar:
case BuiltinType::Short:
case BuiltinType::UShort:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
return true;
default:
return false;
@@ -1284,10 +1288,7 @@ bool Type::isPromotableIntegerType() const {
|| ET->getDecl()->isScoped())
return false;
- const BuiltinType *BT
- = ET->getDecl()->getPromotionType()->getAs<BuiltinType>();
- return BT->getKind() == BuiltinType::Int
- || BT->getKind() == BuiltinType::UInt;
+ return true;
}
return false;
diff --git a/test/CXX/conv/conv.prom/p2.cpp b/test/CXX/conv/conv.prom/p2.cpp
new file mode 100644
index 0000000000..8d75419878
--- /dev/null
+++ b/test/CXX/conv/conv.prom/p2.cpp
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -ffreestanding %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x -fshort-wchar -ffreestanding %s
+
+#include <stdint.h>
+
+// In theory, the promoted types vary by platform; however, in reality they
+// are quite consistent across all platforms where clang runs.
+
+extern int promoted_wchar;
+extern decltype(+L'a') promoted_wchar;
+
+extern int promoted_char16;
+extern decltype(+u'a') promoted_char16;
+
+extern unsigned promoted_char32;
+extern decltype(+U'a') promoted_char32;