From 13b7c5ff42d6077a8d59e2c9ec9e7fedd0150ae6 Mon Sep 17 00:00:00 2001 From: Steve Naroff Date: Wed, 8 Aug 2007 22:15:55 +0000 Subject: [PATCH] Finish implementing __builtin_classify_type()... git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40951 91177308-0d34-0410-b5e6-96231b3b80d8 --- AST/Expr.cpp | 77 +++++++++++++++++++++++++++++ AST/Type.cpp | 20 ++++++++ include/clang/AST/Expr.h | 2 + include/clang/AST/Type.h | 3 ++ test/Parser/builtin_classify_type.c | 21 ++++++++ 5 files changed, 123 insertions(+) create mode 100644 test/Parser/builtin_classify_type.c diff --git a/AST/Expr.cpp b/AST/Expr.cpp index 1a90b13cf1..7397e54ae6 100644 --- a/AST/Expr.cpp +++ b/AST/Expr.cpp @@ -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(getCallee()); + if (!ICE) // FIXME: deal with more complex calls (e.g. (func)(), (*func)()). + return false; + const DeclRefExpr *DRE = dyn_cast(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(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(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(cast(this)->getDecl())) { diff --git a/AST/Type.cpp b/AST/Type.cpp index afdd3cc1f7..27453ca981 100644 --- a/AST/Type.cpp +++ b/AST/Type.cpp @@ -340,6 +340,26 @@ bool Type::isIntegerType() const { return false; } +bool Type::isEnumeralType() const { + if (const TagType *TT = dyn_cast(CanonicalType)) + return TT->getDecl()->getKind() == Decl::Enum; + return false; +} + +bool Type::isBooleanType() const { + if (const BuiltinType *BT = dyn_cast(CanonicalType)) + return BT->getKind() == BuiltinType::Bool; + return false; +} + +bool Type::isCharType() const { + if (const BuiltinType *BT = dyn_cast(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(CanonicalType)) { return BT->getKind() >= BuiltinType::Char_S && diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index df5f68da10..a95315e6f5 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -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); } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 2f492bf918..5b22a42494 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -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 index 0000000000..87b8bb64de --- /dev/null +++ b/test/Parser/builtin_classify_type.c @@ -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); +}