aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Parse/ParseDecl.cpp31
-rw-r--r--lib/Sema/Sema.h14
-rw-r--r--lib/Sema/SemaTemplate.cpp175
-rw-r--r--lib/Sema/SemaTemplateDeduction.cpp118
4 files changed, 334 insertions, 4 deletions
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 75ff82772a..9525eb364c 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -419,13 +419,36 @@ Parser::DeclPtrTy Parser::ParseDeclarationAfterDeclarator(Declarator &D,
}
// Inform the current actions module that we just parsed this declarator.
- DeclPtrTy ThisDecl = TemplateInfo.TemplateParams?
- Actions.ActOnTemplateDeclarator(CurScope,
+ DeclPtrTy ThisDecl;
+ switch (TemplateInfo.Kind) {
+ case ParsedTemplateInfo::NonTemplate:
+ ThisDecl = Actions.ActOnDeclarator(CurScope, D);
+ break;
+
+ case ParsedTemplateInfo::Template:
+ case ParsedTemplateInfo::ExplicitSpecialization:
+ ThisDecl = Actions.ActOnTemplateDeclarator(CurScope,
Action::MultiTemplateParamsArg(Actions,
TemplateInfo.TemplateParams->data(),
TemplateInfo.TemplateParams->size()),
- D)
- : Actions.ActOnDeclarator(CurScope, D);
+ D);
+ break;
+
+ case ParsedTemplateInfo::ExplicitInstantiation: {
+ Action::DeclResult ThisRes
+ = Actions.ActOnExplicitInstantiation(CurScope,
+ TemplateInfo.ExternLoc,
+ TemplateInfo.TemplateLoc,
+ D);
+ if (ThisRes.isInvalid()) {
+ SkipUntil(tok::semi, true, true);
+ return DeclPtrTy();
+ }
+
+ ThisDecl = ThisRes.get();
+ break;
+ }
+ }
// Parse declarator '=' initializer.
if (Tok.is(tok::equal)) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 8377d50939..56f4693cd2 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2550,6 +2550,11 @@ public:
SourceLocation NameLoc,
AttributeList *Attr);
+ virtual DeclResult ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D);
+
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
@@ -2779,6 +2784,15 @@ public:
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC);
+ FunctionDecl *getMostSpecialized(FunctionDecl **Specializations,
+ unsigned NumSpecializations,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag,
+ unsigned *Index = 0);
+
ClassTemplatePartialSpecializationDecl *
getMoreSpecializedPartialSpecialization(
ClassTemplatePartialSpecializationDecl *PS1,
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 509237a855..37fbf45374 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -17,6 +17,7 @@
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/Support/Compiler.h"
#include "llvm/ADT/StringExtras.h"
using namespace clang;
@@ -3326,6 +3327,180 @@ Sema::ActOnExplicitInstantiation(Scope *S,
return TagD;
}
+Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D) {
+ // Explicit instantiations always require a name.
+ DeclarationName Name = GetNameForDeclarator(D);
+ if (!Name) {
+ if (!D.isInvalidType())
+ Diag(D.getDeclSpec().getSourceRange().getBegin(),
+ diag::err_explicit_instantiation_requires_name)
+ << D.getDeclSpec().getSourceRange()
+ << D.getSourceRange();
+
+ return true;
+ }
+
+ // The scope passed in may not be a decl scope. Zip up the scope tree until
+ // we find one that is.
+ while ((S->getFlags() & Scope::DeclScope) == 0 ||
+ (S->getFlags() & Scope::TemplateParamScope) != 0)
+ S = S->getParent();
+
+ // Determine the type of the declaration.
+ QualType R = GetTypeForDeclarator(D, S, 0);
+ if (R.isNull())
+ return true;
+
+ if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
+ // Cannot explicitly instantiate a typedef.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef)
+ << Name;
+ return true;
+ }
+
+ // Determine what kind of explicit instantiation we have.
+ TemplateSpecializationKind TSK
+ = ExternLoc.isInvalid()? TSK_ExplicitInstantiationDefinition
+ : TSK_ExplicitInstantiationDeclaration;
+
+ LookupResult Previous = LookupParsedName(S, &D.getCXXScopeSpec(),
+ Name, LookupOrdinaryName);
+
+ if (!R->isFunctionType()) {
+ // C++ [temp.explicit]p1:
+ // A [...] static data member of a class template can be explicitly
+ // instantiated from the member definition associated with its class
+ // template.
+ if (Previous.isAmbiguous()) {
+ return DiagnoseAmbiguousLookup(Previous, Name, D.getIdentifierLoc(),
+ D.getSourceRange());
+ }
+
+ VarDecl *Prev = dyn_cast_or_null<VarDecl>(Previous.getAsDecl());
+ if (!Prev || !Prev->isStaticDataMember()) {
+ // We expect to see a data data member here.
+ Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_not_known)
+ << Name;
+ for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+ P != PEnd; ++P)
+ Diag(P->getLocation(), diag::note_explicit_instantiation_here);
+ return true;
+ }
+
+ if (!Prev->getInstantiatedFromStaticDataMember()) {
+ // FIXME: Check for explicit specialization?
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_data_member_not_instantiated)
+ << Prev;
+ Diag(Prev->getLocation(), diag::note_explicit_instantiation_here);
+ // FIXME: Can we provide a note showing where this was declared?
+ return true;
+ }
+
+ // Instantiate static data member.
+ // FIXME: Note that this is an explicit instantiation.
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateStaticDataMemberDefinition(D.getIdentifierLoc(), Prev, false);
+
+ // FIXME: Create an ExplicitInstantiation node?
+ return DeclPtrTy();
+ }
+
+ // C++ [temp.explicit]p1:
+ // A [...] function [...] can be explicitly instantiated from its template.
+ // A member function [...] of a class template can be explicitly
+ // instantiated from the member definition associated with its class
+ // template.
+ // FIXME: Implement this!
+ llvm::SmallVector<FunctionDecl *, 8> Matches;
+ for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end();
+ P != PEnd; ++P) {
+ NamedDecl *Prev = *P;
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) {
+ // FIXME: If there were any explicitly-specified template arguments,
+ // don't look for Method declarations.
+ if (Context.hasSameUnqualifiedType(Method->getType(), R)) {
+ Matches.clear();
+ Matches.push_back(Method);
+ break;
+ }
+ }
+
+ FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Prev);
+ if (!FunTmpl)
+ continue;
+
+ TemplateDeductionInfo Info(Context);
+ FunctionDecl *Specialization = 0;
+ if (TemplateDeductionResult TDK
+ = DeduceTemplateArguments(FunTmpl, /*FIXME:*/false, 0, 0,
+ R, Specialization, Info)) {
+ // FIXME: Keep track of almost-matches?
+ (void)TDK;
+ continue;
+ }
+
+ Matches.push_back(Specialization);
+ }
+
+ // Find the most specialized function template specialization.
+ FunctionDecl *Specialization
+ = getMostSpecialized(Matches.data(), Matches.size(), TPOC_Other,
+ D.getIdentifierLoc(),
+ PartialDiagnostic(diag::err_explicit_instantiation_not_known) << Name,
+ PartialDiagnostic(diag::err_explicit_instantiation_ambiguous) << Name,
+ PartialDiagnostic(diag::note_explicit_instantiation_candidate));
+
+ if (!Specialization)
+ return true;
+
+ switch (Specialization->getTemplateSpecializationKind()) {
+ case TSK_Undeclared:
+ Diag(D.getIdentifierLoc(),
+ diag::err_explicit_instantiation_member_function_not_instantiated)
+ << Specialization
+ << (Specialization->getTemplateSpecializationKind() ==
+ TSK_ExplicitSpecialization);
+ Diag(Specialization->getLocation(), diag::note_explicit_instantiation_here);
+ return true;
+
+ case TSK_ExplicitSpecialization:
+ // C++ [temp.explicit]p4:
+ // For a given set of template parameters, if an explicit instantiation
+ // of a template appears after a declaration of an explicit
+ // specialization for that template, the explicit instantiation has no
+ // effect.
+ break;
+
+ case TSK_ExplicitInstantiationDefinition:
+ // FIXME: Check that we aren't trying to perform an explicit instantiation
+ // declaration now.
+ // Fall through
+
+ case TSK_ImplicitInstantiation:
+ case TSK_ExplicitInstantiationDeclaration:
+ // Instantiate the function, if this is an explicit instantiation
+ // definition.
+ if (TSK == TSK_ExplicitInstantiationDefinition)
+ InstantiateFunctionDefinition(D.getIdentifierLoc(), Specialization,
+ false);
+
+ // FIXME: setTemplateSpecializationKind doesn't (yet) work for
+ // non-templated member functions.
+ if (!Specialization->getPrimaryTemplate())
+ break;
+
+ Specialization->setTemplateSpecializationKind(TSK);
+ break;
+ }
+
+ // FIXME: Create some kind of ExplicitInstantiationDecl here.
+ return DeclPtrTy();
+}
+
Sema::TypeResult
Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
const CXXScopeSpec &SS, IdentifierInfo *Name,
diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp
index b5aa075bd6..64b7f8b140 100644
--- a/lib/Sema/SemaTemplateDeduction.cpp
+++ b/lib/Sema/SemaTemplateDeduction.cpp
@@ -1885,6 +1885,124 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
return 0;
}
+/// \brief Determine if the two templates are equivalent.
+static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
+ if (T1 == T2)
+ return true;
+
+ if (!T1 || !T2)
+ return false;
+
+ return T1->getCanonicalDecl() == T2->getCanonicalDecl();
+}
+
+/// \brief Retrieve the most specialized of the given function template
+/// specializations.
+///
+/// \param Specializations the set of function template specializations that
+/// we will be comparing.
+///
+/// \param NumSpecializations the number of function template specializations in
+/// \p Specializations
+///
+/// \param TPOC the partial ordering context to use to compare the function
+/// template specializations.
+///
+/// \param Loc the location where the ambiguity or no-specializations
+/// diagnostic should occur.
+///
+/// \param NoneDiag partial diagnostic used to diagnose cases where there are
+/// no matching candidates.
+///
+/// \param AmbigDiag partial diagnostic used to diagnose an ambiguity, if one
+/// occurs.
+///
+/// \param CandidateDiag partial diagnostic used for each function template
+/// specialization that is a candidate in the ambiguous ordering. One parameter
+/// in this diagnostic should be unbound, which will correspond to the string
+/// describing the template arguments for the function template specialization.
+///
+/// \param Index if non-NULL and the result of this function is non-nULL,
+/// receives the index corresponding to the resulting function template
+/// specialization.
+///
+/// \returns the most specialized function template specialization, if
+/// found. Otherwise, returns NULL.
+///
+/// \todo FIXME: Consider passing in the "also-ran" candidates that failed
+/// template argument deduction.
+FunctionDecl *Sema::getMostSpecialized(FunctionDecl **Specializations,
+ unsigned NumSpecializations,
+ TemplatePartialOrderingContext TPOC,
+ SourceLocation Loc,
+ const PartialDiagnostic &NoneDiag,
+ const PartialDiagnostic &AmbigDiag,
+ const PartialDiagnostic &CandidateDiag,
+ unsigned *Index) {
+ if (NumSpecializations == 0) {
+ Diag(Loc, NoneDiag);
+ return 0;
+ }
+
+ if (NumSpecializations == 1) {
+ if (Index)
+ *Index = 0;
+
+ return Specializations[0];
+ }
+
+
+ // Find the function template that is better than all of the templates it
+ // has been compared to.
+ unsigned Best = 0;
+ FunctionTemplateDecl *BestTemplate
+ = Specializations[Best]->getPrimaryTemplate();
+ assert(BestTemplate && "Not a function template specialization?");
+ for (unsigned I = 1; I != NumSpecializations; ++I) {
+ FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ assert(Challenger && "Not a function template specialization?");
+ if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
+ TPOC),
+ Challenger)) {
+ Best = I;
+ BestTemplate = Challenger;
+ }
+ }
+
+ // Make sure that the "best" function template is more specialized than all
+ // of the others.
+ bool Ambiguous = false;
+ for (unsigned I = 0; I != NumSpecializations; ++I) {
+ FunctionTemplateDecl *Challenger = Specializations[I]->getPrimaryTemplate();
+ if (I != Best &&
+ !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
+ TPOC),
+ BestTemplate)) {
+ Ambiguous = true;
+ break;
+ }
+ }
+
+ if (!Ambiguous) {
+ // We found an answer. Return it.
+ if (Index)
+ *Index = Best;
+ return Specializations[Best];
+ }
+
+ // Diagnose the ambiguity.
+ Diag(Loc, AmbigDiag);
+
+ // FIXME: Can we order the candidates in some sane way?
+ for (unsigned I = 0; I != NumSpecializations; ++I)
+ Diag(Specializations[I]->getLocation(), CandidateDiag)
+ << getTemplateArgumentBindingsText(
+ Specializations[I]->getPrimaryTemplate()->getTemplateParameters(),
+ *Specializations[I]->getTemplateSpecializationArgs());
+
+ return 0;
+}
+
/// \brief Returns the more specialized class template partial specialization
/// according to the rules of partial ordering of class template partial
/// specializations (C++ [temp.class.order]).