r330847 - [ASTImporter] FriendDecl importing improvements

Peter Szecsi via cfe-commits cfe-commits at lists.llvm.org
Wed Apr 25 10:28:03 PDT 2018


Author: szepet
Date: Wed Apr 25 10:28:03 2018
New Revision: 330847

URL: http://llvm.org/viewvc/llvm-project?rev=330847&view=rev
Log:
[ASTImporter] FriendDecl importing improvements

There are only a few cases of importing a frienddecl which is currently supported.
This patch aims to improve the friend import process.
Set FriendObjectKind in case of decls, insert friend into the friend chain
correctly, checks structurally equivalent in a more advanced manner.
Test cases added as well.  


Modified:
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
    cfe/trunk/test/ASTMerge/class/Inputs/class1.cpp
    cfe/trunk/test/ASTMerge/class/Inputs/class2.cpp
    cfe/trunk/test/ASTMerge/class/test.cpp

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=330847&r1=330846&r2=330847&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Wed Apr 25 10:28:03 2018
@@ -309,6 +309,7 @@ private:
 protected:
   friend class ASTDeclReader;
   friend class ASTDeclWriter;
+  friend class ASTImporter;
   friend class ASTReader;
   friend class CXXClassMemberWrapper;
   friend class LinkageComputer;

Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=330847&r1=330846&r2=330847&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Wed Apr 25 10:28:03 2018
@@ -273,6 +273,8 @@ def note_odr_objc_synthesize_ivar_here :
   "property is synthesized to ivar %0 here">;
 
 // Importing C++ ASTs
+def note_odr_friend : Note<"friend declared here">;
+def note_odr_missing_friend : Note<"no corresponding friend here">;
 def err_odr_different_num_template_parameters : Error<
   "template parameter lists have a different number of parameters (%0 vs %1)">;
 def note_odr_template_parameter_list : Note<

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=330847&r1=330846&r2=330847&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Wed Apr 25 10:28:03 2018
@@ -2709,9 +2709,14 @@ Decl *ASTNodeImporter::VisitFriendDecl(F
 
   // Not found. Create it.
   FriendDecl::FriendUnion ToFU;
-  if (NamedDecl *FriendD = D->getFriendDecl())
-    ToFU = cast_or_null<NamedDecl>(Importer.Import(FriendD));
-  else
+  if (NamedDecl *FriendD = D->getFriendDecl()) {
+    auto *ToFriendD = cast_or_null<NamedDecl>(Importer.Import(FriendD));
+    if (ToFriendD && FriendD->getFriendObjectKind() != Decl::FOK_None &&
+        !(FriendD->isInIdentifierNamespace(Decl::IDNS_NonMemberOperator)))
+      ToFriendD->setObjectOfFriendDecl(false);
+
+    ToFU = ToFriendD;
+  }  else // The friend is a type, not a decl.
     ToFU = Importer.Import(D->getFriendType());
   if (!ToFU)
     return nullptr;
@@ -2731,7 +2736,6 @@ Decl *ASTNodeImporter::VisitFriendDecl(F
                                        ToTPLists);
 
   Importer.Imported(D, FrD);
-  RD->pushFriendDecl(FrD);
 
   FrD->setAccess(D->getAccess());
   FrD->setLexicalDeclContext(LexicalDC);
@@ -6596,7 +6600,7 @@ Decl *ASTImporter::Import(Decl *FromD) {
 
   // Record the imported declaration.
   ImportedDecls[FromD] = ToD;
-
+  ToD->IdentifierNamespace = FromD->IdentifierNamespace;
   return ToD;
 }
 

Modified: cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp?rev=330847&r1=330846&r2=330847&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp (original)
+++ cfe/trunk/lib/AST/ASTStructuralEquivalence.cpp Wed Apr 25 10:28:03 2018
@@ -18,6 +18,7 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclBase.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclFriend.h"
 #include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/NestedNameSpecifier.h"
@@ -942,6 +943,44 @@ static bool IsStructurallyEquivalent(Str
           return false;
         }
       }
+
+      // Check the friends for consistency.
+      CXXRecordDecl::friend_iterator Friend2 = D2CXX->friend_begin(),
+              Friend2End = D2CXX->friend_end();
+      for (CXXRecordDecl::friend_iterator Friend1 = D1CXX->friend_begin(),
+                   Friend1End = D1CXX->friend_end();
+           Friend1 != Friend1End; ++Friend1, ++Friend2) {
+        if (Friend2 == Friend2End) {
+          if (Context.Complain) {
+            Context.Diag2(D2->getLocation(),
+                          diag::warn_odr_tag_type_inconsistent)
+                    << Context.ToCtx.getTypeDeclType(D2CXX);
+            Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
+            Context.Diag2(D2->getLocation(), diag::note_odr_missing_friend);
+          }
+          return false;
+        }
+
+        if (!IsStructurallyEquivalent(Context, *Friend1, *Friend2)) {
+          if (Context.Complain) {
+            Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+              << Context.ToCtx.getTypeDeclType(D2CXX);
+            Context.Diag1((*Friend1)->getFriendLoc(), diag::note_odr_friend);
+            Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
+          }
+          return false;
+        }
+      }
+
+      if (Friend2 != Friend2End) {
+        if (Context.Complain) {
+          Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
+                  << Context.ToCtx.getTypeDeclType(D2);
+          Context.Diag2((*Friend2)->getFriendLoc(), diag::note_odr_friend);
+          Context.Diag1(D1->getLocation(), diag::note_odr_missing_friend);
+        }
+        return false;
+      }
     } else if (D1CXX->getNumBases() > 0) {
       if (Context.Complain) {
         Context.Diag2(D2->getLocation(), diag::warn_odr_tag_type_inconsistent)
@@ -1184,6 +1223,31 @@ static bool IsStructurallyEquivalent(Str
                                           D2->getTemplatedDecl()->getType());
 }
 
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+                                     FriendDecl *D1, FriendDecl *D2) {
+  if ((D1->getFriendType() && D2->getFriendDecl()) ||
+      (D1->getFriendDecl() && D2->getFriendType())) {
+      return false;
+  }
+  if (D1->getFriendType() && D2->getFriendType())
+    return IsStructurallyEquivalent(Context,
+                                    D1->getFriendType()->getType(),
+                                    D2->getFriendType()->getType());
+  if (D1->getFriendDecl() && D2->getFriendDecl())
+    return IsStructurallyEquivalent(Context, D1->getFriendDecl(),
+                                    D2->getFriendDecl());
+  return false;
+}
+
+static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
+                                     FunctionDecl *D1, FunctionDecl *D2) {
+  // FIXME: Consider checking for function attributes as well.
+  if (!IsStructurallyEquivalent(Context, D1->getType(), D2->getType()))
+    return false;
+
+  return true;
+}
+
 /// Determine structural equivalence of two declarations.
 static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context,
                                      Decl *D1, Decl *D2) {
@@ -1380,6 +1444,25 @@ bool StructuralEquivalenceContext::Finis
       } else {
         // Kind mismatch.
         Equivalent = false;
+      }
+    } else if (FunctionDecl *FD1 = dyn_cast<FunctionDecl>(D1)) {
+      if (FunctionDecl *FD2 = dyn_cast<FunctionDecl>(D2)) {
+        if (!::IsStructurallyEquivalent(FD1->getIdentifier(),
+                                        FD2->getIdentifier()))
+          Equivalent = false;
+        if (!::IsStructurallyEquivalent(*this, FD1, FD2))
+          Equivalent = false;
+      } else {
+        // Kind mismatch.
+        Equivalent = false;
+      }
+    } else if (FriendDecl *FrD1 = dyn_cast<FriendDecl>(D1)) {
+      if (FriendDecl *FrD2 = dyn_cast<FriendDecl>(D2)) {
+          if (!::IsStructurallyEquivalent(*this, FrD1, FrD2))
+            Equivalent = false;
+      } else {
+        // Kind mismatch.
+        Equivalent = false;
       }
     }
 

Modified: cfe/trunk/test/ASTMerge/class/Inputs/class1.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/class/Inputs/class1.cpp?rev=330847&r1=330846&r2=330847&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/class/Inputs/class1.cpp (original)
+++ cfe/trunk/test/ASTMerge/class/Inputs/class1.cpp Wed Apr 25 10:28:03 2018
@@ -18,3 +18,31 @@ struct C {
 enum E {
   b = 1
 };
+
+//Friend import tests
+void f();
+int g(int a);
+struct X;
+struct Y;
+
+struct F1 {
+public:
+  int x;
+  friend struct X;
+  friend int g(int);
+  friend void f();
+};
+
+struct F2 {
+public:
+  int x;
+  friend struct X;
+  friend void f();
+};
+
+struct F3 {
+public:
+  int x;
+  friend int g(int);
+  friend void f();
+};

Modified: cfe/trunk/test/ASTMerge/class/Inputs/class2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/class/Inputs/class2.cpp?rev=330847&r1=330846&r2=330847&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/class/Inputs/class2.cpp (original)
+++ cfe/trunk/test/ASTMerge/class/Inputs/class2.cpp Wed Apr 25 10:28:03 2018
@@ -12,3 +12,29 @@ enum E {
   a = 0,
   b = 1
 };
+
+//Friend import tests
+void f();
+int g(int a);
+struct X;
+struct Y;
+
+struct F1 {
+public:
+  int x;
+  friend struct X;
+  friend int g(int);
+  friend void f();
+};
+
+struct F2 {
+public:
+  int x;
+  friend struct X;
+};
+
+struct F3 {
+public:
+  int x;
+  friend void f();
+};

Modified: cfe/trunk/test/ASTMerge/class/test.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/ASTMerge/class/test.cpp?rev=330847&r1=330846&r2=330847&view=diff
==============================================================================
--- cfe/trunk/test/ASTMerge/class/test.cpp (original)
+++ cfe/trunk/test/ASTMerge/class/test.cpp Wed Apr 25 10:28:03 2018
@@ -12,3 +12,13 @@
 // CHECK: class1.cpp:18:6: warning: type 'E' has incompatible definitions in different translation units
 // CHECK: class1.cpp:19:3: note: enumerator 'b' with value 1 here
 // CHECK: class2.cpp:12:3: note: enumerator 'a' with value 0 here
+
+// CHECK: class1.cpp:36:8: warning: type 'F2' has incompatible definitions in different translation units
+// CHECK: class1.cpp:39:3: note: friend declared here
+// CHECK: class2.cpp:30:8: note: no corresponding friend here
+
+// CHECK: class1.cpp:43:8: warning: type 'F3' has incompatible definitions in different translation units
+// CHECK: class1.cpp:46:3: note: friend declared here
+// CHECK: class2.cpp:36:8: note: no corresponding friend here
+
+// CHECK: 4 warnings generated.




More information about the cfe-commits mailing list