#include "clang/Basic/IdentifierTable.h"
#include "clang/AST/Type.h"
#include "clang/AST/CanonicalType.h"
+#include "clang/Basic/PartialDiagnostic.h"
namespace llvm {
template <typename T> struct DenseMapInfo;
return DB;
}
-
+/// Insertion operator for partial diagnostics. This allows binding
+/// DeclarationName's into a partial diagnostic with <<.
+inline const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ DeclarationName N) {
+ PD.AddTaggedVal(N.getAsOpaqueInteger(),
+ Diagnostic::ak_declarationname);
+ return PD;
+}
+
} // end namespace clang
namespace llvm {
"non-templated declaration is here">;
def err_explicit_instantiation_out_of_scope : Error<
"explicit instantiation of %0 not in a namespace enclosing %1">;
-
+def err_explicit_instantiation_requires_name : Error<
+ "explicit instantiation declaration requires a name">;
+def err_explicit_instantiation_of_typedef : Error<
+ "explicit instantiation of typedef %0">;
+def err_explicit_instantiation_not_known : Error<
+ "explicit instantiation of %0 does not refer to a function template, member "
+ "function, member class, or static data member">;
+def note_explicit_instantiation_here : Note<
+ "explicit instantiation refers here">;
+def err_explicit_instantiation_data_member_not_instantiated : Error<
+ "explicit instantiation refers to static data member %q0 that is not an "
+ "instantiation">;
+def err_explicit_instantiation_member_function_not_instantiated : Error<
+ "explicit instantiation refers to member function %q0 that is not an "
+ "instantiation">;
+def err_explicit_instantiation_ambiguous : Error<
+ "partial ordering for explicit instantiation of %0 is ambiguous">;
+def note_explicit_instantiation_candidate : Note<
+ "explicit instantiation candidate function template here %0">;
+
// C++ typename-specifiers
def err_typename_nested_not_found : Error<"no type named %0 in %1">;
def err_typename_nested_not_found_global : Error<
#include "clang/AST/Type.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/STLExtras.h"
namespace clang {
+class DeclarationName;
+
class PartialDiagnostic {
struct Storage {
Storage() : NumDiagArgs(0), NumDiagRanges(0) { }
PD.AddSourceRange(R);
return PD;
}
+
+ friend const PartialDiagnostic &operator<<(const PartialDiagnostic &PD,
+ DeclarationName N);
};
inline PartialDiagnostic PDiag(unsigned DiagID) {
return DeclResult();
}
+ /// \brief Process the explicit instantiation of a function template or a
+ /// member of a class template.
+ ///
+ /// This routine is invoked when an explicit instantiation of a
+ /// function template or member function of a class template specialization
+ /// is encountered. In the following example,
+ /// ActOnExplicitInstantiation will be invoked to force the
+ /// instantiation of X<int>:
+ ///
+ /// \code
+ /// template<typename T> void f(T);
+ /// template void f(int); // explicit instantiation
+ /// \endcode
+ ///
+ /// \param S the current scope
+ ///
+ /// \param ExternLoc the location of the 'extern' keyword that specifies that
+ /// this is an extern template (if any).
+ ///
+ /// \param TemplateLoc the location of the 'template' keyword that
+ /// specifies that this is an explicit instantiation.
+ ///
+ /// \param D the declarator describing the declaration to be implicitly
+ /// instantiated.
+ virtual DeclResult ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D) {
+ return DeclResult();
+ }
+
+
/// \brief Called when the parser has parsed a C++ typename
/// specifier that ends in an identifier, e.g., "typename T::type".
///
}
// 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)) {
SourceLocation NameLoc,
AttributeList *Attr);
+ virtual DeclResult ActOnExplicitInstantiation(Scope *S,
+ SourceLocation ExternLoc,
+ SourceLocation TemplateLoc,
+ Declarator &D);
+
bool CheckTemplateArgumentList(TemplateDecl *Template,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
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,
#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;
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,
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]).
// Errors
export class foo { }; // expected-error {{expected template}}
-template x; // expected-error {{C++ requires a type specifier for all declarations}}
+template x; // expected-error {{C++ requires a type specifier for all declarations}} \
+ // expected-error {{does not refer}}
export template x; // expected-error {{expected '<' after 'template'}}
export template<class T> class x0; // expected-note {{exported templates are unsupported}}
template < ; // expected-error {{parse error}} expected-error {{declaration does not declare anything}}
--- /dev/null
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template void *; // expected-error{{expected unqualified-id}}
+
+template typedef void f0; // expected-error{{explicit instantiation of typedef}}
+
+int v0; // expected-note{{refers here}}
+template int v0; // expected-error{{does not refer}}
+
+template<typename T>
+struct X0 {
+ static T value;
+
+ T f0(T x) {
+ return x + 1; // expected-error{{invalid operands}}
+ }
+ T* f0(T*, T*);
+
+ template<typename U>
+ T f0(T, U);
+};
+
+template int X0<int>::value;
+
+struct NotDefaultConstructible {
+ NotDefaultConstructible(int);
+};
+
+template NotDefaultConstructible X0<NotDefaultConstructible>::value;
+
+template int X0<int>::f0(int);
+template int* X0<int>::f0(int*, int*);
+template int X0<int>::f0(int, float);
+
+template int X0<int>::f0(int) const; // expected-error{{does not refer}}
+template int* X0<int>::f0(int*, float*); // expected-error{{does not refer}}
+
+struct X1 { };
+typedef int X1::*MemPtr;
+
+template MemPtr X0<MemPtr>::f0(MemPtr); // expected-note{{requested here}}
+
+struct X2 {
+ int f0(int); // expected-note{{refers here}}
+
+ template<typename T> T f1(T);
+ template<typename T> T* f1(T*);
+
+ template<typename T, typename U> void f2(T, U*); // expected-note{{candidate}}
+ template<typename T, typename U> void f2(T*, U); // expected-note{{candidate}}
+};
+
+template int X2::f0(int); // expected-error{{not an instantiation}}
+
+template int *X2::f1(int *); // okay
+
+template void X2::f2(int *, int *); // expected-error{{ambiguous}}