[cfe-commits] r166781 - /cfe/trunk/lib/AST/ASTImporter.cpp

Douglas Gregor dgregor at apple.com
Fri Oct 26 09:45:11 PDT 2012


Author: dgregor
Date: Fri Oct 26 11:45:11 2012
New Revision: 166781

URL: http://llvm.org/viewvc/llvm-project?rev=166781&view=rev
Log:
Match up anonymous structs/unions in the ASTImporter. Previously, we'd
only actually get the answer right if there was only a single
anonymous struct/union at that level. This is part of
<rdar://problem/11904570>; the test will go into LLDB itself.

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=166781&r1=166780&r2=166781&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Fri Oct 26 11:45:11 2012
@@ -819,8 +819,18 @@
 static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
                                      FieldDecl *Field1, FieldDecl *Field2) {
   RecordDecl *Owner2 = cast<RecordDecl>(Field2->getDeclContext());
-  
-  if (!IsStructurallyEquivalent(Context, 
+
+  // For anonymous structs/unions, match up the anonymous struct/union type
+  // declarations directly, so that we don't go off searching for anonymous
+  // types
+  if (Field1->isAnonymousStructOrUnion() &&
+      Field2->isAnonymousStructOrUnion()) {
+    RecordDecl *D1 = Field1->getType()->castAs<RecordType>()->getDecl();
+    RecordDecl *D2 = Field2->getType()->castAs<RecordType>()->getDecl();
+    return IsStructurallyEquivalent(Context, D1, D2);
+  }
+
+  if (!IsStructurallyEquivalent(Context,
                                 Field1->getType(), Field2->getType())) {
     if (Context.Complain) {
       Context.Diag2(Owner2->getLocation(), diag::warn_odr_tag_type_inconsistent)
@@ -875,6 +885,39 @@
   return true;
 }
 
+/// \brief Find the index of the given anonymous struct/union within its
+/// context.
+///
+/// \returns Returns the index of this anonymous struct/union in its 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 llvm::Optional<unsigned>
+findAnonymousStructOrUnionIndex(RecordDecl *Anon) {
+  ASTContext &Context = Anon->getASTContext();
+  QualType AnonTy = Context.getRecordType(Anon);
+
+  RecordDecl *Owner = dyn_cast<RecordDecl>(Anon->getDeclContext());
+  if (!Owner)
+    return llvm::Optional<unsigned>();
+
+  unsigned Index = 0;
+  for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
+                               DEnd = Owner->noload_decls_end();
+       D != DEnd; ++D) {
+    FieldDecl *F = dyn_cast<FieldDecl>(*D);
+    if (!F || !F->isAnonymousStructOrUnion())
+      continue;
+
+    if (Context.hasSameType(F->getType(), AnonTy))
+      break;
+
+    ++Index;
+  }
+
+  return Index;
+}
+
 /// \brief Determine structural equivalence of two records.
 static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
                                      RecordDecl *D1, RecordDecl *D2) {
@@ -887,7 +930,20 @@
     }
     return false;
   }
-  
+
+  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 (llvm::Optional<unsigned> Index1
+          = findAnonymousStructOrUnionIndex(D1)) {
+      if (llvm::Optional<unsigned> Index2
+            = findAnonymousStructOrUnionIndex(D2)) {
+        if (*Index1 != *Index2)
+          return false;
+      }
+    }
+  }
+
   // If both declarations are class template specializations, we know
   // the ODR applies, so check the template and template arguments.
   ClassTemplateSpecializationDecl *Spec1
@@ -2371,6 +2427,20 @@
       }
       
       if (RecordDecl *FoundRecord = dyn_cast<RecordDecl>(Found)) {
+        if (D->isAnonymousStructOrUnion() && 
+            FoundRecord->isAnonymousStructOrUnion()) {
+          // If both anonymous structs/unions are in a record context, make sure
+          // they occur in the same location in the context records.
+          if (llvm::Optional<unsigned> Index1
+              = findAnonymousStructOrUnionIndex(D)) {
+            if (llvm::Optional<unsigned> Index2
+                = findAnonymousStructOrUnionIndex(FoundRecord)) {
+              if (*Index1 != *Index2)
+                continue;
+            }
+          }
+        }
+
         if (RecordDecl *FoundDef = FoundRecord->getDefinition()) {
           if ((SearchName && !D->isCompleteDefinition())
               || (D->isCompleteDefinition() &&
@@ -2679,6 +2749,25 @@
   return VisitCXXMethodDecl(D);
 }
 
+static unsigned getFieldIndex(Decl *F) {
+  RecordDecl *Owner = dyn_cast<RecordDecl>(F->getDeclContext());
+  if (!Owner)
+    return 0;
+
+  unsigned Index = 1;
+  for (DeclContext::decl_iterator D = Owner->noload_decls_begin(),
+                               DEnd = Owner->noload_decls_end();
+       D != DEnd; ++D) {
+    if (*D == F)
+      return Index;
+
+    if (isa<FieldDecl>(*D) || isa<IndirectFieldDecl>(*D))
+      ++Index;
+  }
+
+  return Index;
+}
+
 Decl *ASTNodeImporter::VisitFieldDecl(FieldDecl *D) {
   // Import the major distinguishing characteristics of a variable.
   DeclContext *DC, *LexicalDC;
@@ -2692,6 +2781,10 @@
   DC->localUncachedLookup(Name, FoundDecls);
   for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
     if (FieldDecl *FoundField = dyn_cast<FieldDecl>(FoundDecls[I])) {
+      // For anonymous fields, match up by index.
+      if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
+        continue;
+
       if (Importer.IsStructurallyEquivalent(D->getType(), 
                                             FoundField->getType())) {
         Importer.Imported(D, FoundField);
@@ -2725,6 +2818,7 @@
   ToField->setLexicalDeclContext(LexicalDC);
   if (ToField->hasInClassInitializer())
     ToField->setInClassInitializer(D->getInClassInitializer());
+  ToField->setImplicit(D->isImplicit());
   Importer.Imported(D, ToField);
   LexicalDC->addDeclInternal(ToField);
   return ToField;
@@ -2744,6 +2838,10 @@
   for (unsigned I = 0, N = FoundDecls.size(); I != N; ++I) {
     if (IndirectFieldDecl *FoundField 
                                 = dyn_cast<IndirectFieldDecl>(FoundDecls[I])) {
+      // For anonymous indirect fields, match up by index.
+      if (!Name && getFieldIndex(D) != getFieldIndex(FoundField))
+        continue;
+
       if (Importer.IsStructurallyEquivalent(D->getType(), 
                                             FoundField->getType(),
                                             Name)) {





More information about the cfe-commits mailing list