When performing template argument deduction, ensure that multiple

deductions of the same template parameter are equivalent. This allows
us to implement the is_same type trait (!).

Also, move template argument deduction into its own file and update a
few build systems with this change (grrrr).

llvm-svn: 72819
This commit is contained in:
Douglas Gregor 2009-06-04 00:03:07 +00:00
parent 2797e7a483
commit 55ca8f6443
7 changed files with 170 additions and 99 deletions

View File

@ -390,20 +390,21 @@ class TemplateArgument {
public:
/// \brief The type of template argument we're storing.
enum ArgKind {
Null = 0,
/// The template argument is a type. It's value is stored in the
/// TypeOrValue field.
Type = 0,
Type = 1,
/// The template argument is a declaration
Declaration = 1,
Declaration = 2,
/// The template argument is an integral value stored in an llvm::APSInt.
Integral = 2,
Integral = 3,
/// The template argument is a value- or type-dependent expression
/// stored in an Expr*.
Expression = 3
Expression = 4
} Kind;
/// \brief Construct an empty, invalid template argument.
TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { }
TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { }
/// \brief Construct a template type argument.
TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
@ -484,6 +485,9 @@ public:
/// \brief Return the kind of stored template argument.
ArgKind getKind() const { return Kind; }
/// \brief Determine whether this template argument has no value.
bool isNull() const { return Kind == Null; }
/// \brief Retrieve the template argument as a type.
QualType getAsType() const {
if (Kind != Type)
@ -534,6 +538,9 @@ public:
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Kind);
switch (Kind) {
case Null:
break;
case Type:
getAsType().Profile(ID);
break;

View File

@ -23,6 +23,7 @@ add_clang_library(clangSema
SemaOverload.cpp
SemaStmt.cpp
SemaTemplate.cpp
SemaTemplateDeduction.cpp
SemaTemplateInstantiate.cpp
SemaTemplateInstantiateDecl.cpp
SemaTemplateInstantiateExpr.cpp

View File

@ -2019,14 +2019,6 @@ public:
const IdentifierInfo &II,
SourceRange Range);
bool DeduceTemplateArguments(QualType Param, QualType Arg,
llvm::SmallVectorImpl<TemplateArgument> &Deduced);
bool DeduceTemplateArguments(const TemplateArgument &Param,
const TemplateArgument &Arg,
llvm::SmallVectorImpl<TemplateArgument> &Deduced);
bool DeduceTemplateArguments(const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
llvm::SmallVectorImpl<TemplateArgument> &Deduced);
bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs);

View File

@ -750,6 +750,10 @@ static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs,
Canonical.reserve(NumTemplateArgs);
for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) {
switch (TemplateArgs[Idx].getKind()) {
case TemplateArgument::Null:
assert(false && "Should never see a NULL template argument here");
break;
case TemplateArgument::Expression:
// FIXME: Build canonical expression (!)
Canonical.push_back(TemplateArgs[Idx]);
@ -765,11 +769,13 @@ static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs,
Canonical.push_back(TemplateArgument(SourceLocation(),
*TemplateArgs[Idx].getAsIntegral(),
TemplateArgs[Idx].getIntegralType()));
break;
case TemplateArgument::Type: {
QualType CanonType
= Context.getCanonicalType(TemplateArgs[Idx].getAsType());
Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
break;
}
}
}
@ -1092,6 +1098,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
}
switch (Arg.getKind()) {
case TemplateArgument::Null:
assert(false && "Should never see a NULL template argument here");
break;
case TemplateArgument::Expression: {
Expr *E = Arg.getAsExpr();
if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted))
@ -1131,6 +1141,10 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template,
= cast<TemplateTemplateParmDecl>(*Param);
switch (Arg.getKind()) {
case TemplateArgument::Null:
assert(false && "Should never see a NULL template argument here");
break;
case TemplateArgument::Expression: {
Expr *ArgExpr = Arg.getAsExpr();
if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
@ -2563,89 +2577,3 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
<< Name;
return QualType();
}
// FIXME: Move to SemaTemplateDeduction.cpp
bool
Sema::DeduceTemplateArguments(QualType Param, QualType Arg,
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);
// If the parameter type is not dependent, just compare the types
// directly.
if (!Param->isDependentType())
return Param == Arg;
// FIXME: Use a visitor or switch to handle all of the kinds of
// types that the parameter may be.
if (const TemplateTypeParmType *TemplateTypeParm
= Param->getAsTemplateTypeParmType()) {
(void)TemplateTypeParm; // FIXME: use this
// The argument type can not be less qualified than the parameter
// type.
if (Param.isMoreQualifiedThan(Arg))
return false;
unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
QualType DeducedType = Arg.getQualifiedType(Quals);
// FIXME: actually save the deduced type, and check that this
// deduction is consistent.
return true;
}
if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
return false;
if (const PointerType *PointerParam = Param->getAsPointerType()) {
const PointerType *PointerArg = Arg->getAsPointerType();
if (!PointerArg)
return false;
return DeduceTemplateArguments(PointerParam->getPointeeType(),
PointerArg->getPointeeType(),
Deduced);
}
// FIXME: Many more cases to go (to go).
return false;
}
bool
Sema::DeduceTemplateArguments(const TemplateArgument &Param,
const TemplateArgument &Arg,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(Param.getKind() == Arg.getKind() &&
"Template argument kind mismatch during deduction");
switch (Param.getKind()) {
case TemplateArgument::Type:
return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(),
Deduced);
default:
return false;
}
}
bool
Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(ParamList.size() == ArgList.size());
for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced))
return false;
}
return true;
}
bool
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs) {
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs,
Deduced);
}

View File

@ -0,0 +1,121 @@
//===------- SemaTemplateDeduction.cpp - Template Argument Deduction ------===/
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//===----------------------------------------------------------------------===/
//
// This file implements C++ template argument deduction.
//
//===----------------------------------------------------------------------===/
#include "Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
using namespace clang;
static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
QualType Arg,
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);
// If the parameter type is not dependent, just compare the types
// directly.
if (!Param->isDependentType())
return Param == Arg;
// FIXME: Use a visitor or switch to handle all of the kinds of
// types that the parameter may be.
if (const TemplateTypeParmType *TemplateTypeParm
= Param->getAsTemplateTypeParmType()) {
// The argument type can not be less qualified than the parameter
// type.
if (Param.isMoreQualifiedThan(Arg))
return false;
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);
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)
return false;
}
return true;
}
if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
return false;
if (const PointerType *PointerParam = Param->getAsPointerType()) {
const PointerType *PointerArg = Arg->getAsPointerType();
if (!PointerArg)
return false;
return DeduceTemplateArguments(Context,
PointerParam->getPointeeType(),
PointerArg->getPointeeType(),
Deduced);
}
// FIXME: Many more cases to go (to go).
return false;
}
static bool
DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
const TemplateArgument &Arg,
llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
assert(Param.getKind() == Arg.getKind() &&
"Template argument kind mismatch during deduction");
switch (Param.getKind()) {
case TemplateArgument::Type:
return DeduceTemplateArguments(Context, Param.getAsType(),
Arg.getAsType(), Deduced);
default:
return false;
}
}
static bool
DeduceTemplateArguments(ASTContext &Context,
const TemplateArgumentList &ParamList,
const TemplateArgumentList &ArgList,
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;
}
return true;
}
bool
Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs) {
llvm::SmallVector<TemplateArgument, 4> Deduced;
Deduced.resize(Partial->getTemplateParameters()->size());
return ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(),
TemplateArgs, Deduced);
}

View File

@ -503,6 +503,10 @@ InstantiateTemplateSpecializationType(
for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
Arg != ArgEnd; ++Arg) {
switch (Arg->getKind()) {
case TemplateArgument::Null:
assert(false && "Should never have a NULL template argument");
break;
case TemplateArgument::Type: {
QualType T = SemaRef.InstantiateType(Arg->getAsType(),
TemplateArgs,

View File

@ -18,3 +18,21 @@ int array0[is_pointer<int>::value? -1 : 1];
int array1[is_pointer<int*>::value? 1 : -1];
int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \
// expected-error{{negative}}
template<typename T, typename U>
struct is_same {
static const bool value = false;
};
template<typename T>
struct is_same<T, T> {
static const bool value = true;
};
typedef int INT;
typedef INT* int_ptr;
int is_same0[is_same<int, int>::value? 1 : -1];
int is_same1[is_same<int, INT>::value? 1 : -1];
int is_same2[is_same<const int, int>::value? -1 : 1];
int is_same3[is_same<int_ptr, int>::value? -1 : 1];