From: Douglas Gregor Date: Fri, 25 Sep 2009 21:45:23 +0000 (+0000) Subject: Declarators can now properly represent template-ids, e.g., for X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=db422dffb720ff41d0b60e228f45c685600ffa9e;p=clang Declarators can now properly represent template-ids, e.g., for template void f(int); ~~~~~~ Previously, we silently dropped the template arguments. With this change, we now use the template arguments (when available) as the explicitly-specified template arguments used to aid template argument deduction for explicit template instantiations. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@82806 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/DeclSpec.h b/include/clang/Parse/DeclSpec.h index b7d90e477e..7ecbf7db7b 100644 --- a/include/clang/Parse/DeclSpec.h +++ b/include/clang/Parse/DeclSpec.h @@ -794,8 +794,10 @@ public: DK_Constructor, // A C++ constructor (identifier is the class name) DK_Destructor, // A C++ destructor (identifier is ~class name) DK_Operator, // A C++ overloaded operator name - DK_Conversion // A C++ conversion function (identifier is + DK_Conversion, // A C++ conversion function (identifier is // "operator " then the type name) + DK_TemplateId // A C++ template-id naming a function template + // specialization. }; private: @@ -839,6 +841,10 @@ private: /// When Kind is DK_Operator, this is the actual overloaded /// operator that this declarator names. OverloadedOperatorKind OperatorKind; + + /// When Kind is DK_TemplateId, this is the template-id annotation that + /// contains the template and its template arguments. + TemplateIdAnnotation *TemplateId; }; /// InlineParams - This is a local array used for the first function decl @@ -916,6 +922,10 @@ public: Identifier = 0; IdentifierLoc = SourceLocation(); Range = DS.getSourceRange(); + + if (Kind == DK_TemplateId) + TemplateId->Destroy(); + Kind = DK_Abstract; for (unsigned i = 0, e = DeclTypeInfo.size(); i != e; ++i) @@ -1023,6 +1033,16 @@ public: SetRangeEnd(EndLoc); } + /// \brief Set this declaration to be a C++ template-id, which includes the + /// template (or set of function templates) along with template arguments. + void setTemplateId(TemplateIdAnnotation *TemplateId) { + assert(TemplateId && "NULL template-id provided to declarator?"); + IdentifierLoc = TemplateId->TemplateNameLoc; + Kind = DK_TemplateId; + SetRangeEnd(TemplateId->RAngleLoc); + this->TemplateId = TemplateId; + } + /// AddTypeInfo - Add a chunk to this declarator. Also extend the range to /// EndLoc, which should be the last token of the chunk. void AddTypeInfo(const DeclaratorChunk &TI, SourceLocation EndLoc) { @@ -1085,10 +1105,22 @@ public: void setExtension(bool Val = true) { Extension = Val; } bool getExtension() const { return Extension; } - ActionBase::TypeTy *getDeclaratorIdType() const { return Type; } + ActionBase::TypeTy *getDeclaratorIdType() const { + assert((Kind == DK_Constructor || Kind == DK_Destructor || + Kind == DK_Conversion) && "Declarator kind does not have a type"); + return Type; + } - OverloadedOperatorKind getOverloadedOperator() const { return OperatorKind; } + OverloadedOperatorKind getOverloadedOperator() const { + assert(Kind == DK_Operator && "Declarator is not an overloaded operator"); + return OperatorKind; + } + TemplateIdAnnotation *getTemplateId() { + assert(Kind == DK_TemplateId && "Declarator is not a template-id"); + return TemplateId; + } + void setInvalidType(bool Val = true) { InvalidType = Val; } bool isInvalidType() const { return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error; diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 9525eb364c..2dac473cc6 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -2210,12 +2210,12 @@ void Parser::ParseDeclaratorInternal(Declarator &D, /// /// id-expression: [C++ 5.1] /// unqualified-id -/// qualified-id [TODO] +/// qualified-id /// /// unqualified-id: [C++ 5.1] /// identifier /// operator-function-id -/// conversion-function-id [TODO] +/// conversion-function-id /// '~' class-name /// template-id /// @@ -2254,15 +2254,7 @@ void Parser::ParseDirectDeclarator(Declarator &D) { TemplateIdAnnotation *TemplateId = static_cast(Tok.getAnnotationValue()); - // FIXME: Could this template-id name a constructor? - - // FIXME: This is an egregious hack, where we silently ignore - // the specialization (which should be a function template - // specialization name) and use the name instead. This hack - // will go away when we have support for function - // specializations. - D.SetIdentifier(TemplateId->Name, Tok.getLocation()); - TemplateId->Destroy(); + D.setTemplateId(TemplateId); ConsumeToken(); goto PastIdentifier; } else if (Tok.is(tok::kw_operator)) { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c9983a8f73..074eb6e149 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1587,6 +1587,17 @@ DeclarationName Sema::GetNameForDeclarator(Declarator &D) { assert(D.getIdentifier() == 0 && "operator names have no identifier"); return Context.DeclarationNames.getCXXOperatorName( D.getOverloadedOperator()); + + case Declarator::DK_TemplateId: { + TemplateName Name + = TemplateName::getFromVoidPointer(D.getTemplateId()->Template); + if (TemplateDecl *Template = Name.getAsTemplateDecl()) + return Template->getDeclName(); + if (OverloadedFunctionDecl *Ovl = Name.getAsOverloadedFunctionDecl()) + return Ovl->getDeclName(); + + return DeclarationName(); + } } assert(false && "Unknown name kind"); diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 37fbf45374..27e8edd962 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3409,23 +3409,38 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return DeclPtrTy(); } + // Translate the parser's template argument list in our AST format. + bool HasExplicitTemplateArgs = false; + llvm::SmallVector TemplateArgs; + if (D.getKind() == Declarator::DK_TemplateId) { + TemplateIdAnnotation *TemplateId = D.getTemplateId(); + ASTTemplateArgsPtr TemplateArgsPtr(*this, + TemplateId->getTemplateArgs(), + TemplateId->getTemplateArgIsType(), + TemplateId->NumArgs); + translateTemplateArguments(TemplateArgsPtr, + TemplateId->getTemplateArgLocations(), + TemplateArgs); + HasExplicitTemplateArgs = true; + } + + // C++ [temp.explicit]p1: // A [...] function [...] can be explicitly instantiated from its template. // A member function [...] of a class template can be explicitly // instantiated from the member definition associated with its class // template. - // FIXME: Implement this! llvm::SmallVector Matches; for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); P != PEnd; ++P) { NamedDecl *Prev = *P; - if (CXXMethodDecl *Method = dyn_cast(Prev)) { - // FIXME: If there were any explicitly-specified template arguments, - // don't look for Method declarations. - if (Context.hasSameUnqualifiedType(Method->getType(), R)) { - Matches.clear(); - Matches.push_back(Method); - break; + if (!HasExplicitTemplateArgs) { + if (CXXMethodDecl *Method = dyn_cast(Prev)) { + if (Context.hasSameUnqualifiedType(Method->getType(), R)) { + Matches.clear(); + Matches.push_back(Method); + break; + } } } @@ -3436,7 +3451,8 @@ Sema::DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateDeductionInfo Info(Context); FunctionDecl *Specialization = 0; if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, /*FIXME:*/false, 0, 0, + = DeduceTemplateArguments(FunTmpl, HasExplicitTemplateArgs, + TemplateArgs.data(), TemplateArgs.size(), R, Specialization, Info)) { // FIXME: Keep track of almost-matches? (void)TDK; diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index c297694b9f..d064e3c3ce 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -842,7 +842,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, switch (D.getKind()) { case Declarator::DK_Abstract: case Declarator::DK_Normal: - case Declarator::DK_Operator: { + case Declarator::DK_Operator: + case Declarator::DK_TemplateId: { const DeclSpec &DS = D.getDeclSpec(); if (OmittedReturnType) { // We default to a dependent type initially. Can be modified by diff --git a/test/SemaTemplate/explicit-instantiation.cpp b/test/SemaTemplate/explicit-instantiation.cpp index f92c4635cc..07994f97d3 100644 --- a/test/SemaTemplate/explicit-instantiation.cpp +++ b/test/SemaTemplate/explicit-instantiation.cpp @@ -55,3 +55,17 @@ template int X2::f0(int); // expected-error{{not an instantiation}} template int *X2::f1(int *); // okay template void X2::f2(int *, int *); // expected-error{{ambiguous}} + + +template void print_type(); + +template void print_type(); +template void print_type(); + +template void print_type(T*); + +template void print_type(int*); +template void print_type(float*); // expected-error{{does not refer}} + +void print_type(double*); +template void print_type(double*);