[cfe-commits] r72819 - in /cfe/trunk: include/clang/AST/DeclTemplate.h lib/Sema/CMakeLists.txt lib/Sema/Sema.h lib/Sema/SemaTemplate.cpp lib/Sema/SemaTemplateDeduction.cpp lib/Sema/SemaTemplateInstantiate.cpp test/SemaTemplate/temp_class_spec.cpp
Douglas Gregor
dgregor at apple.com
Wed Jun 3 17:03:09 PDT 2009
Author: dgregor
Date: Wed Jun 3 19:03:07 2009
New Revision: 72819
URL: http://llvm.org/viewvc/llvm-project?rev=72819&view=rev
Log:
When performing template argument deduction, ensure that multiple
deductions of the same template parameter are equivalent. This allows
us to implement the is_same type trait (!).
Also, move template argument deduction into its own file and update a
few build systems with this change (grrrr).
Added:
cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
Modified:
cfe/trunk/include/clang/AST/DeclTemplate.h
cfe/trunk/lib/Sema/CMakeLists.txt
cfe/trunk/lib/Sema/Sema.h
cfe/trunk/lib/Sema/SemaTemplate.cpp
cfe/trunk/lib/Sema/SemaTemplateInstantiate.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=72819&r1=72818&r2=72819&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
+++ cfe/trunk/include/clang/AST/DeclTemplate.h Wed Jun 3 19:03:07 2009
@@ -390,20 +390,21 @@
public:
/// \brief The type of template argument we're storing.
enum ArgKind {
+ Null = 0,
/// The template argument is a type. It's value is stored in the
/// TypeOrValue field.
- Type = 0,
+ Type = 1,
/// The template argument is a declaration
- Declaration = 1,
+ Declaration = 2,
/// The template argument is an integral value stored in an llvm::APSInt.
- Integral = 2,
+ Integral = 3,
/// The template argument is a value- or type-dependent expression
/// stored in an Expr*.
- Expression = 3
+ Expression = 4
} Kind;
/// \brief Construct an empty, invalid template argument.
- TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Type) { }
+ TemplateArgument() : TypeOrValue(0), StartLoc(), Kind(Null) { }
/// \brief Construct a template type argument.
TemplateArgument(SourceLocation Loc, QualType T) : Kind(Type) {
@@ -484,6 +485,9 @@
/// \brief Return the kind of stored template argument.
ArgKind getKind() const { return Kind; }
+ /// \brief Determine whether this template argument has no value.
+ bool isNull() const { return Kind == Null; }
+
/// \brief Retrieve the template argument as a type.
QualType getAsType() const {
if (Kind != Type)
@@ -534,6 +538,9 @@
void Profile(llvm::FoldingSetNodeID &ID) const {
ID.AddInteger(Kind);
switch (Kind) {
+ case Null:
+ break;
+
case Type:
getAsType().Profile(ID);
break;
Modified: cfe/trunk/lib/Sema/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/CMakeLists.txt?rev=72819&r1=72818&r2=72819&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/CMakeLists.txt (original)
+++ cfe/trunk/lib/Sema/CMakeLists.txt Wed Jun 3 19:03:07 2009
@@ -23,6 +23,7 @@
SemaOverload.cpp
SemaStmt.cpp
SemaTemplate.cpp
+ SemaTemplateDeduction.cpp
SemaTemplateInstantiate.cpp
SemaTemplateInstantiateDecl.cpp
SemaTemplateInstantiateExpr.cpp
Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=72819&r1=72818&r2=72819&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Wed Jun 3 19:03:07 2009
@@ -2019,14 +2019,6 @@
const IdentifierInfo &II,
SourceRange Range);
- bool DeduceTemplateArguments(QualType Param, QualType Arg,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced);
- bool DeduceTemplateArguments(const TemplateArgument &Param,
- const TemplateArgument &Arg,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced);
- bool DeduceTemplateArguments(const TemplateArgumentList &ParamList,
- const TemplateArgumentList &ArgList,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced);
bool DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
const TemplateArgumentList &TemplateArgs);
Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=72819&r1=72818&r2=72819&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed Jun 3 19:03:07 2009
@@ -750,6 +750,10 @@
Canonical.reserve(NumTemplateArgs);
for (unsigned Idx = 0; Idx < NumTemplateArgs; ++Idx) {
switch (TemplateArgs[Idx].getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Should never see a NULL template argument here");
+ break;
+
case TemplateArgument::Expression:
// FIXME: Build canonical expression (!)
Canonical.push_back(TemplateArgs[Idx]);
@@ -765,11 +769,13 @@
Canonical.push_back(TemplateArgument(SourceLocation(),
*TemplateArgs[Idx].getAsIntegral(),
TemplateArgs[Idx].getIntegralType()));
+ break;
case TemplateArgument::Type: {
QualType CanonType
= Context.getCanonicalType(TemplateArgs[Idx].getAsType());
Canonical.push_back(TemplateArgument(SourceLocation(), CanonType));
+ break;
}
}
}
@@ -1092,6 +1098,10 @@
}
switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Should never see a NULL template argument here");
+ break;
+
case TemplateArgument::Expression: {
Expr *E = Arg.getAsExpr();
if (CheckTemplateArgument(NTTP, NTTPType, E, &Converted))
@@ -1131,6 +1141,10 @@
= cast<TemplateTemplateParmDecl>(*Param);
switch (Arg.getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Should never see a NULL template argument here");
+ break;
+
case TemplateArgument::Expression: {
Expr *ArgExpr = Arg.getAsExpr();
if (ArgExpr && isa<DeclRefExpr>(ArgExpr) &&
@@ -2563,89 +2577,3 @@
<< Name;
return QualType();
}
-
-// FIXME: Move to SemaTemplateDeduction.cpp
-bool
-Sema::DeduceTemplateArguments(QualType Param, QualType Arg,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
- // We only want to look at the canonical types, since typedefs and
- // sugar are not part of template argument deduction.
- Param = Context.getCanonicalType(Param);
- Arg = Context.getCanonicalType(Arg);
-
- // If the parameter type is not dependent, just compare the types
- // directly.
- if (!Param->isDependentType())
- return Param == Arg;
-
- // FIXME: Use a visitor or switch to handle all of the kinds of
- // types that the parameter may be.
- if (const TemplateTypeParmType *TemplateTypeParm
- = Param->getAsTemplateTypeParmType()) {
- (void)TemplateTypeParm; // FIXME: use this
- // The argument type can not be less qualified than the parameter
- // type.
- if (Param.isMoreQualifiedThan(Arg))
- return false;
-
- unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
- QualType DeducedType = Arg.getQualifiedType(Quals);
- // FIXME: actually save the deduced type, and check that this
- // deduction is consistent.
- return true;
- }
-
- if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
- return false;
-
- if (const PointerType *PointerParam = Param->getAsPointerType()) {
- const PointerType *PointerArg = Arg->getAsPointerType();
- if (!PointerArg)
- return false;
-
- return DeduceTemplateArguments(PointerParam->getPointeeType(),
- PointerArg->getPointeeType(),
- Deduced);
- }
-
- // FIXME: Many more cases to go (to go).
- return false;
-}
-
-bool
-Sema::DeduceTemplateArguments(const TemplateArgument &Param,
- const TemplateArgument &Arg,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
- assert(Param.getKind() == Arg.getKind() &&
- "Template argument kind mismatch during deduction");
- switch (Param.getKind()) {
- case TemplateArgument::Type:
- return DeduceTemplateArguments(Param.getAsType(), Arg.getAsType(),
- Deduced);
-
- default:
- return false;
- }
-}
-
-bool
-Sema::DeduceTemplateArguments(const TemplateArgumentList &ParamList,
- const TemplateArgumentList &ArgList,
- llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
- assert(ParamList.size() == ArgList.size());
- for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
- if (!DeduceTemplateArguments(ParamList[I], ArgList[I], Deduced))
- return false;
- }
- return true;
-}
-
-
-bool
-Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
- const TemplateArgumentList &TemplateArgs) {
- llvm::SmallVector<TemplateArgument, 4> Deduced;
- Deduced.resize(Partial->getTemplateParameters()->size());
- return DeduceTemplateArguments(Partial->getTemplateArgs(), TemplateArgs,
- Deduced);
-}
Added: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=72819&view=auto
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (added)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Jun 3 19:03:07 2009
@@ -0,0 +1,121 @@
+//===------- SemaTemplateDeduction.cpp - Template Argument Deduction ------===/
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//===----------------------------------------------------------------------===/
+//
+// This file implements C++ template argument deduction.
+//
+//===----------------------------------------------------------------------===/
+
+#include "Sema.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/Compiler.h"
+using namespace clang;
+
+static bool DeduceTemplateArguments(ASTContext &Context, QualType Param,
+ QualType Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ // We only want to look at the canonical types, since typedefs and
+ // sugar are not part of template argument deduction.
+ Param = Context.getCanonicalType(Param);
+ Arg = Context.getCanonicalType(Arg);
+
+ // If the parameter type is not dependent, just compare the types
+ // directly.
+ if (!Param->isDependentType())
+ return Param == Arg;
+
+ // FIXME: Use a visitor or switch to handle all of the kinds of
+ // types that the parameter may be.
+ if (const TemplateTypeParmType *TemplateTypeParm
+ = Param->getAsTemplateTypeParmType()) {
+ // The argument type can not be less qualified than the parameter
+ // type.
+ if (Param.isMoreQualifiedThan(Arg))
+ return false;
+
+ assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0");
+
+ unsigned Quals = Arg.getCVRQualifiers() & ~Param.getCVRQualifiers();
+ QualType DeducedType = Arg.getQualifiedType(Quals);
+ unsigned Index = TemplateTypeParm->getIndex();
+
+ if (Deduced[Index].isNull())
+ Deduced[Index] = TemplateArgument(SourceLocation(), DeducedType);
+ else {
+ // C++ [temp.deduct.type]p2:
+ // [...] If type deduction cannot be done for any P/A pair, or if for
+ // any pair the deduction leads to more than one possible set of
+ // deduced values, or if different pairs yield different deduced
+ // values, or if any template argument remains neither deduced nor
+ // explicitly specified, template argument deduction fails.
+ if (Deduced[Index].getAsType() != DeducedType)
+ return false;
+ }
+ return true;
+ }
+
+ if (Param.getCVRQualifiers() != Arg.getCVRQualifiers())
+ return false;
+
+ if (const PointerType *PointerParam = Param->getAsPointerType()) {
+ const PointerType *PointerArg = Arg->getAsPointerType();
+ if (!PointerArg)
+ return false;
+
+ return DeduceTemplateArguments(Context,
+ PointerParam->getPointeeType(),
+ PointerArg->getPointeeType(),
+ Deduced);
+ }
+
+ // FIXME: Many more cases to go (to go).
+ return false;
+}
+
+static bool
+DeduceTemplateArguments(ASTContext &Context, const TemplateArgument &Param,
+ const TemplateArgument &Arg,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(Param.getKind() == Arg.getKind() &&
+ "Template argument kind mismatch during deduction");
+ switch (Param.getKind()) {
+ case TemplateArgument::Type:
+ return DeduceTemplateArguments(Context, Param.getAsType(),
+ Arg.getAsType(), Deduced);
+
+ default:
+ return false;
+ }
+}
+
+static bool
+DeduceTemplateArguments(ASTContext &Context,
+ const TemplateArgumentList &ParamList,
+ const TemplateArgumentList &ArgList,
+ llvm::SmallVectorImpl<TemplateArgument> &Deduced) {
+ assert(ParamList.size() == ArgList.size());
+ for (unsigned I = 0, N = ParamList.size(); I != N; ++I) {
+ if (!DeduceTemplateArguments(Context, ParamList[I], ArgList[I], Deduced))
+ return false;
+ }
+ return true;
+}
+
+
+bool
+Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial,
+ const TemplateArgumentList &TemplateArgs) {
+ llvm::SmallVector<TemplateArgument, 4> Deduced;
+ Deduced.resize(Partial->getTemplateParameters()->size());
+ return ::DeduceTemplateArguments(Context, Partial->getTemplateArgs(),
+ TemplateArgs, Deduced);
+}
Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=72819&r1=72818&r2=72819&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Wed Jun 3 19:03:07 2009
@@ -503,6 +503,10 @@
for (TemplateSpecializationType::iterator Arg = T->begin(), ArgEnd = T->end();
Arg != ArgEnd; ++Arg) {
switch (Arg->getKind()) {
+ case TemplateArgument::Null:
+ assert(false && "Should never have a NULL template argument");
+ break;
+
case TemplateArgument::Type: {
QualType T = SemaRef.InstantiateType(Arg->getAsType(),
TemplateArgs,
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=72819&r1=72818&r2=72819&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/temp_class_spec.cpp (original)
+++ cfe/trunk/test/SemaTemplate/temp_class_spec.cpp Wed Jun 3 19:03:07 2009
@@ -18,3 +18,21 @@
int array1[is_pointer<int*>::value? 1 : -1];
int array2[is_pointer<const int*>::value? 1 : -1]; // expected-error{{partial ordering}} \
// expected-error{{negative}}
+
+template<typename T, typename U>
+struct is_same {
+ static const bool value = false;
+};
+
+template<typename T>
+struct is_same<T, T> {
+ static const bool value = true;
+};
+
+typedef int INT;
+typedef INT* int_ptr;
+
+int is_same0[is_same<int, int>::value? 1 : -1];
+int is_same1[is_same<int, INT>::value? 1 : -1];
+int is_same2[is_same<const int, int>::value? -1 : 1];
+int is_same3[is_same<int_ptr, int>::value? -1 : 1];
More information about the cfe-commits
mailing list