aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-07-30 23:18:24 +0000
committerDouglas Gregor <dgregor@apple.com>2009-07-30 23:18:24 +0000
commitb197572cf1cd70a817a1f546478cb2cb9112c48e (patch)
tree478c5a2caa30004f0c3662d9f9f5c4d43be3d4ab
parent03e205031b08669f05c41eed5b896fc94c4a12bb (diff)
Canonicalization for dependent typeof(expr) types.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77639 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/ASTContext.h2
-rw-r--r--include/clang/AST/Type.h20
-rw-r--r--lib/AST/ASTContext.cpp23
-rw-r--r--lib/AST/StmtProfile.cpp4
-rw-r--r--lib/AST/Type.cpp5
-rw-r--r--test/SemaTemplate/canonical-expr-type.cpp16
6 files changed, 64 insertions, 6 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h
index 529477f315..a8ed08e387 100644
--- a/include/clang/AST/ASTContext.h
+++ b/include/clang/AST/ASTContext.h
@@ -75,13 +75,13 @@ class ASTContext {
llvm::FoldingSet<VectorType> VectorTypes;
llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes;
llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes;
+ llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes;
llvm::FoldingSet<TemplateTypeParmType> TemplateTypeParmTypes;
llvm::FoldingSet<TemplateSpecializationType> TemplateSpecializationTypes;
llvm::FoldingSet<QualifiedNameType> QualifiedNameTypes;
llvm::FoldingSet<TypenameType> TypenameTypes;
llvm::FoldingSet<ObjCInterfaceType> ObjCInterfaceTypes;
llvm::FoldingSet<ObjCObjectPointerType> ObjCObjectPointerTypes;
-
llvm::FoldingSet<QualifiedTemplateName> QualifiedTemplateNames;
llvm::FoldingSet<DependentTemplateName> DependentTemplateNames;
diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h
index 76a5a3f404..3072c67556 100644
--- a/include/clang/AST/Type.h
+++ b/include/clang/AST/Type.h
@@ -1577,6 +1577,8 @@ public:
/// TypeOfExprType (GCC extension).
class TypeOfExprType : public Type {
Expr *TOExpr;
+
+protected:
TypeOfExprType(Expr *E, QualType can = QualType());
friend class ASTContext; // ASTContext creates these.
public:
@@ -1589,6 +1591,24 @@ public:
static bool classof(const TypeOfExprType *) { return true; }
};
+/// Subclass of TypeOfExprType that is used for canonical, dependent
+/// typeof(expr) types.
+class DependentTypeOfExprType
+ : public TypeOfExprType, public llvm::FoldingSetNode {
+ ASTContext &Context;
+
+public:
+ DependentTypeOfExprType(ASTContext &Context, Expr *E)
+ : TypeOfExprType(E), Context(Context) { }
+
+ void Profile(llvm::FoldingSetNodeID &ID) {
+ Profile(ID, Context, getUnderlyingExpr());
+ }
+
+ static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+ Expr *E);
+};
+
/// TypeOfType (GCC extension).
class TypeOfType : public Type {
QualType TOType;
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index e9bcc04c28..81cab925eb 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1876,9 +1876,26 @@ QualType ASTContext::getObjCInterfaceType(const ObjCInterfaceDecl *Decl,
/// on canonical type's (which are always unique).
QualType ASTContext::getTypeOfExprType(Expr *tofExpr) {
TypeOfExprType *toe;
- if (tofExpr->isTypeDependent())
- toe = new (*this, 8) TypeOfExprType(tofExpr);
- else {
+ if (tofExpr->isTypeDependent()) {
+ llvm::FoldingSetNodeID ID;
+ DependentTypeOfExprType::Profile(ID, *this, tofExpr);
+
+ void *InsertPos = 0;
+ DependentTypeOfExprType *Canon
+ = DependentTypeOfExprTypes.FindNodeOrInsertPos(ID, InsertPos);
+ if (Canon) {
+ // We already have a "canonical" version of an identical, dependent
+ // typeof(expr) type. Use that as our canonical type.
+ toe = new (*this, 8) TypeOfExprType(tofExpr,
+ QualType((TypeOfExprType*)Canon, 0));
+ }
+ else {
+ // Build a new, canonical typeof(expr) type.
+ Canon = new (*this, 8) DependentTypeOfExprType(*this, tofExpr);
+ DependentTypeOfExprTypes.InsertNode(Canon, InsertPos);
+ toe = Canon;
+ }
+ } else {
QualType Canonical = getCanonicalType(tofExpr->getType());
toe = new (*this,8) TypeOfExprType(tofExpr, Canonical);
}
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index 688777d4aa..8039d97731 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -602,9 +602,9 @@ void StmtProfiler::VisitObjCIsaExpr(ObjCIsaExpr *S) {
}
void StmtProfiler::VisitDecl(Decl *D) {
- if (Canonical) {
+ if (Canonical && D) {
if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast_or_null<NonTypeTemplateParmDecl>(D)) {
+ = dyn_cast<NonTypeTemplateParmDecl>(D)) {
ID.AddInteger(NTTP->getDepth());
ID.AddInteger(NTTP->getIndex());
VisitType(NTTP->getType());
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 789bac3c7e..76d35465fe 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -958,6 +958,11 @@ TypeOfExprType::TypeOfExprType(Expr *E, QualType can)
: Type(TypeOfExpr, can, E->isTypeDependent()), TOExpr(E) {
}
+void DependentTypeOfExprType::Profile(llvm::FoldingSetNodeID &ID,
+ ASTContext &Context, Expr *E) {
+ E->Profile(ID, Context, true);
+}
+
DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
: Type(Decltype, can, E->isTypeDependent()), E(E),
UnderlyingType(underlyingType) {
diff --git a/test/SemaTemplate/canonical-expr-type.cpp b/test/SemaTemplate/canonical-expr-type.cpp
new file mode 100644
index 0000000000..250420bedb
--- /dev/null
+++ b/test/SemaTemplate/canonical-expr-type.cpp
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify %s
+
+void f();
+
+// FIXME: would like to refer to the first function parameter in these test,
+// but that won't work (yet).
+
+// Test typeof(expr) canonicalization
+template<typename T, T N>
+void f0(T x, __typeof__(f(N)) y) { } // expected-note{{previous}}
+
+template<typename T, T N>
+void f0(T x, __typeof__((f)(N)) y) { }
+
+template<typename U, U M>
+void f0(U u, __typeof__(f(M))) { } // expected-error{{redefinition}} \ No newline at end of file