forked from OSchip/llvm-project
WIP implementation of explicit function template specialization. This
first implementation recognizes when a function declaration is an explicit function template specialization (based on the presence of a template<> header), performs template argument deduction + ambiguity resolution to determine which template is being specialized, and hooks There are many caveats here: - We completely and totally drop any explicitly-specified template arguments on the floor - We don't diagnose any of the extra semantic things that we should diagnose. - I haven't looked to see that we're getting the right linkage for explicit specializations On a happy note, this silences a bunch of errors that show up in libstdc++'s <iostream>, although Clang still can't get through the entire header. llvm-svn: 82728
This commit is contained in:
parent
d6f9a2f90b
commit
3a923c2d37
|
@ -1081,6 +1081,12 @@ public:
|
|||
TemplateOrSpecialization = Template;
|
||||
}
|
||||
|
||||
/// \brief Determine whether this function is a function template
|
||||
/// specialization.
|
||||
bool isFunctionTemplateSpecialization() const {
|
||||
return getPrimaryTemplate() != 0;
|
||||
}
|
||||
|
||||
/// \brief Retrieve the primary template that this function template
|
||||
/// specialization either specializes or was instantiated from.
|
||||
///
|
||||
|
@ -1105,10 +1111,17 @@ public:
|
|||
///
|
||||
/// \param TemplateArgs the template arguments that produced this
|
||||
/// function template specialization from the template.
|
||||
///
|
||||
/// \param InsertPos If non-NULL, the position in the function template
|
||||
/// specialization set where the function template specialization data will
|
||||
/// be inserted.
|
||||
///
|
||||
/// \param TSK the kind of template specialization this is.
|
||||
void setFunctionTemplateSpecialization(ASTContext &Context,
|
||||
FunctionTemplateDecl *Template,
|
||||
const TemplateArgumentList *TemplateArgs,
|
||||
void *InsertPos);
|
||||
void *InsertPos,
|
||||
TemplateSpecializationKind TSK = TSK_ImplicitInstantiation);
|
||||
|
||||
/// \brief Determine what kind of template instantiation this function
|
||||
/// represents.
|
||||
|
|
|
@ -419,6 +419,9 @@ public:
|
|||
TemplateArgumentListBuilder &Builder,
|
||||
bool TakeArgs);
|
||||
|
||||
/// \brief Produces a shallow copy of the given template argument list
|
||||
TemplateArgumentList(const TemplateArgumentList &Other);
|
||||
|
||||
~TemplateArgumentList();
|
||||
|
||||
/// \brief Retrieve the template argument at a given index.
|
||||
|
|
|
@ -967,6 +967,16 @@ def err_partial_spec_ordering_ambiguous : Error<
|
|||
"ambiguous partial specializations of %0">;
|
||||
def note_partial_spec_match : Note<"partial specialization matches %0">;
|
||||
|
||||
// C++ Function template specializations
|
||||
def err_function_template_spec_no_match : Error<
|
||||
"no function template matches function template specialization %0">;
|
||||
def err_function_template_spec_ambiguous : Error<
|
||||
"function template specialization %0 ambiguously refers to more than one "
|
||||
"function template; explicitly specify%select{|additional }1 template "
|
||||
"arguments to identify a particular function template">;
|
||||
def note_function_template_spec_matched : Note<
|
||||
"function template matches specialization %0">;
|
||||
|
||||
// C++ Template Instantiation
|
||||
def err_template_recursion_depth_exceeded : Error<
|
||||
"recursive template instantiation exceeded maximum depth of %0">,
|
||||
|
|
|
@ -689,7 +689,10 @@ void
|
|||
FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
||||
FunctionTemplateDecl *Template,
|
||||
const TemplateArgumentList *TemplateArgs,
|
||||
void *InsertPos) {
|
||||
void *InsertPos,
|
||||
TemplateSpecializationKind TSK) {
|
||||
assert(TSK != TSK_Undeclared &&
|
||||
"Must specify the type of function template specialization");
|
||||
FunctionTemplateSpecializationInfo *Info
|
||||
= TemplateOrSpecialization.dyn_cast<FunctionTemplateSpecializationInfo*>();
|
||||
if (!Info)
|
||||
|
@ -697,13 +700,24 @@ FunctionDecl::setFunctionTemplateSpecialization(ASTContext &Context,
|
|||
|
||||
Info->Function = this;
|
||||
Info->Template.setPointer(Template);
|
||||
Info->Template.setInt(TSK_ImplicitInstantiation - 1);
|
||||
Info->Template.setInt(TSK - 1);
|
||||
Info->TemplateArguments = TemplateArgs;
|
||||
TemplateOrSpecialization = Info;
|
||||
|
||||
// Insert this function template specialization into the set of known
|
||||
// function template specialiations.
|
||||
Template->getSpecializations().InsertNode(Info, InsertPos);
|
||||
// function template specializations.
|
||||
if (InsertPos)
|
||||
Template->getSpecializations().InsertNode(Info, InsertPos);
|
||||
else {
|
||||
// Try to insert the new node. If there is an existing node, remove it
|
||||
// first.
|
||||
FunctionTemplateSpecializationInfo *Existing
|
||||
= Template->getSpecializations().GetOrInsertNode(Info);
|
||||
if (Existing) {
|
||||
Template->getSpecializations().RemoveNode(Existing);
|
||||
Template->getSpecializations().GetOrInsertNode(Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TemplateSpecializationKind FunctionDecl::getTemplateSpecializationKind() const {
|
||||
|
|
|
@ -373,6 +373,12 @@ TemplateArgumentList::TemplateArgumentList(ASTContext &Context,
|
|||
Builder.ReleaseArgs();
|
||||
}
|
||||
|
||||
TemplateArgumentList::TemplateArgumentList(const TemplateArgumentList &Other)
|
||||
: FlatArguments(Other.FlatArguments.getPointer(), 1),
|
||||
NumFlatArguments(Other.flat_size()),
|
||||
StructuredArguments(Other.StructuredArguments.getPointer(), 1),
|
||||
NumStructuredArguments(Other.NumStructuredArguments) { }
|
||||
|
||||
TemplateArgumentList::~TemplateArgumentList() {
|
||||
// FIXME: Deallocate template arguments
|
||||
}
|
||||
|
|
|
@ -2515,6 +2515,14 @@ public:
|
|||
MultiTemplateParamsArg TemplateParameterLists,
|
||||
Declarator &D);
|
||||
|
||||
bool CheckFunctionTemplateSpecialization(FunctionDecl *FD,
|
||||
bool HasExplicitTemplateArgs,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *ExplicitTemplateArgs,
|
||||
unsigned NumExplicitTemplateArgs,
|
||||
SourceLocation RAngleLoc,
|
||||
NamedDecl *&PrevDecl);
|
||||
|
||||
virtual DeclResult
|
||||
ActOnExplicitInstantiation(Scope *S,
|
||||
SourceLocation ExternLoc,
|
||||
|
|
|
@ -1794,9 +1794,11 @@ Sema::HandleDeclarator(Scope *S, Declarator &D,
|
|||
if (New == 0)
|
||||
return DeclPtrTy();
|
||||
|
||||
// If this has an identifier and is not an invalid redeclaration,
|
||||
// add it to the scope stack.
|
||||
if (Name && !(Redeclaration && New->isInvalidDecl()))
|
||||
// If this has an identifier and is not an invalid redeclaration or
|
||||
// function template specialization, add it to the scope stack.
|
||||
if (Name && !(Redeclaration && New->isInvalidDecl()) &&
|
||||
!(isa<FunctionDecl>(New) &&
|
||||
cast<FunctionDecl>(New)->isFunctionTemplateSpecialization()))
|
||||
PushOnScopeChains(New, S);
|
||||
|
||||
return DeclPtrTy::make(New);
|
||||
|
@ -2516,6 +2518,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
// Match up the template parameter lists with the scope specifier, then
|
||||
// determine whether we have a template or a template specialization.
|
||||
FunctionTemplateDecl *FunctionTemplate = 0;
|
||||
bool isFunctionTemplateSpecialization = false;
|
||||
if (TemplateParameterList *TemplateParams
|
||||
= MatchTemplateParametersToScopeSpecifier(
|
||||
D.getDeclSpec().getSourceRange().getBegin(),
|
||||
|
@ -2536,13 +2539,14 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
FunctionTemplate->setLexicalDeclContext(CurContext);
|
||||
NewFD->setDescribedFunctionTemplate(FunctionTemplate);
|
||||
} else {
|
||||
// FIXME: Handle function template specializations
|
||||
// This is a function template specialization.
|
||||
isFunctionTemplateSpecialization = true;
|
||||
}
|
||||
|
||||
// FIXME: Free this memory properly.
|
||||
TemplateParamLists.release();
|
||||
}
|
||||
|
||||
|
||||
// C++ [dcl.fct.spec]p5:
|
||||
// The virtual specifier shall only be used in declarations of
|
||||
// nonstatic class member functions that appear within a
|
||||
|
@ -2678,6 +2682,18 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC,
|
|||
isOutOfScopePreviousDeclaration(PrevDecl, DC, Context)))
|
||||
PrevDecl = 0;
|
||||
|
||||
// FIXME: If the declarator has a template argument list but
|
||||
// isFunctionTemplateSpecialization is false, this is a function template
|
||||
// specialization but the user forgot the "template<>" header. Complain about
|
||||
// the missing template<> header and set isFunctionTemplateSpecialization.
|
||||
|
||||
if (isFunctionTemplateSpecialization &&
|
||||
CheckFunctionTemplateSpecialization(NewFD,
|
||||
/*FIXME:*/false, SourceLocation(),
|
||||
0, 0, SourceLocation(),
|
||||
PrevDecl))
|
||||
NewFD->setInvalidDecl();
|
||||
|
||||
// Perform semantic checking on the function declaration.
|
||||
bool OverloadableAttrRequired = false; // FIXME: HACK!
|
||||
CheckFunctionDeclaration(NewFD, PrevDecl, Redeclaration,
|
||||
|
|
|
@ -4055,6 +4055,7 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
|||
// resulting template argument list is used to generate a single
|
||||
// function template specialization, which is added to the set of
|
||||
// overloaded functions considered.
|
||||
// FIXME: We don't really want to build the specialization here, do we?
|
||||
FunctionDecl *Specialization = 0;
|
||||
TemplateDeductionInfo Info(Context);
|
||||
if (TemplateDeductionResult Result
|
||||
|
@ -4064,6 +4065,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *From, QualType ToType,
|
|||
// FIXME: make a note of the failed deduction for diagnostics.
|
||||
(void)Result;
|
||||
} else {
|
||||
// FIXME: If the match isn't exact, shouldn't we just drop this as
|
||||
// a candidate? Find a testcase before changing the code.
|
||||
assert(FunctionType
|
||||
== Context.getCanonicalType(Specialization->getType()));
|
||||
Matches.insert(
|
||||
|
|
|
@ -2877,6 +2877,166 @@ Sema::ActOnStartOfFunctionTemplateDef(Scope *FnBodyScope,
|
|||
return DeclPtrTy();
|
||||
}
|
||||
|
||||
/// \brief Perform semantic analysis for the given function template
|
||||
/// specialization.
|
||||
///
|
||||
/// This routine performs all of the semantic analysis required for an
|
||||
/// explicit function template specialization. On successful completion,
|
||||
/// the function declaration \p FD will become a function template
|
||||
/// specialization.
|
||||
///
|
||||
/// \param FD the function declaration, which will be updated to become a
|
||||
/// function template specialization.
|
||||
///
|
||||
/// \param HasExplicitTemplateArgs whether any template arguments were
|
||||
/// explicitly provided.
|
||||
///
|
||||
/// \param LAngleLoc the location of the left angle bracket ('<'), if
|
||||
/// template arguments were explicitly provided.
|
||||
///
|
||||
/// \param ExplicitTemplateArgs the explicitly-provided template arguments,
|
||||
/// if any.
|
||||
///
|
||||
/// \param NumExplicitTemplateArgs the number of explicitly-provided template
|
||||
/// arguments. This number may be zero even when HasExplicitTemplateArgs is
|
||||
/// true as in, e.g., \c void sort<>(char*, char*);
|
||||
///
|
||||
/// \param RAngleLoc the location of the right angle bracket ('>'), if
|
||||
/// template arguments were explicitly provided.
|
||||
///
|
||||
/// \param PrevDecl the set of declarations that
|
||||
bool
|
||||
Sema::CheckFunctionTemplateSpecialization(FunctionDecl *FD,
|
||||
bool HasExplicitTemplateArgs,
|
||||
SourceLocation LAngleLoc,
|
||||
const TemplateArgument *ExplicitTemplateArgs,
|
||||
unsigned NumExplicitTemplateArgs,
|
||||
SourceLocation RAngleLoc,
|
||||
NamedDecl *&PrevDecl) {
|
||||
// The set of function template specializations that could match this
|
||||
// explicit function template specialization.
|
||||
typedef llvm::SmallVector<FunctionDecl *, 8> CandidateSet;
|
||||
CandidateSet Candidates;
|
||||
|
||||
DeclContext *FDLookupContext = FD->getDeclContext()->getLookupContext();
|
||||
for (OverloadIterator Ovl(PrevDecl), OvlEnd; Ovl != OvlEnd; ++Ovl) {
|
||||
if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(*Ovl)) {
|
||||
// Only consider templates found within the same semantic lookup scope as
|
||||
// FD.
|
||||
if (!FDLookupContext->Equals(Ovl->getDeclContext()->getLookupContext()))
|
||||
continue;
|
||||
|
||||
// C++ [temp.expl.spec]p11:
|
||||
// A trailing template-argument can be left unspecified in the
|
||||
// template-id naming an explicit function template specialization
|
||||
// provided it can be deduced from the function argument type.
|
||||
// Perform template argument deduction to determine whether we may be
|
||||
// specializing this template.
|
||||
// FIXME: It is somewhat wasteful to build
|
||||
TemplateDeductionInfo Info(Context);
|
||||
FunctionDecl *Specialization = 0;
|
||||
if (TemplateDeductionResult TDK
|
||||
= DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs,
|
||||
ExplicitTemplateArgs,
|
||||
NumExplicitTemplateArgs,
|
||||
FD->getType(),
|
||||
Specialization,
|
||||
Info)) {
|
||||
// FIXME: Template argument deduction failed; record why it failed, so
|
||||
// that we can provide nifty diagnostics.
|
||||
(void)TDK;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Record this candidate.
|
||||
Candidates.push_back(Specialization);
|
||||
}
|
||||
}
|
||||
|
||||
if (Candidates.empty()) {
|
||||
Diag(FD->getLocation(), diag::err_function_template_spec_no_match)
|
||||
<< FD->getDeclName();
|
||||
// FIXME: Print the almost-ran candidates.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Candidates.size() > 1) {
|
||||
// C++ [temp.func.order]p1:
|
||||
// Partial ordering of overloaded function template declarations is used
|
||||
// [...] when [...] an explicit specialization (14.7.3) refers to a
|
||||
// function template specialization.
|
||||
CandidateSet::iterator Best = Candidates.begin();
|
||||
for (CandidateSet::iterator C = Best + 1, CEnd = Candidates.end();
|
||||
C != CEnd; ++C) {
|
||||
if (getMoreSpecializedTemplate((*Best)->getPrimaryTemplate(),
|
||||
(*C)->getPrimaryTemplate(),
|
||||
TPOC_Other)
|
||||
== (*C)->getPrimaryTemplate())
|
||||
Best = C;
|
||||
}
|
||||
|
||||
bool Ambiguous = false;
|
||||
for (CandidateSet::iterator C = Candidates.begin(), CEnd = Candidates.end();
|
||||
C != CEnd; ++C) {
|
||||
if (C != Best &&
|
||||
getMoreSpecializedTemplate((*Best)->getPrimaryTemplate(),
|
||||
(*C)->getPrimaryTemplate(),
|
||||
TPOC_Other)
|
||||
!= (*Best)->getPrimaryTemplate()) {
|
||||
Ambiguous = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Ambiguous) {
|
||||
// Partial ordering was ambiguous.
|
||||
Diag(FD->getLocation(), diag::err_function_template_spec_ambiguous)
|
||||
<< FD->getDeclName()
|
||||
<< HasExplicitTemplateArgs;
|
||||
|
||||
for (CandidateSet::iterator C = Candidates.begin(),
|
||||
CEnd = Candidates.end();
|
||||
C != CEnd; ++C)
|
||||
Diag((*C)->getLocation(), diag::note_function_template_spec_matched)
|
||||
<< getTemplateArgumentBindingsText(
|
||||
(*C)->getPrimaryTemplate()->getTemplateParameters(),
|
||||
*(*C)->getTemplateSpecializationArgs());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Move the best candidate to the front of the candidates list.
|
||||
std::swap(*Best, Candidates.front());
|
||||
}
|
||||
|
||||
// The first candidate is a prior declaration of the function template
|
||||
// specialization we're declared here, which we may have created above.
|
||||
FunctionDecl *Specialization = Candidates.front();
|
||||
|
||||
// FIXME: Check if the prior specialization has a point of instantiation.
|
||||
// If so, we have run afoul of C++ [temp.expl.spec]p6.
|
||||
|
||||
// Mark the prior declaration as an explicit specialization, so that later
|
||||
// clients know that this is an explicit specialization.
|
||||
// FIXME: Check for prior explicit instantiations?
|
||||
Specialization->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
|
||||
|
||||
// Turn the given function declaration into a function template
|
||||
// specialization, with the template arguments from the previous
|
||||
// specialization.
|
||||
FD->setFunctionTemplateSpecialization(Context,
|
||||
Specialization->getPrimaryTemplate(),
|
||||
new (Context) TemplateArgumentList(
|
||||
*Specialization->getTemplateSpecializationArgs()),
|
||||
/*InsertPos=*/0,
|
||||
TSK_ExplicitSpecialization);
|
||||
|
||||
// The "previous declaration" for this function template specialization is
|
||||
// the prior function template specialization.
|
||||
PrevDecl = Specialization;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Explicit instantiation of a class template specialization
|
||||
// FIXME: Implement extern template semantics
|
||||
Sema::DeclResult
|
||||
|
|
|
@ -1436,7 +1436,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate,
|
|||
}
|
||||
|
||||
/// \brief Deduce template arguments when taking the address of a function
|
||||
/// template (C++ [temp.deduct.funcaddr]).
|
||||
/// template (C++ [temp.deduct.funcaddr]) or matching a
|
||||
///
|
||||
/// \param FunctionTemplate the function template for which we are performing
|
||||
/// template argument deduction.
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
// RUN: clang-cc -fsyntax-only -verify %s
|
||||
|
||||
template<int N> void f0(int (&array)[N]);
|
||||
|
||||
// Simple function template specialization (using overloading)
|
||||
template<> void f0(int (&array)[1]);
|
||||
|
||||
void test_f0() {
|
||||
int iarr1[1];
|
||||
f0(iarr1);
|
||||
}
|
||||
|
||||
// Function template specialization where there are no matches
|
||||
template<> void f0(char (&array)[1]); // expected-error{{no function template matches}}
|
||||
|
||||
// Function template specialization that requires partial ordering
|
||||
template<typename T, int N> void f1(T (&array)[N]); // expected-note{{matches}}
|
||||
template<int N> void f1(int (&array)[N]); // expected-note{{matches}}
|
||||
|
||||
template<> void f1(float (&array)[1]);
|
||||
template<> void f1(int (&array)[1]);
|
||||
|
||||
// Function template specialization that results in an ambiguity
|
||||
template<typename T> void f1(T (&array)[17]); // expected-note{{matches}}
|
||||
template<> void f1(int (&array)[17]); // expected-error{{ambiguous}}
|
Loading…
Reference in New Issue