[ODRHash] Support FunctionTemplateDecl in records.

llvm-svn: 333486
This commit is contained in:
Richard Trieu 2018-05-30 01:12:26 +00:00
parent 92e523bf55
commit 9359e8f22a
4 changed files with 804 additions and 3 deletions

View File

@ -168,11 +168,11 @@ def err_module_odr_violation_mismatch_decl : Error<
"%select{definition in module '%2'|defined here}1 found "
"%select{end of class|public access specifier|private access specifier|"
"protected access specifier|static assert|field|method|type alias|typedef|"
"data member|friend declaration}3">;
"data member|friend declaration|function template}3">;
def note_module_odr_violation_mismatch_decl : Note<"but in '%0' found "
"%select{end of class|public access specifier|private access specifier|"
"protected access specifier|static assert|field|method|type alias|typedef|"
"data member|friend declaration}1">;
"data member|friend declaration|function template}1">;
def err_module_odr_violation_mismatch_decl_diff : Error<
"%q0 has different definitions in different modules; first difference is "
@ -227,6 +227,18 @@ def err_module_odr_violation_mismatch_decl_diff : Error<
"friend %select{class|function}4|"
"friend %4|"
"friend function %4|"
"function template %4 with %5 template parameter%s5|"
"function template %4 with %ordinal5 template parameter being a "
"%select{type|non-type|template}6 template parameter|"
"function template %4 with %ordinal5 template parameter "
"%select{with no name|named %7}6|"
"function template %4 with %ordinal5 template parameter with "
"%select{no |}6default argument|"
"function template %4 with %ordinal5 template parameter with "
"default argument %6|"
"function template %4 with %ordinal5 template parameter with one type|"
"function template %4 with %ordinal5 template parameter %select{not |}6"
"being a template parameter pack|"
"}3">;
def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
@ -280,6 +292,18 @@ def note_module_odr_violation_mismatch_decl_diff : Note<"but in '%0' found "
"friend %select{class|function}2|"
"friend %2|"
"friend function %2|"
"function template %2 with %3 template parameter%s3|"
"function template %2 with %ordinal3 template paramter being a "
"%select{type|non-type|template}4 template parameter|"
"function template %2 with %ordinal3 template parameter "
"%select{with no name|named %5}4|"
"function template %2 with %ordinal3 template parameter with "
"%select{no |}4default argument|"
"function template %2 with %ordinal3 template parameter with "
"default argument %4|"
"function template %2 with %ordinal3 template parameter with different type|"
"function template %2 with %ordinal3 template parameter %select{not |}4"
"being a template parameter pack|"
"}1">;
def err_module_odr_violation_function : Error<

View File

@ -383,6 +383,7 @@ public:
if (hasDefaultArgument) {
AddTemplateArgument(D->getDefaultArgument());
}
Hash.AddBoolean(D->isParameterPack());
Inherited::VisitTemplateTypeParmDecl(D);
}
@ -395,6 +396,7 @@ public:
if (hasDefaultArgument) {
AddStmt(D->getDefaultArgument());
}
Hash.AddBoolean(D->isParameterPack());
Inherited::VisitNonTypeTemplateParmDecl(D);
}
@ -407,9 +409,27 @@ public:
if (hasDefaultArgument) {
AddTemplateArgument(D->getDefaultArgument().getArgument());
}
Hash.AddBoolean(D->isParameterPack());
Inherited::VisitTemplateTemplateParmDecl(D);
}
void VisitTemplateDecl(const TemplateDecl *D) {
Hash.AddTemplateParameterList(D->getTemplateParameters());
Inherited::VisitTemplateDecl(D);
}
void VisitRedeclarableTemplateDecl(const RedeclarableTemplateDecl *D) {
Hash.AddBoolean(D->isMemberSpecialization());
Inherited::VisitRedeclarableTemplateDecl(D);
}
void VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) {
Visit(D->getTemplatedDecl());
ID.AddInteger(D->getTemplatedDecl()->getODRHash());
Inherited::VisitFunctionTemplateDecl(D);
}
};
} // namespace
@ -428,6 +448,7 @@ bool ODRHash::isWhitelistedDecl(const Decl *D, const CXXRecordDecl *Parent) {
case Decl::CXXMethod:
case Decl::Field:
case Decl::Friend:
case Decl::FunctionTemplate:
case Decl::StaticAssert:
case Decl::TypeAlias:
case Decl::Typedef:

View File

@ -9462,6 +9462,14 @@ void ASTReader::diagnoseOdrViolations() {
return Hash.CalculateHash();
};
auto ComputeTemplateParameterListODRHash =
[&Hash](const TemplateParameterList *TPL) {
assert(TPL);
Hash.clear();
Hash.AddTemplateParameterList(TPL);
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
@ -9814,6 +9822,7 @@ void ASTReader::diagnoseOdrViolations() {
TypeDef,
Var,
Friend,
FunctionTemplate,
Other
} FirstDiffType = Other,
SecondDiffType = Other;
@ -9851,6 +9860,8 @@ void ASTReader::diagnoseOdrViolations() {
return Var;
case Decl::Friend:
return Friend;
case Decl::FunctionTemplate:
return FunctionTemplate;
}
};
@ -9937,7 +9948,7 @@ void ASTReader::diagnoseOdrViolations() {
// Used with err_module_odr_violation_mismatch_decl_diff and
// note_module_odr_violation_mismatch_decl_diff
enum ODRDeclDifference{
enum ODRDeclDifference {
StaticAssertCondition,
StaticAssertMessage,
StaticAssertOnlyMessage,
@ -9973,6 +9984,13 @@ void ASTReader::diagnoseOdrViolations() {
FriendTypeFunction,
FriendType,
FriendFunction,
FunctionTemplateDifferentNumberParameters,
FunctionTemplateParameterDifferentKind,
FunctionTemplateParameterName,
FunctionTemplateParameterSingleDefaultArgument,
FunctionTemplateParameterDifferentDefaultArgument,
FunctionTemplateParameterDifferentType,
FunctionTemplatePackParameter,
};
// These lambdas have the common portions of the ODR diagnostics. This
@ -10620,6 +10638,305 @@ void ASTReader::diagnoseOdrViolations() {
Diagnosed = true;
break;
}
case FunctionTemplate: {
FunctionTemplateDecl *FirstTemplate =
cast<FunctionTemplateDecl>(FirstDecl);
FunctionTemplateDecl *SecondTemplate =
cast<FunctionTemplateDecl>(SecondDecl);
TemplateParameterList *FirstTPL =
FirstTemplate->getTemplateParameters();
TemplateParameterList *SecondTPL =
SecondTemplate->getTemplateParameters();
if (FirstTPL->size() != SecondTPL->size()) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateDifferentNumberParameters)
<< FirstTemplate << FirstTPL->size();
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateDifferentNumberParameters)
<< SecondTemplate << SecondTPL->size();
Diagnosed = true;
break;
}
bool ParameterMismatch = false;
for (unsigned i = 0, e = FirstTPL->size(); i != e; ++i) {
NamedDecl *FirstParam = FirstTPL->getParam(i);
NamedDecl *SecondParam = SecondTPL->getParam(i);
if (FirstParam->getKind() != SecondParam->getKind()) {
enum {
TemplateTypeParameter,
NonTypeTemplateParameter,
TemplateTemplateParameter,
};
auto GetParamType = [](NamedDecl *D) {
switch (D->getKind()) {
default:
llvm_unreachable("Unexpected template parameter type");
case Decl::TemplateTypeParm:
return TemplateTypeParameter;
case Decl::NonTypeTemplateParm:
return NonTypeTemplateParameter;
case Decl::TemplateTemplateParm:
return TemplateTemplateParameter;
}
};
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterDifferentKind)
<< FirstTemplate << (i + 1) << GetParamType(FirstParam);
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterDifferentKind)
<< SecondTemplate << (i + 1) << GetParamType(SecondParam);
ParameterMismatch = true;
break;
}
if (FirstParam->getName() != SecondParam->getName()) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterName)
<< FirstTemplate << (i + 1) << (bool)FirstParam->getIdentifier()
<< FirstParam;
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterName)
<< SecondTemplate << (i + 1)
<< (bool)SecondParam->getIdentifier() << SecondParam;
ParameterMismatch = true;
break;
}
if (isa<TemplateTypeParmDecl>(FirstParam) &&
isa<TemplateTypeParmDecl>(SecondParam)) {
TemplateTypeParmDecl *FirstTTPD =
cast<TemplateTypeParmDecl>(FirstParam);
TemplateTypeParmDecl *SecondTTPD =
cast<TemplateTypeParmDecl>(SecondParam);
bool HasFirstDefaultArgument =
FirstTTPD->hasDefaultArgument() &&
!FirstTTPD->defaultArgumentWasInherited();
bool HasSecondDefaultArgument =
SecondTTPD->hasDefaultArgument() &&
!SecondTTPD->defaultArgumentWasInherited();
if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterSingleDefaultArgument)
<< FirstTemplate << (i + 1) << HasFirstDefaultArgument;
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterSingleDefaultArgument)
<< SecondTemplate << (i + 1) << HasSecondDefaultArgument;
ParameterMismatch = true;
break;
}
if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
QualType FirstType = FirstTTPD->getDefaultArgument();
QualType SecondType = SecondTTPD->getDefaultArgument();
if (ComputeQualTypeODRHash(FirstType) !=
ComputeQualTypeODRHash(SecondType)) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterDifferentDefaultArgument)
<< FirstTemplate << (i + 1) << FirstType;
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterDifferentDefaultArgument)
<< SecondTemplate << (i + 1) << SecondType;
ParameterMismatch = true;
break;
}
}
if (FirstTTPD->isParameterPack() !=
SecondTTPD->isParameterPack()) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplatePackParameter)
<< FirstTemplate << (i + 1) << FirstTTPD->isParameterPack();
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplatePackParameter)
<< SecondTemplate << (i + 1) << SecondTTPD->isParameterPack();
ParameterMismatch = true;
break;
}
}
if (isa<TemplateTemplateParmDecl>(FirstParam) &&
isa<TemplateTemplateParmDecl>(SecondParam)) {
TemplateTemplateParmDecl *FirstTTPD =
cast<TemplateTemplateParmDecl>(FirstParam);
TemplateTemplateParmDecl *SecondTTPD =
cast<TemplateTemplateParmDecl>(SecondParam);
TemplateParameterList *FirstTPL =
FirstTTPD->getTemplateParameters();
TemplateParameterList *SecondTPL =
SecondTTPD->getTemplateParameters();
if (ComputeTemplateParameterListODRHash(FirstTPL) !=
ComputeTemplateParameterListODRHash(SecondTPL)) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterDifferentType)
<< FirstTemplate << (i + 1);
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterDifferentType)
<< SecondTemplate << (i + 1);
ParameterMismatch = true;
break;
}
bool HasFirstDefaultArgument =
FirstTTPD->hasDefaultArgument() &&
!FirstTTPD->defaultArgumentWasInherited();
bool HasSecondDefaultArgument =
SecondTTPD->hasDefaultArgument() &&
!SecondTTPD->defaultArgumentWasInherited();
if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterSingleDefaultArgument)
<< FirstTemplate << (i + 1) << HasFirstDefaultArgument;
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterSingleDefaultArgument)
<< SecondTemplate << (i + 1) << HasSecondDefaultArgument;
ParameterMismatch = true;
break;
}
if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
TemplateArgument FirstTA =
FirstTTPD->getDefaultArgument().getArgument();
TemplateArgument SecondTA =
SecondTTPD->getDefaultArgument().getArgument();
if (ComputeTemplateArgumentODRHash(FirstTA) !=
ComputeTemplateArgumentODRHash(SecondTA)) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterDifferentDefaultArgument)
<< FirstTemplate << (i + 1) << FirstTA;
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterDifferentDefaultArgument)
<< SecondTemplate << (i + 1) << SecondTA;
ParameterMismatch = true;
break;
}
}
if (FirstTTPD->isParameterPack() !=
SecondTTPD->isParameterPack()) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplatePackParameter)
<< FirstTemplate << (i + 1) << FirstTTPD->isParameterPack();
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplatePackParameter)
<< SecondTemplate << (i + 1) << SecondTTPD->isParameterPack();
ParameterMismatch = true;
break;
}
}
if (isa<NonTypeTemplateParmDecl>(FirstParam) &&
isa<NonTypeTemplateParmDecl>(SecondParam)) {
NonTypeTemplateParmDecl *FirstNTTPD =
cast<NonTypeTemplateParmDecl>(FirstParam);
NonTypeTemplateParmDecl *SecondNTTPD =
cast<NonTypeTemplateParmDecl>(SecondParam);
QualType FirstType = FirstNTTPD->getType();
QualType SecondType = SecondNTTPD->getType();
if (ComputeQualTypeODRHash(FirstType) !=
ComputeQualTypeODRHash(SecondType)) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterDifferentType)
<< FirstTemplate << (i + 1);
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterDifferentType)
<< SecondTemplate << (i + 1);
ParameterMismatch = true;
break;
}
bool HasFirstDefaultArgument =
FirstNTTPD->hasDefaultArgument() &&
!FirstNTTPD->defaultArgumentWasInherited();
bool HasSecondDefaultArgument =
SecondNTTPD->hasDefaultArgument() &&
!SecondNTTPD->defaultArgumentWasInherited();
if (HasFirstDefaultArgument != HasSecondDefaultArgument) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterSingleDefaultArgument)
<< FirstTemplate << (i + 1) << HasFirstDefaultArgument;
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterSingleDefaultArgument)
<< SecondTemplate << (i + 1) << HasSecondDefaultArgument;
ParameterMismatch = true;
break;
}
if (HasFirstDefaultArgument && HasSecondDefaultArgument) {
Expr *FirstDefaultArgument = FirstNTTPD->getDefaultArgument();
Expr *SecondDefaultArgument = SecondNTTPD->getDefaultArgument();
if (ComputeODRHash(FirstDefaultArgument) !=
ComputeODRHash(SecondDefaultArgument)) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplateParameterDifferentDefaultArgument)
<< FirstTemplate << (i + 1) << FirstDefaultArgument;
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplateParameterDifferentDefaultArgument)
<< SecondTemplate << (i + 1) << SecondDefaultArgument;
ParameterMismatch = true;
break;
}
}
if (FirstNTTPD->isParameterPack() !=
SecondNTTPD->isParameterPack()) {
ODRDiagError(FirstTemplate->getLocation(),
FirstTemplate->getSourceRange(),
FunctionTemplatePackParameter)
<< FirstTemplate << (i + 1) << FirstNTTPD->isParameterPack();
ODRDiagNote(SecondTemplate->getLocation(),
SecondTemplate->getSourceRange(),
FunctionTemplatePackParameter)
<< SecondTemplate << (i + 1)
<< SecondNTTPD->isParameterPack();
ParameterMismatch = true;
break;
}
}
}
if (ParameterMismatch) {
Diagnosed = true;
break;
}
break;
}
}
if (Diagnosed)

View File

@ -2510,6 +2510,445 @@ Invalid1 i1;
#undef DECLS
} // namespace PointersAndReferences
namespace FunctionTemplate {
#if defined(FIRST)
struct S1 {
template <int, int> void foo();
};
#elif defined(SECOND)
struct S1 {
template <int> void foo();
};
#else
S1 s1;
// expected-error@first.h:* {{'FunctionTemplate::S1::foo' from module 'FirstModule' is not present in definition of 'FunctionTemplate::S1' in module 'SecondModule'}}
// expected-note@second.h:* {{declaration of 'foo' does not match}}
#endif
#if defined(FIRST)
struct S2 {
template <char> void foo();
};
#elif defined(SECOND)
struct S2 {
template <int> void foo();
};
#else
S2 s2;
// expected-error@first.h:* {{'FunctionTemplate::S2::foo' from module 'FirstModule' is not present in definition of 'FunctionTemplate::S2' in module 'SecondModule'}}
// expected-note@second.h:* {{declaration of 'foo' does not match}}
#endif
#if defined(FIRST)
struct S3 {
template <int x> void foo();
};
#elif defined(SECOND)
struct S3 {
template <int y> void foo();
};
#else
S3 s3;
// expected-error@second.h:* {{'FunctionTemplate::S3' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter named 'y'}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter named 'x'}}
#endif
#if defined(FIRST)
struct S4 {
template <int x> void foo();
};
#elif defined(SECOND)
struct S4 {
template <int x> void bar();
};
#else
S4 s4;
// expected-error@first.h:* {{'FunctionTemplate::S4::foo' from module 'FirstModule' is not present in definition of 'FunctionTemplate::S4' in module 'SecondModule'}}
// expected-note@second.h:* {{definition has no member 'foo'}}
#endif
#if defined(FIRST)
struct S5 {
template <int x> void foo();
};
#elif defined(SECOND)
struct S5 {
public:
template <int x> void foo();
};
#else
S5 s5;
// expected-error@second.h:* {{'FunctionTemplate::S5' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
// expected-note@first.h:* {{but in 'FirstModule' found function template}}
#endif
#if defined(FIRST)
struct S6 {
template <typename x = int> void foo();
};
#elif defined(SECOND)
struct S6 {
template <typename x> void foo();
};
#else
S6 s6;
// expected-error@second.h:* {{'FunctionTemplate::S6' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with no default argument}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with default argument}}
#endif
#if defined(FIRST)
struct S7 {
template <typename x = void> void foo();
};
#elif defined(SECOND)
struct S7 {
template <typename x = int> void foo();
};
#else
S7 s7;
// expected-error@second.h:* {{'FunctionTemplate::S7' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with default argument 'int'}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with default argument 'void'}}
#endif
#if defined(FIRST)
template <int>
struct U8 {};
struct S8 {
template <template<int> class x = U8> void foo();
};
#elif defined(SECOND)
template <int>
struct T8 {};
struct S8{
template <template<int> class x = T8> void foo();
};
#else
S8 s8;
// expected-error@second.h:* {{'FunctionTemplate::S8' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with default argument 'T8'}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with default argument 'U8'}}
#endif
#if defined(FIRST)
template <int>
struct U9 {};
struct S9 { S9();
template <template<int> class x = U9> void foo();
};
#elif defined(SECOND)
struct S9 { S9();
template <template<int> class x> void foo();
};
#else
S9 s9;
// expected-error@second.h:* {{'FunctionTemplate::S9' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with no default argument}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with default argument}}
#endif
#if defined(FIRST)
struct S10 {
template <template<int> class x> void foo();
template <template<typename> class x> void foo();
};
#elif defined(SECOND)
struct S10 {
template <template<typename> class x> void foo();
template <template<int> class x> void foo();
};
#else
S10 s10;
// expected-error@second.h:* {{'FunctionTemplate::S10' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with one type}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with different type}}
#endif
#if defined(FIRST)
struct S11 {
template <template<int> class x> void foo();
};
#elif defined(SECOND)
struct S11 {
template <template<int> class> void foo();
};
#else
S11 s11;
// expected-error@second.h:* {{'FunctionTemplate::S11' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with no name}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter named 'x'}}
#endif
#if defined(FIRST)
struct S12 {
template <class> void foo();
template <class, class> void foo();
};
#elif defined(SECOND)
struct S12 {
template <class, class> void foo();
template <class> void foo();
};
#else
S12 s12;
// expected-error@second.h:* {{'FunctionTemplate::S12' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 2 template parameters}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1 template parameter}}
#endif
#if defined(FIRST)
struct S13 {
template <class = int> void foo();
};
#elif defined(SECOND)
struct S13 {
template <class = void> void foo();
};
#else
S13 s13;
// expected-error@second.h:* {{'FunctionTemplate::S13' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with default argument 'void'}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with default argument 'int'}}
#endif
#if defined(FIRST)
struct S14 {
template <class = void> void foo();
};
#elif defined(SECOND)
struct S14 {
template <class> void foo();
};
#else
S14 s14;
// expected-error@second.h:* {{'FunctionTemplate::S14' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with no default argument}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with default argument}}
#endif
#if defined(FIRST)
struct S15 {
template <class> void foo();
};
#elif defined(SECOND)
struct S15 {
template <class = void> void foo();
};
#else
S15 s15;
// expected-error@second.h:* {{'FunctionTemplate::S15' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with default argument}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with no default argument}}
#endif
#if defined(FIRST)
struct S16 {
template <short> void foo();
};
#elif defined(SECOND)
struct S16 {
template <short = 1> void foo();
};
#else
S16 s16;
// expected-error@second.h:* {{'FunctionTemplate::S16' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with default argument}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with no default argument}}
#endif
#if defined(FIRST)
struct S17 {
template <short = 2> void foo();
};
#elif defined(SECOND)
struct S17 {
template <short = 1 + 1> void foo();
};
#else
S17 s17;
// expected-error@second.h:* {{'FunctionTemplate::S17' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with default argument 1 + 1}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with default argument 2}}
#endif
#if defined(FIRST)
struct S18 {
template <short> void foo();
template <int> void foo();
};
#elif defined(SECOND)
struct S18 {
template <int> void foo();
template <short> void foo();
};
#else
S18 s18;
// expected-error@second.h:* {{'FunctionTemplate::S18' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter with one type}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter with different type}}
#endif
#if defined(FIRST)
struct S19 {
template <short> void foo();
template <short...> void foo();
};
#elif defined(SECOND)
struct S19 {
template <short...> void foo();
template <short> void foo();
};
#else
S19 s19;
// expected-error@second.h:* {{'FunctionTemplate::S19' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter being a template parameter pack}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter not being a template parameter pack}}
#endif
#if defined(FIRST)
struct S20 {
template <class> void foo();
template <class...> void foo();
};
#elif defined(SECOND)
struct S20 {
template <class...> void foo();
template <class> void foo();
};
#else
S20 s20;
// expected-error@second.h:* {{'FunctionTemplate::S20' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter being a template parameter pack}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter not being a template parameter pack}}
#endif
#if defined(FIRST)
struct S21 {
template <template<class> class...> void foo();
template <template<class> class> void foo();
};
#elif defined(SECOND)
struct S21 {
template <template<class> class> void foo();
template <template<class> class...> void foo();
};
#else
S21 s21;
// expected-error@second.h:* {{'FunctionTemplate::S21' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter not being a template parameter pack}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template parameter being a template parameter pack}}
#endif
#if defined(FIRST)
struct S22 {
template <template<class> class> void foo();
template <class> void foo();
template <int> void foo();
};
#elif defined(SECOND)
struct S22 {
template <class> void foo();
template <int> void foo();
template <template<class> class> void foo();
};
#else
S22 s22;
// expected-error@second.h:* {{'FunctionTemplate::S22' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter being a type template parameter}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template paramter being a template template parameter}}
#endif
#if defined(FIRST)
struct S23 {
template <class> void foo();
template <int> void foo();
template <template<class> class> void foo();
};
#elif defined(SECOND)
struct S23 {
template <int> void foo();
template <template<class> class> void foo();
template <class> void foo();
};
#else
S23 s23;
// expected-error@second.h:* {{'FunctionTemplate::S23' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter being a non-type template parameter}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template paramter being a type template parameter}}
#endif
#if defined(FIRST)
struct S24 {
template <int> void foo();
template <template<class> class> void foo();
template <class> void foo();
};
#elif defined(SECOND)
struct S24 {
template <template<class> class> void foo();
template <class> void foo();
template <int> void foo();
};
#else
S24 s24;
// expected-error@second.h:* {{'FunctionTemplate::S24' has different definitions in different modules; first difference is definition in module 'SecondModule' found function template 'foo' with 1st template parameter being a template template parameter}}
// expected-note@first.h:* {{but in 'FirstModule' found function template 'foo' with 1st template paramter being a non-type template parameter}}
#endif
#if defined(FIRST)
struct S25 {
template <int> void foo();
};
#elif defined(SECOND)
struct S25 {
public:
template <int> void foo();
};
#else
S25 s25;
// expected-error@second.h:* {{'FunctionTemplate::S25' has different definitions in different modules; first difference is definition in module 'SecondModule' found public access specifier}}
// expected-note@first.h:* {{but in 'FirstModule' found function template}}
#endif
#define DECLS \
template <int> \
void nontype1(); \
template <int x> \
void nontype2(); \
template <int, int> \
void nontype3(); \
template <int x = 5> \
void nontype4(); \
template <int... x> \
void nontype5(); \
\
template <class> \
void type1(); \
template <class x> \
void type2(); \
template <class, class> \
void type3(); \
template <class x = int> \
void type4(); \
template <class... x> \
void type5(); \
\
template <template <int> class> \
void template1(); \
template <template <int> class x> \
void template2(); \
template <template <int> class, template <int> class> \
void template3(); \
template <template <int> class x = U> \
void template4(); \
template <template <int> class... x> \
void template5();
#if defined(FIRST) || defined(SECOND)
template<int>
struct U {};
struct Valid1 {
DECLS
};
#else
Valid1 v1;
#endif
#if defined(FIRST) || defined(SECOND)
struct Invalid1 {
DECLS
ACCESS
};
#else
Invalid1 i1;
// expected-error@second.h:* {{'FunctionTemplate::Invalid1' has different definitions in different modules; first difference is definition in module 'SecondModule' found private access specifier}}
// expected-note@first.h:* {{but in 'FirstModule' found public access specifier}}
#endif
#undef DECLS
}
// Collection of interesting cases below.