diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-05-05 21:57:07 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2011-05-05 21:57:07 +0000 |
commit | 3f1b5d077b7e68c0c801a56f17b05dab96f7f992 (patch) | |
tree | 04a1b5da5699318cd42202ad10b1c94fdb6db239 | |
parent | bc8e3f8c45c16e272b6c0b3b93688b85988886d6 (diff) | |
download | bcm5719-llvm-3f1b5d077b7e68c0c801a56f17b05dab96f7f992.tar.gz bcm5719-llvm-3f1b5d077b7e68c0c801a56f17b05dab96f7f992.zip |
Implement support for C++0x alias templates.
llvm-svn: 130953
59 files changed, 1119 insertions, 138 deletions
diff --git a/clang/docs/LanguageExtensions.html b/clang/docs/LanguageExtensions.html index f86835a9d1d..9dcddfad603 100644 --- a/clang/docs/LanguageExtensions.html +++ b/clang/docs/LanguageExtensions.html @@ -32,6 +32,7 @@ td { </ul> <li><a href="#checking_upcoming_features">Checks for Upcoming Standard Language Features</a></li> <ul> + <li><a href="#cxx_alias_templates">C++0x alias templates</a></li> <li><a href="#cxx_attributes">C++0x attributes</a></li> <li><a href="#cxx_decltype">C++0x <tt>decltype()</tt></a></li> <li><a href="#cxx_default_function_template_args">C++0x default template arguments in function templates</a></li> @@ -378,6 +379,11 @@ not yet implemented will be noted.</p> <p>Use <tt>__has_feature(cxx_decltype)</tt> to determine if support for the <tt>decltype()</tt> specifier is enabled.</p> +<h3 id="cxx_alias_templates">C++0x alias templates</h3> + +<p>Use <tt>__has_feature(cxx_alias_templates)</tt> to determine if support for +C++0x's alias declarations and alias templates is enabled.</p> + <h3 id="cxx_attributes">C++0x attributes</h3> <p>Use <tt>__has_feature(cxx_attributes)</tt> to determine if support for diff --git a/clang/include/clang/AST/DeclTemplate.h b/clang/include/clang/AST/DeclTemplate.h index ddbe344cdff..dc50d614bf7 100644 --- a/clang/include/clang/AST/DeclTemplate.h +++ b/clang/include/clang/AST/DeclTemplate.h @@ -30,6 +30,7 @@ class ClassTemplatePartialSpecializationDecl; class TemplateTypeParmDecl; class NonTypeTemplateParmDecl; class TemplateTemplateParmDecl; +class TypeAliasTemplateDecl; /// \brief Stores a template parameter of any kind. typedef llvm::PointerUnion3<TemplateTypeParmDecl*, NonTypeTemplateParmDecl*, @@ -230,6 +231,7 @@ public: static bool classof(const FunctionTemplateDecl *D) { return true; } static bool classof(const ClassTemplateDecl *D) { return true; } static bool classof(const TemplateTemplateParmDecl *D) { return true; } + static bool classof(const TypeAliasTemplateDecl *D) { return true; } static bool classofKind(Kind K) { return K >= firstTemplate && K <= lastTemplate; } @@ -672,6 +674,7 @@ public: static bool classof(const RedeclarableTemplateDecl *D) { return true; } static bool classof(const FunctionTemplateDecl *D) { return true; } static bool classof(const ClassTemplateDecl *D) { return true; } + static bool classof(const TypeAliasTemplateDecl *D) { return true; } static bool classofKind(Kind K) { return K >= firstRedeclarableTemplate && K <= lastRedeclarableTemplate; } @@ -2014,6 +2017,78 @@ public: friend class ASTDeclReader; }; +/// Declaration of an alias template. For example: +/// +/// template <typename T> using V = std::map<T*, int, MyCompare<T>>; +class TypeAliasTemplateDecl : public RedeclarableTemplateDecl, + public RedeclarableTemplate<TypeAliasTemplateDecl> { + static void DeallocateCommon(void *Ptr); + +protected: + typedef RedeclarableTemplate<TypeAliasTemplateDecl> redeclarable_base; + + typedef CommonBase Common; + + TypeAliasTemplateDecl(DeclContext *DC, SourceLocation L, DeclarationName Name, + TemplateParameterList *Params, NamedDecl *Decl) + : RedeclarableTemplateDecl(TypeAliasTemplate, DC, L, Name, Params, Decl) { } + + CommonBase *newCommon(ASTContext &C); + + Common *getCommonPtr() { + return static_cast<Common *>(RedeclarableTemplateDecl::getCommonPtr()); + } + +public: + /// Get the underlying function declaration of the template. + TypeAliasDecl *getTemplatedDecl() const { + return static_cast<TypeAliasDecl*>(TemplatedDecl); + } + + + TypeAliasTemplateDecl *getCanonicalDecl() { + return redeclarable_base::getCanonicalDecl(); + } + const TypeAliasTemplateDecl *getCanonicalDecl() const { + return redeclarable_base::getCanonicalDecl(); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + TypeAliasTemplateDecl *getPreviousDeclaration() { + return redeclarable_base::getPreviousDeclaration(); + } + + /// \brief Retrieve the previous declaration of this function template, or + /// NULL if no such declaration exists. + const TypeAliasTemplateDecl *getPreviousDeclaration() const { + return redeclarable_base::getPreviousDeclaration(); + } + + TypeAliasTemplateDecl *getInstantiatedFromMemberTemplate() { + return redeclarable_base::getInstantiatedFromMemberTemplate(); + } + + + /// \brief Create a function template node. + static TypeAliasTemplateDecl *Create(ASTContext &C, DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl); + + /// \brief Create an empty alias template node. + static TypeAliasTemplateDecl *Create(ASTContext &C, EmptyShell); + + // Implement isa/cast/dyncast support + static bool classof(const Decl *D) { return classofKind(D->getKind()); } + static bool classof(const TypeAliasTemplateDecl *D) { return true; } + static bool classofKind(Kind K) { return K == TypeAliasTemplate; } + + friend class ASTDeclReader; + friend class ASTDeclWriter; +}; + /// Implementation of inline functions that require the template declarations inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD) : Function(FTD) { } diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 930d19373cd..33171bd0036 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -1368,6 +1368,11 @@ DEF_TRAVERSE_DECL(TypeAliasDecl, { // source. }) +DEF_TRAVERSE_DECL(TypeAliasTemplateDecl, { + TRY_TO(TraverseDecl(D->getTemplatedDecl())); + TRY_TO(TraverseTemplateParameterListHelper(D->getTemplateParameters())); + }) + DEF_TRAVERSE_DECL(UnresolvedUsingTypenameDecl, { // A dependent using declaration which was marked with 'typename'. // template<class T> class A : public B<T> { using typename B<T>::foo; }; diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 975a66fefa8..c1c60c0c2e3 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -3201,6 +3201,10 @@ public: /// Other template specialization types, for which the template name /// is dependent, may be canonical types. These types are always /// dependent. +/// +/// An instance of this type is followed by an array of TemplateArgument*s, +/// then, if the template specialization type is for a type alias template, +/// a QualType representing the non-canonical aliased type. class TemplateSpecializationType : public Type, public llvm::FoldingSetNode { /// \brief The name of the template being specialized. @@ -3212,7 +3216,8 @@ class TemplateSpecializationType TemplateSpecializationType(TemplateName T, const TemplateArgument *Args, - unsigned NumArgs, QualType Canon); + unsigned NumArgs, QualType Canon, + QualType Aliased); friend class ASTContext; // ASTContext creates these @@ -3247,6 +3252,16 @@ public: return isa<InjectedClassNameType>(getCanonicalTypeInternal()); } + /// True if this template specialization type is for a type alias + /// template. + bool isTypeAlias() const; + /// Get the aliased type, if this is a specialization of a type alias + /// template. + QualType getAliasedType() const { + assert(isTypeAlias() && "not a type alias template specialization"); + return *reinterpret_cast<const QualType*>(end()); + } + typedef const TemplateArgument * iterator; iterator begin() const { return getArgs(); } @@ -3268,12 +3283,14 @@ public: const TemplateArgument &getArg(unsigned Idx) const; // in TemplateBase.h bool isSugared() const { - return !isDependentType() || isCurrentInstantiation(); + return !isDependentType() || isCurrentInstantiation() || isTypeAlias(); } QualType desugar() const { return getCanonicalTypeInternal(); } void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Ctx) { Profile(ID, Template, getArgs(), NumArgs, Ctx); + if (isTypeAlias()) + getAliasedType().Profile(ID); } static void Profile(llvm::FoldingSetNodeID &ID, TemplateName T, diff --git a/clang/include/clang/Basic/DeclNodes.td b/clang/include/clang/Basic/DeclNodes.td index 9e69492e13c..ddd08278c37 100644 --- a/clang/include/clang/Basic/DeclNodes.td +++ b/clang/include/clang/Basic/DeclNodes.td @@ -50,6 +50,7 @@ def Named : Decl<1>; def RedeclarableTemplate : DDecl<Template, 1>; def FunctionTemplate : DDecl<RedeclarableTemplate>; def ClassTemplate : DDecl<RedeclarableTemplate>; + def TypeAliasTemplate : DDecl<RedeclarableTemplate>; def TemplateTemplateParm : DDecl<Template>; def Using : DDecl<Named>; def UsingShadow : DDecl<Named>; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index e2ffe109c82..3a8a708afa0 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -443,6 +443,8 @@ def ext_alias_declaration : ExtWarn< "alias declarations accepted as a C++0x extension">, InGroup<CXX0x>; def err_alias_declaration_not_identifier : Error< "name defined in alias declaration must be an identifier">; +def err_alias_declaration_specialization : Error< + "%select{partial specialization|explicit specialization|explicit instantiation}0 of alias templates is not permitted">; // C++0x override control def ext_override_control_keyword : Extension< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 26dfc884962..8b73f901265 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -544,6 +544,8 @@ def err_type_defined_in_result_type : Error< "%0 can not be defined in the result type of a function">; def err_type_defined_in_param_type : Error< "%0 can not be defined in a parameter type">; +def err_type_defined_in_alias_template : Error< + "%0 can not be defined in a type alias template">; def note_pure_virtual_function : Note< "unimplemented pure virtual method %0 in %1">; @@ -1674,7 +1676,7 @@ def err_template_arg_must_be_expr : Error< def err_template_arg_nontype_ambig : Error< "template argument for non-type template parameter is treated as type %0">; def err_template_arg_must_be_template : Error< - "template argument for template template parameter must be a class template">; + "template argument for template template parameter must be a class template%select{| or type alias template}0">; def ext_template_arg_local_type : ExtWarn< "template argument uses local type %0">, InGroup<LocalTypeTemplateArgs>; def ext_template_arg_unnamed_type : ExtWarn< @@ -1820,6 +1822,8 @@ def err_template_spec_needs_template_parameters : Error< def err_template_param_list_matches_nontemplate : Error< "template parameter list matching the non-templated nested type %0 should " "be empty ('template<>')">; +def err_alias_template_extra_headers : Error< + "extraneous template parameter list in alias template declaration">; def err_template_spec_extra_headers : Error< "extraneous template parameter list in template specialization or " "out-of-line template definition">; @@ -1897,6 +1901,8 @@ def note_function_template_spec_here : Note< "in instantiation of function template specialization %q0 requested here">; def note_template_static_data_member_def_here : Note< "in instantiation of static data member %q0 requested here">; +def note_template_type_alias_instantiation_here : Note< + "in instantiation of template type alias %0 requested here">; def note_default_arg_instantiation_here : Note< "in instantiation of default argument for '%0' required here">; @@ -2034,7 +2040,7 @@ def err_non_type_template_in_nested_name_specifier : Error< def err_template_id_not_a_type : Error< "template name refers to non-type template '%0'">; def note_template_declared_here : Note< - "%select{function template|class template|template template parameter}0 " + "%select{function template|class template|type alias template|template template parameter}0 " "%1 declared here">; // C++0x Variadic Templates @@ -2172,9 +2178,9 @@ def err_redefinition_different_type : Error< def err_redefinition_different_kind : Error< "redefinition of %0 as different kind of symbol">; def err_redefinition_different_typedef : Error< - "%select{typedef|type alias}0 redefinition with different types (%1 vs %2)">; + "%select{typedef|type alias|type alias template}0 redefinition with different types (%1 vs %2)">; def err_tag_reference_non_tag : Error< - "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template}0">; + "elaborated type refers to %select{a non-tag type|a typedef|a type alias|a template|a type alias template}0">; def err_tag_reference_conflict : Error< "implicit declaration introduced by elaborated type conflicts with " "%select{a declaration|a typedef|a type alias|a template}0 of the same name">; diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index 708c9b2084b..8179b63f459 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1332,7 +1332,8 @@ public: CXXCatchContext, // C++ catch exception-declaration BlockLiteralContext, // Block literal declarator. TemplateTypeArgContext, // Template type argument. - AliasDeclContext // C++0x alias-declaration. + AliasDeclContext, // C++0x alias-declaration. + AliasTemplateContext // C++0x alias-declaration template. }; private: @@ -1474,6 +1475,7 @@ public: case TypeNameContext: case AliasDeclContext: + case AliasTemplateContext: case PrototypeContext: case ObjCPrototypeContext: case TemplateParamContext: @@ -1503,6 +1505,7 @@ public: case TypeNameContext: case AliasDeclContext: + case AliasTemplateContext: case ObjCPrototypeContext: case BlockLiteralContext: case TemplateTypeArgContext: @@ -1531,6 +1534,7 @@ public: case CXXCatchContext: case TypeNameContext: case AliasDeclContext: + case AliasTemplateContext: case BlockLiteralContext: case TemplateTypeArgContext: return false; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index fee483b7f90..4f8a61570e7 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -944,6 +944,7 @@ public: void CheckShadow(Scope *S, VarDecl *D, const LookupResult& R); void CheckShadow(Scope *S, VarDecl *D); void CheckCastAlign(Expr *Op, QualType T, SourceRange TRange); + void CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *D); NamedDecl* ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, QualType R, TypeSourceInfo *TInfo, LookupResult &Previous, bool &Redeclaration); @@ -1652,6 +1653,10 @@ public: AssociatedNamespaceSet &AssociatedNamespaces, AssociatedClassSet &AssociatedClasses); + void FilterLookupForScope(LookupResult &R, DeclContext *Ctx, Scope *S, + bool ConsiderLinkage, + bool ExplicitInstantiationOrSpecialization); + bool DiagnoseAmbiguousLookup(LookupResult &Result); //@} @@ -2468,6 +2473,7 @@ public: SourceLocation TypenameLoc); Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParams, SourceLocation UsingLoc, UnqualifiedId &Name, TypeResult Type); @@ -3412,7 +3418,8 @@ public: TPC_FunctionTemplate, TPC_ClassTemplateMember, TPC_FriendFunctionTemplate, - TPC_FriendFunctionTemplateDefinition + TPC_FriendFunctionTemplateDefinition, + TPC_TypeAliasTemplate }; bool CheckTemplateParameterList(TemplateParameterList *NewParams, diff --git a/clang/include/clang/Sema/Template.h b/clang/include/clang/Sema/Template.h index 4d97f9bef80..a257772ee10 100644 --- a/clang/include/clang/Sema/Template.h +++ b/clang/include/clang/Sema/Template.h @@ -335,9 +335,9 @@ namespace clang { Decl *VisitLabelDecl(LabelDecl *D); Decl *VisitNamespaceDecl(NamespaceDecl *D); Decl *VisitNamespaceAliasDecl(NamespaceAliasDecl *D); - Decl *VisitTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias); Decl *VisitTypedefDecl(TypedefDecl *D); Decl *VisitTypeAliasDecl(TypeAliasDecl *D); + Decl *VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); Decl *VisitVarDecl(VarDecl *D); Decl *VisitAccessSpecDecl(AccessSpecDecl *D); Decl *VisitFieldDecl(FieldDecl *D); @@ -415,6 +415,7 @@ namespace clang { bool SubstQualifier(const TagDecl *OldDecl, TagDecl *NewDecl); + Decl *InstantiateTypedefNameDecl(TypedefNameDecl *D, bool IsTypeAlias); ClassTemplatePartialSpecializationDecl * InstantiateClassTemplatePartialSpecialization( ClassTemplateDecl *ClassTemplate, diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index 7b9e98d3437..0b997563f93 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -761,6 +761,8 @@ namespace clang { DECL_NON_TYPE_TEMPLATE_PARM, /// \brief A TemplateTemplateParmDecl record. DECL_TEMPLATE_TEMPLATE_PARM, + /// \brief A TypeAliasTemplateDecl record. + DECL_TYPE_ALIAS_TEMPLATE, /// \brief A StaticAssertDecl record. DECL_STATIC_ASSERT, /// \brief A record containing CXXBaseSpecifiers. diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index d6535e9f8cf..a5ff6644490 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -969,13 +969,18 @@ ASTContext::getTypeInfo(const Type *T) const { return getTypeInfo( cast<AttributedType>(T)->getEquivalentType().getTypePtr()); - case Type::TemplateSpecialization: + case Type::TemplateSpecialization: { assert(getCanonicalType(T) != T && "Cannot request the size of a dependent type"); - // FIXME: this is likely to be wrong once we support template - // aliases, since a template alias could refer to a typedef that - // has an __aligned__ attribute on it. - return getTypeInfo(getCanonicalType(T)); + const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(T); + // A type alias template specialization may refer to a typedef with the + // aligned attribute on it. + if (TST->isTypeAlias()) + return getTypeInfo(TST->getAliasedType().getTypePtr()); + else + return getTypeInfo(getCanonicalType(T)); + } + } assert(Align && (Align & (Align-1)) == 0 && "Alignment must be power of 2"); @@ -2247,10 +2252,10 @@ TypeSourceInfo * ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, SourceLocation NameLoc, const TemplateArgumentListInfo &Args, - QualType CanonType) const { + QualType Underlying) const { assert(!Name.getAsDependentTemplateName() && "No dependent template names here!"); - QualType TST = getTemplateSpecializationType(Name, Args, CanonType); + QualType TST = getTemplateSpecializationType(Name, Args, Underlying); TypeSourceInfo *DI = CreateTypeSourceInfo(TST); TemplateSpecializationTypeLoc TL @@ -2266,7 +2271,7 @@ ASTContext::getTemplateSpecializationTypeInfo(TemplateName Name, QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgumentListInfo &Args, - QualType Canon) const { + QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); @@ -2278,35 +2283,46 @@ ASTContext::getTemplateSpecializationType(TemplateName Template, ArgVec.push_back(Args[i].getArgument()); return getTemplateSpecializationType(Template, ArgVec.data(), NumArgs, - Canon); + Underlying); } QualType ASTContext::getTemplateSpecializationType(TemplateName Template, const TemplateArgument *Args, unsigned NumArgs, - QualType Canon) const { + QualType Underlying) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); - if (!Canon.isNull()) - Canon = getCanonicalType(Canon); - else - Canon = getCanonicalTemplateSpecializationType(Template, Args, NumArgs); + bool isTypeAlias = + Template.getAsTemplateDecl() && + isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl()); + + QualType CanonType; + if (!Underlying.isNull()) + CanonType = getCanonicalType(Underlying); + else { + assert(!isTypeAlias && + "Underlying type for template alias must be computed by caller"); + CanonType = getCanonicalTemplateSpecializationType(Template, Args, + NumArgs); + } // Allocate the (non-canonical) template specialization type, but don't // try to unique it: these types typically have location information that // we don't unique and don't want to lose. - void *Mem = Allocate((sizeof(TemplateSpecializationType) + - sizeof(TemplateArgument) * NumArgs), + void *Mem = Allocate(sizeof(TemplateSpecializationType) + + sizeof(TemplateArgument) * NumArgs + + (isTypeAlias ? sizeof(QualType) : 0), TypeAlignment); TemplateSpecializationType *Spec = new (Mem) TemplateSpecializationType(Template, Args, NumArgs, - Canon); + CanonType, + isTypeAlias ? Underlying : QualType()); Types.push_back(Spec); return QualType(Spec, 0); @@ -2318,6 +2334,10 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, unsigned NumArgs) const { assert(!Template.getAsDependentTemplateName() && "No dependent template names here!"); + assert((!Template.getAsTemplateDecl() || + !isa<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) && + "Underlying type for template alias must be computed by caller"); + // Look through qualified template names. if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Template = TemplateName(QTN->getTemplateDecl()); @@ -2346,7 +2366,7 @@ ASTContext::getCanonicalTemplateSpecializationType(TemplateName Template, TypeAlignment); Spec = new (Mem) TemplateSpecializationType(CanonTemplate, CanonArgs.data(), NumArgs, - QualType()); + QualType(), QualType()); Types.push_back(Spec); TemplateSpecializationTypes.InsertNode(Spec, InsertPos); } diff --git a/clang/lib/AST/ASTDiagnostic.cpp b/clang/lib/AST/ASTDiagnostic.cpp index 897b4a4c1f2..16d2f853606 100644 --- a/clang/lib/AST/ASTDiagnostic.cpp +++ b/clang/lib/AST/ASTDiagnostic.cpp @@ -56,9 +56,11 @@ static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { continue; } - // Don't desugar template specializations. - if (isa<TemplateSpecializationType>(Ty)) - break; + // Don't desugar template specializations, unless it's an alias template. + if (const TemplateSpecializationType *TST + = dyn_cast<TemplateSpecializationType>(Ty)) + if (!TST->isTypeAlias()) + break; // Don't desugar magic Objective-C types. if (QualType(Ty,0) == Context.getObjCIdType() || diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index 6d517c54408..8f3388ee589 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -439,6 +439,7 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case Typedef: case TypeAlias: + case TypeAliasTemplate: case UnresolvedUsingTypename: case TemplateTypeParm: return IDNS_Ordinary | IDNS_Type; diff --git a/clang/lib/AST/DeclTemplate.cpp b/clang/lib/AST/DeclTemplate.cpp index 6272340691b..bc375d0ad2d 100644 --- a/clang/lib/AST/DeclTemplate.cpp +++ b/clang/lib/AST/DeclTemplate.cpp @@ -735,3 +735,34 @@ FriendTemplateDecl *FriendTemplateDecl::Create(ASTContext &Context, EmptyShell Empty) { return new (Context) FriendTemplateDecl(Empty); } + +//===----------------------------------------------------------------------===// +// TypeAliasTemplateDecl Implementation +//===----------------------------------------------------------------------===// + +TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C, + DeclContext *DC, + SourceLocation L, + DeclarationName Name, + TemplateParameterList *Params, + NamedDecl *Decl) { + AdoptTemplateParameterList(Params, DC); + return new (C) TypeAliasTemplateDecl(DC, L, Name, Params, Decl); +} + +TypeAliasTemplateDecl *TypeAliasTemplateDecl::Create(ASTContext &C, + EmptyShell) { + return new (C) TypeAliasTemplateDecl(0, SourceLocation(), DeclarationName(), + 0, 0); +} + +void TypeAliasTemplateDecl::DeallocateCommon(void *Ptr) { + static_cast<Common *>(Ptr)->~Common(); +} +RedeclarableTemplateDecl::CommonBase * +TypeAliasTemplateDecl::newCommon(ASTContext &C) { + Common *CommonPtr = new (C) Common; + C.AddDeallocation(DeallocateCommon, CommonPtr); + return CommonPtr; +} + diff --git a/clang/lib/AST/DumpXML.cpp b/clang/lib/AST/DumpXML.cpp index 7d593bc46f6..8bb39ba470f 100644 --- a/clang/lib/AST/DumpXML.cpp +++ b/clang/lib/AST/DumpXML.cpp @@ -619,7 +619,8 @@ struct XMLDumper : public XMLDeclVisitor<XMLDumper>, // TemplateDecl void visitTemplateDeclChildren(TemplateDecl *D) { visitTemplateParameters(D->getTemplateParameters()); - dispatch(D->getTemplatedDecl()); + if (D->getTemplatedDecl()) + dispatch(D->getTemplatedDecl()); } // FunctionTemplateDecl diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index ed222355939..b0086d92c89 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -1559,13 +1559,13 @@ anyDependentTemplateArguments(const TemplateArgument *Args, unsigned N) { TemplateSpecializationType:: TemplateSpecializationType(TemplateName T, - const TemplateArgument *Args, - unsigned NumArgs, QualType Canon) + const TemplateArgument *Args, unsigned NumArgs, + QualType Canon, QualType AliasedType) : Type(TemplateSpecialization, Canon.isNull()? QualType(this, 0) : Canon, - T.isDependent(), false, T.containsUnexpandedParameterPack()), - Template(T), NumArgs(NumArgs) -{ + Canon.isNull()? T.isDependent() : Canon->isDependentType(), + false, T.containsUnexpandedParameterPack()), + Template(T), NumArgs(NumArgs) { assert(!T.getAsDependentTemplateName() && "Use DependentTemplateSpecializationType for dependent template-name"); assert((!Canon.isNull() || @@ -1576,7 +1576,12 @@ TemplateSpecializationType(TemplateName T, = reinterpret_cast<TemplateArgument *>(this + 1); for (unsigned Arg = 0; Arg < NumArgs; ++Arg) { // Update dependent and variably-modified bits. - if (Args[Arg].isDependent()) + // If the canonical type exists and is non-dependent, the template + // specialization type can be non-dependent even if one of the type + // arguments is. Given: + // template<typename T> using U = int; + // U<T> is always non-dependent, irrespective of the type T. + if (Canon.isNull() && Args[Arg].isDependent()) setDependent(); if (Args[Arg].getKind() == TemplateArgument::Type && Args[Arg].getAsType()->isVariablyModifiedType()) @@ -1586,6 +1591,15 @@ TemplateSpecializationType(TemplateName T, new (&TemplateArgs[Arg]) TemplateArgument(Args[Arg]); } + + // Store the aliased type if this is a type alias template specialization. + bool IsTypeAlias = !AliasedType.isNull(); + assert(IsTypeAlias == isTypeAlias() && + "allocated wrong size for type alias"); + if (IsTypeAlias) { + TemplateArgument *Begin = reinterpret_cast<TemplateArgument *>(this + 1); + *reinterpret_cast<QualType*>(Begin + getNumArgs()) = AliasedType; + } } void @@ -1599,6 +1613,11 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, Args[Idx].Profile(ID, Context); } +bool TemplateSpecializationType::isTypeAlias() const { + TemplateDecl *D = Template.getAsTemplateDecl(); + return D && isa<TypeAliasTemplateDecl>(D); +} + QualType QualifierCollector::apply(const ASTContext &Context, QualType QT) const { if (!hasNonFastQualifiers()) diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index c0273758181..0e1054affdb 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -51,6 +51,7 @@ void CodeGenFunction::EmitDecl(const Decl &D) { case Decl::ImplicitParam: case Decl::ClassTemplate: case Decl::FunctionTemplate: + case Decl::TypeAliasTemplate: case Decl::TemplateTemplateParm: case Decl::ObjCMethod: case Decl::ObjCCategory: diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 4ce12ecd600..4bf1e3ad3e5 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2060,6 +2060,7 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { case Decl::UsingDirective: case Decl::ClassTemplate: case Decl::FunctionTemplate: + case Decl::TypeAliasTemplate: case Decl::NamespaceAlias: break; case Decl::CXXConstructor: diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp index d6e0d3a1c08..3b4f0422918 100644 --- a/clang/lib/Lex/PPMacroExpansion.cpp +++ b/clang/lib/Lex/PPMacroExpansion.cpp @@ -557,6 +557,7 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { .Case("ownership_returns", true) .Case("ownership_takes", true) // C++0x features + .Case("cxx_alias_templates", LangOpts.CPlusPlus0x) .Case("cxx_attributes", LangOpts.CPlusPlus0x) .Case("cxx_auto_type", LangOpts.CPlusPlus0x) .Case("cxx_decltype", LangOpts.CPlusPlus0x) diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 41b773e0074..ae6b3ff011e 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -387,13 +387,34 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, bool IsAliasDecl = Tok.is(tok::equal); TypeResult TypeAlias; if (IsAliasDecl) { - // TODO: Do we want to support attributes somewhere in an alias declaration? - // Can't follow GCC since it doesn't support them yet! + // TODO: Attribute support. C++0x attributes may appear before the equals. + // Where can GNU attributes appear? ConsumeToken(); if (!getLang().CPlusPlus0x) Diag(Tok.getLocation(), diag::ext_alias_declaration); + // Type alias templates cannot be specialized. + int SpecKind = -1; + if (Name.getKind() == UnqualifiedId::IK_TemplateId) + SpecKind = 0; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitSpecialization) + SpecKind = 1; + if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) + SpecKind = 2; + if (SpecKind != -1) { + SourceRange Range; + if (SpecKind == 0) + Range = SourceRange(Name.TemplateId->LAngleLoc, + Name.TemplateId->RAngleLoc); + else + Range = TemplateInfo.getSourceRange(); + Diag(Range.getBegin(), diag::err_alias_declaration_specialization) + << SpecKind << Range; + SkipUntil(tok::semi); + return 0; + } + // Name must be an identifier. if (Name.getKind() != UnqualifiedId::IK_Identifier) { Diag(Name.StartLocation, diag::err_alias_declaration_not_identifier); @@ -408,7 +429,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, Diag(SS.getBeginLoc(), diag::err_alias_declaration_not_identifier) << FixItHint::CreateRemoval(SS.getRange()); - TypeAlias = ParseTypeName(0, Declarator::AliasDeclContext); + TypeAlias = ParseTypeName(0, TemplateInfo.Kind ? + Declarator::AliasTemplateContext : + Declarator::AliasDeclContext); } else // Parse (optional) attributes (most likely GNU strong-using extension). MaybeParseGNUAttributes(attrs); @@ -421,9 +444,9 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, tok::semi); // Diagnose an attempt to declare a templated using-declaration. - // TODO: in C++0x, alias-declarations can be templates: + // In C++0x, alias-declarations can be templates: // template <...> using id = type; - if (TemplateInfo.Kind) { + if (TemplateInfo.Kind && !IsAliasDecl) { SourceRange R = TemplateInfo.getSourceRange(); Diag(UsingLoc, diag::err_templated_using_declaration) << R << FixItHint::CreateRemoval(R); @@ -434,9 +457,14 @@ Decl *Parser::ParseUsingDeclaration(unsigned Context, return 0; } - if (IsAliasDecl) - return Actions.ActOnAliasDeclaration(getCurScope(), AS, UsingLoc, Name, - TypeAlias); + if (IsAliasDecl) { + TemplateParameterLists *TemplateParams = TemplateInfo.TemplateParams; + MultiTemplateParamsArg TemplateParamsArg(Actions, + TemplateParams ? TemplateParams->data() : 0, + TemplateParams ? TemplateParams->size() : 0); + return Actions.ActOnAliasDeclaration(getCurScope(), AS, TemplateParamsArg, + UsingLoc, Name, TypeAlias); + } return Actions.ActOnUsingDeclaration(getCurScope(), AS, true, UsingLoc, SS, Name, attrs.getList(), @@ -1515,8 +1543,6 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, MaybeParseMicrosoftAttributes(attrs); if (Tok.is(tok::kw_using)) { - // FIXME: Check for template aliases - ProhibitAttributes(attrs); // Eat 'using'. @@ -1527,7 +1553,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, SkipUntil(tok::semi, true, true); } else { SourceLocation DeclEnd; - // Otherwise, it must be using-declaration. + // Otherwise, it must be a using-declaration or an alias-declaration. ParseUsingDeclaration(Declarator::MemberContext, TemplateInfo, UsingLoc, DeclEnd, AS); } diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 12e38daf002..aa89d75c6d1 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -905,10 +905,10 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { // C++0x [temp.arg.template]p1: // A template-argument for a template template-parameter shall be the name - // of a class template or a template alias, expressed as id-expression. + // of a class template or an alias template, expressed as id-expression. // - // We parse an id-expression that refers to a class template or template - // alias. The grammar we parse is: + // We parse an id-expression that refers to a class template or alias + // template. The grammar we parse is: // // nested-name-specifier[opt] template[opt] identifier ...[opt] // @@ -969,7 +969,7 @@ ParsedTemplateArgument Parser::ParseTemplateTemplateArgument() { MemberOfUnknownSpecialization); if (TNK == TNK_Dependent_template_name || TNK == TNK_Type_template) { // We have an id-expression that refers to a class template or - // (C++0x) template alias. + // (C++0x) alias template. Result = ParsedTemplateArgument(SS, Template, Name.StartLocation); } } diff --git a/clang/lib/Sema/SemaAccess.cpp b/clang/lib/Sema/SemaAccess.cpp index 411d424dd8d..63983c3daf9 100644 --- a/clang/lib/Sema/SemaAccess.cpp +++ b/clang/lib/Sema/SemaAccess.cpp @@ -445,8 +445,8 @@ static AccessResult MatchesFriend(Sema &S, continue; // If the template names don't match, it can't be a dependent - // match. This isn't true in C++0x because of template aliases. - if (!S.LangOpts.CPlusPlus0x && CTD->getDeclName() != Friend->getDeclName()) + // match. + if (CTD->getDeclName() != Friend->getDeclName()) continue; // If the class's context can't instantiate to the friend's diff --git a/clang/lib/Sema/SemaCXXScopeSpec.cpp b/clang/lib/Sema/SemaCXXScopeSpec.cpp index 5ee256ab216..ff3890023e5 100644 --- a/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -94,9 +94,13 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, if (EnteringContext) { const Type *NNSType = NNS->getAsType(); if (!NNSType) { - // do nothing, fall out - } else if (const TemplateSpecializationType *SpecType - = NNSType->getAs<TemplateSpecializationType>()) { + return 0; + } + + // Look through type alias templates, per C++0x [temp.dep.type]p1. + NNSType = Context.getCanonicalType(NNSType); + if (const TemplateSpecializationType *SpecType + = NNSType->getAs<TemplateSpecializationType>()) { // We are entering the context of the nested name specifier, so try to // match the nested name specifier to either a primary class template // or a class template partial specialization. @@ -382,7 +386,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, isDependent = ObjectType->isDependentType(); } else if (SS.isSet()) { // This nested-name-specifier occurs after another nested-name-specifier, - // so long into the context associated with the prior nested-name-specifier. + // so look into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); isDependent = isDependentScopeSpecifier(SS); Found.setContextRange(SS.getRange()); @@ -712,8 +716,13 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, if (T.isNull()) return true; - // FIXME: Template aliases will need to check the resulting type to make - // sure that it's either dependent or a tag type. + // Alias template specializations can produce types which are not valid + // nested name specifiers. + if (!T->isDependentType() && !T->getAs<TagType>()) { + Diag(TemplateNameLoc, diag::err_nested_name_spec_non_tag) << T; + NoteAllFoundTemplates(Template.get()); + return true; + } // Provide source-location information for the template specialization // type. diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 6231fbd1117..7845247a249 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -891,19 +891,19 @@ static bool isOutOfScopePreviousDeclaration(NamedDecl *, /// Filters out lookup results that don't fall within the given scope /// as determined by isDeclInScope. -static void FilterLookupForScope(Sema &SemaRef, LookupResult &R, - DeclContext *Ctx, Scope *S, - bool ConsiderLinkage, - bool ExplicitInstantiationOrSpecialization) { +void Sema::FilterLookupForScope(LookupResult &R, + DeclContext *Ctx, Scope *S, + bool ConsiderLinkage, + bool ExplicitInstantiationOrSpecialization) { LookupResult::Filter F = R.makeFilter(); while (F.hasNext()) { NamedDecl *D = F.next(); - if (SemaRef.isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization)) + if (isDeclInScope(D, Ctx, S, ExplicitInstantiationOrSpecialization)) continue; if (ConsiderLinkage && - isOutOfScopePreviousDeclaration(D, Ctx, SemaRef.Context)) + isOutOfScopePreviousDeclaration(D, Ctx, Context)) continue; F.erase(); @@ -3304,15 +3304,13 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewTD, D); + CheckTypedefForVariablyModifiedType(S, NewTD); + return ActOnTypedefNameDecl(S, DC, NewTD, Previous, Redeclaration); } -/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which -/// declares a typedef-name, either using the 'typedef' type specifier or via -/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. -NamedDecl* -Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, - LookupResult &Previous, bool &Redeclaration) { +void +Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { // C99 6.7.7p2: If a typedef name specifies a variably modified type // then it shall have block scope. // Note that variably modified types must be fixed before merging the decl so @@ -3343,10 +3341,18 @@ Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, } } } +} + +/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which +/// declares a typedef-name, either using the 'typedef' type specifier or via +/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. +NamedDecl* +Sema::ActOnTypedefNameDecl(Scope *S, DeclContext *DC, TypedefNameDecl *NewTD, + LookupResult &Previous, bool &Redeclaration) { // Merge the decl with the existing one if appropriate. If the decl is // in an outer scope, it isn't the same thing. - FilterLookupForScope(*this, Previous, DC, S, /*ConsiderLinkage*/ false, + FilterLookupForScope(Previous, DC, S, /*ConsiderLinkage*/ false, /*ExplicitInstantiationOrSpecialization=*/false); if (!Previous.empty()) { Redeclaration = true; @@ -3625,7 +3631,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Don't consider existing declarations that are in a different // scope and are out-of-semantic-context declarations (if the new // declaration has linkage). - FilterLookupForScope(*this, Previous, DC, S, NewVD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewVD->hasLinkage(), isExplicitSpecialization); if (!getLangOptions().CPlusPlus) @@ -4072,7 +4078,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // Set the lexical context. NewFD->setLexicalDeclContext(CurContext); // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), /*ExplicitInstantiationOrSpecialization=*/false); } else { isFriend = D.getDeclSpec().isFriendSpecified(); @@ -4350,7 +4356,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, } // Filter out previous declarations that don't match the scope. - FilterLookupForScope(*this, Previous, DC, S, NewFD->hasLinkage(), + FilterLookupForScope(Previous, DC, S, NewFD->hasLinkage(), isExplicitSpecialization || isFunctionTemplateSpecialization); @@ -4417,6 +4423,9 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, bool IsTypeAlias = false; if (const TypedefType *TT = Param->getType()->getAs<TypedefType>()) IsTypeAlias = isa<TypeAliasDecl>(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + Param->getType()->getAs<TemplateSpecializationType>()) + IsTypeAlias = TST->isTypeAlias(); Diag(Param->getLocation(), diag::err_param_typedef_of_void) << IsTypeAlias; } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 2ef15b672d3..6dad78442dd 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -3467,6 +3467,11 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>()) Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl()); + else if (const TemplateSpecializationType *TST = + DeclaratorType->getAs<TemplateSpecializationType>()) + if (TST->isTypeAlias()) + Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + << DeclaratorType << 1; // C++ [class.dtor]p2: // A destructor is used to destroy objects of its class type. A @@ -4701,9 +4706,13 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS, + MultiTemplateParamsArg TemplateParamLists, SourceLocation UsingLoc, UnqualifiedId &Name, TypeResult Type) { + // Skip up to the relevant declaration scope. + while (S->getFlags() & Scope::TemplateParamScope) + S = S->getParent(); assert((S->getFlags() & Scope::DeclScope) && "got alias-declaration outside of declaration scope"); @@ -4719,8 +4728,11 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, return 0; if (DiagnoseUnexpandedParameterPack(Name.StartLocation, TInfo, - UPPC_DeclarationType)) + UPPC_DeclarationType)) { Invalid = true; + TInfo = Context.getTrivialTypeSourceInfo(Context.IntTy, + TInfo->getTypeLoc().getBeginLoc()); + } LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); LookupName(Previous, S); @@ -4745,13 +4757,93 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, if (Invalid) NewTD->setInvalidDecl(); + CheckTypedefForVariablyModifiedType(S, NewTD); + Invalid |= NewTD->isInvalidDecl(); + bool Redeclaration = false; - ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration); + + NamedDecl *NewND; + if (TemplateParamLists.size()) { + TypeAliasTemplateDecl *OldDecl = 0; + TemplateParameterList *OldTemplateParams = 0; + + if (TemplateParamLists.size() != 1) { + Diag(UsingLoc, diag::err_alias_template_extra_headers) + << SourceRange(TemplateParamLists.get()[1]->getTemplateLoc(), + TemplateParamLists.get()[TemplateParamLists.size()-1]->getRAngleLoc()); + } + TemplateParameterList *TemplateParams = TemplateParamLists.get()[0]; + + // Only consider previous declarations in the same scope. + FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false, + /*ExplicitInstantiationOrSpecialization*/false); + if (!Previous.empty()) { + Redeclaration = true; + + OldDecl = Previous.getAsSingle<TypeAliasTemplateDecl>(); + if (!OldDecl && !Invalid) { + Diag(UsingLoc, diag::err_redefinition_different_kind) + << Name.Identifier; + + NamedDecl *OldD = Previous.getRepresentativeDecl(); + if (OldD->getLocation().isValid()) + Diag(OldD->getLocation(), diag::note_previous_definition); + + Invalid = true; + } + + if (!Invalid && OldDecl && !OldDecl->isInvalidDecl()) { + if (TemplateParameterListsAreEqual(TemplateParams, + OldDecl->getTemplateParameters(), + /*Complain=*/true, + TPL_TemplateMatch)) + OldTemplateParams = OldDecl->getTemplateParameters(); + else + Invalid = true; + + TypeAliasDecl *OldTD = OldDecl->getTemplatedDecl(); + if (!Invalid && + !Context.hasSameType(OldTD->getUnderlyingType(), + NewTD->getUnderlyingType())) { + // FIXME: The C++0x standard does not clearly say this is ill-formed, + // but we can't reasonably accept it. + Diag(NewTD->getLocation(), diag::err_redefinition_different_typedef) + << 2 << NewTD->getUnderlyingType() << OldTD->getUnderlyingType(); + if (OldTD->getLocation().isValid()) + Diag(OldTD->getLocation(), diag::note_previous_definition); + Invalid = true; + } + } + } + + // Merge any previous default template arguments into our parameters, + // and check the parameter list. + if (CheckTemplateParameterList(TemplateParams, OldTemplateParams, + TPC_TypeAliasTemplate)) + return 0; + + TypeAliasTemplateDecl *NewDecl = + TypeAliasTemplateDecl::Create(Context, CurContext, UsingLoc, + Name.Identifier, TemplateParams, + NewTD); + + NewDecl->setAccess(AS); + + if (Invalid) + NewDecl->setInvalidDecl(); + else if (OldDecl) + NewDecl->setPreviousDeclaration(OldDecl); + + NewND = NewDecl; + } else { + ActOnTypedefNameDecl(S, CurContext, NewTD, Previous, Redeclaration); + NewND = NewTD; + } if (!Redeclaration) - PushOnScopeChains(NewTD, S); + PushOnScopeChains(NewND, S); - return NewTD; + return NewND; } Decl *Sema::ActOnNamespaceAliasDef(Scope *S, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 7a4e54de0f7..09431650f26 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -92,11 +92,9 @@ void Sema::FilterAcceptableTemplateNames(LookupResult &R) { // ambiguity in certain cases (for example, if it is found in more than // one base class). If all of the injected-class-names that are found // refer to specializations of the same class template, and if the name - // is followed by a template-argument-list, the reference refers to the - // class template itself and not a specialization thereof, and is not + // is used as a template-name, the reference refers to the class + // template itself and not a specialization thereof, and is not // ambiguous. - // - // FIXME: Will we eventually have to do the same for alias templates? if (ClassTemplateDecl *ClassTmpl = dyn_cast<ClassTemplateDecl>(Repl)) if (!ClassTemplates.insert(ClassTmpl)) { filter.erase(); @@ -199,7 +197,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, // We'll do this lookup again later. R.suppressDiagnostics(); } else { - assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD)); + assert(isa<ClassTemplateDecl>(TD) || isa<TemplateTemplateParmDecl>(TD) || + isa<TypeAliasTemplateDecl>(TD)); TemplateKind = TNK_Type_template; } } @@ -1062,6 +1061,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, SourceRange DefArgRange) { switch (TPC) { case Sema::TPC_ClassTemplate: + case Sema::TPC_TypeAliasTemplate: return false; case Sema::TPC_FunctionTemplate: @@ -1187,9 +1187,10 @@ bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, bool MissingDefaultArg = false; // C++0x [temp.param]p11: - // If a template parameter of a primary class template is a template - // parameter pack, it shall be the last template parameter. - if (SawParameterPack && TPC == TPC_ClassTemplate) { + // If a template parameter of a primary class template or alias template + // is a template parameter pack, it shall be the last template parameter. + if (SawParameterPack && + (TPC == TPC_ClassTemplate || TPC == TPC_TypeAliasTemplate)) { Diag(ParameterPackLoc, diag::err_template_param_pack_must_be_last_template_parameter); Invalid = true; @@ -1655,7 +1656,8 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { Diag(Template->getLocation(), diag::note_template_declared_here) << (isa<FunctionTemplateDecl>(Template)? 0 : isa<ClassTemplateDecl>(Template)? 1 - : 2) + : isa<TypeAliasTemplateDecl>(Template)? 2 + : 3) << Template->getDeclName(); return; } @@ -1675,13 +1677,24 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { QualType Sema::CheckTemplateIdType(TemplateName Name, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { + DependentTemplateName *DTN = Name.getAsDependentTemplateName(); + if (DTN && DTN->isIdentifier()) + // When building a template-id where the template-name is dependent, + // assume the template is a type template. Either our assumption is + // correct, or the code is ill-formed and will be diagnosed when the + // dependent name is substituted. + return Context.getDependentTemplateSpecializationType(ETK_None, + DTN->getQualifier(), + DTN->getIdentifier(), + TemplateArgs); + TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa<FunctionTemplateDecl>(Template)) { // We might have a substituted template template parameter pack. If so, // build a template specialization type for it. if (Name.getAsSubstTemplateTemplateParmPack()) return Context.getTemplateSpecializationType(Name, TemplateArgs); - + Diag(TemplateLoc, diag::err_template_id_not_a_type) << Name; NoteAllFoundTemplates(Name); @@ -1700,9 +1713,29 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, QualType CanonType; - if (Name.isDependent() || - TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs)) { + if (TypeAliasTemplateDecl *AliasTemplate + = dyn_cast<TypeAliasTemplateDecl>(Template)) { + // Find the canonical type for this type alias template specialization. + TypeAliasDecl *Pattern = AliasTemplate->getTemplatedDecl(); + if (Pattern->isInvalidDecl()) + return QualType(); + + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, + Converted.data(), Converted.size()); + + // Only substitute for the innermost template argument list. + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(&TemplateArgs); + + InstantiatingTemplate Inst(*this, TemplateLoc, Template); + CanonType = SubstType(Pattern->getUnderlyingType(), + TemplateArgLists, AliasTemplate->getLocation(), + AliasTemplate->getDeclName()); + if (CanonType.isNull()) + return QualType(); + } else if (Name.isDependent() || + TemplateSpecializationType::anyDependentTemplateArguments( + TemplateArgs)) { // This class template specialization is a dependent // type. Therefore, its canonical type is another class template // specialization type that contains all of the converted @@ -1894,6 +1927,16 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } + + if (TypeAliasTemplateDecl *TAT = + dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) { + // C++0x [dcl.type.elab]p2: + // If the identifier resolves to a typedef-name or the simple-template-id + // resolves to an alias template specialization, the + // elaborated-type-specifier is ill-formed. + Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4; + Diag(TAT->getLocation(), diag::note_declared_at); + } QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) @@ -2485,7 +2528,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, } // We have a template argument that actually does refer to a class - // template, template alias, or template template parameter, and + // template, alias template, or template template parameter, and // therefore cannot be a non-type template argument. Diag(Arg.getLocation(), diag::err_template_arg_must_be_expr) << Arg.getSourceRange(); @@ -2562,7 +2605,8 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, case TemplateArgument::Type: // We have a template template parameter but the template // argument does not refer to a template. - Diag(Arg.getLocation(), diag::err_template_arg_must_be_template); + Diag(Arg.getLocation(), diag::err_template_arg_must_be_template) + << getLangOptions().CPlusPlus0x; return true; case TemplateArgument::Declaration: @@ -3722,9 +3766,10 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, return false; } - // C++ [temp.arg.template]p1: + // C++0x [temp.arg.template]p1: // A template-argument for a template template-parameter shall be - // the name of a class template, expressed as id-expression. Only + // the name of a class template or an alias template, expressed as an + // id-expression. When the template-argument names a class template, only // primary class templates are considered when matching the // template template argument with the corresponding parameter; // partial specializations are not considered even if their @@ -3734,7 +3779,8 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, // will happen when we are dealing with, e.g., class template // partial specializations. if (!isa<ClassTemplateDecl>(Template) && - !isa<TemplateTemplateParmDecl>(Template)) { + !isa<TemplateTemplateParmDecl>(Template) && + !isa<TypeAliasTemplateDecl>(Template)) { assert(isa<FunctionTemplateDecl>(Template) && "Only function templates are possible here"); Diag(Arg.getLocation(), diag::err_template_arg_not_class_template); @@ -4051,7 +4097,7 @@ Sema::TemplateParameterListsAreEqual(TemplateParameterList *New, // C++0x [temp.arg.template]p3: // A template-argument matches a template template-parameter (call it P) // when each of the template parameters in the template-parameter-list of - // the template-argument's corresponding class template or template alias + // the template-argument's corresponding class template or alias template // (call it A) matches the corresponding template parameter in the // template-parameter-list of P. [...] TemplateParameterList::iterator NewParm = New->begin(); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 92ba095cd6c..3e1e735c85b 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -446,10 +446,15 @@ void Sema::PrintInstantiationStack() { Diags.Report(Active->PointOfInstantiation, DiagID) << Function << Active->InstantiationRange; - } else { + } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { Diags.Report(Active->PointOfInstantiation, diag::note_template_static_data_member_def_here) - << cast<VarDecl>(D) + << VD + << Active->InstantiationRange; + } else { + Diags.Report(Active->PointOfInstantiation, + diag::note_template_type_alias_instantiation_here) + << cast<TypeAliasTemplateDecl>(D) << Active->InstantiationRange; } break; @@ -968,8 +973,7 @@ TemplateName TemplateInstantiator::TransformTemplateName(CXXScopeSpec &SS, } TemplateName Template = Arg.getAsTemplate(); - assert(!Template.isNull() && Template.getAsTemplateDecl() && - "Wrong kind of template template argument"); + assert(!Template.isNull() && "Null template template argument"); // We don't ever want to substitute for a qualified template name, since // the qualifier is handled separately. So, look through the qualified diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 6fa208f6f85..2c0c7ae90ff 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -128,8 +128,8 @@ TemplateDeclInstantiator::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { return Inst; } -Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D, - bool IsTypeAlias) { +Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, + bool IsTypeAlias) { bool Invalid = false; TypeSourceInfo *DI = D->getTypeSourceInfo(); if (DI->getType()->isDependentType() || @@ -178,17 +178,62 @@ Decl *TemplateDeclInstantiator::VisitTypedefNameDecl(TypedefNameDecl *D, SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef); Typedef->setAccess(D->getAccess()); - Owner->addDecl(Typedef); return Typedef; } Decl *TemplateDeclInstantiator::VisitTypedefDecl(TypedefDecl *D) { - return VisitTypedefNameDecl(D, /*IsTypeAlias=*/false); + Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/false); + Owner->addDecl(Typedef); + return Typedef; } Decl *TemplateDeclInstantiator::VisitTypeAliasDecl(TypeAliasDecl *D) { - return VisitTypedefNameDecl(D, /*IsTypeAlias=*/true); + Decl *Typedef = InstantiateTypedefNameDecl(D, /*IsTypeAlias=*/true); + Owner->addDecl(Typedef); + return Typedef; +} + +Decl * +TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + // Create a local instantiation scope for this type alias template, which + // will contain the instantiations of the template parameters. + LocalInstantiationScope Scope(SemaRef); + + TemplateParameterList *TempParams = D->getTemplateParameters(); + TemplateParameterList *InstParams = SubstTemplateParams(TempParams); + if (!InstParams) + return 0; + + TypeAliasDecl *Pattern = D->getTemplatedDecl(); + + TypeAliasTemplateDecl *PrevAliasTemplate = 0; + if (Pattern->getPreviousDeclaration()) { + DeclContext::lookup_result Found = Owner->lookup(Pattern->getDeclName()); + if (Found.first != Found.second) { + PrevAliasTemplate = dyn_cast<TypeAliasTemplateDecl>(*Found.first); + } + } + + TypeAliasDecl *AliasInst = cast_or_null<TypeAliasDecl>( + InstantiateTypedefNameDecl(Pattern, /*IsTypeAlias=*/true)); + if (!AliasInst) + return 0; + + TypeAliasTemplateDecl *Inst + = TypeAliasTemplateDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getDeclName(), InstParams, AliasInst); + if (PrevAliasTemplate) + Inst->setPreviousDeclaration(PrevAliasTemplate); + + Inst->setAccess(D->getAccess()); + + if (!PrevAliasTemplate) + Inst->setInstantiatedFromMemberTemplate(D); + + Owner->addDecl(Inst); + + return Inst; } /// \brief Instantiate an initializer, breaking it into separate diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 00ac1d63dbe..06548a44ddb 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -1601,6 +1601,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, Error = 7; // Template type argument break; case Declarator::AliasDeclContext: + case Declarator::AliasTemplateContext: Error = 9; // Type alias break; case Declarator::TypeNameContext: @@ -1659,7 +1660,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // Does this declaration declare a typedef-name? bool IsTypedefName = D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef || - D.getContext() == Declarator::AliasDeclContext; + D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext; // Walk the DeclTypeInfo, building the recursive type as we go. // DeclTypeInfos are ordered from the identifier out, which is @@ -1839,7 +1841,8 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, // anyway. if (IsTypedefName && FTI.getExceptionSpecType()) Diag(FTI.getExceptionSpecLoc(), diag::err_exception_spec_in_typedef) - << (D.getContext() == Declarator::AliasDeclContext); + << (D.getContext() == Declarator::AliasDeclContext || + D.getContext() == Declarator::AliasTemplateContext); if (!FTI.NumArgs && !FTI.isVariadic && !getLangOptions().CPlusPlus) { // Simple void foo(), where the incoming T is the result type. @@ -2204,6 +2207,7 @@ TypeSourceInfo *Sema::GetTypeForDeclarator(Declarator &D, Scope *S, case Declarator::ObjCPrototypeContext: // FIXME: special diagnostic here? case Declarator::TypeNameContext: case Declarator::AliasDeclContext: + case Declarator::AliasTemplateContext: case Declarator::MemberContext: case Declarator::BlockContext: case Declarator::ForContext: @@ -2640,13 +2644,17 @@ TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) { CheckExtraCXXDefaultArguments(D); // C++0x [dcl.type]p3: - // A type-specifier-seq shall not define a class or enumeration - // unless it appears in the type-id of an alias-declaration - // (7.1.3). - if (OwnedTag && OwnedTag->isDefinition() && - D.getContext() != Declarator::AliasDeclContext) - Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) - << Context.getTypeDeclType(OwnedTag); + // A type-specifier-seq shall not define a class or enumeration unless + // it appears in the type-id of an alias-declaration (7.1.3) that is not + // the declaration of a template-declaration. + if (OwnedTag && OwnedTag->isDefinition()) { + if (D.getContext() == Declarator::AliasTemplateContext) + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_alias_template) + << Context.getTypeDeclType(OwnedTag); + else if (D.getContext() != Declarator::AliasDeclContext) + Diag(OwnedTag->getLocation(), diag::err_type_defined_in_type_specifier) + << Context.getTypeDeclType(OwnedTag); + } } return CreateParsedType(T, TInfo); diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 4bb18417164..da60fccf7ed 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -21,6 +21,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -855,7 +856,7 @@ public: case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: { - NamedDecl *SomeDecl = Result.getRepresentativeDecl(); + NamedDecl *SomeDecl = Result.getRepresentativeDecl(); unsigned Kind = 0; if (isa<TypedefDecl>(SomeDecl)) Kind = 1; else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2; @@ -863,7 +864,7 @@ public: SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind; SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at); break; - } + } default: // FIXME: Would be nice to highlight just the source range. SemaRef.Diag(IdLoc, diag::err_not_tag_in_scope) @@ -4389,6 +4390,23 @@ QualType TreeTransform<Derived>::TransformTemplateSpecializationType( NewTemplateArgs); if (!Result.isNull()) { + // Specializations of template template parameters are represented as + // TemplateSpecializationTypes, and substitution of type alias templates + // within a dependent context can transform them into + // DependentTemplateSpecializationTypes. + if (isa<DependentTemplateSpecializationType>(Result)) { + DependentTemplateSpecializationTypeLoc NewTL + = TLB.push<DependentTemplateSpecializationTypeLoc>(Result); + NewTL.setKeywordLoc(TL.getTemplateNameLoc()); + NewTL.setQualifierLoc(NestedNameSpecifierLoc()); + NewTL.setNameLoc(TL.getTemplateNameLoc()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned i = 0, e = NewTemplateArgs.size(); i != e; ++i) + NewTL.setArgLocInfo(i, NewTemplateArgs[i].getLocInfo()); + return Result; + } + TemplateSpecializationTypeLoc NewTL = TLB.push<TemplateSpecializationTypeLoc>(Result); NewTL.setTemplateNameLoc(TL.getTemplateNameLoc()); @@ -4478,6 +4496,21 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, if (NamedT.isNull()) return QualType(); + // C++0x [dcl.type.elab]p2: + // If the identifier resolves to a typedef-name or the simple-template-id + // resolves to an alias template specialization, the + // elaborated-type-specifier is ill-formed. + if (const TemplateSpecializationType *TST = + NamedT->getAs<TemplateSpecializationType>()) { + TemplateName Template = TST->getTemplateName(); + if (TypeAliasTemplateDecl *TAT = + dyn_cast_or_null<TypeAliasTemplateDecl>(Template.getAsTemplateDecl())) { + SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(), + diag::err_tag_reference_non_tag) << 4; + SemaRef.Diag(TAT->getLocation(), diag::note_declared_at); + } + } + QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || QualifierLoc != TL.getQualifierLoc() || diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index 45a771a4724..bad18ff02e2 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -3366,14 +3366,14 @@ QualType ASTReader::ReadTypeRecord(unsigned Index) { TemplateName Name = ReadTemplateName(*Loc.F, Record, Idx); llvm::SmallVector<TemplateArgument, 8> Args; ReadTemplateArgumentList(Args, *Loc.F, Record, Idx); - QualType Canon = GetType(Record[Idx++]); + QualType Underlying = GetType(Record[Idx++]); QualType T; - if (Canon.isNull()) + if (Underlying.isNull()) T = Context->getCanonicalTemplateSpecializationType(Name, Args.data(), Args.size()); else T = Context->getTemplateSpecializationType(Name, Args.data(), - Args.size(), Canon); + Args.size(), Underlying); const_cast<Type*>(T.getTypePtr())->setDependent(IsDependent); return T; } diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 3a825de6e6d..2b82f90ae31 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -125,6 +125,7 @@ namespace clang { void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); @@ -1266,6 +1267,10 @@ void ASTDeclReader::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { D->ParameterPack = Record[Idx++]; } +void ASTDeclReader::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + VisitRedeclarableTemplateDecl(D); +} + void ASTDeclReader::VisitStaticAssertDecl(StaticAssertDecl *D) { VisitDecl(D); D->AssertExpr = Reader.ReadExpr(F); @@ -1572,6 +1577,9 @@ Decl *ASTReader::ReadDeclRecord(unsigned Index, DeclID ID) { D = TemplateTemplateParmDecl::Create(*Context, 0, SourceLocation(), 0, 0, false, 0, 0); break; + case DECL_TYPE_ALIAS_TEMPLATE: + D = TypeAliasTemplateDecl::Create(*Context, Decl::EmptyShell()); + break; case DECL_STATIC_ASSERT: D = StaticAssertDecl::Create(*Context, 0, SourceLocation(), 0, 0, SourceLocation()); diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index be415015ee7..1c62bfd72ab 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -277,7 +277,8 @@ ASTTypeWriter::VisitTemplateSpecializationType( for (TemplateSpecializationType::iterator ArgI = T->begin(), ArgE = T->end(); ArgI != ArgE; ++ArgI) Writer.AddTemplateArgument(*ArgI, Record); - Writer.AddTypeRef(T->isCanonicalUnqualified() ? QualType() + Writer.AddTypeRef(T->isTypeAlias() ? T->getAliasedType() : + T->isCanonicalUnqualified() ? QualType() : T->getCanonicalTypeInternal(), Record); Code = TYPE_TEMPLATE_SPECIALIZATION; diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index 1ca00a32f82..dbcbadb6864 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -86,6 +86,7 @@ namespace clang { void VisitClassTemplateDecl(ClassTemplateDecl *D); void VisitFunctionTemplateDecl(FunctionTemplateDecl *D); void VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); + void VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitLinkageSpecDecl(LinkageSpecDecl *D); @@ -1081,6 +1082,11 @@ void ASTDeclWriter::VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D) { Code = serialization::DECL_TEMPLATE_TEMPLATE_PARM; } +void ASTDeclWriter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { + VisitRedeclarableTemplateDecl(D); + Code = serialization::DECL_TYPE_ALIAS_TEMPLATE; +} + void ASTDeclWriter::VisitStaticAssertDecl(StaticAssertDecl *D) { VisitDecl(D); Writer.AddStmt(D->getAssertExpr()); diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp new file mode 100644 index 00000000000..5fc0fe0411c --- /dev/null +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/dcl.type.elab/p2-0x.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +struct A { }; +template<typename T> using X = A; // expected-note {{declared here}} +struct X<int>* p2; // expected-error {{elaborated type refers to a type alias template}} + + +template<typename T> using Id = T; // expected-note {{declared here}} +template<template<typename> class F> +struct Y { + struct F<int> i; // expected-error {{elaborated type refers to a type alias template}} +}; +template struct Y<Id>; // expected-note {{requested here}} diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp index 10184a058f1..8b278bf2a22 100644 --- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.type/p3-0x.cpp @@ -1,10 +1,9 @@ // RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s -// FIXME: when clang supports alias-declarations. -#if 0 using X = struct { // ok }; -#endif +template<typename T> using Y = struct { // expected-error {{can not be defined in a type alias template}} +}; class K { virtual ~K(); diff --git a/clang/test/CXX/temp/temp.decls/p3.cpp b/clang/test/CXX/temp/temp.decls/p3.cpp new file mode 100644 index 00000000000..21c82e6f227 --- /dev/null +++ b/clang/test/CXX/temp/temp.decls/p3.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +template<typename T> using A = int; +template<typename T> using A<T*> = char; // expected-error {{partial specialization of alias templates is not permitted}} +template<> using A<char> = char; // expected-error {{explicit specialization of alias templates is not permitted}} +template using A<char> = char; // expected-error {{explicit instantiation of alias templates is not permitted}} +// Best guess as to what the user was trying to do: missing template<>. +using A<char> = char; // expected-error {{partial specialization of alias templates is not permitted}} diff --git a/clang/test/CXX/temp/temp.decls/temp.alias/p1.cpp b/clang/test/CXX/temp/temp.decls/temp.alias/p1.cpp new file mode 100644 index 00000000000..80079b33a53 --- /dev/null +++ b/clang/test/CXX/temp/temp.decls/temp.alias/p1.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +template<typename T> using U = T; + +// The name of the alias template is a template-name. +U<char> x; +void f(U<int>); +typedef U<U<U<U<int>>>> I; diff --git a/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp b/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp new file mode 100644 index 00000000000..e145727a8dd --- /dev/null +++ b/clang/test/CXX/temp/temp.decls/temp.alias/p2.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +template<typename T> using U = T; + +using I = U<U<U<U<int>>>>; +using I = int; + +template<typename A, typename B> using Fst = A; +template<typename A, typename B> using Snd = B; + +using I = Fst<Snd<char,int>,double>; + +namespace StdExample { + // Prerequisites for example. + template<class T, class A> struct vector { /* ... */ }; + + + template<class T> struct Alloc {}; + template<class T> using Vec = vector<T, Alloc<T>>; + Vec<int> v; + + template<class T> + void process(Vec<T>& v) // expected-note {{previous definition is here}} + { /* ... */ } + + template<class T> + void process(vector<T, Alloc<T>>& w) // expected-error {{redefinition of 'process'}} + { /* ... */ } + + template<template<class> class TT> + void f(TT<int>); // expected-note {{candidate template ignored}} + + template<template<class,class> class TT> + void g(TT<int, Alloc<int>>); + + int h() { + f(v); // expected-error {{no matching function for call to 'f'}} + g(v); // OK: TT = vector + } + + + // v's type is same as vector<int, Alloc<int>>. + using VTest = vector<int, Alloc<int>>; + using VTest = decltype(v); +} diff --git a/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp b/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp new file mode 100644 index 00000000000..2e9e55cdcb6 --- /dev/null +++ b/clang/test/CXX/temp/temp.decls/temp.alias/p3.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +// The example given in the standard (this is rejected for other reasons anyway). +template<class T> struct A; +template<class T> using B = typename A<T>::U; // expected-error {{no type named 'U' in 'A<T>'}} +template<class T> struct A { + typedef B<T> U; // expected-note {{in instantiation of template type alias 'B' requested here}} +}; +B<short> b; + +template<typename T> using U = int; +// FIXME: This is illegal, but probably only because CWG1044 missed this paragraph. +template<typename T> using U = U<T>; diff --git a/clang/test/CXX/temp/temp.param/p10-0x.cpp b/clang/test/CXX/temp/temp.param/p10-0x.cpp new file mode 100644 index 00000000000..bc7e616fb13 --- /dev/null +++ b/clang/test/CXX/temp/temp.param/p10-0x.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +template<typename> struct Y1; +template<typename, int> struct Y2; + +template<class T1, class T2 = int> using B2 = T1; +template<class T1 = int, class T2> using B2 = T1; + +template<template<class> class F, template<class> class G = Y1> using B2t = F<G<int>>; +template<template<class> class F = Y2, template<class> class G> using B2t = F<G<int>>; + +template<int N, int M = 5> using B2n = Y2<int, N + M>; +template<int N = 5, int M> using B2n = Y2<int, N + M>; diff --git a/clang/test/CXX/temp/temp.param/p11-0x.cpp b/clang/test/CXX/temp/temp.param/p11-0x.cpp index 0bf4341cf8d..10a44380c8d 100644 --- a/clang/test/CXX/temp/temp.param/p11-0x.cpp +++ b/clang/test/CXX/temp/temp.param/p11-0x.cpp @@ -1,29 +1,48 @@ // RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s -// If a template-parameter of a class template has a default -// template-argument, each subsequent template-parameter shall either -// have a default template-argument supplied or be a template -// parameter pack. +// If a template-parameter of a class template or alias template has a default +// template-argument, each subsequent template-parameter shall either have a +// default template-argument supplied or be a template parameter pack. template<typename> struct vector; +template<typename T = int, typename> struct X3t; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}} +template<typename T = int, typename> using A3t = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}} +template<int V = 0, int> struct X3nt; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}} +template<int V = 0, int> using A3nt = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}} +template<template<class> class M = vector, template<class> class> struct X3tt; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}} +template<template<class> class M = vector, template<class> class> using A3tt = int; // expected-error{{template parameter missing a default argument}} expected-note{{previous default template argument defined here}} + template<typename T = int, typename ...Types> struct X2t; +template<typename T = int, typename ...Types> using A2t = X2t<T, Types...>; template<int V = 0, int ...Values> struct X2nt; +template<int V = 0, int ...Values> using A2nt = X2nt<V, Values...>; template<template<class> class M = vector, template<class> class... Metas> struct X2tt; +template<template<class> class M = vector, template<class> class... Metas> + using A2tt = X2tt<M, Metas...>; -// If a template-parameter of a primary class template is a template -// parameter pack, it shall be the last template-parameter . +// If a template-parameter of a primary class template or alias template is a +// template parameter pack, it shall be the last template-parameter. template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}} int After> struct X0t; +template<typename ...Types, // expected-error{{template parameter pack must be the last template parameter}} + int After> +using A0t = int; template<int ...Values, // expected-error{{template parameter pack must be the last template parameter}} int After> struct X0nt; +template<int ...Values, // expected-error{{template parameter pack must be the last template parameter}} + int After> +using A0nt = int; template<template<typename> class ...Templates, // expected-error{{template parameter pack must be the last template parameter}} int After> struct X0tt; +template<template<typename> class ...Templates, // expected-error{{template parameter pack must be the last template parameter}} + int After> +using A0tt = int; // [ Note: These are not requirements for function templates or class // template partial specializations because template arguments can be diff --git a/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp new file mode 100644 index 00000000000..1d1d350cf33 --- /dev/null +++ b/clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +// Examples from CWG1056. +namespace Example1 { + template<class T> struct A; + template<class T> using B = A<T>; + + template<class T> struct A { + struct C {}; + B<T>::C bc; // ok, B<T> is the current instantiation. + }; + + template<class T> struct A<A<T>> { + struct C {}; + B<B<T>>::C bc; // ok, B<B<T>> is the current instantiation. + }; + + template<class T> struct A<A<A<T>>> { + struct C {}; + B<B<T>>::C bc; // expected-error {{missing 'typename'}} + }; +} + +namespace Example2 { + template<class T> struct A { + void g(); + }; + template<class T> using B = A<T>; + template<class T> void B<T>::g() {} // ok. +} diff --git a/clang/test/CXX/temp/temp.type/p1-0x.cpp b/clang/test/CXX/temp/temp.type/p1-0x.cpp new file mode 100644 index 00000000000..c22af22f986 --- /dev/null +++ b/clang/test/CXX/temp/temp.type/p1-0x.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +namespace Old { + template<template<class> class TT> struct X { }; + template<class> struct Y { }; + template<class T> using Z = Y<T>; + X<Y> y; + X<Z> z; + + using SameType = decltype(y); // expected-note {{here}} + using SameType = decltype(z); // expected-error {{different types}} +} + +namespace New { + template<class T> struct X { }; + template<class> struct Y { }; + template<class T> using Z = Y<T>; + X<Y<int>> y; + X<Z<int>> z; + + using SameType = decltype(y); + using SameType = decltype(z); // ok +} diff --git a/clang/test/CodeGenCXX/mangle-alias-template.cpp b/clang/test/CodeGenCXX/mangle-alias-template.cpp new file mode 100644 index 00000000000..2020a0a584e --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-alias-template.cpp @@ -0,0 +1,41 @@ +// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +template<typename T> struct alloc {}; +template<typename T> using Alloc = alloc<T>; +template<typename T, typename A = Alloc<T>> struct vector {}; + +template<typename T> using Vec = vector<T>; + +template<typename T> void f(Vec<T> v); +template<typename T> void g(T); + +template<template<typename> class F> void h(F<int>); + +// CHECK: define void @_Z1zv( +void z() { + vector<int> VI; + f(VI); + // CHECK: call void @_Z1fIiEv6vectorIT_5allocIS1_EE( + + Vec<double> VD; + g(VD); + // CHECK: call void @_Z1gI6vectorId5allocIdEEEvT_( + + h<Vec>(VI); + // CHECK: call void @_Z1hI3VecEvT_IiE( + + Alloc<int> AC; + h(AC); + // CHECK: call void @_Z1hI5allocEvT_IiE( + + h<Alloc>(AC); + // CHECK: call void @_Z1hI5AllocEvT_IiE( + + Vec<char> VC; + g<Vec<char>>(VC); + // CHECK: call void @_Z1gI6vectorIc5allocIcEEEvT_( + + Vec<Vec<int>> VVI; + g(VVI); + // CHECK: call void @_Z1gI6vectorIS0_Ii5allocIiEES1_IS3_EEEvT_( +} diff --git a/clang/test/CodeGenCXX/mangle-unnameable-conversions.cpp b/clang/test/CodeGenCXX/mangle-unnameable-conversions.cpp new file mode 100644 index 00000000000..2132eff5e51 --- /dev/null +++ b/clang/test/CodeGenCXX/mangle-unnameable-conversions.cpp @@ -0,0 +1,14 @@ +// RUN: %clang_cc1 -std=c++0x -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s + +template<typename T> using id = T; +struct S { + template<typename T, int N> + operator id<T[N]>&(); + template<typename T, typename U> + operator id<T (U::*)()>() const; +}; + +void f() { + int (&a)[42] = S(); // CHECK: @_ZN1ScvRAT0__T_IiLi42EEEv( + char (S::*fp)() = S(); // CHECK: @_ZNK1ScvMT0_FT_vEIcS_EEv( +}; diff --git a/clang/test/Lexer/has_feature_cxx0x.cpp b/clang/test/Lexer/has_feature_cxx0x.cpp index 57949e30177..57354f866ec 100644 --- a/clang/test/Lexer/has_feature_cxx0x.cpp +++ b/clang/test/Lexer/has_feature_cxx0x.cpp @@ -155,3 +155,12 @@ int no_override_control(); // CHECK-0X: has_override_control // CHECK-NO-0X: no_override_control + +#if __has_feature(cxx_alias_templates) +int has_alias_templates(); +#else +int no_alias_templates(); +#endif + +// CHECK-0X: has_alias_templates +// CHECK-NO-0X: no_alias_templates diff --git a/clang/test/PCH/cxx-alias-decl.cpp b/clang/test/PCH/cxx-alias-decl.cpp new file mode 100644 index 00000000000..e30311c58b7 --- /dev/null +++ b/clang/test/PCH/cxx-alias-decl.cpp @@ -0,0 +1,20 @@ +// Test this without pch. +// RUN: %clang_cc1 -x c++ -std=c++0x -include %S/cxx-alias-decl.h -fsyntax-only -emit-llvm -o - %s + +// Test with pch. +// RUN: %clang_cc1 -x c++ -std=c++0x -emit-pch -o %t %S/cxx-alias-decl.h +// RUN: %clang_cc1 -x c++ -std=c++0x -include-pch %t -fsyntax-only -emit-llvm -o - %s + +template struct T<S>; +C<A>::A<char> a; + +using T1 = decltype(a); +using T1 = D<int, char>; + +using T2 = B<A>; +using T2 = S; + +using A = int; +template<typename U> using B = S; +template<typename U> using C = T<U>; +template<typename U, typename V> using D = typename T<U>::template A<V>; diff --git a/clang/test/PCH/cxx-alias-decl.h b/clang/test/PCH/cxx-alias-decl.h new file mode 100644 index 00000000000..26bc716b08a --- /dev/null +++ b/clang/test/PCH/cxx-alias-decl.h @@ -0,0 +1,11 @@ +// Header for PCH test cxx-alias-decl.cpp + +struct S {}; +template<typename U> struct T { + template<typename V> using A = T<V>; +}; + +using A = int; +template<typename U> using B = S; +template<typename U> using C = T<U>; +template<typename U, typename V> using D = typename T<U>::template A<V>; diff --git a/clang/test/SemaCXX/alias-template.cpp b/clang/test/SemaCXX/alias-template.cpp new file mode 100644 index 00000000000..f29a9327dab --- /dev/null +++ b/clang/test/SemaCXX/alias-template.cpp @@ -0,0 +1,147 @@ +// RUN: %clang_cc1 -verify -std=c++0x %s + +namespace RedeclAliasTypedef { + template<typename U> using T = int; + template<typename U> using T = int; + template<typename U> using T = T<U>; +} + +namespace IllegalTypeIds { + template<typename U> using A = void(int n = 0); // expected-error {{default arguments can only be specified for parameters in a function declaration}} + template<typename U> using B = inline void(int n); // expected-error {{type name does not allow function specifier}} + template<typename U> using C = virtual void(int n); // expected-error {{type name does not allow function specifier}} + template<typename U> using D = explicit void(int n); // expected-error {{type name does not allow function specifier}} + template<typename U> using E = void(int n) throw(); // expected-error {{exception specifications are not allowed in type aliases}} + // FIXME: this is illegal; we incorrectly accept it for typedefs too. + template<typename U> using F = void(*)(int n) &&; // expected-err + template<typename U> using G = __thread void(int n); // expected-error {{type name does not allow storage class to be specified}} + + template<typename U> using H = void(int n); // ok + template<typename U> using I = void(int n) &&; // ok +} + +namespace IllegalSyntax { + template<typename Z> using ::T = void(int n); // expected-error {{name defined in alias declaration must be an identifier}} + template<typename Z> using operator int = void(int n); // expected-error {{name defined in alias declaration must be an identifier}} + template<typename Z> using typename U = void; // expected-error {{name defined in alias declaration must be an identifier}} + template<typename Z> using typename ::V = void(int n); // expected-error {{name defined in alias declaration must be an identifier}} + template<typename Z> using typename ::operator bool = void(int n); // expected-error {{name defined in alias declaration must be an identifier}} +} + +namespace VariableLengthArrays { + template<typename Z> using T = int[42]; // ok + + int n = 32; + template<typename Z> using T = int[n]; // expected-error {{variable length array declaration not allowed at file scope}} + + const int m = 42; + template<typename Z> using U = int[m]; // expected-note {{previous definition}} + template<typename Z> using U = int[42]; // ok + template<typename Z> using U = int; // expected-error {{type alias template redefinition with different types ('int' vs 'int [42]')}} +} + +namespace RedeclFunc { + int f(int, char**); + template<typename Z> using T = int; + T<char> f(int, char **); // ok +} + +namespace LookupFilter { + namespace N { template<typename U> using S = int; } + using namespace N; + template<typename U> using S = S<U>*; // ok +} + +namespace InFunctions { + template<typename...T> struct S0 { + template<typename Z> using U = T*; // expected-error {{declaration type contains unexpanded parameter pack 'T'}} + U<char> u; + }; + + template<typename Z> using T1 = int; + template<typename Z> using T2 = int[-1]; // expected-error {{array size is negative}} + template<typename...T> struct S3 { // expected-note {{template parameter is declared here}} + template<typename Z> using T = int; // expected-error {{declaration of 'T' shadows template parameter}} + }; + template<typename Z> using Z = Z; +} + +namespace ClassNameRedecl { + class C0 { + // FIXME: this diagnostic is pretty poor + template<typename U> using C0 = int; // expected-error {{name defined in alias declaration must be an identifier}} + }; + class C1 { + // FIXME: this diagnostic is pretty poor + template<typename U> using C1 = C1; // expected-error {{name defined in alias declaration must be an identifier}} + }; + class C2 { + template<typename U> using C0 = C1; // ok + }; + template<typename...T> class C3 { + template<typename U> using f = T; // expected-error {{declaration type contains unexpanded parameter pack 'T'}} + }; + template<typename T> class C4 { // expected-note {{template parameter is declared here}} + template<typename U> using T = int; // expected-error {{declaration of 'T' shadows template parameter}} + }; + class C5 { + class c; // expected-note {{previous definition}} + template<typename U> using c = int; // expected-error {{redefinition of 'c' as different kind of symbol}} + class d; // expected-note {{previous definition}} + template<typename U> using d = d; // expected-error {{redefinition of 'd' as different kind of symbol}} + }; + class C6 { + class c { template<typename U> using C6 = int; }; // ok + }; +} + +class CtorDtorName { + template<typename T> using X = CtorDtorName; + X<int>(); // expected-error {{expected member name}} + ~X<int>(); // expected-error {{destructor cannot be declared using a type alias}} +}; + +namespace TagName { + template<typename Z> using S = struct { int n; }; // expected-error {{can not be defined}} + template<typename Z> using T = class { int n; }; // expected-error {{can not be defined}} + template<typename Z> using U = enum { a, b, c }; // expected-error {{can not be defined}} + template<typename Z> using V = struct V { int n; }; // expected-error {{redefinition of 'V' as different kind of symbol}} \ + expected-error {{'TagName::V' can not be defined in a type alias template}} \ + expected-note {{previous definition is here}} +} + +namespace StdExample { + template<typename T, typename U> struct pair; + + template<typename T> using handler_t = void (*)(T); + extern handler_t<int> ignore; + extern void (*ignore)(int); + // FIXME: we recover as if cell is an undeclared variable. the diagnostics are terrible! + template<typename T> using cell = pair<T*, cell<T>*>; // expected-error {{use of undeclared identifier 'cell'}} \ + expected-error {{'T' does not refer to a value}} \ + expected-note {{declared here}} \ + expected-error {{expected ';' after alias declaration}} +} + +namespace Access { + class C0 { + template<typename Z> using U = int; // expected-note {{declared private here}} + }; + C0::U<int> v; // expected-error {{'U' is a private member}} + class C1 { + public: + template<typename Z> using U = int; + }; + C1::U<int> w; // ok +} + +namespace VoidArg { + template<typename Z> using V = void; + V<int> f(int); // ok + V<char> g(V<double>); // expected-error {{empty parameter list defined with a type alias of 'void' not allowed}} +} + +namespace Curried { + template<typename T, typename U> struct S; + template<typename T> template<typename U> using SS = S<T, U>; // expected-error {{extraneous template parameter list in alias template declaration}} +} diff --git a/clang/test/SemaCXX/attr-cxx0x.cpp b/clang/test/SemaCXX/attr-cxx0x.cpp index 40fe0e01c2e..725f0182db5 100644 --- a/clang/test/SemaCXX/attr-cxx0x.cpp +++ b/clang/test/SemaCXX/attr-cxx0x.cpp @@ -9,8 +9,13 @@ struct align_member { int member [[align(8)]]; }; +typedef char align_typedef [[align(8)]]; +template<typename T> using align_alias_template = align_typedef; + static_assert(alignof(align_big) == alignof(int), "k's alignment is wrong"); static_assert(alignof(align_small) == 1, "j's alignment is wrong"); static_assert(alignof(align_multiple) == 8, "l's alignment is wrong"); static_assert(alignof(align_member) == 8, "quuux's alignment is wrong"); static_assert(sizeof(align_member) == 8, "quuux's size is wrong"); +static_assert(alignof(align_typedef) == 8, "typedef's alignment is wrong"); +static_assert(alignof(align_alias_template<int>) == 8, "alias template's alignment is wrong"); diff --git a/clang/test/SemaCXX/dependent-types.cpp b/clang/test/SemaCXX/dependent-types.cpp index d9b53230c99..053e79bb698 100644 --- a/clang/test/SemaCXX/dependent-types.cpp +++ b/clang/test/SemaCXX/dependent-types.cpp @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s +// RUN: %clang_cc1 -fsyntax-only -pedantic -verify -std=c++0x %s + +template<typename T> using U = int &; template<typename T, int Size> void f() { T x1; @@ -7,4 +9,5 @@ template<typename T, int Size> void f() { T x4[]; // expected-error{{needs an explicit size or an initializer}} T x5[Size]; int x6[Size]; + U<T> x7; // expected-error{{declaration of reference variable 'x7' requires an initializer}} } diff --git a/clang/test/SemaCXX/redeclared-alias-template.cpp b/clang/test/SemaCXX/redeclared-alias-template.cpp new file mode 100644 index 00000000000..b368fcfe550 --- /dev/null +++ b/clang/test/SemaCXX/redeclared-alias-template.cpp @@ -0,0 +1,23 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +template<typename T> using A = int; // expected-note 2{{previous}} +template<typename T> using A = char; // expected-error {{type alias template redefinition with different types ('char' vs 'int')}} +template<typename T1, typename T2> using A = T1; // expected-error {{too many template parameters in template redeclaration}} + +template<typename T1, typename T2> using B = T1; // expected-note {{previous}} +template<typename T2, typename T1> using B = T1; // expected-error {{type alias template redefinition with different types}} + + +template<typename> struct S; +template<template<typename> class F> using FInt = F<int>; +template<typename X> using SXRInt = FInt<S<X>::template R>; +template<typename X> using SXRInt = typename S<X>::template R<int>; // ok, redeclaration. + +template<template<typename> class> struct TT; + +namespace FilterLookup { + TT<A> f(); // expected-note {{previous declaration is here}} + + template<typename> using A = int; + TT<A> f(); // expected-error {{functions that differ only in their return type cannot be overloaded}} +} diff --git a/clang/test/SemaTemplate/alias-church-numerals.cpp b/clang/test/SemaTemplate/alias-church-numerals.cpp new file mode 100644 index 00000000000..751cac73ae0 --- /dev/null +++ b/clang/test/SemaTemplate/alias-church-numerals.cpp @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=c++0x -fsyntax-only -verify %s + +template<template<template<typename> class, typename> class T, template<typename> class V> struct PartialApply { + template<typename W> using R = T<V, W>; +}; + +template<typename T> using Id = T; +template<template<typename> class, typename X> using Zero = X; +template<template<template<typename> class, typename> class N, template<typename> class F, typename X> using Succ = F<N<F,X>>; + +template<template<typename> class F, typename X> using One = Succ<Zero, F, X>; +template<template<typename> class F, typename X> using Two = Succ<One, F, X>; + +template<template<template<typename> class, typename> class A, + template<template<typename> class, typename> class B, + template<typename> class F, + typename X> using Add = A<F, B<F, X>>; + +template<template<template<typename> class, typename> class A, + template<template<typename> class, typename> class B, + template<typename> class F, + typename X> using Mul = A<PartialApply<B,F>::template R, X>; + +template<template<typename> class F, typename X> using Four = Add<Two, Two, F, X>; +template<template<typename> class F, typename X> using Sixteen = Mul<Four, Four, F, X>; +template<template<typename> class F, typename X> using TwoHundredAndFiftySix = Mul<Sixteen, Sixteen, F, X>; + +template<typename T, T N> struct Const { static const T value = N; }; +template<typename A> struct IncrementHelper; +template<typename T, T N> struct IncrementHelper<Const<T, N>> { using Result = Const<T, N+1>; }; +template<typename A> using Increment = typename IncrementHelper<A>::Result; + +using Arr = int[TwoHundredAndFiftySix<Increment, Const<int, 0>>::value]; +using Arr = int[256]; diff --git a/clang/test/SemaTemplate/alias-nested-nontag.cpp b/clang/test/SemaTemplate/alias-nested-nontag.cpp new file mode 100644 index 00000000000..1bb5ce336f9 --- /dev/null +++ b/clang/test/SemaTemplate/alias-nested-nontag.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +template<typename T> using Id = T; // expected-note {{type alias template 'Id' declared here}} +struct U { static Id<int> V; }; +Id<int> ::U::V; // expected-error {{type 'Id<int>' (aka 'int') cannot be used prior to '::' because it has no members}} \ + expected-error {{C++ requires a type specifier}} diff --git a/clang/test/SemaTemplate/alias-template-template-param.cpp b/clang/test/SemaTemplate/alias-template-template-param.cpp new file mode 100644 index 00000000000..a847b0672a2 --- /dev/null +++ b/clang/test/SemaTemplate/alias-template-template-param.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++0x %s + +template<template<typename> class D> using C = D<int>; + +// Substitution of the alias template transforms the TemplateSpecializationType +// 'D<int>' into the DependentTemplateSpecializationType 'T::template U<int>'. +template<typename T> void f(C<T::template U>); diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index 9bd83a53033..7234da3f638 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -3915,6 +3915,7 @@ CXCursor clang_getCursorDefinition(CXCursor C) { case Decl::Namespace: case Decl::Typedef: case Decl::TypeAlias: + case Decl::TypeAliasTemplate: case Decl::TemplateTypeParm: case Decl::EnumConstant: case Decl::Field: diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index f0361d38a5b..ad9a7d01bca 100644 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -460,14 +460,13 @@ welcome!</p> </tr> <tr> <td>template aliases</td> - <td class="basic"></td> - <td class="basic"></td> - <td class="basic"></td> - <td></td> + <td class="complete" align="center">✓</td> + <td class="complete" align="center">✓</td> + <td class="complete" align="center">✓</td> + <td class="complete" align="center">✓</td> <td>7.1.3, 14.6.7</td> <td><a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1489.pdf">N1489</a> <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf">N2258</a> - Only non-template type aliases implemented </td> </tr> <tr> |