r275460 - When importing classes and structs with anonymous structs, it is critical that

Sean Callanan via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 14 12:53:45 PDT 2016


Author: spyffe
Date: Thu Jul 14 14:53:44 2016
New Revision: 275460

URL: http://llvm.org/viewvc/llvm-project?rev=275460&view=rev
Log:
When importing classes and structs with anonymous structs, it is critical 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

Added:
    cfe/trunk/test/ASTMerge/Inputs/anonymous-fields1.cpp
    cfe/trunk/test/ASTMerge/Inputs/anonymous-fields2.cpp
    cfe/trunk/test/ASTMerge/anonymous-fields.cpp
Modified:
    cfe/trunk/lib/AST/ASTImporter.cpp

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=275460&r1=275459&r2=275460&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Thu Jul 14 14:53:44 2016
@@ -1029,7 +1029,7 @@ static bool IsStructurallyEquivalent(Str
 /// 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);
 
@@ -1040,13 +1040,29 @@ static Optional<unsigned> findAnonymousS
   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;
@@ -1068,8 +1084,8 @@ static bool IsStructurallyEquivalent(Str
   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;
       }
@@ -2749,9 +2765,9 @@ Decl *ASTNodeImporter::VisitRecordDecl(R
           // 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;
             }

Added: cfe/trunk/test/ASTMerge/Inputs/anonymous-fields1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/anonymous-fields1.cpp?rev=275460&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/anonymous-fields1.cpp (added)
+++ cfe/trunk/test/ASTMerge/Inputs/anonymous-fields1.cpp Thu Jul 14 14:53:44 2016
@@ -0,0 +1,5 @@
+class A {
+public:
+  struct { int foo; } f;
+  struct { int foo; } g;
+};

Added: cfe/trunk/test/ASTMerge/Inputs/anonymous-fields2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/Inputs/anonymous-fields2.cpp?rev=275460&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/Inputs/anonymous-fields2.cpp (added)
+++ cfe/trunk/test/ASTMerge/Inputs/anonymous-fields2.cpp Thu Jul 14 14:53:44 2016
@@ -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);
+}

Added: cfe/trunk/test/ASTMerge/anonymous-fields.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/anonymous-fields.cpp?rev=275460&view=auto
==============================================================================
--- cfe/trunk/test/ASTMerge/anonymous-fields.cpp (added)
+++ cfe/trunk/test/ASTMerge/anonymous-fields.cpp Thu Jul 14 14:53:44 2016
@@ -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




More information about the cfe-commits mailing list