[cfe-commits] r137573 - in /cfe/trunk: include/clang/AST/ include/clang/Basic/ include/clang/Sema/ include/clang/Serialization/ lib/AST/ lib/CodeGen/ lib/Sema/ lib/Serialization/ test/SemaTemplate/ tools/libclang/

Nico Weber thakis at chromium.org
Sun Aug 14 09:10:18 PDT 2011


Hi Francois,

one question below.

On Sat, Aug 13, 2011 at 8:52 PM, Francois Pichet <pichet2000 at gmail.com> wrote:
> Author: fpichet
> Date: Sat Aug 13 22:52:19 2011
> New Revision: 137573
>
> URL: http://llvm.org/viewvc/llvm-project?rev=137573&view=rev
> Log:
> Implement function template specialization at class scope extension in Microsoft mode. A new AST node is introduced: ClassScopeFunctionSpecialization. This node holds a FunctionDecl that is not yet specialized; then during the class template instantiation the ClassScopeFunctionSpecialization will spawn the actual function specialization.
>
> Example:
> template <class T>
> class A {
> public:
>  template <class U> void f(U p) {  }
>  template <> void f(int p) {  } // <== class scope specialization
> };
>
> This extension is necessary to parse MSVC standard C++ headers, MFC and ATL code.
> BTW, with this feature in, clang can parse (-fsyntax-only) all the MSVC 2010 standard header files without any error.

Great news :-)

>
> Added:
>    cfe/trunk/test/SemaTemplate/ms-function-specialization-class-scope.cpp
> Modified:
>    cfe/trunk/include/clang/AST/ASTContext.h
>    cfe/trunk/include/clang/AST/Decl.h
>    cfe/trunk/include/clang/AST/DeclTemplate.h
>    cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
>    cfe/trunk/include/clang/Basic/DeclNodes.td
>    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
>    cfe/trunk/include/clang/Sema/Sema.h
>    cfe/trunk/include/clang/Sema/Template.h
>    cfe/trunk/include/clang/Serialization/ASTBitCodes.h
>    cfe/trunk/lib/AST/ASTContext.cpp
>    cfe/trunk/lib/AST/Decl.cpp
>    cfe/trunk/lib/AST/DeclBase.cpp
>    cfe/trunk/lib/CodeGen/CGDecl.cpp
>    cfe/trunk/lib/Sema/SemaDecl.cpp
>    cfe/trunk/lib/Sema/SemaDeclCXX.cpp
>    cfe/trunk/lib/Sema/SemaTemplate.cpp
>    cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
>    cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
>    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
>    cfe/trunk/tools/libclang/CIndex.cpp
>
> Modified: cfe/trunk/include/clang/AST/ASTContext.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/ASTContext.h (original)
> +++ cfe/trunk/include/clang/AST/ASTContext.h Sat Aug 13 22:52:19 2011
> @@ -152,6 +152,11 @@
>   /// \brief Mapping from __block VarDecls to their copy initialization expr.
>   llvm::DenseMap<const VarDecl*, Expr*> BlockVarCopyInits;
>
> +  /// \brief Mapping from class scope functions specialization to their
> +  ///  templateS pattern.
> +  llvm::DenseMap<const FunctionDecl*, FunctionDecl*>
> +    ClassScopeSpecilizationPattern;
> +
>   /// \brief Representation of a "canonical" template template parameter that
>   /// is used in canonical template names.
>   class CanonicalTemplateTemplateParm : public llvm::FoldingSetNode {
> @@ -382,6 +387,11 @@
>   MemberSpecializationInfo *getInstantiatedFromStaticDataMember(
>                                                            const VarDecl *Var);
>
> +  FunctionDecl *getClassScopeSpecializationPattern(const FunctionDecl *FD);
> +
> +  void setClassScopeSpecializationPattern(FunctionDecl *FD,
> +                                          FunctionDecl *Pattern);
> +
>   /// \brief Note that the static data member \p Inst is an instantiation of
>   /// the static data member template \p Tmpl of a class template.
>   void setInstantiatedFromStaticDataMember(VarDecl *Inst, VarDecl *Tmpl,
>
> Modified: cfe/trunk/include/clang/AST/Decl.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/Decl.h (original)
> +++ cfe/trunk/include/clang/AST/Decl.h Sat Aug 13 22:52:19 2011
> @@ -1851,7 +1851,11 @@
>   bool isFunctionTemplateSpecialization() const {
>     return getPrimaryTemplate() != 0;
>   }
> -
> +
> +  /// \brief Retrieve the class scope template pattern that this function
> +  ///  template specialization is instantiated from.
> +  FunctionDecl *getClassScopeSpecializationPattern() const;
> +
>   /// \brief If this function is actually a function template specialization,
>   /// retrieve information about this function template specialization.
>   /// Otherwise, returns NULL.
>
> Modified: cfe/trunk/include/clang/AST/DeclTemplate.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclTemplate.h?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/DeclTemplate.h (original)
> +++ cfe/trunk/include/clang/AST/DeclTemplate.h Sat Aug 13 22:52:19 2011
> @@ -2097,6 +2097,58 @@
>   friend class ASTDeclWriter;
>  };
>
> +/// Declaration of a function specialization at template class scope.
> +/// This is a non standard extension needed to support MSVC.
> +/// For example:
> +/// template <class T>
> +/// class A {
> +///    template <class U> void foo(U a) { }
> +///    template<> void foo(int a) { }
> +/// }
> +///
> +/// "template<> foo(int a)" will be saved in Specialization as a normal
> +/// CXXMethodDecl. Then during an instantiation of class A, it will be
> +/// transformed into an actual function specialization.
> +class ClassScopeFunctionSpecializationDecl : public Decl {
> +private:
> +  ClassScopeFunctionSpecializationDecl(DeclContext *DC, SourceLocation Loc,
> +                                       CXXMethodDecl *FD)
> +    : Decl(Decl::ClassScopeFunctionSpecialization, DC, Loc),
> +      Specialization(FD) {}
> +
> +  ClassScopeFunctionSpecializationDecl(EmptyShell Empty)
> +    : Decl(Decl::ClassScopeFunctionSpecialization, Empty) {}
> +
> +  CXXMethodDecl *Specialization;
> +
> +public:
> +  CXXMethodDecl *getSpecialization() const { return Specialization; }
> +
> +  static ClassScopeFunctionSpecializationDecl *Create(ASTContext &C,
> +                                                      DeclContext *DC,
> +                                                      SourceLocation Loc,
> +                                                      CXXMethodDecl *FD) {
> +    return new (C) ClassScopeFunctionSpecializationDecl(DC , Loc, FD);
> +  }
> +
> +  static ClassScopeFunctionSpecializationDecl *Create(ASTContext &Context,
> +                                                      EmptyShell Empty) {
> +    return new (Context)ClassScopeFunctionSpecializationDecl(0,
> +                                                         SourceLocation(), 0);
> +  }
> +  // Implement isa/cast/dyncast/etc.
> +  static bool classof(const Decl *D) { return classofKind(D->getKind()); }
> +  static bool classofKind(Kind K) {
> +    return K == Decl::ClassScopeFunctionSpecialization;
> +  }
> +  static bool classof(const ClassScopeFunctionSpecializationDecl *D) {
> +    return true;
> +  }
> +
> +  friend class ASTDeclReader;
> +  friend class ASTDeclWriter;
> +};
> +
>  /// Implementation of inline functions that require the template declarations
>  inline AnyFunctionDecl::AnyFunctionDecl(FunctionTemplateDecl *FTD)
>   : Function(FTD) { }
>
> Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original)
> +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Sat Aug 13 22:52:19 2011
> @@ -1114,6 +1114,10 @@
>     }
>   })
>
> +DEF_TRAVERSE_DECL(ClassScopeFunctionSpecializationDecl, {
> +  TRY_TO(TraverseDecl(D->getSpecialization()));
> + })
> +
>  DEF_TRAVERSE_DECL(LinkageSpecDecl, { })
>
>  DEF_TRAVERSE_DECL(ObjCClassDecl, {
>
> Modified: cfe/trunk/include/clang/Basic/DeclNodes.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DeclNodes.td?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DeclNodes.td (original)
> +++ cfe/trunk/include/clang/Basic/DeclNodes.td Sat Aug 13 22:52:19 2011
> @@ -74,3 +74,4 @@
>  def FriendTemplate : Decl;
>  def StaticAssert : Decl;
>  def Block : Decl, DeclContext;
> +def ClassScopeFunctionSpecialization : Decl;
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Sat Aug 13 22:52:19 2011
> @@ -2028,6 +2028,9 @@
>   "parameter}0">;
>  def err_function_specialization_in_class : Error<
>   "cannot specialize a function %0 within class scope">;
> +def ext_function_specialization_in_class : ExtWarn<
> +  "explicit specialization of %0 within class scope in a Microsoft extension">,

Should this be "…_is_ a Microsoft extension"?

> +  InGroup<Microsoft>;
>  def ext_explicit_specialization_storage_class : ExtWarn<
>   "explicit specialization cannot have a storage class">;
>  def err_explicit_specialization_inconsistent_storage_class : Error<
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Sat Aug 13 22:52:19 2011
> @@ -1002,7 +1002,8 @@
>                                      LookupResult &Previous,
>                                      MultiTemplateParamsArg TemplateParamLists,
>                                      bool IsFunctionDefinition,
> -                                     bool &Redeclaration);
> +                                     bool &Redeclaration,
> +                                     bool &AddToScope);
>   bool AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
>   void DiagnoseHiddenVirtualMethods(CXXRecordDecl *DC, CXXMethodDecl *MD);
>   void CheckFunctionDeclaration(Scope *S,
>
> Modified: cfe/trunk/include/clang/Sema/Template.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Template.h?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Template.h (original)
> +++ cfe/trunk/include/clang/Sema/Template.h Sat Aug 13 22:52:19 2011
> @@ -350,7 +350,8 @@
>                             TemplateParameterList *TemplateParams = 0);
>     Decl *VisitCXXRecordDecl(CXXRecordDecl *D);
>     Decl *VisitCXXMethodDecl(CXXMethodDecl *D,
> -                             TemplateParameterList *TemplateParams = 0);
> +                             TemplateParameterList *TemplateParams = 0,
> +                             bool IsClassScopeSpecialization = false);
>     Decl *VisitCXXConstructorDecl(CXXConstructorDecl *D);
>     Decl *VisitCXXDestructorDecl(CXXDestructorDecl *D);
>     Decl *VisitCXXConversionDecl(CXXConversionDecl *D);
> @@ -367,6 +368,8 @@
>     Decl *VisitUsingShadowDecl(UsingShadowDecl *D);
>     Decl *VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D);
>     Decl *VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D);
> +    Decl *VisitClassScopeFunctionSpecializationDecl(
> +                                      ClassScopeFunctionSpecializationDecl *D);
>
>     // Base case. FIXME: Remove once we can instantiate everything.
>     Decl *VisitDecl(Decl *D) {
>
> Modified: cfe/trunk/include/clang/Serialization/ASTBitCodes.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Serialization/ASTBitCodes.h?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Serialization/ASTBitCodes.h (original)
> +++ cfe/trunk/include/clang/Serialization/ASTBitCodes.h Sat Aug 13 22:52:19 2011
> @@ -826,7 +826,10 @@
>       DECL_INDIRECTFIELD,
>       /// \brief A NonTypeTemplateParmDecl record that stores an expanded
>       /// non-type template parameter pack.
> -      DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK
> +      DECL_EXPANDED_NON_TYPE_TEMPLATE_PARM_PACK,
> +      /// \brief A ClassScopeFunctionSpecializationDecl record a class scope
> +      /// function specialization. (Microsoft extension).
> +      DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION
>     };
>
>     /// \brief Record codes for each kind of statement or expression.
>
> Modified: cfe/trunk/lib/AST/ASTContext.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/ASTContext.cpp (original)
> +++ cfe/trunk/lib/AST/ASTContext.cpp Sat Aug 13 22:52:19 2011
> @@ -518,6 +518,24 @@
>     = new (*this) MemberSpecializationInfo(Tmpl, TSK, PointOfInstantiation);
>  }
>
> +FunctionDecl *ASTContext::getClassScopeSpecializationPattern(
> +                                                     const FunctionDecl *FD){
> +  assert(FD && "Specialization is 0");
> +  llvm::DenseMap<const FunctionDecl*, FunctionDecl *>::const_iterator Pos
> +    = ClassScopeSpecilizationPattern.find(FD);
> +  if (Pos == ClassScopeSpecilizationPattern.end())
> +    return 0;
> +
> +  return Pos->second;
> +}
> +
> +void ASTContext::setClassScopeSpecializationPattern(FunctionDecl *FD,
> +                                        FunctionDecl *Pattern) {
> +  assert(FD && "Specialization is 0");
> +  assert(Pattern && "Class scope specialization pattern is 0");
> +  ClassScopeSpecilizationPattern[FD] = Pattern;
> +}
> +
>  NamedDecl *
>  ASTContext::getInstantiatedFromUsingDecl(UsingDecl *UUD) {
>   llvm::DenseMap<UsingDecl *, NamedDecl *>::const_iterator Pos
> @@ -6439,5 +6457,6 @@
>     + llvm::capacity_in_bytes(InstantiatedFromUnnamedFieldDecl)
>     + llvm::capacity_in_bytes(OverriddenMethods)
>     + llvm::capacity_in_bytes(Types)
> -    + llvm::capacity_in_bytes(VariableArrayTypes);
> +    + llvm::capacity_in_bytes(VariableArrayTypes)
> +    + llvm::capacity_in_bytes(ClassScopeSpecilizationPattern);
>  }
>
> Modified: cfe/trunk/lib/AST/Decl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/Decl.cpp (original)
> +++ cfe/trunk/lib/AST/Decl.cpp Sat Aug 13 22:52:19 2011
> @@ -1922,13 +1922,17 @@
>
>   switch (getTemplateSpecializationKind()) {
>   case TSK_Undeclared:
> -  case TSK_ExplicitSpecialization:
>   case TSK_ExplicitInstantiationDefinition:
>     return false;
>
>   case TSK_ImplicitInstantiation:
>     return true;
>
> +  // It is possible to instantiate TSK_ExplicitSpecialization kind
> +  // if the FunctionDecl has a class scope specialization pattern.
> +  case TSK_ExplicitSpecialization:
> +    return getClassScopeSpecializationPattern() != 0;
> +
>   case TSK_ExplicitInstantiationDeclaration:
>     // Handled below.
>     break;
> @@ -1951,6 +1955,10 @@
>  }
>
>  FunctionDecl *FunctionDecl::getTemplateInstantiationPattern() const {
> +  // Handle class scope explicit specialization special case.
> +  if (getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
> +    return getClassScopeSpecializationPattern();
> +
>   if (FunctionTemplateDecl *Primary = getPrimaryTemplate()) {
>     while (Primary->getInstantiatedFromMemberTemplate()) {
>       // If we have hit a point where the user provided a specialization of
> @@ -1976,6 +1984,10 @@
>   return 0;
>  }
>
> +FunctionDecl *FunctionDecl::getClassScopeSpecializationPattern() const {
> +    return getASTContext().getClassScopeSpecializationPattern(this);
> +}
> +
>  const TemplateArgumentList *
>  FunctionDecl::getTemplateSpecializationArgs() const {
>   if (FunctionTemplateSpecializationInfo *Info
>
> Modified: cfe/trunk/lib/AST/DeclBase.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclBase.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/AST/DeclBase.cpp (original)
> +++ cfe/trunk/lib/AST/DeclBase.cpp Sat Aug 13 22:52:19 2011
> @@ -493,6 +493,7 @@
>     case UsingDirective:
>     case ClassTemplateSpecialization:
>     case ClassTemplatePartialSpecialization:
> +    case ClassScopeFunctionSpecialization:
>     case ObjCImplementation:
>     case ObjCCategory:
>     case ObjCCategoryImpl:
>
> Modified: cfe/trunk/lib/CodeGen/CGDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGDecl.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGDecl.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGDecl.cpp Sat Aug 13 22:52:19 2011
> @@ -70,6 +70,7 @@
>   case Decl::Friend:
>   case Decl::FriendTemplate:
>   case Decl::Block:
> +  case Decl::ClassScopeFunctionSpecialization:
>     assert(0 && "Declaration should not be in declstmts!");
>   case Decl::Function:  // void X();
>   case Decl::Record:    // struct/union/class X;
>
> Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDecl.cpp Sat Aug 13 22:52:19 2011
> @@ -1722,9 +1722,16 @@
>       // Preserve triviality.
>       NewMethod->setTrivial(OldMethod->isTrivial());
>
> +      // MSVC allows explicit template specialization at class scope:
> +      // 2 CXMethodDecls referring to the same function will be injected.
> +      // We don't want a redeclartion error.
> +      bool IsClassScopeExplicitSpecialization =
> +                              OldMethod->isFunctionTemplateSpecialization() &&
> +                              NewMethod->isFunctionTemplateSpecialization();
>       bool isFriend = NewMethod->getFriendObjectKind();
>
> -      if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord()) {
> +      if (!isFriend && NewMethod->getLexicalDeclContext()->isRecord() &&
> +          !IsClassScopeExplicitSpecialization) {
>         //    -- Member function declarations with the same name and the
>         //       same parameter types cannot be overloaded if any of them
>         //       is a static member function declaration.
> @@ -3226,6 +3233,7 @@
>     Previous.clear();
>
>   bool Redeclaration = false;
> +  bool AddToScope = true;
>   if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) {
>     if (TemplateParamLists.size()) {
>       Diag(D.getIdentifierLoc(), diag::err_template_typedef);
> @@ -3236,7 +3244,8 @@
>   } else if (R->isFunctionType()) {
>     New = ActOnFunctionDeclarator(S, D, DC, R, TInfo, Previous,
>                                   move(TemplateParamLists),
> -                                  IsFunctionDefinition, Redeclaration);
> +                                  IsFunctionDefinition, Redeclaration,
> +                                  AddToScope);
>   } else {
>     New = ActOnVariableDeclarator(S, D, DC, R, TInfo, Previous,
>                                   move(TemplateParamLists),
> @@ -3248,7 +3257,8 @@
>
>   // If this has an identifier and is not an invalid redeclaration or
>   // function template specialization, add it to the scope stack.
> -  if (New->getDeclName() && !(Redeclaration && New->isInvalidDecl()))
> +  if (New->getDeclName() && AddToScope &&
> +       !(Redeclaration && New->isInvalidDecl()))
>     PushOnScopeChains(New, S);
>
>   return New;
> @@ -4201,7 +4211,8 @@
>                               QualType R, TypeSourceInfo *TInfo,
>                               LookupResult &Previous,
>                               MultiTemplateParamsArg TemplateParamLists,
> -                              bool IsFunctionDefinition, bool &Redeclaration) {
> +                              bool IsFunctionDefinition, bool &Redeclaration,
> +                              bool &AddToScope) {
>   assert(R.getTypePtr()->isFunctionType());
>
>   // TODO: consider using NameInfo for diagnostic.
> @@ -4266,6 +4277,7 @@
>   FunctionTemplateDecl *FunctionTemplate = 0;
>   bool isExplicitSpecialization = false;
>   bool isFunctionTemplateSpecialization = false;
> +  bool isDependentClassScopeExplicitSpecialization = false;
>
>   if (!getLangOptions().CPlusPlus) {
>     // Determine whether the function was written with a
> @@ -4769,10 +4781,11 @@
>     } else if (isFunctionTemplateSpecialization) {
>       if (CurContext->isDependentContext() && CurContext->isRecord()
>           && !isFriend) {
> -        Diag(NewFD->getLocation(), diag::err_function_specialization_in_class)
> +        isDependentClassScopeExplicitSpecialization = true;
> +        Diag(NewFD->getLocation(), getLangOptions().Microsoft ?
> +          diag::ext_function_specialization_in_class :
> +          diag::err_function_specialization_in_class)
>           << NewFD->getDeclName();
> -        NewFD->setInvalidDecl();
> -        return 0;
>       } else if (CheckFunctionTemplateSpecialization(NewFD,
>                                   (HasExplicitTemplateArgs ? &TemplateArgs : 0),
>                                                      Previous))
> @@ -4802,8 +4815,9 @@
>     }
>
>     // Perform semantic checking on the function declaration.
> -    CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
> -                             Redeclaration);
> +    if (!isDependentClassScopeExplicitSpecialization)
> +      CheckFunctionDeclaration(S, NewFD, Previous, isExplicitSpecialization,
> +                               Redeclaration);
>
>     assert((NewFD->isInvalidDecl() || !Redeclaration ||
>             Previous.getResultKind() != LookupResult::FoundOverloaded) &&
> @@ -4984,6 +4998,18 @@
>           Context.setcudaConfigureCallDecl(NewFD);
>         }
>       }
> +
> +  // Here we have an function template explicit specialization at class scope.
> +  // The actually specialization will be postponed to template instatiation
> +  // time via the ClassScopeFunctionSpecializationDecl node.
> +  if (isDependentClassScopeExplicitSpecialization) {
> +    ClassScopeFunctionSpecializationDecl *NewSpec =
> +                         ClassScopeFunctionSpecializationDecl::Create(
> +                                Context, CurContext,  SourceLocation(),
> +                                cast<CXXMethodDecl>(NewFD));
> +    CurContext->addDecl(NewSpec);
> +    AddToScope = false;
> +  }
>
>   return NewFD;
>  }
>
> Modified: cfe/trunk/lib/Sema/SemaDeclCXX.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclCXX.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp Sat Aug 13 22:52:19 2011
> @@ -8652,10 +8652,11 @@
>   }
>
>   bool Redeclaration = false;
> +  bool AddToScope = true;
>   NamedDecl *ND = ActOnFunctionDeclarator(DCScope, D, DC, T, TInfo, Previous,
>                                           move(TemplateParams),
>                                           IsDefinition,
> -                                          Redeclaration);
> +                                          Redeclaration, AddToScope);
>   if (!ND) return 0;
>
>   assert(ND->getDeclContext() == DC);
>
> Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplate.cpp Sat Aug 13 22:52:19 2011
> @@ -4511,9 +4511,18 @@
>   }
>
>   if (S.CurContext->isRecord() && !IsPartialSpecialization) {
> -    S.Diag(Loc, diag::err_template_spec_decl_class_scope)
> -      << Specialized;
> -    return true;
> +    if (S.getLangOptions().Microsoft) {
> +      // Do not warn for class scope explicit specialization during
> +      // instantiation, warning was already emitted during pattern
> +      // semantic analysis.
> +      if (!S.ActiveTemplateInstantiations.size())
> +        S.Diag(Loc, diag::ext_function_specialization_in_class)
> +          << Specialized;
> +    } else {
> +      S.Diag(Loc, diag::err_template_spec_decl_class_scope)
> +        << Specialized;
> +      return true;
> +    }
>   }
>
>   // C++ [temp.class.spec]p6:
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiate.cpp Sat Aug 13 22:52:19 2011
> @@ -98,8 +98,9 @@
>     // Add template arguments from a function template specialization.
>     else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Ctx)) {
>       if (!RelativeToPrimary &&
> -          Function->getTemplateSpecializationKind()
> -                                                  == TSK_ExplicitSpecialization)
> +          (Function->getTemplateSpecializationKind() ==
> +                                                  TSK_ExplicitSpecialization &&
> +           !Function->getClassScopeSpecializationPattern()))
>         break;
>
>       if (const TemplateArgumentList *TemplateArgs
>
> Modified: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp Sat Aug 13 22:52:19 2011
> @@ -1288,7 +1288,8 @@
>
>  Decl *
>  TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
> -                                      TemplateParameterList *TemplateParams) {
> +                                      TemplateParameterList *TemplateParams,
> +                                      bool IsClassScopeSpecialization) {
>   FunctionTemplateDecl *FunctionTemplate = D->getDescribedFunctionTemplate();
>   void *InsertPos = 0;
>   if (FunctionTemplate && !TemplateParams) {
> @@ -1493,7 +1494,8 @@
>   }
>
>   bool Redeclaration = false;
> -  SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration);
> +  if (!IsClassScopeSpecialization)
> +    SemaRef.CheckFunctionDeclaration(0, Method, Previous, false, Redeclaration);
>
>   if (D->isPure())
>     SemaRef.CheckPureMethod(Method, SourceRange());
> @@ -1512,7 +1514,7 @@
>                             : Method);
>     if (isFriend)
>       Record->makeDeclVisibleInContext(DeclToAdd);
> -    else
> +    else if (!IsClassScopeSpecialization)
>       Owner->addDecl(DeclToAdd);
>   }
>
> @@ -1907,6 +1909,29 @@
>   return UD;
>  }
>
> +
> +Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl(
> +                                     ClassScopeFunctionSpecializationDecl *Decl) {
> +  CXXMethodDecl *OldFD = Decl->getSpecialization();
> +  CXXMethodDecl *NewFD = cast<CXXMethodDecl>(VisitCXXMethodDecl(OldFD, 0, true));
> +
> +  LookupResult Previous(SemaRef, NewFD->getNameInfo(), Sema::LookupOrdinaryName,
> +                        Sema::ForRedeclaration);
> +
> +  SemaRef.LookupQualifiedName(Previous, SemaRef.CurContext);
> +  if (SemaRef.CheckFunctionTemplateSpecialization(NewFD, 0, Previous)) {
> +    NewFD->setInvalidDecl();
> +    return NewFD;
> +  }
> +
> +  // Associate the specialization with the pattern.
> +  FunctionDecl *Specialization = cast<FunctionDecl>(Previous.getFoundDecl());
> +  assert(Specialization && "Class scope Specialization is null");
> +  SemaRef.Context.setClassScopeSpecializationPattern(Specialization, OldFD);
> +
> +  return NewFD;
> +}
> +
>  Decl *Sema::SubstDecl(Decl *D, DeclContext *Owner,
>                       const MultiLevelTemplateArgumentList &TemplateArgs) {
>   TemplateDeclInstantiator Instantiator(*this, Owner, TemplateArgs);
> @@ -2335,8 +2360,10 @@
>   if (Function->isInvalidDecl() || Function->isDefined())
>     return;
>
> -  // Never instantiate an explicit specialization.
> -  if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization)
> +  // Never instantiate an explicit specialization except if it is a class scope
> +  // explicit specialization.
> +  if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization &&
> +      !Function->getClassScopeSpecializationPattern())
>     return;
>
>   // Find the function body that we'll be substituting.
>
> Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
> +++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Sat Aug 13 22:52:19 2011
> @@ -1568,6 +1568,10 @@
>     D = ClassTemplatePartialSpecializationDecl::Create(*Context,
>                                                        Decl::EmptyShell());
>     break;
> +  case DECL_CLASS_SCOPE_FUNCTION_SPECIALIZATION:
> +    D = ClassScopeFunctionSpecializationDecl::Create(*Context,
> +                                                     Decl::EmptyShell());
> +    break;
>   case DECL_FUNCTION_TEMPLATE:
>       D = FunctionTemplateDecl::Create(*Context, Decl::EmptyShell());
>     break;
>
> Added: cfe/trunk/test/SemaTemplate/ms-function-specialization-class-scope.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/ms-function-specialization-class-scope.cpp?rev=137573&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaTemplate/ms-function-specialization-class-scope.cpp (added)
> +++ cfe/trunk/test/SemaTemplate/ms-function-specialization-class-scope.cpp Sat Aug 13 22:52:19 2011
> @@ -0,0 +1,71 @@
> +// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
> +
> +
> +class A {
> +public:
> +       template <class U>
> +    A(U p) {
> +       }
> +       template <>
> +    A(int p) { // expected-warning{{explicit specialization of 'A' within class scope in a Microsoft extension}}
> +       }
> +
> +       template <class U>
> +    void f(U p) {
> +       }
> +
> +       template <>
> +    void f(int p) { // expected-warning{{explicit specialization of 'f' within class scope in a Microsoft extension}}
> +       }
> +
> +       void f(int p) {
> +    }
> +};
> +
> +void test1()
> +{
> +   A a(3);
> +   char* b ;
> +   a.f(b);
> +   a.f<int>(99);
> +   a.f(100);
> +}
> +
> +
> +
> +
> +template <class T>
> +class B {
> +public:
> +       template <class U>
> +    B(U p) {
> +       }
> +       template <>
> +    B(int p) { // expected-warning{{explicit specialization of 'B<T>' within class scope in a Microsoft extension}}
> +       }
> +
> +       template <class U>
> +    void f(U p) {
> +         T y = 9;
> +       }
> +
> +
> +    template <>
> +    void f(int p) { // expected-warning{{explicit specialization of 'f' within class scope in a Microsoft extension}}
> +         T a = 3;
> +       }
> +
> +       void f(int p) {
> +         T a = 3;
> +    }
> +};
> +
> +void test2()
> +{
> +   B<char> b(3);
> +   char* ptr;
> +   b.f(ptr);
> +   b.f<int>(99);
> +   b.f(100);
> +}
> +
>
> Modified: cfe/trunk/tools/libclang/CIndex.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/libclang/CIndex.cpp?rev=137573&r1=137572&r2=137573&view=diff
> ==============================================================================
> --- cfe/trunk/tools/libclang/CIndex.cpp (original)
> +++ cfe/trunk/tools/libclang/CIndex.cpp Sat Aug 13 22:52:19 2011
> @@ -4048,6 +4048,7 @@
>   case Decl::StaticAssert:
>   case Decl::Block:
>   case Decl::Label:  // FIXME: Is this right??
> +  case Decl::ClassScopeFunctionSpecialization:
>     return C;
>
>   // Declaration kinds that don't make any sense here, but are
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>




More information about the cfe-commits mailing list