diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 31 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 14 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 175 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateDeduction.cpp | 118 |
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]). |