aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Sema/SemaAvailability.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaAvailability.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaAvailability.cpp202
1 files changed, 141 insertions, 61 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaAvailability.cpp b/contrib/llvm-project/clang/lib/Sema/SemaAvailability.cpp
index 846a31a79673..17566c226ec8 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaAvailability.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaAvailability.cpp
@@ -12,21 +12,45 @@
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
+#include "clang/Sema/SemaObjC.h"
+#include "llvm/ADT/StringRef.h"
#include <optional>
using namespace clang;
using namespace sema;
+static bool hasMatchingEnvironmentOrNone(const ASTContext &Context,
+ const AvailabilityAttr *AA) {
+ IdentifierInfo *IIEnvironment = AA->getEnvironment();
+ auto Environment = Context.getTargetInfo().getTriple().getEnvironment();
+ if (!IIEnvironment || Environment == llvm::Triple::UnknownEnvironment)
+ return true;
+
+ llvm::Triple::EnvironmentType ET =
+ AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
+ return Environment == ET;
+}
+
static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
const Decl *D) {
+ AvailabilityAttr const *PartialMatch = nullptr;
// Check each AvailabilityAttr to find the one for this platform.
+ // For multiple attributes with the same platform try to find one for this
+ // environment.
+ // The attribute is always on the FunctionDecl, not on the
+ // FunctionTemplateDecl.
+ if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
+ D = FTD->getTemplatedDecl();
for (const auto *A : D->attrs()) {
if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
// FIXME: this is copied from CheckAvailability. We should try to
@@ -45,11 +69,15 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
// Match the platform name.
- if (RealizedPlatform == TargetPlatform)
- return Avail;
+ if (RealizedPlatform == TargetPlatform) {
+ // Find the best matching attribute for this environment
+ if (hasMatchingEnvironmentOrNone(Context, Avail))
+ return Avail;
+ PartialMatch = Avail;
+ }
}
}
- return nullptr;
+ return PartialMatch;
}
/// The diagnostic we should emit for \c D, and the declaration that
@@ -79,6 +107,12 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
break;
}
+ // For alias templates, get the underlying declaration.
+ if (const auto *ADecl = dyn_cast<TypeAliasTemplateDecl>(D)) {
+ D = ADecl->getTemplatedDecl();
+ Result = D->getAvailability(Message);
+ }
+
// Forward class declarations get their attributes from their definition.
if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) {
if (IDecl->getDefinition()) {
@@ -98,11 +132,11 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
// For +new, infer availability from -init.
if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) {
- if (S.NSAPIObj && ClassReceiver) {
+ if (S.ObjC().NSAPIObj && ClassReceiver) {
ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod(
- S.NSAPIObj->getInitSelector());
+ S.ObjC().NSAPIObj->getInitSelector());
if (Init && Result == AR_Available && MD->isClassMethod() &&
- MD->getSelector() == S.NSAPIObj->getNewSelector() &&
+ MD->getSelector() == S.ObjC().NSAPIObj->getNewSelector() &&
MD->definedInNSObject(S.getASTContext())) {
Result = Init->getAvailability(Message);
D = Init;
@@ -117,10 +151,9 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D,
/// whether we should emit a diagnostic for \c K and \c DeclVersion in
/// the context of \c Ctx. For example, we should emit an unavailable diagnostic
/// in a deprecated context, but not the other way around.
-static bool
-ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
- VersionTuple DeclVersion, Decl *Ctx,
- const NamedDecl *OffendingDecl) {
+static bool ShouldDiagnoseAvailabilityInContext(
+ Sema &S, AvailabilityResult K, VersionTuple DeclVersion,
+ const IdentifierInfo *DeclEnv, Decl *Ctx, const NamedDecl *OffendingDecl) {
assert(K != AR_Available && "Expected an unavailable declaration here!");
// If this was defined using CF_OPTIONS, etc. then ignore the diagnostic.
@@ -135,11 +168,26 @@ ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
}
}
+ // In HLSL, skip emitting diagnostic if the diagnostic mode is not set to
+ // strict (-fhlsl-strict-availability), or if the target is library and the
+ // availability is restricted to a specific environment/shader stage.
+ // For libraries the availability will be checked later in
+ // DiagnoseHLSLAvailability class once where the specific environment/shader
+ // stage of the caller is known.
+ if (S.getLangOpts().HLSL) {
+ if (!S.getLangOpts().HLSLStrictAvailability ||
+ (DeclEnv != nullptr &&
+ S.getASTContext().getTargetInfo().getTriple().getEnvironment() ==
+ llvm::Triple::EnvironmentType::Library))
+ return false;
+ }
+
// Checks if we should emit the availability diagnostic in the context of C.
auto CheckContext = [&](const Decl *C) {
if (K == AR_NotYetIntroduced) {
if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C))
- if (AA->getIntroduced() >= DeclVersion)
+ if (AA->getIntroduced() >= DeclVersion &&
+ AA->getEnvironment() == DeclEnv)
return true;
} else if (K == AR_Deprecated) {
if (C->isDeprecated())
@@ -187,13 +235,16 @@ ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K,
return true;
}
-static bool
-shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
- const VersionTuple &DeploymentVersion,
- const VersionTuple &DeclVersion) {
+static unsigned getAvailabilityDiagnosticKind(
+ const ASTContext &Context, const VersionTuple &DeploymentVersion,
+ const VersionTuple &DeclVersion, bool HasMatchingEnv) {
const auto &Triple = Context.getTargetInfo().getTriple();
VersionTuple ForceAvailabilityFromVersion;
switch (Triple.getOS()) {
+ // For iOS, emit the diagnostic even if -Wunguarded-availability is
+ // not specified for deployment targets >= to iOS 11 or equivalent or
+ // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
+ // later.
case llvm::Triple::IOS:
case llvm::Triple::TvOS:
ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11);
@@ -205,15 +256,26 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
case llvm::Triple::MacOSX:
ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
break;
+ // For HLSL, use diagnostic from HLSLAvailability group which
+ // are reported as errors by default and in strict diagnostic mode
+ // (-fhlsl-strict-availability) and as warnings in relaxed diagnostic
+ // mode (-Wno-error=hlsl-availability)
case llvm::Triple::ShaderModel:
- // Always enable availability diagnostics for shader models.
- return true;
+ return HasMatchingEnv ? diag::warn_hlsl_availability
+ : diag::warn_hlsl_availability_unavailable;
default:
- // New targets should always warn about availability.
- return Triple.getVendor() == llvm::Triple::Apple;
+ // New Apple targets should always warn about availability.
+ ForceAvailabilityFromVersion =
+ (Triple.getVendor() == llvm::Triple::Apple)
+ ? VersionTuple(/*Major=*/0, 0)
+ : VersionTuple(/*Major=*/(unsigned)-1, (unsigned)-1);
}
- return DeploymentVersion >= ForceAvailabilityFromVersion ||
- DeclVersion >= ForceAvailabilityFromVersion;
+ if (DeploymentVersion >= ForceAvailabilityFromVersion ||
+ DeclVersion >= ForceAvailabilityFromVersion)
+ return HasMatchingEnv ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability_unavailable_new;
+ return HasMatchingEnv ? diag::warn_unguarded_availability
+ : diag::warn_unguarded_availability_unavailable;
}
static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) {
@@ -343,10 +405,14 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
unsigned available_here_select_kind;
VersionTuple DeclVersion;
- if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl))
+ const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl);
+ const IdentifierInfo *IIEnv = nullptr;
+ if (AA) {
DeclVersion = AA->getIntroduced();
+ IIEnv = AA->getEnvironment();
+ }
- if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx,
+ if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, IIEnv, Ctx,
OffendingDecl))
return;
@@ -354,8 +420,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
// The declaration can have multiple availability attributes, we are looking
// at one of them.
- const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl);
- if (A && A->isInherited()) {
+ if (AA && AA->isInherited()) {
for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl;
Redecl = Redecl->getPreviousDecl()) {
const AvailabilityAttr *AForRedecl =
@@ -375,26 +440,38 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
// not specified for deployment targets >= to iOS 11 or equivalent or
// for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
// later.
- const AvailabilityAttr *AA =
- getAttrForPlatform(S.getASTContext(), OffendingDecl);
+ assert(AA != nullptr && "expecting valid availability attribute");
VersionTuple Introduced = AA->getIntroduced();
-
- bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
+ bool EnvironmentMatchesOrNone =
+ hasMatchingEnvironmentOrNone(S.getASTContext(), AA);
+
+ const TargetInfo &TI = S.getASTContext().getTargetInfo();
+ std::string PlatformName(
+ AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
+ llvm::StringRef TargetEnvironment(
+ llvm::Triple::getEnvironmentTypeName(TI.getTriple().getEnvironment()));
+ llvm::StringRef AttrEnvironment =
+ AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
+ bool UseEnvironment =
+ (!AttrEnvironment.empty() && !TargetEnvironment.empty());
+
+ unsigned DiagKind = getAvailabilityDiagnosticKind(
S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
- Introduced);
- unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability;
-
- std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
- S.getASTContext().getTargetInfo().getPlatformName()));
+ Introduced, EnvironmentMatchesOrNone);
- S.Diag(Loc, Warning) << OffendingDecl << PlatformName
- << Introduced.getAsString();
+ S.Diag(Loc, DiagKind) << OffendingDecl << PlatformName
+ << Introduced.getAsString() << UseEnvironment
+ << TargetEnvironment;
S.Diag(OffendingDecl->getLocation(),
diag::note_partial_availability_specified_here)
<< OffendingDecl << PlatformName << Introduced.getAsString()
- << S.Context.getTargetInfo().getPlatformMinVersion().getAsString();
+ << S.Context.getTargetInfo().getPlatformMinVersion().getAsString()
+ << UseEnvironment << AttrEnvironment << TargetEnvironment;
+
+ // Do not offer to silence the warning or fixits for HLSL
+ if (S.getLangOpts().HLSL)
+ return;
if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) {
if (const auto *TD = dyn_cast<TagDecl>(Enclosing))
@@ -771,40 +848,48 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
const AvailabilityAttr *AA =
getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl);
+ assert(AA != nullptr && "expecting valid availability attribute");
+ bool EnvironmentMatchesOrNone =
+ hasMatchingEnvironmentOrNone(SemaRef.getASTContext(), AA);
VersionTuple Introduced = AA->getIntroduced();
- if (AvailabilityStack.back() >= Introduced)
+ if (EnvironmentMatchesOrNone && AvailabilityStack.back() >= Introduced)
return;
// If the context of this function is less available than D, we should not
// emit a diagnostic.
- if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx,
+ if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced,
+ AA->getEnvironment(), Ctx,
OffendingDecl))
return;
- // We would like to emit the diagnostic even if -Wunguarded-availability is
- // not specified for deployment targets >= to iOS 11 or equivalent or
- // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or
- // later.
- unsigned DiagKind =
- shouldDiagnoseAvailabilityByDefault(
- SemaRef.Context,
- SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced)
- ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability;
+ const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
+ std::string PlatformName(
+ AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
+ llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName());
+ llvm::StringRef AttrEnvironment =
+ AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
+ bool UseEnvironment =
+ (!AttrEnvironment.empty() && !TargetEnvironment.empty());
- std::string PlatformName(AvailabilityAttr::getPrettyPlatformName(
- SemaRef.getASTContext().getTargetInfo().getPlatformName()));
+ unsigned DiagKind = getAvailabilityDiagnosticKind(
+ SemaRef.Context,
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced,
+ EnvironmentMatchesOrNone);
SemaRef.Diag(Range.getBegin(), DiagKind)
- << Range << D << PlatformName << Introduced.getAsString();
+ << Range << D << PlatformName << Introduced.getAsString()
+ << UseEnvironment << TargetEnvironment;
SemaRef.Diag(OffendingDecl->getLocation(),
diag::note_partial_availability_specified_here)
<< OffendingDecl << PlatformName << Introduced.getAsString()
- << SemaRef.Context.getTargetInfo()
- .getPlatformMinVersion()
- .getAsString();
+ << SemaRef.Context.getTargetInfo().getPlatformMinVersion().getAsString()
+ << UseEnvironment << AttrEnvironment << TargetEnvironment;
+
+ // Do not offer to silence the warning or fixits for HLSL
+ if (SemaRef.getLangOpts().HLSL)
+ return;
auto FixitDiag =
SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence)
@@ -928,11 +1013,6 @@ void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) {
Stmt *Body = nullptr;
if (auto *FD = D->getAsFunction()) {
- // FIXME: We only examine the pattern decl for availability violations now,
- // but we should also examine instantiated templates.
- if (FD->isTemplateInstantiation())
- return;
-
Body = FD->getBody();
if (auto *CD = dyn_cast<CXXConstructorDecl>(FD))