diff options
-rw-r--r-- | include/clang/AST/ASTContext.h | 9 | ||||
-rw-r--r-- | include/clang/AST/Decl.h | 7 | ||||
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 24 | ||||
-rw-r--r-- | include/clang/AST/Type.h | 6 | ||||
-rw-r--r-- | lib/AST/ASTContext.cpp | 30 | ||||
-rw-r--r-- | lib/AST/Decl.cpp | 13 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 59 | ||||
-rw-r--r-- | lib/AST/Type.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 36 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 3 | ||||
-rw-r--r-- | test/SemaTemplate/injected-class-name.cpp | 27 |
12 files changed, 206 insertions, 30 deletions
diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 1f24dee0f3..8b4c89b6e8 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -564,6 +564,9 @@ public: return T1.getUnqualifiedType() == T2.getUnqualifiedType(); } + /// \brief Retrieves the "canonical" declaration of the given declaration. + Decl *getCanonicalDecl(Decl *D); + /// \brief Retrieves the "canonical" declaration of the given tag /// declaration. /// @@ -571,11 +574,11 @@ public: /// either the definition of the tag (if it is a complete type) or /// the first declaration of that tag. TagDecl *getCanonicalDecl(TagDecl *Tag) { - QualType T = getTagDeclType(Tag); - return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType) - ->getDecl()); + return cast<TagDecl>(getCanonicalDecl((Decl *)Tag)); } + /// \brief Retrieves the "canonical" declaration of + /// \brief Retrieves the "canonical" nested name specifier for a /// given nested name specifier. /// diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index 90d1328c3d..79d04b338e 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -902,7 +902,12 @@ public: bool isDefinition() const { return IsDefinition; } - + + /// \brief Whether this declaration declares a type that is + /// dependent, i.e., a type that somehow depends on template + /// parameters. + bool isDependentType() const; + /// @brief Starts the definition of this tag declaration. /// /// This method should be invoked at the beginning of the definition diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index 5036127d3f..0853b29ab1 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -674,6 +674,9 @@ protected: /// \brief The class template specializations for this class /// template, including explicit specializations and instantiations. llvm::FoldingSet<ClassTemplateSpecializationDecl> Specializations; + + /// \brief The injected-class-name type for this class template. + QualType InjectedClassNameType; }; /// \brief Previous declaration of this class template. @@ -700,6 +703,11 @@ public: return static_cast<CXXRecordDecl *>(TemplatedDecl); } + /// \brief Retrieve the previous declaration of this template. + ClassTemplateDecl *getPreviousDeclaration() const { + return PreviousDeclaration; + } + /// Create a class template node. static ClassTemplateDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, @@ -713,6 +721,22 @@ public: return CommonPtr->Specializations; } + /// \brief Retrieve the type of the injected-class-name for this + /// class template. + /// + /// The injected-class-name for a class template \c X is \c + /// X<template-args>, where \c template-args is formed from the + /// template arguments that correspond to the template parameters of + /// \c X. For example: + /// + /// \code + /// template<typename T, int N> + /// struct array { + /// typedef array this_type; // "array" is equivalent to "array<T, N>" + /// }; + /// \endcode + QualType getInjectedClassNameType(ASTContext &Context); + // Implement isa/cast/dyncast support static bool classof(const Decl *D) { return D->getKind() == ClassTemplate; } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 22e36a8215..ff3d89c354 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -1281,11 +1281,7 @@ class TagType : public Type { friend class TagDecl; protected: - // FIXME: We'll need the user to pass in information about whether - // this type is dependent or not, because we don't have enough - // information to compute it here. - TagType(TypeClass TC, TagDecl *D, QualType can) - : Type(TC, can, /*Dependent=*/false), decl(D, 0) {} + TagType(TypeClass TC, TagDecl *D, QualType can); public: TagDecl *getDecl() const { return decl.getPointer(); } diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 133e8c20b8..f9d648b816 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1703,11 +1703,39 @@ QualType ASTContext::getCanonicalType(QualType T) { VAT->getIndexTypeQualifier()); } +Decl *ASTContext::getCanonicalDecl(Decl *D) { + if (TagDecl *Tag = dyn_cast<TagDecl>(D)) { + QualType T = getTagDeclType(Tag); + return cast<TagDecl>(cast<TagType>(T.getTypePtr()->CanonicalType) + ->getDecl()); + } + + if (ClassTemplateDecl *Template = dyn_cast<ClassTemplateDecl>(D)) { + while (Template->getPreviousDeclaration()) + Template = Template->getPreviousDeclaration(); + return Template; + } + + if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { + while (Function->getPreviousDeclaration()) + Function = Function->getPreviousDeclaration(); + return const_cast<FunctionDecl *>(Function); + } + + if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { + while (Var->getPreviousDeclaration()) + Var = Var->getPreviousDeclaration(); + return const_cast<VarDecl *>(Var); + } + + return D; +} + TemplateName ASTContext::getCanonicalTemplateName(TemplateName Name) { // If this template name refers to a template, the canonical // template name merely stores the template itself. if (TemplateDecl *Template = Name.getAsTemplateDecl()) - return TemplateName(Template); + return TemplateName(cast<TemplateDecl>(getCanonicalDecl(Template))); DependentTemplateName *DTN = Name.getAsDependentTemplateName(); assert(DTN && "Non-dependent template names must refer to template decls."); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 9aba33c943..621145f1af 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -14,6 +14,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Stmt.h" #include "clang/AST/Expr.h" @@ -505,6 +506,18 @@ OverloadedOperatorKind FunctionDecl::getOverloadedOperator() const { // TagDecl Implementation //===----------------------------------------------------------------------===// +bool TagDecl::isDependentType() const { + if (isa<TemplateDecl>(this)) + return true; + + if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(getDeclContext())) + return TD->isDependentType(); + + // FIXME: Tag types declared function templates are dependent types. + // FIXME: Look through block scopes. + return false; +} + void TagDecl::startDefinition() { TagType *TagT = const_cast<TagType *>(TypeForDecl->getAsTagType()); TagT->decl.setPointer(this); diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 7389b83d20..4f64f8bd50 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -120,6 +120,65 @@ void ClassTemplateDecl::Destroy(ASTContext& C) { C.Deallocate((void*)this); } +QualType ClassTemplateDecl::getInjectedClassNameType(ASTContext &Context) { + if (!CommonPtr->InjectedClassNameType.isNull()) + return CommonPtr->InjectedClassNameType; + + // FIXME: n2800 14.6.1p1 should say how the template arguments + // corresponding to template parameter packs should be pack + // expansions. We already say that in 14.6.2.1p2, so it would be + // better to fix that redundancy. + + TemplateParameterList *Params = getTemplateParameters(); + + llvm::SmallVector<TemplateArgument, 16> TemplateArgs; + llvm::SmallVector<TemplateArgument, 16> CanonTemplateArgs; + TemplateArgs.reserve(Params->size()); + CanonTemplateArgs.reserve(Params->size()); + + for (TemplateParameterList::iterator + Param = Params->begin(), ParamEnd = Params->end(); + Param != ParamEnd; ++Param) { + if (isa<TemplateTypeParmDecl>(*Param)) { + QualType ParamType = Context.getTypeDeclType(cast<TypeDecl>(*Param)); + TemplateArgs.push_back(TemplateArgument((*Param)->getLocation(), + ParamType)); + CanonTemplateArgs.push_back( + TemplateArgument((*Param)->getLocation(), + Context.getCanonicalType(ParamType))); + } else if (NonTypeTemplateParmDecl *NTTP = + dyn_cast<NonTypeTemplateParmDecl>(*Param)) { + // FIXME: Build canonical expression, too! + Expr *E = new (Context) DeclRefExpr(NTTP, NTTP->getType(), + NTTP->getLocation(), + NTTP->getType()->isDependentType(), + /*Value-dependent=*/true); + TemplateArgs.push_back(TemplateArgument(E)); + CanonTemplateArgs.push_back(TemplateArgument(E)); + } else { + TemplateTemplateParmDecl *TTP = cast<TemplateTemplateParmDecl>(*Param); + TemplateArgs.push_back(TemplateArgument(TTP->getLocation(), TTP)); + CanonTemplateArgs.push_back(TemplateArgument(TTP->getLocation(), + Context.getCanonicalDecl(TTP))); + } + } + + // FIXME: I should really move the "build-the-canonical-type" logic + // into ASTContext::getTemplateSpecializationType. + TemplateName Name = TemplateName(this); + QualType CanonType = Context.getTemplateSpecializationType( + Context.getCanonicalTemplateName(Name), + &CanonTemplateArgs[0], + CanonTemplateArgs.size()); + + CommonPtr->InjectedClassNameType + = Context.getTemplateSpecializationType(Name, + &TemplateArgs[0], + TemplateArgs.size(), + CanonType); + return CommonPtr->InjectedClassNameType; +} + //===----------------------------------------------------------------------===// // TemplateTypeParm Allocation/Deallocation Method Implementations //===----------------------------------------------------------------------===// diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index b5a884085b..bc439c8c89 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1000,6 +1000,9 @@ TypeOfExprType::TypeOfExprType(Expr *E, QualType can) assert(!isa<TypedefType>(can) && "Invalid canonical type"); } +TagType::TagType(TypeClass TC, TagDecl *D, QualType can) + : Type(TC, can, D->isDependentType()), decl(D, 0) {} + bool RecordType::classof(const TagType *TT) { return isa<RecordDecl>(TT->getDecl()); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index ea6913769a..d9e883f7a8 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -123,8 +123,23 @@ Sema::TypeTy *Sema::getTypeName(IdentifierInfo &II, SourceLocation NameLoc, if (TypeDecl *TD = dyn_cast<TypeDecl>(IIDecl)) { // Check whether we can use this type (void)DiagnoseUseOfDecl(IIDecl, NameLoc); - - T = Context.getTypeDeclType(TD); + + if (getLangOptions().CPlusPlus) { + // C++ [temp.local]p2: + // Within the scope of a class template specialization or + // partial specialization, when the injected-class-name is + // not followed by a <, it is equivalent to the + // injected-class-name followed by the template-argument s + // of the class template specialization or partial + // specialization enclosed in <>. + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) + if (RD->isInjectedClassName()) + if (ClassTemplateDecl *Template = RD->getDescribedClassTemplate()) + T = Template->getInjectedClassNameType(Context); + } + + if (T.isNull()) + T = Context.getTypeDeclType(TD); } else if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(IIDecl)) { // Check whether we can use this interface. (void)DiagnoseUseOfDecl(IIDecl, NameLoc); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c8fdc220d0..0c91573180 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -503,7 +503,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0)) Invalid = true; - // If we had a scope specifier, we better have a previous template + // FIXME: If we had a scope specifier, we better have a previous template // declaration! CXXRecordDecl *NewClass = @@ -749,8 +749,9 @@ static void CanonicalizeTemplateArguments(const TemplateArgument *TemplateArgs, break; case TemplateArgument::Declaration: - Canonical.push_back(TemplateArgument(SourceLocation(), - TemplateArgs[Idx].getAsDecl())); + Canonical.push_back( + TemplateArgument(SourceLocation(), + Context.getCanonicalDecl(TemplateArgs[Idx].getAsDecl()))); break; case TemplateArgument::Integral: @@ -1124,10 +1125,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, Invalid = true; // Add the converted template argument. - // FIXME: Need the "canonical" template declaration! - Converted.push_back( - TemplateArgument(Arg.getLocation(), - cast<DeclRefExpr>(ArgExpr)->getDecl())); + Decl *D + = Context.getCanonicalDecl(cast<DeclRefExpr>(ArgExpr)->getDecl()); + Converted.push_back(TemplateArgument(Arg.getLocation(), D)); continue; } } @@ -1549,8 +1549,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentPointerToMember(Arg, Member)) return true; - if (Converted) + if (Converted) { + Member = cast<NamedDecl>(Context.getCanonicalDecl(Member)); Converted->push_back(TemplateArgument(StartLoc, Member)); + } return false; } @@ -1559,8 +1561,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - if (Converted) + if (Converted) { + Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity)); Converted->push_back(TemplateArgument(StartLoc, Entity)); + } return false; } @@ -1598,8 +1602,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - if (Converted) + if (Converted) { + Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity)); Converted->push_back(TemplateArgument(StartLoc, Entity)); + } return false; } @@ -1640,8 +1646,10 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentAddressOfObjectOrFunction(Arg, Entity)) return true; - if (Converted) + if (Converted) { + Entity = cast<NamedDecl>(Context.getCanonicalDecl(Entity)); Converted->push_back(TemplateArgument(StartLoc, Entity)); + } return false; } @@ -1670,9 +1678,11 @@ bool Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (CheckTemplateArgumentPointerToMember(Arg, Member)) return true; - if (Converted) + if (Converted) { + Member = cast<NamedDecl>(Context.getCanonicalDecl(Member)); Converted->push_back(TemplateArgument(StartLoc, Member)); - + } + return false; } diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 62c717b6d3..a075ea938d 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -273,11 +273,8 @@ Decl *TemplateDeclInstantiator::VisitCXXRecordDecl(CXXRecordDecl *D) { D->getLocation(), D->getIdentifier(), PrevDecl); Record->setImplicit(D->isImplicit()); Record->setAccess(D->getAccess()); - if (!D->isInjectedClassName()) Record->setInstantiationOfMemberClass(D); - else - Record->setDescribedClassTemplate(D->getDescribedClassTemplate()); Owner->addDecl(SemaRef.Context, Record); return Record; diff --git a/test/SemaTemplate/injected-class-name.cpp b/test/SemaTemplate/injected-class-name.cpp index 43fb454bca..c5f826d849 100644 --- a/test/SemaTemplate/injected-class-name.cpp +++ b/test/SemaTemplate/injected-class-name.cpp @@ -1,5 +1,4 @@ // RUN: clang-cc -fsyntax-only -verify %s - template<typename T> struct X { X<T*> *ptr; @@ -13,5 +12,29 @@ struct X<int***> { }; // FIXME: EDG rejects this in their strict-conformance mode, but I -// don't see any wording making this ill-formed. +// don't see any wording making this ill-formed. Actually, +// [temp.local]p2 might make it ill-formed. Are we "in the scope of +// the class template specialization?" X<float>::X<int> xi = x; + +// [temp.local]p1: + +// FIXME: test non-type and template template parameters +template<typename T, typename U> +struct X0 { + typedef T type; + typedef U U_type; + typedef U_type U_type2; + + void f0(const X0&); // expected-note{{here}} + void f0(X0&); + void f0(const X0<T, U>&); // expected-error{{redecl}} + + void f1(const X0&); // expected-note{{here}} + void f1(X0&); + void f1(const X0<type, U_type2>&); // expected-error{{redecl}} + + void f2(const X0&); // expected-note{{here}} + void f2(X0&); + void f2(const ::X0<type, U_type2>&); // expected-error{{redecl}} +}; |