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

Helena Kotas via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 2 09:51:37 PDT 2024


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

>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/6] [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/6] 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/6] 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/6] 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
+}

>From 5b6e0a9696861da9e6fe64a9dcca5fcf776aeb95 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 1 Jul 2024 14:53:26 -0700
Subject: [PATCH 5/6] clang-format

---
 clang/lib/Sema/SemaHLSL.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index d22e6e8915067..192238960e545 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -677,11 +677,11 @@ void DiagnoseHLSLAvailability::RunOnTranslationUnit(
   // shader environment context based on whether it is a shader entry function
   // 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;
+  llvm::SmallVector<const DeclContext *, 8> DeclContextsToScan;
   DeclContextsToScan.push_back(TU);
 
   while (!DeclContextsToScan.empty()) {
-    const DeclContext* DC = DeclContextsToScan.pop_back_val();
+    const DeclContext *DC = DeclContextsToScan.pop_back_val();
     for (auto &D : DC->decls()) {
       // do not scan implicit declaration generated by the implementation
       if (D->isImplicit())

>From 7fba9bfc8fbf0bde6354df165363503ea4d6f525 Mon Sep 17 00:00:00 2001
From: Helena Kotas <hekotas at microsoft.com>
Date: Mon, 1 Jul 2024 18:25:42 -0700
Subject: [PATCH 6/6] Make sure we check all function redeclarations

---
 clang/lib/Sema/SemaHLSL.cpp                         | 13 ++++++++++++-
 .../Availability/avail-diag-default-lib.hlsl        |  6 +++---
 .../Availability/avail-diag-relaxed-lib.hlsl        |  6 +++---
 .../Availability/avail-diag-strict-lib.hlsl         |  6 +++---
 4 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 192238960e545..babb984995f13 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -706,7 +706,18 @@ void DiagnoseHLSLAvailability::RunOnTranslationUnit(
         continue;
       }
       // exported library function
-      if (FD->isInExportDeclContext()) {
+      // FIXME: replace this loop with external linkage check once issue #92071
+      // is resolved
+      bool isExport = FD->isInExportDeclContext();
+      if (!isExport) {
+        for (const auto *Redecl : FD->redecls()) {
+          if (Redecl->isInExportDeclContext()) {
+            isExport = true;
+            break;
+          }
+        }
+      }
+      if (isExport) {
         SetUnknownShaderStageContext();
         RunOnFunction(FD);
         continue;
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
index 19b06832c2218..6bfc8577670cc 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-default-lib.hlsl
@@ -110,11 +110,11 @@ class MyClass
   }
 };
 
-// Exported function without body
+// Exported function without body, not used
 export void exportedFunctionUnused(float f);
 
-// Exported function with body - not used
-export void exportedFunctionUnused(float f) {
+// Exported function with body, without export, not used
+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
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
index 33d6e4816dda8..4c9783138f670 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-relaxed-lib.hlsl
@@ -110,11 +110,11 @@ class MyClass
   }
 };
 
-// Exported function without body - not used
+// Exported function without body, not used
 export void exportedFunctionUnused(float f);
 
-// Exported function with body - not used
-export void exportedFunctionUnused(float f) {
+// Exported function with body, without export, not used
+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
diff --git a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
index cea3c33080d27..c7be5afbc2d22 100644
--- a/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
+++ b/clang/test/SemaHLSL/Availability/avail-diag-strict-lib.hlsl
@@ -129,11 +129,11 @@ class MyClass
   }
 };
 
-// Exported function without body - not used
+// Exported function without body, not used
 export void exportedFunctionUnused(float f);
 
-// Exported function with body - not used
-export void exportedFunctionUnused(float f) {
+// Exported function with body, without export, not used
+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



More information about the cfe-commits mailing list