Fix ClassIDs for DLL usage
If ClassID::Of<T>() is used inside tint and used outside tint for the same type, and tint is built as a DLL, then the address of the Unique<T>::token can resolve to different addresses, entirely breaking Castable.
Replace address-of for a unique symbol with a single static counter that's incremented for each use of TINT_INSTANTIATE_CLASS_ID().
Change-Id: I40dc81b1273110291d90a1d5ec05428f7e703c6a
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/42460
Reviewed-by: Antonio Maiorano <amaiorano@google.com>
Commit-Queue: Ben Clayton <bclayton@google.com>
diff --git a/src/castable.h b/src/castable.h
index 3599c34..9528d96 100644
--- a/src/castable.h
+++ b/src/castable.h
@@ -22,28 +22,36 @@
namespace tint {
-/// Helper macro to instantiate the ClassID for `CLASS`.
-#define TINT_INSTANTIATE_CLASS_ID(CLASS) \
- template <> \
- const char ::tint::ClassID::Unique<CLASS>::token = 0
+class ClassID;
+
+/// Helper macro to instantiate the TypeInfo<T> template for `CLASS`.
+#define TINT_INSTANTIATE_CLASS_ID(CLASS) \
+ template <> \
+ const tint::ClassID tint::TypeInfo<CLASS>::class_id { \
+ tint::ClassID::New() \
+ }
+
+/// TypeInfo holds type information for the type T.
+/// TINT_INSTANTIATE_CLASS_ID() must be defined in a .cpp file for each type
+/// `T`.
+template <typename T>
+struct TypeInfo {
+ static const ClassID class_id;
+};
/// ClassID represents a unique, comparable identifier for a C++ type.
class ClassID {
- private:
- /// Helper template that holds a single static field, which is used by Of()
- /// to obtain a unique identifier by taking the field's address.
- template <typename T>
- struct Unique {
- static const char token;
- };
-
public:
+ /// @returns a new and unique ClassID
+ static inline ClassID New() {
+ static uintptr_t next(0);
+ return ClassID(next++);
+ }
+
/// @returns the unique ClassID for the type T.
template <typename T>
- static ClassID Of() {
- // Take the address of a static variable to produce a unique identifier for
- // the type T.
- return ClassID{reinterpret_cast<uintptr_t>(&Unique<T>::token)};
+ static inline ClassID Of() {
+ return TypeInfo<T>::class_id;
}
/// Equality operator
@@ -81,7 +89,7 @@
/// @returns true if this object is of, or derives from the class `TO`
template <typename TO>
- bool Is() const {
+ inline bool Is() const {
using FROM = CastableBase;
constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
@@ -146,13 +154,13 @@
/// @returns true if this object is of, or derives from a class with the
/// ClassID `id`.
/// @param id the ClassID to test for
- bool Is(ClassID id) const override {
+ inline bool Is(ClassID id) const override {
return ClassID::Of<CLASS>() == id || BASE::Is(id);
}
/// @returns true if this object is of, or derives from the class `TO`
template <typename TO>
- bool Is() const {
+ inline bool Is() const {
using FROM = Castable;
constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
constexpr const bool upcast = std::is_base_of<TO, FROM>::value;