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>
This commit is contained in:
parent
72260e44ae
commit
80cb20de7c
|
@ -22,28 +22,36 @@
|
||||||
|
|
||||||
namespace tint {
|
namespace tint {
|
||||||
|
|
||||||
/// Helper macro to instantiate the ClassID for `CLASS`.
|
class ClassID;
|
||||||
|
|
||||||
|
/// Helper macro to instantiate the TypeInfo<T> template for `CLASS`.
|
||||||
#define TINT_INSTANTIATE_CLASS_ID(CLASS) \
|
#define TINT_INSTANTIATE_CLASS_ID(CLASS) \
|
||||||
template <> \
|
template <> \
|
||||||
const char ::tint::ClassID::Unique<CLASS>::token = 0
|
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.
|
/// ClassID represents a unique, comparable identifier for a C++ type.
|
||||||
class ClassID {
|
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:
|
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.
|
/// @returns the unique ClassID for the type T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static ClassID Of() {
|
static inline ClassID Of() {
|
||||||
// Take the address of a static variable to produce a unique identifier for
|
return TypeInfo<T>::class_id;
|
||||||
// the type T.
|
|
||||||
return ClassID{reinterpret_cast<uintptr_t>(&Unique<T>::token)};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Equality operator
|
/// Equality operator
|
||||||
|
@ -81,7 +89,7 @@ class CastableBase {
|
||||||
|
|
||||||
/// @returns true if this object is of, or derives from the class `TO`
|
/// @returns true if this object is of, or derives from the class `TO`
|
||||||
template <typename TO>
|
template <typename TO>
|
||||||
bool Is() const {
|
inline bool Is() const {
|
||||||
using FROM = CastableBase;
|
using FROM = CastableBase;
|
||||||
constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
|
constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
|
||||||
constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
|
constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
|
||||||
|
@ -146,13 +154,13 @@ class Castable : public BASE {
|
||||||
/// @returns true if this object is of, or derives from a class with the
|
/// @returns true if this object is of, or derives from a class with the
|
||||||
/// ClassID `id`.
|
/// ClassID `id`.
|
||||||
/// @param id the ClassID to test for
|
/// @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);
|
return ClassID::Of<CLASS>() == id || BASE::Is(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @returns true if this object is of, or derives from the class `TO`
|
/// @returns true if this object is of, or derives from the class `TO`
|
||||||
template <typename TO>
|
template <typename TO>
|
||||||
bool Is() const {
|
inline bool Is() const {
|
||||||
using FROM = Castable;
|
using FROM = Castable;
|
||||||
constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
|
constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
|
||||||
constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
|
constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
|
||||||
|
|
Loading…
Reference in New Issue