Reviewed By: akotulski Differential Revision: D5398162 fbshipit-source-id: bf61516master
parent
5784357322
commit
30e1f4295b
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <infer_model/common.h>
|
||||||
|
#include <infer_model/infer_traits.h>
|
||||||
|
|
||||||
|
unsigned long int __infer_nondet_unsigned_long_int();
|
||||||
|
|
||||||
|
INFER_NAMESPACE_STD_BEGIN
|
||||||
|
|
||||||
|
// forward declaration because it is used here
|
||||||
|
template <class T>
|
||||||
|
class shared_ptr;
|
||||||
|
|
||||||
|
// Ideally: : public std__weak_ptr<T>
|
||||||
|
// use inheritance to avoid compilation errors when using
|
||||||
|
// methods / non-member functions that are not modeled
|
||||||
|
// Currently not inherited because it leads to Symexec_memory_error
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class weak_ptr {
|
||||||
|
|
||||||
|
template <class>
|
||||||
|
friend class weak_ptr;
|
||||||
|
|
||||||
|
// WARNING: if sizeof(weak_ptr) becomes different than 16, it may
|
||||||
|
// lead to compilation errors
|
||||||
|
T* ptr;
|
||||||
|
void* __ignore;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Conversion constructors to allow implicit conversions.
|
||||||
|
// it's here purely to avoid compilation errors
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
weak_ptr(const std__weak_ptr<Y>& r) {}
|
||||||
|
|
||||||
|
// constructors:
|
||||||
|
constexpr weak_ptr() noexcept { ptr = nullptr; }
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
weak_ptr(const shared_ptr<Y>& r) noexcept {
|
||||||
|
ptr = r.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
weak_ptr(const weak_ptr& r) noexcept { ptr = r.ptr; }
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
weak_ptr(const weak_ptr<Y>& r) noexcept {
|
||||||
|
ptr = r.ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
weak_ptr(weak_ptr&& r) noexcept {
|
||||||
|
ptr = r.ptr;
|
||||||
|
r.ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
weak_ptr(weak_ptr<Y>&& r) noexcept {
|
||||||
|
ptr = r.ptr;
|
||||||
|
r.ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// destructor:
|
||||||
|
~weak_ptr() { ptr = nullptr; }
|
||||||
|
|
||||||
|
// assignment:
|
||||||
|
weak_ptr& operator=(const weak_ptr& r) noexcept {
|
||||||
|
// weak_ptr<T>(r).swap(*this);
|
||||||
|
ptr = r.ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
weak_ptr& operator=(const weak_ptr<Y>& r) noexcept {
|
||||||
|
// weak_ptr<T>(r).swap(*this);
|
||||||
|
ptr = r.ptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
weak_ptr& operator=(const shared_ptr<Y>& r) noexcept {
|
||||||
|
// weak_ptr<T>(r).swap(*this);
|
||||||
|
ptr = r.get();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
weak_ptr& operator=(weak_ptr&& r) noexcept {
|
||||||
|
// shared_ptr<T>(std::move(r)).swap(*this);
|
||||||
|
ptr = r.ptr;
|
||||||
|
r.ptr = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y,
|
||||||
|
typename = typename enable_if<is_convertible<Y*, T*>::value>::type>
|
||||||
|
weak_ptr& operator=(weak_ptr<Y>&& r) {
|
||||||
|
// weak_ptr<T>(std::move(r)).swap(*this);
|
||||||
|
ptr = r.ptr;
|
||||||
|
r.ptr = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// modifiers:
|
||||||
|
void swap(weak_ptr& r) noexcept {
|
||||||
|
T* tmp = ptr;
|
||||||
|
ptr = r.ptr;
|
||||||
|
r.ptr = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() noexcept {
|
||||||
|
// weak_ptr().swap(*this);
|
||||||
|
ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// observers:
|
||||||
|
long use_count() const noexcept {
|
||||||
|
if (ptr) {
|
||||||
|
return __infer_nondet_unsigned_long_int();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool expired() const noexcept { return use_count() <= 0; }
|
||||||
|
|
||||||
|
shared_ptr<T> lock() const noexcept {
|
||||||
|
if (use_count() > 0) {
|
||||||
|
return shared_ptr<T>(ptr);
|
||||||
|
}
|
||||||
|
return shared_ptr<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
bool owner_before(shared_ptr<U> const& b) const {
|
||||||
|
return true; /* FIXME - use non-det*/
|
||||||
|
}
|
||||||
|
template <class U>
|
||||||
|
bool owner_before(weak_ptr<U> const& b) const {
|
||||||
|
return true; /* FIXME - use non-det */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct owner_less;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct owner_less<weak_ptr<T>>
|
||||||
|
: binary_function<weak_ptr<T>, weak_ptr<T>, bool> {
|
||||||
|
typedef bool result_type;
|
||||||
|
bool operator()(weak_ptr<T> const& x, weak_ptr<T> const& y) const {
|
||||||
|
return x.owner_before(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(shared_ptr<T> const& x, weak_ptr<T> const& y) const {
|
||||||
|
return x.owner_before(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator()(weak_ptr<T> const& x, shared_ptr<T> const& y) const {
|
||||||
|
return x.owner_before(y);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
INFER_NAMESPACE_STD_END
|
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
/* Compilation tests */
|
||||||
|
|
||||||
|
namespace shared_ptr_conv_from_derived {
|
||||||
|
/*
|
||||||
|
shared_ptr conversion does not work if inheritance is not public
|
||||||
|
*/
|
||||||
|
class Base {};
|
||||||
|
class Derived : public Base {};
|
||||||
|
class Q {
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<Base> m_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setM(std::shared_ptr<Base> m) { m_ = std::move(m); }
|
||||||
|
};
|
||||||
|
class P {
|
||||||
|
std::shared_ptr<Derived> m_;
|
||||||
|
Q q_;
|
||||||
|
void u() { q_.setM(m_); }
|
||||||
|
};
|
||||||
|
}
|
@ -0,0 +1,256 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
void __infer_fail(char*);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace weak_ptr_constructors {
|
||||||
|
|
||||||
|
struct Base {
|
||||||
|
int* f1;
|
||||||
|
Base(int* f1 = nullptr) : f1(f1) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Derived : public Base {
|
||||||
|
int* f2;
|
||||||
|
Derived(int* f1 = nullptr) : Base(f1) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::weak_ptr<Base> empty() { return std::weak_ptr<Base>(); }
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromWeakBaseConstr(std::weak_ptr<Base> b) {
|
||||||
|
return std::weak_ptr<Base>(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromWeakBaseAssign(std::weak_ptr<Base> b) {
|
||||||
|
std::weak_ptr<Base> result;
|
||||||
|
result = b;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromWeakDerivedConstr(std::weak_ptr<Derived> d) {
|
||||||
|
return std::weak_ptr<Base>(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromWeakDerivedAssign(std::weak_ptr<Derived> d) {
|
||||||
|
std::weak_ptr<Base> result;
|
||||||
|
result = d;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromSharedBaseConstr(std::shared_ptr<Base> b) {
|
||||||
|
return std::weak_ptr<Base>(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromSharedBaseAssign(std::shared_ptr<Base> b) {
|
||||||
|
std::weak_ptr<Base> result;
|
||||||
|
result = b;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromSharedDerivedConstr(std::shared_ptr<Derived> d) {
|
||||||
|
return std::weak_ptr<Base>(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromSharedDerivedConstr2(std::shared_ptr<Derived> d) {
|
||||||
|
std::weak_ptr<Derived> sd(d);
|
||||||
|
return std::weak_ptr<Base>(sd);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::weak_ptr<Base> fromSharedDerivedAssign(std::shared_ptr<Derived> d) {
|
||||||
|
std::weak_ptr<Derived> sd(d);
|
||||||
|
std::weak_ptr<Base> result;
|
||||||
|
result = sd;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace weak_ptr_derefs {
|
||||||
|
using namespace weak_ptr_constructors;
|
||||||
|
|
||||||
|
int safeGetFromEmpty_good() {
|
||||||
|
auto w = empty();
|
||||||
|
auto s = w.lock();
|
||||||
|
while (!s)
|
||||||
|
;
|
||||||
|
return *s->f1; // never reached
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<Base> safeGet(std::weak_ptr<Base> p) {
|
||||||
|
auto s = p.lock();
|
||||||
|
while (!s)
|
||||||
|
;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromWeakBaseConstr_bad(int v) {
|
||||||
|
auto b = std::make_shared<Base>(&v);
|
||||||
|
auto s = safeGet(fromWeakBaseConstr(std::weak_ptr<Base>(b)));
|
||||||
|
b->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromWeakBaseAssign_bad(int v) {
|
||||||
|
auto b = std::make_shared<Base>(&v);
|
||||||
|
auto s = safeGet(fromWeakBaseAssign(std::weak_ptr<Base>(b)));
|
||||||
|
b->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromWeakDerivedConstr_bad(int v) {
|
||||||
|
auto d = std::make_shared<Derived>(&v);
|
||||||
|
auto s = safeGet(fromWeakDerivedConstr(std::weak_ptr<Derived>(d)));
|
||||||
|
d->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromWeakDerivedAssign_bad(int v) {
|
||||||
|
auto d = std::make_shared<Derived>(&v);
|
||||||
|
auto s = safeGet(fromWeakDerivedAssign(std::weak_ptr<Derived>(d)));
|
||||||
|
d->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromSharedBaseConstr_bad(int v) {
|
||||||
|
auto b = std::make_shared<Base>(&v);
|
||||||
|
auto s = safeGet(fromSharedBaseConstr(b));
|
||||||
|
b->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromSharedBaseAssign_bad(int v) {
|
||||||
|
auto b = std::make_shared<Base>(&v);
|
||||||
|
auto s = safeGet(fromSharedBaseAssign(b));
|
||||||
|
b->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromSharedDerivedConstr_bad(int v) {
|
||||||
|
auto b = std::make_shared<Derived>(&v);
|
||||||
|
auto s = safeGet(fromSharedDerivedConstr(b));
|
||||||
|
b->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromSharedDerivedConstr2_bad(int v) {
|
||||||
|
auto b = std::make_shared<Derived>(&v);
|
||||||
|
auto s = safeGet(fromSharedDerivedConstr2(b));
|
||||||
|
b->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int safeGetFromSharedDerivedAssign_bad(int v) {
|
||||||
|
auto b = std::make_shared<Derived>(&v);
|
||||||
|
auto s = safeGet(fromSharedDerivedAssign(b));
|
||||||
|
b->f1 = nullptr;
|
||||||
|
return *s->f1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace weak_ptr_modifiers {
|
||||||
|
|
||||||
|
void reset(std::weak_ptr<int>& p) { p.reset(); }
|
||||||
|
|
||||||
|
void swap(std::weak_ptr<int>& p) {
|
||||||
|
std::weak_ptr<int> q;
|
||||||
|
q.swap(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace weak_ptr_observers {
|
||||||
|
using namespace weak_ptr_constructors;
|
||||||
|
|
||||||
|
long use_count(std::weak_ptr<int>& p) { return p.use_count(); }
|
||||||
|
|
||||||
|
void use_count_empty_bad() {
|
||||||
|
std::weak_ptr<int> p;
|
||||||
|
if (p.use_count() == 0) {
|
||||||
|
__infer_fail("use_count on empty weak_ptr is 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void use_count_after_reset_bad(std::weak_ptr<int>& p) {
|
||||||
|
p.reset();
|
||||||
|
if (p.use_count() == 0) {
|
||||||
|
__infer_fail("use_count after weak_ptr reset is 0");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool expired(std::weak_ptr<int>& p) { return p.expired(); }
|
||||||
|
|
||||||
|
void expired_empty_bad() {
|
||||||
|
std::weak_ptr<int> p;
|
||||||
|
if (p.expired()) {
|
||||||
|
__infer_fail("expired on empty weak_ptr is true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void expired_after_reset_bad(std::weak_ptr<int>& p) {
|
||||||
|
p.reset();
|
||||||
|
if (p.expired()) {
|
||||||
|
__infer_fail("expired after weak_ptr reset is true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void expired_after_swap_bad(std::weak_ptr<int>& p) {
|
||||||
|
std::weak_ptr<int> q;
|
||||||
|
q.swap(p);
|
||||||
|
if (p.expired()) {
|
||||||
|
__infer_fail("expired after weak_ptr swap with empty is true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<int> lock(std::weak_ptr<int>& p) { return p.lock(); }
|
||||||
|
|
||||||
|
void empty_weak_lock_returns_null_bad() {
|
||||||
|
std::weak_ptr<int> p;
|
||||||
|
auto s = p.lock();
|
||||||
|
int _ = *s.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void expired_means_null_bad(std::weak_ptr<int>& p) {
|
||||||
|
if (p.expired()) {
|
||||||
|
auto s = p.lock();
|
||||||
|
int _ = *s.get();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock_can_be_null_bad(std::weak_ptr<int>& p) {
|
||||||
|
auto s = p.lock();
|
||||||
|
int _ = *s.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
int safe_deref_good(std::weak_ptr<int>& p) {
|
||||||
|
if (auto s = p.lock()) {
|
||||||
|
return *s.get();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<int> shared_still_in_scope_good_FP() {
|
||||||
|
/* It's not a big issue to FP in this case.
|
||||||
|
Code should not be written like that anyway. */
|
||||||
|
auto s = std::make_shared<int>();
|
||||||
|
auto p = std::weak_ptr<int>(s);
|
||||||
|
auto s2 = p.lock();
|
||||||
|
auto _ = *s2.get();
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool owner_before(std::weak_ptr<Base>& p, std::weak_ptr<Base>& q) {
|
||||||
|
return p.owner_before(q);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool owner_before(std::weak_ptr<Base>& p, std::shared_ptr<Derived>& q) {
|
||||||
|
return p.owner_before(q);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2017 - present Facebook, Inc.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the BSD style license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree. An additional grant
|
||||||
|
* of patent rights can be found in the PATENTS file in the same directory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
/* Compilation tests */
|
||||||
|
|
||||||
|
namespace weak_ptr_lock_repro_small {
|
||||||
|
template <class T>
|
||||||
|
std::shared_ptr<T> joinT(std::shared_ptr<T> x) {
|
||||||
|
return x;
|
||||||
|
};
|
||||||
|
|
||||||
|
void foo(std::weak_ptr<int> p) {
|
||||||
|
auto self = p.lock();
|
||||||
|
std::shared_ptr<int> x = joinT(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace weak_ptr_lock_repro_large {
|
||||||
|
|
||||||
|
class S {
|
||||||
|
public:
|
||||||
|
template <typename T>
|
||||||
|
std::shared_ptr<T> joinT(std::shared_ptr<T> s);
|
||||||
|
};
|
||||||
|
|
||||||
|
class DCC {
|
||||||
|
public:
|
||||||
|
const std::shared_ptr<S>& s();
|
||||||
|
};
|
||||||
|
|
||||||
|
class DC {};
|
||||||
|
|
||||||
|
class CDM {
|
||||||
|
public:
|
||||||
|
std::shared_ptr<DC> gdc(std::function<DCC()>);
|
||||||
|
};
|
||||||
|
|
||||||
|
class RDC : DC {
|
||||||
|
public:
|
||||||
|
static std::shared_ptr<RDC> create(std::function<DCC()> cf);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const std::shared_ptr<CDM> cdm;
|
||||||
|
mutable std::function<std::shared_ptr<DC>()> dcf;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::shared_ptr<RDC> RDC::create(std::function<DCC()> cf) {
|
||||||
|
auto dc = std::make_shared<RDC>();
|
||||||
|
dc->dcf =
|
||||||
|
[ cf = std::move(cf),
|
||||||
|
weakSelf = std::weak_ptr<RDC>(dc) ]() mutable->std::shared_ptr<DC> {
|
||||||
|
if (auto self = weakSelf.lock()) {
|
||||||
|
return self->cdm->gdc([&]() mutable {
|
||||||
|
auto c = cf();
|
||||||
|
c.s()->joinT(self);
|
||||||
|
return c;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
return dc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace weak_ptr_owner_less {
|
||||||
|
class K {};
|
||||||
|
class V {};
|
||||||
|
class C {
|
||||||
|
using S = std::set<std::weak_ptr<K>, std::owner_less<std::weak_ptr<K>>>;
|
||||||
|
std::
|
||||||
|
map<std::weak_ptr<K>, std::weak_ptr<V>, std::owner_less<std::weak_ptr<K>>>
|
||||||
|
m;
|
||||||
|
S s;
|
||||||
|
#ifdef INFER_USE_LIBCPP
|
||||||
|
/* requires Clang headers */
|
||||||
|
std::unordered_map<K, S> u;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in new issue