llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang

@llvm/pr-subscribers-hlsl

Author: Helena Kotas (hekota)

<details>
<summary>Changes</summary>

Implements HLSL availability diagnostics' default and relaxed mode.

HLSL availability diagnostics emits errors or warning when unavailable shader 
APIs are used. Unavailable shader APIs are APIs that are exposed in HLSL code 
but are not available in the target shader stage or shader model version.

In the default mode the compiler emits an error when an unavailable API is 
found in a code that is reachable from the shader entry point function. In the 
future this check will also extended to exported library functions (#<!-- 
-->92073). The relaxed diagnostic mode is the same except the compiler emits a 
warning. This mode is enabled by ``-Wno-error=hlsl-availability``.

See HLSL Availability Diagnostics design doc 
[here](https://github.com/llvm/llvm-project/blob/main/clang/docs/HLSL/AvailabilityDiagnostics.rst)
 for more details.

Fixes #<!-- -->90095

---

Patch is 64.73 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/92704.diff


20 Files Affected:

- (modified) clang/include/clang/Basic/Attr.td (+52) 
- (modified) clang/include/clang/Basic/DiagnosticGroups.td (+3) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+7) 
- (modified) clang/include/clang/Sema/SemaHLSL.h (+1) 
- (modified) clang/lib/Sema/Sema.cpp (+4) 
- (modified) clang/lib/Sema/SemaAvailability.cpp (+12-2) 
- (modified) clang/lib/Sema/SemaHLSL.cpp (+296) 
- (added) clang/test/Sema/attr-availability-shadermodel-compute.hlsl (+68) 
- (added) clang/test/Sema/attr-availability-shadermodel-mesh.hlsl (+68) 
- (added) clang/test/Sema/attr-availability-shadermodel-pixel.hlsl (+61) 
- (added) clang/test/Sema/attr-availability-shadermodel.hlsl (+11) 
- (modified) clang/test/SemaHLSL/Availability/attr-availability-compute.hlsl 
(+5-10) 
- (modified) clang/test/SemaHLSL/Availability/attr-availability-mesh.hlsl 
(+5-10) 
- (modified) clang/test/SemaHLSL/Availability/attr-availability-pixel.hlsl 
(+2-4) 
- (added) clang/test/SemaHLSL/Availability/avail-diag-default-compute.hlsl 
(+98) 
- (added) clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl (+108) 
- (added) clang/test/SemaHLSL/Availability/avail-diag-relaxed-compute.hlsl 
(+98) 
- (added) clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl (+108) 
- (added) clang/test/SemaHLSL/Availability/avail-lib-multiple-stages.hlsl (+57) 
- (modified) clang/test/SemaHLSL/WaveBuiltinAvailability.hlsl (+5-4) 


``````````diff
diff --git a/clang/include/clang/Basic/Attr.td 
b/clang/include/clang/Basic/Attr.td
index 7008bea483c87..e5c23d54ab826 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1068,11 +1068,37 @@ static llvm::StringRef 
getPrettyEnviromentName(llvm::StringRef Environment) {
              .Case("hull", "hull shader")
              .Case("domain", "domain shader")
              .Case("compute", "compute shader")
+             .Case("raygeneration", "ray generation shader")
+             .Case("intersection", "intersection shader")
+             .Case("anyhit", "anyhit shader")
+             .Case("closesthit", "closesthit shader")
+             .Case("miss", "miss shader")
+             .Case("callable", "callable shader")
              .Case("mesh", "mesh shader")
              .Case("amplification", "amplification shader")
              .Case("library", "shader library")
              .Default(Environment);
 }
+static llvm::StringRef getEnvironmentString(llvm::Triple::EnvironmentType 
EnvironmentType) {
+  switch (EnvironmentType) {
+    case llvm::Triple::EnvironmentType::Pixel: return "pixel";
+    case llvm::Triple::EnvironmentType::Vertex: return "vertex";
+    case llvm::Triple::EnvironmentType::Geometry: return "geometry";
+    case llvm::Triple::EnvironmentType::Hull: return "hull";
+    case llvm::Triple::EnvironmentType::Domain: return "domain";
+    case llvm::Triple::EnvironmentType::Compute: return "compute";
+    case llvm::Triple::EnvironmentType::RayGeneration: return "ray generation";
+    case llvm::Triple::EnvironmentType::Intersection: return "intersection";
+    case llvm::Triple::EnvironmentType::AnyHit: return "any hit";
+    case llvm::Triple::EnvironmentType::ClosestHit: return "closest hit";
+    case llvm::Triple::EnvironmentType::Miss: return "miss";
+    case llvm::Triple::EnvironmentType::Callable: return "callable";
+    case llvm::Triple::EnvironmentType::Mesh: return "mesh";
+    case llvm::Triple::EnvironmentType::Amplification: return "amplification";
+    case llvm::Triple::EnvironmentType::Library: return "library";
+    default: return "";
+  }
+}
 static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef 
Environment) {
     return llvm::StringSwitch<llvm::Triple::EnvironmentType>(Environment)
              .Case("pixel", llvm::Triple::Pixel)
@@ -1081,6 +1107,12 @@ static llvm::Triple::EnvironmentType 
getEnvironmentType(llvm::StringRef Environm
              .Case("hull", llvm::Triple::Hull)
              .Case("domain", llvm::Triple::Domain)
              .Case("compute", llvm::Triple::Compute)
+             .Case("raygeneration", llvm::Triple::RayGeneration)
+             .Case("intersection", llvm::Triple::Intersection)
+             .Case("anyhit", llvm::Triple::AnyHit)
+             .Case("closesthit", llvm::Triple::ClosestHit)
+             .Case("miss", llvm::Triple::Miss)
+             .Case("callable", llvm::Triple::Callable)
              .Case("mesh", llvm::Triple::Mesh)
              .Case("amplification", llvm::Triple::Amplification)
              .Case("library", llvm::Triple::Library)
@@ -4475,6 +4507,26 @@ def HLSLShader : InheritableAttr {
                   "Miss", "Callable", "Mesh", "Amplification"]>
   ];
   let Documentation = [HLSLSV_ShaderTypeAttrDocs];
+  let AdditionalMembers =
+[{static llvm::Triple::EnvironmentType 
getTypeAsEnvironment(HLSLShaderAttr::ShaderType ShaderType) {
+    switch (ShaderType) {
+      case HLSLShaderAttr::Pixel:         return 
llvm::Triple::EnvironmentType::Pixel;
+      case HLSLShaderAttr::Vertex:        return 
llvm::Triple::EnvironmentType::Vertex;
+      case HLSLShaderAttr::Geometry:      return 
llvm::Triple::EnvironmentType::Geometry;
+      case HLSLShaderAttr::Hull:          return 
llvm::Triple::EnvironmentType::Hull;
+      case HLSLShaderAttr::Domain:        return 
llvm::Triple::EnvironmentType::Domain;
+      case HLSLShaderAttr::Compute:       return 
llvm::Triple::EnvironmentType::Compute;
+      case HLSLShaderAttr::RayGeneration: return 
llvm::Triple::EnvironmentType::RayGeneration;
+      case HLSLShaderAttr::Intersection:  return 
llvm::Triple::EnvironmentType::Intersection;
+      case HLSLShaderAttr::AnyHit:        return 
llvm::Triple::EnvironmentType::AnyHit;
+      case HLSLShaderAttr::ClosestHit:    return 
llvm::Triple::EnvironmentType::ClosestHit;
+      case HLSLShaderAttr::Miss:          return 
llvm::Triple::EnvironmentType::Miss;
+      case HLSLShaderAttr::Callable:      return 
llvm::Triple::EnvironmentType::Callable;
+      case HLSLShaderAttr::Mesh:          return 
llvm::Triple::EnvironmentType::Mesh;
+      case HLSLShaderAttr::Amplification: return 
llvm::Triple::EnvironmentType::Amplification;
+    }
+  }
+}];
 }
 
 def HLSLResource : InheritableAttr {
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index 4cb4f3d999f7a..f239198b5f090 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1515,6 +1515,9 @@ def HLSLMixPackOffset : DiagGroup<"mix-packoffset">;
 // Warnings for DXIL validation
 def DXILValidation : DiagGroup<"dxil-validation">;
 
+// Warning for HLSL API availability
+def HLSLAvailability : DiagGroup<"hlsl-availability">;
+
 // Warnings and notes related to const_var_decl_type attribute checks
 def ReadOnlyPlacementChecks : DiagGroup<"read-only-types">;
 
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e3b4186f1b06f..874e7ff187ee2 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12224,6 +12224,13 @@ def err_hlsl_param_qualifier_mismatch :
 def warn_hlsl_impcast_vector_truncation : Warning<
   "implicit conversion truncates vector: %0 to %1">, InGroup<Conversion>;
 
+def warn_hlsl_availability : Warning<
+  "%0 is only available %select{|in %4 environment }3on %1 %2 or newer">,
+  InGroup<HLSLAvailability>, DefaultError;
+def warn_hlsl_availability_unavailable :
+  Warning<err_unavailable.Summary>,
+  InGroup<HLSLAvailability>, DefaultError;
+
 // Layout randomization diagnostics.
 def err_non_designated_init_used : Error<
   "a randomized struct can only be initialized with a designated initializer">;
diff --git a/clang/include/clang/Sema/SemaHLSL.h 
b/clang/include/clang/Sema/SemaHLSL.h
index 34acaf19517f2..eac1f7c07c85d 100644
--- a/clang/include/clang/Sema/SemaHLSL.h
+++ b/clang/include/clang/Sema/SemaHLSL.h
@@ -49,6 +49,7 @@ class SemaHLSL : public SemaBase {
   void DiagnoseAttrStageMismatch(
       const Attr *A, HLSLShaderAttr::ShaderType Stage,
       std::initializer_list<HLSLShaderAttr::ShaderType> AllowedStages);
+  void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU);
 };
 
 } // namespace clang
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index f847c49920cf3..8ee40d3e0d0e4 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -1351,6 +1351,10 @@ void Sema::ActOnEndOfTranslationUnit() {
     Consumer.CompleteExternalDeclaration(D);
   }
 
+  if (LangOpts.HLSL)
+    HLSL().DiagnoseAvailabilityViolations(
+        getASTContext().getTranslationUnitDecl());
+
   // If there were errors, disable 'unused' warnings since they will mostly be
   // noise. Don't warn for a use from a module: either we should warn on all
   // file-scope declarations in modules or not at all, but whether the
diff --git a/clang/lib/Sema/SemaAvailability.cpp 
b/clang/lib/Sema/SemaAvailability.cpp
index 663b6f35b869d..e5cf3037aedef 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -15,6 +15,7 @@
 #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"
@@ -228,8 +229,9 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext 
&Context,
     ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
     break;
   case llvm::Triple::ShaderModel:
-    // Always enable availability diagnostics for shader models.
-    return true;
+    // FIXME: This will be updated when HLSL strict diagnostic mode
+    // is implemented (issue #90096)
+    return false;
   default:
     // New targets should always warn about availability.
     return Triple.getVendor() == llvm::Triple::Apple;
@@ -438,6 +440,10 @@ static void DoEmitAvailabilityWarning(Sema &S, 
AvailabilityResult K,
         << 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))
         if (TD->getDeclName().isEmpty()) {
@@ -865,6 +871,10 @@ void 
DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
         << 
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)
         << Range << D
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 6a12c417e2f3a..6e407cfc4e375 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -9,6 +9,9 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/Sema/SemaHLSL.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/Basic/DiagnosticSema.h"
 #include "clang/Basic/LLVM.h"
 #include "clang/Basic/TargetInfo.h"
@@ -16,6 +19,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/TargetParser/Triple.h"
 #include <iterator>
@@ -290,3 +294,295 @@ void SemaHLSL::DiagnoseAttrStageMismatch(
       << A << HLSLShaderAttr::ConvertShaderTypeToStr(Stage)
       << (AllowedStages.size() != 1) << join(StageStrings, ", ");
 }
+
+namespace {
+
+/// This class implements HLSL availability diagnostics for default
+/// and relaxed mode
+///
+/// The goal of this diagnostic is to emit an error or warning when an
+/// unavailable API is found in a code that is reachable from the shader
+/// entry function or from an exported function (when compiling shader
+/// library).
+///
+/// This is done by traversing the AST of all shader entry point functions
+/// and of all exported functions, and any functions that are refrenced
+/// from this AST. In other words, any function that are reachable from
+/// the entry points.
+class DiagnoseHLSLAvailability
+    : public RecursiveASTVisitor<DiagnoseHLSLAvailability> {
+  // HEKOTAS this is probably not needed
+  // typedef RecursiveASTVisitor<DiagnoseHLSLAvailability> Base;
+
+  Sema &SemaRef;
+
+  // Stack of functions to be scaned
+  llvm::SmallVector<const FunctionDecl *, 8> DeclsToScan;
+
+  // List of functions that were already scanned and in which environment.
+  //
+  // Maps FunctionDecl to a unsigned number that represents a set of shader
+  // environments the function has been scanned for.
+  // Since HLSLShaderAttr::ShaderType enum is generated from Attr.td and is
+  // defined without any assigned values, it is guaranteed to be numbered
+  // sequentially from 0 up and we can use it to 'index' individual bits
+  // in the set.
+  // The N'th bit in the set will be set if the function has been scanned
+  // in shader environment whose ShaderType integer value equals N.
+  // For example, if a function has been scanned in compute and pixel stage
+  // environment, the value will be 0x21 (100001 binary) because
+  // (int)HLSLShaderAttr::ShaderType::Pixel == 1 and
+  // (int)HLSLShaderAttr::ShaderType::Compute == 5.
+  llvm::DenseMap<const FunctionDecl *, unsigned> ScannedDecls;
+
+  // Do not access these directly, use the get/set methods below to make
+  // sure the values are in sync
+  llvm::Triple::EnvironmentType CurrentShaderEnvironment;
+  unsigned CurrentShaderStageBit;
+
+  // True if scanning a function that was already scanned in a different
+  // shader stage context, and therefore we should not report issues that
+  // depend only on shader model version because they would be duplicate.
+  bool ReportOnlyShaderStageIssues;
+
+  void SetShaderStageContext(HLSLShaderAttr::ShaderType ShaderType) {
+    assert((((unsigned)1) << (unsigned)ShaderType) != 0 &&
+           "ShaderType is too big for this bitmap");
+    CurrentShaderEnvironment = 
HLSLShaderAttr::getTypeAsEnvironment(ShaderType);
+    CurrentShaderStageBit = (1 << ShaderType);
+  }
+  void SetUnknownShaderStageContext() {
+    CurrentShaderEnvironment =
+        llvm::Triple::EnvironmentType::UnknownEnvironment;
+    CurrentShaderStageBit = (1 << 31);
+  }
+  llvm::Triple::EnvironmentType GetCurrentShaderEnvironment() {
+    return CurrentShaderEnvironment;
+  }
+  bool InUnknownShaderStageContext() {
+    return CurrentShaderEnvironment ==
+           llvm::Triple::EnvironmentType::UnknownEnvironment;
+  }
+
+  // Scanning methods
+  void HandleFunctionOrMethodRef(FunctionDecl *FD, Expr *RefExpr);
+  void CheckDeclAvailability(NamedDecl *D, const AvailabilityAttr *AA,
+                             SourceRange Range);
+  const AvailabilityAttr *FindAvailabilityAttr(const Decl *D);
+  bool HasMatchingEnvironmentOrNone(const AvailabilityAttr *AA);
+  bool WasAlreadyScannedInCurrentShaderStage(const FunctionDecl *FD,
+                                             bool *WasNeverScanned = nullptr);
+  void AddToScannedFunctions(const FunctionDecl *FD);
+
+public:
+  DiagnoseHLSLAvailability(Sema &SemaRef) : SemaRef(SemaRef) {}
+
+  // AST traversal methods
+  void RunOnTranslationUnit(const TranslationUnitDecl *TU);
+  void RunOnFunction(const FunctionDecl *FD);
+
+  bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+    FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(DRE->getDecl());
+    if (FD)
+      HandleFunctionOrMethodRef(FD, DRE);
+    return true;
+  }
+
+  bool VisitMemberExpr(MemberExpr *ME) {
+    FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(ME->getMemberDecl());
+    if (FD)
+      HandleFunctionOrMethodRef(FD, ME);
+    return true;
+  }
+};
+
+// Returns true if the function has already been scanned in the current
+// shader environment. WasNeverScanned will be set to true if the function
+// has never been scanned before for any shader environment.
+bool DiagnoseHLSLAvailability::WasAlreadyScannedInCurrentShaderStage(
+    const FunctionDecl *FD, bool *WasNeverScanned) {
+  const unsigned &ScannedStages = ScannedDecls.getOrInsertDefault(FD);
+  if (WasNeverScanned)
+    *WasNeverScanned = (ScannedStages == 0);
+  return ScannedStages & CurrentShaderStageBit;
+}
+
+// Marks the function as scanned in the current shader environment
+void DiagnoseHLSLAvailability::AddToScannedFunctions(const FunctionDecl *FD) {
+  unsigned &ScannedStages = ScannedDecls.getOrInsertDefault(FD);
+  ScannedStages |= CurrentShaderStageBit;
+}
+
+void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
+                                                         Expr *RefExpr) {
+  assert((isa<DeclRefExpr>(RefExpr) || isa<MemberExpr>(RefExpr)) &&
+         "expected DeclRefExpr or MemberExpr");
+
+  // has a definition -> add to stack to be scanned
+  const FunctionDecl *FDWithBody = nullptr;
+  if (FD->hasBody(FDWithBody)) {
+    if (!WasAlreadyScannedInCurrentShaderStage(FDWithBody))
+      DeclsToScan.push_back(FDWithBody);
+    return;
+  }
+
+  // no body -> diagnose availability
+  const AvailabilityAttr *AA = FindAvailabilityAttr(FD);
+  if (AA)
+    CheckDeclAvailability(
+        FD, AA, SourceRange(RefExpr->getBeginLoc(), RefExpr->getEndLoc()));
+}
+
+void DiagnoseHLSLAvailability::RunOnTranslationUnit(
+    const TranslationUnitDecl *TU) {
+  // Iterate over all shader entry functions and library exports, and for those
+  // that have a body (definiton), run diag scan on each, setting appropriate
+  // shader environment context based on whether it is a shader entry function
+  // or an exported function.
+  for (auto &D : TU->decls()) {
+    const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
+    if (!FD || !FD->isThisDeclarationADefinition())
+      continue;
+
+    // shader entry point
+    auto ShaderAttr = FD->getAttr<HLSLShaderAttr>();
+    if (ShaderAttr) {
+      SetShaderStageContext(ShaderAttr->getType());
+      RunOnFunction(FD);
+      continue;
+    }
+    // exported library function with definition
+    // FIXME: tracking issue #92073
+#if 0
+    if (FD->getFormalLinkage() == Linkage::External) {
+      SetUnknownShaderStageContext();
+      RunOnFunction(FD);
+    }
+#endif
+  }
+}
+
+void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
+  assert(DeclsToScan.empty() && "DeclsToScan should be empty");
+  DeclsToScan.push_back(FD);
+
+  while (!DeclsToScan.empty()) {
+    // Take one decl from the stack and check it by traversing its AST.
+    // For any CallExpr found during the traversal add it's callee to the top 
of
+    // the stack to be processed next. Functions already processed are stored 
in
+    // ScannedDecls.
+    const FunctionDecl *FD = DeclsToScan.back();
+    DeclsToScan.pop_back();
+
+    // Decl was already scanned
+    bool WasNeverScanned;
+    if (WasAlreadyScannedInCurrentShaderStage(FD, &WasNeverScanned))
+      continue;
+
+    ReportOnlyShaderStageIssues = !WasNeverScanned;
+
+    AddToScannedFunctions(FD);
+
+    Stmt *Body = FD->getBody();
+    assert(Body && "full definition with body expected here");
+
+    TraverseStmt(Body);
+  }
+}
+
+bool DiagnoseHLSLAvailability::HasMatchingEnvironmentOrNone(
+    const AvailabilityAttr *AA) {
+  IdentifierInfo *IIEnvironment = AA->getEnvironment();
+  if (!IIEnvironment)
+    return true;
+
+  llvm::Triple::EnvironmentType CurrentEnv = GetCurrentShaderEnvironment();
+  if (CurrentEnv == llvm::Triple::UnknownEnvironment)
+    return false;
+
+  llvm::Triple::EnvironmentType AttrEnv =
+      AvailabilityAttr::getEnvironmentType(IIEnvironment->getName());
+
+  return CurrentEnv == AttrEnv;
+}
+
+const AvailabilityAttr *
+DiagnoseHLSLAvailability::FindAvailabilityAttr(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.
+  for (const auto *A : D->attrs()) {
+    if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
+      StringRef AttrPlatform = Avail->getPlatform()->getName();
+      StringRef TargetPlatform =
+          SemaRef.getASTContext().getTargetInfo().getPlatformName();
+
+      // Match the platform name.
+      if (AttrPlatform == TargetPlatform) {
+        // Find the best matching attribute for this environment
+        if (HasMatchingEnvironmentOrNone(Avail))
+          return Avail;
+        PartialMatch = Avail;
+      }
+    }
+  }
+  return PartialMatch;
+}
+
+// Check availability against target shader model version and current shader
+// stage and emit diagnostic
+void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
+                                                     const AvailabilityAttr 
*AA,
+                                                     SourceRange Range) {
+  if (ReportOnlyShaderStageIssues && !AA->getEnvironment())
+    return;
+
+  bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
+  VersionTuple Introduced = AA->getIntroduced();
+  VersionTuple TargetVersion =
+      SemaRef.Context.getTargetInfo().getPlatformMinVersion();
+
+  if (TargetVersion >= Introduced && EnvironmentMatches)
+    return;
+
+  // Do not diagnose shade-stage-specific availability when the shader stage
+  // context is unknown
+  if (InUnknownShaderStageContext() && AA->getEnvironment() != nullptr) {
+    return;
+  }
+
+  // Emit diagnos...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/92704
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to