[ODRHash] Support more types in the ODR checker.

Added support for TagType, TypeWithKeyword, and all children types.

llvm-svn: 303231
This commit is contained in:
Richard Trieu 2017-05-17 02:29:02 +00:00
parent 4d5dd3b7ef
commit 58bb7bd18a
2 changed files with 122 additions and 0 deletions
clang
lib/AST
test/Modules

View File

@ -335,6 +335,20 @@ public:
Hash.AddQualType(T);
}
void AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
Hash.AddBoolean(NNS);
if (NNS) {
Hash.AddNestedNameSpecifier(NNS);
}
}
void AddIdentifierInfo(const IdentifierInfo *II) {
Hash.AddBoolean(II);
if (II) {
Hash.AddIdentifierInfo(II);
}
}
void VisitQualifiers(Qualifiers Quals) {
ID.AddInteger(Quals.getAsOpaqueValue());
}
@ -414,6 +428,42 @@ public:
AddQualType(T->getDecl()->getUnderlyingType().getCanonicalType());
VisitType(T);
}
void VisitTagType(const TagType *T) {
AddDecl(T->getDecl());
VisitType(T);
}
void VisitRecordType(const RecordType *T) { VisitTagType(T); }
void VisitEnumType(const EnumType *T) { VisitTagType(T); }
void VisitTypeWithKeyword(const TypeWithKeyword *T) {
ID.AddInteger(T->getKeyword());
VisitType(T);
};
void VisitDependentNameType(const DependentNameType *T) {
AddNestedNameSpecifier(T->getQualifier());
AddIdentifierInfo(T->getIdentifier());
VisitTypeWithKeyword(T);
}
void VisitDependentTemplateSpecializationType(
const DependentTemplateSpecializationType *T) {
AddIdentifierInfo(T->getIdentifier());
AddNestedNameSpecifier(T->getQualifier());
ID.AddInteger(T->getNumArgs());
for (const auto &TA : T->template_arguments()) {
Hash.AddTemplateArgument(TA);
}
VisitTypeWithKeyword(T);
}
void VisitElaboratedType(const ElaboratedType *T) {
AddNestedNameSpecifier(T->getQualifier());
AddQualType(T->getNamedType());
VisitTypeWithKeyword(T);
}
};
void ODRHash::AddType(const Type *T) {

View File

@ -634,6 +634,78 @@ S3 s3;
#endif
} // namespace Using
namespace RecordType {
#if defined(FIRST)
struct B1 {};
struct S1 {
B1 x;
};
#elif defined(SECOND)
struct A1 {};
struct S1 {
A1 x;
};
#else
S1 s1;
// expected-error@first.h:* {{'RecordType::S1::x' from module 'FirstModule' is not present in definition of 'RecordType::S1' in module 'SecondModule'}}
// expected-note@second.h:* {{declaration of 'x' does not match}}
#endif
}
namespace DependentType {
#if defined(FIRST)
template <class T>
class S1 {
typename T::typeA x;
};
#elif defined(SECOND)
template <class T>
class S1 {
typename T::typeB x;
};
#else
template<class T>
using U1 = S1<T>;
// expected-error@first.h:* {{'DependentType::S1::x' from module 'FirstModule' is not present in definition of 'S1<T>' in module 'SecondModule'}}
// expected-note@second.h:* {{declaration of 'x' does not match}}
#endif
}
namespace ElaboratedType {
#if defined(FIRST)
namespace N1 { using type = double; }
struct S1 {
N1::type x;
};
#elif defined(SECOND)
namespace N1 { using type = int; }
struct S1 {
N1::type x;
};
#else
S1 s1;
// expected-error@first.h:* {{'ElaboratedType::S1::x' from module 'FirstModule' is not present in definition of 'ElaboratedType::S1' in module 'SecondModule'}}
// expected-note@second.h:* {{declaration of 'x' does not match}}
#endif
}
namespace Enum {
#if defined(FIRST)
enum A1 {};
struct S1 {
A1 x;
};
#elif defined(SECOND)
enum A2 {};
struct S1 {
A2 x;
};
#else
S1 s1;
// expected-error@first.h:* {{'Enum::S1::x' from module 'FirstModule' is not present in definition of 'Enum::S1' in module 'SecondModule'}}
// expected-note@second.h:* {{declaration of 'x' does not match}}
#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.