]> granicus.if.org Git - clang/commitdiff
Canonicalization for dependent typeof(expr) types.
authorDouglas Gregor <dgregor@apple.com>
Thu, 30 Jul 2009 23:18:24 +0000 (23:18 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 30 Jul 2009 23:18:24 +0000 (23:18 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77639 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/ASTContext.h
include/clang/AST/Type.h
lib/AST/ASTContext.cpp
lib/AST/StmtProfile.cpp
lib/AST/Type.cpp
test/SemaTemplate/canonical-expr-type.cpp [new file with mode: 0644]

index 529477f315786ae9a6efa3a2dd606767b8a928b2..a8ed08e38704c4c83a2867a6f14e6747050ba829 100644 (file)
@@ -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;
 
index 76a5a3f404a242e3a288c8e596273712c00a3efa..3072c675569b998be93515142df4897d3ccda39f 100644 (file)
@@ -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;
index e9bcc04c28abe9615ceff789f88bb1e0b33c9268..81cab925eb08ec8fb8a24ff5080fdea74622205b 100644 (file)
@@ -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);
   }
index 688777d4aacbd15b9dc9afe04eea334a29799c53..8039d97731561dde1659304a3ff88d199c5e4934 100644 (file)
@@ -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());
index 789bac3c7e9384926122b07b2c7983f5d94035aa..76d35465fe09e65d45249cb7e4513d0235623178 100644 (file)
@@ -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 (file)
index 0000000..250420b
--- /dev/null
@@ -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