diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-06-10 23:47:09 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-06-10 23:47:09 +0000 |
commit | 637a4097f61b09d6ccf619298d9d121fafa044e4 (patch) | |
tree | b022162e5a082512c9b055fe568cb373986427ee | |
parent | 42f963dec21ed86f33ba34dc01140f77c7174768 (diff) |
Template argument deduction for member pointers.
Also, introduced some of the framework for performing instantiation as
part of template argument deduction.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73175 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 21 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 39 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiate.cpp | 44 | ||||
-rw-r--r-- | test/SemaTemplate/temp_class_spec.cpp | 95 |
5 files changed, 201 insertions, 1 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 0d0a10eed0..2d55d4c4c5 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 12ebc4adff..ac8997d3b3 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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(); diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 0ad79358cd..6e7a47aeb2 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -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 diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index c1f67c78ad..9a3d9e0160 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -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; + } + } } } diff --git a/test/SemaTemplate/temp_class_spec.cpp b/test/SemaTemplate/temp_class_spec.cpp index 709fa4201f..c02ce9b728 100644 --- a/test/SemaTemplate/temp_class_spec.cpp +++ b/test/SemaTemplate/temp_class_spec.cpp @@ -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]; |