]> granicus.if.org Git - clang/commitdiff
Canonicalization of dependent C++0x decltype types.
authorDouglas Gregor <dgregor@apple.com>
Thu, 30 Jul 2009 23:36:40 +0000 (23:36 +0000)
committerDouglas Gregor <dgregor@apple.com>
Thu, 30 Jul 2009 23:36:40 +0000 (23:36 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77643 91177308-0d34-0410-b5e6-96231b3b80d8

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

index a8ed08e38704c4c83a2867a6f14e6747050ba829..a1f190a74b03b6a06f89383db147ad76106a70f8 100644 (file)
@@ -76,12 +76,14 @@ class ASTContext {
   llvm::FoldingSet<FunctionNoProtoType> FunctionNoProtoTypes;
   llvm::FoldingSet<FunctionProtoType> FunctionProtoTypes;
   llvm::FoldingSet<DependentTypeOfExprType> DependentTypeOfExprTypes;
+  llvm::FoldingSet<DependentDecltypeType> DependentDecltypeTypes;
   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 3072c675569b998be93515142df4897d3ccda39f..6eaa4e67a747af5a3b6ec0c2ac932d8d2b33cf15 100644 (file)
@@ -1636,6 +1636,7 @@ class DecltypeType : public Type {
   // from it.
   QualType UnderlyingType;
   
+protected:
   DecltypeType(Expr *E, QualType underlyingType, QualType can = QualType());
   friend class ASTContext;  // ASTContext creates these.
 public:
@@ -1649,6 +1650,22 @@ public:
   static bool classof(const DecltypeType *) { return true; }
 };
   
+/// Subclass of DecltypeType that is used for canonical, dependent 
+/// C++0x decltype types. 
+class DependentDecltypeType : public DecltypeType, public llvm::FoldingSetNode {
+  ASTContext &Context;
+  
+public:
+  DependentDecltypeType(ASTContext &Context, Expr *E);
+  
+  void Profile(llvm::FoldingSetNodeID &ID) {
+    Profile(ID, Context, getUnderlyingExpr());
+  }
+  
+  static void Profile(llvm::FoldingSetNodeID &ID, ASTContext &Context,
+                      Expr *E);  
+};
+  
 class TagType : public Type {
   /// Stores the TagDecl associated with this type. The decl will
   /// point to the TagDecl that actually defines the entity (or is a
index 81cab925eb08ec8fb8a24ff5080fdea74622205b..f47e28b8f20005b06375167d9efa1a4ae46c5a87 100644 (file)
@@ -1954,9 +1954,26 @@ static QualType getDecltypeForExpr(const Expr *e, ASTContext &Context) {
 /// on canonical type's (which are always unique).
 QualType ASTContext::getDecltypeType(Expr *e) {
   DecltypeType *dt;
-  if (e->isTypeDependent()) // FIXME: canonicalize the expression
-    dt = new (*this, 8) DecltypeType(e, DependentTy);
-  else {
+  if (e->isTypeDependent()) {
+    llvm::FoldingSetNodeID ID;
+    DependentDecltypeType::Profile(ID, *this, e);
+    
+    void *InsertPos = 0;
+    DependentDecltypeType *Canon
+      = DependentDecltypeTypes.FindNodeOrInsertPos(ID, InsertPos);
+    if (Canon) {
+      // We already have a "canonical" version of an equivalent, dependent
+      // decltype type. Use that as our canonical type.
+      dt = new (*this, 8) DecltypeType(e, DependentTy,
+                                       QualType((DecltypeType*)Canon, 0));
+    }
+    else {
+      // Build a new, canonical typeof(expr) type.
+      Canon = new (*this, 8) DependentDecltypeType(*this, e);
+      DependentDecltypeTypes.InsertNode(Canon, InsertPos);
+      dt = Canon;
+    }
+  } else {
     QualType T = getDecltypeForExpr(e, *this);
     dt = new (*this, 8) DecltypeType(e, T, getCanonicalType(T));    
   }
index 76d35465fe09e65d45249cb7e4513d0235623178..c8e317c7d32a13488475bff6a18e0239cbb541ee 100644 (file)
@@ -968,6 +968,14 @@ DecltypeType::DecltypeType(Expr *E, QualType underlyingType, QualType can)
   UnderlyingType(underlyingType) {
 }
 
+DependentDecltypeType::DependentDecltypeType(ASTContext &Context, Expr *E)
+  : DecltypeType(E, Context.DependentTy), Context(Context) { }
+
+void DependentDecltypeType::Profile(llvm::FoldingSetNodeID &ID, 
+                                    ASTContext &Context, Expr *E) {
+  E->Profile(ID, Context, true);
+}
+
 TagType::TagType(TypeClass TC, TagDecl *D, QualType can) 
   : Type(TC, can, D->isDependentType()), decl(D, 0) {}
 
diff --git a/test/SemaTemplate/canonical-expr-type-0x.cpp b/test/SemaTemplate/canonical-expr-type-0x.cpp
new file mode 100644 (file)
index 0000000..a3c177e
--- /dev/null
@@ -0,0 +1,16 @@
+// RUN: clang-cc -fsyntax-only -verify -std=c++0x %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, decltype(f(N)) y) { } // expected-note{{previous}}
+
+template<typename T, T N>
+void f0(T x, decltype((f)(N)) y) { }
+
+template<typename U, U M>
+void f0(U u, decltype(f(M))) { } // expected-error{{redefinition}}
\ No newline at end of file