https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/96823
>From b67ecd20cc2c11f4f99c2d90c95fdbd988659947 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Wed, 26 Jun 2024 12:31:39 -0700 Subject: [PATCH 1/2] [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@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 327f96bfe417559ec9836279c00af42230075740 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Wed, 26 Jun 2024 15:29:12 -0700 Subject: [PATCH 2/2] Add new lines at the end of test files --- clang/test/CodeGenHLSL/export.hlsl | 2 +- clang/test/SemaHLSL/export.hlsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/CodeGenHLSL/export.hlsl b/clang/test/CodeGenHLSL/export.hlsl index cea8875684b9e..53f603739e329 100644 --- a/clang/test/CodeGenHLSL/export.hlsl +++ b/clang/test/CodeGenHLSL/export.hlsl @@ -17,4 +17,4 @@ export { // 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 index 0cb9248f3f589..6e53344dbee08 100644 --- a/clang/test/SemaHLSL/export.hlsl +++ b/clang/test/SemaHLSL/export.hlsl @@ -47,4 +47,4 @@ export cbuffer CB { // expected-error {{export declaration can only be used on f 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 +void f5() export {} // expected-error {{expected function body after function declarator}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits