]> granicus.if.org Git - clang/commitdiff
[ODRHash] Support NestedNameSpecifier
authorRichard Trieu <rtrieu@google.com>
Wed, 17 May 2017 03:23:35 +0000 (03:23 +0000)
committerRichard Trieu <rtrieu@google.com>
Wed, 17 May 2017 03:23:35 +0000 (03:23 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@303233 91177308-0d34-0410-b5e6-96231b3b80d8

lib/AST/ODRHash.cpp
lib/Serialization/ASTReader.cpp
test/Modules/odr_hash.cpp

index 0c42acd121842cb4569d97d344a2b60cab0df62a..24371db64d07f53ce71d0fd94dd7f8a4b83fdbb5 100644 (file)
@@ -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) {}
index ef8481488302435977b000b4da56347231335a83..5cabd0e6740d5382bc8b03b8c3c560fea1818a72 100644 (file)
@@ -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<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;
@@ -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) {
index 63bf1e6f5f3c2a04ae7df0558a16652d275f5921..947583bcfd216712fb91d6611a2a56228fa4b347 100644 (file)
@@ -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 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>;
+// 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 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>;
+// 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 {