[clang] [HLSL] Strict Availability Diagnostics (PR #93860)
Helena Kotas via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 11 17:18:45 PDT 2024
https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/93860
>From 532f10f77c862f6d429366f0d6903773da8fa79b Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 30 May 2024 11:40:27 -0700
Subject: [PATCH 1/3] Implement HLSL strict diagnostic mode
---
clang/include/clang/Basic/Attr.td | 5 -
clang/include/clang/Basic/LangOptions.def | 2 +
clang/include/clang/Driver/Options.td | 9 ++
clang/lib/AST/DeclBase.cpp | 2 +-
clang/lib/Sema/SemaAvailability.cpp | 76 ++++++----
clang/lib/Sema/SemaHLSL.cpp | 54 +++++--
.../avail-diag-strict-compute.hlsl | 129 ++++++++++++++++
.../Availability/avail-diag-strict-lib.hlsl | 142 ++++++++++++++++++
8 files changed, 369 insertions(+), 50 deletions(-)
create mode 100644 clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl
create mode 100644 clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 2665b7353ca4a..6ac2e3b50ee54 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -1060,11 +1060,6 @@ static llvm::StringRef canonicalizePlatformName(llvm::StringRef Platform) {
.Case("ShaderModel", "shadermodel")
.Default(Platform);
}
-static llvm::StringRef getPrettyEnviromentName(llvm::Triple::EnvironmentType EnvironmentType) {
- if (EnvironmentType >= llvm::Triple::Pixel && EnvironmentType <= llvm::Triple::Amplification)
- return llvm::Triple::getEnvironmentTypeName(EnvironmentType);
- return "";
-}
static llvm::Triple::EnvironmentType getEnvironmentType(llvm::StringRef Environment) {
return llvm::StringSwitch<llvm::Triple::EnvironmentType>(Environment)
.Case("pixel", llvm::Triple::Pixel)
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 4061451b2150a..443b49d0e2779 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -276,6 +276,8 @@ LANGOPT(RenderScript , 1, 0, "RenderScript")
LANGOPT(HLSL, 1, 0, "HLSL")
ENUM_LANGOPT(HLSLVersion, HLSLLangStd, 16, HLSL_Unset, "HLSL Version")
+LANGOPT(HLSLStrictAvailability, 1, 0,
+ "Strict availability diagnostic mode for HLSL built-in functions.")
LANGOPT(CUDAIsDevice , 1, 0, "compiling for CUDA device")
LANGOPT(CUDAAllowVariadicFunctions, 1, 0, "allowing variadic functions in CUDA device code")
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 1637a114fcce1..cb380450d0425 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -196,6 +196,10 @@ def m_Group : OptionGroup<"<m group>">, Group<CompileOnly_Group>,
DocName<"Target-dependent compilation options">,
Visibility<[ClangOption, CLOption]>;
+def hlsl_Group : OptionGroup<"<HLSL group>">, Group<f_Group>,
+ DocName<"HLSL options">,
+ Visibility<[ClangOption]>;
+
// Feature groups - these take command line options that correspond directly to
// target specific features and can be translated directly from command line
// options.
@@ -7863,6 +7867,11 @@ def finclude_default_header : Flag<["-"], "finclude-default-header">,
def fdeclare_opencl_builtins : Flag<["-"], "fdeclare-opencl-builtins">,
HelpText<"Add OpenCL builtin function declarations (experimental)">;
+def fhlsl_strict_availability : Flag<["-"], "fhlsl-strict-availability">,
+ HelpText<"Enables strict availability diagnostic mode for HLSL built-in functions.">,
+ Group<hlsl_Group>,
+ MarshallingInfoFlag<LangOpts<"HLSLStrictAvailability">>;
+
def fpreserve_vec3_type : Flag<["-"], "fpreserve-vec3-type">,
HelpText<"Preserve 3-component vector type">,
MarshallingInfoFlag<CodeGenOpts<"PreserveVec3Type">>,
diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp
index ffb22194bce52..f481019eff51a 100644
--- a/clang/lib/AST/DeclBase.cpp
+++ b/clang/lib/AST/DeclBase.cpp
@@ -669,7 +669,7 @@ static AvailabilityResult CheckAvailability(ASTContext &Context,
IdentifierInfo *IIEnv = A->getEnvironment();
StringRef TargetEnv =
Context.getTargetInfo().getTriple().getEnvironmentName();
- StringRef EnvName = AvailabilityAttr::getPrettyEnviromentName(
+ StringRef EnvName = llvm::Triple::getEnvironmentTypeName(
Context.getTargetInfo().getTriple().getEnvironment());
// Matching environment or no environment on attribute
if (!IIEnv || (!TargetEnv.empty() && IIEnv->getName() == TargetEnv)) {
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index 330cd602297d4..0e448c8b13985 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -229,9 +229,7 @@ shouldDiagnoseAvailabilityByDefault(const ASTContext &Context,
ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13);
break;
case llvm::Triple::ShaderModel:
- // FIXME: This will be updated when HLSL strict diagnostic mode
- // is implemented (issue #90096)
- return false;
+ return Context.getLangOpts().HLSLStrictAvailability;
default:
// New targets should always warn about availability.
return Triple.getVendor() == llvm::Triple::Apple;
@@ -410,13 +408,10 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
const TargetInfo &TI = S.getASTContext().getTargetInfo();
std::string PlatformName(
AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
- llvm::StringRef TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName(
- TI.getTriple().getEnvironment()));
+ llvm::StringRef TargetEnvironment(
+ llvm::Triple::getEnvironmentTypeName(TI.getTriple().getEnvironment()));
llvm::StringRef AttrEnvironment =
- AA->getEnvironment() ? AvailabilityAttr::getPrettyEnviromentName(
- AvailabilityAttr::getEnvironmentType(
- AA->getEnvironment()->getName()))
- : "";
+ AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
bool UseEnvironment =
(!AttrEnvironment.empty() && !TargetEnvironment.empty());
@@ -834,34 +829,55 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
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.
- bool UseNewDiagKind = shouldDiagnoseAvailabilityByDefault(
- SemaRef.Context,
- SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced);
-
const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
+
+ // In HLSL, emit diagnostic here during parsing only if the diagnostic
+ // mode is set to strict (-fhlsl-strict-availability), and either the decl
+ // availability is not restricted to a specific environment/shader stage,
+ // or the target stage is known (= it is not shader library).
+ const LangOptions &LandOpts = SemaRef.getLangOpts();
+ if (LandOpts.HLSL) {
+ if (!LandOpts.HLSLStrictAvailability ||
+ (AA->getEnvironment() != nullptr &&
+ TI.getTriple().getEnvironment() ==
+ llvm::Triple::EnvironmentType::Library))
+ return;
+ }
+
std::string PlatformName(
AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
- llvm::StringRef TargetEnvironment(AvailabilityAttr::getPrettyEnviromentName(
- TI.getTriple().getEnvironment()));
+ llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName());
llvm::StringRef AttrEnvironment =
- AA->getEnvironment() ? AvailabilityAttr::getPrettyEnviromentName(
- AvailabilityAttr::getEnvironmentType(
- AA->getEnvironment()->getName()))
- : "";
+ AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
bool UseEnvironment =
(!AttrEnvironment.empty() && !TargetEnvironment.empty());
- unsigned DiagKind =
- EnvironmentMatchesOrNone
- ? (UseNewDiagKind ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability)
- : (UseNewDiagKind
- ? diag::warn_unguarded_availability_unavailable_new
- : diag::warn_unguarded_availability_unavailable);
+ unsigned DiagKind;
+ if (SemaRef.getLangOpts().HLSL) {
+ // For HLSL, use diagnostic from HLSLAvailability group which
+ // are reported as errors in default and in strict diagnostic mode
+ // (-fhlsl-strict-availability) and as warnings in relaxed diagnostic
+ // mode (-Wno-error=hlsl-availability)
+ DiagKind = EnvironmentMatchesOrNone
+ ? diag::warn_hlsl_availability
+ : diag::warn_hlsl_availability_unavailable;
+
+ } else {
+ // 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.
+ bool UseNewDiagKind = shouldDiagnoseAvailabilityByDefault(
+ SemaRef.Context,
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced);
+
+ DiagKind = EnvironmentMatchesOrNone
+ ? (UseNewDiagKind ? diag::warn_unguarded_availability_new
+ : diag::warn_unguarded_availability)
+ : (UseNewDiagKind
+ ? diag::warn_unguarded_availability_unavailable_new
+ : diag::warn_unguarded_availability_unavailable);
+ }
SemaRef.Diag(Range.getBegin(), DiagKind)
<< Range << D << PlatformName << Introduced.getAsString()
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 9e614ae99f37d..87a6043a064c7 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -306,7 +306,7 @@ namespace {
/// 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
+/// and of all exported functions, and any functions that are referenced
/// from this AST. In other words, any functions that are reachable from
/// the entry points.
class DiagnoseHLSLAvailability
@@ -536,9 +536,34 @@ DiagnoseHLSLAvailability::FindAvailabilityAttr(const Decl *D) {
void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
const AvailabilityAttr *AA,
SourceRange Range) {
- if (ReportOnlyShaderStageIssues && !AA->getEnvironment())
- return;
+ IdentifierInfo *IIEnv = AA->getEnvironment();
+
+ if (!IIEnv) {
+ // The availability attribute does not have environment -> it depends only
+ // on shader model version and not on specific the shader stage.
+
+ // Skip emitting the diagnostics if the diagnostic mode is not set to
+ // strict (-fhlsl-strict-availability) because all relevant diagnostics
+ // were already emitted in the DiagnoseUnguardedAvailability scan
+ // (SemaAvailability.cpp).
+ if (SemaRef.getLangOpts().HLSLStrictAvailability)
+ return;
+
+ // Do not report shader-stage-independent issues if scanning a function
+ // that was already scanned in a different shader stage context (they would
+ // be duplicate)
+ if (ReportOnlyShaderStageIssues)
+ return;
+
+ } else {
+ // The availability attribute has environment -> we need to know
+ // the current stage context to property diagnose it.
+ if (InUnknownShaderStageContext())
+ return;
+ }
+
+ // Check introduced version and if environment matches
bool EnvironmentMatches = HasMatchingEnvironmentOrNone(AA);
VersionTuple Introduced = AA->getIntroduced();
VersionTuple TargetVersion =
@@ -547,24 +572,16 @@ void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
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 diagnostic message
const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
llvm::StringRef PlatformName(
AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
llvm::StringRef CurrentEnvStr =
- AvailabilityAttr::getPrettyEnviromentName(GetCurrentShaderEnvironment());
+ llvm::Triple::getEnvironmentTypeName(GetCurrentShaderEnvironment());
- llvm::StringRef AttrEnvStr = AA->getEnvironment()
- ? AvailabilityAttr::getPrettyEnviromentName(
- AvailabilityAttr::getEnvironmentType(
- AA->getEnvironment()->getName()))
- : "";
+ llvm::StringRef AttrEnvStr =
+ AA->getEnvironment() ? AA->getEnvironment()->getName() : "";
bool UseEnvironment = !AttrEnvStr.empty();
if (EnvironmentMatches) {
@@ -585,5 +602,14 @@ void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D,
} // namespace
void SemaHLSL::DiagnoseAvailabilityViolations(TranslationUnitDecl *TU) {
+ // Skip running the diagnostics scan if the diagnostic mode is
+ // strict (-fhlsl-strict-availability) and the target shader stage is known
+ // because all relevant diagnostics were already emitted in the
+ // DiagnoseUnguardedAvailability scan (SemaAvailability.cpp).
+ const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
+ if (SemaRef.getLangOpts().HLSLStrictAvailability &&
+ TI.getTriple().getEnvironment() != llvm::Triple::EnvironmentType::Library)
+ return;
+
DiagnoseHLSLAvailability(SemaRef).RunOnTranslationUnit(TU);
}
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl
new file mode 100644
index 0000000000000..b67e10c9a9017
--- /dev/null
+++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-compute.hlsl
@@ -0,0 +1,129 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute \
+// RUN: -fhlsl-strict-availability -fsyntax-only -verify %s
+
+__attribute__((availability(shadermodel, introduced = 6.5)))
+float fx(float); // #fx
+
+__attribute__((availability(shadermodel, introduced = 6.6)))
+half fx(half); // #fx_half
+
+__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel)))
+__attribute__((availability(shadermodel, introduced = 6.5, environment = compute)))
+float fy(float); // #fy
+
+__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel)))
+__attribute__((availability(shadermodel, introduced = 6.5, environment = mesh)))
+float fz(float); // #fz
+
+float also_alive(float f) {
+ // expected-error@#also_alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #also_alive_fx_call
+ // expected-error@#also_alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(f); // #also_alive_fy_call
+ // expected-error@#also_alive_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(f); // #also_alive_fz_call
+ return 0;
+}
+
+float alive(float f) {
+ // expected-error@#alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #alive_fx_call
+ // expected-error@#alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(f); // #alive_fy_call
+ // expected-error@#alive_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(f); // #alive_fz_call
+
+ return also_alive(f);
+}
+
+float also_dead(float f) {
+ // expected-error@#also_dead_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #also_dead_fx_call
+ // expected-error@#also_dead_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(f); // #also_dead_fy_call
+ // expected-error@#also_dead_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(f); // #also_dead_fz_call
+ return 0;
+}
+
+float dead(float f) {
+ // expected-error@#dead_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #dead_fx_call
+ // expected-error@#dead_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(f); // #dead_fy_call
+ // expected-error@#dead_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(f); // #dead_fz_call
+
+ return also_dead(f);
+}
+
+template<typename T>
+T aliveTemp(T f) {
+ // expected-error@#aliveTemp_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#aliveTemp_inst {{in instantiation of function template specialization 'aliveTemp<float>' requested here}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #aliveTemp_fx_call
+ // expected-error@#aliveTemp_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(f); // #aliveTemp_fy_call
+ // expected-error@#aliveTemp_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(f); // #aliveTemp_fz_call
+ return 0;
+}
+
+template<typename T> T aliveTemp2(T f) {
+ // expected-error@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.6 or newer}}
+ // expected-note@#fx_half {{'fx' has been marked as being introduced in Shader Model 6.6 here, but the deployment target is Shader Model 6.0}}
+ // expected-error@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ return fx(f); // #aliveTemp2_fx_call
+}
+
+half test(half x) {
+ return aliveTemp2(x); // expected-note {{in instantiation of function template specialization 'aliveTemp2<half>' requested here}}
+}
+
+float test(float x) {
+ return aliveTemp2(x); // expected-note {{in instantiation of function template specialization 'aliveTemp2<float>' requested here}}
+}
+
+class MyClass
+{
+ float F;
+ float makeF() {
+ // expected-error@#MyClass_makeF_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(F); // #MyClass_makeF_fx_call
+ // expected-error@#MyClass_makeF_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(F); // #MyClass_makeF_fy_call
+ // expected-error@#MyClass_makeF_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(F); // #MyClass_makeF_fz_call
+ }
+};
+
+[numthreads(4,1,1)]
+float main() {
+ float f = 3;
+ MyClass C = { 1.0f };
+ float a = alive(f);
+ float b = aliveTemp<float>(f); // #aliveTemp_inst
+ float c = C.makeF();
+ float d = test((float)1.0);
+ float e = test((half)1.0);
+ return a * b * c;
+}
\ No newline at end of file
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
new file mode 100644
index 0000000000000..4c9675051e570
--- /dev/null
+++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
@@ -0,0 +1,142 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library \
+// RUN: -fhlsl-strict-availability -fsyntax-only -verify %s
+
+__attribute__((availability(shadermodel, introduced = 6.5)))
+float fx(float); // #fx
+
+__attribute__((availability(shadermodel, introduced = 6.6)))
+half fx(half); // #fx_half
+
+__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel)))
+__attribute__((availability(shadermodel, introduced = 6.5, environment = compute)))
+float fy(float); // #fy
+
+__attribute__((availability(shadermodel, introduced = 5.0, environment = pixel)))
+__attribute__((availability(shadermodel, introduced = 6.5, environment = mesh)))
+float fz(float); // #fz
+
+// FIXME: all diagnostics marked as FUTURE will come alive when HLSL default
+// diagnostic mode is implemented in a future PR which will verify calls in
+// all functions that are reachable from the shader library entry points
+
+float also_alive(float f) {
+ // expected-error@#also_alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #also_alive_fx_call
+
+ // expected-error@#also_alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(f); // #also_alive_fy_call
+
+ // expected-error@#also_alive_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(f); // #also_alive_fz_call
+
+ return 0;
+}
+
+float alive(float f) {
+ // expected-error@#alive_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #alive_fx_call
+
+ // expected-error@#alive_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(f); // #alive_fy_call
+
+ // expected-error@#alive_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(f); // #alive_fz_call
+
+ return also_alive(f);
+}
+
+float also_dead(float f) {
+ // expected-error@#also_dead_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #also_dead_fx_call
+
+ // Call to environment-specific function from an unreachable function
+ // in a shader library - no diagnostic expected.
+ float B = fy(f); // #also_dead_fy_call
+
+ // Call to environment-specific function from an unreachable function
+ // in a shader library - no diagnostic expected.
+ float C = fz(f); // #also_dead_fz_call
+ return 0;
+}
+
+float dead(float f) {
+ // expected-error@#dead_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #dead_fx_call
+
+ // Call to environment-specific function from an unreachable function
+ // in a shader library - no diagnostic expected.
+ float B = fy(f); // #dead_fy_call
+
+ // Call to environment-specific function from an unreachable function
+ // in a shader library - no diagnostic expected.
+ float C = fz(f); // #dead_fz_call
+
+ return also_dead(f);
+}
+
+template<typename T>
+T aliveTemp(T f) {
+ // expected-error@#aliveTemp_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#aliveTemp_inst {{in instantiation of function template specialization 'aliveTemp<float>' requested here}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(f); // #aliveTemp_fx_call
+ // expected-error@#aliveTemp_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(f); // #aliveTemp_fy_call
+ // expected-error@#aliveTemp_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(f); // #aliveTemp_fz_call
+ return 0;
+}
+
+template<typename T> T aliveTemp2(T f) {
+ // expected-error@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.6 or newer}}
+ // expected-note@#fx_half {{'fx' has been marked as being introduced in Shader Model 6.6 here, but the deployment target is Shader Model 6.0}}
+ // expected-error@#aliveTemp2_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ return fx(f); // #aliveTemp2_fx_call
+}
+
+half test(half x) {
+ return aliveTemp2(x); // expected-note {{in instantiation of function template specialization 'aliveTemp2<half>' requested here}}
+}
+
+float test(float x) {
+ return aliveTemp2(x); // expected-note {{in instantiation of function template specialization 'aliveTemp2<float>' requested here}}
+}
+
+class MyClass
+{
+ float F;
+ float makeF() {
+ // expected-error@#MyClass_makeF_fx_call {{'fx' is only available on Shader Model 6.5 or newer}}
+ // expected-note@#fx {{'fx' has been marked as being introduced in Shader Model 6.5 here, but the deployment target is Shader Model 6.0}}
+ float A = fx(F); // #MyClass_makeF_fx_call
+ // expected-error@#MyClass_makeF_fy_call {{'fy' is only available in compute environment on Shader Model 6.5 or newer}}
+ // expected-note@#fy {{'fy' has been marked as being introduced in Shader Model 6.5 in compute environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float B = fy(F); // #MyClass_makeF_fy_call
+ // expected-error@#MyClass_makeF_fz_call {{'fz' is unavailable}}
+ // expected-note@#fz {{'fz' has been marked as being introduced in Shader Model 6.5 in mesh environment here, but the deployment target is Shader Model 6.0 compute environment}}
+ float C = fz(F); // #MyClass_makeF_fz_call
+ }
+};
+
+[shader("compute")]
+[numthreads(4,1,1)]
+float main() {
+ float f = 3;
+ MyClass C = { 1.0f };
+ float a = alive(f);float b = aliveTemp<float>(f); // #aliveTemp_inst
+ float c = C.makeF();
+ float d = test((float)1.0);
+ float e = test((half)1.0);
+ return a * b * c;
+}
\ No newline at end of file
>From 33c54e453f978943154f121e29a3c863f0b83e06 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 3 Jun 2024 12:05:14 -0700
Subject: [PATCH 2/3] Move check to ShouldDiagnoseAvailabilityInContext
---
clang/lib/Sema/SemaAvailability.cpp | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index 0e448c8b13985..3eaf25709e91a 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -157,6 +157,18 @@ static bool ShouldDiagnoseAvailabilityInContext(
}
}
+ // In HLSL, emit diagnostic during parsing only if the diagnostic
+ // mode is set to strict (-fhlsl-strict-availability), and either the decl
+ // availability is not restricted to a specific environment/shader stage,
+ // or the target stage is known (= it is not shader library).
+ 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) {
@@ -830,20 +842,6 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
return;
const TargetInfo &TI = SemaRef.getASTContext().getTargetInfo();
-
- // In HLSL, emit diagnostic here during parsing only if the diagnostic
- // mode is set to strict (-fhlsl-strict-availability), and either the decl
- // availability is not restricted to a specific environment/shader stage,
- // or the target stage is known (= it is not shader library).
- const LangOptions &LandOpts = SemaRef.getLangOpts();
- if (LandOpts.HLSL) {
- if (!LandOpts.HLSLStrictAvailability ||
- (AA->getEnvironment() != nullptr &&
- TI.getTriple().getEnvironment() ==
- llvm::Triple::EnvironmentType::Library))
- return;
- }
-
std::string PlatformName(
AvailabilityAttr::getPrettyPlatformName(TI.getPlatformName()));
llvm::StringRef TargetEnvironment(TI.getTriple().getEnvironmentName());
>From 78a02c7285a9e7aa7e1bc0ebb0533a34e2e1f4f1 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Tue, 11 Jun 2024 17:18:08 -0700
Subject: [PATCH 3/3] Code review feedback
---
clang/lib/Sema/SemaAvailability.cpp | 74 ++++++++++++-----------------
1 file changed, 30 insertions(+), 44 deletions(-)
diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp
index 3eaf25709e91a..f6aa8145fc153 100644
--- a/clang/lib/Sema/SemaAvailability.cpp
+++ b/clang/lib/Sema/SemaAvailability.cpp
@@ -222,13 +222,16 @@ static bool ShouldDiagnoseAvailabilityInContext(
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);
@@ -240,14 +243,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:
- return Context.getLangOpts().HLSLStrictAvailability;
+ 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) {
@@ -427,16 +442,9 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
bool UseEnvironment =
(!AttrEnvironment.empty() && !TargetEnvironment.empty());
- bool UseNewWarning = shouldDiagnoseAvailabilityByDefault(
+ unsigned DiagKind = getAvailabilityDiagnosticKind(
S.Context, S.Context.getTargetInfo().getPlatformMinVersion(),
- Introduced);
-
- unsigned DiagKind =
- EnvironmentMatchesOrNone
- ? (UseNewWarning ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability)
- : (UseNewWarning ? diag::warn_unguarded_availability_unavailable_new
- : diag::warn_unguarded_availability_unavailable);
+ Introduced, EnvironmentMatchesOrNone);
S.Diag(Loc, DiagKind) << OffendingDecl << PlatformName
<< Introduced.getAsString() << UseEnvironment
@@ -850,32 +858,10 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability(
bool UseEnvironment =
(!AttrEnvironment.empty() && !TargetEnvironment.empty());
- unsigned DiagKind;
- if (SemaRef.getLangOpts().HLSL) {
- // For HLSL, use diagnostic from HLSLAvailability group which
- // are reported as errors in default and in strict diagnostic mode
- // (-fhlsl-strict-availability) and as warnings in relaxed diagnostic
- // mode (-Wno-error=hlsl-availability)
- DiagKind = EnvironmentMatchesOrNone
- ? diag::warn_hlsl_availability
- : diag::warn_hlsl_availability_unavailable;
-
- } else {
- // 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.
- bool UseNewDiagKind = shouldDiagnoseAvailabilityByDefault(
- SemaRef.Context,
- SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced);
-
- DiagKind = EnvironmentMatchesOrNone
- ? (UseNewDiagKind ? diag::warn_unguarded_availability_new
- : diag::warn_unguarded_availability)
- : (UseNewDiagKind
- ? diag::warn_unguarded_availability_unavailable_new
- : diag::warn_unguarded_availability_unavailable);
- }
+ unsigned DiagKind = getAvailabilityDiagnosticKind(
+ SemaRef.Context,
+ SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced,
+ EnvironmentMatchesOrNone);
SemaRef.Diag(Range.getBegin(), DiagKind)
<< Range << D << PlatformName << Introduced.getAsString()
More information about the cfe-commits
mailing list