[cfe-commits] r74323 - in /cfe/trunk: include/clang/AST/DeclTemplate.h lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
Douglas Gregor
dgregor at apple.com
Fri Jun 26 13:57:09 PDT 2009
Author: dgregor
Date: Fri Jun 26 15:57:09 2009
New Revision: 74323
URL: http://llvm.org/viewvc/llvm-project?rev=74323&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=74323&r1=74322&r2=74323&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Fri Jun 26 15:57:09 2009
@@ -580,6 +580,30 @@
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; }
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=74323&r1=74322&r2=74323&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Fri Jun 26 15:57:09 2009
@@ -199,16 +199,9 @@
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 @@
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 @@
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 @@
}
// FIXME: Many more cases to go (to go).
- return Sema::TDK_NonDeducedMismatch;
+ return Sema::TDK_Success;
}
static Sema::TemplateDeductionResult
@@ -656,6 +651,62 @@
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 @@
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())
Modified: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp?rev=74323&r1=74322&r2=74323&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp Fri Jun 26 15:57:09 2009
@@ -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 @@
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}}
+}
More information about the cfe-commits
mailing list