diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 39a51bc1f4..df7a83bcbf 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -710,8 +710,6 @@ public: unsigned isBuiltinCall() const; - bool isBuiltinClassifyType(llvm::APSInt &Result) const; - /// isBuiltinConstantExpr - Return true if this built-in call is constant. bool isBuiltinConstantExpr(ASTContext &Ctx) const; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index bd1578fe20..45363d6992 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -12,8 +12,9 @@ //===----------------------------------------------------------------------===// #include "clang/AST/Expr.h" -#include "clang/AST/DeclObjC.h" +#include "clang/AST/APValue.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/TargetInfo.h" @@ -167,64 +168,6 @@ bool CallExpr::isBuiltinConstantExpr(ASTContext &Ctx) const { return Ctx.BuiltinInfo.isConstantExpr(BID); } -bool CallExpr::isBuiltinClassifyType(llvm::APSInt &Result) const { - if (isBuiltinCall() != Builtin::BI__builtin_classify_type) - return false; - - // The following enum mimics the values returned by GCC. - 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); - - // 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 == 0) - return true; - - 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(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type"); - return true; -} - /// getOpcodeStr - Turn an Opcode enum value into the punctuation char it /// corresponds to, e.g. "<<=". const char *BinaryOperator::getOpcodeStr(Opcode Op) { @@ -755,8 +698,17 @@ bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx, case CallExprClass: { const CallExpr *CE = cast(this); Result.zextOrTrunc(static_cast(Ctx.getTypeSize(getType()))); - if (CE->isBuiltinClassifyType(Result)) - break; + + // If this is a call to a builtin function, constant fold it otherwise + // reject it. + if (CE->isBuiltinCall()) { + APValue ResultAP; + if (CE->tryEvaluate(ResultAP, Ctx)) { + Result = ResultAP.getInt(); + break; // It is a constant, expand it. + } + } + if (Loc) *Loc = getLocStart(); return false; } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 2b92cc7355..1506f448aa 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -245,6 +245,61 @@ bool IntExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) { return Error(E->getLocStart(), diag::err_expr_not_constant); } +/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way +/// as GCC. +static int EvaluateBuiltinClassifyType(const CallExpr *E) { + // The following enum mimics the values returned by GCC. + 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 + }; + + // If no argument was supplied, default to "no_type_class". This isn't + // ideal, however it is what gcc does. + if (E->getNumArgs() == 0) + return no_type_class; + + QualType ArgTy = E->getArg(0)->getType(); + if (ArgTy->isVoidType()) + return void_type_class; + else if (ArgTy->isEnumeralType()) + return enumeral_type_class; + else if (ArgTy->isBooleanType()) + return boolean_type_class; + else if (ArgTy->isCharType()) + return string_type_class; // gcc doesn't appear to use char_type_class + else if (ArgTy->isIntegerType()) + return integer_type_class; + else if (ArgTy->isPointerType()) + return pointer_type_class; + else if (ArgTy->isReferenceType()) + return reference_type_class; + else if (ArgTy->isRealType()) + return real_type_class; + else if (ArgTy->isComplexType()) + return complex_type_class; + else if (ArgTy->isFunctionType()) + return function_type_class; + else if (ArgTy->isStructureType()) + return record_type_class; + else if (ArgTy->isUnionType()) + return union_type_class; + else if (ArgTy->isArrayType()) + return array_type_class; + else if (ArgTy->isUnionType()) + return union_type_class; + else // FIXME: offset_type_class, method_type_class, & lang_type_class? + assert(0 && "CallExpr::isBuiltinClassifyType(): unimplemented type"); + return -1; +} + bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { Result.zextOrTrunc(getIntTypeSizeInBits(E->getType())); @@ -252,8 +307,8 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) { default: return Error(E->getLocStart(), diag::err_expr_not_constant); case Builtin::BI__builtin_classify_type: - // __builtin_type_compatible_p is a constant. Return its value. - E->isBuiltinClassifyType(Result); + Result.setIsSigned(true); + Result = EvaluateBuiltinClassifyType(E); return true; case Builtin::BI__builtin_constant_p: {