[cfe-commits] r170639 - in /cfe/trunk: lib/AST/ASTContext.cpp test/CodeGenObjC/encode-test.m
John McCall
rjmccall at apple.com
Wed Dec 19 18:45:14 PST 2012
Author: rjmccall
Date: Wed Dec 19 20:45:14 2012
New Revision: 170639
URL: http://llvm.org/viewvc/llvm-project?rev=170639&view=rev
Log:
Robustify the @encode code and add support for _Atomic.
Fixes PR14628.
Modified:
cfe/trunk/lib/AST/ASTContext.cpp
cfe/trunk/test/CodeGenObjC/encode-test.m
Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=170639&r1=170638&r2=170639&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Dec 19 20:45:14 2012
@@ -4804,17 +4804,19 @@
true /* outermost type */);
}
-static char ObjCEncodingForPrimitiveKind(const ASTContext *C, QualType T) {
- switch (T->getAs<BuiltinType>()->getKind()) {
- default: llvm_unreachable("Unhandled builtin type kind");
+static char getObjCEncodingForPrimitiveKind(const ASTContext *C,
+ BuiltinType::Kind kind) {
+ switch (kind) {
case BuiltinType::Void: return 'v';
case BuiltinType::Bool: return 'B';
case BuiltinType::Char_U:
case BuiltinType::UChar: return 'C';
+ case BuiltinType::Char16:
case BuiltinType::UShort: return 'S';
+ case BuiltinType::Char32:
case BuiltinType::UInt: return 'I';
case BuiltinType::ULong:
- return C->getIntWidth(T) == 32 ? 'L' : 'Q';
+ return C->getTargetInfo().getLongWidth() == 32 ? 'L' : 'Q';
case BuiltinType::UInt128: return 'T';
case BuiltinType::ULongLong: return 'Q';
case BuiltinType::Char_S:
@@ -4824,12 +4826,36 @@
case BuiltinType::WChar_U:
case BuiltinType::Int: return 'i';
case BuiltinType::Long:
- return C->getIntWidth(T) == 32 ? 'l' : 'q';
+ return C->getTargetInfo().getLongWidth() == 32 ? 'l' : 'q';
case BuiltinType::LongLong: return 'q';
case BuiltinType::Int128: return 't';
case BuiltinType::Float: return 'f';
case BuiltinType::Double: return 'd';
case BuiltinType::LongDouble: return 'D';
+ case BuiltinType::NullPtr: return '*'; // like char*
+
+ case BuiltinType::Half:
+ // FIXME: potentially need @encodes for these!
+ return ' ';
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ llvm_unreachable("@encoding ObjC primitive type");
+
+ // OpenCL and placeholder types don't need @encodings.
+ case BuiltinType::OCLImage1d:
+ case BuiltinType::OCLImage1dArray:
+ case BuiltinType::OCLImage1dBuffer:
+ case BuiltinType::OCLImage2d:
+ case BuiltinType::OCLImage2dArray:
+ case BuiltinType::OCLImage3d:
+ case BuiltinType::Dependent:
+#define BUILTIN_TYPE(KIND, ID)
+#define PLACEHOLDER_TYPE(KIND, ID) \
+ case BuiltinType::KIND:
+#include "clang/AST/BuiltinTypes.def"
+ llvm_unreachable("invalid builtin type for @encode");
}
}
@@ -4841,7 +4867,8 @@
return 'i';
// The encoding of a fixed enum type matches its fixed underlying type.
- return ObjCEncodingForPrimitiveKind(C, Enum->getIntegerType());
+ const BuiltinType *BT = Enum->getIntegerType()->castAs<BuiltinType>();
+ return getObjCEncodingForPrimitiveKind(C, BT->getKind());
}
static void EncodeBitField(const ASTContext *Ctx, std::string& S,
@@ -4869,8 +4896,10 @@
S += llvm::utostr(RL.getFieldOffset(FD->getFieldIndex()));
if (const EnumType *ET = T->getAs<EnumType>())
S += ObjCEncodingForEnumType(Ctx, ET);
- else
- S += ObjCEncodingForPrimitiveKind(Ctx, T);
+ else {
+ const BuiltinType *BT = T->castAs<BuiltinType>();
+ S += getObjCEncodingForPrimitiveKind(Ctx, BT->getKind());
+ }
}
S += llvm::utostr(FD->getBitWidthValue(*Ctx));
}
@@ -4885,32 +4914,50 @@
bool StructField,
bool EncodeBlockParameters,
bool EncodeClassNames) const {
- if (T->getAs<BuiltinType>()) {
+ CanQualType CT = getCanonicalType(T);
+ switch (CT->getTypeClass()) {
+ case Type::Builtin:
+ case Type::Enum:
if (FD && FD->isBitField())
return EncodeBitField(this, S, T, FD);
- S += ObjCEncodingForPrimitiveKind(this, T);
+ if (const BuiltinType *BT = dyn_cast<BuiltinType>(CT))
+ S += getObjCEncodingForPrimitiveKind(this, BT->getKind());
+ else
+ S += ObjCEncodingForEnumType(this, cast<EnumType>(CT));
return;
- }
- if (const ComplexType *CT = T->getAs<ComplexType>()) {
+ case Type::Complex: {
+ const ComplexType *CT = T->castAs<ComplexType>();
S += 'j';
getObjCEncodingForTypeImpl(CT->getElementType(), S, false, false, 0, false,
false);
return;
}
-
- // encoding for pointer or r3eference types.
- QualType PointeeTy;
- if (const PointerType *PT = T->getAs<PointerType>()) {
- if (PT->isObjCSelType()) {
- S += ':';
- return;
- }
- PointeeTy = PT->getPointeeType();
+
+ case Type::Atomic: {
+ const AtomicType *AT = T->castAs<AtomicType>();
+ S += 'A';
+ getObjCEncodingForTypeImpl(AT->getValueType(), S, false, false, 0,
+ false, false);
+ return;
}
- else if (const ReferenceType *RT = T->getAs<ReferenceType>())
- PointeeTy = RT->getPointeeType();
- if (!PointeeTy.isNull()) {
+
+ // encoding for pointer or reference types.
+ case Type::Pointer:
+ case Type::LValueReference:
+ case Type::RValueReference: {
+ QualType PointeeTy;
+ if (isa<PointerType>(CT)) {
+ const PointerType *PT = T->castAs<PointerType>();
+ if (PT->isObjCSelType()) {
+ S += ':';
+ return;
+ }
+ PointeeTy = PT->getPointeeType();
+ } else {
+ PointeeTy = T->castAs<ReferenceType>()->getPointeeType();
+ }
+
bool isReadOnly = false;
// For historical/compatibility reasons, the read-only qualifier of the
// pointee gets emitted _before_ the '^'. The read-only qualifier of
@@ -4965,10 +5012,12 @@
NULL);
return;
}
-
- if (const ArrayType *AT =
- // Ignore type qualifiers etc.
- dyn_cast<ArrayType>(T->getCanonicalTypeInternal())) {
+
+ case Type::ConstantArray:
+ case Type::IncompleteArray:
+ case Type::VariableArray: {
+ const ArrayType *AT = cast<ArrayType>(CT);
+
if (isa<IncompleteArrayType>(AT) && !StructField) {
// Incomplete arrays are encoded as a pointer to the array element.
S += '^';
@@ -4997,13 +5046,13 @@
return;
}
- if (T->getAs<FunctionType>()) {
+ case Type::FunctionNoProto:
+ case Type::FunctionProto:
S += '?';
return;
- }
- if (const RecordType *RTy = T->getAs<RecordType>()) {
- RecordDecl *RDecl = RTy->getDecl();
+ case Type::Record: {
+ RecordDecl *RDecl = cast<RecordType>(CT)->getDecl();
S += RDecl->isUnion() ? '(' : '{';
// Anonymous structures print as '?'
if (const IdentifierInfo *II = RDecl->getIdentifier()) {
@@ -5054,19 +5103,12 @@
S += RDecl->isUnion() ? ')' : '}';
return;
}
-
- if (const EnumType *ET = T->getAs<EnumType>()) {
- if (FD && FD->isBitField())
- EncodeBitField(this, S, T, FD);
- else
- S += ObjCEncodingForEnumType(this, ET);
- return;
- }
- if (const BlockPointerType *BT = T->getAs<BlockPointerType>()) {
+ case Type::BlockPointer: {
+ const BlockPointerType *BT = T->castAs<BlockPointerType>();
S += "@?"; // Unlike a pointer-to-function, which is "^?".
if (EncodeBlockParameters) {
- const FunctionType *FT = BT->getPointeeType()->getAs<FunctionType>();
+ const FunctionType *FT = BT->getPointeeType()->castAs<FunctionType>();
S += '<';
// Block return type
@@ -5100,11 +5142,14 @@
return;
}
- // Ignore protocol qualifiers when mangling at this level.
- if (const ObjCObjectType *OT = T->getAs<ObjCObjectType>())
- T = OT->getBaseType();
-
- if (const ObjCInterfaceType *OIT = T->getAs<ObjCInterfaceType>()) {
+ case Type::ObjCObject:
+ case Type::ObjCInterface: {
+ // Ignore protocol qualifiers when mangling at this level.
+ T = T->castAs<ObjCObjectType>()->getBaseType();
+
+ // The assumption seems to be that this assert will succeed
+ // because nested levels will have filtered out 'id' and 'Class'.
+ const ObjCInterfaceType *OIT = T->castAs<ObjCInterfaceType>();
// @encode(class_name)
ObjCInterfaceDecl *OI = OIT->getDecl();
S += '{';
@@ -5124,7 +5169,8 @@
return;
}
- if (const ObjCObjectPointerType *OPT = T->getAs<ObjCObjectPointerType>()) {
+ case Type::ObjCObjectPointer: {
+ const ObjCObjectPointerType *OPT = T->castAs<ObjCObjectPointerType>();
if (OPT->isObjCIdType()) {
S += '@';
return;
@@ -5187,18 +5233,29 @@
}
// gcc just blithely ignores member pointers.
- // TODO: maybe there should be a mangling for these
- if (T->getAs<MemberPointerType>())
+ // FIXME: we shoul do better than that. 'M' is available.
+ case Type::MemberPointer:
return;
- if (T->isVectorType()) {
+ case Type::Vector:
+ case Type::ExtVector:
// This matches gcc's encoding, even though technically it is
// insufficient.
// FIXME. We should do a better job than gcc.
return;
+
+#define ABSTRACT_TYPE(KIND, BASE)
+#define TYPE(KIND, BASE)
+#define DEPENDENT_TYPE(KIND, BASE) \
+ case Type::KIND:
+#define NON_CANONICAL_TYPE(KIND, BASE) \
+ case Type::KIND:
+#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(KIND, BASE) \
+ case Type::KIND:
+#include "clang/AST/TypeNodes.def"
+ llvm_unreachable("@encode for dependent type!");
}
-
- llvm_unreachable("@encode for type not implemented!");
+ llvm_unreachable("bad type kind!");
}
void ASTContext::getObjCEncodingForStructureImpl(RecordDecl *RDecl,
Modified: cfe/trunk/test/CodeGenObjC/encode-test.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenObjC/encode-test.m?rev=170639&r1=170638&r2=170639&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenObjC/encode-test.m (original)
+++ cfe/trunk/test/CodeGenObjC/encode-test.m Wed Dec 19 20:45:14 2012
@@ -165,3 +165,7 @@
// rdar://9622422
// CHECK: @g11 = constant [2 x i8] c"v\00"
const char g11[] = @encode(void);
+
+// PR14628
+// CHECK: @g12 = constant [3 x i8] c"Ai\00"
+const char g12[] = @encode(_Atomic(int));
More information about the cfe-commits
mailing list