diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSerializationKinds.td | 12 | ||||
| -rw-r--r-- | clang/lib/AST/ODRHash.cpp | 11 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReader.cpp | 92 | ||||
| -rw-r--r-- | clang/test/Modules/odr_hash.cpp | 105 | 
4 files changed, 219 insertions, 1 deletions
diff --git a/clang/include/clang/Basic/DiagnosticSerializationKinds.td b/clang/include/clang/Basic/DiagnosticSerializationKinds.td index 250b49f2cac..03aaaefff2d 100644 --- a/clang/include/clang/Basic/DiagnosticSerializationKinds.td +++ b/clang/include/clang/Basic/DiagnosticSerializationKinds.td @@ -211,6 +211,12 @@ def err_module_odr_violation_mismatch_decl_diff : Error<      "with %ordinal6 parameter with%select{out|}7 a default argument|"    "%select{method %5|constructor|destructor}4 "      "with %ordinal6 parameter with a default argument|" +  "%select{method %5|constructor|destructor}4 " +    "with %select{no |}6template arguments|" +  "%select{method %5|constructor|destructor}4 " +    "with %6 template argument%s6|" +  "%select{method %5|constructor|destructor}4 " +    "with %6 for %ordinal7 template argument|"    "%select{typedef|type alias}4 name %5|"    "%select{typedef|type alias}4 %5 with underlying type %6|"    "data member with name %4|" @@ -258,6 +264,12 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "      "with %ordinal4 parameter with%select{out|}5 a default argument|"    "%select{method %3|constructor|destructor}2 "      "with %ordinal4 parameter with a different default argument|" +  "%select{method %3|constructor|destructor}2 " +    "with %select{no |}4template arguments|" +  "%select{method %3|constructor|destructor}2 " +    "with %4 template argument%s4|" +  "%select{method %3|constructor|destructor}2 " +    "with %4 for %ordinal5 template argument|"    "%select{typedef|type alias}2 name %3|"    "%select{typedef|type alias}2 %3 with different underlying type %4|"    "data member with name %2|" diff --git a/clang/lib/AST/ODRHash.cpp b/clang/lib/AST/ODRHash.cpp index 364fd04b83b..ee6950655cf 100644 --- a/clang/lib/AST/ODRHash.cpp +++ b/clang/lib/AST/ODRHash.cpp @@ -148,6 +148,8 @@ void ODRHash::AddTemplateArgument(TemplateArgument TA) {        AddQualType(TA.getAsType());        break;      case TemplateArgument::Declaration: +      AddDecl(TA.getAsDecl()); +      break;      case TemplateArgument::NullPtr:      case TemplateArgument::Integral:        break; @@ -330,6 +332,15 @@ public:      AddQualType(D->getReturnType()); +    const auto* SpecializationArgs = D->getTemplateSpecializationArgs(); +    Hash.AddBoolean(SpecializationArgs); +    if (SpecializationArgs) { +      ID.AddInteger(SpecializationArgs->size()); +      for (const TemplateArgument &TA : SpecializationArgs->asArray()) { +        Hash.AddTemplateArgument(TA); +      } +    } +      Inherited::VisitFunctionDecl(D);    } diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index a8a4f9328d2..9d10b9ebfbb 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -9450,6 +9450,12 @@ void ASTReader::diagnoseOdrViolations() {      return Hash.CalculateHash();    }; +  auto ComputeTemplateArgumentODRHash = [&Hash](const TemplateArgument &TA) { +    Hash.clear(); +    Hash.AddTemplateArgument(TA); +    return Hash.CalculateHash(); +  }; +    // Issue any pending ODR-failure diagnostics.    for (auto &Merge : OdrMergeFailures) {      // If we've already pointed out a specific problem with this class, don't @@ -9948,6 +9954,9 @@ void ASTReader::diagnoseOdrViolations() {          MethodParameterName,          MethodParameterSingleDefaultArgument,          MethodParameterDifferentDefaultArgument, +        MethodNoTemplateArguments, +        MethodDifferentNumberTemplateArguments, +        MethodDifferentTemplateArgument,          TypedefName,          TypedefType,          VarName, @@ -10370,6 +10379,89 @@ void ASTReader::diagnoseOdrViolations() {            break;          } +        const auto *FirstTemplateArgs = +            FirstMethod->getTemplateSpecializationArgs(); +        const auto *SecondTemplateArgs = +            SecondMethod->getTemplateSpecializationArgs(); + +        if ((FirstTemplateArgs && !SecondTemplateArgs) || +            (!FirstTemplateArgs && SecondTemplateArgs)) { +          ODRDiagError(FirstMethod->getLocation(), +                       FirstMethod->getSourceRange(), MethodNoTemplateArguments) +              << FirstMethodType << FirstName << (FirstTemplateArgs != nullptr); +          ODRDiagNote(SecondMethod->getLocation(), +                      SecondMethod->getSourceRange(), MethodNoTemplateArguments) +              << SecondMethodType << SecondName +              << (SecondTemplateArgs != nullptr); + +          Diagnosed = true; +          break; +        } + +        if (FirstTemplateArgs && SecondTemplateArgs) { +          // Remove pack expansions from argument list. +          auto ExpandTemplateArgumentList = +              [](const TemplateArgumentList *TAL) { +                llvm::SmallVector<const TemplateArgument *, 8> ExpandedList; +                for (const TemplateArgument &TA : TAL->asArray()) { +                  if (TA.getKind() != TemplateArgument::Pack) { +                    ExpandedList.push_back(&TA); +                    continue; +                  } +                  for (const TemplateArgument &PackTA : TA.getPackAsArray()) { +                    ExpandedList.push_back(&PackTA); +                  } +                } +                return ExpandedList; +              }; +          llvm::SmallVector<const TemplateArgument *, 8> FirstExpandedList = +              ExpandTemplateArgumentList(FirstTemplateArgs); +          llvm::SmallVector<const TemplateArgument *, 8> SecondExpandedList = +              ExpandTemplateArgumentList(SecondTemplateArgs); + +          if (FirstExpandedList.size() != SecondExpandedList.size()) { +            ODRDiagError(FirstMethod->getLocation(), +                         FirstMethod->getSourceRange(), +                         MethodDifferentNumberTemplateArguments) +                << FirstMethodType << FirstName +                << (unsigned)FirstExpandedList.size(); +            ODRDiagNote(SecondMethod->getLocation(), +                        SecondMethod->getSourceRange(), +                        MethodDifferentNumberTemplateArguments) +                << SecondMethodType << SecondName +                << (unsigned)SecondExpandedList.size(); + +            Diagnosed = true; +            break; +          } + +          bool TemplateArgumentMismatch = false; +          for (unsigned i = 0, e = FirstExpandedList.size(); i != e; ++i) { +            const TemplateArgument &FirstTA = *FirstExpandedList[i], +                                   &SecondTA = *SecondExpandedList[i]; +            if (ComputeTemplateArgumentODRHash(FirstTA) == +                ComputeTemplateArgumentODRHash(SecondTA)) { +              continue; +            } + +            ODRDiagError(FirstMethod->getLocation(), +                         FirstMethod->getSourceRange(), +                         MethodDifferentTemplateArgument) +                << FirstMethodType << FirstName << FirstTA << i + 1; +            ODRDiagNote(SecondMethod->getLocation(), +                        SecondMethod->getSourceRange(), +                        MethodDifferentTemplateArgument) +                << SecondMethodType << SecondName << SecondTA << i + 1; + +            TemplateArgumentMismatch = true; +            break; +          } + +          if (TemplateArgumentMismatch) { +            Diagnosed = true; +            break; +          } +        }          break;        }        case TypeAlias: diff --git a/clang/test/Modules/odr_hash.cpp b/clang/test/Modules/odr_hash.cpp index 8667a3ad5f3..d4c4aceb667 100644 --- a/clang/test/Modules/odr_hash.cpp +++ b/clang/test/Modules/odr_hash.cpp @@ -1635,6 +1635,96 @@ S6 s6;  // expected-note@first.h:* {{but in 'FirstModule' found field 'x'}}  #endif +#if defined(FIRST) +struct S7 { +  template<int> void run() {} +  template<> void run<1>() {} +}; +#elif defined(SECOND) +struct S7 { +  template<int> void run() {} +  void run() {} +}; +#else +S7 s7; +// expected-error@second.h:* {{'TemplateArgument::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with no template arguments}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'run' with template arguments}} +#endif + +#if defined(FIRST) +struct S8 { +  static int a, b; +  template<int&> void run() {} +  template<int&, int&> void run() {} +  template<> void run<a>() {} +}; +#elif defined(SECOND) +struct S8 { +  static int a, b; +  template<int&> void run() {} +  template<int&, int&> void run() {} +  template<> void run<a, b>() {} +}; +#else +S8 s8; +// expected-error@second.h:* {{'TemplateArgument::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with 2 template arguments}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'run' with 1 template argument}} +#endif + +#if defined(FIRST) +struct S9 { +  static int a, b; +  template<int&> void run() {} +  template<> void run<a>() {} +}; +#elif defined(SECOND) +struct S9 { +  static int a, b; +  template<int&> void run() {} +  template<> void run<b>() {} +}; +#else +S9 s9; +// expected-error@second.h:* {{'TemplateArgument::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with 'b' for 1st template argument}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'run' with 'a' for 1st template argument}} +#endif + +#if defined(FIRST) +struct S10 { +  static int a, b; +  template<int, int&...> void run() {} +  template<> void run<1, a>() {} +}; +#elif defined(SECOND) +struct S10 { +  static int a, b; +  template<int, int&...> void run() {} +  template<> void run<1, b>() {} +}; +#else +S10 s10; +// expected-error@second.h:* {{'TemplateArgument::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with 'b' for 2nd template argument}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'run' with 'a' for 2nd template argument}} +#endif + +#if defined(FIRST) +struct S11 { +  static int a, b; +  template<int, int&...> void run() {} +  template<> void run<1, a>() {} +}; +#elif defined(SECOND) +struct S11 { +  static int a, b; +  template<int, int&...> void run() {} +  template<> void run<1, a, a>() {} +}; +#else +S11 s11; +// expected-error@second.h:* {{'TemplateArgument::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found method 'run' with 3 template arguments}} +// expected-note@first.h:* {{but in 'FirstModule' found method 'run' with 2 template arguments}} +#endif +  #define DECLS                   \    OneClass<int> a;              \    OneInt<1> b;                  \ @@ -1642,7 +1732,20 @@ S6 s6;    using d = OneInt<2>;          \    using e = OneInt<2 + 2>;      \    OneTemplateClass<OneClass> f; \ -  OneTemplateInt<OneInt> g; +  OneTemplateInt<OneInt> g;     \ +  static int i1, i2;            \ +  template <int &>              \ +  void Function() {}            \ +  template <int &, int &>       \ +  void Function() {}            \ +  template <>                   \ +  void Function<i1>() {}        \ +  template <>                   \ +  void Function<i2>() {}        \ +  template <>                   \ +  void Function<i1, i2>() {}    \ +  template <>                   \ +  void Function<i2, i1>() {}  #if defined(FIRST) || defined(SECOND)  template <class> struct OneClass{};  | 

