[clang] [clang] Fix loss of `dllexport` for exported template specialization (PR #93302)

via cfe-commits cfe-commits at lists.llvm.org
Fri May 31 05:49:09 PDT 2024


zmodem wrote:

I looked at this some more. Here's a slightly reduced version of your test case:

```
template <typename> void foo();
template <typename> void f() {
    foo<void>();
}
void g() { f<void>(); }
template <> void __declspec(dllexport) foo<void>() {}
```

What happens (when building with `-fno-delayed-template-parsing`) is something like:

1. The `f()` template gets parsed. Because the call to `foo` is not type-dependent, the call gets resolved to a FunctionDecl for `foo<void>`, which isn't dllexport because that happens later.
2. `g()` calls `f<void>()`, so the latter gets queued up for codegen at the end of the TU.
3. Codegen for `foo<void>` happens, with dllexport.
4. (End of the TU) Codegen for `f<void>` happens. When generating the call to `foo<void>`, it uses the FunctionDecl from step 1). We enter `CodeGenModule::GetOrCreateLLVMFunction`, see that the old `Entry` is dllexport but the new FunctionDecl isn't, and so the attribute gets dropped.

I think the "surprise" is that the latter call to `GetOrCreateLLVMFunction` is using an earlier `FunctionDecl`. Because of that, I'm thinking maybe the fix is to call `getMostRecentDecl` on it, something like:

```
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 489c08a4d481..8fe36305e104 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -4554,10 +4554,13 @@ llvm::Constant *CodeGenModule::GetOrCreateLLVMFunction(
     }
 
     // Handle dropped DLL attributes.
-    if (D && !D->hasAttr<DLLImportAttr>() && !D->hasAttr<DLLExportAttr>() &&
-        !shouldMapVisibilityToDLLExport(cast_or_null<NamedDecl>(D))) {
-      Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
-      setDSOLocal(Entry);
+    if (D) {
+      const Decl *MRD = D->getMostRecentDecl();
+      if (!MRD->hasAttr<DLLImportAttr>() && !MRD->hasAttr<DLLExportAttr>() &&
+          !shouldMapVisibilityToDLLExport(cast<NamedDecl>(MRD))) {
+        Entry->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
+        setDSOLocal(Entry);
+      }
     }
 
     // If there are two attempts to define the same mangled name, issue an
```

If we're concerned about the extra function call in a common codepath, we could only do this if there is a dll attribute on the `Entry`.

https://github.com/llvm/llvm-project/pull/93302


More information about the cfe-commits mailing list