From: Douglas Gregor Date: Thu, 26 Feb 2009 22:19:44 +0000 (+0000) Subject: Make the type associated with a ClassTemplateSpecializationDecl be a X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fc705b84347e6fb4746a1a7e26949f64c2f2f358;p=clang Make the type associated with a ClassTemplateSpecializationDecl be a nicely sugared type that shows how the user wrote the actual specialization. This sugared type won't actually show up until we start doing instantiations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@65577 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index aa009c8b4c..9536eca300 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -814,6 +814,7 @@ class TypeDecl : public NamedDecl { friend class DeclContext; friend class TagDecl; friend class TemplateTypeParmDecl; + friend class ClassTemplateSpecializationDecl; protected: TypeDecl(Kind DK, DeclContext *DC, SourceLocation L, diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index a075d74e61..92c2d6b8f6 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -606,6 +606,12 @@ public: Profile(ID, template_arg_begin(), getNumTemplateArgs()); } + /// \brief Sets the type of this specialization as it was written by + /// the user. This will be a class template specialization type. + void setTypeAsWritten(QualType T) { + TypeForDecl = T.getTypePtr(); + } + static void Profile(llvm::FoldingSetNodeID &ID, const TemplateArgument *TemplateArgs, unsigned NumTemplateArgs) { diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index f5bd5f19f0..3ee513b17f 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -407,6 +407,7 @@ public: const BlockPointerType *getAsBlockPointerType() const; const ReferenceType *getAsReferenceType() const; const MemberPointerType *getAsMemberPointerType() const; + const TagType *getAsTagType() const; const RecordType *getAsRecordType() const; const RecordType *getAsStructureType() const; /// NOTE: getAs*ArrayType are methods on ASTContext. @@ -1309,7 +1310,7 @@ class TagType : public Type { /// definition in progress), if there is such a definition. The /// single-bit value will be non-zero when this tag is in the /// process of being defined. - llvm::PointerIntPair decl; + mutable llvm::PointerIntPair decl; friend class ASTContext; friend class TagDecl; diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 60d8b8be80..2b4bc89aac 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1307,6 +1307,8 @@ ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template, unsigned NumArgs, uintptr_t *Args, bool *ArgIsType, QualType Canon) { + Canon = getCanonicalType(Canon); + llvm::FoldingSetNodeID ID; ClassTemplateSpecializationType::Profile(ID, Template, NumArgs, Args, ArgIsType); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 2732bf93c1..ab65492023 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -374,22 +374,24 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { //===----------------------------------------------------------------------===// void TagDecl::startDefinition() { - cast(TypeForDecl)->decl.setPointer(this); - cast(TypeForDecl)->decl.setInt(1); + TagType *TagT = const_cast(TypeForDecl->getAsTagType()); + TagT->decl.setPointer(this); + TagT->getAsTagType()->decl.setInt(1); } void TagDecl::completeDefinition() { assert((!TypeForDecl || - cast(TypeForDecl)->decl.getPointer() == this) && + TypeForDecl->getAsTagType()->decl.getPointer() == this) && "Attempt to redefine a tag definition?"); IsDefinition = true; - cast(TypeForDecl)->decl.setPointer(this); - cast(TypeForDecl)->decl.setInt(0); + TagType *TagT = const_cast(TypeForDecl->getAsTagType()); + TagT->decl.setPointer(this); + TagT->decl.setInt(0); } TagDecl* TagDecl::getDefinition(ASTContext& C) const { QualType T = C.getTypeDeclType(const_cast(this)); - TagDecl* D = cast(cast(T)->getDecl()); + TagDecl* D = cast(T->getAsTagType()->getDecl()); return D->isDefinition() ? D : 0; } diff --git a/lib/AST/DeclBase.cpp b/lib/AST/DeclBase.cpp index d6a0c35d92..574de1675f 100644 --- a/lib/AST/DeclBase.cpp +++ b/lib/AST/DeclBase.cpp @@ -446,8 +446,7 @@ DeclContext *DeclContext::getPrimaryContext() { if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) { // If this is a tag type that has a definition or is currently // being defined, that definition is our primary context. - if (TagType *TagT - = cast_or_null(cast(this)->TypeForDecl)) + if (const TagType *TagT = cast(this)->TypeForDecl->getAsTagType()) if (TagT->isBeingDefined() || (TagT->getDecl() && TagT->getDecl()->isDefinition())) return TagT->getDecl(); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 3ed4435bb3..ed4fd44e70 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -179,7 +179,6 @@ ClassTemplateSpecializationDecl::Create(ASTContext &Context, ClassTemplateSpecializationDecl *Result = new (Mem) ClassTemplateSpecializationDecl(DC, L, SpecializedTemplate, TemplateArgs, NumTemplateArgs); - // FIXME: Do we want a prettier type here? Context.getTypeDeclType(Result, PrevDecl); return Result; } diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 210be03fa8..327e623aaf 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -331,7 +331,7 @@ bool Type::isVariablyModifiedType() const { } const RecordType *Type::getAsRecordType() const { - // If this is directly a reference type, return it. + // If this is directly a record type, return it. if (const RecordType *RTy = dyn_cast(this)) return RTy; @@ -348,6 +348,24 @@ const RecordType *Type::getAsRecordType() const { return getDesugaredType()->getAsRecordType(); } +const TagType *Type::getAsTagType() const { + // If this is directly a tag type, return it. + if (const TagType *TagTy = dyn_cast(this)) + return TagTy; + + // If the canonical form of this type isn't the right kind, reject it. + if (!isa(CanonicalType)) { + // Look through type qualifiers + if (isa(CanonicalType.getUnqualifiedType())) + return CanonicalType.getUnqualifiedType()->getAsTagType(); + return 0; + } + + // If this is a typedef for a tag type, strip the typedef off without + // losing all typedef information. + return getDesugaredType()->getAsTagType(); +} + const RecordType *Type::getAsStructureType() const { // If this is directly a structure type, return it. if (const RecordType *RT = dyn_cast(this)) { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index f69f546177..97eb9be36c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -1727,8 +1727,20 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TagKind TK, } } - // FIXME: We want to create a nicely sugared type to use as the - // type of this explicit specialization. + // Build the fully-sugared type for this class template + // specialization as the user wrote in the specialization + // itself. This means that we'll pretty-print the type retrieved + // from the specialization's declaration the way that the user + // actually wrote the specialization, rather than formatting the + // name based on the "canonical" representation used to store the + // template arguments in the specialization. + Specialization->setTypeAsWritten( + Context.getClassTemplateSpecializationType(ClassTemplate, + TemplateArgs.size(), + reinterpret_cast(TemplateArgs.getArgs()), + TemplateArgs.getArgIsType(), + Context.getTypeDeclType(Specialization))); + TemplateArgs.release(); // C++ [temp.expl.spec]p9: // A template explicit specialization is in the scope of the