This is an archive of the discontinued LLVM Phabricator instance.

[AST] Fix printing tag decl groups in decl contexts
ClosedPublic

Authored by jdenny on Apr 9 2018, 3:38 PM.

Details

Summary

For example, given:

struct T1 {
  struct T2 *p0;
};

-ast-print produced:

struct T1 {
  struct T2; 
  struct T2 *p0;
};

Compiling that produces a warning that the first struct T2 declaration
does not declare anything.

Details:

A tag decl group is one or more decls that share a type specifier that
is a tag decl (that is, a struct/union/class/enum decl). Within
functions, the parser builds such a tag decl group as part of a
DeclStmt. However, in decl contexts, such as file scope or a member
list, the parser does not group together the members of a tag decl
group. Previously, detection of tag decl groups during printing was
implemented but only if the tag decl was unnamed. Otherwise, as in
the above example, the members of the group did not print together and
so sometimes introduced warnings.

This patch extends detection of tag decl groups in decl contexts to
any tag decl that is recorded in the AST as not free-standing.

Diff Detail

Event Timeline

jdenny updated this revision to Diff 142687.Apr 16 2018, 1:29 PM

Rebased onto a more recent master.

jdenny updated this revision to Diff 146668.May 14 2018, 1:13 PM

Rebased. Ping.

rsmith added inline comments.May 14 2018, 2:40 PM
lib/AST/DeclPrinter.cpp
392–395

I would think the right thing to check here is that the ElaboratedType's OwnedTagDecl is Decls[0]. Currently, you also allow cases where it's merely a redeclaration of that same TagDecl, which will combine together declarations too often...

test/Misc/ast-print-record-decl.c
163–173

... such as here, for example. Because the two KW T declarations redeclare the same TagDecl, they will get merged by -ast-print.

jdenny updated this revision to Diff 146709.May 14 2018, 3:49 PM
jdenny marked 2 inline comments as done.

Made the suggested change. Thanks!

rsmith accepted this revision.May 14 2018, 4:09 PM

Looks good, thanks.

It strikes me that this will still lead to inconsistencies. For example, I expect this:

struct A { struct B *a, *b; struct B *c, *d; };

... to print as:

struct A {
  struct B *a, *b;
  struct B *c;
  struct B *d;
};

... where the first two are joined because their type owns a declaration of struct B, and the second two are not joined because their type does not own a declaration (it just has a reference to the already-existing declaration of struct B). One (somewhat hacky) way to address this would be to compare the starting source locations of a sequence of DeclaratorDecls and group them if it's the same.

This revision is now accepted and ready to land.May 14 2018, 4:09 PM

Looks good, thanks.

Thanks.

It strikes me that this will still lead to inconsistencies. For example, I expect this:

struct A { struct B *a, *b; struct B *c, *d; };

... to print as:

struct A {
  struct B *a, *b;
  struct B *c;
  struct B *d;
};

... where the first two are joined because their type owns a declaration of struct B, and the second two are not joined because their type does not own a declaration (it just has a reference to the already-existing declaration of struct B). One (somewhat hacky) way to address this would be to compare the starting source locations of a sequence of DeclaratorDecls and group them if it's the same.

While it would be nice to fix that, I'm not as concerned because, AFAICT, that doesn't ever change the semantics.

This revision was automatically updated to reflect the committed changes.