Template argument deduction for member pointers.

Also, introduced some of the framework for performing instantiation as
part of template argument deduction.

llvm-svn: 73175
This commit is contained in:
Douglas Gregor 2009-06-10 23:47:09 +00:00
parent 96c9dea4a0
commit 637d9984f0
5 changed files with 201 additions and 1 deletions

View File

@ -772,6 +772,9 @@ def note_template_member_function_here : Note<
"in instantiation of member function %q0 requested here">;
def note_default_arg_instantiation_here : Note<
"in instantiation of default argument for '%0' required here">;
def note_partial_spec_deduct_instantiation_here : Note<
"during template argument deduction for class template partial "
"specialization %0, here">;
def err_field_instantiates_to_function : Error<
"data member instantiated with function type %0">;
def err_nested_name_spec_non_tag : Error<

View File

@ -2056,7 +2056,16 @@ public:
/// parameter. The Entity is the template, and
/// TemplateArgs/NumTemplateArguments provides the template
/// arguments as specified.
DefaultTemplateArgumentInstantiation
/// FIXME: Use a TemplateArgumentList
DefaultTemplateArgumentInstantiation,
/// We are performing template argument deduction for a class
/// template partial specialization. The Entity is the class
/// template partial specialization, and
/// TemplateArgs/NumTemplateArgs provides the deduced template
/// arguments.
/// FIXME: Use a TemplateArgumentList
PartialSpecDeductionInstantiation
} Kind;
/// \brief The point of instantiation within the source code.
@ -2090,6 +2099,7 @@ public:
return true;
case DefaultTemplateArgumentInstantiation:
case PartialSpecDeductionInstantiation:
return X.TemplateArgs == Y.TemplateArgs;
}
@ -2146,6 +2156,15 @@ public:
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
/// \brief Note that we are instantiating as part of template
/// argument deduction for a class template partial
/// specialization.
InstantiatingTemplate(Sema &SemaRef, SourceLocation PointOfInstantiation,
ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange = SourceRange());
/// \brief Note that we have finished instantiating this template.
void Clear();

View File

@ -408,6 +408,37 @@ static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
return true;
}
// T type::*
// T T::*
// T (type::*)()
// type (T::*)()
// type (type::*)(T)
// type (T::*)(T)
// T (type::*)(T)
// T (T::*)()
// T (T::*)(T)
case Type::MemberPointer: {
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);
}
case Type::TypeOfExpr:
case Type::TypeOf:
case Type::Typename:
// No template argument deduction for these types
return true;
default:
break;
}
@ -492,6 +523,14 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
if (! ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(),
TemplateArgs, Deduced))
return 0;
// 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;
// FIXME: Substitute the deduced template arguments into the template
// arguments of the class template partial specialization; the resulting

View File

@ -90,6 +90,30 @@ Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
}
}
Sema::InstantiatingTemplate::InstantiatingTemplate(Sema &SemaRef,
SourceLocation PointOfInstantiation,
ClassTemplatePartialSpecializationDecl *PartialSpec,
const TemplateArgument *TemplateArgs,
unsigned NumTemplateArgs,
SourceRange InstantiationRange)
: SemaRef(SemaRef) {
Invalid = CheckInstantiationDepth(PointOfInstantiation,
InstantiationRange);
if (!Invalid) {
ActiveTemplateInstantiation Inst;
Inst.Kind
= ActiveTemplateInstantiation::PartialSpecDeductionInstantiation;
Inst.PointOfInstantiation = PointOfInstantiation;
Inst.Entity = reinterpret_cast<uintptr_t>(PartialSpec);
Inst.TemplateArgs = TemplateArgs;
Inst.NumTemplateArgs = NumTemplateArgs;
Inst.InstantiationRange = InstantiationRange;
SemaRef.ActiveTemplateInstantiations.push_back(Inst);
Invalid = false;
}
}
void Sema::InstantiatingTemplate::Clear() {
if (!Invalid) {
SemaRef.ActiveTemplateInstantiations.pop_back();
@ -157,6 +181,26 @@ void Sema::PrintInstantiationStack() {
<< Active->InstantiationRange;
break;
}
case ActiveTemplateInstantiation::PartialSpecDeductionInstantiation: {
ClassTemplatePartialSpecializationDecl *PartialSpec
= cast<ClassTemplatePartialSpecializationDecl>((Decl *)Active->Entity);
std::string TemplateArgsStr
= TemplateSpecializationType::PrintTemplateArgumentList(
PartialSpec->getTemplateArgs().getFlatArgumentList(),
PartialSpec->getTemplateArgs().flat_size(),
Context.PrintingPolicy);
// FIXME: The active template instantiation's template arguments
// are interesting, too. We should add something like [with T =
// foo, U = bar, etc.] to the string.
Diags.Report(FullSourceLoc(Active->PointOfInstantiation, SourceMgr),
diag::note_partial_spec_deduct_instantiation_here)
<< (PartialSpec->getSpecializedTemplate()->getNameAsString() +
TemplateArgsStr)
<< Active->InstantiationRange;
break;
}
}
}
}

View File

@ -158,3 +158,98 @@ template<typename T, typename Class>
struct is_member_pointer<T Class::*> {
static const bool value = true;
};
struct X { };
int is_member_pointer0[is_member_pointer<int X::*>::value? 1 : -1];
int is_member_pointer1[is_member_pointer<const int X::*>::value? 1 : -1];
int is_member_pointer2[is_member_pointer<int (X::*)()>::value? 1 : -1];
int is_member_pointer3[is_member_pointer<int (X::*)(int) const>::value? 1 : -1];
int is_member_pointer4[is_member_pointer<int (X::**)(int) const>::value? -1 : 1];
int is_member_pointer5[is_member_pointer<int>::value? -1 : 1];
template<typename T>
struct is_member_function_pointer {
static const bool value = false;
};
template<typename T, typename Class>
struct is_member_function_pointer<T (Class::*)()> {
static const bool value = true;
};
template<typename T, typename Class>
struct is_member_function_pointer<T (Class::*)() const> {
static const bool value = true;
};
template<typename T, typename Class>
struct is_member_function_pointer<T (Class::*)() volatile> {
static const bool value = true;
};
template<typename T, typename Class>
struct is_member_function_pointer<T (Class::*)() const volatile> {
static const bool value = true;
};
template<typename T, typename Class, typename A1>
struct is_member_function_pointer<T (Class::*)(A1)> {
static const bool value = true;
};
template<typename T, typename Class, typename A1>
struct is_member_function_pointer<T (Class::*)(A1) const> {
static const bool value = true;
};
template<typename T, typename Class, typename A1>
struct is_member_function_pointer<T (Class::*)(A1) volatile> {
static const bool value = true;
};
template<typename T, typename Class, typename A1>
struct is_member_function_pointer<T (Class::*)(A1) const volatile> {
static const bool value = true;
};
int is_member_function_pointer0[
is_member_function_pointer<int X::*>::value? -1 : 1];
int is_member_function_pointer1[
is_member_function_pointer<int (X::*)()>::value? 1 : -1];
int is_member_function_pointer2[
is_member_function_pointer<X (X::*)(X&)>::value? 1 : -1];
int is_member_function_pointer3[
is_member_function_pointer<int (X::*)() const>::value? 1 : -1];
int is_member_function_pointer4[
is_member_function_pointer<int (X::*)(float) const>::value? 1 : -1];
template<typename T, typename ValueType = T>
struct is_nested_value_type_identity {
static const bool value = false;
};
template<typename T>
struct is_nested_value_type_identity<T, typename T::value_type> {
static const bool value = true;
};
template<typename T>
struct HasValueType {
typedef T value_type;
};
struct HasIdentityValueType {
typedef HasIdentityValueType value_type;
};
struct NoValueType { };
// FIXME: Need substitution into the template arguments of the partial spec
//int is_nested_value_type_identity0[
// is_nested_value_type_identity<HasValueType<int> >::value? -1 : 1];
int is_nested_value_type_identity1[
is_nested_value_type_identity<HasIdentityValueType>::value? 1 : -1];
// FIXME: Enable when we have SFINAE support
//int is_nested_value_type_identity0[
// is_nested_value_type_identity<NoValueType>::value? -1 : 1];