model unique_ptr<T> as T*

Summary:
Follow strategy that was done to `std::shared_ptr` model and translate
`std::unique_ptr<T>` as raw pointer `T*`.
As a bonus, model `operator[]` of array overload as dereference

Reviewed By: jvillard

Differential Revision: D3785031

fbshipit-source-id: 2c5b0a4
master
Andrzej Kotulski 8 years ago committed by Facebook Github Bot 4
parent 13dbaab446
commit 4637bf877e

@ -7,6 +7,8 @@
* of patent rights can be found in the PATENTS file in the same directory. * of patent rights can be found in the PATENTS file in the same directory.
*/ */
#pragma once
namespace infer_traits { namespace infer_traits {
// all friends of this class and will be translated as type T by infer // all friends of this class and will be translated as type T by infer
// frontend instead of their own type // frontend instead of their own type

@ -10,6 +10,7 @@
#pragma once #pragma once
#include <infer_model/common.h> #include <infer_model/common.h>
#include <infer_model/infer_traits.h>
INFER_NAMESPACE_STD_BEGIN INFER_NAMESPACE_STD_BEGIN
@ -18,6 +19,7 @@ INFER_NAMESPACE_STD_BEGIN
// When changing model, remember to change it for specialization as well! // When changing model, remember to change it for specialization as well!
template <class _Tp, class _Dp = default_delete<_Tp>> template <class _Tp, class _Dp = default_delete<_Tp>>
struct unique_ptr { struct unique_ptr {
// use SFINAE to determine whether _Del::pointer exists // use SFINAE to determine whether _Del::pointer exists
class _Pointer { class _Pointer {
template <typename _Up> template <typename _Up>
@ -31,34 +33,72 @@ struct unique_ptr {
public: public:
typedef decltype(__test<_Del>(0)) type; typedef decltype(__test<_Del>(0)) type;
}; };
public: public:
typedef typename _Pointer::type pointer; typedef typename _Pointer::type pointer;
typedef _Tp element_type; typedef _Tp element_type;
typedef _Dp deleter_type; typedef _Dp deleter_type;
pointer data; private:
/* std::unique_ptr<T> in infer is translated as T*
Look at model of std::shared_ptr for more details */
// translate shared_ptr as type 'pointer'
friend class infer_traits::TranslateAsType<pointer>;
/// type of 'this' in unique_ptr<T> as seen by infer
typedef const void** infer_unique_ptr_t;
// use it to avoid compilation errors and make infer analyzer happy
#define __cast_to_infer_ptr(self) ((infer_unique_ptr_t)self)
static void model_set(infer_unique_ptr_t self, const void* value) {
*self = value;
}
static void model_move(infer_unique_ptr_t self, infer_unique_ptr_t other) {
*self = *other;
model_set(other, nullptr);
}
static pointer model_get(infer_unique_ptr_t self) { return (pointer)(*self); }
static void model_swap(infer_unique_ptr_t infer_self,
infer_unique_ptr_t infer_other) {
const void* t = *infer_self;
*infer_self = *infer_other;
*infer_other = t;
}
pointer __ignore__; // used to keep sizeof(unique_ptr) same as in standard
public:
template <class Y> template <class Y>
unique_ptr(const std__unique_ptr<Y>& u) {} unique_ptr(const std__unique_ptr<Y>& u) {}
constexpr unique_ptr() noexcept : data(nullptr) {} constexpr unique_ptr() noexcept {
model_set(__cast_to_infer_ptr(this), nullptr);
}
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr<_Tp, _Dp>() {} constexpr unique_ptr(nullptr_t) noexcept : unique_ptr<_Tp, _Dp>() {}
explicit unique_ptr(pointer ptr) : data(ptr) {} explicit unique_ptr(pointer ptr) {
model_set(__cast_to_infer_ptr(this), ptr);
}
unique_ptr(pointer ptr, unique_ptr(pointer ptr,
typename conditional< typename conditional<
is_reference<deleter_type>::value, is_reference<deleter_type>::value,
deleter_type, deleter_type,
typename add_lvalue_reference<const deleter_type>::type>::type typename add_lvalue_reference<const deleter_type>::type>::type
__d) noexcept : data(ptr) {} __d) noexcept
: unique_ptr<_Tp, _Dp>(ptr) {}
unique_ptr(pointer ptr, unique_ptr(pointer ptr,
typename remove_reference<deleter_type>::type&& __d) noexcept typename remove_reference<deleter_type>::type&& __d) noexcept
: data(ptr) {} : unique_ptr<_Tp, _Dp>(ptr) {}
unique_ptr(unique_ptr&& u) noexcept : data(u.data) { u.data = nullptr; } unique_ptr(unique_ptr&& u) noexcept {
model_move(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&u));
}
template <class _Up, template <class _Up,
class _Ep, class _Ep,
@ -69,8 +109,8 @@ struct unique_ptr {
is_convertible<_Ep, deleter_type>::value && is_convertible<_Ep, deleter_type>::value &&
(!is_reference<deleter_type>::value || (!is_reference<deleter_type>::value ||
is_same<deleter_type, _Ep>::value)>::type> is_same<deleter_type, _Ep>::value)>::type>
unique_ptr(unique_ptr<_Up, _Ep>&& u) noexcept : data(u.data) { unique_ptr(unique_ptr<_Up, _Ep>&& u) noexcept {
u.data = nullptr; model_move(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&u));
} }
template < template <
@ -81,7 +121,7 @@ struct unique_ptr {
~unique_ptr() { reset(); } ~unique_ptr() { reset(); }
unique_ptr& operator=(unique_ptr&& __u) noexcept { unique_ptr& operator=(unique_ptr&& __u) noexcept {
reset(__u.data); model_move(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&__u));
return *this; return *this;
} }
@ -93,7 +133,7 @@ struct unique_ptr {
pointer>::value && pointer>::value &&
is_assignable<deleter_type&, _Ep&&>::value>::type> is_assignable<deleter_type&, _Ep&&>::value>::type>
unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) noexcept { unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) noexcept {
reset(__u.data); model_move(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&__u));
return *this; return *this;
} }
@ -101,11 +141,14 @@ struct unique_ptr {
reset(); reset();
return *this; return *this;
} }
typename add_lvalue_reference<_Tp>::type operator*() const { return *data; } typename add_lvalue_reference<_Tp>::type operator*() const
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
pointer operator->() const { return data; } pointer operator->() const
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
pointer get() const { return data; } pointer get() const
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
typedef typename remove_reference<deleter_type>::type& _Dp_reference; typedef typename remove_reference<deleter_type>::type& _Dp_reference;
typedef const typename remove_reference<deleter_type>::type& typedef const typename remove_reference<deleter_type>::type&
@ -113,15 +156,16 @@ struct unique_ptr {
_Dp_const_reference get_deleter() const {} _Dp_const_reference get_deleter() const {}
_Dp_reference get_deleter() {} _Dp_reference get_deleter() {}
explicit operator bool() const { return data != nullptr; } explicit operator bool() const {
pointer release() { return data; } return !!(bool)(model_get(__cast_to_infer_ptr(this)));
}
pointer release()
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
void reset(pointer p = nullptr) { data = p; } void reset(pointer p = nullptr) { model_set(__cast_to_infer_ptr(this), p); }
void swap(unique_ptr& u) { void swap(unique_ptr& u) {
pointer tmp = data; model_swap(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&u));
data = u.data;
u.data = tmp;
} }
}; };
@ -146,13 +190,45 @@ struct unique_ptr<_Tp[], _Dp> {
typedef _Tp element_type; typedef _Tp element_type;
typedef _Dp deleter_type; typedef _Dp deleter_type;
pointer data; private:
// translate shared_ptr as type pointer
friend class infer_traits::TranslateAsType<pointer>;
/// type of 'this' in unique_ptr<T> as seen by infer
typedef const void** infer_unique_ptr_t;
// use it to avoid compilation errors and make infer analyzer happy
#define __cast_to_infer_ptr(self) ((infer_unique_ptr_t)self)
static void model_set(infer_unique_ptr_t self, const void* value) {
*self = value;
}
static void model_move(infer_unique_ptr_t self, infer_unique_ptr_t other) {
*self = *other;
model_set(other, nullptr);
}
static pointer model_get(infer_unique_ptr_t self) { return (pointer)(*self); }
static void model_swap(infer_unique_ptr_t infer_self,
infer_unique_ptr_t infer_other) {
const void* t = *infer_self;
*infer_self = *infer_other;
*infer_other = t;
}
pointer __ignore__; // used to keep sizeof(unique_ptr) same as in standard
constexpr unique_ptr() noexcept : data(nullptr) {} public:
constexpr unique_ptr() noexcept {
model_set(__cast_to_infer_ptr(this), nullptr);
}
constexpr unique_ptr(nullptr_t) noexcept : data(nullptr) {} constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() {}
explicit unique_ptr(pointer ptr) : data(ptr) {} explicit unique_ptr(pointer ptr) {
model_set(__cast_to_infer_ptr(this), ptr);
}
unique_ptr( unique_ptr(
pointer ptr, pointer ptr,
@ -160,12 +236,14 @@ struct unique_ptr<_Tp[], _Dp> {
is_reference<deleter_type>::value, is_reference<deleter_type>::value,
deleter_type, deleter_type,
typename add_lvalue_reference<const deleter_type>::type>::type __d) typename add_lvalue_reference<const deleter_type>::type>::type __d)
: data(ptr) {} : unique_ptr(ptr) {}
unique_ptr(pointer ptr, typename remove_reference<deleter_type>::type&& __d) unique_ptr(pointer ptr, typename remove_reference<deleter_type>::type&& __d)
: data(ptr) {} : unique_ptr(ptr) {}
unique_ptr(unique_ptr&& u) : data(u.data) { u.data = nullptr; } unique_ptr(unique_ptr&& u) {
model_move(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&u));
}
template <class _Up, template <class _Up,
class _Ep, class _Ep,
@ -176,8 +254,8 @@ struct unique_ptr<_Tp[], _Dp> {
is_convertible<_Ep, deleter_type>::value && is_convertible<_Ep, deleter_type>::value &&
(!is_reference<deleter_type>::value || (!is_reference<deleter_type>::value ||
is_same<deleter_type, _Ep>::value)>::type> is_same<deleter_type, _Ep>::value)>::type>
unique_ptr(unique_ptr<_Up, _Ep>&& u) : data(u.data) { unique_ptr(unique_ptr<_Up, _Ep>&& u) {
u.data = nullptr; model_move(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&u));
} }
template < template <
@ -188,7 +266,7 @@ struct unique_ptr<_Tp[], _Dp> {
~unique_ptr() { reset(); } ~unique_ptr() { reset(); }
unique_ptr& operator=(unique_ptr&& __u) { unique_ptr& operator=(unique_ptr&& __u) {
reset(__u.data); model_move(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&__u));
return *this; return *this;
} }
@ -200,7 +278,7 @@ struct unique_ptr<_Tp[], _Dp> {
pointer>::value && pointer>::value &&
is_assignable<deleter_type&, _Ep&&>::value>::type> is_assignable<deleter_type&, _Ep&&>::value>::type>
unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) { unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) {
reset(__u.data); model_move(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&__u));
return *this; return *this;
} }
@ -209,9 +287,11 @@ struct unique_ptr<_Tp[], _Dp> {
return *this; return *this;
} }
typename add_lvalue_reference<_Tp>::type operator[](size_t i) const {} typename add_lvalue_reference<_Tp>::type operator[](size_t i) const
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
pointer get() const { return data; } pointer get() const
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
typedef typename remove_reference<deleter_type>::type& _Dp_reference; typedef typename remove_reference<deleter_type>::type& _Dp_reference;
typedef const typename remove_reference<deleter_type>::type& typedef const typename remove_reference<deleter_type>::type&
@ -219,15 +299,16 @@ struct unique_ptr<_Tp[], _Dp> {
_Dp_const_reference get_deleter() const {} _Dp_const_reference get_deleter() const {}
_Dp_reference get_deleter() {} _Dp_reference get_deleter() {}
explicit operator bool() const { return data != nullptr; } explicit operator bool() const {
pointer release() { return data; } return !!(bool)(model_get(__cast_to_infer_ptr(this)));
}
pointer release()
__attribute__((deprecated("__infer_replace_with_deref_first_arg"))) {}
void reset(pointer p = nullptr) { data = p; } void reset(pointer p = nullptr) { model_set(__cast_to_infer_ptr(this), p); }
void swap(unique_ptr& u) { void swap(unique_ptr& u) {
pointer tmp = data; model_swap(__cast_to_infer_ptr(this), __cast_to_infer_ptr(&u));
data = u.data;
u.data = tmp;
} }
}; };
@ -370,3 +451,5 @@ template <typename _Tp, typename... _Args>
inline typename _MakeUniq2<_Tp>::__invalid_type make_unique(_Args&&...) = inline typename _MakeUniq2<_Tp>::__invalid_type make_unique(_Args&&...) =
delete; delete;
INFER_NAMESPACE_STD_END INFER_NAMESPACE_STD_END
#undef __cast_to_infer_ptr

@ -29,11 +29,21 @@ int empty_ptr_deref() {
return *x; return *x;
} }
int empty_array_ptr_deref() {
std::unique_ptr<int[]> x;
return x[0];
}
int nullptr_ptr_deref() { int nullptr_ptr_deref() {
std::unique_ptr<int> x(nullptr); std::unique_ptr<int> x(nullptr);
return *x; return *x;
} }
int nullptr_array_ptr_deref() {
std::unique_ptr<int[]> x(nullptr);
return x[2];
}
int empty_ptr_field_deref() { int empty_ptr_field_deref() {
std::unique_ptr<X> x; std::unique_ptr<X> x;
return x.get()->field; return x.get()->field;

@ -49,7 +49,9 @@ public class UniquePtrDerefTest {
throws InterruptedException, IOException, InferException { throws InterruptedException, IOException, InferException {
String[] procedures = { String[] procedures = {
"empty_ptr_deref", "empty_ptr_deref",
"empty_array_ptr_deref",
"nullptr_ptr_deref", "nullptr_ptr_deref",
"nullptr_array_ptr_deref",
"empty_ptr_field_deref", "empty_ptr_field_deref",
"empty_ptr_field_deref2", "empty_ptr_field_deref2",
"empty_ptr_method_deref", "empty_ptr_method_deref",

Loading…
Cancel
Save