From 95b27b2a1e0e9fe0781ec76015b4016b9d04423d Mon Sep 17 00:00:00 2001 From: Sebastian Neubauer Date: Mon, 19 Dec 2022 14:25:05 +0100 Subject: [PATCH] [llvm][ADT] Fix Any with msvc and lto llvm::Any had and has several bugs, so we eventually want to replace it with std::any. Unfortunately, we cannot do that right now because of bugs in the msvc standard library that are only fixed in VS 2022 17.4. When lto is enabled in msvc, constant symbols end up at the same address, breaking the TypeId implementation of llvm::Any. Make the TypeId::Id non-const to fix this. I was able to find an easy reproducer (tried in godbolt with x64 msvc v19.32 and `/GL` as compiler flags to enable lto): ```c++ template struct TypeId { // Remove the const here and below to make it work. static const char Id; }; template const char TypeId::Id = 0; template bool isSame() { return &TypeId::Id == &TypeId::Id; } class A {}; class B {}; int main() { // This should output "is same 0" because the addresses of A's and B's // TypeId::Id should be different. printf("is same %d\n", isSame()); return 0; } ``` Differential Revision: https://reviews.llvm.org/D139974 --- llvm/include/llvm/ADT/Any.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/ADT/Any.h b/llvm/include/llvm/ADT/Any.h index 0e2f587..934dfc1 100644 --- a/llvm/include/llvm/ADT/Any.h +++ b/llvm/include/llvm/ADT/Any.h @@ -31,9 +31,9 @@ class LLVM_EXTERNAL_VISIBILITY Any { // identifier for the type `T`. It is explicitly marked with default // visibility so that when `-fvisibility=hidden` is used, the loader still // merges duplicate definitions across DSO boundaries. - template struct TypeId { - static const char Id; - }; + // We also cannot mark it as `const`, otherwise msvc merges all definitions + // when lto is enabled, making any comparison return true. + template struct TypeId { static char Id; }; struct StorageBase { virtual ~StorageBase() = default; @@ -117,7 +117,7 @@ private: std::unique_ptr Storage; }; -template const char Any::TypeId::Id = 0; +template char Any::TypeId::Id = 0; template bool any_isa(const Any &Value) { if (!Value.Storage) -- 2.7.4