Unify the consistency checking for deduced template arguments into a

single routine. Extend that routine to handle consistency
checking for template argument packs, so that we can compare the
deduced packs for template parameter packs across different pack
expansions.

llvm-svn: 122452
This commit is contained in:
Douglas Gregor 2010-12-22 23:09:49 +00:00
parent 6020ed9d99
commit 7f8e7681ad
3 changed files with 235 additions and 127 deletions

View File

@ -1868,8 +1868,6 @@ def err_pack_expansion_instantiation_unsupported : Error<
"clang cannot yet instantiate pack expansions">;
def err_pack_expansion_mismatch_unsupported : Error<
"clang cannot yet instantiate pack expansions with mismatched pack levels">;
def err_pack_expansion_deduction_compare : Error<
"clang cannot yet compare deduced template argument packs">;
def err_unexpected_typedef : Error<
"unexpected type name %0: expected expression">;

View File

@ -106,6 +106,130 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
return 0;
}
/// \brief Determine whether two declaration pointers refer to the same
/// declaration.
static bool isSameDeclaration(Decl *X, Decl *Y) {
if (!X || !Y)
return !X && !Y;
if (NamedDecl *NX = dyn_cast<NamedDecl>(X))
X = NX->getUnderlyingDecl();
if (NamedDecl *NY = dyn_cast<NamedDecl>(Y))
Y = NY->getUnderlyingDecl();
return X->getCanonicalDecl() == Y->getCanonicalDecl();
}
/// \brief Verify that the given, deduced template arguments are compatible.
///
/// \returns The deduced template argument, or a NULL template argument if
/// the deduced template arguments were incompatible.
static DeducedTemplateArgument
checkDeducedTemplateArguments(ASTContext &Context,
const DeducedTemplateArgument &X,
const DeducedTemplateArgument &Y) {
// We have no deduction for one or both of the arguments; they're compatible.
if (X.isNull())
return Y;
if (Y.isNull())
return X;
switch (X.getKind()) {
case TemplateArgument::Null:
llvm_unreachable("Non-deduced template arguments handled above");
case TemplateArgument::Type:
// If two template type arguments have the same type, they're compatible.
if (Y.getKind() == TemplateArgument::Type &&
Context.hasSameType(X.getAsType(), Y.getAsType()))
return X;
return DeducedTemplateArgument();
case TemplateArgument::Integral:
// If we deduced a constant in one case and either a dependent expression or
// declaration in another case, keep the integral constant.
// If both are integral constants with the same value, keep that value.
if (Y.getKind() == TemplateArgument::Expression ||
Y.getKind() == TemplateArgument::Declaration ||
(Y.getKind() == TemplateArgument::Integral &&
hasSameExtendedValue(*X.getAsIntegral(), *Y.getAsIntegral())))
return DeducedTemplateArgument(X,
X.wasDeducedFromArrayBound() &&
Y.wasDeducedFromArrayBound());
// All other combinations are incompatible.
return DeducedTemplateArgument();
case TemplateArgument::Template:
if (Y.getKind() == TemplateArgument::Template &&
Context.hasSameTemplateName(X.getAsTemplate(), Y.getAsTemplate()))
return X;
// All other combinations are incompatible.
return DeducedTemplateArgument();
case TemplateArgument::Expression:
// If we deduced a dependent expression in one case and either an integral
// constant or a declaration in another case, keep the integral constant
// or declaration.
if (Y.getKind() == TemplateArgument::Integral ||
Y.getKind() == TemplateArgument::Declaration)
return DeducedTemplateArgument(Y, X.wasDeducedFromArrayBound() &&
Y.wasDeducedFromArrayBound());
if (Y.getKind() == TemplateArgument::Expression) {
// Compare the expressions for equality
llvm::FoldingSetNodeID ID1, ID2;
X.getAsExpr()->Profile(ID1, Context, true);
Y.getAsExpr()->Profile(ID2, Context, true);
if (ID1 == ID2)
return X;
}
// All other combinations are incompatible.
return DeducedTemplateArgument();
case TemplateArgument::Declaration:
// If we deduced a declaration and a dependent expression, keep the
// declaration.
if (Y.getKind() == TemplateArgument::Expression)
return X;
// If we deduced a declaration and an integral constant, keep the
// integral constant.
if (Y.getKind() == TemplateArgument::Integral)
return Y;
// If we deduced two declarations, make sure they they refer to the
// same declaration.
if (Y.getKind() == TemplateArgument::Declaration &&
isSameDeclaration(X.getAsDecl(), Y.getAsDecl()))
return X;
// All other combinations are incompatible.
return DeducedTemplateArgument();
case TemplateArgument::Pack:
if (Y.getKind() != TemplateArgument::Pack ||
X.pack_size() != Y.pack_size())
return DeducedTemplateArgument();
for (TemplateArgument::pack_iterator XA = X.pack_begin(),
XAEnd = X.pack_end(),
YA = Y.pack_begin();
XA != XAEnd; ++XA, ++YA) {
// FIXME: We've lost the "deduced from array bound" bit.
if (checkDeducedTemplateArguments(Context, *XA, *YA).isNull())
return DeducedTemplateArgument();
}
return X;
}
return DeducedTemplateArgument();
}
/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
static Sema::TemplateDeductionResult
@ -118,31 +242,18 @@ DeduceNonTypeTemplateArgument(Sema &S,
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
if (Deduced[NTTP->getIndex()].isNull()) {
Deduced[NTTP->getIndex()] = DeducedTemplateArgument(Value, ValueType,
DeducedFromArrayBound);
return Sema::TDK_Success;
}
if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral) {
DeducedTemplateArgument NewDeduced(Value, ValueType, DeducedFromArrayBound);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
NewDeduced);
if (Result.isNull()) {
Info.Param = NTTP;
Info.FirstArg = Deduced[NTTP->getIndex()];
Info.SecondArg = TemplateArgument(Value, ValueType);
Info.SecondArg = NewDeduced;
return Sema::TDK_Inconsistent;
}
// Extent the smaller of the two values.
llvm::APSInt PrevValue = *Deduced[NTTP->getIndex()].getAsIntegral();
if (!hasSameExtendedValue(PrevValue, Value)) {
Info.Param = NTTP;
Info.FirstArg = Deduced[NTTP->getIndex()];
Info.SecondArg = TemplateArgument(Value, ValueType);
return Sema::TDK_Inconsistent;
}
if (!DeducedFromArrayBound)
Deduced[NTTP->getIndex()].setDeducedFromArrayBound(false);
Deduced[NTTP->getIndex()] = Result;
return Sema::TDK_Success;
}
@ -161,30 +272,19 @@ DeduceNonTypeTemplateArgument(Sema &S,
assert((Value->isTypeDependent() || Value->isValueDependent()) &&
"Expression template argument must be type- or value-dependent.");
if (Deduced[NTTP->getIndex()].isNull()) {
Deduced[NTTP->getIndex()] = TemplateArgument(Value);
return Sema::TDK_Success;
}
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral) {
// Okay, we deduced a constant in one case and a dependent expression
// in another case. FIXME: Later, we will check that instantiating the
// dependent expression gives us the constant value.
return Sema::TDK_Success;
}
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) {
// Compare the expressions for equality
llvm::FoldingSetNodeID ID1, ID2;
Deduced[NTTP->getIndex()].getAsExpr()->Profile(ID1, S.Context, true);
Value->Profile(ID2, S.Context, true);
if (ID1 == ID2)
return Sema::TDK_Success;
// FIXME: Fill in argument mismatch information
return Sema::TDK_NonDeducedMismatch;
DeducedTemplateArgument NewDeduced(Value);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
NewDeduced);
if (Result.isNull()) {
Info.Param = NTTP;
Info.FirstArg = Deduced[NTTP->getIndex()];
Info.SecondArg = NewDeduced;
return Sema::TDK_Inconsistent;
}
Deduced[NTTP->getIndex()] = Result;
return Sema::TDK_Success;
}
@ -201,27 +301,18 @@ DeduceNonTypeTemplateArgument(Sema &S,
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
if (Deduced[NTTP->getIndex()].isNull()) {
Deduced[NTTP->getIndex()] = TemplateArgument(D->getCanonicalDecl());
return Sema::TDK_Success;
}
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Expression) {
// Okay, we deduced a declaration in one case and a dependent expression
// in another case.
return Sema::TDK_Success;
}
if (Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Declaration) {
// Compare the declarations for equality
if (Deduced[NTTP->getIndex()].getAsDecl()->getCanonicalDecl() ==
D->getCanonicalDecl())
return Sema::TDK_Success;
// FIXME: Fill in argument mismatch information
return Sema::TDK_NonDeducedMismatch;
DeducedTemplateArgument NewDeduced(D? D->getCanonicalDecl() : 0);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[NTTP->getIndex()],
NewDeduced);
if (Result.isNull()) {
Info.Param = NTTP;
Info.FirstArg = Deduced[NTTP->getIndex()];
Info.SecondArg = NewDeduced;
return Sema::TDK_Inconsistent;
}
Deduced[NTTP->getIndex()] = Result;
return Sema::TDK_Success;
}
@ -241,24 +332,19 @@ DeduceTemplateArguments(Sema &S,
if (TemplateTemplateParmDecl *TempParam
= dyn_cast<TemplateTemplateParmDecl>(ParamDecl)) {
// Bind the template template parameter to the given template name.
TemplateArgument &ExistingArg = Deduced[TempParam->getIndex()];
if (ExistingArg.isNull()) {
// This is the first deduction for this template template parameter.
ExistingArg = TemplateArgument(S.Context.getCanonicalTemplateName(Arg));
return Sema::TDK_Success;
DeducedTemplateArgument NewDeduced(S.Context.getCanonicalTemplateName(Arg));
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[TempParam->getIndex()],
NewDeduced);
if (Result.isNull()) {
Info.Param = TempParam;
Info.FirstArg = Deduced[TempParam->getIndex()];
Info.SecondArg = NewDeduced;
return Sema::TDK_Inconsistent;
}
// Verify that the previous binding matches this deduction.
assert(ExistingArg.getKind() == TemplateArgument::Template);
if (S.Context.hasSameTemplateName(ExistingArg.getAsTemplate(), Arg))
return Sema::TDK_Success;
// Inconsistent deduction.
Info.Param = TempParam;
Info.FirstArg = ExistingArg;
Info.SecondArg = TemplateArgument(Arg);
return Sema::TDK_Inconsistent;
Deduced[TempParam->getIndex()] = Result;
return Sema::TDK_Success;
}
// Verify that the two template names are equivalent.
@ -469,23 +555,18 @@ DeduceTemplateArguments(Sema &S,
if (RecanonicalizeArg)
DeducedType = S.Context.getCanonicalType(DeducedType);
if (Deduced[Index].isNull())
Deduced[Index] = TemplateArgument(DeducedType);
else {
// C++ [temp.deduct.type]p2:
// [...] If type deduction cannot be done for any P/A pair, or if for
// any pair the deduction leads to more than one possible set of
// deduced values, or if different pairs yield different deduced
// values, or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
if (Deduced[Index].getAsType() != DeducedType) {
Info.Param
= cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = Deduced[Index];
Info.SecondArg = TemplateArgument(Arg);
return Sema::TDK_Inconsistent;
}
DeducedTemplateArgument NewDeduced(DeducedType);
DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context,
Deduced[Index],
NewDeduced);
if (Result.isNull()) {
Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
Info.FirstArg = Deduced[Index];
Info.SecondArg = NewDeduced;
return Sema::TDK_Inconsistent;
}
Deduced[Index] = Result;
return Sema::TDK_Success;
}
@ -966,6 +1047,17 @@ getDepthAndIndex(UnexpandedParameterPack UPP) {
return std::make_pair(TTP->getDepth(), TTP->getIndex());
}
/// \brief Helper function to build a TemplateParameter when we don't
/// know its type statically.
static TemplateParameter makeTemplateParameter(Decl *D) {
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D))
return TemplateParameter(TTP);
else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
return TemplateParameter(NTTP);
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
static Sema::TemplateDeductionResult
DeduceTemplateArguments(Sema &S,
TemplateParameterList *TemplateParams,
@ -1090,27 +1182,33 @@ DeduceTemplateArguments(Sema &S,
continue;
}
if (!SavedPacks[I].isNull()) {
// FIXME: Check against the existing argument pack.
S.Diag(Info.getLocation(), diag::err_pack_expansion_deduction_compare);
return Sema::TDK_TooFewArguments;
}
DeducedTemplateArgument NewPack;
if (NewlyDeducedPacks[I].empty()) {
// If we deduced an empty argument pack, create it now.
Deduced[PackIndices[I]]
= DeducedTemplateArgument(TemplateArgument(0, 0));
continue;
}
TemplateArgument *ArgumentPack
= new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()];
std::copy(NewlyDeducedPacks[I].begin(), NewlyDeducedPacks[I].end(),
ArgumentPack);
Deduced[PackIndices[I]]
= DeducedTemplateArgument(TemplateArgument(ArgumentPack,
NewPack = DeducedTemplateArgument(TemplateArgument(0, 0));
} else {
TemplateArgument *ArgumentPack
= new (S.Context) TemplateArgument [NewlyDeducedPacks[I].size()];
std::copy(NewlyDeducedPacks[I].begin(), NewlyDeducedPacks[I].end(),
ArgumentPack);
NewPack
= DeducedTemplateArgument(TemplateArgument(ArgumentPack,
NewlyDeducedPacks[I].size()),
NewlyDeducedPacks[I][0].wasDeducedFromArrayBound());
}
DeducedTemplateArgument Result
= checkDeducedTemplateArguments(S.Context, SavedPacks[I], NewPack);
if (Result.isNull()) {
Info.Param
= makeTemplateParameter(TemplateParams->getParam(PackIndices[I]));
Info.FirstArg = SavedPacks[I];
Info.SecondArg = NewPack;
return Sema::TDK_Inconsistent;
}
Deduced[PackIndices[I]] = Result;
}
}
@ -1188,17 +1286,6 @@ static bool isSameTemplateArg(ASTContext &Context,
return false;
}
/// \brief Helper function to build a TemplateParameter when we don't
/// know its type statically.
static TemplateParameter makeTemplateParameter(Decl *D) {
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D))
return TemplateParameter(TTP);
else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D))
return TemplateParameter(NTTP);
return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
}
/// Complete template argument deduction for a class template partial
/// specialization.
static Sema::TemplateDeductionResult

View File

@ -0,0 +1,23 @@
// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s
// If type deduction cannot be done for any P/A pair, or if for any
// pair the deduction leads to more than one possible set of deduced
// values, or if different pairs yield different deduced values, or if
// any template argument remains neither deduced nor explicitly
// specified, template argument deduction fails.
template<typename ...> struct tuple;
template<typename T, typename U>
struct same_tuple {
static const bool value = false;
};
template<typename ...Types1>
struct same_tuple<tuple<Types1...>, tuple<Types1...> > {
static const bool value = true;
};
//int same_tuple_check1[same_tuple<tuple<int, float>, tuple<int, double>>::value? -1 : 1];
int same_tuple_check2[same_tuple<tuple<float, double>, tuple<float, double>>::value? 1 : -1];