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:
parent
2797e7a483
commit
55ca8f6443
|
@ -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;
|
||||
|
|
|
@ -23,6 +23,7 @@ add_clang_library(clangSema
|
|||
SemaOverload.cpp
|
||||
SemaStmt.cpp
|
||||
SemaTemplate.cpp
|
||||
SemaTemplateDeduction.cpp
|
||||
SemaTemplateInstantiate.cpp
|
||||
SemaTemplateInstantiateDecl.cpp
|
||||
SemaTemplateInstantiateExpr.cpp
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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];
|
||||
|
|
Loading…
Reference in New Issue