aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-06-12 18:26:56 +0000
committerDouglas Gregor <dgregor@apple.com>2009-06-12 18:26:56 +0000
commitf67875d5addf36b951ad37fb04509ab2b572c88a (patch)
treeaf1174dcef4ef448dadcb8123c45c214c7701506 /lib
parent5e300d1a8e37f24e71f8cf204b982f20f85cf91a (diff)
Improve template argument deduction to keep track of why template
argument deduction failed. For example, given template<typename T> struct is_same<T, T> { ... }; template argument deduction will fail for is_same<int, float>, and now reports enough information Right now, we don't do anything with this extra information, but it can be used for informative diagnostics that say, e.g., "template argument deduction failed because T was deduced to 'int' in one context and 'float' in another". git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73237 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/Sema/Sema.h113
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp535
-rw-r--r--lib/Sema/SemaTemplateInstantiate.cpp13
3 files changed, 467 insertions, 194 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index c4b3b2d050..7e3ed36585 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2040,9 +2040,118 @@ public:
const IdentifierInfo &II,
SourceRange Range);
- TemplateArgumentList *
+ /// \brief Describes the result of template argument deduction.
+ ///
+ /// The TemplateDeductionResult enumeration describes the result of
+ /// template argument deduction, as returned from
+ /// DeduceTemplateArguments(). The separate TemplateDeductionInfo
+ /// structure provides additional information about the results of
+ /// template argument deduction, e.g., the deduced template argument
+ /// list (if successful) or the specific template parameters or
+ /// deduced arguments that were involved in the failure.
+ enum TemplateDeductionResult {
+ /// \brief Template argument deduction was successful.
+ TDK_Success = 0,
+ /// \brief Template argument deduction exceeded the maximum template
+ /// instantiation depth (which has already been diagnosed).
+ TDK_InstantiationDepth,
+ /// \brief Template argument deduction did not deduce a value
+ /// for every template parameter.
+ TDK_Incomplete,
+ /// \brief Template argument deduction produced inconsistent
+ /// deduced values for the given template parameter.
+ TDK_Inconsistent,
+ /// \brief Template argument deduction failed due to inconsistent
+ /// cv-qualifiers on a template parameter type that would
+ /// otherwise be deduced, e.g., we tried to deduce T in "const T"
+ /// but were given a non-const "X".
+ TDK_InconsistentQuals,
+ /// \brief Substitution of the deduced template argument values
+ /// resulted in an error.
+ TDK_SubstitutionFailure,
+ /// \brief Substitution of the deduced template argument values
+ /// into a non-deduced context produced a type or value that
+ /// produces a type that does not match the original template
+ /// arguments provided.
+ TDK_NonDeducedMismatch
+ };
+
+ /// \brief Provides information about an attempted template argument
+ /// deduction, whose success or failure was described by a
+ /// TemplateDeductionResult value.
+ class TemplateDeductionInfo {
+ /// \brief The context in which the template arguments are stored.
+ ASTContext &Context;
+
+ /// \brief The deduced template argument list.
+ ///
+ TemplateArgumentList *Deduced;
+
+ // do not implement these
+ TemplateDeductionInfo(const TemplateDeductionInfo&);
+ TemplateDeductionInfo &operator=(const TemplateDeductionInfo&);
+
+ public:
+ TemplateDeductionInfo(ASTContext &Context) : Context(Context), Deduced(0) { }
+
+ ~TemplateDeductionInfo() {
+ // FIXME: if (Deduced) Deduced->Destroy(Context);
+ }
+
+ /// \brief Take ownership of the deduced template argument list.
+ TemplateArgumentList *take() {
+ TemplateArgumentList *Result = Deduced;
+ Deduced = 0;
+ return Result;
+ }
+
+ /// \brief Provide a new template argument list that contains the
+ /// results of template argument deduction.
+ void reset(TemplateArgumentList *NewDeduced) {
+ // FIXME: if (Deduced) Deduced->Destroy(Context);
+ Deduced = NewDeduced;
+ }
+
+ /// \brief The template parameter to which a template argument
+ /// deduction failure refers.
+ ///
+ /// Depending on the result of template argument deduction, this
+ /// template parameter may have different meanings:
+ ///
+ /// TDK_Incomplete: this is the first template parameter whose
+ /// corresponding template argument was not deduced.
+ ///
+ /// TDK_Inconsistent: this is the template parameter for which
+ /// two different template argument values were deduced.
+ TemplateParameter Param;
+
+ /// \brief The first template argument to which the template
+ /// argument deduction failure refers.
+ ///
+ /// Depending on the result of the template argument deduction,
+ /// this template argument may have different meanings:
+ ///
+ /// TDK_Inconsistent: this argument is the first value deduced
+ /// for the corresponding template parameter.
+ ///
+ /// TDK_SubstitutionFailure: this argument is the template
+ /// argument we were instantiating when we encountered an error.
+ ///
+ /// TDK_NonDeducedMismatch: this is the template argument
+ /// provided in the source code.
+ TemplateArgument FirstArg;
+
+ /// \brief The second template argument to which the template
+ /// argument deduction failure refers.
+ ///
+ /// FIXME: Finish documenting this.
+ TemplateArgument SecondArg;
+ };
+
+ TemplateDeductionResult
DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
- const TemplateArgumentList &TemplateArgs);
+ const TemplateArgumentList &TemplateArgs,
+ TemplateDeductionInfo &Info);
//===--------------------------------------------------------------------===//
// C++ Template Instantiation
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index 0bef27c726..252f2d1d0d 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -20,9 +20,12 @@
#include "llvm/Support/Compiler.h"
using namespace clang;
-static bool
-DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ const TemplateArgument &Param,
const TemplateArgument &Arg,
+ Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced);
/// \brief If the given expression is of a form that permits the deduction
@@ -40,12 +43,12 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) {
/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
-///
-/// \returns true if deduction succeeded, false otherwise.
-static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
- NonTypeTemplateParmDecl *NTTP,
- llvm::APInt Value,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceNonTypeTemplateArgument(ASTContext &Context,
+ NonTypeTemplateParmDecl *NTTP,
+ llvm::APInt Value,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
@@ -53,25 +56,41 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
Deduced[NTTP->getIndex()] = TemplateArgument(SourceLocation(),
llvm::APSInt(Value),
NTTP->getType());
- return true;
+ return Sema::TDK_Success;
}
- if (Deduced[NTTP->getIndex()].getKind() != TemplateArgument::Integral)
- return false;
+ assert(Deduced[NTTP->getIndex()].getKind() == TemplateArgument::Integral);
// If the template argument was previously deduced to a negative value,
// then our deduction fails.
const llvm::APSInt *PrevValuePtr = Deduced[NTTP->getIndex()].getAsIntegral();
- assert(PrevValuePtr && "Not an integral template argument?");
- if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative())
- return false;
-
+ if (PrevValuePtr->isSigned() && PrevValuePtr->isNegative()) {
+ // FIXME: This is wacky; we should be dealing with APSInts and
+ // checking the actual signs.
+ Info.Param = NTTP;
+ Info.FirstArg = Deduced[NTTP->getIndex()];
+ Info.SecondArg = TemplateArgument(SourceLocation(),
+ llvm::APSInt(Value),
+ NTTP->getType());
+ return Sema::TDK_Inconsistent;
+ }
+
llvm::APInt PrevValue = *PrevValuePtr;
if (Value.getBitWidth() > PrevValue.getBitWidth())
PrevValue.zext(Value.getBitWidth());
else if (Value.getBitWidth() < PrevValue.getBitWidth())
Value.zext(PrevValue.getBitWidth());
- return Value == PrevValue;
+
+ if (Value != PrevValue) {
+ Info.Param = NTTP;
+ Info.FirstArg = Deduced[NTTP->getIndex()];
+ Info.SecondArg = TemplateArgument(SourceLocation(),
+ llvm::APSInt(Value),
+ NTTP->getType());
+ return Sema::TDK_Inconsistent;
+ }
+
+ return Sema::TDK_Success;
}
/// \brief Deduce the value of the given non-type template parameter
@@ -79,10 +98,12 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
///
/// \returns true if deduction succeeded, false otherwise.
-static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
- NonTypeTemplateParmDecl *NTTP,
- Expr *Value,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceNonTypeTemplateArgument(ASTContext &Context,
+ NonTypeTemplateParmDecl *NTTP,
+ Expr *Value,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
assert((Value->isTypeDependent() || Value->isValueDependent()) &&
@@ -91,53 +112,73 @@ static bool DeduceNonTypeTemplateArgument(ASTContext &Context,
if (Deduced[NTTP->getIndex()].isNull()) {
// FIXME: Clone the Value?
Deduced[NTTP->getIndex()] = TemplateArgument(Value);
- return true;
+ 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 true;
+ return Sema::TDK_Success;
}
// FIXME: Compare the expressions for equality!
- return true;
+ return Sema::TDK_Success;
}
-static bool DeduceTemplateArguments(ASTContext &Context,
- TemplateName Param,
- TemplateName Arg,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateName Param,
+ TemplateName Arg,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
// FIXME: Implement template argument deduction for template
// template parameters.
+ // FIXME: this routine does not have enough information to produce
+ // good diagnostics.
+
TemplateDecl *ParamDecl = Param.getAsTemplateDecl();
TemplateDecl *ArgDecl = Arg.getAsTemplateDecl();
- if (!ParamDecl || !ArgDecl)
- return false;
+ if (!ParamDecl || !ArgDecl) {
+ // FIXME: fill in Info.Param/Info.FirstArg
+ return Sema::TDK_Inconsistent;
+ }
ParamDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ParamDecl));
ArgDecl = cast<TemplateDecl>(Context.getCanonicalDecl(ArgDecl));
- return ParamDecl == ArgDecl;
+ if (ParamDecl != ArgDecl) {
+ // FIXME: fill in Info.Param/Info.FirstArg
+ return Sema::TDK_Inconsistent;
+ }
+
+ return Sema::TDK_Success;
}
-static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
- QualType Arg,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ QualType ParamIn, QualType ArgIn,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
// We only want to look at the canonical types, since typedefs and
// sugar are not part of template argument deduction.
- Param = Context.getCanonicalType(Param);
- Arg = Context.getCanonicalType(Arg);
+ QualType Param = Context.getCanonicalType(ParamIn);
+ QualType Arg = Context.getCanonicalType(ArgIn);
// If the parameter type is not dependent, just compare the types
// directly.
- if (!Param->isDependentType())
- return Param == Arg;
+ if (!Param->isDependentType()) {
+ if (Param == Arg)
+ return Sema::TDK_Success;
+
+ Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
+ Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
+ return Sema::TDK_NonDeducedMismatch;
+ }
// C++ [temp.deduct.type]p9:
- //
// A template type argument T, a template template argument TT or a
// template non-type argument i can be deduced if P and A have one of
// the following forms:
@@ -146,16 +187,21 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
// cv-list T
if (const TemplateTypeParmType *TemplateTypeParm
= Param->getAsTemplateTypeParmType()) {
+ unsigned Index = TemplateTypeParm->getIndex();
+
// The argument type can not be less qualified than the parameter
// type.
- if (Param.isMoreQualifiedThan(Arg))
- return false;
+ if (Param.isMoreQualifiedThan(Arg)) {
+ Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
+ Info.FirstArg = Deduced[Index];
+ Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
+ return Sema::TDK_InconsistentQuals;
+ }
assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
QualType DeducedType = Arg.getQualifiedType(Quals);
- unsigned Index = TemplateTypeParm->getIndex();
if (Deduced[Index].isNull())
Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
@@ -166,55 +212,63 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
// 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)
- return false;
+ if (Deduced[Index].getAsType() != DeducedType) {
+ Info.Param
+ = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index));
+ Info.FirstArg = Deduced[Index];
+ Info.SecondArg = TemplateArgument(SourceLocation(), Arg);
+ return Sema::TDK_Inconsistent;
+ }
}
- return true;
+ return Sema::TDK_Success;
}
+ // Set up the template argument deduction information for a failure.
+ Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn);
+ Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn);
+
if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
switch (Param->getTypeClass()) {
// No deduction possible for these types
case Type::Builtin:
- return false;
-
+ return Sema::TDK_NonDeducedMismatch;
// T *
case Type::Pointer: {
const PointerType *PointerArg = Arg->getAsPointerType();
if (!PointerArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
cast<PointerType>(Param)->getPointeeType(),
PointerArg->getPointeeType(),
- Deduced);
+ Info, Deduced);
}
// T &
case Type::LValueReference: {
const LValueReferenceType *ReferenceArg = Arg->getAsLValueReferenceType();
if (!ReferenceArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
cast<LValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
- Deduced);
+ Info, Deduced);
}
// T && [C++0x]
case Type::RValueReference: {
const RValueReferenceType *ReferenceArg = Arg->getAsRValueReferenceType();
if (!ReferenceArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
cast<RValueReferenceType>(Param)->getPointeeType(),
ReferenceArg->getPointeeType(),
- Deduced);
+ Info, Deduced);
}
// T [] (implied, but not stated explicitly)
@@ -222,12 +276,12 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
const IncompleteArrayType *IncompleteArrayArg =
Context.getAsIncompleteArrayType(Arg);
if (!IncompleteArrayArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
Context.getAsIncompleteArrayType(Param)->getElementType(),
IncompleteArrayArg->getElementType(),
- Deduced);
+ Info, Deduced);
}
// T [integer-constant]
@@ -235,39 +289,40 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
const ConstantArrayType *ConstantArrayArg =
Context.getAsConstantArrayType(Arg);
if (!ConstantArrayArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
const ConstantArrayType *ConstantArrayParm =
Context.getAsConstantArrayType(Param);
if (ConstantArrayArg->getSize() != ConstantArrayParm->getSize())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
ConstantArrayParm->getElementType(),
ConstantArrayArg->getElementType(),
- Deduced);
+ Info, Deduced);
}
// type [i]
case Type::DependentSizedArray: {
const ArrayType *ArrayArg = dyn_cast<ArrayType>(Arg);
if (!ArrayArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
// Check the element type of the arrays
const DependentSizedArrayType *DependentArrayParm
= cast<DependentSizedArrayType>(Param);
- if (!DeduceTemplateArguments(Context,
- DependentArrayParm->getElementType(),
- ArrayArg->getElementType(),
- Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ DependentArrayParm->getElementType(),
+ ArrayArg->getElementType(),
+ Info, Deduced))
+ return Result;
// Determine the array bound is something we can deduce.
NonTypeTemplateParmDecl *NTTP
= getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr());
if (!NTTP)
- return true;
+ return Sema::TDK_Success;
// We can perform template argument deduction for the given non-type
// template parameter.
@@ -277,15 +332,15 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
= dyn_cast<ConstantArrayType>(ArrayArg))
return DeduceNonTypeTemplateArgument(Context, NTTP,
ConstantArrayArg->getSize(),
- Deduced);
+ Info, Deduced);
if (const DependentSizedArrayType *DependentArrayArg
= dyn_cast<DependentSizedArrayType>(ArrayArg))
return DeduceNonTypeTemplateArgument(Context, NTTP,
DependentArrayArg->getSizeExpr(),
- Deduced);
+ Info, Deduced);
// Incomplete type does not match a dependently-sized array type
- return false;
+ return Sema::TDK_NonDeducedMismatch;
}
// type(*)(T)
@@ -295,38 +350,40 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
const FunctionProtoType *FunctionProtoArg =
dyn_cast<FunctionProtoType>(Arg);
if (!FunctionProtoArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
const FunctionProtoType *FunctionProtoParam =
cast<FunctionProtoType>(Param);
if (FunctionProtoParam->getTypeQuals() !=
FunctionProtoArg->getTypeQuals())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
if (FunctionProtoParam->getNumArgs() != FunctionProtoArg->getNumArgs())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
if (FunctionProtoParam->isVariadic() != FunctionProtoArg->isVariadic())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
// Check return types.
- if (!DeduceTemplateArguments(Context,
- FunctionProtoParam->getResultType(),
- FunctionProtoArg->getResultType(),
- Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ FunctionProtoParam->getResultType(),
+ FunctionProtoArg->getResultType(),
+ Info, Deduced))
+ return Result;
for (unsigned I = 0, N = FunctionProtoParam->getNumArgs(); I != N; ++I) {
// Check argument types.
- if (!DeduceTemplateArguments(Context,
- FunctionProtoParam->getArgType(I),
- FunctionProtoArg->getArgType(I),
- Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ FunctionProtoParam->getArgType(I),
+ FunctionProtoArg->getArgType(I),
+ Info, Deduced))
+ return Result;
}
- return true;
+ return Sema::TDK_Success;
}
// template-name<T> (wheretemplate-name refers to a class template)
@@ -344,11 +401,12 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
if (const TemplateSpecializationType *SpecArg
= dyn_cast<TemplateSpecializationType>(Arg)) {
// Perform template argument deduction for the template name.
- if (!DeduceTemplateArguments(Context,
- SpecParam->getTemplateName(),
- SpecArg->getTemplateName(),
- Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context,
+ SpecParam->getTemplateName(),
+ SpecArg->getTemplateName(),
+ Info, Deduced))
+ return Result;
unsigned NumArgs = SpecParam->getNumArgs();
@@ -359,18 +417,19 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
// issue may be resolved elsewhere, because we may want to
// instantiate default template arguments when
if (SpecArg->getNumArgs() != NumArgs)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
// Perform template argument deduction on each template
// argument.
for (unsigned I = 0; I != NumArgs; ++I)
- if (!DeduceTemplateArguments(Context,
- SpecParam->getArg(I),
- SpecArg->getArg(I),
- Deduced))
- return false;
-
- return true;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ SpecParam->getArg(I),
+ SpecArg->getArg(I),
+ Info, Deduced))
+ return Result;
+
+ return Sema::TDK_Success;
}
// If the argument type is a class template specialization, we
@@ -378,34 +437,36 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
// arguments.
const RecordType *RecordArg = dyn_cast<RecordType>(Arg);
if (!RecordArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
ClassTemplateSpecializationDecl *SpecArg
= dyn_cast<ClassTemplateSpecializationDecl>(RecordArg->getDecl());
if (!SpecArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
// Perform template argument deduction for the template name.
- if (!DeduceTemplateArguments(Context,
- SpecParam->getTemplateName(),
- TemplateName(SpecArg->getSpecializedTemplate()),
- Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context,
+ SpecParam->getTemplateName(),
+ TemplateName(SpecArg->getSpecializedTemplate()),
+ Info, Deduced))
+ return Result;
// FIXME: Can the # of arguments in the parameter and the argument differ?
unsigned NumArgs = SpecParam->getNumArgs();
const TemplateArgumentList &ArgArgs = SpecArg->getTemplateArgs();
if (NumArgs != ArgArgs.size())
- return false;
+ return Sema::TDK_NonDeducedMismatch;
for (unsigned I = 0; I != NumArgs; ++I)
- if (!DeduceTemplateArguments(Context,
- SpecParam->getArg(I),
- ArgArgs.get(I),
- Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ SpecParam->getArg(I),
+ ArgArgs.get(I),
+ Info, Deduced))
+ return Result;
- return true;
+ return Sema::TDK_Success;
}
// T type::*
@@ -421,16 +482,19 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
const MemberPointerType *MemPtrParam = cast<MemberPointerType>(Param);
const MemberPointerType *MemPtrArg = dyn_cast<MemberPointerType>(Arg);
if (!MemPtrArg)
- return false;
-
- return DeduceTemplateArguments(Context,
- MemPtrParam->getPointeeType(),
- MemPtrArg->getPointeeType(),
- Deduced) &&
- DeduceTemplateArguments(Context,
- QualType(MemPtrParam->getClass(), 0),
- QualType(MemPtrArg->getClass(), 0),
- Deduced);
+ return Sema::TDK_NonDeducedMismatch;
+
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ MemPtrParam->getPointeeType(),
+ MemPtrArg->getPointeeType(),
+ Info, Deduced))
+ return Result;
+
+ return DeduceTemplateArguments(Context, TemplateParams,
+ QualType(MemPtrParam->getClass(), 0),
+ QualType(MemPtrArg->getClass(), 0),
+ Info, Deduced);
}
// type(^)(T)
@@ -441,30 +505,34 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
const BlockPointerType *BlockPtrArg = dyn_cast<BlockPointerType>(Arg);
if (!BlockPtrArg)
- return false;
+ return Sema::TDK_NonDeducedMismatch;
- return DeduceTemplateArguments(Context,
+ return DeduceTemplateArguments(Context, TemplateParams,
BlockPtrParam->getPointeeType(),
- BlockPtrArg->getPointeeType(), Deduced);
+ BlockPtrArg->getPointeeType(), Info,
+ Deduced);
}
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Typename:
// No template argument deduction for these types
- return true;
+ return Sema::TDK_Success;
default:
break;
}
// FIXME: Many more cases to go (to go).
- return false;
+ return Sema::TDK_NonDeducedMismatch;
}
-static bool
-DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
+static Sema::TemplateDeductionResult
+DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ const TemplateArgument &Param,
const TemplateArgument &Arg,
+ Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
switch (Param.getKind()) {
case TemplateArgument::Null:
@@ -473,24 +541,38 @@ DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
case TemplateArgument::Type:
assert(Arg.getKind() == TemplateArgument::Type && "Type/value mismatch");
- return DeduceTemplateArguments(Context, Param.getAsType(),
- Arg.getAsType(), Deduced);
+ return DeduceTemplateArguments(Context, TemplateParams,
+ Param.getAsType(),
+ Arg.getAsType(), Info, Deduced);
case TemplateArgument::Declaration:
// FIXME: Implement this check
assert(false && "Unimplemented template argument deduction case");
- return false;
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Integral:
if (Arg.getKind() == TemplateArgument::Integral) {
// FIXME: Zero extension + sign checking here?
- return *Param.getAsIntegral() == *Arg.getAsIntegral();
+ if (*Param.getAsIntegral() == *Arg.getAsIntegral())
+ return Sema::TDK_Success;
+
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
+ }
+
+ if (Arg.getKind() == TemplateArgument::Expression) {
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
}
- if (Arg.getKind() == TemplateArgument::Expression)
- return false;
assert(false && "Type/value mismatch");
- return false;
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
case TemplateArgument::Expression: {
if (NonTypeTemplateParmDecl *NTTP
@@ -498,62 +580,81 @@ DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
if (Arg.getKind() == TemplateArgument::Integral)
// FIXME: Sign problems here
return DeduceNonTypeTemplateArgument(Context, NTTP,
- *Arg.getAsIntegral(), Deduced);
+ *Arg.getAsIntegral(),
+ Info, Deduced);
if (Arg.getKind() == TemplateArgument::Expression)
return DeduceNonTypeTemplateArgument(Context, NTTP, Arg.getAsExpr(),
- Deduced);
+ Info, Deduced);
assert(false && "Type/value mismatch");
- return false;
+ Info.FirstArg = Param;
+ Info.SecondArg = Arg;
+ return Sema::TDK_NonDeducedMismatch;
}
// Can't deduce anything, but that's okay.
- return true;
+ return Sema::TDK_Success;
}
}
- return true;
+ return Sema::TDK_Success;
}
-static bool
+static Sema::TemplateDeductionResult
DeduceTemplateArguments(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
+ Sema::TemplateDeductionInfo &Info,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(ParamList.size() == ArgList.size());
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
- if (!DeduceTemplateArguments(Context, ParamList[I], ArgList[I], Deduced))
- return false;
+ if (Sema::TemplateDeductionResult Result
+ = DeduceTemplateArguments(Context, TemplateParams,
+ ParamList[I], ArgList[I],
+ Info, Deduced))
+ return Result;
}
- return true;
+ return Sema::TDK_Success;
}
-TemplateArgumentList *
+Sema::TemplateDeductionResult
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
- const TemplateArgumentList &TemplateArgs) {
+ const TemplateArgumentList &TemplateArgs,
+ TemplateDeductionInfo &Info) {
// Deduce the template arguments for the partial specialization
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
- if (! ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(),
- TemplateArgs, Deduced))
- return 0;
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context,
+ Partial->getTemplateParameters(),
+ Partial->getTemplateArgs(),
+ TemplateArgs, Info, Deduced))
+ return Result;
- // FIXME: It isn't clear whether we want the diagnostic to point at
- // the partial specialization itself or at the actual point of
- // instantiation.
InstantiatingTemplate Inst(*this, Partial->getLocation(), Partial,
Deduced.data(), Deduced.size());
if (Inst)
- return 0;
+ return TDK_InstantiationDepth;
// C++ [temp.deduct.type]p2:
// [...] or if any template argument remains neither deduced nor
// explicitly specified, template argument deduction fails.
TemplateArgumentListBuilder Builder(Context);
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
- if (Deduced[I].isNull())
- return 0;
+ if (Deduced[I].isNull()) {
+ Decl *Param
+ = const_cast<Decl *>(Partial->getTemplateParameters()->getParam(I));
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ Info.