From d684b0027e16163c4bdba3e2f8bfadda7d62a0d3 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 10 Feb 2009 19:49:53 +0000 Subject: [PATCH] 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 --- include/clang/AST/DeclTemplate.h | 81 ++++++- include/clang/Basic/DiagnosticSemaKinds.def | 6 + include/clang/Parse/Action.h | 19 +- lib/AST/DeclTemplate.cpp | 9 + lib/Parse/ParseTemplate.cpp | 57 +++-- lib/Sema/Sema.h | 16 +- lib/Sema/SemaTemplate.cpp | 248 ++++++++++++++++++++ test/Parser/cxx-template-decl.cpp | 4 +- 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