diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-06-26 20:57:09 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-06-26 20:57:09 +0000 |
commit | f670c8cfa58b4c224eb8fb566130dc47844dd3de (patch) | |
tree | dade9f4b6e859edff8b7a47093d7045793004515 | |
parent | e7cf07d8df83e083505c7105c50b2797493008a6 (diff) |
Template argument deduction is no longer responsible for checking
non-dependent parameter types. Instead, class template partial
specializations perform a final check of all of the instantiated
arguments. This model is cleaner, and works better for function
templates where the "final check" occurs during overload resolution.
Also, cope with cv-qualifiers when the parameter type was originally a
reference type, so that the deduced argument can be more qualified
than the transformed argument.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@74323 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 24 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 132 | ||||
-rw-r--r-- | test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp | 19 |
3 files changed, 142 insertions, 33 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 57d645b740..aad19a63ef 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -580,6 +580,30 @@ public: return reinterpret_cast<Expr *>(TypeOrValue); } + /// \brief Iterator that traverses the elements of a template argument pack. + typedef const TemplateArgument * pack_iterator; + + /// \brief Iterator referencing the first argument of a template argument + /// pack. + pack_iterator pack_begin() const { + assert(Kind == Pack); + return Args.Args; + } + + /// \brief Iterator referencing one past the last argument of a template + /// argument pack. + pack_iterator pack_end() const { + assert(Kind == Pack); + return Args.Args + Args.NumArgs; + } + + /// \brief The number of template arguments in the given template argument + /// pack. + unsigned pack_size() const { + assert(Kind == Pack); + return Args.NumArgs; + } + /// \brief Retrieve the location where the template argument starts. SourceLocation getLocation() const { return StartLoc; } diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 66e12fefe6..bad9e7cf61 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -199,16 +199,9 @@ DeduceTemplateArguments(ASTContext &Context, Param.setCVRQualifiers(Param.getCVRQualifiers() & ~ExtraQualsOnParam); } - // If the parameter type is not dependent, just compare the types - // directly. - if (!Param->isDependentType()) { - if (Param == Arg) - return Sema::TDK_Success; - - Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn); - Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn); - return Sema::TDK_NonDeducedMismatch; - } + // If the parameter type is not dependent, there is nothing to deduce. + if (!Param->isDependentType()) + return Sema::TDK_Success; // C++ [temp.deduct.type]p9: // A template type argument T, a template template argument TT or a @@ -259,7 +252,9 @@ DeduceTemplateArguments(ASTContext &Context, Info.FirstArg = TemplateArgument(SourceLocation(), ParamIn); Info.SecondArg = TemplateArgument(SourceLocation(), ArgIn); - if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) + if ((ParamTypeWasReference && Param.isMoreQualifiedThan(Arg)) || + (!ParamTypeWasReference && + (Param.getCVRQualifiers() != Arg.getCVRQualifiers()))) return Sema::TDK_NonDeducedMismatch; switch (Param->getTypeClass()) { @@ -419,7 +414,7 @@ DeduceTemplateArguments(ASTContext &Context, return Sema::TDK_Success; } - // template-name<T> (wheretemplate-name refers to a class template) + // template-name<T> (where template-name refers to a class template) // template-name<i> // TT<T> (TODO) // TT<i> (TODO) @@ -559,7 +554,7 @@ DeduceTemplateArguments(ASTContext &Context, } // FIXME: Many more cases to go (to go). - return Sema::TDK_NonDeducedMismatch; + return Sema::TDK_Success; } static Sema::TemplateDeductionResult @@ -656,6 +651,62 @@ DeduceTemplateArguments(ASTContext &Context, return Sema::TDK_Success; } +/// \brief Determine whether two template arguments are the same. +static bool isSameTemplateArg(ASTContext &Context, + const TemplateArgument &X, + const TemplateArgument &Y) { + if (X.getKind() != Y.getKind()) + return false; + + switch (X.getKind()) { + case TemplateArgument::Null: + assert(false && "Comparing NULL template argument"); + break; + + case TemplateArgument::Type: + return Context.getCanonicalType(X.getAsType()) == + Context.getCanonicalType(Y.getAsType()); + + case TemplateArgument::Declaration: + return Context.getCanonicalDecl(X.getAsDecl()) == + Context.getCanonicalDecl(Y.getAsDecl()); + + case TemplateArgument::Integral: + return *X.getAsIntegral() == *Y.getAsIntegral(); + + case TemplateArgument::Expression: + // FIXME: We assume that all expressions are distinct, but we should + // really check their canonical forms. + return false; + + case TemplateArgument::Pack: + if (X.pack_size() != Y.pack_size()) + return false; + + for (TemplateArgument::pack_iterator XP = X.pack_begin(), + XPEnd = X.pack_end(), + YP = Y.pack_begin(); + XP != XPEnd; ++XP, ++YP) + if (!isSameTemplateArg(Context, *XP, *YP)) + return false; + + return true; + } + + return false; +} + +/// \brief Helper function to build a TemplateParameter when we don't +/// know its type statically. +static TemplateParameter makeTemplateParameter(Decl *D) { + if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(D)) + return TemplateParameter(TTP); + else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(D)) + return TemplateParameter(NTTP); + + return TemplateParameter(cast<TemplateTemplateParmDecl>(D)); +} + /// \brief Perform template argument deduction to determine whether /// the given template arguments match the given class template /// partial specialization per C++ [temp.class.spec.match]. @@ -720,27 +771,44 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) { Decl *Param = const_cast<Decl *>( ClassTemplate->getTemplateParameters()->getParam(I)); - if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) { - TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I], - *DeducedArgumentList); - if (InstArg.getKind() != TemplateArgument::Type) { - Info.Param = TTP; - Info.FirstArg = PartialTemplateArgs[I]; - return TDK_SubstitutionFailure; - } - - if (Context.getCanonicalType(InstArg.getAsType()) - != Context.getCanonicalType(TemplateArgs[I].getAsType())) { - Info.Param = TTP; - Info.FirstArg = TemplateArgs[I]; - Info.SecondArg = InstArg; - return TDK_NonDeducedMismatch; + TemplateArgument InstArg = Instantiate(PartialTemplateArgs[I], + *DeducedArgumentList); + if (InstArg.isNull()) { + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = PartialTemplateArgs[I]; + return TDK_SubstitutionFailure; + } + + if (InstArg.getKind() == TemplateArgument::Expression) { + // When the argument is an expression, check the expression result + // against the actual template parameter to get down to the canonical + // template argument. + Expr *InstExpr = InstArg.getAsExpr(); + if (NonTypeTemplateParmDecl *NTTP + = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + if (CheckTemplateArgument(NTTP, NTTP->getType(), InstExpr, InstArg)) { + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = PartialTemplateArgs[I]; + return TDK_SubstitutionFailure; + } + } else if (TemplateTemplateParmDecl *TTP + = dyn_cast<TemplateTemplateParmDecl>(Param)) { + // FIXME: template template arguments should really resolve to decls + DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InstExpr); + if (!DRE || CheckTemplateArgument(TTP, DRE)) { + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = PartialTemplateArgs[I]; + return TDK_SubstitutionFailure; + } } - - continue; } - - // FIXME: Check template template arguments? + + if (!isSameTemplateArg(Context, TemplateArgs[I], InstArg)) { + Info.Param = makeTemplateParameter(Param); + Info.FirstArg = TemplateArgs[I]; + Info.SecondArg = InstArg; + return TDK_NonDeducedMismatch; + } } if (Trap.hasErrorOccurred()) diff --git a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp index b105afae5d..beb6aad2c0 100644 --- a/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp +++ b/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp @@ -1,4 +1,4 @@ -// RUN: clang-cc -fsyntax-only %s +// RUN: clang-cc -fsyntax-only -verify %s template<typename T> struct A { }; @@ -9,3 +9,20 @@ void test_f0(int *ip, float const *cfp) { A<const float> a1 = f0(cfp); } +template<typename T> void f1(T*, int); + +void test_f1(int *ip, float fv) { + f1(ip, fv); +} + +template<typename T> void f2(T*, T*); + +struct ConvToIntPtr { + operator int*() const; +}; + +void test_f2(int *ip, float *fp) { + f2(ip, ConvToIntPtr()); // expected-error{{no matching function}} + f2(ip, ip); // okay + f2(ip, fp); // expected-error{{no matching function}} +} |