[ODRHash] Support FriendDecl

llvm-svn: 307458
This commit is contained in:
Richard Trieu 2017-07-08 02:04:42 +00:00
parent 8737f0650c
commit ac6a1b6417
4 changed files with 159 additions and 4 deletions

View File

@ -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'">,

View File

@ -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:

View File

@ -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)

View File

@ -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 {