[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