From: Richard Trieu Date: Sat, 8 Jul 2017 02:04:42 +0000 (+0000) Subject: [ODRHash] Support FriendDecl X-Git-Tag: llvmorg-5.0.0-rc1~941 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ac6a1b6417eee05e4aa32a481b0e39a97ade501a;p=platform%2Fupstream%2Fllvm.git [ODRHash] Support FriendDecl llvm-svn: 307458 --- diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 3c64ebb..0fc5484 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 3f66e58..66b9940 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 3aee3c0..678ecfc 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(FirstDecl); + FriendDecl *SecondFriend = cast(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 6e01e98..ee45ae5 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -1339,6 +1339,84 @@ Bravo 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 {