This is an archive of the discontinued LLVM Phabricator instance.

Own/produce FrontendActionFactories by value, rather than new'd/unique_ptr ownership.
AbandonedPublic

Authored by dblaikie on Jun 26 2014, 9:57 AM.

Details

Reviewers
None
Summary

Based on a discussion on cfe-dev, simplify (and make more explicit, in places) the ownership semantics of FrontendActions and FrontendActionFactories using value semantics and std::unique_ptr in places.

Diff Detail

Event Timeline

dblaikie updated this revision to Diff 10893.Jun 26 2014, 9:57 AM
dblaikie retitled this revision from to Own/produce FrontendActionFactories by value, rather than new'd/unique_ptr ownership..
dblaikie added a reviewer: klimek.
dblaikie updated this object.
dblaikie added a subscriber: Unknown Object (MLST).
klimek added inline comments.Jun 26 2014, 10:09 AM
include/clang/Tooling/Tooling.h
320

I thought LLVM style was to not explicitly check against NULL? Also, nullptr?

340

I'd change the name of things that do not return a new pointer to "create...".

tools/clang-check/ClangCheck.cpp
223

I actually dislike that change somewhat (it introduces more structural duplication).

dblaikie updated this revision to Diff 10897.Jun 26 2014, 10:19 AM
  • Propagate nullptr/NULL check improvements from the copied code after nullptr cleanups by (presumably) Craig.
dblaikie added inline comments.Jun 26 2014, 10:32 AM
include/clang/Tooling/Tooling.h
320

This was just copy/paste from the original implementation before NULL had been cleaned up (presumably by Craig Topper) here. I've updated for this and a couple of other places that had been changed since I moved the code.

340

Sure thing - I can do that renaming. I'll leave that until we've hammered out the rest (but I'll be sure to include it in the same commit). Should just be mechanical.

tools/clang-check/ClangCheck.cpp
223

Yep, I called this out as the only place that was "interesting" in the original thread, but perhaps it got lost in all the words:

"The one caller that
did:

unique_ptr<factory> p;
if (x)

p = newFactory();

else if (y)

p = newFactory(a);

else

p = newFactory(b);

Tool.run(p);

and the change was to roll the "Tool.run" call up into the call site,
which wasn't overly burdensome."

It could be refactored in a few other ways (like wrapping up a "run" function:

auto run = [&](const FrontendActionFactory& F) { Tool.run(F); };
if (x)

run(newFactory());

else if (y)

run(newFactory(a));

else

run(newFactory(b));

Which doesn't really seem worthwhile to me.

The next alternative would be to copy/move the factory into a dynamic allocation with a type erased destruction, which might look something like:

template<typename T>
std::shared_ptr<T> newClone(T &&t) {

return std::make_shared<T>(std::forward<T>(t));

}

...

// Use shared_ptr for type erased destruction
std::shared_ptr<FrontendActionFactory> F;
if (x)

F = newClone(newFactory());

else if (y)

F = newClone(newFactory(a));

else

F = newClone(newFactory(b));

Tool.run(*F);

Which also seems excessive to me.

(well, sorry, all those examples are assuming the dtor becomes non-virtual - in this patch they're still virtual, so unique_ptr could be used instead of shared_ptr, but "newClone" would still be needed to move from static to a dynamic allocation)

After reviewing (& making some improvements in r215215 and r215214) some memory leak fixes made in r213851 I think it's rather valuable to change Tool::run to take a reference to a FrontendActionFactory, rather than a pointer. (indeed the memory leaks related to that API that were fixed in r213851 are also fixed by my patch above)

And while I don't mind churning the APIs multiple times (switching to references, then, potentially, switching to the factory functions returning by value) & doing all the legwork internally & externally - it might be nice to settle on it.

I can also split out the other part involving the SingleFrontendActionFactory (and fixing FrontendActionFactory::create to be explicit about returning ownership) that we discussed/were confused by for a while, etc...

tools/clang-check/ClangCheck.cpp
223

Another option would be to expose the types that these factory functions return and then just have the code specify the template arguments explicitly in this one case (old code provided in comments for comparison):

std::shared_ptr<FrontendActionFactory> F; // or std::unique_ptr if the dtors remain virtual
if (x)
  // F = newFrontendActionFactory<clang::ento::AnalysisAction>();
  F = std::make_shared<SimpleFrontendActionFactory<clang::ento::AnalysisAction>>();
else if (y)
  // F = newFrontendActionFactory<FixItAction>();
  F = std::make_shared<SimpleFrontendActionFactory<FixItAction>>();
else
  // F = newFrontendActionFactory(&CheckFactory);
  F = std::make_shared<FrontendActionFactoryAdapter<clang_check::ClangCheckActionFactory>>();
Tool.run(*F);
klimek edited edge metadata.Sep 8 2014, 3:04 AM

This has now been resolved differently, right? Can we abandon the revision?

In D4313#12, @klimek wrote:

This has now been resolved differently, right? Can we abandon the revision?

Not exactly - r207396 made the newFrontendActionFactory change to return unique_ptr, but the original memory leak could still easily be written because it takes a raw pointer (this both complicates callers (having them either use "newFrontendActionFactory(...).get()" or take the address of a local to pass) and risks someone passing a raw 'new' to the function)).

The follow-on refactor to have newFrontendActionFactory return by value (& then, potentially, remove its virtual dtor) is just to simplify the call sites even further. Rather than replacing "run(newFrontendActionFactory(...).get())" with "run(*newFrontendActionFactory(...))" (which might make people twitch a bit, wondering whether that leaks or not) it could just be "run(newFrontendActionFactory(...))" which seems less surprising.

I figure if I'm going to have to touch every caller anyway, it wasn't really extra churn to change newFrontendActionFactory to be value-based.

And there's still the matter of runToolOnCode taking ownership via raw pointer (which then feeds into that confusion we had over ToolInvocation needing to take ownership and SingleFrontendActionFactory taking/returning ownership of that FrontendActionFactory). But that's fairly separable.

klimek resigned from this revision.Jul 3 2015, 6:41 AM
klimek removed a reviewer: klimek.
dblaikie abandoned this revision.Mar 25 2016, 3:44 PM