Make forward-declaring bssl::UniquePtr<T> actually work.
The compiler complains about:
error: explicit specialization of
'bssl::internal::Deleter<evp_pkey_st>' after instantiation
This is because, although the deleter's operator() is not instantiated
without emitting std::unique_ptr's destructor, the deleter itself *is*.
Deleters are allowed to have non-zero size, so a std::unique_ptr
actually embeds a copy of the deleter, so it needs the size of the
deleter.
As with all problems in computer science, we fix this with a layer of
indirection. Instead of specializing the deleter, we specialize
bssl::internal::DeleterImpl which, when specialized, has a static method
Free. That is only instantiated inside
bssl::internal::Deleter::operator(), giving us the desired properties.
(Did I mention forward decls are terrible? I wish people wouldn't want
them so much.)
Also appease clang-format.
Change-Id: I9a07b2fd13e8bdfbd204e225ac72c52d20a397dc
Reviewed-on: https://boringssl-review.googlesource.com/10964
Reviewed-by: Matt Braithwaite <mab@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/base.h b/include/openssl/base.h
index ff3f7ee..fab293e 100644
--- a/include/openssl/base.h
+++ b/include/openssl/base.h
@@ -335,7 +335,23 @@
namespace internal {
-template <class T> struct Deleter {};
+template <typename T>
+struct DeleterImpl {};
+
+template <typename T>
+struct Deleter {
+ void operator()(T *ptr) {
+ // Rather than specialize Deleter for each type, we specialize
+ // DeleterImpl. This allows bssl::UniquePtr<T> to be used while only
+ // including base.h as long as the destructor is not emitted. This matches
+ // std::unique_ptr's behavior on forward-declared types.
+ //
+ // DeleterImpl itself is specialized in the corresponding module's header
+ // and must be included to release an object. If not included, the compiler
+ // will error that DeleterImpl<T> does not have a method Free.
+ DeleterImpl<T>::Free(ptr);
+ }
+};
template <typename T, typename CleanupRet, void (*init)(T *),
CleanupRet (*cleanup)(T *)>
@@ -358,22 +374,24 @@
} // namespace internal
-#define BORINGSSL_MAKE_DELETER(type, deleter) \
- namespace internal { \
- template <> struct Deleter<type> { \
- void operator()(type* ptr) { deleter(ptr); } \
- }; \
+#define BORINGSSL_MAKE_DELETER(type, deleter) \
+ namespace internal { \
+ template <> \
+ struct DeleterImpl<type> { \
+ static void Free(type *ptr) { deleter(ptr); } \
+ }; \
}
// This makes a unique_ptr to STACK_OF(type) that owns all elements on the
// stack, i.e. it uses sk_pop_free() to clean up.
-#define BORINGSSL_MAKE_STACK_DELETER(type, deleter) \
+#define BORINGSSL_MAKE_STACK_DELETER(type, deleter) \
namespace internal { \
- template <> struct Deleter<STACK_OF(type)> { \
- void operator()(STACK_OF(type)* ptr) { \
- sk_##type##_pop_free(ptr, deleter); \
- } \
- }; \
+ template <> \
+ struct DeleterImpl<STACK_OF(type)> { \
+ static void Free(STACK_OF(type) *ptr) { \
+ sk_##type##_pop_free(ptr, deleter); \
+ } \
+ }; \
}
// Holds ownership of heap-allocated BoringSSL structures. Sample usage: