[cfe-commits] r74213 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ lib/AST/ lib/Sema/ test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/ test/Parser/ test/SemaCXX/ test/SemaTemplate/
Douglas Gregor
dgregor at apple.com
Thu Jun 25 15:08:13 PDT 2009
Author: dgregor
Date: Thu Jun 25 17:08:12 2009
New Revision: 74213
URL: http://llvm.org/viewvc/llvm-project?rev=74213&view=rev
Log:
Improved semantic analysis and AST respresentation for function
templates.
For example, this now type-checks (but does not instantiate the body
of deref<int>):
template<typename T> T& deref(T* t) { return *t; }
void test(int *ip) {
int &ir = deref(ip);
}
Specific changes/additions:
* Template argument deduction from a call to a function template.
* Instantiation of a function template specializations (just the
declarations) from the template arguments deduced from a call.
* FunctionTemplateDecls are stored directly in declaration contexts
and found via name lookup (all forms), rather than finding the
FunctionDecl and then realizing it is a template. This is
responsible for most of the churn, since some of the core
declaration matching and lookup code assumes that all functions are
FunctionDecls.
Added:
cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp
Modified:
cfe/trunk/include/clang/AST/DeclBase.h
cfe/trunk/include/clang/AST/DeclCXX.h
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/Decl.cpp
cfe/trunk/lib/AST/DeclBase.cpp
cfe/trunk/lib/AST/DeclCXX.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaDecl.cpp
cfe/trunk/lib/Sema/SemaDeclCXX.cpp
cfe/trunk/lib/Sema/SemaExpr.cpp
cfe/trunk/lib/Sema/SemaLookup.cpp
cfe/trunk/lib/Sema/SemaOverload.cpp
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp
cfe/trunk/test/Parser/cxx-template-decl.cpp
cfe/trunk/test/SemaCXX/template-specialization.cpp
cfe/trunk/test/SemaTemplate/temp_arg_template.cpp
Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Thu Jun 25 17:08:12 2009
@@ -329,6 +329,9 @@
/// template parameter pack.
bool isTemplateParameterPack() const;
+ /// \brief Whether this declaration is a function or function template.
+ bool isFunctionOrFunctionTemplate() const;
+
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *) { return true; }
static DeclContext *castToDeclContext(const Decl *);
Modified: cfe/trunk/include/clang/AST/DeclCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclCXX.h?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclCXX.h (original)
+++ cfe/trunk/include/clang/AST/DeclCXX.h Thu Jun 25 17:08:12 2009
@@ -27,6 +27,40 @@
class CXXMethodDecl;
class ClassTemplateSpecializationDecl;
+/// \brief Represents any kind of function declaration, whether it is a
+/// concrete function or a function template.
+class AnyFunctionDecl {
+ NamedDecl *Function;
+
+public:
+ AnyFunctionDecl(FunctionDecl *FD) : Function(FD) { }
+ AnyFunctionDecl(FunctionTemplateDecl *FTD);
+
+ /// \brief Implicily converts any function or function template into a
+ /// named declaration.
+ operator NamedDecl *() const { return Function; }
+
+ /// \brief Retrieve the underlying function or function template.
+ NamedDecl *get() const { return Function; }
+};
+
+} // end namespace clang
+
+namespace llvm {
+ /// Implement simplify_type for AnyFunctionDecl, so that we can dyn_cast from
+ /// AnyFunctionDecl to any function or function template declaration.
+ template<> struct simplify_type<const ::clang::AnyFunctionDecl> {
+ typedef ::clang::NamedDecl* SimpleType;
+ static SimpleType getSimplifiedValue(const ::clang::AnyFunctionDecl &Val) {
+ return Val;
+ }
+ };
+ template<> struct simplify_type< ::clang::AnyFunctionDecl>
+ : public simplify_type<const ::clang::AnyFunctionDecl> {};
+} // end namespace llvm
+
+namespace clang {
+
/// OverloadedFunctionDecl - An instance of this class represents a
/// set of overloaded functions. All of the functions have the same
/// name and occur within the same scope.
@@ -43,15 +77,15 @@
/// Functions - the set of overloaded functions contained in this
/// overload set.
- llvm::SmallVector<FunctionDecl *, 4> Functions;
+ llvm::SmallVector<AnyFunctionDecl, 4> Functions;
// FIXME: This should go away when we stop using
// OverloadedFunctionDecl to store conversions in CXXRecordDecl.
friend class CXXRecordDecl;
public:
- typedef llvm::SmallVector<FunctionDecl *, 4>::iterator function_iterator;
- typedef llvm::SmallVector<FunctionDecl *, 4>::const_iterator
+ typedef llvm::SmallVector<AnyFunctionDecl, 4>::iterator function_iterator;
+ typedef llvm::SmallVector<AnyFunctionDecl, 4>::const_iterator
function_const_iterator;
static OverloadedFunctionDecl *Create(ASTContext &C, DeclContext *DC,
@@ -71,30 +105,18 @@
this->setLocation(FD->getLocation());
}
+ /// addOverload - Add an overloaded function template FTD to this set of
+ /// overloaded functions.
+ void addOverload(FunctionTemplateDecl *FTD);
+
function_iterator function_begin() { return Functions.begin(); }
function_iterator function_end() { return Functions.end(); }
function_const_iterator function_begin() const { return Functions.begin(); }
function_const_iterator function_end() const { return Functions.end(); }
- /// getNumFunctions - the number of overloaded functions stored in
+ /// \brief Returns the number of overloaded functions stored in
/// this set.
- unsigned getNumFunctions() const { return Functions.size(); }
-
- /// getFunction - retrieve the ith function in the overload set.
- const FunctionDecl *getFunction(unsigned i) const {
- assert(i < getNumFunctions() && "Illegal function #");
- return Functions[i];
- }
- FunctionDecl *getFunction(unsigned i) {
- assert(i < getNumFunctions() && "Illegal function #");
- return Functions[i];
- }
-
- // getDeclContext - Get the context of these overloaded functions.
- DeclContext *getDeclContext() {
- assert(getNumFunctions() > 0 && "Context of an empty overload set");
- return getFunction(0)->getDeclContext();
- }
+ unsigned size() const { return Functions.size(); }
// Implement isa/cast/dyncast/etc.
static bool classof(const Decl *D) {
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Thu Jun 25 17:08:12 2009
@@ -957,6 +957,10 @@
virtual void Destroy(ASTContext& C);
};
+/// Implementation of inline functions that require the template declarations
+inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
+ : Function(FTD) { }
+
} /* end of namespace clang */
#endif
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jun 25 17:08:12 2009
@@ -704,14 +704,15 @@
def err_template_arg_nontype_ambig : Error<
"template argument for non-type template parameter is treated as type %0">;
def err_template_arg_must_be_template : Error<
- "template argument for template template parameter must be a template">;
+ "template argument for template template parameter must be a class template">;
def err_template_arg_local_type : Error<"template argument uses local type %0">;
def err_template_arg_unnamed_type : Error<
"template argument uses unnamed type">;
def note_template_unnamed_type_here : Note<
"unnamed type used in template argument was declared here">;
def err_template_arg_not_class_template : Error<
- "template argument does not refer to a class template">;
+ "template argument does not refer to a class template or template "
+ "template parameter">;
def note_template_arg_refers_here_func : Note<
"template argument refers to function template %0, here">;
def err_template_arg_template_params_mismatch : Error<
Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Thu Jun 25 17:08:12 2009
@@ -269,6 +269,14 @@
// For function declarations, we keep track of redeclarations.
return FD->getPreviousDeclaration() == OldD;
+ // For function templates, the underlying function declarations are linked.
+ if (const FunctionTemplateDecl *FunctionTemplate
+ = dyn_cast<FunctionTemplateDecl>(this))
+ if (const FunctionTemplateDecl *OldFunctionTemplate
+ = dyn_cast<FunctionTemplateDecl>(OldD))
+ return FunctionTemplate->getTemplatedDecl()
+ ->declarationReplaces(OldFunctionTemplate->getTemplatedDecl());
+
// For method declarations, we keep track of redeclarations.
if (isa<ObjCMethodDecl>(this))
return false;
Modified: cfe/trunk/lib/AST/DeclBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclBase.cpp (original)
+++ cfe/trunk/lib/AST/DeclBase.cpp Thu Jun 25 17:08:12 2009
@@ -96,6 +96,10 @@
return false;
}
+bool Decl::isFunctionOrFunctionTemplate() const {
+ return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this);
+}
+
//===----------------------------------------------------------------------===//
// PrettyStackTraceDecl Implementation
//===----------------------------------------------------------------------===//
Modified: cfe/trunk/lib/AST/DeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclCXX.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclCXX.cpp (original)
+++ cfe/trunk/lib/AST/DeclCXX.cpp Thu Jun 25 17:08:12 2009
@@ -420,6 +420,15 @@
return new (C) OverloadedFunctionDecl(DC, N);
}
+void OverloadedFunctionDecl::addOverload(FunctionTemplateDecl *FTD) {
+ Functions.push_back(FTD);
+
+ // An overloaded function declaration always has the location of
+ // the most-recently-added function declaration.
+ if (FTD->getLocation().isValid())
+ this->setLocation(FTD->getLocation());
+}
+
LinkageSpecDecl *LinkageSpecDecl::Create(ASTContext &C,
DeclContext *DC,
SourceLocation L,
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Thu Jun 25 17:08:12 2009
@@ -697,6 +697,11 @@
OverloadCandidateSet& CandidateSet,
bool SuppressUserConversions = false,
bool ForceRValue = false);
+ void AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions = false,
+ bool ForceRValue = false);
void AddConversionCandidate(CXXConversionDecl *Conversion,
Expr *From, QualType ToType,
OverloadCandidateSet& CandidateSet);
@@ -2204,7 +2209,13 @@
/// into a non-deduced context produced a type or value that
/// produces a type that does not match the original template
/// arguments provided.
- TDK_NonDeducedMismatch
+ TDK_NonDeducedMismatch,
+ /// \brief When performing template argument deduction for a function
+ /// template, there were too many call arguments.
+ TDK_TooManyArguments,
+ /// \brief When performing template argument deduction for a class
+ /// template, there were too few call arguments.
+ TDK_TooFewArguments
};
/// \brief Provides information about an attempted template argument
@@ -2284,6 +2295,12 @@
const TemplateArgumentList &TemplateArgs,
TemplateDeductionInfo &Info);
+ TemplateDeductionResult
+ DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ Expr **Args, unsigned NumArgs,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info);
+
void MarkDeducedTemplateParameters(const TemplateArgumentList &TemplateArgs,
llvm::SmallVectorImpl<bool> &Deduced);
Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jun 25 17:08:12 2009
@@ -319,16 +319,16 @@
return;
}
}
- } else if (isa<FunctionDecl>(D) &&
- AllowOverloadingOfFunction(D, Context)) {
- // We are pushing the name of a function, which might be an
- // overloaded name.
- FunctionDecl *FD = cast<FunctionDecl>(D);
+ } else if ((isa<FunctionDecl>(D) &&
+ AllowOverloadingOfFunction(D, Context)) ||
+ isa<FunctionTemplateDecl>(D)) {
+ // We are pushing the name of a function or function template,
+ // which might be an overloaded name.
IdentifierResolver::iterator Redecl
- = std::find_if(IdResolver.begin(FD->getDeclName()),
+ = std::find_if(IdResolver.begin(D->getDeclName()),
IdResolver.end(),
std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces),
- FD));
+ D));
if (Redecl != IdResolver.end() &&
S->isDeclScope(DeclPtrTy::make(*Redecl))) {
// There is already a declaration of a function on our
@@ -655,7 +655,12 @@
"Cannot merge with an overloaded function declaration");
// Verify the old decl was also a function.
- FunctionDecl *Old = dyn_cast<FunctionDecl>(OldD);
+ FunctionDecl *Old = 0;
+ if (FunctionTemplateDecl *OldFunctionTemplate
+ = dyn_cast<FunctionTemplateDecl>(OldD))
+ Old = OldFunctionTemplate->getTemplatedDecl();
+ else
+ Old = dyn_cast<FunctionDecl>(OldD);
if (!Old) {
Diag(New->getLocation(), diag::err_redefinition_different_kind)
<< New->getDeclName();
@@ -2304,8 +2309,6 @@
}
// Finally, we know we have the right number of parameters, install them.
NewFD->setParams(Context, Params.data(), Params.size());
-
-
// If name lookup finds a previous declaration that is not in the
// same scope as the new declaration, this may still be an
@@ -2388,6 +2391,12 @@
// Set this FunctionDecl's range up to the right paren.
NewFD->setLocEnd(D.getSourceRange().getEnd());
+ if (FunctionTemplate && NewFD->isInvalidDecl())
+ FunctionTemplate->setInvalidDecl();
+
+ if (FunctionTemplate)
+ return FunctionTemplate;
+
return NewFD;
}
@@ -2516,7 +2525,11 @@
if (MergeFunctionDecl(NewFD, OldDecl))
return NewFD->setInvalidDecl();
- NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
+ if (FunctionTemplateDecl *OldTemplateDecl
+ = dyn_cast<FunctionTemplateDecl>(OldDecl))
+ NewFD->setPreviousDeclaration(OldTemplateDecl->getTemplatedDecl());
+ else
+ NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
}
}
Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Thu Jun 25 17:08:12 2009
@@ -1625,7 +1625,8 @@
Conv = Conversions->function_begin(),
ConvEnd = Conversions->function_end();
Conv != ConvEnd; ++Conv) {
- if (*Conv == Conversion->getPreviousDeclaration()) {
+ if (*Conv
+ == cast_or_null<NamedDecl>(Conversion->getPreviousDeclaration())) {
*Conv = Conversion;
return DeclPtrTy::make(Conversion);
}
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Jun 25 17:08:12 2009
@@ -2605,11 +2605,16 @@
CommaLocs, RParenLoc));
// Determine whether this is a call to a member function.
- if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens()))
- if (isa<OverloadedFunctionDecl>(MemExpr->getMemberDecl()) ||
- isa<CXXMethodDecl>(MemExpr->getMemberDecl()))
+ if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(Fn->IgnoreParens())) {
+ NamedDecl *MemDecl = MemExpr->getMemberDecl();
+ if (isa<OverloadedFunctionDecl>(MemDecl) ||
+ isa<CXXMethodDecl>(MemDecl) ||
+ (isa<FunctionTemplateDecl>(MemDecl) &&
+ isa<CXXMethodDecl>(
+ cast<FunctionTemplateDecl>(MemDecl)->getTemplatedDecl())))
return Owned(BuildCallToMemberFunction(S, Fn, LParenLoc, Args, NumArgs,
CommaLocs, RParenLoc));
+ }
}
// If we're directly calling a function, get the appropriate declaration.
@@ -2645,13 +2650,19 @@
}
OverloadedFunctionDecl *Ovl = 0;
+ FunctionTemplateDecl *FunctionTemplate = 0;
if (DRExpr) {
FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
+ if ((FunctionTemplate = dyn_cast<FunctionTemplateDecl>(DRExpr->getDecl())))
+ FDecl = FunctionTemplate->getTemplatedDecl();
+ else
+ FDecl = dyn_cast<FunctionDecl>(DRExpr->getDecl());
Ovl = dyn_cast<OverloadedFunctionDecl>(DRExpr->getDecl());
NDecl = dyn_cast<NamedDecl>(DRExpr->getDecl());
}
- if (Ovl || (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
+ if (Ovl || FunctionTemplate ||
+ (getLangOptions().CPlusPlus && (FDecl || UnqualifiedName))) {
// We don't perform ADL for implicit declarations of builtins.
if (FDecl && FDecl->getBuiltinID(Context) && FDecl->isImplicit())
ADL = false;
@@ -2660,7 +2671,7 @@
if (!getLangOptions().CPlusPlus)
ADL = false;
- if (Ovl || ADL) {
+ if (Ovl || FunctionTemplate || ADL) {
FDecl = ResolveOverloadedCallFn(Fn, DRExpr? DRExpr->getDecl() : 0,
UnqualifiedName, LParenLoc, Args,
NumArgs, CommaLocs, RParenLoc, ADL);
Modified: cfe/trunk/lib/Sema/SemaLookup.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaLookup.cpp (original)
+++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu Jun 25 17:08:12 2009
@@ -125,21 +125,30 @@
assert(!isa<OverloadedFunctionDecl>(*I) &&
"Cannot have an overloaded function");
- if (isa<FunctionDecl>(*I)) {
+ if ((*I)->isFunctionOrFunctionTemplate()) {
// If we found a function, there might be more functions. If
// so, collect them into an overload set.
DeclIterator Last = I;
OverloadedFunctionDecl *Ovl = 0;
- for (++Last; Last != IEnd && isa<FunctionDecl>(*Last); ++Last) {
+ for (++Last;
+ Last != IEnd && (*Last)->isFunctionOrFunctionTemplate();
+ ++Last) {
if (!Ovl) {
// FIXME: We leak this overload set. Eventually, we want to stop
// building the declarations for these overload sets, so there will be
// nothing to leak.
Ovl = OverloadedFunctionDecl::Create(Context, (*I)->getDeclContext(),
(*I)->getDeclName());
- Ovl->addOverload(cast<FunctionDecl>(*I));
+ if (isa<FunctionDecl>(*I))
+ Ovl->addOverload(cast<FunctionDecl>(*I));
+ else
+ Ovl->addOverload(cast<FunctionTemplateDecl>(*I));
}
- Ovl->addOverload(cast<FunctionDecl>(*Last));
+
+ if (isa<FunctionDecl>(*Last))
+ Ovl->addOverload(cast<FunctionDecl>(*Last));
+ else
+ Ovl->addOverload(cast<FunctionTemplateDecl>(*Last));
}
// If we had more than one function, we built an overload
@@ -206,7 +215,7 @@
if (TagDecl *TD = dyn_cast<TagDecl>(ND)) {
TagFound = Context.getCanonicalDecl(TD);
TagNames += FoundDecls.insert(TagFound)? 1 : 0;
- } else if (isa<FunctionDecl>(ND))
+ } else if (ND->isFunctionOrFunctionTemplate())
Functions += FoundDecls.insert(ND)? 1 : 0;
else
FoundDecls.insert(ND);
@@ -334,10 +343,10 @@
LookupResult Result;
Result.Context = &Context;
- if (F != L && isa<FunctionDecl>(*F)) {
+ if (F != L && (*F)->isFunctionOrFunctionTemplate()) {
IdentifierResolver::iterator Next = F;
++Next;
- if (Next != L && isa<FunctionDecl>(*Next)) {
+ if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
Result.StoredKind = OverloadedDeclFromIdResolver;
Result.First = F.getAsOpaqueValue();
Result.Last = L.getAsOpaqueValue();
@@ -363,10 +372,10 @@
LookupResult Result;
Result.Context = &Context;
- if (F != L && isa<FunctionDecl>(*F)) {
+ if (F != L && (*F)->isFunctionOrFunctionTemplate()) {
DeclContext::lookup_iterator Next = F;
++Next;
- if (Next != L && isa<FunctionDecl>(*Next)) {
+ if (Next != L && (*Next)->isFunctionOrFunctionTemplate()) {
Result.StoredKind = OverloadedDeclFromDeclContext;
Result.First = reinterpret_cast<uintptr_t>(F);
Result.Last = reinterpret_cast<uintptr_t>(L);
@@ -1083,7 +1092,7 @@
// Lookup in a base class succeeded; return these results.
// If we found a function declaration, return an overload set.
- if (isa<FunctionDecl>(*Paths.front().Decls.first))
+ if ((*Paths.front().Decls.first)->isFunctionOrFunctionTemplate())
return LookupResult::CreateLookupResult(Context,
Paths.front().Decls.first, Paths.front().Decls.second);
@@ -1489,7 +1498,9 @@
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
- FunctionDecl *FDecl = cast<FunctionDecl>(*Func);
+ FunctionDecl *FDecl = dyn_cast<FunctionDecl>(*Func);
+ if (!FDecl)
+ FDecl = cast<FunctionTemplateDecl>(*Func)->getTemplatedDecl();
// Add the namespace in which this function was defined. Note
// that, if this is a member function, we do *not* consider the
Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Jun 25 17:08:12 2009
@@ -300,7 +300,9 @@
// This function overloads every function in the overload set.
return true;
- } else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
+ } else if (FunctionTemplateDecl *Old = dyn_cast<FunctionTemplateDecl>(OldD))
+ return IsOverload(New, Old->getTemplatedDecl(), MatchedDecl);
+ else if (FunctionDecl* Old = dyn_cast<FunctionDecl>(OldD)) {
FunctionTemplateDecl *OldTemplate = Old->getDescribedFunctionTemplate();
FunctionTemplateDecl *NewTemplate = New->getDescribedFunctionTemplate();
@@ -2073,7 +2075,9 @@
assert(Proto && "Functions without a prototype cannot be overloaded");
assert(!isa<CXXConversionDecl>(Function) &&
"Use AddConversionCandidate for conversion functions");
-
+ assert(!Function->getDescribedFunctionTemplate() &&
+ "Use AddTemplateOverloadCandidate for function templates");
+
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
if (!isa<CXXConstructorDecl>(Method)) {
// If we get here, it's because we're calling a member function
@@ -2258,6 +2262,42 @@
}
}
+/// \brief Add a C++ function template as a candidate in the candidate set,
+/// using template argument deduction to produce an appropriate function
+/// template specialization.
+void
+Sema::AddTemplateOverloadCandidate(FunctionTemplateDecl *FunctionTemplate,
+ Expr **Args, unsigned NumArgs,
+ OverloadCandidateSet& CandidateSet,
+ bool SuppressUserConversions,
+ bool ForceRValue) {
+ // C++ [over.match.funcs]p7:
+ // In each case where a candidate is a function template, candidate
+ // function template specializations are generated using template argument
+ // deduction (14.8.3, 14.8.2). Those candidates are then handled as
+ // candidate functions in the usual way.113) A given name can refer to one
+ // or more function templates and also to a set of overloaded non-template
+ // functions. In such a case, the candidate functions generated from each
+ // function template are combined with the set of non-template candidate
+ // functions.
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult Result
+ = DeduceTemplateArguments(FunctionTemplate, Args, NumArgs,
+ Specialization, Info)) {
+ // FIXME: Record what happened with template argument deduction, so
+ // that we can give the user a beautiful diagnostic.
+ (void)Result;
+ return;
+ }
+
+ // Add the function template specialization produced by template argument
+ // deduction as a candidate.
+ assert(Specialization && "Missing function template specialization?");
+ AddOverloadCandidate(Specialization, Args, NumArgs, CandidateSet,
+ SuppressUserConversions, ForceRValue);
+}
+
/// AddConversionCandidate - Add a C++ conversion function as a
/// candidate in the candidate set (C++ [over.match.conv],
/// C++ [over.match.copy]). From is the expression we're converting from,
@@ -3678,8 +3718,15 @@
} else if (IsMember)
continue;
- if (FunctionType == Context.getCanonicalType((*Fun)->getType()))
- return *Fun;
+ if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Fun)) {
+ if (FunctionType == Context.getCanonicalType(FunDecl->getType()))
+ return FunDecl;
+ } else {
+ unsigned DiagID
+ = PP.getDiagnostics().getCustomDiagID(Diagnostic::Warning,
+ "Clang does not yet support templated conversion functions");
+ Diag(From->getLocStart(), DiagID);
+ }
}
return 0;
@@ -3724,10 +3771,18 @@
for (OverloadedFunctionDecl::function_iterator Func = Ovl->function_begin(),
FuncEnd = Ovl->function_end();
Func != FuncEnd; ++Func) {
- AddOverloadCandidate(*Func, Args, NumArgs, CandidateSet);
+ DeclContext *Ctx = 0;
+ if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(*Func)) {
+ AddOverloadCandidate(FunDecl, Args, NumArgs, CandidateSet);
+ Ctx = FunDecl->getDeclContext();
+ } else {
+ FunctionTemplateDecl *FunTmpl = cast<FunctionTemplateDecl>(*Func);
+ AddTemplateOverloadCandidate(FunTmpl, Args, NumArgs, CandidateSet);
+ Ctx = FunTmpl->getDeclContext();
+ }
+
- if ((*Func)->getDeclContext()->isRecord() ||
- (*Func)->getDeclContext()->isFunctionOrMethod())
+ if (Ctx->isRecord() || Ctx->isFunctionOrMethod())
ArgumentDependentLookup = false;
}
} else if (FunctionDecl *Func = dyn_cast_or_null<FunctionDecl>(Callee)) {
@@ -3736,7 +3791,13 @@
if (Func->getDeclContext()->isRecord() ||
Func->getDeclContext()->isFunctionOrMethod())
ArgumentDependentLookup = false;
- }
+ } else if (FunctionTemplateDecl *FuncTemplate
+ = dyn_cast_or_null<FunctionTemplateDecl>(Callee)) {
+ AddTemplateOverloadCandidate(FuncTemplate, Args, NumArgs, CandidateSet);
+
+ if (FuncTemplate->getDeclContext()->isRecord())
+ ArgumentDependentLookup = false;
+ }
if (Callee)
UnqualifiedName = Callee->getDeclName();
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jun 25 17:08:12 2009
@@ -79,7 +79,7 @@
for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(),
FEnd = Ovl->function_end();
F != FEnd; ++F) {
- if ((*F)->getDescribedFunctionTemplate()) {
+ if (isa<FunctionTemplateDecl>(*F)) {
TemplateResult = TemplateTy::make(Ovl);
return TNK_Function_template;
}
@@ -1809,8 +1809,8 @@
!isa<TemplateTemplateParmDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
- Diag(Arg->getSourceRange().getBegin(),
- diag::note_template_arg_refers_here_func)
+ Diag(Arg->getLocStart(), diag::err_template_arg_not_class_template);
+ Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
<< Template;
}
@@ -2527,7 +2527,13 @@
DeclPtrTy DP = HandleDeclarator(ParentScope, D,
move(TemplateParameterLists),
/*IsFunctionDefinition=*/true);
- return ActOnStartOfFunctionDef(FnBodyScope, DP);
+ FunctionTemplateDecl *FunctionTemplate
+ = cast_or_null<FunctionTemplateDecl>(DP.getAs<Decl>());
+ if (FunctionTemplate)
+ return ActOnStartOfFunctionDef(FnBodyScope,
+ DeclPtrTy::make(FunctionTemplate->getTemplatedDecl()));
+
+ return DeclPtrTy();
}
// Explicit instantiation of a class template specialization
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Jun 25 17:08:12 2009
@@ -717,6 +717,162 @@
return TDK_Success;
}
+/// \brief Perform template argument deduction from a function call
+/// (C++ [temp.deduct.call]).
+///
+/// \param FunctionTemplate the function template for which we are performing
+/// template argument deduction.
+///
+/// \param Args the function call arguments
+///
+/// \param NumArgs the number of arguments in Args
+///
+/// \param Specialization if template argument deduction was successful,
+/// this will be set to the function template specialization produced by
+/// template argument deduction.
+///
+/// \param Info the argument will be updated to provide additional information
+/// about template argument deduction.
+///
+/// \returns the result of template argument deduction.
+///
+/// FIXME: We will also need to pass in any explicitly-specified template
+/// arguments.
+Sema::TemplateDeductionResult
+Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
+ Expr **Args, unsigned NumArgs,
+ FunctionDecl *&Specialization,
+ TemplateDeductionInfo &Info) {
+ FunctionDecl *Function = FunctionTemplate->getTemplatedDecl();
+
+ // C++ [temp.deduct.call]p1:
+ // Template argument deduction is done by comparing each function template
+ // parameter type (call it P) with the type of the corresponding argument
+ // of the call (call it A) as described below.
+ unsigned CheckArgs = NumArgs;
+ if (NumArgs < Function->getNumParams())
+ return TDK_TooFewArguments;
+ else if (NumArgs > Function->getNumParams()) {
+ const FunctionProtoType *Proto
+ = Function->getType()->getAsFunctionProtoType();
+ if (!Proto->isVariadic())
+ return TDK_TooManyArguments;
+
+ CheckArgs = Function->getNumParams();
+ }
+
+ SFINAETrap Trap(*this);
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(FunctionTemplate->getTemplateParameters()->size());
+ TemplateParameterList *TemplateParams
+ = FunctionTemplate->getTemplateParameters();
+ for (unsigned I = 0; I != CheckArgs; ++I) {
+ QualType ParamType = Function->getParamDecl(I)->getType();
+ QualType ArgType = Args[I]->getType();
+
+ // C++ [temp.deduct.call]p2:
+ // If P is not a reference type:
+ QualType CanonParamType = Context.getCanonicalType(ParamType);
+ if (!isa<ReferenceType>(CanonParamType)) {
+ // - If A is an array type, the pointer type produced by the
+ // array-to-pointer standard conversion (4.2) is used in place of
+ // A for type deduction; otherwise,
+ if (ArgType->isArrayType())
+ ArgType = Context.getArrayDecayedType(ArgType);
+ // - If A is a function type, the pointer type produced by the
+ // function-to-pointer standard conversion (4.3) is used in place
+ // of A for type deduction; otherwise,
+ else if (ArgType->isFunctionType())
+ ArgType = Context.getPointerType(ArgType);
+ else {
+ // - If A is a cv-qualified type, the top level cv-qualifiers of Aâs
+ // type are ignored for type deduction.
+ QualType CanonArgType = Context.getCanonicalType(ArgType);
+ if (CanonArgType.getCVRQualifiers())
+ ArgType = CanonArgType.getUnqualifiedType();
+ }
+ }
+
+ // C++0x [temp.deduct.call]p3:
+ // If P is a cv-qualified type, the top level cv-qualifiers of Pâs type
+ // are ignored for type deduction.
+ if (CanonParamType.getCVRQualifiers())
+ ParamType = CanonParamType.getUnqualifiedType();
+ if (const ReferenceType *ParamRefType = ParamType->getAsReferenceType()) {
+ // [...] If P is a reference type, the type referred to by P is used
+ // for type deduction.
+ ParamType = ParamRefType->getPointeeType();
+
+ // [...] If P is of the form T&&, where T is a template parameter, and
+ // the argument is an lvalue, the type A& is used in place of A for
+ // type deduction.
+ if (isa<RValueReferenceType>(ParamRefType) &&
+ ParamRefType->getAsTemplateTypeParmType() &&
+ Args[I]->isLvalue(Context) == Expr::LV_Valid)
+ ArgType = Context.getLValueReferenceType(ArgType);
+ }
+
+ // C++0x [temp.deduct.call]p4:
+ // In general, the deduction process attempts to find template argument
+ // values that will make the deduced A identical to A (after the type A
+ // is transformed as described above). [...]
+ //
+ // FIXME: we'll pass down a flag to indicate when these cases may apply,
+ // and then deal with them in the code that deduces template
+ // arguments from a type.
+ if (TemplateDeductionResult Result
+ = ::DeduceTemplateArguments(Context, TemplateParams,
+ ParamType, ArgType, Info, Deduced))
+ return Result;
+
+ // FIXME: C++ [temp.deduct.call] paragraphs 6-9 deal with function
+ // pointer parameters.
+ }
+
+ InstantiatingTemplate Inst(*this, FunctionTemplate->getLocation(),
+ FunctionTemplate, Deduced.data(), Deduced.size());
+ if (Inst)
+ return TDK_InstantiationDepth;
+
+ // C++ [temp.deduct.type]p2:
+ // [...] or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ TemplateArgumentListBuilder Builder(TemplateParams, Deduced.size());
+ for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
+ if (Deduced[I].isNull()) {
+ Decl *Param
+ = const_cast<Decl *>(TemplateParams->getParam(I));
+ if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
+ Info.Param = TTP;
+ else if (NonTypeTemplateParmDecl *NTTP
+ = dyn_cast<NonTypeTemplateParmDecl>(Param))
+ Info.Param = NTTP;
+ else
+ Info.Param = cast<TemplateTemplateParmDecl>(Param);
+ return TDK_Incomplete;
+ }
+
+ Builder.Append(Deduced[I]);
+ }
+
+ // Form the template argument list from the deduced template arguments.
+ TemplateArgumentList *DeducedArgumentList
+ = new (Context) TemplateArgumentList(Context, Builder, /*TakeArgs=*/true);
+ Info.reset(DeducedArgumentList);
+
+ // Substitute the deduced template arguments into the function template
+ // declaration to produce the function template specialization.
+ Specialization = cast_or_null<FunctionDecl>(
+ InstantiateDecl(FunctionTemplate->getTemplatedDecl(),
+ FunctionTemplate->getDeclContext(),
+ *DeducedArgumentList));
+
+ if (!Specialization || Trap.hasErrorOccurred())
+ return TDK_SubstitutionFailure;
+
+ return TDK_Success;
+}
+
static void
MarkDeducedTemplateParameters(Sema &SemaRef,
const TemplateArgument &TemplateArg,
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Thu Jun 25 17:08:12 2009
@@ -44,6 +44,7 @@
Decl *VisitStaticAssertDecl(StaticAssertDecl *D);
Decl *VisitEnumDecl(EnumDecl *D);
Decl *VisitEnumConstantDecl(EnumConstantDecl *D);
+ Decl *VisitFunctionDecl(FunctionDecl *D);
Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
Decl *VisitCXXMethodDecl(CXXMethodDecl *D);
Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
@@ -61,6 +62,7 @@
// Helper functions for instantiating methods.
QualType InstantiateFunctionType(FunctionDecl *D,
llvm::SmallVectorImpl<ParmVarDecl *> &Params);
+ bool InitFunctionInstantiation(FunctionDecl *New, FunctionDecl *Tmpl);
bool InitMethodInstantiation(CXXMethodDecl *New, CXXMethodDecl *Tmpl);
};
}
@@ -291,12 +293,47 @@
return Record;
}
-Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
- // Only handle actual methods; we'll deal with constructors,
- // destructors, etc. separately.
- if (D->getKind() != Decl::CXXMethod)
+Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
+ // FIXME: Look for existing specializations (explicit or otherwise).
+
+ Sema::LocalInstantiationScope Scope(SemaRef);
+
+ llvm::SmallVector<ParmVarDecl *, 4> Params;
+ QualType T = InstantiateFunctionType(D, Params);
+ if (T.isNull())
return 0;
+
+ // Build the instantiated method declaration.
+ FunctionDecl *Function
+ = FunctionDecl::Create(SemaRef.Context, Owner, D->getLocation(),
+ D->getDeclName(), T, D->getStorageClass(),
+ D->isInline(), D->hasWrittenPrototype(),
+ D->getTypeSpecStartLoc());
+
+ // FIXME: friend functions
+
+ // Attach the parameters
+ for (unsigned P = 0; P < Params.size(); ++P)
+ Params[P]->setOwningFunction(Function);
+ Function->setParams(SemaRef.Context, Params.data(), Params.size());
+
+ if (InitFunctionInstantiation(Function, D))
+ Function->setInvalidDecl();
+
+ bool Redeclaration = false;
+ bool OverloadableAttrRequired = false;
+ NamedDecl *PrevDecl = 0;
+ SemaRef.CheckFunctionDeclaration(Function, PrevDecl, Redeclaration,
+ /*FIXME:*/OverloadableAttrRequired);
+
+
+ // FIXME: link this to the function template from which it was instantiated.
+
+ return Function;
+}
+Decl *TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D) {
+ // FIXME: Look for existing, explicit specializations.
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -340,6 +377,7 @@
}
Decl *TemplateDeclInstantiator::VisitCXXConstructorDecl(CXXConstructorDecl *D) {
+ // FIXME: Look for existing, explicit specializations.
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -387,6 +425,7 @@
}
Decl *TemplateDeclInstantiator::VisitCXXDestructorDecl(CXXDestructorDecl *D) {
+ // FIXME: Look for existing, explicit specializations.
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -418,6 +457,7 @@
}
Decl *TemplateDeclInstantiator::VisitCXXConversionDecl(CXXConversionDecl *D) {
+ // FIXME: Look for existing, explicit specializations.
Sema::LocalInstantiationScope Scope(SemaRef);
llvm::SmallVector<ParmVarDecl *, 4> Params;
@@ -557,6 +597,18 @@
D->getLocation(), D->getDeclName());
}
+/// \brief Initializes the common fields of an instantiation function
+/// declaration (New) from the corresponding fields of its template (Tmpl).
+///
+/// \returns true if there was an error
+bool
+TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New,
+ FunctionDecl *Tmpl) {
+ if (Tmpl->isDeleted())
+ New->setDeleted();
+ return false;
+}
+
/// \brief Initializes common fields of an instantiated method
/// declaration (New) from the corresponding fields of its template
/// (Tmpl).
@@ -565,6 +617,9 @@
bool
TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
CXXMethodDecl *Tmpl) {
+ if (InitFunctionInstantiation(New, Tmpl))
+ return true;
+
CXXRecordDecl *Record = cast<CXXRecordDecl>(Owner);
New->setAccess(Tmpl->getAccess());
if (Tmpl->isVirtualAsWritten()) {
@@ -573,8 +628,6 @@
Record->setPOD(false);
Record->setPolymorphic(true);
}
- if (Tmpl->isDeleted())
- New->setDeleted();
if (Tmpl->isPure()) {
New->setPure();
Record->setAbstract(true);
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateExpr.cpp Thu Jun 25 17:08:12 2009
@@ -400,7 +400,7 @@
F = Overloads->function_begin(),
FEnd = Overloads->function_end();
F != FEnd; ++F)
- Functions.insert(*F);
+ Functions.insert(cast<FunctionDecl>(*F));
// Add any functions found via argument-dependent lookup.
DeclarationName OpName
Added: 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=74213&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/basic.cpp Thu Jun 25 17:08:12 2009
@@ -0,0 +1,11 @@
+// RUN: clang-cc -fsyntax-only %s
+
+template<typename T> struct A { };
+
+template<typename T> A<T> f0(T*);
+
+void test_f0(int *ip, float const *cfp) {
+ A<int> a0 = f0(ip);
+ A<const float> a1 = f0(cfp);
+}
+
Modified: cfe/trunk/test/Parser/cxx-template-decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx-template-decl.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/test/Parser/cxx-template-decl.cpp (original)
+++ cfe/trunk/test/Parser/cxx-template-decl.cpp Thu Jun 25 17:08:12 2009
@@ -33,8 +33,8 @@
// Forward declarations w/template template parameters
template <template <typename> class T> class TTP1;
template <template <typename> class> class TTP2;
-template <template <typename> class T = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}}
-template <template <typename> class = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}}
+template <template <typename> class T = foo> class TTP3; // expected-error{{must be a class template}}
+template <template <typename> class = foo> class TTP3; // expected-error{{must be a class template}}
template <template <typename X, typename Y> class T> class TTP5;
// Forward declarations with non-type params
Modified: cfe/trunk/test/SemaCXX/template-specialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/template-specialization.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/template-specialization.cpp (original)
+++ cfe/trunk/test/SemaCXX/template-specialization.cpp Thu Jun 25 17:08:12 2009
@@ -1,4 +1,5 @@
// RUN: clang-cc -fsyntax-only -verify %s
+// XFAIL
template<int N> void f(int (&array)[N]);
template<> void f<1>(int (&array)[1]) { }
Modified: cfe/trunk/test/SemaTemplate/temp_arg_template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_arg_template.cpp?rev=74213&r1=74212&r2=74213&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_arg_template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_arg_template.cpp Thu Jun 25 17:08:12 2009
@@ -26,12 +26,12 @@
C<Y> *a7;
C<Ylong> *a8; // expected-error{{template template argument has different template parameters than its corresponding template template parameter}}
-template<typename T> void f(int);
+template<typename T> void f(int); // expected-note{{function template}}
// FIXME: we're right to provide an error message, but it should say
// that we need a class template. We won't get this right until name
// lookup of 'f' returns a TemplateDecl.
-A<f> *a9; // expected-error{{template argument for template template parameter must be a template}}
+A<f> *a9; // expected-error{{template argument does not refer to}}
// FIXME: The code below is ill-formed, because of the evil digraph '<:'.
// We should provide a much better error message than we currently do.
More information about the cfe-commits
mailing list