diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-02-10 19:49:53 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-02-10 19:49:53 +0000 |
commit | d684b0027e16163c4bdba3e2f8bfadda7d62a0d3 (patch) | |
tree | a79e6aaf67bfe44dfd93d71bf06cb15d53494312 /lib/Sema/SemaTemplate.cpp | |
parent | f63aa3fd429cdb9145d78f0b656bc78754efedb9 (diff) |
Implement parsing, semantic analysis and ASTs for default template
arguments. This commit covers checking and merging default template
arguments from previous declarations, but it does not cover the actual
use of default template arguments when naming class template
specializations.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64229 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaTemplate.cpp')
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
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, |