summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/AST/DeclBase.h1
-rw-r--r--clang/include/clang/Basic/DiagnosticASTKinds.td2
-rw-r--r--clang/lib/AST/ASTImporter.cpp14
-rw-r--r--clang/lib/AST/ASTStructuralEquivalence.cpp83
-rw-r--r--clang/test/ASTMerge/class/Inputs/class1.cpp28
-rw-r--r--clang/test/ASTMerge/class/Inputs/class2.cpp26
-rw-r--r--clang/test/ASTMerge/class/test.cpp10
7 files changed, 159 insertions, 5 deletions
diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h
index 908894c133c..1243a67397d 100644
--- a/clang/include/clang/AST/DeclBase.h
+++ b/clang/include/clang/AST/DeclBase.h
@@ -309,6 +309,7 @@ private:
protected:
friend class ASTDeclReader;
friend class ASTDeclWriter;
+ friend class ASTImporter;
friend class ASTReader;
friend class CXXClassMemberWrapper;
friend class LinkageComputer;
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 215580b2e9b..4fa1db96cb8 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -273,6 +273,8 @@ def note_odr_objc_synthesize_ivar_here : Note<
"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<
diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp
index a2e6c01dc29..17ff23c5fe0 100644
--- a/clang/lib/AST/ASTImporter.cpp
+++ b/clang/lib/AST/ASTImporter.cpp
@@ -2709,9 +2709,14 @@ Decl *ASTNodeImporter::VisitFriendDecl(FriendDecl *D) {
// 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(FriendDecl *D) {
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;
}
diff --git a/clang/lib/AST/ASTStructuralEquivalence.cpp b/clang/lib/AST/ASTStructuralEquivalence.cpp
index 618d27e9b6d..05f414e9fb1 100644
--- a/clang/lib/AST/ASTStructuralEquivalence.cpp
+++ b/clang/lib/AST/ASTStructuralEquivalence.cpp
@@ -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(StructuralEquivalenceContext &Context,
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(StructuralEquivalenceContext &Context,
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) {
@@ -1381,6 +1445,25 @@ bool StructuralEquivalenceContext::Finish() {
// 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;
+ }
}
if (!Equivalent) {
diff --git a/clang/test/ASTMerge/class/Inputs/class1.cpp b/clang/test/ASTMerge/class/Inputs/class1.cpp
index b0a7645cfe6..2bd5503ecf3 100644
--- a/clang/test/ASTMerge/class/Inputs/class1.cpp
+++ b/clang/test/ASTMerge/class/Inputs/class1.cpp
@@ -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();
+};
diff --git a/clang/test/ASTMerge/class/Inputs/class2.cpp b/clang/test/ASTMerge/class/Inputs/class2.cpp
index 2bed6d775bc..6fe38b92066 100644
--- a/clang/test/ASTMerge/class/Inputs/class2.cpp
+++ b/clang/test/ASTMerge/class/Inputs/class2.cpp
@@ -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();
+};
diff --git a/clang/test/ASTMerge/class/test.cpp b/clang/test/ASTMerge/class/test.cpp
index a68a2d1d769..99926b649bc 100644
--- a/clang/test/ASTMerge/class/test.cpp
+++ b/clang/test/ASTMerge/class/test.cpp
@@ -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.
OpenPOWER on IntegriCloud