summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Trieu <rtrieu@google.com>2017-07-08 02:04:42 +0000
committerRichard Trieu <rtrieu@google.com>2017-07-08 02:04:42 +0000
commitac6a1b6417eee05e4aa32a481b0e39a97ade501a (patch)
tree6ca0f1e32e971edce38161505fa5552d8180e79e
parent8737f0650c050918a50504647ac02f137b3a00ad (diff)
downloadbcm5719-llvm-ac6a1b6417eee05e4aa32a481b0e39a97ade501a.tar.gz
bcm5719-llvm-ac6a1b6417eee05e4aa32a481b0e39a97ade501a.zip
[ODRHash] Support FriendDecl
llvm-svn: 307458
-rw-r--r--clang/include/clang/Basic/DiagnosticSerializationKinds.td14
-rw-r--r--clang/lib/AST/ODRHash.cpp18
-rw-r--r--clang/lib/Serialization/ASTReader.cpp53
-rw-r--r--clang/test/Modules/odr_hash.cpp78
4 files changed, 159 insertions, 4 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
index 3c64ebb9c7f..0fc54848581 100644
--- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td
@@ -127,11 +127,11 @@ def err_module_odr_violation_mismatch_decl : Error<
"%select{definition in module '%2'|defined here}1 found "
"%select{end of class|public access specifier|private access specifier|"
"protected access specifier|static assert|field|method|type alias|typedef|"
- "data member}3">;
+ "data member|friend declaration}3">;
def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
"%select{end of class|public access specifier|private access specifier|"
"protected access specifier|static assert|field|method|type alias|typedef|"
- "data member}1">;
+ "data member|friend declaration}1">;
def err_module_odr_violation_mismatch_decl_diff : Error<
"%q0 has different definitions in different modules; first difference is "
@@ -166,6 +166,9 @@ def err_module_odr_violation_mismatch_decl_diff : Error<
"data member %4 with%select{out|}5 an initializer|"
"data member %4 with an initializer|"
"data member %4 %select{is constexpr|is not constexpr}5|"
+ "friend %select{class|function}4|"
+ "friend %4|"
+ "friend function %4|"
"}3">;
def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
@@ -199,18 +202,21 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
"data member %2 with%select{out|}3 an initializer|"
"data member %2 with a different initializer|"
"data member %2 %select{is constexpr|is not constexpr}3|"
+ "friend %select{class|function}2|"
+ "friend %2|"
+ "friend function %2|"
"}1">;
def err_module_odr_violation_mismatch_decl_unknown : Error<
"%q0 %select{with definition in module '%2'|defined here}1 has different "
"definitions in different modules; first difference is this "
"%select{||||static assert|field|method|type alias|typedef|data member|"
- "unexpected decl}3">;
+ "friend declaration|unexpected decl}3">;
def note_module_odr_violation_mismatch_decl_unknown : Note<
"but in '%0' found "
"%select{||||different static assert|different field|different method|"
"different type alias|different typedef|different data member|"
- "another unexpected decl}1">;
+ "different friend declaration|another unexpected decl}1">;
def warn_duplicate_module_file_extension : Warning<
"duplicate module file extension block name '%0'">,
diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp
index 3f66e58eb86..66b9940b8b0 100644
--- a/clang/lib/AST/ODRHash.cpp
+++ b/clang/lib/AST/ODRHash.cpp
@@ -228,6 +228,13 @@ public:
Hash.AddQualType(T);
}
+ void AddDecl(const Decl *D) {
+ Hash.AddBoolean(D);
+ if (D) {
+ Hash.AddDecl(D);
+ }
+ }
+
void Visit(const Decl *D) {
ID.AddInteger(D->getKind());
Inherited::Visit(D);
@@ -321,6 +328,16 @@ public:
void VisitTypeAliasDecl(const TypeAliasDecl *D) {
Inherited::VisitTypeAliasDecl(D);
}
+
+ void VisitFriendDecl(const FriendDecl *D) {
+ TypeSourceInfo *TSI = D->getFriendType();
+ Hash.AddBoolean(TSI);
+ if (TSI) {
+ AddQualType(TSI->getType());
+ } else {
+ AddDecl(D->getFriendDecl());
+ }
+ }
};
// Only allow a small portion of Decl's to be processed. Remove this once
@@ -335,6 +352,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
case Decl::AccessSpec:
case Decl::CXXMethod:
case Decl::Field:
+ case Decl::Friend:
case Decl::StaticAssert:
case Decl::TypeAlias:
case Decl::Typedef:
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 3aee3c04001..678ecfc9a3d 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -9314,6 +9314,7 @@ void ASTReader::diagnoseOdrViolations() {
TypeAlias,
TypeDef,
Var,
+ Friend,
Other
} FirstDiffType = Other,
SecondDiffType = Other;
@@ -9347,6 +9348,8 @@ void ASTReader::diagnoseOdrViolations() {
return TypeDef;
case Decl::Var:
return Var;
+ case Decl::Friend:
+ return Friend;
}
};
@@ -9463,6 +9466,9 @@ void ASTReader::diagnoseOdrViolations() {
VarSingleInitializer,
VarDifferentInitializer,
VarConstexpr,
+ FriendTypeFunction,
+ FriendType,
+ FriendFunction,
};
// These lambdas have the common portions of the ODR diagnostics. This
@@ -9973,6 +9979,53 @@ void ASTReader::diagnoseOdrViolations() {
}
break;
}
+ case Friend: {
+ FriendDecl *FirstFriend = cast<FriendDecl>(FirstDecl);
+ FriendDecl *SecondFriend = cast<FriendDecl>(SecondDecl);
+
+ NamedDecl *FirstND = FirstFriend->getFriendDecl();
+ NamedDecl *SecondND = SecondFriend->getFriendDecl();
+
+ TypeSourceInfo *FirstTSI = FirstFriend->getFriendType();
+ TypeSourceInfo *SecondTSI = SecondFriend->getFriendType();
+
+ if (FirstND && SecondND) {
+ ODRDiagError(FirstFriend->getFriendLoc(),
+ FirstFriend->getSourceRange(), FriendFunction)
+ << FirstND;
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendFunction)
+ << SecondND;
+
+ Diagnosed = true;
+ break;
+ }
+
+ if (FirstTSI && SecondTSI) {
+ QualType FirstFriendType = FirstTSI->getType();
+ QualType SecondFriendType = SecondTSI->getType();
+ assert(ComputeQualTypeODRHash(FirstFriendType) !=
+ ComputeQualTypeODRHash(SecondFriendType));
+ ODRDiagError(FirstFriend->getFriendLoc(),
+ FirstFriend->getSourceRange(), FriendType)
+ << FirstFriendType;
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendType)
+ << SecondFriendType;
+ Diagnosed = true;
+ break;
+ }
+
+ ODRDiagError(FirstFriend->getFriendLoc(), FirstFriend->getSourceRange(),
+ FriendTypeFunction)
+ << (FirstTSI == nullptr);
+ ODRDiagNote(SecondFriend->getFriendLoc(),
+ SecondFriend->getSourceRange(), FriendTypeFunction)
+ << (SecondTSI == nullptr);
+
+ Diagnosed = true;
+ break;
+ }
}
if (Diagnosed == true)
diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp
index 6e01e989a37..ee45ae52996 100644
--- a/clang/test/Modules/odr_hash.cpp
+++ b/clang/test/Modules/odr_hash.cpp
@@ -1339,6 +1339,84 @@ Bravo<char> golf;
#endif
}
+namespace Friend {
+#if defined(FIRST)
+struct T1 {};
+struct S1 {
+ friend class T1;
+};
+#elif defined(SECOND)
+struct T1 {};
+struct S1 {
+ friend T1;
+};
+#else
+S1 s1;
+// expected-error@second.h:* {{'Friend::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'Friend::T1'}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend 'class T1'}}
+#endif
+
+#if defined(FIRST)
+struct T2 {};
+struct S2 {
+ friend class T2;
+};
+#elif defined(SECOND)
+struct T2 {};
+struct S2 {
+ friend struct T2;
+};
+#else
+S2 s2;
+// expected-error@second.h:* {{'Friend::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'struct T2'}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend 'class T2'}}
+#endif
+
+#if defined(FIRST)
+struct T3 {};
+struct S3 {
+ friend const T3;
+};
+#elif defined(SECOND)
+struct T3 {};
+struct S3 {
+ friend T3;
+};
+#else
+S3 s3;
+// expected-error@second.h:* {{'Friend::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend 'Friend::T3'}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend 'const Friend::T3'}}
+#endif
+
+#if defined(FIRST)
+struct T4 {};
+struct S4 {
+ friend T4;
+};
+#elif defined(SECOND)
+struct S4 {
+ friend void T4();
+};
+#else
+S4 s4;
+// expected-error@second.h:* {{'Friend::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend function}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend class}}
+#endif
+
+#if defined(FIRST)
+struct S5 {
+ friend void T5a();
+};
+#elif defined(SECOND)
+struct S5 {
+ friend void T5b();
+};
+#else
+S5 s5;
+// expected-error@second.h:* {{'Friend::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found friend function 'T5b'}}
+// expected-note@first.h:* {{but in 'FirstModule' found friend function 'T5a'}}
+#endif
+}
// Interesting cases that should not cause errors. struct S should not error
// while struct T should error at the access specifier mismatch at the end.
namespace AllDecls {
OpenPOWER on IntegriCloud