diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h index a8ed08e38704..a1f190a74b03 100644 --- a/clang/include/clang/AST/ASTContext.h +++ b/clang/include/clang/AST/ASTContext.h @@ -76,12 +76,14 @@ class ASTContext { llvm::FoldingSet FunctionNoProtoTypes; llvm::FoldingSet FunctionProtoTypes; llvm::FoldingSet DependentTypeOfExprTypes; + llvm::FoldingSet DependentDecltypeTypes; 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/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 3072c675569b..6eaa4e67a747 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -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 diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 81cab925eb08..f47e28b8f200 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -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)); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 76d35465fe09..c8e317c7d32a 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -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/clang/test/SemaTemplate/canonical-expr-type-0x.cpp b/clang/test/SemaTemplate/canonical-expr-type-0x.cpp new file mode 100644 index 000000000000..a3c177e3d240 --- /dev/null +++ b/clang/test/SemaTemplate/canonical-expr-type-0x.cpp @@ -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 +void f0(T x, decltype(f(N)) y) { } // expected-note{{previous}} + +template +void f0(T x, decltype((f)(N)) y) { } + +template +void f0(U u, decltype(f(M))) { } // expected-error{{redefinition}} \ No newline at end of file