From b197572cf1cd70a817a1f546478cb2cb9112c48e Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Thu, 30 Jul 2009 23:18:24 +0000 Subject: [PATCH] Canonicalization for dependent typeof(expr) types. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77639 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/ASTContext.h | 2 +- include/clang/AST/Type.h | 20 ++++++++++++++++++++ lib/AST/ASTContext.cpp | 23 ++++++++++++++++++++--- lib/AST/StmtProfile.cpp | 4 ++-- lib/AST/Type.cpp | 5 +++++ test/SemaTemplate/canonical-expr-type.cpp | 16 ++++++++++++++++ 6 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 test/SemaTemplate/canonical-expr-type.cpp 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 VectorTypes; llvm::FoldingSet FunctionNoProtoTypes; llvm::FoldingSet FunctionProtoTypes; + llvm::FoldingSet DependentTypeOfExprTypes; llvm::FoldingSet TemplateTypeParmTypes; llvm::FoldingSet TemplateSpecializationTypes; llvm::FoldingSet QualifiedNameTypes; llvm::FoldingSet TypenameTypes; llvm::FoldingSet ObjCInterfaceTypes; llvm::FoldingSet ObjCObjectPointerTypes; - llvm::FoldingSet QualifiedTemplateNames; llvm::FoldingSet 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(D)) { + = dyn_cast(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 +void f0(T x, __typeof__(f(N)) y) { } // expected-note{{previous}} + +template +void f0(T x, __typeof__((f)(N)) y) { } + +template +void f0(U u, __typeof__(f(M))) { } // expected-error{{redefinition}} \ No newline at end of file -- 2.40.0