forked from OSchip/llvm-project
PR26449: Fixes for bugs in __builtin_classify_type implementation
This patch fixes the following bugs in __builtin_classify_type implementation: 1) Support for member functions and fields 2) Same behavior as GCC in C mode (specifically, return integer_type_class for enums and pointer_type_class for function pointers and arrays). Behavior in C++ mode didn't changed. Also, it refactors the whole implementation, by replacing a sequence of if-else-if with a couple of switches. Differential Revision: http://reviews.llvm.org/D16846 llvm-svn: 260881
This commit is contained in:
parent
2c2a2f5119
commit
5f6588ec2d
|
@ -6187,7 +6187,8 @@ bool IntExprEvaluator::CheckReferencedDecl(const Expr* E, const Decl* D) {
|
|||
|
||||
/// EvaluateBuiltinClassifyType - Evaluate __builtin_classify_type the same way
|
||||
/// as GCC.
|
||||
static int EvaluateBuiltinClassifyType(const CallExpr *E) {
|
||||
static int EvaluateBuiltinClassifyType(const CallExpr *E,
|
||||
const LangOptions &LangOpts) {
|
||||
// The following enum mimics the values returned by GCC.
|
||||
// FIXME: Does GCC differ between lvalue and rvalue references here?
|
||||
enum gcc_type_class {
|
||||
|
@ -6207,37 +6208,132 @@ static int EvaluateBuiltinClassifyType(const CallExpr *E) {
|
|||
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())
|
||||
QualType CanTy = E->getArg(0)->getType().getCanonicalType();
|
||||
const BuiltinType *BT = dyn_cast<BuiltinType>(CanTy);
|
||||
|
||||
switch (CanTy->getTypeClass()) {
|
||||
#define TYPE(ID, BASE)
|
||||
#define DEPENDENT_TYPE(ID, BASE) case Type::ID:
|
||||
#define NON_CANONICAL_TYPE(ID, BASE) case Type::ID:
|
||||
#define NON_CANONICAL_UNLESS_DEPENDENT_TYPE(ID, BASE) case Type::ID:
|
||||
#include "clang/AST/TypeNodes.def"
|
||||
llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
|
||||
|
||||
case Type::Builtin:
|
||||
switch (BT->getKind()) {
|
||||
#define BUILTIN_TYPE(ID, SINGLETON_ID)
|
||||
#define SIGNED_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: return integer_type_class;
|
||||
#define FLOATING_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: return real_type_class;
|
||||
#define PLACEHOLDER_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: break;
|
||||
#include "clang/AST/BuiltinTypes.def"
|
||||
case BuiltinType::Void:
|
||||
return void_type_class;
|
||||
|
||||
case BuiltinType::Bool:
|
||||
return boolean_type_class;
|
||||
|
||||
case BuiltinType::Char_U: // gcc doesn't appear to use char_type_class
|
||||
case BuiltinType::UChar:
|
||||
case BuiltinType::UShort:
|
||||
case BuiltinType::UInt:
|
||||
case BuiltinType::ULong:
|
||||
case BuiltinType::ULongLong:
|
||||
case BuiltinType::UInt128:
|
||||
return integer_type_class;
|
||||
|
||||
case BuiltinType::NullPtr:
|
||||
return pointer_type_class;
|
||||
|
||||
case BuiltinType::WChar_U:
|
||||
case BuiltinType::Char16:
|
||||
case BuiltinType::Char32:
|
||||
case BuiltinType::ObjCId:
|
||||
case BuiltinType::ObjCClass:
|
||||
case BuiltinType::ObjCSel:
|
||||
case BuiltinType::OCLImage1d:
|
||||
case BuiltinType::OCLImage1dArray:
|
||||
case BuiltinType::OCLImage2d:
|
||||
case BuiltinType::OCLImage2dArray:
|
||||
case BuiltinType::OCLImage1dBuffer:
|
||||
case BuiltinType::OCLImage2dDepth:
|
||||
case BuiltinType::OCLImage2dArrayDepth:
|
||||
case BuiltinType::OCLImage2dMSAA:
|
||||
case BuiltinType::OCLImage2dArrayMSAA:
|
||||
case BuiltinType::OCLImage2dMSAADepth:
|
||||
case BuiltinType::OCLImage2dArrayMSAADepth:
|
||||
case BuiltinType::OCLImage3d:
|
||||
case BuiltinType::OCLSampler:
|
||||
case BuiltinType::OCLEvent:
|
||||
case BuiltinType::OCLClkEvent:
|
||||
case BuiltinType::OCLQueue:
|
||||
case BuiltinType::OCLNDRange:
|
||||
case BuiltinType::OCLReserveID:
|
||||
case BuiltinType::Dependent:
|
||||
llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
|
||||
};
|
||||
|
||||
case Type::Enum:
|
||||
return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class;
|
||||
break;
|
||||
|
||||
case Type::Pointer:
|
||||
return pointer_type_class;
|
||||
else if (ArgTy->isReferenceType())
|
||||
return reference_type_class;
|
||||
else if (ArgTy->isRealType())
|
||||
return real_type_class;
|
||||
else if (ArgTy->isComplexType())
|
||||
break;
|
||||
|
||||
case Type::MemberPointer:
|
||||
if (CanTy->isMemberDataPointerType())
|
||||
return offset_type_class;
|
||||
else {
|
||||
// We expect member pointers to be either data or function pointers,
|
||||
// nothing else.
|
||||
assert(CanTy->isMemberFunctionPointerType());
|
||||
return method_type_class;
|
||||
}
|
||||
|
||||
case Type::Complex:
|
||||
return complex_type_class;
|
||||
else if (ArgTy->isFunctionType())
|
||||
return function_type_class;
|
||||
else if (ArgTy->isStructureOrClassType())
|
||||
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?
|
||||
|
||||
case Type::FunctionNoProto:
|
||||
case Type::FunctionProto:
|
||||
return LangOpts.CPlusPlus ? function_type_class : pointer_type_class;
|
||||
|
||||
case Type::Record:
|
||||
if (const RecordType *RT = CanTy->getAs<RecordType>()) {
|
||||
switch (RT->getDecl()->getTagKind()) {
|
||||
case TagTypeKind::TTK_Struct:
|
||||
case TagTypeKind::TTK_Class:
|
||||
case TagTypeKind::TTK_Interface:
|
||||
return record_type_class;
|
||||
|
||||
case TagTypeKind::TTK_Enum:
|
||||
return LangOpts.CPlusPlus ? enumeral_type_class : integer_type_class;
|
||||
|
||||
case TagTypeKind::TTK_Union:
|
||||
return union_type_class;
|
||||
}
|
||||
}
|
||||
llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
|
||||
|
||||
case Type::ConstantArray:
|
||||
case Type::VariableArray:
|
||||
case Type::IncompleteArray:
|
||||
return LangOpts.CPlusPlus ? array_type_class : pointer_type_class;
|
||||
|
||||
case Type::BlockPointer:
|
||||
case Type::LValueReference:
|
||||
case Type::RValueReference:
|
||||
case Type::Vector:
|
||||
case Type::ExtVector:
|
||||
case Type::Auto:
|
||||
case Type::ObjCObject:
|
||||
case Type::ObjCInterface:
|
||||
case Type::ObjCObjectPointer:
|
||||
case Type::Pipe:
|
||||
case Type::Atomic:
|
||||
llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
|
||||
}
|
||||
|
||||
llvm_unreachable("CallExpr::isBuiltinClassifyType(): unimplemented type");
|
||||
}
|
||||
|
||||
/// EvaluateBuiltinConstantPForLValue - Determine the result of
|
||||
|
@ -6609,7 +6705,7 @@ bool IntExprEvaluator::VisitCallExpr(const CallExpr *E) {
|
|||
}
|
||||
|
||||
case Builtin::BI__builtin_classify_type:
|
||||
return Success(EvaluateBuiltinClassifyType(E), E);
|
||||
return Success(EvaluateBuiltinClassifyType(E, Info.getLangOpts()), E);
|
||||
|
||||
// FIXME: BI__builtin_clrsb
|
||||
// FIXME: BI__builtin_clrsbl
|
||||
|
|
Loading…
Reference in New Issue