From 938cbdb4cf428bf08558c24d845aeac9174c7022 Mon Sep 17 00:00:00 2001 From: Helena Kotas Date: Mon, 1 Jul 2024 13:55:25 -0700 Subject: [HLSL] Implement `export` keyword (#96823) Implements `export` keyword in HLSL. There are two ways the `export` keyword can be used: 1. On individual function declarations ``` export void f() {} ``` 2. On a group of function declaration: ``` export { void f1(); void f2() {} } ``` Functions declared with the `export` keyword have external linkage. The implementation does not include validation of when a function can or cannot be exported, such as when it has resource argument or semantic annotations. That will be covered by llvm/llvm-project#93330. Currently all function declarations in global or named namespaces have external linkage by default so there are no specific code changes required right now to make sure exported function have external linkage as well. That will change as part of llvm/llvm-project#92071. Any additional changes to make sure exported functions still have external linkage will be done as part of this work item. Fixes #92812 --- clang/lib/Sema/SemaModule.cpp | 52 +++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 19 deletions(-) (limited to 'clang/lib/Sema/SemaModule.cpp') diff --git a/clang/lib/Sema/SemaModule.cpp b/clang/lib/Sema/SemaModule.cpp index 9655a39..3b84e7b 100644 --- a/clang/lib/Sema/SemaModule.cpp +++ b/clang/lib/Sema/SemaModule.cpp @@ -855,23 +855,25 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, // An export-declaration shall appear only [...] in the purview of a module // interface unit. An export-declaration shall not appear directly or // indirectly within [...] a private-module-fragment. - if (!isCurrentModulePurview()) { - Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; - D->setInvalidDecl(); - return D; - } else if (currentModuleIsImplementation()) { - Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1; - Diag(ModuleScopes.back().BeginLoc, - diag::note_not_module_interface_add_export) - << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); - D->setInvalidDecl(); - return D; - } else if (ModuleScopes.back().Module->Kind == - Module::PrivateModuleFragment) { - Diag(ExportLoc, diag::err_export_in_private_module_fragment); - Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment); - D->setInvalidDecl(); - return D; + if (!getLangOpts().HLSL) { + if (!isCurrentModulePurview()) { + Diag(ExportLoc, diag::err_export_not_in_module_interface) << 0; + D->setInvalidDecl(); + return D; + } else if (currentModuleIsImplementation()) { + Diag(ExportLoc, diag::err_export_not_in_module_interface) << 1; + Diag(ModuleScopes.back().BeginLoc, + diag::note_not_module_interface_add_export) + << FixItHint::CreateInsertion(ModuleScopes.back().BeginLoc, "export "); + D->setInvalidDecl(); + return D; + } else if (ModuleScopes.back().Module->Kind == + Module::PrivateModuleFragment) { + Diag(ExportLoc, diag::err_export_in_private_module_fragment); + Diag(ModuleScopes.back().BeginLoc, diag::note_private_module_fragment); + D->setInvalidDecl(); + return D; + } } for (const DeclContext *DC = CurContext; DC; DC = DC->getLexicalParent()) { @@ -891,7 +893,7 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, // // Defer exporting the namespace until after we leave it, in order to // avoid marking all subsequent declarations in the namespace as exported. - if (!DeferredExportedNamespaces.insert(ND).second) + if (!getLangOpts().HLSL && !DeferredExportedNamespaces.insert(ND).second) break; } } @@ -906,7 +908,9 @@ Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, return D; } - D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); + if (!getLangOpts().HLSL) + D->setModuleOwnershipKind(Decl::ModuleOwnershipKind::VisibleWhenImported); + return D; } @@ -924,6 +928,16 @@ 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) { + // Export-within-export was already diagnosed in ActOnStartExportDecl + if (!dyn_cast(D) && !dyn_cast(D)) { + 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; -- cgit v1.1