diff options
Diffstat (limited to 'clang/lib/Sema')
| -rw-r--r-- | clang/lib/Sema/Sema.h | 14 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 175 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplateDeduction.cpp | 118 |
3 files changed, 307 insertions, 0 deletions
diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 8377d509391..56f4693cd24 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/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/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 509237a855a..37fbf453742 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/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/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index b5aa075bd64..64b7f8b140e 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/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]). |

