From: Richard Trieu Date: Wed, 17 May 2017 03:23:35 +0000 (+0000) Subject: [ODRHash] Support NestedNameSpecifier X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bb0d458629af8f3d52e8fa61ed730a9081a120c3;p=clang [ODRHash] Support NestedNameSpecifier git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303233 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ODRHash.cpp b/lib/AST/ODRHash.cpp index 0c42acd121..24371db64d 100644 --- a/lib/AST/ODRHash.cpp +++ b/lib/AST/ODRHash.cpp @@ -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) {} diff --git a/lib/Serialization/ASTReader.cpp b/lib/Serialization/ASTReader.cpp index ef84814883..5cabd0e674 100644 --- a/lib/Serialization/ASTReader.cpp +++ b/lib/Serialization/ASTReader.cpp @@ -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); @@ -9446,11 +9440,8 @@ void ASTReader::diagnoseOdrViolations() { QualType FirstType = FirstField->getType(); QualType SecondType = SecondField->getType(); - const TypedefType *FirstTypedef = dyn_cast(FirstType); - const TypedefType *SecondTypedef = dyn_cast(SecondType); - - if ((FirstTypedef && !SecondTypedef) || - (!FirstTypedef && SecondTypedef)) { + if (ComputeQualTypeODRHash(FirstType) != + ComputeQualTypeODRHash(SecondType)) { ODRDiagError(FirstField->getLocation(), FirstField->getSourceRange(), FieldTypeName) << FirstII << FirstType; @@ -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) { diff --git a/test/Modules/odr_hash.cpp b/test/Modules/odr_hash.cpp index 63bf1e6f5f..947583bcfd 100644 --- a/test/Modules/odr_hash.cpp +++ b/test/Modules/odr_hash.cpp @@ -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; +// expected-error@second.h:* {{'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')}} +// expected-note@first.h:* {{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; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::S2' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'int'}} +// expected-note@first.h:* {{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; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'LevelB3::Type' (aka 'int')}} +// expected-note@first.h:* {{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; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::S4' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'TB4::Type' (aka 'int')}} +// expected-note@first.h:* {{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; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'T5::Type' (aka 'int')}} +// expected-note@first.h:* {{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; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type '::NestedNamespaceSpecifier::I' (aka 'int')}} +// expected-note@first.h:* {{but in 'FirstModule' found field 'x' with type 'NestedNamespaceSpecifier::N6::I' (aka 'int')}} +#endif + +#if defined(FIRST) +template +class S7 { + typename T::type *x = {}; + int z = x->T::foo(); +}; +#elif defined(SECOND) +template +class S7 { + typename T::type *x = {}; + int z = x->U::foo(); +}; +#else +template +using U7 = S7; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'z' with an initializer}} +// expected-note@first.h:* {{but in 'FirstModule' found field 'z' with a different initializer}} +#endif + +#if defined(FIRST) +template +class S8 { + int x = T::template X::value; +}; +#elif defined(SECOND) +template +class S8 { + int x = T::template Y::value; +}; +#else +template +using U8 = S8; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with an initializer}} +// expected-note@first.h:* {{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; +// expected-error@second.h:* {{'NestedNamespaceSpecifier::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found field 'x' with type 'P9::I' (aka 'int')}} +// expected-note@first.h:* {{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 {