]> granicus.if.org Git - clang/commitdiff
Finish implementing __builtin_classify_type()...
authorSteve Naroff <snaroff@apple.com>
Wed, 8 Aug 2007 22:15:55 +0000 (22:15 +0000)
committerSteve Naroff <snaroff@apple.com>
Wed, 8 Aug 2007 22:15:55 +0000 (22:15 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40951 91177308-0d34-0410-b5e6-96231b3b80d8

AST/Expr.cpp
AST/Type.cpp
include/clang/AST/Expr.h
include/clang/AST/Type.h
test/Parser/builtin_classify_type.c [new file with mode: 0644]

index 1a90b13cf14065258d966e95fe21a9b5fa1cfdd3..7397e54ae6ac56948bc16f4b36ef5ac7c7b14d18 100644 (file)
@@ -85,6 +85,75 @@ CallExpr::CallExpr(Expr *fn, Expr **args, unsigned numargs, QualType t,
   RParenLoc = rparenloc;
 }
 
+bool CallExpr::isBuiltinClassifyType(llvm::APSInt &Result) const {
+  // The following enum mimics gcc's internal "typeclass.h" file.
+  enum gcc_type_class {
+    no_type_class = -1,
+    void_type_class, integer_type_class, char_type_class,
+    enumeral_type_class, boolean_type_class,
+    pointer_type_class, reference_type_class, offset_type_class,
+    real_type_class, complex_type_class,
+    function_type_class, method_type_class,
+    record_type_class, union_type_class,
+    array_type_class, string_type_class,
+    lang_type_class
+  };
+  Result.setIsSigned(true);
+  
+  // All simple function calls (e.g. func()) are implicitly cast to pointer to
+  // function. As a result, we try and obtain the DeclRefExpr from the 
+  // ImplicitCastExpr.
+  const ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(getCallee());
+  if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()).
+    return false;
+  const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(ICE->getSubExpr());
+  if (!DRE)
+    return false;
+
+  // We have a DeclRefExpr.
+  if (strcmp(DRE->getDecl()->getName(), "__builtin_classify_type") == 0) {
+    // If no argument was supplied, default to "no_type_class". This isn't 
+    // ideal, however it's what gcc does.
+    Result = static_cast<uint64_t>(no_type_class);
+    if (NumArgs >= 1) {
+      QualType argType = getArg(0)->getType();
+      
+      if (argType->isVoidType())
+        Result = void_type_class;
+      else if (argType->isEnumeralType())
+        Result = enumeral_type_class;
+      else if (argType->isBooleanType())
+        Result = boolean_type_class;
+      else if (argType->isCharType())
+        Result = string_type_class; // gcc doesn't appear to use char_type_class
+      else if (argType->isIntegerType())
+        Result = integer_type_class;
+      else if (argType->isPointerType())
+        Result = pointer_type_class;
+      else if (argType->isReferenceType())
+        Result = reference_type_class;
+      else if (argType->isRealType())
+        Result = real_type_class;
+      else if (argType->isComplexType())
+        Result = complex_type_class;
+      else if (argType->isFunctionType())
+        Result = function_type_class;
+      else if (argType->isStructureType())
+        Result = record_type_class;
+      else if (argType->isUnionType())
+        Result = union_type_class;
+      else if (argType->isArrayType())
+        Result = array_type_class;
+      else if (argType->isUnionType())
+        Result = union_type_class;
+      else  // FIXME: offset_type_class, method_type_class, & lang_type_class?
+        assert(1 && "CallExpr::isBuiltinClassifyType(): unimplemented type");
+    }
+    return true;
+  }
+  return false;
+}
+
 /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it
 /// corresponds to, e.g. "<<=".
 const char *BinaryOperator::getOpcodeStr(Opcode Op) {
@@ -311,6 +380,14 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
     Result = TCE->typesAreCompatible();
     break;
   }
+  case CallExprClass: {
+    const CallExpr *CE = cast<CallExpr>(this);
+    Result.zextOrTrunc(Ctx.getTypeSize(getType(), CE->getLocStart()));
+    if (CE->isBuiltinClassifyType(Result))
+      break;
+    if (Loc) *Loc = getLocStart();
+    return false;
+  }
   case DeclRefExprClass:
     if (const EnumConstantDecl *D = 
           dyn_cast<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl())) {
index afdd3cc1f7ebbedbe4977f6ea402e1e2667501a7..27453ca9813ee890a43fbb647ef51a1bf8b48e19 100644 (file)
@@ -340,6 +340,26 @@ bool Type::isIntegerType() const {
   return false;
 }
 
+bool Type::isEnumeralType() const {
+  if (const TagType *TT = dyn_cast<TagType>(CanonicalType))
+    return TT->getDecl()->getKind() == Decl::Enum;
+  return false;
+}
+
+bool Type::isBooleanType() const {
+  if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+    return BT->getKind() == BuiltinType::Bool;
+  return false;
+}
+
+bool Type::isCharType() const {
+  if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
+    return BT->getKind() == BuiltinType::Char_U ||
+           BT->getKind() == BuiltinType::UChar ||
+           BT->getKind() == BuiltinType::Char_S;
+  return false;
+}
+
 bool Type::isSignedIntegerType() const {
   if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType)) {
     return BT->getKind() >= BuiltinType::Char_S &&
index df5f68da108b39af0cc639b7eb67a3e5aeb83172..a95315e6f59e3607aad2a8b6f9b4a922efe51478 100644 (file)
@@ -424,6 +424,8 @@ public:
   /// this function call.
   unsigned getNumCommas() const { return NumArgs ? NumArgs - 1 : 0; }
 
+  bool isBuiltinClassifyType(llvm::APSInt &Result) const;
+  
   SourceRange getSourceRange() const { 
     return SourceRange(Fn->getLocStart(), RParenLoc);
   }
index 2f492bf918316553fd3659172806f755985b6403..5b22a4249403007b65bafeff15ba466acab5c1e2 100644 (file)
@@ -231,6 +231,9 @@ public:
   /// Helper methods to distinguish type categories. All type predicates
   /// operate on the canonical type, ignoring typedefs.
   bool isIntegerType() const;     // C99 6.2.5p17 (int, char, bool, enum)
+  bool isEnumeralType() const;
+  bool isBooleanType() const;
+  bool isCharType() const;
   
   /// Floating point categories.
   bool isRealFloatingType() const; // C99 6.2.5p10 (float, double, long double)
diff --git a/test/Parser/builtin_classify_type.c b/test/Parser/builtin_classify_type.c
new file mode 100644 (file)
index 0000000..87b8bb6
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: clang -parse-ast-check %s
+
+struct foo { int a; };
+
+int main() {
+  int a;
+  float b;
+  double d;
+  struct foo s;
+
+  static int ary[__builtin_classify_type(a)];
+  static int ary2[(__builtin_classify_type)(a)]; // expected-error{{variable length array declared outside of any function}}
+  static int ary3[(*__builtin_classify_type)(a)]; // expected-error{{variable length array declared outside of any function}}
+
+  int result;
+
+  result =  __builtin_classify_type(a);
+  result =  __builtin_classify_type(b);
+  result =  __builtin_classify_type(d);
+  result =  __builtin_classify_type(s);
+}