aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-05-27 20:44:45 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-05-27 20:44:45 +0000
commit33956c43007dfb106f401e3c14abc011a4b1d4ca (patch)
tree50a603f7e1932cd42f58e26687ce907933014db0 /contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
parentff0cc061ecf297f1556e906d229826fd709f37d6 (diff)
parent5e20cdd81c44a443562a09007668ffdf76c455af (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.cpp333
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);
}