[cfe-commits] r122452 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
Douglas Gregor
dgregor at apple.com
Wed Dec 22 15:09:49 PST 2010
Author: dgregor
Date: Wed Dec 22 17:09:49 2010
New Revision: 122452
URL: http://llvm.org/viewvc/llvm-project?rev=122452&view=rev
Log:
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.
Added:
cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp (with props)
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=122452&r1=122451&r2=122452&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed Dec 22 17:09:49 2010
@@ -1868,8 +1868,6 @@
"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">;
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=122452&r1=122451&r2=122452&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Dec 22 17:09:49 2010
@@ -106,6 +106,130 @@
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 @@
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);
- return Sema::TDK_Inconsistent;
+ 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 @@
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 @@
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 @@
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,24 +555,19 @@
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;
}
- return Sema::TDK_Success;
+
+ Deduced[Index] = Result;
+ return Sema::TDK_Success;
}
// Set up the template argument deduction information for a failure.
@@ -966,6 +1047,17 @@
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 @@
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());
+ 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 @@
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
Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp?rev=122452&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp Wed Dec 22 17:09:49 2010
@@ -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];
+
Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.type/p2-0x.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the cfe-commits
mailing list