void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl) { // We're interested specifically in copy assignment operators. // Unlike addedConstructor, this method is not called for implicit // declarations. const FunctionProtoType *FnType = OpDecl->getType()->getAsFunctionProtoType(); assert(FnType && "Overloaded operator has no proto function type."); assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); QualType ArgType = FnType->getArgType(0); if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) ArgType = Ref->getPointeeType(); ArgType = ArgType.getUnqualifiedType(); QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); if (ClassType != Context.getCanonicalType(ArgType)) return; // This is a copy assignment operator. // Suppress the implicit declaration of a copy constructor. UserDeclaredCopyAssignment = true; // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. PlainOldData = false; }
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { assert(!TR->isReferenceType() && "Expressions can't have reference type."); Cl::Kinds kind = ClassifyInternal(Ctx, this); // C99 6.3.2.1: An lvalue is an expression with an object type or an // incomplete type other than void. if (!Ctx.getLangOptions().CPlusPlus) { // Thus, no functions. if (TR->isFunctionType() || TR == Ctx.OverloadTy) kind = Cl::CL_Function; // No void either, but qualified void is OK because it is "other than void". else if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers()) kind = Cl::CL_Void; } // Enable this assertion for testing. switch (kind) { case Cl::CL_LValue: assert(getValueKind() == VK_LValue); break; case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break; case Cl::CL_Function: case Cl::CL_Void: case Cl::CL_DuplicateVectorComponents: case Cl::CL_MemberFunction: case Cl::CL_SubObjCPropertySetting: case Cl::CL_ClassTemporary: case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break; } Cl::ModifiableType modifiable = Cl::CM_Untested; if (Loc) modifiable = IsModifiable(Ctx, this, kind, *Loc); return Classification(kind, modifiable); }
bool CXXConstructorDecl::isCopyConstructor(ASTContext &Context, unsigned &TypeQuals) const { // C++ [class.copy]p2: // A non-template constructor for class X is a copy constructor // if its first parameter is of type X&, const X&, volatile X& or // const volatile X&, and either there are no other parameters // or else all other parameters have default arguments (8.3.6). if ((getNumParams() < 1) || (getNumParams() > 1 && getParamDecl(1)->getDefaultArg() == 0)) return false; const ParmVarDecl *Param = getParamDecl(0); // Do we have a reference type? Rvalue references don't count. const LValueReferenceType *ParamRefType = Param->getType()->getAsLValueReferenceType(); if (!ParamRefType) return false; // Is it a reference to our class type? QualType PointeeType = Context.getCanonicalType(ParamRefType->getPointeeType()); QualType ClassTy = Context.getTagDeclType(const_cast<CXXRecordDecl*>(getParent())); if (PointeeType.getUnqualifiedType() != ClassTy) return false; // We have a copy constructor. TypeQuals = PointeeType.getCVRQualifiers(); return true; }
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, Cl::Kinds Kind, SourceLocation &Loc) { // As a general rule, we only care about lvalues. But there are some rvalues // for which we want to generate special results. if (Kind == Cl::CL_PRValue) { // For the sake of better diagnostics, we want to specifically recognize // use of the GCC cast-as-lvalue extension. if (const ExplicitCastExpr *CE = dyn_cast<ExplicitCastExpr>(E->IgnoreParens())) { if (CE->getSubExpr()->IgnoreParenImpCasts()->isLValue()) { Loc = CE->getExprLoc(); return Cl::CM_LValueCast; } } } if (Kind != Cl::CL_LValue) return Cl::CM_RValue; // This is the lvalue case. // Functions are lvalues in C++, but not modifiable. (C++ [basic.lval]p6) if (Ctx.getLangOpts().CPlusPlus && E->getType()->isFunctionType()) return Cl::CM_Function; // Assignment to a property in ObjC is an implicit setter access. But a // setter might not exist. if (const ObjCPropertyRefExpr *Expr = dyn_cast<ObjCPropertyRefExpr>(E)) { if (Expr->isImplicitProperty() && Expr->getImplicitPropertySetter() == 0) return Cl::CM_NoSetterProperty; } CanQualType CT = Ctx.getCanonicalType(E->getType()); // Const stuff is obviously not modifiable. if (CT.isConstQualified()) return Cl::CM_ConstQualified; if (CT.getQualifiers().getAddressSpace() == LangAS::opencl_constant) return Cl::CM_ConstQualified; // Arrays are not modifiable, only their elements are. if (CT->isArrayType()) return Cl::CM_ArrayType; // Incomplete types are not modifiable. if (CT->isIncompleteType()) return Cl::CM_IncompleteType; // Records with any const fields (recursively) are not modifiable. if (const RecordType *R = CT->getAs<RecordType>()) { assert((E->getObjectKind() == OK_ObjCProperty || !Ctx.getLangOpts().CPlusPlus) && "C++ struct assignment should be resolved by the " "copy assignment operator."); if (R->hasConstFields()) return Cl::CM_ConstQualified; } return Cl::CM_Modifiable; }
static CanQualType GetConversionType(ASTContext &Context, NamedDecl *Conv) { QualType T; if (isa<UsingShadowDecl>(Conv)) Conv = cast<UsingShadowDecl>(Conv)->getTargetDecl(); if (FunctionTemplateDecl *ConvTemp = dyn_cast<FunctionTemplateDecl>(Conv)) T = ConvTemp->getTemplatedDecl()->getResultType(); else T = cast<CXXConversionDecl>(Conv)->getConversionType(); return Context.getCanonicalType(T); }
bool CXXRecordDecl::hasConstCopyAssignment(ASTContext &Context) const { QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); DeclarationName OpName =Context.DeclarationNames.getCXXOperatorName(OO_Equal); DeclContext::lookup_const_iterator Op, OpEnd; for (llvm::tie(Op, OpEnd) = this->lookup(Context, OpName); Op != OpEnd; ++Op) { // C++ [class.copy]p9: // A user-declared copy assignment operator is a non-static non-template // member function of class X with exactly one parameter of type X, X&, // const X&, volatile X& or const volatile X&. const CXXMethodDecl* Method = cast<CXXMethodDecl>(*Op); if (Method->isStatic()) continue; // TODO: Skip templates? Or is this implicitly done due to parameter types? const FunctionProtoType *FnType = Method->getType()->getAsFunctionProtoType(); assert(FnType && "Overloaded operator has no prototype."); // Don't assert on this; an invalid decl might have been left in the AST. if (FnType->getNumArgs() != 1 || FnType->isVariadic()) continue; bool AcceptsConst = true; QualType ArgType = FnType->getArgType(0); if (const LValueReferenceType *Ref = ArgType->getAsLValueReferenceType()) { ArgType = Ref->getPointeeType(); // Is it a non-const lvalue reference? if (!ArgType.isConstQualified()) AcceptsConst = false; } if (Context.getCanonicalType(ArgType).getUnqualifiedType() != ClassType) continue; // We have a single argument of type cv X or cv X&, i.e. we've found the // copy assignment operator. Return whether it accepts const arguments. return AcceptsConst; } assert(isInvalidDecl() && "No copy assignment operator declared in valid code."); return false; }
bool CXXRecordDecl::hasConstCopyConstructor(ASTContext &Context) const { QualType ClassType = Context.getTypeDeclType(const_cast<CXXRecordDecl*>(this)); DeclarationName ConstructorName = Context.DeclarationNames.getCXXConstructorName( Context.getCanonicalType(ClassType)); unsigned TypeQuals; DeclContext::lookup_const_iterator Con, ConEnd; for (llvm::tie(Con, ConEnd) = this->lookup(Context, ConstructorName); Con != ConEnd; ++Con) { if (cast<CXXConstructorDecl>(*Con)->isCopyConstructor(Context, TypeQuals) && (TypeQuals & QualType::Const) != 0) return true; } return false; }
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { assert(!TR->isReferenceType() && "Expressions can't have reference type."); Cl::Kinds kind = ClassifyInternal(Ctx, this); // C99 6.3.2.1: An lvalue is an expression with an object type or an // incomplete type other than void. if (!Ctx.getLangOptions().CPlusPlus) { // Thus, no functions. if (TR->isFunctionType() || TR == Ctx.OverloadTy) kind = Cl::CL_Function; // No void either, but qualified void is OK because it is "other than void". else if (TR->isVoidType() && !Ctx.getCanonicalType(TR).hasQualifiers()) kind = Cl::CL_Void; } Cl::ModifiableType modifiable = Cl::CM_Untested; if (Loc) modifiable = IsModifiable(Ctx, this, kind, *Loc); return Classification(kind, modifiable); }
static bool isHigherOrderRawPtr(QualType T, ASTContext &C) { bool foundPointer = false; while (1) { const PointerType *PT = T->getAs<PointerType>(); if (!PT) { if (!foundPointer) return false; // intptr_t* or intptr_t**, etc? if (T->isIntegerType() && C.getTypeSize(T) == C.getTypeSize(C.VoidPtrTy)) return true; QualType X = C.getCanonicalType(T).getUnqualifiedType(); return X == C.VoidTy; } foundPointer = true; T = PT->getPointeeType(); } }
void CXXRecordDecl::addedAssignmentOperator(ASTContext &Context, CXXMethodDecl *OpDecl) { // We're interested specifically in copy assignment operators. const FunctionProtoType *FnType = OpDecl->getType()->getAs<FunctionProtoType>(); assert(FnType && "Overloaded operator has no proto function type."); assert(FnType->getNumArgs() == 1 && !FnType->isVariadic()); // Copy assignment operators must be non-templates. if (OpDecl->getPrimaryTemplate() || OpDecl->getDescribedFunctionTemplate()) return; QualType ArgType = FnType->getArgType(0); if (const LValueReferenceType *Ref = ArgType->getAs<LValueReferenceType>()) ArgType = Ref->getPointeeType(); ArgType = ArgType.getUnqualifiedType(); QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType( const_cast<CXXRecordDecl*>(this))); if (!Context.hasSameUnqualifiedType(ClassType, ArgType)) return; // This is a copy assignment operator. // Note on the decl that it is a copy assignment operator. OpDecl->setCopyAssignment(true); // Suppress the implicit declaration of a copy constructor. data().UserDeclaredCopyAssignment = true; data().DeclaredCopyAssignment = true; // C++ [class.copy]p11: // A copy assignment operator is trivial if it is implicitly declared. // FIXME: C++0x: don't do this for "= default" copy operators. data().HasTrivialCopyAssignment = false; // C++ [class]p4: // A POD-struct is an aggregate class that [...] has no user-defined copy // assignment operator [...]. data().PlainOldData = false; }
bool CXXBasePaths::lookupInBases(ASTContext &Context, const CXXRecordDecl *Record, CXXRecordDecl::BaseMatchesCallback *BaseMatches, void *UserData) { bool FoundPath = false; // The access of the path down to this record. AccessSpecifier AccessToHere = ScratchPath.Access; bool IsFirstStep = ScratchPath.empty(); for (CXXRecordDecl::base_class_const_iterator BaseSpec = Record->bases_begin(), BaseSpecEnd = Record->bases_end(); BaseSpec != BaseSpecEnd; ++BaseSpec) { // Find the record of the base class subobjects for this type. QualType BaseType = Context.getCanonicalType(BaseSpec->getType()) .getUnqualifiedType(); // C++ [temp.dep]p3: // In the definition of a class template or a member of a class template, // if a base class of the class template depends on a template-parameter, // the base class scope is not examined during unqualified name lookup // either at the point of definition of the class template or member or // during an instantiation of the class tem- plate or member. if (BaseType->isDependentType()) continue; // Determine whether we need to visit this base class at all, // updating the count of subobjects appropriately. std::pair<bool, unsigned>& Subobjects = ClassSubobjects[BaseType]; bool VisitBase = true; bool SetVirtual = false; if (BaseSpec->isVirtual()) { VisitBase = !Subobjects.first; Subobjects.first = true; if (isDetectingVirtual() && DetectedVirtual == 0) { // If this is the first virtual we find, remember it. If it turns out // there is no base path here, we'll reset it later. DetectedVirtual = BaseType->getAs<RecordType>(); SetVirtual = true; } } else ++Subobjects.second; if (isRecordingPaths()) { // Add this base specifier to the current path. CXXBasePathElement Element; Element.Base = &*BaseSpec; Element.Class = Record; if (BaseSpec->isVirtual()) Element.SubobjectNumber = 0; else Element.SubobjectNumber = Subobjects.second; ScratchPath.push_back(Element); // Calculate the "top-down" access to this base class. // The spec actually describes this bottom-up, but top-down is // equivalent because the definition works out as follows: // 1. Write down the access along each step in the inheritance // chain, followed by the access of the decl itself. // For example, in // class A { public: int foo; }; // class B : protected A {}; // class C : public B {}; // class D : private C {}; // we would write: // private public protected public // 2. If 'private' appears anywhere except far-left, access is denied. // 3. Otherwise, overall access is determined by the most restrictive // access in the sequence. if (IsFirstStep) ScratchPath.Access = BaseSpec->getAccessSpecifier(); else ScratchPath.Access = CXXRecordDecl::MergeAccess(AccessToHere, BaseSpec->getAccessSpecifier()); } // Track whether there's a path involving this specific base. bool FoundPathThroughBase = false; if (BaseMatches(BaseSpec, ScratchPath, UserData)) { // We've found a path that terminates at this base. FoundPath = FoundPathThroughBase = true; if (isRecordingPaths()) { // We have a path. Make a copy of it before moving on. Paths.push_back(ScratchPath); } else if (!isFindingAmbiguities()) { // We found a path and we don't care about ambiguities; // return immediately. return FoundPath; } } else if (VisitBase) { CXXRecordDecl *BaseRecord = cast<CXXRecordDecl>(BaseSpec->getType()->castAs<RecordType>() ->getDecl()); if (lookupInBases(Context, BaseRecord, BaseMatches, UserData)) { // C++ [class.member.lookup]p2: // A member name f in one sub-object B hides a member name f in // a sub-object A if A is a base class sub-object of B. Any // declarations that are so hidden are eliminated from // consideration. // There is a path to a base class that meets the criteria. If we're // not collecting paths or finding ambiguities, we're done. FoundPath = FoundPathThroughBase = true; if (!isFindingAmbiguities()) return FoundPath; } } // Pop this base specifier off the current path (if we're // collecting paths). if (isRecordingPaths()) { ScratchPath.pop_back(); } // If we set a virtual earlier, and this isn't a path, forget it again. if (SetVirtual && !FoundPathThroughBase) { DetectedVirtual = 0; } } // Reset the scratch path access. ScratchPath.Access = AccessToHere; return FoundPath; }
clang::analyze_format_string::ArgType::MatchKind ArgType::matchesType(ASTContext &C, QualType argTy) const { if (Ptr) { // It has to be a pointer. const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) return NoMatch; // We cannot write through a const qualified pointer. if (PT->getPointeeType().isConstQualified()) return NoMatch; argTy = PT->getPointeeType(); } switch (K) { case InvalidTy: llvm_unreachable("ArgType must be valid"); case UnknownTy: return Match; case AnyCharTy: { if (const EnumType *ETy = argTy->getAs<EnumType>()) argTy = ETy->getDecl()->getIntegerType(); if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) switch (BT->getKind()) { default: break; case BuiltinType::Char_S: case BuiltinType::SChar: case BuiltinType::UChar: case BuiltinType::Char_U: return Match; } return NoMatch; } case SpecificTy: { if (const EnumType *ETy = argTy->getAs<EnumType>()) argTy = ETy->getDecl()->getIntegerType(); argTy = C.getCanonicalType(argTy).getUnqualifiedType(); if (T == argTy) return Match; // Check for "compatible types". if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) switch (BT->getKind()) { default: break; case BuiltinType::Char_S: case BuiltinType::SChar: case BuiltinType::Char_U: case BuiltinType::UChar: return T == C.UnsignedCharTy || T == C.SignedCharTy ? Match : NoMatch; case BuiltinType::Short: return T == C.UnsignedShortTy ? Match : NoMatch; case BuiltinType::UShort: return T == C.ShortTy ? Match : NoMatch; case BuiltinType::Int: return T == C.UnsignedIntTy ? Match : NoMatch; case BuiltinType::UInt: return T == C.IntTy ? Match : NoMatch; case BuiltinType::Long: return T == C.UnsignedLongTy ? Match : NoMatch; case BuiltinType::ULong: return T == C.LongTy ? Match : NoMatch; case BuiltinType::LongLong: return T == C.UnsignedLongLongTy ? Match : NoMatch; case BuiltinType::ULongLong: return T == C.LongLongTy ? Match : NoMatch; } return NoMatch; } case CStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) return NoMatch; QualType pointeeTy = PT->getPointeeType(); if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) switch (BT->getKind()) { case BuiltinType::Void: case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: return Match; default: break; } return NoMatch; } case WCStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) return NoMatch; QualType pointeeTy = C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); return pointeeTy == C.getWideCharType() ? Match : NoMatch; } case WIntTy: { QualType PromoArg = argTy->isPromotableIntegerType() ? C.getPromotedIntegerType(argTy) : argTy; QualType WInt = C.getCanonicalType(C.getWIntType()).getUnqualifiedType(); PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); // If the promoted argument is the corresponding signed type of the // wint_t type, then it should match. if (PromoArg->hasSignedIntegerRepresentation() && C.getCorrespondingUnsignedType(PromoArg) == WInt) return Match; return WInt == PromoArg ? Match : NoMatch; } case CPointerTy: if (argTy->isVoidPointerType()) { return Match; } if (argTy->isPointerType() || argTy->isObjCObjectPointerType() || argTy->isBlockPointerType() || argTy->isNullPtrType()) { return NoMatchPedantic; } else { return NoMatch; } case ObjCPointerTy: { if (argTy->getAs<ObjCObjectPointerType>() || argTy->getAs<BlockPointerType>()) return Match; // Handle implicit toll-free bridging. if (const PointerType *PT = argTy->getAs<PointerType>()) { // Things such as CFTypeRef are really just opaque pointers // to C structs representing CF types that can often be bridged // to Objective-C objects. Since the compiler doesn't know which // structs can be toll-free bridged, we just accept them all. QualType pointee = PT->getPointeeType(); if (pointee->getAsStructureType() || pointee->isVoidType()) return Match; } return NoMatch; } } llvm_unreachable("Invalid ArgType Kind!"); }
static Cl::ModifiableType IsModifiable(ASTContext &Ctx, const Expr *E, Cl::Kinds Kind, SourceLocation &Loc) { // As a general rule, we only care about lvalues. But there are some rvalues // for which we want to generate special results. if (Kind == Cl::CL_PRValue) { // For the sake of better diagnostics, we want to specifically recognize // use of the GCC cast-as-lvalue extension. if (const CStyleCastExpr *CE = dyn_cast<CStyleCastExpr>(E->IgnoreParens())){ if (CE->getSubExpr()->Classify(Ctx).isLValue()) { Loc = CE->getLParenLoc(); return Cl::CM_LValueCast; } } } if (Kind != Cl::CL_LValue) return Cl::CM_RValue; // This is the lvalue case. // Functions are lvalues in C++, but not modifiable. (C++ [basic.lval]p6) if (Ctx.getLangOptions().CPlusPlus && E->getType()->isFunctionType()) return Cl::CM_Function; // You cannot assign to a variable outside a block from within the block if // it is not marked __block, e.g. // void takeclosure(void (^C)(void)); // void func() { int x = 1; takeclosure(^{ x = 7; }); } if (const BlockDeclRefExpr *BDR = dyn_cast<BlockDeclRefExpr>(E)) { if (!BDR->isByRef() && isa<VarDecl>(BDR->getDecl())) return Cl::CM_NotBlockQualified; } // Assignment to a property in ObjC is an implicit setter access. But a // setter might not exist. if (const ObjCImplicitSetterGetterRefExpr *Expr = dyn_cast<ObjCImplicitSetterGetterRefExpr>(E)) { if (Expr->getSetterMethod() == 0) return Cl::CM_NoSetterProperty; } CanQualType CT = Ctx.getCanonicalType(E->getType()); // Const stuff is obviously not modifiable. if (CT.isConstQualified()) return Cl::CM_ConstQualified; // Arrays are not modifiable, only their elements are. if (CT->isArrayType()) return Cl::CM_ArrayType; // Incomplete types are not modifiable. if (CT->isIncompleteType()) return Cl::CM_IncompleteType; // Records with any const fields (recursively) are not modifiable. if (const RecordType *R = CT->getAs<RecordType>()) { assert(!Ctx.getLangOptions().CPlusPlus && "C++ struct assignment should be resolved by the " "copy assignment operator."); if (R->hasConstFields()) return Cl::CM_ConstQualified; } return Cl::CM_Modifiable; }
bool ArgTypeResult::matchesType(ASTContext &C, QualType argTy) const { switch (K) { case InvalidTy: assert(false && "ArgTypeResult must be valid"); return true; case UnknownTy: return true; case SpecificTy: { argTy = C.getCanonicalType(argTy).getUnqualifiedType(); if (T == argTy) return true; // Check for "compatible types". if (const BuiltinType *BT = argTy->getAs<BuiltinType>()) switch (BT->getKind()) { default: break; case BuiltinType::Char_S: case BuiltinType::SChar: return T == C.UnsignedCharTy; case BuiltinType::Char_U: case BuiltinType::UChar: return T == C.SignedCharTy; case BuiltinType::Short: return T == C.UnsignedShortTy; case BuiltinType::UShort: return T == C.ShortTy; case BuiltinType::Int: return T == C.UnsignedIntTy; case BuiltinType::UInt: return T == C.IntTy; case BuiltinType::Long: return T == C.UnsignedLongTy; case BuiltinType::ULong: return T == C.LongTy; case BuiltinType::LongLong: return T == C.UnsignedLongLongTy; case BuiltinType::ULongLong: return T == C.LongLongTy; } return false; } case CStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) return false; QualType pointeeTy = PT->getPointeeType(); if (const BuiltinType *BT = pointeeTy->getAs<BuiltinType>()) switch (BT->getKind()) { case BuiltinType::Void: case BuiltinType::Char_U: case BuiltinType::UChar: case BuiltinType::Char_S: case BuiltinType::SChar: return true; default: break; } return false; } case WCStrTy: { const PointerType *PT = argTy->getAs<PointerType>(); if (!PT) return false; QualType pointeeTy = C.getCanonicalType(PT->getPointeeType()).getUnqualifiedType(); return pointeeTy == C.getWCharType(); } case WIntTy: { // Instead of doing a lookup for the definition of 'wint_t' (which // is defined by the system headers) instead see if wchar_t and // the argument type promote to the same type. QualType PromoWChar = C.getWCharType()->isPromotableIntegerType() ? C.getPromotedIntegerType(C.getWCharType()) : C.getWCharType(); QualType PromoArg = argTy->isPromotableIntegerType() ? C.getPromotedIntegerType(argTy) : argTy; PromoWChar = C.getCanonicalType(PromoWChar).getUnqualifiedType(); PromoArg = C.getCanonicalType(PromoArg).getUnqualifiedType(); return PromoWChar == PromoArg; } case CPointerTy: return argTy->isPointerType() || argTy->isObjCObjectPointerType() || argTy->isNullPtrType(); case ObjCPointerTy: return argTy->getAs<ObjCObjectPointerType>() != NULL; } // FIXME: Should be unreachable, but Clang is currently emitting // a warning. return false; }