diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp | 320 |
1 files changed, 187 insertions, 133 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index 9c3b51c..9947fad 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -218,7 +218,9 @@ static ObjCMethodDecl *getNSNumberFactoryMethod(Sema &S, SourceLocation Loc, S.Diag(Loc, diag::err_undeclared_nsnumber); return nullptr; } - + } + + if (S.NSNumberPointer.isNull()) { // generate the pointer to NSNumber type. QualType NSNumberObject = CX.getObjCInterfaceType(S.NSNumberDecl); S.NSNumberPointer = CX.getObjCObjectPointerType(NSNumberObject); @@ -1041,7 +1043,7 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, SourceLocation RParenLoc, bool WarnMultipleSelectors) { ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LParenLoc, RParenLoc), false, false); + SourceRange(LParenLoc, RParenLoc)); if (!Method) Method = LookupFactoryMethodInGlobalPool(Sel, SourceRange(LParenLoc, RParenLoc)); @@ -1059,15 +1061,11 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, } else DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc, WarnMultipleSelectors); - + if (Method && Method->getImplementationControl() != ObjCMethodDecl::Optional && - !getSourceManager().isInSystemHeader(Method->getLocation())) { - llvm::DenseMap<Selector, SourceLocation>::iterator Pos - = ReferencedSelectors.find(Sel); - if (Pos == ReferencedSelectors.end()) - ReferencedSelectors.insert(std::make_pair(Sel, AtLoc)); - } + !getSourceManager().isInSystemHeader(Method->getLocation())) + ReferencedSelectors.insert(std::make_pair(Sel, AtLoc)); // In ARC, forbid the user from using @selector for // retain/release/autorelease/dealloc/retainCount. @@ -1137,49 +1135,154 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf(SourceLocation Loc) { } static QualType stripObjCInstanceType(ASTContext &Context, QualType T) { + QualType origType = T; + if (auto nullability = AttributedType::stripOuterNullability(T)) { + if (T == Context.getObjCInstanceType()) { + return Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*nullability), + Context.getObjCIdType(), + Context.getObjCIdType()); + } + + return origType; + } + if (T == Context.getObjCInstanceType()) return Context.getObjCIdType(); - return T; + return origType; } -QualType Sema::getMessageSendResultType(QualType ReceiverType, - ObjCMethodDecl *Method, - bool isClassMessage, bool isSuperMessage) { +/// Determine the result type of a message send based on the receiver type, +/// method, and the kind of message send. +/// +/// This is the "base" result type, which will still need to be adjusted +/// to account for nullability. +static QualType getBaseMessageSendResultType(Sema &S, + QualType ReceiverType, + ObjCMethodDecl *Method, + bool isClassMessage, + bool isSuperMessage) { assert(Method && "Must have a method"); if (!Method->hasRelatedResultType()) return Method->getSendResultType(); - + + ASTContext &Context = S.Context; + + // Local function that transfers the nullability of the method's + // result type to the returned result. + auto transferNullability = [&](QualType type) -> QualType { + // If the method's result type has nullability, extract it. + if (auto nullability = Method->getSendResultType()->getNullability(Context)){ + // Strip off any outer nullability sugar from the provided type. + (void)AttributedType::stripOuterNullability(type); + + // Form a new attributed type using the method result type's nullability. + return Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*nullability), + type, + type); + } + + return type; + }; + // If a method has a related return type: // - if the method found is an instance method, but the message send // was a class message send, T is the declared return type of the method // found if (Method->isInstanceMethod() && isClassMessage) return stripObjCInstanceType(Context, Method->getSendResultType()); - - // - if the receiver is super, T is a pointer to the class of the + + // - if the receiver is super, T is a pointer to the class of the // enclosing method definition if (isSuperMessage) { - if (ObjCMethodDecl *CurMethod = getCurMethodDecl()) - if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) - return Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(Class)); + if (ObjCMethodDecl *CurMethod = S.getCurMethodDecl()) + if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) { + return transferNullability( + Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(Class))); + } } - + // - if the receiver is the name of a class U, T is a pointer to U if (ReceiverType->getAs<ObjCInterfaceType>() || ReceiverType->isObjCQualifiedInterfaceType()) - return Context.getObjCObjectPointerType(ReceiverType); - // - if the receiver is of type Class or qualified Class type, + return transferNullability(Context.getObjCObjectPointerType(ReceiverType)); + // - if the receiver is of type Class or qualified Class type, // T is the declared return type of the method. if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) return stripObjCInstanceType(Context, Method->getSendResultType()); - + // - if the receiver is id, qualified id, Class, or qualified Class, T // is the receiver type, otherwise // - T is the type of the receiver expression. - return ReceiverType; + return transferNullability(ReceiverType); +} + +QualType Sema::getMessageSendResultType(QualType ReceiverType, + ObjCMethodDecl *Method, + bool isClassMessage, + bool isSuperMessage) { + // Produce the result type. + QualType resultType = getBaseMessageSendResultType(*this, ReceiverType, + Method, + isClassMessage, + isSuperMessage); + + // If this is a class message, ignore the nullability of the receiver. + if (isClassMessage) + return resultType; + + // Map the nullability of the result into a table index. + unsigned receiverNullabilityIdx = 0; + if (auto nullability = ReceiverType->getNullability(Context)) + receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability); + + unsigned resultNullabilityIdx = 0; + if (auto nullability = resultType->getNullability(Context)) + resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability); + + // The table of nullability mappings, indexed by the receiver's nullability + // and then the result type's nullability. + static const uint8_t None = 0; + static const uint8_t NonNull = 1; + static const uint8_t Nullable = 2; + static const uint8_t Unspecified = 3; + static const uint8_t nullabilityMap[4][4] = { + // None NonNull Nullable Unspecified + /* None */ { None, None, Nullable, None }, + /* NonNull */ { None, NonNull, Nullable, Unspecified }, + /* Nullable */ { Nullable, Nullable, Nullable, Nullable }, + /* Unspecified */ { None, Unspecified, Nullable, Unspecified } + }; + + unsigned newResultNullabilityIdx + = nullabilityMap[receiverNullabilityIdx][resultNullabilityIdx]; + if (newResultNullabilityIdx == resultNullabilityIdx) + return resultType; + + // Strip off the existing nullability. This removes as little type sugar as + // possible. + do { + if (auto attributed = dyn_cast<AttributedType>(resultType.getTypePtr())) { + resultType = attributed->getModifiedType(); + } else { + resultType = resultType.getDesugaredType(Context); + } + } while (resultType->getNullability(Context)); + + // Add nullability back if needed. + if (newResultNullabilityIdx > 0) { + auto newNullability + = static_cast<NullabilityKind>(newResultNullabilityIdx-1); + return Context.getAttributedType( + AttributedType::getNullabilityAttrKind(newNullability), + resultType, resultType); + } + + return resultType; } /// Look for an ObjC method whose result type exactly matches the given type. @@ -1507,64 +1610,6 @@ ObjCMethodDecl *Sema::LookupMethodInQualifiedType(Selector Sel, return nullptr; } -static void DiagnoseARCUseOfWeakReceiver(Sema &S, Expr *Receiver) { - if (!Receiver) - return; - - if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(Receiver)) - Receiver = OVE->getSourceExpr(); - - Expr *RExpr = Receiver->IgnoreParenImpCasts(); - SourceLocation Loc = RExpr->getLocStart(); - QualType T = RExpr->getType(); - const ObjCPropertyDecl *PDecl = nullptr; - const ObjCMethodDecl *GDecl = nullptr; - if (PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(RExpr)) { - RExpr = POE->getSyntacticForm(); - if (ObjCPropertyRefExpr *PRE = dyn_cast<ObjCPropertyRefExpr>(RExpr)) { - if (PRE->isImplicitProperty()) { - GDecl = PRE->getImplicitPropertyGetter(); - if (GDecl) { - T = GDecl->getReturnType(); - } - } - else { - PDecl = PRE->getExplicitProperty(); - if (PDecl) { - T = PDecl->getType(); - } - } - } - } - else if (ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RExpr)) { - // See if receiver is a method which envokes a synthesized getter - // backing a 'weak' property. - ObjCMethodDecl *Method = ME->getMethodDecl(); - if (Method && Method->getSelector().getNumArgs() == 0) { - PDecl = Method->findPropertyDecl(); - if (PDecl) - T = PDecl->getType(); - } - } - - if (T.getObjCLifetime() != Qualifiers::OCL_Weak) { - if (!PDecl) - return; - if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)) - return; - } - - S.Diag(Loc, diag::warn_receiver_is_weak) - << ((!PDecl && !GDecl) ? 0 : (PDecl ? 1 : 2)); - - if (PDecl) - S.Diag(PDecl->getLocation(), diag::note_property_declare); - else if (GDecl) - S.Diag(GDecl->getLocation(), diag::note_method_declared_at) << GDecl; - - S.Diag(Loc, diag::note_arc_assign_to_strong); -} - /// HandleExprPropertyRefExpr - Handle foo.bar where foo is a pointer to an /// objective C interface. This is a property reference expression. ExprResult Sema:: @@ -1751,29 +1796,30 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IsSuper = true; if (ObjCMethodDecl *CurMethod = tryCaptureObjCSelf(receiverNameLoc)) { - if (CurMethod->isInstanceMethod()) { - ObjCInterfaceDecl *Super = - CurMethod->getClassInterface()->getSuperClass(); - if (!Super) { - // The current class does not have a superclass. - Diag(receiverNameLoc, diag::error_root_class_cannot_use_super) - << CurMethod->getClassInterface()->getIdentifier(); - return ExprError(); + if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) { + if (CurMethod->isInstanceMethod()) { + ObjCInterfaceDecl *Super = Class->getSuperClass(); + if (!Super) { + // The current class does not have a superclass. + Diag(receiverNameLoc, diag::error_root_class_cannot_use_super) + << Class->getIdentifier(); + return ExprError(); + } + QualType T = Context.getObjCInterfaceType(Super); + T = Context.getObjCObjectPointerType(T); + + return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), + /*BaseExpr*/nullptr, + SourceLocation()/*OpLoc*/, + &propertyName, + propertyNameLoc, + receiverNameLoc, T, true); } - QualType T = Context.getObjCInterfaceType(Super); - T = Context.getObjCObjectPointerType(T); - - return HandleExprPropertyRefExpr(T->getAsObjCInterfacePointerType(), - /*BaseExpr*/nullptr, - SourceLocation()/*OpLoc*/, - &propertyName, - propertyNameLoc, - receiverNameLoc, T, true); - } - // Otherwise, if this is a class method, try dispatching to our - // superclass. - IFace = CurMethod->getClassInterface()->getSuperClass(); + // Otherwise, if this is a class method, try dispatching to our + // superclass. + IFace = Class->getSuperClass(); + } } } @@ -2452,8 +2498,11 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (ObjCMethodDecl *BestMethod = SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) Method = BestMethod; - if (!AreMultipleMethodsInGlobalPool(Sel, Method->isInstanceMethod())) + if (!AreMultipleMethodsInGlobalPool(Sel, Method, + SourceRange(LBracLoc, RBracLoc), + receiverIsId)) { DiagnoseUseOfDecl(Method, SelLoc); + } } } else if (ReceiverType->isObjCClassType() || ReceiverType->isObjCQualifiedClassType()) { @@ -2491,14 +2540,12 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // If not messaging 'self', look for any factory method named 'Sel'. if (!Receiver || !isSelfExpr(Receiver)) { Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), - true); + SourceRange(LBracLoc, RBracLoc)); if (!Method) { // If no class (factory) method was found, check if an _instance_ // method of the same name exists in the root class only. Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), - true); + SourceRange(LBracLoc, RBracLoc)); if (Method) if (const ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { @@ -2575,6 +2622,14 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (OCIType->qual_empty()) { Method = LookupInstanceMethodInGlobalPool(Sel, SourceRange(LBracLoc, RBracLoc)); + if (Method) { + if (auto BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + Method = BestMethod; + AreMultipleMethodsInGlobalPool(Sel, Method, + SourceRange(LBracLoc, RBracLoc), + true); + } if (Method && !forwardClass) Diag(SelLoc, diag::warn_maynot_respond) << OCIType->getInterfaceDecl()->getIdentifier() @@ -2757,15 +2812,6 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } if (getLangOpts().ObjCAutoRefCount) { - // Do not warn about IBOutlet weak property receivers being set to null - // as this cannot asynchronously happen. - bool WarnWeakReceiver = true; - if (isImplicit && Method) - if (const ObjCPropertyDecl *PropertyDecl = Method->findPropertyDecl()) - WarnWeakReceiver = !PropertyDecl->hasAttr<IBOutletAttr>(); - if (WarnWeakReceiver) - DiagnoseARCUseOfWeakReceiver(*this, Receiver); - // In ARC, annotate delegate init calls. if (Result->getMethodFamily() == OMF_init && (SuperLoc.isValid() || isSelfExpr(Receiver))) { @@ -2796,7 +2842,9 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, } } } - + + CheckObjCCircularContainer(Result); + return MaybeBindToTemporary(Result); } @@ -2805,8 +2853,7 @@ static void RemoveSelectorFromWarningCache(Sema &S, Expr* Arg) { dyn_cast<ObjCSelectorExpr>(Arg->IgnoreParenCasts())) { Selector Sel = OSE->getSelector(); SourceLocation Loc = OSE->getAtLoc(); - llvm::DenseMap<Selector, SourceLocation>::iterator Pos - = S.ReferencedSelectors.find(Sel); + auto Pos = S.ReferencedSelectors.find(Sel); if (Pos != S.ReferencedSelectors.end() && Pos->second == Loc) S.ReferencedSelectors.erase(Pos); } @@ -3028,17 +3075,20 @@ namespace { /// Some declaration references are okay. ACCResult VisitDeclRefExpr(DeclRefExpr *e) { - // References to global constants from system headers are okay. - // These are things like 'kCFStringTransformToLatin'. They are - // can also be assumed to be immune to retains. VarDecl *var = dyn_cast<VarDecl>(e->getDecl()); + // References to global constants are okay. if (isAnyRetainable(TargetClass) && isAnyRetainable(SourceClass) && var && var->getStorageClass() == SC_Extern && - var->getType().isConstQualified() && - Context.getSourceManager().isInSystemHeader(var->getLocation())) { - return ACC_bottom; + var->getType().isConstQualified()) { + + // In system headers, they can also be assumed to be immune to retains. + // These are things like 'kCFStringTransformToLatin'. + if (Context.getSourceManager().isInSystemHeader(var->getLocation())) + return ACC_bottom; + + return ACC_plusZero; } // Nothing else. @@ -3421,7 +3471,7 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, ObjCInterfaceDecl *CastClass = InterfacePointerType->getObjectType()->getInterface(); if ((CastClass == ExprClass) || - (CastClass && ExprClass->isSuperClassOf(CastClass))) + (CastClass && CastClass->isSuperClassOf(ExprClass))) return true; if (warn) S.Diag(castExpr->getLocStart(), diag::warn_objc_invalid_bridge) @@ -3444,12 +3494,13 @@ static bool CheckObjCBridgeNSCast(Sema &S, QualType castType, Expr *castExpr, return false; } } + } else if (!castType->isObjCIdType()) { + S.Diag(castExpr->getLocStart(), diag::err_objc_cf_bridged_not_interface) + << castExpr->getType() << Parm; + S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); + if (Target) + S.Diag(Target->getLocStart(), diag::note_declared_at); } - S.Diag(castExpr->getLocStart(), diag::err_objc_cf_bridged_not_interface) - << castExpr->getType() << Parm; - S.Diag(TDNDecl->getLocStart(), diag::note_declared_at); - if (Target) - S.Diag(Target->getLocStart(), diag::note_declared_at); return true; } return false; @@ -3469,6 +3520,9 @@ static bool CheckObjCBridgeCFCast(Sema &S, QualType castType, Expr *castExpr, if (TB *ObjCBAttr = getObjCBridgeAttr<TB>(TD)) { if (IdentifierInfo *Parm = ObjCBAttr->getBridgedType()) { HadTheAttribute = true; + if (Parm->isStr("id")) + return true; + NamedDecl *Target = nullptr; // Check for an existing type with this name. LookupResult R(S, DeclarationName(Parm), SourceLocation(), |