r178563 - If a defaulted special member is implicitly deleted, check whether it's

Nico Weber thakis at chromium.org
Thu Apr 18 13:15:56 PDT 2013


On Thu, Apr 18, 2013 at 11:10 AM, Richard Smith <richard at metafoo.co.uk>wrote:

> On Thu, Apr 18, 2013 at 10:50 AM, Nico Weber <thakis at chromium.org> wrote:
>
>> Filed PR15783, thanks.
>>
>> The WebKit code was added here and seems to be doing what the people who
>> wrote it want:
>> https://bugs.webkit.org/show_bug.cgi?id=105026
>> https://bugs.webkit.org/attachment.cgi?id=179485&action=review
>>
>
> Looks like it's trying to determine whether this will compile:
>
> template <>
> template <typename T>
> void
> MemoryInstrumentation::InstrumentationSelector<true>::reportObjectMemoryUsage(const
> T* object, MemoryObjectInfo* memoryObjectInfo)
> {
>     object->reportMemoryUsage(memoryObjectInfo);
> }
>
> For that, it should really be doing SFINAE on the
> "object->reportMemoryUsage(memoryObjectInfo)" expression.
>

Is that possible when using only C++03 features? Checking for
T::reportMemoryUsage in a parameter list will miss cases where only T's
superclass implements reportMemoryUsage.


>
>  On Thu, Apr 18, 2013 at 10:43 AM, Richard Smith <richard at metafoo.co.uk>wrote:
>>
>>> On Thu, Apr 18, 2013 at 10:09 AM, Nico Weber <thakis at chromium.org>wrote:
>>>
>>>> Hi Richard,
>>>>
>>>> this breaks compilation of this bit of code in WebKit, which does
>>>> metaprogramming to check if a class implements a given method:
>>>>
>>>> template <typename Type> class IsInstrumented {
>>>>   class yes { char m; };
>>>>   class no { yes m[2]; };
>>>>   struct BaseMixin {
>>>>     void reportMemoryUsage() const {}
>>>>   };
>>>>   struct Base : public Type, public BaseMixin {
>>>>   };
>>>>   template <typename T, T t> class Helper {
>>>>   };
>>>>   template <typename U>
>>>>   static no
>>>>   deduce(U *, Helper<void(BaseMixin::*)() const, &U::reportMemoryUsage>
>>>> * = 0);
>>>>   static yes deduce(...);
>>>> public:
>>>>   static const bool result = sizeof(yes) == sizeof(deduce((Base *)(0)));
>>>> };
>>>>
>>>> template <typename T> bool hasReportMemoryUsage(const T *object) {
>>>>   return IsInstrumented<T>::result;
>>>> }
>>>>
>>>> class Timer {
>>>>   void operator delete(void *p) {}
>>>> public:
>>>>   virtual ~Timer();
>>>> };
>>>> bool f() {
>>>>   Timer m_cacheTimer;
>>>>   return hasReportMemoryUsage(&m_cacheTimer);
>>>> }
>>>>
>>>>
>>>> The error message looks like this:
>>>>
>>>> $ clang -c repro.ii -std=gnu++11  # works in older clang
>>>> $ third_party/llvm-build/Release+Asserts/bin/clang -c repro.ii
>>>> -std=gnu++11
>>>> repro.ii:7:10: error: deleted function '~Base' cannot override a
>>>> non-deleted function
>>>>   struct Base : public Type, public BaseMixin {
>>>>          ^
>>>> repro.ii:13:51: note: in instantiation of member class
>>>> 'IsInstrumented<Timer>::Base' requested here
>>>>   deduce(U *, Helper<void(BaseMixin::*)() const, &U::reportMemoryUsage>
>>>> * = 0);
>>>>                                                   ^
>>>> repro.ii:13:3: note: while substituting deduced template arguments into
>>>> function template 'deduce' [with U = IsInstrumented<Timer>::Base]
>>>>   deduce(U *, Helper<void(BaseMixin::*)() const, &U::reportMemoryUsage>
>>>> * = 0);
>>>>   ^
>>>> repro.ii:20:10: note: in instantiation of template class
>>>> 'IsInstrumented<Timer>' requested here
>>>>   return IsInstrumented<T>::result;
>>>>          ^
>>>> repro.ii:30:10: note: in instantiation of function template
>>>> specialization 'hasReportMemoryUsage<Timer>' requested here
>>>>   return hasReportMemoryUsage(&m_cacheTimer);
>>>>          ^
>>>> repro.ii:26:11: note: overridden virtual function is here
>>>>   virtual ~Timer();
>>>>           ^
>>>> 1 error generated.
>>>>
>>>>
>>>> Is this expected? I suppose so, but the diagnostic is a bit hard to
>>>> read (it's not clear to me why ~Base() is deleted).
>>>>
>>>
>>> Yes, the diagnostic seems to be correct, if unhelpful. Feel free to file
>>> a bug on the diagnostic (if not, I'll try to remember to fix this but can't
>>> promise!). We should be pointing out that the function is implicitly
>>> deleted because it would otherwise try to call an inaccessible
>>> class-specific 'operator delete'.
>>>
>>>
>>>> It compiles fine if I give Base an explicit destructor. Is this the
>>>> right fix?
>>>>
>>>
>>> It's inelegant, but yes, that should work (unless you use this with a
>>> final class or similar...). The check itself looks a bit odd -- usually,
>>> one would check whether a certain expression is valid (something like
>>> putting sizeof(declval<Type>().reportMemoryUsage()) into your SFINAE
>>> context) rather than checking whether a member with the given name exists
>>> -- but assuming it's getting the effect you want, I'll have a think about a
>>> more reliable way to perform the test.
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130418/53cb1ba4/attachment.html>


More information about the cfe-commits mailing list