[ODRHash] Add IdentiferInfo and FieldDecl support.

IdentifierInfo is hashed based on the stored string.  FieldDecl versus other
Decl is now detected, as well as differently named fields.

Differential Revision: https://reviews.llvm.org/D21675

llvm-svn: 295911
This commit is contained in:
Richard Trieu 2017-02-23 00:23:01 +00:00
parent a55b86c0e5
commit d0786099b1
4 changed files with 98 additions and 5 deletions

View File

@ -121,10 +121,10 @@ def err_module_odr_violation_mismatch_decl : Error<
"%q0 has different definitions in different modules; first difference is "
"%select{definition in module '%2'|defined here}1 found "
"%select{end of class|public access specifier|private access specifier|"
"protected access specifier|static assert}3">;
"protected access specifier|static assert|field}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}1">;
"protected access specifier|static assert|field}1">;
def err_module_odr_violation_mismatch_decl_diff : Error<
"%q0 has different definitions in different modules; first difference is "
@ -132,13 +132,15 @@ def err_module_odr_violation_mismatch_decl_diff : Error<
"%select{"
"static assert with condition|"
"static assert with message|"
"static assert with %select{|no }4message}3">;
"static assert with %select{|no }4message|"
"field %4}3">;
def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
"%select{"
"static assert with different condition|"
"static assert with different message|"
"static assert with %select{|no }2message}1">;
"static assert with %select{|no }2message|"
"field %2}1">;
def warn_module_uses_date_time : Warning<
"%select{precompiled header|module}0 uses __DATE__ or __TIME__">,

View File

@ -26,7 +26,12 @@ void ODRHash::AddStmt(const Stmt *S) {
assert(S && "Expecting non-null pointer.");
S->ProcessODRHash(ID, *this);
}
void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {}
void ODRHash::AddIdentifierInfo(const IdentifierInfo *II) {
assert(II && "Expecting non-null pointer.");
ID.AddString(II->getName());
}
void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {}
void ODRHash::AddTemplateName(TemplateName Name) {}
void ODRHash::AddDeclarationName(DeclarationName Name) {}
@ -90,11 +95,23 @@ public:
}
}
void AddIdentifierInfo(const IdentifierInfo *II) {
Hash.AddBoolean(II);
if (II) {
Hash.AddIdentifierInfo(II);
}
}
void Visit(const Decl *D) {
ID.AddInteger(D->getKind());
Inherited::Visit(D);
}
void VisitNamedDecl(const NamedDecl *D) {
AddIdentifierInfo(D->getIdentifier());
Inherited::VisitNamedDecl(D);
}
void VisitAccessSpecDecl(const AccessSpecDecl *D) {
ID.AddInteger(D->getAccess());
Inherited::VisitAccessSpecDecl(D);
@ -106,6 +123,10 @@ public:
Inherited::VisitStaticAssertDecl(D);
}
void VisitFieldDecl(const FieldDecl *D) {
Inherited::VisitFieldDecl(D);
}
};
// Only allow a small portion of Decl's to be processed. Remove this once
@ -118,6 +139,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
default:
return false;
case Decl::AccessSpec:
case Decl::Field:
case Decl::StaticAssert:
return true;
}

View File

@ -8956,6 +8956,7 @@ void ASTReader::diagnoseOdrViolations() {
PrivateSpecifer,
ProtectedSpecifer,
StaticAssert,
Field,
Other
} FirstDiffType = Other,
SecondDiffType = Other;
@ -8979,6 +8980,8 @@ void ASTReader::diagnoseOdrViolations() {
llvm_unreachable("Invalid access specifier");
case Decl::StaticAssert:
return StaticAssert;
case Decl::Field:
return Field;
}
};
@ -9058,6 +9061,7 @@ void ASTReader::diagnoseOdrViolations() {
StaticAssertCondition,
StaticAssertMessage,
StaticAssertOnlyMessage,
FieldName,
};
// These lambdas have the common portions of the ODR diagnostics. This
@ -9146,6 +9150,24 @@ void ASTReader::diagnoseOdrViolations() {
}
break;
}
case Field: {
FieldDecl *FirstField = cast<FieldDecl>(FirstDecl);
FieldDecl *SecondField = cast<FieldDecl>(SecondDecl);
IdentifierInfo *FirstII = FirstField->getIdentifier();
IdentifierInfo *SecondII = SecondField->getIdentifier();
if (FirstII->getName() != SecondII->getName()) {
ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
FieldName)
<< FirstII;
ODRDiagNote(SecondField->getLocation(), SecondField->getSourceRange(),
FieldName)
<< SecondII;
Diagnosed = true;
break;
}
break;
}
}
if (Diagnosed == true)

View File

@ -115,6 +115,41 @@ S4 s4;
#endif
}
namespace Field {
#if defined(FIRST)
struct S1 {
int x;
private:
int y;
};
#elif defined(SECOND)
struct S1 {
int x;
int y;
};
#else
S1 s1;
// expected-error@second.h:* {{'Field::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found field}}
// expected-note@first.h:* {{but in 'FirstModule' found private access specifier}}
#endif
#if defined(FIRST)
struct S2 {
int x;
int y;
};
#elif defined(SECOND)
struct S2 {
int y;
int x;
};
#else
S2 s2;
// expected-error@second.h:* {{'Field::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'y'}}
// expected-note@first.h:* {{but in 'FirstModule' found field 'x'}}
#endif
} // namespace Field
// Naive parsing of AST can lead to cycles in processing. Ensure
// self-references don't trigger an endless cycles of AST node processing.
namespace SelfReference {
@ -151,6 +186,9 @@ struct S {
static_assert(1 == 1, "Message");
static_assert(2 == 2);
int x;
double y;
};
#elif defined(SECOND)
struct S {
@ -160,6 +198,9 @@ struct S {
static_assert(1 == 1, "Message");
static_assert(2 == 2);
int x;
double y;
};
#else
S s;
@ -174,6 +215,9 @@ struct T {
static_assert(1 == 1, "Message");
static_assert(2 == 2);
int x;
double y;
private:
};
#elif defined(SECOND)
@ -185,6 +229,9 @@ struct T {
static_assert(1 == 1, "Message");
static_assert(2 == 2);
int x;
double y;
public:
};
#else