[clang] [HLSL] Run availability diagnostic on exported functions (PR #97352)

Helena Kotas via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 1 14:37:59 PDT 2024


https://github.com/hekota created https://github.com/llvm/llvm-project/pull/97352

Implements availability diagnostic on `export` functions. 

For shader libraries the HLSL availability diagnostic should run on all entry points and export functions. Now that the `export` keyword is implemented, we can detect which functions are exported and run the diagnostic on them.

Exported functions can be nested in namespaces and in export declarations so we need to scan not just the current translation unit but also namespace and export declarations contexts.

Fixes #92073

>From b67ecd20cc2c11f4f99c2d90c95fdbd988659947 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Wed, 26 Jun 2024 12:31:39 -0700
Subject: [PATCH 1/4] [HLSL] Implement `export` keyword

Fixes #92812
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 ++
 clang/lib/Parse/ParseDeclCXX.cpp              |  8 +++
 clang/lib/Parse/Parser.cpp                    |  2 +-
 clang/lib/Sema/SemaModule.cpp                 | 32 ++++++++++++
 clang/test/AST/HLSL/export.hlsl               | 23 +++++++++
 clang/test/CodeGenHLSL/export.hlsl            | 20 ++++++++
 clang/test/SemaHLSL/export.hlsl               | 50 +++++++++++++++++++
 7 files changed, 137 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/AST/HLSL/export.hlsl
 create mode 100644 clang/test/CodeGenHLSL/export.hlsl
 create mode 100644 clang/test/SemaHLSL/export.hlsl

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 25a87078a5709..a2465ecc936e0 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12265,6 +12265,9 @@ def warn_hlsl_availability_unavailable :
   Warning<err_unavailable.Summary>,
   InGroup<HLSLAvailability>, DefaultError;
 
+def err_hlsl_export_not_on_function : Error<
+  "export declaration can only be used on functions">;
+
 // 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/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 5e3ee5f0579aa..226377e93fe56 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -445,6 +445,14 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
 ///         'export' declaration
 ///         'export' '{' declaration-seq[opt] '}'
 ///
+/// HLSL: Parse export function declaration.
+///
+///      export-function-declaration: 
+///         'export' function-declaration
+/// 
+///      export-declaration-group:
+///         'export' '{' function-declaration-seq[opt] '}'
+///
 Decl *Parser::ParseExportDeclaration() {
   assert(Tok.is(tok::kw_export));
   SourceLocation ExportLoc = ConsumeToken();
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 6d0cf7b174e50..ddc8aa9b49e64 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -970,7 +970,7 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
     SingleDecl = ParseModuleImport(SourceLocation(), IS);
   } break;
   case tok::kw_export:
-    if (getLangOpts().CPlusPlusModules) {
+    if (getLangOpts().CPlusPlusModules || getLangOpts().HLSL) {
       ProhibitAttributes(Attrs);
       SingleDecl = ParseExportDeclaration();
       break;
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index ad118ac90e4aa..e920b880ecb4d 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -851,6 +851,21 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
   CurContext->addDecl(D);
   PushDeclContext(S, D);
 
+  if (getLangOpts().HLSL) {
+    // exported functions cannot be in an unnamed namespace
+    for (const DeclContext *DC = CurContext; DC; DC = DC->getLexicalParent()) {
+      if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) {
+        if (ND->isAnonymousNamespace()) {
+          Diag(ExportLoc, diag::err_export_within_anonymous_namespace);
+          Diag(ND->getLocation(), diag::note_anonymous_namespace);
+          D->setInvalidDecl();
+          return D;
+        }
+      }
+    }
+    return D;
+  }
+
   // C++2a [module.interface]p1:
   //   An export-declaration shall appear only [...] in the purview of a module
   //   interface unit. An export-declaration shall not appear directly or
@@ -924,6 +939,23 @@ static bool checkExportedDeclContext(Sema &S, DeclContext *DC,
 /// Check that it's valid to export \p D.
 static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
 
+  // HLSL: export declaration is valid only on functions
+  if (S.getLangOpts().HLSL) {
+    auto *FD = dyn_cast<FunctionDecl>(D);
+    if (!FD) {
+      if (auto *ED2 = dyn_cast<ExportDecl>(D)) {
+        S.Diag(ED2->getBeginLoc(), diag::err_export_within_export);
+        if (auto *ED1 = dyn_cast<ExportDecl>(D->getDeclContext()))
+          S.Diag(ED1->getBeginLoc(), diag::note_export);
+      }
+      else {
+        S.Diag(D->getBeginLoc(), diag::err_hlsl_export_not_on_function);
+      }
+      D->setInvalidDecl();
+      return false;
+    }
+  }
+
   //  C++20 [module.interface]p3:
   //   [...] it shall not declare a name with internal linkage.
   bool HasName = false;
diff --git a/clang/test/AST/HLSL/export.hlsl b/clang/test/AST/HLSL/export.hlsl
new file mode 100644
index 0000000000000..69c4fb2b457ac
--- /dev/null
+++ b/clang/test/AST/HLSL/export.hlsl
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -x hlsl -ast-dump -o - %s | FileCheck %s
+
+// CHECK:ExportDecl 0x{{[0-9a-f]+}} <{{.*}}> col:1
+// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> col:13 used f1 'void ()'
+// CHECK:CompoundStmt 0x{{[0-9a-f]+}} <{{.*}}>
+export void f1() {}
+
+// CHECK:NamespaceDecl 0x{{[0-9a-f]+}} <{{.*}}>
+// CHECK:ExportDecl 0x{{[0-9a-f]+}} <{{.*}}> col:3
+// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> col:15 used f2 'void ()'
+// CHECK:CompoundStmt 0x{{[0-9a-f]+}} <{{.*}}>
+namespace MyNamespace {
+  export void f2() {}
+}
+
+// CHECK:ExportDecl 0x{{[0-9a-f]+}} <{{.*}}>
+// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> col:10 used f3 'void ()'
+// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> col:10 used f4 'void ()'
+// CHECK:CompoundStmt 0x{{[0-9a-f]+}} <{{.*}}>
+export {
+    void f3() {}
+    void f4() {}
+}
diff --git a/clang/test/CodeGenHLSL/export.hlsl b/clang/test/CodeGenHLSL/export.hlsl
new file mode 100644
index 0000000000000..cea8875684b9e
--- /dev/null
+++ b/clang/test/CodeGenHLSL/export.hlsl
@@ -0,0 +1,20 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN:   dxil-pc-shadermodel6.3-library %s \
+// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
+
+// CHECK: define void @"?f1@@YAXXZ"()
+export void f1() {
+}
+
+// CHECK: define void @"?f2 at MyNamespace@@YAXXZ"()
+namespace MyNamespace {
+  export void f2() {
+  }
+}
+
+export {
+// CHECK: define void @"?f3@@YAXXZ"()
+// CHECK: define void @"?f4@@YAXXZ"()    
+    void f3() {}
+    void f4() {}
+}
\ No newline at end of file
diff --git a/clang/test/SemaHLSL/export.hlsl b/clang/test/SemaHLSL/export.hlsl
new file mode 100644
index 0000000000000..0cb9248f3f589
--- /dev/null
+++ b/clang/test/SemaHLSL/export.hlsl
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify
+
+export void f1();
+
+export void f1() {}
+
+namespace { // expected-note {{anonymous namespace begins here}}
+    export void f2(); // expected-error {{export declaration appears within anonymous namespace}}
+}
+
+export void f3();
+
+export { // expected-note {{export block begins here}}
+    void f4() {}
+    export void f5() {} // expected-error {{export declaration appears within another export declaration}}
+    int A; // expected-error {{export declaration can only be used on functions}}
+    namespace ns { // expected-error {{export declaration can only be used on functions}}
+        void f6();
+    }
+}
+
+void export f7() {} // expected-error {{expected unqualified-id}}
+
+export static void f8() {} // expected-error {{declaration of 'f8' with internal linkage cannot be exported}}
+
+export void f9(); // expected-note {{previous declaration is here}}
+static void f9(); // expected-error {{static declaration of 'f9' follows non-static declaration}}
+
+static void f10(); // expected-note {{previous declaration is here}}
+export void f10(); // expected-error {{cannot export redeclaration 'f10' here since the previous declaration has internal linkage}}
+
+export float V1; // expected-error {{export declaration can only be used on functions}}
+
+static export float V2; // expected-error{{expected unqualified-id}}
+
+export static float V3 = 0; // expected-error {{export declaration can only be used on functions}}
+
+export groupshared float V4; // expected-error {{export declaration can only be used on functions}}
+
+void f6() {
+  export int i;  // expected-error {{expected expression}}
+}
+
+export cbuffer CB { // expected-error {{export declaration can only be used on functions}}
+    int a;
+}
+
+export template<typename T> void tf1(T t) {} // expected-error {{export declaration can only be used on functions}}
+
+void f5() export {} // expected-error {{expected function body after function declarator}}
\ No newline at end of file

>From 3edca8f3cecfd5a5ba269e97cb1e60f3c55eae5c Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Thu, 27 Jun 2024 17:16:24 -0700
Subject: [PATCH 2/4] Add availability diagnostic for export library functions

Fixes #92073
---
 clang/lib/Sema/SemaHLSL.cpp                   | 57 ++++++++++++-------
 .../Availability/avail-diag-default-lib.hlsl  | 50 ++++++++++++++++
 .../Availability/avail-diag-relaxed-lib.hlsl  | 32 +++++++++++
 .../Availability/avail-diag-strict-lib.hlsl   | 50 ++++++++++++++++
 4 files changed, 168 insertions(+), 21 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index cc9c259858148..0b316e658fce3 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -679,30 +679,46 @@ void DiagnoseHLSLAvailability::HandleFunctionOrMethodRef(FunctionDecl *FD,
 
 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;
+  // or an exported function. Exported functions can be in namespaces and in
+  // export declarations so we need to scan those declaration contexts as well.
+  llvm::SmallVector<const DeclContext*, 8> DeclContextsToScan;
+  DeclContextsToScan.push_back(TU);
+
+  while (!DeclContextsToScan.empty()) {
+    const DeclContext* DC = DeclContextsToScan.pop_back_val();
+    for (auto &D : DC->decls()) {
+      // do not scan implicit declaration generated by the implementation
+      if (D->isImplicit())
+        continue;
+
+      // namespace or export declaration - add to the list to be scanned later
+      if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
+        DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
+        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);
+      // skip over other decls or function decls without body
+      const FunctionDecl *FD = llvm::dyn_cast<FunctionDecl>(D);
+      if (!FD || !FD->isThisDeclarationADefinition())
+        continue;
+
+      // shader entry point
+      if (HLSLShaderAttr *ShaderAttr = FD->getAttr<HLSLShaderAttr>()) {
+        SetShaderStageContext(ShaderAttr->getType());
+        RunOnFunction(FD);
+        continue;
+      }
+      // exported library function
+      if (FD->isInExportDeclContext()) {
+        SetUnknownShaderStageContext();
+        RunOnFunction(FD);
+        continue;
+      }
     }
-#endif
   }
 }
 
@@ -715,8 +731,7 @@ void DiagnoseHLSLAvailability::RunOnFunction(const FunctionDecl *FD) {
     // 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();
+    const FunctionDecl *FD = DeclsToScan.pop_back_val();
 
     // Decl was already scanned
     const unsigned ScannedStages = GetScannedStages(FD);
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
index 515e4c5f9df03..19b06832c2218 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
@@ -110,6 +110,55 @@ class MyClass
   }
 };
 
+// Exported function without body
+export void exportedFunctionUnused(float f);
+
+// Exported function with body - not used
+export void exportedFunctionUnused(float f) {
+  // expected-error@#exportedFunctionUnused_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); // #exportedFunctionUnused_fx_call
+
+  // API with shader-stage-specific availability in unused exported library function
+  // - no errors expected because the actual shader stage this function
+  // will be used in not known at this time
+  float B = fy(f);
+  float C = fz(f);
+}
+
+// Exported function with body - called from main() which is a compute shader entry point
+export void exportedFunctionUsed(float f) {
+  // expected-error@#exportedFunctionUsed_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); // #exportedFunctionUsed_fx_call
+
+  // expected-error@#exportedFunctionUsed_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); // #exportedFunctionUsed_fy_call
+
+  // expected-error@#exportedFunctionUsed_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); // #exportedFunctionUsed_fz_call
+}
+
+namespace A {
+  namespace B {
+    export {
+      void exportedFunctionInNS(float x) {
+        // expected-error@#exportedFunctionInNS_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(x); // #exportedFunctionInNS_fx_call
+
+        // API with shader-stage-specific availability in exported library function
+        // - no errors expected because the actual shader stage this function
+        // will be used in not known at this time
+        float B = fy(x);
+        float C = fz(x);
+      }
+    }
+  }
+}
+
 // Shader entry point without body
 [shader("compute")]
 [numthreads(4,1,1)]
@@ -126,5 +175,6 @@ float main() {
   float c = C.makeF();
   float d = test((float)1.0);
   float e = test((half)1.0);
+  exportedFunctionUsed(1.0f);
   return a * b * c;
 }
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
index 6bd20450f8bfa..33d6e4816dda8 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
@@ -110,6 +110,37 @@ class MyClass
   }
 };
 
+// Exported function without body - not used
+export void exportedFunctionUnused(float f);
+
+// Exported function with body - not used
+export void exportedFunctionUnused(float f) {
+  // expected-warning@#exportedFunctionUnused_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); // #exportedFunctionUnused_fx_call
+
+  // API with shader-stage-specific availability in unused exported library function
+  // - no errors expected because the actual shader stage this function
+  // will be used in not known at this time
+  float B = fy(f);
+  float C = fz(f);
+}
+
+// Exported function with body - called from main() which is a compute shader entry point
+export void exportedFunctionUsed(float f) {
+  // expected-warning@#exportedFunctionUsed_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); // #exportedFunctionUsed_fx_call
+
+  // expected-warning@#exportedFunctionUsed_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); // #exportedFunctionUsed_fy_call
+
+  // expected-warning@#exportedFunctionUsed_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); // #exportedFunctionUsed_fz_call
+}
+
 // Shader entry point without body
 [shader("compute")]
 [numthreads(4,1,1)]
@@ -126,5 +157,6 @@ float main() {
   float c = C.makeF();
   float d = test((float)1.0);
   float e = test((half)1.0);
+  exportedFunctionUsed(1.0f);
   return a * b * c;
 }
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
index 4c9675051e570..bc1f006179a8d 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
@@ -129,6 +129,55 @@ class MyClass
   }
 };
 
+// Exported function without body - not used
+export void exportedFunctionUnused(float f);
+
+// Exported function with body - not used
+export void exportedFunctionUnused(float f) {
+  // expected-error@#exportedFunctionUnused_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); // #exportedFunctionUnused_fx_call
+
+  // API with shader-stage-specific availability in unused exported library function
+  // - no errors expected because the actual shader stage this function
+  // will be used in not known at this time
+  float B = fy(f);
+  float C = fz(f);
+}
+
+// Exported function with body - called from main() which is a compute shader entry point
+export void exportedFunctionUsed(float f) {
+  // expected-error@#exportedFunctionUsed_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); // #exportedFunctionUsed_fx_call
+
+  // expected-error@#exportedFunctionUsed_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); // #exportedFunctionUsed_fy_call
+
+  // expected-error@#exportedFunctionUsed_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); // #exportedFunctionUsed_fz_call
+}
+
+namespace A {
+  namespace B {
+    export {
+      void exportedFunctionInNS(float x) {
+        // expected-error@#exportedFunctionInNS_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(x); // #exportedFunctionInNS_fx_call
+
+        // API with shader-stage-specific availability in exported library function
+        // - no errors expected because the actual shader stage this function
+        // will be used in not known at this time
+        float B = fy(x);
+        float C = fz(x);
+      }
+    }
+  }
+}
+
 [shader("compute")]
 [numthreads(4,1,1)]
 float main() {
@@ -138,5 +187,6 @@ float main() {
   float c = C.makeF();
   float d = test((float)1.0);
   float e = test((half)1.0);
+  exportedFunctionUsed(1.0f);
   return a * b * c;
 }
\ No newline at end of file

>From 8a3092ca56f790bd182c09c04bbe5b6756fd3050 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 1 Jul 2024 13:56:35 -0700
Subject: [PATCH 3/4] Revert "[HLSL] Implement `export` keyword"

This reverts commit b67ecd20cc2c11f4f99c2d90c95fdbd988659947.
---
 .../clang/Basic/DiagnosticSemaKinds.td        |  3 --
 clang/lib/Parse/ParseDeclCXX.cpp              |  8 ---
 clang/lib/Parse/Parser.cpp                    |  2 +-
 clang/lib/Sema/SemaModule.cpp                 | 32 ------------
 clang/test/AST/HLSL/export.hlsl               | 23 ---------
 clang/test/CodeGenHLSL/export.hlsl            | 20 --------
 clang/test/SemaHLSL/export.hlsl               | 50 -------------------
 7 files changed, 1 insertion(+), 137 deletions(-)
 delete mode 100644 clang/test/AST/HLSL/export.hlsl
 delete mode 100644 clang/test/CodeGenHLSL/export.hlsl
 delete mode 100644 clang/test/SemaHLSL/export.hlsl

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 64f7935d25d65..b8eafffd4650d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -12324,9 +12324,6 @@ def warn_hlsl_availability_unavailable :
   Warning<err_unavailable.Summary>,
   InGroup<HLSLAvailability>, DefaultError;
 
-def err_hlsl_export_not_on_function : Error<
-  "export declaration can only be used on functions">;
-
 // 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/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index ce827c689beb7..2fc43a7e7926b 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -445,14 +445,6 @@ Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) {
 ///         'export' declaration
 ///         'export' '{' declaration-seq[opt] '}'
 ///
-/// HLSL: Parse export function declaration.
-///
-///      export-function-declaration: 
-///         'export' function-declaration
-/// 
-///      export-declaration-group:
-///         'export' '{' function-declaration-seq[opt] '}'
-///
 Decl *Parser::ParseExportDeclaration() {
   assert(Tok.is(tok::kw_export));
   SourceLocation ExportLoc = ConsumeToken();
diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp
index 5ebe71e496a2e..71b87147e9a5f 100644
--- a/clang/lib/Parse/Parser.cpp
+++ b/clang/lib/Parse/Parser.cpp
@@ -970,7 +970,7 @@ Parser::ParseExternalDeclaration(ParsedAttributes &Attrs,
     SingleDecl = ParseModuleImport(SourceLocation(), IS);
   } break;
   case tok::kw_export:
-    if (getLangOpts().CPlusPlusModules || getLangOpts().HLSL) {
+    if (getLangOpts().CPlusPlusModules) {
       ProhibitAttributes(Attrs);
       SingleDecl = ParseExportDeclaration();
       break;
diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp
index c8c07c0091903..98e7971dc0bf3 100644
--- a/clang/lib/Sema/SemaModule.cpp
+++ b/clang/lib/Sema/SemaModule.cpp
@@ -853,21 +853,6 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc,
   CurContext->addDecl(D);
   PushDeclContext(S, D);
 
-  if (getLangOpts().HLSL) {
-    // exported functions cannot be in an unnamed namespace
-    for (const DeclContext *DC = CurContext; DC; DC = DC->getLexicalParent()) {
-      if (const auto *ND = dyn_cast<NamespaceDecl>(DC)) {
-        if (ND->isAnonymousNamespace()) {
-          Diag(ExportLoc, diag::err_export_within_anonymous_namespace);
-          Diag(ND->getLocation(), diag::note_anonymous_namespace);
-          D->setInvalidDecl();
-          return D;
-        }
-      }
-    }
-    return D;
-  }
-
   // C++2a [module.interface]p1:
   //   An export-declaration shall appear only [...] in the purview of a module
   //   interface unit. An export-declaration shall not appear directly or
@@ -941,23 +926,6 @@ static bool checkExportedDeclContext(Sema &S, DeclContext *DC,
 /// Check that it's valid to export \p D.
 static bool checkExportedDecl(Sema &S, Decl *D, SourceLocation BlockStart) {
 
-  // HLSL: export declaration is valid only on functions
-  if (S.getLangOpts().HLSL) {
-    auto *FD = dyn_cast<FunctionDecl>(D);
-    if (!FD) {
-      if (auto *ED2 = dyn_cast<ExportDecl>(D)) {
-        S.Diag(ED2->getBeginLoc(), diag::err_export_within_export);
-        if (auto *ED1 = dyn_cast<ExportDecl>(D->getDeclContext()))
-          S.Diag(ED1->getBeginLoc(), diag::note_export);
-      }
-      else {
-        S.Diag(D->getBeginLoc(), diag::err_hlsl_export_not_on_function);
-      }
-      D->setInvalidDecl();
-      return false;
-    }
-  }
-
   //  C++20 [module.interface]p3:
   //   [...] it shall not declare a name with internal linkage.
   bool HasName = false;
diff --git a/clang/test/AST/HLSL/export.hlsl b/clang/test/AST/HLSL/export.hlsl
deleted file mode 100644
index 69c4fb2b457ac..0000000000000
--- a/clang/test/AST/HLSL/export.hlsl
+++ /dev/null
@@ -1,23 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -x hlsl -ast-dump -o - %s | FileCheck %s
-
-// CHECK:ExportDecl 0x{{[0-9a-f]+}} <{{.*}}> col:1
-// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> col:13 used f1 'void ()'
-// CHECK:CompoundStmt 0x{{[0-9a-f]+}} <{{.*}}>
-export void f1() {}
-
-// CHECK:NamespaceDecl 0x{{[0-9a-f]+}} <{{.*}}>
-// CHECK:ExportDecl 0x{{[0-9a-f]+}} <{{.*}}> col:3
-// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> col:15 used f2 'void ()'
-// CHECK:CompoundStmt 0x{{[0-9a-f]+}} <{{.*}}>
-namespace MyNamespace {
-  export void f2() {}
-}
-
-// CHECK:ExportDecl 0x{{[0-9a-f]+}} <{{.*}}>
-// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> col:10 used f3 'void ()'
-// CHECK:FunctionDecl 0x{{[0-9a-f]+}} <{{.*}}> col:10 used f4 'void ()'
-// CHECK:CompoundStmt 0x{{[0-9a-f]+}} <{{.*}}>
-export {
-    void f3() {}
-    void f4() {}
-}
diff --git a/clang/test/CodeGenHLSL/export.hlsl b/clang/test/CodeGenHLSL/export.hlsl
deleted file mode 100644
index cea8875684b9e..0000000000000
--- a/clang/test/CodeGenHLSL/export.hlsl
+++ /dev/null
@@ -1,20 +0,0 @@
-// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
-// RUN:   dxil-pc-shadermodel6.3-library %s \
-// RUN:   -emit-llvm -disable-llvm-passes -o - | FileCheck %s
-
-// CHECK: define void @"?f1@@YAXXZ"()
-export void f1() {
-}
-
-// CHECK: define void @"?f2 at MyNamespace@@YAXXZ"()
-namespace MyNamespace {
-  export void f2() {
-  }
-}
-
-export {
-// CHECK: define void @"?f3@@YAXXZ"()
-// CHECK: define void @"?f4@@YAXXZ"()    
-    void f3() {}
-    void f4() {}
-}
\ No newline at end of file
diff --git a/clang/test/SemaHLSL/export.hlsl b/clang/test/SemaHLSL/export.hlsl
deleted file mode 100644
index 0cb9248f3f589..0000000000000
--- a/clang/test/SemaHLSL/export.hlsl
+++ /dev/null
@@ -1,50 +0,0 @@
-// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify
-
-export void f1();
-
-export void f1() {}
-
-namespace { // expected-note {{anonymous namespace begins here}}
-    export void f2(); // expected-error {{export declaration appears within anonymous namespace}}
-}
-
-export void f3();
-
-export { // expected-note {{export block begins here}}
-    void f4() {}
-    export void f5() {} // expected-error {{export declaration appears within another export declaration}}
-    int A; // expected-error {{export declaration can only be used on functions}}
-    namespace ns { // expected-error {{export declaration can only be used on functions}}
-        void f6();
-    }
-}
-
-void export f7() {} // expected-error {{expected unqualified-id}}
-
-export static void f8() {} // expected-error {{declaration of 'f8' with internal linkage cannot be exported}}
-
-export void f9(); // expected-note {{previous declaration is here}}
-static void f9(); // expected-error {{static declaration of 'f9' follows non-static declaration}}
-
-static void f10(); // expected-note {{previous declaration is here}}
-export void f10(); // expected-error {{cannot export redeclaration 'f10' here since the previous declaration has internal linkage}}
-
-export float V1; // expected-error {{export declaration can only be used on functions}}
-
-static export float V2; // expected-error{{expected unqualified-id}}
-
-export static float V3 = 0; // expected-error {{export declaration can only be used on functions}}
-
-export groupshared float V4; // expected-error {{export declaration can only be used on functions}}
-
-void f6() {
-  export int i;  // expected-error {{expected expression}}
-}
-
-export cbuffer CB { // expected-error {{export declaration can only be used on functions}}
-    int a;
-}
-
-export template<typename T> void tf1(T t) {} // expected-error {{export declaration can only be used on functions}}
-
-void f5() export {} // expected-error {{expected function body after function declarator}}
\ No newline at end of file

>From c8c6b5084bd1bb5f01d3e4edd2d8c932ff9ea0ad Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 1 Jul 2024 14:33:34 -0700
Subject: [PATCH 4/4] Update comment and add new line

---
 clang/lib/Sema/SemaHLSL.cpp                                 | 3 ++-
 clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl | 2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 5a4e69d2fee63..d22e6e8915067 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -687,7 +687,8 @@ void DiagnoseHLSLAvailability::RunOnTranslationUnit(
       if (D->isImplicit())
         continue;
 
-      // namespace or export declaration - add to the list to be scanned later
+      // for namespace or export declaration add the context to the list to be
+      // scanned later
       if (llvm::dyn_cast<NamespaceDecl>(D) || llvm::dyn_cast<ExportDecl>(D)) {
         DeclContextsToScan.push_back(llvm::dyn_cast<DeclContext>(D));
         continue;
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
index bc1f006179a8d..cea3c33080d27 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
@@ -189,4 +189,4 @@ float main() {
   float e = test((half)1.0);
   exportedFunctionUsed(1.0f);
   return a * b * c;
-}
\ No newline at end of file
+}



More information about the cfe-commits mailing list