[cfe-commits] r81777 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/Sema.h lib/Sema/SemaOverload.cpp lib/Sema/SemaTemplate.h lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp test/SemaTemplate/temp_func_order.cpp
Douglas Gregor
dgregor at apple.com
Mon Sep 14 11:39:43 PDT 2009
Author: dgregor
Date: Mon Sep 14 13:39:43 2009
New Revision: 81777
URL: http://llvm.org/viewvc/llvm-project?rev=81777&view=rev
Log:
Implement partial ordering of function template specializations
(C++ [temp.func.order]).
Added:
cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp
cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
cfe/trunk/test/SemaTemplate/temp_func_order.cpp
Modified:
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplate.h
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=81777&r1=81776&r2=81777&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Mon Sep 14 13:39:43 2009
@@ -959,10 +959,6 @@
"partial ordering of class template partial specializations is not yet "
"supported">;
-def unsup_function_template_partial_ordering : Warning<
- "partial ordering of function templates is unsupported; overload resolution "
- "may result in an ambiguity that would not occur with a conforming compiler">;
-
// C++ Template Instantiation
def err_template_recursion_depth_exceeded : Error<
"recursive template instantiation exceeded maximum depth of %0">,
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=81777&r1=81776&r2=81777&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Mon Sep 14 13:39:43 2009
@@ -2730,7 +2730,7 @@
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
- bool isCallContext);
+ TemplatePartialOrderingContext TPOC);
void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
llvm::SmallVectorImpl<bool> &Deduced);
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=81777&r1=81776&r2=81777&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Mon Sep 14 13:39:43 2009
@@ -3708,7 +3708,7 @@
if (FunctionTemplateDecl *BetterTemplate
= getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(),
Cand2.Function->getPrimaryTemplate(),
- true))
+ TPOC_Call))
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
// -- the context is an initialization by user-defined conversion
@@ -4029,7 +4029,7 @@
for (++M; M != MEnd; ++M)
if (getMoreSpecializedTemplate((*M)->getPrimaryTemplate(),
(*Best)->getPrimaryTemplate(),
- false)
+ TPOC_Other)
== (*M)->getPrimaryTemplate())
Best = M;
@@ -4040,7 +4040,7 @@
if (M != Best &&
getMoreSpecializedTemplate((*M)->getPrimaryTemplate(),
(*Best)->getPrimaryTemplate(),
- false)
+ TPOC_Other)
!= (*Best)->getPrimaryTemplate()) {
Ambiguous = true;
break;
Modified: cfe/trunk/lib/Sema/SemaTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.h?rev=81777&r1=81776&r2=81777&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.h (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.h Mon Sep 14 13:39:43 2009
@@ -86,6 +86,19 @@
return *TemplateArgumentLists.front();
}
};
+
+ /// \brief The context in which partial ordering of function templates occurs.
+ enum TemplatePartialOrderingContext {
+ /// \brief Partial ordering of function templates for a function call.
+ TPOC_Call,
+ /// \brief Partial ordering of function templates for a call to a
+ /// conversion function.
+ TPOC_Conversion,
+ /// \brief Partial ordering of function templates in other contexts, e.g.,
+ /// taking the address of a function template or matching a function
+ /// template specialization to a function template.
+ TPOC_Other
+ };
}
#endif // LLVM_CLANG_SEMA_TEMPLATE_H
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=81777&r1=81776&r2=81777&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Mon Sep 14 13:39:43 2009
@@ -18,6 +18,7 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Parse/DeclSpec.h"
#include "llvm/Support/Compiler.h"
+#include <algorithm>
namespace clang {
/// \brief Various flags that control template argument deduction.
@@ -1581,6 +1582,209 @@
return Result;
}
+/// \brief Stores the result of comparing the qualifiers of two types.
+enum DeductionQualifierComparison {
+ NeitherMoreQualified = 0,
+ ParamMoreQualified,
+ ArgMoreQualified
+};
+
+/// \brief Deduce the template arguments during partial ordering by comparing
+/// the parameter type and the argument type (C++0x [temp.deduct.partial]).
+///
+/// \param Context the AST context in which this deduction occurs.
+///
+/// \param TemplateParams the template parameters that we are deducing
+///
+/// \param ParamIn the parameter type
+///
+/// \param ArgIn the argument type
+///
+/// \param Info information about the template argument deduction itself
+///
+/// \param Deduced the deduced template arguments
+///
+/// \returns the result of template argument deduction so far. Note that a
+/// "success" result means that template argument deduction has not yet failed,
+/// but it may still fail, later, for other reasons.
+static Sema::TemplateDeductionResult
+DeduceTemplateArgumentsDuringPartialOrdering(ASTContext &Context,
+ TemplateParameterList *TemplateParams,
+ QualType ParamIn, QualType ArgIn,
+ Sema::TemplateDeductionInfo &Info,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced,
+ llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+ CanQualType Param = Context.getCanonicalType(ParamIn);
+ CanQualType Arg = Context.getCanonicalType(ArgIn);
+
+ // C++0x [temp.deduct.partial]p5:
+ // Before the partial ordering is done, certain transformations are
+ // performed on the types used for partial ordering:
+ // - If P is a reference type, P is replaced by the type referred to.
+ CanQual<ReferenceType> ParamRef = Param->getAs<ReferenceType>();
+ if (ParamRef)
+ Param = ParamRef->getPointeeType();
+
+ // - If A is a reference type, A is replaced by the type referred to.
+ CanQual<ReferenceType> ArgRef = Arg->getAs<ReferenceType>();
+ if (ArgRef)
+ Arg = ArgRef->getPointeeType();
+
+ if (QualifierComparisons && ParamRef && ArgRef) {
+ // C++0x [temp.deduct.partial]p6:
+ // If both P and A were reference types (before being replaced with the
+ // type referred to above), determine which of the two types (if any) is
+ // more cv-qualified than the other; otherwise the types are considered to
+ // be equally cv-qualified for partial ordering purposes. The result of this
+ // determination will be used below.
+ //
+ // We save this information for later, using it only when deduction
+ // succeeds in both directions.
+ DeductionQualifierComparison QualifierResult = NeitherMoreQualified;
+ if (Param.isMoreQualifiedThan(Arg))
+ QualifierResult = ParamMoreQualified;
+ else if (Arg.isMoreQualifiedThan(Param))
+ QualifierResult = ArgMoreQualified;
+ QualifierComparisons->push_back(QualifierResult);
+ }
+
+ // C++0x [temp.deduct.partial]p7:
+ // Remove any top-level cv-qualifiers:
+ // - If P is a cv-qualified type, P is replaced by the cv-unqualified
+ // version of P.
+ Param = Param.getUnqualifiedType();
+ // - If A is a cv-qualified type, A is replaced by the cv-unqualified
+ // version of A.
+ Arg = Arg.getUnqualifiedType();
+
+ // C++0x [temp.deduct.partial]p8:
+ // Using the resulting types P and A the deduction is then done as
+ // described in 14.9.2.5. If deduction succeeds for a given type, the type
+ // from the argument template is considered to be at least as specialized
+ // as the type from the parameter template.
+ return DeduceTemplateArguments(Context, TemplateParams, Param, Arg, Info,
+ Deduced, TDF_None);
+}
+
+static void
+MarkDeducedTemplateParameters(Sema &SemaRef, QualType T,
+ llvm::SmallVectorImpl<bool> &Deduced);
+
+/// \brief Determine whether the function template \p FT1 is at least as
+/// specialized as \p FT2.
+static bool isAtLeastAsSpecializedAs(Sema &S,
+ FunctionTemplateDecl *FT1,
+ FunctionTemplateDecl *FT2,
+ TemplatePartialOrderingContext TPOC,
+ llvm::SmallVectorImpl<DeductionQualifierComparison> *QualifierComparisons) {
+ FunctionDecl *FD1 = FT1->getTemplatedDecl();
+ FunctionDecl *FD2 = FT2->getTemplatedDecl();
+ const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>();
+ const FunctionProtoType *Proto2 = FD2->getType()->getAs<FunctionProtoType>();
+
+ assert(Proto1 && Proto2 && "Function templates must have prototypes");
+ TemplateParameterList *TemplateParams = FT2->getTemplateParameters();
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(TemplateParams->size());
+
+ // C++0x [temp.deduct.partial]p3:
+ // The types used to determine the ordering depend on the context in which
+ // the partial ordering is done:
+ Sema::TemplateDeductionInfo Info(S.Context);
+ switch (TPOC) {
+ case TPOC_Call: {
+ // - In the context of a function call, the function parameter types are
+ // used.
+ unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
+ for (unsigned I = 0; I != NumParams; ++I)
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ Proto2->getArgType(I),
+ Proto1->getArgType(I),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+
+ break;
+ }
+
+ case TPOC_Conversion:
+ // - In the context of a call to a conversion operator, the return types
+ // of the conversion function templates are used.
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ Proto2->getResultType(),
+ Proto1->getResultType(),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+ break;
+
+ case TPOC_Other:
+ // - In other contexts (14.6.6.2) the function templateâs function type
+ // is used.
+ if (DeduceTemplateArgumentsDuringPartialOrdering(S.Context,
+ TemplateParams,
+ FD2->getType(),
+ FD1->getType(),
+ Info,
+ Deduced,
+ QualifierComparisons))
+ return false;
+ break;
+ }
+
+ // C++0x [temp.deduct.partial]p11:
+ // In most cases, all template parameters must have values in order for
+ // deduction to succeed, but for partial ordering purposes a template
+ // parameter may remain without a value provided it is not used in the
+ // types being used for partial ordering. [ Note: a template parameter used
+ // in a non-deduced context is considered used. -end note]
+ unsigned ArgIdx = 0, NumArgs = Deduced.size();
+ for (; ArgIdx != NumArgs; ++ArgIdx)
+ if (Deduced[ArgIdx].isNull())
+ break;
+
+ if (ArgIdx == NumArgs) {
+ // All template arguments were deduced. FT1 is at least as specialized
+ // as FT2.
+ return true;
+ }
+
+ // FIXME: MarkDeducedTemplateParameters needs to become
+ // MarkUsedTemplateParameters with a flag that tells us whether to mark
+ // template parameters that are used in non-deduced contexts.
+ llvm::SmallVector<bool, 4> UsedParameters;
+ UsedParameters.resize(TemplateParams->size());
+ switch (TPOC) {
+ case TPOC_Call: {
+ unsigned NumParams = std::min(Proto1->getNumArgs(), Proto2->getNumArgs());
+ for (unsigned I = 0; I != NumParams; ++I)
+ ::MarkDeducedTemplateParameters(S, Proto2->getArgType(I), UsedParameters);
+ break;
+ }
+
+ case TPOC_Conversion:
+ ::MarkDeducedTemplateParameters(S, Proto2->getResultType(), UsedParameters);
+ break;
+
+ case TPOC_Other:
+ ::MarkDeducedTemplateParameters(S, FD2->getType(), UsedParameters);
+ break;
+ }
+
+ for (; ArgIdx != NumArgs; ++ArgIdx)
+ // If this argument had no value deduced but was used in one of the types
+ // used for partial ordering, then deduction fails.
+ if (Deduced[ArgIdx].isNull() && UsedParameters[ArgIdx])
+ return false;
+
+ return true;
+}
+
+
/// \brief Returns the more specialization function template according
/// to the rules of function template partial ordering (C++ [temp.func.order]).
///
@@ -1588,29 +1792,70 @@
///
/// \param FT2 the second function template
///
-/// \param isCallContext whether partial ordering is being performed
-/// for a function call (which ignores the return types of the
-/// functions).
+/// \param TPOC the context in which we are performing partial ordering of
+/// function templates.
///
/// \returns the more specialization function template. If neither
/// template is more specialized, returns NULL.
FunctionTemplateDecl *
Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
- bool isCallContext) {
-#if 0
+ TemplatePartialOrderingContext TPOC) {
// FIXME: Implement this
- bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, isCallContext);
- bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, isCallContext);
- if (Better1 == Better2)
+ llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons;
+ bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, TPOC, 0);
+ bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, TPOC,
+ &QualifierComparisons);
+
+ if (Better1 != Better2) // We have a clear winner
+ return Better1? FT1 : FT2;
+
+ if (!Better1 && !Better2) // Neither is better than the other
return 0;
+
+
+ // C++0x [temp.deduct.partial]p10:
+ // If for each type being considered a given template is at least as
+ // specialized for all types and more specialized for some set of types and
+ // the other template is not more specialized for any types or is not at
+ // least as specialized for any types, then the given template is more
+ // specialized than the other template. Otherwise, neither template is more
+ // specialized than the other.
+ Better1 = false;
+ Better2 = false;
+ for (unsigned I = 0, N = QualifierComparisons.size(); I != N; ++I) {
+ // C++0x [temp.deduct.partial]p9:
+ // If, for a given type, deduction succeeds in both directions (i.e., the
+ // types are identical after the transformations above) and if the type
+ // from the argument template is more cv-qualified than the type from the
+ // parameter template (as described above) that type is considered to be
+ // more specialized than the other. If neither type is more cv-qualified
+ // than the other then neither type is more specialized than the other.
+ switch (QualifierComparisons[I]) {
+ case NeitherMoreQualified:
+ break;
+
+ case ParamMoreQualified:
+ Better1 = true;
+ if (Better2)
+ return 0;
+ break;
+
+ case ArgMoreQualified:
+ Better2 = true;
+ if (Better1)
+ return 0;
+ break;
+ }
+ }
+
+ assert(!(Better1 && Better2) && "Should have broken out in the loop above");
if (Better1)
return FT1;
- return FT2;
-#else
- Diag(SourceLocation(), diag::unsup_function_template_partial_ordering);
- return 0;
-#endif
+ else if (Better2)
+ return FT2;
+ else
+ return 0;
}
static void
Added: cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp?rev=81777&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p4.cpp Mon Sep 14 13:39:43 2009
@@ -0,0 +1,23 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<class T> struct A { A(); };
+template<class T> int &f(T);
+template<class T> float &f(T*);
+template<class T> double &f(const T*);
+
+template<class T> void g(T); // expected-note{{candidate}}
+template<class T> void g(T&); // expected-note{{candidate}}
+
+template<class T> int &h(const T&);
+template<class T> float &h(A<T>&);
+
+void m() {
+ const int *p;
+ double &dr1 = f(p);
+ float x;
+ g(x); // expected-error{{ambiguous}}
+ A<int> z;
+ float &fr1 = h(z);
+ const A<int> z2;
+ int &ir1 = h(z2);
+}
Added: cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp?rev=81777&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.decls/temp.fct/temp.func.order/p5.cpp Mon Sep 14 13:39:43 2009
@@ -0,0 +1,12 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+template<class T> int &f(T);
+template<class T> float &f(T*, int=1);
+
+template<class T> int &g(T);
+template<class T> float &g(T*, ...);
+
+int main() {
+ int* ip;
+ float &fr1 = f(ip);
+ float &fr2 = g(ip);
+}
Added: cfe/trunk/test/SemaTemplate/temp_func_order.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_func_order.cpp?rev=81777&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_func_order.cpp (added)
+++ cfe/trunk/test/SemaTemplate/temp_func_order.cpp Mon Sep 14 13:39:43 2009
@@ -0,0 +1,86 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T>
+int &f0(T);
+
+template<typename T>
+float &f0(T*);
+
+void test_f0(int i, int *ip) {
+ int &ir = f0(i);
+ float &fr = f0(ip);
+}
+
+template<typename T, typename U>
+int &f1(T, U);
+
+template<typename T>
+float &f1(T, T);
+
+void test_f1(int i, float f) {
+ int &ir = f1(i, f);
+ float &fr1 = f1(i, i);
+ float &fr2 = f1(f, f);
+}
+
+template<typename T, typename U>
+struct A { };
+
+template<typename T>
+int &f2(T);
+
+template<typename T, typename U>
+float &f2(A<T, U>);
+
+template<typename T>
+double &f2(A<T, T>);
+
+void test_f2(int i, A<int, float> aif, A<int, int> aii) {
+ int &ir = f2(i);
+ float &fr = f2(aif);
+ double &dr = f2(aii);
+}
+
+template<typename T, typename U>
+int &f3(T*, U); // expected-note{{candidate}}
+
+template<typename T, typename U>
+float &f3(T, U*); // expected-note{{candidate}}
+
+void test_f3(int i, int *ip, float *fp) {
+ int &ir = f3(ip, i);
+ float &fr = f3(i, fp);
+ f3(ip, ip); // expected-error{{ambiguous}}
+}
+
+template<typename T>
+int &f4(T&);
+
+template<typename T>
+float &f4(const T&);
+
+void test_f4(int i, const int ic) {
+ int &ir1 = f4(i);
+ float &fr1 = f4(ic);
+}
+
+template<typename T, typename U>
+int &f5(T&, const U&); // expected-note{{candidate}}
+
+template<typename T, typename U>
+float &f5(const T&, U&); // expected-note{{candidate}}
+
+void test_f5(int i, const int ic) {
+ f5(i, i); // expected-error{{ambiguous}}
+}
+
+template<typename T, typename U>
+int &f6(T&, U&);
+
+template<typename T, typename U>
+float &f6(const T&, U&);
+
+void test_f6(int i, const int ic) {
+ int &ir = f6(i, i);
+ float &fr = f6(ic, ic);
+}
More information about the cfe-commits
mailing list