Skip to content

Commit

Permalink
[ODRHash] Support NestedNameSpecifier
Browse files Browse the repository at this point in the history
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303233 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
Weverything committed May 17, 2017
1 parent ff91697 commit bb0d458
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 30 deletions.
30 changes: 29 additions & 1 deletion lib/AST/ODRHash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,35 @@ void ODRHash::AddDeclarationName(DeclarationName Name) {
}
}

void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {}
void ODRHash::AddNestedNameSpecifier(const NestedNameSpecifier *NNS) {
assert(NNS && "Expecting non-null pointer.");
const auto *Prefix = NNS->getPrefix();
AddBoolean(Prefix);
if (Prefix) {
AddNestedNameSpecifier(Prefix);
}
auto Kind = NNS->getKind();
ID.AddInteger(Kind);
switch (Kind) {
case NestedNameSpecifier::Identifier:
AddIdentifierInfo(NNS->getAsIdentifier());
break;
case NestedNameSpecifier::Namespace:
AddDecl(NNS->getAsNamespace());
break;
case NestedNameSpecifier::NamespaceAlias:
AddDecl(NNS->getAsNamespaceAlias());
break;
case NestedNameSpecifier::TypeSpec:
case NestedNameSpecifier::TypeSpecWithTemplate:
AddType(NNS->getAsType());
break;
case NestedNameSpecifier::Global:
case NestedNameSpecifier::Super:
break;
}
}

void ODRHash::AddTemplateName(TemplateName Name) {}
void ODRHash::AddTemplateArgument(TemplateArgument TA) {}
void ODRHash::AddTemplateParameterList(const TemplateParameterList *TPL) {}
Expand Down
31 changes: 2 additions & 29 deletions lib/Serialization/ASTReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9348,12 +9348,6 @@ void ASTReader::diagnoseOdrViolations() {
return Hash.CalculateHash();
};

auto ComputeDeclNameODRHash = [&Hash](const DeclarationName Name) {
Hash.clear();
Hash.AddDeclarationName(Name);
return Hash.CalculateHash();
};

auto ComputeQualTypeODRHash = [&Hash](QualType Ty) {
Hash.clear();
Hash.AddQualType(Ty);
Expand Down Expand Up @@ -9446,11 +9440,8 @@ void ASTReader::diagnoseOdrViolations() {

QualType FirstType = FirstField->getType();
QualType SecondType = SecondField->getType();
const TypedefType *FirstTypedef = dyn_cast<TypedefType>(FirstType);
const TypedefType *SecondTypedef = dyn_cast<TypedefType>(SecondType);

if ((FirstTypedef && !SecondTypedef) ||
(!FirstTypedef && SecondTypedef)) {
if (ComputeQualTypeODRHash(FirstType) !=
ComputeQualTypeODRHash(SecondType)) {
ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(),
FieldTypeName)
<< FirstII << FirstType;
Expand All @@ -9462,24 +9453,6 @@ void ASTReader::diagnoseOdrViolations() {
break;
}

if (FirstTypedef && SecondTypedef) {
unsigned FirstHash = ComputeDeclNameODRHash(
FirstTypedef->getDecl()->getDeclName());
unsigned SecondHash = ComputeDeclNameODRHash(
SecondTypedef->getDecl()->getDeclName());
if (FirstHash != SecondHash) {
ODRDiagError(FirstField->getLocation(),
FirstField->getSourceRange(), FieldTypeName)
<< FirstII << FirstType;
ODRDiagNote(SecondField->getLocation(),
SecondField->getSourceRange(), FieldTypeName)
<< SecondII << SecondType;

Diagnosed = true;
break;
}
}

const bool IsFirstBitField = FirstField->isBitField();
const bool IsSecondBitField = SecondField->isBitField();
if (IsFirstBitField != IsSecondBitField) {
Expand Down
159 changes: 159 additions & 0 deletions test/Modules/odr_hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,165 @@ S1 s1;
#endif
}

namespace NestedNamespaceSpecifier {
#if defined(FIRST)
namespace LevelA1 {
using Type = int;
}

struct S1 {
LevelA1::Type x;
};
# elif defined(SECOND)
namespace LevelB1 {
namespace LevelC1 {
using Type = int;
}
}

struct S1 {
LevelB1::LevelC1::Type x;
};
#else
S1 s1;
// [email protected]:* {{'NestedNamespaceSpecifier::S1' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'LevelB1::LevelC1::Type' (aka 'int')}}
// [email protected]:* {{but in 'FirstModule' found field 'x' with type 'LevelA1::Type' (aka 'int')}}
#endif

#if defined(FIRST)
namespace LevelA2 { using Type = int; }
struct S2 {
LevelA2::Type x;
};
# elif defined(SECOND)
struct S2 {
int x;
};
#else
S2 s2;
// [email protected]:* {{'NestedNamespaceSpecifier::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'int'}}
// [email protected]:* {{but in 'FirstModule' found field 'x' with type 'LevelA2::Type' (aka 'int')}}
#endif

namespace LevelA3 { using Type = int; }
namespace LevelB3 { using Type = int; }
#if defined(FIRST)
struct S3 {
LevelA3::Type x;
};
# elif defined(SECOND)
struct S3 {
LevelB3::Type x;
};
#else
S3 s3;
// [email protected]:* {{'NestedNamespaceSpecifier::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'LevelB3::Type' (aka 'int')}}
// [email protected]:* {{but in 'FirstModule' found field 'x' with type 'LevelA3::Type' (aka 'int')}}
#endif

#if defined(FIRST)
struct TA4 { using Type = int; };
struct S4 {
TA4::Type x;
};
# elif defined(SECOND)
struct TB4 { using Type = int; };
struct S4 {
TB4::Type x;
};
#else
S4 s4;
// [email protected]:* {{'NestedNamespaceSpecifier::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'TB4::Type' (aka 'int')}}
// [email protected]:* {{but in 'FirstModule' found field 'x' with type 'TA4::Type' (aka 'int')}}
#endif

#if defined(FIRST)
struct T5 { using Type = int; };
struct S5 {
T5::Type x;
};
# elif defined(SECOND)
namespace T5 { using Type = int; };
struct S5 {
T5::Type x;
};
#else
S5 s5;
// [email protected]:* {{'NestedNamespaceSpecifier::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'T5::Type' (aka 'int')}}
// [email protected]:* {{but in 'FirstModule' found field 'x' with type 'T5::Type' (aka 'int')}}
#endif

#if defined(FIRST)
namespace N6 {using I = int;}
struct S6 {
NestedNamespaceSpecifier::N6::I x;
};
# elif defined(SECOND)
using I = int;
struct S6 {
::NestedNamespaceSpecifier::I x;
};
#else
S6 s6;
// [email protected]:* {{'NestedNamespaceSpecifier::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type '::NestedNamespaceSpecifier::I' (aka 'int')}}
// [email protected]:* {{but in 'FirstModule' found field 'x' with type 'NestedNamespaceSpecifier::N6::I' (aka 'int')}}
#endif

#if defined(FIRST)
template <class T, class U>
class S7 {
typename T::type *x = {};
int z = x->T::foo();
};
#elif defined(SECOND)
template <class T, class U>
class S7 {
typename T::type *x = {};
int z = x->U::foo();
};
#else
template <class T, class U>
using U7 = S7<T, U>;
// [email protected]:* {{'NestedNamespaceSpecifier::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'z' with an initializer}}
// [email protected]:* {{but in 'FirstModule' found field 'z' with a different initializer}}
#endif

#if defined(FIRST)
template <class T>
class S8 {
int x = T::template X<int>::value;
};
#elif defined(SECOND)
template <class T>
class S8 {
int x = T::template Y<int>::value;
};
#else
template <class T>
using U8 = S8<T>;
// [email protected]:* {{'NestedNamespaceSpecifier::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with an initializer}}
// [email protected]:* {{but in 'FirstModule' found field 'x' with a different initializer}}
#endif

#if defined(FIRST)
namespace N9 { using I = int; }
namespace O9 = N9;
struct S9 {
O9::I x;
};
#elif defined(SECOND)
namespace N9 { using I = int; }
namespace P9 = N9;
struct S9 {
P9::I x;
};
#else
S9 s9;
// [email protected]:* {{'NestedNamespaceSpecifier::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'P9::I' (aka 'int')}}
// [email protected]:* {{but in 'FirstModule' found field 'x' with type 'O9::I' (aka 'int')}}
#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 {
Expand Down

0 comments on commit bb0d458

Please sign in to comment.