This is an archive of the discontinued LLVM Phabricator instance.

CRTP-based version of D96817
ClosedPublic

Authored by tatyana-krasnukha on Feb 18 2021, 5:35 AM.

Details

Summary

Being graceful, this approach has a few drawbacks. As I wrote, this pattern is not very popular, and when a developer defines a derived class they may not know that the class must inherit from the Clonable.
There is also a hardly probable but still possible pitfall of copy-pasting an existing class. For example, we define OptionValueSInt64 by copying OptionValueUInt64. If we forget to rename the template argument, we will not have any compile-time errors:

class OptionValueSInt64 : public Cloneable<OptionValueUInt64, OptionValue> {
...
};

Now our Clone function turn into:

std::shared_ptr<OptionValue> OptionValueSInt64 ::Clone() const override {
  return std::make_shared<OptionValueUInt64>(static_cast<const OptionValueUInt64&>(*this));
}

So, we get static_cast from OptionValueSInt64 to OptionValueUInt64 and undefined behaviour.

Diff Detail

Event Timeline

tatyana-krasnukha requested review of this revision.Feb 18 2021, 5:35 AM
tatyana-krasnukha edited the summary of this revision. (Show Details)Feb 18 2021, 7:47 AM

I guess a lot of the things I highlighted as "unrelated refactoring" are actually the various bugfixes the patch is about?

It might be worth separating those into separate patches in a series to make it clear what issues are being fixed in each change.

Fair point about the risk of mistyping something. I'm not super fussed either way - just like to avoid rewriting these functions over and over again.

(also, would it be possible for the non-trivial impelmentations to be made trivial by moving the work into the copy constructor?)

lldb/include/lldb/Interpreter/OptionValueArch.h
29–30

There's no need to include "Cloneable(), " here, it's implicit. (indeed you could remove the "OptionValue(), " here in a separate preliminary commit to make this patch's diff smaller/easier to read.

lldb/include/lldb/Interpreter/OptionValueArray.h
41–43

Why does this need to be here?

lldb/include/lldb/Utility/Cloneable.h
47–48

I think you can put the static_assert at the class scope, rather than needing to put it inside a function - having it inside a function here makes the type non-trivially destructible which would be unfortunate/unnecessary overhead.

lldb/source/Interpreter/OptionValueArgs.cpp
16–18 ↗(On Diff #324604)

Is this unrelated refactoring?

lldb/source/Interpreter/OptionValueProperties.cpp
231–275

Is this unrelated refactoring/changes?

545–571

And this?

lldb/source/Target/Process.cpp
91–95

unrelated refactoring?

lldb/source/Target/Target.cpp
3652–3658

This class didn't have a DeepCopy function before - does it need one now? Or is this an intermediate abstract base, in which case it doesn't need to use Cloneable - only the most derived classes (well, the ones that are instantiated, be they most derived or not) need Cloneable, I think?

3670–3672

Why this change?

Oh, is the previous code incorrect - binding two unrelated shared_ptrs to the same memory? Might be best to commit this as a separate change/bugfix?

4200

Unrelated refactoring?

Everything being equal I think I slightly prefer this patch over the original.

Thanks for such a detailed review, David!
I would love to split off the changes into separate patches, but if I do so, this patch just will not be compileable.

lldb/include/lldb/Interpreter/OptionValueArray.h
41–43

DeepCopy is not trivial for aggregate OptionValue{} types. They must call DeepCopy on every element of their collection.

lldb/include/lldb/Utility/Cloneable.h
47–48

I wrote in the comment that static_assert cannot be put at the class scope because std::is_base_of requires derived type to be complete. Probably, it will be better to put it right into the Clone.

lldb/source/Interpreter/OptionValueProperties.cpp
545–571

OptionValueProperties had this code in the constructor, however, now DeepCopy requires a new parent as the argument. It just is not possible to call shared_from_this from the constructor. That's why I moved this code into the DeepCopy and wrapped the call into CreateLocalCopy.

Another benefit is that now one can create a local copy of their SomeOptionValueProperties even if it contains sub-properties as elements.

lldb/source/Target/Process.cpp
91–95

OptionValueProperties's changes require appropriate changes to the Process/Thread/Target.

lldb/source/Target/Target.cpp
3652–3658

This class is the most derived but it doesn't need to override OptionValueProperties's DeepCopy implementation.

3670–3672

No, it was correct. The answer is the same here: OptionValueProperties's changes require appropriate changes to the Process/Thread/Target.

Removed unrelated changes from the patch.

Looks close enough for my level of interest/knowledge. I haven't looked closely at the related cleanups to better understand why they're needed, but I'd take your word for it.

I'd prefer/like if a more seasoned LLDB developer could give the final approval here, though.

JDevlieghere accepted this revision.Feb 25 2021, 8:29 PM

LGTM

lldb/source/Interpreter/OptionValueFileSpecList.cpp
169

I would call the Clone from Cloneable here, it's a bit messy with the templates but it makes it makes it clear we're not hand-rolling an implementation but instead are just protecting it wiht a mutex.

This revision is now accepted and ready to land.Feb 25 2021, 8:29 PM
This revision was automatically updated to reflect the committed changes.
tatyana-krasnukha marked 2 inline comments as done.
Herald added a project: Restricted Project. · View Herald TranscriptFeb 28 2021, 8:24 AM
lldb/source/Interpreter/OptionValueFileSpecList.cpp
169

Thanks! Did this before landing.