Skip to content

Commit

Permalink
When importing classes and structs with anonymous structs, it is crit…
Browse files Browse the repository at this point in the history
…ical that

distinct anonymous structs remain distinct despite having similar layout.

This is already ensured by distinguishing based on their placement in the parent
struct, using the function `findAnonymousStructOrUnionIndex`.

The problem is that this function only handles anonymous structs, like
```
class Foo { struct { int a; } }
```
and not untagged structs like
```
class Foo { struct { int a; } var; }
```
Both need to be handled, and this patch fixes that.  The test case ensures that this functionality doesn't regress.

Thanks to Manman Ren for review.

https://reviews.llvm.org/D22270


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@275460 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
scallanan committed Jul 14, 2016
1 parent 56d0aaf commit c0f3c38
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 9 deletions.
34 changes: 25 additions & 9 deletions lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1029,7 +1029,7 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
/// including the next assigned index (if none of them match). Returns an
/// empty option if the context is not a record, i.e.. if the anonymous
/// struct/union is at namespace or block scope.
static Optional<unsigned> findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
static Optional<unsigned> findUntaggedStructOrUnionIndex(RecordDecl *Anon) {
ASTContext &Context = Anon->getASTContext();
QualType AnonTy = Context.getRecordType(Anon);

Expand All @@ -1040,13 +1040,29 @@ static Optional<unsigned> findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
unsigned Index = 0;
for (const auto *D : Owner->noload_decls()) {
const auto *F = dyn_cast<FieldDecl>(D);
if (!F || !F->isAnonymousStructOrUnion())
if (!F)
continue;

if (Context.hasSameType(F->getType(), AnonTy))
break;
if (F->isAnonymousStructOrUnion()) {
if (Context.hasSameType(F->getType(), AnonTy))
break;
++Index;
continue;
}

++Index;
// If the field looks like this:
// struct { ... } A;
QualType FieldType = F->getType();
if (const auto *RecType = dyn_cast<RecordType>(FieldType)) {
const RecordDecl *RecDecl = RecType->getDecl();
if (RecDecl->getDeclContext() == Owner &&
!RecDecl->getIdentifier()) {
if (Context.hasSameType(FieldType, AnonTy))
break;
++Index;
continue;
}
}
}

return Index;
Expand All @@ -1068,8 +1084,8 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
if (D1->isAnonymousStructOrUnion() && D2->isAnonymousStructOrUnion()) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
if (Optional<unsigned> Index1 = findAnonymousStructOrUnionIndex(D1)) {
if (Optional<unsigned> Index2 = findAnonymousStructOrUnionIndex(D2)) {
if (Optional<unsigned> Index1 = findUntaggedStructOrUnionIndex(D1)) {
if (Optional<unsigned> Index2 = findUntaggedStructOrUnionIndex(D2)) {
if (*Index1 != *Index2)
return false;
}
Expand Down Expand Up @@ -2749,9 +2765,9 @@ Decl *ASTNodeImporter::VisitRecordDecl(RecordDecl *D) {
// If both anonymous structs/unions are in a record context, make sure
// they occur in the same location in the context records.
if (Optional<unsigned> Index1
= findAnonymousStructOrUnionIndex(D)) {
= findUntaggedStructOrUnionIndex(D)) {
if (Optional<unsigned> Index2 =
findAnonymousStructOrUnionIndex(FoundRecord)) {
findUntaggedStructOrUnionIndex(FoundRecord)) {
if (*Index1 != *Index2)
continue;
}
Expand Down
5 changes: 5 additions & 0 deletions test/ASTMerge/Inputs/anonymous-fields1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class A {
public:
struct { int foo; } f;
struct { int foo; } g;
};
9 changes: 9 additions & 0 deletions test/ASTMerge/Inputs/anonymous-fields2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class A {
public:
struct { int foo; } f;
struct { int foo; } g;
};

inline int useA(A &a) {
return (a.f.foo + a.g.foo);
}
4 changes: 4 additions & 0 deletions test/ASTMerge/anonymous-fields.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// RUN: %clang_cc1 -emit-pch -o %t.1.ast %S/Inputs/anonymous-fields1.cpp
// RUN: %clang_cc1 -emit-pch -o %t.2.ast %S/Inputs/anonymous-fields2.cpp
// RUN: %clang_cc1 -emit-obj -o /dev/null -ast-merge %t.1.ast -ast-merge %t.2.ast %s
// expected-no-diagnostics

0 comments on commit c0f3c38

Please sign in to comment.