forked from OSchip/llvm-project
[ODRHash] Hash template arguments of methods.
llvm-svn: 330789
This commit is contained in:
parent
61376d9bed
commit
7282d320b7
clang
include/clang/Basic
lib
test/Modules
|
@ -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|"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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{};
|
||||
|
|
Loading…
Reference in New Issue