[cfe-commits] r81866 - in /cfe/trunk: include/clang/AST/DeclTemplate.h include/clang/Basic/DiagnosticSemaKinds.td lib/AST/DeclTemplate.cpp lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp lib/Sema/SemaTemplateInstantiateDecl.cpp test/SemaTemplate/temp_class_order.cpp test/SemaTemplate/temp_class_spec.cpp
Douglas Gregor
dgregor at apple.com
Tue Sep 15 09:23:52 PDT 2009
Author: dgregor
Date: Tue Sep 15 11:23:51 2009
New Revision: 81866
URL: http://llvm.org/viewvc/llvm-project?rev=81866&view=rev
Log:
Implement partial ordering of class template partial specializations
(C++ [temp.class.order]).
Added:
cfe/trunk/test/SemaTemplate/temp_class_order.cpp (with props)
Modified:
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
cfe/trunk/lib/AST/DeclTemplate.cpp
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
cfe/trunk/test/SemaTemplate/temp_class_spec.cpp
Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Tue Sep 15 11:23:51 2009
@@ -49,38 +49,38 @@
unsigned NumParams;
TemplateParameterList(SourceLocation TemplateLoc, SourceLocation LAngleLoc,
- Decl **Params, unsigned NumParams,
+ NamedDecl **Params, unsigned NumParams,
SourceLocation RAngleLoc);
public:
static TemplateParameterList *Create(ASTContext &C,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- Decl **Params,
+ NamedDecl **Params,
unsigned NumParams,
SourceLocation RAngleLoc);
/// iterator - Iterates through the template parameters in this list.
- typedef Decl** iterator;
+ typedef NamedDecl** iterator;
/// const_iterator - Iterates through the template parameters in this list.
- typedef Decl* const* const_iterator;
+ typedef NamedDecl* const* const_iterator;
- iterator begin() { return reinterpret_cast<Decl **>(this + 1); }
+ iterator begin() { return reinterpret_cast<NamedDecl **>(this + 1); }
const_iterator begin() const {
- return reinterpret_cast<Decl * const *>(this + 1);
+ return reinterpret_cast<NamedDecl * const *>(this + 1);
}
iterator end() { return begin() + NumParams; }
const_iterator end() const { return begin() + NumParams; }
unsigned size() const { return NumParams; }
- Decl* getParam(unsigned Idx) {
+ NamedDecl* getParam(unsigned Idx) {
assert(Idx < size() && "Template parameter index out-of-range");
return begin()[Idx];
}
- const Decl* getParam(unsigned Idx) const {
+ const NamedDecl* getParam(unsigned Idx) const {
assert(Idx < size() && "Template parameter index out-of-range");
return begin()[Idx];
}
Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Tue Sep 15 11:23:51 2009
@@ -955,9 +955,9 @@
"deduced; this partial specialization will never be used">;
def note_partial_spec_unused_parameter : Note<
"non-deducible template parameter %0">;
-def unsup_template_partial_spec_ordering : Error<
- "partial ordering of class template partial specializations is not yet "
- "supported">;
+def err_partial_spec_ordering_ambiguous : Error<
+ "ambiguous partial specializations of %0">;
+def note_partial_spec_match : Note<"partial specialization matches %0">;
// C++ Template Instantiation
def err_template_recursion_depth_exceeded : Error<
Modified: cfe/trunk/lib/AST/DeclTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclTemplate.cpp?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclTemplate.cpp (original)
+++ cfe/trunk/lib/AST/DeclTemplate.cpp Tue Sep 15 11:23:51 2009
@@ -25,7 +25,7 @@
TemplateParameterList::TemplateParameterList(SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
- Decl **Params, unsigned NumParams,
+ NamedDecl **Params, unsigned NumParams,
SourceLocation RAngleLoc)
: TemplateLoc(TemplateLoc), LAngleLoc(LAngleLoc), RAngleLoc(RAngleLoc),
NumParams(NumParams) {
@@ -35,9 +35,10 @@
TemplateParameterList *
TemplateParameterList::Create(ASTContext &C, SourceLocation TemplateLoc,
- SourceLocation LAngleLoc, Decl **Params,
+ SourceLocation LAngleLoc, NamedDecl **Params,
unsigned NumParams, SourceLocation RAngleLoc) {
- unsigned Size = sizeof(TemplateParameterList) + sizeof(Decl *) * NumParams;
+ unsigned Size = sizeof(TemplateParameterList)
+ + sizeof(NamedDecl *) * NumParams;
unsigned Align = llvm::AlignOf<TemplateParameterList>::Alignment;
void *Mem = C.Allocate(Size, Align);
return new (Mem) TemplateParameterList(TemplateLoc, LAngleLoc, Params,
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Tue Sep 15 11:23:51 2009
@@ -2568,6 +2568,10 @@
QualType RebuildTypeInCurrentInstantiation(QualType T, SourceLocation Loc,
DeclarationName Name);
+ std::string
+ getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgumentList &Args);
+
/// \brief Describes the result of template argument deduction.
///
/// The TemplateDeductionResult enumeration describes the result of
@@ -2732,7 +2736,11 @@
FunctionTemplateDecl *getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC);
-
+ ClassTemplatePartialSpecializationDecl *
+ getMoreSpecializedPartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *PS1,
+ ClassTemplatePartialSpecializationDecl *PS2);
+
void MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs,
bool OnlyDeduced,
llvm::SmallVectorImpl<bool> &Deduced);
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Sep 15 11:23:51 2009
@@ -18,7 +18,7 @@
#include "clang/Parse/DeclSpec.h"
#include "clang/Basic/LangOptions.h"
#include "llvm/Support/Compiler.h"
-
+#include "llvm/ADT/StringExtras.h"
using namespace clang;
/// \brief Determine whether the declaration found is acceptable as the name
@@ -537,7 +537,8 @@
Diag(ExportLoc, diag::note_template_export_unsupported);
return TemplateParameterList::Create(Context, TemplateLoc, LAngleLoc,
- (Decl**)Params, NumParams, RAngleLoc);
+ (NamedDecl**)Params, NumParams,
+ RAngleLoc);
}
Sema::DeclResult
@@ -3423,3 +3424,78 @@
CurrentInstantiationRebuilder Rebuilder(*this, Loc, Name);
return Rebuilder.TransformType(T);
}
+
+/// \brief Produces a formatted string that describes the binding of
+/// template parameters to template arguments.
+std::string
+Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params,
+ const TemplateArgumentList &Args) {
+ std::string Result;
+
+ if (!Params || Params->size() == 0)
+ return Result;
+
+ for (unsigned I = 0, N = Params->size(); I != N; ++I) {
+ if (I == 0)
+ Result += "[with ";
+ else
+ Result += ", ";
+
+ if (const IdentifierInfo *Id = Params->getParam(I)->getIdentifier()) {
+ Result += Id->getName();
+ } else {
+ Result += '$';
+ Result += llvm::utostr(I);
+ }
+
+ Result += " = ";
+
+ switch (Args[I].getKind()) {
+ case TemplateArgument::Null:
+ Result += "<no value>";
+ break;
+
+ case TemplateArgument::Type: {
+ std::string TypeStr;
+ Args[I].getAsType().getAsStringInternal(TypeStr,
+ Context.PrintingPolicy);
+ Result += TypeStr;
+ break;
+ }
+
+ case TemplateArgument::Declaration: {
+ bool Unnamed = true;
+ if (NamedDecl *ND = dyn_cast_or_null<NamedDecl>(Args[I].getAsDecl())) {
+ if (ND->getDeclName()) {
+ Unnamed = false;
+ Result += ND->getNameAsString();
+ }
+ }
+
+ if (Unnamed) {
+ Result += "<anonymous>";
+ }
+ break;
+ }
+
+ case TemplateArgument::Integral: {
+ Result += Args[I].getAsIntegral()->toString(10);
+ break;
+ }
+
+ case TemplateArgument::Expression: {
+ assert(false && "No expressions in deduced template arguments!");
+ Result += "<expression>";
+ break;
+ }
+
+ case TemplateArgument::Pack:
+ // FIXME: Format template argument packs
+ Result += "<template argument pack>";
+ break;
+ }
+ }
+
+ Result += ']';
+ return Result;
+}
Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Tue Sep 15 11:23:51 2009
@@ -949,7 +949,8 @@
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
Decl *Param
- = const_cast<Decl *>(Partial->getTemplateParameters()->getParam(I));
+ = const_cast<NamedDecl *>(
+ Partial->getTemplateParameters()->getParam(I));
if (TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
Info.Param = TTP;
else if (NonTypeTemplateParmDecl *NTTP
@@ -976,7 +977,7 @@
ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate();
const TemplateArgumentList &PartialTemplateArgs = Partial->getTemplateArgs();
for (unsigned I = 0, N = PartialTemplateArgs.flat_size(); I != N; ++I) {
- Decl *Param = const_cast<Decl *>(
+ Decl *Param = const_cast<NamedDecl *>(
ClassTemplate->getTemplateParameters()->getParam(I));
TemplateArgument InstArg
= Subst(PartialTemplateArgs[I],
@@ -1199,7 +1200,7 @@
for (unsigned I = 0, N = Deduced.size(); I != N; ++I) {
if (Deduced[I].isNull()) {
Info.Param = makeTemplateParameter(
- const_cast<Decl *>(TemplateParams->getParam(I)));
+ const_cast<NamedDecl *>(TemplateParams->getParam(I)));
return TDK_Incomplete;
}
@@ -1796,7 +1797,7 @@
}
-/// \brief Returns the more specialization function template according
+/// \brief Returns the more specialized function template according
/// to the rules of function template partial ordering (C++ [temp.func.order]).
///
/// \param FT1 the first function template
@@ -1806,13 +1807,12 @@
/// \param TPOC the context in which we are performing partial ordering of
/// function templates.
///
-/// \returns the more specialization function template. If neither
+/// \returns the more specialized function template. If neither
/// template is more specialized, returns NULL.
FunctionTemplateDecl *
Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1,
FunctionTemplateDecl *FT2,
TemplatePartialOrderingContext TPOC) {
- // FIXME: Implement this
llvm::SmallVector<DeductionQualifierComparison, 4> QualifierComparisons;
bool Better1 = isAtLeastAsSpecializedAs(*this, FT1, FT2, TPOC, 0);
bool Better2 = isAtLeastAsSpecializedAs(*this, FT2, FT1, TPOC,
@@ -1869,6 +1869,70 @@
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]).
+///
+/// \param PS1 the first class template partial specialization
+///
+/// \param PS2 the second class template partial specialization
+///
+/// \returns the more specialized class template partial specialization. If
+/// neither partial specialization is more specialized, returns NULL.
+ClassTemplatePartialSpecializationDecl *
+Sema::getMoreSpecializedPartialSpecialization(
+ ClassTemplatePartialSpecializationDecl *PS1,
+ ClassTemplatePartialSpecializationDecl *PS2) {
+ // C++ [temp.class.order]p1:
+ // For two class template partial specializations, the first is at least as
+ // specialized as the second if, given the following rewrite to two
+ // function templates, the first function template is at least as
+ // specialized as the second according to the ordering rules for function
+ // templates (14.6.6.2):
+ // - the first function template has the same template parameters as the
+ // first partial specialization and has a single function parameter
+ // whose type is a class template specialization with the template
+ // arguments of the first partial specialization, and
+ // - the second function template has the same template parameters as the
+ // second partial specialization and has a single function parameter
+ // whose type is a class template specialization with the template
+ // arguments of the second partial specialization.
+ //
+ // Rather than synthesize function templates, we merely perform the
+ // equivalent partial ordering by performing deduction directly on the
+ // template arguments of the class template partial specializations. This
+ // computation is slightly simpler than the general problem of function
+ // template partial ordering, because class template partial specializations
+ // are more constrained. We know that every template parameter is deduc
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Sema::TemplateDeductionInfo Info(Context);
+
+ // Determine whether PS1 is at least as specialized as PS2
+ Deduced.resize(PS2->getTemplateParameters()->size());
+ bool Better1 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ PS2->getTemplateParameters(),
+ Context.getTypeDeclType(PS2),
+ Context.getTypeDeclType(PS1),
+ Info,
+ Deduced,
+ 0);
+
+ // Determine whether PS2 is at least as specialized as PS1
+ Deduced.resize(PS1->getTemplateParameters()->size());
+ bool Better2 = !DeduceTemplateArgumentsDuringPartialOrdering(Context,
+ PS1->getTemplateParameters(),
+ Context.getTypeDeclType(PS1),
+ Context.getTypeDeclType(PS2),
+ Info,
+ Deduced,
+ 0);
+
+ if (Better1 == Better2)
+ return 0;
+
+ return Better1? PS1 : PS2;
+}
+
static void
MarkUsedTemplateParameters(Sema &SemaRef,
const TemplateArgument &TemplateArg,
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Tue Sep 15 11:23:51 2009
@@ -888,17 +888,50 @@
// specialized than all of the other matching
// specializations, then the use of the class template is
// ambiguous and the program is ill-formed.
- // FIXME: Implement partial ordering of class template partial
- // specializations.
- Diag(ClassTemplateSpec->getLocation(),
- diag::unsup_template_partial_spec_ordering);
-
- // FIXME: Temporary hack to fall back to the primary template
- ClassTemplateDecl *OrigTemplate = Template;
- while (OrigTemplate->getInstantiatedFromMemberTemplate())
- OrigTemplate = OrigTemplate->getInstantiatedFromMemberTemplate();
+ llvm::SmallVector<MatchResult, 4>::iterator Best = Matched.begin();
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Best + 1,
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ == P->first)
+ Best = P;
+ }
+
+ // Determine if the best partial specialization is more specialized than
+ // the others.
+ bool Ambiguous = false;
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P) {
+ if (P != Best &&
+ getMoreSpecializedPartialSpecialization(P->first, Best->first)
+ != Best->first) {
+ Ambiguous = true;
+ break;
+ }
+ }
+
+ if (Ambiguous) {
+ // Partial ordering did not produce a clear winner. Complain.
+ ClassTemplateSpec->setInvalidDecl();
+ Diag(ClassTemplateSpec->getPointOfInstantiation(),
+ diag::err_partial_spec_ordering_ambiguous)
+ << ClassTemplateSpec;
+
+ // Print the matching partial specializations.
+ for (llvm::SmallVector<MatchResult, 4>::iterator P = Matched.begin(),
+ PEnd = Matched.end();
+ P != PEnd; ++P)
+ Diag(P->first->getLocation(), diag::note_partial_spec_match)
+ << getTemplateArgumentBindingsText(P->first->getTemplateParameters(),
+ *P->second);
- Pattern = OrigTemplate->getTemplatedDecl();
+ return true;
+ }
+
+ // Instantiate using the best class template partial specialization.
+ Pattern = Best->first;
+ ClassTemplateSpec->setInstantiationOf(Best->first, Best->second);
} else {
// -- If no matches are found, the instantiation is generated
// from the primary template.
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Tue Sep 15 11:23:51 2009
@@ -797,12 +797,12 @@
bool Invalid = false;
unsigned N = L->size();
- typedef llvm::SmallVector<Decl*,8> ParamVector;
+ typedef llvm::SmallVector<NamedDecl *, 8> ParamVector;
ParamVector Params;
Params.reserve(N);
for (TemplateParameterList::iterator PI = L->begin(), PE = L->end();
PI != PE; ++PI) {
- Decl *D = Visit(*PI);
+ NamedDecl *D = cast_or_null<NamedDecl>(Visit(*PI));
Params.push_back(D);
Invalid = Invalid || !D;
}
Added: cfe/trunk/test/SemaTemplate/temp_class_order.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_order.cpp?rev=81866&view=auto
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_order.cpp (added)
+++ cfe/trunk/test/SemaTemplate/temp_class_order.cpp Tue Sep 15 11:23:51 2009
@@ -0,0 +1,42 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+template<typename T, typename U>
+struct X1 {
+ static const int value = 0;
+};
+
+template<typename T, typename U>
+struct X1<T*, U*> {
+ static const int value = 1;
+};
+
+template<typename T>
+struct X1<T*, T*> {
+ static const int value = 2;
+};
+
+template<typename T>
+struct X1<const T*, const T*> {
+ static const int value = 3;
+};
+
+int array0[X1<int, int>::value == 0? 1 : -1];
+int array1[X1<int*, float*>::value == 1? 1 : -1];
+int array2[X1<int*, int*>::value == 2? 1 : -1];
+typedef const int* CIP;
+int array3[X1<const int*, CIP>::value == 3? 1 : -1];
+
+template<typename T, typename U>
+struct X2 { };
+
+template<typename T, typename U>
+struct X2<T*, U> { }; // expected-note{{matches}}
+
+template<typename T, typename U>
+struct X2<T, U*> { }; // expected-note{{matches}}
+
+template<typename T, typename U>
+struct X2<const T*, const U*> { };
+
+X2<int*, int*> x2a; // expected-error{{ambiguous}}
+X2<const int*, const int*> x2b;
Propchange: cfe/trunk/test/SemaTemplate/temp_class_order.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cfe/trunk/test/SemaTemplate/temp_class_order.cpp
------------------------------------------------------------------------------
svn:keywords = Id
Propchange: cfe/trunk/test/SemaTemplate/temp_class_order.cpp
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: cfe/trunk/test/SemaTemplate/temp_class_spec.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/temp_class_spec.cpp?rev=81866&r1=81865&r2=81866&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec.cpp Tue Sep 15 11:23:51 2009
@@ -1,6 +1,6 @@
// RUN: clang-cc -fsyntax-only -verify %s
template<typename T>
-struct is_pointer { // expected-error{{partial ordering}}
+struct is_pointer {
static const bool value = false;
};
@@ -16,7 +16,7 @@
int array0[is_pointer<int>::value? -1 : 1];
int array1[is_pointer<int*>::value? 1 : -1];
-int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{negative}}
+int array2[is_pointer<const int*>::value? 1 : -1];
template<typename T>
struct is_lvalue_reference {
More information about the cfe-commits
mailing list