Triviality of C++11 Copy/Move Constructor, Destructor in clang AST.

Hi All,

We’re working DWARF-5 support in clang, c++11 Defaulted, deleted member functions.
We’re facing an issue while parsing attributes of a destructor which is defined out of class. as default.
as in
class foo {
public;
foo();
~foo();
};
foo::foo() = default;
foo::~foo() = default;

Here’s the code snippet of clang changes–

if (const auto *DXXC = dyn_cast(Method)) {
1624 if (DXXC->getCanonicalDecl()->isDeleted())
1625 SPFlags |= llvm::DISubprogram::SPFlagDeleted;
1626
1627 if (DXXC->getCanonicalDecl()->isDefaulted())
1628 SPFlags |= llvm::DISubprogram::SPFlagDefaultedInClass;
1629 else if (DXXC->isDefined()) {
1630 if (DXXC->getDefinition()->isDefaulted()) {
1631 SPFlags |= llvm::DISubprogram::SPFlagDefaultedOutOfClass;
1632 }
1633 else {
1634 SPFlags |= llvm::DISubprogram::SPFlagNotDefaulted;
1635 }
1636 }
1637 }

For, out of class destructor definition defaulted, as mentioned above. We’re not able get SPFlagDefaultedOutOfClass or SPFlagNotDefaulted.

seems like their is no definition of destructor, even when, we are defining them out of class as default; ??
1629 else if (DXXC->isDefined()) – evaluates as false

On the other side, If we declare our destructor as virtual, then above checks passes gracefully – suggesting clang created a non-trivial destructor definition.

Is this behavior okay ?? , – this behavior is also prevalent in copy/move constructor and assignments.

Note-- For Constructor out of class definition as default – clang create non-trivial constructor definition, and above check passes and we’re are able to check capture the information about, whether the constructor is defaulted in class or out of class.

Any thoughts, greatly appreciated.

Thanks!
Sourabh Singh Tomar

Hmm - I didn’t realize there was DWARF for describing defaulted operations. It looks like maybe this ended up in as a half fix to the issue of calling conventions (we had a few discussions with DWARF folks about whether knowing which ops were defaulted would be enough to know whether a class was to be passed by value or by reference in the calling convention - and eventually managed to demonstrate that it couldn’t be and it would be best if DWARF encoded the decision, rather than the data for the decision - which is how we got DW_AT_calling_convention on types).

What’s the motivation for implementing/emitting this DWARF? Are there any consumers or use cases you have in mind?

Anyway, let’s see what the problem with the code is… looks pretty reasonable.

Might be easier with a test case/patch - perhaps you could post to Phabricator.

Though I don’t see anything immediately wrong, it might be simpler/more efficient to use “getDefinition” to determine if the function is defined - rather than separately calling isDefined+getDefinition later. Call getDefinition and check if it’s non-null:

else if (DXXC->isDefined()) {
if (DXXC->getDefinition()->isDefaulted())
SPFlags |= llvm::DISubprogram::SPFlagDefaultedOutOfClass;
else
SPFlags |= llvm::DISubprogram::SPFlagNotDefaulted;

if (const auto *Def = DXXC->getDefinition())
if (Def->isDefaulted()

else

Posted a patch for this. Please have a look →
https://reviews.llvm.org/D68117

– Sourabh Singh Tomar

Forgot to seek your comments on this one.
Some of my test cases are failing due to this.

Thanks!
–Sourabh

I saw it was already under review & didn’t see any particular spots that referred to the problems you mentioned in this thread - if there are bugs in the code as it is in the review, it’d be good to highlight those in the review description and probably in the test cases (FIXME and/or CHECKs that currently fail to demonstrate what the behavior should be, etc)