diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-05-27 20:44:45 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-05-27 20:44:45 +0000 |
commit | 33956c43007dfb106f401e3c14abc011a4b1d4ca (patch) | |
tree | 50a603f7e1932cd42f58e26687ce907933014db0 /contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp | |
parent | ff0cc061ecf297f1556e906d229826fd709f37d6 (diff) | |
parent | 5e20cdd81c44a443562a09007668ffdf76c455af (diff) |
Merge clang trunk r238337 from ^/vendor/clang/dist, resolve conflicts,
and preserve our customizations, where necessary.
Notes
Notes:
svn path=/projects/clang-trunk/; revision=283633
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp | 333 |
1 files changed, 251 insertions, 82 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index d7ce6f10e60b..31fe05592f00 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -51,6 +51,11 @@ namespace AttributeLangSupport { static bool isFunctionOrMethod(const Decl *D) { return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D); } +/// \brief Return true if the given decl has function type (function or +/// function-typed variable) or an Objective-C method or a block. +static bool isFunctionOrMethodOrBlock(const Decl *D) { + return isFunctionOrMethod(D) || isa<BlockDecl>(D); +} /// Return true if the given decl has a declarator that should have /// been processed by Sema::GetTypeForDeclarator. @@ -257,7 +262,7 @@ static bool checkFunctionOrMethodParameterIndex(Sema &S, const Decl *D, unsigned AttrArgNum, const Expr *IdxExpr, uint64_t &Idx) { - assert(isFunctionOrMethod(D)); + assert(isFunctionOrMethodOrBlock(D)); // In C++ the implicit 'this' function parameter also counts. // Parameters are counted from one. @@ -351,13 +356,13 @@ static bool isIntOrBool(Expr *Exp) { // Check to see if the type is a smart pointer of some kind. We assume // it's a smart pointer if it defines both operator-> and operator*. static bool threadSafetyCheckIsSmartPointer(Sema &S, const RecordType* RT) { - DeclContextLookupConstResult Res1 = RT->getDecl()->lookup( - S.Context.DeclarationNames.getCXXOperatorName(OO_Star)); + DeclContextLookupResult Res1 = RT->getDecl()->lookup( + S.Context.DeclarationNames.getCXXOperatorName(OO_Star)); if (Res1.empty()) return false; - DeclContextLookupConstResult Res2 = RT->getDecl()->lookup( - S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow)); + DeclContextLookupResult Res2 = RT->getDecl()->lookup( + S.Context.DeclarationNames.getCXXOperatorName(OO_Arrow)); if (Res2.empty()) return false; @@ -1492,6 +1497,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } + // Aliases should be on declarations, not definitions. + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->isThisDeclarationADefinition()) { + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD; + return; + } + } else { + const auto *VD = cast<VarDecl>(D); + if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) { + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD; + return; + } + } + // FIXME: check if target symbol exists in current file D->addAttr(::new (S.Context) AliasAttr(Attr.getRange(), S.Context, Str, @@ -1534,18 +1553,16 @@ static void handleTLSModelAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -static void handleMallocAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - QualType RetTy = FD->getReturnType(); - if (RetTy->isAnyPointerType() || RetTy->isBlockPointerType()) { - D->addAttr(::new (S.Context) - MallocAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - return; - } +static void handleRestrictAttr(Sema &S, Decl *D, const AttributeList &Attr) { + QualType ResultType = getFunctionOrMethodResultType(D); + if (ResultType->isAnyPointerType() || ResultType->isBlockPointerType()) { + D->addAttr(::new (S.Context) RestrictAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + return; } - S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only); + S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) + << Attr.getName() << getFunctionOrMethodResultSourceRange(D); } static void handleCommonAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -1589,7 +1606,7 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, // The checking path for 'noreturn' and 'analyzer_noreturn' are different // because 'analyzer_noreturn' does not impact the type. - if (!isFunctionOrMethod(D) && !isa<BlockDecl>(D)) { + if (!isFunctionOrMethodOrBlock(D)) { ValueDecl *VD = dyn_cast<ValueDecl>(D); if (!VD || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { @@ -2105,6 +2122,22 @@ static void handleObjCNSObject(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleObjCIndependentClass(Sema &S, Decl *D, const AttributeList &Attr) { + if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { + QualType T = TD->getUnderlyingType(); + if (!T->isObjCObjectPointerType()) { + S.Diag(TD->getLocation(), diag::warn_ptr_independentclass_attribute); + return; + } + } else { + S.Diag(D->getLocation(), diag::warn_independentclass_attribute); + return; + } + D->addAttr(::new (S.Context) + ObjCIndependentClassAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); +} + static void handleBlocksAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!Attr.isArgIdent(0)) { S.Diag(Attr.getLoc(), diag::err_attribute_argument_n_type) @@ -2330,6 +2363,15 @@ SectionAttr *Sema::mergeSectionAttr(Decl *D, SourceRange Range, AttrSpellingListIndex); } +bool Sema::checkSectionName(SourceLocation LiteralLoc, StringRef SecName) { + std::string Error = Context.getTargetInfo().isValidSectionSpecifier(SecName); + if (!Error.empty()) { + Diag(LiteralLoc, diag::err_attribute_section_invalid_for_target) << Error; + return false; + } + return true; +} + static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Make sure that there is a string literal as the sections's single // argument. @@ -2338,6 +2380,9 @@ static void handleSectionAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str, &LiteralLoc)) return; + if (!S.checkSectionName(LiteralLoc, Str)) + return; + // If the target wants to validate the section specifier, make it happen. std::string Error = S.Context.getTargetInfo().isValidSectionSpecifier(Str); if (!Error.empty()) { @@ -2482,6 +2527,7 @@ static FormatAttrKind getFormatAttrKind(StringRef Format) { .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat) .Case("kprintf", SupportedFormat) // OpenBSD. .Case("freebsd_kprintf", SupportedFormat) // FreeBSD. + .Case("os_trace", SupportedFormat) .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat) .Default(InvalidFormat); @@ -2838,6 +2884,16 @@ static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!Attr.isPackExpansion() && S.DiagnoseUnexpandedParameterPack(E)) return; + if (E->isValueDependent()) { + if (const auto *TND = dyn_cast<TypedefNameDecl>(D)) { + if (!TND->getUnderlyingType()->isDependentType()) { + S.Diag(Attr.getLoc(), diag::err_alignment_dependent_typedef_name) + << E->getSourceRange(); + return; + } + } + } + S.AddAlignedAttr(Attr.getRange(), D, E, Attr.getAttributeSpellingListIndex(), Attr.isPackExpansion()); } @@ -2940,12 +2996,15 @@ void Sema::AddAlignedAttr(SourceRange AttrRange, Decl *D, TypeSourceInfo *TS, void Sema::CheckAlignasUnderalignment(Decl *D) { assert(D->hasAttrs() && "no attributes on decl"); - QualType Ty; - if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) - Ty = VD->getType(); - else - Ty = Context.getTagDeclType(cast<TagDecl>(D)); - if (Ty->isDependentType() || Ty->isIncompleteType()) + QualType UnderlyingTy, DiagTy; + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + UnderlyingTy = DiagTy = VD->getType(); + } else { + UnderlyingTy = DiagTy = Context.getTagDeclType(cast<TagDecl>(D)); + if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + UnderlyingTy = ED->getIntegerType(); + } + if (DiagTy->isDependentType() || DiagTy->isIncompleteType()) return; // C++11 [dcl.align]p5, C11 6.7.5/4: @@ -2964,10 +3023,10 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { if (AlignasAttr && Align) { CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align); - CharUnits NaturalAlign = Context.getTypeAlignInChars(Ty); + CharUnits NaturalAlign = Context.getTypeAlignInChars(UnderlyingTy); if (NaturalAlign > RequestedAlign) Diag(AlignasAttr->getLocation(), diag::err_alignas_underaligned) - << Ty << (unsigned)NaturalAlign.getQuantity(); + << DiagTy << (unsigned)NaturalAlign.getQuantity(); } } @@ -3315,11 +3374,6 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); return; } - case AttributeList::AT_PnaclCall: - D->addAttr(::new (S.Context) - PnaclCallAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); - return; case AttributeList::AT_IntelOclBicc: D->addAttr(::new (S.Context) IntelOclBiccAttr(Attr.getRange(), S.Context, @@ -3376,16 +3430,18 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, Diag(attr.getLoc(), diag::err_invalid_pcs); return true; } - case AttributeList::AT_PnaclCall: CC = CC_PnaclCall; break; case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break; default: llvm_unreachable("unexpected attribute kind"); } const TargetInfo &TI = Context.getTargetInfo(); TargetInfo::CallingConvCheckResult A = TI.checkCallingConvention(CC); - if (A == TargetInfo::CCCR_Warning) { - Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName(); + if (A != TargetInfo::CCCR_OK) { + if (A == TargetInfo::CCCR_Warning) + Diag(attr.getLoc(), diag::warn_cconv_ignored) << attr.getName(); + // This convention is not valid for the target. Use the default function or + // method calling convention. TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown; if (FD) MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member : @@ -3432,20 +3488,63 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { return false; } +// Checks whether an argument of launch_bounds attribute is acceptable +// May output an error. +static bool checkLaunchBoundsArgument(Sema &S, Expr *E, + const CUDALaunchBoundsAttr &Attr, + const unsigned Idx) { + + if (S.DiagnoseUnexpandedParameterPack(E)) + return false; + + // Accept template arguments for now as they depend on something else. + // We'll get to check them when they eventually get instantiated. + if (E->isValueDependent()) + return true; + + llvm::APSInt I(64); + if (!E->isIntegerConstantExpr(I, S.Context)) { + S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) + << &Attr << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); + return false; + } + // Make sure we can fit it in 32 bits. + if (!I.isIntN(32)) { + S.Diag(E->getExprLoc(), diag::err_ice_too_large) << I.toString(10, false) + << 32 << /* Unsigned */ 1; + return false; + } + if (I < 0) + S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) + << &Attr << Idx << E->getSourceRange(); + + return true; +} + +void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, + Expr *MinBlocks, unsigned SpellingListIndex) { + CUDALaunchBoundsAttr TmpAttr(AttrRange, Context, MaxThreads, MinBlocks, + SpellingListIndex); + + if (!checkLaunchBoundsArgument(*this, MaxThreads, TmpAttr, 0)) + return; + + if (MinBlocks && !checkLaunchBoundsArgument(*this, MinBlocks, TmpAttr, 1)) + return; + + D->addAttr(::new (Context) CUDALaunchBoundsAttr( + AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex)); +} + static void handleLaunchBoundsAttr(Sema &S, Decl *D, const AttributeList &Attr) { - uint32_t MaxThreads, MinBlocks = 0; - if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), MaxThreads, 1)) - return; - if (Attr.getNumArgs() > 1 && !checkUInt32Argument(S, Attr, - Attr.getArgAsExpr(1), - MinBlocks, 2)) + if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || + !checkAttributeAtMostNumArgs(S, Attr, 2)) return; - D->addAttr(::new (S.Context) - CUDALaunchBoundsAttr(Attr.getRange(), S.Context, - MaxThreads, MinBlocks, - Attr.getAttributeSpellingListIndex())); + S.AddLaunchBoundsAttr(Attr.getRange(), D, Attr.getArgAsExpr(0), + Attr.getNumArgs() > 1 ? Attr.getArgAsExpr(1) : nullptr, + Attr.getAttributeSpellingListIndex()); } static void handleArgumentWithTypeTagAttr(Sema &S, Decl *D, @@ -3724,6 +3823,22 @@ static void handleObjCBridgeAttr(Sema &S, Scope *Sc, Decl *D, S.Diag(D->getLocStart(), diag::err_objc_attr_not_id) << Attr.getName() << 0; return; } + + // Typedefs only allow objc_bridge(id) and have some additional checking. + if (auto TD = dyn_cast<TypedefNameDecl>(D)) { + if (!Parm->Ident->isStr("id")) { + S.Diag(Attr.getLoc(), diag::err_objc_attr_typedef_not_id) + << Attr.getName(); + return; + } + + // Only allow 'cv void *'. + QualType T = TD->getUnderlyingType(); + if (!T->isVoidPointerType()) { + S.Diag(Attr.getLoc(), diag::err_objc_attr_typedef_not_void_pointer); + return; + } + } D->addAttr(::new (S.Context) ObjCBridgeAttr(Attr.getRange(), S.Context, Parm->Ident, @@ -3770,6 +3885,10 @@ static void handleObjCDesignatedInitializer(Sema &S, Decl *D, IFace = CatDecl->getClassInterface(); else IFace = cast<ObjCInterfaceDecl>(D->getDeclContext()); + + if (!IFace) + return; + IFace->setHasDesignatedInitializers(); D->addAttr(::new (S.Context) ObjCDesignatedInitializerAttr(Attr.getRange(), S.Context, @@ -4226,9 +4345,52 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } } + + if (!S.getLangOpts().CPlusPlus14) + if (Attr.isCXX11Attribute() && + !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) + S.Diag(Attr.getLoc(), diag::ext_deprecated_attr_is_a_cxx14_extension); + handleAttrWithMessage<DeprecatedAttr>(S, D, Attr); } +static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + std::vector<std::string> Sanitizers; + + for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + StringRef SanitizerName; + SourceLocation LiteralLoc; + + if (!S.checkStringLiteralArgumentAttr(Attr, I, SanitizerName, &LiteralLoc)) + return; + + if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0) + S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; + + Sanitizers.push_back(SanitizerName); + } + + D->addAttr(::new (S.Context) NoSanitizeAttr( + Attr.getRange(), S.Context, Sanitizers.data(), Sanitizers.size(), + Attr.getAttributeSpellingListIndex())); +} + +static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + std::string SanitizerName = + llvm::StringSwitch<std::string>(Attr.getName()->getName()) + .Case("no_address_safety_analysis", "address") + .Case("no_sanitize_address", "address") + .Case("no_sanitize_thread", "thread") + .Case("no_sanitize_memory", "memory"); + D->addAttr(::new (S.Context) + NoSanitizeAttr(Attr.getRange(), S.Context, &SanitizerName, 1, + Attr.getAttributeSpellingListIndex())); +} + /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. @@ -4396,6 +4558,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_OptimizeNone: handleOptimizeNoneAttr(S, D, Attr); break; + case AttributeList::AT_FlagEnum: + handleSimpleAttribute<FlagEnumAttr>(S, D, Attr); + break; case AttributeList::AT_Flatten: handleSimpleAttribute<FlattenAttr>(S, D, Attr); break; @@ -4420,8 +4585,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_CUDALaunchBounds: handleLaunchBoundsAttr(S, D, Attr); break; - case AttributeList::AT_Malloc: - handleMallocAttr(S, D, Attr); + case AttributeList::AT_Restrict: + handleRestrictAttr(S, D, Attr); break; case AttributeList::AT_MayAlias: handleSimpleAttribute<MayAliasAttr>(S, D, Attr); @@ -4609,6 +4774,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ObjCNSObject: handleObjCNSObject(S, D, Attr); break; + case AttributeList::AT_ObjCIndependentClass: + handleObjCIndependentClass(S, D, Attr); + break; case AttributeList::AT_Blocks: handleBlocksAttr(S, D, Attr); break; @@ -4645,7 +4813,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_MSABI: case AttributeList::AT_SysVABI: case AttributeList::AT_Pcs: - case AttributeList::AT_PnaclCall: case AttributeList::AT_IntelOclBicc: handleCallConvAttr(S, D, Attr); break; @@ -4657,8 +4824,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, break; // Microsoft attributes: - case AttributeList::AT_MsStruct: - handleSimpleAttribute<MsStructAttr>(S, D, Attr); + case AttributeList::AT_MSNoVTable: + handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr); + break; + case AttributeList::AT_MSStruct: + handleSimpleAttribute<MSStructAttr>(S, D, Attr); break; case AttributeList::AT_Uuid: handleUuidAttr(S, D, Attr); @@ -4689,18 +4859,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ScopedLockable: handleSimpleAttribute<ScopedLockableAttr>(S, D, Attr); break; - case AttributeList::AT_NoSanitizeAddress: - handleSimpleAttribute<NoSanitizeAddressAttr>(S, D, Attr); + case AttributeList::AT_NoSanitize: + handleNoSanitizeAttr(S, D, Attr); + break; + case AttributeList::AT_NoSanitizeSpecific: + handleNoSanitizeSpecificAttr(S, D, Attr); break; case AttributeList::AT_NoThreadSafetyAnalysis: handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, Attr); break; - case AttributeList::AT_NoSanitizeThread: - handleSimpleAttribute<NoSanitizeThreadAttr>(S, D, Attr); - break; - case AttributeList::AT_NoSanitizeMemory: - handleSimpleAttribute<NoSanitizeMemoryAttr>(S, D, Attr); - break; case AttributeList::AT_GuardedBy: handleGuardedByAttr(S, D, Attr); break; @@ -4963,8 +5130,7 @@ void Sema::ProcessPragmaWeak(Scope *S, Decl *D) { ND = FD; if (ND) { if (IdentifierInfo *Id = ND->getIdentifier()) { - llvm::DenseMap<IdentifierInfo*,WeakInfo>::iterator I - = WeakUndeclaredIdentifiers.find(Id); + auto I = WeakUndeclaredIdentifiers.find(Id); if (I != WeakUndeclaredIdentifiers.end()) { WeakInfo W = I->second; DeclApplyPragmaWeak(S, ND, W); @@ -5043,7 +5209,8 @@ static bool isDeclDeprecated(Decl *D) { return true; // A category implicitly has the availability of the interface. if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) - return CatD->getClassInterface()->isDeprecated(); + if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) + return Interface->isDeprecated(); } while ((D = cast_or_null<Decl>(D->getDeclContext()))); return false; } @@ -5054,12 +5221,13 @@ static bool isDeclUnavailable(Decl *D) { return true; // A category implicitly has the availability of the interface. if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) - return CatD->getClassInterface()->isUnavailable(); + if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) + return Interface->isUnavailable(); } while ((D = cast_or_null<Decl>(D->getDeclContext()))); return false; } -static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, +static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, @@ -5076,8 +5244,8 @@ static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, // Don't warn if our current context is deprecated or unavailable. switch (K) { - case DelayedDiagnostic::Deprecation: - if (isDeclDeprecated(Ctx)) + case Sema::AD_Deprecation: + if (isDeclDeprecated(Ctx) || isDeclUnavailable(Ctx)) return; diag = !ObjCPropertyAccess ? diag::warn_deprecated : diag::warn_property_method_deprecated; @@ -5087,7 +5255,7 @@ static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, available_here_select_kind = /* deprecated */ 2; break; - case DelayedDiagnostic::Unavailable: + case Sema::AD_Unavailable: if (isDeclUnavailable(Ctx)) return; diag = !ObjCPropertyAccess ? diag::err_unavailable @@ -5098,8 +5266,13 @@ static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, available_here_select_kind = /* unavailable */ 0; break; - default: - llvm_unreachable("Neither a deprecation or unavailable kind"); + case Sema::AD_Partial: + diag = diag::warn_partial_availability; + diag_message = diag::warn_partial_message; + diag_fwdclass_message = diag::warn_partial_fwdclass_message; + property_note_select = /* partial */ 2; + available_here_select_kind = /* partial */ 3; + break; } if (!Message.empty()) { @@ -5119,15 +5292,21 @@ static void DoEmitAvailabilityWarning(Sema &S, DelayedDiagnostic::DDKind K, S.Diag(D->getLocation(), diag::note_availability_specified_here) << D << available_here_select_kind; + if (K == Sema::AD_Partial) + S.Diag(Loc, diag::note_partial_availability_silence) << D; } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, Decl *Ctx) { + assert(DD.Kind == DelayedDiagnostic::Deprecation || + DD.Kind == DelayedDiagnostic::Unavailable); + Sema::AvailabilityDiagnostic AD = DD.Kind == DelayedDiagnostic::Deprecation + ? Sema::AD_Deprecation + : Sema::AD_Unavailable; DD.Triggered = true; - DoEmitAvailabilityWarning(S, (DelayedDiagnostic::DDKind)DD.Kind, Ctx, - DD.getDeprecationDecl(), DD.getDeprecationMessage(), - DD.Loc, DD.getUnknownObjCClass(), - DD.getObjCProperty(), false); + DoEmitAvailabilityWarning( + S, AD, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, + DD.getUnknownObjCClass(), DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -5193,7 +5372,7 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. - if (DelayedDiagnostics.shouldDelayDiagnostics()) { + if (DelayedDiagnostics.shouldDelayDiagnostics() && AD != AD_Partial) { DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( AD, Loc, D, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); @@ -5201,16 +5380,6 @@ void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, } Decl *Ctx = cast<Decl>(getCurLexicalContext()); - DelayedDiagnostic::DDKind K; - switch (AD) { - case AD_Deprecation: - K = DelayedDiagnostic::Deprecation; - break; - case AD_Unavailable: - K = DelayedDiagnostic::Unavailable; - break; - } - - DoEmitAvailabilityWarning(*this, K, Ctx, D, Message, Loc, - UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); + DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass, + ObjCProperty, ObjCPropertyAccess); } |