diff options
-rw-r--r-- | include/clang/AST/DeclTemplate.h | 81 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.def | 6 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 19 | ||||
-rw-r--r-- | lib/AST/DeclTemplate.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 57 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 16 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 248 | ||||
-rw-r--r-- | test/Parser/cxx-template-decl.cpp | 4 | ||||
-rw-r--r-- | test/SemaTemplate/temp_param.cpp | 62 |
9 files changed, 474 insertions, 28 deletions
diff --git a/include/clang/AST/DeclTemplate.h b/include/clang/AST/DeclTemplate.h index b466a118b1..ccbe1288f8 100644 --- a/include/clang/AST/DeclTemplate.h +++ b/include/clang/AST/DeclTemplate.h @@ -225,9 +225,20 @@ class TemplateTypeParmDecl : public TypeDecl { /// 'class' keyword. bool Typename : 1; + /// \brief Whether this template type parameter inherited its + /// default argument. + bool InheritedDefault : 1; + + /// \brief The location of the default argument, if any. + SourceLocation DefaultArgumentLoc; + + /// \brief The default template argument, if any. + QualType DefaultArgument; + TemplateTypeParmDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id, bool Typename, QualType Type) - : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename) { + : TypeDecl(TemplateTypeParm, DC, L, Id), Typename(Typename), + InheritedDefault(false), DefaultArgument() { TypeForDecl = Type.getTypePtr(); } @@ -241,6 +252,30 @@ public: /// keyword. bool wasDeclaredWithTypename() const { return Typename; } + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return !DefaultArgument.isNull(); } + + /// \brief Retrieve the default argument, if any. + QualType getDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const { return DefaultArgumentLoc; } + + /// \brief Determines whether the default argument was inherited + /// from a previous declaration of this template. + bool defaultArgumentWasInherited() const { return InheritedDefault; } + + /// \brief Set the default argument for this template parameter, and + /// whether that default argument was inherited from another + /// declaration. + void setDefaultArgument(QualType DefArg, SourceLocation DefArgLoc, + bool Inherited) { + DefaultArgument = DefArg; + DefaultArgumentLoc = DefArgLoc; + InheritedDefault = Inherited; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == TemplateTypeParm; @@ -264,11 +299,16 @@ protected: /// @endcode class NonTypeTemplateParmDecl : public VarDecl, protected TemplateParmPosition { + /// \brief The default template argument, if any. + Expr *DefaultArgument; + NonTypeTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, QualType T, SourceLocation TSSL = SourceLocation()) : VarDecl(NonTypeTemplateParm, DC, L, Id, T, VarDecl::None, TSSL), - TemplateParmPosition(D, P) { } + TemplateParmPosition(D, P), DefaultArgument(0) + { } + public: static NonTypeTemplateParmDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, @@ -278,6 +318,21 @@ public: using TemplateParmPosition::getDepth; using TemplateParmPosition::getPosition; + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the default argument, if any. + Expr *getDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Set the default argument for this template parameter. + void setDefaultArgument(Expr *DefArg) { + DefaultArgument = DefArg; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == NonTypeTemplateParm; @@ -304,12 +359,17 @@ protected: /// name of a template and the template parameters allowable for substitution. class TemplateTemplateParmDecl : public TemplateDecl, protected TemplateParmPosition { + + /// \brief The default template argument, if any. + Expr *DefaultArgument; + TemplateTemplateParmDecl(DeclContext *DC, SourceLocation L, unsigned D, unsigned P, IdentifierInfo *Id, TemplateParameterList *Params) : TemplateDecl(TemplateTemplateParm, DC, L, Id, Params), - TemplateParmPosition(D, P) + TemplateParmPosition(D, P), DefaultArgument(0) { } + public: static TemplateTemplateParmDecl *Create(ASTContext &C, DeclContext *DC, SourceLocation L, unsigned D, @@ -319,6 +379,21 @@ public: using TemplateParmPosition::getDepth; using TemplateParmPosition::getPosition; + /// \brief Determine whether this template parameter has a default + /// argument. + bool hasDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the default argument, if any. + Expr *getDefaultArgument() const { return DefaultArgument; } + + /// \brief Retrieve the location of the default argument, if any. + SourceLocation getDefaultArgumentLoc() const; + + /// \brief Set the default argument for this template parameter. + void setDefaultArgument(Expr *DefArg) { + DefaultArgument = DefArg; + } + // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return D->getKind() == TemplateTemplateParm; diff --git a/include/clang/Basic/DiagnosticSemaKinds.def b/include/clang/Basic/DiagnosticSemaKinds.def index 9fad3af483..9c879f740a 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.def +++ b/include/clang/Basic/DiagnosticSemaKinds.def @@ -495,6 +495,12 @@ DIAG(note_template_nontype_parm_prev_declaration, NOTE, "previous non-type template parameter with type %0 is here") DIAG(err_template_nontype_parm_bad_type, ERROR, "a non-type template parameter cannot have type %0") +DIAG(err_template_param_default_arg_redefinition, ERROR, + "template parameter redefines default argument") +DIAG(note_template_param_prev_default_arg, NOTE, + "previous default template argument defined here") +DIAG(err_template_param_default_arg_missing, ERROR, + "template parameter missing a default argument") // C++ Template Argument Lists DIAG(err_template_arg_list_different_arity, ERROR, diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index efa94a2dc7..3c2ecfb0eb 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1040,7 +1040,10 @@ public: /// ActOnTypeParameterDefault - Adds a default argument (the type /// Default) to the given template type parameter (TypeParam). - virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, TypeTy *Default) { + virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, + SourceLocation EqualLoc, + SourceLocation DefaultLoc, + TypeTy *Default) { } /// ActOnNonTypeTemplateParameter - Called when a C++ non-type @@ -1056,6 +1059,13 @@ public: return 0; } + /// \brief Adds a default argument to the given non-type template + /// parameter. + virtual void ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParam, + SourceLocation EqualLoc, + ExprArg Default) { + } + /// ActOnTemplateTemplateParameter - Called when a C++ template template /// parameter (e.g., "int T" in "template<template <typename> class T> class /// Array") has been parsed. TmpLoc is the location of the "template" keyword, @@ -1072,6 +1082,13 @@ public: return 0; } + /// \brief Adds a default argument to the given template template + /// parameter. + virtual void ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParam, + SourceLocation EqualLoc, + ExprArg Default) { + } + /// ActOnTemplateParameterList - Called when a complete template /// parameter list has been parsed, e.g., /// diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp index 4eb866d688..b297dd25cb 100644 --- a/lib/AST/DeclTemplate.cpp +++ b/lib/AST/DeclTemplate.cpp @@ -102,6 +102,11 @@ NonTypeTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, TypeSpecStartLoc); } +SourceLocation NonTypeTemplateParmDecl::getDefaultArgumentLoc() const { + return DefaultArgument? DefaultArgument->getSourceRange().getBegin() + : SourceLocation(); +} + //===----------------------------------------------------------------------===// // TemplateTemplateParmDecl Method Implementations //===----------------------------------------------------------------------===// @@ -114,3 +119,7 @@ TemplateTemplateParmDecl::Create(ASTContext &C, DeclContext *DC, return new (C) TemplateTemplateParmDecl(DC, L, D, P, Id, Params); } +SourceLocation TemplateTemplateParmDecl::getDefaultArgumentLoc() const { + return DefaultArgument? DefaultArgument->getSourceRange().getBegin() + : SourceLocation(); +} diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 25aea35224..d17d244535 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -228,8 +228,10 @@ Parser::DeclTy *Parser::ParseTypeParameter(unsigned Depth, unsigned Position) { // Grab a default type id (if given). if(Tok.is(tok::equal)) { SourceLocation EqualLoc = ConsumeToken(); + SourceLocation DefaultLoc = Tok.getLocation(); if (TypeTy *DefaultType = ParseTypeName()) - Actions.ActOnTypeParameterDefault(TypeParam, DefaultType); + Actions.ActOnTypeParameterDefault(TypeParam, EqualLoc, DefaultLoc, + DefaultType); } return TypeParam; @@ -277,18 +279,6 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { return 0; } - // Get the a default value, if given. - // FIXME: I think that the results of this block need to be passed to the - // act-on call, so we can assemble the parameter correctly. - OwningExprResult DefaultExpr(Actions); - if(Tok.is(tok::equal)) { - ConsumeToken(); - DefaultExpr = ParseCXXIdExpression(); - if(DefaultExpr.isInvalid()) { - return 0; - } - } - TemplateParamsTy *ParamList = Actions.ActOnTemplateParameterList(Depth, SourceLocation(), TemplateLoc, LAngleLoc, @@ -296,9 +286,23 @@ Parser::ParseTemplateTemplateParameter(unsigned Depth, unsigned Position) { TemplateParams.size(), RAngleLoc); - return Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc, - ParamList, ParamName, - NameLoc, Depth, Position); + Parser::DeclTy * Param + = Actions.ActOnTemplateTemplateParameter(CurScope, TemplateLoc, + ParamList, ParamName, + NameLoc, Depth, Position); + + // Get the a default value, if given. + if (Tok.is(tok::equal)) { + SourceLocation EqualLoc = ConsumeToken(); + OwningExprResult DefaultExpr = ParseCXXIdExpression(); + if (DefaultExpr.isInvalid()) + return Param; + else if (Param) + Actions.ActOnTemplateTemplateParameterDefault(Param, EqualLoc, + move(DefaultExpr)); + } + + return Param; } /// ParseNonTypeTemplateParameter - Handle the parsing of non-type @@ -341,12 +345,23 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl, Depth, Position); - // Is there a default value? Parsing this can be fairly annoying because - // we have to stop on the first non-nested (paren'd) '>' as the closure - // for the template parameter list. Or a ','. + // If there is a default value, parse it. if (Tok.is(tok::equal)) { - // TODO: Implement default non-type values. - SkipUntil(tok::comma, tok::greater, true, true); + SourceLocation EqualLoc = ConsumeToken(); + + // C++ [temp.param]p15: + // When parsing a default template-argument for a non-type + // template-parameter, the first non-nested > is taken as the + // end of the template-parameter-list rather than a greater-than + // operator. + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + + OwningExprResult DefaultArg = ParseAssignmentExpression(); + if (DefaultArg.isInvalid()) + SkipUntil(tok::comma, tok::greater, true, true); + else if (Param) + Actions.ActOnNonTypeTemplateParameterDefault(Param, EqualLoc, + move(DefaultArg)); } return Param; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index e3d132efbb..669fd92584 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -1490,9 +1490,17 @@ public: IdentifierInfo *ParamName, SourceLocation ParamNameLoc, unsigned Depth, unsigned Position); + virtual void ActOnTypeParameterDefault(DeclTy *TypeParam, + SourceLocation EqualLoc, + SourceLocation DefaultLoc, + TypeTy *Default); + virtual DeclTy *ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, unsigned Depth, unsigned Position); + virtual void ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParam, + SourceLocation EqualLoc, + ExprArg Default); virtual DeclTy *ActOnTemplateTemplateParameter(Scope *S, SourceLocation TmpLoc, TemplateParamsTy *Params, @@ -1500,6 +1508,10 @@ public: SourceLocation ParamNameLoc, unsigned Depth, unsigned Position); + virtual void ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParam, + SourceLocation EqualLoc, + ExprArg Default); + virtual TemplateParamsTy * ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, @@ -1507,7 +1519,9 @@ public: SourceLocation LAngleLoc, DeclTy **Params, unsigned NumParams, SourceLocation RAngleLoc); - + bool CheckTemplateParameterList(TemplateParameterList *NewParams, + TemplateParameterList *OldParams); + virtual DeclTy * ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, SourceLocation KWLoc, const CXXScopeSpec &SS, diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index c0c6e23baf..5eb2b2145c 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -140,6 +140,29 @@ Sema::DeclTy *Sema::ActOnTypeParameter(Scope *S, bool Typename, return Param; } +/// ActOnTypeParameterDefault - Adds a default argument (the type +/// Default) to the given template type parameter (TypeParam). +void Sema::ActOnTypeParameterDefault(DeclTy *TypeParam, + SourceLocation EqualLoc, + SourceLocation DefaultLoc, + TypeTy *DefaultT) { + TemplateTypeParmDecl *Parm + = cast<TemplateTypeParmDecl>(static_cast<Decl *>(TypeParam)); + QualType Default = QualType::getFromOpaquePtr(DefaultT); + + // C++ [temp.param]p14: + // A template-parameter shall not be used in its own default argument. + // FIXME: Implement this check! Needs a recursive walk over the types. + + // Check the template argument itself. + if (CheckTemplateArgument(Parm, Default, DefaultLoc)) { + Parm->setInvalidDecl(); + return; + } + + Parm->setDefaultArgument(Default, DefaultLoc, false); +} + /// ActOnNonTypeTemplateParameter - Called when a C++ non-type /// template parameter (e.g., "int Size" in "template<int Size> /// class Array") has been parsed. S is the current scope and D is @@ -210,6 +233,28 @@ Sema::DeclTy *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, return Param; } +/// \brief Adds a default argument to the given non-type template +/// parameter. +void Sema::ActOnNonTypeTemplateParameterDefault(DeclTy *TemplateParamD, + SourceLocation EqualLoc, + ExprArg DefaultE) { + NonTypeTemplateParmDecl *TemplateParm + = cast<NonTypeTemplateParmDecl>(static_cast<Decl *>(TemplateParamD)); + Expr *Default = static_cast<Expr *>(DefaultE.get()); + + // C++ [temp.param]p14: + // A template-parameter shall not be used in its own default argument. + // FIXME: Implement this check! Needs a recursive walk over the types. + + // Check the well-formedness of the default template argument. + if (CheckTemplateArgument(TemplateParm, Default)) { + TemplateParm->setInvalidDecl(); + return; + } + + TemplateParm->setDefaultArgument(static_cast<Expr *>(DefaultE.release())); +} + /// ActOnTemplateTemplateParameter - Called when a C++ template template /// parameter (e.g. T in template <template <typename> class T> class array) @@ -250,6 +295,40 @@ Sema::DeclTy *Sema::ActOnTemplateTemplateParameter(Scope* S, return Param; } +/// \brief Adds a default argument to the given template template +/// parameter. +void Sema::ActOnTemplateTemplateParameterDefault(DeclTy *TemplateParamD, + SourceLocation EqualLoc, + ExprArg DefaultE) { + TemplateTemplateParmDecl *TemplateParm + = cast<TemplateTemplateParmDecl>(static_cast<Decl *>(TemplateParamD)); + + // Since a template-template parameter's default argument is an + // id-expression, it must be a DeclRefExpr. + DeclRefExpr *Default + = cast<DeclRefExpr>(static_cast<Expr *>(DefaultE.get())); + + // C++ [temp.param]p14: + // A template-parameter shall not be used in its own default argument. + // FIXME: Implement this check! Needs a recursive walk over the types. + + // Check the well-formedness of the template argument. + if (!isa<TemplateDecl>(Default->getDecl())) { + Diag(Default->getSourceRange().getBegin(), + diag::err_template_arg_must_be_template) + << Default->getSourceRange(); + TemplateParm->setInvalidDecl(); + return; + } + if (CheckTemplateArgument(TemplateParm, Default)) { + TemplateParm->setInvalidDecl(); + return; + } + + DefaultE.release(); + TemplateParm->setDefaultArgument(Default); +} + /// ActOnTemplateParameterList - Builds a TemplateParameterList that /// contains the template parameters in Params/NumParams. Sema::TemplateParamsTy * @@ -274,6 +353,7 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, MultiTemplateParamsArg TemplateParameterLists) { assert(TemplateParameterLists.size() > 0 && "No template parameter lists?"); assert(TK != TK_Reference && "Can only declare or define class templates"); + bool Invalid = false; // Check that we can declare a template here. if (CheckTemplateDeclScope(S, TemplateParameterLists)) @@ -363,6 +443,13 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, return 0; } + // Check the template parameter list of this declaration, possibly + // merging in the template parameter list from the previous class + // template declaration. + if (CheckTemplateParameterList(TemplateParams, + PrevClassTemplate? PrevClassTemplate->getTemplateParameters() : 0)) + Invalid = true; + // If we had a scope specifier, we better have a previous template // declaration! @@ -388,10 +475,171 @@ Sema::ActOnClassTemplate(Scope *S, unsigned TagSpec, TagKind TK, PushOnScopeChains(NewTemplate, S); + if (Invalid) { + NewTemplate->setInvalidDecl(); + NewClass->setInvalidDecl(); + } return NewTemplate; } +/// \brief Checks the validity of a template parameter list, possibly +/// considering the template parameter list from a previous +/// declaration. +/// +/// If an "old" template parameter list is provided, it must be +/// equivalent (per TemplateParameterListsAreEqual) to the "new" +/// template parameter list. +/// +/// \param NewParams Template parameter list for a new template +/// declaration. This template parameter list will be updated with any +/// default arguments that are carried through from the previous +/// template parameter list. +/// +/// \param OldParams If provided, template parameter list from a +/// previous declaration of the same template. Default template +/// arguments will be merged from the old template parameter list to +/// the new template parameter list. +/// +/// \returns true if an error occurred, false otherwise. +bool Sema::CheckTemplateParameterList(TemplateParameterList *NewParams, + TemplateParameterList *OldParams) { + bool Invalid = false; + + // C++ [temp.param]p10: + // The set of default template-arguments available for use with a + // template declaration or definition is obtained by merging the + // default arguments from the definition (if in scope) and all + // declarations in scope in the same way default function + // arguments are (8.3.6). + bool SawDefaultArgument = false; + SourceLocation PreviousDefaultArgLoc; + + TemplateParameterList::iterator OldParam; + if (OldParams) + OldParam = OldParams->begin(); + + for (TemplateParameterList::iterator NewParam = NewParams->begin(), + NewParamEnd = NewParams->end(); + NewParam != NewParamEnd; ++NewParam) { + // Variables used to diagnose redundant default arguments + bool RedundantDefaultArg = false; + SourceLocation OldDefaultLoc; + SourceLocation NewDefaultLoc; + + // Variables used to diagnose missing default arguments + bool MissingDefaultArg = false; + + // Merge default arguments for template type parameters. + if (TemplateTypeParmDecl *NewTypeParm + = dyn_cast<TemplateTypeParmDecl>(*NewParam)) { + TemplateTypeParmDecl *OldTypeParm + = OldParams? cast<TemplateTypeParmDecl>(*OldParam) : 0; + + if (OldTypeParm && OldTypeParm->hasDefaultArgument() && + NewTypeParm->hasDefaultArgument()) { + OldDefaultLoc = OldTypeParm->getDefaultArgumentLoc(); + NewDefaultLoc = NewTypeParm->getDefaultArgumentLoc(); + SawDefaultArgument = true; + RedundantDefaultArg = true; + PreviousDefaultArgLoc = NewDefaultLoc; + } else if (OldTypeParm && OldTypeParm->hasDefaultArgument()) { + // Merge the default argument from the old declaration to the + // new declaration. + SawDefaultArgument = true; + NewTypeParm->setDefaultArgument(OldTypeParm->getDefaultArgument(), + OldTypeParm->getDefaultArgumentLoc(), + true); + PreviousDefaultArgLoc = OldTypeParm->getDefaultArgumentLoc(); + } else if (NewTypeParm->hasDefaultArgument()) { + SawDefaultArgument = true; + PreviousDefaultArgLoc = NewTypeParm->getDefaultArgumentLoc(); + } else if (SawDefaultArgument) + MissingDefaultArg = true; + } + // Merge default arguments for non-type template parameters + else if (NonTypeTemplateParmDecl *NewNonTypeParm + = dyn_cast<NonTypeTemplateParmDecl>(*NewParam)) { + NonTypeTemplateParmDecl *OldNonTypeParm + = OldParams? cast<NonTypeTemplateParmDecl>(*OldParam) : 0; + if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument() && + NewNonTypeParm->hasDefaultArgument()) { + OldDefaultLoc = OldNonTypeParm->getDefaultArgumentLoc(); + NewDefaultLoc = NewNonTypeParm->getDefaultArgumentLoc(); + SawDefaultArgument = true; + RedundantDefaultArg = true; + PreviousDefaultArgLoc = NewDefaultLoc; + } else if (OldNonTypeParm && OldNonTypeParm->hasDefaultArgument()) { + // Merge the default argument from the old declaration to the + // new declaration. + SawDefaultArgument = true; + // FIXME: We need to create a new kind of "default argument" + // expression that points to a previous template template + // parameter. + NewNonTypeParm->setDefaultArgument( + OldNonTypeParm->getDefaultArgument()); + PreviousDefaultArgLoc = OldNonTypeParm->getDefaultArgumentLoc(); + } else if (NewNonTypeParm->hasDefaultArgument()) { + SawDefaultArgument = true; + PreviousDefaultArgLoc = NewNonTypeParm->getDefaultArgumentLoc(); + } else if (SawDefaultArgument) + MissingDefaultArg = true; + } + // Merge default arguments for template template parameters + else { + TemplateTemplateParmDecl *NewTemplateParm + = cast<TemplateTemplateParmDecl>(*NewParam); + TemplateTemplateParmDecl *OldTemplateParm + = OldParams? cast<TemplateTemplateParmDecl>(*OldParam) : 0; + if (OldTemplateParm && OldTemplateParm->hasDefaultArgument() && + NewTemplateParm->hasDefaultArgument()) { + OldDefaultLoc = OldTemplateParm->getDefaultArgumentLoc(); + NewDefaultLoc = NewTemplateParm->getDefaultArgumentLoc(); + SawDefaultArgument = true; + RedundantDefaultArg = true; + PreviousDefaultArgLoc = NewDefaultLoc; + } else if (OldTemplateParm && OldTemplateParm->hasDefaultArgument()) { + // Merge the default argument from the old declaration to the + // new declaration. + SawDefaultArgument = true; + // FIXME: We need to create a new kind of "default argument" + // expression that points to a previous template template + // parameter. + NewTemplateParm->setDefaultArgument( + OldTemplateParm->getDefaultArgument()); + PreviousDefaultArgLoc = OldTemplateParm->getDefaultArgumentLoc(); + } else if (NewTemplateParm->hasDefaultArgument()) { + SawDefaultArgument = true; + PreviousDefaultArgLoc = NewTemplateParm->getDefaultArgumentLoc(); + } else if (SawDefaultArgument) + MissingDefaultArg = true; + } + + if (RedundantDefaultArg) { + // C++ [temp.param]p12: + // A template-parameter shall not be given default arguments + // by two different declarations in the same scope. + Diag(NewDefaultLoc, diag::err_template_param_default_arg_redefinition); + Diag(OldDefaultLoc, diag::note_template_param_prev_default_arg); + Invalid = true; + } else if (MissingDefaultArg) { + // C++ [temp.param]p11: + // If a template-parameter has a default template-argument, + // all subsequent template-parameters shall have a default + // template-argument supplied. + Diag((*NewParam)->getLocation(), + diag::err_template_param_default_arg_missing); + Diag(PreviousDefaultArgLoc, diag::note_template_param_prev_default_arg); + Invalid = true; + } + // If we have an old template parameter list that we're merging + // in, move on to the next parameter. + if (OldParams) + ++OldParam; + } + + return Invalid; +} Action::TypeTy * Sema::ActOnClassTemplateSpecialization(DeclTy *TemplateD, diff --git a/test/Parser/cxx-template-decl.cpp b/test/Parser/cxx-template-decl.cpp index 08b05cf823..54d1081b42 100644 --- a/test/Parser/cxx-template-decl.cpp +++ b/test/Parser/cxx-template-decl.cpp @@ -32,8 +32,8 @@ template <typename = int> X2; // Forward declarations w/template template parameters template <template <typename> class T> class TTP1; template <template <typename> class> class TTP2; -template <template <typename> class T = foo> class TTP3; -template <template <typename> class = foo> class TTP3; +template <template <typename> class T = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}} +template <template <typename> class = foo> class TTP3; // FIXME:expected-error{{template argument for template template parameter must be a template}} template <template <typename X, typename Y> class T> class TTP5; // Forward declararations with non-type params diff --git a/test/SemaTemplate/temp_param.cpp b/test/SemaTemplate/temp_param.cpp index 57a6cdb945..249bf9a08d 100644 --- a/test/SemaTemplate/temp_param.cpp +++ b/test/SemaTemplate/temp_param.cpp @@ -23,5 +23,67 @@ template<float f> struct A11; // expected-error{{a non-type template parameter c template<int X[10]> struct A5; template<int f(float, double)> struct A7; +// C++ [temp.param]p11: +template<typename> struct Y1; // expected-note{{too few template parameters in template template argument}} +template<typename, int> struct Y2; +template<class T1 = int, // expected-note{{previous default template argument defined here}} + class T2> // expected-error{{template parameter missing a default argument}} + class B1; +template<template<class> class = Y1, // expected-note{{previous default template argument defined here}} + template<class> class> // expected-error{{template parameter missing a default argument}} + class B1t; + +template<int N = 5, // expected-note{{previous default template argument defined here}} + int M> // expected-error{{template parameter missing a default argument}} + class B1n; + +// FIXME: spurious "shadow" warning! +//template<template<class T> class = Y1, +// template<class T> class> +// class B1fixme; + +// C++ [temp.param]p10: +template<class T1, class T2 = int> class B2; +template<class T1 = int, class T2> class B2; + +template<template<class, int> class, template<class> class = Y1> class B2t; +template<template<class, int> class = Y2, template<class> class> class B2t; + +template<int N, int M = 5> class B2n; +template<int N = 5, int M> class B2n; + +// C++ [temp.param]p12: +template<class T1, + class T2 = int> // expected-note{{previous default template argument defined here}} + class B3; +template<class T1, typename T2> class B3; +template<class T1, + typename T2 = float> // expected-error{{template parameter redefines default argument}} + class B3; + +template<template<class, int> class, + template<class> class = Y1> // expected-note{{previous default template argument defined here}} + class B3t; + +template<template<class, int> class, template<class> class> class B3t; + +template<template<class, int> class, + template<class> class = Y1> // expected-error{{template parameter redefines default argument}} + class B3t; + +template<int N, + int M = 5> // expected-note{{previous default template argument defined here}} + class B3n; + +template<int N, int M> class B3n; + +template<int N, + int M = 7> // expected-error{{template parameter redefines default argument}} + class B3n; + +// Check validity of default arguments +template<template<class, int> class // expected-note{{previous template template parameter is here}} + = Y1> // expected-error{{template template argument has different template parameters than its corresponding template template parameter}} + class C1; |