[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-19 Thread Romaric Jodin via cfe-commits

rjodinchr wrote:

@aviralg are you able to merge it?

https://github.com/llvm/llvm-project/pull/196571
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-16 Thread Romaric Jodin via cfe-commits

rjodinchr wrote:

Can anyone merge it? I don't have permission to do it myself.

https://github.com/llvm/llvm-project/pull/196571
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-15 Thread Romaric Jodin via cfe-commits

rjodinchr wrote:

@aviralg could you please have a second look at this PR? Thank you in advance 🙏

https://github.com/llvm/llvm-project/pull/196571
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-11 Thread Romaric Jodin via cfe-commits

rjodinchr wrote:

CI is green ✅, I have updated the PR description

https://github.com/llvm/llvm-project/pull/196571
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-09 Thread Romaric Jodin via cfe-commits

https://github.com/rjodinchr edited 
https://github.com/llvm/llvm-project/pull/196571
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-09 Thread Romaric Jodin via cfe-commits

https://github.com/rjodinchr updated 
https://github.com/llvm/llvm-project/pull/196571

>From 97d98f922be0f3ccf1fec99daef82cf40992531e Mon Sep 17 00:00:00 2001
From: Romaric Jodin 
Date: Fri, 8 May 2026 16:14:06 +0200
Subject: [PATCH] Fix MSVC template parsing error in SerializationFormat

This commit fixes a hard compilation error on Windows (when building with
Clang's MSVC compatibility mode) and a subsequent access violation that
occurred during Windows CI testing.

Root Causes:
1. When compiling with `-fms-compatibility`, Clang's two-phase template
   lookup fails to resolve function-local static variables (`SavedSerialize`
   and `SavedDeserialize`) captured by a local class (`ConcreteCodec`) inside
   an uninstantiated template. It incorrectly assumes they are members of a
   dependent base class.
2. Originally, `TypedSerializerFn` and `DeserializerFn` were typed as
   `llvm::function_ref`. Storing these in static variables created dangling
   pointers, as `function_ref` is a non-owning wrapper that only referenced
   the temporaries decaying on the constructor's stack, causing an 0xC005
   access violation on x64 Windows.

The Fix:
* Hoisted `SavedSerialize` and `SavedDeserialize` out of the constructor
  scope to be `static inline` members of the `Add` class template. This allows
  Clang's Phase 1 parser to correctly resolve the symbols.
* Redefined `TypedSerializerFn` and `DeserializerFn` to raw function pointers
  instead of `llvm::function_ref`. This ensures the static registry variables
  safely capture the persistent addresses of the global functions being
  registered, eliminating the dangling pointers.

Safety note: The original concern regarding `dlopen` symbol visibility on
Linux is preserved. `ConcreteCodec` continues to store the functions strictly
as instance members, snapshotting the plugin's local copy of the static
variables at instantiation.
---
 .../Core/Serialization/SerializationFormat.h  | 30 +++
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
 
b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
index fd261c6d9a723..080628a700ba1 100644
--- 
a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
@@ -111,7 +111,7 @@ class SerializationFormat {
   FormatT, llvm::function_ref,
   llvm::function_ref> {
 
-using DeserializerFn = llvm::function_ref;
+using DeserializerFn = DesRet (*)(DesArgs...);
 
   public:
 /// Abstract base type stored in \c llvm::Registry.
@@ -130,8 +130,10 @@ class SerializationFormat {
 };
 
 template  struct Add {
-  using TypedSerializerFn =
-  llvm::function_ref;
+  using TypedSerializerFn = SerRet (*)(const AnalysisResultT &, 
SerArgs...);
+
+  static inline TypedSerializerFn SavedSerialize;
+  static inline DeserializerFn SavedDeserialize;
 
   /// Takes the plugin's typed serializer and the deserializer, and
   /// inserts them into \c llvm::Registry.
@@ -147,15 +149,19 @@ class SerializationFormat {
 Registered = true;
 
 /// The plugin's serializer and deserializer are captured in
-/// function-local statics so that the \c ConcreteCodec default
-/// constructor (required by \c llvm::Registry) can read them.
-/// They are stored as instance members of \c ConcreteCodec rather
-/// than \c static \c inline class members to avoid symbol
-/// visibility issues across shared library boundaries on Linux
-/// (where \c dlopen with \c RTLD_LOCAL can give the host and
-/// plugin separate copies of \c static \c inline members).
-static TypedSerializerFn SavedSerialize = TypedSerialize;
-static DeserializerFn SavedDeserialize = Deserialize;
+/// static inline members of the Add template so that the
+/// \c ConcreteCodec default constructor (required by \c 
llvm::Registry)
+/// can read them. They use raw function pointers to prevent dangling
+/// references to temporary stack variables during registration.
+///
+/// Once read by the constructor, they are stored as instance members
+/// of \c ConcreteCodec rather than directly executed from the \c 
static
+/// \c inline class members. This prevents symbol visibility issues
+/// across shared library boundaries on Linux (where \c dlopen with \c
+/// RTLD_LOCAL can give the host and plugin separate copies of \c 
static
+/// \c inline members).
+SavedSerialize = TypedSerialize;
+SavedDeserialize = Deserialize;
 
 /// Concrete subclass of \c Codec for \c AnalysisResultT.
 /// The \c serialize() override performs the downcast from

___

[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-09 Thread via cfe-commits

github-actions[bot] wrote:


# :window: Windows x64 Test Results

* 53875 tests passed
* 1200 tests skipped
* 2 tests failed

## Failed Tests
(click on a test name to see its output)

### Clang

Clang.Analysis/Scalable/PointerFlow/wpa-result-serialization.test

```
Exit Code: 3221225477

Command Output (stdout):
--
# RUN: at line 1
rm -rf 
C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\PointerFlow\Output\wpa-result-serialization.test.tmp
# executed command: rm -rf 
'C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\PointerFlow\Output\wpa-result-serialization.test.tmp'
# note: command had no output on stdout or stderr
# RUN: at line 2
mkdir -p 
C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\PointerFlow\Output\wpa-result-serialization.test.tmp
# executed command: mkdir -p 
'C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\PointerFlow\Output\wpa-result-serialization.test.tmp'
# note: command had no output on stdout or stderr
# RUN: at line 6
c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe --type wpa 
C:\_work\llvm-project\llvm-project\clang\test\Analysis\Scalable\PointerFlow/Inputs/wpa-result.json
 -o 
C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\PointerFlow\Output\wpa-result-serialization.test.tmp/wpa-result.json
# executed command: 
'c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe' --type wpa 
'C:\_work\llvm-project\llvm-project\clang\test\Analysis\Scalable\PointerFlow/Inputs/wpa-result.json'
 -o 
'C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\PointerFlow\Output\wpa-result-serialization.test.tmp/wpa-result.json'
# .---command stderr
# | PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ 
and include the crash backtrace and instructions to reproduce the bug.
# | Stack dump:
# | 0.  Program arguments: 
c:\\_work\\llvm-project\\llvm-project\\build\\bin\\clang-ssaf-format.exe --type 
wpa 
C:\\_work\\llvm-project\\llvm-project\\clang\\test\\Analysis\\Scalable\\PointerFlow/Inputs/wpa-result.json
 -o 
C:\\_work\\llvm-project\\llvm-project\\build\\tools\\clang\\test\\Analysis\\Scalable\\PointerFlow\\Output\\wpa-result-serialization.test.tmp/wpa-result.json
# | Exception Code: 0xC005
# | #0 0x
# | #1 0x7ff6f680eb82 
(c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe+0x2eb82)
# | #2 0x7ff6f68cdfd9 
(c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe+0xedfd9)
# | #3 0x7ff6f68ceb6b 
(c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe+0xeeb6b)
# | #4 0x7ff6f68cff24 
(c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe+0xeff24)
# | #5 0x7ff6f67e2830 
(c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe+0x2830)
# | #6 0x7ff6f70e067c 
(c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe+0x90067c)
# | #7 0x7ffb813c4cb0 (C:\Windows\System32\KERNEL32.DLL+0x14cb0)
# | #8 0x7ffb8d79edcb (C:\Windows\SYSTEM32\ntdll.dll+0x7edcb)
# `-
# error: command failed with exit status: 0xc005

--

```


Clang.Analysis/Scalable/UnsafeBufferUsage/wpa-result-serialization.test

```
Exit Code: 3221225477

Command Output (stdout):
--
# RUN: at line 1
rm -rf 
C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\UnsafeBufferUsage\Output\wpa-result-serialization.test.tmp
# executed command: rm -rf 
'C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\UnsafeBufferUsage\Output\wpa-result-serialization.test.tmp'
# note: command had no output on stdout or stderr
# RUN: at line 2
mkdir -p 
C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\UnsafeBufferUsage\Output\wpa-result-serialization.test.tmp
# executed command: mkdir -p 
'C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\UnsafeBufferUsage\Output\wpa-result-serialization.test.tmp'
# note: command had no output on stdout or stderr
# RUN: at line 6
c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe --type wpa 
C:\_work\llvm-project\llvm-project\clang\test\Analysis\Scalable\UnsafeBufferUsage/Inputs/wpa-result.json
 -o 
C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\UnsafeBufferUsage\Output\wpa-result-serialization.test.tmp/wpa-result.json
# executed command: 
'c:\_work\llvm-project\llvm-project\build\bin\clang-ssaf-format.exe' --type wpa 
'C:\_work\llvm-project\llvm-project\clang\test\Analysis\Scalable\UnsafeBufferUsage/Inputs/wpa-result.json'
 -o 
'C:\_work\llvm-project\llvm-project\build\tools\clang\test\Analysis\Scalable\UnsafeBufferUsage\Output\wpa-result-serialization.test.tmp/wpa-result.json'
# .---command stderr
# | PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ 
and include the crash backtrace and 

[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-09 Thread via cfe-commits

llvmorg-github-actions[bot] wrote:




@llvm/pr-subscribers-clang

Author: Romaric Jodin (rjodinchr)


Changes

This commit fixes a hard compilation error on Windows when building translation 
units that instantiate the `Add` registry template (such as 
`PointerFlowAnalysis.cpp`).

**Root Cause:**
When compiling on Windows, Clang defaults to MSVC compatibility mode 
(`-fms-compatibility`). Under this mode, Clang's two-phase template lookup 
struggles to resolve function-local static variables (`SavedSerialize` and 
`SavedDeserialize`) captured by a local class (`ConcreteCodec`) inside an 
uninstantiated template. During Phase 1 parsing, Clang incorrectly falls back 
to assuming these variables must be members of a dependent base class, 
rewriting them to `this->SavedSerialize`. During Phase 2 instantiation, 
compilation fails because the base class (`Codec`) has no such members.

**The Fix:**
Hoisted `SavedSerialize` and `SavedDeserialize` out of the constructor scope, 
making them `static inline` members of the `Add` class template. This allows 
Clang's Phase 1 parser to perfectly resolve the symbols without relying on 
broken MSVC fallbacks.

**Why this is safe (Addressing the `dlopen` comment):** The original author 
explicitly commented that they avoided `static inline` class members to prevent 
Linux symbol visibility issues across shared library boundaries (`dlopen` with 
`RTLD_LOCAL`).

That concern is still honored by this fix. The visibility risk only applies if 
the `ConcreteCodec`'s *own* execution state relied directly on static members. 
By moving the static variables to the `Add` factory class, `ConcreteCodec` 
continues to store `SerFn` and `DesFn` as strictly **instance members**. The 
`ConcreteCodec` constructor safely snapshots the plugin's local copy of 
`Add::SavedSerialize` at the moment of instantiation. Since the virtual methods 
executed by the host still read exclusively from the isolated instance state, 
the runtime behavior remains completely identical and safe.

---
Full diff: https://github.com/llvm/llvm-project/pull/196571.diff


1 Files Affected:

- (modified) 
clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
 (+5-2) 


``diff
diff --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
 
b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
index fd261c6d9a723..9ab79dda3fc11 100644
--- 
a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
@@ -133,6 +133,9 @@ class SerializationFormat {
   using TypedSerializerFn =
   llvm::function_ref;
 
+  static inline TypedSerializerFn SavedSerialize;
+  static inline DeserializerFn SavedDeserialize;
+
   /// Takes the plugin's typed serializer and the deserializer, and
   /// inserts them into \c llvm::Registry.
   Add(TypedSerializerFn TypedSerialize, DeserializerFn Deserialize) {
@@ -154,8 +157,8 @@ class SerializationFormat {
 /// visibility issues across shared library boundaries on Linux
 /// (where \c dlopen with \c RTLD_LOCAL can give the host and
 /// plugin separate copies of \c static \c inline members).
-static TypedSerializerFn SavedSerialize = TypedSerialize;
-static DeserializerFn SavedDeserialize = Deserialize;
+SavedSerialize = TypedSerialize;
+SavedDeserialize = Deserialize;
 
 /// Concrete subclass of \c Codec for \c AnalysisResultT.
 /// The \c serialize() override performs the downcast from

``




https://github.com/llvm/llvm-project/pull/196571
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-09 Thread Romaric Jodin via cfe-commits

rjodinchr wrote:

> ~Thank you for the detailed explanation of this fix! Please update the code 
> comments too.~ Looks like the change does not work?

I'm not able to reproduce on my machine, but I'm suspecting an issue regarding 
`llvm::function_ref` as it is a non-owning wrapper.

I still need to update the comments. I'll do that once all CI checks are green.

https://github.com/llvm/llvm-project/pull/196571
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-09 Thread Romaric Jodin via cfe-commits

https://github.com/rjodinchr updated 
https://github.com/llvm/llvm-project/pull/196571

>From 3a1a1f869091943822da9ba301f2d223840f11f9 Mon Sep 17 00:00:00 2001
From: Romaric Jodin 
Date: Fri, 8 May 2026 16:14:06 +0200
Subject: [PATCH 1/2] Fix MSVC template parsing error in SerializationFormat

This commit fixes a hard compilation error on Windows when building
translation units that instantiate the `Add` registry template
(such as `PointerFlowAnalysis.cpp`).

**Root Cause:**
When compiling on Windows, Clang defaults to MSVC compatibility mode
(`-fms-compatibility`). Under this mode, Clang's two-phase template
lookup struggles to resolve function-local static variables
(`SavedSerialize` and `SavedDeserialize`) captured by a local class
(`ConcreteCodec`) inside an uninstantiated template. During Phase 1
parsing, Clang incorrectly falls back to assuming these variables must
be members of a dependent base class, rewriting them to
`this->SavedSerialize`. During Phase 2 instantiation, compilation
fails because the base class (`Codec`) has no such members.

**The Fix:**
Hoisted `SavedSerialize` and `SavedDeserialize` out of the constructor
scope, making them `static inline` members of the `Add` class template.
This allows Clang's Phase 1 parser to perfectly resolve the symbols
without relying on broken MSVC fallbacks.

**Why this is safe (Addressing the `dlopen` comment):**
The original author explicitly commented that they avoided `static inline`
class members to prevent Linux symbol visibility issues across shared
library boundaries (`dlopen` with `RTLD_LOCAL`).

That concern is still honored by this fix. The visibility risk only applies
if the `ConcreteCodec`'s *own* execution state relied directly on static
members. By moving the static variables to the `Add` factory class,
`ConcreteCodec` continues to store `SerFn` and `DesFn` as strictly
**instance members**. The `ConcreteCodec` constructor safely snapshots
the plugin's local copy of `Add::SavedSerialize` at the moment of
instantiation. Since the virtual methods executed by the host still
read exclusively from the isolated instance state, the runtime behavior
remains completely identical and safe.
---
 .../Core/Serialization/SerializationFormat.h   | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
 
b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
index fd261c6d9a723..9ab79dda3fc11 100644
--- 
a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
@@ -133,6 +133,9 @@ class SerializationFormat {
   using TypedSerializerFn =
   llvm::function_ref;
 
+  static inline TypedSerializerFn SavedSerialize;
+  static inline DeserializerFn SavedDeserialize;
+
   /// Takes the plugin's typed serializer and the deserializer, and
   /// inserts them into \c llvm::Registry.
   Add(TypedSerializerFn TypedSerialize, DeserializerFn Deserialize) {
@@ -154,8 +157,8 @@ class SerializationFormat {
 /// visibility issues across shared library boundaries on Linux
 /// (where \c dlopen with \c RTLD_LOCAL can give the host and
 /// plugin separate copies of \c static \c inline members).
-static TypedSerializerFn SavedSerialize = TypedSerialize;
-static DeserializerFn SavedDeserialize = Deserialize;
+SavedSerialize = TypedSerialize;
+SavedDeserialize = Deserialize;
 
 /// Concrete subclass of \c Codec for \c AnalysisResultT.
 /// The \c serialize() override performs the downcast from

>From 71f74736a3ebeb2a59521f298523df17057a7555 Mon Sep 17 00:00:00 2001
From: Romaric Jodin 
Date: Sat, 9 May 2026 17:03:07 +0200
Subject: [PATCH 2/2] Fix Windows CI segfault by using function pointers

This commit fixes an 0xC005 access violation occurring during
Windows CI testing for `clang-ssaf-format.exe`.

* Root Cause:
Because `TypedSerializerFn` and `DeserializerFn` were typed as
`llvm::function_ref`, storing them in static
variables (`SavedSerialize` and `SavedDeserialize`) inadvertently
created dangling pointers. `llvm::function_ref` is a non-owning
wrapper; it only captured a reference to the temporary callables
decaying on the `Add` constructor's stack. Once the constructor
returned, those temporaries were destroyed. Dereferencing the stored
`function_ref` later caused an access violation on x64 Windows.

* The Fix:
Redefined `TypedSerializerFn` and `DeserializerFn` from
`llvm::function_ref` to standard raw function pointers. This ensures
the static registry variables safely capture and store the actual
persistent addresses of the global functions being registered,
completely eliminating the dangling pointers and resolving the crash.
---
 .../Core/Serialization/Serializatio

[clang] Fix MSVC template parsing error in SerializationFormat (PR #196571)

2026-05-09 Thread Romaric Jodin via cfe-commits

https://github.com/rjodinchr created 
https://github.com/llvm/llvm-project/pull/196571

This commit fixes a hard compilation error on Windows when building translation 
units that instantiate the `Add` registry template (such as 
`PointerFlowAnalysis.cpp`).

**Root Cause:**
When compiling on Windows, Clang defaults to MSVC compatibility mode 
(`-fms-compatibility`). Under this mode, Clang's two-phase template lookup 
struggles to resolve function-local static variables (`SavedSerialize` and 
`SavedDeserialize`) captured by a local class (`ConcreteCodec`) inside an 
uninstantiated template. During Phase 1 parsing, Clang incorrectly falls back 
to assuming these variables must be members of a dependent base class, 
rewriting them to `this->SavedSerialize`. During Phase 2 instantiation, 
compilation fails because the base class (`Codec`) has no such members.

**The Fix:**
Hoisted `SavedSerialize` and `SavedDeserialize` out of the constructor scope, 
making them `static inline` members of the `Add` class template. This allows 
Clang's Phase 1 parser to perfectly resolve the symbols without relying on 
broken MSVC fallbacks.

**Why this is safe (Addressing the `dlopen` comment):** The original author 
explicitly commented that they avoided `static inline` class members to prevent 
Linux symbol visibility issues across shared library boundaries (`dlopen` with 
`RTLD_LOCAL`).

That concern is still honored by this fix. The visibility risk only applies if 
the `ConcreteCodec`'s *own* execution state relied directly on static members. 
By moving the static variables to the `Add` factory class, `ConcreteCodec` 
continues to store `SerFn` and `DesFn` as strictly **instance members**. The 
`ConcreteCodec` constructor safely snapshots the plugin's local copy of 
`Add::SavedSerialize` at the moment of instantiation. Since the virtual methods 
executed by the host still read exclusively from the isolated instance state, 
the runtime behavior remains completely identical and safe.

>From 3a1a1f869091943822da9ba301f2d223840f11f9 Mon Sep 17 00:00:00 2001
From: Romaric Jodin 
Date: Fri, 8 May 2026 16:14:06 +0200
Subject: [PATCH] Fix MSVC template parsing error in SerializationFormat

This commit fixes a hard compilation error on Windows when building
translation units that instantiate the `Add` registry template
(such as `PointerFlowAnalysis.cpp`).

**Root Cause:**
When compiling on Windows, Clang defaults to MSVC compatibility mode
(`-fms-compatibility`). Under this mode, Clang's two-phase template
lookup struggles to resolve function-local static variables
(`SavedSerialize` and `SavedDeserialize`) captured by a local class
(`ConcreteCodec`) inside an uninstantiated template. During Phase 1
parsing, Clang incorrectly falls back to assuming these variables must
be members of a dependent base class, rewriting them to
`this->SavedSerialize`. During Phase 2 instantiation, compilation
fails because the base class (`Codec`) has no such members.

**The Fix:**
Hoisted `SavedSerialize` and `SavedDeserialize` out of the constructor
scope, making them `static inline` members of the `Add` class template.
This allows Clang's Phase 1 parser to perfectly resolve the symbols
without relying on broken MSVC fallbacks.

**Why this is safe (Addressing the `dlopen` comment):**
The original author explicitly commented that they avoided `static inline`
class members to prevent Linux symbol visibility issues across shared
library boundaries (`dlopen` with `RTLD_LOCAL`).

That concern is still honored by this fix. The visibility risk only applies
if the `ConcreteCodec`'s *own* execution state relied directly on static
members. By moving the static variables to the `Add` factory class,
`ConcreteCodec` continues to store `SerFn` and `DesFn` as strictly
**instance members**. The `ConcreteCodec` constructor safely snapshots
the plugin's local copy of `Add::SavedSerialize` at the moment of
instantiation. Since the virtual methods executed by the host still
read exclusively from the isolated instance state, the runtime behavior
remains completely identical and safe.
---
 .../Core/Serialization/SerializationFormat.h   | 7 +--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git 
a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
 
b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
index fd261c6d9a723..9ab79dda3fc11 100644
--- 
a/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
+++ 
b/clang/include/clang/ScalableStaticAnalysisFramework/Core/Serialization/SerializationFormat.h
@@ -133,6 +133,9 @@ class SerializationFormat {
   using TypedSerializerFn =
   llvm::function_ref;
 
+  static inline TypedSerializerFn SavedSerialize;
+  static inline DeserializerFn SavedDeserialize;
+
   /// Takes the plugin's typed serializer and the deserializer, and
   /// inserts them into \c ll