Finish implementing __builtin_classify_type()...

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@40951 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Steve Naroff 2007-08-08 22:15:55 +00:00
Родитель 6c216160b6
Коммит 13b7c5ff42
5 изменённых файлов: 123 добавлений и 0 удалений

Просмотреть файл

@ -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())) {

Просмотреть файл

@ -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 &&

Просмотреть файл

@ -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);
}

Просмотреть файл

@ -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)

Просмотреть файл

@ -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);
}